From 75da30311aa734a7addd90d5247b915ea3c8d217 Mon Sep 17 00:00:00 2001 From: LTbinglingfeng Date: Mon, 1 Jun 2026 00:22:09 +0800 Subject: [PATCH] refactor(forms): streamline imports and improve state handling for API keys --- .../providers/sheets/forms/AmpcodeForm.tsx | 32 ++--- .../sheets/forms/BaseProviderForm.tsx | 114 ++++++------------ .../sheets/forms/useConnectivityTest.ts | 64 ++++------ .../sheets/forms/useModelDiscovery.ts | 42 ++----- src/features/providers/types.ts | 1 + .../providers/useProviderWorkbench.ts | 38 +++--- 6 files changed, 91 insertions(+), 200 deletions(-) diff --git a/src/features/providers/sheets/forms/AmpcodeForm.tsx b/src/features/providers/sheets/forms/AmpcodeForm.tsx index c1de3ed..49eafc3 100644 --- a/src/features/providers/sheets/forms/AmpcodeForm.tsx +++ b/src/features/providers/sheets/forms/AmpcodeForm.tsx @@ -2,11 +2,7 @@ import { useEffect, useId, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { Collapsible } from '@/components/ui/Collapsible'; import { IconPlus, IconX } from '@/components/ui/icons'; -import type { - AmpcodeConfig, - AmpcodeModelMapping, - AmpcodeUpstreamApiKeyMapping, -} from '@/types'; +import type { AmpcodeConfig, AmpcodeModelMapping, AmpcodeUpstreamApiKeyMapping } from '@/types'; import type { ProviderResource } from '../../types'; import styles from './sharedForm.module.scss'; @@ -34,7 +30,7 @@ function buildState(config?: AmpcodeConfig | null): AmpcodeFormState { : [emptyModelMapping()]; return { upstreamUrl: safe.upstreamUrl ?? '', - upstreamApiKey: safe.upstreamApiKey ?? '', + upstreamApiKey: '', forceModelMappings: safe.forceModelMappings === true, upstreamMappings, modelMappings, @@ -66,9 +62,7 @@ export function AmpcodeForm({ const fid = useId(); const initialConfig = (resource?.raw as AmpcodeConfig | undefined) ?? {}; const [form, setForm] = useState(() => buildState(initialConfig)); - const [initialFormSignature] = useState(() => - JSON.stringify(buildState(initialConfig)) - ); + const [initialFormSignature] = useState(() => JSON.stringify(buildState(initialConfig))); const [error, setError] = useState(null); const isDirty = useMemo( @@ -109,7 +103,8 @@ export function AmpcodeForm({ const next: AmpcodeConfig = { upstreamUrl: form.upstreamUrl.trim() || undefined, - upstreamApiKey: form.upstreamApiKey.trim() || undefined, + upstreamApiKey: + form.upstreamApiKey.trim() || initialConfig.upstreamApiKey?.trim() || undefined, upstreamApiKeys: upstreamApiKeys.length ? upstreamApiKeys : undefined, modelMappings: modelMappings.length ? modelMappings : undefined, forceModelMappings: form.forceModelMappings, @@ -149,9 +144,7 @@ export function AmpcodeForm({ className={styles.input} type="password" value={form.upstreamApiKey} - onChange={(e) => - setForm((s) => ({ ...s, upstreamApiKey: e.target.value })) - } + onChange={(e) => setForm((s) => ({ ...s, upstreamApiKey: e.target.value }))} autoComplete="new-password" data-1p-ignore="true" data-lpignore="true" @@ -165,9 +158,7 @@ export function AmpcodeForm({ className={styles.checkboxBox} checked={form.forceModelMappings} disabled={mutating} - onChange={(e) => - setForm((s) => ({ ...s, forceModelMappings: e.target.checked })) - } + onChange={(e) => setForm((s) => ({ ...s, forceModelMappings: e.target.checked }))} /> {t('providersPage.ampcode.forceModelMappings')} @@ -197,9 +188,7 @@ export function AmpcodeForm({
- +
{form.modelMappings.map((m, idx) => ( -
+
({ - apiKey: entry.apiKey, + apiKey: '', + existingApiKey: entry.apiKey, proxyUrl: entry.proxyUrl ?? '', authIndex: entry.authIndex, })) @@ -150,15 +143,13 @@ function buildInitialForm( ? Object.entries(cfg.headers).map(([k, v]) => ({ key: k, value: String(v) })) : [emptyHeader()], excludedModelsText: excludedList.join('\n'), - websockets: - brand === 'codex' ? (cfg as ProviderKeyConfig).websockets === true : undefined, + websockets: brand === 'codex' ? (cfg as ProviderKeyConfig).websockets === true : undefined, cloak: brand === 'claude' ? { mode: (cfg as ProviderKeyConfig).cloak?.mode ?? '', strictMode: (cfg as ProviderKeyConfig).cloak?.strictMode === true, - sensitiveWordsText: - (cfg as ProviderKeyConfig).cloak?.sensitiveWords?.join('\n') ?? '', + sensitiveWordsText: (cfg as ProviderKeyConfig).cloak?.sensitiveWords?.join('\n') ?? '', } : undefined, testModel: brand === 'claude' ? '' : undefined, @@ -241,9 +232,7 @@ export function BaseProviderForm({ const fallbackAuthIndex = useMemo(() => { if (mode !== 'edit' || !resource) return ''; - return ( - (resource.raw as { authIndex?: string } | undefined)?.authIndex ?? '' - ); + return (resource.raw as { authIndex?: string } | undefined)?.authIndex ?? ''; }, [mode, resource]); const connectivityMessages = useMemo( @@ -252,8 +241,7 @@ export function BaseProviderForm({ endpointInvalid: t('providersPage.connectivity.endpointInvalid'), apiKeyRequired: t('providersPage.connectivity.apiKeyRequired'), modelRequired: t('providersPage.connectivity.modelRequired'), - timeout: (seconds: number) => - t('providersPage.connectivity.timeout', { seconds }), + timeout: (seconds: number) => t('providersPage.connectivity.timeout', { seconds }), requestFailed: t('providersPage.connectivity.requestFailed'), }), [t] @@ -307,9 +295,7 @@ export function BaseProviderForm({ const autoLabel = firstName ? t('providersPage.form.testModelAutoWith', { name: firstName }) : t('providersPage.form.testModelAutoEmpty'); - const opts: Array<{ value: string; label: string }> = [ - { value: '', label: autoLabel }, - ]; + const opts: Array<{ value: string; label: string }> = [{ value: '', label: autoLabel }]; names.forEach((n) => opts.push({ value: n, label: n })); const tm = (form.testModel ?? '').trim(); if (tm && !seen.has(tm)) { @@ -389,11 +375,7 @@ export function BaseProviderForm({ if (descriptor.supportsName && !form.name.trim()) { return t('providersPage.form.validation.nameRequired'); } - if ( - descriptor.supportsApiKey && - mode === 'create' && - !form.apiKey.trim() - ) { + if (descriptor.supportsApiKey && mode === 'create' && !form.apiKey.trim()) { return t('providersPage.form.validation.apiKeyRequired'); } if (descriptor.baseUrlRequired && !form.baseUrl.trim()) { @@ -436,9 +418,7 @@ export function BaseProviderForm({ ); const apiKeyEntries = useMemo( () => - form.apiKeyEntries && form.apiKeyEntries.length - ? form.apiKeyEntries - : [emptyApiKeyEntry()], + form.apiKeyEntries && form.apiKeyEntries.length ? form.apiKeyEntries : [emptyApiKeyEntry()], [form.apiKeyEntries] ); @@ -519,11 +499,7 @@ export function BaseProviderForm({ : t('providersPage.form.showApiKey') } > - {showSingleApiKey ? ( - - ) : ( - - )} + {showSingleApiKey ? : }
@@ -647,9 +623,7 @@ export function BaseProviderForm({
) : null} {brand === 'claude' && connectivity.claudeStatus.state === 'error' ? ( -
- {connectivity.claudeStatus.message} -
+
{connectivity.claudeStatus.message}
) : null}
) : null} @@ -690,7 +664,9 @@ export function BaseProviderForm({ {descriptor.supportsApiKeyEntries && form.apiKeyEntries ? ( e.apiKey.trim()).length}`} + hint={`${ + apiKeyEntries.filter((e) => e.apiKey.trim() || e.existingApiKey?.trim()).length + }`} defaultOpen >
@@ -700,9 +676,7 @@ export function BaseProviderForm({ type="button" className={styles.addBtn} disabled={mutating} - onClick={() => - updateField('apiKeyEntries', [...apiKeyEntries, emptyApiKeyEntry()]) - } + onClick={() => updateField('apiKeyEntries', [...apiKeyEntries, emptyApiKeyEntry()])} > {t('providersPage.form.addApiKeyEntry')} @@ -731,9 +705,7 @@ export function BaseProviderForm({ return (
- - {t('providersPage.form.apiKeyEntry', { index: realIdx + 1 })} - + {t('providersPage.form.apiKeyEntry', { index: realIdx + 1 })}
- +
- +
{status.state === 'error' ? ( -
- {status.message} -
+
{status.message}
) : null}
); @@ -853,9 +823,7 @@ export function BaseProviderForm({ onChange={(e) => updateField( 'headers', - headersList.map((it, i) => - i === idx ? { ...it, key: e.target.value } : it - ) + headersList.map((it, i) => (i === idx ? { ...it, key: e.target.value } : it)) ) } disabled={mutating} @@ -945,9 +913,7 @@ export function BaseProviderForm({ onChange={(e) => updateField( 'models', - modelsList.map((it, i) => - i === idx ? { ...it, name: e.target.value } : it - ) + modelsList.map((it, i) => (i === idx ? { ...it, name: e.target.value } : it)) ) } disabled={mutating} @@ -959,9 +925,7 @@ export function BaseProviderForm({ onChange={(e) => updateField( 'models', - modelsList.map((it, i) => - i === idx ? { ...it, alias: e.target.value } : it - ) + modelsList.map((it, i) => (i === idx ? { ...it, alias: e.target.value } : it)) ) } disabled={mutating} @@ -997,9 +961,7 @@ export function BaseProviderForm({ {descriptor.supportsExcludedModels ? (
- - {t('providersPage.form.excludedHint')} - + {t('providersPage.form.excludedHint')}