fix(web): workflow editor bug

This commit is contained in:
zhaoying
2026-03-25 15:40:12 +08:00
parent 49364802c2
commit edd115582f
7 changed files with 80 additions and 74 deletions

View File

@@ -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
? <Flex justify="space-between" gap={12}>
<RbButton type="primary" ghost block onClick={() => handleEdit(item)}>{t('common.view')}</RbButton>
{item.share_permission === 'editable' && <RbButton type="primary" className="rb:w-[calc(100%-46px)]" onClick={() => handleCopy(item)}>{t('common.copy')}</RbButton>}
<RbButton block onClick={() => handleEdit(item)}>{t('common.view')}</RbButton>
{item.share_permission === 'editable' && <RbButton type="primary" ghost className="rb:w-[calc(100%-46px)]" onClick={() => handleCopy(item)}>{t('common.copy')}</RbButton>}
</Flex>
: <Flex justify="space-between" gap={12}>
<RbButton danger className="rb:w-22.25" onClick={() => handleDelete(item)}>{t('common.delete')}</RbButton>

View File

@@ -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 = () => {
</RbCard>
</List.Item>
)}
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"
/>
</BodyWrapper>

View File

@@ -16,6 +16,8 @@ const InitialValuePlugin: React.FC<InitialValuePluginProps> = ({ value, options
const prevValueRef = useRef<string>('');
const prevEnableLineNumbersRef = useRef<boolean>(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<InitialValuePluginProps> = ({ 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;
};

View File

@@ -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<CaseListProps> = ({
</Form.Item>
<Divider type="vertical" />
<Form.Item name={[conditionField.name, 'right']} noStyle>
{inputType === 'Variable'
{inputType === 'variable'
? <VariableSelect
placeholder={t('common.pleaseSelect')}
options={options.filter(vo => vo.dataType === 'number')}

View File

@@ -195,7 +195,7 @@ const ConditionList: FC<CaseListProps> = ({
</Form.Item>
<Divider type="vertical" />
<Form.Item name={[field.name, 'right']} noStyle>
{inputType === 'Variable'
{inputType === 'variable'
? (
<VariableSelect
placeholder={t('common.pleaseSelect')}

View File

@@ -78,7 +78,7 @@ const VariableList: FC<VariableListProps> = ({
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)}
>
<span className="rb:font-medium">{vo.name}·{vo.description}</span>
<span className="rb:font-medium rb:flex-1">{vo.name}·{vo.description}</span>
<Space size={8}>
{vo.required && <span className="rb:py-px rb:px-2 rb:bg-white rb-border rb:rounded-sm">{t('workflow.config.start.required')}</span>}

View File

@@ -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<PropertiesProps> = ({
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!')}
>
<Form form={form} size="small" layout="vertical">
<Form key={selectedNode?.getData()?.id} form={form} size="small" layout="vertical">
<Form.Item name="name" label={t('workflow.nodeName')}>
<Input
placeholder={t('common.pleaseEnter')}
@@ -525,7 +525,7 @@ const Properties: FC<PropertiesProps> = ({
}
if (key === 'model_id' && selectedNode?.data?.type === 'llm') {
return <ModelConfig />
return <ModelConfig key={key} />
}
if (selectedNode?.data?.type === 'llm' && key === 'messages' && config.type === 'define') {
// 为llm节点且isArray=true时添加context变量支持