Clicking Settings now opens a dialog with the status-check interval and
canvas snap options plus Save/Cancel, replacing the inline left-panel view.
Removes the 'settings' Sidebar view and SettingsPanel component.
ha-relevant: maybe
Address review nits on the close/Enter fix:
- Add statusFilter to the keydown effect deps so Enter dispatches the
correct bulk action regardless of whether the device list changes
- Drop redundant title="Close" on the X (aria-label is enough)
ha-relevant: maybe
In the Hidden view the only bulk action is Restore, but the Enter
shortcut in select mode always called handleBulkApprove — approving
hidden devices. Dispatch on statusFilter: restore when hidden, approve
when pending. Add regression tests for both views.
ha-relevant: maybe
The close X used a raw <button onClick={onClose}>, bypassing Base UI's
dismissal. Outside-click worked (it goes through onOpenChange) but the
synthetic click on the X was dropped on Firefox/Windows. Route the X
through Base UI's DialogClose, the same path as outside-click and the
library's default close button. Add a regression test.
ha-relevant: maybe
Make designs (canvases) fully user-manageable: create with a chosen name
and icon, rename, change icon, and delete. Replaces the hardcoded
"New Electrical Design" button with a generic "New Canvas" flow.
- Add Design.icon column + migration that backfills legacy rows
(electrical -> zap, others -> dashboard)
- DesignModal: name input + curated lucide icon picker (create + edit)
- Sidebar switcher gains per-canvas edit/delete; delete guards the last
canvas and confirms
- designStore: addDesign/updateDesign/removeDesign with active reassignment
- Fix data loss on design switch: abort load when the save fails and keep
unsaved edits; skip the save-old step when the previous canvas was deleted
- designsApi create/update carry icon; design_type kept for back-compat
Tests: backend design CRUD (icon + cascade + last-canvas guard), designStore
actions, designIcons resolver, DesignModal create/edit/validation.
ha-relevant: yes
The backend stored the MAC, but the frontend built the approved canvas
node locally with properties=[] (non-zigbee) and no mac field. On save,
canvas/save upserts every node field from the in-memory canvas, so the
empty properties overwrote the DB MAC — the address showed after a
no-save reload but vanished once saved.
Now both approve paths (single + bulk) attach a MAC property row and
the mac field to the node added to the canvas, mirroring the backend
build_mac_property. Hidden by default, toggleable from the right panel.
- new buildMacProperty util + unit tests
- bulk-approve modal test asserts MAC propagation (IP device) and
absence for a zigbee device
ha-relevant: yes
Issue #20: bump MAX_BOTTOM_HANDLES 48 -> 64 (covers 48+4 SFP switches) and add
a per-node "Show Port Numbers" toggle that labels each bottom connection point.
Issue #21: add `fibre` as a first-class edge/connection type (bright cyan with a
subtle glow) alongside ethernet/wifi/iot/vlan/virtual/cluster - selectable in the
edge modal, themeable, registered in the React Flow edgeTypes registry, and
round-tripped through YAML import/export.
Backport of homelable-hacs PR #23.
ha-relevant: yes
Personal computing devices (laptops, phones, tablets) currently collapse
into the generic icon because the type vocabulary has no entries for
them. This adds two new NodeTypes with Lucide icons:
- laptop -> Laptop icon (reuses the computer accent color per theme)
- mobile -> Smartphone icon (new pink accent #ec4899 across themes)
Touches:
- types/index.ts NodeType union + NODE_TYPE_LABELS
- utils/nodeIcons.ts Lucide import + ICON_REGISTRY +
NODE_TYPE_DEFAULT_ICONS
- utils/themes.ts nodeAccents in all 6 themes
- canvas/nodes/index.tsx LaptopNode + MobileNode wrappers
- canvas/nodes/nodeTypes.ts register in react-flow nodeTypes
- modals/NodeModal.tsx new "Personal" type group
- modals/CustomStyleModal.tsx expose new types in style editor
- types/__tests__/types.test.ts enumerate new types
- utils/__tests__/themes.test.ts enumerate new types
Backwards-compatible: existing nodes typed as 'generic', 'server', etc.
keep rendering exactly as before. No data migration required.
- App.tsx: filter descendants of edited node from parentCandidates to
prevent picking a child as parent (would create a cycle).
- NodeModal.tsx: clear parent_id when switching to a type with no valid
parents, and revalidate parent_id on submit against the type's allowlist.
- Tests: cover getValidParentTypes for lxc/vm/docker_container and types
that disallow parents.
ha-relevant: yes
Adds back the Parent Container selector in NodeModal, shown when:
- child type is lxc or vm (parents: proxmox/vm/lxc/docker_host)
- child type is docker_container (parents: docker_host/lxc/vm/proxmox)
Selector hidden when no valid candidate node exists on the canvas.
Centralizes the parent-type allowlist in getValidParentTypes
(shared with the virtual-edge auto-parent helper).
ha-relevant: yes
- Center webkit slider thumb on 4px track (margin-top: -4.5px) so the
opacity bullet no longer sits below the bar.
- Drop redundant inline accentColor; CSS module owns track color.
- Remove dead ::-ms-* prefix rules.
- Tests: assert aria-labels on grid/select triggers, cover getFontLabel
happy path + unknown-value fallback via the Font selector DOM.
Backend already writes the properties on approve, but the frontend's local
addNode() call rebuilt NodeData without them — so newly approved zigbee
nodes showed an empty right panel until a full canvas reload. Build the
property list on the client from the PendingDevice fields so the canvas
state matches the DB row immediately. Single + bulk approve flows updated.
- Approval (single + bulk) of zigbee pending devices now writes IEEE, Vendor,
Model, LQI into Node.properties so they show in the right panel.
- Zigbee re-import refreshes properties on existing canvas Nodes and skips
creating a pending row when the device was already approved — keeps
approved devices out of pending/hidden modals.
- Coordinator Node also receives the same properties on first creation and
on re-import.
- Remove the Parent Container selector from the add/edit node modal.
Zigbee nodes have no IP-based check — hide Check Method and Check Target
fields in NodeModal for all three zigbee types. Default and force
check_method='none' so the scheduler marks them always online.
Backend approve and zigbee import routes also set status='online' and
check_method='none' for zigbee node types.
Add a second tab in the node Icon picker to choose from the ~2250 brand
icons hosted by homarr-labs/dashboard-icons (Plex, Sonarr, Home
Assistant, etc.) served via jsDelivr CDN. The Generic tab keeps the
existing lucide picker unchanged.
Storage uses a 'brand:<slug>' prefix on custom_icon, so existing nodes
referencing lucide keys keep working with zero migration. A new
resolveCustomIcon helper returns a discriminated union (lucide | brand)
and a NodeIcon component centralizes rendering for both kinds.
Includes a manifest fetch script (scripts/fetch-dashboard-icons.mjs)
and a checked-in dashboardIcons.json snapshot.
Modal grew taller than viewport when icon picker expanded, hiding
header and footer buttons. Constrain DialogContent to 90vh and add
overflow-y-auto so all controls stay reachable.
Add zigbee_coordinator, zigbee_router, zigbee_enddevice to the
CustomStyleModal editable list with Radio/Zap/Lightbulb icons so users
can tweak color, opacity, and size like any other node type.
Trash button in PendingDevicesModal now removes only filtered devices
instead of wiping the whole pending list. Falls back to clearPending
when no filters are active.
Replaces sidebar pending/hidden panels with a wide modal showing
devices as cards. Adds search, segmented source/status filters,
type filter, select mode for bulk approve/hide/restore, and
keyboard shortcuts. Hidden cards click-to-restore (no approval
detour); approval no longer pops the edit modal.
Backend: new restore + bulk-restore endpoints (hidden -> pending).
- SearchModal.tsx: same null-IP guard as SearchBar; also search by
friendly_name and ieee_address. Fixes Docker CI typecheck.
- python-multipart 0.0.26 -> 0.0.27 (CVE-2026-42561). Fixes
Security pip-audit.
Coordinator auto-approves to a canvas Node; routers/end devices land in
pending_devices keyed by IEEE. Discovered parent->child edges are stored
in pending_device_links so that approving a pending device later
auto-creates the Edge once both endpoints exist as canvas Nodes.
- new POST /api/v1/zigbee/import-pending (default mode in modal)
- new pending_device_links table; ieee_address on nodes + pending_devices
- pending_devices.ip migrated to nullable (table rebuild on existing DBs)
- approve / bulk-approve return auto-created edges; sidebar pushes them
into the canvas store with bottom -> top-t handles
- ZigbeeImportModal: radio toggle pending vs canvas; reset on close
- PendingDeviceModal: zigbee badge, IEEE/LQI/vendor/model rows, services
hidden for zigbee
- Sidebar pending row: ZIG source badge, LQI badge, friendly_name fallback
- SearchBar: null-safe IP, also searches friendly_name and ieee_address
- Tooltip trigger uses asChild to avoid nested-button hydration error
Replaces the 4-option dropdown with a 1..48 slider. Existing handle IDs
('bottom', 'bottom-2'..'bottom-4') are preserved and the hand-tuned pixel
positions for counts 1..4 are locked in (regression-tested) so saved
canvases render identically. Counts >=5 use uniform spacing; node card
auto-grows in width so handles stay clickable. Existing edge-remap on
shrink scales unchanged thanks to its index-based loop.
ha-relevant: yes
Bare if without braces meant onClose() ran unconditionally after the
window.confirm — clicking Cancel still closed the modal and dropped
unsaved edits. Wrap the confirm body so onClose only fires on accept.
New 'firewall' NodeType with Flame icon. Wired through node registry,
icon registry, all six themes (red-tinted accent per palette), NodeModal
Hardware group, and CustomStyleModal editable types.