mirror of https://github.com/langgenius/dify.git
form
This commit is contained in:
parent
fd0a8d5834
commit
2572e99a4b
|
|
@ -99,7 +99,7 @@ const BaseField = ({
|
|||
id={field.name}
|
||||
name={field.name}
|
||||
className={cn(inputClassName)}
|
||||
value={value}
|
||||
value={value || ''}
|
||||
onChange={e => field.handleChange(e.target.value)}
|
||||
onBlur={field.handleBlur}
|
||||
disabled={disabled}
|
||||
|
|
@ -114,7 +114,7 @@ const BaseField = ({
|
|||
name={field.name}
|
||||
type='password'
|
||||
className={cn(inputClassName)}
|
||||
value={value}
|
||||
value={value || ''}
|
||||
onChange={e => field.handleChange(e.target.value)}
|
||||
onBlur={field.handleBlur}
|
||||
disabled={disabled}
|
||||
|
|
@ -129,7 +129,7 @@ const BaseField = ({
|
|||
name={field.name}
|
||||
type='number'
|
||||
className={cn(inputClassName)}
|
||||
value={value}
|
||||
value={value || ''}
|
||||
onChange={e => field.handleChange(e.target.value)}
|
||||
onBlur={field.handleBlur}
|
||||
disabled={disabled}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import {
|
|||
import type {
|
||||
AnyFieldApi,
|
||||
} from '@tanstack/react-form'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useForm } from '@tanstack/react-form'
|
||||
import type {
|
||||
FormRef,
|
||||
|
|
@ -18,6 +19,7 @@ import type {
|
|||
BaseFieldProps,
|
||||
} from '.'
|
||||
import cn from '@/utils/classnames'
|
||||
import { useGetFormValues } from '@/app/components/base/form/hooks'
|
||||
|
||||
export type BaseFormProps = {
|
||||
formSchemas?: FormSchema[]
|
||||
|
|
@ -28,7 +30,7 @@ export type BaseFormProps = {
|
|||
} & Pick<BaseFieldProps, 'fieldClassName' | 'labelClassName' | 'inputContainerClassName' | 'inputClassName'>
|
||||
|
||||
const BaseForm = ({
|
||||
formSchemas,
|
||||
formSchemas = [],
|
||||
defaultValues,
|
||||
formClassName,
|
||||
fieldClassName,
|
||||
|
|
@ -38,17 +40,22 @@ const BaseForm = ({
|
|||
ref,
|
||||
disabled,
|
||||
}: BaseFormProps) => {
|
||||
const { t } = useTranslation()
|
||||
const form = useForm({
|
||||
defaultValues,
|
||||
})
|
||||
const { getFormValues } = useGetFormValues(form)
|
||||
|
||||
useImperativeHandle(ref, () => {
|
||||
return {
|
||||
getForm() {
|
||||
return form
|
||||
},
|
||||
getFormValues: (option) => {
|
||||
return getFormValues(formSchemas, option)
|
||||
},
|
||||
}
|
||||
}, [form])
|
||||
}, [form, formSchemas, getFormValues])
|
||||
|
||||
const renderField = useCallback((field: AnyFieldApi) => {
|
||||
const formSchema = formSchemas?.find(schema => schema.name === field.name)
|
||||
|
|
@ -73,17 +80,37 @@ const BaseForm = ({
|
|||
const renderFieldWrapper = useCallback((formSchema: FormSchema) => {
|
||||
const {
|
||||
name,
|
||||
validators,
|
||||
required,
|
||||
} = formSchema
|
||||
let mergedValidators = validators
|
||||
if (required && !validators) {
|
||||
mergedValidators = {
|
||||
onMount: ({ value }: any) => {
|
||||
if (!value)
|
||||
return t('common.errorMsg.fieldRequired', { field: name })
|
||||
},
|
||||
onChange: ({ value }: any) => {
|
||||
if (!value)
|
||||
return t('common.errorMsg.fieldRequired', { field: name })
|
||||
},
|
||||
onBlur: ({ value }: any) => {
|
||||
if (!value)
|
||||
return t('common.errorMsg.fieldRequired', { field: name })
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<form.Field
|
||||
key={name}
|
||||
name={name}
|
||||
validators={mergedValidators}
|
||||
>
|
||||
{renderField}
|
||||
</form.Field>
|
||||
)
|
||||
}, [renderField, form])
|
||||
}, [renderField, form, t])
|
||||
|
||||
if (!formSchemas?.length)
|
||||
return null
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
export * from './use-check-validated'
|
||||
export * from './use-get-form-values'
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
import { useCallback } from 'react'
|
||||
import type { AnyFormApi } from '@tanstack/react-form'
|
||||
import { useToastContext } from '@/app/components/base/toast'
|
||||
|
||||
export const useCheckValidated = (form: AnyFormApi) => {
|
||||
const { notify } = useToastContext()
|
||||
|
||||
const checkValidated = useCallback(() => {
|
||||
const allError = form?.getAllErrors()
|
||||
|
||||
if (allError) {
|
||||
const fields = allError.fields
|
||||
const errorArray = Object.keys(fields).reduce((acc: string[], key: string) => {
|
||||
const errors: any[] = fields[key].errors
|
||||
|
||||
return [...acc, ...errors]
|
||||
}, [] as string[])
|
||||
|
||||
if (errorArray.length) {
|
||||
notify({
|
||||
type: 'error',
|
||||
message: errorArray[0],
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
return true
|
||||
}, [form, notify])
|
||||
|
||||
return {
|
||||
checkValidated,
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
import { useCallback } from 'react'
|
||||
import type { AnyFormApi } from '@tanstack/react-form'
|
||||
import { useCheckValidated } from './use-check-validated'
|
||||
import type {
|
||||
FormSchema,
|
||||
GetValuesOptions,
|
||||
} from '../types'
|
||||
import { getTransformedValuesWhenSecretInputPristine } from '../utils'
|
||||
|
||||
export const useGetFormValues = (form: AnyFormApi) => {
|
||||
const { checkValidated } = useCheckValidated(form)
|
||||
|
||||
const getFormValues = useCallback((
|
||||
formSchemas: FormSchema[],
|
||||
{
|
||||
needCheckValidatedValues,
|
||||
needTransformWhenSecretFieldIsPristine,
|
||||
}: GetValuesOptions,
|
||||
) => {
|
||||
const values = form?.store.state.values || {}
|
||||
if (!needCheckValidatedValues) {
|
||||
return {
|
||||
values,
|
||||
isCheckValidated: false,
|
||||
}
|
||||
}
|
||||
|
||||
if (checkValidated()) {
|
||||
return {
|
||||
values: needTransformWhenSecretFieldIsPristine ? getTransformedValuesWhenSecretInputPristine(formSchemas, form) : values,
|
||||
isCheckValidated: true,
|
||||
}
|
||||
}
|
||||
else {
|
||||
return {
|
||||
values: {},
|
||||
isCheckValidated: false,
|
||||
}
|
||||
}
|
||||
}, [form, checkValidated])
|
||||
|
||||
return {
|
||||
getFormValues,
|
||||
}
|
||||
}
|
||||
|
|
@ -60,7 +60,15 @@ export type FormSchema = {
|
|||
|
||||
export type FormValues = Record<string, any>
|
||||
|
||||
export type GetValuesOptions = {
|
||||
needTransformWhenSecretFieldIsPristine?: boolean
|
||||
needCheckValidatedValues?: boolean
|
||||
}
|
||||
export type FormRefObject = {
|
||||
getForm: () => AnyFormApi
|
||||
getFormValues: (obj: GetValuesOptions) => {
|
||||
values: Record<string, any>
|
||||
isCheckValidated: boolean
|
||||
}
|
||||
}
|
||||
export type FormRef = ForwardedRef<FormRefObject>
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
export * from './secret-input'
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
import type { AnyFormApi } from '@tanstack/react-form'
|
||||
import type { FormSchema } from '@/app/components/base/form/types'
|
||||
import { FormTypeEnum } from '@/app/components/base/form/types'
|
||||
|
||||
export const transformFormSchemasSecretInput = (isPristineSecretInputNames: string[], values: Record<string, any>) => {
|
||||
const transformedValues: Record<string, any> = { ...values }
|
||||
|
||||
isPristineSecretInputNames.forEach((name) => {
|
||||
if (transformedValues[name])
|
||||
transformedValues[name] = '[__HIDDEN__]'
|
||||
})
|
||||
|
||||
return transformedValues
|
||||
}
|
||||
|
||||
export const getTransformedValuesWhenSecretInputPristine = (formSchemas: FormSchema[], form: AnyFormApi) => {
|
||||
const values = form?.store.state.values || {}
|
||||
const isPristineSecretInputNames: string[] = []
|
||||
for (let i = 0; i < formSchemas.length; i++) {
|
||||
const schema = formSchemas[i]
|
||||
if (schema.type === FormTypeEnum.secretInput) {
|
||||
const fieldMeta = form?.getFieldMeta(schema.name)
|
||||
if (fieldMeta?.isPristine)
|
||||
isPristineSecretInputNames.push(schema.name)
|
||||
}
|
||||
}
|
||||
|
||||
return transformFormSchemasSecretInput(isPristineSecretInputNames, values)
|
||||
}
|
||||
|
|
@ -9,7 +9,6 @@ import { RiExternalLinkLine } from '@remixicon/react'
|
|||
import { Lock01 } from '@/app/components/base/icons/src/vender/solid/security'
|
||||
import Modal from '@/app/components/base/modal/modal'
|
||||
import { CredentialTypeEnum } from '../types'
|
||||
import { transformFormSchemasSecretInput } from '../utils'
|
||||
import AuthForm from '@/app/components/base/form/form-scenarios/auth'
|
||||
import type { FormRefObject } from '@/app/components/base/form/types'
|
||||
import { FormTypeEnum } from '@/app/components/base/form/types'
|
||||
|
|
@ -64,42 +63,32 @@ const ApiKeyModal = ({
|
|||
const invalidatePluginCredentialInfo = useInvalidPluginCredentialInfoHook(pluginPayload)
|
||||
const formRef = useRef<FormRefObject>(null)
|
||||
const handleConfirm = useCallback(async () => {
|
||||
const form = formRef.current?.getForm()
|
||||
const store = form?.store
|
||||
const {
|
||||
isCheckValidated,
|
||||
values,
|
||||
} = formRef.current?.getFormValues({
|
||||
needCheckValidatedValues: true,
|
||||
needTransformWhenSecretFieldIsPristine: true,
|
||||
}) || { isCheckValidated: false, values: {} }
|
||||
if (!isCheckValidated)
|
||||
return
|
||||
|
||||
const {
|
||||
__name__,
|
||||
__credential_id__,
|
||||
...values
|
||||
} = store?.state.values
|
||||
const isPristineSecretInputNames: string[] = []
|
||||
for (let i = 0; i < formSchemas.length; i++) {
|
||||
const schema = formSchemas[i]
|
||||
if (schema.required && !values[schema.name]) {
|
||||
notify({
|
||||
type: 'error',
|
||||
message: t('common.errorMsg.fieldRequired', { field: schema.name }),
|
||||
})
|
||||
return
|
||||
}
|
||||
if (schema.type === FormTypeEnum.secretInput) {
|
||||
const fieldMeta = form?.getFieldMeta(schema.name)
|
||||
if (fieldMeta?.isPristine)
|
||||
isPristineSecretInputNames.push(schema.name)
|
||||
}
|
||||
}
|
||||
|
||||
const transformedValues = transformFormSchemasSecretInput(isPristineSecretInputNames, values)
|
||||
...restValues
|
||||
} = values
|
||||
|
||||
if (editValues) {
|
||||
await updatePluginCredential({
|
||||
credentials: transformedValues,
|
||||
credentials: restValues,
|
||||
credential_id: __credential_id__,
|
||||
name: __name__ || '',
|
||||
})
|
||||
}
|
||||
else {
|
||||
await addPluginCredential({
|
||||
credentials: transformedValues,
|
||||
credentials: restValues,
|
||||
type: CredentialTypeEnum.API_KEY,
|
||||
name: __name__ || '',
|
||||
})
|
||||
|
|
@ -111,7 +100,7 @@ const ApiKeyModal = ({
|
|||
|
||||
onClose?.()
|
||||
invalidatePluginCredentialInfo()
|
||||
}, [addPluginCredential, onClose, invalidatePluginCredentialInfo, updatePluginCredential, notify, t, editValues, formSchemas])
|
||||
}, [addPluginCredential, onClose, invalidatePluginCredentialInfo, updatePluginCredential, notify, t, editValues])
|
||||
|
||||
return (
|
||||
<Modal
|
||||
|
|
|
|||
|
|
@ -15,8 +15,6 @@ import type {
|
|||
FormRefObject,
|
||||
FormSchema,
|
||||
} from '@/app/components/base/form/types'
|
||||
import { FormTypeEnum } from '@/app/components/base/form/types'
|
||||
import { transformFormSchemasSecretInput } from '../utils'
|
||||
import { useToastContext } from '@/app/components/base/toast'
|
||||
|
||||
type OAuthClientSettingsProps = {
|
||||
|
|
@ -46,33 +44,22 @@ const OAuthClientSettings = ({
|
|||
const invalidatePluginCredentialInfo = useInvalidPluginCredentialInfoHook(pluginPayload)
|
||||
const formRef = useRef<FormRefObject>(null)
|
||||
const handleConfirm = useCallback(async () => {
|
||||
const form = formRef.current?.getForm()
|
||||
const store = form?.store
|
||||
const {
|
||||
isCheckValidated,
|
||||
values,
|
||||
} = formRef.current?.getFormValues({
|
||||
needCheckValidatedValues: true,
|
||||
needTransformWhenSecretFieldIsPristine: true,
|
||||
}) || { isCheckValidated: false, values: {} }
|
||||
if (!isCheckValidated)
|
||||
return
|
||||
const {
|
||||
__oauth_client__,
|
||||
...values
|
||||
} = store?.state.values
|
||||
const isPristineSecretInputNames: string[] = []
|
||||
for (let i = 0; i < schemas.length; i++) {
|
||||
const schema = schemas[i]
|
||||
if (schema.required && !values[schema.name]) {
|
||||
notify({
|
||||
type: 'error',
|
||||
message: t('common.errorMsg.fieldRequired', { field: schema.name }),
|
||||
})
|
||||
return
|
||||
}
|
||||
if (schema.type === FormTypeEnum.secretInput) {
|
||||
const fieldMeta = form?.getFieldMeta(schema.name)
|
||||
if (fieldMeta?.isPristine)
|
||||
isPristineSecretInputNames.push(schema.name)
|
||||
}
|
||||
}
|
||||
|
||||
const transformedValues = transformFormSchemasSecretInput(isPristineSecretInputNames, values)
|
||||
...restValues
|
||||
} = values
|
||||
|
||||
await setPluginOAuthCustomClient({
|
||||
client_params: transformedValues,
|
||||
client_params: restValues,
|
||||
enable_oauth_custom_client: __oauth_client__ === 'custom',
|
||||
})
|
||||
notify({
|
||||
|
|
@ -82,7 +69,7 @@ const OAuthClientSettings = ({
|
|||
|
||||
onClose?.()
|
||||
invalidatePluginCredentialInfo()
|
||||
}, [onClose, invalidatePluginCredentialInfo, setPluginOAuthCustomClient, notify, t, schemas])
|
||||
}, [onClose, invalidatePluginCredentialInfo, setPluginOAuthCustomClient, notify, t])
|
||||
|
||||
const handleConfirmAndAuthorize = useCallback(async () => {
|
||||
await handleConfirm()
|
||||
|
|
|
|||
Loading…
Reference in New Issue