feat(admin): list pending invites in user details side panel - #1847
Conversation
panel and extract org role fetching into useOrganizationRoles
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughSummary by CodeRabbit
WalkthroughThis PR centralizes organization role retrieval for membership editing. It adds invitation querying and invitation detail rendering to the user details side panel, including organization data, role titles, status, expiry text, and related styling. ChangesOrganization roles and invitation panel
Estimated code review effort: 3 (Moderate) | ~25 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 2✅ Passed checks (2 passed)
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: 1
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 49158fa7-268d-4f6e-adf1-52556c80c8a0
📒 Files selected for processing (4)
web/sdk/admin/hooks/useOrganizationRoles.tsweb/sdk/admin/views/users/details/layout/membership-dropdown.tsxweb/sdk/admin/views/users/details/layout/side-panel-invitation.tsxweb/sdk/admin/views/users/details/layout/side-panel.tsx
Coverage Report for CI Build 31424705329Warning Build has drifted: This PR's base is out of sync with its target branch, so coverage data may include unrelated changes. Coverage increased (+0.1%) to 48.097%Details
Uncovered ChangesNo uncovered changes found. Coverage Regressions267 previously-covered lines in 6 files lost coverage.
Coverage Stats
💛 - Coveralls |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
web/sdk/admin/utils/connect-timestamp.ts (1)
38-49: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winRefresh invitation expiry state while the panel is open.
formatInviteExpirycalculatesfromNow()andisExpiredonly whenSidePanelInvitationrenders. The shown consumer has no time-based refresh. If an invitation expires while the panel stays open, the UI can continue to showPendingand stale relative text until another render.Add a timer at the expiry boundary or refresh this view periodically. Add a test that advances the clock across
expiresAt.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 7e669235-e24d-41b5-8bf6-dc5d82b8b5c8
📒 Files selected for processing (5)
web/sdk/admin/utils/connect-timestamp.tsweb/sdk/admin/views/users/details/layout/side-panel-details.tsxweb/sdk/admin/views/users/details/layout/side-panel-invitation.tsxweb/sdk/admin/views/users/details/layout/side-panel-membership.tsxweb/sdk/admin/views/users/details/layout/side-panel.module.css
🚧 Files skipped from review as they are similar to previous changes (1)
- web/sdk/admin/views/users/details/layout/side-panel-invitation.tsx
Summary
The user details side panel now lists the organizations a user has been invited to but hasn't joined yet, sitting below their existing memberships. Data comes from
FrontierService/ListUserInvitations.Changes
Invitationssection in the user details side panel — one block per invite, showing the org, the role offered, aStatus(Pending/Expired), and a relative expiry (in 7 days, flipping to5 days agoonce lapsed).useOrganizationRoleshook (admin/hooks/) that fetches the platform's default org roles plus the org's custom roles, returning both aroleslist and an id → title map.membership-dropdown.tsxnow uses that hook (+2 / −40). It previously had its own copy of the same two queries, so both places resolve role titles identically from here on.List.Headerrenders its text in a tertiary-coloured inner span; overridden to--rs-color-foreground-base-primaryto match design, applied to all three sections.Technical Details
ListUserInvitationsis keyed by the invitee's email, not the user uuid — an invitation can exist before the user does. Worth knowing because passing the uuid returns200with an empty list rather than an error, so getting it wrong fails silently. The query usesuser?.emailand is gated on it.expires_atfilter; rows live until the cleanup cron sweeps them. SoPending/Expiredis derived client-side fromexpires_atvs. now.relativeTimewith the stockenlocale, so it readsin 7 days/5 days ago. The newformatInviteExpiryhelper inadmin/utils/connect-timestamp.tsreturns the text and theisExpiredflag together, and that module is wheredayjs.extend(relativeTime)is installed (a one-time global extend, so any other dayjs consumer in the bundle gainsfromNowtoo). An earlier revision registered a customen-invitelocale to get7 days leftphrasing; that's been dropped — the wording gain wasn't worth a locale registration living in a shared util, and stock output already distinguishes the two directions.org_idandrole_ids, so the org title/avatar comes from the existinguseOrganizationLookupand role titles from the new hook. react-query caches both per key, so multiple invite blocks share one fetch.useEffectinside the hook. The dropdown previously logged them from the render body, which repeated on every render.Test Plan
Verified:
tsc --noEmit: 21 errors, all pre-existing and in untouched files (organizations/details/edit/billing.tsx,client/utils,tsup.config.ts, …); 0 in the files this PR touches.eslintclean on all touched files;pnpm buildsucceeds inweb/sdk.Expiry rendering checked across the boundaries:
in 7 daysin a dayin 3 hoursin 30 minutes30 minutes ago5 days agoSQL Safety (if your PR touches
*_repository.goorgoqu.*)Not applicable — frontend only, no Go or query-builder changes.