Skip to content

feat: Playbook permissions Inbound & Outbound#2974

Merged
moshloop merged 15 commits into
mainfrom
feat/playbook-permission-page
Apr 3, 2026
Merged

feat: Playbook permissions Inbound & Outbound#2974
moshloop merged 15 commits into
mainfrom
feat/playbook-permission-page

Conversation

@adityathebe

@adityathebe adityathebe commented Apr 1, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features

    • Playbook permissions modal with separate Inbound ("who-can-run") and Outbound ("what-it-can-do") views
    • "Permissions" option added to playbook menu
    • Connection lookup by name/namespace for link resolution
  • Improvements

    • Richer permissions display via a dedicated resource cell and configurable table columns
    • Confirmation dialogs and modals surface loading states and improved visibility/behavior
  • Documentation

    • Guidance updated: avoid running build while dev server is running; run typecheck instead
  • Style

    • Spacing, padding, and layout refinements across multiple UI components

@vercel

vercel Bot commented Apr 1, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
aws-preview Ready Ready Preview Apr 3, 2026 8:56am
flanksource-ui Ready Ready Preview Apr 3, 2026 8:56am

Request Review

@coderabbitai

coderabbitai Bot commented Apr 1, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

Adds inbound/outbound playbook permission queries, introduces PermissionResourceCell and table/view changes, a PlaybookPermissionsModal with tabbed permission views and cache invalidation, connection lookup enhancements, multiple UI spacing/style tweaks, and refactors the confirmation dialog/modal implementation.

Changes

Cohort / File(s) Summary
Permissions API & Services
src/api/services/permissions.ts
Extended FetchPermissionsInput with playbookName?, playbookNamespace?, direction?. fetchPermissions routes inbound playbook queries to /rpc/permissions_for_obj_selector when direction === "inbound" and playbookName present; otherwise uses /permissions_summary.
Permissions UI Components
src/components/Permissions/PermissionResourceCell.tsx, src/components/Permissions/PermissionsTable.tsx, src/components/Permissions/PermissionsView.tsx
Added PermissionResourceCell and replaced inline Resource cell renderer with it. Added hideSubjectColumn prop to table/view, adjusted hidden-columns logic and table key to trigger remounts, updated column widths, and added query error -> toast handling in view.
Playbook Permissions UX
src/components/Playbooks/Settings/PlaybookPermissionsModal.tsx, src/components/Playbooks/Settings/PlaybookCardMenu.tsx, src/components/Playbooks/Settings/PlaybookSpecCard.tsx, src/components/Playbooks/Settings/PlaybookSpecFormModal.tsx
New PlaybookPermissionsModal with Inbound/Outbound tabs, memoized request keys and cache invalidation on open/tab switch. Added "Permissions" menu item and manage-permissions flow; removed permissions tab from PlaybookSpecFormModal and simplified to always render form.
Connection lookup & Links
src/api/services/connections.ts, src/components/Connections/ConnectionLink.tsx, src/components/Connections/ConnectionForm.tsx, src/components/Connections/ConnectionFormModal.tsx
Added getConnectionByNamespaceName. ConnectionLink accepts optional connectionId, connectionName, connectionNamespace; queries by ID or by name/namespace and only renders link when an ID is resolved. Adjusted form/modal padding and removed connectionType prop from ConnectionSpecEditor.
Dialogs / Modals
src/ui/AlertDialog/ConfirmationPromptDialog.tsx, src/components/Playbooks/Runs/ApprovePlaybookRunModal.tsx, src/components/Playbooks/Runs/CancelPlaybookRunModal.tsx
Reimplemented confirmation dialog using @flanksource-ui/components/ui/dialog primitives, removed ComponentProps<typeof Dialog> prop forwarding and added className?. Consumers now use isOpen and pass isLoading for loading state; confirm button labels reflect loading.
UI Styling & Layout
src/components/ui/card.tsx, src/ui/Menu/index.tsx, src/ui/Tabs/FlatTabs.tsx, src/components/Playbooks/Settings/PlaybookSpecsList.tsx, src/components/Users/UserList.tsx, src/pages/playbooks/PlaybooksList.tsx
Adjusted card rounding/padding, menu item padding, tab spacing/button styles (added contentClassName prop and default), and reduced gaps/paddings in several list and menu components.
Table/Form docs & Misc
AGENTS.md, src/pages/audit-report/components/View/ViewTableFilterForm.tsx
AGENTS.md: clarified to avoid running npm run build while dev server is running and recommend npm run typecheck. Added JSDoc documenting filterFields usage in ViewTableFilterForm.

