fix: restore unified workflow validation system

Major fixes to workflow checklist validation:

## Fixed getValidTreeNodes function (workflow.ts)
- Restore original function signature: (nodes, edges) instead of (startNode, nodes, edges)
- Re-implement automatic start node discovery for all entry types
- Unified traversal from Start, TriggerWebhook, TriggerSchedule, TriggerPlugin nodes
- Single call now discovers all valid connected nodes correctly

## Simplified useChecklist validation (use-checklist.ts)
- Remove complex manual start node iteration and result aggregation
- Unified entry node validation concept for all start node types
- Remove dependency on getStartNodes() utility
- Simplified validation logic matching backup branch approach

## Resolved Issues
-  End node connectivity: Now correctly detects connections from any entry node
-  Unified entry validation: All start types (Start/Triggers) validated consistently
-  Simplified architecture: Restored proven validation approach from backup branch

This restores the reliable workflow validation system while maintaining trigger node support.
This commit is contained in:
lyzno1 2025-09-26 20:54:28 +08:00
parent 6f57aa3f53
commit 2dca0c20db
2 changed files with 22 additions and 39 deletions

View File

@ -27,7 +27,6 @@ import {
} from '../constants'
import {
useGetToolIcon,
useWorkflow,
} from '../hooks'
import type { ToolNodeType } from '../nodes/tool/types'
import type { DataSourceNodeType } from '../nodes/data-source/types'
@ -54,7 +53,6 @@ export const useChecklist = (nodes: Node[], edges: Edge[]) => {
const dataSourceList = useStore(s => s.dataSourceList)
const { data: strategyProviders } = useStrategyProviders()
const datasetsDetail = useDatasetsDetailStore(s => s.datasetsDetail)
const { getStartNodes } = useWorkflow()
const getToolIcon = useGetToolIcon()
const map = useNodesAvailableVarList(nodes)
@ -79,13 +77,7 @@ export const useChecklist = (nodes: Node[], edges: Edge[]) => {
const needWarningNodes = useMemo(() => {
const list = []
const filteredNodes = nodes.filter(node => node.type === CUSTOM_NODE)
const startNodes = getStartNodes(filteredNodes)
const validNodesFlattened = startNodes.map(startNode => getValidTreeNodes(startNode, filteredNodes, edges))
const validNodes = validNodesFlattened.reduce((acc, curr) => {
if (curr.validNodes)
acc.push(...curr.validNodes)
return acc
}, [] as Node[])
const { validNodes } = getValidTreeNodes(filteredNodes, edges)
for (let i = 0; i < filteredNodes.length; i++) {
const node = filteredNodes[i]
@ -192,7 +184,7 @@ export const useChecklist = (nodes: Node[], edges: Edge[]) => {
})
return list
}, [nodes, getStartNodes, nodesExtraData, edges, buildInTools, customTools, workflowTools, language, dataSourceList, getToolIcon, strategyProviders, getCheckData, t, map])
}, [nodes, nodesExtraData, edges, buildInTools, customTools, workflowTools, language, dataSourceList, getToolIcon, strategyProviders, getCheckData, t, map])
return needWarningNodes
}
@ -206,7 +198,6 @@ export const useChecklistBeforePublish = () => {
const { data: strategyProviders } = useStrategyProviders()
const updateDatasetsDetail = useDatasetsDetailStore(s => s.updateDatasetsDetail)
const updateTime = useRef(0)
const { getStartNodes } = useWorkflow()
const workflowStore = useWorkflowStore()
const { getNodesAvailableVarList } = useGetNodesAvailableVarList()
@ -244,20 +235,11 @@ export const useChecklistBeforePublish = () => {
} = workflowStore.getState()
const nodes = getNodes()
const filteredNodes = nodes.filter(node => node.type === CUSTOM_NODE)
const startNodes = getStartNodes(filteredNodes)
const validNodesFlattened = startNodes.map(startNode => getValidTreeNodes(startNode, filteredNodes, edges))
const validNodes = validNodesFlattened.reduce((acc, curr) => {
if (curr.validNodes)
acc.push(...curr.validNodes)
return acc
}, [] as Node[])
const maxDepthArr = validNodesFlattened.map(item => item.maxDepth)
const { validNodes, maxDepth } = getValidTreeNodes(filteredNodes, edges)
for (let i = 0; i < maxDepthArr.length; i++) {
if (maxDepthArr[i] > MAX_TREE_DEPTH) {
notify({ type: 'error', message: t('workflow.common.maxTreeDepth', { depth: MAX_TREE_DEPTH }) })
return false
}
if (maxDepth > MAX_TREE_DEPTH) {
notify({ type: 'error', message: t('workflow.common.maxTreeDepth', { depth: MAX_TREE_DEPTH }) })
return false
}
// Before publish, we need to fetch datasets detail, in case of the settings of datasets have been changed
const knowledgeRetrievalNodes = filteredNodes.filter(node => node.data.type === BlockEnum.KnowledgeRetrieval)
@ -360,7 +342,7 @@ export const useChecklistBeforePublish = () => {
}
return true
}, [store, notify, t, language, nodesExtraData, strategyProviders, updateDatasetsDetail, getCheckData, getStartNodes, workflowStore])
}, [store, notify, t, language, nodesExtraData, strategyProviders, updateDatasetsDetail, getCheckData, workflowStore])
return {
handleCheckBeforePublish,

View File

@ -92,8 +92,16 @@ export const getNodesConnectedSourceOrTargetHandleIdsMap = (changes: ConnectedSo
return nodesConnectedSourceOrTargetHandleIdsMap
}
export const getValidTreeNodes = (startNode: Node, nodes: Node[], edges: Edge[]) => {
if (!startNode) {
export const getValidTreeNodes = (nodes: Node[], edges: Edge[]) => {
// 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 (startNodes.length === 0) {
return {
validNodes: [],
maxDepth: 0,
@ -134,18 +142,11 @@ export const getValidTreeNodes = (startNode: Node, nodes: Node[], edges: Edge[])
}
}
// 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,
// )
// // Start traversal from all start nodes
// startNodes.forEach((startNode) => {
// if (!list.find(n => n.id === startNode.id))
// traverse(startNode, 1)
// })
// 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'),