From cc8ee0ff69759c71d081927326d3f7baa6588de7 Mon Sep 17 00:00:00 2001 From: zxhlyh Date: Fri, 6 Jun 2025 15:35:19 +0800 Subject: [PATCH] dsl --- .../components/rag-pipeline-children.tsx | 2 +- .../components/update-dsl-modal.tsx | 275 ++++++++++++++++++ web/service/use-pipeline.ts | 2 +- 3 files changed, 277 insertions(+), 2 deletions(-) create mode 100644 web/app/components/rag-pipeline/components/update-dsl-modal.tsx diff --git a/web/app/components/rag-pipeline/components/rag-pipeline-children.tsx b/web/app/components/rag-pipeline/components/rag-pipeline-children.tsx index 1da62befd1..87ff86255b 100644 --- a/web/app/components/rag-pipeline/components/rag-pipeline-children.tsx +++ b/web/app/components/rag-pipeline/components/rag-pipeline-children.tsx @@ -8,7 +8,7 @@ import RagPipelinePanel from './panel' import RagPipelineHeader from './rag-pipeline-header' import type { EnvironmentVariable } from '@/app/components/workflow/types' import { DSL_EXPORT_CHECK } from '@/app/components/workflow/constants' -import UpdateDSLModal from '@/app/components/workflow/update-dsl-modal' +import UpdateDSLModal from './update-dsl-modal' import DSLExportConfirmModal from '@/app/components/workflow/dsl-export-confirm-modal' import { useDSL, diff --git a/web/app/components/rag-pipeline/components/update-dsl-modal.tsx b/web/app/components/rag-pipeline/components/update-dsl-modal.tsx new file mode 100644 index 0000000000..090fe1c42f --- /dev/null +++ b/web/app/components/rag-pipeline/components/update-dsl-modal.tsx @@ -0,0 +1,275 @@ +'use client' + +import type { MouseEventHandler } from 'react' +import { + memo, + useCallback, + useRef, + useState, +} from 'react' +import { useContext } from 'use-context-selector' +import { useTranslation } from 'react-i18next' +import { + RiAlertFill, + RiCloseLine, + RiFileDownloadLine, +} from '@remixicon/react' +import { WORKFLOW_DATA_UPDATE } from '@/app/components/workflow/constants' +import { + initialEdges, + initialNodes, +} from '@/app/components/workflow/utils' +import { + useImportPipelineDSL, + useImportPipelineDSLConfirm, +} from '@/service/use-pipeline' +import { fetchWorkflowDraft } from '@/service/workflow' +import { + DSLImportMode, + DSLImportStatus, +} from '@/models/app' +import Uploader from '@/app/components/app/create-from-dsl-modal/uploader' +import Button from '@/app/components/base/button' +import Modal from '@/app/components/base/modal' +import { ToastContext } from '@/app/components/base/toast' +import { useEventEmitterContextContext } from '@/context/event-emitter' +import { usePluginDependencies } from '@/app/components/workflow/plugin-dependency/hooks' +import { useWorkflowStore } from '@/app/components/workflow/store' + +type UpdateDSLModalProps = { + onCancel: () => void + onBackup: () => void + onImport?: () => void +} + +const UpdateDSLModal = ({ + onCancel, + onBackup, + onImport, +}: UpdateDSLModalProps) => { + const { t } = useTranslation() + const { notify } = useContext(ToastContext) + const [currentFile, setDSLFile] = useState() + const [fileContent, setFileContent] = useState() + const [loading, setLoading] = useState(false) + const { eventEmitter } = useEventEmitterContextContext() + const [show, setShow] = useState(true) + const [showErrorModal, setShowErrorModal] = useState(false) + const [versions, setVersions] = useState<{ importedVersion: string; systemVersion: string }>() + const [importId, setImportId] = useState() + const { handleCheckPluginDependencies } = usePluginDependencies() + const { mutateAsync: importDSL } = useImportPipelineDSL() + const { mutateAsync: importDSLConfirm } = useImportPipelineDSLConfirm() + const workflowStore = useWorkflowStore() + + const readFile = (file: File) => { + const reader = new FileReader() + reader.onload = function (event) { + const content = event.target?.result + setFileContent(content as string) + } + reader.readAsText(file) + } + + const handleFile = (file?: File) => { + setDSLFile(file) + if (file) + readFile(file) + if (!file) + setFileContent('') + } + + const handleWorkflowUpdate = useCallback(async (pipelineId: string) => { + const { + graph, + hash, + rag_pipeline_variables, + } = await fetchWorkflowDraft(`/rag/pipelines/${pipelineId}/workflows/draft`) + + const { nodes, edges, viewport } = graph + + eventEmitter?.emit({ + type: WORKFLOW_DATA_UPDATE, + payload: { + nodes: initialNodes(nodes, edges), + edges: initialEdges(edges, nodes), + viewport, + hash, + rag_pipeline_variables: rag_pipeline_variables || [], + }, + } as any) + }, [eventEmitter]) + + const isCreatingRef = useRef(false) + const handleImport: MouseEventHandler = useCallback(async () => { + const { pipelineId } = workflowStore.getState() + if (isCreatingRef.current) + return + isCreatingRef.current = true + if (!currentFile) + return + try { + if (pipelineId && fileContent) { + setLoading(true) + const response = await importDSL({ mode: DSLImportMode.YAML_CONTENT, yaml_content: fileContent, pipeline_id: pipelineId }) + const { id, status, pipeline_id, imported_dsl_version, current_dsl_version } = response + + if (status === DSLImportStatus.COMPLETED || status === DSLImportStatus.COMPLETED_WITH_WARNINGS) { + if (!pipeline_id) { + notify({ type: 'error', message: t('workflow.common.importFailure') }) + return + } + handleWorkflowUpdate(pipeline_id) + if (onImport) + onImport() + notify({ + type: status === DSLImportStatus.COMPLETED ? 'success' : 'warning', + message: t(status === DSLImportStatus.COMPLETED ? 'workflow.common.importSuccess' : 'workflow.common.importWarning'), + children: status === DSLImportStatus.COMPLETED_WITH_WARNINGS && t('workflow.common.importWarningDetails'), + }) + await handleCheckPluginDependencies(pipeline_id, true) + setLoading(false) + onCancel() + } + else if (status === DSLImportStatus.PENDING) { + setShow(false) + setTimeout(() => { + setShowErrorModal(true) + }, 300) + setVersions({ + importedVersion: imported_dsl_version ?? '', + systemVersion: current_dsl_version ?? '', + }) + setImportId(id) + } + else { + setLoading(false) + notify({ type: 'error', message: t('workflow.common.importFailure') }) + } + } + } + // eslint-disable-next-line unused-imports/no-unused-vars + catch (e) { + setLoading(false) + notify({ type: 'error', message: t('workflow.common.importFailure') }) + } + isCreatingRef.current = false + }, [currentFile, fileContent, onCancel, notify, t, onImport, handleWorkflowUpdate, handleCheckPluginDependencies, workflowStore, importDSL]) + + const onUpdateDSLConfirm: MouseEventHandler = async () => { + try { + if (!importId) + return + const response = await importDSLConfirm(importId) + + const { status, pipeline_id } = response + + if (status === DSLImportStatus.COMPLETED) { + if (!pipeline_id) { + notify({ type: 'error', message: t('workflow.common.importFailure') }) + return + } + handleWorkflowUpdate(pipeline_id) + await handleCheckPluginDependencies(pipeline_id, true) + if (onImport) + onImport() + notify({ type: 'success', message: t('workflow.common.importSuccess') }) + setLoading(false) + onCancel() + } + else if (status === DSLImportStatus.FAILED) { + setLoading(false) + notify({ type: 'error', message: t('workflow.common.importFailure') }) + } + } + // eslint-disable-next-line unused-imports/no-unused-vars + catch (e) { + setLoading(false) + notify({ type: 'error', message: t('workflow.common.importFailure') }) + } + } + + return ( + <> + +
+
{t('workflow.common.importDSL')}
+
+ +
+
+
+
+
+ +
+
+
{t('workflow.common.importDSLTip')}
+
+ +
+
+
+
+
+ {t('workflow.common.chooseDSL')} +
+
+ +
+
+
+ + +
+ + setShowErrorModal(false)} + className='w-[480px]' + > +
+
{t('app.newApp.appCreateDSLErrorTitle')}
+
+
{t('app.newApp.appCreateDSLErrorPart1')}
+
{t('app.newApp.appCreateDSLErrorPart2')}
+
+
{t('app.newApp.appCreateDSLErrorPart3')}{versions?.importedVersion}
+
{t('app.newApp.appCreateDSLErrorPart4')}{versions?.systemVersion}
+
+
+
+ + +
+
+ + ) +} + +export default memo(UpdateDSLModal) diff --git a/web/service/use-pipeline.ts b/web/service/use-pipeline.ts index b338615ef6..823f75594f 100644 --- a/web/service/use-pipeline.ts +++ b/web/service/use-pipeline.ts @@ -306,7 +306,7 @@ export const useExportPipelineDSL = () => { pipelineId, include = false, }: { pipelineId: string; include?: boolean }) => { - return get(`/rag/pipelines/${pipelineId}/export?include_secret=${include}`) + return get(`/rag/pipelines/${pipelineId}/exports?include_secret=${include}`) }, }) }