mirror of
https://github.com/langgenius/dify.git
synced 2026-05-06 02:18:08 +08:00
form
This commit is contained in:
@ -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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user