# 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` — 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).