Files
dify/web/app/components/plugins/plugin-detail-panel/subscription-list/edit-modal.tsx
Harry f8503f31f3 refactor: simplify default value assignment in EditModal and update TriggerSubscription types
- Updated the default value assignment in the EditModal component to use a more concise syntax.
- Changed TriggerSubscription structure to use generic Record types for credentials, parameters, and properties, enhancing flexibility.
2025-12-16 17:42:21 +08:00

152 lines
5.2 KiB
TypeScript

'use client'
import { BaseForm } from '@/app/components/base/form/components/base'
import type { FormRefObject, FormSchema } from '@/app/components/base/form/types'
import { FormTypeEnum } from '@/app/components/base/form/types'
import Modal from '@/app/components/base/modal/modal'
import Toast from '@/app/components/base/toast'
import type { ParametersSchema, PluginDetail } from '@/app/components/plugins/types'
import { ReadmeEntrance } from '@/app/components/plugins/readme-panel/entrance'
import type { TriggerSubscription } from '@/app/components/workflow/block-selector/types'
import { useUpdateTriggerSubscription } from '@/service/use-triggers'
import { useMemo, useRef } from 'react'
import { useTranslation } from 'react-i18next'
import { usePluginStore } from '../store'
import { useSubscriptionList } from './use-subscription-list'
import { ReadmeShowType } from '../../readme-panel/store'
type Props = {
onClose: () => void
subscription: TriggerSubscription
pluginDetail?: PluginDetail
}
// Normalize backend type to FormTypeEnum
const normalizeFormType = (type: string): FormTypeEnum => {
switch (type) {
case 'string':
case 'text':
return FormTypeEnum.textInput
case 'password':
case 'secret':
return FormTypeEnum.secretInput
case 'number':
case 'integer':
return FormTypeEnum.textNumber
case 'boolean':
return FormTypeEnum.boolean
case 'select':
return FormTypeEnum.select
default:
if (Object.values(FormTypeEnum).includes(type as FormTypeEnum))
return type as FormTypeEnum
return FormTypeEnum.textInput
}
}
export const EditModal = ({ onClose, subscription, pluginDetail }: Props) => {
const { t } = useTranslation()
const detail = usePluginStore(state => state.detail)
const { refetch } = useSubscriptionList()
const { mutate: updateSubscription, isPending: isUpdating } = useUpdateTriggerSubscription()
const propertiesSchema = useMemo<ParametersSchema[]>(
() => detail?.declaration?.trigger?.subscription_schema || [],
[detail?.declaration?.trigger?.subscription_schema],
)
const formRef = useRef<FormRefObject>(null)
const handleConfirm = () => {
// Use needTransformWhenSecretFieldIsPristine to handle secret fields
// When secret field is not modified, it will be transformed to '[__HIDDEN__]'
// Backend will preserve original value when receiving '[__HIDDEN__]'
const formValues = formRef.current?.getFormValues({
needTransformWhenSecretFieldIsPristine: true,
})
if (!formValues?.isCheckValidated)
return
const name = formValues.values.subscription_name as string
// Extract properties values (exclude subscription_name and callback_url)
const properties = { ...formValues.values }
delete properties.subscription_name
delete properties.callback_url
updateSubscription(
{
subscriptionId: subscription.id,
name,
properties: Object.keys(properties).length > 0 ? properties : undefined,
},
{
onSuccess: () => {
Toast.notify({
type: 'success',
message: t('pluginTrigger.subscription.list.item.actions.edit.success'),
})
refetch?.()
onClose()
},
onError: (error: any) => {
Toast.notify({
type: 'error',
message: error?.message || t('pluginTrigger.subscription.list.item.actions.edit.error'),
})
},
},
)
}
const formSchemas: FormSchema[] = useMemo(() => [
{
name: 'subscription_name',
label: t('pluginTrigger.modal.form.subscriptionName.label'),
placeholder: t('pluginTrigger.modal.form.subscriptionName.placeholder'),
type: FormTypeEnum.textInput,
required: true,
default: subscription.name,
},
{
name: 'callback_url',
label: t('pluginTrigger.modal.form.callbackUrl.label'),
placeholder: t('pluginTrigger.modal.form.callbackUrl.placeholder'),
type: FormTypeEnum.textInput,
required: false,
default: subscription.endpoint || '',
disabled: true,
tooltip: t('pluginTrigger.modal.form.callbackUrl.tooltip'),
showCopy: true,
},
...propertiesSchema.map((schema: ParametersSchema) => ({
...schema,
type: normalizeFormType(schema.type as string),
tooltip: schema.description,
default: subscription.properties?.[schema.name] || schema.default,
})),
], [t, subscription.name, subscription.endpoint, subscription.properties, propertiesSchema])
return (
<Modal
title={t('pluginTrigger.subscription.list.item.actions.edit.title')}
confirmButtonText={isUpdating ? t('common.operation.saving') : t('common.operation.save')}
onClose={onClose}
onCancel={onClose}
onConfirm={handleConfirm}
disabled={isUpdating}
clickOutsideNotClose
wrapperClassName='!z-[101]'
>
{pluginDetail && (
<ReadmeEntrance pluginDetail={pluginDetail} showType={ReadmeShowType.modal} />
)}
<BaseForm
formSchemas={formSchemas}
ref={formRef}
labelClassName='system-sm-medium mb-2 flex items-center gap-1 text-text-primary'
formClassName='space-y-4'
/>
</Modal>
)
}