feat: Add comprehensive design documentation for Krates

- Canvas: Infinite zoomable workspace with LOD and navigation
- Spotlight: Fuzzy search with type filters and view shortcuts
- Krate: Window group container with non-overlapping placement
- Detail Window: YAML/Describe/Logs/Shell views with maximize
- Top Bar: Cluster info, user presence, admin toggle
- Admin Drawer: Multi-user presence and spectate functionality
- Minimap: Browse and navigate canvas overview
- Collection Window: List/tree views with filtering and sorting
- Shell/Logs: Real-time terminal and log streaming
- Backend: Go service with K8s API, WebSocket handlers, CRDT sync
- Architecture: Full project structure and tech stack
This commit is contained in:
Hermes Agent
2026-06-16 08:32:47 -04:00
parent b31fa3cde5
commit 78f19cde7d
12 changed files with 2709 additions and 2 deletions

243
design/collection-window.md Normal file
View File

@@ -0,0 +1,243 @@
# Collection Window Feature Specification
## Overview
A collection window provides an overview of Kubernetes objects in a category (All Pods, All Services, etc.) or namespace. It supports both list and tree views with filtering and selection.
## Default Size
- Width: 540px
- Height: 480px (larger than detail windows for better data visibility)
## Header
### Title
- Format: `pods · ns/payments` or `All Pods`
- Bold styling
### Status Summary
- Health badges: `✓ N / ⚠ N / ✗ N`
- Colors: OK=green, Warn=amber, Error=red
- Order: Ready/Warn/Error counts
### Filter Input
- Auto-focused on open
- Styling:
- `font-family: IBM Plex Mono`
- `font-size: 12px`
- Placeholder: `Filter...`
- Instant filtering (no debounce needed for <1000 items)
### View Toggle
- **List mode** button: `list icon`
- **Tree mode** button: `tree icon`
- Toggles between list and tree display
- Keyboard shortcut: `t` or click toggle button
### Keyboard Hint
- Always visible, muted text: `↑↓ ⌥L/S/D/Y`
- Shows navigation + view shortcuts
## List Mode
### Row Structure
Each row displays:
- Shape glyph (8px, color-coded by object type)
- Name (primary text)
- Relation tag (muted, for tree mode)
- Health metric (icon or text)
- Type badge (small, muted)
- View buttons: `⌥L`, `⌥S`, `⌥D`, `⌥Y` (hover show tooltips)
- Status dot (green/amber/red)
### Selection
- Selected row:
- Background: `accentDim` (subtle accent color)
- Left border: `2px solid accent`
- Hover row:
- Background: `rgba(255,255,255,.04)`
- Border-radius: 4px
### Sorting
1. Primary: Health status
- Degraded/failed first
- Then pending
- Then ready/running
2. Secondary: Alphabetical within each group
## Tree Mode (k9s xray-style)
### Hierarchy
- **Workloads expand to pods**:
- Deployment → pods
- StatefulSet → pods
- DaemonSet → pods
- **Pods expand to resources**:
- Pods show configMaps, secrets, PVCs
- **Services/Ingresses expand to targets**:
- Show selectors
- Show endpoints
### Relation Tags
Show as small icons or labels:
- `pod` (attached to pod rows)
- `configMap` (mounted volumes)
- `secret` (mounted secrets)
- `volume` (PVC)
- `selects` (service → pods)
- `routes` (ingress → service)
- `used by` (reverse relationships)
### Indentation
- Per depth: `20px` indentation
- Connector: L-shaped border element (vertical + horizontal)
- Visual hierarchy clear at a glance
### Expand/Collapse
- Click chevron/arrow: Toggle children
- Double-click name: Toggle
- Click anywhere else on row: Select row
### Filtering in Tree Mode
- Matching nodes + **all their ancestors** must stay visible
- Ancestors shown even if not matching, but with different styling
- Children hidden if no match
- Preserves hierarchy readability
## Keyboard Navigation
### List/Tree Mode
| Key | Context | Action |
|---|---|---|
| ↑ / ↓ | Collection focused | Move row selection |
| PageUp / PageDown | Collection focused | Move selection by page |
| Home / End | Collection focused | First / last row |
| Enter | Row selected | Open default view for selected row |
| ⌥L / ⌥S / ⌥D / ⌥Y | Row selected | Open view for selected row |
| Esc | Filter focused | Blur filter input |
| Esc | Collection focused | No-op (handle in krate) |
| t | Anywhere | Toggle list/tree view |
### Mouse + Type Routing
- Mouse-over collection window + type = focus filter input
- Similar to shell routing but for filter input
- Use `hoveredWindowId` ref to determine routing
## View Shortcuts
### Key Mapping (All use ⌥ Alt)
- `⌥L`: Open logs view (if supported)
- `⌥S`: Open shell view (if supported)
- `⌥D`: Open describe view
- `⌥Y`: Open YAML view
### Implementation
- Event listener with `event.code` for layout safety
- Open views in newly created krate (or existing if spotlight session)
- Shell tab disabled for non-exec types (opacity 0.45)
## View-Specific Content
### Logs View (Pods/Workloads Only)
- **Streaming**: WebSocket → `kubectl logs --follow`
- **Auto-scroll**: To bottom unless user scrolled up
- **Color coding**:
- ERROR: `#ef6f6f`
- WARN: `#e8b54a`
- INFO: `#b9c6d8`
- **Timestamps**: Optional toggle (hidden by default)
### Shell View (Pods Only)
- **Implementation**: xterm.js
- **Disabled**: For non-pod workloads, show disabled (muted)
- **Cursor**: Blinking block cursor
- **Key routing**: Route to shell when collected window hovered
### Describe View
- Human-readable object description
- All metadata sections
- Formatted for easy scanning
### YAML View
- Full object YAML
- **Secrets**: Decode data values
- Banner: `⊙ secret values auto-decoded`
- Monospace font, line numbers optional
## Filter Behavior
### Instant Filtering
- No debounce (fast for <1000 items)
- Debounce if dataset grows: 16ms
### Filter Logic
- Case-insensitive substring match
- Match against: name, labels, annotations, namespace
- For tree mode: Match name only (not ancestors)
### Clear Filter
- Esc key (when filter focused)
- Clear button (×) in input
- Empty string clears filter
### Keyboard Focus
1. Click collection window + type = focus filter
2. Click filter input = focus
3. Click anywhere else = blur filter, focus canvas shortcuts
## State Management
### Per-Window State
```typescript
interface CollectionState {
wid: string; // window ID
search: string; // filter text
view: 'list' | 'tree';
sel: number; // selected row index
expanded: Set<string>; // tree expansion state (node IDs)
}
```
### Data Loading
```typescript
interface CollectionData {
kind: string; // 'Pod', 'Service', etc.
namespace?: string; // undefined for "All Pods"
items: K8sObject[];
filtered: K8sObject[]; // after filter
treeData?: TreeNode[]; // tree mode intermediate
}
```
## Tree Node Structure
```typescript
interface TreeNode {
id: string; // unique within collection
name: string;
kind: string; // 'Pod', 'Deployment', etc.
obj: K8sObject | null; // null for synthetic nodes (e.g., "pods")
depth: number;
parentId: string | null;
children: string[]; // node IDs
relation: string; // 'pod', 'configMap', 'selects', etc.
hasChildren: boolean;
}
```
## Performance Considerations
### Large Datasets
- List virtualization: Only render visible rows (window height / row height)
- Tree optimization: Lazy expand (fetch children on expand, not preload)
- Filtering: Use efficient algorithms (no regex, simple string.match)
### Updates
- Throttle tree rebuild: 100ms
- Only rebuild if filter or data changed
- Keep expansion state on update (if node still exists)
## Gotchas
1. **Tree expansion**: Keep ancestors visible when filtering
2. **Auto-focus**: Focus filter input on window open (use ref + useEffect)
3. **View shortcuts**: Use `event.code` (layout-safe)
4. **Sorting priority**: Health first, then alphabetical
5. **Shell vs other types**: Disable shell tab for non-pod workloads
6. **Filter scope**: In tree mode, filter only on names, not on ancestors