Skip to content

feat: Role and Permission rows open update dialog#4232

Merged
ogzhanolguncu merged 10 commits intomainfrom
eng-1850-make-role-click-open-edit-modal-for-better-ux
Nov 6, 2025
Merged

feat: Role and Permission rows open update dialog#4232
ogzhanolguncu merged 10 commits intomainfrom
eng-1850-make-role-click-open-edit-modal-for-better-ux

Conversation

@MichaelUnkey
Copy link
Collaborator

What does this PR do?

Fixes # (issue)
Eng 1850

If there is not an issue for this, please create one first. This is used to tracking purposes and also helps us understand why this PR exists

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • Chore (refactoring code, technical debt, workflow improvements)
  • Enhancement (small improvements)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How should this be tested?

  • Role and Permissions table rows open update dialog when clicked.
  • Checkbox functionality still works as it should

Checklist

Required

  • Filled out the "How to test" section in this PR
  • Read Contributing Guide
  • Self-reviewed my own code
  • Commented on my code in hard-to-understand areas
  • Ran pnpm build
  • Ran pnpm fmt
  • Ran make fmt on /go directory
  • Checked for warnings, there are none
  • Removed all console.logs
  • Merged the latest changes from main onto my branch with git pull origin main
  • My changes don't cause any responsiveness issues

Appreciated

  • If a UI change was made: Added a screen recording or screenshots to this PR
  • Updated the Unkey Docs if changes were necessary

@linear
Copy link

linear bot commented Nov 4, 2025

@changeset-bot
Copy link

changeset-bot bot commented Nov 4, 2025

⚠️ No Changeset found

Latest commit: 3b705d0

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@vercel
Copy link

vercel bot commented Nov 4, 2025

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

Project Deployment Preview Comments Updated (UTC)
dashboard Ready Ready Preview Comment Nov 5, 2025 9:40pm
1 Skipped Deployment
Project Deployment Preview Comments Updated (UTC)
engineering Ignored Ignored Preview Nov 5, 2025 9:40pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 4, 2025

📝 Walkthrough

Walkthrough

Adds persistent EditPermission/EditRole modals to permissions and roles list components, prevents row-clicks via Checkbox stopPropagation, tweaks icon/Tag cursor and click behavior, and wraps VirtualTable outputs in fragments while preserving skeleton, loading, paging, and selection behavior. (≤50 words)

Changes

Cohort / File(s) Summary
Authorization — Permissions list
apps/dashboard/app/(app)/[workspaceSlug]/authorization/permissions/components/table/permissions-list.tsx
Import EditPermission; move icon cursor/pointer behavior; add onClick stopPropagation on Checkbox; wrap VirtualTable in a fragment; render persistent EditPermission modal controlled by selected permission; keep skeleton/loading/paging/selection unchanged.
Authorization — Roles list
apps/dashboard/app/(app)/[workspaceSlug]/authorization/roles/components/table/roles-list.tsx
Import EditRole; adjust role icon/Tag cursor and click behavior; add e.stopPropagation() to Checkbox onClick; wrap VirtualTable in a fragment; render persistent EditRole modal when a role is selected; preserve skeleton/loading/pagination/state.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant ListComp as Authorization List
    participant Modal as EditModal

    User->>ListComp: Click icon or Checkbox
    activate ListComp
    ListComp->>ListComp: e.stopPropagation() for Checkbox
    ListComp->>ListComp: set selectedItem (role/permission)
    deactivate ListComp

    alt selectedItem present
        ListComp->>Modal: Render EditRole/EditPermission (isOpen)
        activate Modal
        User->>Modal: Edit & submit
        Modal->>ListComp: emit update / close
        deactivate Modal
        ListComp->>ListComp: clear selectedItem
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Focus areas:
    • permissions-list.tsx — confirm Checkbox stopPropagation, modal lifecycle placement, and fragment wrapping effect on table behavior.
    • roles-list.tsx — verify icon/Tag cursor and click behavior, Checkbox propagation prevention, and selectedRole-driven modal open/close.
    • Ensure skeleton/loading/pagination/state interactions remain unaffected after moving modal rendering.

Possibly related PRs

  • feat: rbac roles  #3297 — Adds/changes EditRole/EditPermission modals, checkbox stopPropagation, and fragment-wrapped VirtualTable in list components (strong overlap in components and UI flow).

