# 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: `
` (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 -n -- 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`