sync multi-node drag through collaboration

This commit is contained in:
hjlarry 2026-04-13 17:39:39 +08:00
parent 2f7336b5d9
commit f0cd2e8465
2 changed files with 16 additions and 8 deletions

View File

@ -4,6 +4,7 @@ import { act, waitFor } from '@testing-library/react'
import { useEdges, useNodes, useStoreApi } from 'reactflow'
import { createEdge, createNode } from '../../__tests__/fixtures'
import { renderWorkflowFlowHook } from '../../__tests__/workflow-test-env'
import { collaborationManager } from '../../collaboration/core/collaboration-manager'
import { useSelectionInteractions } from '../use-selection-interactions'
type BundledState = {
@ -126,6 +127,7 @@ describe('useSelectionInteractions', () => {
})
it('handleSelectionDrag should sync node positions', async () => {
const setNodesSpy = vi.spyOn(collaborationManager, 'setNodes')
const { result, store } = renderSelectionInteractions()
const draggedNodes = [
{ id: 'n1', position: { x: 50, y: 60 }, data: {} },
@ -136,6 +138,9 @@ describe('useSelectionInteractions', () => {
})
expect(store.getState().nodeAnimation).toBe(false)
expect(setNodesSpy).toHaveBeenCalledOnce()
expect(setNodesSpy.mock.calls[0]?.[2]).toBe('use-selection-interactions:handleSelectionDrag')
expect(setNodesSpy.mock.calls[0]?.[1].find(node => node.id === 'n1')?.position).toEqual({ x: 50, y: 60 })
await waitFor(() => {
expect(result.current.nodes.find(node => node.id === 'n1')?.position).toEqual({ x: 50, y: 60 })

View File

@ -9,10 +9,14 @@ import {
} from 'react'
import { useStoreApi } from 'reactflow'
import { useWorkflowStore } from '../store'
import { useCollaborativeWorkflow } from './use-collaborative-workflow'
import { useNodesReadOnly } from './use-workflow'
export const useSelectionInteractions = () => {
const store = useStoreApi()
const workflowStore = useWorkflowStore()
const collaborativeWorkflow = useCollaborativeWorkflow()
const { getNodesReadOnly } = useNodesReadOnly()
const handleSelectionStart = useCallback(() => {
const {
@ -81,15 +85,14 @@ export const useSelectionInteractions = () => {
}, [store])
const handleSelectionDrag = useCallback((_: MouseEvent, nodesWithDrag: Node[]) => {
const {
getNodes,
setNodes,
} = store.getState()
workflowStore.setState({
nodeAnimation: false,
})
const nodes = getNodes()
if (getNodesReadOnly())
return
const { nodes, setNodes } = collaborativeWorkflow.getState()
const newNodes = produce(nodes, (draft) => {
draft.forEach((node) => {
const dragNode = nodesWithDrag.find(n => n.id === node.id)
@ -98,8 +101,8 @@ export const useSelectionInteractions = () => {
node.position = dragNode.position
})
})
setNodes(newNodes)
}, [store, workflowStore])
setNodes(newNodes, true, 'use-selection-interactions:handleSelectionDrag')
}, [collaborativeWorkflow, getNodesReadOnly, workflowStore])
const handleSelectionCancel = useCallback(() => {
const {