Skip to content

fix: collapse full-access role categories into "All <category> actions" in Access Control#647

Open
UdaraWickramarathne wants to merge 6 commits into
openchoreo:mainfrom
UdaraWickramarathne:fix/2907-collapse-actions
Open

fix: collapse full-access role categories into "All <category> actions" in Access Control#647
UdaraWickramarathne wants to merge 6 commits into
openchoreo:mainfrom
UdaraWickramarathne:fix/2907-collapse-actions

Conversation

@UdaraWickramarathne

@UdaraWickramarathne UdaraWickramarathne commented Jun 22, 2026

Copy link
Copy Markdown

Purpose

Resolves openchoreo/openchoreo#2907
(openchoreo/openchoreo#2907).

In Access Control, a role's actions were rendered individually. A role granted
every action in a category (e.g. all alerts or all metrics operations,
persisted one-by-one) listed each operation as its own chip, producing long,
noisy lists. The action selection dialog already collapses these on
confirm, so the same role looked different depending on where you viewed it
(Roles table vs. edit dialog vs. selection dialog).

Goals

Display role actions consistently in their collapsed form everywhere: when a
role grants every action in a category, show a single chip — e.g. "All alerts
actions", "All metrics actions" — instead of listing each operation, matching
what the selection dialog produces.

Approach

  • Add normalizeActions() in a new RolesTab/actionUtils.ts. It round-trips a
    role's stored actions through expandWildcardsconvertToWildcards,
    reusing the same per-category collapsing logic the selection dialog applies
    on confirm, so display and edit stay in sync. If the action catalog hasn't
    loaded yet (availableActions empty) it returns the input unchanged, so
    nothing is dropped before we can tell which categories are complete.
  • RolesTable: fetch the action catalog via useActions(), render the
    normalized actions as chips, and label fully-granted categories through
    getActionDisplayLabel as "All actions" (e.g. "All alerts
    actions"). The "+N more" overflow now counts the collapsed chips.
  • RoleDialog: collapse actions on load (when editing a role) and when
    applying a role template; the effect re-runs once availableActions
    resolves.
  • Unit tests in actionUtils.test.ts cover the expand/collapse/normalize paths
    and the empty-catalog passthrough.

Before the change

Before.webm

After the change

After.webm

User stories

As a platform engineer managing roles, I want a role's permissions shown
compactly and consistently across the Roles table and edit dialog, so I can see
at a glance which categories a role fully grants.

Release note

Access Control: when a role grants every action in a category, the Roles table
and Role dialog now show a single collapsed chip (e.g. "All alerts actions",
"All metrics actions") instead of listing each individual action, matching the
action selection dialog.

Documentation

N/A

Training

N/A

Certification

N/A

Marketing

N/A

Automation tests

  • Unit tests

    Added actionUtils.test.ts covering expandWildcards,
    convertToWildcards, and normalizeActions (full-category collapse,
    partial selection kept individual, and empty-catalog passthrough).

  • Integration tests

    N/A — no backend/integration surface changed.

Security checks

  • Followed secure coding standards? yes
  • Ran FindSecurityBugs plugin and verified report? N/A — TypeScript/React frontend; no Java.
  • Confirmed no keys, passwords, tokens, usernames, or other secrets committed? yes

Samples

N/A

Related PRs

N/A

Migrations (if applicable)

N/A

Test environment

  • Node.js 22, Yarn 4.4.1
  • Local Backstage dev server against k3d OpenChoreo 1.2.0-m.1
  • Browser: Chrome (latest)

Learning

N/A

Summary by CodeRabbit

  • New Features
    • Role action lists now display compactly: when a role grants all actions in a category, the UI shows a single collapsed entry (e.g., “All component actions”) instead of listing every operation.
    • The Roles table and Role dialog also normalize action display after the action catalog loads, and the “Select Actions” count reflects the expanded granular selection.
  • Tests
    • Added/extended test coverage for role action normalization, validation, save behavior (including forbidden/403 messaging), and delete flows with binding checks.

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@UdaraWickramarathne, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 46 minutes and 29 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses rolling per-developer review limits. Reviews become available again as older review attempts age out of the rolling limit window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4a80089e-a962-48f1-98c3-f53f0c21ed31

📥 Commits

Reviewing files that changed from the base of the PR and between 5bfb6aa and 467af58.

📒 Files selected for processing (2)
  • plugins/openchoreo/src/components/AccessControl/RolesTab/actionUtils.test.ts
  • plugins/openchoreo/src/components/AccessControl/RolesTab/actionUtils.ts
📝 Walkthrough

Walkthrough

Adds a normalizeActions utility to actionUtils.ts that converts a role's fully-expanded stored action list into wildcard form (category:* or *) for display. Integrates it into RolesTable row rendering and RoleDialog state initialization. Adds test suites for the utility, RolesTable, and RoleDialog, plus a changeset entry.

Changes

Role actions display normalization

Layer / File(s) Summary
normalizeActions utility and tests
plugins/openchoreo/src/components/AccessControl/RolesTab/actionUtils.ts, actionUtils.test.ts, .changeset/normalize-role-actions-display.md
normalizeActions expands then re-collapses stored actions into * / category:* / individual form; returns input unchanged when the action catalog is not yet loaded. Preserves unknown/stale actions not in the catalog without introducing duplicates. Tests assert wildcard collapsing, idempotency, partial-category preservation, empty-catalog pass-through, and stale-action handling. Changeset marks the patch release.
RolesTable normalized chip rendering and tests
plugins/openchoreo/src/components/AccessControl/RolesTab/RolesTable.tsx, RolesTable.test.tsx
Imports useActions, normalizeActions, and getActionDisplayLabel; memoizes availableActions from the hook; derives displayActions per row and renders chips with human-readable labels. "No actions" check and "+N more" overflow are now based on displayActions. Tests validate chip display, wildcard collapsing, "+N more", search, edit/delete permission gating, async deletion binding-check flow, and active-binding blocking.
RoleDialog normalized state initialization and tests
plugins/openchoreo/src/components/AccessControl/RolesTab/RoleDialog.tsx, RoleDialog.test.tsx
Editing useEffect initializes selectedActions via normalizeActions instead of raw role actions. handleApplyTemplate normalizes template actions against availableActions. granularActionCount (from expanding wildcards) replaces selectedActions.length on the "Select Actions" button label. Tests cover normalization on open, template wildcard collapsing, name validation, save payload shape, and forbidden/generic error handling.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • sameerajayasoma
  • stefinie123
  • kaviththiranga

Poem

🐇 Hoppity-hop through the actions so wide,
Where wildcards now fold what once couldn't hide.
"All component actions!" — one chip takes the place
Of a dozen long names cluttering up the space.
The rabbit collapses the sprawl with a grin,
Clean chips in the table — let the review begin!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: collapsing full-access role categories into a single 'All actions' chip in the Access Control UI.
Description check ✅ Passed The PR description comprehensively covers all major template sections with clear purpose, goals, approach with implementation details, user stories, release notes, and automation testing information.
Linked Issues check ✅ Passed The PR fully addresses issue #2907 by implementing consistent action display normalization across RolesTable and RoleDialog using the same collapse logic as the selection dialog.
Out of Scope Changes check ✅ Passed All changes are tightly scoped to the objective of normalizing action display: actionUtils for collapse/expand logic, RolesTable and RoleDialog for applying normalization, and comprehensive test coverage.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

…RolesTable

Signed-off-by: Udara Wickramarathne <bimsaraudara25@gmail.com>
@UdaraWickramarathne UdaraWickramarathne force-pushed the fix/2907-collapse-actions branch from 07643a8 to bb6feca Compare June 22, 2026 09:33

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

Thank you for your contribution @UdaraWickramarathne

@codecov

codecov Bot commented Jun 22, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 20.83333% with 19 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...c/components/AccessControl/RolesTab/RolesTable.tsx 0.00% 17 Missing ⚠️
...c/components/AccessControl/RolesTab/RoleDialog.tsx 0.00% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

Signed-off-by: Udara Wickramarathne <bimsaraudara25@gmail.com>
@UdaraWickramarathne UdaraWickramarathne force-pushed the fix/2907-collapse-actions branch from 1d6f37f to fdf5d72 Compare June 23, 2026 05:01
@stefinie123

Copy link
Copy Markdown
Contributor

@UdaraWickramarathne Even when actions are normalized and collapsed the action count should reflect the actual number of granular actions, not the number of collapsed actions. Shall we fix this as well

@UdaraWickramarathne

UdaraWickramarathne commented Jun 23, 2026

Copy link
Copy Markdown
Author

@UdaraWickramarathne Even when actions are normalized and collapsed the action count should reflect the actual number of granular actions, not the number of collapsed actions. Shall we fix this as well

Fixed with fe530cf

…ns count

Signed-off-by: Udara Wickramarathne <bimsaraudara25@gmail.com>
@UdaraWickramarathne UdaraWickramarathne force-pushed the fix/2907-collapse-actions branch from a609b5d to fe530cf Compare June 23, 2026 05:57

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

Actionable comments posted: 3

🧹 Nitpick comments (2)
plugins/openchoreo/src/components/AccessControl/RolesTab/actionUtils.test.ts (1)

13-65: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a regression test for stale/unknown action preservation.

Please add one case where actions contains an entry absent from AVAILABLE_ACTIONS and assert normalization keeps it. This locks in non-destructive behavior.

🧪 Suggested test case
 describe('normalizeActions', () => {
+  it('preserves stale actions that are missing from the current catalog', () => {
+    const actions = ['component:view', 'legacy:read'];
+    expect(normalizeActions(actions, AVAILABLE_ACTIONS)).toEqual([
+      'component:view',
+      'legacy:read',
+    ]);
+  });
+
   it('returns the input unchanged when the action catalog has not loaded yet', () => {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/openchoreo/src/components/AccessControl/RolesTab/actionUtils.test.ts`
around lines 13 - 65, Add a new test case within the
describe('normalizeActions') block that verifies the function preserves unknown
or stale actions. Create a test that calls normalizeActions with an array
containing both recognized actions from AVAILABLE_ACTIONS and an action that
does not exist in the catalog, then assert that the function returns the result
with the unknown action preserved unchanged. This ensures the normalizeActions
function has non-destructive behavior when encountering actions outside the
available catalog.
plugins/openchoreo/src/components/AccessControl/RolesTab/RoleDialog.test.tsx (1)

68-166: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a regression test for preserving user input across async action-catalog load.

Please add a create-mode test that types a role name before actions finish loading, then simulates catalog arrival and verifies the typed name and selected template/actions are not reset.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/openchoreo/src/components/AccessControl/RolesTab/RoleDialog.test.tsx`
around lines 68 - 166, Add a new test case within the RoleDialog describe block
that tests preserving user input across async action-catalog loads. The test
should render the dialog in create mode with mockUseActions initially returning
a loading state (loading: true), then use userEvent to type a role name,
optionally click a template button to select actions, then update the mock to
return the actual actions (simulating catalog load completion), and finally
verify using screen queries that the typed role name and selected
actions/template have been preserved and not reset.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@plugins/openchoreo/src/components/AccessControl/RolesTab/actionUtils.ts`:
- Around line 123-126: The normalization process in the return statement using
`expandWildcards` and `convertToWildcards` silently drops any actions from the
input that don't exist in the `availableActions` catalog, causing permission
loss on save. Modify the logic to preserve these unknown or stale actions
alongside the normalized catalog-backed actions. After calling
`convertToWildcards(expandWildcards(actions, availableActions),
availableActions)`, merge the result with any actions from the input that were
not present in `availableActions` to ensure no permissions are lost during the
normalization round-trip.

In `@plugins/openchoreo/src/components/AccessControl/RolesTab/RoleDialog.tsx`:
- Around line 321-333: The useEffect hook that initializes the form state in the
RoleDialog component has availableActions in its dependency list, causing it to
re-run whenever the action metadata updates and resetting the form with initial
values, which wipes unsaved changes in both create and edit modes. Remove
availableActions from the dependency array of this useEffect, keeping only
editingRole and open as dependencies, since availableActions should not trigger
a reset of the in-progress form state; this way the form will only reinitialize
when explicitly opening the dialog or switching to edit a different role.

In `@plugins/openchoreo/src/components/AccessControl/RolesTab/RolesTable.tsx`:
- Around line 214-217: The calculation in the Chip label at line 216 uses
displayActions.length - 5, but displayActions has already had wildcard actions
collapsed (e.g., component:* counts as 1 item). To correctly show how many
actual granted actions are hidden, replace displayActions.length with the count
of the original ungrouped actions before any collapse or grouping was applied.
Track or pass the actual total action count from the source data and use that
instead of the collapsed displayActions array length in the calculation.

---

Nitpick comments:
In
`@plugins/openchoreo/src/components/AccessControl/RolesTab/actionUtils.test.ts`:
- Around line 13-65: Add a new test case within the describe('normalizeActions')
block that verifies the function preserves unknown or stale actions. Create a
test that calls normalizeActions with an array containing both recognized
actions from AVAILABLE_ACTIONS and an action that does not exist in the catalog,
then assert that the function returns the result with the unknown action
preserved unchanged. This ensures the normalizeActions function has
non-destructive behavior when encountering actions outside the available
catalog.

In
`@plugins/openchoreo/src/components/AccessControl/RolesTab/RoleDialog.test.tsx`:
- Around line 68-166: Add a new test case within the RoleDialog describe block
that tests preserving user input across async action-catalog loads. The test
should render the dialog in create mode with mockUseActions initially returning
a loading state (loading: true), then use userEvent to type a role name,
optionally click a template button to select actions, then update the mock to
return the actual actions (simulating catalog load completion), and finally
verify using screen queries that the typed role name and selected
actions/template have been preserved and not reset.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: b06a7350-0ffc-4796-ad03-bb34efd2b45c

📥 Commits

Reviewing files that changed from the base of the PR and between d03eaf7 and a609b5d.

📒 Files selected for processing (7)
  • .changeset/normalize-role-actions-display.md
  • plugins/openchoreo/src/components/AccessControl/RolesTab/RoleDialog.test.tsx
  • plugins/openchoreo/src/components/AccessControl/RolesTab/RoleDialog.tsx
  • plugins/openchoreo/src/components/AccessControl/RolesTab/RolesTable.test.tsx
  • plugins/openchoreo/src/components/AccessControl/RolesTab/RolesTable.tsx
  • plugins/openchoreo/src/components/AccessControl/RolesTab/actionUtils.test.ts
  • plugins/openchoreo/src/components/AccessControl/RolesTab/actionUtils.ts

Comment thread plugins/openchoreo/src/components/AccessControl/RolesTab/actionUtils.ts Outdated
Comment thread plugins/openchoreo/src/components/AccessControl/RolesTab/RolesTable.tsx Outdated
…le edits

Signed-off-by: Udara Wickramarathne <bimsaraudara25@gmail.com>
Signed-off-by: Udara Wickramarathne <bimsaraudara25@gmail.com>

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
plugins/openchoreo/src/components/AccessControl/RolesTab/actionUtils.test.ts (1)

13-91: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add a regression test for ['*', stale] normalization.

The suite validates global collapse and stale preservation independently, but not together. Please add a case asserting normalizeActions(['*', 'foo:bar'], AVAILABLE_ACTIONS) returns ['*', 'foo:bar'] so global-collapse behavior stays stable when stale permissions are preserved.

🧪 Suggested test addition
 describe('normalizeActions', () => {
@@
   it('does not duplicate a known category wildcard when preserving', () => {
@@
   });
+
+  it('keeps global wildcard collapsed while preserving stale actions', () => {
+    expect(normalizeActions(['*', 'foo:bar'], AVAILABLE_ACTIONS)).toEqual([
+      '*',
+      'foo:bar',
+    ]);
+  });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/openchoreo/src/components/AccessControl/RolesTab/actionUtils.test.ts`
around lines 13 - 91, Add a regression test case to the normalizeActions
describe block that validates the function correctly handles the combination of
global wildcard collapse and stale action preservation together. Create a test
that calls normalizeActions with an array containing the global wildcard '*' and
a stale action 'foo:bar' against AVAILABLE_ACTIONS, and assert that the result
preserves both elements as ['*', 'foo:bar'] unchanged. This ensures that
global-collapse behavior remains stable when stale permissions coexist with the
global wildcard.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@plugins/openchoreo/src/components/AccessControl/RolesTab/actionUtils.ts`:
- Around line 123-126: Stale or unknown actions in the actions array are
preventing the global wildcard from collapsing because they increase the size
checked by the gate in convertToWildcards. Before passing actions to
expandWildcards on line 123, filter out any actions that are not present in
availableActions. This ensures only valid known actions are processed, allowing
convertToWildcards to properly collapse to the global '*' wildcard when
appropriate instead of returning category wildcards.

---

Nitpick comments:
In
`@plugins/openchoreo/src/components/AccessControl/RolesTab/actionUtils.test.ts`:
- Around line 13-91: Add a regression test case to the normalizeActions describe
block that validates the function correctly handles the combination of global
wildcard collapse and stale action preservation together. Create a test that
calls normalizeActions with an array containing the global wildcard '*' and a
stale action 'foo:bar' against AVAILABLE_ACTIONS, and assert that the result
preserves both elements as ['*', 'foo:bar'] unchanged. This ensures that
global-collapse behavior remains stable when stale permissions coexist with the
global wildcard.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0cf8f956-8919-4621-9a0f-2fdbf3ad66b0

📥 Commits

Reviewing files that changed from the base of the PR and between a609b5d and 5bfb6aa.

📒 Files selected for processing (5)
  • plugins/openchoreo/src/components/AccessControl/RolesTab/RoleDialog.test.tsx
  • plugins/openchoreo/src/components/AccessControl/RolesTab/RoleDialog.tsx
  • plugins/openchoreo/src/components/AccessControl/RolesTab/RolesTable.tsx
  • plugins/openchoreo/src/components/AccessControl/RolesTab/actionUtils.test.ts
  • plugins/openchoreo/src/components/AccessControl/RolesTab/actionUtils.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • plugins/openchoreo/src/components/AccessControl/RolesTab/RoleDialog.test.tsx
  • plugins/openchoreo/src/components/AccessControl/RolesTab/RolesTable.tsx
  • plugins/openchoreo/src/components/AccessControl/RolesTab/RoleDialog.tsx

Comment thread plugins/openchoreo/src/components/AccessControl/RolesTab/actionUtils.ts Outdated
Signed-off-by: Udara Wickramarathne <bimsaraudara25@gmail.com>
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.

Actions are not collapsed in role listing and role editing pages in Backstage

3 participants