mirror of https://github.com/langgenius/dify.git
model auth
This commit is contained in:
parent
4e02abf784
commit
3f57e4a643
|
|
@ -80,13 +80,13 @@ export const useProviderCredentialsAndLoadBalancing = (
|
|||
currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields,
|
||||
credentialId?: string,
|
||||
) => {
|
||||
const { data: predefinedFormSchemasValue, mutate: mutatePredefined } = useSWR(
|
||||
const { data: predefinedFormSchemasValue, mutate: mutatePredefined, isLoading: isPredefinedLoading } = useSWR(
|
||||
(configurationMethod === ConfigurationMethodEnum.predefinedModel && configured && credentialId)
|
||||
? `/workspaces/current/model-providers/${provider}/credentials${credentialId ? `?credential_id=${credentialId}` : ''}`
|
||||
: null,
|
||||
fetchModelProviderCredentials,
|
||||
)
|
||||
const { data: customFormSchemasValue, mutate: mutateCustomized } = useSWR(
|
||||
const { data: customFormSchemasValue, mutate: mutateCustomized, isLoading: isCustomizedLoading } = useSWR(
|
||||
(configurationMethod === ConfigurationMethodEnum.customizableModel && currentCustomConfigurationModelFixedFields && credentialId)
|
||||
? `/workspaces/current/model-providers/${provider}/models/credentials?model=${currentCustomConfigurationModelFixedFields?.__model_name}&model_type=${currentCustomConfigurationModelFixedFields?.__model_type}${credentialId ? `&credential_id=${credentialId}` : ''}`
|
||||
: null,
|
||||
|
|
@ -122,6 +122,7 @@ export const useProviderCredentialsAndLoadBalancing = (
|
|||
: customFormSchemasValue
|
||||
)?.load_balancing,
|
||||
mutate,
|
||||
isLoading: isPredefinedLoading || isCustomizedLoading,
|
||||
}
|
||||
// as ([Record<string, string | boolean | undefined> | undefined, ModelLoadBalancingConfig | undefined])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,10 @@ import Confirm from '@/app/components/base/confirm'
|
|||
import Item from './item'
|
||||
import { useToastContext } from '@/app/components/base/toast'
|
||||
import type { Credential } from '../../declarations'
|
||||
import { useDeleteModelCredential } from '@/service/use-models'
|
||||
import {
|
||||
useDeleteModelCredential,
|
||||
useSetModelCredentialDefault,
|
||||
} from '@/service/use-models'
|
||||
|
||||
type AuthorizedProps = {
|
||||
provider: string
|
||||
|
|
@ -87,6 +90,23 @@ const Authorized = ({
|
|||
setDoingAction(doing)
|
||||
}, [])
|
||||
const { mutateAsync: deleteModelCredential } = useDeleteModelCredential(provider)
|
||||
const { mutateAsync: setModelCredentialDefault } = useSetModelCredentialDefault(provider)
|
||||
const handleSetDefault = useCallback(async (id: string) => {
|
||||
if (doingActionRef.current)
|
||||
return
|
||||
try {
|
||||
handleSetDoingAction(true)
|
||||
await setModelCredentialDefault(id)
|
||||
notify({
|
||||
type: 'success',
|
||||
message: t('common.api.actionSuccess'),
|
||||
})
|
||||
onUpdate?.()
|
||||
}
|
||||
finally {
|
||||
handleSetDoingAction(false)
|
||||
}
|
||||
}, [setModelCredentialDefault, onUpdate, notify, t, handleSetDoingAction])
|
||||
const handleConfirm = useCallback(async () => {
|
||||
if (doingActionRef.current)
|
||||
return
|
||||
|
|
@ -109,9 +129,10 @@ const Authorized = ({
|
|||
handleSetDoingAction(false)
|
||||
}
|
||||
}, [onUpdate, notify, t, handleSetDoingAction])
|
||||
const handleEdit = useCallback((credential: Credential) => {
|
||||
const handleOpenSetup = useCallback((credential?: Credential) => {
|
||||
onSetup(credential)
|
||||
}, [onSetup])
|
||||
setMergedIsOpen(false)
|
||||
}, [onSetup, setMergedIsOpen])
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
@ -142,10 +163,10 @@ const Authorized = ({
|
|||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className='z-[100]'>
|
||||
<div className={cn(
|
||||
'max-h-[360px] w-[360px] overflow-y-auto 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',
|
||||
popupClassName,
|
||||
)}>
|
||||
<div className='py-1'>
|
||||
<div className='max-h-[304px] overflow-y-auto py-1'>
|
||||
{
|
||||
!!credentials.length && (
|
||||
<div className='p-1'>
|
||||
|
|
@ -162,7 +183,8 @@ const Authorized = ({
|
|||
credential={credential}
|
||||
disabled={disabled}
|
||||
onDelete={openConfirm}
|
||||
onEdit={handleEdit}
|
||||
onEdit={handleOpenSetup}
|
||||
onSetDefault={handleSetDefault}
|
||||
onItemClick={onItemClick}
|
||||
showSelectedIcon={showItemSelectedIcon}
|
||||
selectedCredentialId={selectedCredentialId}
|
||||
|
|
@ -176,7 +198,7 @@ const Authorized = ({
|
|||
<div className='h-[1px] bg-divider-subtle'></div>
|
||||
<div className='p-2'>
|
||||
<Button
|
||||
onClick={() => onSetup()}
|
||||
onClick={() => handleOpenSetup()}
|
||||
className='w-full'
|
||||
>
|
||||
add api key
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import ActionButton from '@/app/components/base/action-button'
|
|||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import cn from '@/utils/classnames'
|
||||
import type { Credential } from '../../declarations'
|
||||
import Button from '@/app/components/base/button'
|
||||
|
||||
type ItemProps = {
|
||||
credential: Credential
|
||||
|
|
@ -33,6 +34,7 @@ const Item = ({
|
|||
disabled,
|
||||
onDelete,
|
||||
onEdit,
|
||||
onSetDefault,
|
||||
disableRename,
|
||||
disableEdit,
|
||||
disableDelete,
|
||||
|
|
@ -77,6 +79,20 @@ const Item = ({
|
|||
{
|
||||
showAction && (
|
||||
<div className='ml-2 hidden shrink-0 items-center group-hover:flex'>
|
||||
{
|
||||
!disableSetDefault && (
|
||||
<Button
|
||||
size='small'
|
||||
disabled={disabled}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
onSetDefault?.(credential.credential_id)
|
||||
}}
|
||||
>
|
||||
{t('plugin.auth.setDefault')}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
{
|
||||
!disableEdit && (
|
||||
<Tooltip popupContent={t('common.operation.edit')}>
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ import type {
|
|||
} from '@/app/components/base/form/types'
|
||||
import { useModelFormSchemas } from '../model-auth/hooks'
|
||||
import type { Credential } from '../declarations'
|
||||
import Loading from '@/app/components/base/loading'
|
||||
|
||||
type ModelModalProps = {
|
||||
provider: ModelProvider
|
||||
|
|
@ -70,6 +71,7 @@ const ModelModal: FC<ModelModalProps> = ({
|
|||
credentials: formSchemasValue,
|
||||
loadBalancing: originalConfig,
|
||||
mutate,
|
||||
isLoading,
|
||||
} = useProviderCredentialsAndLoadBalancing(
|
||||
provider.provider,
|
||||
configurateMethod,
|
||||
|
|
@ -185,7 +187,7 @@ const ModelModal: FC<ModelModalProps> = ({
|
|||
)
|
||||
if (res.result === 'success') {
|
||||
notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
|
||||
mutate()
|
||||
// mutate()
|
||||
onSave()
|
||||
onCancel()
|
||||
}
|
||||
|
|
@ -211,21 +213,32 @@ const ModelModal: FC<ModelModalProps> = ({
|
|||
</div>
|
||||
|
||||
<div className='max-h-[calc(100vh-320px)] overflow-y-auto'>
|
||||
<AuthForm
|
||||
formSchemas={formSchemas.map((formSchema) => {
|
||||
return {
|
||||
...formSchema,
|
||||
name: formSchema.variable,
|
||||
showRadioUI: formSchema.type === FormTypeEnum.radio,
|
||||
}
|
||||
}) as FormSchema[]}
|
||||
defaultValues={{
|
||||
...formSchemasValue,
|
||||
__authorization_name__: credential?.credential_name,
|
||||
}}
|
||||
inputClassName='justify-start'
|
||||
ref={formRef}
|
||||
/>
|
||||
{
|
||||
isLoading && (
|
||||
<div className='flex items-center justify-center'>
|
||||
<Loading />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
{
|
||||
!isLoading && (
|
||||
<AuthForm
|
||||
formSchemas={formSchemas.map((formSchema) => {
|
||||
return {
|
||||
...formSchema,
|
||||
name: formSchema.variable,
|
||||
showRadioUI: formSchema.type === FormTypeEnum.radio,
|
||||
}
|
||||
}) as FormSchema[]}
|
||||
defaultValues={{
|
||||
...formSchemasValue,
|
||||
__authorization_name__: credential?.credential_name,
|
||||
}}
|
||||
inputClassName='justify-start'
|
||||
ref={formRef}
|
||||
/>
|
||||
)
|
||||
}
|
||||
{
|
||||
!!draftConfig && (
|
||||
<>
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import { changeModelProviderPriority } from '@/service/common'
|
|||
import { useToastContext } from '@/app/components/base/toast'
|
||||
import { useEventEmitterContextContext } from '@/context/event-emitter'
|
||||
import Authorized from '../model-auth/authorized'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
type CredentialPanelProps = {
|
||||
provider: ModelProvider
|
||||
|
|
@ -49,8 +50,9 @@ const CredentialPanel = ({
|
|||
current_credential_name,
|
||||
available_credentials,
|
||||
} = provider.custom_configuration
|
||||
const authorized = current_credential_id && current_credential_name && available_credentials?.every(item => !!item.credential_id)
|
||||
const authRemoved = !!available_credentials?.length && available_credentials?.every(item => !item.credential_id)
|
||||
const hasCredential = !!available_credentials?.length
|
||||
const authorized = current_credential_id && current_credential_name
|
||||
const authRemoved = hasCredential && !current_credential_id && !current_credential_name
|
||||
|
||||
const handleChangePriority = async (key: PreferredProviderTypeEnum) => {
|
||||
const res = await changeModelProviderPriority({
|
||||
|
|
@ -75,21 +77,30 @@ const CredentialPanel = ({
|
|||
}
|
||||
}
|
||||
const credentialLabel = useMemo(() => {
|
||||
if (!hasCredential)
|
||||
return t('common.model.unAuthorized')
|
||||
if (authorized)
|
||||
return current_credential_name
|
||||
if (authRemoved)
|
||||
return 'Auth removed'
|
||||
return 'Unauthorized'
|
||||
}, [authorized, authRemoved, current_credential_name])
|
||||
return t('common.model.authRemoved')
|
||||
|
||||
return ''
|
||||
}, [authorized, authRemoved, current_credential_name, hasCredential])
|
||||
|
||||
return (
|
||||
<>
|
||||
{
|
||||
provider.provider_credential_schema && (
|
||||
<div className='relative ml-1 w-[112px] shrink-0 rounded-lg border-[0.5px] border-components-panel-border bg-white/[0.18] p-1'>
|
||||
<div className={cn(
|
||||
'relative ml-1 w-[120px] shrink-0 rounded-lg border-[0.5px] border-components-panel-border bg-white/[0.18] p-1',
|
||||
authRemoved && 'border-state-destructive-border bg-state-destructive-hover',
|
||||
)}>
|
||||
<div className='system-xs-medium mb-1 flex h-5 items-center justify-between pl-2 pr-[7px] pt-1 text-text-tertiary'>
|
||||
<div
|
||||
className='grow truncate'
|
||||
className={cn(
|
||||
'grow truncate',
|
||||
authRemoved && 'text-text-destructive',
|
||||
)}
|
||||
title={credentialLabel}
|
||||
>
|
||||
{credentialLabel}
|
||||
|
|
@ -98,7 +109,7 @@ const CredentialPanel = ({
|
|||
</div>
|
||||
<div className='flex items-center gap-0.5'>
|
||||
{
|
||||
(!authorized || authRemoved) && (
|
||||
!hasCredential && (
|
||||
<Button
|
||||
className='grow'
|
||||
size='small'
|
||||
|
|
@ -106,16 +117,12 @@ const CredentialPanel = ({
|
|||
variant={!authorized ? 'secondary-accent' : 'secondary'}
|
||||
>
|
||||
<RiEqualizer2Line className='mr-1 h-3.5 w-3.5' />
|
||||
{
|
||||
authRemoved
|
||||
? t('common.operation.config')
|
||||
: t('common.operation.setup')
|
||||
}
|
||||
{t('common.operation.setup')}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
{
|
||||
authorized && (
|
||||
(hasCredential || authRemoved) && (
|
||||
<Authorized
|
||||
provider={provider.provider}
|
||||
onSetup={onSetup}
|
||||
|
|
|
|||
|
|
@ -145,6 +145,8 @@ const translation = {
|
|||
addMoreModel: 'Go to settings to add more models',
|
||||
settingsLink: 'Model Provider Settings',
|
||||
capabilities: 'MultiModal Capabilities',
|
||||
unAuthorized: 'Unauthorized',
|
||||
authRemoved: 'Auth removed',
|
||||
},
|
||||
menus: {
|
||||
status: 'beta',
|
||||
|
|
|
|||
|
|
@ -145,6 +145,8 @@ const translation = {
|
|||
addMoreModel: '添加更多模型',
|
||||
settingsLink: '模型设置',
|
||||
capabilities: '多模态能力',
|
||||
unAuthorized: '未授权',
|
||||
authRemoved: '授权已移除',
|
||||
},
|
||||
menus: {
|
||||
status: 'beta',
|
||||
|
|
|
|||
|
|
@ -43,3 +43,13 @@ export const useDeleteModelCredential = (providerName: string) => {
|
|||
}),
|
||||
})
|
||||
}
|
||||
|
||||
export const useSetModelCredentialDefault = (providerName: string) => {
|
||||
return useMutation({
|
||||
mutationFn: (credentialId: string) => post<{ result: string }>(`/workspaces/current/model-providers/${providerName}/credentials/switch`, {
|
||||
body: {
|
||||
credential_id: credentialId,
|
||||
},
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue