mirror of
https://github.com/langgenius/dify.git
synced 2026-01-07 23:04:12 +00:00
Compare commits
2 Commits
build/trig
...
feat/trigg
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
037cdb3d7d | ||
|
|
7b9d01bfca |
@@ -2,6 +2,7 @@ export enum AuthCategory {
|
|||||||
tool = 'tool',
|
tool = 'tool',
|
||||||
datasource = 'datasource',
|
datasource = 'datasource',
|
||||||
model = 'model',
|
model = 'model',
|
||||||
|
trigger = 'trigger',
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PluginPayload = {
|
export type PluginPayload = {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import React from 'react'
|
import React, { useEffect } from 'react'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import DetailHeader from './detail-header'
|
import DetailHeader from './detail-header'
|
||||||
import EndpointList from './endpoint-list'
|
import EndpointList from './endpoint-list'
|
||||||
@@ -11,6 +11,7 @@ import { TriggerEventsList } from './trigger-events-list'
|
|||||||
import Drawer from '@/app/components/base/drawer'
|
import Drawer from '@/app/components/base/drawer'
|
||||||
import { type PluginDetail, PluginType } from '@/app/components/plugins/types'
|
import { type PluginDetail, PluginType } from '@/app/components/plugins/types'
|
||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
|
import { usePluginStore } from './store'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
detail?: PluginDetail
|
detail?: PluginDetail
|
||||||
@@ -28,6 +29,12 @@ const PluginDetailPanel: FC<Props> = ({
|
|||||||
onHide()
|
onHide()
|
||||||
onUpdate()
|
onUpdate()
|
||||||
}
|
}
|
||||||
|
const { setDetail } = usePluginStore()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (detail)
|
||||||
|
setDetail(detail)
|
||||||
|
}, [detail])
|
||||||
|
|
||||||
if (!detail)
|
if (!detail)
|
||||||
return null
|
return null
|
||||||
@@ -52,8 +59,8 @@ const PluginDetailPanel: FC<Props> = ({
|
|||||||
<div className='grow overflow-y-auto'>
|
<div className='grow overflow-y-auto'>
|
||||||
{detail.declaration.category === PluginType.trigger && (
|
{detail.declaration.category === PluginType.trigger && (
|
||||||
<>
|
<>
|
||||||
<SubscriptionList detail={detail} />
|
<SubscriptionList />
|
||||||
<TriggerEventsList detail={detail} />
|
<TriggerEventsList />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{!!detail.declaration.tool && <ActionList detail={detail} />}
|
{!!detail.declaration.tool && <ActionList detail={detail} />}
|
||||||
|
|||||||
12
web/app/components/plugins/plugin-detail-panel/store.ts
Normal file
12
web/app/components/plugins/plugin-detail-panel/store.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { create } from 'zustand'
|
||||||
|
import type { PluginDetail } from '../types'
|
||||||
|
|
||||||
|
type Shape = {
|
||||||
|
detail: PluginDetail | undefined
|
||||||
|
setDetail: (detail: PluginDetail) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export const usePluginStore = create<Shape>(set => ({
|
||||||
|
detail: undefined,
|
||||||
|
setDetail: (detail: PluginDetail) => set({ detail }),
|
||||||
|
}))
|
||||||
@@ -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 ? (
|
||||||
|
<Button
|
||||||
|
variant='primary'
|
||||||
|
size='medium'
|
||||||
|
className={className}
|
||||||
|
onClick={() => onClick(methodType)}
|
||||||
|
>
|
||||||
|
<RiAddLine className='mr-2 h-4 w-4' />
|
||||||
|
{buttonTextMap[methodType]}
|
||||||
|
</Button>
|
||||||
|
) : <ActionButton onClick={() => onClick(methodType)}>
|
||||||
|
<RiAddLine className='h-4 w-4' />
|
||||||
|
</ActionButton>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CreateSubscriptionButton
|
||||||
@@ -17,11 +17,10 @@ import {
|
|||||||
useCreateTriggerSubscriptionBuilder,
|
useCreateTriggerSubscriptionBuilder,
|
||||||
useVerifyTriggerSubscriptionBuilder,
|
useVerifyTriggerSubscriptionBuilder,
|
||||||
} from '@/service/use-triggers'
|
} from '@/service/use-triggers'
|
||||||
import type { PluginDetail } from '@/app/components/plugins/types'
|
|
||||||
import { TriggerCredentialTypeEnum } from '@/app/components/workflow/block-selector/types'
|
import { TriggerCredentialTypeEnum } from '@/app/components/workflow/block-selector/types'
|
||||||
|
import { usePluginStore } from '../../store'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
pluginDetail: PluginDetail
|
|
||||||
onClose: () => void
|
onClose: () => void
|
||||||
onSuccess: () => void
|
onSuccess: () => void
|
||||||
}
|
}
|
||||||
@@ -31,9 +30,9 @@ enum ApiKeyStep {
|
|||||||
Configuration = 'configuration',
|
Configuration = 'configuration',
|
||||||
}
|
}
|
||||||
|
|
||||||
const ApiKeyAddModal = ({ pluginDetail, onClose, onSuccess }: Props) => {
|
export const ApiKeyCreateModal = ({ onClose, onSuccess }: Props) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
const detail = usePluginStore(state => state.detail)
|
||||||
// State
|
// State
|
||||||
const [currentStep, setCurrentStep] = useState<ApiKeyStep>(ApiKeyStep.Verify)
|
const [currentStep, setCurrentStep] = useState<ApiKeyStep>(ApiKeyStep.Verify)
|
||||||
const [subscriptionName, setSubscriptionName] = useState('')
|
const [subscriptionName, setSubscriptionName] = useState('')
|
||||||
@@ -50,9 +49,9 @@ const ApiKeyAddModal = ({ pluginDetail, onClose, onSuccess }: Props) => {
|
|||||||
const { mutate: buildSubscription, isPending: isBuilding } = useBuildTriggerSubscription()
|
const { mutate: buildSubscription, isPending: isBuilding } = useBuildTriggerSubscription()
|
||||||
|
|
||||||
// Get provider name and schemas
|
// Get provider name and schemas
|
||||||
const providerName = `${pluginDetail.plugin_id}/${pluginDetail.declaration.name}`
|
const providerName = `${detail?.plugin_id}/${detail?.declaration.name}`
|
||||||
const credentialsSchema = pluginDetail.declaration.trigger?.credentials_schema || []
|
const credentialsSchema = detail?.declaration.trigger?.credentials_schema || []
|
||||||
const parametersSchema = pluginDetail.declaration.trigger?.subscription_schema?.parameters_schema || []
|
const parametersSchema = detail?.declaration.trigger?.subscription_schema?.parameters_schema || []
|
||||||
|
|
||||||
const handleVerify = () => {
|
const handleVerify = () => {
|
||||||
const credentialsFormValues = credentialsFormRef.current?.getFormValues({}) || { values: {}, isCheckValidated: false }
|
const credentialsFormValues = credentialsFormRef.current?.getFormValues({}) || { values: {}, isCheckValidated: false }
|
||||||
@@ -310,5 +309,3 @@ const ApiKeyAddModal = ({ pluginDetail, onClose, onSuccess }: Props) => {
|
|||||||
</Modal>
|
</Modal>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ApiKeyAddModal
|
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
import { ActionButton } from '@/app/components/base/action-button'
|
||||||
|
import Modal from '@/app/components/base/modal'
|
||||||
|
import { RiAddLine, RiCloseLine } from '@remixicon/react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { SupportedCreationMethods } from '../../../types'
|
||||||
|
import { useTriggerOAuthConfig, useTriggerProviderInfo } from '@/service/use-triggers'
|
||||||
|
import { usePluginStore } from '../../store'
|
||||||
|
import { useMemo } from 'react'
|
||||||
|
import { Button } from '@/app/components/base/button'
|
||||||
|
import { CreateTypeDropdown } from './type-dropdown'
|
||||||
|
import { useBoolean } from 'ahooks'
|
||||||
|
|
||||||
|
export const CreateModal = () => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
isShow
|
||||||
|
// onClose={onClose}
|
||||||
|
className='!max-w-[520px] p-6'
|
||||||
|
wrapperClassName='!z-[1002]'
|
||||||
|
>
|
||||||
|
<div className='flex items-center justify-between pb-3'>
|
||||||
|
<h3 className='text-lg font-semibold text-text-primary'>
|
||||||
|
{t('pluginTrigger.modal.oauth.title')}
|
||||||
|
</h3>
|
||||||
|
<ActionButton
|
||||||
|
// onClick={onClose}
|
||||||
|
>
|
||||||
|
<RiCloseLine className='h-4 w-4' />
|
||||||
|
</ActionButton>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum CreateButtonType {
|
||||||
|
FULL_BUTTON = 'full-button',
|
||||||
|
ICON_BUTTON = 'icon-button',
|
||||||
|
}
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
// onClick: (type?: SupportedCreationMethods | typeof DEFAULT_METHOD) => void
|
||||||
|
className?: string
|
||||||
|
buttonType?: CreateButtonType
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DEFAULT_METHOD = 'default'
|
||||||
|
|
||||||
|
export const CreateSubscriptionButton = ({ className, buttonType = CreateButtonType.FULL_BUTTON }: Props) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
const detail = usePluginStore(state => state.detail)
|
||||||
|
const provider = `${detail?.plugin_id}/${detail?.declaration.name}`
|
||||||
|
|
||||||
|
const { data: providerInfo } = useTriggerProviderInfo(provider, !!detail)
|
||||||
|
const supportedMethods = providerInfo?.supported_creation_methods || []
|
||||||
|
const { data: oauthConfig } = useTriggerOAuthConfig(provider, supportedMethods.includes(SupportedCreationMethods.OAUTH))
|
||||||
|
|
||||||
|
const methodType = supportedMethods.length === 1 ? supportedMethods[0] : DEFAULT_METHOD
|
||||||
|
|
||||||
|
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])
|
||||||
|
|
||||||
|
const [isShowCreateDropdown, {
|
||||||
|
setTrue: showCreateDropdown,
|
||||||
|
setFalse: hideCreateDropdown,
|
||||||
|
}] = useBoolean(false)
|
||||||
|
|
||||||
|
const onChooseCreateType = (type: SupportedCreationMethods) => {
|
||||||
|
// setSelectedCreateType(type)
|
||||||
|
hideCreateDropdown()
|
||||||
|
// showCreateModal()
|
||||||
|
}
|
||||||
|
|
||||||
|
const onClickCreate = () => {
|
||||||
|
if (methodType === DEFAULT_METHOD) {
|
||||||
|
showCreateDropdown()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
onChooseCreateType(methodType)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!supportedMethods.length)
|
||||||
|
return null
|
||||||
|
|
||||||
|
return <div className='relative'>
|
||||||
|
{
|
||||||
|
buttonType === CreateButtonType.FULL_BUTTON ? (
|
||||||
|
<Button
|
||||||
|
variant='primary'
|
||||||
|
size='medium'
|
||||||
|
className={className}
|
||||||
|
onClick={onClickCreate}
|
||||||
|
>
|
||||||
|
<RiAddLine className='mr-2 h-4 w-4' />
|
||||||
|
{buttonTextMap[methodType]}
|
||||||
|
</Button>
|
||||||
|
) : <ActionButton onClick={onClickCreate}>
|
||||||
|
<RiAddLine className='h-4 w-4' />
|
||||||
|
</ActionButton>
|
||||||
|
}
|
||||||
|
{isShowCreateDropdown && <CreateTypeDropdown
|
||||||
|
onSelect={onChooseCreateType}
|
||||||
|
onClose={hideCreateDropdown}
|
||||||
|
supportedMethods={supportedMethods}
|
||||||
|
oauthConfig={oauthConfig}
|
||||||
|
/>}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
@@ -14,23 +14,23 @@ import {
|
|||||||
useCreateTriggerSubscriptionBuilder,
|
useCreateTriggerSubscriptionBuilder,
|
||||||
useTriggerSubscriptionBuilderLogs,
|
useTriggerSubscriptionBuilderLogs,
|
||||||
} from '@/service/use-triggers'
|
} from '@/service/use-triggers'
|
||||||
import type { PluginDetail } from '@/app/components/plugins/types'
|
|
||||||
import type { TriggerSubscriptionBuilder } from '@/app/components/workflow/block-selector/types'
|
import type { TriggerSubscriptionBuilder } from '@/app/components/workflow/block-selector/types'
|
||||||
import { TriggerCredentialTypeEnum } from '@/app/components/workflow/block-selector/types'
|
import { TriggerCredentialTypeEnum } from '@/app/components/workflow/block-selector/types'
|
||||||
import { BaseForm } from '@/app/components/base/form/components/base'
|
import { BaseForm } from '@/app/components/base/form/components/base'
|
||||||
import ActionButton from '@/app/components/base/action-button'
|
import ActionButton from '@/app/components/base/action-button'
|
||||||
import { CopyFeedbackNew } from '@/app/components/base/copy-feedback'
|
import { CopyFeedbackNew } from '@/app/components/base/copy-feedback'
|
||||||
import type { FormRefObject } from '@/app/components/base/form/types'
|
import type { FormRefObject } from '@/app/components/base/form/types'
|
||||||
import LogViewer from './log-viewer'
|
import LogViewer from '../log-viewer'
|
||||||
|
import { usePluginStore } from '../../store'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
pluginDetail: PluginDetail
|
|
||||||
onClose: () => void
|
onClose: () => void
|
||||||
onSuccess: () => void
|
onSuccess: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const ManualAddModal = ({ pluginDetail, onClose, onSuccess }: Props) => {
|
export const ManualCreateModal = ({ onClose, onSuccess }: Props) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
const detail = usePluginStore(state => state.detail)
|
||||||
|
|
||||||
const [subscriptionName, setSubscriptionName] = useState('')
|
const [subscriptionName, setSubscriptionName] = useState('')
|
||||||
const [subscriptionBuilder, setSubscriptionBuilder] = useState<TriggerSubscriptionBuilder | undefined>()
|
const [subscriptionBuilder, setSubscriptionBuilder] = useState<TriggerSubscriptionBuilder | undefined>()
|
||||||
@@ -38,8 +38,8 @@ const ManualAddModal = ({ pluginDetail, onClose, onSuccess }: Props) => {
|
|||||||
const { mutate: createBuilder /* isPending: isCreatingBuilder */ } = useCreateTriggerSubscriptionBuilder()
|
const { mutate: createBuilder /* isPending: isCreatingBuilder */ } = useCreateTriggerSubscriptionBuilder()
|
||||||
const { mutate: buildSubscription, isPending: isBuilding } = useBuildTriggerSubscription()
|
const { mutate: buildSubscription, isPending: isBuilding } = useBuildTriggerSubscription()
|
||||||
|
|
||||||
const providerName = `${pluginDetail.plugin_id}/${pluginDetail.declaration.name}`
|
const providerName = `${detail?.plugin_id}/${detail?.declaration.name}`
|
||||||
const propertiesSchema = pluginDetail.declaration.trigger.subscription_schema.properties_schema || []
|
const propertiesSchema = detail?.declaration.trigger.subscription_schema.properties_schema || []
|
||||||
const propertiesFormRef = React.useRef<FormRefObject>(null)
|
const propertiesFormRef = React.useRef<FormRefObject>(null)
|
||||||
|
|
||||||
const { data: logData } = useTriggerSubscriptionBuilderLogs(
|
const { data: logData } = useTriggerSubscriptionBuilderLogs(
|
||||||
@@ -193,7 +193,7 @@ const ManualAddModal = ({ pluginDetail, onClose, onSuccess }: Props) => {
|
|||||||
<RiLoader2Line className='h-full w-full animate-spin' />
|
<RiLoader2Line className='h-full w-full animate-spin' />
|
||||||
</div>
|
</div>
|
||||||
<div className='system-xs-regular text-text-tertiary'>
|
<div className='system-xs-regular text-text-tertiary'>
|
||||||
Awaiting request from {pluginDetail.declaration.name}...
|
Awaiting request from {detail?.declaration.name}...
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -217,5 +217,3 @@ const ManualAddModal = ({ pluginDetail, onClose, onSuccess }: Props) => {
|
|||||||
</Modal>
|
</Modal>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ManualAddModal
|
|
||||||
@@ -15,15 +15,14 @@ import type { FormRefObject } from '@/app/components/base/form/types'
|
|||||||
import {
|
import {
|
||||||
useBuildTriggerSubscription,
|
useBuildTriggerSubscription,
|
||||||
useInitiateTriggerOAuth,
|
useInitiateTriggerOAuth,
|
||||||
useTriggerOAuthConfig,
|
|
||||||
useVerifyTriggerSubscriptionBuilder,
|
useVerifyTriggerSubscriptionBuilder,
|
||||||
} from '@/service/use-triggers'
|
} from '@/service/use-triggers'
|
||||||
import type { PluginDetail } from '@/app/components/plugins/types'
|
|
||||||
import ActionButton from '@/app/components/base/action-button'
|
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'
|
||||||
|
import { usePluginStore } from '../../store'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
pluginDetail: PluginDetail
|
oauthConfig?: TriggerOAuthConfig
|
||||||
onClose: () => void
|
onClose: () => void
|
||||||
onSuccess: () => void
|
onSuccess: () => void
|
||||||
}
|
}
|
||||||
@@ -39,9 +38,9 @@ enum AuthorizationStatusEnum {
|
|||||||
Failed = 'failed',
|
Failed = 'failed',
|
||||||
}
|
}
|
||||||
|
|
||||||
const OAuthAddModal = ({ pluginDetail, onClose, onSuccess }: Props) => {
|
export const OAuthCreateModal = ({ oauthConfig, onClose, onSuccess }: Props) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
const detail = usePluginStore(state => state.detail)
|
||||||
const [currentStep, setCurrentStep] = useState<OAuthStepEnum>(OAuthStepEnum.Setup)
|
const [currentStep, setCurrentStep] = useState<OAuthStepEnum>(OAuthStepEnum.Setup)
|
||||||
const [subscriptionName, setSubscriptionName] = useState('')
|
const [subscriptionName, setSubscriptionName] = useState('')
|
||||||
const [authorizationUrl, setAuthorizationUrl] = useState('')
|
const [authorizationUrl, setAuthorizationUrl] = useState('')
|
||||||
@@ -51,16 +50,14 @@ const OAuthAddModal = ({ pluginDetail, onClose, onSuccess }: Props) => {
|
|||||||
const clientFormRef = React.useRef<FormRefObject>(null)
|
const clientFormRef = React.useRef<FormRefObject>(null)
|
||||||
const parametersFormRef = React.useRef<FormRefObject>(null)
|
const parametersFormRef = React.useRef<FormRefObject>(null)
|
||||||
|
|
||||||
const providerName = `${pluginDetail.plugin_id}/${pluginDetail.declaration.name}`
|
const providerName = `${detail?.plugin_id}/${detail?.declaration.name}`
|
||||||
const clientSchema = pluginDetail.declaration.trigger?.oauth_schema?.client_schema || []
|
const clientSchema = detail?.declaration.trigger?.oauth_schema?.client_schema || []
|
||||||
const parametersSchema = pluginDetail.declaration.trigger?.subscription_schema?.parameters_schema || []
|
const parametersSchema = detail?.declaration.trigger?.subscription_schema?.parameters_schema || []
|
||||||
|
|
||||||
const { mutate: initiateOAuth } = useInitiateTriggerOAuth()
|
const { mutate: initiateOAuth } = useInitiateTriggerOAuth()
|
||||||
const { mutate: verifyBuilder } = useVerifyTriggerSubscriptionBuilder()
|
const { mutate: verifyBuilder } = useVerifyTriggerSubscriptionBuilder()
|
||||||
const { mutate: buildSubscription, isPending: isBuilding } = useBuildTriggerSubscription()
|
const { mutate: buildSubscription, isPending: isBuilding } = useBuildTriggerSubscription()
|
||||||
|
|
||||||
const { data: oauthConfig } = useTriggerOAuthConfig(providerName)
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
initiateOAuth(providerName, {
|
initiateOAuth(providerName, {
|
||||||
onSuccess: (response) => {
|
onSuccess: (response) => {
|
||||||
@@ -290,5 +287,3 @@ const OAuthAddModal = ({ pluginDetail, onClose, onSuccess }: Props) => {
|
|||||||
</Modal>
|
</Modal>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default OAuthAddModal
|
|
||||||
@@ -5,21 +5,19 @@ import { RiEqualizer2Line } from '@remixicon/react'
|
|||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
import Tooltip from '@/app/components/base/tooltip'
|
import Tooltip from '@/app/components/base/tooltip'
|
||||||
import { ActionButton } from '@/app/components/base/action-button'
|
import { ActionButton } from '@/app/components/base/action-button'
|
||||||
|
import { SupportedCreationMethods } from '../../../types'
|
||||||
enum SubscriptionAddTypeEnum {
|
import type { TriggerOAuthConfig } from '@/app/components/workflow/block-selector/types'
|
||||||
OAuth = 'oauth',
|
|
||||||
APIKey = 'api-key',
|
|
||||||
Manual = 'manual',
|
|
||||||
}
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
onSelect: (type: SubscriptionAddTypeEnum) => void
|
onSelect: (type: SupportedCreationMethods) => void
|
||||||
onClose: () => void
|
onClose: () => void
|
||||||
position?: 'bottom' | 'right'
|
position?: 'bottom' | 'right'
|
||||||
className?: string
|
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 { t } = useTranslation()
|
||||||
const dropdownRef = useRef<HTMLDivElement>(null)
|
const dropdownRef = useRef<HTMLDivElement>(null)
|
||||||
|
|
||||||
@@ -37,24 +35,29 @@ const AddTypeDropdown = ({ onSelect, onClose, position = 'bottom', className }:
|
|||||||
// todo: show client settings
|
// todo: show client settings
|
||||||
}
|
}
|
||||||
|
|
||||||
const options = [
|
const allOptions = [
|
||||||
{
|
{
|
||||||
key: SubscriptionAddTypeEnum.OAuth,
|
key: SupportedCreationMethods.OAUTH,
|
||||||
title: t('pluginTrigger.subscription.addType.options.oauth.title'),
|
title: t('pluginTrigger.subscription.addType.options.oauth.title'),
|
||||||
extraContent: <ActionButton onClick={onClickClientSettings}><RiEqualizer2Line className='h-4 w-4 text-text-tertiary' /></ActionButton>,
|
extraContent: <ActionButton onClick={onClickClientSettings}><RiEqualizer2Line className='h-4 w-4 text-text-tertiary' /></ActionButton>,
|
||||||
|
show: supportedMethods.includes(SupportedCreationMethods.OAUTH),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: SubscriptionAddTypeEnum.APIKey,
|
key: SupportedCreationMethods.APIKEY,
|
||||||
title: t('pluginTrigger.subscription.addType.options.apiKey.title'),
|
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 作为标题
|
title: t('pluginTrigger.subscription.addType.options.manual.description'), // 使用 description 作为标题
|
||||||
tooltip: t('pluginTrigger.subscription.addType.options.manual.tip'),
|
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)
|
onSelect(type)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,5 +103,3 @@ const AddTypeDropdown = ({ onSelect, onClose, position = 'bottom', className }:
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AddTypeDropdown
|
|
||||||
@@ -2,50 +2,57 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useBoolean } from 'ahooks'
|
import { useBoolean } from 'ahooks'
|
||||||
import { RiAddLine } from '@remixicon/react'
|
|
||||||
import SubscriptionCard from './subscription-card'
|
import SubscriptionCard from './subscription-card'
|
||||||
import SubscriptionAddModal from './subscription-add-modal'
|
import { SubscriptionCreateModal } from './subscription-create-modal'
|
||||||
import AddTypeDropdown from './add-type-dropdown'
|
import { CreateTypeDropdown } from './create/create-type-dropdown'
|
||||||
import ActionButton from '@/app/components/base/action-button'
|
import CreateSubscriptionButton, { ButtonType, DEFAULT_METHOD } from './create-subscription-button'
|
||||||
import Button from '@/app/components/base/button'
|
|
||||||
import Tooltip from '@/app/components/base/tooltip'
|
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'
|
import cn from '@/utils/classnames'
|
||||||
|
import { usePluginStore } from '../store'
|
||||||
|
|
||||||
type Props = {
|
export const SubscriptionList = () => {
|
||||||
detail: PluginDetail
|
|
||||||
}
|
|
||||||
|
|
||||||
type SubscriptionAddType = 'api-key' | 'oauth' | 'manual'
|
|
||||||
|
|
||||||
export const SubscriptionList = ({ detail }: Props) => {
|
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const showTopBorder = detail.declaration.tool || detail.declaration.endpoint
|
const detail = usePluginStore(state => state.detail)
|
||||||
|
|
||||||
const { data: subscriptions, isLoading, refetch } = useTriggerSubscriptions(`${detail.plugin_id}/${detail.declaration.name}`)
|
const showTopBorder = detail?.declaration.tool || detail?.declaration.endpoint
|
||||||
|
const provider = `${detail?.plugin_id}/${detail?.declaration.name}`
|
||||||
|
|
||||||
const [isShowAddModal, {
|
const { data: subscriptions, isLoading, refetch } = useTriggerSubscriptions(provider)
|
||||||
setTrue: showAddModal,
|
const { data: providerInfo } = useTriggerProviderInfo(provider)
|
||||||
setFalse: hideAddModal,
|
const { data: oauthConfig } = useTriggerOAuthConfig(provider, providerInfo?.supported_creation_methods.includes(SupportedCreationMethods.OAUTH))
|
||||||
|
|
||||||
|
const [isShowCreateDropdown, {
|
||||||
|
setTrue: showCreateDropdown,
|
||||||
|
setFalse: hideCreateDropdown,
|
||||||
}] = useBoolean(false)
|
}] = useBoolean(false)
|
||||||
|
|
||||||
const [selectedAddType, setSelectedAddType] = React.useState<SubscriptionAddType | null>(null)
|
const [selectedCreateType, setSelectedCreateType] = React.useState<SupportedCreationMethods | null>(null)
|
||||||
|
|
||||||
const [isShowAddDropdown, {
|
const [isShowCreateModal, {
|
||||||
setTrue: showAddDropdown,
|
setTrue: showCreateModal,
|
||||||
setFalse: hideAddDropdown,
|
setFalse: hideCreateModal,
|
||||||
}] = useBoolean(false)
|
}] = useBoolean(false)
|
||||||
|
|
||||||
const handleAddTypeSelect = (type: SubscriptionAddType) => {
|
const handleCreateSubscription = (type?: SupportedCreationMethods | typeof DEFAULT_METHOD) => {
|
||||||
setSelectedAddType(type)
|
if (type === DEFAULT_METHOD) {
|
||||||
hideAddDropdown()
|
showCreateDropdown()
|
||||||
showAddModal()
|
return
|
||||||
|
}
|
||||||
|
setSelectedCreateType(type as SupportedCreationMethods)
|
||||||
|
showCreateModal()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleCreateTypeSelect = (type: SupportedCreationMethods) => {
|
||||||
|
setSelectedCreateType(type)
|
||||||
|
hideCreateDropdown()
|
||||||
|
showCreateModal()
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleModalClose = () => {
|
const handleModalClose = () => {
|
||||||
hideAddModal()
|
hideCreateModal()
|
||||||
setSelectedAddType(null)
|
setSelectedCreateType(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleRefreshList = () => {
|
const handleRefreshList = () => {
|
||||||
@@ -68,19 +75,18 @@ export const SubscriptionList = ({ detail }: Props) => {
|
|||||||
<div className={cn('border-divider-subtle px-4 py-2', showTopBorder && 'border-t')}>
|
<div className={cn('border-divider-subtle px-4 py-2', showTopBorder && 'border-t')}>
|
||||||
{!hasSubscriptions ? (
|
{!hasSubscriptions ? (
|
||||||
<div className='relative w-full'>
|
<div className='relative w-full'>
|
||||||
<Button
|
<CreateSubscriptionButton
|
||||||
variant='primary'
|
supportedMethods={providerInfo?.supported_creation_methods || []}
|
||||||
size='medium'
|
onClick={handleCreateSubscription}
|
||||||
className='w-full'
|
className='w-full'
|
||||||
onClick={showAddDropdown}
|
oauthConfig={oauthConfig}
|
||||||
>
|
/>
|
||||||
<RiAddLine className='mr-2 h-4 w-4' />
|
{isShowCreateDropdown && (
|
||||||
{t('pluginTrigger.subscription.empty.button')}
|
<CreateTypeDropdown
|
||||||
</Button>
|
onSelect={handleCreateTypeSelect}
|
||||||
{isShowAddDropdown && (
|
onClose={hideCreateDropdown}
|
||||||
<AddTypeDropdown
|
supportedMethods={providerInfo?.supported_creation_methods || []}
|
||||||
onSelect={handleAddTypeSelect}
|
oauthConfig={oauthConfig}
|
||||||
onClose={hideAddDropdown}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -93,13 +99,18 @@ export const SubscriptionList = ({ detail }: Props) => {
|
|||||||
</span>
|
</span>
|
||||||
<Tooltip popupContent={t('pluginTrigger.subscription.list.tip')} />
|
<Tooltip popupContent={t('pluginTrigger.subscription.list.tip')} />
|
||||||
</div>
|
</div>
|
||||||
<ActionButton onClick={showAddDropdown}>
|
<CreateSubscriptionButton
|
||||||
<RiAddLine className='h-4 w-4' />
|
supportedMethods={providerInfo?.supported_creation_methods || []}
|
||||||
</ActionButton>
|
onClick={handleCreateSubscription}
|
||||||
{isShowAddDropdown && (
|
buttonType={ButtonType.ICON_BUTTON}
|
||||||
<AddTypeDropdown
|
oauthConfig={oauthConfig}
|
||||||
onSelect={handleAddTypeSelect}
|
/>
|
||||||
onClose={hideAddDropdown}
|
{isShowCreateDropdown && (
|
||||||
|
<CreateTypeDropdown
|
||||||
|
onSelect={handleCreateTypeSelect}
|
||||||
|
onClose={hideCreateDropdown}
|
||||||
|
supportedMethods={providerInfo?.supported_creation_methods || []}
|
||||||
|
oauthConfig={oauthConfig}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -116,10 +127,10 @@ export const SubscriptionList = ({ detail }: Props) => {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{isShowAddModal && selectedAddType && (
|
{isShowCreateModal && selectedCreateType && (
|
||||||
<SubscriptionAddModal
|
<SubscriptionCreateModal
|
||||||
type={selectedAddType}
|
type={selectedCreateType}
|
||||||
pluginDetail={detail}
|
oauthConfig={oauthConfig}
|
||||||
onClose={handleModalClose}
|
onClose={handleModalClose}
|
||||||
onSuccess={handleRefreshList}
|
onSuccess={handleRefreshList}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,56 +0,0 @@
|
|||||||
'use client'
|
|
||||||
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 type { PluginDetail } from '@/app/components/plugins/types'
|
|
||||||
|
|
||||||
type SubscriptionAddType = 'api-key' | 'oauth' | 'manual'
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
type: SubscriptionAddType
|
|
||||||
pluginDetail: PluginDetail
|
|
||||||
onClose: () => void
|
|
||||||
onSuccess: () => void
|
|
||||||
}
|
|
||||||
|
|
||||||
const SubscriptionAddModal = ({ type, pluginDetail, onClose, onSuccess }: Props) => {
|
|
||||||
// const { t } = useTranslation()
|
|
||||||
|
|
||||||
const renderModalContent = () => {
|
|
||||||
switch (type) {
|
|
||||||
case 'manual':
|
|
||||||
return (
|
|
||||||
<ManualAddModal
|
|
||||||
pluginDetail={pluginDetail}
|
|
||||||
onClose={onClose}
|
|
||||||
onSuccess={onSuccess}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
case 'api-key':
|
|
||||||
return (
|
|
||||||
<ApiKeyAddModal
|
|
||||||
pluginDetail={pluginDetail}
|
|
||||||
onClose={onClose}
|
|
||||||
onSuccess={onSuccess}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
case 'oauth':
|
|
||||||
return (
|
|
||||||
<OAuthAddModal
|
|
||||||
pluginDetail={pluginDetail}
|
|
||||||
onClose={onClose}
|
|
||||||
onSuccess={onSuccess}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
default:
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return renderModalContent()
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SubscriptionAddModal
|
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
'use client'
|
||||||
|
import React from 'react'
|
||||||
|
import { ManualCreateModal } from './create/manual-create-modal'
|
||||||
|
import { ApiKeyCreateModal } from './create/api-key-create-modal'
|
||||||
|
import { OAuthCreateModal } from './create/oauth-create-modal'
|
||||||
|
import { SupportedCreationMethods } from '@/app/components/plugins/types'
|
||||||
|
import type { TriggerOAuthConfig } from '@/app/components/workflow/block-selector/types'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
type: SupportedCreationMethods
|
||||||
|
oauthConfig?: TriggerOAuthConfig
|
||||||
|
onClose: () => void
|
||||||
|
onSuccess: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SubscriptionCreateModal = ({ type, oauthConfig, onClose, onSuccess }: Props) => {
|
||||||
|
const renderModalContent = () => {
|
||||||
|
switch (type) {
|
||||||
|
case SupportedCreationMethods.MANUAL:
|
||||||
|
return (
|
||||||
|
<ManualCreateModal
|
||||||
|
onClose={onClose}
|
||||||
|
onSuccess={onSuccess}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
case SupportedCreationMethods.APIKEY:
|
||||||
|
return (
|
||||||
|
<ApiKeyCreateModal
|
||||||
|
onClose={onClose}
|
||||||
|
onSuccess={onSuccess}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
case SupportedCreationMethods.OAUTH:
|
||||||
|
return (
|
||||||
|
<OAuthCreateModal
|
||||||
|
oauthConfig={oauthConfig}
|
||||||
|
onClose={onClose}
|
||||||
|
onSuccess={onSuccess}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
default:
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return renderModalContent()
|
||||||
|
}
|
||||||
@@ -202,6 +202,12 @@ export type PluginManifestInMarket = {
|
|||||||
from: Dependency['type']
|
from: Dependency['type']
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum SupportedCreationMethods {
|
||||||
|
OAUTH = 'OAUTH',
|
||||||
|
APIKEY = 'APIKEY',
|
||||||
|
MANUAL = 'MANUAL',
|
||||||
|
}
|
||||||
|
|
||||||
export type PluginDetail = {
|
export type PluginDetail = {
|
||||||
id: string
|
id: string
|
||||||
created_at: string
|
created_at: string
|
||||||
|
|||||||
@@ -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 { Collection, Trigger } from '../../tools/types'
|
||||||
import type { TypeWithI18N } from '../../base/form/types'
|
import type { TypeWithI18N } from '../../base/form/types'
|
||||||
|
|
||||||
@@ -151,6 +151,7 @@ export type TriggerProviderApiEntity = {
|
|||||||
tags: string[]
|
tags: string[]
|
||||||
plugin_id?: string
|
plugin_id?: string
|
||||||
plugin_unique_identifier: string
|
plugin_unique_identifier: string
|
||||||
|
supported_creation_methods: SupportedCreationMethods[]
|
||||||
credentials_schema: TriggerCredentialField[]
|
credentials_schema: TriggerCredentialField[]
|
||||||
oauth_client_schema: TriggerCredentialField[]
|
oauth_client_schema: TriggerCredentialField[]
|
||||||
subscription_schema: TriggerSubscriptionSchema
|
subscription_schema: TriggerSubscriptionSchema
|
||||||
|
|||||||
@@ -7,6 +7,11 @@ const translation = {
|
|||||||
description: 'Create your first subscription to start receiving events',
|
description: 'Create your first subscription to start receiving events',
|
||||||
button: 'New subscription',
|
button: 'New subscription',
|
||||||
},
|
},
|
||||||
|
createButton: {
|
||||||
|
oauth: 'New subscription with OAuth',
|
||||||
|
apiKey: 'New subscription with API Key',
|
||||||
|
manual: 'Paste URL to create a new subscription',
|
||||||
|
},
|
||||||
list: {
|
list: {
|
||||||
title: 'Subscriptions',
|
title: 'Subscriptions',
|
||||||
addButton: 'Add',
|
addButton: 'Add',
|
||||||
|
|||||||
@@ -7,6 +7,11 @@ const translation = {
|
|||||||
description: '创建您的第一个订阅以开始接收事件',
|
description: '创建您的第一个订阅以开始接收事件',
|
||||||
button: '新建订阅',
|
button: '新建订阅',
|
||||||
},
|
},
|
||||||
|
createButton: {
|
||||||
|
oauth: '通过 OAuth 新建订阅',
|
||||||
|
apiKey: '通过 API Key 新建订阅',
|
||||||
|
manual: '粘贴 URL 以创建新订阅',
|
||||||
|
},
|
||||||
list: {
|
list: {
|
||||||
title: '订阅列表',
|
title: '订阅列表',
|
||||||
addButton: '添加',
|
addButton: '添加',
|
||||||
|
|||||||
@@ -95,6 +95,15 @@ export const useInvalidateAllTriggerPlugins = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ===== Trigger Subscriptions Management =====
|
// ===== Trigger Subscriptions Management =====
|
||||||
|
|
||||||
|
export const useTriggerProviderInfo = (provider: string, enabled = true) => {
|
||||||
|
return useQuery<TriggerProviderApiEntity>({
|
||||||
|
queryKey: [NAME_SPACE, 'provider-info', provider],
|
||||||
|
queryFn: () => get<TriggerProviderApiEntity>(`/workspaces/current/trigger-provider/${provider}/info`),
|
||||||
|
enabled: enabled && !!provider,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export const useTriggerSubscriptions = (provider: string, enabled = true) => {
|
export const useTriggerSubscriptions = (provider: string, enabled = true) => {
|
||||||
return useQuery<TriggerSubscription[]>({
|
return useQuery<TriggerSubscription[]>({
|
||||||
queryKey: [NAME_SPACE, 'list-subscriptions', provider],
|
queryKey: [NAME_SPACE, 'list-subscriptions', provider],
|
||||||
|
|||||||
Reference in New Issue
Block a user