What's Changed
Features
- Configurable bottom handles — each node now exposes 1–4 connection points on its bottom edge, configurable per node
- Fit view on load — canvas automatically fits all nodes in view when the app loads
- Node modal UX — Type and Icon pickers are now inline; icon picker trigger shows the selected icon as default
Scanner Rewrite
- Phase 1 — ping sweep — replaced nmap ARP sweep with a concurrent asyncio ping sweep (50 parallel pings, 1 s timeout each). Zero false positives regardless of Docker network mode. Supplements with
/proc/net/arpto catch ICMP-blocked devices (IoT, switches) - Phase 2 — explicit scan type — uses
-sS(root) or-sT(non-root) to prevent nmap silently failing without raw socket access; host-timeout bumped to 60 s - Resilient gather —
return_exceptions=Trueon Phase 2 gather so a single failing host no longer aborts the entire batch
Bug Fixes
- Logging — attach
StreamHandlerto root logger in lifespan soapp.*logs are always visible in Docker regardless of uvicorn log config - CIDR validation — validate scan ranges on both frontend and backend to prevent nmap argument injection
- Thread safety — pre-fetch canvas/hidden IPs before the scan loop (no N+1 queries);
_arp_table_hostswrapped inasyncio.to_threadto avoid blocking the event loop - 404 on missing device — hide/ignore actions on a device that no longer exists now return a proper 404 instead of a 500
Tests
- 21 backend scanner tests (ping sweep, ARP cache, Phase 2 tolerance, privilege-aware args)
- 581 frontend tests passing (NodeModal ×53, handleUtils, LiveView, store, edge label)
Full changelog: v1.7.1...v1.8.0