import { useState } from 'react'; import { acpAuthenticateProvider } from '../../acp/providers'; import { useProviderDeviceCode } from '../../hooks/useProviderDeviceCode'; import type { ProviderDetails } from '../../types/providers'; import DefaultProviderSetupForm, { ConfigInput, } from '../settings/providers/modal/subcomponents/forms/DefaultProviderSetupForm'; import { providerConfigSubmitHandler } from '../settings/providers/modal/subcomponents/handlers/DefaultSubmitHandler'; import ProviderLogo from '../settings/providers/modal/subcomponents/ProviderLogo'; import { SecureStorageNotice } from '../settings/providers/modal/subcomponents/SecureStorageNotice'; import AcpReadinessPanel from '../settings/providers/AcpReadinessPanel'; import { Button } from '../ui/button'; import { ChevronRight, LogIn } from 'lucide-react'; import { defineMessages, useIntl } from '../../i18n'; import { errorMessage } from '../../utils/conversionUtils'; type OnConfigured = (name: string) => void | Promise; const i18n = defineMessages({ browserWindowOpen: { id: 'providerConfigForm.browserWindowOpen', defaultMessage: 'A browser window will open for you to complete the login.', }, deviceCodeFlowHint: { id: 'providerConfigForm.deviceCodeFlowHint', defaultMessage: 'A browser window will open. The verification code will appear here so you can enter it to complete sign-in.', }, signingIn: { id: 'providerConfigForm.signingIn', defaultMessage: 'Signing in...', }, signInWith: { id: 'providerConfigForm.signInWith', defaultMessage: 'Sign in with {providerName}', }, noApiKey: { id: 'providerConfigForm.noApiKey', defaultMessage: "Don't have an API key?", }, configuring: { id: 'providerConfigForm.configuring', defaultMessage: 'Configuring...', }, continue: { id: 'providerConfigForm.continue', defaultMessage: 'Continue', }, deviceCodeVisit: { id: 'providerConfigForm.deviceCodeVisit', defaultMessage: 'Visit', }, deviceCodeAndEnter: { id: 'providerConfigForm.deviceCodeAndEnter', defaultMessage: 'and enter:', }, deviceCodeCopy: { id: 'providerConfigForm.deviceCodeCopy', defaultMessage: 'Copy', }, }); function parseLinks(text: string) { return text.split(/(https?:\/\/[^\s]+)/g).map((part, i) => /^https?:\/\//.test(part) ? ( { e.preventDefault(); window.electron.openExternal(part); }} className="underline hover:text-text-default cursor-pointer" > {part} ) : ( part ) ); } function OAuthForm({ provider, onConfigured, onError, }: { provider: ProviderDetails; onConfigured: OnConfigured; onError: (msg: string) => void; }) { const intl = useIntl(); const [isLoading, setIsLoading] = useState(false); const { deviceCode, clearDeviceCode } = useProviderDeviceCode(provider.name); const handleLogin = async () => { setIsLoading(true); clearDeviceCode(); try { await acpAuthenticateProvider(provider.name); await onConfigured(provider.name); } catch (err) { onError(`Setup failed: ${errorMessage(err)}`); } finally { setIsLoading(false); } }; const isDeviceCodeFlow = provider.metadata.config_keys.some((key) => key.device_code_flow); return (
{isDeviceCodeFlow && isLoading && deviceCode ? (

{intl.formatMessage(i18n.deviceCodeVisit)}{' '} { e.preventDefault(); window.electron.openExternal(deviceCode.verificationUri); }} className="underline" > {deviceCode.verificationUri} {' '} {intl.formatMessage(i18n.deviceCodeAndEnter)}

{deviceCode.userCode}
) : (

{isDeviceCodeFlow ? intl.formatMessage(i18n.deviceCodeFlowHint) : intl.formatMessage(i18n.browserWindowOpen)}

)}
); } function ApiKeyForm({ provider, onConfigured, onError, }: { provider: ProviderDetails; onConfigured: OnConfigured; onError: (msg: string) => void; }) { const intl = useIntl(); const [configValues, setConfigValues] = useState>({}); const [validationErrors, setValidationErrors] = useState>({}); const [isSubmitting, setIsSubmitting] = useState(false); const [showSetupHelp, setShowSetupHelp] = useState(false); const setupSteps = provider.metadata.setup_steps; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setValidationErrors({}); const parameters = provider.metadata.config_keys || []; const errors: Record = {}; parameters.forEach((param) => { if ( param.required && !configValues[param.name]?.value && !configValues[param.name]?.serverValue ) { errors[param.name] = `${param.name} is required`; } }); if (Object.keys(errors).length > 0) { setValidationErrors(errors); return; } const toSubmit = Object.fromEntries( Object.entries(configValues) .filter(([, entry]) => !!entry.value) .map(([k, entry]) => [k, entry.value || '']) ); setIsSubmitting(true); try { await providerConfigSubmitHandler(provider, toSubmit); await onConfigured(provider.name); } catch (err) { onError(errorMessage(err)); } finally { setIsSubmitting(false); } }; return (
{provider.metadata.config_keys.some((k) => k.required && k.secret) && } {setupSteps && setupSteps.length > 0 && (
{showSetupHelp && (
    {setupSteps.map((step, i) => (
  1. {parseLinks(step)}
  2. ))}
)}
)}
); } interface ProviderConfigFormProps { provider: ProviderDetails; onConfigured: OnConfigured; } export default function ProviderConfigForm({ provider, onConfigured }: ProviderConfigFormProps) { const intl = useIntl(); const [error, setError] = useState(null); const isOAuthProvider = provider.metadata.config_keys.some((key) => key.oauth_flow); const renderForm = () => { if (provider.uses_acp) { return ( onConfigured(configured.name)} onError={setError} /> ); } if (isOAuthProvider) { return ; } return ; }; return (

{provider.metadata.display_name}

{provider.metadata.description}

{renderForm()} {error && (
{error}
)}
); }