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:
243
design/collection-window.md
Normal file
243
design/collection-window.md
Normal 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
|
||||
Reference in New Issue
Block a user