feat(acks): surface 999 rejections via sidebar badge + table sort
The 1,156 accepted acks were burying the 5 rejections — the operator had to scroll the whole table to find them. Two changes: 1. Sidebar '999 ACKs' nav item gets a warning-toned badge showing the total rejected segment count from aggregates.rejected_count (mirrors the Reconciliation unmatched badge pattern). One number, visible from any page. 2. Acks page table now sorts rejected rows to the top, then newest-id-first. All 5 rejections fit on page 1 since they're a tiny fraction of the total — no pagination needed. New files: - src/hooks/useAckStats.ts (lightweight aggregates-only fetch) - src/hooks/useAckStats.test.tsx (2 tests) - src/components/Sidebar.test.tsx (3 tests) Pre-existing baseline: 10 frontend failures (api.test.ts exportBatch837, tail-stream.test.ts acks/ta1_acks targeting, Inbox/InboxHeader copy). Unchanged.
This commit is contained in:
+16
-2
@@ -1,4 +1,4 @@
|
||||
import { useCallback, useState } from "react";
|
||||
import { useCallback, useMemo, useState } from "react";
|
||||
import { CheckCircle2, Download, Mail, ShieldCheck } from "lucide-react";
|
||||
import {
|
||||
Table,
|
||||
@@ -63,7 +63,21 @@ export function Acks() {
|
||||
// dedupes by id (first write wins), so a snapshot replay on
|
||||
// reconnect can't double-count an existing row.
|
||||
const mergedItems = useMergedTail("acks", data?.items ?? []);
|
||||
const items = mergedItems;
|
||||
// Display order: rejected rows float to the top, then newest-first
|
||||
// by id. The server returns id-DESC so accepted rows already
|
||||
// follow that order — we only need to bubble the rejections up
|
||||
// (the operator flagged on 2026-07-02 that 5 rejections were
|
||||
// buried inside 1,156 accepted acks and hard to find). All 5 fit
|
||||
// on page 1 since they're a tiny fraction of the total — the
|
||||
// operator never needs to paginate to find them.
|
||||
const items = useMemo(() => {
|
||||
return [...mergedItems].sort((a, b) => {
|
||||
const ra = a.rejectedCount > 0 ? 1 : 0;
|
||||
const rb = b.rejectedCount > 0 ? 1 : 0;
|
||||
if (ra !== rb) return rb - ra; // rejected first
|
||||
return b.id - a.id; // newest id first within each group
|
||||
});
|
||||
}, [mergedItems]);
|
||||
const totalCount = data?.total ?? 0;
|
||||
// Server-side aggregates — sum over the *full* ACK set, not just the
|
||||
// visible page. Without this, the KPI strip silently under-reports
|
||||
|
||||
Reference in New Issue
Block a user