diff --git a/web/app/components/workflow/hooks/use-nodes-interactions.ts b/web/app/components/workflow/hooks/use-nodes-interactions.ts index fdfb25b04..7046d1a93 100644 --- a/web/app/components/workflow/hooks/use-nodes-interactions.ts +++ b/web/app/components/workflow/hooks/use-nodes-interactions.ts @@ -39,6 +39,7 @@ import { import { genNewNodeTitleFromOld, generateNewNode, + getNestedNodePosition, getNodeCustomTypeByNodeDataType, getNodesConnectedSourceOrTargetHandleIdsMap, getTopLeftNodePosition, @@ -1326,8 +1327,7 @@ export const useNodesInteractions = () => { }) newChildren.push(newIterationStartNode!) } - - if (nodeToPaste.data.type === BlockEnum.Loop) { + else if (nodeToPaste.data.type === BlockEnum.Loop) { newLoopStartNode!.parentId = newNode.id; (newNode.data as LoopNodeType).start_node_id = newLoopStartNode!.id @@ -1337,6 +1337,44 @@ export const useNodesInteractions = () => { }) newChildren.push(newLoopStartNode!) } + else { + // single node paste + const selectedNode = nodes.find(node => node.selected) + if (selectedNode) { + const commonNestedDisallowPasteNodes = [ + // end node only can be placed outermost layer + BlockEnum.End, + ] + + // handle disallow paste node + if (commonNestedDisallowPasteNodes.includes(nodeToPaste.data.type)) + return + + // handle paste to nested block + if (selectedNode.data.type === BlockEnum.Iteration) { + newNode.data.isInIteration = true + newNode.data.iteration_id = selectedNode.data.iteration_id + newNode.parentId = selectedNode.id + newNode.positionAbsolute = { + x: newNode.position.x, + y: newNode.position.y, + } + // set position base on parent node + newNode.position = getNestedNodePosition(newNode, selectedNode) + } + else if (selectedNode.data.type === BlockEnum.Loop) { + newNode.data.isInLoop = true + newNode.data.loop_id = selectedNode.data.loop_id + newNode.parentId = selectedNode.id + newNode.positionAbsolute = { + x: newNode.position.x, + y: newNode.position.y, + } + // set position base on parent node + newNode.position = getNestedNodePosition(newNode, selectedNode) + } + } + } nodesToPaste.push(newNode) @@ -1344,6 +1382,7 @@ export const useNodesInteractions = () => { nodesToPaste.push(...newChildren) }) + // only handle edge when paste nested block edges.forEach((edge) => { const sourceId = idMapping[edge.source] const targetId = idMapping[edge.target] diff --git a/web/app/components/workflow/utils/node.ts b/web/app/components/workflow/utils/node.ts index 7a9e33b2f..726908bff 100644 --- a/web/app/components/workflow/utils/node.ts +++ b/web/app/components/workflow/utils/node.ts @@ -135,6 +135,13 @@ export const getTopLeftNodePosition = (nodes: Node[]) => { } } +export const getNestedNodePosition = (node: Node, parentNode: Node) => { + return { + x: node.position.x - parentNode.position.x, + y: node.position.y - parentNode.position.y, + } +} + export const hasRetryNode = (nodeType?: BlockEnum) => { return nodeType === BlockEnum.LLM || nodeType === BlockEnum.Tool || nodeType === BlockEnum.HttpRequest || nodeType === BlockEnum.Code }