fix: cluster edges render on left/right handles from approve flow

Cluster edges created via the pending -> approve path rendered on the top
handle instead of left/right, because the edge and its endpoints lost their
handle information on the way to the canvas.

- Approve resolver (scan.py) now returns each edge's type + source/target
  handle. Handle IDs are the bare slot-0 side names ('right'/'left'), the
  canonical stored form React Flow resolves to the correct side; a '-t' target
  id fails to resolve and falls back to the top handle.
- Frontend injectAutoEdges no longer hardcodes iot/bottom/top-t. It injects
  each edge with its real type + handles and bumps the referenced nodes'
  left/right handle counts (which default to 0) so the cluster endpoints exist.
  Logic extracted to a pure, tested util (applyAutoEdges).
- clusterEdges direct-import path uses the bare 'left' target to match.

Tests: new autoEdges unit tests; updated backend handle assertions.

ha-relevant: maybe
This commit is contained in:
Pouzor
2026-07-06 11:13:32 +02:00
parent 9670d0a86a
commit 05ef746f22
8 changed files with 176 additions and 24 deletions
+2 -2
View File
@@ -88,7 +88,7 @@ export const scanApi = {
approved: boolean
node_id: string
edges_created: number
edges: { id: string; source: string; target: string }[]
edges: { id: string; source: string; target: string; type?: string; source_handle?: string | null; target_handle?: string | null }[]
}>(`/scan/pending/${id}/approve`, nodeData),
hide: (id: string) => api.post(`/scan/pending/${id}/hide`),
ignore: (id: string) => api.post(`/scan/pending/${id}/ignore`),
@@ -98,7 +98,7 @@ export const scanApi = {
node_ids: string[]
device_ids: string[]
edges_created: number
edges: { id: string; source: string; target: string }[]
edges: { id: string; source: string; target: string; type?: string; source_handle?: string | null; target_handle?: string | null }[]
skipped: number
}>('/scan/pending/bulk-approve', { device_ids: ids, design_id: designId ?? undefined }),
bulkHide: (ids: string[]) => api.post<{ hidden: number; skipped: number }>('/scan/pending/bulk-hide', { device_ids: ids }),