feat(ui): Audit KPI tiles on Health dashboard (#23 M7)
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.
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using ScadaLink.Commons.Entities.Audit;
|
||||
using ScadaLink.Commons.Types;
|
||||
using ScadaLink.Commons.Types.Audit;
|
||||
|
||||
namespace ScadaLink.Commons.Interfaces.Repositories;
|
||||
@@ -87,4 +88,50 @@ public interface IAuditLogRepository
|
||||
Task<IReadOnlyList<DateTime>> GetPartitionBoundariesOlderThanAsync(
|
||||
DateTime threshold,
|
||||
CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Audit Log (#23) M7 Bundle E (T13) — returns aggregate counts over the
|
||||
/// trailing <paramref name="window"/> driving the central Health
|
||||
/// dashboard's Audit KPI tiles.
|
||||
/// </summary>
|
||||
/// <param name="window">
|
||||
/// Trailing time window (e.g. <c>TimeSpan.FromHours(1)</c>). Rows whose
|
||||
/// <c>OccurredAtUtc >= nowUtc - window</c> are counted; the upper
|
||||
/// bound is <paramref name="nowUtc"/>.
|
||||
/// </param>
|
||||
/// <param name="nowUtc">
|
||||
/// Optional explicit "now" timestamp used to anchor the trailing window.
|
||||
/// Defaults to <see cref="DateTime.UtcNow"/> at call time when null —
|
||||
/// production callers should leave this null; tests pin a deterministic
|
||||
/// value so the window is reproducible across runs.
|
||||
/// </param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <returns>
|
||||
/// A snapshot with <c>TotalEventsLastHour</c> + <c>ErrorEventsLastHour</c>
|
||||
/// populated; <c>BacklogTotal</c> is left at zero (this method has no
|
||||
/// visibility into per-site backlogs — the service layer composes it in
|
||||
/// from <see cref="ScadaLink.HealthMonitoring.ICentralHealthAggregator"/>).
|
||||
/// <c>AsOfUtc</c> is set to the server-side <c>UtcNow</c> at the time of
|
||||
/// the query.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Implemented as a single aggregate query
|
||||
/// (<c>SELECT COUNT_BIG(*) AS Total, SUM(CASE …) AS Errors</c>) rather than
|
||||
/// two round trips so the volume + error rate tiles read a consistent
|
||||
/// snapshot — the denominator and numerator come from the same scan.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Errors are defined as <see cref="ScadaLink.Commons.Types.Enums.AuditStatus.Failed"/>,
|
||||
/// <see cref="ScadaLink.Commons.Types.Enums.AuditStatus.Parked"/>, or
|
||||
/// <see cref="ScadaLink.Commons.Types.Enums.AuditStatus.Discarded"/>
|
||||
/// — every non-success terminal lifecycle state. <c>Submitted</c>,
|
||||
/// <c>Forwarded</c>, <c>Attempted</c> are in-flight and are NOT errors;
|
||||
/// <c>Delivered</c> is success; <c>Skipped</c> is an intentional no-op.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
Task<AuditLogKpiSnapshot> GetKpiSnapshotAsync(
|
||||
TimeSpan window,
|
||||
DateTime? nowUtc = null,
|
||||
CancellationToken ct = default);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user