From 48295e516121a874b0d5585f0c4197f0e803a2b3 Mon Sep 17 00:00:00 2001 From: yyh Date: Tue, 13 Jan 2026 16:18:08 +0800 Subject: [PATCH] refactor(sandbox-provider): extract shared constants and remove redundant cache invalidation - Extract PROVIDER_ICONS and PROVIDER_DESCRIPTION_KEYS to constants.ts - Create shared ProviderIcon component with size and withBorder props - Remove manual invalidateList() calls from config-modal and switch-modal (mutations already invalidate cache in onSuccess) - Remove unused useInvalidSandboxProviderList hook --- .../sandbox-provider-page/config-modal.tsx | 32 +++-------------- .../sandbox-provider-page/constants.ts | 14 ++++++++ .../sandbox-provider-page/provider-card.tsx | 27 ++------------ .../sandbox-provider-page/provider-icon.tsx | 35 +++++++++++++++++++ .../sandbox-provider-page/switch-modal.tsx | 9 ++--- web/service/use-sandbox-provider.ts | 5 --- 6 files changed, 57 insertions(+), 65 deletions(-) create mode 100644 web/app/components/header/account-setting/sandbox-provider-page/provider-icon.tsx diff --git a/web/app/components/header/account-setting/sandbox-provider-page/config-modal.tsx b/web/app/components/header/account-setting/sandbox-provider-page/config-modal.tsx index 45cf913bf1..df332944eb 100644 --- a/web/app/components/header/account-setting/sandbox-provider-page/config-modal.tsx +++ b/web/app/components/header/account-setting/sandbox-provider-page/config-modal.tsx @@ -12,44 +12,22 @@ import Modal from '@/app/components/base/modal' import { useToastContext } from '@/app/components/base/toast' import { useDeleteSandboxProviderConfig, - useInvalidSandboxProviderList, useSaveSandboxProviderConfig, } from '@/service/use-sandbox-provider' import { PROVIDER_DOC_LINKS, SANDBOX_FIELD_CONFIGS } from './constants' +import ProviderIcon from './provider-icon' type ConfigModalProps = { provider: SandboxProvider onClose: () => void } -const PROVIDER_ICONS: Record = { - e2b: '/sandbox-providers/e2b.svg', - daytona: '/sandbox-providers/daytona.svg', - docker: '/sandbox-providers/docker.svg', - local: '/sandbox-providers/local.svg', -} - -const ProviderIcon = ({ providerType }: { providerType: string }) => { - const iconSrc = PROVIDER_ICONS[providerType] || PROVIDER_ICONS.e2b - - return ( -
- {`${providerType} -
- ) -} - const ConfigModal = ({ provider, onClose, }: ConfigModalProps) => { const { t } = useTranslation() const { notify } = useToastContext() - const invalidateList = useInvalidSandboxProviderList() const formRef = useRef(null) const { mutateAsync: saveConfig, isPending: isSaving } = useSaveSandboxProviderConfig() @@ -84,26 +62,24 @@ const ConfigModal = ({ providerType: provider.provider_type, config: formValues.values, }) - await invalidateList() notify({ type: 'success', message: t('api.saved', { ns: 'common' }) }) onClose() } catch { // Error toast is handled by fetch layer } - }, [saveConfig, provider.provider_type, invalidateList, notify, t, onClose]) + }, [saveConfig, provider.provider_type, notify, t, onClose]) const handleRevoke = useCallback(async () => { try { await deleteConfig(provider.provider_type) - await invalidateList() notify({ type: 'success', message: t('api.remove', { ns: 'common' }) }) onClose() } catch { // Error toast is handled by fetch layer } - }, [deleteConfig, provider.provider_type, invalidateList, notify, t, onClose]) + }, [deleteConfig, provider.provider_type, notify, t, onClose]) const isConfigured = provider.is_tenant_configured const docLink = PROVIDER_DOC_LINKS[provider.provider_type] @@ -121,7 +97,7 @@ const ConfigModal = ({ {t('sandboxProvider.configModal.title', { ns: 'common' })}
- + {provider.label}
diff --git a/web/app/components/header/account-setting/sandbox-provider-page/constants.ts b/web/app/components/header/account-setting/sandbox-provider-page/constants.ts index 426a966fbe..d473fe38b7 100644 --- a/web/app/components/header/account-setting/sandbox-provider-page/constants.ts +++ b/web/app/components/header/account-setting/sandbox-provider-page/constants.ts @@ -1,5 +1,19 @@ import { FormTypeEnum } from '@/app/components/base/form/types' +export const PROVIDER_ICONS: Record = { + e2b: '/sandbox-providers/e2b.svg', + daytona: '/sandbox-providers/daytona.svg', + docker: '/sandbox-providers/docker.svg', + local: '/sandbox-providers/local.svg', +} + +export const PROVIDER_DESCRIPTION_KEYS = { + e2b: 'sandboxProvider.e2b.description', + daytona: 'sandboxProvider.daytona.description', + docker: 'sandboxProvider.docker.description', + local: 'sandboxProvider.local.description', +} as const + export const SANDBOX_FIELD_CONFIGS = { api_key: { labelKey: 'sandboxProvider.configModal.apiKey', diff --git a/web/app/components/header/account-setting/sandbox-provider-page/provider-card.tsx b/web/app/components/header/account-setting/sandbox-provider-page/provider-card.tsx index bc534dd423..2aa414b206 100644 --- a/web/app/components/header/account-setting/sandbox-provider-page/provider-card.tsx +++ b/web/app/components/header/account-setting/sandbox-provider-page/provider-card.tsx @@ -7,6 +7,8 @@ import { useTranslation } from 'react-i18next' import Button from '@/app/components/base/button' import Indicator from '@/app/components/header/indicator' import { cn } from '@/utils/classnames' +import { PROVIDER_DESCRIPTION_KEYS } from './constants' +import ProviderIcon from './provider-icon' type ProviderCardProps = { provider: SandboxProvider @@ -16,31 +18,6 @@ type ProviderCardProps = { disabled?: boolean } -const PROVIDER_ICONS: Record = { - e2b: '/sandbox-providers/e2b.svg', - daytona: '/sandbox-providers/daytona.svg', - docker: '/sandbox-providers/docker.svg', - local: '/sandbox-providers/local.svg', -} - -const PROVIDER_DESCRIPTION_KEYS = { - e2b: 'sandboxProvider.e2b.description', - daytona: 'sandboxProvider.daytona.description', - docker: 'sandboxProvider.docker.description', - local: 'sandboxProvider.local.description', -} as const - -const ProviderIcon = ({ providerType }: { providerType: string }) => { - const iconSrc = PROVIDER_ICONS[providerType] || PROVIDER_ICONS.e2b - return ( - {`${providerType} - ) -} - const ProviderCard = ({ provider, isCurrent = false, diff --git a/web/app/components/header/account-setting/sandbox-provider-page/provider-icon.tsx b/web/app/components/header/account-setting/sandbox-provider-page/provider-icon.tsx new file mode 100644 index 0000000000..d747acf5be --- /dev/null +++ b/web/app/components/header/account-setting/sandbox-provider-page/provider-icon.tsx @@ -0,0 +1,35 @@ +import { cn } from '@/utils/classnames' +import { PROVIDER_ICONS } from './constants' + +type ProviderIconProps = { + providerType: string + size?: 'sm' | 'md' + withBorder?: boolean +} + +const ProviderIcon = ({ providerType, size = 'md', withBorder = false }: ProviderIconProps) => { + const iconSrc = PROVIDER_ICONS[providerType] || PROVIDER_ICONS.e2b + const sizeClass = size === 'sm' ? 'h-4 w-4' : 'h-6 w-6' + + if (withBorder) { + return ( +
+ {`${providerType} +
+ ) + } + + return ( + {`${providerType} + ) +} + +export default ProviderIcon diff --git a/web/app/components/header/account-setting/sandbox-provider-page/switch-modal.tsx b/web/app/components/header/account-setting/sandbox-provider-page/switch-modal.tsx index 530f81b830..3a5cc394ac 100644 --- a/web/app/components/header/account-setting/sandbox-provider-page/switch-modal.tsx +++ b/web/app/components/header/account-setting/sandbox-provider-page/switch-modal.tsx @@ -6,10 +6,7 @@ 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' -import { - useActivateSandboxProvider, - useInvalidSandboxProviderList, -} from '@/service/use-sandbox-provider' +import { useActivateSandboxProvider } from '@/service/use-sandbox-provider' type SwitchModalProps = { provider: SandboxProvider @@ -22,21 +19,19 @@ const SwitchModal = ({ }: SwitchModalProps) => { const { t } = useTranslation() const { notify } = useToastContext() - const invalidateList = useInvalidSandboxProviderList() const { mutateAsync: activateProvider, isPending } = useActivateSandboxProvider() const handleConfirm = useCallback(async () => { try { await activateProvider(provider.provider_type) - await invalidateList() notify({ type: 'success', message: t('api.success', { ns: 'common' }) }) onClose() } catch { // Error toast is handled by fetch layer } - }, [activateProvider, provider.provider_type, invalidateList, notify, t, onClose]) + }, [activateProvider, provider.provider_type, notify, t, onClose]) return ( { }) } -export const useInvalidSandboxProviderList = () => { - return useInvalid(sandboxProviderQueryKeys.list) -} - export const useGetSandboxProvider = (providerType: string) => { return useQuery({ queryKey: sandboxProviderQueryKeys.provider(providerType),