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:
co-authored by
Claude Sonnet 4.6
parent
a8c5b2af29
commit
e9b9d1b5da
@@ -156,7 +156,7 @@
|
|||||||
<h3>
|
<h3>
|
||||||
<span style="display:flex;align-items:center;gap:5px;">
|
<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>
|
<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>
|
</span>
|
||||||
<a href="/Main" target="_blank" class="vv-card-cog" title="Array Management">⚙</a>
|
<a href="/Main" target="_blank" class="vv-card-cog" title="Array Management">⚙</a>
|
||||||
</h3>
|
</h3>
|
||||||
@@ -1207,6 +1207,34 @@ function vvPollMonitor() {
|
|||||||
// ── Pools ─────────────────────────────────────────────────────────────────
|
// ── Pools ─────────────────────────────────────────────────────────────────
|
||||||
vvDiskIo = d.disk_io ?? {};
|
vvDiskIo = d.disk_io ?? {};
|
||||||
vvLastStorageDisks = d.storage ?? [];
|
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);
|
document.getElementById('vv-storage-body').innerHTML = vvRenderPools(vvLastStorageDisks);
|
||||||
|
|
||||||
// ── Array disks — summary header + min 3 columns ─────────────────────────
|
// ── Array disks — summary header + min 3 columns ─────────────────────────
|
||||||
|
|||||||
Reference in New Issue
Block a user