diff --git a/.changeset/fix-dashboard-remount-churn.md b/.changeset/fix-dashboard-remount-churn.md new file mode 100644 index 0000000000..21c5aef2e4 --- /dev/null +++ b/.changeset/fix-dashboard-remount-churn.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": patch +--- + +summary: Terminals, planning sessions, and popped-out task windows no longer reset when switching views or tabs. +category: fix +dev: Keep-alive layer (KeepAliveView, visibility-based out-of-flow hiding) for Planning Mode, task-detail terminal/planner-chat tabs, and popped-out task FloatingWindows; hidden surfaces suspend SSE/EventSource work via `active` props. Stable keys for streaming chat segments, dock task cards, and MCP server rows. CommandCenter/DevServerView selections persist per project via modalPersistence. diff --git a/docs/dashboard-guide.md b/docs/dashboard-guide.md index de443ef050..fb49559db5 100644 --- a/docs/dashboard-guide.md +++ b/docs/dashboard-guide.md @@ -196,7 +196,8 @@ If **Settings → Appearance → Open tasks in the right sidebar** is enabled, b FNXC:TaskPopupGeometry 2026-07-03-00:00: Desktop/tablet task popups share a persisted geometry key across task IDs so operators can size and place the popup once, then open other tasks without repeating that setup. Mobile remains a full-screen sheet regardless of saved desktop geometry. FNXC:RightDockTaskPopup 2026-07-03-00:00: The same task-popup preference also applies to ordinary clicks in the right-dock Tasks list so that opted-in operators never lose the list to embedded detail by clicking a dock task row. FNXC:TaskPopupLayer 2026-07-17-15:55: Task popups and Quick Chat share the board/task-detail interaction stack, so the most recently clicked or focused overlapping surface appears on top. Terminal, Files, New Task, workflow editor, and other utility windows retain their separate higher utility stacking. -FNXC:TaskPopupViewGating 2026-07-15-15:20: FN-8016 makes popup view scoping default-on for every dashboard view. Hidden popups are render-only hidden, not closed, so snapshots and shared geometry survive navigation; same-task popups remain independently addressable by origin view. --> +FNXC:TaskPopupViewGating 2026-07-15-15:20: FN-8016 makes popup view scoping default-on for every dashboard view. Same-task popups remain independently addressable by origin view. +FNXC:TaskPopupViewGating 2026-07-22-13:20: FN remount-churn fix R7 — off-origin-view popups are now render-only hidden (FloatingWindow `hidden`: visibility-based, aria-hidden, effects suspended), never unmounted. The embedded task detail, including an open terminal WebSocket, stays live while hidden; the detail's SSE/EventSource channels close via `active={false}` and reopen on reveal. Returning to the origin view is an instant reveal, not a remount. --> **Settings → Appearance → Open tasks as popups** changes ordinary board task-card clicks, List row/card opens, and right-dock Tasks-list clicks across desktop, tablet, and mobile viewports. When enabled, those clicks use the existing task popup/FloatingWindow surface on the board/task-detail layer instead of the full-panel task detail, List split-detail/docked detail, or right-dock task detail, keeping the board, List view, or dock list visible in the background. Overlapping Quick Chat and task popups interleave by the most-recent pointer or focus interaction; other utility windows retain their higher global stacking. On desktop and tablet, task popups restore the last saved popup size and position between tasks; on mobile, task popups stay full-screen sheets. Board task-card `changes`/`retries`/`workflow` chips open the popup with the requested tab. List context-menu/refine actions, task-detail links, plugin/graph opens, and explicit pop-out actions keep their existing paths. **Settings → Appearance → Keep task popups on the view where they were opened** is enabled by default. Every task-detail popup is attached to its exact originating view, including Planning, Agents, Command Center, Documents, Missions, and plugin views: navigating elsewhere hides it without closing it, and returning re-shows it in the same saved position. You can open the same task independently in more than one view; closing or pressing Escape on one popup does not affect the other. Disable this setting only to restore legacy globally shared popups. Legacy saved popups without an origin remain visible everywhere for compatibility. diff --git a/docs/plans/2026-07-22-001-fix-dashboard-remount-churn-plan.md b/docs/plans/2026-07-22-001-fix-dashboard-remount-churn-plan.md new file mode 100644 index 0000000000..542e798643 --- /dev/null +++ b/docs/plans/2026-07-22-001-fix-dashboard-remount-churn-plan.md @@ -0,0 +1,292 @@ +--- +title: "fix: Stop over-aggressive component unmounts across the dashboard" +type: fix +status: completed +date: 2026-07-22 +--- + +# fix: Stop over-aggressive component unmounts across the dashboard + +## Summary + +Fix every confirmed source of unnecessary unmount/remount churn in the dashboard: two volatile-key bugs, two mechanical anti-patterns, and — the substantive part — a keep-alive layer so conversation- and terminal-bearing surfaces (Planning Mode, task-detail terminal and planner-chat tabs, popped-out task windows) survive navigation and tab switches mounted-but-hidden, mirroring the existing Quick Chat hidden-FloatingWindow pattern. Includes a deep audit of Planning Mode's internal session/view transitions and lightweight state preservation for the cheaper views. + +--- + +## Problem Frame + +A remount audit (2026-07-22) found the dashboard unmounts components far more often than intended. The main-content area is a pure `if (taskView === ...) return` switch (`packages/dashboard/app/components/dashboard/MainContent.tsx`), so every navigation destroys the previous view entirely; TaskDetail's tab body is one mutually-exclusive ternary, so every tab switch tears down terminals (WebSocket close + xterm dispose) and the planner chat; popped-out task windows are filtered out of the render array when the user leaves their origin view. On top of the architectural cause, two keys are more volatile than the identity they represent: the streaming chat segment key embeds `entries.length` (remounts the actively streaming thinking block on every entry), and the dock task list keys `TaskCard` by `id-index` (remounts on any reorder). + +User-visible symptoms: an expanded thinking block snapping shut on every streamed entry, terminals reconnecting and losing scroll/unsent input on every tab flip, Planning Mode losing in-flight interview UI (view state, streaming output, retry counters, unsaved summary edits) on any sidebar navigation, and floating task windows vanishing and remounting when switching views. + +The codebase already contains the correct pattern twice: Quick Chat stays mounted via `