feat(ui): secured-write history paging + submission age in approve dialog (arch-review S2/P3)
Claude-Session: https://claude.ai/code/session_01MtdgwpEeCUn6cUA5f1LMPj
This commit is contained in:
@@ -92,13 +92,18 @@ public interface ISecuredWriteService
|
||||
|
||||
/// <summary>
|
||||
/// Lists secured writes, optionally filtered by <paramref name="status"/> and
|
||||
/// <paramref name="siteId"/> (read-only — any authenticated user). On any failure
|
||||
/// an empty list is returned so the page renders gracefully.
|
||||
/// <paramref name="siteId"/> with offset paging (read-only — any authenticated user).
|
||||
/// On any failure an empty result (<c>TotalCount = 0</c>) is returned so the page
|
||||
/// renders gracefully. The returned <see cref="SecuredWriteListResult.TotalCount"/> is
|
||||
/// the unpaged match count, so the page can drive a pager independent of page size.
|
||||
/// </summary>
|
||||
/// <param name="status">Status filter; <c>null</c> matches every status.</param>
|
||||
/// <param name="siteId">Site id filter; <c>null</c> matches every site.</param>
|
||||
/// <param name="skip">Rows to skip (offset paging); clamped to >= 0 server-side.</param>
|
||||
/// <param name="take">Maximum rows to return; clamped to 1..500 server-side.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A task resolving to the matching rows, newest submission first.</returns>
|
||||
Task<IReadOnlyList<SecuredWriteDto>> ListAsync(
|
||||
string? status, string? siteId, CancellationToken cancellationToken = default);
|
||||
/// <returns>A task resolving to the matching page + total match count, newest submission first.</returns>
|
||||
Task<SecuredWriteListResult> ListAsync(
|
||||
string? status, string? siteId, int skip = 0, int take = 200,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@@ -79,21 +79,23 @@ public sealed class SecuredWriteService : ISecuredWriteService
|
||||
=> DispatchAsync(new RejectSecuredWriteCommand(id, comment), cancellationToken);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<IReadOnlyList<SecuredWriteDto>> ListAsync(
|
||||
string? status, string? siteId, CancellationToken cancellationToken = default)
|
||||
public async Task<SecuredWriteListResult> ListAsync(
|
||||
string? status, string? siteId, int skip = 0, int take = 200,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var response = await SendAsync(new ListSecuredWritesCommand(status, siteId), cancellationToken);
|
||||
var response = await SendAsync(
|
||||
new ListSecuredWritesCommand(status, siteId, skip, take), cancellationToken);
|
||||
if (response is ManagementSuccess success)
|
||||
{
|
||||
var result = JsonSerializer.Deserialize<SecuredWriteListResult>(
|
||||
success.JsonData, ResultDeserializerOptions);
|
||||
return result?.Items ?? Array.Empty<SecuredWriteDto>();
|
||||
return result ?? new SecuredWriteListResult(Array.Empty<SecuredWriteDto>(), 0);
|
||||
}
|
||||
|
||||
// Read path: log + return empty so the queue/history tables render gracefully.
|
||||
_logger.LogWarning(
|
||||
"ListSecuredWrites failed: {Response}", DescribeFailure(response));
|
||||
return Array.Empty<SecuredWriteDto>();
|
||||
return new SecuredWriteListResult(Array.Empty<SecuredWriteDto>(), 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user