refactor(ui): gate mosaic organization sections by permission and admin-delete#9041
Conversation
…in-delete Mirror the legacy OrganizationGeneralPage gating in the mosaic delete/leave sections: the delete section only renders when the user has the org:sys_profile:delete permission and organization.adminDeleteEnabled is true; the leave section only renders when there is an active organization membership. The gating lives in the controllers (the only Clerk-aware layer), surfaced as a new 'hidden' status. The wrappers render nothing until 'ready', matching legacy and avoiding a skeleton that would flash then vanish for gated users. Controllers now declare explicit return-type unions instead of per-return `as const`.
🦋 Changeset detectedLatest commit: 11d1f3d The changes in this PR will be included in the next version bump. This PR includes changesets to release 0 packagesWhen changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository YAML (base), Repository UI (inherited) Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (6)
💤 Files with no reviewable changes (6)
📝 WalkthroughWalkthroughControllers for ChangesOrg Section Controller Gating
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
Comment |
@clerk/astro
@clerk/backend
@clerk/chrome-extension
@clerk/clerk-js
@clerk/electron
@clerk/electron-passkeys
@clerk/eslint-plugin
@clerk/expo
@clerk/expo-passkeys
@clerk/express
@clerk/fastify
@clerk/hono
@clerk/localizations
@clerk/nextjs
@clerk/nuxt
@clerk/react
@clerk/react-router
@clerk/shared
@clerk/tanstack-react-start
@clerk/testing
@clerk/ui
@clerk/upgrade
@clerk/vue
commit: |
API Changes Report
Summary
No API Changes DetectedAll packages have stable APIs with no detected changes. Report generated by Break Check Last ran on |
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 @.changeset/mosaic-org-section-gating.md:
- Around line 1-2: Add a real changeset entry for the published `@clerk/ui`
package instead of keeping this placeholder empty. Update the changeset in the
.changeset file to describe the shipped packages/ui behavior change so
versioning and changelog generation include it, and make sure the entry is
associated with `@clerk/ui` rather than leaving only the frontmatter marker.
In `@packages/ui/src/mosaic/sections/delete-organization-controller.tsx`:
- Around line 19-20: The authorization check in DeleteOrganizationController is
running before useSession() has finished loading, so the transient undefined
session state is treated as denied. Update the logic that derives the hidden/not
allowed state to first respect the session loading flag from useSession()
(alongside useOrganization()), and only evaluate authorization after loading is
complete. Add a regression test covering the isLoaded: false with session ===
undefined case to ensure the controller does not hide prematurely.
In `@packages/ui/src/mosaic/sections/leave-organization-controller.tsx`:
- Around line 36-41: The `useLeaveOrganizationController` logic is treating an
unresolved `membership === undefined` as `hidden` when `isLoaded` is already
true, which prematurely hides the leave section during Clerk hydration. Update
the controller’s branching so `hidden` is only returned for an explicit `null`
membership, while `undefined` continues to return `loading`, and keep the
existing `organization` check aligned with that behavior. Also add or adjust the
tests for `useLeaveOrganizationController` to cover the transient `organization`
present / `membership undefined` case and verify it stays in `loading`.
🪄 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 YAML (base), Repository UI (inherited)
Review profile: CHILL
Plan: Pro Plus
Run ID: 2e0945d6-f73d-489a-93b6-6a75a0b1a6e9
📒 Files selected for processing (7)
.changeset/mosaic-org-section-gating.mdpackages/ui/src/mosaic/sections/__tests__/delete-organization-controller.test.tsxpackages/ui/src/mosaic/sections/__tests__/leave-organization-controller.test.tsxpackages/ui/src/mosaic/sections/delete-organization-controller.tsxpackages/ui/src/mosaic/sections/delete-organization.tsxpackages/ui/src/mosaic/sections/leave-organization-controller.tsxpackages/ui/src/mosaic/sections/leave-organization.tsx
…osaic org sections A still-loading session (delete) or unresolved membership (leave) was being collapsed into 'hidden' instead of 'loading'. Gate the delete permission check on the session being loaded, and treat membership === undefined as loading while reserving 'hidden' for an explicit null.
|
@alexcarpenter (minor thing. i dont feel strongly) but wdyt about |
Rename the delete/leave section slices to <name>.<layer> (.machine/.controller/.view), update the wrappers, swingset stories, and the mosaic-architecture file-shape doc (also refreshing the stale wrapper example to render null until ready).
Summary
Mirrors the legacy
OrganizationGeneralPagevisibility gating in the mosaic delete/leave sections (packages/ui/src/mosaic/sections/). Previously both sections rendered for everyone onceuseOrganization()loaded. Now:org:sys_profile:deletepermission andorganization.adminDeleteEnabledis true.This matches
OrganizationDeleteSection/OrganizationLeaveSectioninpackages/ui/src/components/OrganizationProfile/OrganizationGeneralPage.tsx.How
hiddenstatus alongsideloading/ready. The delete controller reads the permission viauseSession().session.checkAuthorization({ permission: 'org:sys_profile:delete' })— the same thing legacyuseProtectdoes internally, kept inside the mosaic boundary (only@clerk/shared/react).ready(if (controller.status !== 'ready') { return null; }). They no longer renderSectionSkeleton: during the load window the controller can't tell a permitted user from a gated one, so a skeleton would flash then vanish for gated users. Rendering nothing until ready matches legacy exactly.as const, so TypeScript checks every return arm against the contract.SectionSkeleton(and theSkeletonprimitive it alone used) are now unused; left in place as design-system building blocks.Changeset
Empty — mosaic is not on the
@clerk/uipublic export surface, so there's no user-facing change to the published package.Summary by CodeRabbit
New Features
Bug Fixes
Documentation
Tests