// SPDX-License-Identifier: GPL-3.0-or-later /* === Threshold editor panel === */ let threshData = null; async function loadThresh() { try { const r = await fetch("/api/thresholds", { cache: "no-store" }); if (!r.ok) throw new Error("" + r.status); const j = await r.json(); threshData = j.thresholds || j.defaults || {}; const defs = j.defaults || {}; const fields = [ ["diskFullPct", "Disk full %", "90"], ["diskWarnPct", "Disk warn %", "80"], ["memLowRatio", "Mem low ratio", "0.15"], ["memWarnRatio", "Mem warn ratio", "0.25"], ["loadWarnRatio", "Load warn", "0.7"], ["loadHighRatio", "Load high", "1.0"], ["loadCriticalRatio", "Load crit", "1.5"], ["tempWarnC", "Temp warn \u00b0C", "85"], ["tempHotC", "Temp hot \u00b0C", "95"], ["procWarnRatio", "Proc warn", "0.2"], ["procHighRatio", "Proc high", "0.4"], ["journalWarnBytes", "Journal bytes", "2147483648"], ["containerWarnGB", "Cont. warn GB", "20"], ["containerHighGB", "Cont. high GB", "50"], ["dnsSlowMs", "DNS slow ms", "500"], ["certWarnDays", "Cert warn days", "30"], ["certCritDays", "Cert crit days", "7"], ["backupStaleDays", "Backup stale days", "30"], ]; $("#threshbody").innerHTML = fields.map(([k, label, def]) => { const v = threshData[k] ?? defs[k] ?? def; return '
'; }).join(""); if (!threshData || Object.keys(threshData).length === 0) { try { const r2 = await fetch("http://127.0.0.1:17321/thresholds", { cache: "no-store" }); if (r2.ok) { const j2 = await r2.json(); if (j2.thresholds) threshData = j2.thresholds; } } catch {} } } catch (e) { $("#threshbody").innerHTML = '
Could not load thresholds: ' + esc(e.message) + '
'; } } function setupThresholds() { const threshBtn = $("#threshbtn"); const threshPanel = $("#threshpanel"); const threshBody = $("#threshbody"); const threshMsg = $("#threshmsg"); if (!threshBtn || !threshPanel) return; threshBtn.addEventListener("click", async () => { const hidden = threshPanel.hidden; threshPanel.hidden = !hidden; if (!hidden) return; await loadThresh(); }); $("#threshclose")?.addEventListener("click", () => threshPanel.hidden = true); $("#threshcopy")?.addEventListener("click", async () => { const data = {}; threshBody.querySelectorAll("input[data-k]").forEach(inp => { const k = inp.dataset.k; const v = Number(inp.value); if (Number.isFinite(v)) data[k] = v; }); await copyText(JSON.stringify({ thresholds: data }, null, 2)); threshMsg.textContent = "\u2713 Copied JSON"; showToast("\u2713 Thresholds JSON copied \u2014 paste into ~/.config/linux-doctor/config.json"); setTimeout(() => threshMsg.textContent = "", 1500); }); $("#threshsave")?.addEventListener("click", async () => { const data = {}; threshBody.querySelectorAll("input[data-k]").forEach(inp => { const k = inp.dataset.k; const v = Number(inp.value); if (Number.isFinite(v)) data[k] = v; }); threshMsg.textContent = "Saving\u2026"; let ok = false; try { const r = await fetch("/api/thresholds", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ thresholds: data }) }); ok = r.ok; } catch {} if (!ok) { try { const r2 = await fetch("http://127.0.0.1:17321/thresholds", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ thresholds: data }) }); ok = r2.ok; } catch {} } threshMsg.textContent = ok ? "\u2713 Saved \u2014 re-run checks to apply" : "\u2717 Save failed"; showToast(ok ? "\u2713 Thresholds saved" : "\u2717 Could not save thresholds"); if (ok) setTimeout(() => threshPanel.hidden = true, 900); }); }