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 = ``;
}
+ 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'],