- 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
189 lines
4.8 KiB
Markdown
189 lines
4.8 KiB
Markdown
# Admin Drawer Feature Specification
|
|
|
|
## 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.
|
|
|
|
## Trigger
|
|
|
|
### Activation
|
|
- Button: `◉ admin` in top bar
|
|
- Toggle: Click to open/close
|
|
- Close on: clicking backdrop, pressing Esc
|
|
|
|
### Modal Overlay
|
|
- Backdrop: `rgba(7,9,13,.4)`
|
|
- Click backdrop: Close drawer
|
|
- Click outside: Close drawer
|
|
|
|
## Drawer Layout
|
|
|
|
### Container
|
|
- Width: 380px
|
|
- Position: `absolute; right: 0; top: 0; bottom: 0; z-index: 56`
|
|
- Background: `rgba(13,17,24,.98)`
|
|
- Border: `border-left: 1px solid rgba(140,165,200,.2)`
|
|
- Animation: Slide-in from right
|
|
|
|
### Content Structure
|
|
- Header (fixed, sticky)
|
|
- Scrollable user list
|
|
- Footer (optional, for actions)
|
|
|
|
## User Card Structure
|
|
|
|
For each connected user (including self):
|
|
|
|
### Avatar Section
|
|
- Circle: 40px直径
|
|
- Background: User color from palette
|
|
- Content:
|
|
- For self: `★` (star)
|
|
- For others: 2-letter initials
|
|
- Hover: Show full name + status tooltip
|
|
|
|
### Identity
|
|
- Name (bold)
|
|
- Status:
|
|
- Active: `active · ns/payments`
|
|
- Idle: `idle 5m` (or `idle Nm`)
|
|
|
|
### Activity Info
|
|
- Current spotlight query (if open)
|
|
- Display: `🔍 pods in payments`
|
|
- "typing…" pulsing indicator (if currently typing)
|
|
- Krate count: `N krates open`
|
|
|
|
### Open Krate List
|
|
Collapsible section showing each active krate:
|
|
- Clickable row
|
|
- Content:
|
|
- Krate name
|
|
- View-letter badges: `Y`, `D`, `L`, `S`
|
|
- Status dot (health indicator)
|
|
- **Spectate**: Click any krate row to:
|
|
- Close admin panel
|
|
- Fly camera to that krate
|
|
- Zoom to center the krate at `zoom: 0.92`
|
|
|
|
### Self User Special Case
|
|
- Real-time state updates
|
|
- Shows actual spotlight query
|
|
- Lists user's actual open krates
|
|
- Updates as user interacts
|
|
|
|
## Real-Time Updates
|
|
|
|
### Presence Protocol
|
|
Each client publishes to awareness channel:
|
|
```
|
|
{
|
|
userId: string,
|
|
name: string,
|
|
color: string,
|
|
lastActive: timestamp,
|
|
query: string | null, // spotlight query
|
|
krateIds: string[], // list of open krate IDs
|
|
cursor: { x, y } | null // optional cursor position
|
|
}
|
|
```
|
|
|
|
### Update Frequency
|
|
- On connection/disconnection: immediate
|
|
- On spotlight open/close: immediate
|
|
- On krate create/delete: immediate
|
|
- Periodic heartbeat: every 5 seconds
|
|
|
|
## Keyboard Navigation
|
|
|
|
| Key | Context | Action |
|
|
|---|---|---|
|
|
| Esc | Admin drawer open | Close drawer |
|
|
| ↑ / ↓ | Drawer focused | Navigate user cards |
|
|
| Click user card | User list | Expand/collapse krate list |
|
|
| Click krate row | Krate list | Spectate (fly to krate) |
|
|
| Click backdrop | Anywhere | Close drawer |
|
|
|
|
## User Sorting
|
|
- Self user: Always first
|
|
- Active users: Ordered by last active (most recent first)
|
|
- Idle users: Ordered by last active
|
|
- Collapsed by default: Minimize height
|
|
|
|
## Visual Feedback
|
|
|
|
### Active/Idle Indicators
|
|
- Active: Solid color avatar, no dimming
|
|
- Idle: Dimmed avatar (80% opacity), `idle Nm` label
|
|
|
|
### Typing Indicator
|
|
- Text: `typing…`
|
|
- Color: Muted accent
|
|
- Animation: Pulsing opacity or small bounce
|
|
- Show when user has spotlight open AND hasn't typed in <1s
|
|
|
|
### Status Dots
|
|
- Krate status: Green/amber/red dot (matching window content)
|
|
- Pod status dot: Already in krate view (reuse same color logic)
|
|
|
|
## Admin Features (Optional Future)
|
|
|
|
### Control Actions
|
|
- Notify user: Send notification to specific user
|
|
- Suspend: Temporarily disconnect user (for debugging)
|
|
- View logs: See admin-level logs per user
|
|
|
|
### Spectate Controls
|
|
- Step forward/backward: Next/previous krate
|
|
- Cycle through users: Left/right arrow
|
|
- Lock view: Prevent camera from moving (spectator mode)
|
|
|
|
## State Management
|
|
|
|
### Drawer State
|
|
```typescript
|
|
interface AdminState {
|
|
open: boolean;
|
|
users: {
|
|
id: string;
|
|
name: string;
|
|
color: string;
|
|
self: boolean;
|
|
status: 'active' | 'idle';
|
|
idleMinutes?: number;
|
|
query?: string;
|
|
typing: boolean;
|
|
krateIds: string[];
|
|
}[];
|
|
focusedUserId: string | null;
|
|
}
|
|
```
|
|
|
|
### User State
|
|
```typescript
|
|
interface UserPresence {
|
|
userId: string;
|
|
name: string;
|
|
color: string;
|
|
lastActive: number; // timestamp
|
|
lastTyping: number; // timestamp
|
|
spotlightQuery: string | null;
|
|
openKrates: KratePresence[];
|
|
}
|
|
|
|
interface KratePresence {
|
|
krateId: string;
|
|
label: string;
|
|
viewCount: number;
|
|
views: string[]; // ['Y', 'D', 'L', 'S']
|
|
status: string; // from first window
|
|
}
|
|
```
|
|
|
|
## Gotchas
|
|
1. **Self-updates**: User's own card must show real-time state, not cached data
|
|
2. **Focus management**: Keep focus on drawer when open, trap Tab cycle
|
|
3. **Idle detection**: 60 seconds of no activity = idle
|
|
4. **Typing indicator**: Debounce by 1000ms after last keypress
|
|
5. **Spectate behavior**: Close admin panel first, THEN fly camera
|
|
6. **Roster overflow**: Handle >10 users gracefully (scroll, paginate, or truncate)
|