docs: add EntityList, docs updates, and inventory to spec

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-03-24 11:54:52 +01:00
parent c4cb2b2e31
commit b168d7c867

View File

@@ -84,6 +84,74 @@ interface SplitPaneProps {
---
## 2b. EntityList — New Composite
**Problem:** The left-side list panels in UsersTab, GroupsTab, and RolesTab all build the same frame: a search input + "Add" button header, a scrollable list of items (avatar + text + badges), and selection highlighting. Each tab re-implements this frame with ~50 lines of identical structure.
**Solution:** New composite `EntityList`.
```tsx
interface EntityListProps<T> {
items: T[]
renderItem: (item: T, isSelected: boolean) => ReactNode
getItemId: (item: T) => string
selectedId?: string
onSelect?: (id: string) => void
searchPlaceholder?: string // Default: "Search..."
onSearch?: (query: string) => void
addLabel?: string // e.g. "+ Add user" — omit to hide button
onAdd?: () => void
emptyMessage?: string // Default: "No items found"
className?: string
}
```
**Layout:**
- Header row: `Input` (search, with icon) on the left, `Button variant="secondary" size="sm"` (add) on the right. Header hidden when both `onSearch` and `onAdd` are omitted.
- Scrollable list below header, `var(--bg-surface)` background
- Each item: clickable row with `var(--bg-hover)` on hover, `var(--amber-bg)` + left amber border when selected
- Items rendered via `renderItem` — the component provides the clickable row wrapper, the caller provides the content
- `role="listbox"` on the list, `role="option"` on each item for accessibility
- Empty state: centered `emptyMessage` text when `items` is empty
**Typical item content (provided by caller via `renderItem`):**
- Avatar + name + subtitle + badge tags — but this is not prescribed by EntityList. The component is agnostic about item content.
**Combined usage with SplitPane:**
```tsx
<SplitPane
list={
<EntityList
items={filteredUsers}
renderItem={(user, isSelected) => (
<>
<Avatar name={user.name} size="sm" />
<div>
<div>{user.name}</div>
<div>{user.email}</div>
<div>{user.roles.map(r => <Badge key={r} label={r} />)}</div>
</div>
</>
)}
getItemId={(u) => u.id}
selectedId={selectedId}
onSelect={setSelectedId}
searchPlaceholder="Search users..."
onSearch={setSearchQuery}
addLabel="+ Add user"
onAdd={() => setAddDialogOpen(true)}
/>
}
detail={selectedUser ? <UserDetail user={selectedUser} /> : null}
/>
```
**File location:** `src/design-system/composites/EntityList/`
**Pages to refactor:** UsersTab.tsx, GroupsTab.tsx, RolesTab.tsx — replace custom list rendering with `<EntityList>`. Combined with SplitPane, each tab reduces from ~200 lines to ~50 lines of domain-specific render logic.
---
## 3. Refactor AgentHealth Instance Table to DataTable
**Problem:** AgentHealth builds instance tables using raw HTML `<table>` elements instead of the existing `DataTable` composite.
@@ -189,7 +257,7 @@ interface CardProps {
1. **KpiStrip** — highest impact, 3 pages, ~320 lines eliminated
2. **StatusText** — smallest scope, quick win, unblocks cleaner page code
3. **Card title** — small change to existing component, unblocks Routes cleanup
4. **SplitPane** — 3 admin tabs, clean pattern
4. **SplitPane + EntityList** — 3 admin tabs, clean pattern. Build together since EntityList is the natural content for SplitPane's list slot.
5. **LogViewer** — 1 page but important for real app
6. **AgentHealth DataTable refactor** — pure page cleanup, no DS changes
@@ -201,4 +269,27 @@ All new components tested with Vitest + React Testing Library, co-located test f
New components added to respective barrel exports:
- `src/design-system/primitives/index.ts` — StatusText
- `src/design-system/composites/index.ts` — KpiStrip, SplitPane, LogViewer
- `src/design-system/composites/index.ts` — KpiStrip, SplitPane, EntityList, LogViewer
## Documentation Updates
### COMPONENT_GUIDE.md
Add entries for each new component to the appropriate decision trees:
- **Data Display section:** Add KpiStrip — "Use KpiStrip for a row of summary metrics at the top of a page (exchanges, error rate, latency, etc.)"
- **Data Display section:** Add LogViewer — "Use LogViewer for scrollable log output with timestamped, severity-colored entries"
- **Layout section:** Add SplitPane — "Use SplitPane for master/detail layouts: selectable list on the left, detail view on the right"
- **Data Display section:** Add EntityList — "Use EntityList for searchable, selectable lists of entities (users, groups, roles, etc.). Combine with SplitPane for CRUD management screens."
- **Text & Labels section:** Add StatusText — "Use StatusText for inline colored status values (success rates, SLA status, trend indicators). Use StatusDot for colored dot indicators."
- **Card section:** Document new `title` prop — "Pass `title` to Card for a titled content container (e.g., chart cards). Title renders as an uppercase header with separator."
### Inventory Page
Add demos for each new component to `src/pages/Inventory/sections/`:
- **CompositesSection.tsx:** Add KpiStrip, SplitPane, EntityList, LogViewer demos with realistic sample data
- **PrimitivesSection.tsx:** Add StatusText demo showing all variants
- **Card demo:** Update existing Card demo to show the `title` prop variant
Each demo follows the existing DemoCard pattern with `id` anchors, and nav entries are added to `Inventory.tsx`.