Skip to content

Mattermost mobile file upload#9898

Open
sbishel wants to merge 6 commits into
mainfrom
mattermost-mobile-file-upload
Open

Mattermost mobile file upload#9898
sbishel wants to merge 6 commits into
mainfrom
mattermost-mobile-file-upload

Conversation

@sbishel

@sbishel sbishel commented Jun 29, 2026

Copy link
Copy Markdown
Member

Summary

Ticket Link

Checklist

  • Added or updated unit tests (required for all new features)
  • Has UI changes
  • Includes text changes and localization file updates
  • Have tested against the 5 core themes to ensure consistency between them.
  • Have run E2E tests by adding label E2E/Run (or E2E/Run-iOS / E2E/Run-Android for platform-specific runs).

Device Information

This PR was tested on:

Screenshots

Release Note


@mattermost-build mattermost-build added the E2E/Run Triggers E2E tests on both iOS and Android via Matterwick label Jun 29, 2026
@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown

Coverage Comparison Report

Generated on June 29, 2026 at 22:15:55 UTC

+-----------------+------------+------------+-----------+
| Metric          | Main       | This PR    | Diff      |
+-----------------+------------+------------+-----------+
| Lines           |     87.76% |     87.77% |     0.01% |
| Statements      |     87.62% |     87.63% |     0.01% |
| Branches        |     76.47% |     76.49% |     0.02% |
| Functions       |     87.22% |     87.24% |     0.02% |
+-----------------+------------+------------+-----------+
| Total           |     84.76% |     84.78% |     0.02% |
+-----------------+------------+------------+-----------+

@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a8a0ac53-65e1-46d3-8d21-cca5d6475157

📥 Commits

Reviewing files that changed from the base of the PR and between f7daa09 and db48256.

