mirror of
https://github.com/langgenius/dify.git
synced 2026-05-05 09:58:04 +08:00
refactor: update model attribute references from 'model' to 'model_name' across multiple files and introduce new fetch_model_config function in llm_utils.py
This commit is contained in:
@ -3,6 +3,7 @@ export const ACCOUNT_SETTING_MODAL_ACTION = 'showSettings'
|
||||
export const ACCOUNT_SETTING_TAB = {
|
||||
SANDBOX_PROVIDER: 'sandbox-provider',
|
||||
MODEL_PROVIDER: 'model-provider',
|
||||
PROVIDER: 'model-provider',
|
||||
MEMBERS: 'members',
|
||||
BILLING: 'billing',
|
||||
DATA_SOURCE: 'data-source',
|
||||
|
||||
@ -32,6 +32,7 @@ import Trigger from './trigger'
|
||||
|
||||
export type ModelParameterModalProps = {
|
||||
popupClassName?: string
|
||||
portalToFollowElemContentClassName?: string
|
||||
isAdvancedMode: boolean
|
||||
modelId: string
|
||||
provider: string
|
||||
|
||||
@ -19,6 +19,7 @@ import {
|
||||
|
||||
export type TriggerProps = {
|
||||
open?: boolean
|
||||
disabled?: boolean
|
||||
currentProvider?: ModelProvider | Model
|
||||
currentModel?: ModelItem
|
||||
providerName?: string
|
||||
|
||||
@ -7,9 +7,9 @@ import { useTranslation } from 'react-i18next'
|
||||
import Button from '@/app/components/base/button'
|
||||
import { BaseForm } from '@/app/components/base/form/components/base'
|
||||
import { FormTypeEnum } from '@/app/components/base/form/types'
|
||||
import Modal from '@/app/components/base/modal'
|
||||
import RadioUI from '@/app/components/base/radio/ui'
|
||||
import { useToastContext } from '@/app/components/base/toast/context'
|
||||
import { Dialog, DialogCloseButton, DialogContent } from '@/app/components/base/ui/dialog'
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
import {
|
||||
useActivateSandboxProvider,
|
||||
useDeleteSandboxProviderConfig,
|
||||
@ -21,7 +21,6 @@ import ProviderIcon from './provider-icon'
|
||||
|
||||
type ConfigMode = 'managed' | 'byok'
|
||||
|
||||
// Providers that support mode selection (must have system config available)
|
||||
const PROVIDERS_WITH_MODE_SELECTION: readonly string[] = ['e2b']
|
||||
|
||||
type ModeOptionProps = {
|
||||
@ -64,20 +63,16 @@ type ConfigModalProps = {
|
||||
|
||||
function ConfigModal({ provider, onClose }: ConfigModalProps) {
|
||||
const { t } = useTranslation()
|
||||
const { notify } = useToastContext()
|
||||
const formRef = useRef<FormRefObject>(null)
|
||||
|
||||
const { mutateAsync: saveConfig, isPending: isSaving } = useSaveSandboxProviderConfig()
|
||||
const { mutateAsync: deleteConfig, isPending: isDeleting } = useDeleteSandboxProviderConfig()
|
||||
const { mutateAsync: activateProvider, isPending: isActivating } = useActivateSandboxProvider()
|
||||
|
||||
// Determine if mode selection should be shown (for providers that support it)
|
||||
const shouldShowModeSelection = PROVIDERS_WITH_MODE_SELECTION.includes(provider.provider_type)
|
||||
|
||||
// Managed mode is only available when system has configured this provider
|
||||
const isManagedModeAvailable = provider.is_system_configured
|
||||
|
||||
// Determine default mode based on configuration state
|
||||
const defaultMode: ConfigMode = provider.is_tenant_configured
|
||||
? 'byok'
|
||||
: provider.is_system_configured
|
||||
@ -105,11 +100,10 @@ function ConfigModal({ provider, onClose }: ConfigModalProps) {
|
||||
}, [provider.config_schema, provider.config, t])
|
||||
|
||||
const handleSave = useCallback(async () => {
|
||||
// For managed mode, activate system config (preserves user config for future use)
|
||||
if (shouldShowModeSelection && configMode === 'managed') {
|
||||
try {
|
||||
await activateProvider({ providerType: provider.provider_type, type: 'system' })
|
||||
notify({ type: 'success', message: t('api.saved', { ns: 'common' }) })
|
||||
toast.success(t('api.saved', { ns: 'common' }))
|
||||
onClose()
|
||||
}
|
||||
catch {
|
||||
@ -118,7 +112,6 @@ function ConfigModal({ provider, onClose }: ConfigModalProps) {
|
||||
return
|
||||
}
|
||||
|
||||
// For BYOK mode, validate and save user-provided config
|
||||
const formValues = formRef.current?.getFormValues({
|
||||
needTransformWhenSecretFieldIsPristine: true,
|
||||
})
|
||||
@ -132,124 +125,126 @@ function ConfigModal({ provider, onClose }: ConfigModalProps) {
|
||||
config: formValues.values,
|
||||
activate: true,
|
||||
})
|
||||
notify({ type: 'success', message: t('api.saved', { ns: 'common' }) })
|
||||
toast.success(t('api.saved', { ns: 'common' }))
|
||||
onClose()
|
||||
}
|
||||
catch {
|
||||
// Error toast is handled by fetch layer
|
||||
}
|
||||
}, [shouldShowModeSelection, configMode, saveConfig, activateProvider, provider.provider_type, notify, t, onClose])
|
||||
}, [shouldShowModeSelection, configMode, saveConfig, activateProvider, provider.provider_type, t, onClose])
|
||||
|
||||
const handleRevoke = useCallback(async () => {
|
||||
try {
|
||||
await deleteConfig(provider.provider_type)
|
||||
notify({ type: 'success', message: t('api.remove', { ns: 'common' }) })
|
||||
toast.success(t('api.remove', { ns: 'common' }))
|
||||
onClose()
|
||||
}
|
||||
catch {
|
||||
// Error toast is handled by fetch layer
|
||||
}
|
||||
}, [deleteConfig, provider.provider_type, notify, t, onClose])
|
||||
}, [deleteConfig, provider.provider_type, t, onClose])
|
||||
|
||||
const docLink = PROVIDER_DOC_LINKS[provider.provider_type]
|
||||
const providerLabel = PROVIDER_STATIC_LABELS[provider.provider_type as keyof typeof PROVIDER_STATIC_LABELS]
|
||||
?? provider.provider_type
|
||||
|
||||
// Only show revoke button when in BYOK mode, tenant has custom config, and provider is not active
|
||||
// (active provider cannot be revoked to prevent "no sandbox provider" error)
|
||||
const showRevokeButton = provider.is_tenant_configured && !provider.is_active && (!shouldShowModeSelection || configMode === 'byok')
|
||||
const isActionDisabled = isSaving || isDeleting || isActivating
|
||||
const showByokForm = !shouldShowModeSelection || configMode === 'byok'
|
||||
|
||||
return (
|
||||
<Modal isShow onClose={onClose} closable className="w-[480px]">
|
||||
{/* Header */}
|
||||
<div className="mb-4 flex flex-col gap-2">
|
||||
<h3 className="text-text-primary title-2xl-semi-bold">
|
||||
{t('sandboxProvider.configModal.title', { ns: 'common' })}
|
||||
</h3>
|
||||
<div className="flex items-center gap-2">
|
||||
<ProviderIcon providerType={provider.provider_type} size="sm" withBorder />
|
||||
<span className="text-text-secondary system-md-regular">{providerLabel}</span>
|
||||
</div>
|
||||
</div>
|
||||
<Dialog open onOpenChange={open => !open && onClose()}>
|
||||
<DialogContent className="w-[480px]">
|
||||
<DialogCloseButton />
|
||||
|
||||
{/* Mode Selection */}
|
||||
{shouldShowModeSelection && (
|
||||
<div className="mb-4 flex flex-col gap-1">
|
||||
<label className="text-text-secondary system-sm-medium">
|
||||
{t('sandboxProvider.configModal.connectionMode', { ns: 'common' })}
|
||||
</label>
|
||||
<div className="flex flex-col gap-2">
|
||||
<ModeOption
|
||||
isSelected={configMode === 'managed'}
|
||||
isDisabled={!isManagedModeAvailable}
|
||||
title={t('sandboxProvider.configModal.managedByDify', { ns: 'common' })}
|
||||
description={t('sandboxProvider.configModal.managedByDifyDesc', { ns: 'common' })}
|
||||
onClick={() => setConfigMode('managed')}
|
||||
/>
|
||||
<ModeOption
|
||||
isSelected={configMode === 'byok'}
|
||||
title={t('sandboxProvider.configModal.bringYourOwnKey', { ns: 'common' })}
|
||||
description={t('sandboxProvider.configModal.bringYourOwnKeyDesc', { ns: 'common' })}
|
||||
onClick={() => setConfigMode('byok')}
|
||||
/>
|
||||
{/* Header */}
|
||||
<div className="mb-4 flex flex-col gap-2">
|
||||
<h3 className="text-text-primary title-2xl-semi-bold">
|
||||
{t('sandboxProvider.configModal.title', { ns: 'common' })}
|
||||
</h3>
|
||||
<div className="flex items-center gap-2">
|
||||
<ProviderIcon providerType={provider.provider_type} size="sm" withBorder />
|
||||
<span className="text-text-secondary system-md-regular">{providerLabel}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Form fields (hidden when managed mode is selected) */}
|
||||
{showByokForm && (
|
||||
<BaseForm
|
||||
formSchemas={formSchemas}
|
||||
ref={formRef}
|
||||
labelClassName="system-sm-medium mb-1 flex items-center gap-1 text-text-secondary"
|
||||
formClassName="space-y-4"
|
||||
/>
|
||||
)}
|
||||
{/* Mode Selection */}
|
||||
{shouldShowModeSelection && (
|
||||
<div className="mb-4 flex flex-col gap-1">
|
||||
<label className="text-text-secondary system-sm-medium">
|
||||
{t('sandboxProvider.configModal.connectionMode', { ns: 'common' })}
|
||||
</label>
|
||||
<div className="flex flex-col gap-2">
|
||||
<ModeOption
|
||||
isSelected={configMode === 'managed'}
|
||||
isDisabled={!isManagedModeAvailable}
|
||||
title={t('sandboxProvider.configModal.managedByDify', { ns: 'common' })}
|
||||
description={t('sandboxProvider.configModal.managedByDifyDesc', { ns: 'common' })}
|
||||
onClick={() => setConfigMode('managed')}
|
||||
/>
|
||||
<ModeOption
|
||||
isSelected={configMode === 'byok'}
|
||||
title={t('sandboxProvider.configModal.bringYourOwnKey', { ns: 'common' })}
|
||||
description={t('sandboxProvider.configModal.bringYourOwnKeyDesc', { ns: 'common' })}
|
||||
onClick={() => setConfigMode('byok')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Footer Actions */}
|
||||
<div className="mt-6 flex items-center justify-between">
|
||||
<div>
|
||||
{docLink && (
|
||||
<a
|
||||
href={docLink}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="inline-flex items-center gap-1 text-text-accent system-xs-regular hover:underline"
|
||||
>
|
||||
{t('sandboxProvider.configModal.readDocLink', { ns: 'common', provider: providerLabel })}
|
||||
<span className="i-ri-external-link-line h-3 w-3" />
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
{showRevokeButton && (
|
||||
<Button variant="warning" size="medium" onClick={handleRevoke} disabled={isActionDisabled}>
|
||||
{t('sandboxProvider.configModal.revoke', { ns: 'common' })}
|
||||
{/* Form fields */}
|
||||
{showByokForm && (
|
||||
<BaseForm
|
||||
formSchemas={formSchemas}
|
||||
ref={formRef}
|
||||
labelClassName="system-sm-medium mb-1 flex items-center gap-1 text-text-secondary"
|
||||
formClassName="space-y-4"
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Footer Actions */}
|
||||
<div className="mt-6 flex items-center justify-between">
|
||||
<div>
|
||||
{docLink && (
|
||||
<a
|
||||
href={docLink}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="inline-flex items-center gap-1 text-text-accent system-xs-regular hover:underline"
|
||||
>
|
||||
{t('sandboxProvider.configModal.readDocLink', { ns: 'common', provider: providerLabel })}
|
||||
<span className="i-ri-external-link-line h-3 w-3" />
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
{showRevokeButton && (
|
||||
<Button variant="warning" size="medium" onClick={handleRevoke} disabled={isActionDisabled}>
|
||||
{t('sandboxProvider.configModal.revoke', { ns: 'common' })}
|
||||
</Button>
|
||||
)}
|
||||
<Button variant="secondary" size="medium" onClick={onClose} disabled={isActionDisabled}>
|
||||
{t('sandboxProvider.configModal.cancel', { ns: 'common' })}
|
||||
</Button>
|
||||
)}
|
||||
<Button variant="secondary" size="medium" onClick={onClose} disabled={isActionDisabled}>
|
||||
{t('sandboxProvider.configModal.cancel', { ns: 'common' })}
|
||||
</Button>
|
||||
<Button variant="primary" size="medium" onClick={handleSave} disabled={isActionDisabled}>
|
||||
{t('sandboxProvider.configModal.save', { ns: 'common' })}
|
||||
</Button>
|
||||
<Button variant="primary" size="medium" onClick={handleSave} disabled={isActionDisabled}>
|
||||
{t('sandboxProvider.configModal.save', { ns: 'common' })}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Security tip */}
|
||||
<div className="-mx-6 -mb-6 mt-4 flex items-start justify-center gap-1 rounded-b-2xl border-t border-divider-subtle bg-background-soft px-2 py-3">
|
||||
<span className="i-ri-lock-2-fill h-3 w-3 shrink-0 text-text-primary" />
|
||||
<p className="text-text-tertiary system-xs-regular">
|
||||
{t('sandboxProvider.configModal.securityTip', { ns: 'common' })}
|
||||
{' '}
|
||||
<span className="text-text-accent">PKCS1_OAEP</span>
|
||||
{' '}
|
||||
{t('sandboxProvider.configModal.securityTipTechnology', { ns: 'common' })}
|
||||
</p>
|
||||
</div>
|
||||
</Modal>
|
||||
{/* Security tip */}
|
||||
<div className="-mx-6 -mb-6 mt-4 flex items-start justify-center gap-1 rounded-b-2xl border-t border-divider-subtle bg-background-soft px-2 py-3">
|
||||
<span className="i-ri-lock-2-fill h-3 w-3 shrink-0 text-text-primary" />
|
||||
<p className="text-text-tertiary system-xs-regular">
|
||||
{t('sandboxProvider.configModal.securityTip', { ns: 'common' })}
|
||||
{' '}
|
||||
<span className="text-text-accent">PKCS1_OAEP</span>
|
||||
{' '}
|
||||
{t('sandboxProvider.configModal.securityTipTechnology', { ns: 'common' })}
|
||||
</p>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ -4,8 +4,8 @@ import type { SandboxProvider } from '@/types/sandbox-provider'
|
||||
import { memo, useCallback } from 'react'
|
||||
import { Trans, useTranslation } from 'react-i18next'
|
||||
import Button from '@/app/components/base/button'
|
||||
import Modal from '@/app/components/base/modal'
|
||||
import { useToastContext } from '@/app/components/base/toast/context'
|
||||
import { Dialog, DialogCloseButton, DialogContent, DialogTitle } from '@/app/components/base/ui/dialog'
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
import { useActivateSandboxProvider } from '@/service/use-sandbox-provider'
|
||||
import { PROVIDER_STATIC_LABELS } from './constants'
|
||||
|
||||
@ -19,77 +19,75 @@ const SwitchModal = ({
|
||||
onClose,
|
||||
}: SwitchModalProps) => {
|
||||
const { t } = useTranslation()
|
||||
const { notify } = useToastContext()
|
||||
|
||||
const { mutateAsync: activateProvider, isPending } = useActivateSandboxProvider()
|
||||
const providerLabel = PROVIDER_STATIC_LABELS[provider.provider_type as keyof typeof PROVIDER_STATIC_LABELS]
|
||||
?? provider.provider_type
|
||||
|
||||
// Determine the type based on provider configuration
|
||||
// If tenant has custom config, activate as 'user', otherwise as 'system'
|
||||
const activationType: 'system' | 'user' = provider.is_tenant_configured ? 'user' : 'system'
|
||||
|
||||
const handleConfirm = useCallback(async () => {
|
||||
try {
|
||||
await activateProvider({ providerType: provider.provider_type, type: activationType })
|
||||
notify({ type: 'success', message: t('api.success', { ns: 'common' }) })
|
||||
toast.success(t('api.success', { ns: 'common' }))
|
||||
onClose()
|
||||
}
|
||||
catch {
|
||||
// Error toast is handled by fetch layer
|
||||
}
|
||||
}, [activateProvider, provider.provider_type, activationType, notify, t, onClose])
|
||||
}, [activateProvider, provider.provider_type, activationType, t, onClose])
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isShow
|
||||
onClose={onClose}
|
||||
title={t('sandboxProvider.switchModal.title', { ns: 'common' })}
|
||||
closable
|
||||
className="w-[480px]"
|
||||
>
|
||||
<div className="mt-4">
|
||||
{/* Warning Section */}
|
||||
<div>
|
||||
<div className="text-text-destructive system-sm-semibold">
|
||||
{t('sandboxProvider.switchModal.warning', { ns: 'common' })}
|
||||
<Dialog open onOpenChange={open => !open && onClose()}>
|
||||
<DialogContent className="w-[480px]">
|
||||
<DialogCloseButton />
|
||||
<DialogTitle className="text-text-primary title-2xl-semi-bold">
|
||||
{t('sandboxProvider.switchModal.title', { ns: 'common' })}
|
||||
</DialogTitle>
|
||||
|
||||
<div className="mt-4">
|
||||
{/* Warning Section */}
|
||||
<div>
|
||||
<div className="text-text-destructive system-sm-semibold">
|
||||
{t('sandboxProvider.switchModal.warning', { ns: 'common' })}
|
||||
</div>
|
||||
<div className="mt-0.5 text-text-destructive system-xs-regular">
|
||||
{t('sandboxProvider.switchModal.warningDesc', { ns: 'common' })}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-0.5 text-text-destructive system-xs-regular">
|
||||
{t('sandboxProvider.switchModal.warningDesc', { ns: 'common' })}
|
||||
|
||||
{/* Confirm Text */}
|
||||
<div className="mt-4 text-text-secondary system-sm-regular">
|
||||
<Trans
|
||||
i18nKey="sandboxProvider.switchModal.confirmText"
|
||||
ns="common"
|
||||
values={{ provider: providerLabel }}
|
||||
components={{ bold: <span className="system-sm-semibold" /> }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Footer Actions */}
|
||||
<div className="mt-6 flex items-center justify-end gap-2">
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="medium"
|
||||
onClick={onClose}
|
||||
disabled={isPending}
|
||||
>
|
||||
{t('sandboxProvider.switchModal.cancel', { ns: 'common' })}
|
||||
</Button>
|
||||
<Button
|
||||
variant="warning"
|
||||
size="medium"
|
||||
onClick={handleConfirm}
|
||||
disabled={isPending}
|
||||
>
|
||||
{t('sandboxProvider.switchModal.confirm', { ns: 'common' })}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Confirm Text */}
|
||||
<div className="mt-4 text-text-secondary system-sm-regular">
|
||||
<Trans
|
||||
i18nKey="sandboxProvider.switchModal.confirmText"
|
||||
ns="common"
|
||||
values={{ provider: providerLabel }}
|
||||
components={{ bold: <span className="system-sm-semibold" /> }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Footer Actions */}
|
||||
<div className="mt-6 flex items-center justify-end gap-2">
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="medium"
|
||||
onClick={onClose}
|
||||
disabled={isPending}
|
||||
>
|
||||
{t('sandboxProvider.switchModal.cancel', { ns: 'common' })}
|
||||
</Button>
|
||||
<Button
|
||||
variant="warning"
|
||||
size="medium"
|
||||
onClick={handleConfirm}
|
||||
disabled={isPending}
|
||||
>
|
||||
{t('sandboxProvider.switchModal.confirm', { ns: 'common' })}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user