Files
opencode-krates-connector/design/detail-window.md
Hermes Agent 78f19cde7d 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
2026-06-16 08:32:47 -04:00

177 lines
5.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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`