refactor(centralui): AuditResultsGrid adopts KeysetPager + AuditFilterBar adopts DateTimeRangeFilter (T35g)

This commit is contained in:
Joseph Doherty
2026-06-18 20:03:40 -04:00
parent a3ac77dd41
commit 1d82e6bc8c
3 changed files with 26 additions and 31 deletions
@@ -91,18 +91,17 @@
<div class="col-auto" data-test="filter-custom-range"> <div class="col-auto" data-test="filter-custom-range">
@if (_model.TimeRange == AuditTimeRangePreset.Custom) @if (_model.TimeRange == AuditTimeRangePreset.Custom)
{ {
<div class="d-flex gap-1 align-items-end"> @* DateTimeRangeFilter is INPUT-ONLY: it surfaces the raw datetime-local
<div> picks (DateTimeKind.Unspecified) straight into the model's range fields.
<label class="form-label small mb-1" for="audit-from">From (UTC)</label> The local→UTC conversion still happens later in Apply()/LocalInputToUtc,
<input id="audit-from" type="datetime-local" class="form-control form-control-sm" exactly as before. IdPrefix="audit" keeps the audit-from/audit-to ids. *@
@bind="_model.CustomFromUtc" /> <DateTimeRangeFilter From="_model.CustomFromUtc"
</div> FromChanged="@(v => _model.CustomFromUtc = v)"
<div> To="_model.CustomToUtc"
<label class="form-label small mb-1" for="audit-to">To (UTC)</label> ToChanged="@(v => _model.CustomToUtc = v)"
<input id="audit-to" type="datetime-local" class="form-control form-control-sm" IdPrefix="audit"
@bind="_model.CustomToUtc" /> FromLabel="From (UTC)"
</div> ToLabel="To (UTC)" />
</div>
} }
else else
{ {
@@ -72,24 +72,20 @@
</table> </table>
</div> </div>
<div class="d-flex justify-content-between align-items-center"> @* CentralUI-032: keyset paging is naturally forward-only, but the
<span class="text-muted small">Page @_pageNumber · @_rows.Count rows</span> in-component _cursorStack lets the user step back through previous
@* CentralUI-032: keyset paging is naturally forward-only, but the pages by replaying the prior cursor. The Previous button is gated
in-component _cursorStack lets the user step back through previous on CanGoBack (the stack having at least one prior cursor — i.e. we
pages by replaying the prior cursor. The Previous button is gated are not on the first page); HasNextPage mirrors the prior "short
on the stack having at least one prior cursor — i.e. we are not on page = end" signal (a full page suggests more rows may follow). All
the first page. *@ cursor logic stays page-side; KeysetPager is purely presentational. *@
<div class="btn-group"> <KeysetPager PageNumber="_pageNumber"
<button class="btn btn-outline-secondary btn-sm" RowCount="_rows.Count"
data-test="grid-prev-page" CanGoBack="CanGoBack"
disabled="@(_loading || !CanGoBack)" HasNextPage="@(!_loading && _rows.Count >= _pageSize)"
@onclick="PrevPage">Previous page</button> Disabled="_loading"
<button class="btn btn-outline-secondary btn-sm" OnPrevious="PrevPage"
data-test="grid-next-page" OnNext="NextPage" />
disabled="@(_loading || _rows.Count < _pageSize)"
@onclick="NextPage">Next page</button>
</div>
</div>
</div> </div>
@code { @code {
@@ -95,7 +95,7 @@ public class AuditResultsGridTests : BunitContext
var cut = Render<AuditResultsGrid>(p => p.Add(c => c.Filter, new AuditLogQueryFilter())); var cut = Render<AuditResultsGrid>(p => p.Add(c => c.Filter, new AuditLogQueryFilter()));
cut.Find("[data-test=\"grid-next-page\"]").Click(); cut.Find("[data-test=\"keyset-next\"]").Click();
// Two service calls: initial + next. // Two service calls: initial + next.
Assert.Equal(2, _calls.Count); Assert.Equal(2, _calls.Count);