- Menu group "Servere" with Windows-servere (/servere) and Syntetiske tjek
(/syntetiske-tjek).
- /servere: every server with status (overvåges, delvist målbar, kan ikke læses),
CPU, free memory, the fullest disk and the nearest "fuld om ca. N dage", findings;
add application/AOS/file servers. /servere/{id}: findings and what is not
measurable and why, CPU/memory for the last day, disks with forecasts, watched
and stopped services, grouped event log errors, scheduled tasks, rights per area
with the latest test, the least-privilege PowerShell script (copy or download,
UTF-8 with BOM), role and service lists, pause and remove. /servere/fund/{id}.
- /syntetiske-tjek: checks with status and response time; one form for every kind
(TCP, HTTP(S), SQL login + query, DNS, AX logon) with an optional server and
service; a SQL login password is sealed for the agent at once and never shown.
/syntetiske-tjek/{id}: latest result (incl. "kun porten er testet"), findings,
response times, history, edit, run now, pause, remove.
- API v1: /windows-servers (+ test, grant-script, performance, disks, services,
events, tasks, rule-states), /server-findings, /synthetic-checks (+ run, results,
rule-states); all in OpenAPI. Passwords are write-only; event samples, failure
messages and sensitive evidence are "[udeladt]" unless
SQLInsight:Web:ApiIncludesSensitiveEvidence is on. /api/v1/rules lists the new rules.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
107 lines
3 KiB
Text
107 lines
3 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> <a href="@ServerSetup.ServerPage(_finding.ScopeId)">@_finding.ScopeName</a>
|
||
}
|
||
else
|
||
{
|
||
<a href="@ServerSetup.ChecksPage">Syntetiske tjek</a> <text>/</text> <a href="@ServerSetup.CheckPage(_finding.ScopeId)">@_finding.ScopeName</a>
|
||
}
|
||
/ @_finding.RuleId
|
||
</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);
|
||
}
|
||
}
|