diff --git a/web/app/components/base/form/components/base/base-field.tsx b/web/app/components/base/form/components/base/base-field.tsx index 5da10ba78a..75b5cd3225 100644 --- a/web/app/components/base/form/components/base/base-field.tsx +++ b/web/app/components/base/form/components/base/base-field.tsx @@ -64,7 +64,6 @@ const BaseField = ({ onChange, } = formSchema const type = typeof typeOrFn === 'function' ? typeOrFn(field.form) : typeOrFn - console.log('type', field.name, type) const memorizedLabel = useMemo(() => { if (isValidElement(label)) @@ -120,13 +119,12 @@ const BaseField = ({ const show = useMemo(() => { return (Array.isArray(show_on) ? show_on : show_on(field.form)).every((condition) => { const conditionValue = values[condition.variable] - console.log('conditionValue', condition.value, field.name, conditionValue) return Array.isArray(condition.value) ? condition.value.includes(conditionValue) : conditionValue === condition.value }) }, [values, show_on, field.name]) const handleChange = useCallback((value: any) => { field.handleChange(value) - onChange?.(field.form) + onChange?.(field.form, value) }, [field, onChange]) if (!show) diff --git a/web/app/components/base/form/types.ts b/web/app/components/base/form/types.ts index eda37aa1ae..36137fda09 100644 --- a/web/app/components/base/form/types.ts +++ b/web/app/components/base/form/types.ts @@ -69,7 +69,7 @@ export type FormSchema = { inputClassName?: string validators?: AnyValidators selfFormProps?: (form: AnyFormApi) => Record - onChange?: (form: AnyFormApi) => void + onChange?: (form: AnyFormApi, v: any) => void } export type FormValues = Record diff --git a/web/app/components/workflow/panel/chat-variable-panel/components/variable-modal.tsx b/web/app/components/workflow/panel/chat-variable-panel/components/variable-modal.tsx index 32813c5d8e..9f9de880e4 100644 --- a/web/app/components/workflow/panel/chat-variable-panel/components/variable-modal.tsx +++ b/web/app/components/workflow/panel/chat-variable-panel/components/variable-modal.tsx @@ -57,7 +57,9 @@ const ChatVariableModal = ({ const handleConfirm = useCallback(async () => { const { values, - } = formRef.current?.getFormValues({}) || { isCheckValidated: false, values: {} } + } = formRef.current?.getFormValues({ + needCheckValidatedValues: true, + }) || { isCheckValidated: false, values: {} } const { name, type, diff --git a/web/app/components/workflow/panel/chat-variable-panel/constants.ts b/web/app/components/workflow/panel/chat-variable-panel/constants.ts new file mode 100644 index 0000000000..286d0f1c39 --- /dev/null +++ b/web/app/components/workflow/panel/chat-variable-panel/constants.ts @@ -0,0 +1,37 @@ +import { ChatVarType } from './type' + +export const objectPlaceholder = `# example +# { +# "name": "ray", +# "age": 20 +# }` +export const arrayStringPlaceholder = `# example +# [ +# "value1", +# "value2" +# ]` +export const arrayNumberPlaceholder = `# example +# [ +# 100, +# 200 +# ]` +export const arrayObjectPlaceholder = `# example +# [ +# { +# "name": "ray", +# "age": 20 +# }, +# { +# "name": "lily", +# "age": 18 +# } +# ]` +export const typeList = [ + ChatVarType.String, + ChatVarType.Number, + ChatVarType.Object, + ChatVarType.ArrayString, + ChatVarType.ArrayNumber, + ChatVarType.ArrayObject, + 'memory', +] diff --git a/web/app/components/workflow/panel/chat-variable-panel/hooks/use-form.ts b/web/app/components/workflow/panel/chat-variable-panel/hooks/use-form.ts deleted file mode 100644 index e0961bc422..0000000000 --- a/web/app/components/workflow/panel/chat-variable-panel/hooks/use-form.ts +++ /dev/null @@ -1,293 +0,0 @@ -import { useTranslation } from 'react-i18next' -import type { - AnyFormApi, -} from '@tanstack/react-form' -import { ChatVarType } from '@/app/components/workflow/panel/chat-variable-panel/type' -import { useCallback, useMemo } from 'react' -// import { DEFAULT_OBJECT_VALUE } from '@/app/components/workflow/panel/chat-variable-panel/components/object-value-item' -// import type { ConversationVariable } from '@/app/components/workflow/types' - -const objectPlaceholder = `# example -# { -# "name": "ray", -# "age": 20 -# }` -const arrayStringPlaceholder = `# example -# [ -# "value1", -# "value2" -# ]` -const arrayNumberPlaceholder = `# example -# [ -# 100, -# 200 -# ]` -const arrayObjectPlaceholder = `# example -# [ -# { -# "name": "ray", -# "age": 20 -# }, -# { -# "name": "lily", -# "age": 18 -# } -# ]` -const typeList = [ - ChatVarType.String, - ChatVarType.Number, - ChatVarType.Object, - ChatVarType.ArrayString, - ChatVarType.ArrayNumber, - ChatVarType.ArrayObject, - 'memory', -] - -export const useForm = () => { - const { t } = useTranslation() - const getEditModeLabel = useCallback((form: AnyFormApi) => { - const { - type, - editInJSON, - } = form.state.values - const editModeLabelWhenFalse = t('workflow.chatVariable.modal.editInJSON') - let editModeLabelWhenTrue = t('workflow.chatVariable.modal.oneByOne') - if (type === ChatVarType.Object) - editModeLabelWhenTrue = t('workflow.chatVariable.modal.editInForm') - - return { - editModeLabel: editInJSON ? editModeLabelWhenTrue : editModeLabelWhenFalse, - } - }, [t]) - const handleTypeChange = useCallback((form: AnyFormApi) => { - const { - resetField, - } = form - resetField('editInJSON') - resetField('objectListValue') - resetField('arrayListValue') - resetField('jsonValue') - }, []) - const handleEditInJSONChange = useCallback((form: AnyFormApi) => { - const { - resetField, - } = form - resetField('objectListValue') - resetField('arrayListValue') - resetField('jsonValue') - }, []) - - const getValueFormType = useCallback((form: AnyFormApi) => { - const { - type, - editInJSON, - } = form.state.values - if (type === ChatVarType.String) { - return 'textarea-input' - } - else if (type === ChatVarType.Number) { - return 'number-input' - } - else if (type === ChatVarType.Object) { - if (editInJSON) - return 'json-input' - else - return 'object-list' - } - else if (type === ChatVarType.ArrayString || type === ChatVarType.ArrayNumber) { - if (editInJSON) - return 'json-input' - else - return 'array-list' - } - else if (type === ChatVarType.ArrayObject) { - return 'json-input' - } - }, []) - const getSelfFormProps = useCallback((form: AnyFormApi) => { - const { - type, - editInJSON, - } = form.state.values - if (editInJSON || type === ChatVarType.ArrayObject) { - let minHeight = '120px' - if (type === ChatVarType.ArrayObject) - minHeight = '240px' - let placeholder = objectPlaceholder - if (type === ChatVarType.ArrayString) - placeholder = arrayStringPlaceholder - else if (type === ChatVarType.ArrayNumber) - placeholder = arrayNumberPlaceholder - else if (type === ChatVarType.ArrayObject) - placeholder = arrayObjectPlaceholder - return { - editorMinHeight: minHeight, - placeholder, - } - } - if (type === ChatVarType.ArrayString || type === ChatVarType.ArrayNumber) { - if (!editInJSON) { - return { - isString: type === ChatVarType.ArrayString, - } - } - } - }, []) - - const formSchemas = useMemo(() => { - return [ - { - name: 'name', - label: t('workflow.chatVariable.modal.name'), - type: 'text-input', - placeholder: t('workflow.chatVariable.modal.namePlaceholder'), - required: true, - }, - { - name: 'type', - label: t('workflow.chatVariable.modal.type'), - type: 'select', - options: typeList.map(type => ({ - label: type, - value: type, - })), - onChange: handleTypeChange, - required: true, - }, - { - name: 'editInJSON', - label: '', - type: 'edit-mode', - show_on: [ - { - variable: 'type', - value: [ChatVarType.Object, ChatVarType.ArrayString, ChatVarType.ArrayNumber], - }, - ], - selfFormProps: getEditModeLabel, - labelClassName: '-mb-9 justify-end', - onChange: handleEditInJSONChange, - }, - { - name: 'value', - label: t('workflow.chatVariable.modal.value'), - type: getValueFormType, - placeholder: t('workflow.chatVariable.modal.valuePlaceholder'), - show_on: [ - { - variable: 'type', - value: [ChatVarType.String, ChatVarType.Number, ChatVarType.Object, ChatVarType.ArrayString, ChatVarType.ArrayNumber, ChatVarType.ArrayObject], - }, - ], - selfFormProps: getSelfFormProps, - }, - // { - // name: 'objectListValue', - // label: t('workflow.chatVariable.modal.value'), - // type: 'object-list', - // placeholder: t('workflow.chatVariable.modal.valuePlaceholder'), - // show_on: [ - // { - // variable: 'type', - // value: ChatVarType.Object, - // }, - // { - // variable: 'editInJSON', - // value: false, - // }, - // ], - // }, - // { - // name: 'arrayListValue', - // label: t('workflow.chatVariable.modal.value'), - // type: 'array-list', - // placeholder: t('workflow.chatVariable.modal.valuePlaceholder'), - // show_on: [ - // { - // variable: 'type', - // value: [ChatVarType.ArrayString, ChatVarType.ArrayNumber], - // }, - // { - // variable: 'editInJSON', - // value: false, - // }, - // ], - // selfFormProps: getArrayListProps, - // }, - // { - // name: 'jsonValue', - // label: t('workflow.chatVariable.modal.value'), - // type: 'json-input', - // placeholder: arrayObjectPlaceholder, - // show_on: getJsonEditorShowOn, - // selfFormProps: getJsonEditorProps, - // }, - // { - // name: 'description', - // label: t('workflow.chatVariable.modal.description'), - // type: 'textarea-input', - // placeholder: t('workflow.chatVariable.modal.descriptionPlaceholder'), - // show_on: [ - // { - // variable: 'type', - // value: [ChatVarType.String, ChatVarType.Number, ChatVarType.Object, ChatVarType.ArrayString, ChatVarType.ArrayNumber, ChatVarType.ArrayObject], - // }, - // ], - // }, - // { - // name: 'memoryTemplate', - // label: 'Memory template', - // type: 'prompt-input', - // }, - // { - // name: 'updateTrigger', - // label: 'Update trigger', - // type: 'radio', - // required: true, - // fieldClassName: 'flex items-center justify-between', - // options: [ - // { - // label: 'Every N turns', - // value: 'every_n_turns', - // }, - // { - // label: 'Auto', - // value: 'auto', - // }, - // ], - // }, - // { - // name: 'moreSettings', - // label: 'More settings', - // type: 'collapse', - // }, - // { - // name: 'memoryModel', - // label: 'Memory model', - // type: 'model-selector', - // show_on: [ - // { - // variable: 'moreSettings', - // value: true, - // }, - // ], - // }, - ] - }, [t, handleTypeChange, handleEditInJSONChange, getValueFormType, getSelfFormProps]) - const defaultValues = useMemo(() => { - return { - type: ChatVarType.String, - value: '', - // textareaInputValue: '', - // numberInputValue: 0, - // objectListValue: [DEFAULT_OBJECT_VALUE], - // arrayListValue: [undefined], - editInJSON: false, - } - }, []) - - return { - formSchemas, - defaultValues, - } -} diff --git a/web/app/components/workflow/panel/chat-variable-panel/hooks/use-form/index.ts b/web/app/components/workflow/panel/chat-variable-panel/hooks/use-form/index.ts new file mode 100644 index 0000000000..12b89caeea --- /dev/null +++ b/web/app/components/workflow/panel/chat-variable-panel/hooks/use-form/index.ts @@ -0,0 +1,41 @@ +import { useTranslation } from 'react-i18next' +import { ChatVarType } from '@/app/components/workflow/panel/chat-variable-panel/type' +import { useMemo } from 'react' +import { useTypeSchema } from './use-type-schema' +import { useValueSchema } from './use-value-schema' +import { useEditInJSONSchema } from './use-edit-in-json-schema' + +export const useForm = () => { + const { t } = useTranslation() + + const typeSchema = useTypeSchema() + const valueSchema = useValueSchema() + const editInJSONSchema = useEditInJSONSchema() + + const formSchemas = useMemo(() => { + return [ + { + name: 'name', + label: t('workflow.chatVariable.modal.name'), + type: 'text-input', + placeholder: t('workflow.chatVariable.modal.namePlaceholder'), + required: true, + }, + typeSchema, + editInJSONSchema, + valueSchema, + ] + }, [t, valueSchema, typeSchema, editInJSONSchema]) + const defaultValues = useMemo(() => { + return { + type: ChatVarType.String, + value: '', + editInJSON: false, + } + }, []) + + return { + formSchemas, + defaultValues, + } +} diff --git a/web/app/components/workflow/panel/chat-variable-panel/hooks/use-form/use-edit-in-json-schema.ts b/web/app/components/workflow/panel/chat-variable-panel/hooks/use-form/use-edit-in-json-schema.ts new file mode 100644 index 0000000000..4b5e3e9836 --- /dev/null +++ b/web/app/components/workflow/panel/chat-variable-panel/hooks/use-form/use-edit-in-json-schema.ts @@ -0,0 +1,47 @@ +import { useCallback } from 'react' +import { useTranslation } from 'react-i18next' +import type { + AnyFormApi, +} from '@tanstack/react-form' +import { ChatVarType } from '@/app/components/workflow/panel/chat-variable-panel/type' + +export const useEditInJSONSchema = () => { + const { t } = useTranslation() + const getEditModeLabel = useCallback((form: AnyFormApi) => { + const { + type, + editInJSON, + } = form.state.values + const editModeLabelWhenFalse = t('workflow.chatVariable.modal.editInJSON') + let editModeLabelWhenTrue = t('workflow.chatVariable.modal.oneByOne') + if (type === ChatVarType.Object) + editModeLabelWhenTrue = t('workflow.chatVariable.modal.editInForm') + + return { + editModeLabel: editInJSON ? editModeLabelWhenTrue : editModeLabelWhenFalse, + } + }, [t]) + const handleEditInJSONChange = useCallback((form: AnyFormApi) => { + const { + resetField, + } = form + resetField('objectListValue') + resetField('arrayListValue') + resetField('jsonValue') + }, []) + + return { + name: 'editInJSON', + label: '', + type: 'edit-mode', + show_on: [ + { + variable: 'type', + value: [ChatVarType.Object, ChatVarType.ArrayString, ChatVarType.ArrayNumber], + }, + ], + selfFormProps: getEditModeLabel, + labelClassName: '-mb-9 justify-end', + onChange: handleEditInJSONChange, + } +} diff --git a/web/app/components/workflow/panel/chat-variable-panel/hooks/use-form/use-type-schema.ts b/web/app/components/workflow/panel/chat-variable-panel/hooks/use-form/use-type-schema.ts new file mode 100644 index 0000000000..254b0bbc65 --- /dev/null +++ b/web/app/components/workflow/panel/chat-variable-panel/hooks/use-form/use-type-schema.ts @@ -0,0 +1,41 @@ +import { useCallback } from 'react' +import { useTranslation } from 'react-i18next' +import type { + AnyFormApi, +} from '@tanstack/react-form' +import { ChatVarType } from '@/app/components/workflow/panel/chat-variable-panel/type' +import { DEFAULT_OBJECT_VALUE } from '@/app/components/workflow/panel/chat-variable-panel/components/object-value-item' +import { typeList } from '@/app/components/workflow/panel/chat-variable-panel/constants' + +export const useTypeSchema = () => { + const { t } = useTranslation() + const handleTypeChange = useCallback((form: AnyFormApi, v: string) => { + const { + setFieldValue, + } = form + if (v === ChatVarType.String) + setFieldValue('value', '') + else if (v === ChatVarType.Number) + setFieldValue('value', 0) + else if (v === ChatVarType.Object) + setFieldValue('value', [DEFAULT_OBJECT_VALUE]) + else if (v === ChatVarType.ArrayString) + setFieldValue('value', [undefined]) + else if (v === ChatVarType.ArrayNumber) + setFieldValue('value', [undefined]) + else if (v === ChatVarType.ArrayObject) + setFieldValue('value', undefined) + }, []) + + return { + name: 'type', + label: t('workflow.chatVariable.modal.type'), + type: 'select', + options: typeList.map(type => ({ + label: type, + value: type, + })), + onChange: handleTypeChange, + required: true, + } +} diff --git a/web/app/components/workflow/panel/chat-variable-panel/hooks/use-form/use-value-schema.ts b/web/app/components/workflow/panel/chat-variable-panel/hooks/use-form/use-value-schema.ts new file mode 100644 index 0000000000..3fb7ecf769 --- /dev/null +++ b/web/app/components/workflow/panel/chat-variable-panel/hooks/use-form/use-value-schema.ts @@ -0,0 +1,91 @@ +import { useCallback } from 'react' +import { useTranslation } from 'react-i18next' +import type { + AnyFormApi, +} from '@tanstack/react-form' +import { ChatVarType } from '@/app/components/workflow/panel/chat-variable-panel/type' +import { + arrayNumberPlaceholder, + arrayObjectPlaceholder, + arrayStringPlaceholder, + objectPlaceholder, +} from '@/app/components/workflow/panel/chat-variable-panel/constants' + +export const useValueSchema = () => { + const { t } = useTranslation() + const getValueFormType = useCallback((form: AnyFormApi) => { + const { + type, + editInJSON, + } = form.state.values + console.log(editInJSON, 'editInJSON', type, 'type') + if (type === ChatVarType.String) { + return 'textarea-input' + } + else if (type === ChatVarType.Number) { + return 'number-input' + } + else if (type === ChatVarType.Object) { + if (editInJSON) + return 'json-input' + else + return 'object-list' + } + else if (type === ChatVarType.ArrayString || type === ChatVarType.ArrayNumber) { + if (editInJSON) + return 'json-input' + else + return 'array-list' + } + else if (type === ChatVarType.ArrayObject) { + return 'json-input' + } + }, []) + const getSelfFormProps = useCallback((form: AnyFormApi) => { + const { + type, + editInJSON, + } = form.state.values + if (editInJSON || type === ChatVarType.ArrayObject) { + let minHeight = '120px' + if (type === ChatVarType.ArrayObject) + minHeight = '240px' + let placeholder = objectPlaceholder + if (type === ChatVarType.ArrayString) + placeholder = arrayStringPlaceholder + else if (type === ChatVarType.ArrayNumber) + placeholder = arrayNumberPlaceholder + else if (type === ChatVarType.ArrayObject) + placeholder = arrayObjectPlaceholder + return { + editorMinHeight: minHeight, + placeholder, + } + } + if (type === ChatVarType.ArrayString || type === ChatVarType.ArrayNumber) { + if (!editInJSON) { + return { + isString: type === ChatVarType.ArrayString, + } + } + } + }, []) + + return { + name: 'value', + label: t('workflow.chatVariable.modal.value'), + type: getValueFormType, + placeholder: t('workflow.chatVariable.modal.valuePlaceholder'), + show_on: [ + { + variable: 'type', + value: [ChatVarType.String, ChatVarType.Number, ChatVarType.Object, ChatVarType.ArrayString, ChatVarType.ArrayNumber, ChatVarType.ArrayObject], + }, + { + variable: 'editInJSON', + value: [true, false], + }, + ], + selfFormProps: getSelfFormProps, + } +}