mirror of
https://github.com/langgenius/dify.git
synced 2026-01-14 18:59:49 +00:00
Compare commits
1 Commits
deploy/age
...
refactor/p
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c29af7a15f |
@@ -0,0 +1,65 @@
|
||||
import type { PluginPayload } from '../types'
|
||||
import { memo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Confirm from '@/app/components/base/confirm'
|
||||
import ApiKeyModal from '../authorize/api-key-modal'
|
||||
|
||||
type AuthorizedModalsProps = {
|
||||
pluginPayload: PluginPayload
|
||||
// Delete confirmation
|
||||
deleteCredentialId: string | null
|
||||
doingAction: boolean
|
||||
onDeleteConfirm: () => void
|
||||
onDeleteCancel: () => void
|
||||
// Edit modal
|
||||
editValues: Record<string, unknown> | null
|
||||
disabled?: boolean
|
||||
onEditClose: () => void
|
||||
onRemove: () => void
|
||||
onUpdate?: () => void
|
||||
}
|
||||
|
||||
/**
|
||||
* Component for managing authorized modals (delete confirmation and edit modal)
|
||||
* Extracted to reduce complexity in the main Authorized component
|
||||
*/
|
||||
const AuthorizedModals = ({
|
||||
pluginPayload,
|
||||
deleteCredentialId,
|
||||
doingAction,
|
||||
onDeleteConfirm,
|
||||
onDeleteCancel,
|
||||
editValues,
|
||||
disabled,
|
||||
onEditClose,
|
||||
onRemove,
|
||||
onUpdate,
|
||||
}: AuthorizedModalsProps) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<>
|
||||
{deleteCredentialId && (
|
||||
<Confirm
|
||||
isShow
|
||||
title={t('list.delete.title', { ns: 'datasetDocuments' })}
|
||||
isDisabled={doingAction}
|
||||
onCancel={onDeleteCancel}
|
||||
onConfirm={onDeleteConfirm}
|
||||
/>
|
||||
)}
|
||||
{!!editValues && (
|
||||
<ApiKeyModal
|
||||
pluginPayload={pluginPayload}
|
||||
editValues={editValues}
|
||||
onClose={onEditClose}
|
||||
onRemove={onRemove}
|
||||
disabled={disabled || doingAction}
|
||||
onUpdate={onUpdate}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(AuthorizedModals)
|
||||
@@ -0,0 +1,123 @@
|
||||
import type { Credential } from '../types'
|
||||
import { memo } from 'react'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import Item from './item'
|
||||
|
||||
type CredentialItemHandlers = {
|
||||
onDelete?: (id: string) => void
|
||||
onEdit?: (id: string, values: Record<string, unknown>) => void
|
||||
onSetDefault?: (id: string) => void
|
||||
onRename?: (payload: { credential_id: string, name: string }) => void
|
||||
onItemClick?: (id: string) => void
|
||||
}
|
||||
|
||||
type CredentialSectionProps = CredentialItemHandlers & {
|
||||
title: string
|
||||
credentials: Credential[]
|
||||
disabled?: boolean
|
||||
disableRename?: boolean
|
||||
disableEdit?: boolean
|
||||
disableDelete?: boolean
|
||||
disableSetDefault?: boolean
|
||||
showSelectedIcon?: boolean
|
||||
selectedCredentialId?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Reusable component for rendering a section of credentials
|
||||
* Used for OAuth, API Key, and extra authorization items
|
||||
*/
|
||||
const CredentialSection = ({
|
||||
title,
|
||||
credentials,
|
||||
disabled,
|
||||
disableRename,
|
||||
disableEdit,
|
||||
disableDelete,
|
||||
disableSetDefault,
|
||||
showSelectedIcon,
|
||||
selectedCredentialId,
|
||||
onDelete,
|
||||
onEdit,
|
||||
onSetDefault,
|
||||
onRename,
|
||||
onItemClick,
|
||||
}: CredentialSectionProps) => {
|
||||
if (!credentials.length)
|
||||
return null
|
||||
|
||||
return (
|
||||
<div className="p-1">
|
||||
<div className={cn(
|
||||
'system-xs-medium px-3 pb-0.5 pt-1 text-text-tertiary',
|
||||
showSelectedIcon && 'pl-7',
|
||||
)}
|
||||
>
|
||||
{title}
|
||||
</div>
|
||||
{credentials.map(credential => (
|
||||
<Item
|
||||
key={credential.id}
|
||||
credential={credential}
|
||||
disabled={disabled}
|
||||
disableRename={disableRename}
|
||||
disableEdit={disableEdit}
|
||||
disableDelete={disableDelete}
|
||||
disableSetDefault={disableSetDefault}
|
||||
showSelectedIcon={showSelectedIcon}
|
||||
selectedCredentialId={selectedCredentialId}
|
||||
onDelete={onDelete}
|
||||
onEdit={onEdit}
|
||||
onSetDefault={onSetDefault}
|
||||
onRename={onRename}
|
||||
onItemClick={onItemClick}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(CredentialSection)
|
||||
|
||||
type ExtraCredentialSectionProps = {
|
||||
credentials?: Credential[]
|
||||
disabled?: boolean
|
||||
onItemClick?: (id: string) => void
|
||||
showSelectedIcon?: boolean
|
||||
selectedCredentialId?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialized section for extra authorization items (read-only)
|
||||
*/
|
||||
export const ExtraCredentialSection = memo(({
|
||||
credentials,
|
||||
disabled,
|
||||
onItemClick,
|
||||
showSelectedIcon,
|
||||
selectedCredentialId,
|
||||
}: ExtraCredentialSectionProps) => {
|
||||
if (!credentials?.length)
|
||||
return null
|
||||
|
||||
return (
|
||||
<div className="p-1">
|
||||
{credentials.map(credential => (
|
||||
<Item
|
||||
key={credential.id}
|
||||
credential={credential}
|
||||
disabled={disabled}
|
||||
onItemClick={onItemClick}
|
||||
disableRename
|
||||
disableEdit
|
||||
disableDelete
|
||||
disableSetDefault
|
||||
showSelectedIcon={showSelectedIcon}
|
||||
selectedCredentialId={selectedCredentialId}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
ExtraCredentialSection.displayName = 'ExtraCredentialSection'
|
||||
@@ -0,0 +1,2 @@
|
||||
export { useCredentialActions } from './use-credential-actions'
|
||||
export { useModalState } from './use-modal-state'
|
||||
@@ -0,0 +1,116 @@
|
||||
import type { MutableRefObject } from 'react'
|
||||
import type { PluginPayload } from '../../types'
|
||||
import {
|
||||
useCallback,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useToastContext } from '@/app/components/base/toast'
|
||||
import {
|
||||
useDeletePluginCredentialHook,
|
||||
useSetPluginDefaultCredentialHook,
|
||||
useUpdatePluginCredentialHook,
|
||||
} from '../../hooks/use-credential'
|
||||
|
||||
type UseCredentialActionsOptions = {
|
||||
pluginPayload: PluginPayload
|
||||
onUpdate?: () => void
|
||||
}
|
||||
|
||||
type UseCredentialActionsReturn = {
|
||||
doingAction: boolean
|
||||
doingActionRef: MutableRefObject<boolean>
|
||||
pendingOperationCredentialIdRef: MutableRefObject<string | null>
|
||||
handleSetDoingAction: (doing: boolean) => void
|
||||
handleDelete: (credentialId: string) => Promise<void>
|
||||
handleSetDefault: (id: string) => Promise<void>
|
||||
handleRename: (payload: { credential_id: string, name: string }) => Promise<void>
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom hook for credential CRUD operations
|
||||
* Consolidates delete, setDefault, rename actions with shared loading state
|
||||
*/
|
||||
export const useCredentialActions = ({
|
||||
pluginPayload,
|
||||
onUpdate,
|
||||
}: UseCredentialActionsOptions): UseCredentialActionsReturn => {
|
||||
const { t } = useTranslation()
|
||||
const { notify } = useToastContext()
|
||||
|
||||
const [doingAction, setDoingAction] = useState(false)
|
||||
const doingActionRef = useRef(doingAction)
|
||||
const pendingOperationCredentialIdRef = useRef<string | null>(null)
|
||||
|
||||
const handleSetDoingAction = useCallback((doing: boolean) => {
|
||||
doingActionRef.current = doing
|
||||
setDoingAction(doing)
|
||||
}, [])
|
||||
|
||||
const { mutateAsync: deletePluginCredential } = useDeletePluginCredentialHook(pluginPayload)
|
||||
const { mutateAsync: setPluginDefaultCredential } = useSetPluginDefaultCredentialHook(pluginPayload)
|
||||
const { mutateAsync: updatePluginCredential } = useUpdatePluginCredentialHook(pluginPayload)
|
||||
|
||||
const showSuccessNotification = useCallback(() => {
|
||||
notify({
|
||||
type: 'success',
|
||||
message: t('api.actionSuccess', { ns: 'common' }),
|
||||
})
|
||||
}, [notify, t])
|
||||
|
||||
const handleDelete = useCallback(async (credentialId: string) => {
|
||||
if (doingActionRef.current)
|
||||
return
|
||||
try {
|
||||
handleSetDoingAction(true)
|
||||
await deletePluginCredential({ credential_id: credentialId })
|
||||
showSuccessNotification()
|
||||
onUpdate?.()
|
||||
}
|
||||
finally {
|
||||
handleSetDoingAction(false)
|
||||
}
|
||||
}, [deletePluginCredential, onUpdate, showSuccessNotification, handleSetDoingAction])
|
||||
|
||||
const handleSetDefault = useCallback(async (id: string) => {
|
||||
if (doingActionRef.current)
|
||||
return
|
||||
try {
|
||||
handleSetDoingAction(true)
|
||||
await setPluginDefaultCredential(id)
|
||||
showSuccessNotification()
|
||||
onUpdate?.()
|
||||
}
|
||||
finally {
|
||||
handleSetDoingAction(false)
|
||||
}
|
||||
}, [setPluginDefaultCredential, onUpdate, showSuccessNotification, handleSetDoingAction])
|
||||
|
||||
const handleRename = useCallback(async (payload: {
|
||||
credential_id: string
|
||||
name: string
|
||||
}) => {
|
||||
if (doingActionRef.current)
|
||||
return
|
||||
try {
|
||||
handleSetDoingAction(true)
|
||||
await updatePluginCredential(payload)
|
||||
showSuccessNotification()
|
||||
onUpdate?.()
|
||||
}
|
||||
finally {
|
||||
handleSetDoingAction(false)
|
||||
}
|
||||
}, [updatePluginCredential, showSuccessNotification, handleSetDoingAction, onUpdate])
|
||||
|
||||
return {
|
||||
doingAction,
|
||||
doingActionRef,
|
||||
pendingOperationCredentialIdRef,
|
||||
handleSetDoingAction,
|
||||
handleDelete,
|
||||
handleSetDefault,
|
||||
handleRename,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
import type { MutableRefObject } from 'react'
|
||||
import {
|
||||
useCallback,
|
||||
useState,
|
||||
} from 'react'
|
||||
|
||||
type CredentialValues = Record<string, unknown>
|
||||
|
||||
type UseModalStateOptions = {
|
||||
pendingOperationCredentialIdRef: MutableRefObject<string | null>
|
||||
}
|
||||
|
||||
type UseModalStateReturn = {
|
||||
// Delete modal state
|
||||
deleteCredentialId: string | null
|
||||
openDeleteConfirm: (credentialId?: string) => void
|
||||
closeDeleteConfirm: () => void
|
||||
// Edit modal state
|
||||
editValues: CredentialValues | null
|
||||
openEditModal: (id: string, values: CredentialValues) => void
|
||||
closeEditModal: () => void
|
||||
// Remove action (used from edit modal)
|
||||
handleRemoveFromEdit: () => void
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom hook for managing modal states
|
||||
* Handles delete confirmation and edit modal with shared pending credential tracking
|
||||
*/
|
||||
export const useModalState = ({
|
||||
pendingOperationCredentialIdRef,
|
||||
}: UseModalStateOptions): UseModalStateReturn => {
|
||||
const [deleteCredentialId, setDeleteCredentialId] = useState<string | null>(null)
|
||||
const [editValues, setEditValues] = useState<CredentialValues | null>(null)
|
||||
|
||||
const openDeleteConfirm = useCallback((credentialId?: string) => {
|
||||
if (credentialId)
|
||||
pendingOperationCredentialIdRef.current = credentialId
|
||||
|
||||
setDeleteCredentialId(pendingOperationCredentialIdRef.current)
|
||||
}, [pendingOperationCredentialIdRef])
|
||||
|
||||
const closeDeleteConfirm = useCallback(() => {
|
||||
setDeleteCredentialId(null)
|
||||
pendingOperationCredentialIdRef.current = null
|
||||
}, [pendingOperationCredentialIdRef])
|
||||
|
||||
const openEditModal = useCallback((id: string, values: CredentialValues) => {
|
||||
pendingOperationCredentialIdRef.current = id
|
||||
setEditValues(values)
|
||||
}, [pendingOperationCredentialIdRef])
|
||||
|
||||
const closeEditModal = useCallback(() => {
|
||||
setEditValues(null)
|
||||
pendingOperationCredentialIdRef.current = null
|
||||
}, [pendingOperationCredentialIdRef])
|
||||
|
||||
const handleRemoveFromEdit = useCallback(() => {
|
||||
setDeleteCredentialId(pendingOperationCredentialIdRef.current)
|
||||
}, [pendingOperationCredentialIdRef])
|
||||
|
||||
return {
|
||||
deleteCredentialId,
|
||||
openDeleteConfirm,
|
||||
closeDeleteConfirm,
|
||||
editValues,
|
||||
openEditModal,
|
||||
closeEditModal,
|
||||
handleRemoveFromEdit,
|
||||
}
|
||||
}
|
||||
1496
web/app/components/plugins/plugin-auth/authorized/index.spec.tsx
Normal file
1496
web/app/components/plugins/plugin-auth/authorized/index.spec.tsx
Normal file
File diff suppressed because it is too large
Load Diff
@@ -8,29 +8,23 @@ import {
|
||||
import {
|
||||
memo,
|
||||
useCallback,
|
||||
useRef,
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Button from '@/app/components/base/button'
|
||||
import Confirm from '@/app/components/base/confirm'
|
||||
import {
|
||||
PortalToFollowElem,
|
||||
PortalToFollowElemContent,
|
||||
PortalToFollowElemTrigger,
|
||||
} from '@/app/components/base/portal-to-follow-elem'
|
||||
import { useToastContext } from '@/app/components/base/toast'
|
||||
import Indicator from '@/app/components/header/indicator'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import Authorize from '../authorize'
|
||||
import ApiKeyModal from '../authorize/api-key-modal'
|
||||
import {
|
||||
useDeletePluginCredentialHook,
|
||||
useSetPluginDefaultCredentialHook,
|
||||
useUpdatePluginCredentialHook,
|
||||
} from '../hooks/use-credential'
|
||||
import { CredentialTypeEnum } from '../types'
|
||||
import Item from './item'
|
||||
import AuthorizedModals from './authorized-modals'
|
||||
import CredentialSection, { ExtraCredentialSection } from './credential-section'
|
||||
import { useCredentialActions, useModalState } from './hooks'
|
||||
|
||||
type AuthorizedProps = {
|
||||
pluginPayload: PluginPayload
|
||||
@@ -53,6 +47,7 @@ type AuthorizedProps = {
|
||||
onUpdate?: () => void
|
||||
notAllowCustomCredential?: boolean
|
||||
}
|
||||
|
||||
const Authorized = ({
|
||||
pluginPayload,
|
||||
credentials,
|
||||
@@ -75,105 +70,55 @@ const Authorized = ({
|
||||
notAllowCustomCredential,
|
||||
}: AuthorizedProps) => {
|
||||
const { t } = useTranslation()
|
||||
const { notify } = useToastContext()
|
||||
|
||||
// Dropdown open state
|
||||
const [isLocalOpen, setIsLocalOpen] = useState(false)
|
||||
const mergedIsOpen = isOpen ?? isLocalOpen
|
||||
const setMergedIsOpen = useCallback((open: boolean) => {
|
||||
if (onOpenChange)
|
||||
onOpenChange(open)
|
||||
|
||||
onOpenChange?.(open)
|
||||
setIsLocalOpen(open)
|
||||
}, [onOpenChange])
|
||||
const oAuthCredentials = credentials.filter(credential => credential.credential_type === CredentialTypeEnum.OAUTH2)
|
||||
const apiKeyCredentials = credentials.filter(credential => credential.credential_type === CredentialTypeEnum.API_KEY)
|
||||
const pendingOperationCredentialId = useRef<string | null>(null)
|
||||
const [deleteCredentialId, setDeleteCredentialId] = useState<string | null>(null)
|
||||
const { mutateAsync: deletePluginCredential } = useDeletePluginCredentialHook(pluginPayload)
|
||||
const openConfirm = useCallback((credentialId?: string) => {
|
||||
if (credentialId)
|
||||
pendingOperationCredentialId.current = credentialId
|
||||
|
||||
setDeleteCredentialId(pendingOperationCredentialId.current)
|
||||
}, [])
|
||||
const closeConfirm = useCallback(() => {
|
||||
setDeleteCredentialId(null)
|
||||
pendingOperationCredentialId.current = null
|
||||
}, [])
|
||||
const [doingAction, setDoingAction] = useState(false)
|
||||
const doingActionRef = useRef(doingAction)
|
||||
const handleSetDoingAction = useCallback((doing: boolean) => {
|
||||
doingActionRef.current = doing
|
||||
setDoingAction(doing)
|
||||
}, [])
|
||||
const handleConfirm = useCallback(async () => {
|
||||
if (doingActionRef.current)
|
||||
// Credential actions hook
|
||||
const {
|
||||
doingAction,
|
||||
doingActionRef,
|
||||
pendingOperationCredentialIdRef,
|
||||
handleSetDefault,
|
||||
handleRename,
|
||||
handleDelete,
|
||||
} = useCredentialActions({ pluginPayload, onUpdate })
|
||||
|
||||
// Modal state management hook
|
||||
const {
|
||||
deleteCredentialId,
|
||||
openDeleteConfirm,
|
||||
closeDeleteConfirm,
|
||||
editValues,
|
||||
openEditModal,
|
||||
closeEditModal,
|
||||
handleRemoveFromEdit,
|
||||
} = useModalState({ pendingOperationCredentialIdRef })
|
||||
|
||||
// Handle delete confirmation
|
||||
const handleDeleteConfirm = useCallback(async () => {
|
||||
if (doingActionRef.current || !pendingOperationCredentialIdRef.current)
|
||||
return
|
||||
if (!pendingOperationCredentialId.current) {
|
||||
setDeleteCredentialId(null)
|
||||
return
|
||||
}
|
||||
try {
|
||||
handleSetDoingAction(true)
|
||||
await deletePluginCredential({ credential_id: pendingOperationCredentialId.current })
|
||||
notify({
|
||||
type: 'success',
|
||||
message: t('api.actionSuccess', { ns: 'common' }),
|
||||
})
|
||||
onUpdate?.()
|
||||
setDeleteCredentialId(null)
|
||||
pendingOperationCredentialId.current = null
|
||||
}
|
||||
finally {
|
||||
handleSetDoingAction(false)
|
||||
}
|
||||
}, [deletePluginCredential, onUpdate, notify, t, handleSetDoingAction])
|
||||
const [editValues, setEditValues] = useState<Record<string, any> | null>(null)
|
||||
const handleEdit = useCallback((id: string, values: Record<string, any>) => {
|
||||
pendingOperationCredentialId.current = id
|
||||
setEditValues(values)
|
||||
}, [])
|
||||
const handleRemove = useCallback(() => {
|
||||
setDeleteCredentialId(pendingOperationCredentialId.current)
|
||||
}, [])
|
||||
const { mutateAsync: setPluginDefaultCredential } = useSetPluginDefaultCredentialHook(pluginPayload)
|
||||
const handleSetDefault = useCallback(async (id: string) => {
|
||||
if (doingActionRef.current)
|
||||
return
|
||||
try {
|
||||
handleSetDoingAction(true)
|
||||
await setPluginDefaultCredential(id)
|
||||
notify({
|
||||
type: 'success',
|
||||
message: t('api.actionSuccess', { ns: 'common' }),
|
||||
})
|
||||
onUpdate?.()
|
||||
}
|
||||
finally {
|
||||
handleSetDoingAction(false)
|
||||
}
|
||||
}, [setPluginDefaultCredential, onUpdate, notify, t, handleSetDoingAction])
|
||||
const { mutateAsync: updatePluginCredential } = useUpdatePluginCredentialHook(pluginPayload)
|
||||
const handleRename = useCallback(async (payload: {
|
||||
credential_id: string
|
||||
name: string
|
||||
}) => {
|
||||
if (doingActionRef.current)
|
||||
return
|
||||
try {
|
||||
handleSetDoingAction(true)
|
||||
await updatePluginCredential(payload)
|
||||
notify({
|
||||
type: 'success',
|
||||
message: t('api.actionSuccess', { ns: 'common' }),
|
||||
})
|
||||
onUpdate?.()
|
||||
}
|
||||
finally {
|
||||
handleSetDoingAction(false)
|
||||
}
|
||||
}, [updatePluginCredential, notify, t, handleSetDoingAction, onUpdate])
|
||||
const unavailableCredentials = credentials.filter(credential => credential.not_allowed_to_use)
|
||||
const unavailableCredential = credentials.find(credential => credential.not_allowed_to_use && credential.is_default)
|
||||
await handleDelete(pendingOperationCredentialIdRef.current)
|
||||
closeDeleteConfirm()
|
||||
}, [doingActionRef, pendingOperationCredentialIdRef, handleDelete, closeDeleteConfirm])
|
||||
|
||||
// Filter credentials by type
|
||||
const { oAuthCredentials, apiKeyCredentials } = useMemo(() => ({
|
||||
oAuthCredentials: credentials.filter(c => c.credential_type === CredentialTypeEnum.OAUTH2),
|
||||
apiKeyCredentials: credentials.filter(c => c.credential_type === CredentialTypeEnum.API_KEY),
|
||||
}), [credentials])
|
||||
|
||||
// Unavailable credentials info
|
||||
const { unavailableCredentials, hasUnavailableDefault } = useMemo(() => ({
|
||||
unavailableCredentials: credentials.filter(c => c.not_allowed_to_use),
|
||||
hasUnavailableDefault: credentials.some(c => c.not_allowed_to_use && c.is_default),
|
||||
}), [credentials])
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -188,33 +133,27 @@ const Authorized = ({
|
||||
onClick={() => setMergedIsOpen(!mergedIsOpen)}
|
||||
asChild
|
||||
>
|
||||
{
|
||||
renderTrigger
|
||||
? renderTrigger(mergedIsOpen)
|
||||
: (
|
||||
<Button
|
||||
className={cn(
|
||||
'w-full',
|
||||
isOpen && 'bg-components-button-secondary-bg-hover',
|
||||
)}
|
||||
>
|
||||
<Indicator className="mr-2" color={unavailableCredential ? 'gray' : 'green'} />
|
||||
{credentials.length}
|
||||
|
||||
{
|
||||
credentials.length > 1
|
||||
? t('auth.authorizations', { ns: 'plugin' })
|
||||
: t('auth.authorization', { ns: 'plugin' })
|
||||
}
|
||||
{
|
||||
!!unavailableCredentials.length && (
|
||||
` (${unavailableCredentials.length} ${t('auth.unavailable', { ns: 'plugin' })})`
|
||||
)
|
||||
}
|
||||
<RiArrowDownSLine className="ml-0.5 h-4 w-4" />
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
{renderTrigger
|
||||
? renderTrigger(mergedIsOpen)
|
||||
: (
|
||||
<Button
|
||||
className={cn(
|
||||
'w-full',
|
||||
isOpen && 'bg-components-button-secondary-bg-hover',
|
||||
)}
|
||||
>
|
||||
<Indicator className="mr-2" color={hasUnavailableDefault ? 'gray' : 'green'} />
|
||||
{credentials.length}
|
||||
|
||||
{credentials.length > 1
|
||||
? t('auth.authorizations', { ns: 'plugin' })
|
||||
: t('auth.authorization', { ns: 'plugin' })}
|
||||
{!!unavailableCredentials.length && (
|
||||
` (${unavailableCredentials.length} ${t('auth.unavailable', { ns: 'plugin' })})`
|
||||
)}
|
||||
<RiArrowDownSLine className="ml-0.5 h-4 w-4" />
|
||||
</Button>
|
||||
)}
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className="z-[100]">
|
||||
<div className={cn(
|
||||
@@ -223,137 +162,72 @@ const Authorized = ({
|
||||
)}
|
||||
>
|
||||
<div className="py-1">
|
||||
{
|
||||
!!extraAuthorizationItems?.length && (
|
||||
<div className="p-1">
|
||||
{
|
||||
extraAuthorizationItems.map(credential => (
|
||||
<Item
|
||||
key={credential.id}
|
||||
credential={credential}
|
||||
disabled={disabled}
|
||||
onItemClick={onItemClick}
|
||||
disableRename
|
||||
disableEdit
|
||||
disableDelete
|
||||
disableSetDefault
|
||||
showSelectedIcon={showItemSelectedIcon}
|
||||
selectedCredentialId={selectedCredentialId}
|
||||
/>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
{
|
||||
!!oAuthCredentials.length && (
|
||||
<div className="p-1">
|
||||
<div className={cn(
|
||||
'system-xs-medium px-3 pb-0.5 pt-1 text-text-tertiary',
|
||||
showItemSelectedIcon && 'pl-7',
|
||||
)}
|
||||
>
|
||||
OAuth
|
||||
</div>
|
||||
{
|
||||
oAuthCredentials.map(credential => (
|
||||
<Item
|
||||
key={credential.id}
|
||||
credential={credential}
|
||||
disabled={disabled}
|
||||
disableEdit
|
||||
onDelete={openConfirm}
|
||||
onSetDefault={handleSetDefault}
|
||||
onRename={handleRename}
|
||||
disableSetDefault={disableSetDefault}
|
||||
onItemClick={onItemClick}
|
||||
showSelectedIcon={showItemSelectedIcon}
|
||||
selectedCredentialId={selectedCredentialId}
|
||||
/>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
{
|
||||
!!apiKeyCredentials.length && (
|
||||
<div className="p-1">
|
||||
<div className={cn(
|
||||
'system-xs-medium px-3 pb-0.5 pt-1 text-text-tertiary',
|
||||
showItemSelectedIcon && 'pl-7',
|
||||
)}
|
||||
>
|
||||
API Keys
|
||||
</div>
|
||||
{
|
||||
apiKeyCredentials.map(credential => (
|
||||
<Item
|
||||
key={credential.id}
|
||||
credential={credential}
|
||||
disabled={disabled}
|
||||
onDelete={openConfirm}
|
||||
onEdit={handleEdit}
|
||||
onSetDefault={handleSetDefault}
|
||||
disableSetDefault={disableSetDefault}
|
||||
disableRename
|
||||
onItemClick={onItemClick}
|
||||
onRename={handleRename}
|
||||
showSelectedIcon={showItemSelectedIcon}
|
||||
selectedCredentialId={selectedCredentialId}
|
||||
/>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
<ExtraCredentialSection
|
||||
credentials={extraAuthorizationItems}
|
||||
disabled={disabled}
|
||||
onItemClick={onItemClick}
|
||||
showSelectedIcon={showItemSelectedIcon}
|
||||
selectedCredentialId={selectedCredentialId}
|
||||
/>
|
||||
<CredentialSection
|
||||
title="OAuth"
|
||||
credentials={oAuthCredentials}
|
||||
disabled={disabled}
|
||||
disableEdit
|
||||
disableSetDefault={disableSetDefault}
|
||||
showSelectedIcon={showItemSelectedIcon}
|
||||
selectedCredentialId={selectedCredentialId}
|
||||
onDelete={openDeleteConfirm}
|
||||
onSetDefault={handleSetDefault}
|
||||
onRename={handleRename}
|
||||
onItemClick={onItemClick}
|
||||
/>
|
||||
<CredentialSection
|
||||
title="API Keys"
|
||||
credentials={apiKeyCredentials}
|
||||
disabled={disabled}
|
||||
disableRename
|
||||
disableSetDefault={disableSetDefault}
|
||||
showSelectedIcon={showItemSelectedIcon}
|
||||
selectedCredentialId={selectedCredentialId}
|
||||
onDelete={openDeleteConfirm}
|
||||
onEdit={openEditModal}
|
||||
onSetDefault={handleSetDefault}
|
||||
onRename={handleRename}
|
||||
onItemClick={onItemClick}
|
||||
/>
|
||||
</div>
|
||||
{
|
||||
!notAllowCustomCredential && (
|
||||
<>
|
||||
<div className="h-[1px] bg-divider-subtle"></div>
|
||||
<div className="p-2">
|
||||
<Authorize
|
||||
pluginPayload={pluginPayload}
|
||||
theme="secondary"
|
||||
showDivider={false}
|
||||
canOAuth={canOAuth}
|
||||
canApiKey={canApiKey}
|
||||
disabled={disabled}
|
||||
onUpdate={onUpdate}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
{!notAllowCustomCredential && (
|
||||
<>
|
||||
<div className="h-[1px] bg-divider-subtle"></div>
|
||||
<div className="p-2">
|
||||
<Authorize
|
||||
pluginPayload={pluginPayload}
|
||||
theme="secondary"
|
||||
showDivider={false}
|
||||
canOAuth={canOAuth}
|
||||
canApiKey={canApiKey}
|
||||
disabled={disabled}
|
||||
onUpdate={onUpdate}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</PortalToFollowElemContent>
|
||||
</PortalToFollowElem>
|
||||
{
|
||||
deleteCredentialId && (
|
||||
<Confirm
|
||||
isShow
|
||||
title={t('list.delete.title', { ns: 'datasetDocuments' })}
|
||||
isDisabled={doingAction}
|
||||
onCancel={closeConfirm}
|
||||
onConfirm={handleConfirm}
|
||||
/>
|
||||
)
|
||||
}
|
||||
{
|
||||
!!editValues && (
|
||||
<ApiKeyModal
|
||||
pluginPayload={pluginPayload}
|
||||
editValues={editValues}
|
||||
onClose={() => {
|
||||
setEditValues(null)
|
||||
pendingOperationCredentialId.current = null
|
||||
}}
|
||||
onRemove={handleRemove}
|
||||
disabled={disabled || doingAction}
|
||||
onUpdate={onUpdate}
|
||||
/>
|
||||
)
|
||||
}
|
||||
<AuthorizedModals
|
||||
pluginPayload={pluginPayload}
|
||||
deleteCredentialId={deleteCredentialId}
|
||||
doingAction={doingAction}
|
||||
onDeleteConfirm={handleDeleteConfirm}
|
||||
onDeleteCancel={closeDeleteConfirm}
|
||||
editValues={editValues}
|
||||
disabled={disabled}
|
||||
onEditClose={closeEditModal}
|
||||
onRemove={handleRemoveFromEdit}
|
||||
onUpdate={onUpdate}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user