Skip to content

feat(PermissionSessionContext): extract, export, and self-resolve from permissionKey - #1774

Open
rishiraj38 wants to merge 1 commit into
layer5io:masterfrom
rishiraj38:feat/permission-session-context
Open

feat(PermissionSessionContext): extract, export, and self-resolve from permissionKey#1774
rishiraj38 wants to merge 1 commit into
layer5io:masterfrom
rishiraj38:feat/permission-session-context

Conversation

@rishiraj38

@rishiraj38 rishiraj38 commented Aug 5, 2026

Copy link
Copy Markdown
Member

Description

Extracts PermissionSessionContext from PermissionShield into a standalone, exported component so that permission failure details (required keys, function names, descriptions, and user/org/role context) can be rendered in any layout — tooltips, cards, and full-page 403 error pages — from a single source of truth.

What changed

Self-resolving permissionKey prop

PermissionSessionContext now accepts an optional permissionKey prop. When provided, the component internally resolves displayedKeys, subtitle, categories, and subcategories using the same hooks as PermissionShield (useUnmetPermissionKeys, getPermissionKeys, getPermissionKeyCombinator). This eliminates the need for callers to manually derive and pass these values.

PermissionShield refactored to delegate

PermissionShield previously duplicated the full key-resolution logic before passing pre-resolved props to PermissionSessionContext. It now passes permissionKey directly, keeping the tooltip and card rendering paths in sync through a single resolution path.

Accessibility improvements

  • Copy-key control has role="button", tabIndex={0}, and keyboard handler (Enter/Space).
  • Uses promise-based navigator.clipboard.writeText() with .catch() fallback.

Boolean coercion fix

  • Chip-container length checks wrapped with Boolean() to prevent React from rendering the literal string "0".

Barrel export

  • PermissionSessionContext and PermissionSessionContextProps exported from src/index.tsx.

Two usage modes

Mode Prop Use case
Self-resolving permissionKey={Keys.X} Error pages, PermissionShield tooltip — pass the key, get the full UI
Pre-resolved displayedKeys={[...]} Advanced layouts that need custom resolution

Related Issues / PRs

Type of Change

  • New feature (non-breaking change which adds functionality)
  • Refactor / UI enhancement
Screen.Recording.2026-08-05.at.2.30.03.PM.mov

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The change adds the reusable PermissionSessionContext component, supports resolved and self-resolving permission data, applies variant-aware theme styling, updates PermissionShield integration, and exports the new component and props type.

Changes

Permission context UI

Layer / File(s) Summary
Permission session context component
src/custom/permissions.tsx
Adds PermissionSessionContextProps and PermissionSessionContext. The component supports resolved or self-resolved permission data and renders permission and user context.
Themed permission detail rendering
src/custom/permissions.tsx
Updates permission details, metadata chips, reference links, organization and role rows, footer styling, and keyboard-accessible key copying for variants and theme values.
PermissionShield integration and public exports
src/custom/permissions.tsx, src/index.tsx
Routes PermissionShield tooltip content through PermissionSessionContext and exports the component and props type.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant PermissionShield
  participant PermissionSessionContext
  participant PermissionResolver
  PermissionShield->>PermissionSessionContext: Render tooltip content
  PermissionSessionContext->>PermissionResolver: Resolve permission when needed
  PermissionResolver-->>PermissionSessionContext: Return permission data
  PermissionSessionContext-->>PermissionShield: Render permission details
Loading

Possibly related PRs

Suggested reviewers: aabidsofi19, leecalcote

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes: extracting, exporting, and self-resolving PermissionSessionContext from permissionKey.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/index.tsx (1)

76-89: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add PermissionSessionContext to the custom domain index and bundle it.

src/custom/index.ts exports only the existing custom components and does not include custom permissions. Add PermissionSessionContext and type PermissionSessionContextProps to that export, then rebuild so dist/index.d.ts exposes them for consumers importing @sistent/sistent.

🤖 Prompt for 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.

In `@src/index.tsx` around lines 76 - 89, Add PermissionSessionContext and type
PermissionSessionContextProps to the exports in src/custom/index.ts, then
rebuild the package so the generated dist/index.d.ts also exposes both symbols
to `@sistent/sistent` consumers.

Source: Coding guidelines

🧹 Nitpick comments (4)
src/custom/permissions.tsx (4)

504-506: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Prefer text.secondary over text.disabled for this message in the card variant.

palette.subtle maps to theme.palette.text.disabled for the card variant. That token is intended for disabled affordances and carries low contrast. In the card variant this line is informational content on a full page, so low contrast reduces readability. Confirm the contrast ratio of the Sistent text.disabled token against background.paper in both light and dark modes, or switch this line to theme.palette.text.secondary.

As per coding guidelines: "Theme-aware UI must use Sistent theme exports and semantic palette tokens rather than raw MUI defaults."

🤖 Prompt for 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.

In `@src/custom/permissions.tsx` around lines 504 - 506, Update the message color
in the card variant near the font styling to use the Sistent semantic
text.secondary theme token instead of palette.subtle, which resolves to
text.disabled. Preserve the existing typography and ensure the color remains
theme-aware in both light and dark modes.

Source: Coding guidelines


543-554: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Move the event dispatch out of the setOpen updater.

React may invoke a state updater more than once, including under Strict Mode double-invocation. The window.dispatchEvent call at line 548 then fires more than once per click. Compute the next value first, then dispatch outside the setter.

♻️ Proposed refactor
   const handleToggle = (e: React.MouseEvent) => {
     e.stopPropagation();
-    setOpen((prev) => {
-      const next = !prev;
-      if (next) {
-        window.dispatchEvent(
-          new CustomEvent('permission-shield-opened', { detail: { id: uniqueId } })
-        );
-      }
-      return next;
-    });
+    const next = !open;
+    setOpen(next);
+    if (next) {
+      window.dispatchEvent(
+        new CustomEvent('permission-shield-opened', { detail: { id: uniqueId } })
+      );
+    }
   };
🤖 Prompt for 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.

In `@src/custom/permissions.tsx` around lines 543 - 554, Update handleToggle so it
computes the next open state before calling setOpen, then dispatches
permission-shield-opened outside the state updater only when opening. Keep
stopPropagation and the existing uniqueId event detail unchanged.

Source: Linters/SAST tools


577-598: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Let PermissionShield delegate key resolution to PermissionSessionContext.

PermissionShield duplicates the logic already implemented by PermissionSessionContext when permissionKey is provided. Pass permissionKey to the child, remove the locals, and remove the useUnmetPermissionKeys(permissionKey) call at line 537 if it has no other reference in this file.

🤖 Prompt for 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.

In `@src/custom/permissions.tsx` around lines 577 - 598, Update PermissionShield
so PermissionSessionContext receives permissionKey and performs key resolution
itself; remove the duplicated declaredKeys, displayedKeys, combinator, keyNames,
subtitle, categories, and subcategories locals. Remove the
useUnmetPermissionKeys(permissionKey) call if it has no remaining references in
the file, while preserving the existing tooltip rendering.

5-5: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Import useTheme from the Sistent theme barrel.

src/theme/index.tsx exports useTheme, and nearby custom components import it from that barrel. Keep this component in line by using import { useTheme } from '../theme'; instead of @mui/material/styles.

🤖 Prompt for 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.

In `@src/custom/permissions.tsx` at line 5, Update the useTheme import in the
permissions component to use the Sistent theme barrel at ../theme instead of
`@mui/material/styles`, matching the import convention used by nearby custom
components.

Source: Coding guidelines

🤖 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 `@src/custom/permissions.tsx`:
- Line 309: Coerce the combined length check in the hasKeys rendering guard to a
boolean so empty categories and subcategories do not render a visible 0.
Preserve rendering when either array contains entries and keep the existing
hasKeys requirement.
- Around line 254-274: Update the key copy control in the map callback to guard
navigator.clipboard availability, handle writeText rejections without unhandled
errors, and make the Box keyboard-operable with appropriate focus and keyboard
activation behavior. Store the pending reset timeout via the suggested copy
timer identifier, clear it before scheduling a new reset, and preserve the
copied-state feedback for successful copies.

---

Outside diff comments:
In `@src/index.tsx`:
- Around line 76-89: Add PermissionSessionContext and type
PermissionSessionContextProps to the exports in src/custom/index.ts, then
rebuild the package so the generated dist/index.d.ts also exposes both symbols
to `@sistent/sistent` consumers.

---

