diff --git a/web/src/views/Workflow/components/CheckList/index.tsx b/web/src/views/Workflow/components/CheckList/index.tsx index 636ae9a9..0256416a 100644 --- a/web/src/views/Workflow/components/CheckList/index.tsx +++ b/web/src/views/Workflow/components/CheckList/index.tsx @@ -79,7 +79,6 @@ const specialValidators: Record boolean> = { } function isEmpty(val: any): boolean { - console.log('validateNode isEmpty', val, val === undefined || val === null || val === '') if (val === undefined || val === null || val === '') return true if (Array.isArray(val)) return val.length === 0 return false @@ -98,7 +97,6 @@ function validateNode(type: string, config: Record): CheckError[] { const specialKey = `${type}.${field}` const specialValidator = specialValidators[specialKey] const isInvalid = specialValidator ? specialValidator(val) : isEmpty(val) - console.log('validateNode', val, specialKey, specialValidator, isEmpty(val)) if (isInvalid) errors.push({ key: specialKey, message: '' }) }) @@ -114,62 +112,6 @@ function validateNode(type: string, config: Record): CheckError[] { return errors } -export async function runCheckOnGraph( - graph: import('@antv/x6').Graph, - t: (key: string) => string -): Promise { - const nodes = graph.getNodes() - const edges = graph.getEdges() - const targetIds = new Set() - const childTargetIds = new Set() - edges.forEach(e => { - targetIds.add(e.getTargetCellId()) - const srcData = graph.getCellById(e.getSourceCellId())?.getData() - const tgtData = graph.getCellById(e.getTargetCellId())?.getData() - if (srcData?.cycle && tgtData?.cycle && srcData.cycle === tgtData.cycle) { - childTargetIds.add(e.getTargetCellId()) - } - }) - - const checked: NodeCheckResult[] = [] - for (const node of nodes) { - const data = node.getData() - if (!data || ['add-node', 'notes', 'cycle-start', 'break'].includes(data.type)) continue - - const errors: CheckError[] = [] - const isChildNode = !!data.cycle - const hasIncoming = isChildNode ? childTargetIds.has(node.id) : !['start', 'cycle-start'].includes(data.type) ? targetIds.has(node.id) : true - if (!hasIncoming) errors.push({ key: 'notConnected', message: t('workflow.notConnected') }) - - const configErrors = validateNode(data.type, data.config ?? {}) - configErrors.forEach(e => { - errors.push({ key: e.key, message: `${t(`workflow.checkListErrors.${e.key}`)} ${t('workflow.cannotBeEmpty')}`.trim() }) - }) - - if (data.type === 'tool') { - const toolId = data.config?.tool_id?.defaultValue ?? data.config?.tool_id - const toolParameters = data.config?.tool_parameters?.defaultValue ?? data.config?.tool_parameters ?? {} - if (toolId) { - try { - const methods = await getToolMethods(toolId) as Array<{ name: string; parameters: Array<{ name: string; required: boolean }> }> - const operation = toolParameters?.operation - const method = operation ? methods.find(m => m.name === operation) : methods[0] - if (method) { - method.parameters - .filter(p => p.required && (toolParameters[p.name] === undefined || toolParameters[p.name] === null || toolParameters[p.name] === '')) - .forEach(p => errors.push({ key: 'tool.tool_parameters', message: `${p.name} ${t('workflow.cannotBeEmpty')}` })) - } - } catch { /* ignore */ } - } - } - - if (errors.length) { - checked.push({ id: node.id, name: data.name || t(`workflow.${data.type}`), type: data.type, icon: nodeIconMap[data.type] ?? '', errors }) - } - } - return checked -} - const CheckList: FC = ({ workflowRef, appId }) => { const { t } = useTranslation() const [open, setOpen] = useState(false) @@ -222,7 +164,8 @@ const CheckList: FC = ({ workflowRef, appId }) => { if (data.type === 'tool') { const toolId = data.config?.tool_id?.defaultValue ?? data.config?.tool_id const toolParameters = data.config?.tool_parameters?.defaultValue ?? data.config?.tool_parameters ?? {} - if (toolId) { + + if (typeof toolId === 'string') { try { const methods = await getToolMethods(toolId) as Array<{ name: string; parameters: Array<{ name: string; required: boolean }> }> const operation = toolParameters?.operation @@ -251,21 +194,27 @@ const CheckList: FC = ({ workflowRef, appId }) => { return checked }, [workflowRef.current?.graphRef?.current, t]) + const scheduleCheckRef = useRef<() => void>() + const scheduleCheck = useCallback(() => { clearTimeout(timerRef.current) timerRef.current = setTimeout(async () => { setCheckResults(appId, await runCheck()) - }, 500) + }, 300) }, [runCheck]) + scheduleCheckRef.current = scheduleCheck + useEffect(() => { const graph = workflowRef.current?.graphRef?.current + console.log('graph') if (!graph) return - const events = ['node:added', 'node:removed', 'node:change:data', 'edge:added', 'edge:removed'] - events.forEach(e => graph.on(e, scheduleCheck)) - scheduleCheck() + const handler = () => scheduleCheckRef.current?.() + const events = ['node:added', 'node:removed', 'node:change:data', 'edge:added', 'edge:removed', 'edge:connected', 'edge:changed'] + events.forEach(e => graph.on(e, handler)) + scheduleCheckRef.current?.() return () => { - events.forEach(e => graph.off(e, scheduleCheck)) + events.forEach(e => graph.off(e, handler)) clearTimeout(timerRef.current) } }, [workflowRef.current?.graphRef?.current])