Skip to content

[Due for payment 2026-10-19] Spend - Amount is out of view when merging reports with long name #100493

Open

Description

@applause-bot

If you haven’t already, check out our contributing guidelines for onboarding. To join our Slack channel, fill out this form.


Version Number: 9.4.73-0
Reproducible in staging?: Yes
Reproducible in production?: N/A - new feature, doesn't exist in prod
If this was caught during regression testing, add the test name, ID and link from BrowserStack: #95658
Email or phone of affected tester (no customers): [email protected]
Issue reported by: Applause Internal Team
Bug source: Exploratory - Significant User Experience Deterioration
Device used: Mac 26.5 / Chrome
App Component: Search

Action Performed:

  1. Go to staging.new.expensify.com
  2. Go to workspace chat.
  3. Create two reports with an expense each. One of the expenses must have long report title (eg, sjdoijsdnodjsoinsjdiodnsjiodsjoijsjdoijsdnodjsoinsjdiodnsjiodsjoijsjdoijsdnodjsoinsjdiodnsjiodsjoijsjdoijsdnodjsoinsjdiodnsjiodsjoijsjdoijsdnodjsoinsjdiodnsjiodsjoijsjdoijsdnodjsoinsjdiodnsjiodsjoijsjdoijsdnodjsoinsjdiodnsjiodsjoij).
  4. Go to Spend > Reports.
  5. Select both reports via checkbox.
  6. Click dropdown menu > Merge reports.

Expected Result:

Amount will not be out of view when merging reports.

Actual Result:

Amount is out of view when merging reports.

Workaround:

Unknown

Platforms:

  • Android: App
  • Android: mWeb Chrome
  • iOS: App
  • iOS: mWeb Safari
  • iOS: mWeb Chrome
  • Windows: Chrome
  • MacOS: Chrome Safari

Screenshots/Videos

Bug7253296_1788779517987.1.mp4

View all open jobs on GitHub

Applause Internal Information
Exported by: Julia Ponikarchuk
Bug ID: 7253296

Issue OwnerCurrent Issue Owner: @mallenexpensify

