ui: pools card — live summary header matching array card style

Shows N/total ok · X% used · max Y° · ↓read ↑write in the Pools
card title, using SSD thresholds for temp coloring.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Gmer4Lfe
2026-05-31 22:37:30 -04:00
co-authored by Claude Sonnet 4.6
parent a8c5b2af29
commit e9b9d1b5da
+29 -1
View File
@@ -156,7 +156,7 @@
<h3>
<span style="display:flex;align-items:center;gap:5px;">
<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>
Pools
<span id="vv-pools-title">Pools</span>
</span>
<a href="/Main" target="_blank" class="vv-card-cog" title="Array Management">⚙</a>
</h3>
@@ -1207,6 +1207,34 @@ function vvPollMonitor() {
// ── Pools ─────────────────────────────────────────────────────────────────
vvDiskIo = d.disk_io ?? {};
vvLastStorageDisks = d.storage ?? [];
(() => {
const disks = vvLastStorageDisks;
const titleEl = document.getElementById('vv-pools-title');
if (titleEl && disks.length) {
const okDisks = disks.filter(d => d.status === 'DISK_OK' || !d.status).length;
const totalGb = disks.reduce((s, d) => s + (d.size_gb ?? 0), 0);
const usedGb = disks.reduce((s, d) => s + (d.used_gb ?? 0), 0);
const pct = totalGb > 0 ? Math.round(usedGb / totalGb * 100) : 0;
const pctColor = pct >= (vvThresholds.util_crit ?? 90) ? '#f44336' : pct >= (vvThresholds.util_warn ?? 70) ? '#ff9800' : '#4caf50';
const temps = disks.map(d => d.temp).filter(t => t != null);
const maxTemp = temps.length ? Math.max(...temps) : null;
const maxTempColor = maxTemp == null ? '#444'
: maxTemp >= (vvThresholds.ssd_crit ?? 70) ? '#f44336'
: maxTemp >= (vvThresholds.ssd_warn ?? 60) ? '#ff9800' : '#4caf50';
const [pIor, pIow] = vvIoSum(disks.map(d => d.device));
const ioParts = [];
if (pIor >= 0.05) ioParts.push(`<span style="color:#3a7a3a;">↓${vvFmtRate(pIor)}</span>`);
if (pIow >= 0.05) ioParts.push(`<span style="color:#7a4a1a;">↑${vvFmtRate(pIow)}</span>`);
const ioHtml = ioParts.length ? `· <span style="font-weight:400;">${ioParts.join(' ')}</span>` : '';
titleEl.innerHTML = `Pools
<span style="font-size:10px;color:#444;font-weight:400;text-transform:none;letter-spacing:0;margin-left:6px;">
${okDisks}/${disks.length} ok
· <span style="color:${pctColor};">${pct}%</span> used
${maxTemp != null ? `· <span style="color:${maxTempColor};">max ${maxTemp}°</span>` : ''}
${ioHtml}
</span>`;
}
})();
document.getElementById('vv-storage-body').innerHTML = vvRenderPools(vvLastStorageDisks);
// ── Array disks — summary header + min 3 columns ─────────────────────────