Nitpick comments:
In `@src/custom/permissions.tsx`:
- Around line 504-506: Update the message color in the card variant near the
font styling to use the Sistent semantic text.secondary theme token instead of
palette.subtle, which resolves to text.disabled. Preserve the existing
typography and ensure the color remains theme-aware in both light and dark
modes.
- Around line 543-554: Update handleToggle so it computes the next open state
before calling setOpen, then dispatches permission-shield-opened outside the
state updater only when opening. Keep stopPropagation and the existing uniqueId
event detail unchanged.
- Around line 577-598: Update PermissionShield so PermissionSessionContext
receives permissionKey and performs key resolution itself; remove the duplicated
declaredKeys, displayedKeys, combinator, keyNames, subtitle, categories, and
subcategories locals. Remove the useUnmetPermissionKeys(permissionKey) call if
it has no remaining references in the file, while preserving the existing
tooltip rendering.
- Line 5: Update the useTheme import in the permissions component to use the
Sistent theme barrel at ../theme instead of `@mui/material/styles`, matching the
import convention used by nearby custom components.
🪄 Autofix

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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e3ec21e2-3fd9-4c74-b553-fd6ffa08a5c5

📥 Commits

Reviewing files that changed from the base of the PR and between 310d02f and 0d63638.

📒 Files selected for processing (2)
  • src/custom/permissions.tsx
  • src/index.tsx

Comment thread src/custom/permissions.tsx
Comment thread src/custom/permissions.tsx Outdated
@rishiraj38
rishiraj38 force-pushed the feat/permission-session-context branch 2 times, most recently from efb30f7 to 4b8ba8c Compare August 5, 2026 11:01
Comment on lines +601 to +607
<PermissionSessionContext
variant="tooltip"
displayedKeys={displayedKeys}
subtitle={subtitle}
categories={categories}
subcategories={subcategories}
/>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that PermissionSessionContext can self-resolve from permissionKey, should PermissionShield pass permissionKey here instead of re-deriving displayedKeys / subtitle / categories so the tooltip and card paths stay in sync?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch; yes, that was redundant. Updated PermissionShield to pass permissionKey directly to PermissionSessionContext instead of manually deriving everything. Both the tooltip and card paths now go through the same self-resolving logic, so they'll stay in sync automatically.

…m permissionKey

- Extract PermissionSessionContext from PermissionShield into a standalone
  exported component for reuse in card/full-page layouts (e.g. 403 error pages).
- Add self-resolving mode via permissionKey prop — resolves displayedKeys,
  subtitle, categories, and subcategories internally using useUnmetPermissionKeys,
  getPermissionKeys, and getPermissionKeyCombinator.
- Refactor PermissionShield to delegate key resolution to
  PermissionSessionContext instead of duplicating it, keeping tooltip and
  card rendering paths in sync.
- Fix accessibility: copy-key control now has role=button, tabIndex=0, and
  keyboard handler (Enter/Space).
- Fix boolean coercion: wrap chip-container length checks with Boolean()
  to prevent rendering literal '0'.
- Export PermissionSessionContext and PermissionSessionContextProps from
  the root barrel file (src/index.tsx).

Signed-off-by: Rishi Raj <rishiraj824@gmail.com>
Signed-off-by: Rishi Raj <rishiraj438gt@gmail.com>
@rishiraj38
rishiraj38 force-pushed the feat/permission-session-context branch from 4b8ba8c to c621514 Compare August 6, 2026 05:54
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@rishiraj38 rishiraj38 changed the title feat(permissions): export PermissionSessionContext with self-resolving permissionKey support feat(PermissionSessionContext): extract, export, and self-resolve from permissionKey Aug 6, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/custom/permissions.tsx (2)

244-254: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Skip the copy action when the key has no id.

id becomes '' when key.id is absent. The handler then writes an empty string and shows "Copied!". Return early instead.

♻️ Proposed change
           const copyKeyId = (e: React.SyntheticEvent) => {
             e.stopPropagation();
-            const id = key.id || '';
+            const id = key.id;
+            if (!id) return;
             void navigator.clipboard
               ?.writeText(id)
               .then(() => {
-                setCopiedKeyId(key.id || `#${index}`);
+                setCopiedKeyId(id);
                 setTimeout(() => setCopiedKeyId(null), 1500);
               })
               .catch(() => undefined);
           };
🤖 Prompt for 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.

In `@src/custom/permissions.tsx` around lines 244 - 254, Update the copyKeyId
handler to return immediately when key.id is absent or empty, before invoking
navigator.clipboard.writeText or updating copied state. Preserve the existing
copy and confirmation behavior for keys with a valid id.

