mirror of
https://github.com/langgenius/dify.git
synced 2026-05-04 01:18:05 +08:00
tool oauth
This commit is contained in:
@ -0,0 +1,46 @@
|
||||
import {
|
||||
memo,
|
||||
useState,
|
||||
} from 'react'
|
||||
import Button from '@/app/components/base/button'
|
||||
import type { ButtonProps } from '@/app/components/base/button'
|
||||
import ApiKeyModal from './api-key-modal'
|
||||
|
||||
export type AddApiKeyButtonProps = {
|
||||
provider?: string
|
||||
buttonVariant?: ButtonProps['variant']
|
||||
buttonText?: string
|
||||
disabled?: boolean
|
||||
}
|
||||
const AddApiKeyButton = ({
|
||||
provider = '',
|
||||
buttonVariant = 'secondary-accent',
|
||||
buttonText = 'use api key',
|
||||
disabled,
|
||||
}: AddApiKeyButtonProps) => {
|
||||
const [isApiKeyModalOpen, setIsApiKeyModalOpen] = useState(false)
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
className='grow'
|
||||
variant={buttonVariant}
|
||||
onClick={() => setIsApiKeyModalOpen(true)}
|
||||
disabled={disabled}
|
||||
>
|
||||
{buttonText}
|
||||
</Button>
|
||||
{
|
||||
isApiKeyModalOpen && (
|
||||
<ApiKeyModal
|
||||
provider={provider}
|
||||
onClose={() => setIsApiKeyModalOpen(false)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
</>
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(AddApiKeyButton)
|
||||
@ -0,0 +1,72 @@
|
||||
import {
|
||||
memo,
|
||||
useState,
|
||||
} from 'react'
|
||||
import { RiEqualizer2Line } from '@remixicon/react'
|
||||
import Button from '@/app/components/base/button'
|
||||
import type { ButtonProps } from '@/app/components/base/button'
|
||||
import OAuthClientSettings from './oauth-client-settings'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
export type AddOAuthButtonProps = {
|
||||
buttonVariant?: ButtonProps['variant']
|
||||
buttonText?: string
|
||||
className?: string
|
||||
buttonLeftClassName?: string
|
||||
buttonRightClassName?: string
|
||||
dividerClassName?: string
|
||||
disabled?: boolean
|
||||
}
|
||||
const AddOAuthButton = ({
|
||||
buttonVariant = 'primary',
|
||||
buttonText = 'use oauth',
|
||||
className,
|
||||
buttonLeftClassName,
|
||||
buttonRightClassName,
|
||||
dividerClassName,
|
||||
disabled,
|
||||
}: AddOAuthButtonProps) => {
|
||||
const [isOAuthSettingsOpen, setIsOAuthSettingsOpen] = useState(false)
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
variant={buttonVariant}
|
||||
className={cn(
|
||||
'grow px-0 py-0 hover:bg-components-button-primary-bg',
|
||||
className,
|
||||
)}
|
||||
disabled={disabled}
|
||||
>
|
||||
<div className={cn(
|
||||
'flex h-full grow items-center justify-center rounded-l-lg hover:bg-components-button-primary-bg-hover',
|
||||
buttonLeftClassName,
|
||||
)}>
|
||||
{buttonText}
|
||||
</div>
|
||||
<div className={cn(
|
||||
'h-4 w-[1px] bg-text-primary-on-surface opacity-[0.15]',
|
||||
dividerClassName,
|
||||
)}></div>
|
||||
<div
|
||||
className={cn(
|
||||
'flex h-full w-8 shrink-0 items-center justify-center rounded-r-lg hover:bg-components-button-primary-bg-hover',
|
||||
buttonRightClassName,
|
||||
)}
|
||||
onClick={() => setIsOAuthSettingsOpen(true)}
|
||||
>
|
||||
<RiEqualizer2Line className='h-4 w-4' />
|
||||
</div>
|
||||
</Button>
|
||||
{
|
||||
isOAuthSettingsOpen && (
|
||||
<OAuthClientSettings
|
||||
onClose={() => setIsOAuthSettingsOpen(false)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(AddOAuthButton)
|
||||
@ -0,0 +1,109 @@
|
||||
import {
|
||||
memo,
|
||||
useCallback,
|
||||
useRef,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { RiExternalLinkLine } from '@remixicon/react'
|
||||
import { Lock01 } from '@/app/components/base/icons/src/vender/solid/security'
|
||||
import Modal from '@/app/components/base/modal/modal'
|
||||
import {
|
||||
useAddPluginToolCredential,
|
||||
useGetPluginToolCredentialSchema,
|
||||
useInvalidPluginToolCredentialInfo,
|
||||
useUpdatePluginToolCredential,
|
||||
} from '@/service/use-plugins-auth'
|
||||
import { CredentialTypeEnum } from '../types'
|
||||
import AuthForm from '@/app/components/base/form/form-scenarios/auth'
|
||||
import type { FromRefObject } from '@/app/components/base/form/types'
|
||||
import { useToastContext } from '@/app/components/base/toast'
|
||||
|
||||
export type ApiKeyModalProps = {
|
||||
provider: string
|
||||
onClose?: () => void
|
||||
editValues?: Record<string, any>
|
||||
onRemove?: () => void
|
||||
}
|
||||
const ApiKeyModal = ({
|
||||
provider,
|
||||
onClose,
|
||||
editValues,
|
||||
onRemove,
|
||||
}: ApiKeyModalProps) => {
|
||||
const { t } = useTranslation()
|
||||
const { notify } = useToastContext()
|
||||
const { data } = useGetPluginToolCredentialSchema(provider, CredentialTypeEnum.API_KEY)
|
||||
const { mutateAsync: addPluginToolCredential } = useAddPluginToolCredential(provider)
|
||||
const { mutateAsync: updatePluginToolCredential } = useUpdatePluginToolCredential(provider)
|
||||
const invalidatePluginToolCredentialInfo = useInvalidPluginToolCredentialInfo(provider)
|
||||
const formRef = useRef<FromRefObject>(null)
|
||||
const handleConfirm = useCallback(async () => {
|
||||
const store = formRef.current?.getFormStore()
|
||||
const values = store?.state.values
|
||||
|
||||
if (editValues) {
|
||||
await updatePluginToolCredential({
|
||||
credentials: values,
|
||||
type: CredentialTypeEnum.API_KEY,
|
||||
})
|
||||
}
|
||||
else {
|
||||
await addPluginToolCredential({
|
||||
credentials: values,
|
||||
type: CredentialTypeEnum.API_KEY,
|
||||
})
|
||||
}
|
||||
notify({
|
||||
type: 'success',
|
||||
message: t('common.api.actionSuccess'),
|
||||
})
|
||||
|
||||
onClose?.()
|
||||
invalidatePluginToolCredentialInfo()
|
||||
}, [addPluginToolCredential, onClose, invalidatePluginToolCredentialInfo, updatePluginToolCredential, notify, t, editValues])
|
||||
|
||||
return (
|
||||
<Modal
|
||||
size='md'
|
||||
title='API Key Authorization Configuration'
|
||||
subTitle='After configuring credentials, all members within the workspace can use this tool when orchestrating applications.'
|
||||
onClose={onClose}
|
||||
onCancel={onClose}
|
||||
footerSlot={
|
||||
<a
|
||||
className='system-xs-regular flex h-8 grow items-center text-text-accent'
|
||||
href=''
|
||||
target='_blank'
|
||||
>
|
||||
Get your API Key from OpenAI
|
||||
<RiExternalLinkLine className='ml-1 h-3 w-3' />
|
||||
</a>
|
||||
}
|
||||
bottomSlot={
|
||||
<div className='flex items-center justify-center bg-background-section-burn py-3 text-xs text-text-tertiary'>
|
||||
<Lock01 className='mr-1 h-3 w-3 text-text-tertiary' />
|
||||
{t('common.modelProvider.encrypted.front')}
|
||||
<a
|
||||
className='mx-1 text-text-accent'
|
||||
target='_blank' rel='noopener noreferrer'
|
||||
href='https://pycryptodome.readthedocs.io/en/latest/src/cipher/oaep.html'
|
||||
>
|
||||
PKCS1_OAEP
|
||||
</a>
|
||||
{t('common.modelProvider.encrypted.back')}
|
||||
</div>
|
||||
}
|
||||
onConfirm={handleConfirm}
|
||||
showExtraButton={!!editValues}
|
||||
onExtraButtonClick={onRemove}
|
||||
>
|
||||
<AuthForm
|
||||
ref={formRef}
|
||||
formSchemas={data}
|
||||
defaultValues={editValues}
|
||||
/>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(ApiKeyModal)
|
||||
91
web/app/components/plugins/plugin-auth/authorize/index.tsx
Normal file
91
web/app/components/plugins/plugin-auth/authorize/index.tsx
Normal file
@ -0,0 +1,91 @@
|
||||
import {
|
||||
memo,
|
||||
useMemo,
|
||||
} from 'react'
|
||||
import AddOAuthButton from './add-oauth-button'
|
||||
import type { AddOAuthButtonProps } from './add-oauth-button'
|
||||
import AddApiKeyButton from './add-api-key-button'
|
||||
import type { AddApiKeyButtonProps } from './add-api-key-button'
|
||||
|
||||
type AuthorizeProps = {
|
||||
provider?: string
|
||||
theme?: 'primary' | 'secondary'
|
||||
showDivider?: boolean
|
||||
canOAuth?: boolean
|
||||
canApiKey?: boolean
|
||||
disabled?: boolean
|
||||
}
|
||||
const Authorize = ({
|
||||
provider = '',
|
||||
theme = 'primary',
|
||||
showDivider = true,
|
||||
canOAuth,
|
||||
canApiKey,
|
||||
disabled,
|
||||
}: AuthorizeProps) => {
|
||||
const oAuthButtonProps: AddOAuthButtonProps = useMemo(() => {
|
||||
if (theme === 'secondary') {
|
||||
return {
|
||||
buttonText: !canApiKey ? 'Add OAuth Authorization' : 'Add OAuth',
|
||||
buttonVariant: 'secondary',
|
||||
className: 'hover:bg-components-button-secondary-bg',
|
||||
buttonLeftClassName: 'hover:bg-components-button-secondary-bg-hover',
|
||||
buttonRightClassName: 'hover:bg-components-button-secondary-bg-hover',
|
||||
dividerClassName: 'bg-divider-regular opacity-100',
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
buttonText: !canApiKey ? 'Use OAuth Authorization' : '',
|
||||
}
|
||||
}, [canApiKey, theme])
|
||||
|
||||
const apiKeyButtonProps: AddApiKeyButtonProps = useMemo(() => {
|
||||
if (theme === 'secondary') {
|
||||
return {
|
||||
provider,
|
||||
buttonVariant: 'secondary',
|
||||
buttonText: !canOAuth ? 'API Key Authorization Configuration' : 'Add API Key',
|
||||
}
|
||||
}
|
||||
return {
|
||||
provider,
|
||||
buttonText: !canOAuth ? 'API Key Authorization Configuration' : '',
|
||||
buttonVariant: !canOAuth ? 'primary' : 'secondary-accent',
|
||||
}
|
||||
}, [canOAuth, theme, provider])
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='flex items-center space-x-1.5'>
|
||||
{
|
||||
canOAuth && (
|
||||
<AddOAuthButton
|
||||
{...oAuthButtonProps}
|
||||
disabled={disabled}
|
||||
/>
|
||||
)
|
||||
}
|
||||
{
|
||||
showDivider && canOAuth && canApiKey && (
|
||||
<div className='system-2xs-medium-uppercase flex shrink-0 flex-col items-center justify-between text-text-tertiary'>
|
||||
<div className='h-2 w-[1px] bg-divider-subtle'></div>
|
||||
or
|
||||
<div className='h-2 w-[1px] bg-divider-subtle'></div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
{
|
||||
canApiKey && (
|
||||
<AddApiKeyButton
|
||||
{...apiKeyButtonProps}
|
||||
disabled={disabled}
|
||||
/>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(Authorize)
|
||||
@ -0,0 +1,26 @@
|
||||
import { memo } from 'react'
|
||||
import Modal from '@/app/components/base/modal/modal'
|
||||
|
||||
type OAuthClientSettingsProps = {
|
||||
onClose?: () => void
|
||||
}
|
||||
const OAuthClientSettings = ({
|
||||
onClose,
|
||||
}: OAuthClientSettingsProps) => {
|
||||
return (
|
||||
<Modal
|
||||
title='Oauth client settings'
|
||||
confirmButtonText='Save & Authorize'
|
||||
cancelButtonText='Save only'
|
||||
extraButtonText='Cancel'
|
||||
showExtraButton
|
||||
extraButtonVariant='secondary'
|
||||
onExtraButtonClick={onClose}
|
||||
onClose={onClose}
|
||||
>
|
||||
<div>oauth</div>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(OAuthClientSettings)
|
||||
Reference in New Issue
Block a user