Skip to content

Conversation

@dougfabris
Copy link
Member

@dougfabris dougfabris commented Sep 25, 2025

Proposed changes (including videos or screenshots)

This PR introduces a helper to function to store some permission we wan't to disabled based on specific roles in order to prevent admins from removing themselves the permission to access the permission table.

image

Issue(s)

Steps to test or reproduce

Further comments

CORE-267

Summary by CodeRabbit

  • New Features
    • Added a confirmation modal when removing the last role with critical permissions to prevent accidental lockout.
    • Improved permission-change flow with clearer messaging and accessible checkbox labels.
  • Bug Fixes
    • Disabled Permissions tab no longer navigates for users without access.
  • Localization
    • Added warning text for removing the final role from a permission.
  • Tests
    • Added tests covering modal display when a permission has a single granted role.
  • Chores
    • Reduced story fixture payload and made permissions table pagination optional.

@dionisio-bot
Copy link
Contributor

dionisio-bot bot commented Sep 25, 2025

Looks like this PR is not ready to merge, because of the following issues:

  • This PR is targeting the wrong base branch. It should target 7.12.0, but it targets 7.11.0

Please fix the issues and try again

If you have any trouble, please check the PR guidelines

@changeset-bot
Copy link

changeset-bot bot commented Sep 25, 2025

🦋 Changeset detected

Latest commit: c483dc5

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 42 packages
Name Type
@rocket.chat/meteor Minor
@rocket.chat/core-typings Minor
@rocket.chat/rest-typings Minor
@rocket.chat/uikit-playground Patch
@rocket.chat/api-client Patch
@rocket.chat/apps Patch
@rocket.chat/core-services Patch
@rocket.chat/cron Patch
@rocket.chat/ddp-client Patch
@rocket.chat/freeswitch Patch
@rocket.chat/fuselage-ui-kit Major
@rocket.chat/gazzodown Major
@rocket.chat/http-router Patch
@rocket.chat/livechat Patch
@rocket.chat/model-typings Patch
@rocket.chat/ui-avatar Major
@rocket.chat/ui-client Major
@rocket.chat/ui-contexts Major
@rocket.chat/web-ui-registration Major
@rocket.chat/account-service Patch
@rocket.chat/authorization-service Patch
@rocket.chat/ddp-streamer Patch
@rocket.chat/federation-service Patch
@rocket.chat/omnichannel-transcript Patch
@rocket.chat/presence-service Patch
@rocket.chat/queue-worker Patch
@rocket.chat/stream-hub-service Patch
@rocket.chat/federation-matrix Patch
@rocket.chat/license Patch
@rocket.chat/media-calls Patch
@rocket.chat/omnichannel-services Patch
@rocket.chat/pdf-worker Patch
@rocket.chat/presence Patch
rocketchat-services Patch
@rocket.chat/models Patch
@rocket.chat/network-broker Patch
@rocket.chat/omni-core-ee Patch
@rocket.chat/mock-providers Patch
@rocket.chat/ui-video-conf Major
@rocket.chat/ui-voip Major
@rocket.chat/instance-status Patch
@rocket.chat/omni-core Patch

Not sure what this means? Click here to learn what changesets are.

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 25, 2025

Walkthrough

Adds a guarded confirmation modal preventing removal of the last granted role for protected permissions (notably access-permissions), adjusts permission identifiers and role-cell flow, guards tab navigation, adds a localization string and exported constant, updates tests and stories, and makes table pagination optional.

Changes

