feat: when copy/paste multi nodes not require reconnect them (#32631)

This commit is contained in:
非法操作
2026-03-09 13:55:12 +08:00
committed by GitHub
parent 654e41d47f
commit 4a2ba058bb
2 changed files with 51 additions and 5 deletions

View File

@ -1735,6 +1735,7 @@ export const useNodesInteractions = () => {
const offsetX = currentPosition.x - x
const offsetY = currentPosition.y - y
let idMapping: Record<string, string> = {}
const pastedNodesMap: Record<string, Node> = {}
const parentChildrenToAppend: { parentId: string, childId: string, childType: BlockEnum }[] = []
clipboardElements.forEach((nodeToPaste, index) => {
const nodeType = nodeToPaste.data.type
@ -1794,7 +1795,21 @@ export const useNodesInteractions = () => {
newLoopStartNode!.parentId = newNode.id;
(newNode.data as LoopNodeType).start_node_id = newLoopStartNode!.id
newChildren = handleNodeLoopChildrenCopy(nodeToPaste.id, newNode.id)
const oldLoopStartNode = nodes.find(
n =>
n.parentId === nodeToPaste.id
&& n.type === CUSTOM_LOOP_START_NODE,
)
idMapping[oldLoopStartNode!.id] = newLoopStartNode!.id
const { copyChildren, newIdMapping }
= handleNodeLoopChildrenCopy(
nodeToPaste.id,
newNode.id,
idMapping,
)
newChildren = copyChildren
idMapping = newIdMapping
newChildren.forEach((child) => {
newNode.data._children?.push({
nodeId: child.id,
@ -1839,18 +1854,31 @@ export const useNodesInteractions = () => {
}
}
idMapping[nodeToPaste.id] = newNode.id
nodesToPaste.push(newNode)
pastedNodesMap[newNode.id] = newNode
if (newChildren.length)
if (newChildren.length) {
newChildren.forEach((child) => {
pastedNodesMap[child.id] = child
})
nodesToPaste.push(...newChildren)
}
})
// only handle edge when paste nested block
// Rebuild edges where both endpoints are part of the pasted set.
edges.forEach((edge) => {
const sourceId = idMapping[edge.source]
const targetId = idMapping[edge.target]
if (sourceId && targetId) {
const sourceNode = pastedNodesMap[sourceId]
const targetNode = pastedNodesMap[targetId]
const parentNode = sourceNode?.parentId && sourceNode.parentId === targetNode?.parentId
? pastedNodesMap[sourceNode.parentId] ?? nodes.find(n => n.id === sourceNode.parentId)
: null
const isInIteration = parentNode?.data.type === BlockEnum.Iteration
const isInLoop = parentNode?.data.type === BlockEnum.Loop
const newEdge: Edge = {
...edge,
id: `${sourceId}-${edge.sourceHandle}-${targetId}-${edge.targetHandle}`,
@ -1858,8 +1886,19 @@ export const useNodesInteractions = () => {
target: targetId,
data: {
...edge.data,
isInIteration,
iteration_id: isInIteration ? parentNode?.id : undefined,
isInLoop,
loop_id: isInLoop ? parentNode?.id : undefined,
_connectedNodeIsSelected: false,
},
zIndex: parentNode
? isInIteration
? ITERATION_CHILDREN_Z_INDEX
: isInLoop
? LOOP_CHILDREN_Z_INDEX
: 0
: 0,
}
edgesToPaste.push(newEdge)
}

View File

@ -108,12 +108,13 @@ export const useNodeLoopInteractions = () => {
handleNodeLoopRerender(parentId)
}, [store, handleNodeLoopRerender])
const handleNodeLoopChildrenCopy = useCallback((nodeId: string, newNodeId: string) => {
const handleNodeLoopChildrenCopy = useCallback((nodeId: string, newNodeId: string, idMapping: Record<string, string>) => {
const { getNodes } = store.getState()
const nodes = getNodes()
const childrenNodes = nodes.filter(n => n.parentId === nodeId && n.type !== CUSTOM_LOOP_START_NODE)
const newIdMapping = { ...idMapping }
return childrenNodes.map((child, index) => {
const copyChildren = childrenNodes.map((child, index) => {
const childNodeType = child.data.type as BlockEnum
const { defaultValue } = nodesMetaDataMap![childNodeType]
const nodesWithSameType = nodes.filter(node => node.data.type === childNodeType)
@ -139,8 +140,14 @@ export const useNodeLoopInteractions = () => {
zIndex: LOOP_CHILDREN_Z_INDEX,
})
newNode.id = `${newNodeId}${newNode.id + index}`
newIdMapping[child.id] = newNode.id
return newNode
})
return {
copyChildren,
newIdMapping,
}
}, [store, nodesMetaDataMap])
return {