feat(my-org): wire invitation details modal to invitation roles endpoint [2/2] - #457
Conversation
📝 WalkthroughWalkthroughThe member-management service now fetches roles for the selected invitation. The organization hook exposes those roles and loading state. The invitation details modal renders resolved role names, a loading spinner, or a dash when no roles are assigned. ChangesInvitation role retrieval and display
Estimated code review effort: 3 (Moderate) | ~25 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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 |
|
@coderabbitai review |
✅ Action performedReview finished.
|
…oles-api-integration
… into feat/invitation-roles-api-integration
… into feat/invitation-roles-api-integration
Summary
Wires the invitation details modal to
GET /my-org/member-invitations/{invitation_id}/roles, replacing the tenant-wide roles fetch and client-side intersection that resolved role names before.This is part 2 of 2 and targets
feat/invitation-roles-api-setup(#456). Merge this into #456 first, then #456 intofeat/my-org-ea-branch.Why
Opening the details modal used to fetch up to 100 tenant roles (
MAX_ROLES_AVAILABLE_FOR_ASSIGNMENT) and intersect them against the role IDs on the invitation, purely to turn IDs into display names. Two consequences:role_a1b2c3instead ofBilling Admin— with nothing signalling that the lookup had failed rather than that the name was genuinely missing.The new endpoint returns the invitation's roles directly, so the intersection disappears and the cap becomes irrelevant.
What
Service query —
rolesQuery(bulkorganization.roles.list({ take: 100 })) is replaced by a scoped, gated query:invitationRolesIdis both the request parameter and the enablement gate, so no request fires unless a details modal is open. The?? ''fallback exists becausequeryKeyis evaluated eagerly on every render even while disabled; the!inqueryFnis safe becausequeryFnonly runs onceenabledis true.Parent hook — derives the ID from modal state and exposes the results:
Hidden coupling fixed — the assign-roles optimistic update read the now-deleted bulk roles cache to build its new-roles list. It is repointed at the role search cache, which is where the assign modal's options actually come from:
Without this the optimistic update would have silently produced an empty list after the bulk query was removed.
Modal rendering — the 9-line intersection memo collapses to
roles.map((role) => role.name), and the Roles field gains a loading branch: spinner while fetching, chips when roles exist,-when empty.Error handling — failures surface through the shared
useQueryErrorToasthook with theinvitation.error.fetch_roles_failedfallback, matching the existing/member/{user_id}/rolesbehaviour as requested in review. This replaced a hand-rolleduseEffect+ ref that turned out to be byte-for-byte identical to that existing hook.Cleanup — removes the dead
enableRolesList: falseoption fromuse-member-detail-service, which only existed to suppress the bulk fetch.Packages
packages/corepackages/reactexamplesReferences
Testing
packages/react: 111 files, 1729 tests passing.tsc --noEmitand ESLint clean on every file in this PR.New and updated coverage:
use-member-management-service.test.ts— therolesQueryblock becomesinvitationRolesQuery:invitations.roles.list('uinv_1')with the correct IDroles.listcall is still aDEFAULT_ROLES_PAGE_SIZEsearch page, which is the regression guard for the truncation bugidleand never calls the endpoint wheninvitationRolesIdis nulluinv_1populated,uinv_2untouched)[]when the response omitsrolesisErroron failureuse-organization-member-management.test.ts(new file — this hook had no coverage at all, and it owns the error handling):invitationRolesIdis null until a details modal opens, then becomes the invitation's IDinvitationRoles/isFetchingInvitationRoles, defaulting to[]organization-invitation-details-modal.test.tsx— rewritten for therolesprop, plus anisLoadingRolesspinner test and a tightened empty-state assertion.Intentionally not covered, and why:
OrganizationMemberManagementView) prop-forwarding tests. Per review, this is being covered from the parent component instead once the latest changes are pulled frommain.fr.jsonlocale. See feat(my-org): invitation roles API types, constants and locales [1/2] #456 — the file has nomember_management.invitationblock at all, so this key is deliberately absent rather than stranded alone.One pre-existing failure unrelated to this work:
packages/react/src/components/ui/dropdown-menu.tsxfails typecheck on a Radixalignunion mismatch (ContentvsSubContentprops). Present on the base branch too; being resolved by taking upstream frommain.Checklist
The breaking public-API change (the
useOrganizationMemberManagementreturn type) is declared in #456, which carries the type edits. This PR only updates implementations to match.Contributing
Summary by CodeRabbit
New Features
Bug Fixes