feat(web): auto-poll request progress when ingests are in flight (#369)

Half of #369 — the auto-poll piece. Inbox deferred (separate task).

Both /requests (user) and /admin/requests (admin, 'approved' tab only)
now refetch every 12s while at least one row has status='approved'.
Stops automatically when all rows settle to pending/completed/rejected.
TanStack Query's default refetchIntervalInBackground=false handles
the visibility behavior — polling pauses when the tab is hidden and
resumes on focus.

Predicate hasInFlightRequest() is exported + tested so the polling
logic is auditable independent of TanStack Query's internals.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-10 17:59:38 -04:00
co-authored by Claude Opus 4.7
parent 7bc254e17e
commit 861dd8ef17
3 changed files with 63 additions and 3 deletions
+29 -1
View File
@@ -14,7 +14,8 @@ import {
createRequest,
listMyRequests,
getRequest,
cancelRequest
cancelRequest,
hasInFlightRequest
} from './requests';
import { api, apiFetch } from './client';
import { qk } from './queries';
@@ -155,3 +156,30 @@ describe('qk.myRequests', () => {
expect(qk.myRequests()).toEqual(['myRequests']);
});
});
describe('hasInFlightRequest', () => {
test('false for undefined / empty', () => {
expect(hasInFlightRequest(undefined)).toBe(false);
expect(hasInFlightRequest([])).toBe(false);
});
test('false when no row is approved', () => {
expect(
hasInFlightRequest([
{ ...mockRow, status: 'pending' },
{ ...mockRow, status: 'completed' },
{ ...mockRow, status: 'rejected' }
])
).toBe(false);
});
test('true when at least one row is approved (mid-ingest)', () => {
expect(
hasInFlightRequest([
{ ...mockRow, status: 'pending' },
{ ...mockRow, status: 'approved' },
{ ...mockRow, status: 'completed' }
])
).toBe(true);
});
});