Activity

  1. added
    DeployBlockerCashThis issue or pull request should block deployment
    BugSomething is broken. Auto assigns a BugZero manager.
    on Sep 7, 2026
  2. applause-bot commented on Sep 7, 2026

    @applause-bot
    Author

    While Applause doesn't embed attachments for this bug, here are the links for quick view:
    https://platform.applause.com/services/links/v1/external/81eb4bd8ed3f095f426cc843f7ca2ca5e0670a997f3bec026f7441c3f2e5947d

  3. melvin-bot commented on Sep 7, 2026

    @melvin-bot

    You have been assigned to this deploy blocker because you recently merged this PR: #95658

  4. github-actions commented on Sep 7, 2026

    @github-actions
    Contributor

    👋 Friendly reminder that deploy blockers are time-sensitive ⏱ issues! Check out the open `StagingDeployCash` deploy checklist to see the list of PRs included in this release, then work quickly to do one of the following:

    1. Identify the pull request that introduced this issue and revert it.
    2. Find someone who can quickly fix the issue.
    3. Fix the issue yourself.
  5. melvin-bot commented on Sep 7, 2026

    @melvin-bot

    @Gonals @situchan you have been assigned to this deploy blocker because you reviewed the offending PR: #95658

  6. melvin-bot commented on Sep 7, 2026

    @melvin-bot

    @dmkt9 you have been assigned to this deploy blocker because you authored the offending PR: #95658

  7. melvin-bot commented on Sep 7, 2026

    @melvin-bot

    💬 A slack conversation has been started in #expensify-open-source

  8. MelvinBot commented on Sep 7, 2026

    @MelvinBot
    Contributor

    🔍 Investigation Summary

    Classification: Frontend bug
    Causing PR: #95658 - "feat: implement Merge Reports RHP and action menu" by @dmkt9 (High confidence)
    Related Issues: #94873, #94874 (the issues fixed by the causing PR)

    Recommendation: ROLL FORWARD

    The layout flaw is a 3-line style problem in one shared row component, while a revert would back out an entire feature (28 files, new route/screen, navigation config, mergeReports wiring, 10 language files). Fixing forward is far lower risk than reverting.

    Assigned: @dmkt9 (PR author), @Gonals and @situchan (approving reviewers) from #95658 — already assigned by Melvin.
    Labels: No changes. DeployBlockerCash stays (App-side fix required). DeployBlocker was not present, so nothing to remove.

    Root cause and suggested fix

    The name/amount row lives in ExpenseReportListItemRowNarrow.tsx#L39-L47:

    <View style={[styles.flexRow, styles.gap2]}>
        <Text numberOfLines={2} style={[styles.lh20, styles.flex1]}>
            {item.reportName ?? ''}
        </Text>
        <Text style={[styles.lh20, styles.flexShrink0, styles.textAlignRight]}>{amountText}</Text>
    </View>

    The report-name Text is itself the flex item. On web, react-native-web gives View a min-width: 0 reset but not Text, so the name keeps min-width: auto, whose used value for a flex item is its content-based minimum size — for a single unbreakable 300-character word that is the full width of the word. flex: 1 (flex-basis: 0%) cannot shrink it below that floor, and min-width beats the max-width: 100% that numberOfLines > 1 adds, so the row overflows and pushes the flexShrink0 amount out of the visible area. The default overflow-wrap: break-word does not help here: per spec it does not reduce min-content size (only word-break/overflow-wrap: anywhere do). Note that numberOfLines > 1 in RNW 0.21 applies overflow: clip, which is not a scroll container, so it does not zero out the automatic minimum size the way overflow: hidden would.

    Minimal fix — move flex1 onto a View wrapper (a View gets min-width: 0, and Yoga on native is unaffected), matching the existing styles.optionItemAvatarNameWrapper ({minWidth: 0, flex: 1}) idiom used for the same problem in option rows:

    <View style={[styles.flexRow, styles.gap2]}>
        <View style={styles.flex1}>
            <Text numberOfLines={2} style={styles.lh20}>
                {item.reportName ?? ''}
            </Text>
        </View>
        <Text style={[styles.lh20, styles.flexShrink0, styles.textAlignRight]}>{amountText}</Text>
    </View>

    Adding styles.breakWord to the name Text also works on its own (it lowers min-content to one character), but the wrapper is the pattern already used elsewhere in the app. The date/expense-count row directly below (L48-L51) has the identical shape and should get the same treatment for consistency, even though those strings are short today.

    📋 Detailed Analysis

    Evidence

    • #95658 (merged 2026-09-04, item 47 in the current checklist) is the only PR in this release that builds the Merge reports flow: it adds the route/screen SearchReportsMergeReports.tsx, the MERGE_REPORTS_SEARCH_RHP screen, the Merge reports bulk action in useSearchBulkActions, and the report-selection row SearchMergeReportsListItem.tsx. The reproduction steps go through exactly that flow, and Applause confirms it does not exist in production, which is why this is staging-only.
    • No other PR in the checklist touches the merge-reports selection list. Nothing else in the release explains a name/amount row that only exists in the new RHP.
    • The new row component SearchMergeReportsListItem.tsx#L58-L86 reuses ExpenseReportListItemRowNarrow unconditionally (not behind isLargeScreenWidth, unlike ExpenseReportListItem.tsx#L509-L517), and squeezes it further by putting a RadioButton next to it in the same row. That is what surfaces the flaw on desktop Chrome/Safari.
    • Honest caveat on scope: the name/amount markup itself is not new. The same block already exists on the production branch of the shared file (the only delta from feat: implement Merge Reports RHP and action menu #95658 is adding styles.cursorPointer), so this is a latent flaw in shared narrow-row code that feat: implement Merge Reports RHP and action menu #95658 newly made reachable in the desktop RHP. It is still an App-side fix, so DeployBlockerCash stays, and feat: implement Merge Reports RHP and action menu #95658 remains the PR that makes it block this deploy.

    Verification

    • Affected file: src/components/Search/SearchList/ListItem/ExpenseReportListItemRow/ExpenseReportListItemRowNarrow.tsx (name + amount row), reached via src/components/Search/SearchList/ListItem/SearchMergeReportsListItem.tsx → src/pages/Search/SearchReportsMergeReports.tsx.
    • gh pr view 95658 --json files confirms the PR adds both SearchMergeReportsListItem.tsx and SearchReportsMergeReports.tsx and modifies ExpenseReportListItemRowNarrow.tsx.
    • Container chain checked end to end: pressable (selectionListPressableItemWrapper, flexDirection: row) → BaseListItem wrapper (flex1, flexColumn, alignItemsStretch) → merge row (flexRow, flex1, gap3) → View flex1 → narrow row. Every ancestor is a View, so each one gets RNW's min-width: 0 and shrinks correctly; the name Text is the only node in the chain with a min-content floor, which isolates the overflow to that element.
    • Platform match: native Yoga has no min-width: auto content floor, which is consistent with the PR's Android/iOS videos looking fine and the bug being reported only on Chrome/Safari.
    • Not verified in a browser (no browser available in this environment); the conclusion is from the markup plus [email protected] Text styles (textMultiLine: display: -webkit-box, maxWidth: 100%, overflow: clip) and CSS flexbox automatic-minimum-size behavior.

    💡 Suggested AI code review rule

    This bug looks like a recurring, mechanically detectable pattern, so it may be worth a coding-standards rule so the AI reviewer catches the next one. Proposed for Expensify/App:

    • Rule: UI-4 Constrain flexible text with a minWidth: 0 wrapper, not flex1 on Text
    • Condition: flag a <Text> that renders user-generated content, carries styles.flex1 (or flexShrink) directly, and is a flex-row sibling of content that must stay visible (e.g. a styles.flexShrink0 amount). Wrap the text in a View that owns the flex1 (see styles.optionItemAvatarNameWrapper), or add styles.breakWord.
    • Why: on web, react-native-web resets min-width: 0 on View but not on Text, so a Text flex item keeps a min-content floor. A single long unbreakable string then refuses to shrink and pushes its siblings out of view — numberOfLines does not save it, because min-width overrides the max-width: 100% it adds. Incident: [Due for payment 2026-10-19] Spend - Amount is out of view when merging reports with long name #100493.
    • Search pattern: files containing styles.flexShrink0 that also contain <Text with styles.flex1 in its style array — grep -rln "styles.flexShrink0" src --include=*.tsx | xargs grep -n "styles.flex1" (~4 files today, plus ~25 <Text ... styles.flex1> sites overall).
    • Offending code (❌):
      <View style={[styles.flexRow, styles.gap2]}>
      <Text
      numberOfLines={2}
      style={[styles.lh20, styles.flex1]}
      >
      {item.reportName ?? ''}
      </Text>
      <Text style={[styles.lh20, styles.flexShrink0, styles.textAlignRight]}>{amountText}</Text>
      </View>
    • Fix (✅): the View-wrapper version shown above, mirroring

      App/src/styles/index.ts

      Lines 2123 to 2126 in f29363e

      optionItemAvatarNameWrapper: {
      minWidth: 0,
      flex: 1,
      },

    The full rule file, with the ❌/✅ code inline in Expensify/App's coding-standards format, would go in Expensify/App itself (.claude/skills/coding-standards/rules/ui-4-*.md + a UI-4 index entry). If it's worth adding, a maintainer can open it there as a draft PR.

  9. 17 remaining items

  10. melvin-bot commented on Oct 13, 2026

    @melvin-bot

    @situchan / @dmkt9

    The solution for this issue has been 🚀 deployed to production 🚀 in version 9.5.7-3 and is now subject to a 7-day regression period 📆. Here is the list of pull requests that resolve this issue:

    The following checklist (instructions) will need to be completed before the issue can be closed. Please copy/paste the Contributor+ Checklist from here into a new comment on this GH and complete it. If you have the K2 extension, you can simply click: [this button]. If no checklist is needed for this issue, you can click: [no checklist button]

  11. Gonals commented on Oct 15, 2026

    @Gonals
    Contributor

    Should be done. Closing

  12. situchan commented on Oct 19, 2026

    @situchan
    Contributor

    I believe we're eligible for payment since this bug existed in production and we fixed this.

    ⚠️ Looks like this issue was linked to a Deploy Blocker here

    This was production bug, not caused by our PR

  13. added
    Awaiting PaymentAuto-added when associated PR is deployed to production
    and removed
    Skip PaymentSkips all the payment process steps for an issue. Use it for fixed-price projects.
    on Oct 19, 2026
  14. changed the title [-]Spend - Amount is out of view when merging reports with long name[/-] [+][Due for payment 2026-10-19] Spend - Amount is out of view when merging reports with long name[/+] on Oct 19, 2026
  15. melvin-bot commented on Oct 19, 2026

    @melvin-bot

    Triggered auto assignment to @mallenexpensify (Awaiting Payment)

  16. melvin-bot commented on Oct 19, 2026

    @melvin-bot

    Payment Summary

    Resolving PRs:

    BugZero Checklist (@mallenexpensify)

    • I have confirmed assignees, roles, and Upwork contracts look correct
    • I have paid out Upwork contracts / manual NewDot requests
    • [BugZero Assignee] I have created a GH issue for creating/updating the regression test once above steps have been agreed upon
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Awaiting PaymentAuto-added when associated PR is deployed to productionBugSomething is broken. Auto assigns a BugZero manager.DailyKSv2Engineering

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions