mirror of
http://112.124.100.131/huang.ze/ebiz-dify-ai.git
synced 2025-12-10 19:36:53 +08:00
195 lines
6.8 KiB
TypeScript
195 lines
6.8 KiB
TypeScript
'use client'
|
|
import type { FC } from 'react'
|
|
import React, { useCallback, useState } from 'react'
|
|
import { useTranslation } from 'react-i18next'
|
|
import { useContext } from 'use-context-selector'
|
|
import ModalFoot from '../modal-foot'
|
|
import ConfigSelect from '../config-select'
|
|
import ConfigString from '../config-string'
|
|
import SelectTypeItem from '../select-type-item'
|
|
import Field from './field'
|
|
import Toast from '@/app/components/base/toast'
|
|
import { checkKeys, getNewVarInWorkflow } from '@/utils/var'
|
|
import ConfigContext from '@/context/debug-configuration'
|
|
import type { InputVar, MoreInfo } from '@/app/components/workflow/types'
|
|
import Modal from '@/app/components/base/modal'
|
|
import Switch from '@/app/components/base/switch'
|
|
import { ChangeType, InputVarType } from '@/app/components/workflow/types'
|
|
|
|
const TEXT_MAX_LENGTH = 256
|
|
|
|
export type IConfigModalProps = {
|
|
isCreate?: boolean
|
|
payload?: InputVar
|
|
isShow: boolean
|
|
varKeys?: string[]
|
|
onClose: () => void
|
|
onConfirm: (newValue: InputVar, moreInfo?: MoreInfo) => void
|
|
}
|
|
|
|
const inputClassName = 'w-full px-3 text-sm leading-9 text-gray-900 border-0 rounded-lg grow h-9 bg-gray-100 focus:outline-none focus:ring-1 focus:ring-inset focus:ring-gray-200'
|
|
|
|
const ConfigModal: FC<IConfigModalProps> = ({
|
|
isCreate,
|
|
payload,
|
|
isShow,
|
|
onClose,
|
|
onConfirm,
|
|
}) => {
|
|
const { modelConfig } = useContext(ConfigContext)
|
|
const { t } = useTranslation()
|
|
const [tempPayload, setTempPayload] = useState<InputVar>(payload || getNewVarInWorkflow('') as any)
|
|
const { type, label, variable, options, max_length } = tempPayload
|
|
|
|
const isStringInput = type === InputVarType.textInput || type === InputVarType.paragraph
|
|
const checkVariableName = useCallback((value: string) => {
|
|
const { isValid, errorMessageKey } = checkKeys([value], false)
|
|
if (!isValid) {
|
|
Toast.notify({
|
|
type: 'error',
|
|
message: t(`appDebug.varKeyError.${errorMessageKey}`, { key: t('appDebug.variableConig.varName') }),
|
|
})
|
|
return false
|
|
}
|
|
return true
|
|
}, [t])
|
|
const handlePayloadChange = useCallback((key: string) => {
|
|
return (value: any) => {
|
|
setTempPayload((prev) => {
|
|
const newPayload = {
|
|
...prev,
|
|
[key]: value,
|
|
}
|
|
|
|
return newPayload
|
|
})
|
|
}
|
|
}, [])
|
|
|
|
const handleVarKeyBlur = useCallback((e: any) => {
|
|
const varName = e.target.value
|
|
if (!checkVariableName(varName) || tempPayload.label)
|
|
return
|
|
|
|
setTempPayload((prev) => {
|
|
return {
|
|
...prev,
|
|
label: varName,
|
|
}
|
|
})
|
|
}, [checkVariableName, tempPayload.label])
|
|
|
|
const handleConfirm = () => {
|
|
const moreInfo = tempPayload.variable === payload?.variable
|
|
? undefined
|
|
: {
|
|
type: ChangeType.changeVarName,
|
|
payload: { beforeKey: payload?.variable || '', afterKey: tempPayload.variable },
|
|
}
|
|
|
|
const isVariableNameValid = checkVariableName(tempPayload.variable)
|
|
if (!isVariableNameValid)
|
|
return
|
|
|
|
// TODO: check if key already exists. should the consider the edit case
|
|
// if (varKeys.map(key => key?.trim()).includes(tempPayload.variable.trim())) {
|
|
// Toast.notify({
|
|
// type: 'error',
|
|
// message: t('appDebug.varKeyError.keyAlreadyExists', { key: tempPayload.variable }),
|
|
// })
|
|
// return
|
|
// }
|
|
|
|
if (!tempPayload.label) {
|
|
Toast.notify({ type: 'error', message: t('appDebug.variableConig.errorMsg.labelNameRequired') })
|
|
return
|
|
}
|
|
if (isStringInput || type === InputVarType.number) {
|
|
onConfirm(tempPayload, moreInfo)
|
|
}
|
|
else {
|
|
if (options?.length === 0) {
|
|
Toast.notify({ type: 'error', message: t('appDebug.variableConig.errorMsg.atLeastOneOption') })
|
|
return
|
|
}
|
|
const obj: Record<string, boolean> = {}
|
|
let hasRepeatedItem = false
|
|
options?.forEach((o) => {
|
|
if (obj[o]) {
|
|
hasRepeatedItem = true
|
|
return
|
|
}
|
|
obj[o] = true
|
|
})
|
|
if (hasRepeatedItem) {
|
|
Toast.notify({ type: 'error', message: t('appDebug.variableConig.errorMsg.optionRepeat') })
|
|
return
|
|
}
|
|
onConfirm(tempPayload, moreInfo)
|
|
}
|
|
}
|
|
|
|
return (
|
|
<Modal
|
|
title={t(`appDebug.variableConig.${isCreate ? 'addModalTitle' : 'editModalTitle'}`)}
|
|
isShow={isShow}
|
|
onClose={onClose}
|
|
>
|
|
<div className='mb-8'>
|
|
<div className='space-y-2'>
|
|
|
|
<Field title={t('appDebug.variableConig.fieldType')}>
|
|
<div className='flex space-x-2'>
|
|
<SelectTypeItem type={InputVarType.textInput} selected={type === InputVarType.textInput} onClick={() => handlePayloadChange('type')(InputVarType.textInput)} />
|
|
<SelectTypeItem type={InputVarType.paragraph} selected={type === InputVarType.paragraph} onClick={() => handlePayloadChange('type')(InputVarType.paragraph)} />
|
|
<SelectTypeItem type={InputVarType.select} selected={type === InputVarType.select} onClick={() => handlePayloadChange('type')(InputVarType.select)} />
|
|
<SelectTypeItem type={InputVarType.number} selected={type === InputVarType.number} onClick={() => handlePayloadChange('type')(InputVarType.number)} />
|
|
</div>
|
|
</Field>
|
|
|
|
<Field title={t('appDebug.variableConig.varName')}>
|
|
<input
|
|
type='text'
|
|
className={inputClassName}
|
|
value={variable}
|
|
onChange={e => handlePayloadChange('variable')(e.target.value)}
|
|
onBlur={handleVarKeyBlur}
|
|
placeholder={t('appDebug.variableConig.inputPlaceholder')!}
|
|
/>
|
|
</Field>
|
|
<Field title={t('appDebug.variableConig.labelName')}>
|
|
<input
|
|
type='text'
|
|
className={inputClassName}
|
|
value={label as string}
|
|
onChange={e => handlePayloadChange('label')(e.target.value)}
|
|
placeholder={t('appDebug.variableConig.inputPlaceholder')!}
|
|
/>
|
|
</Field>
|
|
|
|
{isStringInput && (
|
|
<Field title={t('appDebug.variableConig.maxLength')}>
|
|
<ConfigString maxLength={type === InputVarType.textInput ? TEXT_MAX_LENGTH : Infinity} modelId={modelConfig.model_id} value={max_length} onChange={handlePayloadChange('max_length')} />
|
|
</Field>
|
|
|
|
)}
|
|
{type === InputVarType.select && (
|
|
<Field title={t('appDebug.variableConig.options')}>
|
|
<ConfigSelect options={options || []} onChange={handlePayloadChange('options')} />
|
|
</Field>
|
|
)}
|
|
|
|
<Field title={t('appDebug.variableConig.required')}>
|
|
<Switch defaultValue={tempPayload.required} onChange={handlePayloadChange('required')} />
|
|
</Field>
|
|
</div>
|
|
</div>
|
|
<ModalFoot
|
|
onConfirm={handleConfirm}
|
|
onCancel={onClose}
|
|
/>
|
|
</Modal>
|
|
)
|
|
}
|
|
export default React.memo(ConfigModal)
|