diff --git a/web/app/components/base/form/components/base/base-field.tsx b/web/app/components/base/form/components/base/base-field.tsx index 53b6bd4b58..a64516d813 100644 --- a/web/app/components/base/form/components/base/base-field.tsx +++ b/web/app/components/base/form/components/base/base-field.tsx @@ -196,7 +196,7 @@ const BaseField = ({ ) } { - formItemType === FormTypeEnum.select && multiple && ( + formItemType === FormTypeEnum.checkbox /* && multiple */ && ( tooltip?: string | TypeWithI18N | Record show_on?: FormShowOnObject[] url?: string diff --git a/web/app/components/base/modal/modal.tsx b/web/app/components/base/modal/modal.tsx index e6e9fb8804..cbcbe31c6f 100644 --- a/web/app/components/base/modal/modal.tsx +++ b/web/app/components/base/modal/modal.tsx @@ -55,8 +55,8 @@ const Modal = ({ >
e.stopPropagation()} diff --git a/web/app/components/plugins/plugin-detail-panel/subscription-list/create/common-modal.tsx b/web/app/components/plugins/plugin-detail-panel/subscription-list/create/common-modal.tsx index 0e7c6c9562..201cb9d748 100644 --- a/web/app/components/plugins/plugin-detail-panel/subscription-list/create/common-modal.tsx +++ b/web/app/components/plugins/plugin-detail-panel/subscription-list/create/common-modal.tsx @@ -15,7 +15,7 @@ import { useVerifyTriggerSubscriptionBuilder, } from '@/service/use-triggers' import { RiLoader2Line } from '@remixicon/react' -import React, { useEffect, useState } from 'react' +import React, { useEffect, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import LogViewer from '../log-viewer' import { usePluginStore, usePluginSubscriptionStore } from '../store' @@ -67,55 +67,65 @@ export const CommonCreateModal = ({ onClose, createType, builder }: Props) => { const [subscriptionBuilder, setSubscriptionBuilder] = useState(builder) const [verificationError, setVerificationError] = useState('') + const isInitializedRef = useRef(false) const { mutate: verifyCredentials, isPending: isVerifyingCredentials } = useVerifyTriggerSubscriptionBuilder() - const { mutate: createBuilder /* isPending: isCreatingBuilder */ } = useCreateTriggerSubscriptionBuilder() + const { mutateAsync: createBuilder /* isPending: isCreatingBuilder */ } = useCreateTriggerSubscriptionBuilder() const { mutate: buildSubscription, isPending: isBuilding } = useBuildTriggerSubscription() - const propertiesSchema = detail?.declaration.trigger.subscription_schema.properties_schema || [] // manual + const manualPropertiesSchema = detail?.declaration.trigger.subscription_schema || [] // manual + const manualPropertiesFormRef = React.useRef(null) + const subscriptionFormRef = React.useRef(null) - const propertiesFormRef = React.useRef(null) - const parametersSchema = detail?.declaration.trigger?.subscription_schema?.parameters_schema || [] // apikey and oauth - const parametersFormRef = React.useRef(null) - const credentialsSchema = detail?.declaration.trigger?.credentials_schema || [] - const credentialsFormRef = React.useRef(null) + + const autoCommonParametersSchema = detail?.declaration.trigger?.subscription_constructor?.parameters || [] // apikey and oauth + const autoCommonParametersFormRef = React.useRef(null) + + const apiKeyCredentialsSchema = detail?.declaration.trigger?.subscription_constructor?.credentials_schema || [] + const apiKeyCredentialsFormRef = React.useRef(null) const { data: logData } = useTriggerSubscriptionBuilderLogs( detail?.provider || '', subscriptionBuilder?.id || '', { - enabled: createType === SupportedCreationMethods.MANUAL && !!subscriptionBuilder?.id, + enabled: createType === SupportedCreationMethods.MANUAL, refetchInterval: 3000, }, ) useEffect(() => { - if (!subscriptionBuilder) { - createBuilder( - { + const initializeBuilder = async () => { + isInitializedRef.current = true + try { + const response = await createBuilder({ provider: detail?.provider || '', credential_type: CREDENTIAL_TYPE_MAP[createType], - }, - { - onSuccess: (response) => { - const builder = response.subscription_builder - setSubscriptionBuilder(builder) - }, - onError: (error) => { - Toast.notify({ - type: 'error', - message: t('pluginTrigger.modal.errors.createFailed'), - }) - console.error('Failed to create subscription builder:', error) - }, - }, - ) + }) + setSubscriptionBuilder(response.subscription_builder) + } + catch (error) { + console.error('createBuilder error:', error) + Toast.notify({ + type: 'error', + message: t('pluginTrigger.modal.errors.createFailed'), + }) + } } - }, [createBuilder, detail?.provider, subscriptionBuilder, t]) + if (!isInitializedRef.current && !subscriptionBuilder && detail?.provider) + initializeBuilder() + }, [subscriptionBuilder, detail?.provider, createType, createBuilder, t]) + + useEffect(() => { + if (subscriptionBuilder?.endpoint && subscriptionFormRef.current) { + const form = subscriptionFormRef.current.getForm() + if (form) + form.setFieldValue('callback_url', subscriptionBuilder.endpoint) + } + }, [subscriptionBuilder?.endpoint]) const handleVerify = () => { - const credentialsFormValues = credentialsFormRef.current?.getFormValues({}) || { values: {}, isCheckValidated: false } - const credentials = credentialsFormValues.values + const apiKeyCredentialsFormValues = apiKeyCredentialsFormRef.current?.getFormValues({}) || { values: {}, isCheckValidated: false } + const credentials = apiKeyCredentialsFormValues.values if (!Object.keys(credentials).length) { Toast.notify({ @@ -149,24 +159,24 @@ export const CommonCreateModal = ({ onClose, createType, builder }: Props) => { } const handleCreate = () => { - const parameterForm = parametersFormRef.current?.getFormValues({}) || { values: {}, isCheckValidated: false } - const subscriptionForm = subscriptionFormRef.current?.getFormValues({}) + const autoCommonParametersFormValues = autoCommonParametersFormRef.current?.getFormValues({}) || { values: {}, isCheckValidated: false } + const subscriptionFormValues = subscriptionFormRef.current?.getFormValues({}) || { values: {}, isCheckValidated: false } // console.log('parameterForm', parameterForm) - if (!subscriptionForm?.isCheckValidated || !parameterForm?.isCheckValidated) + if (!subscriptionFormValues?.isCheckValidated || !autoCommonParametersFormValues?.isCheckValidated) return if (!subscriptionBuilder) return - const subscriptionNameValue = subscriptionForm.values.subscription_name as string + const subscriptionNameValue = subscriptionFormValues?.values.subscription_name as string buildSubscription( { provider: detail?.provider || '', subscriptionBuilderId: subscriptionBuilder.id, name: subscriptionNameValue, - parameters: { ...parameterForm.values, events: ['*'] }, + parameters: autoCommonParametersFormValues.values, // properties: formValues.values, }, { @@ -210,11 +220,11 @@ export const CommonCreateModal = ({ onClose, createType, builder }: Props) => { {createType === SupportedCreationMethods.APIKEY && } {currentStep === ApiKeyStep.Verify && ( <> - {credentialsSchema.length > 0 && ( + {apiKeyCredentialsSchema.length > 0 && (
{ {/*
{t('pluginTrigger.modal.form.callbackUrl.description')}
*/} - {createType !== SupportedCreationMethods.MANUAL && parametersSchema.length > 0 && ( + {createType !== SupportedCreationMethods.MANUAL && autoCommonParametersSchema.length > 0 && ( ({ + formSchemas={autoCommonParametersSchema.map(schema => ({ ...schema, dynamicSelectParams: schema.type === FormTypeEnum.dynamicSelect ? { plugin_id: detail?.plugin_id || '', @@ -276,17 +286,17 @@ export const CommonCreateModal = ({ onClose, createType, builder }: Props) => { credential_id: subscriptionBuilder?.id || '', } : undefined, }))} - ref={parametersFormRef} + ref={autoCommonParametersFormRef} labelClassName='system-sm-medium mb-2 block text-text-primary' formClassName='space-y-4' /> )} {createType === SupportedCreationMethods.MANUAL && <> - {propertiesSchema.length > 0 && ( + {manualPropertiesSchema.length > 0 && (
diff --git a/web/app/components/plugins/plugin-detail-panel/subscription-list/store.ts b/web/app/components/plugins/plugin-detail-panel/subscription-list/store.ts index c98eb7baae..be02c5ba42 100644 --- a/web/app/components/plugins/plugin-detail-panel/subscription-list/store.ts +++ b/web/app/components/plugins/plugin-detail-panel/subscription-list/store.ts @@ -1,29 +1,16 @@ import { create } from 'zustand' +import type { PluginDetail } from '../../types' -export type SubscriptionListDetail = { - plugin_id: string - // name: string - provider: string - declaration: { - tool?: any - endpoint?: any - trigger?: any - name?: string - meta?: { - version?: string - } - } - version?: string -} +type SimpleDetail = Pick & { provider: string } type Shape = { - detail: SubscriptionListDetail | undefined - setDetail: (detail: SubscriptionListDetail) => void + detail: SimpleDetail | undefined + setDetail: (detail: SimpleDetail) => void } export const usePluginStore = create(set => ({ detail: undefined, - setDetail: (detail: SubscriptionListDetail) => set({ detail }), + setDetail: (detail: SimpleDetail) => set({ detail }), })) type ShapeSubscription = { diff --git a/web/app/components/plugins/plugin-detail-panel/trigger-events-list.tsx b/web/app/components/plugins/plugin-detail-panel/trigger-events-list.tsx index adc3047470..684f043be9 100644 --- a/web/app/components/plugins/plugin-detail-panel/trigger-events-list.tsx +++ b/web/app/components/plugins/plugin-detail-panel/trigger-events-list.tsx @@ -83,7 +83,7 @@ export const TriggerEventsList = () => { const locale = useContextSelector(I18n, state => state.locale) const language = getLanguage(locale) const detail = usePluginStore(state => state.detail) - const triggers = detail?.declaration.trigger?.triggers || [] + const events = detail?.declaration.trigger?.events || [] const providerKey = useMemo(() => { if (!detail?.plugin_id || !detail?.declaration?.name) return '' @@ -98,7 +98,7 @@ export const TriggerEventsList = () => { const tools = (providerInfo.events || []).map((trigger: any) => toTool(trigger, providerInfo.author)) - const metaVersion = detail.declaration.meta?.version || detail.version || '1.0' + const metaVersion = detail.declaration.meta?.version || detail.declaration.version || '1.0' return { id: providerInfo.plugin_id || providerInfo.name, @@ -118,19 +118,19 @@ export const TriggerEventsList = () => { } }, [detail, providerInfo]) - if (!triggers.length) + if (!events.length) return null return (
- {t('pluginTrigger.events.actionNum', { num: triggers.length, event: t(`pluginTrigger.events.${triggers.length > 1 ? 'events' : 'event'}`) })} + {t('pluginTrigger.events.actionNum', { num: events.length, event: t(`pluginTrigger.events.${events.length > 1 ? 'events' : 'event'}`) })}
{collection - ? triggers.map((triggerEvent: Trigger) => { + ? events.map((triggerEvent: Trigger) => { const triggerName = triggerEvent.identity?.name || '' const tool = collection.tools.find(item => item.name === triggerName) || toTool(triggerEvent, collection.author) @@ -146,7 +146,7 @@ export const TriggerEventsList = () => { /> ) }) - : triggers.map((triggerEvent: Trigger) => ( + : events.map((triggerEvent: Trigger) => (