Sequence Diagram(s)

sequenceDiagram
  participant UI as PlaybookPermissionsModal (UI)
  participant Q as React Query
  participant API as permissions service (fetchPermissions)
  participant Server as Backend (permissions endpoints)

  UI->>Q: open modal / switch tab (inbound/outbound)
  Q->>API: fetchPermissions(input with direction/playbookName or subject)
  API->>Server: GET /rpc/permissions_for_obj_selector (inbound w/playbookName) or /permissions_summary (others)
  Server-->>API: permissions payload
  API-->>Q: resolve permissions data
  Q-->>UI: render PermissionsView -> PermissionsTable -> PermissionResourceCell
Loading

Possibly related PRs

Suggested reviewers

  • moshloop
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: Playbook permissions Inbound & Outbound' clearly summarizes the main changes: adding playbook permission management with both inbound and outbound directions.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/playbook-permission-page
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch feat/playbook-permission-page

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 and usage tips.

@adityathebe adityathebe force-pushed the feat/playbook-permission-page branch from 84c9005 to e461b5d Compare April 1, 2026 19:54
@adityathebe adityathebe force-pushed the feat/playbook-permission-page branch from d97854a to dd57355 Compare April 2, 2026 07:59
@adityathebe adityathebe marked this pull request as ready for review April 2, 2026 08:13
@adityathebe adityathebe linked an issue Apr 2, 2026 that may be closed by this pull request
@adityathebe adityathebe force-pushed the feat/playbook-permission-page branch from dd57355 to d2579cb Compare April 3, 2026 07:54

@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: 5

Caution

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

⚠️ Outside diff range comments (2)
src/ui/AlertDialog/ConfirmationPromptDialog.tsx (1)

14-26: ⚠️ Potential issue | 🟠 Major

Preserve the dialog pass-through props.

This exported prop type no longer forwards the underlying Dialog props, which unexpectedly narrows both ConfirmationPromptDialog and src/ui/Buttons/DeleteButton.tsx, where the remaining props are still forwarded into this component. That is a breaking API change unrelated to the markup refactor.

