204 lines
5.2 KiB
Markdown
204 lines
5.2 KiB
Markdown
# Design Document: Spotlight Feature Specification
|
|
|
|
## Overview
|
|
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
|
|
- Handle universal search across Kubernetes resources
|
|
- Support fuzzy matching of names, namespaces, labels
|
|
- Allow quick creation of krates from search results
|
|
- Support filtering by resource type
|
|
|
|
## 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
|
|
|
|
## Spotlight Anatomy
|
|
|
|
### Search Input
|
|
- Position: Top of spotlight panel
|
|
- Auto-focused on open
|
|
- Placeholder: `Search...`
|
|
- Clear on Esc
|
|
- Debounced: 16ms for fuzzy search
|
|
|
|
### Filter Bar
|
|
- Location: Below search input
|
|
- Filter chips: All, Krates, Namespaces, Pods, Deployments, Services
|
|
- Click filter: Apply filter
|
|
- Click active filter: Clear filter
|
|
|
|
### Results List
|
|
- Position: Below filter bar
|
|
- Max height: ~400px
|
|
- Scrollable
|
|
- Results: Search results + quick actions
|
|
- Keyboard navigation: ↑↓ to navigate, Enter to select, Esc to close
|
|
|
|
### Results Item
|
|
Content per item:
|
|
- Shape glyph (8px, color-coded by type)
|
|
- Name (primary text)
|
|
- Type badge (muted color)
|
|
- Namespace (muted, optional)
|
|
- View shortcuts: `L`, `S`, `D`, `Y`
|
|
- Hover: Highlight, show view shortcut tooltips
|
|
|
|
## Search Implementation
|
|
|
|
### Fuzzy Algorithm
|
|
```typescript
|
|
function fuzzy(query: string, text: string): number {
|
|
// Prefer starts-with matches
|
|
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
|
|
}
|
|
```
|
|
|
|
### Search Scope
|
|
- Namespaces
|
|
- Pods
|
|
- Deployments
|
|
- Services
|
|
- ConfigMaps
|
|
- Secrets
|
|
- Krates (created by user)
|
|
|
|
### Resource Discovery
|
|
1. Initial load: Fetch all resources from `/api/resources`
|
|
2. Real-time updates: WebSocket `/ws/watch` for changes
|
|
3. Local cache: Store in Zustand krateStore
|
|
4. Filtering: Apply fuzzy search + type filter
|
|
|
|
## Results Organization
|
|
|
|
### Search vs Quick Actions
|
|
- Search results: Resource matches (top section)
|
|
- Quick actions: Create new krate, open specific view (bottom section)
|
|
|
|
### Quick Actions
|
|
- `Create krate for ns/{namespace}`
|
|
- `All pods`
|
|
- `All services`
|
|
- `All deployments`
|
|
- `Search again for...`
|
|
|
|
## Keyboard Navigation
|
|
|
|
| Key | Context | Action |
|
|
|---|---|---|
|
|
| ↑ / ↓ | Spotlight open | Move selection |
|
|
| PageUp / PageDown | Spotlight open | Page navigation |
|
|
| Home / End | Spotlight open | First / last item |
|
|
| Enter | Item selected | Create krate / open resource |
|
|
| Esc | Spotlight open | Close spotlight |
|
|
| Space | Input focused | Search space character |
|
|
| Ctrl+K | Anywhere | Open spotlight |
|
|
| / | Anywhere | Open spotlight |
|
|
|
|
## View Shortcuts
|
|
All use **Option/Alt** key:
|
|
- `⌥L`: Open logs view (if supported)
|
|
- `⌥S`: Open shell view (if supported)
|
|
- `⌥D`: Open describe view
|
|
- `⌥Y`: Open YAML view
|
|
|
|
## Krate Creation Flow
|
|
1. User selects resource from spotlight
|
|
2. Create new krate with:
|
|
- Title: Resource name
|
|
- 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 Management
|
|
|
|
### Spotlight State
|
|
```typescript
|
|
interface SpotlightState {
|
|
open: boolean;
|
|
query: string;
|
|
filterType: string | null;
|
|
sel: number;
|
|
navigated: boolean;
|
|
}
|
|
|
|
type FilterType = 'all' | 'krate' | 'namespace' | 'pod' | 'deployment' | 'service'
|
|
```
|
|
|
|
### 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
|
|
1. **Space character**: When spotlight open, space goes to search (not canvas pan)
|
|
2. **Esc handling**: Must be handled in spotlight, not propagate to canvas
|
|
3. **Fuzzy search**: Use debounced search for large datasets
|
|
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
|