From df96297c68dc5a35efcff73a4417965f257049b2 Mon Sep 17 00:00:00 2001 From: Supra4E8C Date: Sat, 14 Mar 2026 15:25:29 +0800 Subject: [PATCH] feat(ai-providers): add Vertex AI config toggle --- .../providers/VertexSection/VertexSection.tsx | 21 ++++++++++++++- src/pages/AiProvidersPage.tsx | 26 +++++++++++++++---- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/components/providers/VertexSection/VertexSection.tsx b/src/components/providers/VertexSection/VertexSection.tsx index fcf0541..0926563 100644 --- a/src/components/providers/VertexSection/VertexSection.tsx +++ b/src/components/providers/VertexSection/VertexSection.tsx @@ -2,6 +2,7 @@ import { Fragment, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { Button } from '@/components/ui/Button'; import { Card } from '@/components/ui/Card'; +import { ToggleSwitch } from '@/components/ui/ToggleSwitch'; import iconVertex from '@/assets/icons/vertex.svg'; import type { ProviderKeyConfig } from '@/types'; import { maskApiKey } from '@/utils/format'; @@ -14,7 +15,7 @@ import { import styles from '@/pages/AiProvidersPage.module.scss'; import { ProviderList } from '../ProviderList'; import { ProviderStatusBar } from '../ProviderStatusBar'; -import { getStatsBySource } from '../utils'; +import { getStatsBySource, hasDisableAllModelsRule } from '../utils'; interface VertexSectionProps { configs: ProviderKeyConfig[]; @@ -26,6 +27,7 @@ interface VertexSectionProps { onAdd: () => void; onEdit: (index: number) => void; onDelete: (index: number) => void; + onToggle: (index: number, enabled: boolean) => void; } export function VertexSection({ @@ -38,9 +40,11 @@ export function VertexSection({ onAdd, onEdit, onDelete, + onToggle, }: VertexSectionProps) { const { t } = useTranslation(); const actionsDisabled = disableControls || loading || isSwitching; + const toggleDisabled = disableControls || loading || isSwitching; const statusBarCache = useMemo(() => { const cache = new Map>(); @@ -84,9 +88,19 @@ export function VertexSection({ onEdit={onEdit} onDelete={onDelete} actionsDisabled={actionsDisabled} + getRowDisabled={(item) => hasDisableAllModelsRule(item.excludedModels)} + renderExtraActions={(item, index) => ( + void onToggle(index, value)} + /> + )} renderContent={(item, index) => { const stats = getStatsBySource(item.apiKey, keyStats, item.prefix); const headerEntries = Object.entries(item.headers || {}); + const configDisabled = hasDisableAllModelsRule(item.excludedModels); const excludedModels = item.excludedModels ?? []; const statusData = statusBarCache.get(item.apiKey) || calculateStatusBarData([]); @@ -126,6 +140,11 @@ export function VertexSection({ ))} )} + {configDisabled && ( +
+ {t('ai_providers.config_disabled_badge')} +
+ )} {item.models?.length ? (
diff --git a/src/pages/AiProvidersPage.tsx b/src/pages/AiProvidersPage.tsx index 27276aa..9a4bfbe 100644 --- a/src/pages/AiProvidersPage.tsx +++ b/src/pages/AiProvidersPage.tsx @@ -164,7 +164,7 @@ export function AiProvidersPage() { }; const setConfigEnabled = async ( - provider: 'gemini' | 'codex' | 'claude', + provider: 'gemini' | 'codex' | 'claude' | 'vertex', index: number, enabled: boolean ) => { @@ -204,7 +204,12 @@ export function AiProvidersPage() { return; } - const source = provider === 'codex' ? codexConfigs : claudeConfigs; + const source = + provider === 'codex' + ? codexConfigs + : provider === 'claude' + ? claudeConfigs + : vertexConfigs; const current = source[index]; if (!current) return; @@ -222,17 +227,23 @@ export function AiProvidersPage() { setCodexConfigs(nextList); updateConfigValue('codex-api-key', nextList); clearCache('codex-api-key'); - } else { + } else if (provider === 'claude') { setClaudeConfigs(nextList); updateConfigValue('claude-api-key', nextList); clearCache('claude-api-key'); + } else { + setVertexConfigs(nextList); + updateConfigValue('vertex-api-key', nextList); + clearCache('vertex-api-key'); } try { if (provider === 'codex') { await providersApi.saveCodexConfigs(nextList); - } else { + } else if (provider === 'claude') { await providersApi.saveClaudeConfigs(nextList); + } else { + await providersApi.saveVertexConfigs(nextList); } showNotification( enabled ? t('notification.config_enabled') : t('notification.config_disabled'), @@ -244,10 +255,14 @@ export function AiProvidersPage() { setCodexConfigs(previousList); updateConfigValue('codex-api-key', previousList); clearCache('codex-api-key'); - } else { + } else if (provider === 'claude') { setClaudeConfigs(previousList); updateConfigValue('claude-api-key', previousList); clearCache('claude-api-key'); + } else { + setVertexConfigs(previousList); + updateConfigValue('vertex-api-key', previousList); + clearCache('vertex-api-key'); } showNotification(`${t('notification.update_failed')}: ${message}`, 'error'); } finally { @@ -400,6 +415,7 @@ export function AiProvidersPage() { onAdd={() => openEditor('/ai-providers/vertex/new')} onEdit={(index) => openEditor(`/ai-providers/vertex/${index}`)} onDelete={deleteVertex} + onToggle={(index, enabled) => void setConfigEnabled('vertex', index, enabled)} />