.counts is display: flex. On the <td> itself it made the cell a flex box with its own height, so the row divider jumped in the findings column of SQLInsight Web's overview and the hub portal's customer overview. The class now sits on a <div> inside the cell; the CSS rule is unchanged. TableMarkupTests checks Web, Hub and Community: no <td>/<th> may carry a class whose rule sets display flex or grid. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
69 lines
3.3 KiB
Text
69 lines
3.3 KiB
Text
@page "/portal"
|
||
@attribute [Authorize]
|
||
@inject PortalQueries Queries
|
||
|
||
<PageTitle>Overblik · SQLInsight Hub</PageTitle>
|
||
|
||
<h1>Kundeoverblik</h1>
|
||
<p class="lead">Betalende kunders instanser og deres aktuelle problemer.</p>
|
||
|
||
<div class="kpis">
|
||
<div class="kpi"><div><strong>@_customers.Count</strong><span>kunder</span></div></div>
|
||
<div class="kpi"><div><strong>@_customers.Sum(c => c.Instances)</strong><span>instanser</span></div></div>
|
||
<div class="kpi sev-critical"><div><strong>@_customers.Sum(c => c.Critical)</strong><span>kritiske fund</span></div></div>
|
||
<div class="kpi sev-high"><div><strong>@_customers.Sum(c => c.High)</strong><span>høje fund</span></div></div>
|
||
<div class="kpi"><div><strong>@_new</strong><span>nye fund, 7 dage</span></div></div>
|
||
<div class="kpi sev-info"><div><strong>@_silent</strong><span>instanser uden data i 1 time</span></div></div>
|
||
</div>
|
||
|
||
<section class="card">
|
||
<div class="card-head"><h2>Kunder</h2><span class="muted">sorteret efter alvor</span></div>
|
||
<table>
|
||
<thead><tr><th>Kunde</th><th>Aftale</th><th>Licens udløber</th><th class="num">Instanser</th><th>Fund</th><th>Seneste data</th></tr></thead>
|
||
<tbody>
|
||
@foreach (var c in _customers)
|
||
{
|
||
<tr>
|
||
<td><a href="/portal/kunder/@c.Id"><strong>@c.Name</strong></a></td>
|
||
<td>@(c.Plan ?? "–")</td>
|
||
<td class="nowrap @(c.LicenseExpires < Queries.Now.AddDays(30) ? "bad" : "")">@(c.LicenseExpires?.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture) ?? "–")</td>
|
||
<td class="num">@c.Instances</td>
|
||
<td><div class="counts">
|
||
@if (c.Critical > 0) { <Sev Severity="4" Count="c.Critical" /> }
|
||
@if (c.High > 0) { <Sev Severity="3" Count="c.High" /> }
|
||
@if (c.Critical == 0 && c.High == 0) { <span class="muted">ingen kritiske/høje</span> }
|
||
</div></td>
|
||
<td class="nowrap @(c.LastSubmission < Queries.Now.AddHours(-1) ? "bad" : "")">@(c.LastSubmission?.ToString("yyyy-MM-dd HH:mm", CultureInfo.InvariantCulture) ?? "aldrig") UTC</td>
|
||
</tr>
|
||
}
|
||
</tbody>
|
||
</table>
|
||
</section>
|
||
|
||
<section class="card">
|
||
<div class="card-head"><h2>Mest udbredte problemer</h2><span class="muted">hvor en vejledning eller en produktændring hjælper flest</span></div>
|
||
<table>
|
||
<thead><tr><th>Regel</th><th>Eksempel</th><th class="num">Kunder</th><th class="num">Fund</th><th>Værst</th></tr></thead>
|
||
<tbody>
|
||
@foreach (var p in _common)
|
||
{
|
||
<tr><td class="mono">@p.RuleId</td><td>@p.Title</td><td class="num">@p.Customers</td><td class="num">@p.Findings</td><td><Sev Severity="p.WorstSeverity" /></td></tr>
|
||
}
|
||
</tbody>
|
||
</table>
|
||
</section>
|
||
|
||
@code {
|
||
private IReadOnlyList<CustomerRow> _customers = [];
|
||
private IReadOnlyList<CommonProblem> _common = [];
|
||
private int _new;
|
||
private int _silent;
|
||
|
||
protected override async Task OnInitializedAsync()
|
||
{
|
||
_customers = await Queries.CustomersAsync();
|
||
_common = await Queries.CommonProblemsAsync();
|
||
_new = await Queries.NewFindingsSinceAsync(Queries.Now.AddDays(-7));
|
||
_silent = await Queries.SilentInstancesAsync();
|
||
}
|
||
}
|