From 6ac8692d0d63de9ce65551e8ba1f57638ad4e200 Mon Sep 17 00:00:00 2001 From: Iqbal Date: Thu, 29 Oct 2026 17:12:51 +0700 Subject: [PATCH] Read results once a minute Every read of results asks each video schedule for its drafts, and the dashboard read them every 10s while anything was being made, so the network tab filled with video-drafts requests. Poll once a minute on the dashboard and Results page, and reuse a read under a minute old when a page opens or regains focus. Actions still refresh results at once. Co-Authored-By: Claude Opus 5.5 --- src/express/results.ts | 5 +++++ src/pages/Production.tsx | 5 ++--- src/pages/Results.tsx | 4 ++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/express/results.ts b/src/express/results.ts index 56e45bc..3a8f3dc 100644 --- a/src/express/results.ts +++ b/src/express/results.ts @@ -201,6 +201,11 @@ export async function settleLimited(items: T[], limit: number, fn: (item: const PER_SCHEDULE_LIMIT = 4 +// Results cost one request per schedule (every video schedule's drafts), so they are read once a +// minute, and a page opened or refocused within that minute reuses what was read. An action on a +// result or schedule still refreshes them at once. +export const RESULTS_POLL = { refetchInterval: 60_000, staleTime: 60_000 } + export async function listResults(): Promise<{ materials: Material[]; sources: FoundSource[] }> { const schedules = await expressAgents({ archived: true }) const content = schedules.filter(s => s.rule.type === 'content') diff --git a/src/pages/Production.tsx b/src/pages/Production.tsx index f71d27e..37b9b83 100644 --- a/src/pages/Production.tsx +++ b/src/pages/Production.tsx @@ -7,7 +7,7 @@ import { Icon } from '../components/Icon' import { PageHead, Skeleton, SkeletonCards } from '../components/Page' import { buildGraph, CLUSTERS, type Cluster, type Graph, type GraphNode } from '../express/graph' import { describeRule } from '../express/parse' -import { isWorking, listResults, materialKey, titleOf, type Material } from '../express/results' +import { isWorking, listResults, materialKey, RESULTS_POLL, titleOf, type Material } from '../express/results' import { listSchedules } from '../express/schedules' import { locale, t, type Key } from '../i18n' import { ContentCard, Preview } from './Results' @@ -54,8 +54,7 @@ export function ProductionPage() { const results = useQuery({ queryKey: ['results'], queryFn: listResults, - // Polled more often than on Results so a run that just started shows up under content in progress. - refetchInterval: q => (q.state.data?.materials.some(isWorking) ? 10_000 : 20_000), + ...RESULTS_POLL, }) const schedules = useQuery({ queryKey: ['schedules'], queryFn: listSchedules, refetchInterval: 30_000 }) diff --git a/src/pages/Results.tsx b/src/pages/Results.tsx index b592944..f72c025 100644 --- a/src/pages/Results.tsx +++ b/src/pages/Results.tsx @@ -8,7 +8,7 @@ import { Empty, PageHead, SkeletonCards, SkeletonLines, SkeletonRows } from '../ import { toast } from '../components/Toast' import { describeRule, kindLabel, type ContentKind } from '../express/parse' import { - decideMaterial, download, exportPptx, fileName, isWorking, printPdf, listOf, listResults, materialContent, materialKey, questionsOf, retryMaterial, reviewSource, slidesOf, textOf, + decideMaterial, download, exportPptx, fileName, isWorking, printPdf, listOf, listResults, materialContent, RESULTS_POLL, materialKey, questionsOf, retryMaterial, reviewSource, slidesOf, textOf, titleOf, toMarkdown, type FoundSource, type Material, type MaterialContent, type MaterialStatus, } from '../express/results' import { MASTERY, scormPackage } from '../express/scorm' @@ -35,7 +35,7 @@ export function ResultsPage() { const results = useQuery({ queryKey: ['results'], queryFn: listResults, - refetchInterval: q => (q.state.data?.materials.some(isWorking) ? 10_000 : 60_000), + ...RESULTS_POLL, }) const [tab, setTab] = useState<'content' | 'research'>('content') const [query, setQuery] = useState('')