fix(workflow): validate node compatibility when importing dsl between chatflows and workflows (#28012)

This commit is contained in:
yangzheli 2025-11-20 11:40:24 +08:00 committed by GitHub
parent fa910be0f6
commit 4833d39ab3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 50 additions and 3 deletions

View File

@ -239,7 +239,7 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
const secondaryOperations: Operation[] = [
// Import DSL (conditional)
...(appDetail.mode !== AppModeEnum.AGENT_CHAT && (appDetail.mode === AppModeEnum.ADVANCED_CHAT || appDetail.mode === AppModeEnum.WORKFLOW)) ? [{
...(appDetail.mode === AppModeEnum.ADVANCED_CHAT || appDetail.mode === AppModeEnum.WORKFLOW) ? [{
id: 'import',
title: t('workflow.common.importDSL'),
icon: <RiFileUploadLine />,
@ -271,7 +271,7 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
]
// Keep the switch operation separate as it's not part of the main operations
const switchOperation = (appDetail.mode !== AppModeEnum.AGENT_CHAT && (appDetail.mode === AppModeEnum.COMPLETION || appDetail.mode === AppModeEnum.CHAT)) ? {
const switchOperation = (appDetail.mode === AppModeEnum.COMPLETION || appDetail.mode === AppModeEnum.CHAT) ? {
id: 'switch',
title: t('app.switch'),
icon: <RiExchange2Line />,

View File

@ -9,6 +9,7 @@ import {
} from 'react'
import { useContext } from 'use-context-selector'
import { useTranslation } from 'react-i18next'
import { load as yamlLoad } from 'js-yaml'
import {
RiAlertFill,
RiCloseLine,
@ -16,8 +17,14 @@ import {
} from '@remixicon/react'
import { WORKFLOW_DATA_UPDATE } from './constants'
import {
BlockEnum,
SupportUploadFileTypes,
} from './types'
import type {
CommonNodeType,
Node,
} from './types'
import { AppModeEnum } from '@/types/app'
import {
initialEdges,
initialNodes,
@ -130,6 +137,33 @@ const UpdateDSLModal = ({
} as any)
}, [eventEmitter])
const validateDSLContent = (content: string): boolean => {
try {
const data = yamlLoad(content) as any
const nodes = data?.workflow?.graph?.nodes ?? []
const invalidNodes = appDetail?.mode === AppModeEnum.ADVANCED_CHAT
? [
BlockEnum.End,
BlockEnum.TriggerWebhook,
BlockEnum.TriggerSchedule,
BlockEnum.TriggerPlugin,
]
: [BlockEnum.Answer]
const hasInvalidNode = nodes.some((node: Node<CommonNodeType>) => {
return invalidNodes.includes(node?.data?.type)
})
if (hasInvalidNode) {
notify({ type: 'error', message: t('workflow.common.importFailure') })
return false
}
return true
}
catch (err: any) {
notify({ type: 'error', message: t('workflow.common.importFailure') })
return false
}
}
const isCreatingRef = useRef(false)
const handleImport: MouseEventHandler = useCallback(async () => {
if (isCreatingRef.current)
@ -138,7 +172,7 @@ const UpdateDSLModal = ({
if (!currentFile)
return
try {
if (appDetail && fileContent) {
if (appDetail && fileContent && validateDSLContent(fileContent)) {
setLoading(true)
const response = await importDSL({ mode: DSLImportMode.YAML_CONTENT, yaml_content: fileContent, app_id: appDetail.id })
const { id, status, app_id, imported_dsl_version, current_dsl_version } = response

View File

@ -88,6 +88,7 @@
"immer": "^10.1.3",
"js-audio-recorder": "^1.0.7",
"js-cookie": "^3.0.5",
"js-yaml": "^4.1.0",
"jsonschema": "^1.5.0",
"katex": "^0.16.25",
"ky": "^1.12.0",
@ -163,6 +164,7 @@
"@testing-library/react": "^16.3.0",
"@types/jest": "^29.5.14",
"@types/js-cookie": "^3.0.6",
"@types/js-yaml": "^4.0.9",
"@types/lodash-es": "^4.17.12",
"@types/negotiator": "^0.6.4",
"@types/node": "18.15.0",

View File

@ -192,6 +192,9 @@ importers:
js-cookie:
specifier: ^3.0.5
version: 3.0.5
js-yaml:
specifier: ^4.1.0
version: 4.1.0
jsonschema:
specifier: ^1.5.0
version: 1.5.0
@ -412,6 +415,9 @@ importers:
'@types/js-cookie':
specifier: ^3.0.6
version: 3.0.6
'@types/js-yaml':
specifier: ^4.0.9
version: 4.0.9
'@types/lodash-es':
specifier: ^4.17.12
version: 4.17.12
@ -3240,6 +3246,9 @@ packages:
'@types/js-cookie@3.0.6':
resolution: {integrity: sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==}
'@types/js-yaml@4.0.9':
resolution: {integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==}
'@types/json-schema@7.0.15':
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
@ -11632,6 +11641,8 @@ snapshots:
'@types/js-cookie@3.0.6': {}
'@types/js-yaml@4.0.9': {}
'@types/json-schema@7.0.15': {}
'@types/katex@0.16.7': {}