Update table pages to scroll full page - #93877
Conversation
265dd82 to
e3d26d7
Compare
|
@Krishna2323 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] |
|
🚧 @shawnborton has triggered a test Expensify/App build. You can view the workflow run here. |
|
🧪🧪 Use the links below to test this adhoc build on Android, iOS, and Web. Happy testing! 🧪🧪
|
|
Otherwise feeling pretty good to me, very excited for this one! |
trjExpensify
left a comment
There was a problem hiding this comment.
Looks nice, good from product. 👍
|
Codex Review: Didn't find any major issues. Swish! Reviewed commit: ℹ️ About Codex in GitHubCodex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
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". |
…ing-flow # Conflicts: # src/components/Table/Table.tsx
|
@Krishna2323 Kind ping here. Thanks! |
|
re-reviewing today |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 059f5d8bdd
ℹ️ 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".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| function buildTableListData<DataType extends TableData>(data: Array<TableRow<DataType>>, metadata: TableListMetadata): DataType[] { | ||
| return [ | ||
| ...(metadata.hasPageHeader ? [createSyntheticRow<DataType>(PAGE_HEADER_KEY)] : []), | ||
| ...(metadata.shouldRenderStickyHeader ? [createSyntheticRow<DataType>(TABLE_HEADER_KEY)] : []), |
There was a problem hiding this comment.
Preserve ListEmptyComponent when sticky headers are enabled
When a table opts into shouldUseStickyColumnHeader and supplies a ListEmptyComponent without a page header, this synthetic table-header row makes the FlashList data non-empty even when there are no real rows. TableBody stays mounted for ListEmptyComponent in that empty case, but FlashList will never render it because data.length is now 1, and TableHeader itself returns null for empty data, leaving a blank table instead of the caller's empty view. Consider suppressing the sticky header for empty data or rendering the list-empty content as a synthetic row in this path too.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Good catch — fixed in b976f00. Empty tables with a sticky header and no page header now render ListEmptyComponent as a synthetic row, and I added coverage for this case.
luacmartins
left a comment
There was a problem hiding this comment.
Can we migrate RulesAgentsTab too?
|
@luacmartins Done — |
|
@KJ21-ENG, please resolve the conflicts and check this comment. Let's try to avoid any kind of workaround here, please. |
…ing-flow # Conflicts: # src/pages/settings/Agents/AgentsPage.tsx # src/pages/workspace/rules/tabs/RulesAgentsTab.tsx
|
@KJ21-ENG the empty state floats over the header/input when keyboard appears: Monosnap.screencast.2026-07-27.17-16-18.mp4 |
1 similar comment
|
@KJ21-ENG the empty state floats over the header/input when keyboard appears: Monosnap.screencast.2026-07-27.17-16-18.mp4 |
|
Lets push to get this one in please, our tables feel pretty wonky with the minimum scroll they currently have |
|
Sure, investigating this new bug mentioned by Krishna. will be fixed shortly. |
@Krishna2323 Fixed in 8299f00 Apologies I missed this as I generally do test in a simulator, and in this case, on-screen keyboard was not opened when I tested. So, I missed this bug. The blank space was caused by the empty state using a flex-growing footer. While fixing it, we also found that the no-results transition could remount the search input, briefly closing and reopening the keyboard. We now keep the same list/header/input mounted and render the empty state in the normal list flow. Both issues are fixed and verified on iOS. cc: @JS00001 Simulator.Screen.Recording.-.iPhone.17.-.2026-07-28.at.01.24.07.mov |



Explanation of Change
Adds
headerComponentsupport to the sharedTableso page-level controls (header content, buttons, search/filter bar) render inside the table'sFlashListand scroll away with the rows, while the table column header is rendered as a sticky list item. Row render indexes andscrollToIndexcallers remain aligned to the real table data, and sticky-header activation waits until the list has data to avoid the StickyHeaders load-time error.All migrated table pages now use the table-owned header flow: Workspaces, Domains (list, admins, groups, members), Categories, Tags, Taxes, Members, Company Cards, Distance Rates, Per Diem, Rooms, Rules (personal rules and all workspace rules tabs), Agents, Expensify Cards, and report participants.
The table empty states (
Table.EmptyState/Table.NoResultsState) render inside the scrolling list below the page header, so the page controls stay visible and usable when the table is empty or a search/filter matches nothing.This PR also $ #95556: on native, focusing the table search bar now scrolls it above the keyboard (using the existing
useScrollToFocusedInputpattern), so the input stays visible while typing in landscape.Fixed Issues
$ #92930
PROPOSAL: #92930 (comment)
$ #95556
Tests
Offline 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 in all cases)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
611393262-bb275b7b-db8e-4386-b9f5-19de01001916.mp4
Android: mWeb Chrome
611381825-6fceb35a-5f11-4439-97cd-76fac7124bd9.mp4
iOS: Native
Screen.Recording.2026-06-23.at.12.49.39.AM.mov
iOS: mWeb Safari
VIDEO-2026-06-23-00-03-34.mp4
MacOS: Chrome / Safari
ezyZip.53.mp4