Skip to content

Commit 53cc077

Browse files
authored
feat(user-mgmt): clarify group permissions combine via union (closes #1001) (#1008)
Add a brief helper note in the Group Membership expand panel explaining that a user's effective permissions are the union of all their groups' permissions, so assigning a lower-privilege group alongside a higher-privilege one has no effect (only redundancy, no conflict). No blocking/mutual-exclusion logic added; working-as-designed per #1001 Option A decision. Also add two unit tests asserting the hint text is rendered in the panel.
1 parent 3405060 commit 53cc077

2 files changed

Lines changed: 56 additions & 0 deletions

File tree

‎frontend/src/__tests__/users.test.ts‎

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2483,3 +2483,58 @@ describe('group assignment UX (issue #998)', () => {
24832483
});
24842484
});
24852485
});
2486+
2487+
// ============================================================================
2488+
// GROUP UNION HINT (issue #1001)
2489+
// ============================================================================
2490+
describe('group union permission hint (issue #1001)', () => {
2491+
const mockUsers = [
2492+
{ id: '1', email: 'alice@test.com', groups: ['g1'], mfa_enabled: false },
2493+
];
2494+
const mockGroups = [
2495+
{ id: 'g1', name: 'Admins', permissions: [], description: '', allowed_accounts: [] },
2496+
{ id: 'g2', name: 'Viewers', permissions: [], description: '', allowed_accounts: [] },
2497+
];
2498+
2499+
beforeEach(() => {
2500+
document.body.innerHTML = `
2501+
<div id="users-list"></div>
2502+
<div id="user-stats"></div>
2503+
<div id="bulk-actions-bar" class="hidden">
2504+
<span id="selected-count">0</span>
2505+
</div>
2506+
`;
2507+
userState.setAllUsers(mockUsers as any);
2508+
userState.setFilteredUsers(mockUsers as any);
2509+
userState.setAvailableGroups(mockGroups as any);
2510+
userState.clearSelectedUserIds();
2511+
jest.clearAllMocks();
2512+
});
2513+
2514+
it('renders the union hint in the group membership expand panel', () => {
2515+
userList.renderUsers(mockUsers as any);
2516+
2517+
const expandBtn = document.querySelector<HTMLButtonElement>(
2518+
'.user-expand-btn[data-user-id="1"]',
2519+
);
2520+
expect(expandBtn).toBeTruthy();
2521+
expandBtn!.click();
2522+
2523+
const panel = document.querySelector('.user-expand-panel[data-user-id="1"]');
2524+
expect(panel).toBeTruthy();
2525+
expect(panel!.textContent).toContain('combined (union) of all selected groups');
2526+
});
2527+
2528+
it('hint appears in expand-panel-groups section, before the checkbox list', () => {
2529+
userList.renderUsers(mockUsers as any);
2530+
2531+
const expandBtn = document.querySelector<HTMLButtonElement>(
2532+
'.user-expand-btn[data-user-id="1"]',
2533+
);
2534+
expandBtn!.click();
2535+
2536+
const groupsSection = document.querySelector('.expand-panel-groups');
2537+
expect(groupsSection).toBeTruthy();
2538+
expect(groupsSection!.textContent).toContain('combined (union) of all selected groups');
2539+
});
2540+
});

‎frontend/src/users/userList.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ function renderUserExpandPanel(user: APIUser): string {
182182
<div class="expand-panel-body">
183183
<div class="expand-panel-groups">
184184
<h5>Group Membership</h5>
185+
<p class="text-muted">A user receives the combined (union) of all selected groups&#8217; permissions, so adding a lower-privilege group alongside a higher one has no effect.</p>
185186
${availableGroups.length === 0
186187
? '<p class="text-muted">No groups defined yet.</p>'
187188
: `<div class="group-checkbox-list">

0 commit comments

Comments
 (0)