- /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>
123 lines
3.7 KiB
Text
123 lines
3.7 KiB
Text
@page "/servere/fund/{Id:long}"
|
||
@inject InsightRepository Repository
|
||
@inject Display Display
|
||
|
||
@if (_finding is null)
|
||
{
|
||
<PageTitle>Ukendt fund · SQLInsight Pro</PageTitle>
|
||
<h1>Ukendt fund</h1>
|
||
return;
|
||
}
|
||
|
||
<PageTitle>@_finding.Title · SQLInsight Pro</PageTitle>
|
||
|
||
<p class="crumbs">
|
||
@if (_finding.Scope == FindingScope.Server)
|
||
{
|
||
<a href="@ServerSetup.ServersPage">Windows-servere</a> <text>/</text>
|
||
}
|
||
else
|
||
{
|
||
<a href="@ServerSetup.ChecksPage">Syntetiske tjek</a> <text>/</text>
|
||
}
|
||
@if (_finding.ScopeRemoved)
|
||
{
|
||
<span>@_finding.ScopeName</span>
|
||
}
|
||
else
|
||
{
|
||
<a href="@(_finding.Scope == FindingScope.Server ? ServerSetup.ServerPage(_finding.ScopeId) : ServerSetup.CheckPage(_finding.ScopeId))">@_finding.ScopeName</a>
|
||
}
|
||
/ @_finding.RuleId
|
||
</p>
|
||
@if (_finding.ResolvedAt is null && _finding.ScopeRemoved)
|
||
{
|
||
<p class="notice" role="note">@(_finding.Scope == FindingScope.Server ? "Serveren" : "Tjekket") er fjernet og overvåges ikke længere. Fundet er historik og løses inden for en time.</p>
|
||
}
|
||
else if (_finding.ResolvedAt is null && _finding.ScopePaused)
|
||
{
|
||
<p class="notice" role="note">@(_finding.Scope == FindingScope.Server ? "Serveren" : "Tjekket") er sat på pause, så fundet er ikke med blandt de aktive fund og løses inden for en time.</p>
|
||
}
|
||
<h1 data-finding-id="@_finding.FindingId"><SeverityBadge Severity="_finding.Severity" /> @_finding.Title</h1>
|
||
<p class="lead">
|
||
@if (_finding.ResolvedAt is { } resolved)
|
||
{
|
||
<span>Løst @Display.Time(resolved) · </span>
|
||
}
|
||
Set første gang @Display.Time(_finding.FirstSeenAt) · senest @Display.Time(_finding.LastSeenAt)
|
||
@if (!string.IsNullOrEmpty(_finding.Subject)) { <span> · @_finding.Subject</span> }
|
||
</p>
|
||
|
||
<section class="panel">
|
||
<h2>Hvorfor er det et problem?</h2>
|
||
<p>@_finding.Explanation</p>
|
||
</section>
|
||
|
||
@if (_finding.Evidence.Count > 0)
|
||
{
|
||
<section class="panel">
|
||
<h2>Målinger</h2>
|
||
<table class="evidence">
|
||
@foreach (var e in _finding.Evidence)
|
||
{
|
||
<tr><th>@e.Name</th><td>@e.Value</td></tr>
|
||
}
|
||
</table>
|
||
</section>
|
||
}
|
||
|
||
<section class="panel recommendation">
|
||
<h2>Hvad skal jeg gøre?</h2>
|
||
<p>@_finding.Recommendation</p>
|
||
<p class="muted">SQLInsight ændrer aldrig noget på serveren: den starter ikke tjenester og rydder ikke op.</p>
|
||
</section>
|
||
|
||
@if (_history.Count > 0)
|
||
{
|
||
<section class="panel">
|
||
<h2>Tidligere</h2>
|
||
<ul>
|
||
@foreach (var h in _history)
|
||
{
|
||
<li><a href="@ServerSetup.FindingPage(h.FindingId)">@Display.Time(h.FirstSeenAt) – @(h.ResolvedAt is { } r ? Display.Time(r) : "nu")</a>: @h.Title</li>
|
||
}
|
||
</ul>
|
||
</section>
|
||
}
|
||
|
||
@if (_finding.References.Count > 0)
|
||
{
|
||
<section class="panel">
|
||
<h2>Læs mere</h2>
|
||
<ul>
|
||
@foreach (var r in _finding.References)
|
||
{
|
||
<li><a href="@r.Url" rel="noopener noreferrer" target="_blank">@r.Title</a></li>
|
||
}
|
||
</ul>
|
||
</section>
|
||
}
|
||
|
||
@code {
|
||
[Parameter] public long Id { get; set; }
|
||
[CascadingParameter] private HttpContext? Http { get; set; }
|
||
|
||
private StoredServerFinding? _finding;
|
||
private IReadOnlyList<StoredServerFinding> _history = [];
|
||
|
||
protected override async Task OnInitializedAsync()
|
||
{
|
||
_finding = await Repository.GetServerFindingAsync(Id);
|
||
if (_finding is null)
|
||
{
|
||
if (Http is not null)
|
||
{
|
||
Http.Response.StatusCode = StatusCodes.Status404NotFound;
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
_history = await Repository.GetServerFindingHistoryAsync(_finding);
|
||
}
|
||
}
|