feat: restyle Admin UI with the technical-light design system

Adopt the technical-light design system across the Admin web UI:

- Vendor theme.css + IBM Plex woff2 fonts into wwwroot; include
  theme.css globally after Bootstrap.
- Rebuild MainLayout: top app-bar (brand mark, breadcrumb, connection
  pill) + hairline-ruled side rail with accent-bordered active link.
- Convert all 33 pages to the component catalog — tables to
  panel + data-table (num/mono columns), KPI cards to agg-grid,
  detail blocks to metric-card/kv rows, badges to chips, alerts to
  panel notice, headings to page-title/panel-head, .rise reveals.
- Buttons/forms stay on Bootstrap; theme.css restyles them via
  --bs-* overrides. View-specific layout lives in app.css; all
  colour/type comes from theme.css tokens.

Also fix a pre-existing /fleet 500: the node-state query ordered on
a property of a constructed FleetNodeRow record, which EF Core
cannot translate. Order the join's columns before projecting.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Joseph Doherty
2026-05-18 02:20:09 -04:00
parent 31b9468102
commit 482d5f5637
40 changed files with 1837 additions and 1206 deletions

View File

@@ -7,8 +7,8 @@
<div class="d-flex justify-content-between align-items-center mb-3">
<div>
<h1 class="mb-0">Draft editor</h1>
<small class="text-muted">Cluster <code>@ClusterId</code> · generation @GenerationId</small>
<h1 class="page-title mb-0">Draft editor</h1>
<small class="text-muted">Cluster <span class="mono">@ClusterId</span> · generation @GenerationId</small>
</div>
<div>
<a class="btn btn-outline-secondary" href="/clusters/@ClusterId">Back to cluster</a>
@@ -36,32 +36,32 @@
else if (_tab == "scripts") { <ScriptsTab GenerationId="@GenerationId" ClusterId="@ClusterId"/> }
</div>
<div class="col-md-4">
<div class="card sticky-top">
<div class="card-header d-flex justify-content-between align-items-center">
<section class="panel rise sticky-top" style="animation-delay:.02s">
<div class="panel-head d-flex justify-content-between align-items-center">
<strong>Validation</strong>
<button class="btn btn-sm btn-outline-secondary" @onclick="RevalidateAsync">Re-run</button>
</div>
<div class="card-body">
<div class="p-3">
@if (_validating) { <p class="text-muted">Checking…</p> }
else if (_errors.Count == 0) { <div class="alert alert-success mb-0">No validation errors — safe to publish.</div> }
else if (_errors.Count == 0) { <p class="s-ok mb-0">No validation errors — safe to publish.</p> }
else
{
<div class="alert alert-danger mb-2">@_errors.Count error@(_errors.Count == 1 ? "" : "s")</div>
<p class="s-bad mb-2">@_errors.Count error@(_errors.Count == 1 ? "" : "s")</p>
<ul class="list-unstyled">
@foreach (var e in _errors)
{
<li class="mb-2">
<span class="badge bg-danger me-1">@e.Code</span>
<span class="chip chip-bad me-1">@e.Code</span>
<small>@e.Message</small>
@if (!string.IsNullOrEmpty(e.Context)) { <div class="text-muted"><code>@e.Context</code></div> }
@if (!string.IsNullOrEmpty(e.Context)) { <div class="text-muted"><span class="mono">@e.Context</span></div> }
</li>
}
</ul>
}
</div>
</div>
</section>
@if (_publishError is not null) { <div class="alert alert-danger mt-3">@_publishError</div> }
@if (_publishError is not null) { <section class="panel notice rise mt-2" style="animation-delay:.08s"><span class="s-bad">@_publishError</span></section> }
</div>
</div>