sqlinsight-pro/src/SQLInsight.Hub/Portal/Pages/Overview.razor
Claude 7088efff52
Some checks are pending
CI / Build og unit tests (push) Waiting to run
CI / Integration (mcr.microsoft.com/mssql/server:2017-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2019-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2022-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2025-latest) (push) Blocked by required conditions
Fase 3: Hub portal for vendor staff
Server-rendered portal on the Hub: staff login (PBKDF2 hashes, rate
limited, antiforgery, local-only return URLs), customer overview with
the most widespread problems across customers, customer and finding
pages, support cases linked to findings, and license revocation that
takes effect on the next agent submission. add-staff CLI command.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E3EExwndy8Z22EK2Qpt6BK
2026-09-29 08:58:34 +00:00

69 lines
3.3 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

@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 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> }
</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();
}
}