docs: Finalize all design documents

Signed-off-by: Hermes Agent <hermes@nosuchhost>
This commit is contained in:
Hermes Agent
2026-06-16 09:00:33 -04:00
parent 76f0fb4b09
commit 89bc5e8c15
10 changed files with 384 additions and 423 deletions

View File

@@ -1,4 +1,4 @@
# Admin Drawer Feature Specification # Design Document: Admin Drawer Feature Specification
## Overview ## Overview
The admin drawer is a right-side panel that displays all users connected to the current yard (shared cluster workspace). It enables administrators to see real-time user activity and spectate on other users' workspaces. The admin drawer is a right-side panel that displays all users connected to the current yard (shared cluster workspace). It enables administrators to see real-time user activity and spectate on other users' workspaces.
@@ -34,7 +34,7 @@ The admin drawer is a right-side panel that displays all users connected to the
For each connected user (including self): For each connected user (including self):
### Avatar Section ### Avatar Section
- Circle: 40px直径 - Circle: 40px diameter
- Background: User color from palette - Background: User color from palette
- Content: - Content:
- For self: `★` (star) - For self: `★` (star)

View File

@@ -1,4 +1,4 @@
# Backend & Real-Time Sync Feature Specification # Design Document: Backend & Real-Time Sync Feature Specification
## Overview ## Overview
The backend service aggregates Kubernetes API data and provides real-time WebSocket connections for shell, logs, and multi-user collaboration. The backend service aggregates Kubernetes API data and provides real-time WebSocket connections for shell, logs, and multi-user collaboration.

View File