Suggested labels

🕹️ oss.gg

Pre-merge checks and finishing touches

✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely summarizes the main feature: enabling role and permission table rows to open an update dialog when clicked.
Description check ✅ Passed The description covers the key required sections: issue reference (ENG-1850), type of change marked correctly, testing instructions provided, and most required checklist items completed.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch eng-1850-make-role-click-open-edit-modal-for-better-ux

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.

@github-actions
Copy link
Contributor

github-actions bot commented Nov 4, 2025

Thank you for following the naming conventions for pull request titles! 🙏

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 41f5c77 and ec65f00.

📒 Files selected for processing (2)
  • apps/dashboard/app/(app)/[workspaceSlug]/authorization/permissions/components/table/permissions-list.tsx (3 hunks)
  • apps/dashboard/app/(app)/[workspaceSlug]/authorization/roles/components/table/roles-list.tsx (3 hunks)
🧰 Additional context used
🧠 Learnings (7)
📓 Common learnings
Learnt from: AkshayBandi027
Repo: unkeyed/unkey PR: 2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In `authorization/roles/[roleId]/update-role.tsx`, the tag `role-${role.id}` is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
📚 Learning: 2025-01-07T19:55:33.055Z
Learnt from: chronark
Repo: unkeyed/unkey PR: 2792
File: apps/dashboard/app/(app)/settings/user/update-user-email.tsx:76-78
Timestamp: 2025-01-07T19:55:33.055Z
Learning: In the Unkey codebase, the Empty component can be used as a container for loading states, as demonstrated in the UpdateUserEmail component where it wraps the Loading component.

Applied to files:

  • apps/dashboard/app/(app)/[workspaceSlug]/authorization/permissions/components/table/permissions-list.tsx
  • apps/dashboard/app/(app)/[workspaceSlug]/authorization/roles/components/table/roles-list.tsx
📚 Learning: 2025-08-25T13:05:22.441Z
Learnt from: ogzhanolguncu
Repo: unkeyed/unkey PR: 3834
File: internal/ui/src/components/form/input.tsx:130-131
Timestamp: 2025-08-25T13:05:22.441Z
Learning: The Input component in internal/ui/src/components/form/input.tsx is designed to support interactive right icons (like X buttons for deletion) by enabling pointer events on the right icon container, allowing clicks to be handled by the icon rather than passed through to the input.

Applied to files:

  • apps/dashboard/app/(app)/[workspaceSlug]/authorization/permissions/components/table/permissions-list.tsx
  • apps/dashboard/app/(app)/[workspaceSlug]/authorization/roles/components/table/roles-list.tsx
📚 Learning: 2024-12-03T14:17:08.016Z
Learnt from: ogzhanolguncu
Repo: unkeyed/unkey PR: 2143
File: apps/dashboard/app/(app)/logs/logs-page.tsx:77-83
Timestamp: 2024-12-03T14:17:08.016Z
Learning: The `<LogsTable />` component already implements virtualization to handle large datasets efficiently.

Applied to files:

  • apps/dashboard/app/(app)/[workspaceSlug]/authorization/permissions/components/table/permissions-list.tsx
  • apps/dashboard/app/(app)/[workspaceSlug]/authorization/roles/components/table/roles-list.tsx
📚 Learning: 2024-10-08T15:33:04.290Z
Learnt from: AkshayBandi027
Repo: unkeyed/unkey PR: 2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In `authorization/roles/[roleId]/update-role.tsx`, the tag `role-${role.id}` is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.

Applied to files:

  • apps/dashboard/app/(app)/[workspaceSlug]/authorization/roles/components/table/roles-list.tsx
📚 Learning: 2025-06-19T11:48:05.070Z
Learnt from: ogzhanolguncu
Repo: unkeyed/unkey PR: 3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses `roleId` as the property name for the role identifier, not `id`. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.

Applied to files:

  • apps/dashboard/app/(app)/[workspaceSlug]/authorization/roles/components/table/roles-list.tsx
📚 Learning: 2024-12-03T14:07:45.173Z
Learnt from: ogzhanolguncu
Repo: unkeyed/unkey PR: 2143
File: apps/dashboard/components/ui/group-button.tsx:21-31
Timestamp: 2024-12-03T14:07:45.173Z
Learning: In the `ButtonGroup` component (`apps/dashboard/components/ui/group-button.tsx`), avoid suggesting the use of `role="group"` in ARIA attributes.

Applied to files:

  • apps/dashboard/app/(app)/[workspaceSlug]/authorization/roles/components/table/roles-list.tsx
🧬 Code graph analysis (2)
apps/dashboard/app/(app)/[workspaceSlug]/authorization/permissions/components/table/permissions-list.tsx (2)
internal/icons/src/icons/page-2.tsx (1)
  • Page2 (15-75)
apps/dashboard/components/virtual-table/index.tsx (1)
  • VirtualTable (38-407)
apps/dashboard/app/(app)/[workspaceSlug]/authorization/roles/components/table/roles-list.tsx (2)
internal/icons/src/icons/tag.tsx (1)
  • Tag (15-39)
apps/dashboard/components/virtual-table/index.tsx (1)
  • VirtualTable (38-407)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Test Dashboard / Test Dashboard
🔇 Additional comments (1)
apps/dashboard/app/(app)/[workspaceSlug]/authorization/permissions/components/table/permissions-list.tsx (1)

178-264: Modal wiring looks solid.

Line 185’s onRowClick hands the row item straight into setSelectedPermission, and Lines 178-265 wrap the VirtualTable with the EditPermission modal without disturbing the table config. Nice, clean integration.

…omponents/table/roles-list.tsx

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

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 (1)
apps/dashboard/app/(app)/[workspaceSlug]/authorization/roles/components/table/roles-list.tsx (1)

242-248: Simplify redundant isOpen prop.

Since you're already conditionally rendering EditRole based on selectedRole (line 242), the isOpen={!!selectedRole} prop is redundant. Consider simplifying to isOpen={true} or removing the prop entirely if EditRole defaults to open.

       {selectedRole && (
         <EditRole
           role={selectedRole}
-          isOpen={!!selectedRole}
+          isOpen={true}
           onClose={() => setSelectedRole(null)}
         />
       )}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ec65f00 and 93fb85d.

📒 Files selected for processing (1)
  • apps/dashboard/app/(app)/[workspaceSlug]/authorization/roles/components/table/roles-list.tsx (3 hunks)
🧰 Additional context used
🧠 Learnings (9)
📓 Common learnings
Learnt from: imeyer
Repo: unkeyed/unkey PR: 3755
File: .github/actions/setup-node/action.yaml:0-0
Timestamp: 2025-08-08T15:10:46.436Z
Learning: Repo: unkeyed/unkey — Preference: If imeyer comments “issue” on a PR thread, automatically open a thorough GitHub issue (Summary, Impact, Where, Observed vs Expected, Acceptance Criteria, Validation Plan, Out of Scope, References), include backlinks to the PR and comment, and assign to imeyer.
Learnt from: Flo4604
Repo: unkeyed/unkey PR: 4190
File: go/internal/services/keys/verifier.go:51-53
Timestamp: 2025-10-30T15:10:52.743Z
Learning: PR #4190 for unkeyed/unkey is focused solely on database schema and query changes for identity-based credits. It adds IdentityCredits and KeyCredits fields to structs and queries, but does not implement the priority enforcement logic in the usagelimiter. The logic implementation is intentionally deferred to a later PR in the stack.
📚 Learning: 2024-10-08T15:33:04.290Z
Learnt from: AkshayBandi027
Repo: unkeyed/unkey PR: 2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In `authorization/roles/[roleId]/update-role.tsx`, the tag `role-${role.id}` is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.

Applied to files:

  • apps/dashboard/app/(app)/[workspaceSlug]/authorization/roles/components/table/roles-list.tsx
📚 Learning: 2025-06-19T11:48:05.070Z
Learnt from: ogzhanolguncu
Repo: unkeyed/unkey PR: 3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses `roleId` as the property name for the role identifier, not `id`. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.

Applied to files:

  • apps/dashboard/app/(app)/[workspaceSlug]/authorization/roles/components/table/roles-list.tsx
📚 Learning: 2024-12-03T14:07:45.173Z
Learnt from: ogzhanolguncu
Repo: unkeyed/unkey PR: 2143
File: apps/dashboard/components/ui/group-button.tsx:21-31
Timestamp: 2024-12-03T14:07:45.173Z
Learning: In the `ButtonGroup` component (`apps/dashboard/components/ui/group-button.tsx`), avoid suggesting the use of `role="group"` in ARIA attributes.

Applied to files:

  • apps/dashboard/app/(app)/[workspaceSlug]/authorization/roles/components/table/roles-list.tsx
📚 Learning: 2025-04-22T17:33:28.162Z
Learnt from: MichaelUnkey
Repo: unkeyed/unkey PR: 3173
File: apps/docs/security/delete-protection.mdx:32-36
Timestamp: 2025-04-22T17:33:28.162Z
Learning: In the Unkey dashboard UI for delete protection, the button/link to initiate the process is labeled "Disable Delete Protection" while the confirmation button is labeled "Disable API Delete Protection". The documentation should maintain these different labels to match the actual UI.

Applied to files:

  • apps/dashboard/app/(app)/[workspaceSlug]/authorization/roles/components/table/roles-list.tsx
📚 Learning: 2025-04-22T17:34:04.438Z
Learnt from: MichaelUnkey
Repo: unkeyed/unkey PR: 3173
File: apps/docs/security/delete-protection.mdx:21-24
Timestamp: 2025-04-22T17:34:04.438Z
Learning: In the Unkey dashboard UI for enabling delete protection, the button/link to initiate the process is labeled "Enable Delete Protection" while the confirmation button is labeled "Enable API Delete Protection". The documentation should maintain these different labels to match the actual UI.

Applied to files:

  • apps/dashboard/app/(app)/[workspaceSlug]/authorization/roles/components/table/roles-list.tsx
📚 Learning: 2025-01-07T19:55:33.055Z
Learnt from: chronark
Repo: unkeyed/unkey PR: 2792
File: apps/dashboard/app/(app)/settings/user/update-user-email.tsx:76-78
Timestamp: 2025-01-07T19:55:33.055Z
Learning: In the Unkey codebase, the Empty component can be used as a container for loading states, as demonstrated in the UpdateUserEmail component where it wraps the Loading component.

Applied to files:

  • apps/dashboard/app/(app)/[workspaceSlug]/authorization/roles/components/table/roles-list.tsx
📚 Learning: 2025-08-25T13:05:22.441Z
Learnt from: ogzhanolguncu
Repo: unkeyed/unkey PR: 3834
File: internal/ui/src/components/form/input.tsx:130-131
Timestamp: 2025-08-25T13:05:22.441Z
Learning: The Input component in internal/ui/src/components/form/input.tsx is designed to support interactive right icons (like X buttons for deletion) by enabling pointer events on the right icon container, allowing clicks to be handled by the icon rather than passed through to the input.

Applied to files:

  • apps/dashboard/app/(app)/[workspaceSlug]/authorization/roles/components/table/roles-list.tsx
📚 Learning: 2024-12-03T14:17:08.016Z
Learnt from: ogzhanolguncu
Repo: unkeyed/unkey PR: 2143
File: apps/dashboard/app/(app)/logs/logs-page.tsx:77-83
Timestamp: 2024-12-03T14:17:08.016Z
Learning: The `<LogsTable />` component already implements virtualization to handle large datasets efficiently.

Applied to files:

  • apps/dashboard/app/(app)/[workspaceSlug]/authorization/roles/components/table/roles-list.tsx
🧬 Code graph analysis (1)
apps/dashboard/app/(app)/[workspaceSlug]/authorization/roles/components/table/roles-list.tsx (2)
internal/icons/src/icons/tag.tsx (1)
  • Tag (15-39)
apps/dashboard/components/virtual-table/index.tsx (1)
  • VirtualTable (38-407)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Test Dashboard / Test Dashboard
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (3)
apps/dashboard/app/(app)/[workspaceSlug]/authorization/roles/components/table/roles-list.tsx (3)

9-9: LGTM! Clean modal integration.

The EditRole import and modal rendering structure look good. The selectedRole state effectively manages which role to edit, and the conditional rendering is straightforward.

Also applies to: 27-27, 242-248


70-73: LGTM! Proper event handling to prevent unintended modal opens.

