Commit 8a1705e5 authored by jan.koester's avatar jan.koester
Browse files

test

parent 32ca1026
Loading
Loading
Loading
Loading
+4 −0
Changes for www/app.css: 4 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -277,6 +277,10 @@ svg.spark { display: block; width: 100%; height: 28px; margin-top: 10px; }
@media (max-width: 720px) { .dash-two { grid-template-columns: 1fr; } }
.legend { display: flex; flex-wrap: wrap; gap: 4px 16px; font-size: .9em; color: var(--muted); margin-bottom: 6px; }
.legend b { color: var(--text); font-weight: 600; font-variant-numeric: tabular-nums; }
.swatch.s1, .chart-area.s1, .chart-dot.s1 { background: var(--series-1); fill: var(--series-1); }
.swatch.s2, .chart-area.s2, .chart-dot.s2 { background: var(--series-2); fill: var(--series-2); }
.chart-line.s1 { stroke: var(--series-1); }
.chart-line.s2 { stroke: var(--series-2); }
.swatch { display: inline-block; width: 10px; height: 10px; border-radius: 2px; margin-right: .4em; vertical-align: -1px; }
.chart-plot { position: relative; touch-action: pan-y; }
.chart-svg { display: block; }
+16 −9
Changes for www/modules/dashboard.js: 16 added lines, 9 removed lines.
Original line number Diff line number Diff line
@@ -118,7 +118,7 @@
    const svg = s('svg', {class: 'chart-svg', height: H, role: 'img'});
    const tip = h('div', {class: 'chart-tip', hidden: true});
    const legend = h('div', {class: 'legend'}, series.map(sr =>
      h('span', {}, h('i', {class: 'swatch', style: `background: var(${sr.color})`}), sr.label, ' ', h('b', {class: 'legend-value'}))));
      h('span', {}, h('i', {class: 'swatch ' + sr.color}), sr.label, ' ', h('b', {class: 'legend-value'}))));
    const plot = h('div', {class: 'chart-plot'}, svg, tip);
    const el = h('div', {class: 'chart'}, legend, plot);
    let hover = null;   // index under the pointer
@@ -153,18 +153,18 @@
      if (n >= 2) {
        for (const sr of series) {
          const d = hist[sr.key].map((v, i) => (i ? 'L' : 'M') + x(i).toFixed(1) + ' ' + y(v).toFixed(1)).join('');
          kids.push(s('path', {d: d + `L${x(n - 1).toFixed(1)} ${y(0)}L${x(0).toFixed(1)} ${y(0)}Z`, class: 'chart-area', style: `fill: var(${sr.color})`}));
          kids.push(s('path', {d, class: 'chart-line', style: `stroke: var(${sr.color})`}));
          kids.push(s('path', {d: d + `L${x(n - 1).toFixed(1)} ${y(0)}L${x(0).toFixed(1)} ${y(0)}Z`, class: 'chart-area ' + sr.color}));
          kids.push(s('path', {d, class: 'chart-line ' + sr.color}));
        }
      }
      if (hover !== null && hover < n) {
        const xx = x(hover);
        kids.push(s('line', {x1: xx, x2: xx, y1: PAD.t, y2: PAD.t + ph, class: 'crosshair'}));
        for (const sr of series)
          kids.push(s('circle', {cx: xx, cy: y(hist[sr.key][hover]), r: 4, class: 'chart-dot', style: `fill: var(${sr.color})`}));
          kids.push(s('circle', {cx: xx, cy: y(hist[sr.key][hover]), r: 4, class: 'chart-dot ' + sr.color}));
        const ago = Math.round((hist.at[n - 1] - hist.at[hover]) / 1000);
        tip.replaceChildren(h('div', {class: 'muted'}, ago ? t('{0} ago', ago + ' s') : t('now')),
          series.map(sr => h('div', {}, h('i', {class: 'swatch', style: `background: var(${sr.color})`}), sr.label + ': ',
          ...series.map(sr => h('div', {}, h('i', {class: 'swatch ' + sr.color}), sr.label + ': ',
            h('b', {}, format(hist[sr.key][hover])))));
        tip.hidden = false;
        const left = xx + 12 + tip.offsetWidth > W ? xx - 12 - tip.offsetWidth : xx + 12;
@@ -217,8 +217,8 @@
    ui.disk = card(t('System disk'), '⛁', false);
    ui.temp = card(t('Temperature'), '🌡', true);
    ui.cores = h('div', {class: 'cores'});
    ui.net = lineChart([{key: 'rx', label: t('received'), color: '--series-1'}, {key: 'tx', label: t('sent'), color: '--series-2'}], bitRate);
    ui.io = lineChart([{key: 'read', label: t('read'), color: '--series-1'}, {key: 'write', label: t('written'), color: '--series-2'}], byteRate);
    ui.net = lineChart([{key: 'rx', label: t('received'), color: 's1'}, {key: 'tx', label: t('sent'), color: 's2'}], bitRate);
    ui.io = lineChart([{key: 'read', label: t('read'), color: 's1'}, {key: 'write', label: t('written'), color: 's2'}], byteRate);
    ui.fs = h('div', {});
    ui.ifaces = h('div', {});
    ui.sensors = h('div', {});
@@ -302,7 +302,7 @@
    // cores: one bar each, height = load
    ui.cores.replaceChildren(...cores.map((c, i) =>
      h('div', {class: 'core', title: t('core {0}', i) + ': ' + pct(c)},
        h('div', {class: 'core-bar'}, h('span', {class: level(c), style: `height: ${Math.max(c, 1.5)}%`})),
        h('div', {class: 'core-bar'}, sized(h('span', {class: level(c)}), 'height', Math.max(c, 1.5))),
        h('div', {class: 'core-label'}, i))));

    ui.net.draw();
@@ -344,11 +344,18 @@
    })));
  }

  // sizes go through the CSSOM: the CSP (default-src 'self') blocks style
  // attributes
  function sized(el, prop, percent) {
    el.style[prop] = percent + '%';
    return el;
  }

  // a horizontal meter, colored by level
  function bar(p) {
    const v = Math.max(0, Math.min(100, p || 0));
    return h('div', {class: 'meter', role: 'meter', 'aria-valuenow': Math.round(v), 'aria-valuemin': 0, 'aria-valuemax': 100},
      h('span', {class: level(v), style: `width: ${v}%`}));
      sized(h('span', {class: level(v)}), 'width', v));
  }

  webctl.register('dashboard', {