mirror of https://github.com/langgenius/dify.git
feat: oauth config
This commit is contained in:
parent
bd1fcd3525
commit
7b9d01bfca
|
|
@ -2,6 +2,7 @@ export enum AuthCategory {
|
|||
tool = 'tool',
|
||||
datasource = 'datasource',
|
||||
model = 'model',
|
||||
trigger = 'trigger',
|
||||
}
|
||||
|
||||
export type PluginPayload = {
|
||||
|
|
|
|||
|
|
@ -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) => {
|
|||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export default ApiKeyAddModal
|
||||
|
|
@ -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
|
||||
|
|
@ -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<HTMLDivElement>(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: <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'),
|
||||
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 }:
|
|||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default AddTypeDropdown
|
||||
|
|
@ -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<SubscriptionAddType | null>(null)
|
||||
const [selectedCreateType, setSelectedCreateType] = React.useState<SupportedCreationMethods | null>(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) => {
|
|||
<div className={cn('border-divider-subtle px-4 py-2', showTopBorder && 'border-t')}>
|
||||
{!hasSubscriptions ? (
|
||||
<div className='relative w-full'>
|
||||
<Button
|
||||
variant='primary'
|
||||
size='medium'
|
||||
<CreateSubscriptionButton
|
||||
supportedMethods={providerInfo?.supported_creation_methods || []}
|
||||
onClick={handleCreateSubscription}
|
||||
className='w-full'
|
||||
onClick={showAddDropdown}
|
||||
>
|
||||
<RiAddLine className='mr-2 h-4 w-4' />
|
||||
{t('pluginTrigger.subscription.empty.button')}
|
||||
</Button>
|
||||
{isShowAddDropdown && (
|
||||
<AddTypeDropdown
|
||||
onSelect={handleAddTypeSelect}
|
||||
onClose={hideAddDropdown}
|
||||
oauthConfig={oauthConfig}
|
||||
/>
|
||||
{isShowCreateDropdown && (
|
||||
<CreateTypeDropdown
|
||||
onSelect={handleCreateTypeSelect}
|
||||
onClose={hideCreateDropdown}
|
||||
supportedMethods={providerInfo?.supported_creation_methods || []}
|
||||
oauthConfig={oauthConfig}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -93,13 +101,18 @@ export const SubscriptionList = ({ detail }: Props) => {
|
|||
</span>
|
||||
<Tooltip popupContent={t('pluginTrigger.subscription.list.tip')} />
|
||||
</div>
|
||||
<ActionButton onClick={showAddDropdown}>
|
||||
<RiAddLine className='h-4 w-4' />
|
||||
</ActionButton>
|
||||
{isShowAddDropdown && (
|
||||
<AddTypeDropdown
|
||||
onSelect={handleAddTypeSelect}
|
||||
onClose={hideAddDropdown}
|
||||
<CreateSubscriptionButton
|
||||
supportedMethods={providerInfo?.supported_creation_methods || []}
|
||||
onClick={handleCreateSubscription}
|
||||
buttonType={ButtonType.ICON_BUTTON}
|
||||
oauthConfig={oauthConfig}
|
||||
/>
|
||||
{isShowCreateDropdown && (
|
||||
<CreateTypeDropdown
|
||||
onSelect={handleCreateTypeSelect}
|
||||
onClose={hideCreateDropdown}
|
||||
supportedMethods={providerInfo?.supported_creation_methods || []}
|
||||
oauthConfig={oauthConfig}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -116,9 +129,10 @@ export const SubscriptionList = ({ detail }: Props) => {
|
|||
</>
|
||||
)}
|
||||
|
||||
{isShowAddModal && selectedAddType && (
|
||||
<SubscriptionAddModal
|
||||
type={selectedAddType}
|
||||
{isShowCreateModal && selectedCreateType && (
|
||||
<SubscriptionCreateModal
|
||||
type={selectedCreateType}
|
||||
oauthConfig={oauthConfig}
|
||||
pluginDetail={detail}
|
||||
onClose={handleModalClose}
|
||||
onSuccess={handleRefreshList}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ type Props = {
|
|||
onSuccess: () => 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) => {
|
|||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export default ManualAddModal
|
||||
|
|
@ -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>(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) => {
|
|||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export default OAuthAddModal
|
||||
|
|
@ -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 (
|
||||
<ManualAddModal
|
||||
<ManualCreateModal
|
||||
pluginDetail={pluginDetail}
|
||||
onClose={onClose}
|
||||
onSuccess={onSuccess}
|
||||
/>
|
||||
)
|
||||
case 'api-key':
|
||||
case SupportedCreationMethods.APIKEY:
|
||||
return (
|
||||
<ApiKeyAddModal
|
||||
<ApiKeyCreateModal
|
||||
pluginDetail={pluginDetail}
|
||||
onClose={onClose}
|
||||
onSuccess={onSuccess}
|
||||
/>
|
||||
)
|
||||
case 'oauth':
|
||||
case SupportedCreationMethods.OAUTH:
|
||||
return (
|
||||
<OAuthAddModal
|
||||
<OAuthCreateModal
|
||||
pluginDetail={pluginDetail}
|
||||
oauthConfig={oauthConfig}
|
||||
onClose={onClose}
|
||||
onSuccess={onSuccess}
|
||||
/>
|
||||
|
|
@ -52,5 +54,3 @@ const SubscriptionAddModal = ({ type, pluginDetail, onClose, onSuccess }: Props)
|
|||
|
||||
return renderModalContent()
|
||||
}
|
||||
|
||||
export default SubscriptionAddModal
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -7,6 +7,11 @@ const translation = {
|
|||
description: '创建您的第一个订阅以开始接收事件',
|
||||
button: '新建订阅',
|
||||
},
|
||||
createButton: {
|
||||
oauth: '通过 OAuth 新建订阅',
|
||||
apiKey: '通过 API Key 新建订阅',
|
||||
manual: '粘贴 URL 以创建新订阅',
|
||||
},
|
||||
list: {
|
||||
title: '订阅列表',
|
||||
addButton: '添加',
|
||||
|
|
|
|||
|
|
@ -95,6 +95,15 @@ export const useInvalidateAllTriggerPlugins = () => {
|
|||
}
|
||||
|
||||
// ===== 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) => {
|
||||
return useQuery<TriggerSubscription[]>({
|
||||
queryKey: [NAME_SPACE, 'list-subscriptions', provider],
|
||||
|
|
|
|||
Loading…
Reference in New Issue