The stopPropagation calls correctly prevent row clicks from triggering the edit modal when users interact with the selection controls. The Checkbox uses onCheckedChange for the selection logic while onClick just stops propagation.

Also applies to: 82-84


165-241: LGTM! Clean VirtualTable integration.

The onRowClick={setSelectedRole} correctly opens the edit modal when clicking a role row, achieving the PR objective. The separation between row selection (selectedRole for editing) and bulk selection (selectedRoles for batch operations) is clear and well-implemented.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
apps/dashboard/app/(app)/[workspaceSlug]/authorization/roles/components/table/roles-list.tsx (1)

234-240: Simplify redundant isOpen prop.

Since the EditRole modal only renders when selectedRole is truthy (line 234), the isOpen={!!selectedRole} prop on line 237 will always be true. Consider simplifying to isOpen={true} or removing the conditional wrapper in favor of passing isOpen={!!selectedRole} without the outer condition.

Apply this diff to remove the redundancy:

-      {selectedRole && (
-        <EditRole
-          role={selectedRole}
-          isOpen={!!selectedRole}
-          onClose={() => setSelectedRole(null)}
-        />
-      )}
+      <EditRole
+        role={selectedRole}
+        isOpen={!!selectedRole}
+        onClose={() => setSelectedRole(null)}
+      />

Note: This assumes EditRole handles null role gracefully, otherwise keep the conditional but simplify isOpen to true.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 93fb85d and 4807ac8.

📒 Files selected for processing (2)
  • apps/dashboard/app/(app)/[workspaceSlug]/authorization/permissions/components/table/permissions-list.tsx (3 hunks)
  • apps/dashboard/app/(app)/[workspaceSlug]/authorization/roles/components/table/roles-list.tsx (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/dashboard/app/(app)/[workspaceSlug]/authorization/permissions/components/table/permissions-list.tsx
🧰 Additional context used
🧠 Learnings (8)
📚 Learning: 2024-10-08T15:33:04.290Z
Learnt from: AkshayBandi027
Repo: unkeyed/unkey PR: 2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In `authorization/roles/[roleId]/update-role.tsx`, the tag `role-${role.id}` is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.

Applied to files:

  • apps/dashboard/app/(app)/[workspaceSlug]/authorization/roles/components/table/roles-list.tsx
📚 Learning: 2025-06-19T11:48:05.070Z
Learnt from: ogzhanolguncu
Repo: unkeyed/unkey PR: 3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses `roleId` as the property name for the role identifier, not `id`. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.

Applied to files:

  • apps/dashboard/app/(app)/[workspaceSlug]/authorization/roles/components/table/roles-list.tsx
📚 Learning: 2024-12-03T14:07:45.173Z
Learnt from: ogzhanolguncu
Repo: unkeyed/unkey PR: 2143
File: apps/dashboard/components/ui/group-button.tsx:21-31
Timestamp: 2024-12-03T14:07:45.173Z
Learning: In the `ButtonGroup` component (`apps/dashboard/components/ui/group-button.tsx`), avoid suggesting the use of `role="group"` in ARIA attributes.

Applied to files:

  • apps/dashboard/app/(app)/[workspaceSlug]/authorization/roles/components/table/roles-list.tsx
📚 Learning: 2025-04-22T17:33:28.162Z
Learnt from: MichaelUnkey
Repo: unkeyed/unkey PR: 3173
File: apps/docs/security/delete-protection.mdx:32-36
Timestamp: 2025-04-22T17:33:28.162Z
Learning: In the Unkey dashboard UI for delete protection, the button/link to initiate the process is labeled "Disable Delete Protection" while the confirmation button is labeled "Disable API Delete Protection". The documentation should maintain these different labels to match the actual UI.

Applied to files:

  • apps/dashboard/app/(app)/[workspaceSlug]/authorization/roles/components/table/roles-list.tsx
📚 Learning: 2025-04-22T17:34:04.438Z
Learnt from: MichaelUnkey
Repo: unkeyed/unkey PR: 3173
File: apps/docs/security/delete-protection.mdx:21-24
Timestamp: 2025-04-22T17:34:04.438Z
Learning: In the Unkey dashboard UI for enabling delete protection, the button/link to initiate the process is labeled "Enable Delete Protection" while the confirmation button is labeled "Enable API Delete Protection". The documentation should maintain these different labels to match the actual UI.

Applied to files:

  • apps/dashboard/app/(app)/[workspaceSlug]/authorization/roles/components/table/roles-list.tsx
📚 Learning: 2025-01-07T19:55:33.055Z
Learnt from: chronark
Repo: unkeyed/unkey PR: 2792
File: apps/dashboard/app/(app)/settings/user/update-user-email.tsx:76-78
Timestamp: 2025-01-07T19:55:33.055Z
Learning: In the Unkey codebase, the Empty component can be used as a container for loading states, as demonstrated in the UpdateUserEmail component where it wraps the Loading component.

Applied to files:

  • apps/dashboard/app/(app)/[workspaceSlug]/authorization/roles/components/table/roles-list.tsx
📚 Learning: 2025-08-25T13:05:22.441Z
Learnt from: ogzhanolguncu
Repo: unkeyed/unkey PR: 3834
File: internal/ui/src/components/form/input.tsx:130-131
Timestamp: 2025-08-25T13:05:22.441Z
Learning: The Input component in internal/ui/src/components/form/input.tsx is designed to support interactive right icons (like X buttons for deletion) by enabling pointer events on the right icon container, allowing clicks to be handled by the icon rather than passed through to the input.

Applied to files:

  • apps/dashboard/app/(app)/[workspaceSlug]/authorization/roles/components/table/roles-list.tsx
📚 Learning: 2024-12-03T14:17:08.016Z
Learnt from: ogzhanolguncu
Repo: unkeyed/unkey PR: 2143
File: apps/dashboard/app/(app)/logs/logs-page.tsx:77-83
Timestamp: 2024-12-03T14:17:08.016Z
Learning: The `<LogsTable />` component already implements virtualization to handle large datasets efficiently.

Applied to files:

  • apps/dashboard/app/(app)/[workspaceSlug]/authorization/roles/components/table/roles-list.tsx
🧬 Code graph analysis (1)
apps/dashboard/app/(app)/[workspaceSlug]/authorization/roles/components/table/roles-list.tsx (2)
internal/icons/src/icons/tag.tsx (1)
  • Tag (15-39)
apps/dashboard/components/virtual-table/index.tsx (1)
  • VirtualTable (38-407)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Test Dashboard / Test Dashboard
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (3)
apps/dashboard/app/(app)/[workspaceSlug]/authorization/roles/components/table/roles-list.tsx (3)

9-9: LGTM: EditRole import added for modal functionality.

The import is correctly placed and used later to render the edit modal when a role is selected.


54-79: Past issues resolved by refactoring; stopPropagation is correct.

The refactoring from Button to Tag icon resolves the previous concerns about incorrect aria-label and unused group-hover classes. The cursor-pointer is now appropriately placed on the Tag (line 67) rather than the container, and the stopPropagation on line 74 correctly prevents the Checkbox interaction from triggering the row click handler.


157-241: Excellent modal integration pattern.

The fragment wrapping and rendering of the EditRole modal alongside the VirtualTable is a clean pattern. The modal opens when a row is clicked (via onRowClick={setSelectedRole} on line 164) and closes by clearing the selection. This mirrors the pattern in permissions-list.tsx and provides good UX.

Copy link
Member

@perkinsjr perkinsjr left a comment

Choose a reason for hiding this comment

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

Worked as intended

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
apps/dashboard/app/(app)/[workspaceSlug]/authorization/permissions/components/table/permissions-list.tsx (2)

66-66: Optional: Redundant cursor-pointer class on icon.

The Page2 icon has cursor-pointer, but the entire row already has cursor-pointer from the VirtualTable component, making this redundant. Consider removing it for cleaner styling.

-                <Page2 iconSize="sm-regular" className="text-gray-12 cursor-pointer" />
+                <Page2 iconSize="sm-regular" className="text-gray-12" />

250-256: Optional: Redundant isOpen prop.

The isOpen={!!selectedPermission} is redundant since the component is already conditionally rendered based on selectedPermission. When the component renders, isOpen will always be true.

Consider simplifying:

       {selectedPermission && (
         <EditPermission
           permission={selectedPermission}
-          isOpen={!!selectedPermission}
+          isOpen={true}
           onClose={() => setSelectedPermission(null)}
         />
       )}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4807ac8 and 3b705d0.

📒 Files selected for processing (2)
  • apps/dashboard/app/(app)/[workspaceSlug]/authorization/permissions/components/table/permissions-list.tsx (3 hunks)
  • apps/dashboard/app/(app)/[workspaceSlug]/authorization/roles/components/table/roles-list.tsx (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/dashboard/app/(app)/[workspaceSlug]/authorization/roles/components/table/roles-list.tsx
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-01-07T19:55:33.055Z
Learnt from: chronark
Repo: unkeyed/unkey PR: 2792
File: apps/dashboard/app/(app)/settings/user/update-user-email.tsx:76-78
Timestamp: 2025-01-07T19:55:33.055Z
Learning: In the Unkey codebase, the Empty component can be used as a container for loading states, as demonstrated in the UpdateUserEmail component where it wraps the Loading component.

Applied to files:

  • apps/dashboard/app/(app)/[workspaceSlug]/authorization/permissions/components/table/permissions-list.tsx
📚 Learning: 2025-08-25T13:05:22.441Z
Learnt from: ogzhanolguncu
Repo: unkeyed/unkey PR: 3834
File: internal/ui/src/components/form/input.tsx:130-131
Timestamp: 2025-08-25T13:05:22.441Z
Learning: The Input component in internal/ui/src/components/form/input.tsx is designed to support interactive right icons (like X buttons for deletion) by enabling pointer events on the right icon container, allowing clicks to be handled by the icon rather than passed through to the input.

Applied to files:

  • apps/dashboard/app/(app)/[workspaceSlug]/authorization/permissions/components/table/permissions-list.tsx
📚 Learning: 2024-12-03T14:17:08.016Z
Learnt from: ogzhanolguncu
Repo: unkeyed/unkey PR: 2143
File: apps/dashboard/app/(app)/logs/logs-page.tsx:77-83
Timestamp: 2024-12-03T14:17:08.016Z
Learning: The `<LogsTable />` component already implements virtualization to handle large datasets efficiently.

Applied to files:

  • apps/dashboard/app/(app)/[workspaceSlug]/authorization/permissions/components/table/permissions-list.tsx
🧬 Code graph analysis (1)
apps/dashboard/app/(app)/[workspaceSlug]/authorization/permissions/components/table/permissions-list.tsx (2)
internal/icons/src/icons/page-2.tsx (1)
  • Page2 (15-75)
apps/dashboard/components/virtual-table/index.tsx (1)
  • VirtualTable (38-407)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Test Dashboard / Test Dashboard
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (3)
apps/dashboard/app/(app)/[workspaceSlug]/authorization/permissions/components/table/permissions-list.tsx (3)

9-9: LGTM!

The import is clean and the component is properly used later in the file.


72-72: Correct use of stopPropagation to isolate checkbox interaction.

This prevents checkbox clicks from bubbling up to the row's onRowClick handler, ensuring that selecting a permission via checkbox doesn't inadvertently open the edit modal.


167-249: LGTM!

The fragment wrapper correctly enables returning multiple elements (VirtualTable + modal), and all VirtualTable props are properly configured. The table behavior, loading states, pagination, and selection functionality are preserved.

Copy link
Contributor

@ogzhanolguncu ogzhanolguncu left a comment

Choose a reason for hiding this comment

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

LGTM.

@ogzhanolguncu ogzhanolguncu added this pull request to the merge queue Nov 6, 2025
@graphite-app
Copy link

graphite-app bot commented Nov 6, 2025

Movie gif. Robert Downey Jr as Tony Stark in Iron Man slides on sunglasses with a smooth grin on his face. He gives a thumbs up as people in business attire and military uniforms stand and clap behind him.  (Added via Giphy)

Merged via the queue into main with commit 28d07df Nov 6, 2025
20 checks passed
@ogzhanolguncu ogzhanolguncu deleted the eng-1850-make-role-click-open-edit-modal-for-better-ux branch November 6, 2025 10:18
@graphite-app
Copy link

graphite-app bot commented Nov 6, 2025

Graphite Automations

"Post a GIF when PR approved" took an action on this PR • (11/06/25)

1 gif was posted to this PR based on Andreas Thomas's automation.

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