feat(sdk): add sorting and RQL infinite loading to views-new tokens#1565
feat(sdk): add sorting and RQL infinite loading to views-new tokens#1565paanSinghCoder wants to merge 23 commits intomainfrom
Conversation
Move the RPC from AdminService to FrontierService so org admins (not only platform superusers) can list their own org's token transactions. Matches the FrontierService/ListInvoices gate pattern (UpdatePermission on the org namespace). Superusers still pass via the standard interceptor bypass. - Bump PROTON_COMMIT to pick up the proto move (raystack/proton#482). - Regenerate proto/v1beta1 via make proto. - Swap authorization.go entry from IsSuperUser to IsAuthorized(org, UpdatePermission). - Switch the admin dashboard Tokens page + AddTokensDialog from AdminServiceQueries to FrontierServiceQueries; request/response shape is unchanged. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughSummary by CodeRabbit
WalkthroughAdds a token Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 2✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 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. Review rate limit: 0/1 reviews remaining, refill in 60 minutes.Comment |
Coverage Report for CI Build 25100950141Coverage remained the same at 42.353%Details
Uncovered Changes
Coverage RegressionsNo coverage regressions found. Coverage Stats
💛 - Coveralls |
Updates PROTON_COMMIT to the merge commit of raystack/proton#482 and bumps @raystack/proton npm pin to the same SHA. Regen produces no .pb.go diff since proton branch SHA and proton main merge SHA have identical content. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace listBillingTransactions (non-RQL, client-mode) with searchOrganizationTokens (RQL, server-mode, infinite scroll) in the views-new Tokens page. - useInfiniteQuery with pageParamKey driven by getConnectNextPageParam. - DataTable mode="server" with Toolbar (sort + filter + reset UI) and scroll-triggered fetchNextPage via onLoadMore. - Sorting enabled on Date (createdAt), Tokens (amount), Member (userTitle). Column hiding on Events and Member. Date + number filters on the toolbar. - Default sort: createdAt desc. - Events column shows raw description (source -> friendly-label mapping dropped; not in the new RPC response shape). Balance panel, useTokens, and AddTokensDialog are unchanged. Shared utils (transform-query, connect-pagination) duplicated into react/utils/ since the react and admin SDK entry points deploy independently. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
301e0df to
31b444e
Compare
…at/add-sorting-and-pagination-tokens
…at/add-sorting-and-pagination-tokens
Revert accidental regression during the views-new tokens rewrite. The old BillingTransaction columns used getInitials(userTitle) which produces two-letter initials (e.g. "Alice Smith" → "AS"). The rewrite mistakenly used title?.[0] which only produces one letter. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Old behavior: userTitle -> userId UUID -> '-'
New behavior: userTitle -> '-'
Surfacing a raw UUID ("4f3b2a1c-...") is worse UX than a plain '-'.
Avatar color keying stays on userId since that's a stable
per-user identifier regardless of title.
The proto response shape (OrganizationToken) carries no email, so
restoring the pre-PR user.title -> user.email -> '-' chain is not
possible without a server-side proto change.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Keeps the inline ErrorState as the user-visible affordance (toast was a worse UX), but re-adds the console log so operators have a signal when debugging a failed page. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Accidentally dropped during the rewrite. Auto-sizing let the tiny "Tokens" header collapse and the long description cell in Events eat into adjacent columns. Matches the widths the pre-PR BillingTransaction columns used. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Unhandled rejections fired from the DataTable scroll handler are easy to miss in dev and noisy in prod. Wrap the awaited fetchNextPage in try/catch and log on failure. The existing isError state still drives the user-visible ErrorState. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
web/sdk/react/views-new/tokens/tokens-view.tsx (1)
251-254:⚠️ Potential issue | 🟠 MajorVirtualization still missing for the infinite-scroll table.
This was raised in an earlier review: with infinite loading, the table can accumulate many rows and should use
DataTable.VirtualizedContent(or equivalent) instead ofDataTable.Contentto keep DOM/render cost bounded.
🧹 Nitpick comments (2)
internal/store/postgres/org_tokens_repository_test.go (1)
11-146: Consider adding a test for the newsourcefilter.The SQL projection is updated everywhere, but no test case exercises a filter on the new
sourcefield that was added tovalidFilterFieldsinorg_tokens_repository.go. A small case (e.g.,Operator: "eq", Value: "system.buy") would lock in the whitelist wiring.web/sdk/react/views-new/tokens/tokens-view.tsx (1)
45-50: Initial query doesn't includeDEFAULT_SORT, likely causing a double fetch on mount.
tableQuerystarts asINITIAL_QUERY(no sort) so the first RQL request goes out unsorted; once the DataTable echoesdefaultSortback throughonTableQueryChange, the debounced query changes and a second request fires withcreated_at desc. Seeding the initial state with the default sort avoids the wasted request and any momentary mis-ordering.♻️ Proposed seed
const INITIAL_QUERY: DataTableQuery = { offset: 0, - limit: DEFAULT_PAGE_SIZE + limit: DEFAULT_PAGE_SIZE, + sort: [DEFAULT_SORT] };
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: c4a77814-c9d1-428e-bce0-021f6378af4e
⛔ Files ignored due to path filters (1)
proto/v1beta1/frontier.pb.gois excluded by!**/*.pb.go,!proto/**
📒 Files selected for processing (8)
Makefilecore/aggregates/orgtokens/service.gointernal/api/v1beta1connect/organization_tokens.gointernal/store/postgres/org_tokens_repository.gointernal/store/postgres/org_tokens_repository_test.goweb/sdk/react/views-new/tokens/components/columns.tsxweb/sdk/react/views-new/tokens/tokens-view.module.cssweb/sdk/react/views-new/tokens/tokens-view.tsx
…ged) Drops the local file: tarball workaround now that proton#484 is merged and the new @raystack/proton@0.1.0-7523cfd3 is published. - Makefile: PROTON_COMMIT -> 7523cfd3 (proton main tip). - web/sdk + web/apps/admin: @raystack/proton pinned to the published npm version. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace the (non-existent) message/delayDuration props on the root Tooltip with the standard Tooltip.Trigger + Tooltip.Content composition. The trigger renders as a span so the truncated Text fits the table cell layout. Delay is already 200ms inside apsara-v1's TooltipTrigger wrapper; no need to pass it. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
0065ab6 to
0602180
Compare
Token transaction history is unbounded — orgs accumulate thousands
over time, and infinite scroll keeps all loaded pages in
infiniteData.pages. Without virtualization the DOM grows linearly
with scroll depth.
Bring back the pre-PR settings: rowHeight={48}, overscan={10}.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…roll VirtualizedContent's internal scroll container kept the page header + balance panel pinned and confined scrolling to the table area, which isn't the intended UX. Content uses an IntersectionObserver-based load-more so infinite pagination still fires while the page scrolls naturally and the top section can scroll off. Tradeoff: DOM grows linearly with loaded rows. Acceptable at 50/page volumes; if it ever becomes a problem we'd need to upstream a window- virtualization mode in apsara rather than paper over it here. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
🧹 Nitpick comments (1)
web/sdk/react/views-new/tokens/components/columns.tsx (1)
88-101: Optional: simplifyhas/getto bracket access + nullish coalescing.
TxnEventSourceMapis a plainRecord<string, string>, so the lodash indirection and the trailingas stringaren't pulling their weight. Inline lookup also avoids the empty-string corner case (has(map, '')is false anyway, but the intent is clearer).♻️ Suggested refactor
- cell: ({ row, getValue }) => { - const value = getValue() as string; - const eventName = ( - has(TxnEventSourceMap, value) - ? get(TxnEventSourceMap, value) - : row?.original?.description - ) as string; + cell: ({ row, getValue }) => { + const value = getValue() as string; + const eventName = + TxnEventSourceMap[value] ?? row?.original?.description ?? ''; if (!eventName) {The
has/getimports from lodash can then be dropped if unused elsewhere in this file.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 0ec31c7b-40b2-4c7b-bfa1-4c9e0128f6b3
⛔ Files ignored due to path filters (1)
web/pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (4)
Makefileweb/apps/admin/package.jsonweb/sdk/package.jsonweb/sdk/react/views-new/tokens/components/columns.tsx
✅ Files skipped from review due to trivial changes (2)
- web/sdk/package.json
- web/apps/admin/package.json
🚧 Files skipped from review as they are similar to previous changes (1)
- Makefile
eb2f4a9 to
6a75c85
Compare
Use DataTable.VirtualizedContent (rowHeight=48, overscan=10) so the DOM stays bounded as users scroll through many fetched pages of token transactions. Bound .tableRoot height (max-height calc(100vh - 320px), min-height 320px) so the inner scroll container can overflow and fire onLoadMore. Tradeoff: page-level scroll keeps the balance panel + header pinned; only the table region scrolls. Acceptable for tokens since the data volume can be large. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
♻️ Duplicate comments (1)
web/sdk/react/views-new/tokens/tokens-view.tsx (1)
140-141:⚠️ Potential issue | 🟡 MinorKeep pagination fetches out of table-wide loading state.
Line [141] still ties
isFetchingNextPagetoDataTable.isLoading, which can show global loading UI during infinite-scroll pagination instead of incremental loading behavior.Proposed fix
const isTxnDataLoading = - (isLoading || isTransactionsListLoading || isFetchingNextPage) && !isError; + (isLoading || isTransactionsListLoading) && !isError;
🧹 Nitpick comments (1)
web/sdk/react/views-new/tokens/tokens-view.tsx (1)
48-51: Seed the controlled query with the default sort.Since
queryis controlled (Line [245]), initializing Line [48-51] without sort can allow an unsorted first request before table state sync. Put the default sort directly inINITIAL_QUERYto guarantee initial request ordering.Proposed fix
const INITIAL_QUERY: DataTableQuery = { offset: 0, - limit: DEFAULT_PAGE_SIZE + limit: DEFAULT_PAGE_SIZE, + sort: [DEFAULT_SORT] };Also applies to: 241-241, 245-245
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 8d69bdaa-36bb-44b0-a2ae-fa4faec6a66c
📒 Files selected for processing (2)
web/sdk/react/views-new/tokens/tokens-view.module.cssweb/sdk/react/views-new/tokens/tokens-view.tsx
Summary
listBillingTransactions(non-RQL, client-mode) withsearchOrganizationTokens(RQL, server-mode, infinite scroll) on the views-new Tokens page.createdAt desc.description(the oldsource→ friendly-label mapping is dropped;sourceisn't in the new RPC response).useTokens, andAddTokensDialogare untouched.Screen.Recording.2026-04-22.at.3.35.46.PM.mov
Dependency
Depends on #1564 (backend move + admin dashboard swap). Merge #1564 first, then this.
Test plan
pnpm run build(web turbo) passes