⛔ Files ignored due to path filters (2)
  • ios/Podfile.lock is excluded by !**/*.lock
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (4)
  • app/utils/dialog_conversion.test.ts
  • app/utils/dialog_conversion.ts
  • assets/base/i18n/en.json
  • package.json
✅ Files skipped from review due to trivial changes (1)
  • assets/base/i18n/en.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • app/utils/dialog_conversion.test.ts
  • app/utils/dialog_conversion.ts

📝 Walkthrough

Walkthrough

Adds FILE support across dialog conversion, Apps Form, dialog routing, REST file-info fetching, and E2E coverage, including file upload, hydration, validation, and submission payload handling.

Changes

File Upload Field in Interactive Dialogs

Layer / File(s) Summary
Types and REST file fetch
types/api/integrations.d.ts, types/api/apps.d.ts, app/constants/apps.ts, app/utils/dialog_utils.ts, app/client/rest/files.ts, app/client/rest/files.test.ts, app/actions/remote/file.ts, app/actions/remote/file.test.ts
DialogSubmission, DialogElement, InteractiveDialogElementType, AppFieldTypes, and DialogElementTypes add FILE-related members. ClientFiles adds getFileInfo, and fetchFilesInfo fetches multiple file infos with partial-failure handling and tests.
Dialog conversion and validation
app/utils/dialog_conversion.ts, app/utils/dialog_conversion.test.ts, app/utils/integrations.ts, app/utils/integrations.test.ts, app/utils/interactive_dialog_adapter.ts, app/utils/interactive_dialog_adapter.test.ts, app/utils/navigation/index.tsx
Adds FILE conversion helpers, FILE submission handling, allow_multiple mapping, required-field validation for FILE values, file_ids collection in dialog submission, and the updated attachment upload callback type.
Apps Form file field
app/screens/apps_form/apps_form_file_field/apps_form_file_field.tsx, app/screens/apps_form/apps_form_file_field/index.ts, assets/base/i18n/en.json, app/screens/apps_form/apps_form_file_field/apps_form_file_field.test.tsx
Introduces the file-field component, its database wrapper, UI strings, and tests for hydration, upload, removal, pending state, and single/multi-file behaviour.
Apps Form wiring
app/screens/apps_form/apps_form_field.tsx, app/screens/apps_form/apps_form_component.tsx, app/screens/apps_form/index.tsx
Renders FILE fields in the form, tracks upload-in-progress state to block submission, and passes channel context into the form screen.
DialogRouter channel and file IDs
app/screens/dialog_router/dialog_router.tsx, app/screens/dialog_router/index.tsx, app/screens/dialog_router/dialog_router.test.tsx
Injects channelId into DialogRouter, accumulates FILE values across multiform and refresh flows, includes file_ids on submission, and updates router tests and wrapper wiring.
E2E file upload dialog coverage
detox/e2e/support/server_api/plugin.ts, detox/e2e/support/ui/screen/interactive_dialog.ts, detox/e2e/test/products/channels/interactive_dialog/interactive_dialog_plugin.e2e.ts
Adds plugin API submission for the file-upload dialog, UI helpers for file-field interactions, and E2E coverage for submit-with-no-files, disabled upload state, and hydrated file previews.

Sequence Diagram(s)

sequenceDiagram
  participant AppsFormFileField
  participant AppsFormComponent
  participant DialogRouter
  participant Server

  AppsFormFileField->>AppsFormComponent: onPendingChange(true/false)
  AppsFormComponent->>AppsFormComponent: block submit while uploads active
  AppsFormComponent->>DialogRouter: submit values
  DialogRouter->>DialogRouter: mergeFileFieldValues + flattenFileFieldValues
  DialogRouter->>Server: submitInteractiveDialog({ submission, file_ids })
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Suggested labels

Build Apps for PR, 3: QA Review, 2: UX Review

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The description is just the PR template and does not describe the actual changes. Replace the template with a short summary of the file upload changes and any notable implementation details.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding mobile file upload support.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch mattermost-mobile-file-upload

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🧹 Nitpick comments (8)
app/screens/apps_form/apps_form_file_field/apps_form_file_field.test.tsx (2)

252-257: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Avoid TypeScript-satisfaction conditionals in these mocks.

The if (onComplete) / if (onError) guards make the tests less strict and can hide a callback contract break. Capture those callbacks with a typed mock signature or direct assertion instead. As per coding guidelines, don't create conditionals in tests for TypeScript satisfaction.

Also applies to: 289-293, 333-337, 366-370, 397-401, 467-471, 515-519

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/screens/apps_form/apps_form_file_field/apps_form_file_field.test.tsx`
around lines 252 - 257, The test mocks in apps_form_file_field.test.tsx use
TypeScript-satisfaction guards around callback capture, which weakens the
contract being tested. Update the mock implementations for upload and related
handlers to capture callbacks directly with a typed mock signature or an
explicit assertion instead of using conditional checks like if (onComplete) or
if (onError). Apply the same cleanup in all affected mock blocks so the tests
rely on the real callback contract rather than optional-guarded behavior.

Source: Coding guidelines


328-359: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert the full joined ID list.

toMatch(/id-a|id-b/) passes even if only one uploaded ID makes it into onChange, so this won't catch the regression the spec is meant to cover. Please assert the exact joined value, or split it and verify both IDs plus length. As per coding guidelines, check array lengths in addition to individual items, and test expectations must match actual implementation behaviour.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/screens/apps_form/apps_form_file_field/apps_form_file_field.test.tsx`
around lines 328 - 359, The multiple-upload test in AppsFormFileField is too
loose because it only matches either uploaded ID instead of verifying the full
joined result. Update the assertion in the joined-IDs case to check the exact
value emitted by onChange, or split the returned string and verify both IDs and
the array length; use the AppsFormFileField upload callback flow and
mockOnChange call capture to ensure both uploaded IDs are preserved in order.

Source: Coding guidelines

app/actions/remote/file.test.ts (1)

256-278: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert the forwarded file IDs here.

These specs only verify the returned files, so they would still pass if fetchFilesInfo called getFileInfo with the wrong IDs or duplicated one of them. Add toHaveBeenNthCalledWith (or inspect mock.calls) for the requested IDs as well. As per coding guidelines, test expectations must match actual implementation behaviour.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/actions/remote/file.test.ts` around lines 256 - 278, The fetchFilesInfo
tests only check the returned files, so they do not verify that the requested
file IDs are actually forwarded to mockClient.getFileInfo. Update the specs in
file.test.ts around fetchFilesInfo to assert the exact call arguments using
toHaveBeenNthCalledWith or mock.calls, alongside the existing order/skip
assertions. Make sure the checks reference the fetchFilesInfo and getFileInfo
flow so the test fails if IDs are duplicated, reordered, or replaced.

Source: Coding guidelines

app/screens/apps_form/apps_form_component.tsx (1)

279-281: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Log the blocked submit early return.

This new no-op path is silent today, which makes stuck-submit reports harder to trace. As per coding guidelines, "Log on early returns in handlers with a logDebug call so the no-op is traceable, and add function/class prefix to logs..."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/screens/apps_form/apps_form_component.tsx` around lines 279 - 281, The
early return in handleSubmit is currently silent when submitting is true or
uploadingFields.size > 0, so add a logDebug call before returning to trace the
blocked submit path. Use the AppsFormComponent/handleSubmit context in the log
message so it clearly identifies the handler and includes the reason for the
no-op. Keep the behavior unchanged otherwise and ensure the log happens only on
this blocked-submit branch.

Source: Coding guidelines

app/screens/apps_form/apps_form_file_field/apps_form_file_field.tsx (1)

82-95: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Read serverUrl from context inside this component.

Please avoid threading serverUrl through AppsFormField/AppsFormComponent just to reach this leaf. As per coding guidelines, "Use useServerUrl() hook instead of passing serverUrl as a prop - it's available via context."

Also applies to: 161-162

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/screens/apps_form/apps_form_file_field/apps_form_file_field.tsx` around
lines 82 - 95, The Props for AppsFormFileField should not require serverUrl to
be threaded down from AppsFormField/AppsFormComponent; read it directly from
context instead. Update AppsFormFileField to use the useServerUrl() hook where
serverUrl is currently consumed, and remove the serverUrl prop from the
component’s public API and all call sites that pass it through.

Source: Coding guidelines

app/utils/dialog_conversion.test.ts (1)

1005-1041: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Rename the new test cases to the repo’s should... format.

These new it(...) names skip the required prefix, so the suite is inconsistent with the repo’s test naming convention. As per coding guidelines, **/*.test.{ts,tsx}: Use it('should...') format for test names.

Proposed rename pattern
-        it('collects and trims comma-joined IDs from FILE elements', () => {
+        it('should collect and trim comma-joined IDs from FILE elements', () => {

-        it('collects across multiple FILE fields', () => {
+        it('should collect across multiple FILE fields', () => {

-        it('deduplicates repeated IDs', () => {
+        it('should deduplicate repeated IDs', () => {

-        it('ignores non-FILE elements and empty values', () => {
+        it('should ignore non-FILE elements and empty values', () => {

-        it('returns an empty array when elements is omitted', () => {
+        it('should return an empty array when elements is omitted', () => {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/utils/dialog_conversion.test.ts` around lines 1005 - 1041, The new
collectFileIds test cases in dialog_conversion.test.ts should use the repo’s
required should... naming convention. Update each existing it(...) description
under the collectFileIds describe block to start with should while preserving
the same behavior coverage, so the test names match the established pattern used
across the suite.

Source: Coding guidelines

app/utils/integrations.test.ts (1)

227-240: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Rename these cases to the repo’s it('should...') form.

These new FILE tests are the only added cases in this block that drift from the enforced Jest naming pattern. As per coding guidelines, Use it('should...') format for test names.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/utils/integrations.test.ts` around lines 227 - 240, The new FILE-related
Jest cases in integrations.test.ts use a different naming style than the repo
standard. Rename the affected `it(...)` descriptions to the enforced
`it('should...')` format for these FILE test cases, keeping the test logic and
assertions unchanged in the `checkDialogElementForError` block.

Source: Coding guidelines

app/screens/dialog_router/dialog_router.test.tsx (1)

121-343: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a multistep FILE regression case here.

These updates cover the new channelId prop, but they still do not exercise the new accumulated FILE-ID path. A case where step 2 clears or replaces a step 1 upload would catch mismatches between submission[field] and file_ids before this ships.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/screens/dialog_router/dialog_router.test.tsx` around lines 121 - 343, Add
a multistep FILE regression test in dialog_router.test.tsx that exercises the
accumulated FILE-ID flow. Use DialogRouter with a mock config containing a FILE
field, then simulate step 1 selecting/uploading a file and step 2 clearing or
replacing it so the submitted values differ from the accumulated file_ids.
Assert the submit path still sends the correct FILE-ID mapping through the
DialogRouter submit handler and AppsFormComponent props, catching any mismatch
between submission[field] and file_ids.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/screens/apps_form/apps_form_file_field/apps_form_file_field.test.tsx`:
- Around line 462-508: The single-file replace spec is exercising a flow that
the UI currently blocks, so it can pass without proving the real behavior. In
AppsFormFileField, either update the choose-button gating in the file field
component so a second selection is actually allowed when allowMultiple is false,
or change this test to assert the second press really opens the picker before
reusing captureOnUploadFiles. Use the AppsFormFileField choose-button and
openAttachmentOptions path to locate the relevant behavior.

In `@app/screens/apps_form/apps_form_file_field/apps_form_file_field.tsx`:
- Around line 278-281: The upload flow in apps_form_file_field.tsx does not
handle the synchronous {error} return shape from uploadFile, so a failed upload
can leave the entry stuck in uploading. Update the logic around uploadFile in
the file upload handler to detect and process a returned error immediately,
using the existing onError/onComplete flow or equivalent state cleanup, and only
store result.cancel in cancelMapRef.current when a valid cancel handle is
present.
- Around line 176-185: The cleanup in AppsFormFileField’s useEffect only cancels
in-flight transports, so the field can remain stuck in AppsFormComponent’s
uploadingFields after unmount. Update the unmount path in AppsFormFileField to
also clear this field’s pending/uploading state before or after canceling
outstanding requests, using the existing field identity used by the upload
tracking logic so submit is re-enabled when the FILE field is removed.
- Around line 190-205: The hydration path in apps_form_file_field.tsx updates
only the local entries state, so missing/deleted file IDs can remain in the
submitted comma-separated value. After fetchFilesInfo resolves in the
useDidMount logic, derive the kept IDs from the returned files and sync the form
value through the existing onChange path when hydrating, while still respecting
isMountedRef and hasInteractedRef. Use uploadedEntryFromFileInfo and the current
value parsing/splitting logic to ensure any IDs filtered out by fetchFilesInfo
are removed from the submitted value.

In `@app/screens/dialog_router/dialog_router.tsx`:
- Around line 71-75: The current accumulatedFileIds state in dialog_router.tsx
is append-only, so it can keep stale FILE attachments when a later step clears
or replaces an earlier field. Update the DialogRouter flow to track retained
file IDs per field name (or derive them from the merged submission state)
instead of a single flat array, and make sure the final submit path uses that
field-aware source when building file_ids. Review the logic around
accumulatedFileIds, the per-step merge/update handlers, and the final submit
assembly so removed uploads are dropped correctly.

In `@detox/e2e/support/ui/screen/interactive_dialog.ts`:
- Around line 182-187: The check in expectFileFieldChooseButtonDisabled
currently uses an immediate not.toExist assertion, so it can miss a picker that
appears slightly later during the animation. Update the logic around
getFileFieldChooseButton and the file_attachment.photo_library element to use a
bounded waitFor(...).not.toExist() with an appropriate timeout after the tap, so
the test verifies the sheet stays hidden instead of only being absent at one
instant.

In
`@detox/e2e/test/products/channels/interactive_dialog/interactive_dialog_plugin.e2e.ts`:
- Around line 789-810: The test in InteractiveDialogScreen mutates shared server
config by toggling FileSettings.EnableMobileUpload, so if it fails the cleanup
never runs and later specs inherit bad state. Wrap the config changes in a
try/finally around the body of MM-T6072_1, and in the finally restore
EnableMobileUpload to true after any dialog cleanup so the state is always reset
even on failure.
- Around line 749-842: Remove the `it.only` guards from the three Detox cases in
`interactive_dialog_plugin.e2e.ts` so the full spec suite runs instead of
isolating only `MM-T6070_1`, `MM-T6072_1`, and `MM-T6073_1`; keep the test
bodies and assertions unchanged, just convert each `it.only(...)` back to a
normal `it(...)` so other tests in `interactive_dialog_plugin.e2e.ts` are no
longer skipped.

In `@detox/e2e/test/setup.ts`:
- Line 10: This setup file is still importing serverOneUrl and siteOneUrl from
the old test_config module, so it can diverge from the URLs resolved during
global setup. Update the import in setup.ts (and the related admin-login/debug
usage around the referenced lines) to use the new shared server_urls module so
the same resolved URLs are used everywhere, especially when SITE_1_API_URL or
LAN-based simulator URLs are in play.

---

Nitpick comments:
In `@app/actions/remote/file.test.ts`:
- Around line 256-278: The fetchFilesInfo tests only check the returned files,
so they do not verify that the requested file IDs are actually forwarded to
mockClient.getFileInfo. Update the specs in file.test.ts around fetchFilesInfo
to assert the exact call arguments using toHaveBeenNthCalledWith or mock.calls,
alongside the existing order/skip assertions. Make sure the checks reference the
fetchFilesInfo and getFileInfo flow so the test fails if IDs are duplicated,
reordered, or replaced.

In `@app/screens/apps_form/apps_form_component.tsx`:
- Around line 279-281: The early return in handleSubmit is currently silent when
submitting is true or uploadingFields.size > 0, so add a logDebug call before
returning to trace the blocked submit path. Use the
AppsFormComponent/handleSubmit context in the log message so it clearly
identifies the handler and includes the reason for the no-op. Keep the behavior
unchanged otherwise and ensure the log happens only on this blocked-submit
branch.

In `@app/screens/apps_form/apps_form_file_field/apps_form_file_field.test.tsx`:
- Around line 252-257: The test mocks in apps_form_file_field.test.tsx use
TypeScript-satisfaction guards around callback capture, which weakens the
contract being tested. Update the mock implementations for upload and related
handlers to capture callbacks directly with a typed mock signature or an
explicit assertion instead of using conditional checks like if (onComplete) or
if (onError). Apply the same cleanup in all affected mock blocks so the tests
rely on the real callback contract rather than optional-guarded behavior.
- Around line 328-359: The multiple-upload test in AppsFormFileField is too
loose because it only matches either uploaded ID instead of verifying the full
joined result. Update the assertion in the joined-IDs case to check the exact
value emitted by onChange, or split the returned string and verify both IDs and
the array length; use the AppsFormFileField upload callback flow and
mockOnChange call capture to ensure both uploaded IDs are preserved in order.

In `@app/screens/apps_form/apps_form_file_field/apps_form_file_field.tsx`:
- Around line 82-95: The Props for AppsFormFileField should not require
serverUrl to be threaded down from AppsFormField/AppsFormComponent; read it
directly from context instead. Update AppsFormFileField to use the
useServerUrl() hook where serverUrl is currently consumed, and remove the
serverUrl prop from the component’s public API and all call sites that pass it
through.

In `@app/screens/dialog_router/dialog_router.test.tsx`:
- Around line 121-343: Add a multistep FILE regression test in
dialog_router.test.tsx that exercises the accumulated FILE-ID flow. Use
DialogRouter with a mock config containing a FILE field, then simulate step 1
selecting/uploading a file and step 2 clearing or replacing it so the submitted
values differ from the accumulated file_ids. Assert the submit path still sends
the correct FILE-ID mapping through the DialogRouter submit handler and
AppsFormComponent props, catching any mismatch between submission[field] and
file_ids.

In `@app/utils/dialog_conversion.test.ts`:
- Around line 1005-1041: The new collectFileIds test cases in
dialog_conversion.test.ts should use the repo’s required should... naming
convention. Update each existing it(...) description under the collectFileIds
describe block to start with should while preserving the same behavior coverage,
so the test names match the established pattern used across the suite.

In `@app/utils/integrations.test.ts`:
- Around line 227-240: The new FILE-related Jest cases in integrations.test.ts
use a different naming style than the repo standard. Rename the affected
`it(...)` descriptions to the enforced `it('should...')` format for these FILE
test cases, keeping the test logic and assertions unchanged in the
`checkDialogElementForError` block.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9546da8f-465e-4168-b8e5-b222fff12064

📥 Commits

Reviewing files that changed from the base of the PR and between 84ea188 and 3b0e3d1.

📒 Files selected for processing (32)
  • app/actions/remote/file.test.ts
  • app/actions/remote/file.ts
  • app/client/rest/files.test.ts
  • app/client/rest/files.ts
  • app/constants/apps.ts
  • app/screens/apps_form/apps_form_component.tsx
  • app/screens/apps_form/apps_form_field.tsx
  • app/screens/apps_form/apps_form_file_field/apps_form_file_field.test.tsx
  • app/screens/apps_form/apps_form_file_field/apps_form_file_field.tsx
  • app/screens/apps_form/apps_form_file_field/index.ts
  • app/screens/apps_form/index.tsx
  • app/screens/dialog_router/dialog_router.test.tsx
  • app/screens/dialog_router/dialog_router.tsx
  • app/screens/dialog_router/index.tsx
  • app/utils/dialog_conversion.test.ts
  • app/utils/dialog_conversion.ts
  • app/utils/dialog_utils.ts
  • app/utils/integrations.test.ts
  • app/utils/integrations.ts
  • app/utils/interactive_dialog_adapter.test.ts
  • app/utils/interactive_dialog_adapter.ts
  • app/utils/navigation/index.tsx
  • assets/base/i18n/en.json
  • detox/e2e/global_setup.js
  • detox/e2e/support/server_api/plugin.ts
  • detox/e2e/support/server_urls.d.ts
  • detox/e2e/support/server_urls.js
  • detox/e2e/support/ui/screen/interactive_dialog.ts
  • detox/e2e/test/products/channels/interactive_dialog/interactive_dialog_plugin.e2e.ts
  • detox/e2e/test/setup.ts
  • types/api/apps.d.ts
  • types/api/integrations.d.ts

Comment thread app/screens/apps_form/apps_form_file_field/apps_form_file_field.test.tsx Outdated
Comment thread app/screens/apps_form/apps_form_file_field/apps_form_file_field.tsx
Comment thread app/screens/apps_form/apps_form_file_field/apps_form_file_field.tsx Outdated
Comment thread app/screens/apps_form/apps_form_file_field/apps_form_file_field.tsx
Comment thread app/screens/dialog_router/dialog_router.tsx Outdated
Comment thread detox/e2e/support/ui/screen/interactive_dialog.ts
Comment thread detox/e2e/test/setup.ts Outdated
@mattermost-build mattermost-build added E2E/Run Triggers E2E tests on both iOS and Android via Matterwick and removed E2E/Run Triggers E2E tests on both iOS and Android via Matterwick labels Jun 29, 2026
@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown
Documentation Impact Analysis — updates needed

Documentation Impact Analysis

Overall Assessment: Documentation Updates Recommended

Changes Summary

PR 9898 adds support for a new file field type in Interactive Dialogs (Apps Forms) on the Mattermost mobile app, allowing plugin and integration developers to include file upload fields in their dialogs. The implementation introduces a new AppsFormFileField component with upload/remove/progress UI, a new REST client method for fetching file metadata, file ID collection and submission with dialog payloads, and three new i18n strings for the file field UI.

Documentation Impact Details

Change Type Files Changed Affected Personas Documentation Action Docs Location
New i18n strings (new user-facing feature) assets/base/i18n/en.json — new keys apps_form.file_field.choose_file, apps_form.file_field.choose_files, apps_form.file_field.upload_failed End User, Developer/Integrator Add changelog entry for file upload support in interactive dialog forms docs/source/product-overview/mobile-app-changelog.md
New or changed UI component (new user interaction) app/screens/apps_form/apps_form_file_field/ (new component), app/screens/apps_form/apps_form_field.tsx, app/screens/apps_form/apps_form_component.tsx End User, Developer/Integrator Note that interactive dialogs on mobile now support file field type including upload, progress, and remove interactions docs/source/product-overview/mobile-app-changelog.md
New or changed API endpoint consumed app/client/rest/files.ts — new getFileInfo method; app/actions/remote/file.ts — new fetchFilesInfo action Developer/Integrator Document that the file Interactive Dialog element type is now supported on mobile (plugin authors using type: "file" in dialog elements can now expect mobile clients to render a file picker and submit file_ids) New page or section needed in docs/source/integrations-guide/ — no dedicated Interactive Dialogs page currently exists in this directory

Recommended Actions

  • Add an entry to docs/source/product-overview/mobile-app-changelog.md for the next mobile release noting that interactive dialogs now support file upload fields (type: file), including single- and multi-file modes, upload progress, and removal of uploaded files before submission.
  • Consider adding documentation for Interactive Dialog file field support in docs/source/integrations-guide/ (no dedicated interactive dialogs page currently exists there). A note in docs/source/integrations-guide/plugins.rst or a new interactive-dialogs.rst page would help plugin developers know that type: "file" dialog elements — including the allow_multiple flag and file_ids in the submission payload — are now supported on mobile clients.

Confidence

Medium — The mobile-app-changelog entry is high-confidence (new user-visible feature with new i18n strings). The integrations-guide recommendation is medium-confidence: primary Interactive Dialog developer documentation lives at developers.mattermost.com (outside docs/source/), so the gap inside docs/source/ may be intentional. The changelog entry is the clearest and most actionable recommendation.

@github-actions github-actions Bot added the Docs/Needed Requires documentation label Jun 29, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/utils/dialog_conversion.ts`:
- Around line 40-42: The file merge logic in dialog conversion is using the
generic `in` operator, so inherited prototype keys can be treated as real
submitted fields. Update the `elements.forEach` block in
`app/utils/dialog_conversion.ts` to use an own-property check against
`submission` before assigning into `merged`, so only actual submitted file
fields are copied and reserved names like `toString`, `constructor`, or
`__proto__` are ignored.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6650ec08-ee49-419e-b8b7-c3e08743ffce

📥 Commits

Reviewing files that changed from the base of the PR and between 3b0e3d1 and f7daa09.

📒 Files selected for processing (9)
  • app/screens/apps_form/apps_form_file_field/apps_form_file_field.test.tsx
  • app/screens/apps_form/apps_form_file_field/apps_form_file_field.tsx
  • app/screens/dialog_router/dialog_router.tsx
  • app/utils/dialog_conversion.test.ts
  • app/utils/dialog_conversion.ts
  • assets/base/i18n/en.json
  • detox/e2e/support/ui/screen/interactive_dialog.ts
  • detox/e2e/test/products/channels/interactive_dialog/interactive_dialog_plugin.e2e.ts
  • types/api/integrations.d.ts
💤 Files with no reviewable changes (1)
  • types/api/integrations.d.ts
✅ Files skipped from review due to trivial changes (1)
  • assets/base/i18n/en.json
🚧 Files skipped from review as they are similar to previous changes (6)
  • app/utils/dialog_conversion.test.ts
  • detox/e2e/support/ui/screen/interactive_dialog.ts
  • app/screens/apps_form/apps_form_file_field/apps_form_file_field.test.tsx
  • app/screens/dialog_router/dialog_router.tsx
  • detox/e2e/test/products/channels/interactive_dialog/interactive_dialog_plugin.e2e.ts
  • app/screens/apps_form/apps_form_file_field/apps_form_file_field.tsx

Comment thread app/utils/dialog_conversion.ts
@mattermost-build mattermost-build added E2E/Run Triggers E2E tests on both iOS and Android via Matterwick and removed E2E/Run Triggers E2E tests on both iOS and Android via Matterwick labels Jun 29, 2026
@mattermost-build mattermost-build removed the E2E/Run Triggers E2E tests on both iOS and Android via Matterwick label Jun 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Docs/Needed Requires documentation release-note

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants