Skip to content

fix(studio): forward-port Roles select-all filter fix and 3.9 polish (studio#1116) - #8592

Merged
sfmskywalker merged 1 commit into
mainfrom
cursor/studio-roles-select-all-c00c
Oct 3, 2026
Merged

sfmskywalker merged 1 commit into
mainfrom
cursor/studio-roles-select-all-c00c

Conversation

@sfmskywalker

@sfmskywalker sfmskywalker commented Oct 3, 2026 •

Copy link
Copy Markdown
Member

Purpose

Forward-port elsa-studio #1116 into elsa-core main, where Studio now lives under src/studio after the consolidation.

Refs elsa-studio #1114
Refs elsa-studio #1115
Refs elsa-studio #1116


Scope

  • Bug fix (behavior change)
  • Refactor (no behavior change)
  • Documentation update
  • Formatting / code cleanup
  • Dependency / build update
  • New feature

Description

Problem

Select all in the Roles create/edit editor ignored the permission filter and granted every permission in the category. The Roles list and editor also still shipped leftover loader copy and lecture text that 3.9 trimmed in studio.

Solution

Port of studio 0ad1874859fdd5beabfdac980ab13ee7f9b372af (#1116) into src/studio/modules/Elsa.Studio.Security and its tests:

  1. Select all / Deselect act only on the resources currently visible under the active filter. The category summary counts only what is on screen.
  2. 3.9-safe polish from the Roles UX review (items 1–6, 8–14, 18–19).
  3. Deselect uses the same selectable set as Select all, so a wildcard-covered exact grant is not dropped.

F4 work already on main (#8586, #8587) is preserved: KeepPanelsAlive on the permission tabs, in-place advanced-grant editing, and the permission-refresh signal on administration access boundaries.

3.9-safe checklist

# Change
1 Cut the Exact-permissions lecture.
2 Cut the Core-generates-ID helper and the read-only ID caption.
3 List count is N role(s); hide it when empty; drop the footer, suffixes, and check icon. Same on mobile.
4 Hide the header counter at zero; otherwise N selected.
5 Cut the Advanced lecture. Empty state is No wildcards.
6 Also covered by … once per resource row. Covered-only verbs still show the chip.
8 Search and permission filter: no field label; placeholder Name, ID, or permission.
9 Add advanced grant → Add. Safe-delete Close → Cancel. Create first role stays.
10 Edit title is {name}. ID stays under the title.
11 One Wildcard chip. 1 resource today / N resources today.
12 Safe delete: no banner; hide the 0 · 0 line; token sentence shortened. Delete {name} kept. Other delete states unchanged.
13 ID column (and mobile ID) hidden. ID remains on the edit header.
14 Select all toggles to Deselect when the visible set is fully selected.
18 Delete is text, Cancel outline, Save filled primary.
19 Filtered-empty card has Clear search.

Out of scope (3.10): 15 tab renames, 16 permission-preview redesign, 17 Remove duplicates, 20 blocked/remediation delete copy.


Verification

Server host: dotnet build src/studio/hosts/Elsa.Studio.Host.Server/Elsa.Studio.Host.Server.csproj --configuration Release — Build succeeded, 0 warnings, 0 errors (net8/net9/net10).

WASM host: dotnet build src/studio/hosts/Elsa.Studio.Host.Wasm/Elsa.Studio.Host.Wasm.csproj --configuration Release — Build succeeded, 0 warnings, 0 errors (net8/net9/net10).

Security tests: dotnet test src/studio/modules/Elsa.Studio.Security.Tests/Elsa.Studio.Security.Tests.csproj --configuration Release — 154 passed, 0 failed (net10.0), including:

  • SelectAll_WithAnActiveFilter_GrantsOnlyTheVisibleResources
  • SelectAll_TogglesToDeselectForTheVisibleSet
  • Deselect_PreservesExactGrantsThatAreAlsoCoveredByAWildcard
  • PermissionCounter_HidesAtZeroAndShowsSelectedCount
  • ExactGrantCoveredByAWildcard_ShowsOneNotePerResource
  • AdvancedGrants_UseASingleWildcardChipAndSingularResourceCopy
  • Render_WhenSearchMatchesNothing_HidesTheCountAndClearSearchRestoresTheList
  • Render_WhenImpactIsSafe_ShowsSafeConfirmationAndDeleteAction

Administration tests: dotnet test src/studio/modules/Elsa.Studio.Administration.Tests/Elsa.Studio.Administration.Tests.csproj --configuration Release — 65 passed, 0 failed (net10.0).

Reverting the filter-aware Select all (passing the unfiltered category into ToggleCategory) makes SelectAll_WithAnActiveFilter_GrantsOnlyTheVisibleResources fail (Assert.False expected false, actual true on a hidden resource after Select all). The revert was not committed.

Live browser pass was not run here: this environment has no Elsa Core identity backend.


Checklist

  • The PR is focused on a single concern
  • Commit messages follow the recommended convention
  • Tests added or updated (if applicable)
  • Documentation updated (if applicable)
  • No unrelated cleanup included
  • All tests pass
Open in Web Open in Cursor 

Port elsa-studio #1116 into the consolidated Studio tree: Select all and
Deselect act only on resources visible under the active filter, Deselect
keeps wildcard-covered exact grants, and the 3.9-safe Roles list/editor
copy is trimmed. F4 keep-alive tabs, in-place advanced grant editing, and
permission-refresh boundaries are unchanged.

Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com>
@coderabbitai

coderabbitai Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 56d683a2-4f0c-4916-902d-a015aad0acf3
📥 Commits

Reviewing files that changed from the base of the PR and between b104fd2 and 4083e9e.

📒 Files selected for processing (8)
  • src/studio/modules/Elsa.Studio.Security.Tests/DeleteRoleDialogTests.cs
  • src/studio/modules/Elsa.Studio.Security.Tests/RoleEditorSurfaceTests.cs
  • src/studio/modules/Elsa.Studio.Security.Tests/RolesPageTests.cs
  • src/studio/modules/Elsa.Studio.Security/Components/DeleteRoleDialog.razor
  • src/studio/modules/Elsa.Studio.Security/Components/DeleteRoleDialog.razor.cs
  • src/studio/modules/Elsa.Studio.Security/Components/RoleAdvancedGrantCard.razor
  • src/studio/modules/Elsa.Studio.Security/Components/RoleEditorSurface.razor
  • src/studio/modules/Elsa.Studio.Security/Pages/Roles.razor
 ____________________________________________________________________________________________________________________
< Always design for concurrency. Allow for concurrency, and you'll design cleaner interfaces with fewer assumptions. >
 --------------------------------------------------------------------------------------------------------------------
  \
   \   \
        \ /\
        ( )
      .( o ).
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

@cursor

cursor Bot commented Oct 3, 2026

Copy link
Copy Markdown

@greptileai

@greptile-apps

greptile-apps Bot commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 5/5

[Medium risk] Updates role management UI and test assertions.

The confirmed permissions-display issue is non-blocking; the PR is safe to merge with this finding.

Findings

  1. P2 Wildcard notes lose verb context ▶
Fix with agent prompt
### Issue 1
src/studio/modules/Elsa.Studio.Security/Components/RoleEditorSurface.razor:174-178
When different wildcards cover exact grants for different verbs of the same resource, the editor now groups their “Also covered by” notes under the resource instead of beside the relevant checkboxes. An administrator must work out which note describes each exact grant from the wildcard text, making the permissions display misleading.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

The PR updates the role editor’s permission controls and simplifies role-management UI copy. In the changed editor, wildcard redundancy notes appear under the resource rather than beside the verbs they describe. This makes overlapping grants harder to interpret, but does not block merging.

Reviews (2) · Last reviewed commit: "fix(studio): forward-port Roles select-a..."

@greptile-apps

greptile-apps Bot commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

Comments Outside Diff

These findings could not be posted inline.

  • P1 Same-named roles lack identifiers src/studio/modules/Elsa.Studio.Security/Pages/Roles.razor:326 ▶

    A role can be renamed to match another visible role. The desktop and mobile lists now omit their IDs, leaving the roles with identical displayed names and action labels although the actions target different IDs. An administrator cannot tell which role they are opening or deleting; restore a visible identifier before merging.

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@sfmskywalker sfmskywalker left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Elsa 3 Code Review: APPROVE + HIGH @ 4083e9e

Code Review, Round 1/4

Scope: main @ b104fd2d (F4: #8586 + #8587 merged) ← 4083e9e7. One commit, 8 files under src/studio/modules/Elsa.Studio.Security*. Forward-port of studio#1116, whose merge 0ad18748 has the same tree as the approved head c94032a2.

Verdict: No blockers. The port matches #1116 line for line. All 3.9 tests are ported. No 3.10 item is included. The F4 behaviour is unchanged. Permission semantics change only in how far Select all/Deselect reach.

Fidelity to #1116

  • I compared the changed lines of 2842adf0..c94032a2 (studio) with b104fd2d..4083e9e7 (core) file by file, after mapping the paths. All 5 production files are identical: RoleEditorSurface.razor, RoleAdvancedGrantCard.razor, DeleteRoleDialog.razor(.cs) and Roles.razor. So are RolesPageTests.cs and DeleteRoleDialogTests.cs.
  • RoleEditorSurfaceTests.cs has one extra line: Assert.DoesNotContain("Direct grant", …) in the edit-render test. Studio already had this assertion and core's base did not, so the port brings the two files back in line.
  • After the port, the only differences between the studio and core files are the ones that already existed. Core keeps its extra @using Elsa.Studio.Security.Models and its extra workflows/definitions:update assertion.
  • The test method sets in all three test files are identical to studio's head. All 7 new #1116 tests are present, and so are the updated assertions for items 1–6, 8–14, 18 and 19.
  • 3.10 items are out:
    • 15: the tabs are still Exact permissions / Advanced grants.
    • 16: RolePermissionPreview is untouched.
    • 17: there is no Remove duplicates.
    • 20: in DeleteRoleDialog only the SafeConfirmation branch and its CloseLabel changed. The blocked, remediation, incomplete and last-default copy is unchanged.

F4 behaviour

  • KeepPanelsAlive is still on the permission MudTabs (RoleEditorSurface.razor:121).
  • In-place advanced-grant editing: the card's edit branch, BeginEditAdvancedGrant and ApplyAdvancedGrantEditAsync, are untouched. The existing in-place edit tests pass.
  • Access boundary (B2): RoleAdministrationAccessBoundary is not touched. During a re-check it still keeps the content mounted, passes down CanCreate/CanUpdate/CanDelete = false, and queues changes that arrive mid-check.
    • The new bulk action fits this model. The Select all/Deselect button only renders when !IsReadOnly, and ToggleCategory, SelectCategory and DeselectCategory all return early when IsReadOnly.
    • I added a scratch probe that re-renders the editor with the re-check access and then with the restored access. While access is being re-checked, Select all/Deselect and Save are hidden. Once access is restored, Deselect is back. The filter and the selection are kept through both steps.
    • RoleAdministrationAccessBoundaryTests (including Render_WhenChangedArrivesDuringACheck_KeepsEditsAndHonoursTheQueuedRefresh) pass.

Permission semantics

  • The save payload is unchanged. It is still NormalizePermissions(_direct ∪ _advanced ∪ _unresolved) into CreateRoleRequest / UpdateRoleRequest.
  • LoadStoredGrants, RolePermissionAuthoring and wildcard validation and matching are all unchanged. There are no API or contract changes.
  • Select all adds the same uncovered exact grants as before, but only for visible resources. Deselect removes exactly that set. Wildcards, unresolved grants, hidden resources and covered exact grants are kept.

Revert probes

Mutation Result
Select all widened back to the whole category SelectAll_WithAnActiveFilter_GrantsOnlyTheVisibleResources fails
Category summary widened back to the whole category SelectAll_WithAnActiveFilter_GrantsOnlyTheVisibleResources fails
Deselect back to all concrete grants (the Deselect wildcard fix reverted) Deselect_PreservesExactGrantsThatAreAlsoCoveredByAWildcard fails
Deselect widened to the whole category No ported test fails; only a scratch probe catches it (N3)

Edge cases

I ran these as scratch bUnit tests (not committed). All pass on the head:

  • Empty filter: Select all grants all 9 verbs and shows 9 selected and Deselect; Deselect clears all 9.
  • Filtered Deselect with a hidden grant: saves ["identity/applications:view"].
  • identity/*:view + filtered Select all: saves the wildcard plus roles:create and roles:update only.
  • Deselect with a covered exact grant: saves identity/*:view and identity/roles:view.
  • Everything covered by identity/*:*: Select all does nothing, and the save is unchanged.
  • Partly selected visible set: Select all completes only the visible resource.
  • Access re-check: see F4 behaviour above.

Builds and tests

  • Elsa.Studio.Host.Server Release (net8/9/10): build succeeded, 0 warnings, 0 errors.
  • Elsa.Studio.Host.Wasm Release (net8/9/10): build succeeded, 0 warnings, 0 errors.
  • Elsa.Studio.Security.Tests: 154/154 passed. Elsa.Studio.Administration.Tests: 65/65 passed.
  • Solution grouping: scripts/solution unit tests passed (8/8), and solution_groups.py --check reports "Solution grouping and 10 filters are up to date." The Solution groups workflow did not run in CI, because no .sln, .slnf or .csproj changed.

Security and maintainability

There are no new inputs, no markup injection and no change to authorization. Maintainability is the same as #1116. SelectableGrants is the single source for Select all, Deselect and the fully-selected check, and the port is a clean copy of that design.

Non-blocking (carried over from #1116; all still apply)

  • N1. N selected mixes units. SelectedCount = direct + covered + advanced, so identity/roles:* alone shows 4 selected with no box checked. Greptile raised this again here (thread at RoleEditorSurface.razor:325, open).
  • N2. The Roles browser spec is stale. test/studio/browser/RoleManagement/role-management.spec.ts still targets Filter permissions, Add advanced grant, Search roles by name, ID, or permission, all loaded|matching search and 0 roles · matching search. CI does not run it.
  • N3. Test gap. No test proves that a filtered Deselect keeps grants on hidden resources (the widen-Deselect mutation passes the suite).
  • N4. Select all can do nothing. When every visible verb is covered by a wildcard, Select all is shown but does nothing. Greptile raised this here (thread at RoleEditorSurface.razor:524, open).
  • N5. Dead CSS. The .role-id rule in Roles.razor (line 83) no longer has any users.

These are best fixed in studio first and then ported, so the two copies stay identical.

CI, Greptile and threads on 4083e9e7

  • Green: pr / ubuntu-latest (Compile + Test), CodeQL and all its Analyze jobs, select-tests, GitGuardian and CLA. run-affected-tests was skipped. CodeRabbit was skipped because the PR is a draft.
  • Greptile: 4/5 at 4083e9e7 (advisory only).
  • Threads: 2, both open and both from Greptile. They match N1 and N4 and are non-blocking.

Gate: APPROVE + HIGH and green CI on 4083e9e7. Before merging, the PR still needs to come out of draft, and the two open Greptile threads need a reply or resolution, since GitHub currently reports the merge state as BLOCKED.

@sfmskywalker
sfmskywalker marked this pull request as ready for review October 3, 2026 21:01
@sfmskywalker
sfmskywalker merged commit ee2f80c into main Oct 3, 2026
16 of 17 checks passed
@sfmskywalker
sfmskywalker deleted the cursor/studio-roles-select-all-c00c branch October 3, 2026 21:01
Comment on lines +174 to +178
@foreach (var covering in alsoCovered)
{
<MudTooltip Text="The wildcard already grants this; the exact grant is redundant.">
<span class="role-grant-state">Also covered by @covering</span>
</MudTooltip>

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.

P2 Wildcard notes lose verb context

When different wildcards cover exact grants for different verbs of the same resource, the editor now groups their “Also covered by” notes under the resource instead of beside the relevant checkboxes. An administrator must work out which note describes each exact grant from the wildcard text, making the permissions display misleading.

Artifacts

Authored bUnit test for two wildcard-covered verbs

  • This executable test renders the role with both exact grants and wildcards and checks which verb option contains each note; it passes before the PR and fails after it.

Chromium capture script for the rendered permission row

  • This script opens each actual bUnit-rendered row in Playwright Chromium and records its visible text, video, and poster; the recordings compare the same scenario.

bUnit result at the previous review SHA

  • The recorded dotnet test command passes and prints both notes inside their respective verb options; verb association is visible before the PR.

▶ Previous rendered editor row with notes beside each verb

  • Chromium displays the bUnit-rendered row from the previous review SHA, where each wildcard note accompanies its applicable verb.

Poster of previous row with verb-associated notes

  • The captured Chromium frame shows the previous render's wildcard notes within the verb options; their associations remain visible.

Chromium capture output for the previous row

  • The recorded capture command reports wildcard notes in both verb options and exits successfully; it confirms what the previous video displays.

bUnit result at the current PR HEAD

  • The same recorded dotnet test command fails and prints two resource-level notes but verb options containing only update and view; the associations are lost.

▶ Current rendered editor row with notes detached from verbs

  • Chromium displays the bUnit-rendered PR row with both wildcard notes beside the resource and none inside its verb options; the changed placement is visible.

Poster of current row with resource-level notes

  • The captured Chromium frame shows both notes grouped under the resource rather than beside update and view; the verb context is absent.

Chromium capture output for the current row

  • The recorded capture command reports both notes in the resource row and verb options containing only their labels; it confirms the current video's visible result.

View artifacts

T-Rex Ran code and verified through T-Rex

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/studio/modules/Elsa.Studio.Security/Components/RoleEditorSurface.razor
Line: 174-178

Comment:
**Wildcard notes lose verb context**

When different wildcards cover exact grants for different verbs of the same resource, the editor now groups their “Also covered by” notes under the resource instead of beside the relevant checkboxes. An administrator must work out which note describes each exact grant from the wildcard text, making the permissions display misleading.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

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.

2 participants