fix: prevent worktree modal from disappearing after opening (#1585)

The worktree dialog state was local React state in SessionSidebar,
which gets destroyed when the component unmounts (mobile drawer close,
VSCode view switch). This caused the modal to briefly appear then
disappear.

Three changes:
- Move newWorktreeDialogOpen from local state to useUIStore so it
  survives component unmount
- Guard useProjectSessionSelection layout effect to skip when the
  worktree dialog is open (prevents auto-session-selection from
  closing the sidebar)
- Remove setSessionSwitcherOpen(false) from worktree button handler
  on mobile (prevents drawer close that unmounts the sidebar)

Fixes #1414
This commit is contained in:
Tom Rochette
2026-06-13 08:55:17 +03:00
committed by GitHub
parent e74ce993d5
commit 560e24cbc2
4 changed files with 15 additions and 3 deletions
@@ -189,7 +189,8 @@ export const SessionSidebar: React.FC<SessionSidebarProps> = ({
const [projectRepoStatus, setProjectRepoStatus] = React.useState<Map<string, boolean | null>>(new Map());
const [visibleSessionCountByGroup, setVisibleSessionCountByGroup] = React.useState<Map<string, number>>(new Map());
const [newWorktreeDialogOpen, setNewWorktreeDialogOpen] = React.useState(false);
const newWorktreeDialogOpen = useUIStore((state) => state.isNewWorktreeDialogOpen);
const setNewWorktreeDialogOpen = useUIStore((state) => state.setNewWorktreeDialogOpen);
const [updateDialogOpen, setUpdateDialogOpen] = React.useState(false);
const [openSidebarMenuKey, setOpenSidebarMenuKey] = React.useState<string | null>(null);
const [renamingFolderId, setRenamingFolderId] = React.useState<string | null>(null);
@@ -545,7 +546,7 @@ export const SessionSidebar: React.FC<SessionSidebarProps> = ({
const openNewWorktreeDialog = React.useCallback(() => {
setNewWorktreeDialogOpen(true);
}, []);
}, [setNewWorktreeDialogOpen]);
const handleOpenUpdateDialog = React.useCallback(() => {
const current = useUpdateStore.getState();
@@ -192,7 +192,6 @@ export function SidebarProjectsList(props: Props): React.ReactNode {
onNewWorktreeSession={() => {
if (projectKey !== props.activeProjectId) props.setActiveProjectIdOnly(projectKey);
props.setActiveMainTab('chat');
if (props.mobileVariant) props.setSessionSwitcherOpen(false);
props.openNewWorktreeDialog();
}}
onRenameStart={() => props.openProjectEditDialog(projectKey)}
@@ -3,6 +3,7 @@ import type { Session } from '@opencode-ai/sdk/v2';
import type { SessionGroup, SessionNode } from '../types';
import { normalizePath } from '../utils';
import type { MainTab } from '@/stores/useUIStore';
import { useUIStore } from '@/stores/useUIStore';
type ProjectSection = {
project: { id: string; normalizedPath: string };
@@ -93,6 +94,10 @@ export const useProjectSessionSelection = (args: Args): { currentSessionDirector
return;
}
if (useUIStore.getState().isNewWorktreeDialogOpen) {
return;
}
if (previousActiveProjectRef.current === activeProjectId) {
return;
}
+7
View File
@@ -536,6 +536,7 @@ interface UIStore {
isSessionCreateDialogOpen: boolean;
isScheduledTasksDialogOpen: boolean;
isSettingsDialogOpen: boolean;
isNewWorktreeDialogOpen: boolean;
isModelSelectorOpen: boolean;
sidebarSection: SidebarSection;
@@ -684,6 +685,7 @@ interface UIStore {
setSessionCreateDialogOpen: (open: boolean) => void;
setScheduledTasksDialogOpen: (open: boolean) => void;
setSettingsDialogOpen: (open: boolean) => void;
setNewWorktreeDialogOpen: (open: boolean) => void;
setModelSelectorOpen: (open: boolean) => void;
applyTheme: () => void;
setSidebarSection: (section: SidebarSection) => void;
@@ -824,6 +826,7 @@ export const useUIStore = create<UIStore>()(
isSessionCreateDialogOpen: false,
isScheduledTasksDialogOpen: false,
isSettingsDialogOpen: false,
isNewWorktreeDialogOpen: false,
isModelSelectorOpen: false,
sidebarSection: 'sessions',
settingsPage: 'home',
@@ -1495,6 +1498,10 @@ export const useUIStore = create<UIStore>()(
});
},
setNewWorktreeDialogOpen: (open) => {
set({ isNewWorktreeDialogOpen: open });
},
setModelSelectorOpen: (open) => {
set({ isModelSelectorOpen: open });
},