import { useCallback } from "react"; import { useTranslation } from "react-i18next"; import { Plus } from "lucide-react"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Button } from "@/components/ui/button"; import type { Provider, CustomEndpoint } from "@/types"; import type { AppId } from "@/lib/api"; import { ProviderForm, type ProviderFormValues, } from "@/components/providers/forms/ProviderForm"; import { providerPresets } from "@/config/claudeProviderPresets"; import { codexProviderPresets } from "@/config/codexProviderPresets"; import { geminiProviderPresets } from "@/config/geminiProviderPresets"; interface AddProviderDialogProps { open: boolean; onOpenChange: (open: boolean) => void; appId: AppId; onSubmit: (provider: Omit) => Promise | void; } export function AddProviderDialog({ open, onOpenChange, appId, onSubmit, }: AddProviderDialogProps) { const { t } = useTranslation(); const handleSubmit = useCallback( async (values: ProviderFormValues) => { const parsedConfig = JSON.parse(values.settingsConfig) as Record< string, unknown >; // 构造基础提交数据 const providerData: Omit = { name: values.name.trim(), notes: values.notes?.trim() || undefined, websiteUrl: values.websiteUrl?.trim() || undefined, settingsConfig: parsedConfig, ...(values.presetCategory ? { category: values.presetCategory } : {}), ...(values.meta ? { meta: values.meta } : {}), }; const hasCustomEndpoints = providerData.meta?.custom_endpoints && Object.keys(providerData.meta.custom_endpoints).length > 0; if (!hasCustomEndpoints) { // 收集端点候选(仅在缺少自定义端点时兜底) // 1. 从预设配置中获取 endpointCandidates // 2. 从当前配置中提取 baseUrl (ANTHROPIC_BASE_URL 或 Codex base_url) const urlSet = new Set(); const addUrl = (rawUrl?: string) => { const url = (rawUrl || "").trim().replace(/\/+$/, ""); if (url && url.startsWith("http")) { urlSet.add(url); } }; if (values.presetId) { if (appId === "claude") { const presets = providerPresets; const presetIndex = parseInt( values.presetId.replace("claude-", ""), ); if ( !isNaN(presetIndex) && presetIndex >= 0 && presetIndex < presets.length ) { const preset = presets[presetIndex]; if (preset?.endpointCandidates) { preset.endpointCandidates.forEach(addUrl); } } } else if (appId === "codex") { const presets = codexProviderPresets; const presetIndex = parseInt(values.presetId.replace("codex-", "")); if ( !isNaN(presetIndex) && presetIndex >= 0 && presetIndex < presets.length ) { const preset = presets[presetIndex]; if (Array.isArray(preset.endpointCandidates)) { preset.endpointCandidates.forEach(addUrl); } } } else if (appId === "gemini") { const presets = geminiProviderPresets; const presetIndex = parseInt( values.presetId.replace("gemini-", ""), ); if ( !isNaN(presetIndex) && presetIndex >= 0 && presetIndex < presets.length ) { const preset = presets[presetIndex]; if (Array.isArray(preset.endpointCandidates)) { preset.endpointCandidates.forEach(addUrl); } } } } if (appId === "claude") { const env = parsedConfig.env as Record | undefined; if (env?.ANTHROPIC_BASE_URL) { addUrl(env.ANTHROPIC_BASE_URL); } } else if (appId === "codex") { const config = parsedConfig.config as string | undefined; if (config) { const baseUrlMatch = config.match( /base_url\s*=\s*["']([^"']+)["']/, ); if (baseUrlMatch?.[1]) { addUrl(baseUrlMatch[1]); } } } else if (appId === "gemini") { const env = parsedConfig.env as Record | undefined; if (env?.GOOGLE_GEMINI_BASE_URL) { addUrl(env.GOOGLE_GEMINI_BASE_URL); } } const urls = Array.from(urlSet); if (urls.length > 0) { const now = Date.now(); const customEndpoints: Record = {}; urls.forEach((url) => { customEndpoints[url] = { url, addedAt: now, lastUsed: undefined, }; }); providerData.meta = { ...(providerData.meta ?? {}), custom_endpoints: customEndpoints, }; } } await onSubmit(providerData); onOpenChange(false); }, [appId, onSubmit, onOpenChange], ); const submitLabel = appId === "claude" ? t("provider.addClaudeProvider") : appId === "codex" ? t("provider.addCodexProvider") : t("provider.addGeminiProvider"); return ( {submitLabel} {t("provider.addProviderHint")}
onOpenChange(false)} showButtons={false} />
); }