Merge claude/2

This commit is contained in:
librelad 2026-05-28 21:28:19 +01:00
commit b4607de950

View File

@ -202,22 +202,41 @@ class SystemStoragePage {
const palette = SystemStoragePage.PALETTE;
const colorFor = i => palette[i % palette.length];
// ---- Headline: on-disk usage by app (the disk question that matters) ----
// ---- Headline: ONE donut covering everything — a slice per app, then
// Docker's own categories (images, build cache). Colours run continuously
// across the whole list so app and Docker slices stay distinct, and the
// legend lists them all. This is the unified "where's my disk going" view.
const appTotal = (as && as.total) || 0;
const appSegs = appRows.map((a, i) => ({ color: colorFor(i), data: { size: a.bytes || 0 } }));
const headline = appRows.length
const appSegs = appRows.map((a, i) => ({ label: a.app, color: colorFor(i), data: { size: a.bytes || 0 } }));
const dockerCats = d ? SystemStoragePage.segmentsFrom(d).map((s, j) => ({ ...s, color: colorFor(appSegs.length + j) })) : [];
const allSegs = [...appSegs, ...dockerCats];
const grandTotal = allSegs.reduce((t, s) => t + ((s.data && s.data.size) || 0), 0);
const legend = `
<ul class="sys-storage-legend">
${allSegs.map(s => `
<li>
<span class="sys-storage-swatch" style="background: var(--${s.color})"></span>
<span class="sys-storage-leg-k">${fmt.escape(s.label)}</span>
<span></span>
<span class="sys-storage-leg-v">${fmt.bytes((s.data && s.data.size) || 0)}</span>
</li>`).join('')}
</ul>`;
const headline = allSegs.length
? `<div class="sys-storage-headline">
<div class="sys-storage-head-card">${SystemStoragePage.donutSvg(appSegs, appTotal, 'app data')}</div>
<div class="sys-storage-head-card">
${SystemStoragePage.donutSvg(allSegs, grandTotal, 'in use')}
${legend}
</div>
<div class="sys-storage-head-stats">
<div class="sys-storage-stat">
<span class="sys-storage-stat-k">App data on disk</span>
<strong class="sys-storage-stat-v">${fmt.bytes(appTotal)}</strong>
<span class="sys-storage-stat-sub">${appRows.length} app${appRows.length === 1 ? '' : 's'}${as && as.total_external ? ` · ${fmt.bytes(as.total_external)} on external drives` : ''}</span>
<span class="sys-storage-stat-sub">${appRows.length} app${appRows.length === 1 ? '' : 's'}${as && as.total_external ? ` · ${fmt.bytes(as.total_external)} external` : ''}</span>
</div>
${d ? `<div class="sys-storage-stat">
<span class="sys-storage-stat-k">Docker engine</span>
<strong class="sys-storage-stat-v">${fmt.bytes(d.total || 0)}</strong>
<span class="sys-storage-stat-sub">${fmt.bytes(d.reclaimable || 0)} reclaimable</span>
${d ? `<div class="sys-storage-stat sys-storage-stat-recl">
<span class="sys-storage-stat-k">Docker reclaimable</span>
<strong class="sys-storage-stat-v">${fmt.bytes(d.reclaimable || 0)}</strong>
<span class="sys-storage-stat-sub">of ${fmt.bytes(d.total || 0)} engine overhead</span>
</div>` : ''}
</div>
</div>`
@ -262,10 +281,9 @@ class SystemStoragePage {
// plus the largest images. The cleanup view, clearly separate from data.
let dockerSection = '';
if (d) {
const segments = SystemStoragePage.segmentsFrom(d);
const total = d.total || 0;
const recl = d.reclaimable || 0;
const cards = segments.map(s => {
const cards = dockerCats.map(s => {
const v = s.data || {};
const pct = v.size && total ? (v.size / total) * 100 : 0;
const rPct = v.size ? (v.reclaimable / v.size) * 100 : 0;