@@ -1,4 +1,4 @@
# Canvas Feature Specification # Design Document: Canvas Feature Specification
## Overview ## Overview
The canvas is the infinite zoomable/pannable workspace where krates live. It serves as the primary interaction surface for exploring Kubernetes clusters. The canvas is the infinite zoomable/pannable workspace where krates live. It serves as the primary interaction surface for exploring Kubernetes clusters.
@@ -39,8 +39,8 @@ interface CanvasState {
## Navigation ## Navigation
### Scroll Wheel ### Scroll Wheel
- ** Default **: Pan canvas - **Default**: Pan canvas
- ** Ctrl/⌘ + scroll **: Zoom canvas (intercepted via wheel event with `e.ctrlKey || e.metaKey`) - **Ctrl/⌘ + scroll**: Zoom canvas (intercepted via wheel event with `e.ctrlKey || e.metaKey`)
### Space + Drag Panning ### Space + Drag Panning
- Critical: must work even when shell window has keyboard focus - Critical: must work even when shell window has keyboard focus
@@ -52,13 +52,13 @@ interface CanvasState {
- Do NOT use `e.stopPropagation()` - allow event propagation - Do NOT use `e.stopPropagation()` - allow event propagation
### Click/Typed Key Triggers ### Click/Typed Key Triggers
- ** Click on empty canvas **: Open spotlight - **Click on empty canvas**: Open spotlight
- ** Type any key **: Open spotlight with that character pre-seeded - **Type any key**: Open spotlight with that character pre-seeded
### Zoom Levels / LOD ### Zoom Levels / LOD
- ** zoom > 0.5 **: Normal view — krates expanded, all windows visible, draggable - **zoom > 0.5**: Normal view — krates expanded, all windows visible, draggable
- ** zoom < 0.4 **: Collapsed view — krates become 230px wide overview cards, no windows rendered - **zoom < 0.4**: Collapsed view — krates become 230px wide overview cards, no windows rendered
- ** Hysteresis**: Collapse at 0.4, re-expand at 0.5 (prevents flickering) - **Hysteresis**: Collapse at 0.4, re-expand at 0.5 (prevents flickering)
### Animations ### Animations
- CSS `transform` with `transition` only for programmatic "fly" animations: `.52s cubic-bezier(.22,.8,.28,1)` - CSS `transform` with `transition` only for programmatic "fly" animations: `.52s cubic-bezier(.22,.8,.28,1)`

View File

@@ -1,4 +1,4 @@
# Collection Window Feature Specification # Design Document: Collection Window Feature Specification
## Overview ## 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. 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.
@@ -132,7 +132,7 @@ Show as small icons or labels:
### Implementation ### Implementation
- Event listener with `event.code` for layout safety - Event listener with `event.code` for layout safety
- Open views in newly created krate (or existing if spotlight session) - Open views in newly created krate (or existing if spotlight session)
- Shell tab disabled for non-exec types (opacity 0.45) - Shell tab disabled for non-pod workloads (opacity 0.45)
## View-Specific Content ## View-Specific Content

View File

@@ -1,4 +1,4 @@
# Detail Window Feature Specification # Design Document: Detail Window Feature Specification
## Overview ## 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. 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.

View File

@@ -1,4 +1,4 @@
# Krate (Window Group) Feature Specification # Design Document: Krate (Window Group) Feature Specification
## Overview ## Overview
A krate is a named group of detail windows for a single Kubernetes object or collection. Krates live on the canvas and serve as organizational units for related workspace views. A krate is a named group of detail windows for a single Kubernetes object or collection. Krates live on the canvas and serve as organizational units for related workspace views.

View File

@@ -1,4 +1,4 @@
# Minimap Feature Specification # Design Document: Minimap Feature Specification
## Overview ## Overview
The minimap provides a bird's-eye overview of all krates' positions on the canvas. It allows navigation by clicking to fly the camera to any location. The minimap provides a bird's-eye overview of all krates' positions on the canvas. It allows navigation by clicking to fly the camera to any location.

View File

@@ -1,337 +1,232 @@
# Shell & Logs Windows Feature Specification # Design Document: Shell & Logs Feature Specification
## Overview ## Overview
Shell and Logs windows are specialized detail windows that stream real-time data from Kubernetes pods. Shell provides an interactive terminal, while Logs shows container output. Shell and Logs are real-time terminal and streaming views for Kubernetes resources. These features enable users to interact with running pods and monitor application behavior.
--- ## Shell Terminal (kubectl exec)
## Shell Window ### Requirements
- **Implementation**: xterm.js on client
- **Backend**: WebSocket → kubectl exec
- **Protocol**: Bidirectional terminal protocol
### Purpose ### Terminal Configuration
Interactive pseudo-terminal session inside the application, connected to a pod via `kubectl exec`.
### Implementation
#### Client-Side (xterm.js)
```typescript ```typescript
// Initialization {
import { Terminal } from 'xterm';
import { FitAddon } from 'xterm-addon-fit';
const term = new Terminal({
rows: 24, rows: 24,
cols: 80, cols: 80,
fontFamily: 'IBM Plex Mono', fontFamily: 'IBM Plex Mono',
fontSize: 12, fontSize: 12,
lineHeight: 1.5,
cursorBlink: true,
theme: { theme: {
background: '#0b0e13', background: '#1a1e26',
foreground: '#e6edf6', foreground: '#b9c6d8',
cursor: '#4dd6e8'
}
});
const fitAddon = new FitAddon();
term.loadAddon(fitAddon);
fitAddon.fit();
```
#### WebSocket Connection
```typescript
// On krate creation with shell tab
const ws = new WebSocket(`/ws/shell?pod=${pod}&ns=${ns}`);
ws.onopen = () => {
term.focus();
};
ws.onmessage = (event) => {
term.write(event.data); // stdout/stderr
};
term.onData((data) => {
ws.send(data); // stdin (keypresses, etc.)
});
term.onResize(({ rows, cols }) => {
ws.send(JSON.stringify({ type: 'resize', rows, cols }));
});
```
### Keyboard Routing
#### Mouse-Over Focus
- Track `mouseenter`/`mouseleave` per window
- Set `hoveredWindowId` on shell windows
- Global `keydown` handler routes to shell when focused
#### Critical: Space Key
- **Must NOT open spotlight** when shell has focus
- Shell window handles space as input (terminal command)
- Implementation:
```typescript
document.addEventListener('keydown', (e) => {
if (hoveredWindowId && isShellWindow(hoveredWindowId)) {
// Space goes to shell
return; // Don't trigger canvas shortcuts
}
// Handle canvas shortcuts (space pan, etc.)
}, { capture: true });
```
### Scroll Wheel Behavior
- On shell content: Scroll terminal (not canvas)
- On empty canvas: Pan
- **Ctrl/⌘ + scroll over shell**: Zoom canvas (not terminal zoom)
- Use `{ capture: true }` on canvas wheel handler
- Check `e.ctrlKey || e.metaKey`
- If true: zoom canvas; otherwise: let event propagate
### Terminal Features
- **Full PTY emulation**: Support all ANSI escapes
- **Resize**: Send new size on container resize
- **Paste**: Support Ctrl+Shift+V or Shift+Insert
- **Copy**: Ctrl+Shift+C or Ctrl+C (custom)
- **Search**: `/` to search, `n`/`N` for next/prev
- **Font scaling**: Ctrl+wheel for terminal font size
### Backend Implementation (Go)
```go
// WebSocket connection
func (s *Server) handleShell(w http.ResponseWriter, r *http.Request) {
ws, err := upgrader.Upgrade(w, r, nil)
if err != nil {
return
}
defer ws.Close()
pod := r.URL.Query().Get("pod")
ns := r.URL.Query().Get("ns")
// Create k8s exec request
req := s.client.CoreV1().RESTClient().Post().
Name(pod).Namespace(ns).Resource("pods").SubResource("exec")
req.VersionedParams(&v1.ExecOptions{
Stdin: true,
Stdout: true,
Stderr: true,
Terminal: true,
}, scheme.ParameterCodec)
exec, err := remotecommand.NewSPDYExecutor(s.config, "POST", req.URL())
if err != nil {
ws.Close()
return
}
// Stream between WebSocket and exec
exec.Stream(remotecommand.StreamOptions{
Stdin: ws,
Stdout: ws,
Stderr: ws,
TermSize: &remotecommand.TerminalSize{
Width: 80,
Height: 24,
},
})
}
```
---
## Logs Window
### Purpose
Live-tailing container logs, showing output in real-time.
### Streaming
```typescript
// WebSocket connection
const ws = new WebSocket(`/ws/logs?pod=${pod}&ns=${ns}`);
ws.onmessage = (event) => {
const line = event.data;
addLogLine(line);
};
function addLogLine(line: string) {
const entry = parseLogLine(line);
logBuffer.push(entry);
// Auto-scroll if at bottom
if (atBottom()) {
scrollToBottom();
} }
} }
``` ```
### Auto-Scroll Behavior ### Connection Flow
- **New lines arrive**: Auto-scroll to bottom 1. User opens shell view
- **User scrolls up**: Stop auto-scrolling 2. Extract pod name and namespace
- **Detection**: 3. Connect WebSocket to `/ws/shell?pod=X&ns=Y`
```typescript 4. Backend:
function atBottom(): boolean { - Extract query params
const threshold = 50; // px - Connect to k8s exec API
return (scrollTop + clientHeight + threshold) >= scrollHeight; - Create execstream
} - Proxy bidirectionally
``` 5. Frontend:
- Initialize xterm
- Attach to WebSocket
- Handle resize events
- Route keypresses
### Color Coding ### Key Routing
Parse lines and color-code by pattern: - **Shell focused + type**: Route to terminal
- **Canvas shortcuts disabled** when shell has focus
- **Space key**: Goes to terminal (not spotlight)
- **Ctrl/⌘+scroll**: Zoom canvas (not terminal zoom)
```typescript ### Resize Handling
function parseLogLine(line: string): LogEntry { - **Client**: term.resize(cols, rows)
// Pattern matching for common log levels - **Server**: Send resize message via WebSocket
if (line.includes('ERROR') || line.includes('ERR')) { - **Backend**: Update k8s exec term size
return { text: line, color: '#ef6f6f' }; // Red - **Debounce**: 100ms for resize events
} else if (line.includes('WARN') || line.includes('WARNING')) {
return { text: line, color: '#e8b54a' }; // Amber
} else if (line.includes('INFO') || line.includes('I ')) {
return { text: line, color: '#b9c6d8' }; // Default
} else {
return { text: line, color: '#c7d2e0' }; // Muted
}
}
```
### Timestamps ### State Management
- **Default**: Include timestamps
- **Toggle**: Optional button to show/hide
- **Format**: ISO 8601 or container format
### Scrollbar Styling
- Width: 8px
- Track: rgba(140,165,200,.1)
- Thumb: rgba(140,165,200,.3)
- Hover thumb: rgba(140,165,200,.5)
### Content Rendering
```typescript
<pre style={{ overflow: 'auto', height: '286px', fontFamily: 'IBM Plex Mono' }}>
{logs.map((line, i) => (
<div key={i} style={{ color: line.color }}>
{line.timestamp && <span className="timestamp">{line.timestamp} </span>}
{line.text}
</div>
))}
</pre>
```
---
## View-Specific Behavior
### Shell Tab
- **Enabled for**: Pods, and workloads that support exec
- **Disabled for**: Deployments, Services, etc.
- **Visual**: `opacity: 0.45` for disabled
- **Label**: Show "shell" but don't route to it
### Logs Tab
- **Enabled for**: Pods and workloads ( Deployments, StatefulSets, DaemonSets)
- **Disabled for**: ConfigMaps, Secrets, PVCs, etc.
- **Visual**: Same as shell
---
## Keyboard Shortcuts
| Key | Context | Action |
|---|---|---|
| ↑ / ↓ | Logs shell focused | Navigate scroll (logs) / line history (shell) |
| PageUp / PageDown | Logs focused | Page scroll |
| Ctrl+L | Logs focused | Clear screen (only in shell) |
| Ctrl+C | Shell focused | Send interrupt to shell |
| Ctrl+Z | Shell focused | Send suspend (if supported) |
| Ctrl+Shift+F | Logs focused | Find (future enhancement) |
| Ctrl+Shift+V | Shell focused | Paste |
| Ctrl+Shift+C | Shell focused | Copy selection |
---
## Error Handling
### Connection Errors
- **Shell**: Show error border, keep terminal buffer, retry button
- **Logs**: Show error indicator, auto-reconnect with backoff
### Reconnection Strategy
```typescript
let retries = 0;
const maxRetries = 5;
function reconnect() {
if (retries >= maxRetries) {
showFatalError('Connection failed');
return;
}
setTimeout(() => {
retries++;
connect();
}, Math.min(1000 * 2^retries, 10000)); // Exponential backoff
}
```
### Buffer Management
- **Shell**: Keep last 1000 lines in buffer
- **Logs**: Keep last 2000 lines
- **Overflow**: Drop oldest lines, mark with "..." indicator
---
## State Management
### Shell State
```typescript ```typescript
interface ShellState { interface ShellState {
connected: boolean; connected: boolean;
rows: number; connectedAt: number;
lastActive: number;
buffer: string[];
cols: number; cols: number;
buffer: string[]; // Last N lines rows: number;
cursor: { x, y };
} }
``` ```
### Logs State ### Error States
- Connection failed: Show error message
- Disconnected: Show "Disconnected" + reconnect button
- Permission denied: Show clear error
- Pod not found: Show error message
## Logs Viewer (kubectl logs)
### Requirements
- **Implementation**: WebSocket streaming
- **Auto-scroll**: To bottom by default
- **Color coding**: ERROR/WARN/INFO
### Connection Flow
1. User opens logs view
2. Connect to `/ws/logs?pod=X&ns=Y`
3. Backend:
- Start kubectl logs stream
- Forward to WebSocket
4. Frontend:
- Append lines to buffer
- Auto-scroll if at bottom
- Colorize based on level
### Log Parsing
Each log line should include:
- Timestamp
- Log level (ERROR/WARN/INFO/DEBUG)
- Message
Format:
```typescript
interface LogLine {
timestamp: string; // ISO 8601
level: 'ERROR' | 'WARN' | 'INFO' | 'DEBUG';
message: string;
}
```
### Color Coding
- **ERROR**: `#ef6f6f`
- **WARN**: `#e8b54a`
- **INFO**: `#b9c6d8`
- **DEBUG**: `#6b7280`
### Auto-Scroll Logic
- **Track scroll position**: Store `scrollTop`
- **At bottom**: Auto-scroll on new log
- **Scrolled up**: Don't auto-scroll
- **Threshold**: Within 20px of bottom = "at bottom"
### User Controls
- **Click auto-scroll toggle**: Switch between auto and manual scroll
- **Clear logs**: Button to clear buffer
- **Copy log line**: Right-click menu
- **Filter**: Simple filtering (show/hide levels)
### State Management
```typescript ```typescript
interface LogsState { interface LogsState {
lines: LogEntry[]; connected: boolean;
scrollTop: number;
autoScroll: boolean; autoScroll: boolean;
timestamp: boolean; logLines: LogLine[];
scrollPosition: number;
filterLevels: Set<LogLevel>;
} }
``` ```
--- ### Streaming Considerations
- **Backpressure**: Buffer if client slow
- **Rate limiting**: Server can throttle logs
- **Keep-alive**: Ping every 30s
- **Reconnect**: Exponential backoff on disconnect
### Performance Optimization
- **Virtualization**: Only render visible lines
- **Batching**: Flush logs in batches if high volume
- **Throttling**: 16ms throttle for updates
- **Cleanup**: Remove old logs (keep last 1000 lines)
## Shared Features
### View State
- Both views persist state in krate.window.state
- reconnect: Auto reconnect on disconnect
- timestamps: Show/hide timestamps
- wrap: Word wrap toggle
### Tab Switching
- Shell tab: Enabled for pods only
- Logs tab: Enabled for pods/workloads
- Empty state: Show helpful message for unsupported resources
### Close Behavior
- Shell: Keep buffer, show "Disconnnected"
- Logs: Stop streaming, keep buffer
- Cleanup: Close WebSocket, cancel watchers
## WebSocket Protocol
### Shell
```
// Client → Server
{
type: 'shell:input',
data: string // Key press data
}
{
type: 'shell:resize',
cols: number,
rows: number
}
// Server → Client
{
type: 'shell:output',
data: string // stdout/stderr
}
{
type: 'shell:status',
connected: boolean,
message?: string
}
```
### Logs
```
// Client → Server
{
type: 'logs:subscribe',
pod: string,
namespace: string,
follow: boolean,
timestamps: boolean
}
{
type: 'logs:filter',
levels: string[]
}
// Server → Client
{
type: 'log',
log: LogLine
}
{
type: 'status',
connected: boolean,
message?: string
}
```
## Gotchas ## Gotchas
1. **Space key**: Must distinguish between canvas pan and shell input
### Critical Issues 2. **Focus routing**: Route keys based on hovered window
1. **Space key routing**: Must distinguish between shell space (input) and canvas space-pan 3. **Scroll management**: Track scroll position for logs
2. **Ctrl/⌘+scroll**: Intercept on canvas with `{ capture: true }`, check modifier 4. **Terminal resize**: Debounce resize events
3. **Terminal resize**: Send `TermSize` on window resize events 5. **Reconnection**: Handle WebSocket disconnects gracefully
4. **Paste security**: Sanitize pasted content, avoid escape sequences 6. **Memory**: Clean up old logs/shell buffers
5. **Cursor position**: xterm.js tracks cursor; keep in sync with server 7. **Authentication**: Validate user on WebSocket upgrade
6. **Buffer overflow**: Implement LRU buffer, don't memory leak 8. **Permissions**: Enforce namespace RBAC on backend
### Performance
1. **Throttle updates**: Don't render on every log line, batch
2. **Virtual scrolling**: For logs with many lines
3. **Web Worker**: Offload parsing to worker for large logs
### Animation
1. **Blinking cursor**: CSS animation or xterm.js built-in
2. **Auto-scroll indicator**: Small arrow when scrolled up
3. **Connection status**: Green/amber/red dot
## Testing Checklist
- [ ] Shell key press → terminal receives it
- [ ] Terminal output → WebSocket → UI
- [ ] Resize → terminal resizes correctly
- [ ] Space in shell ≠ spotlight open
- [ ] Ctrl+scroll over shell ≠ zoom canvas
- [ ] Logs auto-scroll works (and stops on manual scroll)
- [ ] Connection loss → retry with backoff
- [ ] Buffer overflow → old lines dropped
- [ ] Shell interrupt (Ctrl+C) handled
- [ ] Paste works (Ctrl+Shift+V)

View File

@@ -1,137 +1,203 @@
# Spotlight Search Feature Specification # Design Document: Spotlight Feature Specification
## Overview ## Overview
The spotlight is the global search overlay that allows users to find any Kubernetes object or existing krate. It provides fuzzy-ranked search results with quick view shortcuts. Spotlight is the universal search and discovery interface that allows users to quickly find and create krates for Kubernetes resources. It's triggered by clicking the canvas or typing any character.
## Core Responsibilities ## Core Responsibilities
- Display search results ranked by fuzzy matching - Handle universal search across Kubernetes resources
- Support typed filters (Tab to cycle through types) - Support fuzzy matching of names, namespaces, labels
- Provide view shortcuts (Logs, Shell, Describe, YAML) - Allow quick creation of krates from search results
- Auto-close after keyboard idle and open selected object - Support filtering by resource type
## UI Components ## Trigger
- **Click on empty canvas**: Open spotlight
- **Type any key**: Open spotlight with that character pre-seeded
- **Esc key**: Close spotlight
- **Spotlight open**: Prevent canvas shortcuts from triggering
### Layout ## Spotlight Anatomy
- Full-screen backdrop: `rgba(7,9,13,.55)`, `backdrop-filter: blur(2px)`
- Search panel: `width: min(660px, 93vw)`, `top: 15%`, centered horizontally
- Panel: `background: rgba(16,20,28,.97)`, `border: 1px solid rgba(140,165,200,.26)`, `border-radius: 14px`
### Sections (top→bottom) ### Search Input
1. **Input row** (~52px): - Position: Top of spotlight panel
- `⌕` glyph (accent color) - Auto-focused on open
- Optional type-filter pill - Placeholder: `Search...`
- Input field (`font-size: 18px`, IBM Plex Sans) - Clear on Esc
- Optional Tab ghost hint - Debounced: 16ms for fuzzy search
2. **Type chips row** (scrollable): ### Filter Bar
- All / deploy / svc / pods / secrets / config / sts / crd / namespace / ns - Location: Below search input
- Scrollable horizontally on small screens - Filter chips: All, Krates, Namespaces, Pods, Deployments, Services
- Shows selected filter as pill - Click filter: Apply filter
- Click active filter: Clear filter
3. **Results list** (`max-height: 48vh, overflow: auto`): ### Results List
- Each row: shape glyph + name + subtext (type · ns/namespace) + CRD badge + type badge - Position: Below filter bar
- Selected row highlight: accent background - Max height: ~400px
- Scrollbar styled (8px, rgba(140,165,200,.18)) - Scrollable
- Results: Search results + quick actions
- Keyboard navigation: ↑↓ to navigate, Enter to select, Esc to close
4. **View chips** (expanded on selected row only): ### Results Item
- `⌥L logs · ⌥S shell · ⌥D describe · ⌥Y yaml` Content per item:
- Only available views shown (YAML and Describe always shown; Logs and Shell for pods/deployments/daemonsets/statefulsets) - Shape glyph (8px, color-coded by type)
- Click to open that view for selected result - Name (primary text)
- Type badge (muted color)
- Namespace (muted, optional)
- View shortcuts: `L`, `S`, `D`, `Y`
- Hover: Highlight, show view shortcut tooltips
5. **Footer**: ## Search Implementation
- `↑↓ pick · ⌥L/S/D/Y open views · ⏎ open default · ⇥ filter type · esc done`
## Fuzzy Search Algorithm ### Fuzzy Algorithm
```typescript
### Scoring Formula function fuzzy(query: string, text: string): number {
``` // Prefer starts-with matches
Score = character-match score × 10 + type boost if (text.toLowerCase().startsWith(query.toLowerCase())) {
return 1 - query.length / text.length
}
// Then scoring based on character matching
let score = 0
let queryIndex = 0
for (let i = 0; i < text.length && queryIndex < query.length; i++) {
if (text[i].toLowerCase() === query[queryIndex].toLowerCase()) {
score++
queryIndex++
}
}
return score / query.length
}
``` ```
### Type Boosts ### Search Scope
- CRD: 60 - Namespaces
- Deployment: 50 - Pods
- StatefulSet: 48 - Deployments
- Service: 46 - Services
- DaemonSet: 44 - ConfigMaps
- Ingress: 42 - Secrets
- Secret: 24 - Krates (created by user)
- ConfigMap: 22
- PVC: 18
- Pod: 16
### Character Matching ### Resource Discovery
- Sequential character match 1. Initial load: Fetch all resources from `/api/resources`
- Bonus for consecutive matches: +3 2. Real-time updates: WebSocket `/ws/watch` for changes
- Bonus for word-boundary starts: +5 3. Local cache: Store in Zustand krateStore
4. Filtering: Apply fuzzy search + type filter
### Results ## Results Organization
- Capped at 8 results
- Debounce: 16ms (one animation frame) for performance with large datasets
## Type Filter ### Search vs Quick Actions
- Search results: Resource matches (top section)
- Quick actions: Create new krate, open specific view (bottom section)
### Tab Quick-Filter ### Quick Actions
- Typing type alias (e.g., `pod`, `svc`) shows ghost hint: `⇥ Pods` - `Create krate for ns/{namespace}`
- Tab locks filter as pill - `All pods`
- Backspace removes filter (only when empty query and filter active) - `All services`
- Tab cycles through type filters (most-recently-opened first) - `All deployments`
- `Search again for...`
## View Shortcuts
### Key Mapping
All use **⌥ (Alt/Option)**, NOT Ctrl (reserved for terminal):
- `⌥L` = logs
- `⌥S` = shell
- `⌥D` = describe
- `⌥Y` = yaml
### Implementation
- Use `event.code` (layout-safe, e.g., `KeyL`), not `event.key`
- Multiple views can be opened before closing spotlight
- Views stack as windows in one krate
## Keyboard Navigation ## Keyboard Navigation
| Key | Context | Action | | Key | Context | Action |
|---|---|---| |---|---|---|
| ↑ / ↓ | Spotlight | Navigate results | | ↑ / ↓ | Spotlight open | Move selection |
| Tab | Spotlight | Apply type filter / cycle filters | | PageUp / PageDown | Spotlight open | Page navigation |
| Backspace | Spotlight (empty query, filter active) | Clear type filter | | Home / End | Spotlight open | First / last item |
| Enter | Spotlight (result selected) | Open default view + close | | Enter | Item selected | Create krate / open resource |
| ⌥L/S/D/Y | Spotlight | Open that view for selected result | | Esc | Spotlight open | Close spotlight |
| Esc | Spotlight | Close spotlight | | Space | Input focused | Search space character |
| Ctrl+K | Anywhere | Open spotlight |
| / | Anywhere | Open spotlight |
## Auto-Close Behavior ## View Shortcuts
- After 500ms of keyboard idle (no more keypresses) All use **Option/Alt** key:
- Spotlight closes automatically - `⌥L`: Open logs view (if supported)
- Camera flies to the newly created krate - `⌥S`: Open shell view (if supported)
- Debounce timer resets on each keypress - `⌥D`: Open describe view
- `⌥Y`: Open YAML view
## Search Results Include ## Krate Creation Flow
- **Existing krates** (jump to working set, camera flies there) 1. User selects resource from spotlight
- **Namespace results** (`ns/payments`) → opens collection window 2. Create new krate with:
- **Category results** (`All Pods`, `All Services`) → opens collection window - Title: Resource name
- **Kubernetes objects**: pods, deployments, services, secrets, configmaps, etc. - Color: Namespace color palette
- Position: Find non-overlapping location
- Windows: Create detail windows for selected views
3. Fly camera to new krate
4. Zoom to 0.92
## State ## State Management
### Spotlight State
```typescript ```typescript
interface SpotlightState { interface SpotlightState {
open: boolean; open: boolean;
query: string; query: string;
filterType: string | null; filterType: string | null;
sel: number; // selected result index sel: number;
navigated: boolean; // true after ↑/↓ press navigated: boolean;
session: { // tracks views opened before closing }
kid: string;
objId: string; type FilterType = 'all' | 'krate' | 'namespace' | 'pod' | 'deployment' | 'service'
views: string[]; ```
} | null;
### Search State
```typescript
interface SearchState {
results: SearchResult[];
loading: boolean;
error: string | null;
}
interface SearchResult {
id: string;
type: string;
name: string;
namespace?: string;
score: number;
icon: string;
} }
``` ```
## Visual Design
### Spotlight Panel
- Position: Fixed, centered horizontally at top of canvas
- Width: 600px
- Max height: 500px
- Background: `#1a1e26`
- Border: `1px solid rgba(140,165,200,0.18)`
- Border-radius: 12px
- Shadow: `0 10px 40px rgba(0,0,0,0.5)`
### Results Item
- Hover background: `rgba(255,255,255,0.04)`
- Selected: `accentDim` (subtle accent color)
- Left border: 2px solid accent when selected
- Padding: 8px 12px
- Font-size: 14px
### Color Palette (by namespace)
- `default`: `#6fb1ff`
- `kube-system`: `#9c88ff`
- `kube-public`: `#4dd6e8`
- Custom namespaces: Pick from palette
## Gotchas ## Gotchas
1. **Fuzzy search speed**: For real clusters with thousands of objects, debounce by 16ms or run in Web Worker 1. **Space character**: When spotlight open, space goes to search (not canvas pan)
2. **View shortcuts**: Must use `event.code` for layout safety across OS/keyboard layouts 2. **Esc handling**: Must be handled in spotlight, not propagate to canvas
3. **Auto-close timer**: Reset on each keypress, don't close during active typing 3. **Fuzzy search**: Use debounced search for large datasets
4. **Pre-seeding**: All printable characters (not just letters) should pre-seed spotlight 4. **Keyboard routing**: When spotlight open, route keys to spotlight, not canvas
5. **Focus management**: Auto-focus input, trap Tab cycle when open
6. **Selection reset**: Reset selection on query change
## Future Enhancements
- Quick pick recent resources
- Star/favorite resources
- Saved searches
- Search history
- Resource previews
- Multi-resource selection

View File

@@ -1,4 +1,4 @@
# Top Bar Feature Specification # Design Document: Top Bar Feature Specification
## Overview ## Overview
The top bar is the primary navigation and status bar for the application. It provides quick access to cluster information, user presence, and global actions. The top bar is the primary navigation and status bar for the application. It provides quick access to cluster information, user presence, and global actions.