Files
cameleer-server/docs/superpowers/specs/2026-04-16-runtime-compact-view-design.md

92 lines
5.2 KiB
Markdown
Raw Permalink Normal View History

# Runtime Dashboard — Compact View
## Summary
Add a compact/collapsed view mode to the runtime dashboard (AgentHealth page). In compact mode, each application is rendered as a small status card showing app name, live agent count, and last heartbeat, with health-state coloring (tinted background + tinted border + thick left accent border). Individual cards can be expanded inline to reveal the full agent instance table. A global toggle switches between compact and expanded views.
## Decisions
| Question | Decision |
|----------|----------|
| Default view | Compact — all apps start collapsed |
| Expand behavior | Inline — card expands in place, pushes others down |
| Grid layout | Auto-fill responsive (`repeat(auto-fill, minmax(220px, 1fr))`) |
| Toggle location | Inside stat strip area (icon toggle, no new toolbar row) |
| Health coloring | Same logic as existing `appHealth()` — worst agent state wins |
| Card styling | Tinted background (8% health color) + tinted border (25%) + 3px left accent border |
## View Mode State
- `viewMode: 'compact' | 'expanded'` — persisted to `localStorage` key `cameleer:runtime:viewMode`, default `'compact'`.
- `expandedApps: Set<string>` — tracks individually expanded app IDs. Ephemeral (not persisted).
- When `viewMode === 'compact'`: apps in `expandedApps` show the full GroupCard table. All others show compact cards.
- When `viewMode === 'expanded'`: all apps show the full GroupCard table (current behavior). `expandedApps` is ignored.
- Collapse all / expand all: sets `viewMode` and clears `expandedApps`.
## View Toggle
- Two-button icon toggle rendered in the `.statStrip` area after the last StatCard.
- Uses `Button` from `@cameleer/design-system` with `variant="ghost"`. Active button styled with `var(--running)` background.
- Icons: `LayoutGrid` (compact) / `List` (expanded) from `lucide-react`.
- `.statStrip` grid changes from `repeat(5, 1fr)` to `repeat(5, 1fr) auto` to accommodate the toggle.
## Compact Card (CompactAppCard)
Inline component in `AgentHealth.tsx` (page-specific, not reusable).
**Props:** `group: AppGroup`, `onExpand: () => void`.
**Layout:**
- Container: `var(--bg-raised)` with health-color tint via CSS custom property `--card-accent`.
- `background: color-mix(in srgb, var(--card-accent) 8%, var(--bg-raised))`
- `border: 1px solid color-mix(in srgb, var(--card-accent) 25%, transparent)`
- `border-left: 3px solid var(--card-accent)`
- `border-radius: var(--radius-md)`
- Cursor pointer, entire card clickable.
- **Row 1:** App name (font-weight 700, `var(--text-primary)`) left. `ChevronRight` icon (`var(--text-muted)`) right.
- **Row 2:** `"{liveCount}/{total} live"` in health color (font-weight 600) left. Last heartbeat right — computed as `timeAgo(max(instances.map(i => i.lastHeartbeat)))` (most recent across all instances in the group). Color: `var(--text-muted)` when healthy, health color when stale/dead.
- **Hover:** tint increases to 12%.
**Health color mapping** (reuses existing `appHealth()` function):
- `.compactCardSuccess``--card-accent: var(--success)`
- `.compactCardWarning``--card-accent: var(--warning)`
- `.compactCardError``--card-accent: var(--error)`
## Expanded Card in Compact Mode
- Renders existing `GroupCard` + `DataTable` unchanged.
- GroupCard header gets a `ChevronDown` icon button to collapse back.
- Expanded card gets `grid-column: span 2` in the compact grid for adequate table width (roughly matches current half-page GroupCard width).
- **Animation (single card toggle):** CSS transition on wrapper div with `overflow: hidden`. Expand: compact fades out (opacity 0, ~100ms), expanded fades in + grows (opacity 1, max-height transition, ~200ms ease-out). Collapse: reverse. Collapse-all / expand-all toggle is instant (no animation).
## Grid Layout
- `viewMode === 'expanded'`: existing `.groupGrid` (2-column `1fr 1fr`, unchanged).
- `viewMode === 'compact'`: new `.compactGrid` class:
```css
.compactGrid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
gap: 10px;
margin-bottom: 20px;
}
```
## Files Changed
| File | Change |
|------|--------|
| `ui/src/pages/AgentHealth/AgentHealth.tsx` | `viewMode`/`expandedApps` state, localStorage init, `CompactAppCard` component, view toggle in stat strip, conditional grid rendering |
| `ui/src/pages/AgentHealth/AgentHealth.module.css` | `.compactGrid`, `.compactCard`, `.compactCardSuccess/Warning/Error`, `.compactCardHeader`, `.compactCardMeta`, `.viewToggle`, `.viewToggleActive`, animation classes, `.statStrip` column adjustment |
| `.claude/rules/ui.md` | Add compact view mention under Runtime section |
No new files. No new design system components. No API changes. Feature is entirely contained in the AgentHealth page and its CSS module.
## Style Guide Compliance
- All colors via `@cameleer/design-system` CSS variables (`var(--success)`, `var(--warning)`, `var(--error)`, `var(--bg-raised)`, `var(--text-primary)`, `var(--text-muted)`, `var(--running)`, `var(--radius-md)`, `var(--border-subtle)`).
- No hardcoded hex values.
- Shared CSS modules imported where applicable.
- Design system components (`Button`, `GroupCard`, `DataTable`, `StatusDot`, `Badge`, `MonoText`) used throughout.
- `lucide-react` for icons (consistent with rest of UI).