5-5: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use the Sistent palette token for the card background.

The card background should use the Sistent theme palette rather than the raw MUI background.paper slot, e.g. theme.palette.background.card or theme.palette.background.surfaces, so the UI uses the semantic palette token.

🤖 Prompt for 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.

In `@src/custom/permissions.tsx` at line 5, Update the card styling in the
permissions component to use the Sistent semantic palette token, such as
theme.palette.background.card or theme.palette.background.surfaces, instead of
the raw MUI theme.palette.background.paper value; preserve the existing card
layout and styling behavior.

Source: Coding guidelines

🤖 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 `@src/custom/permissions.tsx`:
- Around line 552-563: Update handleToggle so it computes the next open state
from the current state before calling setOpen, then dispatches
permission-shield-opened outside the state updater only when opening. Keep
stopPropagation and the existing event detail unchanged.

---

Nitpick comments:
In `@src/custom/permissions.tsx`:
- Around line 244-254: Update the copyKeyId handler to return immediately when
key.id is absent or empty, before invoking navigator.clipboard.writeText or
updating copied state. Preserve the existing copy and confirmation behavior for
keys with a valid id.
- Line 5: Update the card styling in the permissions component to use the
Sistent semantic palette token, such as theme.palette.background.card or
theme.palette.background.surfaces, instead of the raw MUI
theme.palette.background.paper value; preserve the existing card layout and
styling behavior.
🪄 Autofix

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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 6cbfa91f-605f-4cdb-8f15-f8bc5b956a42

📥 Commits

Reviewing files that changed from the base of the PR and between e1cdbc0 and c621514.

📒 Files selected for processing (2)
  • src/custom/permissions.tsx
  • src/index.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/index.tsx

Comment on lines +552 to +563
const handleToggle = (e: React.MouseEvent) => {
e.stopPropagation();
setOpen((prev) => {
const next = !prev;
if (next) {
window.dispatchEvent(
new CustomEvent('permission-shield-opened', { detail: { id: uniqueId } })
);
}
return next;
});
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Move the event dispatch out of the state updater.

React can invoke the updater more than once. The permission-shield-opened event then fires more than once for one toggle. Compute the next value first, then dispatch outside the setter.

🐛 Proposed fix
   const handleToggle = (e: React.MouseEvent) => {
     e.stopPropagation();
-    setOpen((prev) => {
-      const next = !prev;
-      if (next) {
-        window.dispatchEvent(
-          new CustomEvent('permission-shield-opened', { detail: { id: uniqueId } })
-        );
-      }
-      return next;
-    });
+    const next = !open;
+    setOpen(next);
+    if (next) {
+      window.dispatchEvent(
+        new CustomEvent('permission-shield-opened', { detail: { id: uniqueId } })
+      );
+    }
   };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const handleToggle = (e: React.MouseEvent) => {
e.stopPropagation();
setOpen((prev) => {
const next = !prev;
if (next) {
window.dispatchEvent(
new CustomEvent('permission-shield-opened', { detail: { id: uniqueId } })
);
}
return next;
});
};
const handleToggle = (e: React.MouseEvent) => {
e.stopPropagation();
const next = !open;
setOpen(next);
if (next) {
window.dispatchEvent(
new CustomEvent('permission-shield-opened', { detail: { id: uniqueId } })
);
}
};
🧰 Tools
🪛 React Doctor (0.9.3)

[error] 557-557: This side-effecting call runs inside a state updater, which React may invoke more than once. Move it outside the setter after computing the next state.

React may replay a state updater, so callbacks, analytics, and persistence inside it can run more than once. Compute state purely, then perform the side effect outside the setter.

(no-side-effect-in-state-updater-function)

🤖 Prompt for 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.

In `@src/custom/permissions.tsx` around lines 552 - 563, Update handleToggle so it
computes the next open state from the current state before calling setOpen, then
dispatches permission-shield-opened outside the state updater only when opening.
Keep stopPropagation and the existing event detail unchanged.

Source: Linters/SAST tools

@hiyach28

hiyach28 commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Really liked the direction of this refactor. one thing I was curious about while reading it: pages in Meshery still perform their own useHasPermission(...) checks before rendering the error state. so will we continue with it to stay as the current pattern, or do you think it could eventually be abstracted further? that was one of the things I saw earlier, so wanted to understand/ learn from how you think about the long-term architectures.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants