From edd115582f1d03a88063596b0bdbd7df0cf725f6 Mon Sep 17 00:00:00 2001 From: zhaoying Date: Wed, 25 Mar 2026 15:40:12 +0800 Subject: [PATCH] fix(web): workflow editor bug --- web/src/views/ApplicationManagement/index.tsx | 6 +- web/src/views/SpaceManagement/index.tsx | 4 +- .../Editor/plugin/InitialValuePlugin.tsx | 130 +++++++++--------- .../components/Properties/CaseList/index.tsx | 4 +- .../Properties/ConditionList/index.tsx | 2 +- .../Properties/VariableList/index.tsx | 2 +- .../Workflow/components/Properties/index.tsx | 6 +- 7 files changed, 80 insertions(+), 74 deletions(-) diff --git a/web/src/views/ApplicationManagement/index.tsx b/web/src/views/ApplicationManagement/index.tsx index faf7e55d..4d49635c 100644 --- a/web/src/views/ApplicationManagement/index.tsx +++ b/web/src/views/ApplicationManagement/index.tsx @@ -2,7 +2,7 @@ * @Author: ZhaoYing * @Date: 2026-02-03 16:34:12 * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-03-25 11:16:04 + * @Last Modified time: 2026-03-25 15:38:13 */ /** * Application Management Page @@ -199,8 +199,8 @@ const ApplicationManagement: React.FC = () => { footer={ item.is_shared ? - handleEdit(item)}>{t('common.view')} - {item.share_permission === 'editable' && handleCopy(item)}>{t('common.copy')}} + handleEdit(item)}>{t('common.view')} + {item.share_permission === 'editable' && handleCopy(item)}>{t('common.copy')}} : handleDelete(item)}>{t('common.delete')} diff --git a/web/src/views/SpaceManagement/index.tsx b/web/src/views/SpaceManagement/index.tsx index a11c9d9e..0df3c653 100644 --- a/web/src/views/SpaceManagement/index.tsx +++ b/web/src/views/SpaceManagement/index.tsx @@ -2,7 +2,7 @@ * @Author: ZhaoYing * @Date: 2026-02-03 17:48:59 * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-03-20 18:49:51 + * @Last Modified time: 2026-03-25 15:33:38 */ /** * Space Management Page @@ -93,7 +93,7 @@ const SpaceManagement: React.FC = () => { )} - className="rb:h-[calc(100vh-148px)] rb:overflow-y-auto rb:overflow-x-hidden" + className="rb:h-[calc(100vh-124px)] rb:overflow-y-auto rb:overflow-x-hidden" /> diff --git a/web/src/views/Workflow/components/Editor/plugin/InitialValuePlugin.tsx b/web/src/views/Workflow/components/Editor/plugin/InitialValuePlugin.tsx index 8fe29d19..04e8ae1d 100644 --- a/web/src/views/Workflow/components/Editor/plugin/InitialValuePlugin.tsx +++ b/web/src/views/Workflow/components/Editor/plugin/InitialValuePlugin.tsx @@ -16,6 +16,8 @@ const InitialValuePlugin: React.FC = ({ value, options const prevValueRef = useRef(''); const prevEnableLineNumbersRef = useRef(enableLineNumbers); const isUserInputRef = useRef(false); + const optionsRef = useRef(options); + optionsRef.current = options; useEffect(() => { const removeListener = editor.registerUpdateListener(({ editorState, tags }) => { @@ -41,80 +43,84 @@ const InitialValuePlugin: React.FC = ({ value, options isUserInputRef.current = false; return; } + // Update refs BEFORE editor.update to prevent re-entry + prevValueRef.current = value; + prevEnableLineNumbersRef.current = enableLineNumbers; + isUserInputRef.current = false; + queueMicrotask(() => { editor.update(() => { - const root = $getRoot(); - root.clear(); + const root = $getRoot(); + root.clear(); - const parts = value.split(/(\{\{[^}]+\}\})/); + const parts = value.split(/(\{\{[^}]+\}\})/); - if (enableLineNumbers) { - // Handle newlines properly in Jinja2 mode - const lines = value.split('\n'); - lines.forEach((line) => { + if (enableLineNumbers) { + const lines = value.split('\n'); + lines.forEach((line) => { + const paragraph = $createParagraphNode(); + paragraph.append($createTextNode(line)); + root.append(paragraph); + }); + } else { const paragraph = $createParagraphNode(); - paragraph.append($createTextNode(line)); - root.append(paragraph); - }); - } else { - const paragraph = $createParagraphNode(); - parts.forEach(part => { - const match = part.match(/^\{\{([^.]+)\.([^}]+)\}\}$/); - const contextMatch = part.match(/^\{\{context\}\}$/); - const conversationMatch = part.match(/^\{\{conv\.([^}]+)\}\}$/); + parts.forEach(part => { + const match = part.match(/^\{\{([^.]+)\.([^}]+)\}\}$/); + const contextMatch = part.match(/^\{\{context\}\}$/); + const conversationMatch = part.match(/^\{\{conv\.([^}]+)\}\}$/); - if (contextMatch) { - const contextSuggestion = options.find(s => s.isContext && s.label === 'context'); - if (contextSuggestion) { - paragraph.append($createVariableNode(contextSuggestion)); - } else { - paragraph.append($createTextNode(part)); - } - return - } - - if (conversationMatch) { - const [_, variableName] = conversationMatch; - const conversationSuggestion = options.find(s => - s.group === 'CONVERSATION' && s.label === variableName - ); - if (conversationSuggestion) { - paragraph.append($createVariableNode(conversationSuggestion)); - } else { - paragraph.append($createTextNode(part)); - } - return - } - - if (match) { - const [_, nodeId, label] = match; - - const suggestion = options.find(s => { - if (nodeId === 'sys') { - return s.nodeData.type === 'start' && s.label === `sys.${label}` + if (contextMatch) { + const contextSuggestion = optionsRef.current.find(s => s.isContext && s.label === 'context'); + if (contextSuggestion) { + paragraph.append($createVariableNode(contextSuggestion)); + } else { + paragraph.append($createTextNode(part)); } - return s.nodeData.id === nodeId && s.label === label - }); + return + } + + if (conversationMatch) { + const [_, variableName] = conversationMatch; + const conversationSuggestion = optionsRef.current.find(s => + s.group === 'CONVERSATION' && s.label === variableName + ); + if (conversationSuggestion) { + paragraph.append($createVariableNode(conversationSuggestion)); + } else { + paragraph.append($createTextNode(part)); + } + return + } + + if (match) { + const [_, nodeId, label] = match; - if (suggestion) { - paragraph.append($createVariableNode(suggestion)); - } else { + const suggestion = optionsRef.current.find(s => { + if (nodeId === 'sys') { + return s.nodeData.type === 'start' && s.label === `sys.${label}` + } + return s.nodeData.id === nodeId && s.label === label + }); + + if (suggestion) { + paragraph.append($createVariableNode(suggestion)); + } else { + paragraph.append($createTextNode(part)); + } + } else if (part) { paragraph.append($createTextNode(part)); } - } else if (part) { - paragraph.append($createTextNode(part)); - } - }); - root.append(paragraph); - } - }, { discrete: true, tag: 'programmatic' }); + }); + root.append(paragraph); + } + }, { tag: 'programmatic' }); }); + } else { + prevValueRef.current = value; + prevEnableLineNumbersRef.current = enableLineNumbers; + isUserInputRef.current = false; } - - prevValueRef.current = value; - prevEnableLineNumbersRef.current = enableLineNumbers; - isUserInputRef.current = false; - }, [value, options, editor, enableLineNumbers]); + }, [value, editor, enableLineNumbers]); return null; }; diff --git a/web/src/views/Workflow/components/Properties/CaseList/index.tsx b/web/src/views/Workflow/components/Properties/CaseList/index.tsx index 43c18791..12ca38d5 100644 --- a/web/src/views/Workflow/components/Properties/CaseList/index.tsx +++ b/web/src/views/Workflow/components/Properties/CaseList/index.tsx @@ -2,7 +2,7 @@ * @Author: ZhaoYing * @Date: 2026-02-09 18:24:53 * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-03-24 15:00:46 + * @Last Modified time: 2026-03-25 15:23:45 */ import { type FC } from 'react' import clsx from 'clsx' @@ -321,7 +321,7 @@ const CaseList: FC = ({ - {inputType === 'Variable' + {inputType === 'variable' ? vo.dataType === 'number')} diff --git a/web/src/views/Workflow/components/Properties/ConditionList/index.tsx b/web/src/views/Workflow/components/Properties/ConditionList/index.tsx index 9028ed9f..84beb561 100644 --- a/web/src/views/Workflow/components/Properties/ConditionList/index.tsx +++ b/web/src/views/Workflow/components/Properties/ConditionList/index.tsx @@ -195,7 +195,7 @@ const ConditionList: FC = ({ - {inputType === 'Variable' + {inputType === 'variable' ? ( = ({ className="rb:cursor-pointer rb:group rb:py-2! rb:pl-2.5! rb:pr-2! rb:text-[12px] rb:bg-[#F6F6F6] rb-border rb:rounded-lg" onClick={() => handleEditVariable(index, vo)} > - {vo.name}·{vo.description} + {vo.name}·{vo.description} {vo.required && {t('workflow.config.start.required')}} diff --git a/web/src/views/Workflow/components/Properties/index.tsx b/web/src/views/Workflow/components/Properties/index.tsx index 96036821..57ce2f38 100644 --- a/web/src/views/Workflow/components/Properties/index.tsx +++ b/web/src/views/Workflow/components/Properties/index.tsx @@ -2,7 +2,7 @@ * @Author: ZhaoYing * @Date: 2026-02-03 15:39:59 * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-03-24 16:33:32 + * @Last Modified time: 2026-03-25 15:08:02 */ import { type FC, useEffect, useState, useMemo } from "react"; import clsx from 'clsx' @@ -454,7 +454,7 @@ const Properties: FC = ({ className="rb:h-full! rb:hover:shadow-none!" bodyClassName={clsx('rb:overflow-y-auto! rb:h-[calc(100vh-131px)]! rb:px-3! rb:pt-0! rb:pb-3!')} > -
+ = ({ } if (key === 'model_id' && selectedNode?.data?.type === 'llm') { - return + return } if (selectedNode?.data?.type === 'llm' && key === 'messages' && config.type === 'define') { // 为llm节点且isArray=true时添加context变量支持