Repository navigation
Offer export templates when a group row is selected on a grouped search - #100520
Conversation
Co-authored-by: Eugene Voloshchak <eVoloshchak@users.noreply.github.com>
|
No code fix is needed — nothing is actually broken. The only failing check is Every other check on the head commit ( Why it looked worse earlierWhen the request came in, |
|
🤖 Web test steps verification results: The core fix works on Web: with only the group row ticked on a grouped Accounting search, the Export submenu now lists a template ("All Data - expense level") alongside "Current view" instead of only "Current view", "Basic export" stays hidden, and picking the template started an export scoped to the selected group's 2 expenses ($65.00). Steps 8 and 9 could not be completed — dismissing the "Preparing download…" modal via its "Send me the file when it's ready" button navigated the browser off-app to an unreachable The collapsed-group case (step 8) still needs a human pass — that is the view run · no recording available |
|
@MelvinBot, pull the latest main |
…plates Co-authored-by: Eugene Voloshchak <eVoloshchak@users.noreply.github.com>
|
@MelvinBot, isn't this redundant after #98779 and #99217 was implemented? |
|
🤖 Merged the latest Merge commit: Worth knowing: both files this PR touches moved a lot on Verification after the mergeRun locally on the merged branch:
On CI, every check on the merge commit is green except I could not re-verify in the browser this run — the web test environment failed to come up, so no NewDot session was available. The earlier Web and Android test runs on this PR still stand, and the |
|
No fix to push — nothing is broken. After the merge of That's a human gate, not a code failure — the PR currently has zero reviews, and the workflow requires an approval from someone who isn't an author or co-author. It goes green once an independent reviewer approves. Full check status on 5f498e4Passing: Skipped (not applicable): Failing: When the request came in, several jobs were still |
|
🤖 No — they don't overlap. Always open the Export submenu on Search, even with a single export option changed how many clicks it takes to reach the export option list. This PR changes what is in that list. After #99217, a group selection still reaches a one-item menu containing only "Current view". The The clearest evidence is #99217's own test, still passing on Why the two are orthogonal, and the one place they do touchWhat #99217 changed (diff): it deleted the single-option collapse and replaced it with What this PR changes: it removes the guard that stops the template options from being built in the first place. A group selection on a grouped search currently fails both branches — Nothing else surfaces the templates. The suppression was always cosmetic. Where the two PRs do touch: this PR edits two tests #99217 added. It does not delete their behaviour — it re-fixtures them onto a deleted-selection case ( A useful contrast that isolates the cause: I could not verify this in a browser — the web test environment failed to start this run. The conclusion rests on the code and on the checked-in tests, which assert the hook's output directly. The earlier Web and Android test passes on this PR still stand. |
Reviewer Checklist
Screenshots/VideosiOS: HybridAppScreen.Recording.2026-09-22.at.20.38.21.movMacOS: Chrome / SafariScreen.Recording.2026-10-12.at.14.19.28.mov |
|
@MelvinBot, please fill out the Tests sections with the following tests I've performed:
|
eVoloshchak
left a comment
There was a problem hiding this comment.
@MelvinBot, makr this as ready for review
|
We did not find an internal engineer to review this PR, trying to assign a random engineer to #100074 as well as to this PR... Please reach out for help on Slack if no one gets assigned! |
|
🤖 Filled out the Tests section with the steps you performed:
This replaced the Two sections are still open and need you, since I shouldn't fill them in on your behalf:
I couldn't verify the steps in a browser this run — the web test environment failed to come up, so no NewDot session was available. The Web and Android runs recorded earlier in this PR still stand. |
|
@eVoloshchak 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] |
|
🤖 Done — this PR is out of draft and marked ready for review. Reviewers have been auto-requested. One thing to fix before it can merge: the QA Steps section still has the The The PR Author Checklist is also still unchecked; that is yours to complete. I could not verify the change in the browser this run — the web test environment failed to come up, so no NewDot session was available. The earlier Web and Android test passes on this PR still stand. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5f498e4bba
ℹ️ 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".
|
|
||
| if (!allSelectedAreDeleted && !includesGroupExport) { | ||
| // A group selection is exported through a query filter (see `addSelectedGroupsFilter`) rather than a list of IDs, so the templates work for it just like they do for an individual selection. | ||
| if (!allSelectedAreDeleted) { |
There was a problem hiding this comment.
Route expanded group template exports through the group query
When an expanded group row is selected, its entries have transaction keys such as tx1 and carry isSelectedViaGroup, as exercised by the new test, but beginExportWithTemplate recognizes a group export only when a selected key starts with group_. Exposing templates here therefore sends {} as jsonQuery and only the currently loaded transaction IDs; if limit: leaves some group children unloaded, the resulting accounting export silently omits them. Use the same isGroupSelection detection and group-query filtering already used by handleCSVExport before making these templates available.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
🤖 Applied in 88dacc9. The feedback was right.
- Fix:
beginExportWithTemplatenow usesisGroupSelection, the same check ashandleCSVExport(src/hooks/useSearchBulkActions.ts:964). An expanded group now exports through the group query, so children thatlimit:left unloaded are included. - Related gap: A template export sends either the group query or an ID list, never both. So if you select a group and also pick single expenses from elsewhere, the menu now shows only "Current view" (
:2223-2227). This stops one side of the selection from being dropped silently.
Tests
I added two tests (useSearchBulkActionsExportTest.ts:1261):
- One test checks that an expanded group with a template picked sends empty ID lists plus the grouped query. It fails with the old
group_-prefix check, which received["tx1"]. - One test checks that a mixed group-plus-single selection offers only "Current view".
Checks I ran:
useSearchBulkActionsExportTest.ts: 41 passed.tests/unit/hooks/useSearchBulkActions+tests/unit/Search: 65 suites and 1902 tests passed.typecheck,linton the changed files, andspell-changed: all passed.- React Compiler: 10 babel / 9 oxc errors, the same as before this commit.
I could not run oxfmt in this environment, so CI's Oxfmt check will confirm formatting. I did not run a browser test for this change.
|
I removed |
|
@MelvinBot, is the updated backend request supposed to filter out some expenses? I.e. if the app says "6 selected" during the export and there are 6 expenses visible, the exported CSV is always supposed to have 6 rows? Or is there some filtering/consolidation happening on the BE? |
|
🤖 For an expense-level template, yes: "6 selected" with 6 visible expenses should export 6 rows. The App side of this PR applies no extra filtering. The row count can legitimately differ in two cases:
If you saw a mismatch with "All Data - Expense Level Export" on a non-reconciliation view, treat it as a bug. Please share the template, view, and selected/exported counts. What the request sends for a group selection
I couldn't confirm the backend side from here. That includes how it combines |
|
Ah, turns out it filters out transactions with "Unreported" status when exporting; that's why there's a discrepancy. |
@trjExpensify is this expected? |
|
No. For example, "Card accruals" includes |
|
@dukenv0307 we probably need to fix that then ^ |
|
@MelvinBot investigate #100520 (comment), #100520 (comment). Is it BE bug? |
|
🤖 Yes, this looks like a backend bug. The App asks for unreported expenses, but the template export leaves them out. For a Card accruals group, the App sends
This PR didn't cause it. Notes
|
|
@MelvinBot create an E/E issue then assign me |
|
🤖 I created an internal Expensify/Expensify issue for the backend bug and assigned you. I'm not linking it here because this repo is public. You'll find it in your assigned issues. The issue covers template exports that leave out unreported expenses, such as unreported card expenses in Card accruals. It includes the request the App sends and the steps to reproduce. |
|
@MelvinBot I think it shouldn't block this PR since it's a pre-existing issue, right? |
|
🤖 Yes, I agree it shouldn't block this PR. The backend drops unreported expenses for the same request on
|
|
@trjExpensify I think we can merge it and handle the issue above separately. Is it ok cc @JS00001 |
|
Yeah we can handle it separately, that sounds good |
|
🚧 JS00001 has triggered a test Expensify/App build. You can view the workflow run here. |
|
✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release. |
|
🧪🧪 Use the links below to test this adhoc build on Android, iOS, and Web. Happy testing! 🧪🧪
|
|
🚀 Deployed to staging by https://github.com/JS00001 in version: 9.5.10-0 🚀
|
|
No help site update needed. This PR makes the existing export templates available when you select a group row, which is what users would already expect. No article says that only Current view is offered for grouped selections, and the Expensify Card reconciliation article already tells users to "Choose an export template," which is now more accurate. |
|
🚀 Deployed to staging by https://github.com/JS00001 in version: 9.5.12-0 🚀
|
|
No help site update needed. This PR makes the existing export templates available when you select a group row, which is what users would already expect. No article says that only Current view is offered for grouped selections, and the Expensify Card reconciliation article already tells users to "Choose an export template," which is now more accurate. |
|
🚀 Deployed to production by https://github.com/cristipaval in version: 9.5.12-1 🚀
Bundle Size Analysis (Sentry): |


















Explanation of Change
On a grouped search (the Spend > Accounting views such as card accruals, cash accruals, card statements and bank reconciliation), selecting a group row left "Current view" as the only export option. Card groups only got "Reconciliation - All Expenses". The other export templates were only reachable by ticking every line item in the group one by one.
A template export already sends a group selection as an ungrouped query filtered to the selected groups (
getTemplateGroupExportQuery), plus the IDs of any expenses ticked on their own. So the templates work for a group selection. They were just never offered.This PR offers every template for a group selection when the search is grouped by
from,card,withdrawal-id,category,merchantortag. These are the groupingsgetSelectedGroupFilterEntrycan turn into a filter, listed inTEMPLATE_EXPORTABLE_GROUP_BYSinsrc/hooks/useSearchBulkActions.ts. This covers:Time-based groupings (
day,week,month,quarter,year) have no group filter, so the export would fail. They keep only "Current view". The basic export stays hidden on grouped searches, as before.Both selection shapes are covered: a collapsed group stored as a single
group_<id>stub, and an expanded group stored as one entry per child taggedisSelectedViaGroup.AI Tests
Run locally on merge commit
45fa336:npm test -- tests/unit/hooks/useSearchBulkActionsExportTest.ts: 61 passednpm test -- --silent tests/unit/hooks/useSearchBulkActions tests/unit/Search: 77 suites, 2152 tests passednpm run lint -- <changed files>: passednpm run spell-changed -- <changed files>: 0 issuesnpm run typecheck: no errors in the changed files. The localnode_modulesis older thanmain, so other files fail on missing exports fromreact-native-gesture-handler,react-native-onyxandexpensify-common. CI installs the right versions.npm run react-compiler-compliance-check check src/hooks/useSearchBulkActions.ts: this file already fails onmain. Every error is on a line this PR doesn't touch.Could not run: browser verification of the exported file contents.
Fixed Issues
$ #100074
PROPOSAL: #100074 (comment)
Tests
display: by group > user/card/bank.Offline tests
Same as tests
QA Steps
Same as tests
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectionAvatar, I verified the components usingAvatarare working as expected)StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))npm run compress-svg)Avataris modified, I verified thatAvataris working as expected)Designlabel and/or tagged@Expensify/designso the design team can review the changes.mainbranch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTeststeps.Screenshots/Videos
Android: Native
Android: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari