Adds three KPI tiles to the central Health dashboard for the Audit channel: volume (rows in the last hour), error rate (Failed/Parked/Discarded over total), and backlog (sum of SiteAuditBacklog.PendingCount across all sites). Repo + service: - IAuditLogRepository.GetKpiSnapshotAsync(window, nowUtc) — single aggregate SELECT over the trailing window returning total + error counts; nowUtc is optional for production callers and pinned by integration tests against the shared MSSQL fixture so the global counts are deterministic. - AuditLogQueryService.GetKpiSnapshotAsync() — composes the repo aggregate with a sum of SiteAuditBacklog.PendingCount read from ICentralHealthAggregator. - AuditLogKpiSnapshot record in Commons/Types/. UI: - New AuditKpiTiles Blazor component (Components/Health/) — three Bootstrap card-tiles, click navigates to /audit/log with the matching pre-filter. - Health.razor wires the tiles in alongside the existing Notification Outbox KPIs; LoadAuditKpis() runs on every 10s refresh tick and degrades to em dashes + inline error if the query fails. - AuditLogPage extended to parse ?status= so the error-rate tile drill-in (?status=Failed) auto-loads the grid. Tests: - AuditLogRepositoryTests: GetKpiSnapshotAsync mixed-status + empty-window cases against the MSSQL migration fixture. - AuditLogQueryServiceTests: forwarding + backlog composition; sites with null SiteAuditBacklog contribute zero. - AuditKpiTilesTests: 9 bUnit tests covering tile render, error-rate maths with safe zero-events handling, em-dash unavailable path, click-through navigation, and warning/danger border thresholds. - HealthPageTests: new Renders_AuditKpiTiles_WithValues plus IAuditLogQueryService stub registration in the constructor so existing outbox tests still pass. - AuditLogPageScaffoldTests: ?status=Failed auto-load + unknown status drop.
60 lines
2.9 KiB
Plaintext
60 lines
2.9 KiB
Plaintext
@*
|
|
Audit Log (#23) M7 Bundle E (T13) — three Health-dashboard KPI tiles for the
|
|
Audit channel: Volume / Error rate / Backlog. Renders Bootstrap card tiles in
|
|
a single row, each acting as a navigation link to a pre-filtered Audit Log
|
|
view. The component is purely presentational — the parent page owns the
|
|
refresh loop and passes the latest snapshot via the Snapshot parameter.
|
|
*@
|
|
|
|
@namespace ScadaLink.CentralUI.Components.Health
|
|
@inject NavigationManager Navigation
|
|
|
|
<div class="d-flex justify-content-between align-items-center mb-2">
|
|
<h6 class="text-muted mb-0">Audit</h6>
|
|
<a class="small" href="/audit/log">View details →</a>
|
|
</div>
|
|
<div class="row g-3 mb-3">
|
|
@* ── Volume tile ───────────────────────────────────────────────────────── *@
|
|
<div class="col-lg-4 col-md-6 col-12">
|
|
<button type="button"
|
|
class="card h-100 w-100 text-start border-0 shadow-none p-0 audit-kpi-tile"
|
|
data-test="audit-kpi-volume"
|
|
@onclick="NavigateToVolume">
|
|
<div class="card-body text-center">
|
|
<h3 class="mb-0">@VolumeDisplay</h3>
|
|
<small class="text-muted">Audit volume (last hour)</small>
|
|
</div>
|
|
</button>
|
|
</div>
|
|
|
|
@* ── Error rate tile ───────────────────────────────────────────────────── *@
|
|
<div class="col-lg-4 col-md-6 col-12">
|
|
<button type="button"
|
|
class="card h-100 w-100 text-start border-0 shadow-none p-0 audit-kpi-tile @ErrorRateBorderClass"
|
|
data-test="audit-kpi-error-rate"
|
|
@onclick="NavigateToErrors">
|
|
<div class="card-body text-center">
|
|
<h3 class="mb-0 @ErrorRateTextClass">@ErrorRateDisplay</h3>
|
|
<small class="text-muted">Audit error rate (last hour)</small>
|
|
</div>
|
|
</button>
|
|
</div>
|
|
|
|
@* ── Backlog tile ──────────────────────────────────────────────────────── *@
|
|
<div class="col-lg-4 col-md-6 col-12">
|
|
<button type="button"
|
|
class="card h-100 w-100 text-start border-0 shadow-none p-0 audit-kpi-tile @BacklogBorderClass"
|
|
data-test="audit-kpi-backlog"
|
|
@onclick="NavigateToBacklog">
|
|
<div class="card-body text-center">
|
|
<h3 class="mb-0 @BacklogTextClass">@BacklogDisplay</h3>
|
|
<small class="text-muted">Audit backlog (sites pending)</small>
|
|
</div>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
@if (!IsAvailable && !string.IsNullOrEmpty(ErrorMessage))
|
|
{
|
|
<div class="text-muted small mb-3">Audit KPIs unavailable: @ErrorMessage</div>
|
|
}
|