add role-based UI restrictions for TinaCMS editors#586
Merged
ajolipa merged 8 commits intoRB-clerk-authfrom Mar 25, 2026
Merged
add role-based UI restrictions for TinaCMS editors#586ajolipa merged 8 commits intoRB-clerk-authfrom
ajolipa merged 8 commits intoRB-clerk-authfrom
Conversation
- Shared getUserRole helper with dev-mode override for local testing - MutationObserver locks admin-only sidebar links (Settings, Branding, Internationalization, Navbar) with gray styling and lock icon - Ownership notice banner on posts/paths when viewing another user's content - beforeSubmit guard blocks saves for non-owners with clear error - Refactor PublishToggle to use shared role detection
- CSS-disable all form fields (inputs, buttons, date picker, dropzone) - Hide status dot SVG, show lock icon in form header - Fix banner text and sizing (remove email, fix overflow) - Use useEffect for data attribute to avoid render loops - Add Pages to admin-only sidebar collections - Consolidate CSS selectors to target form scroll area
✅ Deploy Preview for padp-staging ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
- cmsCallback only loads role-ui when TINA_PUBLIC_AUTH_USE_SSO is true - getUserRole defaults to admin when no Clerk user is found - Non-Clerk sites are unaffected by RBAC restrictions
This was referenced Mar 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Role Mapping: Clerk → TinaCMS
This PR maps Clerk organization roles to TinaCMS permissions, and closes #580 and #581.
org:adminorg:memberRole detection uses a shared helper (
tina/utils/getUserRole.ts) that reads Clerk org membership. For local development, a dev-mode override is available viaTINA_PUBLIC_DEV_ROLEandTINA_PUBLIC_DEV_USER_IDenv vars (set on the Netlify site's dev context).Non-Clerk site compatibility: Role-based UI is gated behind
TINA_PUBLIC_AUTH_USE_SSO. Sites not using Clerk are completely unaffected —getUserRoledefaults to admin when no Clerk user is found, and thecmsCallbackskips role-ui initialization entirely.UX for Editors
Sidebar restrictions
Admin-only collections (Settings, Branding, Internationalization, Navbar, Pages) appear grayed out with a lock icon and are not clickable. Editors can only navigate to Posts and Paths.
Non-owned content (view-only mode)
When an editor opens a post or path created by another user:
When an editor opens their own content, none of these restrictions apply.
Published toggle
Admins see an interactive toggle. Editors see a read-only "Published/Unpublished" label.
Save guard
If an editor somehow bypasses the CSS restrictions and attempts to save non-owned content, a
beforeSubmitguard throws a clear error. This is a safety net — the backend enforcement innetlify/functions/tina.tsis the real security layer.Code Changes
tina/utils/getUserRole.tstina/role-ui.tstina/components/OwnershipNotice.tsxdata-tina-read-onlyattribute via useEffecttina/components/PublishToggle.tsxgetUserRolehelpertina/config.tscmsCallbackto initialize role-based UI on CMS load, gated behinduseSSOtina/content/posts.tsbeforeSubmittina/content/paths.tsdocs/clerk-rbac-fixes.mdAll frontend restrictions are cosmetic — backend enforcement in
netlify/functions/tina.ts(from PR #577) is unchanged and remains the security boundary.How to Test
Local testing with dev role override
The PADP staging site has
TINA_PUBLIC_DEV_ROLEandTINA_PUBLIC_DEV_USER_IDset on its dev context.As editor:
netlify env:set TINA_PUBLIC_DEV_ROLE org:member --context dev # restart dev server/admin→ sidebar should show Settings/Branding/I18n/Navbar/Pages as lockedcreator.idthat doesn't matchTINA_PUBLIC_DEV_USER_ID→ banner, disabled fields, lock iconcreatorfield (e.g., Local-test-post) → fully editable (no owner = editable)As admin:
netlify env:set TINA_PUBLIC_DEV_ROLE org:admin --context dev # restart dev serverOn deployed PADP staging
Log in with a Clerk account that is an
org:memberof the Performant org. Verify the same restrictions apply. Log in asorg:adminand verify full access.Known Limitations
_ownershipNoticepseudo-field appears as a sort option in collection list viewscreatorfield (pre-existing content) are treated as editable by all editorsdocs/clerk-rbac-fixes.mdfor full TODO list including migration planning