// jobs.js (Aktivität) — System-Metriken & Hintergrund-Jobs
import { $, esc, icon } from "../core/ui.js";
const tracked = new Set();
let JOBS = [];
let SYS = null;
export function track(id) {
tracked.add(id);
renderJobs();
}
function statusBadge(state) {
if (state === "done") return 'fertig';
if (state === "failed") return 'fehler';
return 'lädt…';
}
function dotClass(state) {
if (state === "done") return "on";
if (state === "failed") return "";
return "load";
}
function kpi(cls, title, ic, value, sub) {
return `
${title}${icon(ic)}
${value}
${sub}
`;
}
function kvRow(k, v, cls = "") {
return `${k}${v}
`;
}
// Chart-Daten (letzte 30 Sekunden, je 0.5s Stream = 60 Punkte)
const hist = { cpu: [], ram: [], gpu: [] };
const MAX_HIST = 60;
function renderSys() {
if (!SYS) return;
const sysV = `${SYS.cpu.percent.toFixed(0)}% CPU`;
const sysS = `${SYS.ram.percent.toFixed(0)}% RAM, ${SYS.gpu_temp ? SYS.gpu_temp.toFixed(0)+'°C' : SYS.cpu.temp ? SYS.cpu.temp.toFixed(0)+'°C' : '–'}`;
// History aktualisieren
hist.cpu.push(SYS.cpu.percent);
hist.ram.push(SYS.ram.percent);
let gpuP = 0;
if (SYS.gpu && SYS.gpu.vram.total) {
gpuP = ((SYS.gpu.vram.used + SYS.gpu.gtt.used) / (SYS.gpu.vram.total + SYS.gpu.gtt.total)) * 100;
}
hist.gpu.push(gpuP);
if (hist.cpu.length > MAX_HIST) hist.cpu.shift();
if (hist.ram.length > MAX_HIST) hist.ram.shift();
if (hist.gpu.length > MAX_HIST) hist.gpu.shift();
// Mini-Sparklines generieren
const makeBars = (arr, color) => {
return '' +
arr.map(v => `
`).join("") +
'
';
};
$("#act-kpis").innerHTML =
kpi("blue", "CPU Last", "gauge", sysV, sysS) +
kpi("purple", "RAM", "monitor", `${SYS.ram.percent.toFixed(0)}%`, "Arbeitsspeicher") +
kpi("green", "GPU VRAM", "layers", `${gpuP.toFixed(0)}%`, "Grafikspeicher");
const gb = b => (b / 1024 / 1024 / 1024).toFixed(1);
const ramStr = `${gb(SYS.ram.used)} GB / ${gb(SYS.ram.total)} GB`;
const gpuStr = (SYS.gpu && SYS.gpu.vram.total) ? `${gb(SYS.gpu.vram.used + SYS.gpu.gtt.used)} GB / ${gb(SYS.gpu.vram.total + SYS.gpu.gtt.total)} GB` : "–";
const diskStr = `${SYS.disk.percent.toFixed(0)}% belegt`;
$("#act-sys").innerHTML = `
System-Metriken (Bosgame)
${kvRow("Arbeitsspeicher (RAM)", ramStr)}
${kvRow("Grafikspeicher (VRAM+GTT)", gpuStr)}
${kvRow("Speicherplatz (Disk)", diskStr)}
${kvRow("Temperatur (GPU / CPU)", `${SYS.gpu_temp?.toFixed(1) || '–'}°C / ${SYS.cpu.temp?.toFixed(1) || '–'}°C`)}
CPU Historie
${makeBars(hist.cpu, "act")}
RAM Historie
${makeBars(hist.ram, "purple")}
VRAM Historie
${makeBars(hist.gpu, "on")}
`;
}
function mount() {
$("#v-activity").innerHTML = `
Hintergrund-Aktivitäten
Keine laufenden Jobs.
Downloads, Updates & Co. erscheinen hier mit Live-Log.
`;
// Klicks auf Job-Kopf -> auf/zuklappen
$("#v-activity").addEventListener("click", e => {
const h = e.target.closest(".job-h");
if (!h) return;
const id = h.getAttribute("data-id");
tracked.has(id) ? tracked.delete(id) : tracked.add(id);
renderJobs();
});
if (SYS) renderSys();
}
function renderJobs() {
const c = $("#jobs");
if (!c) return;
$("#jobs-empty").style.display = JOBS.length ? "none" : "flex";
const failed = JOBS.filter(j => j.state === "failed").length;
$("#job-count").textContent = JOBS.length ? (failed ? failed + " Fehler" : JOBS.length + " gesamt") : "";
c.innerHTML = JOBS.map(j => {
const open = tracked.has(j.id);
const log = open ? `${esc((j.log || []).join("\\n"))}
` : "";
return `
${esc(j.label)}${statusBadge(j.state)}
${log}
`;
}).join("");
}
function onJobs(jobs) {
JOBS = jobs || [];
renderJobs();
}
function onSystem(sys) {
SYS = sys;
const c = $("#act-sys");
if (c) renderSys();
}
export default { id: "jobs", mount, onJobs, onSystem };