Refactor/model credential (#24994)
This commit is contained in:
parent
b88146c443
commit
9e125e2029
30 changed files with 1226 additions and 596 deletions
|
|
@ -2,18 +2,17 @@ import {
|
|||
memo,
|
||||
useCallback,
|
||||
} from 'react'
|
||||
import { RiAddLine } from '@remixicon/react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import CredentialItem from './credential-item'
|
||||
import type {
|
||||
Credential,
|
||||
CustomModel,
|
||||
CustomModelCredential,
|
||||
ModelProvider,
|
||||
} from '../../declarations'
|
||||
import Button from '@/app/components/base/button'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import ModelIcon from '../../model-icon'
|
||||
|
||||
type AuthorizedItemProps = {
|
||||
provider: ModelProvider
|
||||
model?: CustomModelCredential
|
||||
title?: string
|
||||
disabled?: boolean
|
||||
|
|
@ -25,8 +24,12 @@ type AuthorizedItemProps = {
|
|||
onItemClick?: (credential: Credential, model?: CustomModel) => void
|
||||
enableAddModelCredential?: boolean
|
||||
notAllowCustomCredential?: boolean
|
||||
showModelTitle?: boolean
|
||||
disableDeleteButShowAction?: boolean
|
||||
disableDeleteTip?: string
|
||||
}
|
||||
export const AuthorizedItem = ({
|
||||
provider,
|
||||
model,
|
||||
title,
|
||||
credentials,
|
||||
|
|
@ -36,10 +39,10 @@ export const AuthorizedItem = ({
|
|||
showItemSelectedIcon,
|
||||
selectedCredentialId,
|
||||
onItemClick,
|
||||
enableAddModelCredential,
|
||||
notAllowCustomCredential,
|
||||
showModelTitle,
|
||||
disableDeleteButShowAction,
|
||||
disableDeleteTip,
|
||||
}: AuthorizedItemProps) => {
|
||||
const { t } = useTranslation()
|
||||
const handleEdit = useCallback((credential?: Credential) => {
|
||||
onEdit?.(credential, model)
|
||||
}, [onEdit, model])
|
||||
|
|
@ -52,34 +55,29 @@ export const AuthorizedItem = ({
|
|||
|
||||
return (
|
||||
<div className='p-1'>
|
||||
<div
|
||||
className='flex h-9 items-center'
|
||||
>
|
||||
<div className='h-5 w-5 shrink-0'></div>
|
||||
<div
|
||||
className='system-md-medium mx-1 grow truncate text-text-primary'
|
||||
title={title ?? model?.model}
|
||||
>
|
||||
{title ?? model?.model}
|
||||
</div>
|
||||
{
|
||||
enableAddModelCredential && !notAllowCustomCredential && (
|
||||
<Tooltip
|
||||
asChild
|
||||
popupContent={t('common.modelProvider.auth.addModelCredential')}
|
||||
{
|
||||
showModelTitle && (
|
||||
<div
|
||||
className='flex h-9 items-center px-2'
|
||||
>
|
||||
{
|
||||
model?.model && (
|
||||
<ModelIcon
|
||||
className='mr-1 h-5 w-5 shrink-0'
|
||||
provider={provider}
|
||||
modelName={model.model}
|
||||
/>
|
||||
)
|
||||
}
|
||||
<div
|
||||
className='system-md-medium mx-1 grow truncate text-text-primary'
|
||||
title={title ?? model?.model}
|
||||
>
|
||||
<Button
|
||||
className='h-6 w-6 shrink-0 rounded-full p-0'
|
||||
size='small'
|
||||
variant='secondary-accent'
|
||||
onClick={() => handleEdit?.()}
|
||||
>
|
||||
<RiAddLine className='h-4 w-4' />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
{title ?? model?.model}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
{
|
||||
credentials.map(credential => (
|
||||
<CredentialItem
|
||||
|
|
@ -91,6 +89,8 @@ export const AuthorizedItem = ({
|
|||
showSelectedIcon={showItemSelectedIcon}
|
||||
selectedCredentialId={selectedCredentialId}
|
||||
onItemClick={handleItemClick}
|
||||
disableDeleteButShowAction={disableDeleteButShowAction}
|
||||
disableDeleteTip={disableDeleteTip}
|
||||
/>
|
||||
))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ type CredentialItemProps = {
|
|||
disableRename?: boolean
|
||||
disableEdit?: boolean
|
||||
disableDelete?: boolean
|
||||
disableDeleteButShowAction?: boolean
|
||||
disableDeleteTip?: string
|
||||
showSelectedIcon?: boolean
|
||||
selectedCredentialId?: string
|
||||
}
|
||||
|
|
@ -36,6 +38,8 @@ const CredentialItem = ({
|
|||
disableRename,
|
||||
disableEdit,
|
||||
disableDelete,
|
||||
disableDeleteButShowAction,
|
||||
disableDeleteTip,
|
||||
showSelectedIcon,
|
||||
selectedCredentialId,
|
||||
}: CredentialItemProps) => {
|
||||
|
|
@ -43,6 +47,9 @@ const CredentialItem = ({
|
|||
const showAction = useMemo(() => {
|
||||
return !(disableRename && disableEdit && disableDelete)
|
||||
}, [disableRename, disableEdit, disableDelete])
|
||||
const disableDeleteWhenSelected = useMemo(() => {
|
||||
return disableDeleteButShowAction && selectedCredentialId === credential.credential_id
|
||||
}, [disableDeleteButShowAction, selectedCredentialId, credential.credential_id])
|
||||
|
||||
const Item = (
|
||||
<div
|
||||
|
|
@ -104,16 +111,21 @@ const CredentialItem = ({
|
|||
}
|
||||
{
|
||||
!disableDelete && !credential.from_enterprise && (
|
||||
<Tooltip popupContent={t('common.operation.delete')}>
|
||||
<Tooltip popupContent={disableDeleteWhenSelected ? disableDeleteTip : t('common.operation.delete')}>
|
||||
<ActionButton
|
||||
className='hover:bg-transparent'
|
||||
disabled={disabled}
|
||||
onClick={(e) => {
|
||||
if (disabled || disableDeleteWhenSelected)
|
||||
return
|
||||
e.stopPropagation()
|
||||
onDelete?.(credential)
|
||||
}}
|
||||
>
|
||||
<RiDeleteBinLine className='h-4 w-4 text-text-tertiary hover:text-text-destructive' />
|
||||
<RiDeleteBinLine className={cn(
|
||||
'h-4 w-4 text-text-tertiary',
|
||||
!disableDeleteWhenSelected && 'hover:text-text-destructive',
|
||||
disableDeleteWhenSelected && 'opacity-50',
|
||||
)} />
|
||||
</ActionButton>
|
||||
</Tooltip>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
import {
|
||||
Fragment,
|
||||
memo,
|
||||
useCallback,
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react'
|
||||
import {
|
||||
RiAddLine,
|
||||
RiEqualizer2Line,
|
||||
} from '@remixicon/react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
|
|
@ -25,6 +24,7 @@ import type {
|
|||
Credential,
|
||||
CustomConfigurationModelFixedFields,
|
||||
CustomModel,
|
||||
ModelModalModeEnum,
|
||||
ModelProvider,
|
||||
} from '../../declarations'
|
||||
import { useAuth } from '../hooks'
|
||||
|
|
@ -34,15 +34,20 @@ type AuthorizedProps = {
|
|||
provider: ModelProvider,
|
||||
configurationMethod: ConfigurationMethodEnum,
|
||||
currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields,
|
||||
isModelCredential?: boolean
|
||||
authParams?: {
|
||||
isModelCredential?: boolean
|
||||
onUpdate?: (newPayload?: any, formValues?: Record<string, any>) => void
|
||||
onRemove?: (credentialId: string) => void
|
||||
mode?: ModelModalModeEnum
|
||||
}
|
||||
items: {
|
||||
title?: string
|
||||
model?: CustomModel
|
||||
selectedCredential?: Credential
|
||||
credentials: Credential[]
|
||||
}[]
|
||||
selectedCredential?: Credential
|
||||
disabled?: boolean
|
||||
renderTrigger?: (open?: boolean) => React.ReactNode
|
||||
renderTrigger: (open?: boolean) => React.ReactNode
|
||||
isOpen?: boolean
|
||||
onOpenChange?: (open: boolean) => void
|
||||
offset?: PortalToFollowElemOptions['offset']
|
||||
|
|
@ -50,18 +55,22 @@ type AuthorizedProps = {
|
|||
triggerPopupSameWidth?: boolean
|
||||
popupClassName?: string
|
||||
showItemSelectedIcon?: boolean
|
||||
onUpdate?: () => void
|
||||
onItemClick?: (credential: Credential, model?: CustomModel) => void
|
||||
enableAddModelCredential?: boolean
|
||||
bottomAddModelCredentialText?: string
|
||||
triggerOnlyOpenModal?: boolean
|
||||
hideAddAction?: boolean
|
||||
disableItemClick?: boolean
|
||||
popupTitle?: string
|
||||
showModelTitle?: boolean
|
||||
disableDeleteButShowAction?: boolean
|
||||
disableDeleteTip?: string
|
||||
}
|
||||
const Authorized = ({
|
||||
provider,
|
||||
configurationMethod,
|
||||
currentCustomConfigurationModelFixedFields,
|
||||
items,
|
||||
isModelCredential,
|
||||
selectedCredential,
|
||||
authParams,
|
||||
disabled,
|
||||
renderTrigger,
|
||||
isOpen,
|
||||
|
|
@ -71,10 +80,14 @@ const Authorized = ({
|
|||
triggerPopupSameWidth = false,
|
||||
popupClassName,
|
||||
showItemSelectedIcon,
|
||||
onUpdate,
|
||||
onItemClick,
|
||||
enableAddModelCredential,
|
||||
bottomAddModelCredentialText,
|
||||
triggerOnlyOpenModal,
|
||||
hideAddAction,
|
||||
disableItemClick,
|
||||
popupTitle,
|
||||
showModelTitle,
|
||||
disableDeleteButShowAction,
|
||||
disableDeleteTip,
|
||||
}: AuthorizedProps) => {
|
||||
const { t } = useTranslation()
|
||||
const [isLocalOpen, setIsLocalOpen] = useState(false)
|
||||
|
|
@ -85,6 +98,12 @@ const Authorized = ({
|
|||
|
||||
setIsLocalOpen(open)
|
||||
}, [onOpenChange])
|
||||
const {
|
||||
isModelCredential,
|
||||
onUpdate,
|
||||
onRemove,
|
||||
mode,
|
||||
} = authParams || {}
|
||||
const {
|
||||
openConfirmDelete,
|
||||
closeConfirmDelete,
|
||||
|
|
@ -93,7 +112,17 @@ const Authorized = ({
|
|||
handleConfirmDelete,
|
||||
deleteCredentialId,
|
||||
handleOpenModal,
|
||||
} = useAuth(provider, configurationMethod, currentCustomConfigurationModelFixedFields, isModelCredential, onUpdate)
|
||||
} = useAuth(
|
||||
provider,
|
||||
configurationMethod,
|
||||
currentCustomConfigurationModelFixedFields,
|
||||
{
|
||||
isModelCredential,
|
||||
onUpdate,
|
||||
onRemove,
|
||||
mode,
|
||||
},
|
||||
)
|
||||
|
||||
const handleEdit = useCallback((credential?: Credential, model?: CustomModel) => {
|
||||
handleOpenModal(credential, model)
|
||||
|
|
@ -101,28 +130,18 @@ const Authorized = ({
|
|||
}, [handleOpenModal, setMergedIsOpen])
|
||||
|
||||
const handleItemClick = useCallback((credential: Credential, model?: CustomModel) => {
|
||||
if (disableItemClick)
|
||||
return
|
||||
|
||||
if (onItemClick)
|
||||
onItemClick(credential, model)
|
||||
else
|
||||
handleActiveCredential(credential, model)
|
||||
|
||||
setMergedIsOpen(false)
|
||||
}, [handleActiveCredential, onItemClick, setMergedIsOpen])
|
||||
}, [handleActiveCredential, onItemClick, setMergedIsOpen, disableItemClick])
|
||||
const notAllowCustomCredential = provider.allow_custom_token === false
|
||||
|
||||
const Trigger = useMemo(() => {
|
||||
const Item = (
|
||||
<Button
|
||||
className='grow'
|
||||
size='small'
|
||||
>
|
||||
<RiEqualizer2Line className='mr-1 h-3.5 w-3.5' />
|
||||
{t('common.operation.config')}
|
||||
</Button>
|
||||
)
|
||||
return Item
|
||||
}, [t])
|
||||
|
||||
return (
|
||||
<>
|
||||
<PortalToFollowElem
|
||||
|
|
@ -134,44 +153,60 @@ const Authorized = ({
|
|||
>
|
||||
<PortalToFollowElemTrigger
|
||||
onClick={() => {
|
||||
if (triggerOnlyOpenModal) {
|
||||
handleOpenModal()
|
||||
return
|
||||
}
|
||||
|
||||
setMergedIsOpen(!mergedIsOpen)
|
||||
}}
|
||||
asChild
|
||||
>
|
||||
{
|
||||
renderTrigger
|
||||
? renderTrigger(mergedIsOpen)
|
||||
: Trigger
|
||||
}
|
||||
{renderTrigger(mergedIsOpen)}
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className='z-[100]'>
|
||||
<div className={cn(
|
||||
'w-[360px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg',
|
||||
'w-[360px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg backdrop-blur-[5px]',
|
||||
popupClassName,
|
||||
)}>
|
||||
{
|
||||
popupTitle && (
|
||||
<div className='system-xs-medium px-3 pb-0.5 pt-[10px] text-text-tertiary'>
|
||||
{popupTitle}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
<div className='max-h-[304px] overflow-y-auto'>
|
||||
{
|
||||
items.map((item, index) => (
|
||||
<AuthorizedItem
|
||||
key={index}
|
||||
title={item.title}
|
||||
model={item.model}
|
||||
credentials={item.credentials}
|
||||
disabled={disabled}
|
||||
onDelete={openConfirmDelete}
|
||||
onEdit={handleEdit}
|
||||
showItemSelectedIcon={showItemSelectedIcon}
|
||||
selectedCredentialId={selectedCredential?.credential_id}
|
||||
onItemClick={handleItemClick}
|
||||
enableAddModelCredential={enableAddModelCredential}
|
||||
notAllowCustomCredential={notAllowCustomCredential}
|
||||
/>
|
||||
<Fragment key={index}>
|
||||
<AuthorizedItem
|
||||
provider={provider}
|
||||
title={item.title}
|
||||
model={item.model}
|
||||
credentials={item.credentials}
|
||||
disabled={disabled}
|
||||
onDelete={openConfirmDelete}
|
||||
disableDeleteButShowAction={disableDeleteButShowAction}
|
||||
disableDeleteTip={disableDeleteTip}
|
||||
onEdit={handleEdit}
|
||||
showItemSelectedIcon={showItemSelectedIcon}
|
||||
selectedCredentialId={item.selectedCredential?.credential_id}
|
||||
onItemClick={handleItemClick}
|
||||
showModelTitle={showModelTitle}
|
||||
/>
|
||||
{
|
||||
index !== items.length - 1 && (
|
||||
<div className='h-[1px] bg-divider-subtle'></div>
|
||||
)
|
||||
}
|
||||
</Fragment>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
<div className='h-[1px] bg-divider-subtle'></div>
|
||||
{
|
||||
isModelCredential && !notAllowCustomCredential && (
|
||||
isModelCredential && !notAllowCustomCredential && !hideAddAction && (
|
||||
<div
|
||||
onClick={() => handleEdit(
|
||||
undefined,
|
||||
|
|
@ -182,15 +217,15 @@ const Authorized = ({
|
|||
}
|
||||
: undefined,
|
||||
)}
|
||||
className='system-xs-medium flex h-[30px] cursor-pointer items-center px-3 text-text-accent-light-mode-only'
|
||||
className='system-xs-medium flex h-[40px] cursor-pointer items-center px-3 text-text-accent-light-mode-only'
|
||||
>
|
||||
<RiAddLine className='mr-1 h-4 w-4' />
|
||||
{bottomAddModelCredentialText ?? t('common.modelProvider.auth.addModelCredential')}
|
||||
{t('common.modelProvider.auth.addModelCredential')}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
{
|
||||
!isModelCredential && !notAllowCustomCredential && (
|
||||
!isModelCredential && !notAllowCustomCredential && !hideAddAction && (
|
||||
<div className='p-2'>
|
||||
<Button
|
||||
onClick={() => handleEdit()}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue