Merge pull request #866 from SuanmoSuanyangTechnology/fix/v0.3.0_zy

Fix/v0.3.0 zy
This commit is contained in:
yingzhao
2026-04-13 12:20:06 +08:00
committed by GitHub
2 changed files with 19 additions and 69 deletions

View File

@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2025-12-30 13:59:36
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-04-08 11:05:34
* @Last Modified time: 2026-04-13 12:16:00
*/
import { forwardRef, useImperativeHandle, useState, useRef, useMemo } from 'react';
import { Form, Input, Select, InputNumber, Button, Row, Col, Flex } from 'antd';
@@ -345,15 +345,16 @@ const ChatVariableModal = forwardRef<ChatVariableModalRef, ChatVariableModalProp
<Form.Item
name="defaultValue"
label={t('workflow.config.parameter-extractor.default')}
rules={[
(type === 'object' || type === 'array[object]') ? {
rules={(type === 'object' || type === 'array[object]')
? [{
validator: (_, value) => {
if (!value) return Promise.resolve();
try { JSON.parse(value); return Promise.resolve(); }
catch { return Promise.reject(t('workflow.invalidJSON')); }
}
} : {}
]}
}]
: undefined
}
>
{type === 'number'
? <InputNumber placeholder={t('common.enter')} style={{ width: '100%' }} />

View File

@@ -79,7 +79,6 @@ const specialValidators: Record<string, (val: any) => 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<string, any>): 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<string, any>): CheckError[] {
return errors
}
export async function runCheckOnGraph(
graph: import('@antv/x6').Graph,
t: (key: string) => string
): Promise<NodeCheckResult[]> {
const nodes = graph.getNodes()
const edges = graph.getEdges()
const targetIds = new Set<string>()
const childTargetIds = new Set<string>()
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<CheckListProps> = ({ workflowRef, appId }) => {
const { t } = useTranslation()
const [open, setOpen] = useState(false)
@@ -222,7 +164,8 @@ const CheckList: FC<CheckListProps> = ({ 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<CheckListProps> = ({ 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])