perf: all plugin variables type support referense & replace input and textarea with prompt editor (#2950)

* support reference as plugin variables

* replace input and textarea with prompt editor

* adjust height & optimize textarea and input

* input select
This commit is contained in:
heheer
2024-10-22 11:21:28 +08:00
committed by GitHub
parent 779ff29ed5
commit 3f34c33d4c
17 changed files with 258 additions and 141 deletions

View File

@@ -267,6 +267,7 @@ export enum NodeOutputKeyEnum {
export enum VariableInputEnum { export enum VariableInputEnum {
input = 'input', input = 'input',
textarea = 'textarea', textarea = 'textarea',
textInput = 'textInput',
numberInput = 'numberInput', numberInput = 'numberInput',
select = 'select', select = 'select',
custom = 'custom' custom = 'custom'
@@ -294,6 +295,12 @@ export const variableMap: Record<
defaultValueType: WorkflowIOValueTypeEnum.string, defaultValueType: WorkflowIOValueTypeEnum.string,
description: i18nT('app:variable.textarea_type_desc') description: i18nT('app:variable.textarea_type_desc')
}, },
[VariableInputEnum.textInput]: {
icon: 'core/workflow/inputType/input',
label: i18nT('common:core.workflow.inputType.textInput'),
value: VariableInputEnum.textInput,
defaultValueType: WorkflowIOValueTypeEnum.string
},
[VariableInputEnum.numberInput]: { [VariableInputEnum.numberInput]: {
icon: 'core/workflow/inputType/numberInput', icon: 'core/workflow/inputType/numberInput',
label: i18nT('common:core.workflow.inputType.number input'), label: i18nT('common:core.workflow.inputType.number input'),

View File

@@ -1,14 +1,13 @@
import { WorkflowIOValueTypeEnum } from '../constants'; import { WorkflowIOValueTypeEnum } from '../constants';
import { i18nT } from '../../../../web/i18n/utils'; import { i18nT } from '../../../../web/i18n/utils';
export enum FlowNodeInputTypeEnum { // render ui export enum FlowNodeInputTypeEnum { // render ui
textInput = 'textInput',
reference = 'reference', // reference to other node output reference = 'reference', // reference to other node output
input = 'input', // one line input
numberInput = 'numberInput', numberInput = 'numberInput',
switch = 'switch', // true/false switch = 'switch', // true/false
select = 'select', select = 'select',
// editor // editor
textarea = 'textarea',
JSONEditor = 'JSONEditor', JSONEditor = 'JSONEditor',
addInputParam = 'addInputParam', // params input addInputParam = 'addInputParam', // params input
@@ -27,7 +26,11 @@ export enum FlowNodeInputTypeEnum { // render ui
settingDatasetQuotePrompt = 'settingDatasetQuotePrompt', settingDatasetQuotePrompt = 'settingDatasetQuotePrompt',
hidden = 'hidden', hidden = 'hidden',
custom = 'custom' custom = 'custom',
// deprecated
input = 'input', // one line input
textarea = 'textarea'
} }
export const FlowNodeInputMap: Record< export const FlowNodeInputMap: Record<
FlowNodeInputTypeEnum, FlowNodeInputTypeEnum,
@@ -35,12 +38,12 @@ export const FlowNodeInputMap: Record<
icon: string; icon: string;
} }
> = { > = {
[FlowNodeInputTypeEnum.textInput]: {
icon: 'core/workflow/inputType/input'
},
[FlowNodeInputTypeEnum.reference]: { [FlowNodeInputTypeEnum.reference]: {
icon: 'core/workflow/inputType/reference' icon: 'core/workflow/inputType/reference'
}, },
[FlowNodeInputTypeEnum.input]: {
icon: 'core/workflow/inputType/input'
},
[FlowNodeInputTypeEnum.numberInput]: { [FlowNodeInputTypeEnum.numberInput]: {
icon: 'core/workflow/inputType/numberInput' icon: 'core/workflow/inputType/numberInput'
}, },
@@ -50,9 +53,6 @@ export const FlowNodeInputMap: Record<
[FlowNodeInputTypeEnum.switch]: { [FlowNodeInputTypeEnum.switch]: {
icon: 'core/workflow/inputType/switch' icon: 'core/workflow/inputType/switch'
}, },
[FlowNodeInputTypeEnum.textarea]: {
icon: 'core/workflow/inputType/textarea'
},
[FlowNodeInputTypeEnum.JSONEditor]: { [FlowNodeInputTypeEnum.JSONEditor]: {
icon: 'core/workflow/inputType/jsonEditor' icon: 'core/workflow/inputType/jsonEditor'
}, },
@@ -85,6 +85,12 @@ export const FlowNodeInputMap: Record<
}, },
[FlowNodeInputTypeEnum.custom]: { [FlowNodeInputTypeEnum.custom]: {
icon: 'core/workflow/inputType/custom' icon: 'core/workflow/inputType/custom'
},
[FlowNodeInputTypeEnum.input]: {
icon: 'core/workflow/inputType/input'
},
[FlowNodeInputTypeEnum.textarea]: {
icon: 'core/workflow/inputType/textarea'
} }
}; };

