mirror of
https://github.com/langgenius/dify.git
synced 2026-01-08 07:14:14 +00:00
feat: implement subscription editing modals and enhance subscription management
- Added `ApiKeyEditModal`, `OAuthEditModal`, and `ManualEditModal` for editing different types of subscriptions. - Updated `EditModal` to conditionally render the appropriate modal based on the subscription's credential type. - Introduced `useVerifyTriggerSubscription` hook for verifying subscription credentials. - Enhanced form handling and validation for subscription properties and parameters across modals. - Refactored existing components to integrate new editing functionality, improving user experience in subscription management.
This commit is contained in:
@@ -0,0 +1,323 @@
|
||||
'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, useVerifyTriggerSubscription } from '@/service/use-triggers'
|
||||
import { parsePluginErrorMessage } from '@/utils/error-parser'
|
||||
import { useMemo, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { usePluginStore } from '../../store'
|
||||
import { useSubscriptionList } from '../use-subscription-list'
|
||||
import { ReadmeShowType } from '../../../readme-panel/store'
|
||||
import { EncryptedBottom } from '@/app/components/base/encrypted-bottom'
|
||||
|
||||
type Props = {
|
||||
onClose: () => void
|
||||
subscription: TriggerSubscription
|
||||
pluginDetail?: PluginDetail
|
||||
}
|
||||
|
||||
enum EditStep {
|
||||
EditCredentials = 'edit_credentials',
|
||||
EditConfiguration = 'edit_configuration',
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
const StatusStep = ({ isActive, text }: { isActive: boolean, text: string }) => {
|
||||
return <div className={`system-2xs-semibold-uppercase flex items-center gap-1 ${isActive
|
||||
? 'text-state-accent-solid'
|
||||
: 'text-text-tertiary'}`}>
|
||||
{isActive && (
|
||||
<div className='h-1 w-1 rounded-full bg-state-accent-solid'></div>
|
||||
)}
|
||||
{text}
|
||||
</div>
|
||||
}
|
||||
|
||||
const MultiSteps = ({ currentStep }: { currentStep: EditStep }) => {
|
||||
const { t } = useTranslation()
|
||||
return <div className='mb-6 flex w-1/3 items-center gap-2'>
|
||||
<StatusStep isActive={currentStep === EditStep.EditCredentials} text={t('pluginTrigger.modal.steps.verify')} />
|
||||
<div className='h-px w-3 shrink-0 bg-divider-deep'></div>
|
||||
<StatusStep isActive={currentStep === EditStep.EditConfiguration} text={t('pluginTrigger.modal.steps.configuration')} />
|
||||
</div>
|
||||
}
|
||||
|
||||
export const ApiKeyEditModal = ({ onClose, subscription, pluginDetail }: Props) => {
|
||||
const { t } = useTranslation()
|
||||
const detail = usePluginStore(state => state.detail)
|
||||
const { refetch } = useSubscriptionList()
|
||||
|
||||
const [currentStep, setCurrentStep] = useState<EditStep>(EditStep.EditCredentials)
|
||||
|
||||
const { mutate: updateSubscription, isPending: isUpdating } = useUpdateTriggerSubscription()
|
||||
const { mutate: verifyCredentials, isPending: isVerifying } = useVerifyTriggerSubscription()
|
||||
|
||||
const parametersSchema = useMemo<ParametersSchema[]>(
|
||||
() => detail?.declaration?.trigger?.subscription_constructor?.parameters || [],
|
||||
[detail?.declaration?.trigger?.subscription_constructor?.parameters],
|
||||
)
|
||||
|
||||
const rawApiKeyCredentialsSchema = detail?.declaration.trigger?.subscription_constructor?.credentials_schema || []
|
||||
const apiKeyCredentialsSchema = useMemo(() => {
|
||||
return rawApiKeyCredentialsSchema.map(schema => ({
|
||||
...schema,
|
||||
tooltip: schema.help,
|
||||
}))
|
||||
}, [rawApiKeyCredentialsSchema])
|
||||
|
||||
const basicFormRef = useRef<FormRefObject>(null)
|
||||
const parametersFormRef = useRef<FormRefObject>(null)
|
||||
const credentialsFormRef = useRef<FormRefObject>(null)
|
||||
|
||||
const handleVerifyCredentials = () => {
|
||||
const credentialsFormValues = credentialsFormRef.current?.getFormValues({
|
||||
needTransformWhenSecretFieldIsPristine: true,
|
||||
}) || { values: {}, isCheckValidated: false }
|
||||
|
||||
if (!credentialsFormValues.isCheckValidated)
|
||||
return
|
||||
|
||||
const credentials = credentialsFormValues.values
|
||||
|
||||
// Clear previous errors
|
||||
if (Object.keys(credentials).length > 0) {
|
||||
credentialsFormRef.current?.setFields([{
|
||||
name: Object.keys(credentials)[0],
|
||||
errors: [],
|
||||
}])
|
||||
}
|
||||
|
||||
verifyCredentials(
|
||||
{
|
||||
provider: subscription.provider,
|
||||
subscriptionId: subscription.id,
|
||||
credentials,
|
||||
},
|
||||
{
|
||||
onSuccess: () => {
|
||||
Toast.notify({
|
||||
type: 'success',
|
||||
message: t('pluginTrigger.modal.apiKey.verify.success'),
|
||||
})
|
||||
setCurrentStep(EditStep.EditConfiguration)
|
||||
},
|
||||
onError: async (error: any) => {
|
||||
const errorMessage = await parsePluginErrorMessage(error) || t('pluginTrigger.modal.apiKey.verify.error')
|
||||
if (Object.keys(credentials).length > 0) {
|
||||
credentialsFormRef.current?.setFields([{
|
||||
name: Object.keys(credentials)[0],
|
||||
errors: [errorMessage],
|
||||
}])
|
||||
}
|
||||
},
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
const handleUpdate = () => {
|
||||
const basicFormValues = basicFormRef.current?.getFormValues({})
|
||||
if (!basicFormValues?.isCheckValidated)
|
||||
return
|
||||
|
||||
const name = basicFormValues.values.subscription_name as string
|
||||
|
||||
let parameters: Record<string, any> | undefined
|
||||
|
||||
if (parametersSchema.length > 0) {
|
||||
const paramsFormValues = parametersFormRef.current?.getFormValues({
|
||||
needTransformWhenSecretFieldIsPristine: true,
|
||||
})
|
||||
if (!paramsFormValues?.isCheckValidated)
|
||||
return
|
||||
parameters = Object.keys(paramsFormValues.values).length > 0 ? paramsFormValues.values : undefined
|
||||
}
|
||||
|
||||
updateSubscription(
|
||||
{
|
||||
subscriptionId: subscription.id,
|
||||
name,
|
||||
parameters,
|
||||
},
|
||||
{
|
||||
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 handleConfirm = () => {
|
||||
if (currentStep === EditStep.EditCredentials)
|
||||
handleVerifyCredentials()
|
||||
else
|
||||
handleUpdate()
|
||||
}
|
||||
|
||||
const handleCredentialsChange = () => {
|
||||
if (apiKeyCredentialsSchema.length > 0) {
|
||||
credentialsFormRef.current?.setFields([{
|
||||
name: apiKeyCredentialsSchema[0].name,
|
||||
errors: [],
|
||||
}])
|
||||
}
|
||||
}
|
||||
|
||||
const basicFormSchemas: 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,
|
||||
},
|
||||
], [t, subscription.name, subscription.endpoint])
|
||||
|
||||
const credentialsFormSchemas: FormSchema[] = useMemo(() => {
|
||||
return apiKeyCredentialsSchema.map(schema => ({
|
||||
...schema,
|
||||
type: normalizeFormType(schema.type as string),
|
||||
tooltip: schema.help,
|
||||
default: subscription.credentials?.[schema.name] || schema.default,
|
||||
}))
|
||||
}, [apiKeyCredentialsSchema, subscription.credentials])
|
||||
|
||||
const parametersFormSchemas: FormSchema[] = useMemo(() => {
|
||||
return parametersSchema.map((schema: ParametersSchema) => {
|
||||
const normalizedType = normalizeFormType(schema.type as string)
|
||||
return {
|
||||
...schema,
|
||||
type: normalizedType,
|
||||
tooltip: schema.description,
|
||||
default: subscription.parameters?.[schema.name] || schema.default,
|
||||
dynamicSelectParams: normalizedType === FormTypeEnum.dynamicSelect
|
||||
? {
|
||||
plugin_id: detail?.plugin_id || '',
|
||||
provider: detail?.provider || '',
|
||||
action: 'provider',
|
||||
parameter: schema.name,
|
||||
credential_id: subscription.id,
|
||||
}
|
||||
: undefined,
|
||||
fieldClassName: schema.type === FormTypeEnum.boolean ? 'flex items-center justify-between' : undefined,
|
||||
labelClassName: schema.type === FormTypeEnum.boolean ? 'mb-0' : undefined,
|
||||
}
|
||||
})
|
||||
}, [parametersSchema, subscription.parameters, subscription.id, detail?.plugin_id, detail?.provider])
|
||||
|
||||
const getConfirmButtonText = () => {
|
||||
if (currentStep === EditStep.EditCredentials)
|
||||
return isVerifying ? t('pluginTrigger.modal.common.verifying') : t('pluginTrigger.modal.common.verify')
|
||||
|
||||
return isUpdating ? t('common.operation.saving') : t('common.operation.save')
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title={t('pluginTrigger.subscription.list.item.actions.edit.title')}
|
||||
confirmButtonText={getConfirmButtonText()}
|
||||
onClose={onClose}
|
||||
onCancel={onClose}
|
||||
onConfirm={handleConfirm}
|
||||
disabled={isUpdating || isVerifying}
|
||||
clickOutsideNotClose
|
||||
wrapperClassName='!z-[101]'
|
||||
bottomSlot={currentStep === EditStep.EditCredentials ? <EncryptedBottom /> : null}
|
||||
>
|
||||
{pluginDetail && (
|
||||
<ReadmeEntrance pluginDetail={pluginDetail} showType={ReadmeShowType.modal} />
|
||||
)}
|
||||
|
||||
{/* Multi-step indicator */}
|
||||
<MultiSteps currentStep={currentStep} />
|
||||
|
||||
{/* Step 1: Edit Credentials */}
|
||||
{currentStep === EditStep.EditCredentials && (
|
||||
<div className='mb-4'>
|
||||
{credentialsFormSchemas.length > 0 && (
|
||||
<BaseForm
|
||||
formSchemas={credentialsFormSchemas}
|
||||
ref={credentialsFormRef}
|
||||
labelClassName='system-sm-medium mb-2 flex items-center gap-1 text-text-primary'
|
||||
formClassName='space-y-4'
|
||||
preventDefaultSubmit={true}
|
||||
onChange={handleCredentialsChange}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Step 2: Edit Configuration */}
|
||||
{currentStep === EditStep.EditConfiguration && (
|
||||
<div className='max-h-[70vh]'>
|
||||
{/* Basic form: subscription name and callback URL */}
|
||||
<BaseForm
|
||||
formSchemas={basicFormSchemas}
|
||||
ref={basicFormRef}
|
||||
labelClassName='system-sm-medium mb-2 flex items-center gap-1 text-text-primary'
|
||||
formClassName='space-y-4 mb-4'
|
||||
/>
|
||||
|
||||
{/* Parameters */}
|
||||
{parametersFormSchemas.length > 0 && (
|
||||
<BaseForm
|
||||
formSchemas={parametersFormSchemas}
|
||||
ref={parametersFormRef}
|
||||
labelClassName='system-sm-medium mb-2 flex items-center gap-1 text-text-primary'
|
||||
formClassName='space-y-4'
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
'use client'
|
||||
import type { PluginDetail } from '@/app/components/plugins/types'
|
||||
import type { TriggerSubscription } from '@/app/components/workflow/block-selector/types'
|
||||
import { TriggerCredentialTypeEnum } from '@/app/components/workflow/block-selector/types'
|
||||
import { ManualEditModal } from './manual-edit-modal'
|
||||
import { OAuthEditModal } from './oauth-edit-modal'
|
||||
import { ApiKeyEditModal } from './apikey-edit-modal'
|
||||
|
||||
type Props = {
|
||||
onClose: () => void
|
||||
subscription: TriggerSubscription
|
||||
pluginDetail?: PluginDetail
|
||||
}
|
||||
|
||||
export const EditModal = ({ onClose, subscription, pluginDetail }: Props) => {
|
||||
const credentialType = subscription.credential_type
|
||||
|
||||
switch (credentialType) {
|
||||
case TriggerCredentialTypeEnum.Unauthorized:
|
||||
return <ManualEditModal onClose={onClose} subscription={subscription} pluginDetail={pluginDetail} />
|
||||
case TriggerCredentialTypeEnum.Oauth2:
|
||||
return <OAuthEditModal onClose={onClose} subscription={subscription} pluginDetail={pluginDetail} />
|
||||
case TriggerCredentialTypeEnum.ApiKey:
|
||||
return <ApiKeyEditModal onClose={onClose} subscription={subscription} pluginDetail={pluginDetail} />
|
||||
default:
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -10,9 +10,9 @@ import type { TriggerSubscription } from '@/app/components/workflow/block-select
|
||||
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'
|
||||
import { usePluginStore } from '../../store'
|
||||
import { useSubscriptionList } from '../use-subscription-list'
|
||||
import { ReadmeShowType } from '../../../readme-panel/store'
|
||||
|
||||
type Props = {
|
||||
onClose: () => void
|
||||
@@ -20,7 +20,6 @@ type Props = {
|
||||
pluginDetail?: PluginDetail
|
||||
}
|
||||
|
||||
// Normalize backend type to FormTypeEnum
|
||||
const normalizeFormType = (type: string): FormTypeEnum => {
|
||||
switch (type) {
|
||||
case 'string':
|
||||
@@ -43,7 +42,7 @@ const normalizeFormType = (type: string): FormTypeEnum => {
|
||||
}
|
||||
}
|
||||
|
||||
export const EditModal = ({ onClose, subscription, pluginDetail }: Props) => {
|
||||
export const ManualEditModal = ({ onClose, subscription, pluginDetail }: Props) => {
|
||||
const { t } = useTranslation()
|
||||
const detail = usePluginStore(state => state.detail)
|
||||
const { refetch } = useSubscriptionList()
|
||||
@@ -54,12 +53,10 @@ export const EditModal = ({ onClose, subscription, pluginDetail }: Props) => {
|
||||
() => 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,
|
||||
})
|
||||
@@ -68,7 +65,7 @@ export const EditModal = ({ onClose, subscription, pluginDetail }: Props) => {
|
||||
|
||||
const name = formValues.values.subscription_name as string
|
||||
|
||||
// Extract properties values (exclude subscription_name and callback_url)
|
||||
// Extract properties (exclude subscription_name and callback_url)
|
||||
const properties = { ...formValues.values }
|
||||
delete properties.subscription_name
|
||||
delete properties.callback_url
|
||||
@@ -0,0 +1,162 @@
|
||||
'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
|
||||
}
|
||||
|
||||
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 OAuthEditModal = ({ onClose, subscription, pluginDetail }: Props) => {
|
||||
const { t } = useTranslation()
|
||||
const detail = usePluginStore(state => state.detail)
|
||||
const { refetch } = useSubscriptionList()
|
||||
|
||||
const { mutate: updateSubscription, isPending: isUpdating } = useUpdateTriggerSubscription()
|
||||
|
||||
const parametersSchema = useMemo<ParametersSchema[]>(
|
||||
() => detail?.declaration?.trigger?.subscription_constructor?.parameters || [],
|
||||
[detail?.declaration?.trigger?.subscription_constructor?.parameters],
|
||||
)
|
||||
|
||||
const formRef = useRef<FormRefObject>(null)
|
||||
|
||||
const handleConfirm = () => {
|
||||
const formValues = formRef.current?.getFormValues({
|
||||
needTransformWhenSecretFieldIsPristine: true,
|
||||
})
|
||||
if (!formValues?.isCheckValidated)
|
||||
return
|
||||
|
||||
const name = formValues.values.subscription_name as string
|
||||
|
||||
// Extract parameters (exclude subscription_name and callback_url)
|
||||
const parameters = { ...formValues.values }
|
||||
delete parameters.subscription_name
|
||||
delete parameters.callback_url
|
||||
|
||||
updateSubscription(
|
||||
{
|
||||
subscriptionId: subscription.id,
|
||||
name,
|
||||
parameters: Object.keys(parameters).length > 0 ? parameters : 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,
|
||||
},
|
||||
...parametersSchema.map((schema: ParametersSchema) => {
|
||||
const normalizedType = normalizeFormType(schema.type as string)
|
||||
return {
|
||||
...schema,
|
||||
type: normalizedType,
|
||||
tooltip: schema.description,
|
||||
default: subscription.parameters?.[schema.name] || schema.default,
|
||||
dynamicSelectParams: normalizedType === FormTypeEnum.dynamicSelect
|
||||
? {
|
||||
plugin_id: detail?.plugin_id || '',
|
||||
provider: detail?.provider || '',
|
||||
action: 'provider',
|
||||
parameter: schema.name,
|
||||
credential_id: subscription.id,
|
||||
}
|
||||
: undefined,
|
||||
fieldClassName: schema.type === FormTypeEnum.boolean ? 'flex items-center justify-between' : undefined,
|
||||
labelClassName: schema.type === FormTypeEnum.boolean ? 'mb-0' : undefined,
|
||||
}
|
||||
}),
|
||||
], [t, subscription.name, subscription.endpoint, subscription.parameters, subscription.id, parametersSchema, detail?.plugin_id, detail?.provider])
|
||||
|
||||
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>
|
||||
)
|
||||
}
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
import { useBoolean } from 'ahooks'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { DeleteConfirm } from './delete-confirm'
|
||||
import { EditModal } from './edit-modal'
|
||||
import { EditModal } from './edit'
|
||||
|
||||
type Props = {
|
||||
data: TriggerSubscription
|
||||
|
||||
@@ -180,6 +180,24 @@ export const useVerifyAndUpdateTriggerSubscriptionBuilder = () => {
|
||||
})
|
||||
}
|
||||
|
||||
export const useVerifyTriggerSubscription = () => {
|
||||
return useMutation({
|
||||
mutationKey: [NAME_SPACE, 'verify-subscription'],
|
||||
mutationFn: (payload: {
|
||||
provider: string;
|
||||
subscriptionId: string;
|
||||
credentials?: Record<string, any>;
|
||||
}) => {
|
||||
const { provider, subscriptionId, ...body } = payload
|
||||
return post<{ verified: boolean }>(
|
||||
`/workspaces/current/trigger-provider/${provider}/subscriptions/verify/${subscriptionId}`,
|
||||
{ body },
|
||||
{ silent: true },
|
||||
)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export type BuildTriggerSubscriptionPayload = {
|
||||
provider: string
|
||||
subscriptionBuilderId: string
|
||||
@@ -215,6 +233,7 @@ export type UpdateTriggerSubscriptionPayload = {
|
||||
subscriptionId: string
|
||||
name?: string
|
||||
properties?: Record<string, any>
|
||||
parameters?: Record<string, any>
|
||||
}
|
||||
|
||||
export const useUpdateTriggerSubscription = () => {
|
||||
|
||||
Reference in New Issue
Block a user