feat(ui): add Node column + filter to AuditLog grid

This commit is contained in:
Joseph Doherty
2026-05-23 18:01:36 -04:00
parent 466e1454fe
commit bb29d65a94
19 changed files with 392 additions and 8 deletions

View File

@@ -175,4 +175,12 @@ public interface IAuditLogRepository
Task<IReadOnlyList<ExecutionTreeNode>> GetExecutionTreeAsync(
Guid executionId,
CancellationToken ct = default);
/// <summary>
/// Returns the distinct, non-null <c>SourceNode</c> values present in the
/// <c>AuditLog</c> table, in ascending order. Backs the Audit Log page's
/// "Node" multi-select filter dropdown — the Central UI caches the result
/// for ~60s so the repository is hit at most once per minute per circuit.
/// </summary>
Task<IReadOnlyList<string>> GetDistinctSourceNodesAsync(CancellationToken ct = default);
}

View File

@@ -5,16 +5,24 @@ namespace ScadaLink.Commons.Types.Audit;
/// <summary>
/// Filter predicate for <see cref="ScadaLink.Commons.Interfaces.Repositories.IAuditLogRepository.QueryAsync"/>.
/// Any field left <c>null</c> means "do not constrain on that column". The
/// <see cref="Channels"/>, <see cref="Kinds"/>, <see cref="Statuses"/> and
/// <see cref="SourceSiteIds"/> dimensions are multi-value: a <c>null</c> OR empty
/// list means "do not constrain", and a non-empty list is OR-combined within the
/// dimension (translated to a SQL <c>IN (…)</c>). Time bounds are half-open in
/// the spec sense — <see cref="FromUtc"/> is inclusive and <see cref="ToUtc"/> is
/// inclusive of the upper bound; the repository SQL uses <c>&gt;=</c> / <c>&lt;=</c>
/// <see cref="Channels"/>, <see cref="Kinds"/>, <see cref="Statuses"/>,
/// <see cref="SourceSiteIds"/> and <see cref="SourceNodes"/> dimensions are
/// multi-value: a <c>null</c> OR empty list means "do not constrain", and a
/// non-empty list is OR-combined within the dimension (translated to a SQL
/// <c>IN (…)</c>). Time bounds are half-open in the spec sense —
/// <see cref="FromUtc"/> is inclusive and <see cref="ToUtc"/> is inclusive of
/// the upper bound; the repository SQL uses <c>&gt;=</c> / <c>&lt;=</c>
/// respectively. All filter dimensions are AND-combined with one another. The
/// single-value <see cref="CorrelationId"/>, <see cref="ExecutionId"/> and
/// <see cref="ParentExecutionId"/> dimensions constrain on equality when set.
/// </summary>
/// <param name="SourceNodes">
/// Restrict to rows whose <c>SourceNode</c> matches one of the supplied node
/// identifiers (e.g. <c>"central-a"</c>, <c>"site-plant-a-node-a"</c>). A null
/// or empty list means "do not constrain"; a non-empty list is translated to
/// SQL <c>SourceNode IN (…)</c>. Rows with NULL <c>SourceNode</c> are excluded
/// when the filter is set (the same SourceSiteIds contract).
/// </param>
public sealed record AuditLogQueryFilter(
IReadOnlyList<AuditChannel>? Channels = null,
IReadOnlyList<AuditKind>? Kinds = null,
@@ -26,4 +34,5 @@ public sealed record AuditLogQueryFilter(
Guid? ExecutionId = null,
Guid? ParentExecutionId = null,
DateTime? FromUtc = null,
DateTime? ToUtc = null);
DateTime? ToUtc = null,
IReadOnlyList<string>? SourceNodes = null);