Refactor/model credential (#24994)
This commit is contained in:
parent
b88146c443
commit
9e125e2029
30 changed files with 1226 additions and 596 deletions
|
|
@ -111,7 +111,6 @@ const CredentialPanel = ({
|
|||
<div className='flex items-center gap-0.5'>
|
||||
<ConfigProvider
|
||||
provider={provider}
|
||||
configurationMethod={ConfigurationMethodEnum.predefinedModel}
|
||||
/>
|
||||
{
|
||||
systemConfig.enabled && isCustomConfigured && (
|
||||
|
|
|
|||
|
|
@ -25,7 +25,10 @@ import { useEventEmitterContextContext } from '@/context/event-emitter'
|
|||
import { IS_CE_EDITION } from '@/config'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
import cn from '@/utils/classnames'
|
||||
import { AddCustomModel } from '@/app/components/header/account-setting/model-provider-page/model-auth'
|
||||
import {
|
||||
AddCustomModel,
|
||||
ManageCustomModelCredentials,
|
||||
} from '@/app/components/header/account-setting/model-provider-page/model-auth'
|
||||
|
||||
export const UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST = 'UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST'
|
||||
type ProviderAddedCardProps = {
|
||||
|
|
@ -155,10 +158,17 @@ const ProviderAddedCard: FC<ProviderAddedCardProps> = ({
|
|||
)}
|
||||
{
|
||||
configurationMethods.includes(ConfigurationMethodEnum.customizableModel) && isCurrentWorkspaceManager && (
|
||||
<AddCustomModel
|
||||
provider={provider}
|
||||
configurationMethod={ConfigurationMethodEnum.customizableModel}
|
||||
/>
|
||||
<div className='flex grow justify-end'>
|
||||
<ManageCustomModelCredentials
|
||||
provider={provider}
|
||||
currentCustomConfigurationModelFixedFields={undefined}
|
||||
/>
|
||||
<AddCustomModel
|
||||
provider={provider}
|
||||
configurationMethod={ConfigurationMethodEnum.customizableModel}
|
||||
currentCustomConfigurationModelFixedFields={undefined}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -16,7 +16,10 @@ import {
|
|||
import ModelListItem from './model-list-item'
|
||||
import { useModalContextSelector } from '@/context/modal-context'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
import { AddCustomModel } from '@/app/components/header/account-setting/model-provider-page/model-auth'
|
||||
import {
|
||||
AddCustomModel,
|
||||
ManageCustomModelCredentials,
|
||||
} from '@/app/components/header/account-setting/model-provider-page/model-auth'
|
||||
|
||||
type ModelListProps = {
|
||||
provider: ModelProvider
|
||||
|
|
@ -67,6 +70,10 @@ const ModelList: FC<ModelListProps> = ({
|
|||
{
|
||||
isConfigurable && isCurrentWorkspaceManager && (
|
||||
<div className='flex grow justify-end'>
|
||||
<ManageCustomModelCredentials
|
||||
provider={provider}
|
||||
currentCustomConfigurationModelFixedFields={undefined}
|
||||
/>
|
||||
<AddCustomModel
|
||||
provider={provider}
|
||||
configurationMethod={ConfigurationMethodEnum.customizableModel}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@ import type { Dispatch, SetStateAction } from 'react'
|
|||
import { useCallback, useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
RiDeleteBinLine,
|
||||
RiEqualizer2Line,
|
||||
RiIndeterminateCircleLine,
|
||||
} from '@remixicon/react'
|
||||
import type {
|
||||
Credential,
|
||||
|
|
@ -28,7 +27,6 @@ import GridMask from '@/app/components/base/grid-mask'
|
|||
import { useProviderContextSelector } from '@/context/provider-context'
|
||||
import { IS_CE_EDITION } from '@/config'
|
||||
import { AddCredentialInLoadBalancing } from '@/app/components/header/account-setting/model-provider-page/model-auth'
|
||||
import { useModelModalHandler } from '@/app/components/header/account-setting/model-provider-page/hooks'
|
||||
import Badge from '@/app/components/base/badge/index'
|
||||
|
||||
export type ModelLoadBalancingConfigsProps = {
|
||||
|
|
@ -40,7 +38,8 @@ export type ModelLoadBalancingConfigsProps = {
|
|||
withSwitch?: boolean
|
||||
className?: string
|
||||
modelCredential: ModelCredential
|
||||
onUpdate?: () => void
|
||||
onUpdate?: (payload?: any, formValues?: Record<string, any>) => void
|
||||
onRemove?: (credentialId: string) => void
|
||||
model: CustomModelCredential
|
||||
}
|
||||
|
||||
|
|
@ -55,11 +54,11 @@ const ModelLoadBalancingConfigs = ({
|
|||
className,
|
||||
modelCredential,
|
||||
onUpdate,
|
||||
onRemove,
|
||||
}: ModelLoadBalancingConfigsProps) => {
|
||||
const { t } = useTranslation()
|
||||
const providerFormSchemaPredefined = configurationMethod === ConfigurationMethodEnum.predefinedModel
|
||||
const modelLoadBalancingEnabled = useProviderContextSelector(state => state.modelLoadBalancingEnabled)
|
||||
const handleOpenModal = useModelModalHandler()
|
||||
|
||||
const updateConfigEntry = useCallback(
|
||||
(
|
||||
|
|
@ -130,6 +129,17 @@ const ModelLoadBalancingConfigs = ({
|
|||
return draftConfig.configs
|
||||
}, [draftConfig])
|
||||
|
||||
const handleUpdate = useCallback((payload?: any, formValues?: Record<string, any>) => {
|
||||
onUpdate?.(payload, formValues)
|
||||
}, [onUpdate])
|
||||
|
||||
const handleRemove = useCallback((credentialId: string) => {
|
||||
const index = draftConfig?.configs.findIndex(item => item.credential_id === credentialId && item.name !== '__inherit__')
|
||||
if (index && index > -1)
|
||||
updateConfigEntry(index, () => undefined)
|
||||
onRemove?.(credentialId)
|
||||
}, [draftConfig?.configs, updateConfigEntry, onRemove])
|
||||
|
||||
if (!draftConfig)
|
||||
return null
|
||||
|
||||
|
|
@ -190,7 +200,7 @@ const ModelLoadBalancingConfigs = ({
|
|||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
<div className='mr-1 text-[13px]'>
|
||||
<div className='mr-1 text-[13px] text-text-secondary'>
|
||||
{isProviderManaged ? t('common.modelProvider.defaultConfig') : config.name}
|
||||
</div>
|
||||
{isProviderManaged && providerFormSchemaPredefined && (
|
||||
|
|
@ -206,34 +216,14 @@ const ModelLoadBalancingConfigs = ({
|
|||
{!isProviderManaged && (
|
||||
<>
|
||||
<div className='flex items-center gap-1 opacity-0 transition-opacity group-hover:opacity-100'>
|
||||
{
|
||||
config.credential_id && !credential?.not_allowed_to_use && !credential?.from_enterprise && (
|
||||
<span
|
||||
className='flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg bg-components-button-secondary-bg text-text-tertiary transition-colors hover:bg-components-button-secondary-bg-hover'
|
||||
onClick={() => {
|
||||
handleOpenModal(
|
||||
provider,
|
||||
configurationMethod,
|
||||
currentCustomConfigurationModelFixedFields,
|
||||
configurationMethod === ConfigurationMethodEnum.customizableModel,
|
||||
(config.credential_id && config.name) ? {
|
||||
credential_id: config.credential_id,
|
||||
credential_name: config.name,
|
||||
} : undefined,
|
||||
model,
|
||||
)
|
||||
}}
|
||||
>
|
||||
<RiEqualizer2Line className='h-4 w-4' />
|
||||
</span>
|
||||
)
|
||||
}
|
||||
<span
|
||||
className='flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg bg-components-button-secondary-bg text-text-tertiary transition-colors hover:bg-components-button-secondary-bg-hover'
|
||||
onClick={() => updateConfigEntry(index, () => undefined)}
|
||||
>
|
||||
<RiDeleteBinLine className='h-4 w-4' />
|
||||
</span>
|
||||
<Tooltip popupContent={t('common.operation.remove')}>
|
||||
<span
|
||||
className='flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg bg-components-button-secondary-bg text-text-tertiary transition-colors hover:bg-components-button-secondary-bg-hover'
|
||||
onClick={() => updateConfigEntry(index, () => undefined)}
|
||||
>
|
||||
<RiIndeterminateCircleLine className='h-4 w-4' />
|
||||
</span>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
|
@ -261,7 +251,8 @@ const ModelLoadBalancingConfigs = ({
|
|||
configurationMethod={configurationMethod}
|
||||
modelCredential={modelCredential}
|
||||
onSelectCredential={addConfigEntry}
|
||||
onUpdate={onUpdate}
|
||||
onUpdate={handleUpdate}
|
||||
onRemove={handleRemove}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { memo, useCallback, useEffect, useMemo, useState } from 'react'
|
|||
import { useTranslation } from 'react-i18next'
|
||||
import type {
|
||||
Credential,
|
||||
CustomConfigurationModelFixedFields,
|
||||
ModelItem,
|
||||
ModelLoadBalancingConfig,
|
||||
ModelLoadBalancingConfigEntry,
|
||||
|
|
@ -24,10 +25,14 @@ import {
|
|||
useGetModelCredential,
|
||||
useUpdateModelLoadBalancingConfig,
|
||||
} from '@/service/use-models'
|
||||
import { useAuth } from '../model-auth/hooks/use-auth'
|
||||
import Confirm from '@/app/components/base/confirm'
|
||||
import { useRefreshModel } from '../hooks'
|
||||
|
||||
export type ModelLoadBalancingModalProps = {
|
||||
provider: ModelProvider
|
||||
configurateMethod: ConfigurationMethodEnum
|
||||
currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields
|
||||
model: ModelItem
|
||||
credential?: Credential
|
||||
open?: boolean
|
||||
|
|
@ -39,6 +44,7 @@ export type ModelLoadBalancingModalProps = {
|
|||
const ModelLoadBalancingModal = ({
|
||||
provider,
|
||||
configurateMethod,
|
||||
currentCustomConfigurationModelFixedFields,
|
||||
model,
|
||||
credential,
|
||||
open = false,
|
||||
|
|
@ -47,7 +53,20 @@ const ModelLoadBalancingModal = ({
|
|||
}: ModelLoadBalancingModalProps) => {
|
||||
const { t } = useTranslation()
|
||||
const { notify } = useToastContext()
|
||||
|
||||
const {
|
||||
doingAction,
|
||||
deleteModel,
|
||||
openConfirmDelete,
|
||||
closeConfirmDelete,
|
||||
handleConfirmDelete,
|
||||
} = useAuth(
|
||||
provider,
|
||||
configurateMethod,
|
||||
currentCustomConfigurationModelFixedFields,
|
||||
{
|
||||
isModelCredential: true,
|
||||
},
|
||||
)
|
||||
const [loading, setLoading] = useState(false)
|
||||
const providerFormSchemaPredefined = configurateMethod === ConfigurationMethodEnum.predefinedModel
|
||||
const configFrom = providerFormSchemaPredefined ? 'predefined-model' : 'custom-model'
|
||||
|
|
@ -121,6 +140,7 @@ const ModelLoadBalancingModal = ({
|
|||
}
|
||||
}, [current_credential_id, current_credential_name])
|
||||
const [customModelCredential, setCustomModelCredential] = useState<Credential | undefined>(initialCustomModelCredential)
|
||||
const { handleRefreshModel } = useRefreshModel()
|
||||
const handleSave = async () => {
|
||||
try {
|
||||
setLoading(true)
|
||||
|
|
@ -139,6 +159,7 @@ const ModelLoadBalancingModal = ({
|
|||
)
|
||||
if (res.result === 'success') {
|
||||
notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
|
||||
handleRefreshModel(provider, configurateMethod, currentCustomConfigurationModelFixedFields)
|
||||
onSave?.(provider.provider)
|
||||
onClose?.()
|
||||
}
|
||||
|
|
@ -147,120 +168,208 @@ const ModelLoadBalancingModal = ({
|
|||
setLoading(false)
|
||||
}
|
||||
}
|
||||
const handleDeleteModel = useCallback(async () => {
|
||||
await handleConfirmDelete()
|
||||
onClose?.()
|
||||
}, [handleConfirmDelete, onClose])
|
||||
|
||||
const handleUpdate = useCallback(async (payload?: any, formValues?: Record<string, any>) => {
|
||||
const result = await refetch()
|
||||
const available_credentials = result.data?.available_credentials || []
|
||||
const credentialName = formValues?.__authorization_name__
|
||||
const modelCredential = payload?.credential
|
||||
|
||||
if (!available_credentials.length) {
|
||||
onClose?.()
|
||||
return
|
||||
}
|
||||
|
||||
if (!modelCredential) {
|
||||
const currentCredential = available_credentials.find(c => c.credential_name === credentialName)
|
||||
if (currentCredential) {
|
||||
setDraftConfig((prev: any) => {
|
||||
if (!prev)
|
||||
return prev
|
||||
return {
|
||||
...prev,
|
||||
configs: [...prev.configs, {
|
||||
credential_id: currentCredential.credential_id,
|
||||
enabled: true,
|
||||
name: currentCredential.credential_name,
|
||||
}],
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
else {
|
||||
setDraftConfig((prev) => {
|
||||
if (!prev)
|
||||
return prev
|
||||
const newConfigs = [...prev.configs]
|
||||
const prevIndex = newConfigs.findIndex(item => item.credential_id === modelCredential.credential_id && item.name !== '__inherit__')
|
||||
const newIndex = available_credentials.findIndex(c => c.credential_id === modelCredential.credential_id)
|
||||
|
||||
if (newIndex > -1 && prevIndex > -1)
|
||||
newConfigs[prevIndex].name = available_credentials[newIndex].credential_name || ''
|
||||
|
||||
return {
|
||||
...prev,
|
||||
configs: newConfigs,
|
||||
}
|
||||
})
|
||||
}
|
||||
}, [refetch, credential])
|
||||
|
||||
const handleUpdateWhenSwitchCredential = useCallback(async () => {
|
||||
const result = await refetch()
|
||||
const available_credentials = result.data?.available_credentials || []
|
||||
if (!available_credentials.length)
|
||||
onClose?.()
|
||||
}, [refetch, onClose])
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isShow={Boolean(model) && open}
|
||||
onClose={onClose}
|
||||
className='w-[640px] max-w-none px-8 pt-8'
|
||||
title={
|
||||
<div className='pb-3 font-semibold'>
|
||||
<div className='h-[30px]'>{
|
||||
draftConfig?.enabled
|
||||
? t('common.modelProvider.auth.configLoadBalancing')
|
||||
: t('common.modelProvider.auth.configModel')
|
||||
}</div>
|
||||
{Boolean(model) && (
|
||||
<div className='flex h-5 items-center'>
|
||||
<ModelIcon
|
||||
className='mr-2 shrink-0'
|
||||
provider={provider}
|
||||
modelName={model!.model}
|
||||
/>
|
||||
<ModelName
|
||||
className='system-md-regular grow text-text-secondary'
|
||||
modelItem={model!}
|
||||
showModelType
|
||||
showMode
|
||||
showContextSize
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
>
|
||||
{!draftConfig
|
||||
? <Loading type='area' />
|
||||
: (
|
||||
<>
|
||||
<div className='py-2'>
|
||||
<div
|
||||
className={classNames(
|
||||
'min-h-16 rounded-xl border bg-components-panel-bg transition-colors',
|
||||
draftConfig.enabled ? 'cursor-pointer border-components-panel-border' : 'cursor-default border-util-colors-blue-blue-600',
|
||||
)}
|
||||
onClick={draftConfig.enabled ? () => toggleModalBalancing(false) : undefined}
|
||||
>
|
||||
<div className='flex select-none items-center gap-2 px-[15px] py-3'>
|
||||
<div className='flex h-8 w-8 shrink-0 grow-0 items-center justify-center rounded-lg border border-components-card-border bg-components-card-bg'>
|
||||
{Boolean(model) && (
|
||||
<ModelIcon className='shrink-0' provider={provider} modelName={model!.model} />
|
||||
)}
|
||||
</div>
|
||||
<div className='grow'>
|
||||
<div className='text-sm text-text-secondary'>{
|
||||
providerFormSchemaPredefined
|
||||
? t('common.modelProvider.auth.providerManaged')
|
||||
: t('common.modelProvider.auth.specifyModelCredential')
|
||||
}</div>
|
||||
<div className='text-xs text-text-tertiary'>{
|
||||
providerFormSchemaPredefined
|
||||
? t('common.modelProvider.auth.providerManagedTip')
|
||||
: t('common.modelProvider.auth.specifyModelCredentialTip')
|
||||
}</div>
|
||||
<>
|
||||
<Modal
|
||||
isShow={Boolean(model) && open}
|
||||
onClose={onClose}
|
||||
className='w-[640px] max-w-none px-8 pt-8'
|
||||
title={
|
||||
<div className='pb-3 font-semibold'>
|
||||
<div className='h-[30px]'>{
|
||||
draftConfig?.enabled
|
||||
? t('common.modelProvider.auth.configLoadBalancing')
|
||||
: t('common.modelProvider.auth.configModel')
|
||||
}</div>
|
||||
{Boolean(model) && (
|
||||
<div className='flex h-5 items-center'>
|
||||
<ModelIcon
|
||||
className='mr-2 shrink-0'
|
||||
provider={provider}
|
||||
modelName={model!.model}
|
||||
/>
|
||||
<ModelName
|
||||
className='system-md-regular grow text-text-secondary'
|
||||
modelItem={model!}
|
||||
showModelType
|
||||
showMode
|
||||
showContextSize
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
>
|
||||
{!draftConfig
|
||||
? <Loading type='area' />
|
||||
: (
|
||||
<>
|
||||
<div className='py-2'>
|
||||
<div
|
||||
className={classNames(
|
||||
'min-h-16 rounded-xl border bg-components-panel-bg transition-colors',
|
||||
draftConfig.enabled ? 'cursor-pointer border-components-panel-border' : 'cursor-default border-util-colors-blue-blue-600',
|
||||
)}
|
||||
onClick={draftConfig.enabled ? () => toggleModalBalancing(false) : undefined}
|
||||
>
|
||||
<div className='flex select-none items-center gap-2 px-[15px] py-3'>
|
||||
<div className='flex h-8 w-8 shrink-0 grow-0 items-center justify-center rounded-lg border border-components-card-border bg-components-card-bg'>
|
||||
{Boolean(model) && (
|
||||
<ModelIcon className='shrink-0' provider={provider} modelName={model!.model} />
|
||||
)}
|
||||
</div>
|
||||
<div className='grow'>
|
||||
<div className='text-sm text-text-secondary'>{
|
||||
providerFormSchemaPredefined
|
||||
? t('common.modelProvider.auth.providerManaged')
|
||||
: t('common.modelProvider.auth.specifyModelCredential')
|
||||
}</div>
|
||||
<div className='text-xs text-text-tertiary'>{
|
||||
providerFormSchemaPredefined
|
||||
? t('common.modelProvider.auth.providerManagedTip')
|
||||
: t('common.modelProvider.auth.specifyModelCredentialTip')
|
||||
}</div>
|
||||
</div>
|
||||
{
|
||||
!providerFormSchemaPredefined && (
|
||||
<SwitchCredentialInLoadBalancing
|
||||
provider={provider}
|
||||
customModelCredential={customModelCredential ?? initialCustomModelCredential}
|
||||
setCustomModelCredential={setCustomModelCredential}
|
||||
model={model}
|
||||
credentials={available_credentials}
|
||||
onUpdate={handleUpdateWhenSwitchCredential}
|
||||
onRemove={handleUpdateWhenSwitchCredential}
|
||||
/>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
{
|
||||
modelCredential && (
|
||||
<ModelLoadBalancingConfigs {...{
|
||||
draftConfig,
|
||||
setDraftConfig,
|
||||
provider,
|
||||
currentCustomConfigurationModelFixedFields: {
|
||||
__model_name: model.model,
|
||||
__model_type: model.model_type,
|
||||
},
|
||||
configurationMethod: model.fetch_from,
|
||||
className: 'mt-2',
|
||||
modelCredential,
|
||||
onUpdate: handleUpdate,
|
||||
onRemove: handleUpdateWhenSwitchCredential,
|
||||
model: {
|
||||
model: model.model,
|
||||
model_type: model.model_type,
|
||||
},
|
||||
}} />
|
||||
)
|
||||
}
|
||||
</div>
|
||||
|
||||
<div className='mt-6 flex items-center justify-between gap-2'>
|
||||
<div>
|
||||
{
|
||||
!providerFormSchemaPredefined && (
|
||||
<SwitchCredentialInLoadBalancing
|
||||
provider={provider}
|
||||
customModelCredential={initialCustomModelCredential ?? customModelCredential}
|
||||
setCustomModelCredential={setCustomModelCredential}
|
||||
model={model}
|
||||
credentials={available_credentials}
|
||||
/>
|
||||
<Button
|
||||
onClick={() => openConfirmDelete(undefined, { model: model.model, model_type: model.model_type })}
|
||||
className='text-components-button-destructive-secondary-text'
|
||||
>
|
||||
{t('common.modelProvider.auth.removeModel')}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
<div className='space-x-2'>
|
||||
<Button onClick={onClose}>{t('common.operation.cancel')}</Button>
|
||||
<Button
|
||||
variant='primary'
|
||||
onClick={handleSave}
|
||||
disabled={
|
||||
loading
|
||||
|| (draftConfig?.enabled && (draftConfig?.configs.filter(config => config.enabled).length ?? 0) < 2)
|
||||
|| isLoading
|
||||
}
|
||||
>{t('common.operation.save')}</Button>
|
||||
</div>
|
||||
</div>
|
||||
{
|
||||
modelCredential && (
|
||||
<ModelLoadBalancingConfigs {...{
|
||||
draftConfig,
|
||||
setDraftConfig,
|
||||
provider,
|
||||
currentCustomConfigurationModelFixedFields: {
|
||||
__model_name: model.model,
|
||||
__model_type: model.model_type,
|
||||
},
|
||||
configurationMethod: model.fetch_from,
|
||||
className: 'mt-2',
|
||||
modelCredential,
|
||||
onUpdate: refetch,
|
||||
model: {
|
||||
model: model.model,
|
||||
model_type: model.model_type,
|
||||
},
|
||||
}} />
|
||||
)
|
||||
}
|
||||
</div>
|
||||
|
||||
<div className='mt-6 flex items-center justify-end gap-2'>
|
||||
<Button onClick={onClose}>{t('common.operation.cancel')}</Button>
|
||||
<Button
|
||||
variant='primary'
|
||||
onClick={handleSave}
|
||||
disabled={
|
||||
loading
|
||||
|| (draftConfig?.enabled && (draftConfig?.configs.filter(config => config.enabled).length ?? 0) < 2)
|
||||
|| isLoading
|
||||
}
|
||||
>{t('common.operation.save')}</Button>
|
||||
</div>
|
||||
</>
|
||||
</>
|
||||
)
|
||||
}
|
||||
</Modal >
|
||||
{
|
||||
deleteModel && (
|
||||
<Confirm
|
||||
isShow
|
||||
title={t('common.modelProvider.confirmDelete')}
|
||||
onCancel={closeConfirmDelete}
|
||||
onConfirm={handleDeleteModel}
|
||||
isDisabled={doingAction}
|
||||
/>
|
||||
)
|
||||
}
|
||||
</Modal >
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue