Implements Bundle C (M7-T4 through M7-T8) of the Audit Log #23 M7
Central UI work: a right-side off-canvas drawer that opens from
AuditResultsGrid row clicks and renders one AuditEvent in full.
Cohesive single-component delivery:
- Read-only fields stacked (form-layout memory): Channel/Kind, Status,
HttpStatus, Target, Actor, Source* provenance, CorrelationId,
OccurredAtUtc, IngestedAtUtc, DurationMs.
- Channel-aware body renderer: DbOutbound {sql, parameters} payloads
render a code-block with CSS-only .language-sql class plus a
parameter <dl>; other channels JSON-pretty-print when parseable and
fall back to verbatim <pre>.
- Redaction badges on Request/Response when the body contains the
<redacted> or <redacted: redactor error> sentinels.
- Copy-as-cURL (API channels only) builds a curl command from Target
+ optional {method, headers, body} RequestSummary JSON and writes
it via navigator.clipboard.writeText.
- Show-all-events drill-back navigates to /audit/log?correlationId={id}
when the event carries a CorrelationId.
- Close button + backdrop-click both raise OnClose.
AuditLogPage wires Event/IsOpen/OnClose; row clicks now open the
drawer (HandleRowSelected pins _selectedEvent + _drawerOpen=true).
11 bUnit tests cover field rendering, JSON pretty-print, verbatim
fallback, SQL block, conditional buttons, redaction badges,
navigation drill-back, and clipboard interop. No third-party UI
libraries: Bootstrap offcanvas + scoped razor.css only.
Adds the results grid + query facade for the central Audit Log page
(#23 M7-T3):
* IAuditLogQueryService / AuditLogQueryService — CentralUI facade over
IAuditLogRepository.QueryAsync so the grid can be tested with a stubbed
query source. Default page size is 100; callers can override per call.
* AuditResultsGrid.razor + .razor.cs — Blazor Server component (Bootstrap
only, no third-party UI libs). Renders the 10 columns from
Component-AuditLog.md §10 (OccurredAtUtc, Site, Channel, Kind, Status,
Target, Actor, DurationMs, HttpStatus, ErrorMessage). Keyset-paged via
the last visible row's (OccurredAtUtc, EventId) as the cursor; Next-page
button disabled when the current page is short (no count query). Row
clicks emit OnRowSelected(AuditEvent) for Bundle C's drilldown drawer.
Status badges are colour-coded (Delivered=green; Failed/Parked/Discarded
=red; other=gray). Error messages truncated to 80 chars with full text
on hover.
* Column model framework: a ColumnOrder [Parameter] reorders columns by
stable string keys; unknown keys are dropped. M7 scope decision (in the
class doc): the framework is in place but drag-reorder / resize UX is
not implemented — M7.x can add persisted-per-user reordering without
rewriting the column model.
* AuditLogPage wired: hosts AuditFilterBar + AuditResultsGrid, threads
the filter through and stubs OnRowSelected for Bundle C.
* AuditLogQueryService registered as scoped in AddCentralUI.
* Tests: 4 grid bUnit tests (10 columns rendered, next-page cursor
carries last row, row click raises callback, badge classes for
Failed vs Delivered), 2 service tests (filter+paging pass-through,
default page size of 100). AuditLogPageScaffoldTests updated to
provide the new ISiteRepository + IAuditLogQueryService stubs the
page now resolves.
Adds the filter bar for the central Audit Log page (#23 M7-T2):
* AuditQueryModel — UI binding model with chip-style multi-select state for
Channel/Kind/Status/Site, a Channel→Kind narrowing map (CachedSubmit and
CachedResolve appear under both ApiOutbound and DbOutbound per
Component-AuditLog.md §4), time-range presets (5min/1h/24h/Custom),
free-text Instance/Script/Target/Actor searches and an Errors-only toggle.
Collapses to the single-value AuditLogQueryFilter on ToFilter(utcNow);
multi-select chips take the first selected per dimension and the
Errors-only toggle pins Failed when Status chips are empty (chip-set wins
otherwise) — documented Bundle B scope decision.
* AuditFilterBar.razor + .razor.cs — Blazor Server component (Bootstrap
only, no third-party UI libs). Renders the 10 spec elements plus the
Errors-only toggle, populates Site chips from ISiteRepository at
initialisation, exposes [Parameter] EventCallback<AuditLogQueryFilter>
OnFilterChanged and an optional NowUtcProvider seam for time-window tests.
* AuditFilterBarTests — 5 bUnit tests pinning element presence, Apply
callback payload, Channel→Kind narrowing, Errors-only toggle precedence
and the LastHour time-window collapse.