- Fix DockerNode default icon: use Anchor instead of Package
- Add border_style option to Group Rectangle (solid/dashed/dotted/double/none)
- Group node type selector by category (Hardware, Virtualization, IoT, Generic)
- Add tests for border style feature
Silent return when label was empty made the Add button appear broken.
Native browser required tooltip doesn't render in Radix Dialog portals.
Now shows inline red error message and highlights the field.
- Add animated toggle per edge in EdgeModal (cyan switch, "Flow Animation")
- SVG-native <animate> element for reliable cross-browser dot animation
- Persist animated field: backend model, schemas (EdgeBase/EdgeUpdate/EdgeSave), DB migration
- Include animated in App.tsx edgesToSave serialization so it survives save/reload
- Add animated: bool to EdgeData TypeScript type
- 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
- Add groupRect entry to NODE_DEFAULT_COLORS (required by Record<NodeType, NodeColors>)
- Explicitly type Select onValueChange callbacks as (v: string) to satisfy
stricter type inference in tsc -b build mode
- 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
source handles: visible, can initiate drag from top or bottom
target handles: invisible (opacity:0, 12x12px), overlap the source at same
position — React Flow detects them for snapping and shows visual feedback
without the user seeing a second dot. Ensures bottom→top connections work.
connectionMode=loose alone does not reliably make source handles act as
drop targets. Each position now has both a source handle (to initiate
drag) and a target handle (to receive drops). They overlap visually as
one dot but support full bidirectional connections.
React Flow only allows initiating a drag from type=source handles.
Top handles were type=target so users could never start a connection
from the top of any node. With connectionMode=loose, source-to-source
connections are already allowed, so all handles can now be source.
React Flow blocks connections involving a parentId parent/child pair by
default to prevent hierarchy cycles. Override with isValidConnection
that only rejects self-loops (source === target), allowing explicit
edges between Proxmox container nodes and their nested VMs/LXCs.
The visibleEdges filter was silently dropping any edge between a
container-mode Proxmox and its children, even ones the user explicitly
drew. Since no edges are auto-generated, the filter only blocked
intentional connections. Removed it entirely.
- NodeSave schema was missing custom_icon field — icon reset to default on reload
- handleSave was not including custom_icon in the payload
- CameraNode now uses Cctv icon (clearer than Camera)
- Added 'cctv' entry to ICON_REGISTRY for the icon picker
- New 'camera' node type with Camera icon (frontend + types)
- Scanner fingerprint: camera ports (554, 8554, 37777, 34567, 2020) now suggest 'camera' instead of 'iot'
- service_signatures.json: all camera/NVR entries updated to suggested_node_type=camera
- 'camera' added to priority list in suggest_node_type (above iot)
- Add 65+ icons across 7 categories (Infrastructure, Media, Monitoring,
Storage, Security, Automation, Dev & Containers, Communications) covering
popular self-hosted apps: Home Assistant, Jellyfin, Plex, Grafana, Portainer,
Pi-hole, Vaultwarden, Gitea, Nextcloud, Node-RED, Frigate, etc.
- New nodeIcons.ts utility with ICON_REGISTRY, ICON_MAP and resolveNodeIcon()
- Inline icon picker in NodeModal: collapsible panel with search + grid grouped
by category; click to select, click again or Reset to revert to type default
- BaseNode uses resolveNodeIcon() so custom icon renders live on canvas
- Add custom_icon field to NodeData type, NodeBase/NodeUpdate schemas, Node ORM
model, and database.py idempotent ALTER TABLE migration
- 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
- Add custom_color field to EdgeData type, Edge DB model and all schemas
- HomelableEdge applies custom_color as stroke override (before selected highlight)
- EDGE_DEFAULT_COLORS extracted to utils/edgeColors.ts (react-refresh compliant)
- EdgeModal: color picker row showing effective color (custom or type default)
with hex value, Reset button when custom color is active
- Auto-migration adds custom_color column to edges table
- Add resolveNodeColors() utility merging type defaults with per-node overrides
- Default colors per node type (cyan=isp/router/lxc/ap, green=switch/nas,
purple=server/vm, orange=proxmox, amber=iot, gray=generic)
- Remove glowColor prop from BaseNode — colors now come from node data
- ProxmoxGroupNode uses resolveNodeColors for group border/header/icon
- NodeModal: Appearance section with 3 color swatches (border, background, icon)
— click swatch to open native color picker; Reset to defaults button
- custom_colors persisted as JSON in DB (backend model + schemas + migration)
- 7 new unit tests for resolveNodeColors covering all node types + partial overrides