fix(web): workflow editor bug
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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')}
|
||||
|
||||
@@ -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')}
|
||||
|
||||
@@ -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>}
|
||||
|
||||
@@ -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变量支持
|
||||
|
||||
Reference in New Issue
Block a user