docs: add admin section redesign spec
Based on 3-expert UX/UI review: fixes critical --bg-base bug, migrates AuditLog to DataTable, replaces admin nav with Tabs, reworks user creation with provider-aware flow, adds password management, toast feedback, and accessibility improvements. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
207
docs/superpowers/specs/2026-03-18-admin-redesign.md
Normal file
207
docs/superpowers/specs/2026-03-18-admin-redesign.md
Normal file
@@ -0,0 +1,207 @@
|
||||
# Admin Section Redesign Spec
|
||||
|
||||
**Date:** 2026-03-18
|
||||
**Scope:** UX/UI consistency overhaul of AuditLog, OidcConfig, UserManagement admin pages
|
||||
|
||||
## Overview
|
||||
|
||||
Three expert reviews identified critical bugs, consistency gaps, and usability issues in the admin section. This spec covers all changes organized by priority tier.
|
||||
|
||||
---
|
||||
|
||||
## Tier 1: Critical Bugs
|
||||
|
||||
### 1.1 Replace nonexistent `--bg-base` token
|
||||
|
||||
`--bg-base` is referenced 3 times but does not exist in `tokens.css`. Dark mode is broken.
|
||||
|
||||
**Files:**
|
||||
- `Admin.module.css` line 6: `.adminNav`
|
||||
- `UserManagement.module.css` lines 13, 19: `.listPane`, `.detailPane`
|
||||
|
||||
**Fix:** Replace all `var(--bg-base)` with `var(--bg-surface)`.
|
||||
|
||||
### 1.2 Change AuditEvent `id` to string
|
||||
|
||||
`DataTable` requires `T extends { id: string }`. Current `AuditEvent.id` is `number`.
|
||||
|
||||
**Files:**
|
||||
- `auditMocks.ts`: change `id: number` to `id: string`, update all IDs to `'audit-1'`, `'audit-2'`, etc.
|
||||
- `AuditLog.tsx`: update `expandedId` state from `number | null` to `string | null`
|
||||
|
||||
---
|
||||
|
||||
## Tier 2: High-Impact Consistency
|
||||
|
||||
### 2.1 Replace admin nav with Tabs composite
|
||||
|
||||
The hand-rolled admin nav in `Admin.tsx` lacks ARIA roles and has subtle color differences from the Tabs composite.
|
||||
|
||||
**Fix:** Replace the custom `<nav>` block with:
|
||||
```tsx
|
||||
<Tabs
|
||||
tabs={[
|
||||
{ label: 'User Management', value: '/admin/rbac' },
|
||||
{ label: 'Audit Log', value: '/admin/audit' },
|
||||
{ label: 'OIDC', value: '/admin/oidc' },
|
||||
]}
|
||||
active={location.pathname}
|
||||
onChange={(path) => navigate(path)}
|
||||
/>
|
||||
```
|
||||
|
||||
Delete `.adminNav`, `.adminTab`, `.adminTabActive` from `Admin.module.css`.
|
||||
|
||||
### 2.2 Remove duplicate page titles
|
||||
|
||||
Breadcrumb + active tab + h2 heading all show the same label. Remove the h2.
|
||||
|
||||
**Files:**
|
||||
- `AuditLog.tsx`: remove the `.header` div with `<h2>Audit Log</h2>`. Move the event count badge into a toolbar row.
|
||||
- `OidcConfig.tsx`: remove the `.header` div with `<h2>`. Keep Save/Test buttons in a compact toolbar row below the tabs.
|
||||
|
||||
Delete `.header`, `.title` CSS from both `AuditLog.module.css` and `OidcConfig.module.css`.
|
||||
|
||||
### 2.3 Migrate AuditLog to DataTable
|
||||
|
||||
Replace the hand-built `<table>` with the DataTable composite.
|
||||
|
||||
**Column definitions:**
|
||||
- Timestamp: render with `MonoText`, width `'170px'`
|
||||
- User: render with bold text
|
||||
- Category: render with `Badge color="auto"`
|
||||
- Action: plain text
|
||||
- Target: render with ellipsis style
|
||||
- Result: render with `Badge color={row.result === 'SUCCESS' ? 'success' : 'error'}`
|
||||
|
||||
**Features to enable:**
|
||||
- `sortable` on Timestamp, User, Category, Result columns
|
||||
- `rowAccent={(row) => row.result === 'FAILURE' ? 'error' : undefined}` — red left-border on failures
|
||||
- `expandedContent={(row) => <detail block with IP, user agent, CodeBlock>}`
|
||||
- `pageSize={10}`
|
||||
- `flush` prop (table sits inside a card wrapper)
|
||||
|
||||
**Card wrapper:** Wrap DataTable in a section with `background: var(--bg-surface)`, `border: 1px solid var(--border-subtle)`, `border-radius: var(--radius-lg)`, `box-shadow: var(--shadow-card)`. Add a header row with title + event count badge, matching Dashboard's `.tableSection` pattern.
|
||||
|
||||
**Delete from AuditLog.module.css:** `.tableWrap`, `.table`, `.th`, `.row`, `.td`, `.userCell`, `.target`, `.empty`, `.detailRow`, `.detailCell`, `.detailGrid`, `.detailField`, `.detailLabel`, `.detailValue`, `.detailJson`. Also remove the separate `Pagination` import — DataTable handles pagination internally.
|
||||
|
||||
### 2.4 Fix content padding
|
||||
|
||||
`Admin.module.css` `.adminContent`: change `padding: 20px` to `padding: 20px 24px 40px`.
|
||||
|
||||
### 2.5 Center OIDC form
|
||||
|
||||
`OidcConfig.module.css` `.page`: add `margin: 0 auto` to center the 640px max-width form.
|
||||
|
||||
### 2.6 Replace inline style
|
||||
|
||||
`UserManagement.tsx` line 20: replace `style={{ marginTop: 16 }}` with a CSS class `.tabContent { margin-top: 16px; }` in `UserManagement.module.css`.
|
||||
|
||||
---
|
||||
|
||||
## Tier 3: Usability Improvements
|
||||
|
||||
### 3.1 Add toast notifications to RBAC mutations
|
||||
|
||||
Import `useToast` into `UsersTab.tsx`, `GroupsTab.tsx`, `RolesTab.tsx`. Fire toasts on:
|
||||
- Create user/group/role: `variant: 'success'`
|
||||
- Delete user/group/role: `variant: 'warning'`
|
||||
- Role assigned/removed: `variant: 'success'`
|
||||
- Group added/removed: `variant: 'success'`
|
||||
|
||||
### 3.2 Rework user creation form
|
||||
|
||||
Replace the flat inline form with a provider-aware two-step form.
|
||||
|
||||
**Form structure:**
|
||||
1. **Provider selection** — RadioGroup with "Local" and "OIDC" options. Default: "Local".
|
||||
2. **Fields (always shown):** Username (required), Display name (optional), Email (optional)
|
||||
3. **Fields (Local only):** Password (required)
|
||||
4. **OIDC info callout:** When OIDC selected, show an InfoCallout: "OIDC users authenticate via the configured identity provider. Pre-register to assign roles/groups before their first login."
|
||||
|
||||
**Components used:** RadioGroup + RadioItem (existing primitive), Input, InfoCallout (existing primitive), Button.
|
||||
|
||||
**Create handler:** Set `provider` based on RadioGroup selection. Only validate password when provider is 'local'.
|
||||
|
||||
The form should use the existing inline pattern (appears at the top of the list pane), but use a proper card-like treatment (the existing `.createForm` background is fine).
|
||||
|
||||
### 3.3 Add password management to user detail pane
|
||||
|
||||
Add a "Security" section (using `SectionHeader`) in the user detail pane, below the metadata grid.
|
||||
|
||||
**For local users:**
|
||||
- Show "Password: ••••••••" with a "Reset password" Button
|
||||
- Clicking "Reset password" reveals an inline form: Input (type=password, placeholder "New password") + Cancel/Set buttons
|
||||
- Setting fires a success toast: "Password updated"
|
||||
|
||||
**For OIDC users:**
|
||||
- Show "Authentication: OIDC ({provider})"
|
||||
- Show InfoCallout: "Password managed by the identity provider."
|
||||
- No password reset option
|
||||
|
||||
### 3.4 Add ConfirmDialog to cascading removals
|
||||
|
||||
When removing a group from a user (which may strip inherited roles), show a confirmation dialog if the group grants roles.
|
||||
|
||||
When removing a role from a group (which affects all members), show a confirmation dialog.
|
||||
|
||||
Direct role removal from a user does not need confirmation (low risk).
|
||||
|
||||
### 3.5 Make entity list items keyboard accessible
|
||||
|
||||
Add to each `.entityItem` div:
|
||||
- `role="option"`
|
||||
- `tabIndex={0}`
|
||||
- `aria-selected={selectedId === item.id}`
|
||||
- `onKeyDown`: Enter/Space to select, ArrowUp/ArrowDown to navigate
|
||||
|
||||
Add `role="listbox"` and `aria-label` to each `.entityList` container.
|
||||
|
||||
### 3.6 Add expand/collapse affordance to AuditLog
|
||||
|
||||
After DataTable migration (2.3), add a first column with a chevron indicator (`>` / `v`) that rotates when the row is expanded. Width: `'40px'`. This makes the expandable row pattern discoverable.
|
||||
|
||||
### 3.7 Add duplicate name validation
|
||||
|
||||
Before creating, check for existing names:
|
||||
- Users: `users.some(u => u.username === newUsername.trim())`
|
||||
- Groups: `groups.some(g => g.name.toLowerCase() === newName.trim().toLowerCase())`
|
||||
- Roles: `roles.some(r => r.name === newName.trim().toUpperCase())`
|
||||
|
||||
Show inline error using state + red text below the name field. Disable Create button.
|
||||
|
||||
### 3.8 Partial FilterBar migration for AuditLog
|
||||
|
||||
After DataTable migration, use FilterBar for search + category filters:
|
||||
- Search input maps to FilterBar's built-in search
|
||||
- Categories (INFRA, AUTH, USER_MGMT, CONFIG) become FilterPill toggles
|
||||
- Keep DateRangePicker and user filter Input alongside FilterBar in a row
|
||||
|
||||
### 3.9 Add empty-search states to entity lists
|
||||
|
||||
When search returns no results in Users/Groups/Roles lists, show centered muted text: "No users match your search" (etc.) inside the `.entityList` area.
|
||||
|
||||
---
|
||||
|
||||
## Tier 4: Polish
|
||||
|
||||
### 4.1 Replace lock emoji with Badge
|
||||
|
||||
`RolesTab.tsx`: replace `🔒` with `<Badge label="system" color="auto" variant="outlined" />`.
|
||||
|
||||
### 4.2 Fix split-pane border radius
|
||||
|
||||
`UserManagement.module.css`: change `border-radius: var(--radius-md)` to `var(--radius-lg)` on `.splitPane`, `.listPane`, `.detailPane`.
|
||||
|
||||
### 4.3 Add shadow to split-pane
|
||||
|
||||
`UserManagement.module.css`: add `box-shadow: var(--shadow-card)` to `.splitPane`.
|
||||
|
||||
---
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- Replacing split-pane with DataTable+DetailPanel (not appropriate for dense editing)
|
||||
- EventFeed as alternative audit view (future enhancement)
|
||||
- Tabs inside user detail pane (not needed until more sections are added)
|
||||
- FilterBar extension to support DateRangePicker slots (separate design system ticket)
|
||||
Reference in New Issue
Block a user