sqlinsight-pro/src/SQLInsight.Web/Components/Pages/SyntheticChecksPage.razor
Søren Eggert Lundsteen Olsen 18cd879dbb Review 1.5: server and check pages: one overview query, paused checks are not run, bad numbers refused, seconds kept
- /servere reads the overview in one query and says which paused servers and checks are left out of the active
  findings; admin notes use InstanceSetup.WhoMayChangeText as main.
- The check form refuses a port, interval, timeout or limit that is not a number (Danish message) and clamps
  minutes before multiplying; an interval set to part of a minute through the API is shown and kept in seconds.
- "Kør nu" is refused for a paused check (message, no button); ?koersel= shows that run.
- A finding of a removed server or check does not link to a missing page and says why it is not active.
- The forecast text uses the history the forecasts were computed from; the grant script text matches the new
  script (-WhatIf first, -WinRM, -EnableFirewall -AgentAddress, -Remove only what it added).
- HTTP addresses are at most 2000 characters.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 15:53:26 +02:00

92 lines
4.2 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 "/syntetiske-tjek"
@using SQLInsight.Core.SyntheticChecks
@inject InsightRepository Repository
@inject Display Display
@inject Microsoft.Extensions.Options.IOptions<WebOptions> Options
<PageTitle>Syntetiske tjek · SQLInsight Pro</PageTitle>
<h1>Syntetiske tjek</h1>
<p class="lead">Agenten gør det, en bruger eller en applikation gør – forbinder til AOS-porten, henter en side, logger på SQL Server, slår et navn op, logger på Dynamics AX – med jævne mellemrum og med sin egen konto. Så opdages det, når en applikationsserver ikke svarer, selv om tjenesten kører.</p>
@if (Fjernet == 1)
{
<p class="notice ok" role="status">Tjekket er fjernet. Resultaterne er bevaret, indtil de udløber.</p>
}
@if (!string.IsNullOrEmpty(Fejl))
{
<p class="notice bad" role="alert">@Fejl</p>
}
@if (!_mayChange)
{
<p class="notice" role="note">Du kan se tjekkene, men kun administratorer kan tilføje og ændre dem. @InstanceSetup.WhoMayChangeText(Options.Value)</p>
}
<section class="card">
<div class="card-head"><h2>Tjek</h2><span class="muted">@_checks.Count(c => !c.Paused) aktive · <a href="@ServerSetup.ServersPage">Windows-servere</a></span></div>
@if (_checks.Count == 0)
{
<p class="empty">Der er ingen syntetiske tjek endnu.@(_mayChange ? " Tilføj det første nedenfor." : string.Empty)</p>
}
else
{
<table>
<thead><tr><th>Tjek</th><th>Type</th><th>Mål</th><th>Status</th><th class="num">Svartid</th><th>Seneste</th><th>Fund</th></tr></thead>
<tbody>
@foreach (var c in _checks)
{
var counts = _counts.GetValueOrDefault((FindingScope.Check, c.CheckId));
<tr>
<td><a href="@ServerSetup.CheckPage(c.CheckId)">@c.Name</a>@if (c.ServerName is { } server) { <div class="muted small">@server@(c.Settings.ServiceName is { } svc ? " · " + svc : string.Empty)</div> }</td>
<td>@SyntheticCheckKind.Display(c.Kind)</td>
<td class="mono small">@c.Settings.Target(c.Kind)</td>
<td><CheckStatus Check="c" /></td>
<td class="num">@(c.LastDurationMs is { } ms ? Display.Number(ms) + " ms" : "–")</td>
<td title="@c.LastMessage">@Display.Ago(c.LastRunAt)</td>
<td>
@if (counts is null || counts.Count == 0)
{
<SeverityBadge Severity="null" />
}
else
{
@foreach (var (severity, count) in counts.OrderByDescending(x => x.Key))
{
<SeverityBadge Severity="severity" Count="count" />
}
}
</td>
</tr>
}
</tbody>
</table>
}
</section>
@if (_mayChange)
{
<section class="panel" id="tilfoej">
<h2>Tilføj tjek</h2>
<p class="muted">Udfyld felterne for den valgte type; de andre ignoreres. Efter tilføjelsen kører agenten tjekket med det samme.</p>
<CheckForm Action="/syntetiske-tjek/tilfoej" Servers="_servers" SubmitText="Tilføj og kør tjekket" />
</section>
}
@code {
[CascadingParameter] private HttpContext? Http { get; set; }
[SupplyParameterFromQuery(Name = "fejl")] public string? Fejl { get; set; }
[SupplyParameterFromQuery(Name = "fjernet")] public int? Fjernet { get; set; }
private IReadOnlyList<SyntheticCheckRow> _checks = [];
private IReadOnlyList<WindowsServerRow> _servers = [];
private IReadOnlyDictionary<(string, int), IReadOnlyDictionary<Severity, int>> _counts = new Dictionary<(string, int), IReadOnlyDictionary<Severity, int>>();
private bool _mayChange;
protected override async Task OnInitializedAsync()
{
_checks = await Repository.GetSyntheticChecksAsync();
_servers = await Repository.GetWindowsServersAsync();
_counts = await Repository.GetServerFindingCountsAsync();
_mayChange = Http is not null && InstanceSetup.MayChange(Http.User, Options.Value);
}
}