docs: add admin pages + new components design spec

Covers MultiSelect, ConfirmDialog, InlineEdit components and
AuditLog, OidcConfig, UserManagement admin example pages.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-03-18 22:43:24 +01:00
parent dd4e01d6a7
commit d41961dbe2

View File

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