From 80b81813b16ba9f1761a784beb2b7093c1ee438e Mon Sep 17 00:00:00 2001 From: Dylan Savage Date: Thu, 18 Jun 2026 11:05:29 -0700 Subject: [PATCH] fix(profiler-ui): rehydrate report on mount so split panes keep the chart Report data lived only in ProfilerView local state, populated solely by the live Stop flow. Splitting a tab mounts fresh instances with empty state, so both panes showed 'No profiling data available' while the status line still read 'report available' (status is server-backed). Add a mount-time effect that refetches the existing report when has_report is true but local data is empty. Co-Authored-By: Claude Opus 4.8 (1M context) --- apps/profiler-ui/src/views/ProfilerView.tsx | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/apps/profiler-ui/src/views/ProfilerView.tsx b/apps/profiler-ui/src/views/ProfilerView.tsx index b993dee79..e814426f7 100644 --- a/apps/profiler-ui/src/views/ProfilerView.tsx +++ b/apps/profiler-ui/src/views/ProfilerView.tsx @@ -423,6 +423,9 @@ const ProfilerView: React.FC = ({ host, port, name }) => { // Guard against stale async responses when target changes mid-flight const fetchIdRef = useRef(0); + // Guard so an existing server-side report is rehydrated at most once per target + const rehydratedTargetRef = useRef(undefined); + // ========================================================================= // STATUS POLLING // ========================================================================= @@ -546,6 +549,22 @@ const ProfilerView: React.FC = ({ host, port, name }) => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [showSystemCalls]); + // Rehydrate an existing report when this view mounts (or re-mounts) without + // local data — e.g. after the tab is split, which mounts fresh ProfilerView + // instances. Report DATA lives only in local state and is otherwise populated + // solely by the live Stop flow, so a fresh instance shows "No profiling data + // available" even though the server still holds a report (status.has_report + // stays true because it is server-backed). Fetch it once per target. + useEffect(() => { + if (!isConnected) { rehydratedTargetRef.current = undefined; return; } + if (status?.active === true) return; // a live session owns the data + if (!status?.has_report) return; // nothing on the server to rehydrate + if (treeData?.tree != null) return; // already have data locally + if (rehydratedTargetRef.current === target) return; // already attempted for this target + rehydratedTargetRef.current = target; + fetchReport(); + }, [isConnected, status?.active, status?.has_report, target, treeData, fetchReport]); + // ========================================================================= // ROOT CHANGE HANDLER // =========================================================================