feat(ui): add type filter toggles

This commit is contained in:
2026-02-18 23:13:28 -08:00
commit a4cff9894c
14457 changed files with 2204835 additions and 0 deletions

487
SPEC.md Normal file
View File

@@ -0,0 +1,487 @@
# Homelab Topology Visualizer - Specification
## 1. Project Overview
**Project Name:** Homelab Topology Visualizer (HomelabTV)
**Type:** Interactive Web Application
**Core Functionality:** A visual, interactive graph-based UI that displays the complete topology of a homelab - from network infrastructure (UniFi gateway, VLANs) through hosts, Docker containers/services, to filesystem paths and files.
**Target Users:** Homelab administrators, DevOps engineers, home network enthusiasts
---
## 2. UI/UX Specification
### Layout Structure
```
┌─────────────────────────────────────────────────────────────────────────────────┐
│ HEADER: Logo + Title + View Mode Selector + Refresh Button │
├─────────────┬───────────────────────────────────────────────────┬───────────────┤
│ │ │ │
│ LEFT │ MAIN GRAPH CANVAS │ RIGHT │
│ PANEL │ (React Flow / D3.js) │ PANEL │
│ │ │ │
│ Subnodes │ Nodes connected by edges showing │ Details │
│ of │ relationships: │ Tabs: │
│ selected │ Gateway → VLAN → Host → Service → Volume │ │
│ node │ │ - Details │
│ │ [Interactive: click to select, │ - Config │
│ - List │ drag to pan, scroll to zoom] │ - Files │
│ - Click │ │ - Usage │
│ to │ │ - Importance │
│ select │ │ │
│ │ │ │
├─────────────┴───────────────────────────────────────────────────┴───────────────┤
│ FOOTER: Status bar (last refresh, node count, connection status) │
└─────────────────────────────────────────────────────────────────────────────────┘
```
- **Header:** Fixed, 56px height
- **Left Panel:** 280px width, collapsible
- **Right Panel:** 360px width, collapsible
- **Graph Canvas:** Flexible, fills remaining space
- **Footer:** Fixed, 32px height
### Responsive Breakpoints
- **Desktop (≥1200px):** Full 3-column layout
- **Tablet (768px-1199px):** Left panel hidden, right panel 300px
- **Mobile (<768px):** Panels as overlays/drawers
### Visual Design
#### Color Palette
```css
/* Network Layer */
--network-gateway: #6366F1; /* Indigo - UniFi gateway */
--network-vlan: #8B5CF6; /* Purple - VLANs */
--network-wifi: #EC4899; /* Pink - Access points */
/* Host Layer */
--host-physical: #10B981; /* Emerald - Physical servers */
--host-vm: #14B8A6; /* Teal - Virtual machines */
--host-container: #F59E0B; /* Amber - LXC containers */
/* Service Layer */
--service-media: #EF4444; /* Red - Jellyfin, Radarr, etc */
--service-infra: #3B82F6; /* Blue - Traefik, Authentik */
--service-monitoring: #22C55E; /* Green - Prometheus, Grafana */
--service-ai: #F97316; /* Orange - Ollama, Litellm */
--service-storage: #06B6D4; /* Cyan - Storage services */
/* Filesystem Layer */
--filesystem-nfs: #84CC16; /* Lime - NFS mounts */
--filesystem-volume: #A855F7; /* Purple - Docker volumes */
--filesystem-path: #EAB308; /* Yellow - File paths */
/* UI Colors */
--bg-primary: #0F172A; /* Slate 900 */
--bg-secondary: #1E293B; /* Slate 800 */
--bg-tertiary: #334155; /* Slate 700 */
--text-primary: #F8FAFC; /* Slate 50 */
--text-secondary: #94A3B8; /* Slate 400 */
--border: #475569; /* Slate 600 */
--accent: #38BDF8; /* Sky 400 */
--success: #22C55E;
--warning: #F59E0B;
--error: #EF4444;
```
#### Typography
- **Font Family:** `"JetBrains Mono", "Fira Code", monospace` for data; `"Inter", system-ui` for UI
- **Sizes:**
- H1 (Title): 24px, weight 700
- H2 (Section): 18px, weight 600
- H3 (Node name): 14px, weight 600
- Body: 13px, weight 400
- Caption: 11px, weight 400
#### Spacing System
- Base unit: 4px
- Padding: 8px (sm), 12px (md), 16px (lg), 24px (xl)
- Margins: 4px (xs), 8px (sm), 16px (md), 24px (lg)
- Border radius: 4px (sm), 8px (md), 12px (lg)
#### Visual Effects
- **Node shadows:** `0 2px 8px rgba(0,0,0,0.3)`
- **Panel shadows:** `0 4px 24px rgba(0,0,0,0.4)`
- **Glow on hover:** `0 0 12px var(--node-color)`
- **Transitions:** 200ms ease-out for all interactive elements
- **Graph edges:** Animated dashed lines for active connections
### Components
#### Node Component
- **Shape:** Rounded rectangle (120x48px) or circle (48x48px) for endpoints
- **Content:** Icon + Label + Status indicator
- **States:**
- Default: bg-secondary, border solid
- Hover: Glow effect, scale 1.02
- Selected: Border 2px accent, elevated shadow
- Running: Green status dot
- Stopped: Red status dot
- Warning: Yellow status dot
#### Edge Component
- **Style:** Curved bezier lines with arrows
- **States:**
- Default: border 1px text-secondary
- Active/Selected: border 2px accent, animated dash
#### Left Panel - Subnodes
- **Header:** "CHILD NODES" with count badge
- **List Items:** Icon + Name + Type badge
- **Interaction:** Click to focus/select in graph
- **Empty state:** "No child nodes"
#### Right Panel - Details Tabs
- **Tab Bar:** Details | Config | Files | Usage | Importance
- **Details Tab:** IP, MAC, Status, Uptime, Type, Description
- **Config Tab:** YAML/JSON view of configuration
- **Files Tab:** Tree view of relevant file paths
- **Usage Tab:** CPU, Memory, Network graphs
- **Importance Tab:** Critical / High / Medium / Low with reasoning
#### View Mode Selector
- **Options:**
- 🌐 Network: Shows gateway, VLANs, WiFi, hosts
- 🖥️ Hosts: Shows hosts and their services
- 📦 Services: Shows all services and their dependencies
- 💾 Filesystem: Shows volumes, mounts, paths
- 🔗 Full: Complete topology (default)
---
## 3. Functionality Specification
### Core Features
#### F1: Interactive Graph Visualization
- Render infrastructure as directed graph
- Pan, zoom, fit-to-view controls
- Click node to select (shows details)
- Double-click to focus/center
- Drag nodes to rearrange
- Minimap for navigation
#### F2: Node Selection & Navigation
- Single click: Select node, show details in right panel
- Double click: Zoom to node, expand children
- Right click: Context menu (copy IP, open URL, etc.)
- Keyboard: Arrow keys to navigate, Enter to select
#### F3: Multi-View Modes
- **Network View:** UniFi → VLANs → Subnets → Hosts
- **Host View:** Hosts → VMs/LXCs → Containers
- **Service View:** Services → Dependencies → Volumes
- **Filesystem View:** TrueNAS → NFS → Volumes → Paths
- **Full View:** Everything connected
#### F4: Detail Panels
**Left Panel (Subnodes):**
- Shows children of selected node
- Click to select in graph
- Shows node count per type
**Right Panel (Details):**
- 5 tabs with content
- Details: Basic info (IP, type, status)
- Config: Docker compose, YAML configs
- Files: Related file paths (clickable)
- Usage: Resource consumption
- Importance: 1-5 stars with why
#### F5: Data Discovery (Hybrid Approach)
**Static Config (JSON/YAML):**
```json
{
"network": {
"gateway": { "model": "UniFi Dream Machine Pro", "ip": "192.168.1.1" },
"vlans": [
{ "id": 10, "name": "Family", "subnet": "192.168.10.0/24" },
{ "id": 30, "name": "IoT", "subnet": "192.168.30.0/24" },
{ "id": 50, "name": "Production", "subnet": "192.168.50.0/24" }
],
"wifi": [
{ "ssid": "Will of D.", "vlan": "default" },
{ "ssid": "Will of D. IoT", "vlan": 30 }
]
},
"hosts": [
{
"name": "ubuntu",
"ip": "192.168.50.61",
"type": "vm",
"role": "Primary Docker Host",
"containers": ["traefik", "jellyfin", "authentik", ...]
},
{
"name": "grizzley",
"ip": "192.168.50.84",
"type": "rpi5",
"role": "Edge Services",
"containers": ["frigate", "traefik"]
}
]
}
```
**Auto-Discovery (SSH):**
- SSH to hosts and run commands
- `docker ps --format json` for containers
- `docker network inspect` for network topology
- `ls /mnt/truenas/` for NFS mounts
- `cat /proc/cpuinfo` for hardware info
#### F6: Search & Filter
- Search bar: Filter nodes by name
- Type filter: Show/hide node types
- Status filter: Running/Stopped/All
- Quick jump: Cmd+K to open command palette
#### F7: Real-time Updates
- Poll intervals: 30s (configurable)
- WebSocket option for live updates
- Visual indicator for stale data
### User Interactions & Flows
1. **Initial Load:**
- Load static config
- Run auto-discovery in background
- Render graph with all nodes
- Fit to view
2. **Select Node:**
- Click node → Highlight path to root
- Left panel shows children
- Right panel shows details (Details tab)
3. **Change View:**
- Click view mode → Re-render graph with filter
- Preserve selected node if visible
4. **View Service Config:**
- Select service node
- Click "Config" tab
- Shows docker-compose.yml content
- Clickable file paths
5. **Refresh Data:**
- Click refresh → Show loading state
- Run discovery commands
- Update graph
- Show "Last updated: X seconds ago"
### Data Handling
- **State Management:** React Context + useReducer
- **Persistence:** LocalStorage for user preferences (view mode, panel states)
- **Caching:** In-memory cache with 30s TTL
- **Error Handling:** Show stale data with warning banner if discovery fails
### Edge Cases
- Host unreachable: Show node with "Offline" status, gray out
- Container stopped: Show with red indicator, allow config view
- Empty discovery: Use static config as fallback
- Large graphs (100+ nodes): Enable clustering, lazy render
- Mobile: Simplified single-panel view with drawer navigation
---
## 4. Technical Architecture
### Tech Stack
- **Framework:** React 18 + TypeScript
- **Build Tool:** Vite
- **Graph Library:** React Flow (@xyflow/react)
- **Styling:** Tailwind CSS
- **State:** Zustand (lightweight)
- **HTTP Client:** Axios
- **SSH:** Node-SSH (backend) or jsch (frontend via proxy)
- **Icons:** Lucide React
- **Charts:** Recharts (for usage graphs)
### Project Structure
```
homelab-topology/
├── src/
│ ├── components/
│ │ ├── Graph/
│ │ │ ├── TopologyGraph.tsx
│ │ │ ├── NodeComponent.tsx
│ │ │ ├── EdgeComponent.tsx
│ │ │ └── controls.tsx
│ │ ├── Panels/
│ │ │ ├── LeftPanel.tsx
│ │ │ ├── RightPanel.tsx
│ │ │ └── DetailTabs/
│ │ ├── Header/
│ │ │ └── Header.tsx
│ │ └── common/
│ │ ├── Button.tsx
│ │ ├── Badge.tsx
│ │ └── Tabs.tsx
│ ├── hooks/
│ │ ├── useTopology.ts
│ │ ├── useDiscovery.ts
│ │ └── useSelection.ts
│ ├── store/
│ │ └── topologyStore.ts
│ ├── types/
│ │ └── index.ts
│ ├── utils/
│ │ ├── graphLayout.ts
│ │ └── formatters.ts
│ ├── data/
│ │ └── staticConfig.ts
│ ├── services/
│ │ └── discovery.ts
│ ├── App.tsx
│ ├── main.tsx
│ └── index.css
├── public/
├── docker/
│ └── Dockerfile
├── package.json
├── tsconfig.json
├── vite.config.ts
├── tailwind.config.js
└── README.md
```
### Backend/API (Optional)
If running auto-discovery, need a small backend:
- **Technology:** Node.js + Express
- **Purpose:** Proxy SSH commands to homelab hosts
- **Endpoints:**
- `GET /api/discover/:host` - Run discovery on specific host
- `GET /api/containers` - Get all containers across hosts
- `GET /api/volumes` - Get all Docker volumes
---
## 5. Acceptance Criteria
### Visual Checkpoints
- [ ] Graph renders with nodes and edges
- [ ] Nodes are color-coded by type
- [ ] Clicking a node highlights it and shows details
- [ ] Left panel shows child nodes of selected
- [ ] Right panel shows 5 tabs with content
- [ ] View mode selector changes graph content
- [ ] Panels can be collapsed/expanded
- [ ] Search filters nodes in real-time
### Functional Checkpoints
- [ ] Initial data loads from static config
- [ ] Auto-discovery populates missing data
- [ ] Graph is pannable and zoomable
- [ ] Node selection is persistent across view changes
- [ ] Config tab shows Docker compose content
- [ ] Files tab shows relevant file paths
- [ ] Refresh button updates data
### Performance Checkpoints
- [ ] Initial load < 2 seconds
- [ ] Graph renders 100+ nodes smoothly
- [ ] Interactions feel responsive (< 100ms)
### Deployment Checkpoints
- [ ] Builds successfully with `npm run build`
- [ ] Docker image builds and runs
- [ ] Accessible at localhost:3000
- [ ] Works in browser via local network
---
## 6. Data Model
### Node Types
```typescript
type NodeType =
| 'gateway'
| 'vlan'
| 'wifi'
| 'host_physical'
| 'host_vm'
| 'host_container'
| 'service'
| 'volume'
| 'mount'
| 'path';
interface TopologyNode {
id: string;
type: NodeType;
name: string;
data: {
ip?: string;
mac?: string;
status: 'running' | 'stopped' | 'unknown';
metadata: Record<string, any>;
config?: string;
files?: string[];
importance: 1 | 2 | 3 | 4 | 5;
};
position?: { x: number; y: number };
}
interface TopologyEdge {
id: string;
source: string;
target: string;
type?: string;
label?: string;
}
```
---
## 7. Implementation Priority
### Phase 1 (MVP - Week 1)
1. Set up React + React Flow project
2. Create static config with hardcoded topology
3. Render basic graph with nodes and edges
4. Implement node selection
5. Build right panel with Details tab
6. Add view mode selector
### Phase 2 (Week 2)
1. Complete right panel tabs (Config, Files, Usage, Importance)
2. Build left panel with child nodes
3. Add search and filters
4. Implement basic auto-discovery (Docker)
### Phase 3 (Week 3)
1. Add SSH-based discovery
2. Implement real-time updates
3. Add animations and polish
4. Create Docker build
### Phase 4 (Ongoing)
1. Add more node types
2. Improve auto-discovery coverage
3. Add mobile optimizations
4. Add saved layouts