feat: implement Schedule Trigger validation with multi-start node topology support (#24134)

This commit is contained in:
lyzno1
2025-08-19 11:55:15 +08:00
committed by GitHub
parent d4ff1e031a
commit f7bb3b852a
7 changed files with 439 additions and 21 deletions

View File

@ -94,19 +94,28 @@ export const getNodesConnectedSourceOrTargetHandleIdsMap = (changes: ConnectedSo
}
export const getValidTreeNodes = (nodes: Node[], edges: Edge[]) => {
const startNode = nodes.find(node => node.data.type === BlockEnum.Start)
// Find all start nodes (Start and Trigger nodes)
const startNodes = nodes.filter(node =>
node.data.type === BlockEnum.Start
|| node.data.type === BlockEnum.TriggerSchedule
|| node.data.type === BlockEnum.TriggerWebhook
|| node.data.type === BlockEnum.TriggerPlugin,
)
if (!startNode) {
if (startNodes.length === 0) {
return {
validNodes: [],
maxDepth: 0,
}
}
const list: Node[] = [startNode]
let maxDepth = 1
const list: Node[] = []
let maxDepth = 0
const traverse = (root: Node, depth: number) => {
// Add the current node to the list
list.push(root)
if (depth > maxDepth)
maxDepth = depth
@ -114,19 +123,19 @@ export const getValidTreeNodes = (nodes: Node[], edges: Edge[]) => {
if (outgoers.length) {
outgoers.forEach((outgoer) => {
list.push(outgoer)
// Only traverse if we haven't processed this node yet (avoid cycles)
if (!list.find(n => n.id === outgoer.id)) {
if (outgoer.data.type === BlockEnum.Iteration)
list.push(...nodes.filter(node => node.parentId === outgoer.id))
if (outgoer.data.type === BlockEnum.Loop)
list.push(...nodes.filter(node => node.parentId === outgoer.id))
if (outgoer.data.type === BlockEnum.Iteration)
list.push(...nodes.filter(node => node.parentId === outgoer.id))
if (outgoer.data.type === BlockEnum.Loop)
list.push(...nodes.filter(node => node.parentId === outgoer.id))
traverse(outgoer, depth + 1)
traverse(outgoer, depth + 1)
}
})
}
else {
list.push(root)
else {
// Leaf node - add iteration/loop children if any
if (root.data.type === BlockEnum.Iteration)
list.push(...nodes.filter(node => node.parentId === root.id))
if (root.data.type === BlockEnum.Loop)
@ -134,7 +143,11 @@ export const getValidTreeNodes = (nodes: Node[], edges: Edge[]) => {
}
}
traverse(startNode, maxDepth)
// Start traversal from all start nodes
startNodes.forEach((startNode) => {
if (!list.find(n => n.id === startNode.id))
traverse(startNode, 1)
})
return {
validNodes: uniqBy(list, 'id'),
@ -196,7 +209,12 @@ export const getParallelInfo = (nodes: Node[], edges: Edge[], parentNodeId?: str
startNode = nodes.find(node => node.id === (parentNode.data as (IterationNodeType | LoopNodeType)).start_node_id)
}
else {
startNode = nodes.find(node => node.data.type === BlockEnum.Start)
startNode = nodes.find(node =>
node.data.type === BlockEnum.Start
|| node.data.type === BlockEnum.TriggerSchedule
|| node.data.type === BlockEnum.TriggerWebhook
|| node.data.type === BlockEnum.TriggerPlugin,
)
}
if (!startNode)
throw new Error('Start node not found')