feat(canvas): edge endpoint reconnect + proxmox container snap points
- Selected edge shows interactive dots at both endpoints; drag onto any handle (different snap point or different node) to reconnect. Edge follows the cursor live during drag; drop on empty space leaves edge unchanged. - Endpoint dots render in EdgeLabelRenderer above the node layer and walk the elementsFromPoint stack so the underlying handle wins over the dragged dot itself. - ProxmoxGroupNode in container mode now renders bottom_handles snap points (was always single 'bottom' handle), matching BaseNode. - New canvasStore.reconnectEdge action: swaps source/target/handles via normalizeHandle, snapshots history, marks dirty.
This commit is contained in:
@@ -497,6 +497,31 @@ describe('canvasStore', () => {
|
||||
expect(useCanvasStore.getState().hasUnsavedChanges).toBe(true)
|
||||
})
|
||||
|
||||
it('reconnectEdge swaps source/target and normalizes handles', () => {
|
||||
useCanvasStore.setState((s) => ({
|
||||
edges: [...s.edges, { ...makeEdge('e1', 'n1', 'n2'), sourceHandle: 'bottom', targetHandle: 'top' }],
|
||||
}))
|
||||
useCanvasStore.getState().markSaved()
|
||||
useCanvasStore.getState().reconnectEdge('e1', {
|
||||
source: 'n1',
|
||||
target: 'n3',
|
||||
sourceHandle: 'bottom-2-t',
|
||||
targetHandle: 'top-t',
|
||||
})
|
||||
const edge = useCanvasStore.getState().edges.find((e) => e.id === 'e1')
|
||||
expect(edge?.target).toBe('n3')
|
||||
expect(edge?.source).toBe('n1')
|
||||
expect(edge?.sourceHandle).toBe('bottom-2')
|
||||
expect(edge?.targetHandle).toBe('top')
|
||||
expect(useCanvasStore.getState().hasUnsavedChanges).toBe(true)
|
||||
})
|
||||
|
||||
it('reconnectEdge snapshots history for undo', () => {
|
||||
useCanvasStore.setState((s) => ({ edges: [...s.edges, makeEdge('e1', 'n1', 'n2')], past: [] }))
|
||||
useCanvasStore.getState().reconnectEdge('e1', { source: 'n1', target: 'n3', sourceHandle: null, targetHandle: null })
|
||||
expect(useCanvasStore.getState().past.length).toBe(1)
|
||||
})
|
||||
|
||||
it('deleteEdge removes the edge and marks unsaved', () => {
|
||||
useCanvasStore.setState((s) => ({ edges: [...s.edges, makeEdge('e1', 'n1', 'n2'), makeEdge('e2', 'n2', 'n3')] }))
|
||||
useCanvasStore.getState().markSaved()
|
||||
|
||||
Reference in New Issue
Block a user