feat(ui): AuditDrilldownDrawer with JSON/SQL render, cURL, drill-back, redaction badges (#23 M7)

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.
This commit is contained in:
Joseph Doherty
2026-05-20 20:13:33 -04:00
parent e052aa4ff8
commit ae4480e7aa
6 changed files with 847 additions and 3 deletions

View File

@@ -15,6 +15,8 @@ namespace ScadaLink.CentralUI.Components.Pages.Audit;
public partial class AuditLogPage
{
private AuditLogQueryFilter? _currentFilter;
private AuditEvent? _selectedEvent;
private bool _drawerOpen;
private void HandleFilterChanged(AuditLogQueryFilter filter)
{
@@ -25,8 +27,17 @@ public partial class AuditLogPage
private void HandleRowSelected(AuditEvent row)
{
// Reserved for Bundle C (drilldown drawer). Intentionally left empty: the
// grid still raises the event, but we do nothing with it yet.
_ = row;
// Bundle C: a grid row click hands us the full AuditEvent. We pin it as
// the selected row and open the drilldown drawer — the drawer is fully
// presentational so we do not need to refetch the row.
_selectedEvent = row;
_drawerOpen = true;
}
private void HandleDrawerClose()
{
// We deliberately keep _selectedEvent set so re-opening (e.g. via the
// grid) shows the same row instantly without a re-render flicker.
_drawerOpen = false;
}
}