- 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
177 lines
5.8 KiB
Markdown
177 lines
5.8 KiB
Markdown
# 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`
|