Covers MultiSelect, ConfirmDialog, InlineEdit components and AuditLog, OidcConfig, UserManagement admin example pages. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
9.0 KiB
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:
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
onChangewith 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:
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
confirmTextexactly - 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:
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:
- Header — "Audit Log" title + event count badge
- Filter bar — DateRangePicker (from/to), Input (user), Select (category: INFRA/AUTH/USER_MGMT/CONFIG), Input (search)
- Data table — DataTable with columns: Timestamp (monospace), User, Category (Badge), Action, Target, Result (Badge with success/error color)
- Expandable rows — Clicking a row reveals detail section with IP address, user agent, and JSON detail (CodeBlock)
- 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:
- Header — "OIDC Configuration" + Save/Test/Delete buttons
- Behavior — Two Toggle fields (Enabled, Auto Sign-Up) wrapped in FormField
- Provider Settings — FormField-wrapped Inputs for Issuer URI, Client ID, Client Secret (type=password)
- Claim Mapping — FormField-wrapped Inputs for Roles Claim, Display Name Claim with hint text
- Default Roles — Tag list (removable) + Input + Button to add new roles
- 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