Suggested change
-export type ConfirmationPromptDialogProps = {
+export type ConfirmationPromptDialogProps = Omit<
+  React.ComponentProps<typeof Dialog>,
+  "open" | "onOpenChange" | "className"
+> & {
   isOpen: boolean;
   title: string;
   description: React.ReactNode;
   onClose: () => void;
   onConfirm: () => void;
@@
   isLoading?: boolean;
   confirmationStyle?: "delete" | "approve";
   error?: unknown;
   className?: string;
 };
@@
 export function ConfirmationPromptDialog({
   title,
   confirmationStyle = "delete",
   description,
   isOpen,
@@
   closeLabel = "Cancel",
   isLoading = false,
   error,
-  className
+  className,
+  ...dialogProps
 }: ConfirmationPromptDialogProps) {
   return (
     <Dialog
+      {...dialogProps}
       open={isOpen}
       onOpenChange={(open) => {
         if (!open) {
           onClose();
         }

Also applies to: 28-50

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/ui/AlertDialog/ConfirmationPromptDialog.tsx` around lines 14 - 26, The
exported ConfirmationPromptDialogProps type no longer forwards the underlying
Dialog props which breaks callers that spread extra props (e.g., DeleteButton
forwarding into ConfirmationPromptDialog); fix by extending the Dialog's prop
type (e.g., make ConfirmationPromptDialogProps extend
React.ComponentProps<typeof Dialog> or DialogProps) so all pass-through props
are preserved, update the ConfirmationPromptDialog component signature to use
the extended type and ensure any explicit prop names remain listed as
overrides/optional.
src/components/Playbooks/Settings/PlaybookSpecCard.tsx (1)

56-69: ⚠️ Potential issue | 🟠 Major

Disable repeated deletes while the mutation is running.

The confirmation dialog at line 152-160 does not receive a loading state from the deletePlaybook mutation. This leaves the confirm button fully clickable during the deletion request, allowing double clicks to trigger multiple delete operations and produce conflicting error toasts.

The useMutation hook at line 56 only destructures mutate, but @tanstack/react-query v4 provides an isLoading state that must be threaded to the dialog's isLoading prop (supported by ConfirmationPromptDialog at line 22 of the component definition).

Update the mutation destructuring to include the loading flag and pass it to the dialog:

Suggested fix
-  const { mutate: deletePlaybook } = useMutation({
+  const { mutate: deletePlaybook, isLoading: isDeleting } = useMutation({
     mutationFn: async (id: string) => {
       const res = await deletePlaybookSpec(id);
       return res;
     },
     onSuccess: () => {
       toastSuccess("Playbook Spec deleted successfully");
       setIsDeleteConfirmOpen(false);
       refetch();
     },
     onError: (err: Error) => {
       toastError("Unable to delete playbook spec: " + err.message);
     }
   });
       <ConfirmationPromptDialog
         isOpen={isDeleteConfirmOpen}
         title="Delete Playbook"
         description={`Are you sure you want to delete ${playbook.title || playbook.name}?`}
         onClose={() => setIsDeleteConfirmOpen(false)}
         onConfirm={() => deletePlaybook(playbook.id)}
         confirmationStyle="delete"
+        isLoading={isDeleting}
-        yesLabel="Delete"
+        yesLabel={isDeleting ? "Deleting..." : "Delete"}
       />

Also applies to: 152-160

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Playbooks/Settings/PlaybookSpecCard.tsx` around lines 56 - 69,
The delete mutation currently only destructures mutate from useMutation, so the
ConfirmationPromptDialog never receives the mutation loading state and the
confirm button remains clickable; change the hook destructuring to pull out
isLoading (e.g. const { mutate: deletePlaybook, isLoading: isDeleting } =
useMutation(...)), then pass that flag into the ConfirmationPromptDialog's
isLoading prop where the dialog is rendered (so the confirm button is disabled
while deletePlaybookSpec runs) and keep existing onSuccess/onError behavior
(toastSuccess, toastError, setIsDeleteConfirmOpen, refetch).
🧹 Nitpick comments (1)
src/components/Playbooks/Settings/PlaybookCardMenu.tsx (1)

10-18: Don't show a dead Permissions action.

onManagePermissions is optional, but the menu row is always rendered and defaults to a no-op. If any caller omits that callback, users get a clickable item that does nothing.

Suggested change
 type PlaybookCardMenuDropdownProps = {
   onDeletePlaybook?: () => void;
   onEditPlaybook?: () => void;
   onManagePermissions?: () => void;
   onHistory?: () => void;
 };

 export default function PlaybookCardMenuDropdown({
   onDeletePlaybook = () => {},
   onEditPlaybook = () => {},
-  onManagePermissions = () => {}
+  onManagePermissions
 }: PlaybookCardMenuDropdownProps) {
   return (
     <Menu>
@@
-        <MenuItem
-          as="div"
-          className="flex w-full cursor-pointer items-center gap-2 px-3 py-1.5 text-sm leading-5 text-gray-700 hover:bg-gray-200"
-          onClick={() => {
-            onManagePermissions();
-          }}
-        >
-          <>
-            <MdSecurity
-              className="border-l-1 border-0 border-gray-200 text-gray-600"
-              size={16}
-            />
-            <span>Permissions</span>
-          </>
-        </MenuItem>
+        {onManagePermissions ? (
+          <MenuItem
+            as="div"
+            className="flex w-full cursor-pointer items-center gap-2 px-3 py-1.5 text-sm leading-5 text-gray-700 hover:bg-gray-200"
+            onClick={onManagePermissions}
+          >
+            <>
+              <MdSecurity
+                className="border-l-1 border-0 border-gray-200 text-gray-600"
+                size={16}
+              />
+              <span>Permissions</span>
+            </>
+          </MenuItem>
+        ) : null}

Also applies to: 55-69

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Playbooks/Settings/PlaybookCardMenu.tsx` around lines 10 - 18,
The Permissions menu item is always rendered with a no-op when
onManagePermissions is omitted, producing a dead clickable row; update
PlaybookCardMenuDropdown to only render the Permissions menu entry when the
onManagePermissions prop is provided (i.e., check if onManagePermissions !==
undefined before rendering the menu row and its Click handler), and apply the
same conditional rendering pattern for other optional callbacks such as
onHistory so no menu item appears unless its handler is passed in.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/api/services/permissions.ts`:
- Around line 57-59: The current branch incorrectly maps playbookId into the
subject filter (using subject and subject_type), which breaks direct playbook_id
queries; in the block that checks if (playbookId && !subject) update the filters
to push a playbook_id equality filter (e.g., playbook_id=eq.${playbookId})
instead of subject/subject_type, leaving the existing subject-based path
unchanged so outbound callers that provide subject/subject_type still work and
RPC inbound flow continues to bypass this branch.

In `@src/components/Permissions/PermissionResourceCell.tsx`:
- Around line 191-202: The current early return in PermissionResourceCell when
PermissionsSummary.object is truthy causes every concrete resource to be treated
as generic text and can yield blank labels because
permissionObjectList.find(...) may return undefined; update
PermissionResourceCell to first check for and render the concrete-object case
(the renderer that shows links/icons for actual resources) before falling back
to a safe label lookup, and replace use of permissionObjectList.find(...) with
an explicit label map keyed by PermissionGlobalObject (e.g., a const
OBJECT_LABELS: Record<PermissionGlobalObject, string>) to guarantee a fallback
label for values like "playbook" and "component"; ensure PermissionErrorDisplay
is still rendered and remove the early return so the detailed renderer (the
block currently after the return) can execute when appropriate.

In `@src/components/ui/card.tsx`:
- Line 12: The Card primitive has been modified with project-specific classes
("rounded-sm border bg-card p-1 text-card-foreground"); revert the Card
component back to the upstream/default class names (remove those
spacing/radius/padding overrides) and instead create or update a wrapper
component (e.g., PermissionCard) that composes Card and applies the desired
"rounded-sm", "border", "p-1", etc. Move all variant/custom classes currently
added in Card (also present at the other modified spots) into that wrapper so
the original Card primitive stays upstream-consistent.
- Line 12: The Card component's root class list currently includes a global
padding "p-1" which causes unintended spacing regressions; remove "p-1" from the
root class string/array in the Card component (the exported Card element in
src/components/ui/card.tsx) so the container does not inject default padding,
leaving padding to be applied by consumers that need it.

In `@src/ui/AlertDialog/ConfirmationPromptDialog.tsx`:
- Around line 111-126: The confirm button currently still invokes onConfirm
while isLoading is true; update the ConfirmationPromptDialog confirm button (the
element with data-testid={`confirm-button-${yesLabel}`} and the
onClick={onConfirm}) to prevent duplicate confirms by disabling it when
isLoading: add the disabled attribute (disabled={isLoading}) and/or guard the
onClick handler so it no-ops when isLoading is true, and ensure styling reflects
disabled state (e.g., keep clsx logic but include a disabled class or rely on
native disabled) so rapid clicks cannot trigger duplicate mutations.

---

Outside diff comments:
In `@src/components/Playbooks/Settings/PlaybookSpecCard.tsx`:
- Around line 56-69: The delete mutation currently only destructures mutate from
useMutation, so the ConfirmationPromptDialog never receives the mutation loading
state and the confirm button remains clickable; change the hook destructuring to
pull out isLoading (e.g. const { mutate: deletePlaybook, isLoading: isDeleting }
= useMutation(...)), then pass that flag into the ConfirmationPromptDialog's
isLoading prop where the dialog is rendered (so the confirm button is disabled
while deletePlaybookSpec runs) and keep existing onSuccess/onError behavior
(toastSuccess, toastError, setIsDeleteConfirmOpen, refetch).

In `@src/ui/AlertDialog/ConfirmationPromptDialog.tsx`:
- Around line 14-26: The exported ConfirmationPromptDialogProps type no longer
forwards the underlying Dialog props which breaks callers that spread extra
props (e.g., DeleteButton forwarding into ConfirmationPromptDialog); fix by
extending the Dialog's prop type (e.g., make ConfirmationPromptDialogProps
extend React.ComponentProps<typeof Dialog> or DialogProps) so all pass-through
props are preserved, update the ConfirmationPromptDialog component signature to
use the extended type and ensure any explicit prop names remain listed as
overrides/optional.

---

Nitpick comments:
In `@src/components/Playbooks/Settings/PlaybookCardMenu.tsx`:
- Around line 10-18: The Permissions menu item is always rendered with a no-op
when onManagePermissions is omitted, producing a dead clickable row; update
PlaybookCardMenuDropdown to only render the Permissions menu entry when the
onManagePermissions prop is provided (i.e., check if onManagePermissions !==
undefined before rendering the menu row and its Click handler), and apply the
same conditional rendering pattern for other optional callbacks such as
onHistory so no menu item appears unless its handler is passed in.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7fb96171-ad6e-43c9-9309-c1e52ffc8c90

📥 Commits

Reviewing files that changed from the base of the PR and between 6540fdb and d2579cb.

📒 Files selected for processing (21)
  • AGENTS.md
  • src/api/services/permissions.ts
  • src/components/Connections/ConnectionForm.tsx
  • src/components/Connections/ConnectionFormModal.tsx
  • src/components/Permissions/PermissionResourceCell.tsx
  • src/components/Permissions/PermissionsTable.tsx
  • src/components/Permissions/PermissionsView.tsx
  • src/components/Playbooks/Runs/ApprovePlaybookRunModal.tsx
  • src/components/Playbooks/Runs/CancelPlaybookRunModal.tsx
  • src/components/Playbooks/Settings/PlaybookCardMenu.tsx
  • src/components/Playbooks/Settings/PlaybookPermissionsModal.tsx
  • src/components/Playbooks/Settings/PlaybookSpecCard.tsx
  • src/components/Playbooks/Settings/PlaybookSpecFormModal.tsx
  • src/components/Playbooks/Settings/PlaybookSpecsList.tsx
  • src/components/Users/UserList.tsx
  • src/components/ui/card.tsx
  • src/pages/audit-report/components/View/ViewTableFilterForm.tsx
  • src/pages/playbooks/PlaybooksList.tsx
  • src/ui/AlertDialog/ConfirmationPromptDialog.tsx
  • src/ui/Menu/index.tsx
  • src/ui/Tabs/FlatTabs.tsx

Comment thread src/api/services/permissions.ts Outdated
Comment thread src/components/Permissions/PermissionResourceCell.tsx
Comment thread src/components/ui/card.tsx
Comment thread src/ui/AlertDialog/ConfirmationPromptDialog.tsx

@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

♻️ Duplicate comments (1)
src/components/Permissions/PermissionResourceCell.tsx (1)

190-201: ⚠️ Potential issue | 🟡 Minor

Missing fallback when permissionObjectList.find() returns undefined.

If permission.object has a value not present in permissionObjectList (e.g., a new permission type), the .find() returns undefined and the cell renders an empty <span>. Consider providing a fallback to display the raw object value.

Proposed fix
         <span>
-          {permissionObjectList.find((o) => o.value === object)?.label}
+          {permissionObjectList.find((o) => o.value === object)?.label ??
+            object}
         </span>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Permissions/PermissionResourceCell.tsx` around lines 190 -
201, The cell currently calls permissionObjectList.find((o) => o.value ===
object)?.label which can be undefined; update the rendering in
PermissionResourceCell (the branch where object is truthy) to fall back to the
raw object value when find returns undefined by using the found label if present
otherwise the object string (e.g., compute a displayName from
permissionObjectList.find(...) and render displayName || object) so the span
never renders empty; keep PermissionErrorDisplay as-is.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/api/services/connections.ts`:
- Around line 19-34: The query-building in getConnectionByNamespaceName
interpolates raw user input into filters causing malformed queries; update the
filter construction to URL-encode name and namespace (e.g., via
encodeURIComponent) before embedding them into the filter strings (or build the
whole query with URLSearchParams) so the final call to IncidentCommander.get
uses encoded values for `name` and `namespace`; ensure you apply encoding to
both the `name` parameter and the optional `namespace` when pushing into
`filters` and keep the existing select portion unchanged.

In `@src/components/Connections/ConnectionLink.tsx`:
- Around line 58-60: The branch in ConnectionLink that returns <ConnectionIcon
showLabel connection={connectionData} /> when connectionData.id is falsy
violates ConnectionIcon's prop requirement (it expects connection:
Pick<Connection, "type" | "name" | "id">). Fix by either (A) changing
ConnectionLink to render a safe fallback when id is missing (e.g., render the
connection name/type text or a simple label instead of using ConnectionIcon) by
checking connectionData.id before passing to ConnectionIcon, or (B) update
ConnectionIcon's props to accept an optional id (make id?: string in its
connection prop and handle missing id inside ConnectionIcon). Reference the
ConnectionLink component branch that returns ConnectionIcon and the
ConnectionIcon component type signature to locate the code.

---

Duplicate comments:
In `@src/components/Permissions/PermissionResourceCell.tsx`:
- Around line 190-201: The cell currently calls permissionObjectList.find((o) =>
o.value === object)?.label which can be undefined; update the rendering in
PermissionResourceCell (the branch where object is truthy) to fall back to the
raw object value when find returns undefined by using the found label if present
otherwise the object string (e.g., compute a displayName from
permissionObjectList.find(...) and render displayName || object) so the span
never renders empty; keep PermissionErrorDisplay as-is.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 803a27d1-214e-4405-8baf-cc51eea8c3e7

📥 Commits

Reviewing files that changed from the base of the PR and between d2579cb and 84e540b.

📒 Files selected for processing (3)
  • src/api/services/connections.ts
  • src/components/Connections/ConnectionLink.tsx
  • src/components/Permissions/PermissionResourceCell.tsx

Comment thread src/api/services/connections.ts
Comment thread src/components/Connections/ConnectionLink.tsx
@CLAassistant

CLAassistant commented Apr 3, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@adityathebe adityathebe force-pushed the feat/playbook-permission-page branch from ae2f3ee to f104fed Compare April 3, 2026 08:48
@adityathebe adityathebe requested a review from moshloop April 3, 2026 09:08
@adityathebe adityathebe changed the title feat: Playbook permissions feat: Playbook permissions Inbound & Outbound Apr 3, 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.

Caution

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

⚠️ Outside diff range comments (1)
src/components/Connections/ConnectionLink.tsx (1)

45-49: ⚠️ Potential issue | 🟠 Major

Guard the loader by fetch intent to avoid a stuck skeleton.

When the query is disabled by the condition at line 45, React Query v4 reports isLoading=true without cache (status is 'loading' but isFetching=false). This causes line 48-49 to return <TextSkeletonLoader /> indefinitely, skipping the data rendering at line 52.

Use isInitialLoading instead of isLoading and guard with the fetch condition to show the loader only during active fetches:

Proposed fix
 export default function ConnectionLink({
   connection,
   connectionId,
   connectionName,
   connectionNamespace
 }: ConnectionLinkProps) {
+  const shouldFetchConnection =
+    connection === undefined && (!!connectionId || !!connectionName);
+
-  const { isLoading, data } = useQuery({
+  const { isInitialLoading, data } = useQuery({
     queryKey: [
       "connections",
       connectionId,
       connectionName,
       connectionNamespace
     ],
     queryFn: () => {
       if (connectionId) {
         return getConnectionByID(connectionId);
       }

       if (connectionName) {
         return getConnectionByNamespaceName(
           connectionName,
           connectionNamespace
         );
       }

       return Promise.resolve(null);
     },
-    enabled: connection === undefined && (!!connectionId || !!connectionName)
+    enabled: shouldFetchConnection
   });
 
-  if (isLoading) {
+  if (shouldFetchConnection && isInitialLoading) {
     return <TextSkeletonLoader />;
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Connections/ConnectionLink.tsx` around lines 45 - 49, The
loader is shown even when the query is disabled because React Query's isLoading
can be true for disabled queries; update the ConnectionLink component to use
isInitialLoading instead of isLoading and also check the query-enabled condition
(the same expression used for the query's enabled option: enabled: connection
=== undefined && (!!connectionId || !!connectionName)) so the TextSkeletonLoader
is returned only when the fetch is actively starting; locate the query hook and
replace the isLoading guard with a combined check like "queryEnabled &&
isInitialLoading" referencing the query's enabled condition and the
isInitialLoading variable.
🧹 Nitpick comments (1)
src/components/Playbooks/Settings/PlaybookCardMenu.tsx (1)

29-54: Minor styling inconsistency between menu items.

The Edit item uses IconButton wrapper with mr-2 for spacing, while Permissions and Delete items use gap-2 on the parent MenuItem. Consider aligning the approach for consistency.

♻️ Option to align Edit item with other items
         <MenuItem
           as="div"
-          className="flex w-full cursor-pointer items-center px-3 py-1.5 text-sm leading-5 text-gray-700 hover:bg-gray-200"
+          className="flex w-full cursor-pointer items-center gap-2 px-3 py-1.5 text-sm leading-5 text-gray-700 hover:bg-gray-200"
           onClick={() => {
             onEditPlaybook();
           }}
         >
           <>
-            <IconButton
-              className="z-5 mr-2 bg-transparent group-hover:inline-block"
-              ovalProps={{
-                stroke: "blue",
-                height: "18px",
-                width: "18px",
-                fill: "transparent"
-              }}
-              icon={
-                <MdEdit
-                  className="border-l-1 border-0 border-gray-200 text-gray-600"
-                  size={16}
-                />
-              }
-            />
+            <MdEdit
+              className="border-l-1 border-0 border-gray-200 text-gray-600"
+              size={16}
+            />
             <span>Edit</span>
           </>
         </MenuItem>

Also applies to: 55-69, 70-84

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Playbooks/Settings/PlaybookCardMenu.tsx` around lines 29 - 54,
The Edit menu item's spacing differs from the other items: it uses an IconButton
with className "mr-2" while the Permissions and Delete MenuItem entries use
"gap-2" on the parent. Update the Edit MenuItem (the JSX block containing
MenuItem, IconButton and onEditPlaybook) to match the others by removing the
IconButton's "mr-2" spacing and applying "gap-2" to the MenuItem container (or
vice-versa across all menu items)—ensure spacing is consistent across MenuItem
instances for Edit, Permissions and Delete.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/components/Connections/ConnectionLink.tsx`:
- Around line 45-49: The loader is shown even when the query is disabled because
React Query's isLoading can be true for disabled queries; update the
ConnectionLink component to use isInitialLoading instead of isLoading and also
check the query-enabled condition (the same expression used for the query's
enabled option: enabled: connection === undefined && (!!connectionId ||
!!connectionName)) so the TextSkeletonLoader is returned only when the fetch is
actively starting; locate the query hook and replace the isLoading guard with a
combined check like "queryEnabled && isInitialLoading" referencing the query's
enabled condition and the isInitialLoading variable.

---

Nitpick comments:
In `@src/components/Playbooks/Settings/PlaybookCardMenu.tsx`:
- Around line 29-54: The Edit menu item's spacing differs from the other items:
it uses an IconButton with className "mr-2" while the Permissions and Delete
MenuItem entries use "gap-2" on the parent. Update the Edit MenuItem (the JSX
block containing MenuItem, IconButton and onEditPlaybook) to match the others by
removing the IconButton's "mr-2" spacing and applying "gap-2" to the MenuItem
container (or vice-versa across all menu items)—ensure spacing is consistent
across MenuItem instances for Edit, Permissions and Delete.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 832d72e8-da6b-441e-98fa-5463e1b047fc

📥 Commits

Reviewing files that changed from the base of the PR and between 84e540b and f104fed.

📒 Files selected for processing (23)
  • AGENTS.md
  • src/api/services/connections.ts
  • src/api/services/permissions.ts
  • src/components/Connections/ConnectionForm.tsx
  • src/components/Connections/ConnectionFormModal.tsx
  • src/components/Connections/ConnectionLink.tsx
  • src/components/Permissions/PermissionResourceCell.tsx
  • src/components/Permissions/PermissionsTable.tsx
  • src/components/Permissions/PermissionsView.tsx
  • src/components/Playbooks/Runs/ApprovePlaybookRunModal.tsx
  • src/components/Playbooks/Runs/CancelPlaybookRunModal.tsx
  • src/components/Playbooks/Settings/PlaybookCardMenu.tsx
  • src/components/Playbooks/Settings/PlaybookPermissionsModal.tsx
  • src/components/Playbooks/Settings/PlaybookSpecCard.tsx
  • src/components/Playbooks/Settings/PlaybookSpecFormModal.tsx
  • src/components/Playbooks/Settings/PlaybookSpecsList.tsx
  • src/components/Users/UserList.tsx
  • src/components/ui/card.tsx
  • src/pages/audit-report/components/View/ViewTableFilterForm.tsx
  • src/pages/playbooks/PlaybooksList.tsx
  • src/ui/AlertDialog/ConfirmationPromptDialog.tsx
  • src/ui/Menu/index.tsx
  • src/ui/Tabs/FlatTabs.tsx
✅ Files skipped from review due to trivial changes (9)
  • AGENTS.md
  • src/pages/playbooks/PlaybooksList.tsx
  • src/components/Connections/ConnectionForm.tsx
  • src/components/Playbooks/Settings/PlaybookSpecsList.tsx
  • src/components/ui/card.tsx
  • src/pages/audit-report/components/View/ViewTableFilterForm.tsx
  • src/components/Users/UserList.tsx
  • src/ui/Menu/index.tsx
  • src/components/Playbooks/Settings/PlaybookSpecCard.tsx
🚧 Files skipped from review as they are similar to previous changes (11)
  • src/components/Playbooks/Runs/ApprovePlaybookRunModal.tsx
  • src/components/Playbooks/Runs/CancelPlaybookRunModal.tsx
  • src/components/Connections/ConnectionFormModal.tsx
  • src/api/services/connections.ts
  • src/components/Playbooks/Settings/PlaybookSpecFormModal.tsx
  • src/api/services/permissions.ts
  • src/ui/Tabs/FlatTabs.tsx
  • src/components/Permissions/PermissionsTable.tsx
  • src/components/Permissions/PermissionsView.tsx
  • src/components/Playbooks/Settings/PlaybookPermissionsModal.tsx
  • src/components/Permissions/PermissionResourceCell.tsx

@moshloop moshloop merged commit a3c4833 into main Apr 3, 2026
14 of 16 checks passed
@moshloop moshloop deleted the feat/playbook-permission-page branch April 3, 2026 11:21
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.

Enhance Playbook Permission Page

3 participants