Commit Graph

454 Commits

Author SHA1 Message Date
Rémy 4795dc40b8 Merge pull request #149 from Pouzor/feat/homepage-widget-stats
feat(api): stats endpoint for gethomepage widget
2026-05-15 01:16:48 +02:00
Pouzor 994ed9d77a feat(api): stats endpoint for gethomepage widget (closes #131)
Adds GET /api/v1/stats/summary, gated by HOMEPAGE_API_KEY env var and
X-API-Key header (hmac.compare_digest, matches the liveview pattern).

Payload:
  nodes / online / offline / unknown
  pending_devices (status='pending')
  zigbee_devices  (Node.ieee_address IS NOT NULL)
  last_scan_at    (max ScanRun.finished_at)

Disabled by default — endpoint returns 403 unless HOMEPAGE_API_KEY is set.
README documents activation and ships a ready-to-paste gethomepage
`customapi` widget snippet.

Tests cover: disabled-by-default, missing header, wrong key, empty DB,
and full aggregation across nodes/pending/zigbee/scan-runs.
2026-05-14 18:11:43 +02:00
Rémy 4d4befa916 Merge pull request #106 from findthelorax/fix/zone-styling
fix: zone styling
2026-05-14 15:58:45 +02:00
Pouzor 8f741691d0 fix(zone-modal): center slider thumb on track, drop dead code, cover a11y
- 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.
2026-05-14 15:35:19 +02:00
Pouzor c21fbac599 Merge remote-tracking branch 'origin/main' into fix/zone-styling 2026-05-14 14:03:46 +02:00
Rémy e9c66fceda Merge pull request #148 from Pouzor/feat/zigbee-properties
feat(zigbee): IEEE/Vendor/Model/LQI properties + security + tests
2026-05-14 13:47:12 +02:00
Pouzor 373960f6ea test(frontend): cover api client, ProxmoxGroupNode, CustomStyleModal 2026-05-14 13:25:41 +02:00
Pouzor aa17edf1d0 chore(security): drop passlib for direct bcrypt + reject CLI-flag check targets
- Replace passlib.CryptContext with bcrypt 4.2.1 directly (passlib is
  unmaintained and only emitted warnings when paired with bcrypt 4+).
  hash_password / verify_password now call bcrypt.checkpw / .hashpw, and
  verify_password is hardened against empty inputs without raising.
  scripts/hash_password.py + tests/conftest.py updated to match.
- status_checker.check_node() now rejects targets starting with '-' before
  any subprocess invocation, defending ping/tcp paths against arg-injection
  if an admin sets a check_target like '-O'.

Tests added:
- test_auth: expired JWT, malformed JWT, wrong-secret JWT, empty password
  vs empty server hash, verify_password edge cases.
- test_scan: _background_scan failure path marks ScanRun failed, leaves
  non-running terminal status alone, success path invokes run_scan.
- test_status_checker: ping/tcp invocations are bypassed when target or
  ip starts with '-'.

Backend coverage 89% → 90%.
2026-05-14 12:11:40 +02:00
Pouzor 5f87c64dcf fix(zigbee): default IEEE/Vendor/Model/LQI props to hidden, preserve user visibility
- New zigbee props (approve + first-time re-import) ship with visible=false
  so the canvas card stays clean. User opts in from the right panel.
- On re-import of an already-approved node, merge instead of overwrite:
  keys already present keep their visible flag (and any user-edited value
  is replaced with the freshly imported one), brand-new keys are appended
  hidden. Non-zigbee custom properties are preserved untouched.
2026-05-14 01:10:45 +02:00
Pouzor 5822a1483a fix(zigbee): inject IEEE/Vendor/Model/LQI props into approved nodes client-side
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.
2026-05-14 00:45:58 +02:00
Pouzor 3a303a1376 feat(zigbee): populate IEEE/Vendor/Model/LQI properties on approve and re-import
- 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.
2026-05-14 00:17:13 +02:00
Rémy f5e0e68806 Update README.md 2026-05-13 11:49:14 +02:00
Pouzor 8541922386 bump: version 2.0.3 v2.0.3 2026-05-13 11:37:06 +02:00
Rémy 3ed9cb0d4f Merge pull request #146 from Pouzor/fix/zigbee-no-check-method
fix(zigbee): hide check method in modal, force none/online for zigbee nodes
2026-05-13 11:35:10 +02:00
Pouzor fff11a4b6a fix(zigbee): hide check method in modal, force none/online for zigbee nodes
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.
2026-05-13 11:14:35 +02:00
Brett Ferrante 890463373a Merge branch 'Pouzor:main' into fix/zone-styling 2026-05-12 14:40:41 -04:00
Pouzor 0680566081 bump: 2.0.2 v2.0.2 2026-05-11 19:55:21 +02:00
Remy 2f5a90a00e Merge pull request #142 from Pouzor/fix/visual
Node modal polish + Smart Home and Brand icon pickers
2026-05-11 19:53:48 +02:00
Pouzor 928f63df0f fix(icons): narrow ICON_MAP lookup type for strict build
tsc -b (used in npm run build) flagged TS2774 because LucideIcon is a
function and therefore always truthy. Cast the lookup result to
LucideIcon | undefined so the falsy branch becomes meaningful.
2026-05-11 19:44:20 +02:00
Pouzor e84a4e0eb3 merge feat/brand-icons into fix/visual 2026-05-11 19:20:10 +02:00
Pouzor 3b0dbd7a8b feat(icons): add brand icon picker from dashboard-icons
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.
2026-05-11 19:18:01 +02:00
Pouzor 3a9b3b2650 feat(icons): add Smart Home / Sensors icon category
Add 27 new icons covering common IoT/Zigbee endpoints: smart plug,
relay, energy meter, solar, door/window sensor, smart lock, smoke
detector, siren, motion radar, presence, vibration, water leak,
humidity, air quality, HVAC vent, fan, AC, smart light, blinds,
doorbell, speaker, remote, garage, valve, weather station, plus
voice assistant and webhook in the existing Automation category.
2026-05-11 17:08:11 +02:00
Pouzor ff02f3b5db fix(node-modal): cap height at 90vh with scroll
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.
2026-05-11 16:54:33 +02:00
Pouzor a66e6aa906 bump: version 2.0.1 v2.0.1 2026-05-11 16:11:51 +02:00
Remy 8e59d9a0d1 Merge pull request #141 from Pouzor/fix/zigbee-node-types-in-modal
fix(node-modal): expose Zigbee device types in selector
2026-05-11 16:09:07 +02:00
Pouzor ee4136b506 fix(node-modal): expose Zigbee device types in selector
Add Zigbee section (coordinator, router, end device) to NodeModal
type group list, matching types used by zigbee2mqtt import.
2026-05-11 15:55:34 +02:00
Pouzor 8e8f01d6ca bump version 2.0.0 v2.0.0 2026-05-11 02:23:48 +02:00
Pouzor aba4f34168 feat(style-modal): expose Zigbee node types for customization
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.
2026-05-11 01:44:24 +02:00
Remy 6524efe126 Merge pull request #139 from Pouzor/feature/node-alignment-guides
feat(canvas): alignment guides + snap while dragging
2026-05-11 01:29:44 +02:00
Pouzor 062a08f116 fix(alignment): only snap top-level dragged nodes
Code review flagged silent corruption when dragging a mixed selection
of a parent + one of its children: the child's ids stayed in
pendingSnap even though nodeBox excluded it from the bbox. On drag
stop we shifted the child's parent-relative position by the same delta
the parent already moves by — double-snapping the child off-screen.

Restrict the pendingSnap id set to nodes that contributed a box
(top-level only). Children follow their parent's move automatically;
no extra shift is needed.
2026-05-11 01:23:37 +02:00
Pouzor 5e9963db4d refactor(alignment): defer snap to drag stop, stabilise callback deps
Code review flagged a drag race + deps issues:

- Race: setNodes during onNodeDrag fights React Flow's internal drag
  handler, which derives positions from the cursor offset captured at
  drag start. Snap delta could be overwritten on the next frame.
- Deps: useCallback closed over guides.length, causing recreation on
  every guide change and pulling stale references into onNodeDrag.

Fix: compute guides live during drag for visual feedback, store the
pending snap delta in a ref, and apply it via setNodes only on
onNodeDragStop. Replace the guides.length dep with a ref mirror updated
via useEffect (not during render).
2026-05-11 01:14:47 +02:00
Pouzor 82203f67d8 fix(alignment): use OnNodeDrag (NodeDragHandler doesn't exist in @xyflow/react)
CI build failed with TS2305: NodeDragHandler is not exported. Local
typecheck missed it because tsc-noEmit is more permissive than tsc -b.

Use the exported OnNodeDrag<NodeType> type and alias it with our
NodeData so the callback params are inferred (no implicit any).
2026-05-11 01:00:36 +02:00
Pouzor 004a8f19c1 feat(canvas): alignment guides + snap while dragging nodes
Draw.io / Figma style: while dragging a node, show dashed cyan guide
lines when its edges (left / center / right / top / middle / bottom)
align with another node's, and snap the position to the matched line
within a configurable threshold.

- utils/alignment.ts: pure snap math, returns delta + guide segments.
  Same-size boxes show all aligned guides simultaneously.
- canvas/AlignmentGuides.tsx: SVG overlay locked to the React Flow
  viewport (panned/zoomed correctly).
- hooks/useAlignmentGuides.ts: wires onNodeDrag/onNodeDragStop, applies
  snap via setNodes, listens for Alt to temporarily disable.
- utils/alignmentSettings.ts: localStorage-backed prefs (enabled,
  threshold 2-16px) with a tiny CustomEvent pub-sub so the SettingsPanel
  and the drag hook stay in sync without a global store.
- Sidebar settings panel: toggle + threshold slider.

Multi-selection drag uses the union bounding box. Children with
parentId are skipped for v1 to avoid mixing absolute and parent-relative
coordinates. Hold Alt to escape snap.
2026-05-11 00:35:50 +02:00
Pouzor 5ab0bdeb7f fix(text-node): persist text in label so it survives reload
text_content is not in the API serializer schema, so text node content
was dropped on save and the node came back empty after reload.

Store text in label instead — already persisted, and TextNode + the
edit modal already fall back to label, so existing data stays
compatible. Clear stale text_content on update.

Regression test added for the text-node save/load roundtrip.
2026-05-11 00:34:38 +02:00
Pouzor 3f9866e8a1 fix(detail): handle non-Z timezone offsets in Last Seen
Backend sends ISO timestamps with +00:00 offset. Code blindly appended
'Z' when the string didn't end with 'Z', producing '...+00:00Z' which
parses to Invalid Date.

Detect any timezone marker (Z, z, or numeric offset like +00:00) and
only append 'Z' for naive datetimes.

Co-authored-by:
2026-05-10 21:45:22 +02:00
Pouzor ebdf6cb55b fix(scan): default check_method='ping' for approved devices
Approving a pending device created a Node with check_method=NULL, so
the status scheduler silently skipped it (scheduler.py:64 filters
falsy check_method) and the bubble stayed grey forever.

Default to 'ping' when the device has an IP, in both single and bulk
approve paths. Also persist caller-supplied check_method/check_target
in the single-approve path.

Add regression tests asserting default check_method='ping' after
approval for both endpoints.
2026-05-10 20:33:49 +02:00
Pouzor ec8f1c87f1 fix(status): use ms timeout for ping on macOS
ping(8) -W flag is milliseconds on macOS, seconds on Linux. Code used
-W 1 for both, giving macOS a 1ms timeout that fails any host with
RTT >1ms (typical wifi/mesh is 2-10ms).

Use -W 1000 on darwin to match the intended 1s timeout. Add regression
test asserting the platform-specific value.
2026-05-10 19:45:36 +02:00
Pouzor 2b91f31807 fix(group): preserve children + size on edit, fix status WS proxy
- Skip NodeModal on double-click for 'group'/'groupRect' (use inline rename)
- Exempt 'group' from properties-clears-height rule in updateNode
  (was collapsing group + hiding children with extent: 'parent')
- Enable ws: true on Vite /api proxy so /api/v1/status/ws/status upgrades
  (status bubbles stayed grey because WS handshake failed)
- Add regression tests for group/groupRect height preservation
2026-05-10 19:30:04 +02:00
Remy c6965b827b Merge pull request #138 from Pouzor/feature/text-node
feat: add Text node type to canvas
2026-05-10 16:58:41 +02:00
Pouzor afdea65d4e feat: add demo text nodes with onboarding hints
Top-right banner: 'This is demo canvas, start with fresh scan'.
Bottom-left hint: 'You can remove all nodes'.
2026-05-10 16:50:39 +02:00
Pouzor 32eb9fbe23 fix: add 'text' entry to nodeIcons + all themes
Build failed because Record<NodeType, ...> in nodeIcons.ts and
themes.ts requires every NodeType key. Add Type icon for text and
neutral border/icon palette per theme.
2026-05-10 16:31:38 +02:00
Pouzor 27fd78ece6 feat: add Text node type to canvas
New canvas object Text with edit/create modal: text content (single
or multi-line), font (Inter, JetBrains Mono, Serif, System Sans),
size, color, border (style + width + color), background. Double-click
on node opens edit modal. Sidebar gets "Add Text" entry below "Add Zone".

Refs #124
2026-05-10 15:58:35 +02:00
Remy e672cb086a Merge pull request #107 from findthelorax/feature/services-node-toggle
feature: services node toggle
2026-05-10 03:29:31 +02:00
findthelorax 3cddcf5b81 added cursor pointer to edit and delete buttons on services 2026-05-10 03:15:57 +02:00
findthelorax 19791abf5b adjusted show services toggle for alignment 2026-05-10 03:15:57 +02:00
findthelorax d9d4be9a53 services styling in node and detail panel 2026-05-10 03:15:57 +02:00
findthelorax c165b8b016 rebase with new main branch 2026-05-10 03:15:57 +02:00
findthelorax b16e81cf29 fixed some styling inconsistencies, removed show services toggle from affecting custom colors 2026-05-10 03:15:57 +02:00
findthelorax 3028e5a3f7 fix: cleanup 2026-05-10 03:15:57 +02:00
findthelorax 340bd15099 fix: external link icon on the detail panel for non URL services 2026-05-10 03:15:57 +02:00