// main.js — App-Boot: Panels mounten, Nav starten, Topbar/Alert pflegen, Polling fahren. // Panel-Vertrag: { id, mount?(), onStatus?(s), onJobs?(jobs) }. import { api, getToken, setToken } from "./core/api.js"; import { $ } from "./core/ui.js"; import { initNav } from "./core/nav.js"; import overview from "./panels/overview.js"; import models from "./panels/models.js"; import maintenance from "./panels/maintenance.js"; import jobs from "./panels/jobs.js"; import cookbook from "./panels/cookbook.js"; import guides from "./panels/guides.js"; const panels = [overview, models, maintenance, jobs, cookbook, guides]; let lastJobs = []; let lastSystem = null; // ---- Topbar / Alert aus dem Status ableiten ---- function applyStatus(s) { const dot = $("#swdot"), label = $("#swlabel"), alert = $("#alert"); if (!s) { dot.className = "dot off"; label.textContent = "Backend nicht erreichbar"; $("#top-models").textContent = "–"; showAlert("Backend nicht erreichbar — läuft uvicorn?", false); } else { const host = s.swap_url.replace(/^https?:\/\//, ""); dot.className = "dot " + (s.swap_ok ? "on" : "off"); label.textContent = (s.swap_ok ? "llama-swap online · " : "llama-swap offline · ") + host; $("#top-models").textContent = (s.models || []).length; if (s.swap_ok) hideAlert(); else showAlert(`llama-swap nicht erreichbar unter ${host} — läuft der Dienst?`, true); } for (const p of panels) p.onStatus?.(s); } function applyJobs(jobs) { lastJobs = jobs || []; $("#top-jobs").textContent = lastJobs.filter(j => j.state === "running" || j.state === "queued").length; for (const p of panels) p.onJobs?.(lastJobs); } function applySystem(sys) { lastSystem = sys; for (const p of panels) p.onSystem?.(sys); } function showAlert(html, warn) { const a = $("#alert"); a.className = "alert" + (warn ? " warn" : ""); a.innerHTML = `${html}`; a.style.display = "flex"; } function hideAlert() { $("#alert").style.display = "none"; } // ---- Polling ---- async function pollStatus() { try { applyStatus(await api("/api/status")); } catch { applyStatus(null); } } async function pollJobs() { try { applyJobs(await api("/api/jobs")); } catch { /* still */ } } async function pollSystem() { try { applySystem(await api("/api/system/status")); } catch { /* still */ } } // ---- Boot ---- function bootToken() { const i = $("#token"); i.value = getToken(); i.addEventListener("change", e => { setToken(e.target.value); pollStatus(); }); } function tickClock() { $("#clock").textContent = new Date().toTimeString().slice(0, 5); } for (const p of panels) p.mount?.(); initNav("overview"); bootToken(); tickClock(); document.addEventListener("mc:refresh", pollStatus); pollStatus(); pollJobs(); pollSystem(); setInterval(tickClock, 1000); setInterval(pollStatus, 3000); setInterval(pollJobs, 1500); setInterval(pollSystem, 3000);