From 2bb3dcd69e96203258d617eac5b5bcba883c83a0 Mon Sep 17 00:00:00 2001 From: Oliver Kieselbach Date: Thu, 8 Oct 2026 21:22:52 +0200 Subject: [PATCH] Push status page: Diagnostics collapsed by default, collected when opened The section is for troubleshooting, not for every visit: a disclosure button in the heading opens it, the diagnostics are collected the first time it opens (not on page load), Refresh shows only while open, and a one-line note under the import button says what it does. Co-Authored-By: Claude Fable 5.1 --- .../app/push/status/page.tsx | 157 ++++++++++++------ 1 file changed, 102 insertions(+), 55 deletions(-) diff --git a/src/Web/autopilot-monitor-web/app/push/status/page.tsx b/src/Web/autopilot-monitor-web/app/push/status/page.tsx index 8f2840d8..30737518 100644 --- a/src/Web/autopilot-monitor-web/app/push/status/page.tsx +++ b/src/Web/autopilot-monitor-web/app/push/status/page.tsx @@ -40,24 +40,24 @@ export default function PushStatusPage() { const [retention, setRetention] = useState(null); const [retentionInput, setRetentionInput] = useState(null); const [retentionNote, setRetentionNote] = useState({ kind: "idle" }); - // Diagnostics (null: not collected yet) and the feedback line of the manual import. + // Diagnostics: collapsed by default and collected the first time the section is opened + // (null: not collected yet); plus the feedback line of the manual import. + const [diagOpen, setDiagOpen] = useState(false); const [diag, setDiag] = useState(null); const [importNote, setImportNote] = useState(null); useEffect(() => { let cancelled = false; const run = async () => { - const [reconciled, storage, days, diagnostics] = await Promise.all([ + const [reconciled, storage, days] = await Promise.all([ reconcileDevice(), isStoragePersisted(), readRetentionDays().catch(() => null), - collectPushDiagnostics().catch(() => null), ]); if (cancelled) return; setResult(reconciled); setPersisted(storage); setRetention(days); - setDiag(diagnostics); }; void run(); return () => { @@ -73,6 +73,20 @@ export default function PushStatusPage() { return () => clearTimeout(timer); }, [savedAt]); + // The diagnostics are collected when the section is first opened, not on every visit. + useEffect(() => { + if (!diagOpen || diag !== null) return; + let cancelled = false; + const run = async () => { + const collected = await collectPushDiagnostics().catch(() => null); + if (!cancelled) setDiag(collected); + }; + void run(); + return () => { + cancelled = true; + }; + }, [diagOpen, diag]); + const retentionText = retentionInput ?? (retention === null ? "" : String(retention)); const saveRetention = async () => { @@ -254,59 +268,92 @@ export default function PushStatusPage() { {paired && (
-

Diagnostics

- +

+ +

+ {diagOpen && ( + + )}
-

What this device knows about the last pushes. Nothing here leaves the device.

-
- - - -
- {diag && diag.displayed && diag.displayed.length > 0 && ( -
    - {diag.displayed.map((n, i) => ( -
  • - {n.title} - {" · "} - {n.tag ? `tag ${n.tag}` : "no tag"} - {" · "} - {n.data} - {n.timestamp ? ` · ${formatDateTime(n.timestamp)}` : ""} - {n.id ? " · ours" : " · not recognised"} -
  • - ))} -
+ {!diagOpen &&

For troubleshooting: what this device knows about the last pushes.

} + {diagOpen && ( +
+

What this device knows about the last pushes. Nothing here leaves the device.

+
+ + + +
+ {diag && diag.displayed && diag.displayed.length > 0 && ( +
    + {diag.displayed.map((n, i) => ( +
  • + {n.title} + {" · "} + {n.tag ? `tag ${n.tag}` : "no tag"} + {" · "} + {n.data} + {n.timestamp ? ` · ${formatDateTime(n.timestamp)}` : ""} + {n.id ? " · ours" : " · not recognised"} +
  • + ))} +
+ )} +
+ + {importNote && ( + + {importNote} + + )} +
+

+ The import reads the notifications still in the notification centre and adds the ones the history lacks — the same + catch-up the history page runs on every open. +

+
+

Worker trace

+ {diag && diag.trace.length === 0 &&

The worker has not recorded anything yet.

} + {diag && diag.trace.length > 0 && ( +
    + {diag.trace.slice(0, TRACE_ROWS).map((record, i) => ( +
  • + {formatTraceRecord(record)} +
  • + ))} +
+ )} +
+
)} -
- - {importNote && ( - - {importNote} - - )} -
-
-

Worker trace

- {diag && diag.trace.length === 0 &&

The worker has not recorded anything yet.

} - {diag && diag.trace.length > 0 && ( -
    - {diag.trace.slice(0, TRACE_ROWS).map((record, i) => ( -
  • - {formatTraceRecord(record)} -
  • - ))} -
- )} -
)}