first commit

This commit is contained in:
nix
2026-05-16 11:10:19 +02:00
commit 509c9b3737
172 changed files with 14496 additions and 0 deletions
+166
View File
@@ -0,0 +1,166 @@
/**
* System Stats Loader — inclut MDADM
*/
(function() {
'use strict';
const API_STATS = '/data/api/system-stats.php';
const API_MDADM = '/data/api/mdadm-status.php';
const INTERVAL = 5000;
let timer = null;
let updating = false;
let loadedOnce = false;
const el = {
uptime: document.getElementById('uptime'),
cpu: document.getElementById('cpu'),
ram: document.getElementById('ram'),
ramSub: document.getElementById('ram-subtitle'),
diskRoot: document.getElementById('disk-root'),
diskRootSub: document.getElementById('disk-root-subtitle'),
diskVar: document.getElementById('disk-var'),
diskVarSub: document.getElementById('disk-var-subtitle'),
diskSrv: document.getElementById('disk-srv'),
diskSrvSub: document.getElementById('disk-srv-subtitle'),
load: document.getElementById('load'),
processes: document.getElementById('processes'),
mdadmCard: document.getElementById('mdadm-card'),
mdadmStatus: document.getElementById('mdadm-status'),
mdadmSub: document.getElementById('mdadm-subtitle'),
};
function set(element, value) {
if (!element || value === undefined) return;
const v = String(value);
if (element.textContent !== v) element.textContent = v;
}
function color(element, percent, warn, danger) {
if (!element) return;
const c = percent > danger ? '#ff5555' : percent > warn ? '#ffb86c' : '#50fa7b';
if (element.style.color !== c) element.style.color = c;
}
async function fetchStats() {
if (updating) return;
updating = true;
try {
const r = await fetch(API_STATS, { cache: 'no-cache' });
if (!r.ok) throw new Error(`HTTP ${r.status}`);
const { success, data } = await r.json();
if (success && data) renderStats(data);
else if (loadedOnce) showError();
} catch(e) {
console.error('system-stats:', e);
if (loadedOnce) showError();
} finally {
updating = false;
}
}
function renderStats(s) {
loadedOnce = true;
set(el.uptime, s.uptime);
if (s.cpu_usage !== undefined) {
set(el.cpu, s.cpu_usage + '%');
color(el.cpu, s.cpu_usage, 50, 80);
}
if (s.ram_used !== undefined) {
set(el.ram, s.ram_used + ' Gio');
set(el.ramSub, `sur ${s.ram_total} Gio (${s.ram_percent}%)`);
color(el.ram, s.ram_percent, 60, 80);
}
if (s.disk_root_free !== undefined) {
set(el.diskRoot, s.disk_root_free + ' Gio');
set(el.diskRootSub, `sur ${s.disk_root_total} Gio (${s.disk_root_percent}% utilisé)`);
color(el.diskRoot, s.disk_root_percent, 70, 90);
}
if (s.disk_var_free !== undefined) {
set(el.diskVar, s.disk_var_free + ' Gio');
set(el.diskVarSub, `sur ${s.disk_var_total} Gio (${s.disk_var_percent}% utilisé)`);
color(el.diskVar, s.disk_var_percent, 70, 90);
}
if (s.disk_srv_free !== undefined) {
set(el.diskSrv, s.disk_srv_free + ' Gio');
set(el.diskSrvSub, `sur ${s.disk_srv_total} Gio (${s.disk_srv_percent}% utilisé)`);
color(el.diskSrv, s.disk_srv_percent, 70, 90);
}
if (s.load_1 !== undefined) {
set(el.load, s.load_1);
color(el.load, (s.load_1 / 4) * 100, 50, 80);
}
set(el.processes, s.processes);
}
async function fetchMdadm() {
try {
const r = await fetch(API_MDADM, { cache: 'no-cache' });
if (!r.ok) throw new Error(`HTTP ${r.status}`);
const d = await r.json();
if (d.healthy) {
set(el.mdadmStatus, '✓ Sain');
if (el.mdadmStatus) el.mdadmStatus.style.color = '#50fa7b';
set(el.mdadmSub, d.arrays.map(a => `${a.name} [${a.bitmap}]`).join(' · '));
if (el.mdadmCard) el.mdadmCard.style.borderTop = '';
} else {
set(el.mdadmStatus, '⚠ Dégradé');
if (el.mdadmStatus) el.mdadmStatus.style.color = '#ff5555';
set(el.mdadmSub, d.arrays
.filter(a => a.health !== 'ok')
.map(a => `${a.name}: ${a.detail || a.health}`)
.join(' · '));
if (el.mdadmCard) el.mdadmCard.style.borderTop = '2px solid #ff5555';
}
} catch(e) {
set(el.mdadmStatus, '?');
if (el.mdadmStatus) el.mdadmStatus.style.color = '#ffb86c';
set(el.mdadmSub, 'erreur fetch');
}
}
function showError() {
['uptime','cpu','ram','diskRoot','diskVar','diskSrv','load','processes'].forEach(k => {
if (el[k]) { el[k].textContent = 'Erreur'; el[k].style.color = '#ff5555'; }
});
}
async function refresh() {
await fetchStats();
await fetchMdadm();
}
function stop() {
if (timer) { clearInterval(timer); timer = null; }
}
function start() {
stop();
timer = setInterval(refresh, INTERVAL);
}
function init() {
if (!document.querySelector('.stats-section')) return;
refresh();
start();
window.addEventListener('beforeunload', stop);
document.addEventListener('visibilitychange', () => {
if (document.hidden) stop();
else { refresh(); start(); }
});
}
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
else init();
})();