Skip to content

Add Privileges > 'Permissions' page - #1140

Open
carma12 wants to merge 3 commits into
freeipa:mainfrom
carma12:privileges-permissions-page
Open

Add Privileges > 'Permissions' page#1140
carma12 wants to merge 3 commits into
freeipa:mainfrom
carma12:privileges-permissions-page

Conversation

@carma12

@carma12 carma12 commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

The 'Permissions' subpage allows to
grant or revoke some permissions to
a given Privilege.

Assisted-by: Claude noreply@anthropic.com

Summary by Sourcery

Add a new Privileges Permissions page and wire it into routing and RPC APIs to manage privilege-permission memberships.

New Features:

  • Introduce a Privileges permissions tab page to view, search, paginate, and manage permissions assigned to a privilege.
  • Add RPC endpoints for fetching a single privilege, listing permissions, and adding/removing permissions to/from a privilege.

Enhancements:

  • Extend privilege data mapping and types to include member permissions and ensure empty defaults.
  • Update privileges listing to support linking into a specific privilege and increase the fetch size limit.
  • Teach the membership table to support a new permissions entity type without navigation links.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've found 3 issues, and left some high level feedback:

  • In Privileges.tsx the stopIdx is now hard-coded to 100, which can get out of sync with pagination controls; consider wiring this back to perPage or another configurable value so the list size matches user-selected page size.
  • Now that privilege detail pages exist (/privileges/:cn with tabs), the NO_LINK_TYPES array still treating privileges as non-linkable may be inconsistent with the new routing; review whether privilege rows from MembershipTable should link to the new PrivilegesTabs page and adjust NO_LINK_TYPES accordingly.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `Privileges.tsx` the `stopIdx` is now hard-coded to `100`, which can get out of sync with pagination controls; consider wiring this back to `perPage` or another configurable value so the list size matches user-selected page size.
- Now that privilege detail pages exist (`/privileges/:cn` with tabs), the `NO_LINK_TYPES` array still treating `privileges` as non-linkable may be inconsistent with the new routing; review whether privilege rows from `MembershipTable` should link to the new `PrivilegesTabs` page and adjust `NO_LINK_TYPES` accordingly.

## Individual Comments

### Comment 1
<location path="src/pages/Privileges/PrivilegesPermissions.tsx" line_range="119-126" />
<code_context>
+  );
+
+  // Load available permissions (only when modal is open)
+  const permissionsQuery = useGetPermissionsQuery(adderSearchValue, {
+    skip: !showAddModal,
+  });
+
+  // Trigger available permissions search
+  useEffect(() => {
+    if (showAddModal) {
+      permissionsQuery.refetch();
+    }
+  }, [showAddModal, adderSearchValue, permissionNames]);
+
+  // Update available permissions
</code_context>
<issue_to_address>
**suggestion (performance):** The refetch effect for available permissions may trigger more API calls than necessary due to its dependency list.

Because `permissionNames` is an array that likely changes identity on each update, including it in the `useEffect` dependencies can cause unnecessary `permissionsQuery.refetch()` calls even when `adderSearchValue` is unchanged. Given that `useGetPermissionsQuery` already fetches when `skip` becomes `false` and when `adderSearchValue` changes, consider narrowing the dependencies (e.g., remove `permissionNames`) or relying on RTK Query’s built‑in refetch when `showAddModal` becomes `true` to avoid redundant network requests.

```suggestion
  // Update available permissions
```
</issue_to_address>

### Comment 2
<location path="src/pages/Privileges/PrivilegesPermissions.tsx" line_range="154-163" />
<code_context>
+    if (props.privilege.cn === undefined || newPermissionNames.length === 0) {
</code_context>
<issue_to_address>
**nitpick:** Guard clauses check `cn === undefined`, but the type is a string, making the condition slightly misleading.

Given `Privilege.cn` is typed as `string`, these `=== undefined` checks are defensive rather than type-driven. If the goal is to prevent empty IDs, consider a falsy or length check (e.g. `!props.privilege.cn`) so the runtime validation matches the TypeScript type and avoids relying on an impossible `undefined` state.
</issue_to_address>

### Comment 3
<location path="src/pages/Privileges/PrivilegesTabs.tsx" line_range="58" />
<code_context>
+  const privilegeQuery = useGetPrivilegeByIdQuery(cn);
+  const privilege = privilegeQuery.data;
+
+  // Tab
+  const [activeTabKey, setActiveTabKey] = useState(() =>
+    getTabKeyFromSection(section)
</code_context>
<issue_to_address>
**issue (complexity):** Consider deriving the active tab directly from the URL section instead of storing it in state so the tabs are purely URL-driven.

You can simplify the tab/routing logic by removing `activeTabKey` state entirely and deriving it from `section` on render. This keeps all behaviour (URL-driven tabs, redirects, breadcrumbs) but removes overlapping effects and synchronization logic.

Concretely:

1. **Remove `activeTabKey` state and its setters**  
   `activeTabKey` is always computed from `section`, so you don’t need state or effects to keep it in sync.

   ```tsx
   // Remove:
   const [activeTabKey, setActiveTabKey] = useState(() =>
     getTabKeyFromSection(section)
   );
   ```

   Use a derived value instead:

   ```tsx
   const currentTabKey = getTabKeyFromSection(section);
   ```

2. **Stop setting tab state inside effects**  
   The breadcrumb effect and the redirect effect both call `setActiveTabKey`, which becomes unnecessary (and is currently redundant):

   ```tsx
   React.useEffect(() => {
     const currentPath: BreadCrumbItem[] = [
       { name: "Privileges", url: "/privileges" },
       { name: cn, url: "/privileges/" + cn, isActive: true },
     ];
     setBreadcrumbItems(currentPath);
     // Remove this:
     // setActiveTabKey("permissions");
     dispatch(updateBreadCrumbPath(currentPath));
   }, [cn, dispatch]);

   React.useEffect(() => {
     if (!section) {
       navigate(TAB_ROUTES.permissions(cn));
     }
     // Remove this:
     // setActiveTabKey(getTabKeyFromSection(section));
   }, [section, cn, navigate]);
   ```

3. **Drive `<Tabs>` directly from the URL-derived key**  
   Use `currentTabKey` as the single source of truth for the active tab:

   ```tsx
   const currentTabKey = getTabKeyFromSection(section);

   // ...

   <Tabs
     activeKey={currentTabKey}
     onSelect={handleTabClick}
     variant="secondary"
     isBox
     className="pf-v6-u-ml-lg"
     mountOnEnter
     unmountOnExit
   >
     <Tab
       eventKey="permissions"
       name="permissions-details"
       title={<TabTitleText>Permissions</TabTitleText>}
       data-cy="privileges-tab-permissions"
     >
       <PrivilegesPermissions
         privilege={partialPrivilegeToPrivilege(privilege)}
       />
     </Tab>
   </Tabs>
   ```

4. **Keep navigation logic in one place (the URL)**  
   `handleTabClick` can remain unchanged, since it already uses `TAB_ROUTES` to navigate and therefore updates `section` via the route:

   ```tsx
   const handleTabClick = (
     _event: React.MouseEvent<HTMLElement, MouseEvent>,
     tabIndex: number | string
   ) => {
     const tabKey = String(tabIndex);
     const toPath = TAB_ROUTES[tabKey];
     if (toPath) {
       navigate(toPath(cn));
     }
   };
   ```

With these changes, the URL (via `section`) is the single source of truth for the active tab, and effects only handle side effects (breadcrumbs, redirect), which should reduce cognitive load and avoid subtle ordering issues.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread src/pages/Privileges/PrivilegesPermissions.tsx Outdated
Comment on lines +154 to +163
if (props.privilege.cn === undefined || newPermissionNames.length === 0) {
return;
}

setSpinning(true);
addPermissionToPrivilege({
privilegeCn: props.privilege.cn,
permissions: newPermissionNames,
}).then((response) => {
if ("data" in response) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nitpick: Guard clauses check cn === undefined, but the type is a string, making the condition slightly misleading.

Given Privilege.cn is typed as string, these === undefined checks are defensive rather than type-driven. If the goal is to prevent empty IDs, consider a falsy or length check (e.g. !props.privilege.cn) so the runtime validation matches the TypeScript type and avoids relying on an impossible undefined state.

Comment thread src/pages/Privileges/PrivilegesTabs.tsx Outdated
@carma12 carma12 added the WIP Work in Progress (do not merge) label Jul 16, 2026
@carma12
carma12 force-pushed the privileges-permissions-page branch from 0119f41 to 0b3f4c7 Compare July 16, 2026 14:58
@carma12
carma12 force-pushed the privileges-permissions-page branch from 0b3f4c7 to aeb59c9 Compare August 5, 2026 14:01
@carma12 carma12 added needs-review This PR is waiting on a review and removed WIP Work in Progress (do not merge) labels Aug 5, 2026
@carma12
carma12 force-pushed the privileges-permissions-page branch 2 times, most recently from 7cd6c83 to cd2e891 Compare August 7, 2026 07:13

@duzda duzda 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.

Hi, after navigating to Permissions, I'm unable to get back through clicking on Settings:

Image

The permissions include at most 100 options, just by installing there is around 280 permissions, maybe we should lift the limit here? I also think the list should include a search bar.

Image

Please also see the inline comments

Comment thread src/pages/Privileges/PrivilegesPermissions.tsx Outdated
Comment thread src/pages/Privileges/PrivilegesPermissions.tsx Outdated
Comment thread src/pages/Privileges/PrivilegesPermissions.tsx Outdated
Comment thread src/pages/Privileges/PrivilegesPermissions.tsx Outdated
Comment thread src/pages/Privileges/PrivilegesPermissions.tsx Outdated
Comment thread src/pages/Privileges/PrivilegesPermissions.tsx Outdated
Comment thread src/pages/Privileges/PrivilegesTabs.tsx Outdated
@carma12
carma12 force-pushed the privileges-permissions-page branch 3 times, most recently from 681dd4a to d430217 Compare August 10, 2026 13:55
@carma12

carma12 commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator Author

Hi, after navigating to Permissions, I'm unable to get back through clicking on Settings:
Image

The permissions include at most 100 options, just by installing there is around 280 permissions, maybe we should lift the limit here? I also think the list should include a search bar.
Image

Please also see the inline

@duzda - I agree on the search bar in the DualListSelector, I have modified the component and limited the entries to 100. Also, I amended your comments in the code.

@veronnicka veronnicka 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.

Hi, apart from the comments, I suggest to add a BulkSelector (select page / select all) as in the other membership tables. Maybe it would be a good idea to add it to the .md files as well

Comment thread src/components/layouts/DualListSelectorGeneric.tsx
Comment thread src/pages/Privileges/PrivilegesPermissions.tsx Outdated
@carma12
carma12 force-pushed the privileges-permissions-page branch from d430217 to 1e7b8e9 Compare August 11, 2026 12:30
@carma12

carma12 commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator Author

Hi, apart from the comments, I suggest to add a BulkSelector (select page / select all) as in the other membership tables. Maybe it would be a good idea to add it to the .md files as well

Not sure if adding the BulkSelector in this page would be a good idea, as typically a Privilege doesn't have a hundred of permissions, and that would also require to modify other similar pages as this one to match with the same pattern. However, we can keep this discussion open and share this idea with other team members. WDYT?

@carma12

carma12 commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator Author

@veronnicka - I fixed the code based on your feedback.

@carma12
carma12 force-pushed the privileges-permissions-page branch from 1e7b8e9 to 22c3228 Compare August 12, 2026 10:54
@carma12
carma12 requested review from duzda and veronnicka August 12, 2026 11:31

@duzda duzda 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.

Please do backend filtering, don't filter on the frontend, it will simplify the code by a lot, and will be much more useful.

Comment thread src/services/rpcPrivileges.ts Outdated
Comment thread src/pages/Privileges/PrivilegesPermissions.tsx Outdated
Comment thread src/pages/Privileges/PrivilegesPermissions.tsx Outdated
Comment thread src/pages/Privileges/PrivilegesPermissions.tsx Outdated
@carma12
carma12 force-pushed the privileges-permissions-page branch from 22c3228 to 6d24df3 Compare August 13, 2026 13:42
@veronnicka

Copy link
Copy Markdown
Contributor

Hi, apart from the comments, I suggest to add a BulkSelector (select page / select all) as in the other membership tables. Maybe it would be a good idea to add it to the .md files as well

Not sure if adding the BulkSelector in this page would be a good idea, as typically a Privilege doesn't have a hundred of permissions, and that would also require to modify other similar pages as this one to match with the same pattern. However, we can keep this discussion open and share this idea with other team members. WDYT?

The old webui has this feature, see
image

But if it doesnt align with the new design, Im fine with not adding it, I will leave it up to you.

@carma12
carma12 force-pushed the privileges-permissions-page branch from 6d24df3 to 9880627 Compare August 14, 2026 08:59
@carma12

carma12 commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator Author

Hi, apart from the comments, I suggest to add a BulkSelector (select page / select all) as in the other membership tables. Maybe it would be a good idea to add it to the .md files as well

Not sure if adding the BulkSelector in this page would be a good idea, as typically a Privilege doesn't have a hundred of permissions, and that would also require to modify other similar pages as this one to match with the same pattern. However, we can keep this discussion open and share this idea with other team members. WDYT?

The old webui has this feature, see image

But if it doesnt align with the new design, Im fine with not adding it, I will leave it up to you.

On a second thought, I see that the BulkSelector is actually in other pages like 'DNS zones>DNS records`, so maybe it would make sense to keep it for this and other subpages as well. I'll create an issue mentioning that and will be fixed in other pages in different PRs.

The 'Permissions' subpage allows to
grant or revoke some permissions to
a given Privilege.

Assisted-by: Claude <noreply@anthropic.com>
Signed-off-by: Carla Martinez <carlmart@redhat.com>
The `BulkSelector` component allows to
perform bulk operations in the table.

Assisted-by: Claude <noreply@anthropic.com>
Signed-off-by: Carla Martinez <carlmart@redhat.com>
Unless it is specified otherwise, the `BulkSelector`
component must be present in all the independent
subpages (i.e. any subpage that is not 'Settings',
'Is a member of' , 'Members', or 'ManagedBy`).

Assisted-by: Claude <noreply@anthropic.com>
Signed-off-by: Carla Martinez <carlmart@redhat.com>
@carma12
carma12 force-pushed the privileges-permissions-page branch from 84063a0 to c01759c Compare August 14, 2026 10:47

@veronnicka veronnicka 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.

Hi, the delete button is active even though no item is selected.
Please see my other comments as well.

Image

* @param {PrivilegesFullDataPayload} - Search parameters
* @returns {BatchRPCResponse} - Batch response with privilege data
*/
searchPrivilegesEntries: build.mutation<

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.

there is no hook for this so I think this is a redundant function?

const { cn } = useSafeParams<CnParams>(["cn"]);
const navigate = useNavigate();
const dispatch = useAppDispatch();
useContextualHelpTopic("privileges-settings");

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.

maybe this is intentional, but shouldnt the help context change with the tabs?

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

Labels

needs-review This PR is waiting on a review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants