fix(docker): bars line up down the column; headers name the window (#5214)
CI / lint (push) Successful in 3s
CI / integration (push) Successful in 59s
CI / unit (push) Successful in 1m21s
CI / publish (push) Successful in 2m4s

Each figure after its bars takes a fixed width, so memory figures of
different lengths no longer shift their bars. CPU and Memory headers say
"last 6h" and the note gives the slice length.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-07 15:15:25 -04:00
co-authored by Claude Opus 5.5
parent 30f4de3612
commit da79c43891
2 changed files with 8 additions and 5 deletions
@@ -23,7 +23,8 @@
<table class="w-table">
<colgroup><col><col class="w-wide-only" style="width:7.5rem"><col class="w-barcol"><col class="w-barcol"></colgroup>
<thead><tr><th>Container</th><th class="w-wide-only w-text">Host</th>
<th title="Cores, averaged over the last {{ minutes }} minutes">CPU</th><th title="In use now">Memory</th></tr></thead>
<th title="Cores, averaged over the last {{ minutes }} minutes; bars: the last {{ hours }}h">CPU<span class="w-wide-only"> · last {{ hours }}h</span></th>
<th title="In use now; bars: the last {{ hours }}h">Memory<span class="w-wide-only"> · last {{ hours }}h</span></th></tr></thead>
<tbody>
{% for r in rows %}
{% set u = r.usage %}
@@ -35,16 +36,16 @@
<td class="tone-{{ status_class(u.cpu_share, 'cpu') if u.cpus and u.cores is not none else 'dim' }}"
{% if u.cpus and u.cores is not none %}title="{{ '%.1f'|format(u.cpu_share) }}% of {{ r.host_name }}'s {{ u.cpus }} cores"{% endif %}>
{{- bars(r.cpu_bars, (cores(r.cpu_bars.peak) ~ " cores") if r.cpu_bars.peak is not none else "", cores(r.cpu_bars.roof) ~ " cores") -}}
{%- if u.cores is none %}—{% else %}{{ cores(u.cores) }} cores{% endif -%}
<span class="w-fig">{% if u.cores is none %}—{% else %}{{ cores(u.cores) }} cores{% endif %}</span>
</td>
<td class="tone-{{ status_class(u.mem_pct, 'mem') if u.mem_of and u.mem_bytes is not none else 'dim' }}"
{% if u.mem_pct is not none and u.mem_of and u.mem_bytes is not none %}title="{{ '%.1f'|format(u.mem_pct) }}% of {{ u.mem_of }}"{% endif %}>
{{- bars(r.mem_bars, r.mem_bars.peak|bytes if r.mem_bars.peak is not none else "", r.mem_bars.roof|bytes) -}}
{%- if u.mem_bytes is none %}—{% else %}{{ u.mem_bytes|bytes }}{% endif -%}
<span class="w-fig">{% if u.mem_bytes is none %}—{% else %}{{ u.mem_bytes|bytes }}{% endif %}</span>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="w-note w-wide-only">Bars: last {{ hours }}h, each row up to its own peak, at least {{ cores(cpu_floor) }} core{{ 's' if cpu_floor != 1 }} and {{ mem_floor|bytes }}.</div>
<div class="w-note w-wide-only">Bars: {{ (hours * 60 // 24) }}-minute slices, oldest left; each row up to its own peak, at least {{ cores(cpu_floor) }} core{{ 's' if cpu_floor != 1 }} and {{ mem_floor|bytes }}.</div>
{% endif %}
+3 -1
View File
@@ -406,7 +406,7 @@ body.dash-editing .widget-drawer { transform:translateY(0); }
.w-item .w-label a { color:inherit; text-decoration:none; }
.w-item .w-meta { flex-shrink:0; font-size:0.72rem; color:var(--text-muted); font-variant-numeric:tabular-nums; }
.w-note { font-size:0.7rem; color:var(--text-dim); margin-top:0.3rem; }
.w-table col.w-barcol { width:9.5rem; }
.w-table col.w-barcol { width:10.2rem; }
/* Bars of a figure's recent past, inline before it (Busiest Containers, #5214):
the row's tone, faint, with the newest bar solid. A gap is a slice with no
samples. Heights are set per bar as a % of the row's roof. */
@@ -414,6 +414,8 @@ body.dash-editing .widget-drawer { transform:translateY(0); }
.w-bars i { flex:1; min-height:1px; background:currentColor; opacity:0.4; border-radius:1px 1px 0 0; }
.w-bars i:last-child { opacity:1; }
.w-bars i.gap { background:none; }
/* The figure after a row of bars takes a fixed width, so the bars line up down the column whatever the figure's length. */
.w-fig { display:inline-block; min-width:4.9rem; text-align:right; }
@container (max-width: 26rem) { .w-wide-only { display:none; } .w-table col.w-barcol { width:5.5rem; } }