- Add lasso/box selection via selectionOnDrag (Space to pan, lasso by default)
- Add lasso/pan toggle button in canvas controls (bottom-left)
- Multi-select panel in right panel when 2+ nodes selected (including zones)
- Create named Group node from selected nodes with bounding box math
- Group node: resizable, inline rename, show/hide border toggle, status summary
- GroupDetailPanel: lists members, online/offline count, ungroup action
- Fix group persistence after save/reload (extend proxmox container map to include group nodes)
- Fix groupRect serialization to preserve parent_id
- Remove background color from group and proxmox container node wrappers
- Add tests for all new store actions, GroupNode, MultiSelectPanel, GroupDetailPanel
- POST /scan/{run_id}/stop endpoint signals running scan to cancel
- Scanner checks cancellation flag between CIDR ranges and hosts, exits early
- Cancelled scans get status 'cancelled' instead of 'done'
- Stop button (red StopCircle) shown in Scan History panel for running scans
- 6 new backend tests, 5 new frontend tests
- Add 'Delete' to deleteKeyCode so both Backspace and Delete remove nodes
- Call snapshotHistory() in onBeforeDelete (keyboard) and in DetailPanel
handleDelete (button) so deletions can be undone with Ctrl+Z
- Opens panel and calls settingsApi.get
- Displays interval loaded from API
- Saves updated interval via settingsApi.save
- Shows error toast on save failure
- Toggles panel closed on second Settings click
- New GET/POST /api/v1/settings for status check interval
- Scan /api/v1/scan/config now handles ranges only
- Frontend: settingsApi client, SettingsPanel uses settingsApi
- ScanConfigModal no longer reads/writes interval
- 4 new backend tests for settings endpoint
- Add Settings item in sidebar actions section (below Save Canvas)
- Settings panel shows status check interval with save button
- Remove interval field from ScanConfigModal (now belongs in Settings)
- Scan modal shows a hint pointing to sidebar Settings
- Rename "Rectangle" → "Zone" in sidebar, add modal and edit modal
- Add border width selector (1–5px, default 2px) to the Zone modal
- Border width persisted in custom_colors.border_width and applied in GroupRectNode
- Add hideIp / toggleHideIp to canvasStore (UI-only, not persisted)
- Add maskIp util: 192.168.1.115 → 192.168.XX.XX (non-IPv4 passthrough)
- BaseNode reads hideIp from store and masks last two octets when active
- Sidebar shows Eye/EyeOff toggle below Scan Network, highlights when active
- Add custom SVG favicon and Logo component (house + network nodes motif)
- Update page title to Homelable with meta description
- Show Logo in sidebar header and toolbar
- Add theme store and ThemeModal for canvas style switching
- Refactor node colors and edge styles for theme support
- Any TCP service (except port 22 and known non-HTTP protocols) is now
clickable — fixes Sonarr, Radarr, Jellyfin, Proxmox web UI, etc.
- HTTPS auto-detected for port 443/8443 or names containing ssl/tls/https
- Non-HTTP blocklist: FTP, SMTP, DNS, LDAP, SMB, MySQL, Postgres,
Redis, MongoDB, Kafka, Memcached, etc.
- Inline "Add service" form in detail panel (name, port, tcp/udp)
- Remove button (×) on hover for each service row
- Group rect nodes excluded from detail panel
- getServiceUrl extracted to utils/serviceUrl.ts
- 13 new tests (79 total, all pass)
- New GroupRectNode: rounded rect with NodeResizer (8 handles), no
connection handles, always behind network nodes via negative zIndex
- GroupRectModal: label, font preset (Inter/Mono/Serif), 3×3 text
position grid, text/border/background color pickers, z-order 1–9
- Sidebar: "Add Rectangle" button (below Add Node), group rects
excluded from node count stats
- Save/load: size persisted in custom_colors.width/height, no backend
schema changes required
- elevateNodesOnSelect=false on ReactFlow so selected rects never
pop above network nodes
- Tests: 3 new store tests + 9 GroupRectModal tests (66 total, all pass)
Backend:
- Add MAC OUI lookup table (QEMU 52:54:00, Proxmox bc:24:11, VMware, VBox, Hyper-V)
- suggest_node_type() now accepts mac param and uses OUI as a low-priority hint
Frontend:
- Detect VM type from MAC prefix on pending device cards
- Show colored badge (QEMU / PVE / VMware / VBox / Hyper-V) in orange with tooltip
- Show recognized service name (Home Assistant, Synology, Proxmox, etc.) as
card title instead of IP when detected via service signatures
- Keep IP displayed smaller below when title differs from IP
- Add SSH / HTTP / HTTPS badges as colored pills
- Show +N badge for additional services beyond the three common ones
- nodeColors.ts: add missing camera/printer/computer/cpl entries to Record<NodeType, NodeColors>
- CanvasContainer.tsx: use ConnectionMode enum instead of bare string literal
- export.ts: cast style object to Partial<CSSStyleDeclaration> for CSS custom property
- Sidebar.tsx: cast suggested_type to NodeType to satisfy NodeData type
- Click any pending device row to open a detail modal
- Modal shows IP, hostname, MAC, OS, suggested type, discovered_at
- Service list with port/protocol/service_name, colored dot by category
- Approve / Hide / Delete buttons with matching color coding
- List items now show IP, service count, hostname and suggested type at a glance
Backend:
- asyncio.to_thread(_nmap_scan) — nmap no longer blocks the event loop
- Commit each discovered device immediately (previously one bulk commit at end)
- Update ScanRun.devices_found after each device so history panel shows live count
- broadcast_scan_update() pushes {type: scan_device_found} WS event per device
- Refactor broadcast_status to shared _broadcast() helper, adds type: "status" field
Frontend:
- useStatusPolling handles both WS message types (status / scan_device_found)
- canvasStore: scanEventTs + notifyScanDeviceFound() action
- PendingDevicesPanel auto-refreshes when WS scan event is received
- scanner.py: re-raise nmap exceptions so they reach ScanRun.error
(previously silently returned [] hiding the root cause)
- Sidebar: after triggering scan, auto-switch to History tab
- ScanHistoryPanel: auto-refresh every 3s while any run is 'running';
show error toast when a run transitions running→error; show spinner
on running runs; error message fully visible (no truncation)
- scripts/run_scan.py: standalone scan script to run with sudo for
nmap OS detection / SYN scans on macOS