diff --git a/web/app/components/plugins/plugin-auth/types.ts b/web/app/components/plugins/plugin-auth/types.ts index 1fb2c1a531..f2a9186993 100644 --- a/web/app/components/plugins/plugin-auth/types.ts +++ b/web/app/components/plugins/plugin-auth/types.ts @@ -2,6 +2,7 @@ export enum AuthCategory { tool = 'tool', datasource = 'datasource', model = 'model', + trigger = 'trigger', } export type PluginPayload = { diff --git a/web/app/components/plugins/plugin-detail-panel/subscription-list/api-key-add-modal.tsx b/web/app/components/plugins/plugin-detail-panel/subscription-list/api-key-create-modal.tsx similarity index 99% rename from web/app/components/plugins/plugin-detail-panel/subscription-list/api-key-add-modal.tsx rename to web/app/components/plugins/plugin-detail-panel/subscription-list/api-key-create-modal.tsx index d55c8399c8..e0ce551745 100644 --- a/web/app/components/plugins/plugin-detail-panel/subscription-list/api-key-add-modal.tsx +++ b/web/app/components/plugins/plugin-detail-panel/subscription-list/api-key-create-modal.tsx @@ -31,7 +31,7 @@ enum ApiKeyStep { Configuration = 'configuration', } -const ApiKeyAddModal = ({ pluginDetail, onClose, onSuccess }: Props) => { +export const ApiKeyCreateModal = ({ pluginDetail, onClose, onSuccess }: Props) => { const { t } = useTranslation() // State @@ -310,5 +310,3 @@ const ApiKeyAddModal = ({ pluginDetail, onClose, onSuccess }: Props) => { ) } - -export default ApiKeyAddModal diff --git a/web/app/components/plugins/plugin-detail-panel/subscription-list/create-subscription-button.tsx b/web/app/components/plugins/plugin-detail-panel/subscription-list/create-subscription-button.tsx new file mode 100644 index 0000000000..45df2e9a6c --- /dev/null +++ b/web/app/components/plugins/plugin-detail-panel/subscription-list/create-subscription-button.tsx @@ -0,0 +1,57 @@ +'use client' +import React, { useMemo } from 'react' +import { useTranslation } from 'react-i18next' +import { RiAddLine } from '@remixicon/react' +import Button from '@/app/components/base/button' +import { SupportedCreationMethods } from '@/app/components/plugins/types' +import ActionButton from '@/app/components/base/action-button' +import type { TriggerOAuthConfig } from '@/app/components/workflow/block-selector/types' + +type Props = { + supportedMethods: SupportedCreationMethods[] + onClick: (type?: SupportedCreationMethods | typeof DEFAULT_METHOD) => void + className?: string + buttonType?: ButtonType + oauthConfig?: TriggerOAuthConfig +} + +export enum ButtonType { + FULL_BUTTON = 'full-button', + ICON_BUTTON = 'icon-button', +} + +export const DEFAULT_METHOD = 'default' + +const CreateSubscriptionButton = ({ supportedMethods, onClick, className, buttonType = ButtonType.FULL_BUTTON }: Props) => { + const { t } = useTranslation() + + const buttonTextMap = useMemo(() => { + return { + [SupportedCreationMethods.OAUTH]: t('pluginTrigger.subscription.createButton.oauth'), + [SupportedCreationMethods.APIKEY]: t('pluginTrigger.subscription.createButton.apiKey'), + [SupportedCreationMethods.MANUAL]: t('pluginTrigger.subscription.createButton.manual'), + [DEFAULT_METHOD]: t('pluginTrigger.subscription.empty.button'), + } + }, [t]) + + if (supportedMethods.length === 0) + return null + + const methodType = supportedMethods.length === 1 ? supportedMethods[0] : DEFAULT_METHOD + + return buttonType === ButtonType.FULL_BUTTON ? ( + + ) : onClick(methodType)}> + + +} + +export default CreateSubscriptionButton diff --git a/web/app/components/plugins/plugin-detail-panel/subscription-list/add-type-dropdown.tsx b/web/app/components/plugins/plugin-detail-panel/subscription-list/create-type-dropdown.tsx similarity index 75% rename from web/app/components/plugins/plugin-detail-panel/subscription-list/add-type-dropdown.tsx rename to web/app/components/plugins/plugin-detail-panel/subscription-list/create-type-dropdown.tsx index 604cd7b5ee..8d33542212 100644 --- a/web/app/components/plugins/plugin-detail-panel/subscription-list/add-type-dropdown.tsx +++ b/web/app/components/plugins/plugin-detail-panel/subscription-list/create-type-dropdown.tsx @@ -5,21 +5,19 @@ import { RiEqualizer2Line } from '@remixicon/react' import cn from '@/utils/classnames' import Tooltip from '@/app/components/base/tooltip' import { ActionButton } from '@/app/components/base/action-button' - -enum SubscriptionAddTypeEnum { - OAuth = 'oauth', - APIKey = 'api-key', - Manual = 'manual', -} +import { SupportedCreationMethods } from '../../types' +import type { TriggerOAuthConfig } from '@/app/components/workflow/block-selector/types' type Props = { - onSelect: (type: SubscriptionAddTypeEnum) => void + onSelect: (type: SupportedCreationMethods) => void onClose: () => void position?: 'bottom' | 'right' className?: string + supportedMethods: SupportedCreationMethods[] + oauthConfig?: TriggerOAuthConfig } -const AddTypeDropdown = ({ onSelect, onClose, position = 'bottom', className }: Props) => { +export const CreateTypeDropdown = ({ onSelect, onClose, position = 'bottom', className, supportedMethods }: Props) => { const { t } = useTranslation() const dropdownRef = useRef(null) @@ -37,24 +35,29 @@ const AddTypeDropdown = ({ onSelect, onClose, position = 'bottom', className }: // todo: show client settings } - const options = [ + const allOptions = [ { - key: SubscriptionAddTypeEnum.OAuth, + key: SupportedCreationMethods.OAUTH, title: t('pluginTrigger.subscription.addType.options.oauth.title'), extraContent: , + show: supportedMethods.includes(SupportedCreationMethods.OAUTH), }, { - key: SubscriptionAddTypeEnum.APIKey, + key: SupportedCreationMethods.APIKEY, title: t('pluginTrigger.subscription.addType.options.apiKey.title'), + show: supportedMethods.includes(SupportedCreationMethods.APIKEY), }, { - key: SubscriptionAddTypeEnum.Manual, + key: SupportedCreationMethods.MANUAL, title: t('pluginTrigger.subscription.addType.options.manual.description'), // 使用 description 作为标题 tooltip: t('pluginTrigger.subscription.addType.options.manual.tip'), + show: supportedMethods.includes(SupportedCreationMethods.MANUAL), }, ] - const handleOptionClick = (type: SubscriptionAddTypeEnum) => { + const options = allOptions.filter(option => option.show) + + const handleOptionClick = (type: SupportedCreationMethods) => { onSelect(type) } @@ -100,5 +103,3 @@ const AddTypeDropdown = ({ onSelect, onClose, position = 'bottom', className }: ) } - -export default AddTypeDropdown diff --git a/web/app/components/plugins/plugin-detail-panel/subscription-list/index.tsx b/web/app/components/plugins/plugin-detail-panel/subscription-list/index.tsx index 42856ec768..1351d3142d 100644 --- a/web/app/components/plugins/plugin-detail-panel/subscription-list/index.tsx +++ b/web/app/components/plugins/plugin-detail-panel/subscription-list/index.tsx @@ -2,50 +2,59 @@ import React from 'react' import { useTranslation } from 'react-i18next' import { useBoolean } from 'ahooks' -import { RiAddLine } from '@remixicon/react' import SubscriptionCard from './subscription-card' -import SubscriptionAddModal from './subscription-add-modal' -import AddTypeDropdown from './add-type-dropdown' -import ActionButton from '@/app/components/base/action-button' -import Button from '@/app/components/base/button' +import { SubscriptionCreateModal } from './subscription-create-modal' +import { CreateTypeDropdown } from './create-type-dropdown' +import CreateSubscriptionButton, { ButtonType, DEFAULT_METHOD } from './create-subscription-button' import Tooltip from '@/app/components/base/tooltip' -import { useTriggerSubscriptions } from '@/service/use-triggers' +import { useTriggerOAuthConfig, useTriggerProviderInfo, useTriggerSubscriptions } from '@/service/use-triggers' import type { PluginDetail } from '@/app/components/plugins/types' +import { SupportedCreationMethods } from '@/app/components/plugins/types' import cn from '@/utils/classnames' type Props = { detail: PluginDetail } -type SubscriptionAddType = 'api-key' | 'oauth' | 'manual' - export const SubscriptionList = ({ detail }: Props) => { const { t } = useTranslation() const showTopBorder = detail.declaration.tool || detail.declaration.endpoint + const provider = `${detail.plugin_id}/${detail.declaration.name}` - const { data: subscriptions, isLoading, refetch } = useTriggerSubscriptions(`${detail.plugin_id}/${detail.declaration.name}`) + const { data: subscriptions, isLoading, refetch } = useTriggerSubscriptions(provider) + const { data: providerInfo } = useTriggerProviderInfo(provider) + const { data: oauthConfig } = useTriggerOAuthConfig(provider, providerInfo?.supported_creation_methods.includes(SupportedCreationMethods.OAUTH)) - const [isShowAddModal, { - setTrue: showAddModal, - setFalse: hideAddModal, + const [isShowCreateDropdown, { + setTrue: showCreateDropdown, + setFalse: hideCreateDropdown, }] = useBoolean(false) - const [selectedAddType, setSelectedAddType] = React.useState(null) + const [selectedCreateType, setSelectedCreateType] = React.useState(null) - const [isShowAddDropdown, { - setTrue: showAddDropdown, - setFalse: hideAddDropdown, + const [isShowCreateModal, { + setTrue: showCreateModal, + setFalse: hideCreateModal, }] = useBoolean(false) - const handleAddTypeSelect = (type: SubscriptionAddType) => { - setSelectedAddType(type) - hideAddDropdown() - showAddModal() + const handleCreateSubscription = (type?: SupportedCreationMethods | typeof DEFAULT_METHOD) => { + if (type === DEFAULT_METHOD) { + showCreateDropdown() + return + } + setSelectedCreateType(type as SupportedCreationMethods) + showCreateModal() + } + + const handleCreateTypeSelect = (type: SupportedCreationMethods) => { + setSelectedCreateType(type) + hideCreateDropdown() + showCreateModal() } const handleModalClose = () => { - hideAddModal() - setSelectedAddType(null) + hideCreateModal() + setSelectedCreateType(null) } const handleRefreshList = () => { @@ -68,19 +77,18 @@ export const SubscriptionList = ({ detail }: Props) => {
{!hasSubscriptions ? (
- - {isShowAddDropdown && ( - + {isShowCreateDropdown && ( + )}
@@ -93,13 +101,18 @@ export const SubscriptionList = ({ detail }: Props) => {
- - - - {isShowAddDropdown && ( - + {isShowCreateDropdown && ( + )} @@ -116,9 +129,10 @@ export const SubscriptionList = ({ detail }: Props) => { )} - {isShowAddModal && selectedAddType && ( - void } -const ManualAddModal = ({ pluginDetail, onClose, onSuccess }: Props) => { +export const ManualCreateModal = ({ pluginDetail, onClose, onSuccess }: Props) => { const { t } = useTranslation() const [subscriptionName, setSubscriptionName] = useState('') @@ -217,5 +217,3 @@ const ManualAddModal = ({ pluginDetail, onClose, onSuccess }: Props) => { ) } - -export default ManualAddModal diff --git a/web/app/components/plugins/plugin-detail-panel/subscription-list/oauth-add-modal.tsx b/web/app/components/plugins/plugin-detail-panel/subscription-list/oauth-create-modal.tsx similarity index 97% rename from web/app/components/plugins/plugin-detail-panel/subscription-list/oauth-add-modal.tsx rename to web/app/components/plugins/plugin-detail-panel/subscription-list/oauth-create-modal.tsx index 29d36dafdc..e48e03d145 100644 --- a/web/app/components/plugins/plugin-detail-panel/subscription-list/oauth-add-modal.tsx +++ b/web/app/components/plugins/plugin-detail-panel/subscription-list/oauth-create-modal.tsx @@ -15,15 +15,15 @@ import type { FormRefObject } from '@/app/components/base/form/types' import { useBuildTriggerSubscription, useInitiateTriggerOAuth, - useTriggerOAuthConfig, useVerifyTriggerSubscriptionBuilder, } from '@/service/use-triggers' import type { PluginDetail } from '@/app/components/plugins/types' import ActionButton from '@/app/components/base/action-button' -import type { TriggerSubscriptionBuilder } from '@/app/components/workflow/block-selector/types' +import type { TriggerOAuthConfig, TriggerSubscriptionBuilder } from '@/app/components/workflow/block-selector/types' type Props = { pluginDetail: PluginDetail + oauthConfig?: TriggerOAuthConfig onClose: () => void onSuccess: () => void } @@ -39,7 +39,7 @@ enum AuthorizationStatusEnum { Failed = 'failed', } -const OAuthAddModal = ({ pluginDetail, onClose, onSuccess }: Props) => { +export const OAuthCreateModal = ({ pluginDetail, oauthConfig, onClose, onSuccess }: Props) => { const { t } = useTranslation() const [currentStep, setCurrentStep] = useState(OAuthStepEnum.Setup) @@ -59,8 +59,6 @@ const OAuthAddModal = ({ pluginDetail, onClose, onSuccess }: Props) => { const { mutate: verifyBuilder } = useVerifyTriggerSubscriptionBuilder() const { mutate: buildSubscription, isPending: isBuilding } = useBuildTriggerSubscription() - const { data: oauthConfig } = useTriggerOAuthConfig(providerName) - useEffect(() => { initiateOAuth(providerName, { onSuccess: (response) => { @@ -290,5 +288,3 @@ const OAuthAddModal = ({ pluginDetail, onClose, onSuccess }: Props) => { ) } - -export default OAuthAddModal diff --git a/web/app/components/plugins/plugin-detail-panel/subscription-list/subscription-add-modal.tsx b/web/app/components/plugins/plugin-detail-panel/subscription-list/subscription-create-modal.tsx similarity index 54% rename from web/app/components/plugins/plugin-detail-panel/subscription-list/subscription-add-modal.tsx rename to web/app/components/plugins/plugin-detail-panel/subscription-list/subscription-create-modal.tsx index 896642afa5..52731b31d1 100644 --- a/web/app/components/plugins/plugin-detail-panel/subscription-list/subscription-add-modal.tsx +++ b/web/app/components/plugins/plugin-detail-panel/subscription-list/subscription-create-modal.tsx @@ -2,45 +2,47 @@ import React from 'react' // import { useTranslation } from 'react-i18next' // import Modal from '@/app/components/base/modal' -import ManualAddModal from './manual-add-modal' -import ApiKeyAddModal from './api-key-add-modal' -import OAuthAddModal from './oauth-add-modal' +import { ManualCreateModal } from './manual-create-modal' +import { ApiKeyCreateModal } from './api-key-create-modal' +import { OAuthCreateModal } from './oauth-create-modal' import type { PluginDetail } from '@/app/components/plugins/types' - -type SubscriptionAddType = 'api-key' | 'oauth' | 'manual' +import { SupportedCreationMethods } from '@/app/components/plugins/types' +import type { TriggerOAuthConfig } from '@/app/components/workflow/block-selector/types' type Props = { - type: SubscriptionAddType + type: SupportedCreationMethods pluginDetail: PluginDetail + oauthConfig?: TriggerOAuthConfig onClose: () => void onSuccess: () => void } -const SubscriptionAddModal = ({ type, pluginDetail, onClose, onSuccess }: Props) => { +export const SubscriptionCreateModal = ({ type, pluginDetail, oauthConfig, onClose, onSuccess }: Props) => { // const { t } = useTranslation() const renderModalContent = () => { switch (type) { - case 'manual': + case SupportedCreationMethods.MANUAL: return ( - ) - case 'api-key': + case SupportedCreationMethods.APIKEY: return ( - ) - case 'oauth': + case SupportedCreationMethods.OAUTH: return ( - @@ -52,5 +54,3 @@ const SubscriptionAddModal = ({ type, pluginDetail, onClose, onSuccess }: Props) return renderModalContent() } - -export default SubscriptionAddModal diff --git a/web/app/components/plugins/types.ts b/web/app/components/plugins/types.ts index 5f4f603368..102be22c17 100644 --- a/web/app/components/plugins/types.ts +++ b/web/app/components/plugins/types.ts @@ -202,6 +202,12 @@ export type PluginManifestInMarket = { from: Dependency['type'] } +export enum SupportedCreationMethods { + OAUTH = 'OAUTH', + APIKEY = 'APIKEY', + MANUAL = 'MANUAL', +} + export type PluginDetail = { id: string created_at: string diff --git a/web/app/components/workflow/block-selector/types.ts b/web/app/components/workflow/block-selector/types.ts index bdbd24f7b3..4853520dd0 100644 --- a/web/app/components/workflow/block-selector/types.ts +++ b/web/app/components/workflow/block-selector/types.ts @@ -1,4 +1,4 @@ -import type { PluginMeta } from '../../plugins/types' +import type { PluginMeta, SupportedCreationMethods } from '../../plugins/types' import type { Collection, Trigger } from '../../tools/types' import type { TypeWithI18N } from '../../base/form/types' @@ -151,6 +151,7 @@ export type TriggerProviderApiEntity = { tags: string[] plugin_id?: string plugin_unique_identifier: string + supported_creation_methods: SupportedCreationMethods[] credentials_schema: TriggerCredentialField[] oauth_client_schema: TriggerCredentialField[] subscription_schema: TriggerSubscriptionSchema diff --git a/web/i18n/en-US/plugin-trigger.ts b/web/i18n/en-US/plugin-trigger.ts index 61d2ecb247..a28e33922d 100644 --- a/web/i18n/en-US/plugin-trigger.ts +++ b/web/i18n/en-US/plugin-trigger.ts @@ -7,6 +7,11 @@ const translation = { description: 'Create your first subscription to start receiving events', button: 'New subscription', }, + createButton: { + oauth: 'New subscription with OAuth', + apiKey: 'New subscription with API Key', + manual: 'Paste URL to create a new subscription', + }, list: { title: 'Subscriptions', addButton: 'Add', diff --git a/web/i18n/zh-Hans/plugin-trigger.ts b/web/i18n/zh-Hans/plugin-trigger.ts index 0daddae271..4a47ba4b89 100644 --- a/web/i18n/zh-Hans/plugin-trigger.ts +++ b/web/i18n/zh-Hans/plugin-trigger.ts @@ -7,6 +7,11 @@ const translation = { description: '创建您的第一个订阅以开始接收事件', button: '新建订阅', }, + createButton: { + oauth: '通过 OAuth 新建订阅', + apiKey: '通过 API Key 新建订阅', + manual: '粘贴 URL 以创建新订阅', + }, list: { title: '订阅列表', addButton: '添加', diff --git a/web/service/use-triggers.ts b/web/service/use-triggers.ts index c4193ae650..bf23d80875 100644 --- a/web/service/use-triggers.ts +++ b/web/service/use-triggers.ts @@ -95,6 +95,15 @@ export const useInvalidateAllTriggerPlugins = () => { } // ===== Trigger Subscriptions Management ===== + +export const useTriggerProviderInfo = (provider: string, enabled = true) => { + return useQuery({ + queryKey: [NAME_SPACE, 'provider-info', provider], + queryFn: () => get(`/workspaces/current/trigger-provider/${provider}/info`), + enabled: enabled && !!provider, + }) +} + export const useTriggerSubscriptions = (provider: string, enabled = true) => { return useQuery({ queryKey: [NAME_SPACE, 'list-subscriptions', provider],