"use client"; import { useEffect, useState } from "react"; import { useTranslations } from "next-intl"; type PipelineStep = { engine: string; intensity?: string }; type CompressionCombo = { id: string; name: string; description: string; pipeline: PipelineStep[]; languagePacks: string[]; outputMode: boolean; outputModeIntensity: string; isDefault: boolean; }; type RoutingCombo = { id?: string; name?: string }; type LanguagePack = { language: string; ruleCount: number }; const EMPTY_PIPELINE: PipelineStep[] = [ { engine: "rtk", intensity: "standard" }, { engine: "caveman", intensity: "full" }, ]; const ENGINE_INTENSITIES: Record = { rtk: ["minimal", "standard", "aggressive"], caveman: ["lite", "full", "ultra"], lite: ["lite"], aggressive: ["standard"], ultra: ["ultra"], }; export default function CompressionCombosPageClient() { const t = useTranslations("contextCombos"); const [combos, setCombos] = useState([]); const [routingCombos, setRoutingCombos] = useState([]); const [languagePacks, setLanguagePacks] = useState([]); const [editingId, setEditingId] = useState(null); const [name, setName] = useState(""); const [description, setDescription] = useState(""); const [pipeline, setPipeline] = useState(EMPTY_PIPELINE); const [selectedPacks, setSelectedPacks] = useState(["en"]); const [outputMode, setOutputMode] = useState(false); const [outputModeIntensity, setOutputModeIntensity] = useState("full"); const [assignmentIds, setAssignmentIds] = useState([]); const [saving, setSaving] = useState(false); const refresh = () => { fetch("/api/context/combos") .then((res) => (res.ok ? res.json() : null)) .then((data) => setCombos(Array.isArray(data?.combos) ? data.combos : [])) .catch(() => {}); }; useEffect(() => { refresh(); fetch("/api/combos") .then((res) => (res.ok ? res.json() : null)) .then((data) => setRoutingCombos(Array.isArray(data?.combos) ? data.combos : [])) .catch(() => {}); fetch("/api/compression/language-packs") .then((res) => (res.ok ? res.json() : null)) .then((data) => setLanguagePacks(Array.isArray(data?.packs) ? data.packs : [])) .catch(() => {}); }, []); const resetForm = () => { setEditingId(null); setName(""); setDescription(""); setPipeline(EMPTY_PIPELINE); setSelectedPacks(["en"]); setOutputMode(false); setOutputModeIntensity("full"); setAssignmentIds([]); }; const loadAssignments = async (id: string) => { const res = await fetch(`/api/context/combos/${id}/assignments`); if (!res.ok) return []; const data = await res.json(); return Array.isArray(data?.assignments) ? data.assignments.map((item: { routingComboId: string }) => item.routingComboId) : []; }; const editCombo = async (combo: CompressionCombo) => { setEditingId(combo.id); setName(combo.name); setDescription(combo.description ?? ""); setPipeline(combo.pipeline.length > 0 ? combo.pipeline : EMPTY_PIPELINE); setSelectedPacks(combo.languagePacks?.length ? combo.languagePacks : ["en"]); setOutputMode(Boolean(combo.outputMode)); setOutputModeIntensity(combo.outputModeIntensity ?? "full"); setAssignmentIds(await loadAssignments(combo.id)); }; const saveCombo = async () => { const trimmed = name.trim(); if (!trimmed) return; setSaving(true); try { const payload = { name: trimmed, description, pipeline, languagePacks: selectedPacks, outputMode, outputModeIntensity, }; const res = await fetch( editingId ? `/api/context/combos/${editingId}` : "/api/context/combos", { method: editingId ? "PUT" : "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload), } ); if (!res.ok) return; const combo = await res.json(); await fetch(`/api/context/combos/${combo.id}/assignments`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ routingComboIds: assignmentIds }), }); resetForm(); refresh(); } finally { setSaving(false); } }; const deleteCombo = async (combo: CompressionCombo) => { if (!confirm(t("deleteConfirm"))) return; const res = await fetch(`/api/context/combos/${combo.id}`, { method: "DELETE" }); if (res.ok) refresh(); }; const setDefault = async (id: string) => { const res = await fetch(`/api/context/combos/${id}`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ isDefault: true }), }); if (res.ok) refresh(); }; const updateStep = (index: number, patch: Partial) => { setPipeline((current) => current.map((step, stepIndex) => { if (stepIndex !== index) return step; const next = { ...step, ...patch }; const allowed = ENGINE_INTENSITIES[next.engine] ?? ["standard"]; return { ...next, intensity: allowed.includes(next.intensity ?? "") ? next.intensity : allowed[0], }; }) ); }; const togglePack = (language: string, enabled: boolean) => { setSelectedPacks((current) => enabled ? [...new Set([...current, language])] : current.filter((item) => item !== language && item !== "en") ); }; const toggleAssignment = (id: string, enabled: boolean) => { setAssignmentIds((current) => enabled ? [...new Set([...current, id])] : current.filter((item) => item !== id) ); }; return (
setName(event.target.value)} placeholder={t("name")} className="rounded-lg border border-border bg-bg px-3 py-2 text-sm text-text-main" /> setDescription(event.target.value)} placeholder={t("descriptionField")} className="rounded-lg border border-border bg-bg px-3 py-2 text-sm text-text-main" />

{t("pipeline")}

{pipeline.map((step, index) => (
))}

{t("languagePacks")}

{languagePacks.map((pack) => ( ))}

{t("outputMode")}

{t("assignToRouting")}

{routingCombos.length === 0 ? (

{t("noAssignments")}

) : ( routingCombos.map((combo) => { const id = combo.id ?? combo.name ?? ""; if (!id) return null; return ( ); }) )}
{editingId && ( )}
{combos.map((combo) => (

{combo.name}

{combo.description}

{combo.isDefault && ( {t("default")} )}
{combo.pipeline.map((step, index) => ( {index + 1}. {step.engine} {step.intensity ? `:${step.intensity}` : ""} ))}

{t("languagePacks")}: {combo.languagePacks.join(", ")}

{!combo.isDefault && ( )} {!combo.isDefault && ( )}
))}
); }