fix: add cursor-based pagination and fix refresh for feedback records#7935
Conversation
The feedback records table lacked pagination support — it always showed only the first page with no way to load more. Additionally, refresh re-fetched from scratch without tracking pagination state. This adds: - Per-FRD cursor tracking from the Hub API's next_cursor response - A "Load more" button when more records are available - Refresh now properly resets cursors and fetches a fresh first page Resolves ENG-770
WalkthroughThe changes implement cursor-based pagination for the feedback records feature. The server-side page now extracts 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. 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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 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
`@apps/web/app/`(app)/workspaces/[workspaceId]/unify/feedback-records/components/feedback-records-table.tsx:
- Around line 141-146: The toast error messages are hiding server-action
details; update both failure branches that handle the result from fetchRecords
(the one after const result = await fetchRecords("refresh") and the later branch
that currently calls toast.error(t(...))) to include the server error text by
calling toast.error(getFormattedErrorMessage(result), { id: toastId }) (or
toast.error(getFormattedErrorMessage(result)) if no id is used), ensuring you
import/consume the existing getFormattedErrorMessage helper and preserve the
localized fallback when result has no server message.
- Around line 159-176: handleRefresh and handleLoadMore can run concurrently and
the last finisher overwrites records/cursors; add a single mutual-exclusion
guard to prevent overlapping fetches by introducing and checking a shared lock
(e.g., isFetchingRef or fetchMutex) at the start of both handlers (handleRefresh
and handleLoadMore), bail out if already locked, then set the lock before
calling fetchRecords and clear it in a finally block; ensure you still set the
per-action UI flags (isLoadingMore/isRefreshing) but only update setRecords and
setCursors when the lock is held (or by the winning operation) so pagination
state cannot be clobbered.
In `@apps/web/app/`(app)/workspaces/[workspaceId]/unify/feedback-records/page.tsx:
- Around line 47-54: The bug: initialCursors is built from each FRD's full
first-page next_cursor but the rendered dataset is globally sliced to 50, so
some FRD first-page items may be omitted and later become unreachable. Fix by
computing initialCursors only for FRDs whose first-page items are included in
the initial displayed set (i.e., derive the map from the dataset after the
global slice), or by building the cursor map from the full per-FRD results
before slicing and then tracking which FRDs contributed items to the rendered 50
so you only advance cursors for those FRDs; update the logic around
initialCursors, frds and results (or the pre-slice result variable) to reflect
this consistent approach so load-more uses cursors only for FRDs that actually
contributed to the initial render.
🪄 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: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: b6fdc781-d14b-41bd-a8b4-7beb61304ab4
📒 Files selected for processing (3)
apps/web/app/(app)/workspaces/[workspaceId]/unify/feedback-records/components/feedback-records-page-client.tsxapps/web/app/(app)/workspaces/[workspaceId]/unify/feedback-records/components/feedback-records-table.tsxapps/web/app/(app)/workspaces/[workspaceId]/unify/feedback-records/page.tsx
- Restore getFormattedErrorMessage for actionable error toasts - Add mutual exclusion between refresh and load-more to prevent concurrent fetches from clobbering pagination state - Remove global .slice() from initial load and refresh so no first-page FRD records become unreachable via cursors
|



Summary
next_cursorresponseChanges
page.tsx: Extractsnext_cursorfrom each FRD's Hub response and passesinitialCursorsto the clientfeedback-records-page-client.tsx: PassesinitialCursorsthrough to the table componentfeedback-records-table.tsx:cursorsstate to track per-FRD pagination cursorshandleLoadMorethat fetches the next page using stored cursors and appends resultsfetchRecordshelper used by both refresh and load-moreTest plan
Resolves ENG-770