View File

@@ -230,6 +230,10 @@ export const appData2FlowNodeIO = ({
FlowNodeInputTypeEnum.textarea, FlowNodeInputTypeEnum.textarea,
FlowNodeInputTypeEnum.reference FlowNodeInputTypeEnum.reference
], ],
[VariableInputEnum.textInput]: [
FlowNodeInputTypeEnum.textInput,
FlowNodeInputTypeEnum.reference
],
[VariableInputEnum.numberInput]: [FlowNodeInputTypeEnum.numberInput], [VariableInputEnum.numberInput]: [FlowNodeInputTypeEnum.numberInput],
[VariableInputEnum.select]: [FlowNodeInputTypeEnum.select], [VariableInputEnum.select]: [FlowNodeInputTypeEnum.select],
[VariableInputEnum.custom]: [ [VariableInputEnum.custom]: [

View File

@@ -36,6 +36,11 @@ const NodeInputSelect = ({
icon: FlowNodeInputMap[FlowNodeInputTypeEnum.input].icon, icon: FlowNodeInputMap[FlowNodeInputTypeEnum.input].icon,
title: t('common:core.workflow.inputType.Manual input') title: t('common:core.workflow.inputType.Manual input')
}, },
{
type: FlowNodeInputTypeEnum.textInput,
icon: FlowNodeInputMap[FlowNodeInputTypeEnum.input].icon,
title: t('common:core.workflow.inputType.Manual input')
},
{ {
type: FlowNodeInputTypeEnum.numberInput, type: FlowNodeInputTypeEnum.numberInput,
icon: FlowNodeInputMap[FlowNodeInputTypeEnum.numberInput].icon, icon: FlowNodeInputMap[FlowNodeInputTypeEnum.numberInput].icon,

View File

@@ -800,6 +800,7 @@
"core.workflow.inputType.selectDataset": "Dataset Select", "core.workflow.inputType.selectDataset": "Dataset Select",
"core.workflow.inputType.selectLLMModel": "Chat Model Select", "core.workflow.inputType.selectLLMModel": "Chat Model Select",
"core.workflow.inputType.switch": "Switch", "core.workflow.inputType.switch": "Switch",
"core.workflow.inputType.textInput": "Text Input box",
"core.workflow.inputType.textarea": "Multi-line Input Box", "core.workflow.inputType.textarea": "Multi-line Input Box",
"core.workflow.publish.OnRevert version": "Click to Revert to This Version", "core.workflow.publish.OnRevert version": "Click to Revert to This Version",
"core.workflow.publish.OnRevert version confirm": "Confirm to Revert to This Version? The configuration of the editing version will be saved, and a new release version will be created for the reverted version.", "core.workflow.publish.OnRevert version confirm": "Confirm to Revert to This Version? The configuration of the editing version will be saved, and a new release version will be created for the reverted version.",

View File

@@ -2,8 +2,8 @@
"Array_element": "Array element", "Array_element": "Array element",
"Code": "Code", "Code": "Code",
"Confirm_sync_node": "It will be updated to the latest node configuration and fields that do not exist in the template will be deleted (including all custom fields).\n\nIf the fields are complex, it is recommended that you copy a node first and then update the original node to facilitate parameter copying.", "Confirm_sync_node": "It will be updated to the latest node configuration and fields that do not exist in the template will be deleted (including all custom fields).\n\nIf the fields are complex, it is recommended that you copy a node first and then update the original node to facilitate parameter copying.",
"Node_variables": "Node variables",
"Node.Open_Node_Course": "Open node course", "Node.Open_Node_Course": "Open node course",
"Node_variables": "Node variables",
"Quote_prompt_setting": "Quote prompt", "Quote_prompt_setting": "Quote prompt",
"Variable.Variable type": "Variable type", "Variable.Variable type": "Variable type",
"Variable_name": "Variable name", "Variable_name": "Variable name",
@@ -54,6 +54,7 @@
"field_description_placeholder": "Describe the function of this input field. If it is a tool call parameter, this description will affect the quality of the model generation.", "field_description_placeholder": "Describe the function of this input field. If it is a tool call parameter, this description will affect the quality of the model generation.",
"field_name_already_exists": "Field name already exists", "field_name_already_exists": "Field name already exists",
"field_required": "Required", "field_required": "Required",
"field_used_as_reference": "Support reference",
"field_used_as_tool_input": "Used as Tool Call Parameter", "field_used_as_tool_input": "Used as Tool Call Parameter",
"filter_description": "Currently supports filtering by tags and creation time. Fill in the format as follows:\n{\n \"tags\": {\n \"$and\": [\"Tag 1\",\"Tag 2\"],\n \"$or\": [\"When there are $and tags, and is effective, or is not effective\"]\n },\n \"createTime\": {\n \"$gte\": \"YYYY-MM-DD HH:mm format, collection creation time greater than this time\",\n \"$lte\": \"YYYY-MM-DD HH:mm format, collection creation time less than this time, can be used with $gte\"\n }\n}", "filter_description": "Currently supports filtering by tags and creation time. Fill in the format as follows:\n{\n \"tags\": {\n \"$and\": [\"Tag 1\",\"Tag 2\"],\n \"$or\": [\"When there are $and tags, and is effective, or is not effective\"]\n },\n \"createTime\": {\n \"$gte\": \"YYYY-MM-DD HH:mm format, collection creation time greater than this time\",\n \"$lte\": \"YYYY-MM-DD HH:mm format, collection creation time less than this time, can be used with $gte\"\n }\n}",
"form_input_result": "User complete input result", "form_input_result": "User complete input result",

View File

@@ -805,6 +805,7 @@
"core.workflow.inputType.selectDataset": "知识库选择", "core.workflow.inputType.selectDataset": "知识库选择",
"core.workflow.inputType.selectLLMModel": "对话模型选择", "core.workflow.inputType.selectLLMModel": "对话模型选择",
"core.workflow.inputType.switch": "开关", "core.workflow.inputType.switch": "开关",
"core.workflow.inputType.textInput": "文本输入框",
"core.workflow.inputType.textarea": "多行输入框", "core.workflow.inputType.textarea": "多行输入框",
"core.workflow.publish.OnRevert version": "点击回退到该版本", "core.workflow.publish.OnRevert version": "点击回退到该版本",
"core.workflow.publish.OnRevert version confirm": "确认回退至该版本?会为您保存编辑中版本的配置,并为回退版本创建一个新的发布版本。", "core.workflow.publish.OnRevert version confirm": "确认回退至该版本?会为您保存编辑中版本的配置,并为回退版本创建一个新的发布版本。",

View File

@@ -2,8 +2,8 @@
"Array_element": "数组元素", "Array_element": "数组元素",
"Code": "代码", "Code": "代码",
"Confirm_sync_node": "将会更新至最新的节点配置,不存在模板中的字段将会被删除(包括所有自定义字段)。\n如果字段较为复杂建议您先复制一份节点再更新原来的节点便于参数复制。", "Confirm_sync_node": "将会更新至最新的节点配置,不存在模板中的字段将会被删除(包括所有自定义字段)。\n如果字段较为复杂建议您先复制一份节点再更新原来的节点便于参数复制。",
"Node_variables": "节点变量",
"Node.Open_Node_Course": "查看节点教程", "Node.Open_Node_Course": "查看节点教程",
"Node_variables": "节点变量",
"Quote_prompt_setting": "引用提示词配置", "Quote_prompt_setting": "引用提示词配置",
"Variable.Variable type": "变量类型", "Variable.Variable type": "变量类型",
"Variable_name": "变量名", "Variable_name": "变量名",
@@ -55,6 +55,7 @@
"field_description_placeholder": "描述该输入字段的功能,如果为工具调用参数,则该描述会影响模型生成的质量", "field_description_placeholder": "描述该输入字段的功能,如果为工具调用参数,则该描述会影响模型生成的质量",
"field_name_already_exists": "字段名已经存在", "field_name_already_exists": "字段名已经存在",
"field_required": "必填", "field_required": "必填",
"field_used_as_reference": "支持变量引用",
"field_used_as_tool_input": "作为工具调用参数", "field_used_as_tool_input": "作为工具调用参数",
"filter_description": "目前支持标签和创建时间过滤,需按照以下格式填写:\n{\n \"tags\": {\n \"$and\": [\"标签 1\",\"标签 2\"],\n \"$or\": [\"有 $and 标签时and 生效or 不生效\"]\n },\n \"createTime\": {\n \"$gte\": \"YYYY-MM-DD HH:mm 格式即可,集合的创建时间大于该时间\",\n \"$lte\": \"YYYY-MM-DD HH:mm 格式即可,集合的创建时间小于该时间,可和 $gte 共同使用\"\n }\n}", "filter_description": "目前支持标签和创建时间过滤,需按照以下格式填写:\n{\n \"tags\": {\n \"$and\": [\"标签 1\",\"标签 2\"],\n \"$or\": [\"有 $and 标签时and 生效or 不生效\"]\n },\n \"createTime\": {\n \"$gte\": \"YYYY-MM-DD HH:mm 格式即可,集合的创建时间大于该时间\",\n \"$lte\": \"YYYY-MM-DD HH:mm 格式即可,集合的创建时间小于该时间,可和 $gte 共同使用\"\n }\n}",
"form_input_result": "用户完整输入结果", "form_input_result": "用户完整输入结果",

View File

@@ -36,7 +36,7 @@ export const defaultVariable: VariableItemType = {
id: nanoid(), id: nanoid(),
key: '', key: '',
label: '', label: '',
type: VariableInputEnum.input, type: VariableInputEnum.textInput,
description: '', description: '',
required: true, required: true,
valueType: WorkflowIOValueTypeEnum.string valueType: WorkflowIOValueTypeEnum.string
@@ -72,13 +72,18 @@ const VariableEdit = ({
const inputTypeList = useMemo( const inputTypeList = useMemo(
() => () =>
Object.values(variableMap).map((item) => ({ Object.values(variableMap)
icon: item.icon, .filter(
label: t(item.label as any), (item) =>
value: item.value, item.value !== VariableInputEnum.input && item.value !== VariableInputEnum.textarea
defaultValueType: item.defaultValueType, )
description: item.description ? t(item.description as any) : '' .map((item) => ({
})), icon: item.icon,
label: t(item.label as any),
value: item.value,
defaultValueType: item.defaultValueType,
description: item.description ? t(item.description as any) : ''
})),
[t] [t]
); );

View File

@@ -24,6 +24,7 @@ import { ChatBoxContext } from '../Provider';
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip'; import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
import { useDeepCompareEffect } from 'ahooks'; import { useDeepCompareEffect } from 'ahooks';
import { VariableItemType } from '@fastgpt/global/core/app/type'; import { VariableItemType } from '@fastgpt/global/core/app/type';
import PromptEditor from '@fastgpt/web/components/common/Textarea/PromptEditor';
export const VariableInputItem = ({ export const VariableInputItem = ({
item, item,
@@ -77,6 +78,16 @@ export const VariableInputItem = ({
maxLength={item.maxLength || 4000} maxLength={item.maxLength || 4000}
/> />
)} )}
{item.type === VariableInputEnum.textInput && (
<PromptEditor
value={item.defaultValue}
onChange={(e) => setValue(item.key, e)}
bg={'myGray.50'}
minH={50}
maxH={150}
showOpenModal={false}
/>
)}
{item.type === VariableInputEnum.select && ( {item.type === VariableInputEnum.select && (
<Controller <Controller
key={item.key} key={item.key}

View File

@@ -38,6 +38,7 @@ import { FlowNodeInputTypeEnum } from '@fastgpt/global/core/workflow/node/consta
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Controller, useForm } from 'react-hook-form'; import { Controller, useForm } from 'react-hook-form';
import MySelect from '@fastgpt/web/components/common/MySelect'; import MySelect from '@fastgpt/web/components/common/MySelect';
import PromptEditor from '@fastgpt/web/components/common/Textarea/PromptEditor';
type props = { type props = {
value: UserChatItemValueItemType | AIChatItemValueItemType; value: UserChatItemValueItemType | AIChatItemValueItemType;
@@ -240,6 +241,15 @@ const RenderUserFormInteractive = React.memo(function RenderFormInput({
maxLength={input.maxLength || 4000} maxLength={input.maxLength || 4000}
/> />
)} )}
{input.type === FlowNodeInputTypeEnum.textInput && (
<PromptEditor
value={input.value}
onChange={(e) => setValue(input.label, e)}
minH={40}
maxH={100}
showOpenModal={false}
/>
)}
{input.type === FlowNodeInputTypeEnum.numberInput && ( {input.type === FlowNodeInputTypeEnum.numberInput && (
<NumberInput <NumberInput
step={1} step={1}

View File

@@ -13,7 +13,6 @@ import {
Box, Box,
Button, Button,
Flex, Flex,
Textarea,
NumberDecrementStepper, NumberDecrementStepper,
NumberIncrementStepper, NumberIncrementStepper,
NumberInput, NumberInput,
@@ -34,6 +33,7 @@ import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
import { AppContext } from '../../../context'; import { AppContext } from '../../../context';
import { VariableInputItem } from '@/components/core/chat/ChatContainer/ChatBox/components/VariableInput'; import { VariableInputItem } from '@/components/core/chat/ChatContainer/ChatBox/components/VariableInput';
import LightRowTabs from '@fastgpt/web/components/common/Tabs/LightRowTabs'; import LightRowTabs from '@fastgpt/web/components/common/Tabs/LightRowTabs';
import PromptEditor from '@fastgpt/web/components/common/Textarea/PromptEditor';
const MyRightDrawer = dynamic( const MyRightDrawer = dynamic(
() => import('@fastgpt/web/components/common/MyDrawer/MyRightDrawer') () => import('@fastgpt/web/components/common/MyDrawer/MyRightDrawer')
@@ -270,10 +270,14 @@ export const useDebug = () => {
const RenderInput = (() => { const RenderInput = (() => {
if (input.valueType === WorkflowIOValueTypeEnum.string) { if (input.valueType === WorkflowIOValueTypeEnum.string) {
return ( return (
<Textarea <PromptEditor
{...register(`nodeVariables.${input.key}`, { value={getValues(`nodeVariables.${input.key}`)}
required onChange={(e) => {
})} setValue(`nodeVariables.${input.key}`, e);
}}
minH={50}
maxH={150}
showOpenModal={false}
placeholder={t(input.placeholder || ('' as any))} placeholder={t(input.placeholder || ('' as any))}
bg={'myGray.50'} bg={'myGray.50'}
/> />

View File

@@ -11,7 +11,7 @@ import { useToast } from '@fastgpt/web/hooks/useToast';
import InputTypeConfig from '../NodePluginIO/InputTypeConfig'; import InputTypeConfig from '../NodePluginIO/InputTypeConfig';
export const defaultFormInput: UserInputFormItemType = { export const defaultFormInput: UserInputFormItemType = {
type: FlowNodeInputTypeEnum.input, type: FlowNodeInputTypeEnum.textInput,
key: '', key: '',
label: '', label: '',
description: '', description: '',
@@ -54,14 +54,8 @@ const InputFormEditModal = ({
const inputTypeList = [ const inputTypeList = [
{ {
icon: 'core/workflow/inputType/input', icon: 'core/workflow/inputType/input',
label: t('common:core.workflow.inputType.input'), label: t('common:core.workflow.inputType.textInput'),
value: FlowNodeInputTypeEnum.input, value: FlowNodeInputTypeEnum.textInput,
defaultValueType: WorkflowIOValueTypeEnum.string
},
{
icon: 'core/workflow/inputType/textarea',
label: t('common:core.workflow.inputType.textarea'),
value: FlowNodeInputTypeEnum.textarea,
defaultValueType: WorkflowIOValueTypeEnum.string defaultValueType: WorkflowIOValueTypeEnum.string
}, },
{ {

View File

@@ -54,14 +54,8 @@ const FieldEditModal = ({
}, },
{ {
icon: 'core/workflow/inputType/input', icon: 'core/workflow/inputType/input',
label: t('common:core.workflow.inputType.input'), label: t('common:core.workflow.inputType.textInput'),
value: FlowNodeInputTypeEnum.input, value: FlowNodeInputTypeEnum.textInput,
defaultValueType: WorkflowIOValueTypeEnum.string
},
{
icon: 'core/workflow/inputType/textarea',
label: t('common:core.workflow.inputType.textarea'),
value: FlowNodeInputTypeEnum.textarea,
defaultValueType: WorkflowIOValueTypeEnum.string defaultValueType: WorkflowIOValueTypeEnum.string
}, },
{ {
@@ -138,11 +132,24 @@ const FieldEditModal = ({
}); });
const { getValues, setValue, watch, reset } = form; const { getValues, setValue, watch, reset } = form;
const inputType = watch('renderTypeList.0') || FlowNodeInputTypeEnum.reference; const renderTypeList = watch('renderTypeList');
const inputType = renderTypeList[0] || FlowNodeInputTypeEnum.reference;
const valueType = watch('valueType'); const valueType = watch('valueType');
const [isToolInput, { toggle: setIsToolInput }] = useBoolean(!!getValues('toolDescription')); const [isToolInput, { toggle: setIsToolInput }] = useBoolean(!!getValues('toolDescription'));
const isRefrence = renderTypeList.includes(FlowNodeInputTypeEnum.reference);
const setIsRefrence = () => {
if (isRefrence) {
setValue(
'renderTypeList',
renderTypeList.filter((item) => item !== FlowNodeInputTypeEnum.reference)
);
} else {
setValue('renderTypeList', [...getValues('renderTypeList'), FlowNodeInputTypeEnum.reference]);
}
};
const maxLength = watch('maxLength'); const maxLength = watch('maxLength');
const max = watch('max'); const max = watch('max');
const min = watch('min'); const min = watch('min');
@@ -328,6 +335,8 @@ const FieldEditModal = ({
defaultValue={defaultInputValue} defaultValue={defaultInputValue}
isToolInput={isToolInput} isToolInput={isToolInput}
setIsToolInput={setIsToolInput} setIsToolInput={setIsToolInput}
isRefrence={isRefrence}
setIsRefrence={setIsRefrence}
valueType={valueType} valueType={valueType}
defaultValueType={defaultValueType} defaultValueType={defaultValueType}
onSubmitSuccess={onSubmitSuccess} onSubmitSuccess={onSubmitSuccess}

View File

@@ -34,6 +34,7 @@ import { useFieldArray, UseFormReturn } from 'react-hook-form';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import MyIcon from '@fastgpt/web/components/common/Icon'; import MyIcon from '@fastgpt/web/components/common/Icon';
import DndDrag, { Draggable } from '@fastgpt/web/components/common/DndDrag'; import DndDrag, { Draggable } from '@fastgpt/web/components/common/DndDrag';
import PromptEditor from '@fastgpt/web/components/common/Textarea/PromptEditor';
type ListValueType = { id: string; value: string; label: string }[]; type ListValueType = { id: string; value: string; label: string }[];
@@ -50,6 +51,8 @@ const InputTypeConfig = ({
defaultValue, defaultValue,
isToolInput, isToolInput,
setIsToolInput, setIsToolInput,
isRefrence,
setIsRefrence,
valueType, valueType,
defaultValueType, defaultValueType,
onSubmitSuccess, onSubmitSuccess,
@@ -72,6 +75,8 @@ const InputTypeConfig = ({
// Plugin-specific fields // Plugin-specific fields
isToolInput?: boolean; isToolInput?: boolean;
setIsToolInput?: () => void; setIsToolInput?: () => void;
isRefrence?: boolean;
setIsRefrence?: () => void;
valueType?: WorkflowIOValueTypeEnum; valueType?: WorkflowIOValueTypeEnum;
defaultValueType?: WorkflowIOValueTypeEnum; defaultValueType?: WorkflowIOValueTypeEnum;
@@ -132,7 +137,7 @@ const InputTypeConfig = ({
}, [inputType]); }, [inputType]);
const showMaxLenInput = useMemo(() => { const showMaxLenInput = useMemo(() => {
const list = [FlowNodeInputTypeEnum.input, FlowNodeInputTypeEnum.textarea]; const list = [FlowNodeInputTypeEnum.textInput];
return list.includes(inputType as FlowNodeInputTypeEnum); return list.includes(inputType as FlowNodeInputTypeEnum);
}, [inputType]); }, [inputType]);
@@ -143,8 +148,7 @@ const InputTypeConfig = ({
const showDefaultValue = useMemo(() => { const showDefaultValue = useMemo(() => {
const list = [ const list = [
FlowNodeInputTypeEnum.input, FlowNodeInputTypeEnum.textInput,
FlowNodeInputTypeEnum.textarea,
FlowNodeInputTypeEnum.JSONEditor, FlowNodeInputTypeEnum.JSONEditor,
FlowNodeInputTypeEnum.numberInput, FlowNodeInputTypeEnum.numberInput,
FlowNodeInputTypeEnum.switch, FlowNodeInputTypeEnum.switch,
@@ -158,7 +162,7 @@ const InputTypeConfig = ({
<Stack flex={1} borderLeft={'1px solid #F0F1F6'} justifyContent={'space-between'}> <Stack flex={1} borderLeft={'1px solid #F0F1F6'} justifyContent={'space-between'}>
<Flex flexDirection={'column'} p={8} pb={2} gap={4} flex={'1 0 0'} overflow={'auto'}> <Flex flexDirection={'column'} p={8} pb={2} gap={4} flex={'1 0 0'} overflow={'auto'}>
<Flex alignItems={'center'}> <Flex alignItems={'center'}>
<FormLabel flex={'0 0 100px'} fontWeight={'medium'}> <FormLabel flex={'0 0 132px'} fontWeight={'medium'}>
{typeLabels.name[type] || typeLabels.name.formInput} {typeLabels.name[type] || typeLabels.name.formInput}
</FormLabel> </FormLabel>
<Input <Input
@@ -170,7 +174,7 @@ const InputTypeConfig = ({
/> />
</Flex> </Flex>
<Flex alignItems={'flex-start'}> <Flex alignItems={'flex-start'}>
<FormLabel flex={'0 0 100px'} fontWeight={'medium'}> <FormLabel flex={'0 0 132px'} fontWeight={'medium'}>
{typeLabels.description[type] || typeLabels.description.plugin} {typeLabels.description[type] || typeLabels.description.plugin}
</FormLabel> </FormLabel>
<Textarea <Textarea
@@ -184,7 +188,7 @@ const InputTypeConfig = ({
{/* value type */} {/* value type */}
{type !== 'formInput' && ( {type !== 'formInput' && (
<Flex alignItems={'center'}> <Flex alignItems={'center'}>
<FormLabel flex={'0 0 100px'} fontWeight={'medium'}> <FormLabel flex={'0 0 132px'} fontWeight={'medium'}>
{t('common:core.module.Data Type')} {t('common:core.module.Data Type')}
</FormLabel> </FormLabel>
{showValueTypeSelect ? ( {showValueTypeSelect ? (
@@ -208,18 +212,33 @@ const InputTypeConfig = ({
)} )}
{showRequired && ( {showRequired && (
<Flex alignItems={'center'} minH={'40px'}> <Flex alignItems={'center'} minH={'40px'}>
<FormLabel flex={'0 0 100px'} fontWeight={'medium'}> <FormLabel flex={'0 0 132px'} fontWeight={'medium'}>
{t('workflow:field_required')} {t('workflow:field_required')}
</FormLabel> </FormLabel>
<Switch {...register('required')} /> <Switch {...register('required')} />
</Flex> </Flex>
)} )}
{/* reference */} {inputType !== FlowNodeInputTypeEnum.reference && setIsRefrence && (
{inputType === FlowNodeInputTypeEnum.reference && (
<> <>
<Flex alignItems={'center'} minH={'40px'}> <Flex alignItems={'center'} minH={'40px'}>
<FormLabel flex={'1'} fontWeight={'medium'}> <FormLabel flex={'0 0 132px'} fontWeight={'medium'}>
{t('workflow:field_used_as_reference')}
</FormLabel>
<Switch
isChecked={isRefrence}
onChange={(e) => {
setIsRefrence();
}}
/>
</Flex>
</>
)}
{/* reference */}
{(inputType === FlowNodeInputTypeEnum.reference || isRefrence) && (
<>
<Flex alignItems={'center'} minH={'40px'}>
<FormLabel flex={'0 0 132px'} fontWeight={'medium'}>
{t('workflow:field_used_as_tool_input')} {t('workflow:field_used_as_tool_input')}
</FormLabel> </FormLabel>
<Switch <Switch
@@ -234,7 +253,7 @@ const InputTypeConfig = ({
{showMaxLenInput && ( {showMaxLenInput && (
<Flex alignItems={'center'}> <Flex alignItems={'center'}>
<FormLabel flex={'0 0 100px'} fontWeight={'medium'}> <FormLabel flex={'0 0 132px'} fontWeight={'medium'}>
{t('common:core.module.Max Length')} {t('common:core.module.Max Length')}
</FormLabel> </FormLabel>
<MyNumberInput <MyNumberInput
@@ -254,7 +273,7 @@ const InputTypeConfig = ({
{showMinMaxInput && ( {showMinMaxInput && (
<> <>
<Flex alignItems={'center'}> <Flex alignItems={'center'}>
<FormLabel flex={'0 0 100px'} fontWeight={'medium'}> <FormLabel flex={'0 0 132px'} fontWeight={'medium'}>
{t('common:core.module.Max Value')} {t('common:core.module.Max Value')}
</FormLabel> </FormLabel>
<MyNumberInput <MyNumberInput
@@ -268,7 +287,7 @@ const InputTypeConfig = ({
/> />
</Flex> </Flex>
<Flex alignItems={'center'}> <Flex alignItems={'center'}>
<FormLabel flex={'0 0 100px'} fontWeight={'medium'}> <FormLabel flex={'0 0 132px'} fontWeight={'medium'}>
{t('common:core.module.Min Value')} {t('common:core.module.Min Value')}
</FormLabel> </FormLabel>
<MyNumberInput <MyNumberInput
@@ -286,70 +305,77 @@ const InputTypeConfig = ({
{showDefaultValue && ( {showDefaultValue && (
<Flex alignItems={'center'} minH={'40px'}> <Flex alignItems={'center'} minH={'40px'}>
<FormLabel <FormLabel flex={'0 0 132px'} fontWeight={'medium'}>
flex={inputType === FlowNodeInputTypeEnum.switch ? 1 : '0 0 100px'}
fontWeight={'medium'}
>
{t('common:core.module.Default Value')} {t('common:core.module.Default Value')}
</FormLabel> </FormLabel>
{inputType === FlowNodeInputTypeEnum.numberInput && ( <Flex alignItems={'start'} flex={1} h={10}>
<NumberInput flex={1} step={1} min={min} max={max} position={'relative'}> {inputType === FlowNodeInputTypeEnum.numberInput && (
<NumberInputField <NumberInput flex={1} step={1} min={min} max={max} position={'relative'}>
{...register('defaultValue', { <NumberInputField
min: min, {...register('defaultValue', {
max: max min: min,
})} max: max
})}
/>
<NumberInputStepper>
<NumberIncrementStepper />
<NumberDecrementStepper />
</NumberInputStepper>
</NumberInput>
)}
{inputType === FlowNodeInputTypeEnum.textInput && (
<PromptEditor
value={defaultValue}
onChange={(e) => {
setValue('defaultValue', e);
}}
minH={40}
maxH={200}
showOpenModal={false}
bg={'myGray.50'}
/> />
<NumberInputStepper> )}
<NumberIncrementStepper /> {inputType === FlowNodeInputTypeEnum.JSONEditor && (
<NumberDecrementStepper /> <JsonEditor
</NumberInputStepper> bg={'myGray.50'}
</NumberInput> resize
)} w={'full'}
{inputType === FlowNodeInputTypeEnum.input && ( onChange={(e) => {
<Input bg={'myGray.50'} maxLength={maxLength} {...register('defaultValue')} /> setValue('defaultValue', e);
)} }}
{inputType === FlowNodeInputTypeEnum.textarea && ( defaultValue={defaultValue}
<Textarea bg={'myGray.50'} maxLength={maxLength} {...register('defaultValue')} /> />
)} )}
{inputType === FlowNodeInputTypeEnum.JSONEditor && ( {inputType === FlowNodeInputTypeEnum.switch && (
<JsonEditor <Switch {...register('defaultValue')} />
bg={'myGray.50'} )}
resize {inputType === FlowNodeInputTypeEnum.select && (
w={'full'} <MySelect<string>
onChange={(e) => { list={[defaultListValue, ...listValue]
setValue('defaultValue', e); .filter((item) => item.label !== '')
}} .map((item) => ({
defaultValue={defaultValue} label: item.label,
/> value: item.value
)} }))}
{inputType === FlowNodeInputTypeEnum.switch && <Switch {...register('defaultValue')} />} value={
{inputType === FlowNodeInputTypeEnum.select && ( defaultValue && listValue.map((item) => item.value).includes(defaultValue)
<MySelect<string> ? defaultValue
list={[defaultListValue, ...listValue] : ''
.filter((item) => item.label !== '') }
.map((item) => ({ onchange={(e) => {
label: item.label, setValue('defaultValue', e);
value: item.value }}
}))} w={'200px'}
value={ />
defaultValue && listValue.map((item) => item.value).includes(defaultValue) )}
? defaultValue </Flex>
: ''
}
onchange={(e) => {
setValue('defaultValue', e);
}}
w={'200px'}
/>
)}
</Flex> </Flex>
)} )}
{inputType === FlowNodeInputTypeEnum.addInputParam && ( {inputType === FlowNodeInputTypeEnum.addInputParam && (
<> <>
<Flex alignItems={'center'}> <Flex alignItems={'center'}>
<FormLabel flex={'0 0 100px'} fontWeight={'medium'}> <FormLabel flex={'0 0 132px'} fontWeight={'medium'}>
{t('common:core.module.Input Type')} {t('common:core.module.Input Type')}
</FormLabel> </FormLabel>
<Box fontSize={'14px'}>{t('workflow:only_the_reference_type_is_supported')}</Box> <Box fontSize={'14px'}>{t('workflow:only_the_reference_type_is_supported')}</Box>
@@ -432,7 +458,7 @@ const InputTypeConfig = ({
transform={snapshot.isDragging ? `scale(0.5)` : ''} transform={snapshot.isDragging ? `scale(0.5)` : ''}
transformOrigin={'top left'} transformOrigin={'top left'}
> >
<FormLabel flex={'0 0 100px'} fontWeight={'medium'}> <FormLabel flex={'0 0 132px'} fontWeight={'medium'}>
{`${t('common:core.module.variable.variable options')} ${i + 1}`} {`${t('common:core.module.variable.variable options')} ${i + 1}`}
</FormLabel> </FormLabel>
<FormControl> <FormControl>

View File

@@ -16,10 +16,6 @@ const RenderList: {
types: [FlowNodeInputTypeEnum.reference], types: [FlowNodeInputTypeEnum.reference],
Component: dynamic(() => import('./templates/Reference')) Component: dynamic(() => import('./templates/Reference'))
}, },
{
types: [FlowNodeInputTypeEnum.input],
Component: dynamic(() => import('./templates/TextInput'))
},
{ {
types: [FlowNodeInputTypeEnum.select], types: [FlowNodeInputTypeEnum.select],
Component: dynamic(() => import('./templates/Select')) Component: dynamic(() => import('./templates/Select'))
@@ -33,8 +29,8 @@ const RenderList: {
Component: dynamic(() => import('./templates/Switch')) Component: dynamic(() => import('./templates/Switch'))
}, },
{ {
types: [FlowNodeInputTypeEnum.textarea], types: [FlowNodeInputTypeEnum.textInput],
Component: dynamic(() => import('./templates/Textarea')) Component: dynamic(() => import('./templates/TextInput'))
}, },
{ {
types: [FlowNodeInputTypeEnum.selectApp], types: [FlowNodeInputTypeEnum.selectApp],
@@ -67,6 +63,14 @@ const RenderList: {
{ {
types: [FlowNodeInputTypeEnum.settingDatasetQuotePrompt], types: [FlowNodeInputTypeEnum.settingDatasetQuotePrompt],
Component: dynamic(() => import('./templates/SettingQuotePrompt')) Component: dynamic(() => import('./templates/SettingQuotePrompt'))
},
{
types: [FlowNodeInputTypeEnum.input],
Component: dynamic(() => import('./templates/TextInput'))
},
{
types: [FlowNodeInputTypeEnum.textarea],
Component: dynamic(() => import('./templates/Textarea'))
} }
]; ];

View File

@@ -1,37 +1,65 @@
import React, { useMemo } from 'react'; import React, { useCallback, useMemo } from 'react';
import type { RenderInputProps } from '../type'; import type { RenderInputProps } from '../type';
import { Input } from '@chakra-ui/react'; import { useTranslation } from 'next-i18next';
import PromptEditor from '@fastgpt/web/components/common/Textarea/PromptEditor';
import { useContextSelector } from 'use-context-selector'; import { useContextSelector } from 'use-context-selector';
import { WorkflowContext } from '@/pages/app/detail/components/WorkflowComponents/context'; import { WorkflowContext } from '@/pages/app/detail/components/WorkflowComponents/context';
import { useTranslation } from 'next-i18next'; import { useCreation } from 'ahooks';
import { AppContext } from '@/pages/app/detail/components/context';
import { getEditorVariables } from '../../../../../utils';
const TextInput = ({ item, nodeId }: RenderInputProps) => { const TextInputRender = ({ inputs = [], item, nodeId }: RenderInputProps) => {
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
const { t } = useTranslation(); const { t } = useTranslation();
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
const edges = useContextSelector(WorkflowContext, (v) => v.edges);
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
const { appDetail } = useContextSelector(AppContext, (v) => v);
// get variable
const variables = useCreation(() => {
return getEditorVariables({
nodeId,
nodeList,
edges,
appDetail,
t
});
}, [nodeId, nodeList, edges, appDetail, t]);
const onChange = useCallback(
(e: string) => {
onChangeNode({
nodeId,
type: 'updateInput',
key: item.key,
value: {
...item,
value: e
}
});
},
[item, nodeId, onChangeNode]
);
const Render = useMemo(() => { const Render = useMemo(() => {
return ( return (
<Input <PromptEditor
placeholder={t(item.placeholder as any) ?? t(item.description as any)} variableLabels={variables}
defaultValue={item.value} variables={variables}
bg={'white'} title={t(item.label as any)}
px={3} maxLength={item.maxLength}
borderRadius={'sm'} minH={40}
onBlur={(e) => { maxH={120}
onChangeNode({ placeholder={t((item.placeholder as any) || '')}
nodeId, value={item.value}
type: 'updateInput', onChange={onChange}
key: item.key, isFlow={true}
value: {
...item,
value: e.target.value
}
});
}}
/> />
); );
}, [item, nodeId, onChangeNode, t]); }, [item.label, item.maxLength, item.placeholder, item.value, onChange, t, variables]);
return Render; return Render;
}; };
export default React.memo(TextInput); export default React.memo(TextInputRender);