Skip to content

Show report field save errors on the field's row - #104938

Open
MelvinBot wants to merge 6 commits into
mainfrom
claude-showReportFieldFormulaError
Open

MelvinBot wants to merge 6 commits into
mainfrom
claude-showReportFieldFormulaError

Conversation

@MelvinBot

@MelvinBot MelvinBot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

Explanation of Change

When the server rejects a new report field (for example, because its default value has an invalid formula like {field:DoesNotExist}), the App removed the field from the list and stored a generic error that nothing displayed. The user got no feedback.

The backend now returns the specific error at errorFields.fieldList.<fieldKey>.defaultValue.<microtime>, the same shape the App already reads for the report title error. This PR shows that error on the failed field's row, as Categories and Tags do:

  • Keep the failed row: createReportField's failure data no longer touches the policy's fieldList, so the field stays on the policy with the pendingAction: ADD set by the optimistic data. It is still removed from each report's fieldList.
  • Set the generic error in the same place as the server error: The generic failure error of createReportField and updateReportFieldInitialValue is now set at errorFields.fieldList.<fieldKey>.defaultValue, instead of errorFields.<fieldKey>.
  • Show the error on the row: WorkspaceFieldsSection passes each row's latest errorFields.fieldList[fieldKey].defaultValue error to OfflineWithFeedback.
  • Dismiss: The new clearReportFieldErrors clears the field's errors. If the field is still pending ADD (it failed to be created), it also removes the field, mirroring clearCategoryErrors.
  • Keep failed fields off reports: getAvailableReportFields skips policy fields that are pending ADD and not already on the report. Optimistic adds are written to the report's fieldList, so they still show.
  • Clear errors narrowly: The optimistic and success data of createReportField and updateReportFieldInitialValue used errorFields: null, which wiped every policy error, including the report title error. They now clear only that field's errors.

updateReportFieldInitialValue already keeps the row and reverts the value on failure, so its server error now also shows on the row.

Fixed Issues

$ #104067
PROPOSAL: #104067 (comment)

Tests

// TODO: The human co-author must fill out the tests you ran before marking this PR as "ready for review"
// Please describe what tests you performed that validates your changed worked.

  • Verify that no errors appear in the JS console

Offline tests

QA Steps

// TODO: The human co-author must fill out the QA tests you ran before marking this PR as "ready for review".
// Please describe what QA needs to do to validate your changes and what areas do they need to test for regressions.

  • Verify that no errors appear in the JS console

PR Author Checklist

  • I linked the correct issue in the ### Fixed Issues section above
  • I wrote clear testing steps that cover the changes made in this PR
    • I added steps for local testing in the Tests section
    • I added steps for the expected offline behavior in the Offline steps section
    • I added steps for Staging and/or Production testing in the QA steps section
    • I added steps to cover failure scenarios (i.e. verify an input displays the correct error message if the entered data is not correct)
    • I turned off my network connection and tested it while offline to ensure it matches the expected behavior (i.e. verify the default avatar icon is displayed if app is offline)
    • I tested this PR with a High Traffic account against the staging or production API to ensure there are no regressions (e.g. long loading states that impact usability).
  • I included screenshots or videos for tests on all platforms
  • I ran the tests on all platforms & verified they passed on:
    • Android: Native
    • Android: mWeb Chrome
    • iOS: Native
    • iOS: mWeb Safari
    • MacOS: Chrome / Safari
  • I verified there are no console errors (if there's a console error not related to the PR, report it or open an issue for it to be fixed)
  • I verified any copy / text that was added to the app is either coming verbatim from figma or has been approved by marketing (in order to get marketing approval, ask the Bug Zero team member to add the Waiting for copy label to the issue)
  • If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers
  • I tested other components that can be impacted by my changes (i.e. if the PR modifies a shared library or component like Avatar, I verified the components using Avatar are working as expected)
  • If new assets were added or existing ones were modified, I verified that:
    • The assets are optimized and compressed (for SVG files, run npm run compress-svg)
    • The assets load correctly across all supported platforms.
  • If the PR modifies code that runs when editing or sending messages, I tested and verified there is no unexpected behavior for all supported markdown - URLs, single line code, code blocks, quotes, headings, bold, strikethrough, and italic.
  • If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like Avatar is modified, I verified that Avatar is working as expected)
  • If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected.
  • If the PR modifies a component or page that can be accessed by a direct deeplink, I verified that the code functions as expected when the deeplink is used - from a logged in and logged out account.
  • If the PR modifies the UI (e.g. new buttons, new UI components, changing the padding/spacing/sizing, moving components, etc) or modifies the form input styles:
    • I verified that all the inputs inside a form are aligned with each other.
    • I added Design label and/or tagged @Expensify/design so the design team can review the changes.
  • If the PR adds or modifies the UI:
    • I asked an AI agent to review the changes for accessibility issues and addressed its findings.
    • I tested with a screen reader (VoiceOver on macOS) and verified all new/changed elements are reachable with a logical focus order.
    • I verified all new/changed elements have meaningful accessible names and roles.
    • I verified state changes are announced (e.g. checked/unchecked, expanded/collapsed, selected).
  • I added unit tests for any new feature or bug fix in this PR to help automatically prevent regressions in this user flow.
  • If the main branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to the Test steps.

Screenshots/Videos

Android: Native
Android: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari

AI Tests

  • npm run typecheck: passed
  • npm run lint -- <changed files>: passed (lint-changed couldn't resolve the base branch in CI)
  • npm run fmt (oxfmt): no changes outside the edited files
  • npm run react-compiler-compliance-check check src/pages/workspace/fields/WorkspaceFieldsSection.tsx: passed on the first commit (check-changed couldn't resolve the base branch in CI)
  • npm test -- tests/actions/ReportFieldTest.ts tests/unit/ReportUtilsTest.ts: 1567 passed, including tests for failed-create, dismiss, narrow error clearing, and getAvailableReportFields
  • spell-changed: not run on the latest commit (couldn't resolve the base branch in CI)
  • Full npm test, full npm run lint, and Storybook smoke test: not run
  • Web browser test: passed on the first commit (failed row kept with the server's error, dismiss removed it, valid field saved). A re-test after the latest commit was blocked because the test session rendered a blank page

Co-authored-by: Shubham Agrawal <shubham1206agra@users.noreply.github.com>
@MelvinBot
MelvinBot requested a review from a team October 25, 2026 13:41
@melvin-bot melvin-bot Bot added Melvin-Test-Android Melvin-Test-Web Triggers Melvin to run the testing steps of the PR on web labels Oct 25, 2026
@MelvinBot

Copy link
Copy Markdown
Contributor Author

I created this PR from an upstream branch since I don't have push access to your fork.

To take ownership of this branch and be able to push updates, run:

git remote add upstream https://github.com/Expensify/App.git
git fetch upstream claude-showReportFieldFormulaError
git checkout -b claude-showReportFieldFormulaError upstream/claude-showReportFieldFormulaError
git push -u origin claude-showReportFieldFormulaError

Then you can close this PR and open a new one from your fork.

@codecov

codecov Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ Changes either increased or maintained existing code coverage, great job!

Files with missing lines Coverage Δ
...RequestReportView/MoneyRequestViewReportFields.tsx 98.33% <100.00%> (ø)
...rc/components/ReportActionItem/MoneyReportView.tsx 95.38% <100.00%> (ø)
src/hooks/useAdvancedSearchFilters.ts 97.82% <100.00%> (ø)
src/libs/ReportUtils.ts 89.98% <100.00%> (+0.01%) ⬆️
...micReportDetailsPage/ReportDetailsTitleSection.tsx 91.37% <100.00%> (ø)
src/libs/actions/Policy/ReportField.ts 68.85% <92.30%> (+1.79%) ⬆️
.../pages/workspace/fields/FieldsInitialValuePage.tsx 0.00% <0.00%> (ø)
src/selectors/Policy.ts 88.07% <0.00%> (ø)
src/pages/DynamicEditReportFieldPage.tsx 0.00% <0.00%> (ø)
src/pages/workspace/fields/CreateFieldsPage.tsx 0.00% <0.00%> (ø)
... and 1 more
... and 12 files with indirect coverage changes

@MelvinBot

MelvinBot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor Author

🤖 Web test steps verification results: ⚠️ partial

A report field that fails to save because of an invalid formula now stays in the list with the server's error on its row, and dismissing the error removes the failed row; a valid field still saves cleanly. The PR has no Tests section yet, so I used the linked issue's reproduction steps, and the JS console could not be inspected on this web setup.
Valid text field saved with no error

Step Status
Open Workspace settings > Report fields and the page loadsThe Reports tab showed the Report fields section with its toggle and the Add field control after the feature was enabled.
Report fields page loaded
✅
Add a Text report field with the default value {field:DoesNotExist}Created "Invalid Formula Field" as a Text field with Initial value {field:DoesNotExist}. The Type then changed to "Formula" on its own. This is the App's existing brace detection, not this PR.
Initial value set to {field:DoesNotExist}
✅
Save the field: the row stays and shows an errorThe row stayed in the list with a red error and a dismiss (X) control. The error read "Formula field {field:DoesNotExist} not recognized". This is the server's message, not the generic fallback.
Row-level error after save
✅
Dismiss the error on the rowClicking X cleared the error and removed the failed field from the list.
Failed field removed after dismissing error
✅
Add a valid Text field with no default value"Valid Text Field" saved and appeared in the list as Text, with no error.
Valid text field saved with no error
✅
No new JS console errorsNot verified. The web test tool cannot read console output. No error toasts, crashes, or broken layouts appeared, and the App stayed responsive throughout.
⚠️

view run · view recording

@MelvinBot

MelvinBot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor Author

🤖 Android test steps verification results: ⚠️ partial

On Android, a report field that fails to save because of an invalid formula stays in the list with the server's error on its row, and dismissing the error removes the failed row; a valid field still saves cleanly. The PR has no Tests section yet, so I used the linked issue's reproduction steps, and device logs were not captured, so the log check is based on the UI only.
Valid text field saved with no error

Step Status
Open Workspace settings > Report fields and the page loadsTurning on Report fields under Workspace settings > Reports showed the section and the Add field control.
Report fields enabled with Add field button
✅
Add a Text report field with the default value {field:DoesNotExist}Created "Test Field" as a Text field and entered {field:DoesNotExist} as the Initial value. The Type then changed to "Formula" on its own. This is the App's existing formula detection, not this PR. No screenshot was taken for this step.
✅
Save the field: the row stays and shows an errorThe row stayed in the list with a red error and a dismiss (X) control. The error read "Formula field {field:DoesNotExist} not recognized".
Row-level error after save
✅
Dismiss the error on the rowTapping X cleared the error and removed the failed field from the list.
Failed field removed after dismissing error
✅
Add a valid Text field with no default value"Valid Field" saved and appeared in the list as Text, with no error.
Valid text field saved with no error
✅
No new errors in the app logsNot fully verified. Device log capture was off for this run. No error toasts, crashes, or unexpected error states appeared in the UI.
⚠️

view run · view recording

Comment thread src/libs/actions/Policy/ReportField.ts Outdated
// Keep the failed field in the list so its error shows on its own row until the user dismisses it
fieldList: {
[fieldKey]: null,
[fieldKey]: {...optimisticReportFieldDataForPolicy, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD},

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.

@MelvinBot We don't need to update anything in case of failure. Maybe remove this altogether. Also, wrong errorField is added, fix that too.

@MelvinBot MelvinBot Oct 25, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I made both changes in f6b7910.

  • Failure data: createReportField no longer updates the policy's fieldList on failure. The optimistic data already keeps the row with pendingAction: ADD. The failure data still removes the field from each report's fieldList, so a failed field doesn't stay on reports.
  • Error field: The generic error now goes to errorFields.fieldList.<fieldKey>.defaultValue, where the server returns its error (ReportField.ts:112). I made the same fix in updateReportFieldInitialValue, which used the same wrong key. Since nothing writes errorFields.<fieldKey> anymore, I removed the row's fallback to it and stopped clearing it.

Typecheck, lint, and ReportFieldTest/ReportUtilsTest (1567 tests) pass. I couldn't re-test on Web because the test session showed a blank page. The first commit passed on Web.


view run · no recording available

…undant failure fieldList update

The optimistic data already keeps the new field on the policy with pendingAction ADD, so the failure data no longer re-writes it. The generic failure error now goes to errorFields.fieldList.<fieldKey>.defaultValue, where the server returns its errors, so the row reads a single location.

Co-authored-by: Shubham Agrawal <shubham1206agra@users.noreply.github.com>
<OfflineWithFeedback
pendingAction={item.pendingAction}
errors={item.errors}
errorRowStyles={[cardPaddingHorizontal, styles.mb2]}

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.

Suggested change
errorRowStyles={[cardPaddingHorizontal, styles.mb2]}
errorRowStyles={cardPaddingHorizontal}
errorRowTextStyles={styles.mv2}

@MelvinBot Implement this suggestion

@MelvinBot MelvinBot Oct 25, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I applied your suggestion in 73fc3e7. The error row now uses errorRowStyles={cardPaddingHorizontal} and errorRowTextStyles={styles.mv2}. I also changed styles.mb2 to styles.mv2 in the renderItem dependency list (WorkspaceFieldsSection.tsx:179-195).

On Web, the error lines up with the field name and has even spacing above and below. Dismissing it still removes the failed field.

Close-up of the failed field row and its error with the new spacing

Typecheck and the React Compiler check pass. ESLint reports only the MenuItem deprecation, which is already in the seatbelt baseline for this file.


view run · no recording available

Co-authored-by: Shubham Agrawal <shubham1206agra@users.noreply.github.com>
Comment thread src/libs/ReportUtils.ts Outdated
// If the report is unsettled, we want to merge the new fields that get added to the policy with the fields that
// are attached to the report.
const mergedFieldIds = Array.from(new Set([...policyReportFields.map(({fieldID}) => fieldID), ...reportFields.map(({fieldID}) => fieldID)]));
// Skip policy fields pending ADD that aren't on the report yet. Optimistic adds are written to the report too, so this

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.

@MelvinBot Do we really need this condition given that we are clearing that field from reports on failure?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, we still need it. Removing the field from each report's fieldList on failure isn't enough, because getAvailableReportFields also pulls fields from the policy.

Without the filter, that failed field would come back on every unsettled report until the error is dismissed. Before this PR, the failure data removed the field from the policy too, so this didn't come up.

The reportFieldIDs.has(fieldID) part keeps optimistic adds visible: they're written to the report as well, so a successful add in progress still shows. The test at ReportUtilsTest.ts:22765 covers the failed case, and the one at ReportUtilsTest.ts:22782 covers the in-progress case.


view run

@MelvinBot

Copy link
Copy Markdown
Contributor Author

The failing check is unrelated to this PR, so I didn't push a fix.

Analysis: The only failing code check is Jest test (job 3). One test failed: WorkspaceCategories › should delete categories through UI interactions, with Found multiple elements with accessibility label: Select all at tests/ui/WorkspaceCategoriesTest.tsx:169. It looks flaky.

Evidence:

  • This PR only changes report field code (ReportUtils.ts, Policy/ReportField.ts, WorkspaceFieldsSection.tsx) and their tests. The categories page doesn't render WorkspaceFieldsSection.
  • The same test passed on the previous commit (f6b79108). The latest commit only changes the error row spacing in WorkspaceFieldsSection.tsx.
  • The other 4,589 tests passed.

Next step: Rerun the failed Jest job (run). I couldn't start the rerun from here.

Check independent approval and the checklist checks also fail. They clear after review and approval.

@MelvinBot

Copy link
Copy Markdown
Contributor Author

The failing test (job 3) check is unrelated to this PR. It's a flaky test, so I didn't push a fix. Please rerun the failed job.

Failing test: WorkspaceCategories › should delete categories through UI interactions at tests/ui/WorkspaceCategoriesTest.tsx:169. It fails with Found multiple elements with accessibility label: Select all.

Why it's unrelated
  • This PR changes report-field code: ReportUtils.ts, ReportField.ts, WorkspaceFieldsSection.tsx, and their tests. None of them render the Categories page.
  • The latest commit (73fc3e74) only changes the error row styles in WorkspaceFieldsSection.tsx.
  • All Jest jobs passed on the previous commit (f6b79108).
  • The same test failed with the same error today on two unrelated branches: ishpaul/684546-talk-to-human-ticket and fix/approve-only-deploy-blockers.

The other failing checks (Check independent approval and PR Reviewer Checklist) clear after review and approval.


view run

* Returns the errorFields update that sets a report field's generic failure error at errorFields.fieldList.<fieldKey>.defaultValue, where the server also returns its errors.
*/
function getReportFieldFailureErrorFields(fieldKey: string) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- ErrorFields doesn't model the nested fieldList.<fieldKey>.defaultValue shape the server uses, same as the report title error

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.

@MelvinBot Is there any way to fix this? If not, point me to similar functions.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

No. The as unknown as ErrorFields cast can't be removed with a local change. Policy.errorFields is typed as ErrorFields, which is one level too shallow for fieldList.<fieldKey>.defaultValue.<microtime>. The App already writes the report title error the same way, with the same cast.

Similar functions:

Why a type change is out of scope
  • ErrorFields is Record<string, Errors>, and Errors is Record<string, string | null> (OnyxCommon.ts:27-30). So errorFields.fieldList.<fieldKey> has to be a string, not {defaultValue: {...}}.
  • Adding & {fieldList?: Record<string, ErrorFields>} doesn't work. The intersection with the string index collapses the values to null.
  • A separate PolicyErrorFields type with a union index would change what every reader of policy.errorFields gets back. There are about 320 readers in src, including getLatestErrorField(policy, ...). That belongs in its own PR.

The cast in the title code has no disable comment, so I assume it's covered by the lint baseline. The new helper uses an eslint-disable with a reason instead, so the cast stays in one documented place.


view run

@shubham1206agra

Copy link
Copy Markdown
Contributor

@MelvinBot Ready the PR for review

@MelvinBot

Copy link
Copy Markdown
Contributor Author

The failing test (job 3) check is unrelated to this PR, so I didn't push a fix. Please re-run the failed job. It should pass.

The other two failures, checklist and Check independent approval, clear once a reviewer completes the checklist and approves.

Analysis
  • What failed: WorkspaceCategories › should delete categories through UI interactions at tests/ui/WorkspaceCategoriesTest.tsx:169, with Found multiple elements with accessibility label: Select all. The other 4,589 tests in the shard passed.
  • Why it's unrelated: This PR changes only report field files: ReportUtils.ts, ReportField.ts, WorkspaceFieldsSection.tsx, and their tests. The categories page doesn't render WorkspaceFieldsSection. The latest commit (73fc3e74) only swaps an error row style in WorkspaceFieldsSection.tsx:179-180.
  • Evidence it's flaky: The same test passed in the full Jest run on the previous commit (f6b79108). The branch is up to date with main, so the test code didn't change between the two runs.

@MelvinBot
MelvinBot marked this pull request as ready for review October 25, 2026 15:23
@MelvinBot
MelvinBot requested a review from a team as a code owner October 25, 2026 15:23
@MelvinBot

Copy link
Copy Markdown
Contributor Author

🤖 I marked this PR as ready for review.

The Tests, Offline tests, and QA Steps sections still have TODO placeholders. shubham1206agra, please fill them in. You can base them on the Web test results above.


view run

@melvin-bot
melvin-bot Bot requested review from flaviadefaria and shubham1206agra and removed request for a team and flaviadefaria October 25, 2026 15:23
@melvin-bot

melvin-bot Bot commented Oct 25, 2026

Copy link
Copy Markdown

@shubham1206agra Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button]

@melvin-bot
melvin-bot Bot removed the request for review from a team October 25, 2026 15:23
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-25T15:26:45.047022Z 73fc3e7 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@MelvinBot

Copy link
Copy Markdown
Contributor Author

The failing Jest check is unrelated to this PR. It looks flaky, so I didn't push a fix. Please rerun the failed job.

Analysis: test (job 3) failed in tests/ui/WorkspaceCategoriesTest.tsx:169 with Found multiple elements with accessibility label: Select all. That test covers the Categories page. It doesn't import any file this PR changes.

Evidence:

  • The same test passed on the previous commit f6b79108.
  • The only change since then is a style swap in WorkspaceFieldsSection.tsx (errorRowStyles → errorRowTextStyles={styles.mv2}), which the Categories page doesn't render.

The other two failures, PR Reviewer Checklist / checklist and Check independent approval, clear once a reviewer completes the checklist and approves.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 73fc3e7497

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/libs/ReportUtils.ts Outdated
// Skip policy fields pending ADD that aren't on the report yet. Optimistic adds are written to the report too, so this
// keeps fields that failed to be created (kept on the policy until their error is dismissed) off reports.
const reportFieldIDs = new Set(reportFields.map(({fieldID}) => fieldID));
const availablePolicyReportFields = policyReportFields.filter(({fieldID, pendingAction}) => pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD || reportFieldIDs.has(fieldID));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve pending fields on reports created offline

When a field is created while offline and then a new report is created before that request is sent, the new report was not present in policyReportIDs and therefore does not contain the optimistic field in its own fieldList. This filter consequently hides the policy field solely because it is pending ADD, so the newly created report omits a valid optimistic field until reconnection and API success. Failed additions need to be distinguished by their error state rather than treating every pending addition absent from a report as failed.

Useful? React with 👍 / 👎.

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.

@MelvinBot Address this

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 8928621. The filter now hides a policy field only when it's pending ADD and also has an error, so it skips only failed adds (ReportUtils.ts:5661-5663). A field added offline still shows on reports created before the request is sent.

  • getAvailableReportFields and getReportFieldMaps take an optional policyErrorFields. The filter checks errorFields.fieldList.<fieldKey>, the same key the row error reads.
  • All 5 callers in src now pass policy.errorFields.
  • I added a test for the offline case (ReportUtilsTest.ts:22773). The failed-add test now passes an error.

Typecheck, ESLint on the changed files, the React Compiler check, and ReportUtilsTest/ReportFieldTest (1568 tests) pass. I didn't re-test on Web or run the spell check.


view run

…adds

Co-authored-by: Shubham Agrawal <shubham1206agra@users.noreply.github.com>
@MelvinBot
MelvinBot requested a review from a team as a code owner October 25, 2026 15:34
@melvin-bot
melvin-bot Bot requested review from flodnv and removed request for a team October 25, 2026 15:35
@melvin-bot

melvin-bot Bot commented Oct 25, 2026

Copy link
Copy Markdown

@flodnv Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button]

@shubham1206agra

Copy link
Copy Markdown
Contributor

Reviewer Checklist

  • I have verified the author checklist is complete (all boxes are checked off).
  • I verified the correct issue is linked in the ### Fixed Issues section above
  • I verified testing steps are clear and they cover the changes made in this PR
    • I verified the steps for local testing are in the Tests section
    • I verified the steps for Staging and/or Production testing are in the QA steps section
    • I verified the steps cover any possible failure scenarios (i.e. verify an input displays the correct error message if the entered data is not correct)
    • I turned off my network connection and tested it while offline to ensure it matches the expected behavior (i.e. verify the default avatar icon is displayed if app is offline)
  • I checked that screenshots or videos are included for tests on all platforms
  • I included screenshots or videos for tests on all platforms
  • I verified that the composer does not automatically focus or open the keyboard on mobile unless explicitly intended. This includes checking that returning the app from the background does not unexpectedly open the keyboard.
  • I verified tests pass on all platforms & I tested again on:
    • Android: HybridApp
    • Android: mWeb Chrome
    • iOS: HybridApp
    • iOS: mWeb Safari
    • MacOS: Chrome / Safari
  • If there are any errors in the console that are unrelated to this PR, I either fixed them (preferred) or linked to where I reported them in Slack
  • I verified proper code patterns were followed (see Reviewing the code)
    • I verified that any callback methods that were added or modified are named for what the method does and never what callback they handle (i.e. toggleReport and not onIconClick).
    • I verified that comments were added to code that is not self explanatory
    • I verified that any new or modified comments were clear, correct English, and explained "why" the code was doing something instead of only explaining "what" the code was doing.
    • I verified any copy / text that was added to the app is grammatically correct in English. It adheres to proper capitalization guidelines (note: only the first word of header/labels should be capitalized), and is either coming verbatim from figma or has been approved by marketing (in order to get marketing approval, ask the Bug Zero team member to add the Waiting for copy label to the issue)
  • If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers
  • I verified that this PR follows the guidelines as stated in the Review Guidelines
  • I verified other components that can be impacted by these changes have been tested, and I retested again (i.e. if the PR modifies a shared library or component like Avatar, I verified the components using Avatar have been tested & I retested again)
  • If a new component is created I verified that:
    • A similar component doesn't exist in the codebase
    • All props are defined accurately and each prop has a /** comment above it */
    • The file is named correctly
    • The component has a clear name that is non-ambiguous and the purpose of the component can be inferred from the name alone
    • The only data being stored in the state is data necessary for rendering and nothing else
    • For Class Components, any internal methods passed to components event handlers are bound to this properly so there are no scoping issues (i.e. for onClick={this.submit} the method this.submit should be bound to this in the constructor)
    • Any internal methods bound to this are necessary to be bound (i.e. avoid this.submit = this.submit.bind(this); if this.submit is never passed to a component event handler like onClick)
    • All JSX used for rendering exists in the render method
    • The component has the minimum amount of code necessary for its purpose, and it is broken down into smaller components in order to separate concerns and functions
  • If any new file was added I verified that:
    • The file has a description of what it does and/or why is needed at the top of the file if the code is not self explanatory
  • If a new CSS style is added I verified that:
    • A similar style doesn't already exist
    • The style can't be created with an existing StyleUtils function (i.e. StyleUtils.getBackgroundAndBorderStyle(theme.componentBG)
  • If the PR modifies code that runs when editing or sending messages, I tested and verified there is no unexpected behavior for all supported markdown - URLs, single line code, code blocks, quotes, headings, bold, strikethrough, and italic.
  • If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like Avatar is modified, I verified that Avatar is working as expected in all cases)
  • If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected.
  • If the PR modifies a component or page that can be accessed by a direct deeplink, I verified that the code functions as expected when the deeplink is used - from a logged in and logged out account.
  • If the PR modifies the UI (e.g. new buttons, new UI components, changing the padding/spacing/sizing, moving components, etc) or modifies the form input styles:
    • I verified that all the inputs inside a form are aligned with each other.
    • I added Design label and/or tagged @Expensify/design so the design team can review the changes.
  • For any bug fix or new feature in this PR, I verified that sufficient unit tests are included to prevent regressions in this flow.
  • If the main branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to the Test steps.
  • I have checked off every checkbox in the PR reviewer checklist, including those that don't apply to this PR.

Screenshots/Videos

Screen.Recording.2026-10-25.at.8.46.57.PM.mov

@flodnv

flodnv commented Oct 27, 2026

Copy link
Copy Markdown
Contributor

Lots of conflicts @shubham1206agra

@shubham1206agra

Copy link
Copy Markdown
Contributor

@MelvinBot Fix conflicts

@flodnv flodnv 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.

1. Medium: a failed field's row still opens its settings page.
The failed field stays in policy.fieldList with pendingAction: ADD, so navigateToFieldSettings opens its settings page. There, you can edit the initial value or delete the field. Both send API calls for a field the server doesn't have, so they fail again. Separately, isReportFieldNameExisting blocks creating a new field with the same name until you dismiss the error. That is the obvious way to retry with a fixed formula. I'd stop navigation for rows that are pending ADD and have an error, or at least add a QA step for this flow.

2. Low: errors stored under the old key can now stay forever.
Before this PR, the generic error went to errorFields.expensify_<id>, and the next create or update wiped it with errorFields: null. Now the optimistic data clears only errorFields.fieldList.<key>, and nothing clears the old key. hasPolicyErrorFields (src/libs/PolicyUtils/errors.ts:65) treats any non-empty errorFields entry as a workspace error. So users who already have one of these old errors keep a red dot they can't dismiss. A fix: also set errorFields[fieldKey]: null in the optimistic data.

3. Low: other code still treats failed fields as real.
These read policy.fieldList directly and don't skip failed fields:

  • The Search report-field filter (src/components/Search/FilterComponents/ReportField/index.tsx:210 and :283).
  • hasCircularReferences (src/libs/Formula.ts:224).
  • useAdvancedSearchFilters.ts:247.

The impact is minor until you dismiss the error.

@shubham1206agra

Copy link
Copy Markdown
Contributor

@MelvinBot Address points 1 and 3 from #104938 (review)

…dFormulaError

Co-authored-by: Shubham Agrawal <shubham1206agra@users.noreply.github.com>

# Conflicts:
#	src/components/MoneyRequestReportView/MoneyRequestViewReportFields.tsx
#	src/components/ReportActionItem/MoneyReportView.tsx
#	src/pages/workspace/fields/WorkspaceFieldsSection.tsx
@MelvinBot

Copy link
Copy Markdown
Contributor Author

I merged main into this branch and fixed the conflicts in 8d3ded34. The PR can merge now.

Since this branch was created, main removed manual useMemo/useCallback from these files because React Compiler now memoizes them. I kept main's version and added this PR's changes back:

npm run typecheck passes. I couldn't run ESLint or Jest here because of sandbox setup problems unrelated to this PR, so CI will check those.

@MelvinBot

Copy link
Copy Markdown
Contributor Author

⚠️ MelvinBot CI Fix Loop Detected

MelvinBot has made 5 consecutive commits trying to fix CI failures. Automatic CI fix dispatches are now paused for this PR.

Next steps: A human should review the recent commits and resolve the conflicting CI errors manually.

…r row

Their row no longer opens the settings page, and the name check, the circular reference check, and the Search report field filters skip them.

Co-authored-by: Shubham Agrawal <shubham1206agra@users.noreply.github.com>
@MelvinBot

Copy link
Copy Markdown
Contributor Author

I addressed points 1 and 3 from flodnv's review in 93fa674f. Point 2 is unchanged.

The new isFailedReportFieldAdd and getReportFieldsWithoutFailedAdds helpers find a failed field: one with pendingAction: ADD and an error. A field added offline without an error doesn't count as failed. getAvailableReportFields now uses the same helper.

1. Failed rows:

  • A failed row no longer opens its settings page or shows the right arrow (WorkspaceFieldsSection.tsx:160-181). The user can still dismiss the error.
  • The duplicate-name check skips failed fields, so the user can retry with the same name right away (CreateFieldsPage.tsx:61). The field ID comes from the name, so the retry replaces the failed field and clears its error.

3. Other readers of policy.fieldList now skip failed fields:

I added unit tests for getReportFieldsWithoutFailedAdds. Typecheck, ESLint, oxfmt, and the React Compiler check pass. These test suites also pass: ReportUtilsTest, ReportFieldTest, FormulaTest, useAdvancedSearchFilters, useFilterFormValues, MoneyRequestViewReportFieldsTest, and WorkspaceSelectorTest.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Melvin-Test-Android Melvin-Test-Web Triggers Melvin to run the testing steps of the PR on web

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants