|
@@ -29,6 +29,8 @@ import {
|
|
CUSTOM_EDGE,
|
|
CUSTOM_EDGE,
|
|
ITERATION_CHILDREN_Z_INDEX,
|
|
ITERATION_CHILDREN_Z_INDEX,
|
|
ITERATION_PADDING,
|
|
ITERATION_PADDING,
|
|
|
|
+ LOOP_CHILDREN_Z_INDEX,
|
|
|
|
+ LOOP_PADDING,
|
|
NODES_INITIAL_DATA,
|
|
NODES_INITIAL_DATA,
|
|
NODE_WIDTH_X_OFFSET,
|
|
NODE_WIDTH_X_OFFSET,
|
|
X_OFFSET,
|
|
X_OFFSET,
|
|
@@ -42,9 +44,12 @@ import {
|
|
} from '../utils'
|
|
} from '../utils'
|
|
import { CUSTOM_NOTE_NODE } from '../note-node/constants'
|
|
import { CUSTOM_NOTE_NODE } from '../note-node/constants'
|
|
import type { IterationNodeType } from '../nodes/iteration/types'
|
|
import type { IterationNodeType } from '../nodes/iteration/types'
|
|
|
|
+import type { LoopNodeType } from '../nodes/loop/types'
|
|
import { CUSTOM_ITERATION_START_NODE } from '../nodes/iteration-start/constants'
|
|
import { CUSTOM_ITERATION_START_NODE } from '../nodes/iteration-start/constants'
|
|
|
|
+import { CUSTOM_LOOP_START_NODE } from '../nodes/loop-start/constants'
|
|
import type { VariableAssignerNodeType } from '../nodes/variable-assigner/types'
|
|
import type { VariableAssignerNodeType } from '../nodes/variable-assigner/types'
|
|
import { useNodeIterationInteractions } from '../nodes/iteration/use-interactions'
|
|
import { useNodeIterationInteractions } from '../nodes/iteration/use-interactions'
|
|
|
|
+import { useNodeLoopInteractions } from '../nodes/loop/use-interactions'
|
|
import { useWorkflowHistoryStore } from '../workflow-history-store'
|
|
import { useWorkflowHistoryStore } from '../workflow-history-store'
|
|
import { useNodesSyncDraft } from './use-nodes-sync-draft'
|
|
import { useNodesSyncDraft } from './use-nodes-sync-draft'
|
|
import { useHelpline } from './use-helpline'
|
|
import { useHelpline } from './use-helpline'
|
|
@@ -73,6 +78,10 @@ export const useNodesInteractions = () => {
|
|
handleNodeIterationChildDrag,
|
|
handleNodeIterationChildDrag,
|
|
handleNodeIterationChildrenCopy,
|
|
handleNodeIterationChildrenCopy,
|
|
} = useNodeIterationInteractions()
|
|
} = useNodeIterationInteractions()
|
|
|
|
+ const {
|
|
|
|
+ handleNodeLoopChildDrag,
|
|
|
|
+ handleNodeLoopChildrenCopy,
|
|
|
|
+ } = useNodeLoopInteractions()
|
|
const dragNodeStartPosition = useRef({ x: 0, y: 0 } as { x: number; y: number })
|
|
const dragNodeStartPosition = useRef({ x: 0, y: 0 } as { x: number; y: number })
|
|
|
|
|
|
const { saveStateToHistory, undo, redo } = useWorkflowHistory()
|
|
const { saveStateToHistory, undo, redo } = useWorkflowHistory()
|
|
@@ -86,6 +95,9 @@ export const useNodesInteractions = () => {
|
|
if (node.type === CUSTOM_ITERATION_START_NODE || node.type === CUSTOM_NOTE_NODE)
|
|
if (node.type === CUSTOM_ITERATION_START_NODE || node.type === CUSTOM_NOTE_NODE)
|
|
return
|
|
return
|
|
|
|
|
|
|
|
+ if (node.type === CUSTOM_LOOP_START_NODE || node.type === CUSTOM_NOTE_NODE)
|
|
|
|
+ return
|
|
|
|
+
|
|
dragNodeStartPosition.current = { x: node.position.x, y: node.position.y }
|
|
dragNodeStartPosition.current = { x: node.position.x, y: node.position.y }
|
|
}, [workflowStore, getNodesReadOnly])
|
|
}, [workflowStore, getNodesReadOnly])
|
|
|
|
|
|
@@ -96,6 +108,9 @@ export const useNodesInteractions = () => {
|
|
if (node.type === CUSTOM_ITERATION_START_NODE)
|
|
if (node.type === CUSTOM_ITERATION_START_NODE)
|
|
return
|
|
return
|
|
|
|
|
|
|
|
+ if (node.type === CUSTOM_LOOP_START_NODE)
|
|
|
|
+ return
|
|
|
|
+
|
|
const {
|
|
const {
|
|
getNodes,
|
|
getNodes,
|
|
setNodes,
|
|
setNodes,
|
|
@@ -105,6 +120,7 @@ export const useNodesInteractions = () => {
|
|
const nodes = getNodes()
|
|
const nodes = getNodes()
|
|
|
|
|
|
const { restrictPosition } = handleNodeIterationChildDrag(node)
|
|
const { restrictPosition } = handleNodeIterationChildDrag(node)
|
|
|
|
+ const { restrictPosition: restrictLoopPosition } = handleNodeLoopChildDrag(node)
|
|
|
|
|
|
const {
|
|
const {
|
|
showHorizontalHelpLineNodes,
|
|
showHorizontalHelpLineNodes,
|
|
@@ -120,6 +136,8 @@ export const useNodesInteractions = () => {
|
|
currentNode.position.x = showVerticalHelpLineNodes[0].position.x
|
|
currentNode.position.x = showVerticalHelpLineNodes[0].position.x
|
|
else if (restrictPosition.x !== undefined)
|
|
else if (restrictPosition.x !== undefined)
|
|
currentNode.position.x = restrictPosition.x
|
|
currentNode.position.x = restrictPosition.x
|
|
|
|
+ else if (restrictLoopPosition.x !== undefined)
|
|
|
|
+ currentNode.position.x = restrictLoopPosition.x
|
|
else
|
|
else
|
|
currentNode.position.x = node.position.x
|
|
currentNode.position.x = node.position.x
|
|
|
|
|
|
@@ -127,12 +145,13 @@ export const useNodesInteractions = () => {
|
|
currentNode.position.y = showHorizontalHelpLineNodes[0].position.y
|
|
currentNode.position.y = showHorizontalHelpLineNodes[0].position.y
|
|
else if (restrictPosition.y !== undefined)
|
|
else if (restrictPosition.y !== undefined)
|
|
currentNode.position.y = restrictPosition.y
|
|
currentNode.position.y = restrictPosition.y
|
|
|
|
+ else if (restrictLoopPosition.y !== undefined)
|
|
|
|
+ currentNode.position.y = restrictLoopPosition.y
|
|
else
|
|
else
|
|
currentNode.position.y = node.position.y
|
|
currentNode.position.y = node.position.y
|
|
})
|
|
})
|
|
-
|
|
|
|
setNodes(newNodes)
|
|
setNodes(newNodes)
|
|
- }, [store, getNodesReadOnly, handleSetHelpline, handleNodeIterationChildDrag])
|
|
|
|
|
|
+ }, [getNodesReadOnly, store, handleNodeIterationChildDrag, handleNodeLoopChildDrag, handleSetHelpline])
|
|
|
|
|
|
const handleNodeDragStop = useCallback<NodeDragHandler>((_, node) => {
|
|
const handleNodeDragStop = useCallback<NodeDragHandler>((_, node) => {
|
|
const {
|
|
const {
|
|
@@ -163,6 +182,9 @@ export const useNodesInteractions = () => {
|
|
if (node.type === CUSTOM_NOTE_NODE || node.type === CUSTOM_ITERATION_START_NODE)
|
|
if (node.type === CUSTOM_NOTE_NODE || node.type === CUSTOM_ITERATION_START_NODE)
|
|
return
|
|
return
|
|
|
|
|
|
|
|
+ if (node.type === CUSTOM_LOOP_START_NODE || node.type === CUSTOM_NOTE_NODE)
|
|
|
|
+ return
|
|
|
|
+
|
|
const {
|
|
const {
|
|
getNodes,
|
|
getNodes,
|
|
setNodes,
|
|
setNodes,
|
|
@@ -237,6 +259,9 @@ export const useNodesInteractions = () => {
|
|
if (node.type === CUSTOM_NOTE_NODE || node.type === CUSTOM_ITERATION_START_NODE)
|
|
if (node.type === CUSTOM_NOTE_NODE || node.type === CUSTOM_ITERATION_START_NODE)
|
|
return
|
|
return
|
|
|
|
|
|
|
|
+ if (node.type === CUSTOM_NOTE_NODE || node.type === CUSTOM_LOOP_START_NODE)
|
|
|
|
+ return
|
|
|
|
+
|
|
const {
|
|
const {
|
|
setEnteringNodePayload,
|
|
setEnteringNodePayload,
|
|
} = workflowStore.getState()
|
|
} = workflowStore.getState()
|
|
@@ -311,6 +336,8 @@ export const useNodesInteractions = () => {
|
|
const handleNodeClick = useCallback<NodeMouseHandler>((_, node) => {
|
|
const handleNodeClick = useCallback<NodeMouseHandler>((_, node) => {
|
|
if (node.type === CUSTOM_ITERATION_START_NODE)
|
|
if (node.type === CUSTOM_ITERATION_START_NODE)
|
|
return
|
|
return
|
|
|
|
+ if (node.type === CUSTOM_LOOP_START_NODE)
|
|
|
|
+ return
|
|
handleNodeSelect(node.id)
|
|
handleNodeSelect(node.id)
|
|
}, [handleNodeSelect])
|
|
}, [handleNodeSelect])
|
|
|
|
|
|
@@ -344,6 +371,10 @@ export const useNodesInteractions = () => {
|
|
if (edges.find(edge => edge.source === source && edge.sourceHandle === sourceHandle && edge.target === target && edge.targetHandle === targetHandle))
|
|
if (edges.find(edge => edge.source === source && edge.sourceHandle === sourceHandle && edge.target === target && edge.targetHandle === targetHandle))
|
|
return
|
|
return
|
|
|
|
|
|
|
|
+ const parendNode = nodes.find(node => node.id === targetNode?.parentId)
|
|
|
|
+ const isInIteration = parendNode && parendNode.data.type === BlockEnum.Iteration
|
|
|
|
+ const isInLoop = !!parendNode && parendNode.data.type === BlockEnum.Loop
|
|
|
|
+
|
|
const newEdge = {
|
|
const newEdge = {
|
|
id: `${source}-${sourceHandle}-${target}-${targetHandle}`,
|
|
id: `${source}-${sourceHandle}-${target}-${targetHandle}`,
|
|
type: CUSTOM_EDGE,
|
|
type: CUSTOM_EDGE,
|
|
@@ -354,10 +385,12 @@ export const useNodesInteractions = () => {
|
|
data: {
|
|
data: {
|
|
sourceType: nodes.find(node => node.id === source)!.data.type,
|
|
sourceType: nodes.find(node => node.id === source)!.data.type,
|
|
targetType: nodes.find(node => node.id === target)!.data.type,
|
|
targetType: nodes.find(node => node.id === target)!.data.type,
|
|
- isInIteration: !!targetNode?.parentId,
|
|
|
|
- iteration_id: targetNode?.parentId,
|
|
|
|
|
|
+ isInIteration,
|
|
|
|
+ iteration_id: isInIteration ? targetNode?.parentId : undefined,
|
|
|
|
+ isInLoop,
|
|
|
|
+ loop_id: isInLoop ? targetNode?.parentId : undefined,
|
|
},
|
|
},
|
|
- zIndex: targetNode?.parentId ? ITERATION_CHILDREN_Z_INDEX : 0,
|
|
|
|
|
|
+ zIndex: targetNode?.parentId ? (isInIteration ? ITERATION_CHILDREN_Z_INDEX : LOOP_CHILDREN_Z_INDEX) : 0,
|
|
}
|
|
}
|
|
const nodesConnectedSourceOrTargetHandleIdsMap = getNodesConnectedSourceOrTargetHandleIdsMap(
|
|
const nodesConnectedSourceOrTargetHandleIdsMap = getNodesConnectedSourceOrTargetHandleIdsMap(
|
|
[
|
|
[
|
|
@@ -554,6 +587,45 @@ export const useNodesInteractions = () => {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ if (currentNode.data.type === BlockEnum.Loop) {
|
|
|
|
+ const loopChildren = nodes.filter(node => node.parentId === currentNode.id)
|
|
|
|
+
|
|
|
|
+ if (loopChildren.length) {
|
|
|
|
+ if (currentNode.data._isBundled) {
|
|
|
|
+ loopChildren.forEach((child) => {
|
|
|
|
+ handleNodeDelete(child.id)
|
|
|
|
+ })
|
|
|
|
+ return handleNodeDelete(nodeId)
|
|
|
|
+ }
|
|
|
|
+ else {
|
|
|
|
+ if (loopChildren.length === 1) {
|
|
|
|
+ handleNodeDelete(loopChildren[0].id)
|
|
|
|
+ handleNodeDelete(nodeId)
|
|
|
|
+
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ const { setShowConfirm, showConfirm } = workflowStore.getState()
|
|
|
|
+
|
|
|
|
+ if (!showConfirm) {
|
|
|
|
+ setShowConfirm({
|
|
|
|
+ title: t('workflow.nodes.loop.deleteTitle'),
|
|
|
|
+ desc: t('workflow.nodes.loop.deleteDesc') || '',
|
|
|
|
+ onConfirm: () => {
|
|
|
|
+ loopChildren.forEach((child) => {
|
|
|
|
+ handleNodeDelete(child.id)
|
|
|
|
+ })
|
|
|
|
+ handleNodeDelete(nodeId)
|
|
|
|
+ handleSyncWorkflowDraft()
|
|
|
|
+ setShowConfirm(undefined)
|
|
|
|
+ },
|
|
|
|
+ })
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
const connectedEdges = getConnectedEdges([{ id: nodeId } as Node], edges)
|
|
const connectedEdges = getConnectedEdges([{ id: nodeId } as Node], edges)
|
|
const nodesConnectedSourceOrTargetHandleIdsMap = getNodesConnectedSourceOrTargetHandleIdsMap(connectedEdges.map(edge => ({ type: 'remove', edge })), nodes)
|
|
const nodesConnectedSourceOrTargetHandleIdsMap = getNodesConnectedSourceOrTargetHandleIdsMap(connectedEdges.map(edge => ({ type: 'remove', edge })), nodes)
|
|
const newNodes = produce(nodes, (draft: Node[]) => {
|
|
const newNodes = produce(nodes, (draft: Node[]) => {
|
|
@@ -612,6 +684,7 @@ export const useNodesInteractions = () => {
|
|
const {
|
|
const {
|
|
newNode,
|
|
newNode,
|
|
newIterationStartNode,
|
|
newIterationStartNode,
|
|
|
|
+ newLoopStartNode,
|
|
} = generateNewNode({
|
|
} = generateNewNode({
|
|
data: {
|
|
data: {
|
|
...NODES_INITIAL_DATA[nodeType],
|
|
...NODES_INITIAL_DATA[nodeType],
|
|
@@ -640,13 +713,28 @@ export const useNodesInteractions = () => {
|
|
}
|
|
}
|
|
newNode.parentId = prevNode.parentId
|
|
newNode.parentId = prevNode.parentId
|
|
newNode.extent = prevNode.extent
|
|
newNode.extent = prevNode.extent
|
|
|
|
+
|
|
|
|
+ const parentNode = nodes.find(node => node.id === prevNode.parentId) || null
|
|
|
|
+ const isInIteration = !!parentNode && parentNode.data.type === BlockEnum.Iteration
|
|
|
|
+ const isInLoop = !!parentNode && parentNode.data.type === BlockEnum.Loop
|
|
|
|
+
|
|
if (prevNode.parentId) {
|
|
if (prevNode.parentId) {
|
|
- newNode.data.isInIteration = true
|
|
|
|
- newNode.data.iteration_id = prevNode.parentId
|
|
|
|
- newNode.zIndex = ITERATION_CHILDREN_Z_INDEX
|
|
|
|
- if (newNode.data.type === BlockEnum.Answer || newNode.data.type === BlockEnum.Tool || newNode.data.type === BlockEnum.Assigner) {
|
|
|
|
- const parentIterNodeIndex = nodes.findIndex(node => node.id === prevNode.parentId)
|
|
|
|
- const iterNodeData: IterationNodeType = nodes[parentIterNodeIndex].data
|
|
|
|
|
|
+ newNode.data.isInIteration = isInIteration
|
|
|
|
+ newNode.data.isInLoop = isInLoop
|
|
|
|
+ if (isInIteration) {
|
|
|
|
+ newNode.data.iteration_id = parentNode.id
|
|
|
|
+ newNode.zIndex = ITERATION_CHILDREN_Z_INDEX
|
|
|
|
+ }
|
|
|
|
+ if (isInLoop) {
|
|
|
|
+ newNode.data.loop_id = parentNode.id
|
|
|
|
+ newNode.zIndex = LOOP_CHILDREN_Z_INDEX
|
|
|
|
+ }
|
|
|
|
+ if (isInIteration && (newNode.data.type === BlockEnum.Answer || newNode.data.type === BlockEnum.Tool || newNode.data.type === BlockEnum.Assigner)) {
|
|
|
|
+ const iterNodeData: IterationNodeType = parentNode.data
|
|
|
|
+ iterNodeData._isShowTips = true
|
|
|
|
+ }
|
|
|
|
+ if (isInLoop && (newNode.data.type === BlockEnum.Answer || newNode.data.type === BlockEnum.Tool || newNode.data.type === BlockEnum.Assigner)) {
|
|
|
|
+ const iterNodeData: IterationNodeType = parentNode.data
|
|
iterNodeData._isShowTips = true
|
|
iterNodeData._isShowTips = true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -661,11 +749,13 @@ export const useNodesInteractions = () => {
|
|
data: {
|
|
data: {
|
|
sourceType: prevNode.data.type,
|
|
sourceType: prevNode.data.type,
|
|
targetType: newNode.data.type,
|
|
targetType: newNode.data.type,
|
|
- isInIteration: !!prevNode.parentId,
|
|
|
|
- iteration_id: prevNode.parentId,
|
|
|
|
|
|
+ isInIteration,
|
|
|
|
+ isInLoop,
|
|
|
|
+ iteration_id: isInIteration ? prevNode.parentId : undefined,
|
|
|
|
+ loop_id: isInLoop ? prevNode.parentId : undefined,
|
|
_connectedNodeIsSelected: true,
|
|
_connectedNodeIsSelected: true,
|
|
},
|
|
},
|
|
- zIndex: prevNode.parentId ? ITERATION_CHILDREN_Z_INDEX : 0,
|
|
|
|
|
|
+ zIndex: prevNode.parentId ? (isInIteration ? ITERATION_CHILDREN_Z_INDEX : LOOP_CHILDREN_Z_INDEX) : 0,
|
|
}
|
|
}
|
|
const nodesConnectedSourceOrTargetHandleIdsMap = getNodesConnectedSourceOrTargetHandleIdsMap(
|
|
const nodesConnectedSourceOrTargetHandleIdsMap = getNodesConnectedSourceOrTargetHandleIdsMap(
|
|
[
|
|
[
|
|
@@ -686,10 +776,17 @@ export const useNodesInteractions = () => {
|
|
|
|
|
|
if (node.data.type === BlockEnum.Iteration && prevNode.parentId === node.id)
|
|
if (node.data.type === BlockEnum.Iteration && prevNode.parentId === node.id)
|
|
node.data._children?.push(newNode.id)
|
|
node.data._children?.push(newNode.id)
|
|
|
|
+
|
|
|
|
+ if (node.data.type === BlockEnum.Loop && prevNode.parentId === node.id)
|
|
|
|
+ node.data._children?.push(newNode.id)
|
|
})
|
|
})
|
|
draft.push(newNode)
|
|
draft.push(newNode)
|
|
|
|
+
|
|
if (newIterationStartNode)
|
|
if (newIterationStartNode)
|
|
draft.push(newIterationStartNode)
|
|
draft.push(newIterationStartNode)
|
|
|
|
+
|
|
|
|
+ if (newLoopStartNode)
|
|
|
|
+ draft.push(newLoopStartNode)
|
|
})
|
|
})
|
|
|
|
|
|
if (newNode.data.type === BlockEnum.VariableAssigner || newNode.data.type === BlockEnum.VariableAggregator) {
|
|
if (newNode.data.type === BlockEnum.VariableAssigner || newNode.data.type === BlockEnum.VariableAggregator) {
|
|
@@ -736,10 +833,22 @@ export const useNodesInteractions = () => {
|
|
}
|
|
}
|
|
newNode.parentId = nextNode.parentId
|
|
newNode.parentId = nextNode.parentId
|
|
newNode.extent = nextNode.extent
|
|
newNode.extent = nextNode.extent
|
|
- if (nextNode.parentId) {
|
|
|
|
- newNode.data.isInIteration = true
|
|
|
|
- newNode.data.iteration_id = nextNode.parentId
|
|
|
|
- newNode.zIndex = ITERATION_CHILDREN_Z_INDEX
|
|
|
|
|
|
+
|
|
|
|
+ const parentNode = nodes.find(node => node.id === nextNode.parentId) || null
|
|
|
|
+ const isInIteration = !!parentNode && parentNode.data.type === BlockEnum.Iteration
|
|
|
|
+ const isInLoop = !!parentNode && parentNode.data.type === BlockEnum.Loop
|
|
|
|
+
|
|
|
|
+ if (parentNode && nextNode.parentId) {
|
|
|
|
+ newNode.data.isInIteration = isInIteration
|
|
|
|
+ newNode.data.isInLoop = isInLoop
|
|
|
|
+ if (isInIteration) {
|
|
|
|
+ newNode.data.iteration_id = parentNode.id
|
|
|
|
+ newNode.zIndex = ITERATION_CHILDREN_Z_INDEX
|
|
|
|
+ }
|
|
|
|
+ if (isInLoop) {
|
|
|
|
+ newNode.data.loop_id = parentNode.id
|
|
|
|
+ newNode.zIndex = LOOP_CHILDREN_Z_INDEX
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
let newEdge
|
|
let newEdge
|
|
@@ -755,11 +864,13 @@ export const useNodesInteractions = () => {
|
|
data: {
|
|
data: {
|
|
sourceType: newNode.data.type,
|
|
sourceType: newNode.data.type,
|
|
targetType: nextNode.data.type,
|
|
targetType: nextNode.data.type,
|
|
- isInIteration: !!nextNode.parentId,
|
|
|
|
- iteration_id: nextNode.parentId,
|
|
|
|
|
|
+ isInIteration,
|
|
|
|
+ isInLoop,
|
|
|
|
+ iteration_id: isInIteration ? nextNode.parentId : undefined,
|
|
|
|
+ loop_id: isInLoop ? nextNode.parentId : undefined,
|
|
_connectedNodeIsSelected: true,
|
|
_connectedNodeIsSelected: true,
|
|
},
|
|
},
|
|
- zIndex: nextNode.parentId ? ITERATION_CHILDREN_Z_INDEX : 0,
|
|
|
|
|
|
+ zIndex: nextNode.parentId ? (isInIteration ? ITERATION_CHILDREN_Z_INDEX : LOOP_CHILDREN_Z_INDEX) : 0,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -796,10 +907,20 @@ export const useNodesInteractions = () => {
|
|
node.data.start_node_id = newNode.id
|
|
node.data.start_node_id = newNode.id
|
|
node.data.startNodeType = newNode.data.type
|
|
node.data.startNodeType = newNode.data.type
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ if (node.data.type === BlockEnum.Loop && nextNode.parentId === node.id)
|
|
|
|
+ node.data._children?.push(newNode.id)
|
|
|
|
+
|
|
|
|
+ if (node.data.type === BlockEnum.Loop && node.data.start_node_id === nextNodeId) {
|
|
|
|
+ node.data.start_node_id = newNode.id
|
|
|
|
+ node.data.startNodeType = newNode.data.type
|
|
|
|
+ }
|
|
})
|
|
})
|
|
draft.push(newNode)
|
|
draft.push(newNode)
|
|
if (newIterationStartNode)
|
|
if (newIterationStartNode)
|
|
draft.push(newIterationStartNode)
|
|
draft.push(newIterationStartNode)
|
|
|
|
+ if (newLoopStartNode)
|
|
|
|
+ draft.push(newLoopStartNode)
|
|
})
|
|
})
|
|
if (newEdge) {
|
|
if (newEdge) {
|
|
const newEdges = produce(edges, (draft) => {
|
|
const newEdges = produce(edges, (draft) => {
|
|
@@ -840,10 +961,22 @@ export const useNodesInteractions = () => {
|
|
}
|
|
}
|
|
newNode.parentId = prevNode.parentId
|
|
newNode.parentId = prevNode.parentId
|
|
newNode.extent = prevNode.extent
|
|
newNode.extent = prevNode.extent
|
|
- if (prevNode.parentId) {
|
|
|
|
- newNode.data.isInIteration = true
|
|
|
|
- newNode.data.iteration_id = prevNode.parentId
|
|
|
|
- newNode.zIndex = ITERATION_CHILDREN_Z_INDEX
|
|
|
|
|
|
+
|
|
|
|
+ const parentNode = nodes.find(node => node.id === prevNode.parentId) || null
|
|
|
|
+ const isInIteration = !!parentNode && parentNode.data.type === BlockEnum.Iteration
|
|
|
|
+ const isInLoop = !!parentNode && parentNode.data.type === BlockEnum.Loop
|
|
|
|
+
|
|
|
|
+ if (parentNode && prevNode.parentId) {
|
|
|
|
+ newNode.data.isInIteration = isInIteration
|
|
|
|
+ newNode.data.isInLoop = isInLoop
|
|
|
|
+ if (isInIteration) {
|
|
|
|
+ newNode.data.iteration_id = parentNode.id
|
|
|
|
+ newNode.zIndex = ITERATION_CHILDREN_Z_INDEX
|
|
|
|
+ }
|
|
|
|
+ if (isInLoop) {
|
|
|
|
+ newNode.data.loop_id = parentNode.id
|
|
|
|
+ newNode.zIndex = LOOP_CHILDREN_Z_INDEX
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
const currentEdgeIndex = edges.findIndex(edge => edge.source === prevNodeId && edge.target === nextNodeId)
|
|
const currentEdgeIndex = edges.findIndex(edge => edge.source === prevNodeId && edge.target === nextNodeId)
|
|
@@ -857,13 +990,20 @@ export const useNodesInteractions = () => {
|
|
data: {
|
|
data: {
|
|
sourceType: prevNode.data.type,
|
|
sourceType: prevNode.data.type,
|
|
targetType: newNode.data.type,
|
|
targetType: newNode.data.type,
|
|
- isInIteration: !!prevNode.parentId,
|
|
|
|
- iteration_id: prevNode.parentId,
|
|
|
|
|
|
+ isInIteration,
|
|
|
|
+ isInLoop,
|
|
|
|
+ iteration_id: isInIteration ? prevNode.parentId : undefined,
|
|
|
|
+ loop_id: isInLoop ? prevNode.parentId : undefined,
|
|
_connectedNodeIsSelected: true,
|
|
_connectedNodeIsSelected: true,
|
|
},
|
|
},
|
|
- zIndex: prevNode.parentId ? ITERATION_CHILDREN_Z_INDEX : 0,
|
|
|
|
|
|
+ zIndex: prevNode.parentId ? (isInIteration ? ITERATION_CHILDREN_Z_INDEX : LOOP_CHILDREN_Z_INDEX) : 0,
|
|
}
|
|
}
|
|
let newNextEdge: Edge | null = null
|
|
let newNextEdge: Edge | null = null
|
|
|
|
+
|
|
|
|
+ const nextNodeParentNode = nodes.find(node => node.id === nextNode.parentId) || null
|
|
|
|
+ const isNextNodeInIteration = !!nextNodeParentNode && nextNodeParentNode.data.type === BlockEnum.Iteration
|
|
|
|
+ const isNextNodeInLoop = !!nextNodeParentNode && nextNodeParentNode.data.type === BlockEnum.Loop
|
|
|
|
+
|
|
if (nodeType !== BlockEnum.IfElse && nodeType !== BlockEnum.QuestionClassifier) {
|
|
if (nodeType !== BlockEnum.IfElse && nodeType !== BlockEnum.QuestionClassifier) {
|
|
newNextEdge = {
|
|
newNextEdge = {
|
|
id: `${newNode.id}-${sourceHandle}-${nextNodeId}-${nextNodeTargetHandle}`,
|
|
id: `${newNode.id}-${sourceHandle}-${nextNodeId}-${nextNodeTargetHandle}`,
|
|
@@ -875,11 +1015,13 @@ export const useNodesInteractions = () => {
|
|
data: {
|
|
data: {
|
|
sourceType: newNode.data.type,
|
|
sourceType: newNode.data.type,
|
|
targetType: nextNode.data.type,
|
|
targetType: nextNode.data.type,
|
|
- isInIteration: !!nextNode.parentId,
|
|
|
|
- iteration_id: nextNode.parentId,
|
|
|
|
|
|
+ isInIteration: isNextNodeInIteration,
|
|
|
|
+ isInLoop: isNextNodeInLoop,
|
|
|
|
+ iteration_id: isNextNodeInIteration ? nextNode.parentId : undefined,
|
|
|
|
+ loop_id: isNextNodeInLoop ? nextNode.parentId : undefined,
|
|
_connectedNodeIsSelected: true,
|
|
_connectedNodeIsSelected: true,
|
|
},
|
|
},
|
|
- zIndex: nextNode.parentId ? ITERATION_CHILDREN_Z_INDEX : 0,
|
|
|
|
|
|
+ zIndex: nextNode.parentId ? (isNextNodeInIteration ? ITERATION_CHILDREN_Z_INDEX : LOOP_CHILDREN_Z_INDEX) : 0,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
const nodesConnectedSourceOrTargetHandleIdsMap = getNodesConnectedSourceOrTargetHandleIdsMap(
|
|
const nodesConnectedSourceOrTargetHandleIdsMap = getNodesConnectedSourceOrTargetHandleIdsMap(
|
|
@@ -908,10 +1050,14 @@ export const useNodesInteractions = () => {
|
|
|
|
|
|
if (node.data.type === BlockEnum.Iteration && prevNode.parentId === node.id)
|
|
if (node.data.type === BlockEnum.Iteration && prevNode.parentId === node.id)
|
|
node.data._children?.push(newNode.id)
|
|
node.data._children?.push(newNode.id)
|
|
|
|
+ if (node.data.type === BlockEnum.Loop && prevNode.parentId === node.id)
|
|
|
|
+ node.data._children?.push(newNode.id)
|
|
})
|
|
})
|
|
draft.push(newNode)
|
|
draft.push(newNode)
|
|
if (newIterationStartNode)
|
|
if (newIterationStartNode)
|
|
draft.push(newIterationStartNode)
|
|
draft.push(newIterationStartNode)
|
|
|
|
+ if (newLoopStartNode)
|
|
|
|
+ draft.push(newLoopStartNode)
|
|
})
|
|
})
|
|
setNodes(newNodes)
|
|
setNodes(newNodes)
|
|
if (newNode.data.type === BlockEnum.VariableAssigner || newNode.data.type === BlockEnum.VariableAggregator) {
|
|
if (newNode.data.type === BlockEnum.VariableAssigner || newNode.data.type === BlockEnum.VariableAggregator) {
|
|
@@ -969,6 +1115,7 @@ export const useNodesInteractions = () => {
|
|
const {
|
|
const {
|
|
newNode: newCurrentNode,
|
|
newNode: newCurrentNode,
|
|
newIterationStartNode,
|
|
newIterationStartNode,
|
|
|
|
+ newLoopStartNode,
|
|
} = generateNewNode({
|
|
} = generateNewNode({
|
|
data: {
|
|
data: {
|
|
...NODES_INITIAL_DATA[nodeType],
|
|
...NODES_INITIAL_DATA[nodeType],
|
|
@@ -978,7 +1125,9 @@ export const useNodesInteractions = () => {
|
|
_connectedTargetHandleIds: [],
|
|
_connectedTargetHandleIds: [],
|
|
selected: currentNode.data.selected,
|
|
selected: currentNode.data.selected,
|
|
isInIteration: currentNode.data.isInIteration,
|
|
isInIteration: currentNode.data.isInIteration,
|
|
|
|
+ isInLoop: currentNode.data.isInLoop,
|
|
iteration_id: currentNode.data.iteration_id,
|
|
iteration_id: currentNode.data.iteration_id,
|
|
|
|
+ loop_id: currentNode.data.loop_id,
|
|
},
|
|
},
|
|
position: {
|
|
position: {
|
|
x: currentNode.position.x,
|
|
x: currentNode.position.x,
|
|
@@ -1010,6 +1159,8 @@ export const useNodesInteractions = () => {
|
|
draft.splice(index, 1, newCurrentNode)
|
|
draft.splice(index, 1, newCurrentNode)
|
|
if (newIterationStartNode)
|
|
if (newIterationStartNode)
|
|
draft.push(newIterationStartNode)
|
|
draft.push(newIterationStartNode)
|
|
|
|
+ if (newLoopStartNode)
|
|
|
|
+ draft.push(newLoopStartNode)
|
|
})
|
|
})
|
|
setNodes(newNodes)
|
|
setNodes(newNodes)
|
|
const newEdges = produce(edges, (draft) => {
|
|
const newEdges = produce(edges, (draft) => {
|
|
@@ -1058,6 +1209,9 @@ export const useNodesInteractions = () => {
|
|
if (node.type === CUSTOM_NOTE_NODE || node.type === CUSTOM_ITERATION_START_NODE)
|
|
if (node.type === CUSTOM_NOTE_NODE || node.type === CUSTOM_ITERATION_START_NODE)
|
|
return
|
|
return
|
|
|
|
|
|
|
|
+ if (node.type === CUSTOM_NOTE_NODE || node.type === CUSTOM_LOOP_START_NODE)
|
|
|
|
+ return
|
|
|
|
+
|
|
e.preventDefault()
|
|
e.preventDefault()
|
|
const container = document.querySelector('#workflow-container')
|
|
const container = document.querySelector('#workflow-container')
|
|
const { x, y } = container!.getBoundingClientRect()
|
|
const { x, y } = container!.getBoundingClientRect()
|
|
@@ -1085,13 +1239,15 @@ export const useNodesInteractions = () => {
|
|
|
|
|
|
if (nodeId) {
|
|
if (nodeId) {
|
|
// If nodeId is provided, copy that specific node
|
|
// If nodeId is provided, copy that specific node
|
|
- const nodeToCopy = nodes.find(node => node.id === nodeId && node.data.type !== BlockEnum.Start && node.type !== CUSTOM_ITERATION_START_NODE)
|
|
|
|
|
|
+ const nodeToCopy = nodes.find(node => node.id === nodeId && node.data.type !== BlockEnum.Start
|
|
|
|
+ && node.type !== CUSTOM_ITERATION_START_NODE && node.type !== CUSTOM_LOOP_START_NODE)
|
|
if (nodeToCopy)
|
|
if (nodeToCopy)
|
|
setClipboardElements([nodeToCopy])
|
|
setClipboardElements([nodeToCopy])
|
|
}
|
|
}
|
|
else {
|
|
else {
|
|
// If no nodeId is provided, fall back to the current behavior
|
|
// If no nodeId is provided, fall back to the current behavior
|
|
- const bundledNodes = nodes.filter(node => node.data._isBundled && node.data.type !== BlockEnum.Start && !node.data.isInIteration)
|
|
|
|
|
|
+ const bundledNodes = nodes.filter(node => node.data._isBundled && node.data.type !== BlockEnum.Start
|
|
|
|
+ && !node.data.isInIteration && !node.data.isInLoop)
|
|
|
|
|
|
if (bundledNodes.length) {
|
|
if (bundledNodes.length) {
|
|
setClipboardElements(bundledNodes)
|
|
setClipboardElements(bundledNodes)
|
|
@@ -1138,6 +1294,7 @@ export const useNodesInteractions = () => {
|
|
const {
|
|
const {
|
|
newNode,
|
|
newNode,
|
|
newIterationStartNode,
|
|
newIterationStartNode,
|
|
|
|
+ newLoopStartNode,
|
|
} = generateNewNode({
|
|
} = generateNewNode({
|
|
type: nodeToPaste.type,
|
|
type: nodeToPaste.type,
|
|
data: {
|
|
data: {
|
|
@@ -1176,6 +1333,17 @@ export const useNodesInteractions = () => {
|
|
newChildren.push(newIterationStartNode!)
|
|
newChildren.push(newIterationStartNode!)
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (nodeToPaste.data.type === BlockEnum.Loop) {
|
|
|
|
+ newLoopStartNode!.parentId = newNode.id;
|
|
|
|
+ (newNode.data as LoopNodeType).start_node_id = newLoopStartNode!.id
|
|
|
|
+
|
|
|
|
+ newChildren = handleNodeLoopChildrenCopy(nodeToPaste.id, newNode.id)
|
|
|
|
+ newChildren.forEach((child) => {
|
|
|
|
+ newNode.data._children?.push(child.id)
|
|
|
|
+ })
|
|
|
|
+ newChildren.push(newLoopStartNode!)
|
|
|
|
+ }
|
|
|
|
+
|
|
nodesToPaste.push(newNode)
|
|
nodesToPaste.push(newNode)
|
|
|
|
|
|
if (newChildren.length)
|
|
if (newChildren.length)
|
|
@@ -1206,7 +1374,7 @@ export const useNodesInteractions = () => {
|
|
saveStateToHistory(WorkflowHistoryEvent.NodePaste)
|
|
saveStateToHistory(WorkflowHistoryEvent.NodePaste)
|
|
handleSyncWorkflowDraft()
|
|
handleSyncWorkflowDraft()
|
|
}
|
|
}
|
|
- }, [getNodesReadOnly, workflowStore, store, reactflow, saveStateToHistory, handleSyncWorkflowDraft, handleNodeIterationChildrenCopy])
|
|
|
|
|
|
+ }, [getNodesReadOnly, workflowStore, store, reactflow, saveStateToHistory, handleSyncWorkflowDraft, handleNodeIterationChildrenCopy, handleNodeLoopChildrenCopy])
|
|
|
|
|
|
const handleNodesDuplicate = useCallback((nodeId?: string) => {
|
|
const handleNodesDuplicate = useCallback((nodeId?: string) => {
|
|
if (getNodesReadOnly())
|
|
if (getNodesReadOnly())
|
|
@@ -1278,9 +1446,12 @@ export const useNodesInteractions = () => {
|
|
})
|
|
})
|
|
|
|
|
|
if (rightNode! && bottomNode!) {
|
|
if (rightNode! && bottomNode!) {
|
|
- if (width < rightNode!.position.x + rightNode.width! + ITERATION_PADDING.right)
|
|
|
|
|
|
+ const parentNode = nodes.find(n => n.id === rightNode.parentId)
|
|
|
|
+ const paddingMap = parentNode?.data.type === BlockEnum.Iteration ? ITERATION_PADDING : LOOP_PADDING
|
|
|
|
+
|
|
|
|
+ if (width < rightNode!.position.x + rightNode.width! + paddingMap.right)
|
|
return
|
|
return
|
|
- if (height < bottomNode.position.y + bottomNode.height! + ITERATION_PADDING.bottom)
|
|
|
|
|
|
+ if (height < bottomNode.position.y + bottomNode.height! + paddingMap.bottom)
|
|
return
|
|
return
|
|
}
|
|
}
|
|
const newNodes = produce(nodes, (draft) => {
|
|
const newNodes = produce(nodes, (draft) => {
|