From 0deeaf5ffbe1e27abe50b20f2d863c626c02c0f5 Mon Sep 17 00:00:00 2001 From: diegosouzapw Date: Fri, 20 Feb 2026 02:53:14 -0300 Subject: [PATCH] feat: combo enable/disable toggle + provider toggle always visible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Combos page: added Toggle to each ComboCard — disable/enable combos with optimistic UI update. Disabled combos show opacity-50. 2. /v1/models: disabled combos (isActive=false) are excluded from the model list. 3. Providers page: toggle is now always visible instead of hover-only. --- src/app/(dashboard)/dashboard/combos/page.tsx | 113 +++++++++++------- .../(dashboard)/dashboard/providers/page.tsx | 4 +- src/app/api/v1/models/route.ts | 3 +- 3 files changed, 76 insertions(+), 44 deletions(-) diff --git a/src/app/(dashboard)/dashboard/combos/page.tsx b/src/app/(dashboard)/dashboard/combos/page.tsx index aa6648ee29..3dcda4d1ab 100644 --- a/src/app/(dashboard)/dashboard/combos/page.tsx +++ b/src/app/(dashboard)/dashboard/combos/page.tsx @@ -6,6 +6,7 @@ import { Button, Modal, Input, + Toggle, CardSkeleton, ModelSelectModal, ProxyConfigModal, @@ -170,6 +171,25 @@ export default function CombosPage() { } }; + const handleToggleCombo = async (combo) => { + const newActive = combo.isActive === false ? true : false; + // Optimistic update + setCombos((prev) => prev.map((c) => (c.id === combo.id ? { ...c, isActive: newActive } : c))); + try { + await fetch(`/api/combos/${combo.id}`, { + method: "PUT", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ isActive: newActive }), + }); + } catch (error) { + // Revert on error + setCombos((prev) => + prev.map((c) => (c.id === combo.id ? { ...c, isActive: !newActive } : c)) + ); + notify.error("Failed to toggle combo"); + } + }; + if (loading) { return (
@@ -219,6 +239,7 @@ export default function CombosPage() { testing={testingCombo === combo.name} onProxy={() => setProxyTargetCombo(combo)} hasProxy={!!proxyConfig?.combos?.[combo.id]} + onToggle={() => handleToggleCombo(combo)} /> ))}
@@ -287,12 +308,14 @@ function ComboCard({ testing, onProxy, hasProxy, + onToggle, }) { const strategy = combo.strategy || "priority"; const models = combo.models || []; + const isDisabled = combo.isActive === false; return ( - +
{/* Icon */} @@ -386,47 +409,55 @@ function ComboCard({
{/* Actions */} -
- - - - - + + {testing ? "progress_activity" : "play_arrow"} + + + + + + +
diff --git a/src/app/(dashboard)/dashboard/providers/page.tsx b/src/app/(dashboard)/dashboard/providers/page.tsx index 4f5b68f994..7ab21fcae9 100644 --- a/src/app/(dashboard)/dashboard/providers/page.tsx +++ b/src/app/(dashboard)/dashboard/providers/page.tsx @@ -534,7 +534,7 @@ function ProviderCard({ providerId, provider, stats, authType, onToggle }) { e.stopPropagation(); onToggle(!allDisabled ? false : true); }} - className="opacity-0 group-hover:opacity-100 transition-opacity" + className="" >