mirror of
https://github.com/langgenius/dify.git
synced 2026-05-12 15:58:19 +08:00
form
This commit is contained in:
parent
239e15eac6
commit
761ad336e9
@ -27,6 +27,10 @@ import ArrayValueList from '@/app/components/workflow/panel/chat-variable-panel/
|
||||
import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor'
|
||||
import { CodeLanguage } from '@/app/components/workflow/nodes/code/types'
|
||||
import Button from '@/app/components/base/button'
|
||||
import PromptGeneratorBtn from '@/app/components/workflow/nodes/llm/components/prompt-generator-btn'
|
||||
import Switch from '@/app/components/base/switch'
|
||||
import Slider from '@/app/components/base/slider'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
|
||||
export type BaseFieldProps = {
|
||||
fieldClassName?: string
|
||||
@ -62,6 +66,7 @@ const BaseField = ({
|
||||
help,
|
||||
selfFormProps,
|
||||
onChange,
|
||||
tooltip,
|
||||
} = formSchema
|
||||
const type = typeof typeOrFn === 'function' ? typeOrFn(field.form) : typeOrFn
|
||||
|
||||
@ -82,6 +87,13 @@ const BaseField = ({
|
||||
if (typeof placeholder === 'object' && placeholder !== null)
|
||||
return renderI18nObject(placeholder as Record<string, string>)
|
||||
}, [placeholder, renderI18nObject])
|
||||
const memorizedTooltip = useMemo(() => {
|
||||
if (typeof tooltip === 'string')
|
||||
return tooltip
|
||||
|
||||
if (typeof tooltip === 'object' && tooltip !== null)
|
||||
return renderI18nObject(tooltip as Record<string, string>)
|
||||
}, [tooltip, renderI18nObject])
|
||||
const optionValues = useStore(field.form.store, (s) => {
|
||||
const result: Record<string, any> = {}
|
||||
options?.forEach((option) => {
|
||||
@ -127,12 +139,26 @@ const BaseField = ({
|
||||
onChange?.(field.form, value)
|
||||
}, [field, onChange])
|
||||
|
||||
const selfProps = typeof selfFormProps === 'function' ? selfFormProps(field.form) : selfFormProps
|
||||
|
||||
if (!show)
|
||||
return null
|
||||
|
||||
return (
|
||||
<>
|
||||
{
|
||||
selfProps?.withTopDivider && (
|
||||
<div className='h-px w-full bg-divider-subtle' />
|
||||
)
|
||||
}
|
||||
<div className={cn(fieldClassName, formFieldClassName)}>
|
||||
<div className={cn(labelClassName, formLabelClassName)}>
|
||||
<div
|
||||
className={cn(type === FormTypeEnum.collapse && 'cursor-pointer', labelClassName, formLabelClassName)}
|
||||
onClick={() => {
|
||||
if (type === FormTypeEnum.collapse)
|
||||
handleChange(!value)
|
||||
}}
|
||||
>
|
||||
{memorizedLabel}
|
||||
{
|
||||
required && !isValidElement(label) && (
|
||||
@ -143,10 +169,9 @@ const BaseField = ({
|
||||
type === FormTypeEnum.collapse && (
|
||||
<RiArrowDownSFill
|
||||
className={cn(
|
||||
'h-4 w-4',
|
||||
value && 'rotate-180',
|
||||
'h-4 w-4 text-text-quaternary',
|
||||
value && '-rotate-90',
|
||||
)}
|
||||
onClick={() => handleChange(!value)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@ -159,10 +184,18 @@ const BaseField = ({
|
||||
onClick={() => handleChange(!value)}
|
||||
>
|
||||
{value ? <RiInputField className='mr-1 h-3.5 w-3.5' /> : <RiDraftLine className='mr-1 h-3.5 w-3.5' />}
|
||||
{selfFormProps?.(field.form)?.editModeLabel}
|
||||
{selfProps?.editModeLabel}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
{
|
||||
memorizedTooltip && (
|
||||
<Tooltip
|
||||
popupContent={memorizedTooltip}
|
||||
triggerClassName='ml-1 w-4 h-4'
|
||||
/>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
<div className={cn(inputContainerClassName, formInputContainerClassName)}>
|
||||
{
|
||||
@ -195,7 +228,7 @@ const BaseField = ({
|
||||
)
|
||||
}
|
||||
{
|
||||
type === FormTypeEnum.textNumber && (
|
||||
type === FormTypeEnum.textNumber && !selfProps?.withSlider && (
|
||||
<Input
|
||||
id={field.name}
|
||||
name={field.name}
|
||||
@ -209,6 +242,34 @@ const BaseField = ({
|
||||
/>
|
||||
)
|
||||
}
|
||||
{
|
||||
type === FormTypeEnum.textNumber && selfProps?.withSlider && (
|
||||
<div className='flex items-center space-x-2'>
|
||||
<Slider
|
||||
min={selfProps?.sliderMin}
|
||||
max={selfProps?.sliderMax}
|
||||
step={selfProps?.sliderStep}
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
className={cn(selfProps.sliderClassName)}
|
||||
trackClassName={cn(selfProps.sliderTrackClassName)}
|
||||
thumbClassName={cn(selfProps.sliderThumbClassName)}
|
||||
/>
|
||||
<Input
|
||||
id={field.name}
|
||||
name={field.name}
|
||||
type='number'
|
||||
className={cn('', inputClassName, formInputClassName)}
|
||||
wrapperClassName={cn(selfProps.inputWrapperClassName)}
|
||||
value={value || ''}
|
||||
onChange={e => handleChange(e.target.value)}
|
||||
onBlur={field.handleBlur}
|
||||
disabled={disabled}
|
||||
placeholder={memorizedPlaceholder}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
{
|
||||
type === FormTypeEnum.select && (
|
||||
<PureSelect
|
||||
@ -239,7 +300,7 @@ const BaseField = ({
|
||||
onClick={() => handleChange(option.value)}
|
||||
>
|
||||
{
|
||||
selfFormProps?.(field.form)?.showRadioUI && (
|
||||
selfProps?.showRadioUI && (
|
||||
<RadioE
|
||||
className='mr-2'
|
||||
isChecked={value === option.value}
|
||||
@ -271,18 +332,34 @@ const BaseField = ({
|
||||
}
|
||||
{
|
||||
type === FormTypeEnum.promptInput && (
|
||||
<PromptEditor
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
onBlur={field.handleBlur}
|
||||
editable={!disabled}
|
||||
placeholder={memorizedPlaceholder}
|
||||
className={cn(
|
||||
'min-h-[80px]',
|
||||
inputClassName,
|
||||
formInputClassName,
|
||||
)}
|
||||
/>
|
||||
<div className={cn(
|
||||
'relative rounded-lg bg-components-input-bg-normal p-2',
|
||||
formInputContainerClassName,
|
||||
)}>
|
||||
{
|
||||
selfProps?.enablePromptGenerator && (
|
||||
<PromptGeneratorBtn
|
||||
nodeId={selfProps?.nodeId}
|
||||
className='absolute right-0 top-[-26px]'
|
||||
onGenerated={handleChange}
|
||||
modelConfig={selfProps?.modelConfig}
|
||||
currentPrompt={value}
|
||||
/>
|
||||
)
|
||||
}
|
||||
<PromptEditor
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
onBlur={field.handleBlur}
|
||||
editable={!disabled}
|
||||
placeholder={memorizedPlaceholder || selfProps?.placeholder}
|
||||
className={cn(
|
||||
'min-h-[80px]',
|
||||
inputClassName,
|
||||
formInputClassName,
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
{
|
||||
@ -296,7 +373,7 @@ const BaseField = ({
|
||||
{
|
||||
type === FormTypeEnum.arrayList && (
|
||||
<ArrayValueList
|
||||
isString={selfFormProps?.(field.form)?.isString}
|
||||
isString={selfProps?.isString}
|
||||
list={value}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
@ -304,13 +381,13 @@ const BaseField = ({
|
||||
}
|
||||
{
|
||||
type === FormTypeEnum.jsonInput && (
|
||||
<div className='w-full rounded-[10px] bg-components-input-bg-normal py-2 pl-3 pr-1' style={{ height: selfFormProps?.(field.form)?.editorMinHeight }}>
|
||||
<div className='w-full rounded-[10px] bg-components-input-bg-normal py-2 pl-3 pr-1' style={{ height: selfProps?.editorMinHeight }}>
|
||||
<CodeEditor
|
||||
isExpand
|
||||
noWrapper
|
||||
language={CodeLanguage.json}
|
||||
value={value}
|
||||
placeholder={<div className='whitespace-pre'>{selfFormProps?.(field.form)?.placeholder as string}</div>}
|
||||
placeholder={<div className='whitespace-pre'>{selfProps?.placeholder as string}</div>}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
@ -328,6 +405,15 @@ const BaseField = ({
|
||||
/>
|
||||
)
|
||||
}
|
||||
{
|
||||
type === FormTypeEnum.boolean && (
|
||||
<Switch
|
||||
defaultValue={value}
|
||||
onChange={handleChange}
|
||||
disabled={disabled}
|
||||
/>
|
||||
)
|
||||
}
|
||||
{
|
||||
url && (
|
||||
<a
|
||||
@ -346,6 +432,12 @@ const BaseField = ({
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
{
|
||||
selfProps?.withBottomDivider && (
|
||||
<div className='h-px w-full bg-divider-subtle' />
|
||||
)
|
||||
}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ -68,7 +68,7 @@ export type FormSchema = {
|
||||
inputContainerClassName?: string
|
||||
inputClassName?: string
|
||||
validators?: AnyValidators
|
||||
selfFormProps?: (form: AnyFormApi) => Record<string, any>
|
||||
selfFormProps?: ((form: AnyFormApi) => Record<string, any>) | Record<string, any>
|
||||
onChange?: (form: AnyFormApi, v: any) => void
|
||||
}
|
||||
|
||||
|
||||
@ -40,7 +40,7 @@ const ChatVariableModal = ({
|
||||
const form = useTanstackForm({
|
||||
defaultValues,
|
||||
})
|
||||
const type = useTanstackStore(form.store, s => s.values.type)
|
||||
const type = useTanstackStore(form.store, (s: any) => s.values.value_type)
|
||||
|
||||
const checkVariableName = (value: string) => {
|
||||
const { isValid, errorMessageKey } = checkKeys([value], false)
|
||||
@ -57,19 +57,23 @@ const ChatVariableModal = ({
|
||||
const handleConfirm = useCallback(async () => {
|
||||
const {
|
||||
values,
|
||||
isCheckValidated,
|
||||
} = formRef.current?.getFormValues({
|
||||
needCheckValidatedValues: true,
|
||||
}) || { isCheckValidated: false, values: {} }
|
||||
const {
|
||||
name,
|
||||
type,
|
||||
'object-list-value': objectValue,
|
||||
value,
|
||||
} = values
|
||||
console.log(values, 'xxx')
|
||||
if (!isCheckValidated)
|
||||
return
|
||||
if (!checkVariableName(name))
|
||||
return
|
||||
if (!chatVar && varList.some(chatVar => chatVar.name === name))
|
||||
return notify({ type: 'error', message: 'name is existed' })
|
||||
if (type === ChatVarType.Object && objectValue.some((item: any) => !item.key && !!item.value))
|
||||
if (type === ChatVarType.Object && value.some((item: any) => !item.key && !!item.value))
|
||||
return notify({ type: 'error', message: 'object key can not be empty' })
|
||||
|
||||
// onSave({
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { ChatVarType } from './type'
|
||||
import { DEFAULT_OBJECT_VALUE } from '@/app/components/workflow/panel/chat-variable-panel/components/object-value-item'
|
||||
|
||||
export const objectPlaceholder = `# example
|
||||
# {
|
||||
@ -33,5 +34,12 @@ export const typeList = [
|
||||
ChatVarType.ArrayString,
|
||||
ChatVarType.ArrayNumber,
|
||||
ChatVarType.ArrayObject,
|
||||
'memory',
|
||||
ChatVarType.Memory,
|
||||
]
|
||||
|
||||
export const TYPE_STRING_DEFAULT_VALUE = ''
|
||||
export const TYPE_NUMBER_DEFAULT_VALUE = 0
|
||||
export const TYPE_OBJECT_DEFAULT_VALUE = [DEFAULT_OBJECT_VALUE]
|
||||
export const TYPE_ARRAY_STRING_DEFAULT_VALUE = [undefined]
|
||||
export const TYPE_ARRAY_NUMBER_DEFAULT_VALUE = [undefined]
|
||||
export const TYPE_ARRAY_OBJECT_DEFAULT_VALUE = undefined
|
||||
|
||||
@ -4,13 +4,20 @@ import { useMemo } from 'react'
|
||||
import { useTypeSchema } from './use-type-schema'
|
||||
import { useValueSchema } from './use-value-schema'
|
||||
import { useEditInJSONSchema } from './use-edit-in-json-schema'
|
||||
import {
|
||||
useMemoryDefaultValues,
|
||||
useMemorySchema,
|
||||
} from './use-memory-schema'
|
||||
import type { ConversationVariable } from '@/app/components/workflow/types'
|
||||
|
||||
export const useForm = () => {
|
||||
export const useForm = (chatVar?: ConversationVariable) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const typeSchema = useTypeSchema()
|
||||
const valueSchema = useValueSchema()
|
||||
const editInJSONSchema = useEditInJSONSchema()
|
||||
const memorySchema = useMemorySchema()
|
||||
const memoryDefaultValues = useMemoryDefaultValues()
|
||||
|
||||
const formSchemas = useMemo(() => {
|
||||
return [
|
||||
@ -24,15 +31,31 @@ export const useForm = () => {
|
||||
typeSchema,
|
||||
editInJSONSchema,
|
||||
valueSchema,
|
||||
{
|
||||
name: 'description',
|
||||
label: t('workflow.chatVariable.modal.description'),
|
||||
type: 'textarea-input',
|
||||
placeholder: t('workflow.chatVariable.modal.descriptionPlaceholder'),
|
||||
show_on: [
|
||||
{
|
||||
variable: 'value_type',
|
||||
value: [ChatVarType.String, ChatVarType.Number, ChatVarType.Object, ChatVarType.ArrayString, ChatVarType.ArrayNumber, ChatVarType.ArrayObject],
|
||||
},
|
||||
],
|
||||
},
|
||||
...memorySchema,
|
||||
]
|
||||
}, [t, valueSchema, typeSchema, editInJSONSchema])
|
||||
}, [t, valueSchema, typeSchema, editInJSONSchema, memorySchema])
|
||||
const defaultValues = useMemo(() => {
|
||||
if (chatVar)
|
||||
return chatVar
|
||||
return {
|
||||
type: ChatVarType.String,
|
||||
value_type: ChatVarType.Memory,
|
||||
value: '',
|
||||
editInJSON: false,
|
||||
...memoryDefaultValues,
|
||||
}
|
||||
}, [])
|
||||
}, [chatVar])
|
||||
|
||||
return {
|
||||
formSchemas,
|
||||
|
||||
@ -4,30 +4,35 @@ import type {
|
||||
AnyFormApi,
|
||||
} from '@tanstack/react-form'
|
||||
import { ChatVarType } from '@/app/components/workflow/panel/chat-variable-panel/type'
|
||||
import { getValue } from '@/app/components/workflow/panel/chat-variable-panel/utils'
|
||||
|
||||
export const useEditInJSONSchema = () => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const getEditModeLabel = useCallback((form: AnyFormApi) => {
|
||||
const {
|
||||
type,
|
||||
value_type,
|
||||
editInJSON,
|
||||
} = form.state.values
|
||||
const editModeLabelWhenFalse = t('workflow.chatVariable.modal.editInJSON')
|
||||
let editModeLabelWhenTrue = t('workflow.chatVariable.modal.oneByOne')
|
||||
if (type === ChatVarType.Object)
|
||||
if (value_type === ChatVarType.Object)
|
||||
editModeLabelWhenTrue = t('workflow.chatVariable.modal.editInForm')
|
||||
|
||||
return {
|
||||
editModeLabel: editInJSON ? editModeLabelWhenTrue : editModeLabelWhenFalse,
|
||||
}
|
||||
}, [t])
|
||||
const handleEditInJSONChange = useCallback((form: AnyFormApi) => {
|
||||
const handleEditInJSONChange = useCallback((form: AnyFormApi, v: boolean) => {
|
||||
const {
|
||||
resetField,
|
||||
setFieldValue,
|
||||
getFieldValue,
|
||||
} = form
|
||||
resetField('objectListValue')
|
||||
resetField('arrayListValue')
|
||||
resetField('jsonValue')
|
||||
const type = getFieldValue('value_type')
|
||||
const value = getFieldValue('value')
|
||||
|
||||
const newValue = getValue(type, !v, value)
|
||||
setFieldValue('value', newValue)
|
||||
}, [])
|
||||
|
||||
return {
|
||||
@ -36,7 +41,7 @@ export const useEditInJSONSchema = () => {
|
||||
type: 'edit-mode',
|
||||
show_on: [
|
||||
{
|
||||
variable: 'type',
|
||||
variable: 'value_type',
|
||||
value: [ChatVarType.Object, ChatVarType.ArrayString, ChatVarType.ArrayNumber],
|
||||
},
|
||||
],
|
||||
|
||||
@ -0,0 +1,227 @@
|
||||
import { FormTypeEnum } from '@/app/components/base/form/types'
|
||||
import type { FormSchema } from '@/app/components/base/form/types'
|
||||
import { ChatVarType } from '@/app/components/workflow/panel/chat-variable-panel/type'
|
||||
|
||||
export const useMemorySchema = () => {
|
||||
return [
|
||||
{
|
||||
name: 'template',
|
||||
label: 'Memory Template',
|
||||
type: FormTypeEnum.promptInput,
|
||||
tooltip: 'template',
|
||||
placeholder: 'Enter template for AI memory (e.g., user profile, preferences, context)...',
|
||||
show_on: [
|
||||
{
|
||||
variable: 'value_type',
|
||||
value: [ChatVarType.Memory],
|
||||
},
|
||||
],
|
||||
selfFormProps: {
|
||||
withTopDivider: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'instruction',
|
||||
label: 'Update Instructions',
|
||||
type: FormTypeEnum.promptInput,
|
||||
show_on: [
|
||||
{
|
||||
variable: 'value_type',
|
||||
value: [ChatVarType.Memory],
|
||||
},
|
||||
],
|
||||
selfFormProps: {
|
||||
enablePromptGenerator: true,
|
||||
placeholder: 'How should the AI update this memory...',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'strategy',
|
||||
label: 'Update trigger',
|
||||
type: FormTypeEnum.radio,
|
||||
default: 'on_turns',
|
||||
fieldClassName: 'flex justify-between',
|
||||
inputClassName: 'w-[102px]',
|
||||
options: [
|
||||
{
|
||||
label: 'Every N turns',
|
||||
value: 'on_turns',
|
||||
},
|
||||
{
|
||||
label: 'Auto',
|
||||
value: 'on_auto',
|
||||
},
|
||||
],
|
||||
show_on: [
|
||||
{
|
||||
variable: 'value_type',
|
||||
value: [ChatVarType.Memory],
|
||||
},
|
||||
],
|
||||
selfFormProps: {
|
||||
withTopDivider: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'update_turns',
|
||||
label: 'Update every',
|
||||
type: FormTypeEnum.textNumber,
|
||||
fieldClassName: 'flex justify-between',
|
||||
show_on: [
|
||||
{
|
||||
variable: 'value_type',
|
||||
value: [ChatVarType.Memory],
|
||||
},
|
||||
{
|
||||
variable: 'strategy',
|
||||
value: 'on_turns',
|
||||
},
|
||||
],
|
||||
selfFormProps: {
|
||||
withSlider: true,
|
||||
sliderMin: 0,
|
||||
sliderMax: 1000,
|
||||
sliderStep: 50,
|
||||
sliderClassName: 'w-[98px]',
|
||||
inputWrapperClassName: 'w-[102px]',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'scope',
|
||||
label: 'Scope',
|
||||
type: FormTypeEnum.radio,
|
||||
default: 'app',
|
||||
fieldClassName: 'flex justify-between',
|
||||
inputClassName: 'w-[102px]',
|
||||
options: [
|
||||
{
|
||||
label: 'Conversation',
|
||||
value: 'conversation',
|
||||
},
|
||||
{
|
||||
label: 'App',
|
||||
value: 'app',
|
||||
},
|
||||
],
|
||||
show_on: [
|
||||
{
|
||||
variable: 'value_type',
|
||||
value: [ChatVarType.Memory],
|
||||
},
|
||||
],
|
||||
selfFormProps: {
|
||||
withTopDivider: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'term',
|
||||
label: 'Term',
|
||||
type: FormTypeEnum.radio,
|
||||
default: 'session',
|
||||
fieldClassName: 'flex justify-between',
|
||||
inputClassName: 'w-[102px]',
|
||||
options: [
|
||||
{
|
||||
label: 'Session',
|
||||
value: 'session',
|
||||
},
|
||||
{
|
||||
label: 'Persistent',
|
||||
value: 'persistent',
|
||||
},
|
||||
],
|
||||
show_on: [
|
||||
{
|
||||
variable: 'value_type',
|
||||
value: [ChatVarType.Memory],
|
||||
},
|
||||
],
|
||||
selfFormProps: {
|
||||
withBottomDivider: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'more',
|
||||
label: 'MoreSettings',
|
||||
type: FormTypeEnum.collapse,
|
||||
show_on: [
|
||||
{
|
||||
variable: 'value_type',
|
||||
value: [ChatVarType.Memory],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'model',
|
||||
label: 'Memory model',
|
||||
type: FormTypeEnum.modelSelector,
|
||||
show_on: [
|
||||
{
|
||||
variable: 'value_type',
|
||||
value: [ChatVarType.Memory],
|
||||
},
|
||||
{
|
||||
variable: 'more',
|
||||
value: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'schedule_mode',
|
||||
label: 'Update method',
|
||||
type: FormTypeEnum.radio,
|
||||
options: [
|
||||
{
|
||||
label: 'Sync',
|
||||
value: 'sync',
|
||||
},
|
||||
{
|
||||
label: 'Async',
|
||||
value: 'async',
|
||||
},
|
||||
],
|
||||
show_on: [
|
||||
{
|
||||
variable: 'value_type',
|
||||
value: [ChatVarType.Memory],
|
||||
},
|
||||
{
|
||||
variable: 'more',
|
||||
value: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'end_user_editable',
|
||||
label: 'Editable in web app',
|
||||
type: FormTypeEnum.boolean,
|
||||
fieldClassName: 'flex justify-between',
|
||||
show_on: [
|
||||
{
|
||||
variable: 'value_type',
|
||||
value: [ChatVarType.Memory],
|
||||
},
|
||||
{
|
||||
variable: 'more',
|
||||
value: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
] as FormSchema[]
|
||||
}
|
||||
|
||||
export const useMemoryDefaultValues = () => {
|
||||
return {
|
||||
template: '',
|
||||
instruction: '',
|
||||
strategy: 'on_turns',
|
||||
update_turns: 0,
|
||||
scope: 'conversation',
|
||||
term: 'session',
|
||||
more: false,
|
||||
model: '',
|
||||
schedule_mode: 'sync',
|
||||
end_user_visible: false,
|
||||
end_user_editable: false,
|
||||
}
|
||||
}
|
||||
@ -4,8 +4,15 @@ 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'
|
||||
import {
|
||||
TYPE_ARRAY_NUMBER_DEFAULT_VALUE,
|
||||
TYPE_ARRAY_OBJECT_DEFAULT_VALUE,
|
||||
TYPE_ARRAY_STRING_DEFAULT_VALUE,
|
||||
TYPE_NUMBER_DEFAULT_VALUE,
|
||||
TYPE_OBJECT_DEFAULT_VALUE,
|
||||
TYPE_STRING_DEFAULT_VALUE,
|
||||
} from '@/app/components/workflow/panel/chat-variable-panel/constants'
|
||||
|
||||
export const useTypeSchema = () => {
|
||||
const { t } = useTranslation()
|
||||
@ -13,22 +20,23 @@ export const useTypeSchema = () => {
|
||||
const {
|
||||
setFieldValue,
|
||||
} = form
|
||||
setFieldValue('editInJSON', false)
|
||||
if (v === ChatVarType.String)
|
||||
setFieldValue('value', '')
|
||||
setFieldValue('value', TYPE_STRING_DEFAULT_VALUE)
|
||||
else if (v === ChatVarType.Number)
|
||||
setFieldValue('value', 0)
|
||||
setFieldValue('value', TYPE_NUMBER_DEFAULT_VALUE)
|
||||
else if (v === ChatVarType.Object)
|
||||
setFieldValue('value', [DEFAULT_OBJECT_VALUE])
|
||||
setFieldValue('value', TYPE_OBJECT_DEFAULT_VALUE)
|
||||
else if (v === ChatVarType.ArrayString)
|
||||
setFieldValue('value', [undefined])
|
||||
setFieldValue('value', TYPE_ARRAY_STRING_DEFAULT_VALUE)
|
||||
else if (v === ChatVarType.ArrayNumber)
|
||||
setFieldValue('value', [undefined])
|
||||
setFieldValue('value', TYPE_ARRAY_NUMBER_DEFAULT_VALUE)
|
||||
else if (v === ChatVarType.ArrayObject)
|
||||
setFieldValue('value', undefined)
|
||||
setFieldValue('value', TYPE_ARRAY_OBJECT_DEFAULT_VALUE)
|
||||
}, [])
|
||||
|
||||
return {
|
||||
name: 'type',
|
||||
name: 'value_type',
|
||||
label: t('workflow.chatVariable.modal.type'),
|
||||
type: 'select',
|
||||
options: typeList.map(type => ({
|
||||
|
||||
@ -15,57 +15,57 @@ export const useValueSchema = () => {
|
||||
const { t } = useTranslation()
|
||||
const getValueFormType = useCallback((form: AnyFormApi) => {
|
||||
const {
|
||||
type,
|
||||
value_type,
|
||||
editInJSON,
|
||||
} = form.state.values
|
||||
console.log(editInJSON, 'editInJSON', type, 'type')
|
||||
if (type === ChatVarType.String) {
|
||||
|
||||
if (value_type === ChatVarType.String) {
|
||||
return 'textarea-input'
|
||||
}
|
||||
else if (type === ChatVarType.Number) {
|
||||
else if (value_type === ChatVarType.Number) {
|
||||
return 'number-input'
|
||||
}
|
||||
else if (type === ChatVarType.Object) {
|
||||
else if (value_type === ChatVarType.Object) {
|
||||
if (editInJSON)
|
||||
return 'json-input'
|
||||
else
|
||||
return 'object-list'
|
||||
}
|
||||
else if (type === ChatVarType.ArrayString || type === ChatVarType.ArrayNumber) {
|
||||
else if (value_type === ChatVarType.ArrayString || value_type === ChatVarType.ArrayNumber) {
|
||||
if (editInJSON)
|
||||
return 'json-input'
|
||||
else
|
||||
return 'array-list'
|
||||
}
|
||||
else if (type === ChatVarType.ArrayObject) {
|
||||
else if (value_type === ChatVarType.ArrayObject) {
|
||||
return 'json-input'
|
||||
}
|
||||
}, [])
|
||||
const getSelfFormProps = useCallback((form: AnyFormApi) => {
|
||||
const {
|
||||
type,
|
||||
value_type,
|
||||
editInJSON,
|
||||
} = form.state.values
|
||||
if (editInJSON || type === ChatVarType.ArrayObject) {
|
||||
if (editInJSON || value_type === ChatVarType.ArrayObject) {
|
||||
let minHeight = '120px'
|
||||
if (type === ChatVarType.ArrayObject)
|
||||
if (value_type === ChatVarType.ArrayObject)
|
||||
minHeight = '240px'
|
||||
let placeholder = objectPlaceholder
|
||||
if (type === ChatVarType.ArrayString)
|
||||
if (value_type === ChatVarType.ArrayString)
|
||||
placeholder = arrayStringPlaceholder
|
||||
else if (type === ChatVarType.ArrayNumber)
|
||||
else if (value_type === ChatVarType.ArrayNumber)
|
||||
placeholder = arrayNumberPlaceholder
|
||||
else if (type === ChatVarType.ArrayObject)
|
||||
else if (value_type === ChatVarType.ArrayObject)
|
||||
placeholder = arrayObjectPlaceholder
|
||||
return {
|
||||
editorMinHeight: minHeight,
|
||||
placeholder,
|
||||
}
|
||||
}
|
||||
if (type === ChatVarType.ArrayString || type === ChatVarType.ArrayNumber) {
|
||||
if (value_type === ChatVarType.ArrayString || value_type === ChatVarType.ArrayNumber) {
|
||||
if (!editInJSON) {
|
||||
return {
|
||||
isString: type === ChatVarType.ArrayString,
|
||||
isString: value_type === ChatVarType.ArrayString,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -78,12 +78,12 @@ export const useValueSchema = () => {
|
||||
placeholder: t('workflow.chatVariable.modal.valuePlaceholder'),
|
||||
show_on: [
|
||||
{
|
||||
variable: 'type',
|
||||
variable: 'value_type',
|
||||
value: [ChatVarType.String, ChatVarType.Number, ChatVarType.Object, ChatVarType.ArrayString, ChatVarType.ArrayNumber, ChatVarType.ArrayObject],
|
||||
},
|
||||
{
|
||||
variable: 'editInJSON',
|
||||
value: [true, false],
|
||||
value: [true, false, undefined],
|
||||
},
|
||||
],
|
||||
selfFormProps: getSelfFormProps,
|
||||
|
||||
@ -5,4 +5,11 @@ export enum ChatVarType {
|
||||
ArrayString = 'array[string]',
|
||||
ArrayNumber = 'array[number]',
|
||||
ArrayObject = 'array[object]',
|
||||
Memory = 'memory',
|
||||
}
|
||||
|
||||
export type ObjectValueItem = {
|
||||
key: string
|
||||
type: ChatVarType
|
||||
value: string | number | undefined
|
||||
}
|
||||
|
||||
@ -0,0 +1,66 @@
|
||||
import type { ObjectValueItem } from './type'
|
||||
import { ChatVarType } from './type'
|
||||
import {
|
||||
TYPE_ARRAY_STRING_DEFAULT_VALUE,
|
||||
TYPE_OBJECT_DEFAULT_VALUE,
|
||||
} from './constants'
|
||||
|
||||
const formatValueFromObject = (list: ObjectValueItem[]) => {
|
||||
return list.reduce((acc: any, curr) => {
|
||||
if (curr.key)
|
||||
acc[curr.key] = curr.value || null
|
||||
return acc
|
||||
}, {})
|
||||
}
|
||||
export const getObjectValue = (fromJson: boolean, value?: any) => {
|
||||
if (fromJson) {
|
||||
if (!value)
|
||||
return TYPE_OBJECT_DEFAULT_VALUE
|
||||
try {
|
||||
const result = JSON.parse(value)
|
||||
const newValue = Object.keys(result).map((key) => {
|
||||
return {
|
||||
key,
|
||||
type: typeof result[key] === 'string' ? ChatVarType.String : ChatVarType.Number,
|
||||
value: result[key],
|
||||
}
|
||||
})
|
||||
return newValue
|
||||
}
|
||||
catch {
|
||||
return TYPE_OBJECT_DEFAULT_VALUE
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!value)
|
||||
return undefined
|
||||
return JSON.stringify(formatValueFromObject(value))
|
||||
}
|
||||
}
|
||||
|
||||
export const getArrayValue = (fromJson: boolean, value?: any) => {
|
||||
if (fromJson) {
|
||||
if (!value)
|
||||
return TYPE_ARRAY_STRING_DEFAULT_VALUE
|
||||
|
||||
return JSON.parse(value)
|
||||
}
|
||||
else {
|
||||
if (!value)
|
||||
return undefined
|
||||
|
||||
return JSON.stringify((value?.length && value.filter(Boolean).length) ? value.filter(Boolean) : undefined)
|
||||
}
|
||||
}
|
||||
|
||||
export const getValue = (type: ChatVarType, fromJson: boolean, value?: any) => {
|
||||
switch (type) {
|
||||
case ChatVarType.Object:
|
||||
return getObjectValue(fromJson, value)
|
||||
case ChatVarType.ArrayNumber:
|
||||
case ChatVarType.ArrayString:
|
||||
return getArrayValue(fromJson, value)
|
||||
default:
|
||||
return value
|
||||
}
|
||||
}
|
||||
@ -156,13 +156,25 @@ export type EnvironmentVariable = {
|
||||
description: string
|
||||
}
|
||||
|
||||
export type MemoryVariable = {
|
||||
template?: string
|
||||
instruction?: string
|
||||
schedule_mode?: string
|
||||
model?: any
|
||||
strategy?: string
|
||||
update_turns?: number
|
||||
scope?: string
|
||||
term?: string
|
||||
end_user_editable?: boolean
|
||||
}
|
||||
|
||||
export type ConversationVariable = {
|
||||
id: string
|
||||
name: string
|
||||
value_type: ChatVarType
|
||||
value: any
|
||||
description: string
|
||||
}
|
||||
} & MemoryVariable
|
||||
|
||||
export type GlobalVariable = {
|
||||
name: string
|
||||
|
||||
Loading…
Reference in New Issue
Block a user