fix: approve devices onto the active design + Z-Wave node fields
Approve (single + bulk) created the canvas Node under the first design instead of the design the user is viewing, so approved devices were invisible on the active canvas and got wiped on the next save — and a re-approve returned "0 approved" because the rows were already approved. - bulk-approve now accepts design_id; the UI sends the active design. - single approve already honoured design_id; the UI now sends it too. - generalize the wireless branch (status=online, mesh props, no ICMP check) to Z-Wave as well as Zigbee, using build_zwave_properties. ha-relevant: yes
This commit is contained in:
@@ -186,7 +186,9 @@ describe('api/client', () => {
|
||||
mod.scanApi.ignore('d1')
|
||||
expect(api.post).toHaveBeenCalledWith('/scan/pending/d1/ignore')
|
||||
mod.scanApi.bulkApprove(['a', 'b'])
|
||||
expect(api.post).toHaveBeenCalledWith('/scan/pending/bulk-approve', { device_ids: ['a', 'b'] })
|
||||
expect(api.post).toHaveBeenCalledWith('/scan/pending/bulk-approve', { device_ids: ['a', 'b'], design_id: undefined })
|
||||
mod.scanApi.bulkApprove(['a'], 'design-9')
|
||||
expect(api.post).toHaveBeenCalledWith('/scan/pending/bulk-approve', { device_ids: ['a'], design_id: 'design-9' })
|
||||
mod.scanApi.bulkHide(['a'])
|
||||
expect(api.post).toHaveBeenCalledWith('/scan/pending/bulk-hide', { device_ids: ['a'] })
|
||||
mod.scanApi.restore('d1')
|
||||
|
||||
@@ -81,7 +81,7 @@ export const scanApi = {
|
||||
}>(`/scan/pending/${id}/approve`, nodeData),
|
||||
hide: (id: string) => api.post(`/scan/pending/${id}/hide`),
|
||||
ignore: (id: string) => api.post(`/scan/pending/${id}/ignore`),
|
||||
bulkApprove: (ids: string[]) =>
|
||||
bulkApprove: (ids: string[], designId?: string | null) =>
|
||||
api.post<{
|
||||
approved: number
|
||||
node_ids: string[]
|
||||
@@ -89,7 +89,7 @@ export const scanApi = {
|
||||
edges_created: number
|
||||
edges: { id: string; source: string; target: string }[]
|
||||
skipped: number
|
||||
}>('/scan/pending/bulk-approve', { device_ids: ids }),
|
||||
}>('/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 }),
|
||||
restore: (id: string) => api.post<{ restored: boolean; device_id: string }>(`/scan/pending/${id}/restore`),
|
||||
bulkRestore: (ids: string[]) => api.post<{ restored: number; skipped: number }>('/scan/pending/bulk-restore', { device_ids: ids }),
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
import { Dialog, DialogClose, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'
|
||||
import { scanApi } from '@/api/client'
|
||||
import { useCanvasStore } from '@/stores/canvasStore'
|
||||
import { useDesignStore } from '@/stores/designStore'
|
||||
import { toast } from 'sonner'
|
||||
import { PendingDeviceModal, type PendingDevice } from '@/components/modals/PendingDeviceModal'
|
||||
import type { NodeType, ServiceInfo } from '@/types'
|
||||
@@ -127,6 +128,7 @@ export function PendingDevicesModal({ open, onClose, highlightId, initialStatus
|
||||
// Optionally restrict to devices that have at least one detected service.
|
||||
const [withServicesOnly, setWithServicesOnly] = useState(false)
|
||||
const { addNode, scanEventTs } = useCanvasStore()
|
||||
const activeDesignId = useDesignStore((s) => s.activeDesignId)
|
||||
const highlightRef = useRef<HTMLButtonElement>(null)
|
||||
|
||||
const load = useCallback(async () => {
|
||||
@@ -283,6 +285,8 @@ export function PendingDevicesModal({ open, onClose, highlightId, initialStatus
|
||||
status: wireless ? 'online' : 'unknown',
|
||||
services: (device.services ?? []) as ServiceInfo[],
|
||||
properties,
|
||||
// Approve onto the design the user is viewing, not the first design.
|
||||
design_id: activeDesignId ?? undefined,
|
||||
}
|
||||
const res = await scanApi.approve(device.id, nodeData)
|
||||
const nodeId = res.data.node_id
|
||||
@@ -327,7 +331,7 @@ export function PendingDevicesModal({ open, onClose, highlightId, initialStatus
|
||||
const ids = [...selectedIds]
|
||||
if (ids.length === 0) return
|
||||
try {
|
||||
const res = await scanApi.bulkApprove(ids)
|
||||
const res = await scanApi.bulkApprove(ids, activeDesignId)
|
||||
const deviceToNode: Record<string, string> = {}
|
||||
res.data.device_ids.forEach((did, i) => { deviceToNode[did] = res.data.node_ids[i] })
|
||||
const approvedDevices = devices.filter((d) => ids.includes(d.id))
|
||||
|
||||
@@ -213,7 +213,7 @@ describe('PendingDevicesModal', () => {
|
||||
fireEvent.click(screen.getByTestId('pending-card-dev-a'))
|
||||
fireEvent.click(screen.getByTestId('pending-card-dev-b'))
|
||||
fireEvent.click(screen.getByRole('button', { name: /Approve \(2\)/ }))
|
||||
await waitFor(() => expect(mockBulkApprove).toHaveBeenCalledWith(['dev-a', 'dev-b']))
|
||||
await waitFor(() => expect(mockBulkApprove).toHaveBeenCalledWith(['dev-a', 'dev-b'], null))
|
||||
})
|
||||
|
||||
it('bulk approve carries the scanned MAC onto the canvas node (#168)', async () => {
|
||||
@@ -290,7 +290,7 @@ describe('PendingDevicesModal', () => {
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Select mode' }))
|
||||
fireEvent.click(screen.getByTestId('pending-card-dev-a'))
|
||||
fireEvent.keyDown(window, { key: 'Enter' })
|
||||
await waitFor(() => expect(mockBulkApprove).toHaveBeenCalledWith(['dev-a']))
|
||||
await waitFor(() => expect(mockBulkApprove).toHaveBeenCalledWith(['dev-a'], null))
|
||||
expect(mockBulkRestore).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user