"use client"; import { useState, useEffect } from "react"; import PropTypes from "prop-types"; import Modal from "@/shared/components/Modal"; import Input from "@/shared/components/Input"; import Button from "@/shared/components/Button"; import Badge from "@/shared/components/Badge"; import { isOpenAICompatibleProvider, isAnthropicCompatibleProvider } from "@/shared/constants/providers"; export default function EditConnectionModal({ isOpen, connection, proxyPools, onSave, onClose }) { const [formData, setFormData] = useState({ name: "", priority: 1, apiKey: "", }); const [azureData, setAzureData] = useState({ azureEndpoint: "", apiVersion: "2024-10-01-preview", deployment: "", organization: "", }); const [cloudflareData, setCloudflareData] = useState({ accountId: "" }); const [testing, setTesting] = useState(false); const [testResult, setTestResult] = useState(null); const [validating, setValidating] = useState(false); const [validationResult, setValidationResult] = useState(null); const [saving, setSaving] = useState(false); useEffect(() => { if (connection) { setFormData({ name: connection.name || "", priority: connection.priority || 1, apiKey: "", }); // Load Azure-specific data if present if (connection.provider === "azure" && connection.providerSpecificData) { setAzureData({ azureEndpoint: connection.providerSpecificData.azureEndpoint || "", apiVersion: connection.providerSpecificData.apiVersion || "2024-10-01-preview", deployment: connection.providerSpecificData.deployment || "", organization: connection.providerSpecificData.organization || "", }); } if (connection.provider === "cloudflare-ai" && connection.providerSpecificData) { setCloudflareData({ accountId: connection.providerSpecificData.accountId || "" }); } setTestResult(null); setValidationResult(null); } }, [connection]); const isOAuth = connection?.authType === "oauth"; const isAzure = connection?.provider === "azure"; const isCloudflareAi = connection?.provider === "cloudflare-ai"; const isCompatible = connection ? (isOpenAICompatibleProvider(connection.provider) || isAnthropicCompatibleProvider(connection.provider)) : false; const handleTest = async () => { if (!connection?.provider) return; setTesting(true); setTestResult(null); try { const res = await fetch(`/api/providers/${connection.id}/test`, { method: "POST" }); const data = await res.json(); setTestResult(data.valid ? "success" : "failed"); } catch { setTestResult("failed"); } finally { setTesting(false); } }; const handleValidate = async () => { if (!connection?.provider || !formData.apiKey) return; setValidating(true); setValidationResult(null); try { const res = await fetch("/api/providers/validate", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ provider: connection.provider, apiKey: formData.apiKey, ...(isAzure ? { providerSpecificData: azureData } : {}), ...(isCloudflareAi ? { providerSpecificData: cloudflareData } : {}), }), }); const data = await res.json(); setValidationResult(data.valid ? "success" : "failed"); } catch { setValidationResult("failed"); } finally { setValidating(false); } }; const handleSubmit = async () => { if (!connection) return; setSaving(true); try { const updates = { name: formData.name, priority: formData.priority, }; if (!isOAuth && formData.apiKey) { updates.apiKey = formData.apiKey; let isValid = validationResult === "success"; if (!isValid) { try { setValidating(true); setValidationResult(null); const res = await fetch("/api/providers/validate", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ provider: connection.provider, apiKey: formData.apiKey, ...(isAzure ? { providerSpecificData: azureData } : {}), ...(isCloudflareAi ? { providerSpecificData: cloudflareData } : {}), }), }); const data = await res.json(); isValid = !!data.valid; setValidationResult(isValid ? "success" : "failed"); } catch { setValidationResult("failed"); } finally { setValidating(false); } } if (isValid) { updates.testStatus = "active"; updates.lastError = null; updates.lastErrorAt = null; } } // Add Azure-specific data if this is an Azure connection if (isAzure) { updates.providerSpecificData = { azureEndpoint: azureData.azureEndpoint, apiVersion: azureData.apiVersion, deployment: azureData.deployment, organization: azureData.organization, }; } if (isCloudflareAi) { updates.providerSpecificData = { accountId: cloudflareData.accountId }; } await onSave(updates); } finally { setSaving(false); } }; if (!connection) return null; return (
setFormData({ ...formData, name: e.target.value })} placeholder={isOAuth ? "Account name" : "Production Key"} /> {isOAuth && connection.email && (

Email

{connection.email}

)} setFormData({ ...formData, priority: Number.parseInt(e.target.value, 10) || 1 })} /> {!isOAuth && ( <>
setFormData({ ...formData, apiKey: e.target.value })} placeholder="Enter new API key" hint="Leave blank to keep the current API key." className="flex-1" />
{validationResult && ( {validationResult === "success" ? "Valid" : "Invalid"} )} )} {isAzure && (

Azure OpenAI Configuration

setAzureData({ ...azureData, azureEndpoint: e.target.value })} placeholder="https://your-resource.openai.azure.com" hint="Your Azure OpenAI resource endpoint URL" /> setAzureData({ ...azureData, deployment: e.target.value })} placeholder="gpt-4" hint="The deployment name in your Azure resource" /> setAzureData({ ...azureData, apiVersion: e.target.value })} placeholder="2024-10-01-preview" hint="Azure OpenAI API version to use" /> setAzureData({ ...azureData, organization: e.target.value })} placeholder="Organization ID" hint="Required for billing" />
)} {!isCompatible && !isAzure && !isCloudflareAi && (
{testResult && ( {testResult === "success" ? "Valid" : "Failed"} )}
)}
); } EditConnectionModal.propTypes = { isOpen: PropTypes.bool.isRequired, connection: PropTypes.shape({ id: PropTypes.string, name: PropTypes.string, email: PropTypes.string, priority: PropTypes.number, authType: PropTypes.string, provider: PropTypes.string, providerSpecificData: PropTypes.object, }), proxyPools: PropTypes.arrayOf(PropTypes.shape({ id: PropTypes.string, name: PropTypes.string, })), onSave: PropTypes.func.isRequired, onClose: PropTypes.func.isRequired, };