Feature/newnew workflow loop node (#14863)
Co-authored-by: arkunzz <4873204@qq.com>
This commit is contained in:
@@ -21,6 +21,14 @@ export const useHelpline = () => {
|
||||
showVerticalHelpLineNodes: [],
|
||||
}
|
||||
}
|
||||
|
||||
if (node.data.isInLoop) {
|
||||
return {
|
||||
showHorizontalHelpLineNodes: [],
|
||||
showVerticalHelpLineNodes: [],
|
||||
}
|
||||
}
|
||||
|
||||
const showHorizontalHelpLineNodes = nodes.filter((n) => {
|
||||
if (n.id === node.id)
|
||||
return false
|
||||
@@ -28,6 +36,9 @@ export const useHelpline = () => {
|
||||
if (n.data.isInIteration)
|
||||
return false
|
||||
|
||||
if (n.data.isInLoop)
|
||||
return false
|
||||
|
||||
const nY = Math.ceil(n.position.y)
|
||||
const nodeY = Math.ceil(node.position.y)
|
||||
|
||||
@@ -67,6 +78,8 @@ export const useHelpline = () => {
|
||||
return false
|
||||
if (n.data.isInIteration)
|
||||
return false
|
||||
if (n.data.isInLoop)
|
||||
return false
|
||||
|
||||
const nX = Math.ceil(n.position.x)
|
||||
const nodeX = Math.ceil(node.position.x)
|
||||
|
@@ -31,7 +31,7 @@ export const useNodesExtraData = () => {
|
||||
}), [t, isChatMode])
|
||||
}
|
||||
|
||||
export const useAvailableBlocks = (nodeType?: BlockEnum, isInIteration?: boolean) => {
|
||||
export const useAvailableBlocks = (nodeType?: BlockEnum, isInIteration?: boolean, isInLoop?: boolean) => {
|
||||
const nodesExtraData = useNodesExtraData()
|
||||
const availablePrevBlocks = useMemo(() => {
|
||||
if (!nodeType)
|
||||
@@ -48,15 +48,23 @@ export const useAvailableBlocks = (nodeType?: BlockEnum, isInIteration?: boolean
|
||||
return useMemo(() => {
|
||||
return {
|
||||
availablePrevBlocks: availablePrevBlocks.filter((nType) => {
|
||||
if (isInIteration && (nType === BlockEnum.Iteration || nType === BlockEnum.End))
|
||||
if (isInIteration && (nType === BlockEnum.Iteration || nType === BlockEnum.Loop || nType === BlockEnum.End))
|
||||
return false
|
||||
|
||||
if (isInLoop && (nType === BlockEnum.Iteration || nType === BlockEnum.Loop || nType === BlockEnum.End))
|
||||
return false
|
||||
|
||||
return true
|
||||
}),
|
||||
availableNextBlocks: availableNextBlocks.filter((nType) => {
|
||||
if (isInIteration && (nType === BlockEnum.Iteration || nType === BlockEnum.End))
|
||||
if (isInIteration && (nType === BlockEnum.Iteration || nType === BlockEnum.Loop || nType === BlockEnum.End))
|
||||
return false
|
||||
|
||||
if (isInLoop && (nType === BlockEnum.Iteration || nType === BlockEnum.Loop || nType === BlockEnum.End))
|
||||
return false
|
||||
|
||||
return true
|
||||
}),
|
||||
}
|
||||
}, [isInIteration, availablePrevBlocks, availableNextBlocks])
|
||||
}, [isInIteration, availablePrevBlocks, availableNextBlocks, isInLoop])
|
||||
}
|
||||
|
@@ -29,6 +29,8 @@ import {
|
||||
CUSTOM_EDGE,
|
||||
ITERATION_CHILDREN_Z_INDEX,
|
||||
ITERATION_PADDING,
|
||||
LOOP_CHILDREN_Z_INDEX,
|
||||
LOOP_PADDING,
|
||||
NODES_INITIAL_DATA,
|
||||
NODE_WIDTH_X_OFFSET,
|
||||
X_OFFSET,
|
||||
@@ -42,9 +44,12 @@ import {
|
||||
} from '../utils'
|
||||
import { CUSTOM_NOTE_NODE } from '../note-node/constants'
|
||||
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_LOOP_START_NODE } from '../nodes/loop-start/constants'
|
||||
import type { VariableAssignerNodeType } from '../nodes/variable-assigner/types'
|
||||
import { useNodeIterationInteractions } from '../nodes/iteration/use-interactions'
|
||||
import { useNodeLoopInteractions } from '../nodes/loop/use-interactions'
|
||||
import { useWorkflowHistoryStore } from '../workflow-history-store'
|
||||
import { useNodesSyncDraft } from './use-nodes-sync-draft'
|
||||
import { useHelpline } from './use-helpline'
|
||||
@@ -73,6 +78,10 @@ export const useNodesInteractions = () => {
|
||||
handleNodeIterationChildDrag,
|
||||
handleNodeIterationChildrenCopy,
|
||||
} = useNodeIterationInteractions()
|
||||
const {
|
||||
handleNodeLoopChildDrag,
|
||||
handleNodeLoopChildrenCopy,
|
||||
} = useNodeLoopInteractions()
|
||||
const dragNodeStartPosition = useRef({ x: 0, y: 0 } as { x: number; y: number })
|
||||
|
||||
const { saveStateToHistory, undo, redo } = useWorkflowHistory()
|
||||
@@ -86,6 +95,9 @@ export const useNodesInteractions = () => {
|
||||
if (node.type === CUSTOM_ITERATION_START_NODE || node.type === CUSTOM_NOTE_NODE)
|
||||
return
|
||||
|
||||
if (node.type === CUSTOM_LOOP_START_NODE || node.type === CUSTOM_NOTE_NODE)
|
||||
return
|
||||
|
||||
dragNodeStartPosition.current = { x: node.position.x, y: node.position.y }
|
||||
}, [workflowStore, getNodesReadOnly])
|
||||
|
||||
@@ -96,6 +108,9 @@ export const useNodesInteractions = () => {
|
||||
if (node.type === CUSTOM_ITERATION_START_NODE)
|
||||
return
|
||||
|
||||
if (node.type === CUSTOM_LOOP_START_NODE)
|
||||
return
|
||||
|
||||
const {
|
||||
getNodes,
|
||||
setNodes,
|
||||
@@ -105,6 +120,7 @@ export const useNodesInteractions = () => {
|
||||
const nodes = getNodes()
|
||||
|
||||
const { restrictPosition } = handleNodeIterationChildDrag(node)
|
||||
const { restrictPosition: restrictLoopPosition } = handleNodeLoopChildDrag(node)
|
||||
|
||||
const {
|
||||
showHorizontalHelpLineNodes,
|
||||
@@ -120,6 +136,8 @@ export const useNodesInteractions = () => {
|
||||
currentNode.position.x = showVerticalHelpLineNodes[0].position.x
|
||||
else if (restrictPosition.x !== undefined)
|
||||
currentNode.position.x = restrictPosition.x
|
||||
else if (restrictLoopPosition.x !== undefined)
|
||||
currentNode.position.x = restrictLoopPosition.x
|
||||
else
|
||||
currentNode.position.x = node.position.x
|
||||
|
||||
@@ -127,12 +145,13 @@ export const useNodesInteractions = () => {
|
||||
currentNode.position.y = showHorizontalHelpLineNodes[0].position.y
|
||||
else if (restrictPosition.y !== undefined)
|
||||
currentNode.position.y = restrictPosition.y
|
||||
else if (restrictLoopPosition.y !== undefined)
|
||||
currentNode.position.y = restrictLoopPosition.y
|
||||
else
|
||||
currentNode.position.y = node.position.y
|
||||
})
|
||||
|
||||
setNodes(newNodes)
|
||||
}, [store, getNodesReadOnly, handleSetHelpline, handleNodeIterationChildDrag])
|
||||
}, [getNodesReadOnly, store, handleNodeIterationChildDrag, handleNodeLoopChildDrag, handleSetHelpline])
|
||||
|
||||
const handleNodeDragStop = useCallback<NodeDragHandler>((_, node) => {
|
||||
const {
|
||||
@@ -163,6 +182,9 @@ export const useNodesInteractions = () => {
|
||||
if (node.type === CUSTOM_NOTE_NODE || node.type === CUSTOM_ITERATION_START_NODE)
|
||||
return
|
||||
|
||||
if (node.type === CUSTOM_LOOP_START_NODE || node.type === CUSTOM_NOTE_NODE)
|
||||
return
|
||||
|
||||
const {
|
||||
getNodes,
|
||||
setNodes,
|
||||
@@ -237,6 +259,9 @@ export const useNodesInteractions = () => {
|
||||
if (node.type === CUSTOM_NOTE_NODE || node.type === CUSTOM_ITERATION_START_NODE)
|
||||
return
|
||||
|
||||
if (node.type === CUSTOM_NOTE_NODE || node.type === CUSTOM_LOOP_START_NODE)
|
||||
return
|
||||
|
||||
const {
|
||||
setEnteringNodePayload,
|
||||
} = workflowStore.getState()
|
||||
@@ -311,6 +336,8 @@ export const useNodesInteractions = () => {
|
||||
const handleNodeClick = useCallback<NodeMouseHandler>((_, node) => {
|
||||
if (node.type === CUSTOM_ITERATION_START_NODE)
|
||||
return
|
||||
if (node.type === CUSTOM_LOOP_START_NODE)
|
||||
return
|
||||
handleNodeSelect(node.id)
|
||||
}, [handleNodeSelect])
|
||||
|
||||
@@ -344,6 +371,10 @@ export const useNodesInteractions = () => {
|
||||
if (edges.find(edge => edge.source === source && edge.sourceHandle === sourceHandle && edge.target === target && edge.targetHandle === targetHandle))
|
||||
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 = {
|
||||
id: `${source}-${sourceHandle}-${target}-${targetHandle}`,
|
||||
type: CUSTOM_EDGE,
|
||||
@@ -354,10 +385,12 @@ export const useNodesInteractions = () => {
|
||||
data: {
|
||||
sourceType: nodes.find(node => node.id === source)!.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(
|
||||
[
|
||||
@@ -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 nodesConnectedSourceOrTargetHandleIdsMap = getNodesConnectedSourceOrTargetHandleIdsMap(connectedEdges.map(edge => ({ type: 'remove', edge })), nodes)
|
||||
const newNodes = produce(nodes, (draft: Node[]) => {
|
||||
@@ -612,6 +684,7 @@ export const useNodesInteractions = () => {
|
||||
const {
|
||||
newNode,
|
||||
newIterationStartNode,
|
||||
newLoopStartNode,
|
||||
} = generateNewNode({
|
||||
data: {
|
||||
...NODES_INITIAL_DATA[nodeType],
|
||||
@@ -640,13 +713,28 @@ export const useNodesInteractions = () => {
|
||||
}
|
||||
newNode.parentId = prevNode.parentId
|
||||
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) {
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -661,11 +749,13 @@ export const useNodesInteractions = () => {
|
||||
data: {
|
||||
sourceType: prevNode.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,
|
||||
},
|
||||
zIndex: prevNode.parentId ? ITERATION_CHILDREN_Z_INDEX : 0,
|
||||
zIndex: prevNode.parentId ? (isInIteration ? ITERATION_CHILDREN_Z_INDEX : LOOP_CHILDREN_Z_INDEX) : 0,
|
||||
}
|
||||
const nodesConnectedSourceOrTargetHandleIdsMap = getNodesConnectedSourceOrTargetHandleIdsMap(
|
||||
[
|
||||
@@ -686,10 +776,17 @@ export const useNodesInteractions = () => {
|
||||
|
||||
if (node.data.type === BlockEnum.Iteration && prevNode.parentId === node.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)
|
||||
|
||||
if (newIterationStartNode)
|
||||
draft.push(newIterationStartNode)
|
||||
|
||||
if (newLoopStartNode)
|
||||
draft.push(newLoopStartNode)
|
||||
})
|
||||
|
||||
if (newNode.data.type === BlockEnum.VariableAssigner || newNode.data.type === BlockEnum.VariableAggregator) {
|
||||
@@ -736,10 +833,22 @@ export const useNodesInteractions = () => {
|
||||
}
|
||||
newNode.parentId = nextNode.parentId
|
||||
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
|
||||
@@ -755,11 +864,13 @@ export const useNodesInteractions = () => {
|
||||
data: {
|
||||
sourceType: newNode.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,
|
||||
},
|
||||
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.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)
|
||||
if (newIterationStartNode)
|
||||
draft.push(newIterationStartNode)
|
||||
if (newLoopStartNode)
|
||||
draft.push(newLoopStartNode)
|
||||
})
|
||||
if (newEdge) {
|
||||
const newEdges = produce(edges, (draft) => {
|
||||
@@ -840,10 +961,22 @@ export const useNodesInteractions = () => {
|
||||
}
|
||||
newNode.parentId = prevNode.parentId
|
||||
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)
|
||||
@@ -857,13 +990,20 @@ export const useNodesInteractions = () => {
|
||||
data: {
|
||||
sourceType: prevNode.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,
|
||||
},
|
||||
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
|
||||
|
||||
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) {
|
||||
newNextEdge = {
|
||||
id: `${newNode.id}-${sourceHandle}-${nextNodeId}-${nextNodeTargetHandle}`,
|
||||
@@ -875,11 +1015,13 @@ export const useNodesInteractions = () => {
|
||||
data: {
|
||||
sourceType: newNode.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,
|
||||
},
|
||||
zIndex: nextNode.parentId ? ITERATION_CHILDREN_Z_INDEX : 0,
|
||||
zIndex: nextNode.parentId ? (isNextNodeInIteration ? ITERATION_CHILDREN_Z_INDEX : LOOP_CHILDREN_Z_INDEX) : 0,
|
||||
}
|
||||
}
|
||||
const nodesConnectedSourceOrTargetHandleIdsMap = getNodesConnectedSourceOrTargetHandleIdsMap(
|
||||
@@ -908,10 +1050,14 @@ export const useNodesInteractions = () => {
|
||||
|
||||
if (node.data.type === BlockEnum.Iteration && prevNode.parentId === node.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)
|
||||
if (newIterationStartNode)
|
||||
draft.push(newIterationStartNode)
|
||||
if (newLoopStartNode)
|
||||
draft.push(newLoopStartNode)
|
||||
})
|
||||
setNodes(newNodes)
|
||||
if (newNode.data.type === BlockEnum.VariableAssigner || newNode.data.type === BlockEnum.VariableAggregator) {
|
||||
@@ -969,6 +1115,7 @@ export const useNodesInteractions = () => {
|
||||
const {
|
||||
newNode: newCurrentNode,
|
||||
newIterationStartNode,
|
||||
newLoopStartNode,
|
||||
} = generateNewNode({
|
||||
data: {
|
||||
...NODES_INITIAL_DATA[nodeType],
|
||||
@@ -978,7 +1125,9 @@ export const useNodesInteractions = () => {
|
||||
_connectedTargetHandleIds: [],
|
||||
selected: currentNode.data.selected,
|
||||
isInIteration: currentNode.data.isInIteration,
|
||||
isInLoop: currentNode.data.isInLoop,
|
||||
iteration_id: currentNode.data.iteration_id,
|
||||
loop_id: currentNode.data.loop_id,
|
||||
},
|
||||
position: {
|
||||
x: currentNode.position.x,
|
||||
@@ -1010,6 +1159,8 @@ export const useNodesInteractions = () => {
|
||||
draft.splice(index, 1, newCurrentNode)
|
||||
if (newIterationStartNode)
|
||||
draft.push(newIterationStartNode)
|
||||
if (newLoopStartNode)
|
||||
draft.push(newLoopStartNode)
|
||||
})
|
||||
setNodes(newNodes)
|
||||
const newEdges = produce(edges, (draft) => {
|
||||
@@ -1058,6 +1209,9 @@ export const useNodesInteractions = () => {
|
||||
if (node.type === CUSTOM_NOTE_NODE || node.type === CUSTOM_ITERATION_START_NODE)
|
||||
return
|
||||
|
||||
if (node.type === CUSTOM_NOTE_NODE || node.type === CUSTOM_LOOP_START_NODE)
|
||||
return
|
||||
|
||||
e.preventDefault()
|
||||
const container = document.querySelector('#workflow-container')
|
||||
const { x, y } = container!.getBoundingClientRect()
|
||||
@@ -1085,13 +1239,15 @@ export const useNodesInteractions = () => {
|
||||
|
||||
if (nodeId) {
|
||||
// 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)
|
||||
setClipboardElements([nodeToCopy])
|
||||
}
|
||||
else {
|
||||
// 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) {
|
||||
setClipboardElements(bundledNodes)
|
||||
@@ -1138,6 +1294,7 @@ export const useNodesInteractions = () => {
|
||||
const {
|
||||
newNode,
|
||||
newIterationStartNode,
|
||||
newLoopStartNode,
|
||||
} = generateNewNode({
|
||||
type: nodeToPaste.type,
|
||||
data: {
|
||||
@@ -1176,6 +1333,17 @@ export const useNodesInteractions = () => {
|
||||
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)
|
||||
|
||||
if (newChildren.length)
|
||||
@@ -1206,7 +1374,7 @@ export const useNodesInteractions = () => {
|
||||
saveStateToHistory(WorkflowHistoryEvent.NodePaste)
|
||||
handleSyncWorkflowDraft()
|
||||
}
|
||||
}, [getNodesReadOnly, workflowStore, store, reactflow, saveStateToHistory, handleSyncWorkflowDraft, handleNodeIterationChildrenCopy])
|
||||
}, [getNodesReadOnly, workflowStore, store, reactflow, saveStateToHistory, handleSyncWorkflowDraft, handleNodeIterationChildrenCopy, handleNodeLoopChildrenCopy])
|
||||
|
||||
const handleNodesDuplicate = useCallback((nodeId?: string) => {
|
||||
if (getNodesReadOnly())
|
||||
@@ -1278,9 +1446,12 @@ export const useNodesInteractions = () => {
|
||||
})
|
||||
|
||||
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
|
||||
if (height < bottomNode.position.y + bottomNode.height! + ITERATION_PADDING.bottom)
|
||||
if (height < bottomNode.position.y + bottomNode.height! + paddingMap.bottom)
|
||||
return
|
||||
}
|
||||
const newNodes = produce(nodes, (draft) => {
|
||||
|
@@ -6,6 +6,9 @@ export * from './use-workflow-node-finished'
|
||||
export * from './use-workflow-node-iteration-started'
|
||||
export * from './use-workflow-node-iteration-next'
|
||||
export * from './use-workflow-node-iteration-finished'
|
||||
export * from './use-workflow-node-loop-started'
|
||||
export * from './use-workflow-node-loop-next'
|
||||
export * from './use-workflow-node-loop-finished'
|
||||
export * from './use-workflow-node-retry'
|
||||
export * from './use-workflow-text-chunk'
|
||||
export * from './use-workflow-text-replace'
|
||||
|
@@ -0,0 +1,46 @@
|
||||
import { useCallback } from 'react'
|
||||
import { useStoreApi } from 'reactflow'
|
||||
import produce from 'immer'
|
||||
import type { LoopFinishedResponse } from '@/types/workflow'
|
||||
import { useWorkflowStore } from '@/app/components/workflow/store'
|
||||
import { DEFAULT_LOOP_TIMES } from '@/app/components/workflow/constants'
|
||||
|
||||
export const useWorkflowNodeLoopFinished = () => {
|
||||
const store = useStoreApi()
|
||||
const workflowStore = useWorkflowStore()
|
||||
|
||||
const handleWorkflowNodeLoopFinished = useCallback((params: LoopFinishedResponse) => {
|
||||
const { data } = params
|
||||
const {
|
||||
workflowRunningData,
|
||||
setWorkflowRunningData,
|
||||
setLoopTimes,
|
||||
} = workflowStore.getState()
|
||||
const {
|
||||
getNodes,
|
||||
setNodes,
|
||||
} = store.getState()
|
||||
const nodes = getNodes()
|
||||
setWorkflowRunningData(produce(workflowRunningData!, (draft) => {
|
||||
const currentIndex = draft.tracing!.findIndex(item => item.id === data.id)
|
||||
|
||||
if (currentIndex > -1) {
|
||||
draft.tracing![currentIndex] = {
|
||||
...draft.tracing![currentIndex],
|
||||
...data,
|
||||
}
|
||||
}
|
||||
}))
|
||||
setLoopTimes(DEFAULT_LOOP_TIMES)
|
||||
const newNodes = produce(nodes, (draft) => {
|
||||
const currentNode = draft.find(node => node.id === data.node_id)!
|
||||
|
||||
currentNode.data._runningStatus = data.status
|
||||
})
|
||||
setNodes(newNodes)
|
||||
}, [workflowStore, store])
|
||||
|
||||
return {
|
||||
handleWorkflowNodeLoopFinished,
|
||||
}
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
import { useCallback } from 'react'
|
||||
import { useStoreApi } from 'reactflow'
|
||||
import produce from 'immer'
|
||||
import type { LoopNextResponse } from '@/types/workflow'
|
||||
import { useWorkflowStore } from '@/app/components/workflow/store'
|
||||
|
||||
export const useWorkflowNodeLoopNext = () => {
|
||||
const store = useStoreApi()
|
||||
const workflowStore = useWorkflowStore()
|
||||
|
||||
const handleWorkflowNodeLoopNext = useCallback((params: LoopNextResponse) => {
|
||||
const {
|
||||
loopTimes,
|
||||
setLoopTimes,
|
||||
} = workflowStore.getState()
|
||||
|
||||
const { data } = params
|
||||
const {
|
||||
getNodes,
|
||||
setNodes,
|
||||
} = store.getState()
|
||||
|
||||
const nodes = getNodes()
|
||||
const newNodes = produce(nodes, (draft) => {
|
||||
const currentNode = draft.find(node => node.id === data.node_id)!
|
||||
currentNode.data._loopIndex = loopTimes
|
||||
setLoopTimes(loopTimes + 1)
|
||||
})
|
||||
setNodes(newNodes)
|
||||
}, [workflowStore, store])
|
||||
|
||||
return {
|
||||
handleWorkflowNodeLoopNext,
|
||||
}
|
||||
}
|
@@ -0,0 +1,85 @@
|
||||
import { useCallback } from 'react'
|
||||
import {
|
||||
useReactFlow,
|
||||
useStoreApi,
|
||||
} from 'reactflow'
|
||||
import produce from 'immer'
|
||||
import { useWorkflowStore } from '@/app/components/workflow/store'
|
||||
import type { LoopStartedResponse } from '@/types/workflow'
|
||||
import { NodeRunningStatus } from '@/app/components/workflow/types'
|
||||
import { DEFAULT_LOOP_TIMES } from '@/app/components/workflow/constants'
|
||||
|
||||
export const useWorkflowNodeLoopStarted = () => {
|
||||
const store = useStoreApi()
|
||||
const reactflow = useReactFlow()
|
||||
const workflowStore = useWorkflowStore()
|
||||
|
||||
const handleWorkflowNodeLoopStarted = useCallback((
|
||||
params: LoopStartedResponse,
|
||||
containerParams: {
|
||||
clientWidth: number,
|
||||
clientHeight: number,
|
||||
},
|
||||
) => {
|
||||
const { data } = params
|
||||
const {
|
||||
workflowRunningData,
|
||||
setWorkflowRunningData,
|
||||
setLoopTimes,
|
||||
} = workflowStore.getState()
|
||||
const {
|
||||
getNodes,
|
||||
setNodes,
|
||||
edges,
|
||||
setEdges,
|
||||
transform,
|
||||
} = store.getState()
|
||||
const nodes = getNodes()
|
||||
setWorkflowRunningData(produce(workflowRunningData!, (draft) => {
|
||||
draft.tracing!.push({
|
||||
...data,
|
||||
status: NodeRunningStatus.Running,
|
||||
})
|
||||
}))
|
||||
setLoopTimes(DEFAULT_LOOP_TIMES)
|
||||
|
||||
const {
|
||||
setViewport,
|
||||
} = reactflow
|
||||
const currentNodeIndex = nodes.findIndex(node => node.id === data.node_id)
|
||||
const currentNode = nodes[currentNodeIndex]
|
||||
const position = currentNode.position
|
||||
const zoom = transform[2]
|
||||
|
||||
if (!currentNode.parentId) {
|
||||
setViewport({
|
||||
x: (containerParams.clientWidth - 400 - currentNode.width! * zoom) / 2 - position.x * zoom,
|
||||
y: (containerParams.clientHeight - currentNode.height! * zoom) / 2 - position.y * zoom,
|
||||
zoom: transform[2],
|
||||
})
|
||||
}
|
||||
const newNodes = produce(nodes, (draft) => {
|
||||
draft[currentNodeIndex].data._runningStatus = NodeRunningStatus.Running
|
||||
draft[currentNodeIndex].data._loopLength = data.metadata.loop_length
|
||||
draft[currentNodeIndex].data._waitingRun = false
|
||||
})
|
||||
setNodes(newNodes)
|
||||
const newEdges = produce(edges, (draft) => {
|
||||
const incomeEdges = draft.filter(edge => edge.target === data.node_id)
|
||||
|
||||
incomeEdges.forEach((edge) => {
|
||||
edge.data = {
|
||||
...edge.data,
|
||||
_sourceRunningStatus: nodes.find(node => node.id === edge.source)!.data._runningStatus,
|
||||
_targetRunningStatus: NodeRunningStatus.Running,
|
||||
_waitingRun: false,
|
||||
}
|
||||
})
|
||||
})
|
||||
setEdges(newEdges)
|
||||
}, [workflowStore, store, reactflow])
|
||||
|
||||
return {
|
||||
handleWorkflowNodeLoopStarted,
|
||||
}
|
||||
}
|
@@ -6,6 +6,9 @@ import {
|
||||
useWorkflowNodeIterationFinished,
|
||||
useWorkflowNodeIterationNext,
|
||||
useWorkflowNodeIterationStarted,
|
||||
useWorkflowNodeLoopFinished,
|
||||
useWorkflowNodeLoopNext,
|
||||
useWorkflowNodeLoopStarted,
|
||||
useWorkflowNodeRetry,
|
||||
useWorkflowNodeStarted,
|
||||
useWorkflowStarted,
|
||||
@@ -22,6 +25,9 @@ export const useWorkflowRunEvent = () => {
|
||||
const { handleWorkflowNodeIterationStarted } = useWorkflowNodeIterationStarted()
|
||||
const { handleWorkflowNodeIterationNext } = useWorkflowNodeIterationNext()
|
||||
const { handleWorkflowNodeIterationFinished } = useWorkflowNodeIterationFinished()
|
||||
const { handleWorkflowNodeLoopStarted } = useWorkflowNodeLoopStarted()
|
||||
const { handleWorkflowNodeLoopNext } = useWorkflowNodeLoopNext()
|
||||
const { handleWorkflowNodeLoopFinished } = useWorkflowNodeLoopFinished()
|
||||
const { handleWorkflowNodeRetry } = useWorkflowNodeRetry()
|
||||
const { handleWorkflowTextChunk } = useWorkflowTextChunk()
|
||||
const { handleWorkflowTextReplace } = useWorkflowTextReplace()
|
||||
@@ -36,6 +42,9 @@ export const useWorkflowRunEvent = () => {
|
||||
handleWorkflowNodeIterationStarted,
|
||||
handleWorkflowNodeIterationNext,
|
||||
handleWorkflowNodeIterationFinished,
|
||||
handleWorkflowNodeLoopStarted,
|
||||
handleWorkflowNodeLoopNext,
|
||||
handleWorkflowNodeLoopFinished,
|
||||
handleWorkflowNodeRetry,
|
||||
handleWorkflowTextChunk,
|
||||
handleWorkflowTextReplace,
|
||||
|
@@ -36,6 +36,9 @@ export const useWorkflowRun = () => {
|
||||
handleWorkflowNodeIterationStarted,
|
||||
handleWorkflowNodeIterationNext,
|
||||
handleWorkflowNodeIterationFinished,
|
||||
handleWorkflowNodeLoopStarted,
|
||||
handleWorkflowNodeLoopNext,
|
||||
handleWorkflowNodeLoopFinished,
|
||||
handleWorkflowNodeRetry,
|
||||
handleWorkflowAgentLog,
|
||||
handleWorkflowTextChunk,
|
||||
@@ -118,6 +121,9 @@ export const useWorkflowRun = () => {
|
||||
onIterationStart,
|
||||
onIterationNext,
|
||||
onIterationFinish,
|
||||
onLoopStart,
|
||||
onLoopNext,
|
||||
onLoopFinish,
|
||||
onNodeRetry,
|
||||
onAgentLog,
|
||||
onError,
|
||||
@@ -162,7 +168,7 @@ export const useWorkflowRun = () => {
|
||||
else
|
||||
ttsUrl = `/apps/${params.appId}/text-to-audio`
|
||||
}
|
||||
const player = AudioPlayerManager.getInstance().getAudioPlayer(ttsUrl, ttsIsPublic, uuidV4(), 'none', 'none', (_: any): any => {})
|
||||
const player = AudioPlayerManager.getInstance().getAudioPlayer(ttsUrl, ttsIsPublic, uuidV4(), 'none', 'none', (_: any): any => { })
|
||||
|
||||
ssePost(
|
||||
url,
|
||||
@@ -230,6 +236,30 @@ export const useWorkflowRun = () => {
|
||||
if (onIterationFinish)
|
||||
onIterationFinish(params)
|
||||
},
|
||||
onLoopStart: (params) => {
|
||||
handleWorkflowNodeLoopStarted(
|
||||
params,
|
||||
{
|
||||
clientWidth,
|
||||
clientHeight,
|
||||
},
|
||||
)
|
||||
|
||||
if (onLoopStart)
|
||||
onLoopStart(params)
|
||||
},
|
||||
onLoopNext: (params) => {
|
||||
handleWorkflowNodeLoopNext(params)
|
||||
|
||||
if (onLoopNext)
|
||||
onLoopNext(params)
|
||||
},
|
||||
onLoopFinish: (params) => {
|
||||
handleWorkflowNodeLoopFinished(params)
|
||||
|
||||
if (onLoopFinish)
|
||||
onLoopFinish(params)
|
||||
},
|
||||
onNodeRetry: (params) => {
|
||||
handleWorkflowNodeRetry(params)
|
||||
|
||||
@@ -260,7 +290,27 @@ export const useWorkflowRun = () => {
|
||||
...restCallback,
|
||||
},
|
||||
)
|
||||
}, [store, workflowStore, doSyncWorkflowDraft, handleWorkflowStarted, handleWorkflowFinished, handleWorkflowFailed, handleWorkflowNodeStarted, handleWorkflowNodeFinished, handleWorkflowNodeIterationStarted, handleWorkflowNodeIterationNext, handleWorkflowNodeIterationFinished, handleWorkflowNodeRetry, handleWorkflowTextChunk, handleWorkflowTextReplace, handleWorkflowAgentLog, pathname])
|
||||
}, [
|
||||
store,
|
||||
workflowStore,
|
||||
doSyncWorkflowDraft,
|
||||
handleWorkflowStarted,
|
||||
handleWorkflowFinished,
|
||||
handleWorkflowFailed,
|
||||
handleWorkflowNodeStarted,
|
||||
handleWorkflowNodeFinished,
|
||||
handleWorkflowNodeIterationStarted,
|
||||
handleWorkflowNodeIterationNext,
|
||||
handleWorkflowNodeIterationFinished,
|
||||
handleWorkflowNodeLoopStarted,
|
||||
handleWorkflowNodeLoopNext,
|
||||
handleWorkflowNodeLoopFinished,
|
||||
handleWorkflowNodeRetry,
|
||||
handleWorkflowTextChunk,
|
||||
handleWorkflowTextReplace,
|
||||
handleWorkflowAgentLog,
|
||||
pathname],
|
||||
)
|
||||
|
||||
const handleStopRun = useCallback((taskId: string) => {
|
||||
const appId = useAppStore.getState().appDetail?.id
|
||||
|
@@ -44,6 +44,7 @@ export const useWorkflowVariables = () => {
|
||||
parentNode,
|
||||
valueSelector,
|
||||
isIterationItem,
|
||||
isLoopItem,
|
||||
availableNodes,
|
||||
isChatMode,
|
||||
isConstant,
|
||||
@@ -51,6 +52,7 @@ export const useWorkflowVariables = () => {
|
||||
valueSelector: ValueSelector
|
||||
parentNode?: Node | null
|
||||
isIterationItem?: boolean
|
||||
isLoopItem?: boolean
|
||||
availableNodes: any[]
|
||||
isChatMode: boolean
|
||||
isConstant?: boolean
|
||||
@@ -59,6 +61,7 @@ export const useWorkflowVariables = () => {
|
||||
parentNode,
|
||||
valueSelector,
|
||||
isIterationItem,
|
||||
isLoopItem,
|
||||
availableNodes,
|
||||
isChatMode,
|
||||
isConstant,
|
||||
|
@@ -57,6 +57,7 @@ import {
|
||||
import I18n from '@/context/i18n'
|
||||
import { CollectionType } from '@/app/components/tools/types'
|
||||
import { CUSTOM_ITERATION_START_NODE } from '@/app/components/workflow/nodes/iteration-start/constants'
|
||||
import { CUSTOM_LOOP_START_NODE } from '@/app/components/workflow/nodes/loop-start/constants'
|
||||
import { useWorkflowConfig } from '@/service/use-workflow'
|
||||
import { canFindTool } from '@/utils'
|
||||
|
||||
@@ -89,7 +90,7 @@ export const useWorkflow = () => {
|
||||
const currentNode = nodes.find(node => node.id === nodeId)
|
||||
|
||||
if (currentNode?.parentId)
|
||||
startNode = nodes.find(node => node.parentId === currentNode.parentId && node.type === CUSTOM_ITERATION_START_NODE)
|
||||
startNode = nodes.find(node => node.parentId === currentNode.parentId && (node.type === CUSTOM_ITERATION_START_NODE || node.type === CUSTOM_LOOP_START_NODE))
|
||||
|
||||
if (!startNode)
|
||||
return []
|
||||
@@ -239,6 +240,15 @@ export const useWorkflow = () => {
|
||||
return nodes.filter(node => node.parentId === nodeId)
|
||||
}, [store])
|
||||
|
||||
const getLoopNodeChildren = useCallback((nodeId: string) => {
|
||||
const {
|
||||
getNodes,
|
||||
} = store.getState()
|
||||
const nodes = getNodes()
|
||||
|
||||
return nodes.filter(node => node.parentId === nodeId)
|
||||
}, [store])
|
||||
|
||||
const isFromStartNode = useCallback((nodeId: string) => {
|
||||
const { getNodes } = store.getState()
|
||||
const nodes = getNodes()
|
||||
@@ -280,7 +290,7 @@ export const useWorkflow = () => {
|
||||
setNodes(newNodes)
|
||||
}
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [store])
|
||||
|
||||
const isVarUsedInNodes = useCallback((varSelector: ValueSelector) => {
|
||||
@@ -425,6 +435,7 @@ export const useWorkflow = () => {
|
||||
getNode,
|
||||
getBeforeNodeById,
|
||||
getIterationNodeChildren,
|
||||
getLoopNodeChildren,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -520,7 +531,7 @@ export const useWorkflowInit = () => {
|
||||
|
||||
useEffect(() => {
|
||||
handleGetInitialWorkflowData()
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [])
|
||||
|
||||
const handleFetchPreloadData = useCallback(async () => {
|
||||
@@ -537,7 +548,7 @@ export const useWorkflowInit = () => {
|
||||
workflowStore.getState().setPublishedAt(publishedWorkflow?.created_at)
|
||||
}
|
||||
catch (e) {
|
||||
|
||||
console.error(e)
|
||||
}
|
||||
}, [workflowStore, appDetail])
|
||||
|
||||
@@ -638,3 +649,26 @@ export const useIsNodeInIteration = (iterationId: string) => {
|
||||
isNodeInIteration,
|
||||
}
|
||||
}
|
||||
|
||||
export const useIsNodeInLoop = (loopId: string) => {
|
||||
const store = useStoreApi()
|
||||
|
||||
const isNodeInLoop = useCallback((nodeId: string) => {
|
||||
const {
|
||||
getNodes,
|
||||
} = store.getState()
|
||||
const nodes = getNodes()
|
||||
const node = nodes.find(node => node.id === nodeId)
|
||||
|
||||
if (!node)
|
||||
return false
|
||||
|
||||
if (node.parentId === loopId)
|
||||
return true
|
||||
|
||||
return false
|
||||
}, [loopId, store])
|
||||
return {
|
||||
isNodeInLoop,
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user