From 3faf27af482bdc8ef1d22dc3829773dee005996f Mon Sep 17 00:00:00 2001 From: Rassl Date: Fri, 24 Jul 2026 20:26:57 +0700 Subject: [PATCH] fix(reviews): surface failed approvals and clear stale bulk selection Two UI guardrails paired with the backend merge-reconciliation fix: - review-row: on a failed/errored approval, keep the row and its inline error visible instead of immediately refetching it out of the pending list. A failed merge (e.g. "Nodes already merged") previously just vanished and looked like it had succeeded. Still refresh the pending badge so the count reflects that the item left the queue. - reviews page: clear selectedIds after a bulk approve/dismiss. The silent refetch intentionally skips the selection reset, which left stale ids selected after the decided rows had left the list. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/app/admin/reviews/page.tsx | 3 +++ src/components/admin/review-row.tsx | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/src/app/admin/reviews/page.tsx b/src/app/admin/reviews/page.tsx index 129bb2a..2ae829c 100644 --- a/src/app/admin/reviews/page.tsx +++ b/src/app/admin/reviews/page.tsx @@ -244,6 +244,9 @@ export default function ReviewsPage() { ) } await fetchReviews(skip, { silent: true }) + // The silent refetch intentionally skips the selection reset, so clear the + // now-stale selection here — decided rows have left the pending list. + setSelectedIds(new Set()) refreshPendingCount() } diff --git a/src/components/admin/review-row.tsx b/src/components/admin/review-row.tsx index db25153..ed36d29 100644 --- a/src/components/admin/review-row.tsx +++ b/src/components/admin/review-row.tsx @@ -621,7 +621,13 @@ export function ReviewRow({ : undefined const res = await approveReview(review.ref_id, override) if (res.error_message || res.status === "failed") { + // Keep the row and its error visible instead of silently refetching it + // out of the pending list (it is now 'failed', not pending) — otherwise + // a failed merge just vanishes and looks like it succeeded. Still refresh + // the pending badge so the count reflects that it left the queue. setInlineError(res.error_message ?? "Approval failed") + onCountRefresh?.() + return } onRefresh() onCountRefresh?.()