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

176
design/detail-window.md Normal file
View File

@@ -0,0 +1,176 @@
# Detail Window Feature Specification
## Overview
A detail window shows one view (YAML / Describe / Logs / Shell) for one Kubernetes object. Windows are grouped into krates and can be resized/moved within their container.
## Core Responsibilities
- Display object data in one of four view types
- Allow window dragging within krate
- Support window resizing with proportional sibling adjustment
- Implement maximize/restore functionality
- Route keyboard focus on mouse-over
## Window Types
### Detail View (default)
- **Purpose**: Display static object information
- **Content types**: YAML, Describe, Logs (for pods/workloads)
### Collection Window
- **Purpose**: List/Tree view of multiple objects
- **Special features**: Filter input, selection highlighting, view shortcuts
## Window anatomy (380×362px default)
### Header (36px height)
- Left: Shape glyph (8px, color-coded by object type)
- Middle: View label (uppercase, accent-colored) + object name + status badge
- Right: × button (close window)
- **Cursor**: `grab` — drag to reposition within canvas
- **Double-click header**: Maximize / restore window
- **Drag**: Move window within krate
### Tab Bar
- Tabs: YAML · Describe · Logs · Shell
- Shell tab: disabled (opacity 0.45) for non-exec object types
- Active tab: accent underline/highlight
- Click tab: Switch view content
### Content Area (286px height)
- Element: `<pre>` (preformatted text)
- Styling:
- `overflow: auto`
- `height: 286px`
- `font-family: 'IBM Plex Mono'`
- `font-size: 12px`
- `line-height: 1.65`
- Scrollbar:
- Width: 8px
- Color: rgba(140,165,200,.18)
## Resize Behavior
### Resize Handle
- Positioned at bottom-right corner
- Drag to resize
- **Proportional adjustment**: When one window resized, siblings in same column/row resize proportionally
- Storage: Use `rowHeights` and `colWidths` arrays per krate (future enhancement)
### Window Grid
- **Column pitch**: 412px
- **Row pitch**: 416px
- **Window default**: 380×362px (leaves room for grip/padding)
## Maximize Functionality
### Maximize State
- Width: `viewport.width - 44px` (22px margins)
- Height: `viewport.height - topBarHeight(68px) - bottomBarHeight(66px)`
- Camera adjusted: `camX = 22 - krate.wx - window.dx`, `camY = 68 - krate.wy - window.dy`, `zoom = 1`
### Trigger
- **Key**: `z` (when mouse is over window)
- **Mouse**: Double-click header
- Restore: Same trigger again
## Keyboard Focus Routing
### Mouse-Over Detection
- Track `mouseenter`/`mouseleave` per window
- Set `hoveredWindowId` ref
- Clear on `mouseleave`
### Key Event Routing
Global `keydown` handler with `{ capture: true }`:
```
if (hoveredWindowId is shell) {
route keypress to shell
} else if (hoveredWindowId is collection) {
route keypress to filter input
} else {
let it fall through to canvas shortcuts
}
```
### Shell Special Case
- Space character goes to terminal (NOT spotlight)
- Must distinguish between canvas space-pan and shell space-input
## View-Specific Content
### YAML View
- Display full object YAML
- **Secret objects**: Base64-decode all data values
- Show banner: `⊙ secret values auto-decoded`
- Security: Handle carefully, never log decoded values
### Describe View
- Human-readable object description
- Formatted for readability
- All metadata sections included
### Logs View
- **Pods/workloads only**
- **Live-tailing**: Stream via WebSocket
- Auto-scroll to bottom on new lines (unless user scrolled up)
- Color-code:
- ERROR: `#ef6f6f`
- WARN: `#e8b54a`
- INFO: `#b9c6d8`
### Shell View
- **Implementation**: xterm.js (real terminal)
- **Backend**: WebSocket → `kubectl exec -it <pod> -n <ns> -- sh`
- **Keyboard routing**: Route keypresses to terminal, passthrough terminal output
- **Scroll wheel**: Scroll terminal content (NOT canvas pan)
- **Ctrl/⌘+scroll**: Zoom canvas (not terminal zoom)
## Collection Window Specifics
### Size
- Default: 540×480px (larger than detail windows)
### Header
- Title: `pods · ns/payments`
- Status summary badges: `✓ N / ⚠ N / ✗ N`
- Filter input (auto-focused on open)
- List / Tree toggle buttons
- Keyboard hint: `↑↓ ⌥L/S/D/Y`
### List Mode
- Rows: shape glyph + name + health metric + type badge + view buttons + status dot
- Selected row: `background: accentDim; border-left: 2px solid accent`
- Hover row: `background: rgba(255,255,255,.04)`
- Sorted: degraded/failed first, then pending, then ready; alpha within groups
### Tree Mode (k9s xray)
- Workloads expand to show pods
- Pods expand to show configMaps, secrets, PVCs
- Services/ingresses expand to show targets
- Relation tags: `pod`, `configMap`, `secret`, `volume`, `selects`, `routes`, `used by`
- Indent: `20px * depth`
- Filtering: Keep matching nodes + all ancestors for hierarchy
## Window State
```typescript
interface Window {
wid: string; // unique window ID
kind: 'detail' | 'collection';
tab: 'logs' | 'shell' | 'describe' | 'yaml';
dx: number; // offset within krate (column * 412)
dy: number; // offset within krate (row * 416)
w: number; // width
h: number; // height
isMaximized: boolean; // current state
prevW?: number; // previous width (for restore)
prevH?: number; // previous height (for restore)
}
```
## Gotchas
1. **Space key**: Must distinguish between canvas space-pan (capture with `{ capture: true }`) and shell space-input
2. **Ctrl/⌘+scroll**: Use `{ capture: true }` on canvas to intercept before window scroll containers
3. **Secret decoding**: Do server-side or careful client-side; never log decoded values
4. **Window resizing**: Proportional siblings requires storing `rowHeights`/`colWidths` arrays (not just individual `dx/dy`)
5. **Focus routing**: Mouse-over + type should focus shell/filter, not trigger canvas shortcuts
6. **Collection auto-focus**: On creation, focus filter input in next tick using ref + `useEffect`