diff --git a/ui/src/components/agents/AgentGitPanel.tsx b/ui/src/components/agents/AgentGitPanel.tsx index e2871505..b85c97e5 100644 --- a/ui/src/components/agents/AgentGitPanel.tsx +++ b/ui/src/components/agents/AgentGitPanel.tsx @@ -72,6 +72,9 @@ function commonDirPrefix(paths: Array): string { } const PANEL_STORAGE_WIDTH = "open-swe.gitpanel.width" +const PANEL_STORAGE_COLLAPSED = "open-swe.gitpanel.collapsed" +const COLLAPSED_STATE_TRUE = "1" +const COLLAPSED_STATE_FALSE = "0" const PANEL_DEFAULT_WIDTH = 420 const PANEL_MIN_WIDTH = 320 const PANEL_MAX_WIDTH = 720 @@ -84,6 +87,14 @@ function readStoredPanelWidth(): number { return Math.min(PANEL_MAX_WIDTH, Math.max(PANEL_MIN_WIDTH, parsed)) } +function readStoredPanelCollapsed(): boolean { + if (typeof window === "undefined") return true + // Default to collapsed until the user opens it once. + return ( + window.localStorage.getItem(PANEL_STORAGE_COLLAPSED) !== COLLAPSED_STATE_FALSE + ) +} + function PanelResizeHandle({ width, onResize, @@ -163,10 +174,22 @@ export function treeThemeStyle(): React.CSSProperties { export function AgentGitPanel({ thread, messages }: AgentGitPanelProps) { const [topTab, setTopTab] = useState<"git" | "desktop" | "terminal">("git") const [tab, setTab] = useState<"diff" | "review" | "commits">("diff") - const [collapsed, setCollapsed] = useState(true) + const [collapsed, setCollapsedState] = useState(() => + readStoredPanelCollapsed() + ) const [width, setWidthState] = useState(() => readStoredPanelWidth()) const [fullScreen, setFullScreen] = useState(false) + const setCollapsed = (next: boolean) => { + setCollapsedState(next) + if (typeof window !== "undefined") { + window.localStorage.setItem( + PANEL_STORAGE_COLLAPSED, + next ? COLLAPSED_STATE_TRUE : COLLAPSED_STATE_FALSE + ) + } + } + const setWidth = useCallback((next: number) => { const clamped = Math.min(PANEL_MAX_WIDTH, Math.max(PANEL_MIN_WIDTH, next)) setWidthState(clamped) @@ -176,14 +199,13 @@ export function AgentGitPanel({ thread, messages }: AgentGitPanelProps) { const sectionRefs = useRef>({}) const pr = thread.pr - // Always start collapsed; re-collapse when switching threads, and - // uncollapse when a PR lands mid-session. + // The open/closed state is persisted to localStorage, so it carries across + // threads and reloads. Still uncollapse when a PR lands mid-session. const [prSeen, setPrSeen] = useState<{ threadId: string; hadPr: boolean }>( () => ({ threadId: thread.id, hadPr: Boolean(pr) }) ) if (prSeen.threadId !== thread.id) { setPrSeen({ threadId: thread.id, hadPr: Boolean(pr) }) - setCollapsed(true) } else if (pr && !prSeen.hadPr) { setPrSeen({ threadId: thread.id, hadPr: true }) setCollapsed(false)