import { useTranslation } from "react-i18next"; import { CircuitBreakerConfig } from "../../types/config"; import { ShieldAlert, Trash2, Plus, Minus, Clock } from "lucide-react"; interface CircuitBreakerProps { config: CircuitBreakerConfig; onChange: (config: CircuitBreakerConfig) => void; onClearRateLimits?: () => void; } export default function CircuitBreaker({ config, onChange, onClearRateLimits, }: CircuitBreakerProps) { const { t } = useTranslation(); const handleLevelChange = (index: number, val: string) => { let num = parseInt(val, 10); if (isNaN(num)) num = 0; const newSteps = [...config.backoff_steps]; newSteps[index] = Math.max(0, num); onChange({ ...config, backoff_steps: newSteps }); }; const addLevel = () => { const lastVal = config.backoff_steps[config.backoff_steps.length - 1] || 60; onChange({ ...config, backoff_steps: [...config.backoff_steps, lastVal * 2], }); }; const removeLevel = (index: number) => { if (config.backoff_steps.length <= 1) return; const newSteps = config.backoff_steps.filter((_, i) => i !== index); onChange({ ...config, backoff_steps: newSteps }); }; const getStepColorCls = (index: number) => { if (index === 0) return "border-yellow-200 dark:border-yellow-700/50 bg-yellow-50/30 dark:bg-yellow-900/10"; if (index === 1) return "border-orange-200 dark:border-orange-700/50 bg-orange-50/30 dark:bg-orange-900/10"; if (index === 2) return "border-red-200 dark:border-red-700/50 bg-red-50/30 dark:bg-red-900/10"; return "border-rose-200 dark:border-rose-700/50 bg-rose-50/30 dark:bg-rose-900/10"; }; return (

{t("proxy.config.circuit_breaker.title", { defaultValue: "Adaptive Circuit Breaker" })}

{t("proxy.config.circuit_breaker.tooltip", { defaultValue: "Automatically increases lockout duration for accounts that repeatedly fail with quota exhaustion. This prevents wasting API calls on dead accounts while allowing transient errors to recover quickly.", })}

{config.backoff_steps.map((seconds, idx) => (
{t("proxy.config.circuit_breaker.level", { level: idx + 1, defaultValue: `Lv ${idx + 1}` })} {config.backoff_steps.length > 1 && ( )}
handleLevelChange(idx, e.target.value)} className="w-full bg-white dark:bg-base-100 border border-gray-200 dark:border-gray-700 rounded-lg px-3 py-1.5 text-sm font-mono focus:ring-2 focus:ring-blue-500/20 outline-none transition-all [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none" min="0" /> S
))}
{onClearRateLimits && (
)}
); }