adminui: render the self-test instead of dumping it

The box under "Self-test" was `%+v` of a Go struct on one line, read
through a horizontal scrollbar — on a phone you could see about six words
of it, from the middle. The design pass had polished the frame around it
and left the contents a debug dump.

The report was structured the whole time: each sysctl check carries the
name, what was found, what was wanted, a severity, and a sentence
explaining why the setting matters to measurement. All of that was being
flattened into one string. It now renders as records like everything
else, with the explanation set as prose across the full row, because it
is a sentence and not a fourth column.

Two faults the render caught: the desktop row grid applied to every
readout, so the standalone summary panel was chopped into four narrow
columns and "full 1500" broke into "ful/l/150/0"; and a fixed first
column wrapped `net.ipv6.conf.all.accept_ra` mid-word. The grid is now
scoped to readouts inside a row, and the label column may grow to 18rem
before it wraps.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
mrambossek
2026-08-01 23:04:55 +02:00
co-authored by Claude Opus 5
parent 332b6f3589
commit 8001234e8b
+51 -8
View File
@@ -155,6 +155,9 @@ const baseHTML = `<!doctype html>
font:.85rem/1.3 var(--mono);margin-bottom:.35rem}
.rec-head .id{overflow-wrap:anywhere;color:var(--ink)}
.rec form{margin-top:.6rem}
/* Why a check matters is a sentence, so it is set as one — full width under the row rather
than squeezed into a column, where it would wrap to a ribbon two words wide. */
.why{font:.85rem/1.5 var(--prose);color:var(--dim);margin-top:.45rem;max-width:52rem}
.tag{font:.68rem/1 var(--mono);letter-spacing:.1em;text-transform:uppercase;
padding:.24rem .45rem;border-radius:2px;border:1px solid currentColor;white-space:nowrap}
.v-green{color:var(--green)} .v-yellow{color:var(--amber)}
@@ -196,17 +199,19 @@ const baseHTML = `<!doctype html>
main{padding:1.6rem}
.recs{margin:.8rem 0}
/* Every row shares one grid, so the columns agree across rows without a header or a table. */
.rec{display:grid;grid-template-columns:12.5rem minmax(0,1fr) auto;gap:.35rem 1.4rem;
.rec{display:grid;grid-template-columns:minmax(12.5rem,18rem) minmax(0,1fr) auto;gap:.35rem 1.4rem;
align-items:baseline;background:none;border:0;border-bottom:1px solid var(--rule);
border-radius:0;padding:.6rem 0;margin:0}
.rec-head{margin:0;flex-direction:column;align-items:flex-start;gap:.3rem}
.rec form{margin:0}
/* Widths follow the content: a device name needs room, a finding count does not. */
.readout{display:grid;grid-template-columns:1.7fr .9fr .9fr 1.1fr;gap:.15rem 1.2rem}
.readout li{padding:0}
.readout .lead{display:none}
.readout .v{text-align:left}
.rec .readout{display:grid;grid-template-columns:1.7fr .9fr .9fr 1.1fr;gap:.15rem 1.2rem}
.rec .readout li{padding:0}
.rec .readout .lead{display:none}
.rec .readout .v{text-align:left}
.open{white-space:nowrap}
/* Spans the full row: the sentence is the useful part, not a fourth column. */
.why{grid-column:1/-1;margin-top:.1rem}
}
</style></head><body>
<header class="top">
@@ -270,9 +275,47 @@ const baseHTML = `<!doctype html>
{{end}}
{{with .SelfTest}}
<h2>Self-test</h2>
<p class="lede">What this server can measure from where it stands. A capability missing here is
missing from every run it takes part in.</p>
<pre>{{printf "%+v" .}}</pre>
<p class="lede">What this server can measure from where it stands, checked at startup. A
capability missing here is missing from every run this server takes part in &mdash; so a
client asking for that measurement gets nothing, rather than a wrong answer.</p>
<ul class="readout panel">
<li><span class="k">kernel settings</span><span class="lead"></span>
<span class="v {{if .SysctlOK}}v-green{{else}}v-yellow{{end}}">{{if .SysctlOK}}as needed{{else}}need attention{{end}}</span></li>
<li><span class="k">egress path MTU</span><span class="lead"></span>
<span class="v {{if .MTUOK}}v-green{{else}}v-yellow{{end}}">{{if .MTUOK}}full 1500{{else}}reduced{{end}}</span></li>
</ul>
{{if .Sysctls}}
<h3>Kernel settings</h3>
<div class="recs">
{{range .Sysctls}}
<div class="rec">
<div class="rec-head"><span class="id">{{.Name}}</span>
<span class="tag {{if eq .Severity "ok"}}v-green{{else}}v-yellow{{end}}">{{.Severity}}</span></div>
<ul class="readout">
<li><span class="k">found</span><span class="lead"></span><span class="v">{{.Got}}</span></li>
<li><span class="k">wanted</span><span class="lead"></span><span class="v">{{.Want}}</span></li>
</ul>
<div class="why">{{.Why}}</div>
</div>
{{end}}
</div>
{{end}}
{{if .EgressMTU}}
<h3>Egress path MTU</h3>
<div class="recs">
{{range .EgressMTU}}
<div class="rec">
<div class="rec-head"><span class="id">{{.Target}}</span>
<span class="tag {{if .FullMTU}}v-green{{else}}v-yellow{{end}}">{{if .FullMTU}}full{{else}}reduced{{end}}</span></div>
<ul class="readout">
<li><span class="k">discovered</span><span class="lead"></span>
<span class="v">{{if .DiscoveredMTU}}{{.DiscoveredMTU}} bytes{{else}}not measured{{end}}</span></li>
</ul>
{{with .Err}}<div class="why">{{.}}</div>{{end}}
</div>
{{end}}
</div>
{{end}}
{{end}}
{{else if eq .Page "devices"}}