Cohort / File(s) Summary
Changeset
.changeset/spicy-zebras-deliver.md
Adds a changeset entry describing the minor release containing the modal hardening for critical permissions.
Permissions navigation
apps/meteor/client/views/admin/permissions/PermissionsPage.tsx
Prevents navigation by leaving onClick undefined when the user lacks view permission; keeps tab visually disabled otherwise.
Permissions table row IDs
apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionRow.tsx
Renames local identifiers (_idpermissionId, role _idroleId), updates keys, translation keys, and prop names to use permissionId/roleId.
Role cell confirmation flow
apps/meteor/client/views/admin/permissions/PermissionsTable/RoleCell.tsx
Adds permissionName prop; gates removal flow using confirmationRequiredPermissions and single-role detection; shows localized GenericModal for last-role removal; centralizes change handling, loading/disabled logic, and adds aria-labels.
Authorization constants
apps/meteor/app/authorization/lib/index.ts
Exports confirmationRequiredPermissions = ['access-permissions'].
Localization
packages/i18n/src/locales/en.i18n.json
Adds Last_role_in_permission_warning translation explaining risk of removing the last role.
Tests
apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionsTable.spec.tsx
Adds tests and fixtures asserting modal appears when removing a permission with a single granted role and does not appear when multiple roles exist; uses testing-library screen and userEvent.
Stories
apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionsTable.stories.tsx
Simplifies story permission objects by removing fields (fields, level, section, settingId, sorter) from sample permissions.
PermissionsTable props
apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionsTable.tsx
Makes paginationProps optional in PermissionsTableProps (paginationProps?: ReturnType<typeof usePagination>).

Sequence Diagram(s)

sequenceDiagram
  actor Admin as Admin User
  participant PermPage as PermissionsPage
  participant Table as PermissionsTable
  participant RoleCell as RoleCell
  participant Auth as AuthLib
  participant Modal as ConfirmationModal

  Admin->>PermPage: Open Permissions tab (guarded)
  PermPage->>Table: Render permissions & roles
  Admin->>RoleCell: Toggle role checkbox

  RoleCell->>Auth: Check confirmationRequiredPermissions
  RoleCell->>RoleCell: Determine if last granted role?

  alt Confirmation required (protected permission + last role)
    RoleCell->>Modal: Show `Last_role_in_permission_warning`
    Admin-->>Modal: Confirm removal
    Modal->>RoleCell: Submit
    RoleCell->>RoleCell: handleConfirmChange -> call onChange, update state
  else No confirmation
    RoleCell->>RoleCell: handleConfirmChange -> call onChange, update state
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • dougfabris
  • MartinSchoeler
  • ggazzo

Poem

A careful hop, a cautious stare,
A little modal guards the lair.
"Last role here — think twice," it sings,
So admins keep their fixing wings.
I nibble code and press confirm — safe things! 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Out of Scope Changes Check ⚠️ Warning The PR includes refactor and storybook adjustments—such as renaming paginationProps to optional, altering story data shapes, and renaming identifiers in PermissionRow—that are not required to implement the warning for removing access-permissions and fall outside the CORE-267 scope. These unrelated changes complicate the review by mixing feature work with refactoring and presentation updates. Please separate the paginationProps optionality change, storybook data modifications, and identifier renaming into a dedicated refactor PR to keep this feature branch focused on the access-permissions warning implementation. If any of these changes were essential to support the warning behavior, include that justification in the PR description. This will streamline the review and ensure the PR aligns strictly with CORE-267 objectives.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title succinctly captures the primary change by stating that a warning is added when removing the access-permissions permission from the last granted role, directly matching the feature implemented in the PR. It is concise, clear, and specific enough for a reviewer to understand the main purpose without extraneous detail. The use of backticks around access-permissions accurately highlights the exact permission affected.
Linked Issues Check ✅ Passed The pull request adds a confirmation modal flow gated by a new confirmationRequiredPermissions constant containing access-permissions, updates the RoleCell component to warn when removing that permission from its last granted role, and includes tests verifying the modal behavior, thereby directly fulfilling the CORE-267 objectives to prevent admin lockout of the permissions table and maintain edit access. The translation, constant, UI changes, and test coverage together implement the required safeguard.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/permission-screen-checkbox

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d160056 and c483dc5.

📒 Files selected for processing (1)
  • packages/i18n/src/locales/en.i18n.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/i18n/src/locales/en.i18n.json

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.

@dougfabris dougfabris added this to the 7.12.0 milestone Sep 25, 2025
@codecov
Copy link

codecov bot commented Sep 25, 2025

Codecov Report

❌ Patch coverage is 92.00000% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 67.35%. Comparing base (fd4f9b2) to head (c483dc5).
⚠️ Report is 1 commits behind head on develop.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop   #37073      +/-   ##
===========================================
+ Coverage    67.32%   67.35%   +0.02%     
===========================================
  Files         3278     3276       -2     
  Lines       112000   111878     -122     
  Branches     20315    20282      -33     
===========================================
- Hits         75402    75350      -52     
+ Misses       33996    33933      -63     
+ Partials      2602     2595       -7     
Flag Coverage Δ
e2e 57.31% <55.00%> (-0.01%) ⬇️
unit 71.14% <93.87%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@dougfabris dougfabris changed the title feat: Prevent access-permissions from being remove from admin feat: Prevent access-permissions from being removed from admin Sep 26, 2025
@dougfabris dougfabris marked this pull request as ready for review September 30, 2025 19:23
@dougfabris dougfabris requested a review from a team as a code owner September 30, 2025 19:23
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 (4)
apps/meteor/client/views/root/hooks/loggedIn/useRestrictedRoles.ts (1)

20-20: Consider centralizing hardcoded permission identifiers.

The hardcoded string 'access-permissions' creates a maintenance concern if this permission identifier changes or if additional critical permissions need similar protection in the future.

Consider extracting this to a constant:

// At the top of the file or in a shared constants file
const CRITICAL_ADMIN_PERMISSIONS = ['access-permissions'] as const;

// Then use it in the effect:
AuthorizationUtils.addRolePermissionDisabledList('admin', CRITICAL_ADMIN_PERMISSIONS);
apps/meteor/app/authorization/lib/AuthorizationUtils.spec.ts (2)

6-9: Consider adding cleanup in afterEach/afterAll.

The beforeAll hook sets up shared state in AuthorizationUtils, but there's no cleanup. If these maps persist between test suites, it could lead to test pollution.

Consider adding cleanup:

afterAll(() => {
  // Reset the internal maps if AuthorizationUtils provides a reset method
  // or ensure tests are isolated
});

Note: If AuthorizationUtils uses module-level state (as suggested by the static methods), you may need to add a reset() or clear() method for testing purposes.


11-33: Expand test coverage for edge cases and error conditions.

The current tests cover the happy path but miss several important scenarios:

  • Invalid parameters (null, undefined, empty strings)
  • Multiple permissions in the disabled/whitelist
  • Role that doesn't exist in either map
  • Permission that exists for one role but not another

Consider adding tests for:

it('should throw error for invalid parameters', () => {
  expect(() => AuthorizationUtils.isPermissionDisabledForRole('', fakeRole)).toThrow('invalid-param');
  expect(() => AuthorizationUtils.isPermissionDisabledForRole(fakePermissionId, '')).toThrow('invalid-param');
});

it('should return false for role without any disabled permissions', () => {
  const result = AuthorizationUtils.isPermissionDisabledForRole(fakePermissionId, 'non-existent-role');
  expect(result).toBe(false);
});

it('should handle multiple permissions in disabled list', () => {
  AuthorizationUtils.addRolePermissionDisabledList('test-role', ['perm1', 'perm2']);
  expect(AuthorizationUtils.isPermissionDisabledForRole('perm1', 'test-role')).toBe(true);
  expect(AuthorizationUtils.isPermissionDisabledForRole('perm2', 'test-role')).toBe(true);
});
apps/meteor/app/authorization/lib/AuthorizationUtils.ts (1)

29-50: Consider renaming the modifier parameter for clarity.

The modifier parameter with values 'allow' and 'deny' is semantically confusing:

  • 'deny' actually implements whitelist logic (returns true when permission is NOT in the list)
  • 'allow' actually implements blacklist logic (returns true when permission IS in the list)

This inversion can lead to maintenance errors.

Consider renaming to better reflect the actual behavior:

 private static checkPermissionForRole(
   permissionId: string,
   roleId: string,
   permissionMap: Map<string, Set<string>>,
-  modifier: 'allow' | 'deny' = 'deny',
+  listType: 'whitelist' | 'blacklist' = 'whitelist',
 ): boolean {
   // ... validation ...
   
   const hasPermission = rules.has(permissionId);
-  return modifier === 'deny' ? !hasPermission : hasPermission;
+  return listType === 'whitelist' ? !hasPermission : hasPermission;
 }

Then update the call sites:

 static isPermissionRestrictedForRole(permissionId: string, roleId: string): boolean {
-  return this.checkPermissionForRole(permissionId, roleId, restrictedRolePermissions);
+  return this.checkPermissionForRole(permissionId, roleId, restrictedRolePermissions, 'whitelist');
 }

 static isPermissionDisabledForRole(permissionId: string, roleId: string): boolean {
-  return this.checkPermissionForRole(permissionId, roleId, disabledRolePermissions, 'allow');
+  return this.checkPermissionForRole(permissionId, roleId, disabledRolePermissions, 'blacklist');
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d0467df and 024a65f.

📒 Files selected for processing (8)
  • .changeset/spicy-zebras-deliver.md (1 hunks)
  • apps/meteor/app/authorization/lib/AuthorizationUtils.spec.ts (1 hunks)
  • apps/meteor/app/authorization/lib/AuthorizationUtils.ts (1 hunks)
  • apps/meteor/client/views/admin/permissions/PermissionsPage.tsx (1 hunks)
  • apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionRow.tsx (1 hunks)
  • apps/meteor/client/views/admin/permissions/PermissionsTable/RoleCell.tsx (2 hunks)
  • apps/meteor/client/views/root/hooks/loggedIn/useRestrictedRoles.ts (1 hunks)
  • apps/meteor/jest.config.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-16T22:08:51.490Z
Learnt from: CR
PR: RocketChat/Rocket.Chat#0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-09-16T22:08:51.490Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : All Playwright test files must be located under apps/meteor/tests/e2e/ and use the .spec.ts extension (e.g., login.spec.ts)

Applied to files:

  • apps/meteor/jest.config.ts
🧬 Code graph analysis (4)
apps/meteor/app/authorization/lib/AuthorizationUtils.spec.ts (1)
apps/meteor/app/authorization/lib/AuthorizationUtils.ts (1)
  • AuthorizationUtils (4-77)
apps/meteor/client/views/admin/permissions/PermissionsTable/RoleCell.tsx (1)
apps/meteor/app/authorization/lib/AuthorizationUtils.ts (1)
  • AuthorizationUtils (4-77)
apps/meteor/client/views/root/hooks/loggedIn/useRestrictedRoles.ts (1)
apps/meteor/app/authorization/lib/AuthorizationUtils.ts (1)
  • AuthorizationUtils (4-77)
apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionRow.tsx (2)
apps/meteor/app/utils/lib/i18n.ts (1)
  • t (6-6)
packages/ui-contexts/src/index.ts (1)
  • TranslationKey (103-103)
⏰ 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). (4)
  • GitHub Check: 📦 Build Packages
  • GitHub Check: Builds matrix rust bindings against alpine
  • GitHub Check: CodeQL-Build
  • GitHub Check: CodeQL-Build
🔇 Additional comments (10)
.changeset/spicy-zebras-deliver.md (1)

1-5: LGTM! Clear changeset entry.

The changeset correctly documents the hardening measure and clearly explains the purpose of preventing administrators from accidentally removing their own access to the permission management screen.

apps/meteor/jest.config.ts (1)

16-16: LGTM! Appropriate test coverage extension.

The new testMatch pattern correctly includes authorization specs under the client project configuration, aligning with the new unit tests for AuthorizationUtils.

apps/meteor/app/authorization/lib/AuthorizationUtils.ts (3)

5-19: LGTM! Good refactoring to centralize map manipulation.

The addRolePermissionRule helper effectively consolidates the logic for adding permissions to both the restricted and disabled maps, reducing code duplication.


21-27: LGTM! Clear public API for managing role permissions.

The new methods addRolePermissionWhiteList and addRolePermissionDisabledList provide a clear and consistent interface for managing both restricted (whitelisted) and disabled (blacklisted) permissions.


52-58: LGTM! Consistent permission checking methods.

Both isPermissionRestrictedForRole and isPermissionDisabledForRole correctly leverage the centralized checkPermissionForRole helper with appropriate modifiers to implement whitelist and blacklist semantics respectively.

apps/meteor/client/views/root/hooks/loggedIn/useRestrictedRoles.ts (1)

20-20: Permission identifier is correct. The 'access-permissions' string matches its _id in the permissions constant and is used consistently in server checks, client hooks, and tests.

apps/meteor/client/views/admin/permissions/PermissionsPage.tsx (1)

65-65: LGTM! Tab behavior correctly prevents unauthorized navigation.

The conditional onClick handler ensures users without access-permissions cannot activate the Permissions tab, complementing the existing disabled state.

apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionRow.tsx (2)

37-54: LGTM! Semantic renaming improves clarity and enables per-role permission checks.

The refactoring from _id to permissionId and role's _id to roleId makes the code more readable and correctly propagates permissionId to RoleCell, which is now required for the new isPermissionDisabledForRole check.


37-54: Runtime initialization confirmed. The call to AuthorizationUtils.addRolePermissionDisabledList('admin', ['access-permissions']) exists in apps/meteor/client/views/root/hooks/loggedIn/useRestrictedRoles.ts, so the disabled-permissions list is correctly initialized.

apps/meteor/client/views/admin/permissions/PermissionsTable/RoleCell.tsx (1)

24-34: UI now honors per-role disabled permissions.
Combining the new isPermissionDisabledForRole check with the existing restricted/loading flags cleanly prevents the admin access-permissions checkbox from being toggled. Looks solid.

Copy link
Member

@gabriellsh gabriellsh left a comment

Choose a reason for hiding this comment

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

Summary from discussion in DM:

  1. It would be nice if instead of disabling change, we show a warning modal of some sort.
  2. We found it a little hard to justify all these changes for just one permission, specially since this will only be needed in the UI for now.
  3. It might make more sense to warn the user if he's removing the last role from the permission, or identify if HE will lose access to the page, instead of limiting the warning to admins. I could have this permission in another role and not on the admin role for example, so the same issue would exist in that case.

@dougfabris dougfabris force-pushed the feat/permission-screen-checkbox branch from ff70be8 to 8fe2acf Compare October 7, 2025 14:40
@dougfabris dougfabris requested a review from gabriellsh October 7, 2025 14:46
@dougfabris dougfabris changed the title feat: Prevent access-permissions from being removed from admin feat: Add warning when removing access-permissions from last granted role Oct 7, 2025
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

Caution

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

⚠️ Outside diff range comments (1)
apps/meteor/client/views/admin/permissions/PermissionsTable/RoleCell.tsx (1)

48-53: Add error handling to prevent stuck loading state.

If onChange throws an error or the promise rejects, setLoading(false) will never be called, leaving the checkbox in a perpetually disabled loading state.

Apply this diff to add error handling:

 const handleConfirmChange = useEffectEvent(async () => {
 	setLoading(true);
-	const result = await onChange(_id, granted);
-	setGranted(result);
-	setLoading(false);
+	try {
+		const result = await onChange(_id, granted);
+		setGranted(result);
+	} finally {
+		setLoading(false);
+	}
 });
🧹 Nitpick comments (4)
apps/meteor/app/authorization/lib/index.ts (1)

12-13: Consider adding as const for stronger type safety.

The confirmationRequiredPermissions constant is currently inferred as string[], making it mutable. Adding as const would make it a readonly tuple readonly ['access-permissions'], preventing accidental modifications and enabling more precise type checking in consuming code.

Apply this diff:

-export const confirmationRequiredPermissions = ['access-permissions'];
+export const confirmationRequiredPermissions = ['access-permissions'] as const;

Additionally, consider adding a JSDoc comment to document the purpose of this constant:

+/**
+ * List of permissions that require user confirmation before removal from the last role.
+ * Prevents admins from accidentally locking themselves out of critical features.
+ */
 export const confirmationRequiredPermissions = ['access-permissions'] as const;
packages/i18n/src/locales/en.i18n.json (1)

2907-2907: Clarify warning copy and include permission placeholder for context

“soft-lock” is jargon and “this page” is ambiguous. Suggest clearer wording and exposing the permission name (if available) to improve UX.

Apply:

-  "Last_role_in_permission_warning": "This is the last role with this permission. Removing it will soft-lock this page from the UI, requiring database access to revert it. Do you want to proceed?",
+  "Last_role_in_permission_warning": "You are removing the last role with the '{{permission}}' permission. This will lock the Permissions page in the UI and require database access to revert. Do you want to continue?"

If the UI doesn’t have the permission name handy, keep the structure but drop the placeholder:

-  "Last_role_in_permission_warning": "This is the last role with this permission. Removing it will soft-lock this page from the UI, requiring database access to revert it. Do you want to proceed?",
+  "Last_role_in_permission_warning": "You are removing the last role with this permission. This will lock the Permissions page in the UI and require database access to revert. Do you want to continue?"
  • Confirm RoleCell.tsx uses the exact key "Last_role_in_permission_warning".
  • If you add the {{permission}} placeholder, ensure the component passes it.
  • Consider adding this key to other locales or rely on fallback.
apps/meteor/client/views/admin/permissions/PermissionsTable/RoleCell.tsx (2)

38-42: Consider cleanup effect for modal on unmount.

If the component unmounts while the modal is open (e.g., user navigates away), the modal should be cleaned up to prevent memory leaks or stale UI state.

Add a cleanup effect:

useEffect(() => {
	return () => setModal(null);
}, [setModal]);

55-55: Remove unnecessary double negation.

The double negation (!!) is unnecessary since loading is already a boolean and isRestrictedForRole is used in a boolean context.

-const isDisabled = !!loading || !!isRestrictedForRole;
+const isDisabled = loading || isRestrictedForRole;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 024a65f and 7ad90fb.

📒 Files selected for processing (4)
  • .changeset/spicy-zebras-deliver.md (1 hunks)
  • apps/meteor/app/authorization/lib/index.ts (1 hunks)
  • apps/meteor/client/views/admin/permissions/PermissionsTable/RoleCell.tsx (2 hunks)
  • packages/i18n/src/locales/en.i18n.json (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
apps/meteor/client/views/admin/permissions/PermissionsTable/RoleCell.tsx (2)
packages/ui-contexts/src/index.ts (1)
  • useSetModal (68-68)
apps/meteor/app/authorization/lib/index.ts (2)
  • AuthorizationUtils (14-14)
  • confirmationRequiredPermissions (12-12)
🔇 Additional comments (4)
apps/meteor/client/views/admin/permissions/PermissionsTable/RoleCell.tsx (4)

4-10: LGTM!

The new imports are appropriate for the confirmation modal functionality. GenericModal and useSetModal enable the modal UI, useTranslation provides i18n support, and confirmationRequiredPermissions defines which permissions require confirmation.


29-29: Confirmation logic is correct for the use case.

The shouldDisplayConfirmation check correctly identifies the scenario where removing a permission from the last role should trigger a warning. The logic ensures the modal only appears when:

  1. The permission is critical (in confirmationRequiredPermissions)
  2. Only one role has the permission (grantedRoles.length === 1)
  3. The current role has the permission (granted === true)

This prevents admins from accidentally removing their ability to manage permissions.


28-28: Don’t add isPermissionRequiredForRole check: missing API
No isPermissionRequiredForRole exists in AuthorizationUtils; implement that method first if you need a permission-required check.

Likely an incorrect or invalid review comment.


31-46: Verify checkbox change handling
• Ensure CheckBox’s onChange signature aligns with handleChange (no extra args passed)
• Confirm rapid clicks can’t open multiple modals or bypass the confirmation step

@dougfabris dougfabris force-pushed the feat/permission-screen-checkbox branch from 7ad90fb to 7d116f4 Compare October 7, 2025 14:49
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/meteor/client/views/admin/permissions/PermissionsTable/RoleCell.tsx (1)

32-47: Optional: Remove unnecessary return statement.

The modal confirmation flow is well-implemented with proper danger styling and translation support. However, line 46 has an unnecessary return statement since handleConfirmChange doesn't return a meaningful value for this context.

Consider this minor cleanup:

 		}
 
-		return handleConfirmChange();
+		handleConfirmChange();
 	});
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 7ad90fb and d160056.

⛔ Files ignored due to path filters (1)
  • apps/meteor/client/views/admin/permissions/PermissionsTable/__snapshots__/PermissionsTable.spec.tsx.snap is excluded by !**/*.snap
📒 Files selected for processing (6)
  • .changeset/spicy-zebras-deliver.md (1 hunks)
  • apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionRow.tsx (1 hunks)
  • apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionsTable.spec.tsx (2 hunks)
  • apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionsTable.stories.tsx (0 hunks)
  • apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionsTable.tsx (1 hunks)
  • apps/meteor/client/views/admin/permissions/PermissionsTable/RoleCell.tsx (2 hunks)
💤 Files with no reviewable changes (1)
  • apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionsTable.stories.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionRow.tsx
🧰 Additional context used
🧬 Code graph analysis (2)
apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionsTable.spec.tsx (1)
packages/mock-providers/src/index.ts (1)
  • mockAppRoot (3-3)
apps/meteor/client/views/admin/permissions/PermissionsTable/RoleCell.tsx (2)
packages/ui-contexts/src/index.ts (1)
  • useSetModal (68-68)
apps/meteor/app/authorization/lib/index.ts (2)
  • AuthorizationUtils (14-14)
  • confirmationRequiredPermissions (12-12)
⏰ 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: CodeQL-Build
  • GitHub Check: CodeQL-Build
🔇 Additional comments (11)
.changeset/spicy-zebras-deliver.md (1)

1-5: LGTM!

The changeset is well-formatted and accurately describes the feature. The grammatical issue from the previous review has been successfully addressed.

apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionsTable.tsx (1)

19-19: LGTM!

Making paginationProps optional improves component flexibility. The implementation already safely handles the undefined case with optional chaining (lines 81-82) and safe spreading (line 83).

apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionsTable.spec.tsx (4)

1-8: LGTM!

The new imports are appropriate for the added tests. The testing utilities (screen, userEvent) and types (IPermission, IRole) support the modal behavior verification tests.


27-50: LGTM!

The test data is well-structured and appropriate for testing the modal behavior:

  • defaultPermissions correctly represents a permission with a single granted role
  • roles array includes all necessary fields with realistic values
  • Using a fixed date for _updatedAt ensures test stability

64-79: LGTM!

The test correctly validates that no modal appears when the permission has multiple granted roles. Good use of queryByRole for asserting non-existence, which returns null instead of throwing.


52-62: Approve modal display test; aria-label format is correct
The aria-label uses ${permissionName} - ${description || name}, matching the test’s getByRole query, and the test follows accessible best practices.

apps/meteor/client/views/admin/permissions/PermissionsTable/RoleCell.tsx (5)

4-5: LGTM!

The new imports are appropriate for implementing the modal confirmation feature. All dependencies are from established libraries and internal modules.

Also applies to: 8-8, 10-10


19-19: LGTM!

The new permissionName prop enables better accessibility and user-facing text. The type signature is appropriate.

Also applies to: 23-23


30-30: LGTM!

The shouldDisplayConfirmation logic correctly identifies when to show the warning modal. All three conditions are necessary to prevent administrators from removing the last role with access to permissions management.


57-57: LGTM!

The aria-label construction is excellent for accessibility. The format (permissionName - description/name) provides clear context for screen reader users and matches the test expectations.

Also applies to: 62-62


49-56: Utility isPermissionRequiredForRole missing. The method doesn’t exist in AuthorizationUtils; implement it or remove this check.

Likely an incorrect or invalid review comment.

@gabriellsh gabriellsh added the stat: QA assured Means it has been tested and approved by a company insider label Oct 7, 2025
@dionisio-bot dionisio-bot bot added the stat: ready to merge PR tested and approved waiting for merge label Oct 7, 2025
@kodiakhq kodiakhq bot merged commit 67f9939 into develop Oct 7, 2025
87 of 89 checks passed
@kodiakhq kodiakhq bot deleted the feat/permission-screen-checkbox branch October 7, 2025 20:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stat: QA assured Means it has been tested and approved by a company insider stat: ready to merge PR tested and approved waiting for merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants