diff --git a/docs/superpowers/specs/2026-03-18-admin-pages-design.md b/docs/superpowers/specs/2026-03-18-admin-pages-design.md new file mode 100644 index 0000000..0796b37 --- /dev/null +++ b/docs/superpowers/specs/2026-03-18-admin-pages-design.md @@ -0,0 +1,226 @@ +# Admin Pages + New Components Design + +**Date:** 2026-03-18 +**Scope:** 3 new design system components + 3 admin example pages + +## Overview + +Transfer the admin section from cameleer3-server UI to the design system project as example pages. Add three new reusable components to the design system that are needed by these pages and useful generally. + +## New Design System Components + +### 1. MultiSelect (primitive) + +Dropdown trigger that opens a popover with searchable checkbox list and "Apply" action. + +**Props:** +```typescript +interface MultiSelectOption { + value: string + label: string +} + +interface MultiSelectProps { + options: MultiSelectOption[] + value: string[] + onChange: (value: string[]) => void + placeholder?: string // default: "Select..." + searchable?: boolean // default: true + disabled?: boolean + className?: string +} +``` + +**Behavior:** +- Click trigger → popover opens below with search input + checkbox list + "Apply (N)" footer +- Search filters options by label (case-insensitive) +- Checkboxes toggle selection; changes are local until "Apply" is clicked +- Apply calls `onChange` with selected values and closes popover +- Click outside or Escape closes without applying +- Trigger shows count: "2 selected" or placeholder when empty + +**Implementation:** +- New directory: `src/design-system/primitives/MultiSelect/` +- Uses Popover composite for positioning +- CSS Modules with design tokens +- No forwardRef needed (not a native form control) + +### 2. ConfirmDialog (composite) + +Modal dialog requiring the user to type a confirmation string before a destructive action proceeds. + +**Props:** +```typescript +interface ConfirmDialogProps { + open: boolean + onClose: () => void + onConfirm: () => void + title?: string // default: "Confirm Deletion" + message: string // e.g., "Delete user 'alice'? This cannot be undone." + confirmText: string // text the user must type to enable confirm button + confirmLabel?: string // default: "Delete" + cancelLabel?: string // default: "Cancel" + variant?: 'danger' | 'warning' // default: 'danger' + className?: string +} +``` + +**Behavior:** +- Built on Modal (size="sm") +- Shows title, message, text input with label "Type '{confirmText}' to confirm" +- Confirm button disabled until input matches `confirmText` exactly +- Input clears on open +- Enter submits when enabled; Escape closes +- Confirm button uses danger/warning variant styling + +**Implementation:** +- New directory: `src/design-system/composites/ConfirmDialog/` +- Reuses Modal internally (same pattern as AlertDialog) +- Auto-focuses input on open + +### 3. InlineEdit (primitive) + +Click-to-edit text field that toggles between display and edit modes. + +**Props:** +```typescript +interface InlineEditProps { + value: string + onSave: (value: string) => void + placeholder?: string // shown when value is empty in display mode + disabled?: boolean + className?: string +} +``` + +**Behavior:** +- **Display mode:** Shows value as text with subtle edit icon (pencil). Clicking text or icon enters edit mode. +- **Edit mode:** Input field with current value. Enter or blur saves. Escape cancels (reverts to original value). +- If saved value is empty and placeholder exists, display mode shows placeholder in muted style. +- No save/cancel buttons — Enter saves, Escape cancels (lightweight inline pattern). + +**Implementation:** +- New directory: `src/design-system/primitives/InlineEdit/` +- Uses `forwardRef` (wraps an input) +- Manages internal editing state + +## Admin Pages + +### Route Structure + +``` +/admin → redirects to /admin/rbac +/admin/audit → AuditLog page +/admin/oidc → OidcConfig page +/admin/rbac → UserManagement page (tabs: Users | Groups | Roles) +``` + +All pages use the standard AppShell + Sidebar + TopBar layout with breadcrumbs. + +### Sidebar Integration + +Add admin links to the Sidebar bottom links. The existing Sidebar component already supports `bottomLinks` — add entries for Audit Log, OIDC, and User Management. + +Update the mock sidebar data in `src/mocks/sidebar.ts` to include admin navigation, and update the Sidebar usage across all example pages. + +### Page: Audit Log (`src/pages/Admin/AuditLog/`) + +**Layout:** Full-width content area (no split pane). + +**Sections:** +1. **Header** — "Audit Log" title + event count badge +2. **Filter bar** — DateRangePicker (from/to), Input (user), Select (category: INFRA/AUTH/USER_MGMT/CONFIG), Input (search) +3. **Data table** — DataTable with columns: Timestamp (monospace), User, Category (Badge), Action, Target, Result (Badge with success/error color) +4. **Expandable rows** — Clicking a row reveals detail section with IP address, user agent, and JSON detail (CodeBlock) +5. **Pagination** — Pagination component below table + +**Mock data:** ~30 audit events with varied categories, actions, results. + +### Page: OIDC Config (`src/pages/Admin/OidcConfig/`) + +**Layout:** Single-column form layout, max-width constrained. + +**Sections:** +1. **Header** — "OIDC Configuration" + Save/Test/Delete buttons +2. **Behavior** — Two Toggle fields (Enabled, Auto Sign-Up) wrapped in FormField +3. **Provider Settings** — FormField-wrapped Inputs for Issuer URI, Client ID, Client Secret (type=password) +4. **Claim Mapping** — FormField-wrapped Inputs for Roles Claim, Display Name Claim with hint text +5. **Default Roles** — Tag list (removable) + Input + Button to add new roles +6. **Delete** — Button (danger) that opens ConfirmDialog + +**Mock data:** Pre-filled form state with sample OIDC config. + +### Page: User Management (`src/pages/Admin/UserManagement/`) + +**Layout:** Tabs component at top (Users | Groups | Roles). Each tab has a CSS grid split-pane (roughly 52/48). + +#### Users Tab +- **Left pane:** Input search + "Add user" Button + scrollable user list. Each item: Avatar + name + provider Badge + meta (email, group path) + Tag list (roles: amber, groups: green, inherited: dashed Badge). +- **Inline create form:** Appears at top of list when "Add user" clicked. Input fields for username, display, email, password. Cancel/Create buttons. +- **Right pane (detail):** Large Avatar + InlineEdit (display name) + email + Delete Button. Metadata fields (Status, ID as MonoText, Created). SectionHeader "Group membership" + Tag list (removable) + MultiSelect to add groups. SectionHeader "Effective roles" + Tag list (direct: solid, inherited: dashed with source label) + MultiSelect to add roles. +- **Delete:** ConfirmDialog (type username to confirm). + +#### Groups Tab +- **Left pane:** Same pattern — search + "Add group" + group list. Each item: Avatar (square) + name + meta (parent, child count, member count) + role Tags. +- **Inline create form:** Name input + parent Select (top-level or existing group). +- **Right pane:** Avatar + InlineEdit (name) + hierarchy label. Metadata (ID, Parent — editable via Select). SectionHeader "Members" + Tag list. SectionHeader "Child groups" + Tag list. SectionHeader "Assigned roles" + removable Tags + MultiSelect. SectionHeader "Hierarchy" with indented tree display. +- **Delete:** ConfirmDialog. + +#### Roles Tab +- **Left pane:** Search + "Add role" + role list. Each item: Avatar (square) + name + lock icon if system + meta (description, assignment count) + Tags. +- **Inline create form:** Name, Description, Scope inputs. +- **Right pane:** Avatar + role name (non-editable for system roles) + description. Metadata (ID, Scope, Type). SectionHeader "Assigned to groups" (read-only list). SectionHeader "Assigned to users (direct)" (read-only). SectionHeader "Effective principals" with inherited entries in dashed style. +- **Delete:** ConfirmDialog (only for non-system roles). + +**Mock data:** ~8 users, ~4 groups (with nesting), ~6 roles (including system roles ADMIN, USER). Realistic role/group assignments with inheritance. + +### Inventory Updates + +Add demos for all three new components: + +- **MultiSelect** → PrimitivesSection: Demo showing multi-select with sample options, displaying selected count +- **InlineEdit** → PrimitivesSection: Demo showing display/edit toggle with a sample name +- **ConfirmDialog** → CompositesSection: Demo with a "Delete item" button that opens the dialog + +## File Structure + +``` +src/design-system/primitives/MultiSelect/ + MultiSelect.tsx + MultiSelect.module.css + MultiSelect.test.tsx + +src/design-system/primitives/InlineEdit/ + InlineEdit.tsx + InlineEdit.module.css + InlineEdit.test.tsx + +src/design-system/composites/ConfirmDialog/ + ConfirmDialog.tsx + ConfirmDialog.module.css + ConfirmDialog.test.tsx + +src/pages/Admin/ + AuditLog/ + AuditLog.tsx + AuditLog.module.css + auditMocks.ts + OidcConfig/ + OidcConfig.tsx + OidcConfig.module.css + UserManagement/ + UserManagement.tsx + UserManagement.module.css + UsersTab.tsx + GroupsTab.tsx + RolesTab.tsx + rbacMocks.ts +``` + +## Out of Scope + +- No backend API integration (static mock data with useState) +- No persistence across page refresh +- No access control / role gating in the example app +- Dashboard tab from RBAC is excluded per user request +- Split pane is page-local CSS, not a design system component