diff --git a/hbd/server/templates/plugins.html b/hbd/server/templates/plugins.html index 917d82b..94f3659 100644 --- a/hbd/server/templates/plugins.html +++ b/hbd/server/templates/plugins.html @@ -809,15 +809,11 @@ return json.samples || []; } - function renderCpuChart(hostname, samples) { - const el = document.getElementById(`cpu-chart-${hostname}`); - if (!el || !samples.length) return; - - const pts = samples - .filter(s => s.data.cpu_percent != null) - .map(s => ({ t: s.timestamp, v: s.data.cpu_percent })); - if (pts.length < 2) { el.style.display = 'none'; return; } + function renderTimeSeriesChart(elId, pts, opts) { + const el = document.getElementById(elId); + if (!el || pts.length < 2) { if (el) el.style.display = 'none'; return; } + const unitSuffix = opts.unitSuffix || ''; const W = 600, H = 80, PAD = { top: 6, right: 8, bottom: 18, left: 28 }; const cW = W - PAD.left - PAD.right; const cH = H - PAD.top - PAD.bottom; @@ -826,13 +822,15 @@ const tRange = tMax - tMin || 1; const x = t => PAD.left + ((t - tMin) / tRange) * cW; - // Auto-scale Y axis with 10% padding, clamped to [0, 100] + // Auto-scale Y axis with 10% padding, optionally clamped to opts.yDomain const vMin = Math.min(...pts.map(p => p.v)); const vMax = Math.max(...pts.map(p => p.v)); const vRange = vMax - vMin || 1; const vPad = Math.max(vRange * 0.1, 1); - const yLow = Math.max(0, vMin - vPad); - const yHigh = Math.min(100, vMax + vPad); + const domainLow = Array.isArray(opts.yDomain) ? opts.yDomain[0] : 0; + const domainHigh = Array.isArray(opts.yDomain) ? opts.yDomain[1] : Infinity; + const yLow = Math.max(domainLow, vMin - vPad); + const yHigh = Math.min(domainHigh, vMax + vPad); const yRange = yHigh - yLow || 1; const y = v => PAD.top + cH - ((v - yLow) / yRange) * cH; @@ -842,10 +840,9 @@ pts.map(p => `L${x(p.t).toFixed(1)},${y(p.v).toFixed(1)}`).join(' ') + ` L${x(pts[pts.length-1].t).toFixed(1)},${(PAD.top + cH).toFixed(1)} Z`; - // Color based on latest absolute CPU % + // Color based on latest value const latest = pts[pts.length - 1].v; - const strokeColor = latest > 90 ? '#e53935' : latest > 70 ? '#fb8c00' : '#43a047'; - const fillColor = latest > 90 ? '#ffcdd2' : latest > 70 ? '#ffe0b2' : '#c8e6c9'; + const { stroke: strokeColor, fill: fillColor } = opts.colorFor(latest); // Compute nice tick step for ~3-5 grid lines const rawStep = yRange / 4; @@ -855,7 +852,7 @@ let gridLines = ''; for (let v = tickStart; v <= yHigh + 0.001; v += niceStep) { const yy = y(v).toFixed(1); - const label = Number.isInteger(v) ? v : v.toFixed(1); + const label = (Number.isInteger(v) ? v : v.toFixed(1)) + unitSuffix; gridLines += ``; gridLines += `${label}`; } @@ -872,14 +869,14 @@ el.innerHTML = ` - + ${gridLines} - + @@ -887,6 +884,21 @@ `; } + function renderCpuChart(hostname, samples) { + const pts = samples + .filter(s => s.data.cpu_percent != null) + .map(s => ({ t: s.timestamp, v: s.data.cpu_percent })); + + renderTimeSeriesChart(`cpu-chart-${hostname}`, pts, { + yDomain: [0, 100], + clipId: `cpu-clip-${hostname}`, + colorFor: (latest) => ({ + stroke: latest > 90 ? '#e53935' : latest > 70 ? '#fb8c00' : '#43a047', + fill: latest > 90 ? '#ffcdd2' : latest > 70 ? '#ffe0b2' : '#c8e6c9', + }), + }); + } + function renderCpuTable(hostname, d) { const KEYS = [ ['cpu_percent', 'CPU Usage', 'bar'],