From 32f4a43cc0740f3c42d355b7d93dc61aa4bcda53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Flor=C3=AAncio?= Date: Thu, 26 Feb 2026 14:10:17 +0000 Subject: [PATCH] feat: restore correct scroll position after layout switch (#295) --- apps/backend/internal/github/controller.go | 2 +- apps/web/components/task/chat/use-chat-panel-state.ts | 5 ++--- apps/web/components/task/chat/use-tiptap-editor.ts | 1 - apps/web/lib/state/dockview-store.ts | 5 +++++ 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/backend/internal/github/controller.go b/apps/backend/internal/github/controller.go index 509ea2b994..71cc40750a 100644 --- a/apps/backend/internal/github/controller.go +++ b/apps/backend/internal/github/controller.go @@ -82,7 +82,7 @@ func (c *Controller) httpGetTaskPR(ctx *gin.Context) { return } if tp == nil { - ctx.JSON(http.StatusNotFound, gin.H{"error": "no PR associated with task"}) + ctx.Status(http.StatusNoContent) return } ctx.JSON(http.StatusOK, tp) diff --git a/apps/web/components/task/chat/use-chat-panel-state.ts b/apps/web/components/task/chat/use-chat-panel-state.ts index 5e66d4a357..bf59c9281d 100644 --- a/apps/web/components/task/chat/use-chat-panel-state.ts +++ b/apps/web/components/task/chat/use-chat-panel-state.ts @@ -5,7 +5,6 @@ import { useAppStore } from "@/components/state-provider"; import { getLocalStorage } from "@/lib/local-storage"; import { useLayoutStore } from "@/lib/state/layout-store"; import { useDockviewStore } from "@/lib/state/dockview-store"; -import { preserveChatScrollDuringLayout } from "@/lib/state/dockview-scroll-preserve"; import { usePanelActions } from "@/hooks/use-panel-actions"; import { useSessionMessages } from "@/hooks/domains/session/use-session-messages"; import { useCustomPrompts } from "@/hooks/domains/settings/use-custom-prompts"; @@ -70,9 +69,9 @@ export function usePlanMode(resolvedSessionId: string | null, taskId: string | n } }, [resolvedSessionId, setPlanMode, addContextFile]); - // Preserve scroll position and re-focus chat input after dockview layout rebuild + // Re-focus chat input after dockview layout rebuild. + // Scroll preservation is handled by the store layout actions (before DOM rebuild). const refocusChatAfterLayout = useCallback(() => { - preserveChatScrollDuringLayout(); const unsub = useDockviewStore.subscribe((state) => { if (!state.isRestoringLayout) { unsub(); diff --git a/apps/web/components/task/chat/use-tiptap-editor.ts b/apps/web/components/task/chat/use-tiptap-editor.ts index d898287751..27067a181d 100644 --- a/apps/web/components/task/chat/use-tiptap-editor.ts +++ b/apps/web/components/task/chat/use-tiptap-editor.ts @@ -315,7 +315,6 @@ function useSubmitKeymap( return false; }, "Shift-Tab": () => { - console.log("[ShiftTab] toggling plan mode", { current: planModeEnabledRef.current }); onPlanModeChangeRef.current?.(!planModeEnabledRef.current); return true; }, diff --git a/apps/web/lib/state/dockview-store.ts b/apps/web/lib/state/dockview-store.ts index 05f3037c34..31ce9814e7 100644 --- a/apps/web/lib/state/dockview-store.ts +++ b/apps/web/lib/state/dockview-store.ts @@ -23,6 +23,7 @@ import { } from "./layout-manager"; import { buildFileStateActions } from "./dockview-file-state"; import { buildPanelActions, buildExtraPanelActions } from "./dockview-panel-actions"; +import { preserveChatScrollDuringLayout } from "./dockview-scroll-preserve"; // Re-export types and constants used by other modules export type { BuiltInPreset } from "./layout-manager"; @@ -232,6 +233,7 @@ function buildVisibilityActions(set: StoreSet, get: StoreGet) { const { api, sidebarVisible } = get(); if (!api) return; const liveWidths = captureLiveWidths(api, set); + preserveChatScrollDuringLayout(); if (sidebarVisible) { const current = fromDockviewApi(api); const withoutSidebar: LayoutState = { @@ -261,6 +263,7 @@ function buildVisibilityActions(set: StoreSet, get: StoreGet) { const { api, rightPanelsVisible } = get(); if (!api) return; const liveWidths = captureLiveWidths(api, set); + preserveChatScrollDuringLayout(); if (rightPanelsVisible) { const current = fromDockviewApi(api); const withoutRight: LayoutState = { @@ -310,6 +313,7 @@ function buildPresetActions(set: StoreSet, get: StoreGet) { const { api } = get(); if (!api) return; const liveWidths = captureLiveWidths(api, set); + preserveChatScrollDuringLayout(); // Capture dimensions before layout change — api.width can become stale // inside the rAF callback after dockview serialization const safeWidth = api.width; @@ -340,6 +344,7 @@ function buildPresetActions(set: StoreSet, get: StoreGet) { const { api } = get(); if (!api) return; const liveWidths = captureLiveWidths(api, set); + preserveChatScrollDuringLayout(); const safeWidth = api.width; const safeHeight = api.height; set({ isRestoringLayout: true });