Skip to content

[#91727] Add Load more pattern to Workspace Workflows approval list#55

Closed
elirangoshen wants to merge 3 commits into
mainfrom
feat/91727-workflows-load-more
Closed

[#91727] Add Load more pattern to Workspace Workflows approval list#55
elirangoshen wants to merge 3 commits into
mainfrom
feat/91727-workflows-load-more

Conversation

@elirangoshen

@elirangoshen elirangoshen commented Jun 19, 2026

Copy link
Copy Markdown

Explanation of Change

Adds a Load more button to the Approvals list on Workspace → Workflows (WorkspaceWorkflowsPage). Workspaces with many custom approval workflows previously rendered every rich workflow card at once (member pills, approver chain, limits), causing a slow/janky initial render and burying the Add approval workflow button under heavy scrolling.

What changed:

  • The approvals list now renders only the first CONST.WORKFLOW_APPROVALS_INITIAL_BATCH (5) workflow cards.
  • When there are more than 5 workflows, a Load more card is shown between the list and Add approval workflow, labelled with the full remaining count (e.g. "Load 8 more"). Pressing it reveals all remaining workflows at once (per product decision) and the card disappears.
  • While searching, pagination is bypassed and every match is shown (the search bar already narrows the list).
  • New WorkflowsLoadMoreCard matches the approved Figma spec: a bordered row where the whole card is the tap target and gets the row-hover state, with a 12px CircularArrowBackwards icon + "Load X more" label in textSupporting.
  • Added the workflowsPage.loadMoreWorkflows copy to all locales (English string verbatim from Figma; other locales generated).
  • Added a UI test (tests/ui/WorkspaceWorkflowsLoadMoreTest.tsx) covering the initial batch, the button gate (>5), reveal-all on press, and the search-bypass behavior.

No API or data-layer changes — workflow data is already client-side (derived from policy.employeeList via WorkflowUtils.convertPolicyEmployeesToApprovalWorkflows); this is purely UI pagination.

Fixed Issues

$ Expensify#91727
PROPOSAL:

Tests

  1. Open the Control workspace and go to Workspace → Workflows.
  2. Toggle Approvals on (Advanced mode) so custom workflows are listed.
  3. In the Approvals section, verify only the first 5 workflow cards render, followed by a Load more card, then Add approval workflow.
  4. Verify the Load more label reads "Load X more" where X = (total workflows − 5).
  5. Click Load more and verify all remaining workflow cards now render and the Load more card disappears.
  6. (Web) Hover the Load more card and verify the whole card highlights (row-hover), not just the text.
  7. Open a workspace with 5 or fewer workflows and verify no Load more card appears.
  8. With more than 3 workflows, type a member/approver name into the Find workflow search and verify all matching workflows are shown regardless of the 5-item limit, and no Load more card appears while a search query is active. Clear the search and verify the list returns to the first 5 + Load more.
  • Verify that no errors appear in the JS console

Offline tests

Workflow data is fully client-side, so the pattern behaves identically offline.

  1. Go offline.
  2. Open Workspace → Workflows on a workspace with more than 5 approval workflows.
  3. Verify the first 5 cards render with the Load more card; tap it and verify all remaining workflows render — identical to the online behavior.

QA Steps

  1. Open the Control workspace and go to Workspace → Workflows.
  2. In the Approvals section, verify only the first 5 workflow cards render, followed by a Load more card, then Add approval workflow.
  3. Verify the Load more label reads "Load X more" where X = (total workflows − 5).
  4. Tap Load more and verify all remaining workflow cards render and the Load more card disappears.
  5. Confirm a workspace with 5 or fewer workflows shows no Load more card.
  6. Type a member/approver name into the Find workflow search and verify all matches show and no Load more card appears while searching.
  • 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 followed proper code patterns (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 followed the guidelines as stated in the Review Guidelines
  • 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 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 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 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.
  • 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 609101638-68eb6fc6-135f-4a6b-bc32-68b964d3bdcc
Android: mWeb Chrome
iOS: Native 609101639-4fe3cd7e-4a8c-4fab-b097-1097c27bbc1a
iOS: mWeb Safari
MacOS: Chrome / Safari 609101640-372e7ca6-689f-494b-beaa-461215679760

Summary by CodeRabbit

  • New Features
    • Added "Load more" pagination to workflow approvals list, displaying an initial batch of 5 items with a button to load remaining workflows.
    • Implemented multilingual support for the new "Load more" functionality across all supported languages.

elirangoshen and others added 2 commits June 17, 2026 15:35
…91727)

Render approval workflows in batches of WORKFLOW_APPROVALS_INITIAL_BATCH (5)
with a "Load more" card that reveals the next batch and shows the remaining
count (capped at 5). Search bypasses pagination and shows all matches.

The card matches the Figma spec: bordered row with whole-card row-hover, a
small CircularArrowBackwards icon (12px) + "Load X more" label in
textSupporting, 8px radius to match the other workflow cards.

Adds the workflowsPage.loadMoreWorkflows string to all locales and a UI test
covering the batch, reveal, hide, and search-bypass behaviors.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…#91727)

Per product decision, the "Load more" button reveals every remaining workflow
at once (with the full remaining count in the label) instead of paging 5 at a
time. Updates the UI test to match.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@elirangoshen, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 23 minutes and 14 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 579d90f1-18f7-455e-923f-9a0d7af00d1e

📥 Commits

Reviewing files that changed from the base of the PR and between d4cc5d5 and 1caab34.

📒 Files selected for processing (1)
  • tests/ui/WorkspaceWorkflowsLoadMoreTest.tsx
📝 Walkthrough

Walkthrough

Adds "Load more" pagination to the workspace workflows approval list. A new WORKFLOW_APPROVALS_INITIAL_BATCH constant (5) controls the initial render count. A new WorkflowsLoadMoreCard component and associated state/derived values limit visible workflows unless expanded or a search is active. Localized strings are added across 10 languages, and a UI test suite validates all four pagination scenarios.

Changes

Workflow approvals load-more pagination

Layer / File(s) Summary
Constants and i18n contracts
src/CONST/index.ts, src/languages/en.ts, src/languages/de.ts, src/languages/es.ts, src/languages/fr.ts, src/languages/it.ts, src/languages/ja.ts, src/languages/nl.ts, src/languages/pl.ts, src/languages/pt-BR.ts, src/languages/zh-hans.ts
Adds WORKFLOW_APPROVALS_INITIAL_BATCH (5) and LOAD_MORE_APPROVALS Sentry label to CONST, and adds a parameterized loadMoreWorkflows translation function in all 10 supported languages.
WorkflowsLoadMoreCard component and pagination logic
src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx
Adds WorkflowsLoadMoreCard using PressableWithFeedback; introduces isWorkflowListExpanded state and derived displayedWorkflows/hiddenWorkflowsCount; switches the render loop to displayedWorkflows; conditionally renders the load-more card when hidden workflows exist; updates memo dependencies.
UI test suite for load-more behavior
tests/ui/WorkspaceWorkflowsLoadMoreTest.tsx
Adds four test scenarios covering: exact batch size (no button shown), exceeding batch (button with remaining count), pressing load-more reveals all items, and search input bypassing pagination entirely.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐇 Hop, hop — too many workflows to see!
Five cards appear, the rest hide behind a tree.
"Load more," says the button with its circular spin,
Press it once and all the workflows come in.
Search bypasses the batch without a fuss,
This rabbit's pagination — riding the right bus! 🚌

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title '[#91727] Add Load more pattern to Workspace Workflows approval list' accurately and specifically describes the main change: introducing pagination to the workflows approval list via a load-more pattern.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/91727-workflows-load-more

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 and usage tips.

@elirangoshen elirangoshen marked this pull request as ready for review June 19, 2026 12:07
@elirangoshen

Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx (1)

339-343: ⚡ Quick win

Memoize displayedWorkflows before using it in optionItems dependencies.

displayedWorkflows is rebuilt on every render (especially via .slice(...)), so optionItems gets recomputed even when source data is unchanged. Wrapping the derived pagination values in useMemo will preserve memoization and avoid unnecessary work in this large tree.

Suggested diff
-    const isSearchingWorkflows = workflowSearchInput.length > 0;
-    const displayedWorkflows = isWorkflowListExpanded || isSearchingWorkflows ? searchFilteredWorkflows : searchFilteredWorkflows.slice(0, CONST.WORKFLOW_APPROVALS_INITIAL_BATCH);
-    const hiddenWorkflowsCount = searchFilteredWorkflows.length - displayedWorkflows.length;
+    const isSearchingWorkflows = workflowSearchInput.length > 0;
+    const displayedWorkflows = useMemo(
+        () =>
+            isWorkflowListExpanded || isSearchingWorkflows
+                ? searchFilteredWorkflows
+                : searchFilteredWorkflows.slice(0, CONST.WORKFLOW_APPROVALS_INITIAL_BATCH),
+        [isWorkflowListExpanded, isSearchingWorkflows, searchFilteredWorkflows],
+    );
+    const hiddenWorkflowsCount = useMemo(
+        () => searchFilteredWorkflows.length - displayedWorkflows.length,
+        [searchFilteredWorkflows.length, displayedWorkflows.length],
+    );

Also applies to: 772-803

🤖 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 `@src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx` around lines 339 -
343, The variable `displayedWorkflows` is being recalculated on every render due
to the `.slice()` operation, causing `optionItems` to be unnecessarily
recomputed when included in its dependency array. Wrap the pagination logic that
creates `displayedWorkflows` and `hiddenWorkflowsCount` in a `useMemo` hook with
dependencies on `isSearchingWorkflows`, `isWorkflowListExpanded`,
`searchFilteredWorkflows`, and `CONST.WORKFLOW_APPROVALS_INITIAL_BATCH`. This
will preserve the memoization chain and prevent unnecessary recalculations in
the component tree.
🤖 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 `@tests/ui/WorkspaceWorkflowsLoadMoreTest.tsx`:
- Line 159: The negative assertions at line 159 and line 195 are too narrow,
checking only for the absence of the specific label loadMoreLabel(BATCH). If a
load-more card appears with a different count, these assertions will still pass
incorrectly. Strengthen these assertions to check for the absence of the
load-more card element itself rather than checking for one specific label text.
Use a query selector that targets the card container or a test ID that uniquely
identifies the load-more card, ensuring the test fails if any version of the
load-more card is visible regardless of its label.

---

Nitpick comments:
In `@src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx`:
- Around line 339-343: The variable `displayedWorkflows` is being recalculated
on every render due to the `.slice()` operation, causing `optionItems` to be
unnecessarily recomputed when included in its dependency array. Wrap the
pagination logic that creates `displayedWorkflows` and `hiddenWorkflowsCount` in
a `useMemo` hook with dependencies on `isSearchingWorkflows`,
`isWorkflowListExpanded`, `searchFilteredWorkflows`, and
`CONST.WORKFLOW_APPROVALS_INITIAL_BATCH`. This will preserve the memoization
chain and prevent unnecessary recalculations in the component tree.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 572b2639-d465-4b2d-8287-d425efb56d06

📥 Commits

Reviewing files that changed from the base of the PR and between facfcc1 and d4cc5d5.

📒 Files selected for processing (13)
  • src/CONST/index.ts
  • src/languages/de.ts
  • src/languages/en.ts
  • src/languages/es.ts
  • src/languages/fr.ts
  • src/languages/it.ts
  • src/languages/ja.ts
  • src/languages/nl.ts
  • src/languages/pl.ts
  • src/languages/pt-BR.ts
  • src/languages/zh-hans.ts
  • src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx
  • tests/ui/WorkspaceWorkflowsLoadMoreTest.tsx

Comment thread tests/ui/WorkspaceWorkflowsLoadMoreTest.tsx Outdated
Use queryByRole(button, /load .* more/i) instead of the exact-count label so the
absence checks fail if a load-more card appears with any count.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant