diff --git a/changelog.d/features/6760-compression-mode-selector-context-cache.md b/changelog.d/features/6760-compression-mode-selector-context-cache.md new file mode 100644 index 0000000000..ae25386636 --- /dev/null +++ b/changelog.d/features/6760-compression-mode-selector-context-cache.md @@ -0,0 +1 @@ +- **feat(dashboard):** add per-routing-combo compression-mode override to the Compression Combos page under Context & Cache, alongside the existing combo-card quick override. (#6760) diff --git a/docs/compression/COMPRESSION_GUIDE.md b/docs/compression/COMPRESSION_GUIDE.md index 48bf546093..326a042a1c 100644 --- a/docs/compression/COMPRESSION_GUIDE.md +++ b/docs/compression/COMPRESSION_GUIDE.md @@ -188,6 +188,14 @@ Combo: "free-forever" This lets you use stacked compression on free/coding providers while keeping lite mode on paid subscriptions. +This "Per-Combo Override" assignment is a different control from the **routing-combo compression +mode** override (Default/Off/Lite/Standard/Aggressive/Ultra) — that override does not pick a named +compression-combo pipeline; it just sets the `compressionMode` field consulted by +`resolveCompressionPlan`. It can be set either on the combo card (`Dashboard → Combos`) or, since +#6760, per routing combo in the "Assign to routing" list on +`Dashboard → Context & Cache → Compression Combos`, right next to the pipeline-assignment checkbox +documented above. Both surfaces persist through the same `PUT /api/combos/{id}` endpoint. + ### Per-request override Send the `x-omniroute-compression` request header to override the compression plan for a single diff --git a/src/app/(dashboard)/dashboard/combos/page.tsx b/src/app/(dashboard)/dashboard/combos/page.tsx index 9125fcea08..1b794a1651 100644 --- a/src/app/(dashboard)/dashboard/combos/page.tsx +++ b/src/app/(dashboard)/dashboard/combos/page.tsx @@ -12,6 +12,7 @@ import Input from "@/shared/components/Input"; import Modal from "@/shared/components/Modal"; import Toggle from "@/shared/components/Toggle"; import Tooltip from "@/shared/components/Tooltip"; +import { ComboCompressionModeSelect } from "@/shared/components/compression/ComboCompressionModeSelect"; import { useCopyToClipboard } from "@/shared/hooks/useCopyToClipboard"; import { filterUsableConnections } from "@/shared/utils/connectionStatus"; import { FieldLabelWithHelp, WeightTotalBar } from "./parts"; @@ -1576,46 +1577,6 @@ function ComboCard({ const tc = useTranslations("common"); const emailsVisible = useEmailPrivacyStore((s) => s.emailsVisible); const strategyDescription = getStrategyDescription(t, strategy); - const hasRuntimeConfig = combo?.config && typeof combo.config === "object"; - const initialCompressionMode = - typeof combo?.config?.compressionMode === "string" - ? combo.config.compressionMode - : hasRuntimeConfig - ? "" - : combo.compressionOverride || ""; - const [compressionOverride, setCompressionOverride] = useState(initialCompressionMode); - const [isSavingCompression, setIsSavingCompression] = useState(false); - - useEffect(() => { - setCompressionOverride(initialCompressionMode); - }, [initialCompressionMode]); - - const handleCompressionOverrideChange = async (value) => { - setCompressionOverride(value); - setIsSavingCompression(true); - const nextConfig = { ...(combo.config || {}) }; - if (value) { - nextConfig.compressionMode = value; - } else { - delete nextConfig.compressionMode; - } - try { - const response = await fetch(`/api/combos/${combo.id}`, { - method: "PUT", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ config: nextConfig }), - }); - if (!response.ok) { - console.error("Failed to update compression override"); - setCompressionOverride(initialCompressionMode); - } - } catch (error) { - console.error("Error updating compression override:", error); - setCompressionOverride(initialCompressionMode); - } finally { - setIsSavingCompression(false); - } - }; return (
{compressionEnabled && ( - + className="text-xs py-1 px-2 rounded border border-black/10 dark:border-white/10 bg-surface text-text-main focus:border-primary focus:outline-none transition-colors disabled:opacity-50 max-w-[130px] md:max-w-none" + /> )} ([]); const [saving, setSaving] = useState(false); const [activeComboId, setActiveComboId] = useState(null); + const [compressionEnabled, setCompressionEnabled] = useState(false); const [error, setError] = useState(null); const refresh = () => { @@ -70,7 +76,10 @@ function NamedCombosManager() { .catch(() => {}); fetch("/api/settings/compression") .then((res) => (res.ok ? res.json() : null)) - .then((data) => setActiveComboId(data?.activeComboId ?? null)) + .then((data) => { + setActiveComboId(data?.activeComboId ?? null); + setCompressionEnabled(Boolean(data?.enabled)); + }) .catch(() => {}); }, []); @@ -255,14 +264,22 @@ function NamedCombosManager() { const id = combo.id ?? combo.name ?? ""; if (!id) return null; return ( -