feat: cumulative pulled/pushed GB totals in pools and array card headers

disk_io now returns {tr, tw} cumulative GB alongside {r, w} rates.
A centered span in each card h3 shows ↓total ↑total (since last boot),
updating each poll. Helpers updated for the new object format.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Gmer4Lfe
2026-05-31 22:40:56 -04:00
co-authored by Claude Sonnet 4.6
parent e9b9d1b5da
commit 63b1f0a76c
2 changed files with 38 additions and 10 deletions
+23 -2
View File
@@ -158,6 +158,7 @@
<span class="vv-ico"><svg width="12" height="12" viewBox="0 0 12 12" fill="none" stroke="#aaa" stroke-width="1.1" stroke-linecap="round"><ellipse cx="6" cy="3" rx="4.5" ry="1.5"/><line x1="1.5" y1="3" x2="1.5" y2="9"/><line x1="10.5" y1="3" x2="10.5" y2="9"/><ellipse cx="6" cy="9" rx="4.5" ry="1.5"/></svg></span>
<span id="vv-pools-title">Pools</span>
</span>
<span id="vv-pools-io-total" style="font-size:9px;font-weight:400;color:#333;text-transform:none;letter-spacing:0;"></span>
<a href="/Main" target="_blank" class="vv-card-cog" title="Array Management">⚙</a>
</h3>
<div id="vv-storage-body">Loading...</div>
@@ -169,6 +170,7 @@
<span class="vv-ico"><svg width="14" height="12" viewBox="0 0 14 12" fill="none" stroke="#aaa" stroke-width="1.1" stroke-linecap="round"><rect x="0.7" y="0.7" width="12.6" height="3" rx="0.8"/><rect x="0.7" y="4.5" width="12.6" height="3" rx="0.8"/><rect x="0.7" y="8.3" width="12.6" height="3" rx="0.8"/><circle cx="11.5" cy="2.2" r="0.8" fill="#888" stroke="none"/><circle cx="11.5" cy="6" r="0.8" fill="#888" stroke="none"/><circle cx="11.5" cy="9.8" r="0.8" fill="#888" stroke="none"/></svg></span>
<span id="vv-array-title">Array</span>
</span>
<span id="vv-array-io-total" style="font-size:9px;font-weight:400;color:#333;text-transform:none;letter-spacing:0;"></span>
<a href="/Main" target="_blank" class="vv-card-cog" title="Array Management">⚙</a>
</h3>
<div id="vv-array-body">Loading...</div>
@@ -515,7 +517,7 @@ function vvFmtRate(mbs) {
function vvIoChip(dev) {
const io = vvDiskIo[dev];
if (!io) return '';
const [r, w] = io;
const r = io.r ?? 0, w = io.w ?? 0;
if (r < 0.05 && w < 0.05) return '';
const parts = [];
if (r >= 0.05) parts.push(`<span style="color:#3a7a3a;">↓${vvFmtRate(r)}</span>`);
@@ -524,9 +526,19 @@ function vvIoChip(dev) {
}
function vvIoSum(devices) {
let r = 0, w = 0;
devices.forEach(dev => { const io = vvDiskIo[dev]; if (io) { r += io[0]; w += io[1]; } });
devices.forEach(dev => { const io = vvDiskIo[dev]; if (io) { r += io.r ?? 0; w += io.w ?? 0; } });
return [r, w];
}
function vvIoTotalSum(devices) {
let tr = 0, tw = 0;
devices.forEach(dev => { const io = vvDiskIo[dev]; if (io) { tr += io.tr ?? 0; tw += io.tw ?? 0; } });
return [tr, tw];
}
function vvFmtGb(gb) {
if (gb >= 1024) return (gb / 1024).toFixed(1) + ' TB';
if (gb >= 1) return gb.toFixed(1) + ' GB';
return (gb * 1024).toFixed(0) + ' MB';
}
function vvDiskRow(disk) {
const tempC = disk.temp;
@@ -1233,6 +1245,10 @@ function vvPollMonitor() {
${maxTemp != null ? `· <span style="color:${maxTempColor};">max ${maxTemp}°</span>` : ''}
${ioHtml}
</span>`;
const [ptr, ptw] = vvIoTotalSum(disks.map(d => d.device));
const totEl = document.getElementById('vv-pools-io-total');
if (totEl && (ptr > 0.001 || ptw > 0.001))
totEl.innerHTML = `<span style="color:#3a5a3a;">↓${vvFmtGb(ptr)}</span> <span style="color:#5a3a1a;">↑${vvFmtGb(ptw)}</span>`;
}
})();
document.getElementById('vv-storage-body').innerHTML = vvRenderPools(vvLastStorageDisks);
@@ -1268,6 +1284,11 @@ function vvPollMonitor() {
${arrIoHtml}
</span>`;
const [atr, atw] = vvIoTotalSum(arrayDisks.map(d => d.device));
const arrTotEl = document.getElementById('vv-array-io-total');
if (arrTotEl && (atr > 0.001 || atw > 0.001))
arrTotEl.innerHTML = `<span style="color:#3a5a3a;">↓${vvFmtGb(atr)}</span> <span style="color:#5a3a1a;">↑${vvFmtGb(atw)}</span>`;
const numCols = window.innerWidth <= 1024 ? 2 : Math.max(3, Math.ceil(arrayDisks.length / 6));
const perCol = Math.ceil(arrayDisks.length / numCols);
const cols = [];