"use client"; import { useState, useEffect, useCallback, useRef } from "react"; import PropTypes from "prop-types"; import { Card, Badge, Button, Modal, Select, Toggle, EditConnectionModal, ConfirmModal } from "@/shared/components"; // ── CooldownTimer ────────────────────────────────────────────── function CooldownTimer({ until }) { const [remaining, setRemaining] = useState(""); useEffect(() => { const update = () => { const diff = new Date(until).getTime() - Date.now(); if (diff <= 0) { setRemaining(""); return; } const s = Math.floor(diff / 1000); if (s < 60) setRemaining(`${s}s`); else if (s < 3600) setRemaining(`${Math.floor(s / 60)}m ${s % 60}s`); else setRemaining(`${Math.floor(s / 3600)}h ${Math.floor((s % 3600) / 60)}m`); }; update(); const t = setInterval(update, 1000); return () => clearInterval(t); }, [until]); if (!remaining) return null; return ⏱ {remaining}; } CooldownTimer.propTypes = { until: PropTypes.string.isRequired }; // ── ConnectionRow ────────────────────────────────────────────── function ConnectionRow({ connection, proxyPools, isOAuth, isFirst, isLast, onMoveUp, onMoveDown, onToggleActive, onUpdateProxy, onEdit, onDelete }) { const [showProxyDropdown, setShowProxyDropdown] = useState(false); const [updatingProxy, setUpdatingProxy] = useState(false); const [isCooldown, setIsCooldown] = useState(false); const proxyDropdownRef = useRef(null); const proxyPoolMap = new Map((proxyPools || []).map((p) => [p.id, p])); const boundProxyPoolId = connection.providerSpecificData?.proxyPoolId || null; const boundProxyPool = boundProxyPoolId ? proxyPoolMap.get(boundProxyPoolId) : null; const hasLegacyProxy = connection.providerSpecificData?.connectionProxyEnabled === true && !!connection.providerSpecificData?.connectionProxyUrl; const hasAnyProxy = !!boundProxyPoolId || hasLegacyProxy; const proxyDisplayText = boundProxyPool ? `Pool: ${boundProxyPool.name}` : boundProxyPoolId ? `Pool: ${boundProxyPoolId} (inactive/missing)` : hasLegacyProxy ? `Legacy: ${connection.providerSpecificData?.connectionProxyUrl}` : ""; let maskedProxyUrl = ""; const rawProxyUrl = boundProxyPool?.proxyUrl || connection.providerSpecificData?.connectionProxyUrl; if (rawProxyUrl) { try { const p = new URL(rawProxyUrl); maskedProxyUrl = `${p.protocol}//${p.hostname}${p.port ? `:${p.port}` : ""}`; } catch { maskedProxyUrl = rawProxyUrl; } } const noProxyText = boundProxyPool?.noProxy || connection.providerSpecificData?.connectionNoProxy || ""; const proxyBadgeVariant = boundProxyPool?.isActive === true ? "success" : (boundProxyPoolId || hasLegacyProxy) ? "error" : "default"; const modelLockUntil = Object.entries(connection) .filter(([k]) => k.startsWith("modelLock_")) .map(([, v]) => v).filter(Boolean).sort()[0] || null; useEffect(() => { const check = () => { const until = Object.entries(connection) .filter(([k]) => k.startsWith("modelLock_")) .map(([, v]) => v).filter(v => v && new Date(v).getTime() > Date.now()).sort()[0] || null; setIsCooldown(!!until); }; check(); const t = modelLockUntil ? setInterval(check, 1000) : null; return () => { if (t) clearInterval(t); }; }, [modelLockUntil]); useEffect(() => { if (!showProxyDropdown) return; const handler = (e) => { if (proxyDropdownRef.current && !proxyDropdownRef.current.contains(e.target)) setShowProxyDropdown(false); }; document.addEventListener("mousedown", handler); return () => document.removeEventListener("mousedown", handler); }, [showProxyDropdown]); const effectiveStatus = connection.testStatus === "unavailable" && !isCooldown ? "active" : connection.testStatus; const getStatusVariant = () => { if (connection.isActive === false) return "default"; if (effectiveStatus === "active" || effectiveStatus === "success") return "success"; if (effectiveStatus === "error" || effectiveStatus === "expired" || effectiveStatus === "unavailable") return "error"; return "default"; }; const displayName = isOAuth ? connection.name || connection.email || connection.displayName || "OAuth Account" : connection.name; const handleSelectProxy = async (poolId) => { setUpdatingProxy(true); try { await onUpdateProxy(poolId === "__none__" ? null : poolId); } finally { setUpdatingProxy(false); setShowProxyDropdown(false); } }; return (
{isOAuth ? "lock" : "key"}

{displayName}

{connection.isActive === false ? "disabled" : (effectiveStatus || "Unknown")} {hasAnyProxy && Proxy} {isCooldown && connection.isActive !== false && } {connection.lastError && connection.isActive !== false && ( {connection.lastError} )} #{connection.priority}
{hasAnyProxy && (
{proxyDisplayText} {maskedProxyUrl && {maskedProxyUrl}} {noProxyText && no_proxy: {noProxyText}}
)}
{(proxyPools || []).length > 0 && (
{showProxyDropdown && (
{(proxyPools || []).map((pool) => ( ))}
)}
)}
); } ConnectionRow.propTypes = { connection: PropTypes.shape({ id: PropTypes.string, name: PropTypes.string, email: PropTypes.string, displayName: PropTypes.string, testStatus: PropTypes.string, isActive: PropTypes.bool, lastError: PropTypes.string, priority: PropTypes.number, }).isRequired, proxyPools: PropTypes.array, isOAuth: PropTypes.bool.isRequired, isFirst: PropTypes.bool.isRequired, isLast: PropTypes.bool.isRequired, onMoveUp: PropTypes.func.isRequired, onMoveDown: PropTypes.func.isRequired, onToggleActive: PropTypes.func.isRequired, onUpdateProxy: PropTypes.func, onEdit: PropTypes.func.isRequired, onDelete: PropTypes.func.isRequired, }; // ── AddApiKeyModal ───────────────────────────────────────────── function AddApiKeyModal({ isOpen, provider, providerName, proxyPools, onSave, onClose }) { const NONE = "__none__"; const [formData, setFormData] = useState({ name: "", apiKey: "", priority: 1, proxyPoolId: NONE }); const [validating, setValidating] = useState(false); const [validationResult, setValidationResult] = useState(null); const [saving, setSaving] = useState(false); const handleValidate = async () => { setValidating(true); try { const res = await fetch("/api/providers/validate", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ provider, apiKey: formData.apiKey }), }); const data = await res.json(); setValidationResult(data.valid ? "success" : "failed"); } catch { setValidationResult("failed"); } finally { setValidating(false); } }; const handleSubmit = async () => { if (!provider || !formData.apiKey) return; setSaving(true); try { let isValid = false; try { setValidating(true); setValidationResult(null); const res = await fetch("/api/providers/validate", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ provider, apiKey: formData.apiKey }), }); const data = await res.json(); isValid = !!data.valid; setValidationResult(isValid ? "success" : "failed"); } catch { setValidationResult("failed"); } finally { setValidating(false); } await onSave({ name: formData.name, apiKey: formData.apiKey, priority: formData.priority, proxyPoolId: formData.proxyPoolId === NONE ? null : formData.proxyPoolId, testStatus: isValid ? "active" : "unknown", }); } finally { setSaving(false); } }; if (!provider) return null; return (
setFormData({ ...formData, name: e.target.value })} placeholder="Production Key" />
setFormData({ ...formData, apiKey: e.target.value })} />
{validationResult && ( {validationResult === "success" ? "Valid" : "Invalid"} )}
setFormData({ ...formData, priority: Number.parseInt(e.target.value) || 1 })} />
{ setProviderStickyLimit(e.target.value); saveStrategy("round-robin", e.target.value); }} className="w-16 px-2 py-1 text-xs border border-border rounded-md bg-background focus:outline-none focus:border-primary" />
)} {connections.length === 0 ? (

No connections yet

) : ( <>
{connections.map((conn, idx) => ( handleSwapPriority(idx, idx - 1)} onMoveDown={() => handleSwapPriority(idx, idx + 1)} onToggleActive={(isActive) => handleToggleActive(conn.id, isActive)} onUpdateProxy={(poolId) => handleUpdateProxy(conn.id, poolId)} onEdit={() => { setSelectedConnection(conn); setShowEditModal(true); }} onDelete={() => handleDelete(conn.id)} /> ))}
)} setShowAddModal(false)} /> setShowEditModal(false)} /> {/* Confirm Modal */} setConfirmState(null)} onConfirm={confirmState?.onConfirm} title={confirmState?.title || "Confirm"} message={confirmState?.message} variant="danger" /> ); } ConnectionsCard.propTypes = { providerId: PropTypes.string.isRequired, isOAuth: PropTypes.bool, };