diff --git a/src/features/providers/sheets/forms/BaseProviderForm.tsx b/src/features/providers/sheets/forms/BaseProviderForm.tsx index 03dd197..24fa4ea 100644 --- a/src/features/providers/sheets/forms/BaseProviderForm.tsx +++ b/src/features/providers/sheets/forms/BaseProviderForm.tsx @@ -4,6 +4,8 @@ import { IconAlertTriangle, IconCheckCircle2, IconDownload, + IconEye, + IconEyeOff, IconLoader2, IconPlus, IconX, @@ -65,6 +67,19 @@ const headersObjectToText = (headers?: Record): string => const stripDisableAllRule = (list?: string[]): string[] => (list ?? []).filter((s) => s.trim() !== '*'); +/** Populate apiKey from resource.raw when editing a non-OpenAI provider. */ +const applyRawApiKey = ( + brand: Exclude, + resource: ProviderResource | null, + mode: 'create' | 'edit', + form: ProviderEntryFormInput +): void => { + if (mode === 'edit' && resource && brand !== 'openaiCompatibility') { + const rawKey = (resource.raw as { apiKey?: string } | undefined)?.apiKey ?? ''; + if (rawKey) form.apiKey = rawKey; + } +}; + function buildInitialForm( brand: Exclude, resource: ProviderResource | null, @@ -204,13 +219,37 @@ export function BaseProviderForm({ const { t } = useTranslation(); const descriptor = PROVIDER_DESCRIPTORS[brand]; const fid = useId(); - const [form, setForm] = useState(() => - buildInitialForm(brand, resource, mode) - ); - const [initialFormSignature] = useState(() => - JSON.stringify(buildInitialForm(brand, resource, mode)) - ); + const [form, setForm] = useState(() => { + const initial = buildInitialForm(brand, resource, mode); + applyRawApiKey(brand, resource, mode, initial); + return initial; + }); + const [initialFormSignature] = useState(() => { + const initial = buildInitialForm(brand, resource, mode); + applyRawApiKey(brand, resource, mode, initial); + return JSON.stringify(initial); + }); const [error, setError] = useState(null); + const [showPasswords, setShowPasswords] = useState>(new Set()); + const [showSingleApiKey, setShowSingleApiKey] = useState(false); + + // Reset password visibility when the sheet closes or resource changes + useEffect(() => { + setShowPasswords(new Set()); + setShowSingleApiKey(false); + }, [resource?.id, mode]); + + const togglePasswordVisibility = (idx: number) => { + setShowPasswords((prev) => { + const next = new Set(prev); + if (next.has(idx)) { + next.delete(idx); + } else { + next.add(idx); + } + return next; + }); + }; const isDirty = useMemo( () => JSON.stringify(form) !== initialFormSignature, @@ -454,19 +493,43 @@ export function BaseProviderForm({ - updateField('apiKey', e.target.value)} - placeholder={ - mode === 'edit' - ? t('providersPage.form.apiKeyEditPlaceholder') - : t('providersPage.form.apiKeyCreatePlaceholder') - } - disabled={mutating} - /> +
+ updateField('apiKey', e.target.value)} + placeholder={ + mode === 'edit' + ? t('providersPage.form.apiKeyEditPlaceholder') + : t('providersPage.form.apiKeyCreatePlaceholder') + } + disabled={mutating} + /> + +
) : null} @@ -695,21 +758,45 @@ export function BaseProviderForm({ - - updateField( - 'apiKeyEntries', - apiKeyEntries.map((it, i) => - i === idx ? { ...it, apiKey: e.target.value } : it +
+ + updateField( + 'apiKeyEntries', + apiKeyEntries.map((it, i) => + i === idx ? { ...it, apiKey: e.target.value } : it + ) ) - ) - } - disabled={mutating} - placeholder={t('providersPage.form.apiKeyCreatePlaceholder')} - /> + } + disabled={mutating} + placeholder={t('providersPage.form.apiKeyCreatePlaceholder')} + /> + +