From 0c01627d67c62faaf973759384fd2d5719c2913d Mon Sep 17 00:00:00 2001 From: kris Date: Tue, 7 Apr 2026 18:00:14 +0800 Subject: [PATCH] Refresh status pages in realtime --- src/app/me/about/page.tsx | 2 + src/app/me/ops/audit/page.tsx | 2 + src/app/me/ops/page.tsx | 2 + src/app/me/page.tsx | 2 + src/app/threads/[threadId]/page.tsx | 5 +++ tests/status-pages-realtime-refresh.test.ts | 49 +++++++++++++++++++++ 6 files changed, 62 insertions(+) create mode 100644 tests/status-pages-realtime-refresh.test.ts diff --git a/src/app/me/about/page.tsx b/src/app/me/about/page.tsx index 3fb2a84..4db3196 100644 --- a/src/app/me/about/page.tsx +++ b/src/app/me/about/page.tsx @@ -1,3 +1,4 @@ +import { RealtimeRefresh } from "@/components/app-runtime"; import { AppShell, OtaCenterCard, PageNav, StatusBar } from "@/components/app-ui"; import { requirePageSession } from "@/lib/boss-auth"; import { getOtaStatus, readState } from "@/lib/boss-data"; @@ -10,6 +11,7 @@ export default async function AboutPage() { return ( +
diff --git a/src/app/me/ops/audit/page.tsx b/src/app/me/ops/audit/page.tsx index acfa8a7..5e4b4ba 100644 --- a/src/app/me/ops/audit/page.tsx +++ b/src/app/me/ops/audit/page.tsx @@ -1,4 +1,5 @@ import Link from "next/link"; +import { RealtimeRefresh } from "@/components/app-runtime"; import { AppShell, PageNav, StatusBar } from "@/components/app-ui"; import { requirePageSession } from "@/lib/boss-auth"; import { getAuditSummaryView } from "@/lib/boss-projections"; @@ -13,6 +14,7 @@ export default async function AuditPage() { return ( +
diff --git a/src/app/me/ops/page.tsx b/src/app/me/ops/page.tsx index bb58e2c..c52ad14 100644 --- a/src/app/me/ops/page.tsx +++ b/src/app/me/ops/page.tsx @@ -1,4 +1,5 @@ import Link from "next/link"; +import { RealtimeRefresh } from "@/components/app-runtime"; import { AppShell, PageNav, RepairTicketActions, StatusBar } from "@/components/app-ui"; import { requirePageSession } from "@/lib/boss-auth"; import { getOpsSummaryView } from "@/lib/boss-projections"; @@ -13,6 +14,7 @@ export default async function OpsPage() { return ( +
diff --git a/src/app/me/page.tsx b/src/app/me/page.tsx index 6db2ff9..1c389e7 100644 --- a/src/app/me/page.tsx +++ b/src/app/me/page.tsx @@ -1,3 +1,4 @@ +import { RealtimeRefresh } from "@/components/app-runtime"; import { AppShell, HeaderTitle, @@ -17,6 +18,7 @@ export default async function MePage() { return ( +
diff --git a/src/app/threads/[threadId]/page.tsx b/src/app/threads/[threadId]/page.tsx index c125835..8b64bdc 100644 --- a/src/app/threads/[threadId]/page.tsx +++ b/src/app/threads/[threadId]/page.tsx @@ -1,5 +1,6 @@ import { notFound } from "next/navigation"; import Link from "next/link"; +import { RealtimeRefresh } from "@/components/app-runtime"; import { AppShell, PageNav, StatusBar } from "@/components/app-ui"; import { requirePageSession } from "@/lib/boss-auth"; import { getThreadContextDetailView } from "@/lib/boss-projections"; @@ -21,6 +22,10 @@ export default async function ThreadPage({ return ( +
diff --git a/tests/status-pages-realtime-refresh.test.ts b/tests/status-pages-realtime-refresh.test.ts new file mode 100644 index 0000000..45b83cd --- /dev/null +++ b/tests/status-pages-realtime-refresh.test.ts @@ -0,0 +1,49 @@ +import test from "node:test"; +import assert from "node:assert/strict"; +import path from "node:path"; +import { readFile } from "node:fs/promises"; +import { fileURLToPath } from "node:url"; + +const testsDir = path.dirname(fileURLToPath(import.meta.url)); + +async function readWorkspaceFile(relativePath: string) { + return readFile(path.join(testsDir, "..", relativePath), "utf8"); +} + +test("thread detail page refreshes when context risk updates for its project", async () => { + const source = await readWorkspaceFile("src/app/threads/[threadId]/page.tsx"); + + assert.match(source, /import \{ RealtimeRefresh \}/, "expected thread page to import RealtimeRefresh"); + assert.match(source, /projectId=\{detail\.snapshot\.projectId\}/, "expected thread page to scope realtime refresh to its project"); + assert.match(source, /"project\.context_risk\.updated"/, "expected thread page to listen for context risk updates"); +}); + +test("me and about pages refresh when OTA status changes", async () => { + const [mePage, aboutPage] = await Promise.all([ + readWorkspaceFile("src/app/me/page.tsx"), + readWorkspaceFile("src/app/me/about/page.tsx"), + ]); + + for (const [label, source] of [ + ["me", mePage], + ["about", aboutPage], + ] as const) { + assert.match(source, / { + const [opsPage, auditPage] = await Promise.all([ + readWorkspaceFile("src/app/me/ops/page.tsx"), + readWorkspaceFile("src/app/me/ops/audit/page.tsx"), + ]); + + for (const [label, source] of [ + ["ops", opsPage], + ["audit", auditPage], + ] as const) { + assert.match(source, /