92 lines
5.2 KiB
Markdown
92 lines
5.2 KiB
Markdown
|
|
# 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).
|