Separate explorer checkout from panel state
This commit is contained in:
@@ -388,9 +388,11 @@ function AppContainer({
|
|||||||
const { theme } = useUnistyles();
|
const { theme } = useUnistyles();
|
||||||
const daemons = useHosts();
|
const daemons = useHosts();
|
||||||
const { settings, updateSettings } = useAppSettings();
|
const { settings, updateSettings } = useAppSettings();
|
||||||
const toggleAgentList = usePanelStore((state) => state.toggleAgentList);
|
const toggleMobileAgentList = usePanelStore((state) => state.toggleMobileAgentList);
|
||||||
const toggleFileExplorer = usePanelStore((state) => state.toggleFileExplorer);
|
const toggleMobileFileExplorer = usePanelStore((state) => state.toggleMobileFileExplorer);
|
||||||
const toggleBothSidebars = usePanelStore((state) => state.toggleBothSidebars);
|
const toggleDesktopAgentList = usePanelStore((state) => state.toggleDesktopAgentList);
|
||||||
|
const toggleDesktopFileExplorer = usePanelStore((state) => state.toggleDesktopFileExplorer);
|
||||||
|
const toggleDesktopSidebars = usePanelStore((state) => state.toggleDesktopSidebars);
|
||||||
const toggleFocusMode = usePanelStore((state) => state.toggleFocusMode);
|
const toggleFocusMode = usePanelStore((state) => state.toggleFocusMode);
|
||||||
const isFocusModeEnabled = usePanelStore((state) => state.desktop.focusModeEnabled);
|
const isFocusModeEnabled = usePanelStore((state) => state.desktop.focusModeEnabled);
|
||||||
const agentListOpen = usePanelStore((state) => state.desktop.agentListOpen);
|
const agentListOpen = usePanelStore((state) => state.desktop.agentListOpen);
|
||||||
@@ -405,6 +407,8 @@ function AppContainer({
|
|||||||
const isCompactLayout = useIsCompactFormFactor();
|
const isCompactLayout = useIsCompactFormFactor();
|
||||||
const chromeEnabled = chromeEnabledOverride ?? daemons.length > 0;
|
const chromeEnabled = chromeEnabledOverride ?? daemons.length > 0;
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
|
const toggleAgentList = isCompactLayout ? toggleMobileAgentList : toggleDesktopAgentList;
|
||||||
|
const toggleFileExplorer = isCompactLayout ? toggleMobileFileExplorer : toggleDesktopFileExplorer;
|
||||||
// TODO: stop matching pathname here as a branch. `chromeEnabled` should not
|
// TODO: stop matching pathname here as a branch. `chromeEnabled` should not
|
||||||
// conflate workspace/project-specific chrome (sidebar, mobile gesture) with
|
// conflate workspace/project-specific chrome (sidebar, mobile gesture) with
|
||||||
// global concerns like keyboard shortcuts. Split those out so settings (and
|
// global concerns like keyboard shortcuts. Split those out so settings (and
|
||||||
@@ -445,7 +449,7 @@ function AppContainer({
|
|||||||
isMobile: isCompactLayout,
|
isMobile: isCompactLayout,
|
||||||
toggleAgentList,
|
toggleAgentList,
|
||||||
toggleFileExplorer,
|
toggleFileExplorer,
|
||||||
toggleBothSidebars,
|
toggleBothSidebars: toggleDesktopSidebars,
|
||||||
toggleFocusMode,
|
toggleFocusMode,
|
||||||
cycleTheme,
|
cycleTheme,
|
||||||
});
|
});
|
||||||
@@ -490,7 +494,7 @@ function MobileGestureWrapper({
|
|||||||
chromeEnabled: boolean;
|
chromeEnabled: boolean;
|
||||||
}) {
|
}) {
|
||||||
const mobileView = usePanelStore((state) => state.mobileView);
|
const mobileView = usePanelStore((state) => state.mobileView);
|
||||||
const openAgentList = usePanelStore((state) => state.openAgentList);
|
const showMobileAgentList = usePanelStore((state) => state.showMobileAgentList);
|
||||||
const horizontalScroll = useHorizontalScrollOptional();
|
const horizontalScroll = useHorizontalScrollOptional();
|
||||||
const {
|
const {
|
||||||
translateX,
|
translateX,
|
||||||
@@ -507,8 +511,8 @@ function MobileGestureWrapper({
|
|||||||
|
|
||||||
const handleGestureOpen = useCallback(() => {
|
const handleGestureOpen = useCallback(() => {
|
||||||
gestureAnimatingRef.current = true;
|
gestureAnimatingRef.current = true;
|
||||||
openAgentList();
|
showMobileAgentList();
|
||||||
}, [openAgentList, gestureAnimatingRef]);
|
}, [showMobileAgentList, gestureAnimatingRef]);
|
||||||
|
|
||||||
const openGesture = useMemo(
|
const openGesture = useMemo(
|
||||||
() =>
|
() =>
|
||||||
|
|||||||
@@ -125,7 +125,8 @@ const AgentStreamViewComponent = forwardRef<AgentStreamViewHandle, AgentStreamVi
|
|||||||
const [expandedInlineToolCallIds, setExpandedInlineToolCallIds] = useState<Set<string>>(
|
const [expandedInlineToolCallIds, setExpandedInlineToolCallIds] = useState<Set<string>>(
|
||||||
new Set(),
|
new Set(),
|
||||||
);
|
);
|
||||||
const openFileExplorer = usePanelStore((state) => state.openFileExplorer);
|
const showMobileFileExplorer = usePanelStore((state) => state.showMobileFileExplorer);
|
||||||
|
const openDesktopFileExplorer = usePanelStore((state) => state.openDesktopFileExplorer);
|
||||||
const setExplorerTabForCheckout = usePanelStore((state) => state.setExplorerTabForCheckout);
|
const setExplorerTabForCheckout = usePanelStore((state) => state.setExplorerTabForCheckout);
|
||||||
|
|
||||||
// Get serverId (fallback to agent's serverId if not provided)
|
// Get serverId (fallback to agent's serverId if not provided)
|
||||||
@@ -205,15 +206,21 @@ const AgentStreamViewComponent = forwardRef<AgentStreamViewHandle, AgentStreamVi
|
|||||||
isGit: agent.projectPlacement?.checkout?.isGit ?? true,
|
isGit: agent.projectPlacement?.checkout?.isGit ?? true,
|
||||||
tab: "files",
|
tab: "files",
|
||||||
});
|
});
|
||||||
openFileExplorer();
|
if (isMobile) {
|
||||||
|
showMobileFileExplorer();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
openDesktopFileExplorer();
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
agent.cwd,
|
agent.cwd,
|
||||||
openFileExplorer,
|
isMobile,
|
||||||
|
openDesktopFileExplorer,
|
||||||
requestDirectoryListing,
|
requestDirectoryListing,
|
||||||
resolvedServerId,
|
resolvedServerId,
|
||||||
router,
|
router,
|
||||||
setExplorerTabForCheckout,
|
setExplorerTabForCheckout,
|
||||||
|
showMobileFileExplorer,
|
||||||
openWorkspaceFile,
|
openWorkspaceFile,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -54,7 +54,8 @@ export function ExplorerSidebar({
|
|||||||
const isMobile = useIsCompactFormFactor();
|
const isMobile = useIsCompactFormFactor();
|
||||||
const mobileView = usePanelStore((state) => state.mobileView);
|
const mobileView = usePanelStore((state) => state.mobileView);
|
||||||
const desktopFileExplorerOpen = usePanelStore((state) => state.desktop.fileExplorerOpen);
|
const desktopFileExplorerOpen = usePanelStore((state) => state.desktop.fileExplorerOpen);
|
||||||
const closeToAgent = usePanelStore((state) => state.closeToAgent);
|
const showMobileAgent = usePanelStore((state) => state.showMobileAgent);
|
||||||
|
const closeDesktopFileExplorer = usePanelStore((state) => state.closeDesktopFileExplorer);
|
||||||
const explorerTab = usePanelStore((state) => state.explorerTab);
|
const explorerTab = usePanelStore((state) => state.explorerTab);
|
||||||
const explorerWidth = usePanelStore((state) => state.explorerWidth);
|
const explorerWidth = usePanelStore((state) => state.explorerWidth);
|
||||||
const setExplorerTabForCheckout = usePanelStore((state) => state.setExplorerTabForCheckout);
|
const setExplorerTabForCheckout = usePanelStore((state) => state.setExplorerTabForCheckout);
|
||||||
@@ -107,15 +108,26 @@ export function ExplorerSidebar({
|
|||||||
mobileView,
|
mobileView,
|
||||||
desktopFileExplorerOpen,
|
desktopFileExplorerOpen,
|
||||||
});
|
});
|
||||||
closeToAgent();
|
if (isMobile) {
|
||||||
|
showMobileAgent();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
closeDesktopFileExplorer();
|
||||||
},
|
},
|
||||||
[closeToAgent, desktopFileExplorerOpen, isOpen, mobileView],
|
[
|
||||||
|
closeDesktopFileExplorer,
|
||||||
|
desktopFileExplorerOpen,
|
||||||
|
isMobile,
|
||||||
|
isOpen,
|
||||||
|
mobileView,
|
||||||
|
showMobileAgent,
|
||||||
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleCloseFromGesture = useCallback(() => {
|
const handleCloseFromGesture = useCallback(() => {
|
||||||
gestureAnimatingRef.current = true;
|
gestureAnimatingRef.current = true;
|
||||||
closeToAgent();
|
showMobileAgent();
|
||||||
}, [closeToAgent, gestureAnimatingRef]);
|
}, [gestureAnimatingRef, showMobileAgent]);
|
||||||
|
|
||||||
const enableSidebarCloseGesture = isMobile && isOpen;
|
const enableSidebarCloseGesture = isMobile && isOpen;
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,8 @@ export function SidebarMenuToggle({
|
|||||||
const isMobile = useIsCompactFormFactor();
|
const isMobile = useIsCompactFormFactor();
|
||||||
const mobileView = usePanelStore((state) => state.mobileView);
|
const mobileView = usePanelStore((state) => state.mobileView);
|
||||||
const desktopAgentListOpen = usePanelStore((state) => state.desktop.agentListOpen);
|
const desktopAgentListOpen = usePanelStore((state) => state.desktop.agentListOpen);
|
||||||
const toggleAgentList = usePanelStore((state) => state.toggleAgentList);
|
const toggleMobileAgentList = usePanelStore((state) => state.toggleMobileAgentList);
|
||||||
|
const toggleDesktopAgentList = usePanelStore((state) => state.toggleDesktopAgentList);
|
||||||
const toggleShortcutKeys = getShortcutOs() === "mac" ? ["mod", "B"] : ["mod", "."];
|
const toggleShortcutKeys = getShortcutOs() === "mac" ? ["mod", "B"] : ["mod", "."];
|
||||||
|
|
||||||
const isOpen = isMobile ? mobileView === "agent-list" : desktopAgentListOpen;
|
const isOpen = isMobile ? mobileView === "agent-list" : desktopAgentListOpen;
|
||||||
@@ -57,7 +58,7 @@ export function SidebarMenuToggle({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<HeaderToggleButton
|
<HeaderToggleButton
|
||||||
onPress={toggleAgentList}
|
onPress={isMobile ? toggleMobileAgentList : toggleDesktopAgentList}
|
||||||
tooltipLabel="Toggle sidebar"
|
tooltipLabel="Toggle sidebar"
|
||||||
tooltipKeys={toggleShortcutKeys}
|
tooltipKeys={toggleShortcutKeys}
|
||||||
tooltipSide={tooltipSide}
|
tooltipSide={tooltipSide}
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ export const LeftSidebar = memo(function LeftSidebar({
|
|||||||
const isCompactLayout = useIsCompactFormFactor();
|
const isCompactLayout = useIsCompactFormFactor();
|
||||||
const mobileView = usePanelStore((state) => state.mobileView);
|
const mobileView = usePanelStore((state) => state.mobileView);
|
||||||
const desktopAgentListOpen = usePanelStore((state) => state.desktop.agentListOpen);
|
const desktopAgentListOpen = usePanelStore((state) => state.desktop.agentListOpen);
|
||||||
const closeToAgent = usePanelStore((state) => state.closeToAgent);
|
const showMobileAgent = usePanelStore((state) => state.showMobileAgent);
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
const daemons = useHosts();
|
const daemons = useHosts();
|
||||||
const activeServerIdFromPath = useMemo(() => parseServerIdFromPathname(pathname), [pathname]);
|
const activeServerIdFromPath = useMemo(() => parseServerIdFromPathname(pathname), [pathname]);
|
||||||
@@ -208,18 +208,18 @@ export const LeftSidebar = memo(function LeftSidebar({
|
|||||||
const openProjectPicker = useOpenProjectPicker(activeServerId);
|
const openProjectPicker = useOpenProjectPicker(activeServerId);
|
||||||
|
|
||||||
const handleOpenProjectMobile = useCallback(() => {
|
const handleOpenProjectMobile = useCallback(() => {
|
||||||
closeToAgent();
|
showMobileAgent();
|
||||||
void openProjectPicker();
|
void openProjectPicker();
|
||||||
}, [closeToAgent, openProjectPicker]);
|
}, [showMobileAgent, openProjectPicker]);
|
||||||
|
|
||||||
const handleOpenProjectDesktop = useCallback(() => {
|
const handleOpenProjectDesktop = useCallback(() => {
|
||||||
void openProjectPicker();
|
void openProjectPicker();
|
||||||
}, [openProjectPicker]);
|
}, [openProjectPicker]);
|
||||||
|
|
||||||
const handleSettingsMobile = useCallback(() => {
|
const handleSettingsMobile = useCallback(() => {
|
||||||
closeToAgent();
|
showMobileAgent();
|
||||||
router.push(buildSettingsRoute());
|
router.push(buildSettingsRoute());
|
||||||
}, [closeToAgent]);
|
}, [showMobileAgent]);
|
||||||
|
|
||||||
const handleSettingsDesktop = useCallback(() => {
|
const handleSettingsDesktop = useCallback(() => {
|
||||||
router.push(buildSettingsRoute());
|
router.push(buildSettingsRoute());
|
||||||
@@ -272,7 +272,7 @@ export const LeftSidebar = memo(function LeftSidebar({
|
|||||||
insetsTop={insets.top}
|
insetsTop={insets.top}
|
||||||
insetsBottom={insets.bottom}
|
insetsBottom={insets.bottom}
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
closeToAgent={closeToAgent}
|
closeToAgent={showMobileAgent}
|
||||||
handleOpenProject={handleOpenProjectMobile}
|
handleOpenProject={handleOpenProjectMobile}
|
||||||
handleSettings={handleSettingsMobile}
|
handleSettings={handleSettingsMobile}
|
||||||
handleViewMoreNavigate={handleViewMoreNavigate}
|
handleViewMoreNavigate={handleViewMoreNavigate}
|
||||||
|
|||||||
@@ -89,8 +89,8 @@ export function TerminalPane({ serverId, cwd, terminalId, isPaneFocused }: Termi
|
|||||||
const xtermTheme = useMemo(() => toXtermTheme(theme.colors.terminal), [theme]);
|
const xtermTheme = useMemo(() => toXtermTheme(theme.colors.terminal), [theme]);
|
||||||
const isMobile = useIsCompactFormFactor();
|
const isMobile = useIsCompactFormFactor();
|
||||||
const mobileView = usePanelStore((state) => state.mobileView);
|
const mobileView = usePanelStore((state) => state.mobileView);
|
||||||
const openAgentList = usePanelStore((state) => state.openAgentList);
|
const showMobileAgentList = usePanelStore((state) => state.showMobileAgentList);
|
||||||
const openFileExplorer = usePanelStore((state) => state.openFileExplorer);
|
const showMobileFileExplorer = usePanelStore((state) => state.showMobileFileExplorer);
|
||||||
const swipeGesturesEnabled = isMobile && mobileView === "agent";
|
const swipeGesturesEnabled = isMobile && mobileView === "agent";
|
||||||
const { shift: keyboardShift, style: keyboardPaddingStyle } = useKeyboardShiftStyle({
|
const { shift: keyboardShift, style: keyboardPaddingStyle } = useKeyboardShiftStyle({
|
||||||
mode: "padding",
|
mode: "padding",
|
||||||
@@ -573,13 +573,13 @@ export function TerminalPane({ serverId, cwd, terminalId, isPaneFocused }: Termi
|
|||||||
if (!swipeGesturesEnabled) {
|
if (!swipeGesturesEnabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
openAgentList();
|
showMobileAgentList();
|
||||||
}}
|
}}
|
||||||
onSwipeLeft={() => {
|
onSwipeLeft={() => {
|
||||||
if (!swipeGesturesEnabled) {
|
if (!swipeGesturesEnabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
openFileExplorer();
|
showMobileFileExplorer();
|
||||||
}}
|
}}
|
||||||
onInput={handleTerminalData}
|
onInput={handleTerminalData}
|
||||||
onResize={handleTerminalResize}
|
onResize={handleTerminalResize}
|
||||||
|
|||||||
@@ -36,7 +36,11 @@ import {
|
|||||||
useHostRuntimeIsConnected,
|
useHostRuntimeIsConnected,
|
||||||
} from "@/runtime/host-runtime";
|
} from "@/runtime/host-runtime";
|
||||||
import { ExplorerSidebarAnimationProvider } from "@/contexts/explorer-sidebar-animation-context";
|
import { ExplorerSidebarAnimationProvider } from "@/contexts/explorer-sidebar-animation-context";
|
||||||
import { usePanelStore, type ExplorerCheckoutContext } from "@/stores/panel-store";
|
import { usePanelStore } from "@/stores/panel-store";
|
||||||
|
import {
|
||||||
|
setActiveExplorerCheckout,
|
||||||
|
type ExplorerCheckoutContext,
|
||||||
|
} from "@/stores/explorer-checkout-context";
|
||||||
import { MAX_CONTENT_WIDTH, useIsCompactFormFactor } from "@/constants/layout";
|
import { MAX_CONTENT_WIDTH, useIsCompactFormFactor } from "@/constants/layout";
|
||||||
import { WelcomeScreen } from "@/components/welcome-screen";
|
import { WelcomeScreen } from "@/components/welcome-screen";
|
||||||
import type { Agent } from "@/contexts/session-context";
|
import type { Agent } from "@/contexts/session-context";
|
||||||
@@ -237,10 +241,12 @@ function DraftAgentScreenContent({
|
|||||||
const isMobile = useIsCompactFormFactor();
|
const isMobile = useIsCompactFormFactor();
|
||||||
const mobileView = usePanelStore((state) => state.mobileView);
|
const mobileView = usePanelStore((state) => state.mobileView);
|
||||||
const desktopFileExplorerOpen = usePanelStore((state) => state.desktop.fileExplorerOpen);
|
const desktopFileExplorerOpen = usePanelStore((state) => state.desktop.fileExplorerOpen);
|
||||||
const toggleFileExplorer = usePanelStore((state) => state.toggleFileExplorer);
|
const showMobileFileExplorer = usePanelStore((state) => state.showMobileFileExplorer);
|
||||||
const openFileExplorer = usePanelStore((state) => state.openFileExplorer);
|
const toggleMobileFileExplorer = usePanelStore((state) => state.toggleMobileFileExplorer);
|
||||||
const closeFileExplorer = usePanelStore((state) => state.closeFileExplorer);
|
const showMobileAgent = usePanelStore((state) => state.showMobileAgent);
|
||||||
const setActiveExplorerCheckout = usePanelStore((state) => state.setActiveExplorerCheckout);
|
const openDesktopFileExplorer = usePanelStore((state) => state.openDesktopFileExplorer);
|
||||||
|
const toggleDesktopFileExplorer = usePanelStore((state) => state.toggleDesktopFileExplorer);
|
||||||
|
const closeDesktopFileExplorer = usePanelStore((state) => state.closeDesktopFileExplorer);
|
||||||
const activateExplorerTabForCheckout = usePanelStore(
|
const activateExplorerTabForCheckout = usePanelStore(
|
||||||
(state) => state.activateExplorerTabForCheckout,
|
(state) => state.activateExplorerTabForCheckout,
|
||||||
);
|
);
|
||||||
@@ -646,18 +652,39 @@ function DraftAgentScreenContent({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
activateExplorerTabForCheckout(draftExplorerCheckout);
|
activateExplorerTabForCheckout(draftExplorerCheckout);
|
||||||
openFileExplorer();
|
if (isMobile) {
|
||||||
}, [activateExplorerTabForCheckout, draftExplorerCheckout, openFileExplorer]);
|
showMobileFileExplorer();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
openDesktopFileExplorer();
|
||||||
|
}, [
|
||||||
|
activateExplorerTabForCheckout,
|
||||||
|
draftExplorerCheckout,
|
||||||
|
isMobile,
|
||||||
|
openDesktopFileExplorer,
|
||||||
|
showMobileFileExplorer,
|
||||||
|
]);
|
||||||
const handleToggleExplorer = useCallback(() => {
|
const handleToggleExplorer = useCallback(() => {
|
||||||
if (!canOpenExplorer) {
|
if (!canOpenExplorer) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isExplorerOpen) {
|
if (isExplorerOpen) {
|
||||||
toggleFileExplorer();
|
if (isMobile) {
|
||||||
|
toggleMobileFileExplorer();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
toggleDesktopFileExplorer();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
openExplorerForDraftCheckout();
|
openExplorerForDraftCheckout();
|
||||||
}, [canOpenExplorer, isExplorerOpen, openExplorerForDraftCheckout, toggleFileExplorer]);
|
}, [
|
||||||
|
canOpenExplorer,
|
||||||
|
isExplorerOpen,
|
||||||
|
isMobile,
|
||||||
|
openExplorerForDraftCheckout,
|
||||||
|
toggleDesktopFileExplorer,
|
||||||
|
toggleMobileFileExplorer,
|
||||||
|
]);
|
||||||
const explorerOpenGesture = useExplorerOpenGesture({
|
const explorerOpenGesture = useExplorerOpenGesture({
|
||||||
enabled: isMobile && mobileView === "agent" && canOpenExplorer,
|
enabled: isMobile && mobileView === "agent" && canOpenExplorer,
|
||||||
onOpen: openExplorerForDraftCheckout,
|
onOpen: openExplorerForDraftCheckout,
|
||||||
@@ -956,8 +983,19 @@ function DraftAgentScreenContent({
|
|||||||
if (!isFocused || canOpenExplorer || !isExplorerOpen) {
|
if (!isFocused || canOpenExplorer || !isExplorerOpen) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
closeFileExplorer();
|
if (isMobile) {
|
||||||
}, [canOpenExplorer, closeFileExplorer, isExplorerOpen, isFocused]);
|
showMobileAgent();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
closeDesktopFileExplorer();
|
||||||
|
}, [
|
||||||
|
canOpenExplorer,
|
||||||
|
closeDesktopFileExplorer,
|
||||||
|
isExplorerOpen,
|
||||||
|
isFocused,
|
||||||
|
isMobile,
|
||||||
|
showMobileAgent,
|
||||||
|
]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
setActiveExplorerCheckout(null);
|
setActiveExplorerCheckout(null);
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import { useIsLocalDaemon } from "@/hooks/use-is-local-daemon";
|
|||||||
import { PairDeviceModal } from "@/desktop/components/pair-device-modal";
|
import { PairDeviceModal } from "@/desktop/components/pair-device-modal";
|
||||||
|
|
||||||
export function OpenProjectScreen({ serverId }: { serverId: string }) {
|
export function OpenProjectScreen({ serverId }: { serverId: string }) {
|
||||||
const openAgentList = usePanelStore((s) => s.openAgentList);
|
const openDesktopAgentList = usePanelStore((s) => s.openDesktopAgentList);
|
||||||
const openProjectPicker = useOpenProjectPicker(serverId);
|
const openProjectPicker = useOpenProjectPicker(serverId);
|
||||||
const hasHydrated = useSessionStore((s) => s.sessions[serverId]?.hasHydratedWorkspaces ?? false);
|
const hasHydrated = useSessionStore((s) => s.sessions[serverId]?.hasHydratedWorkspaces ?? false);
|
||||||
const hasProjects = useHasWorkspaces(serverId);
|
const hasProjects = useHasWorkspaces(serverId);
|
||||||
@@ -31,9 +31,9 @@ export function OpenProjectScreen({ serverId }: { serverId: string }) {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isCompactLayout) {
|
if (!isCompactLayout) {
|
||||||
openAgentList();
|
openDesktopAgentList();
|
||||||
}
|
}
|
||||||
}, [isCompactLayout, openAgentList]);
|
}, [isCompactLayout, openDesktopAgentList]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
|
|||||||
@@ -48,7 +48,11 @@ import { WorkspaceScriptsButton } from "@/screens/workspace/workspace-scripts-bu
|
|||||||
import { ExplorerSidebarAnimationProvider } from "@/contexts/explorer-sidebar-animation-context";
|
import { ExplorerSidebarAnimationProvider } from "@/contexts/explorer-sidebar-animation-context";
|
||||||
import { useToast } from "@/contexts/toast-context";
|
import { useToast } from "@/contexts/toast-context";
|
||||||
import { useExplorerOpenGesture } from "@/hooks/use-explorer-open-gesture";
|
import { useExplorerOpenGesture } from "@/hooks/use-explorer-open-gesture";
|
||||||
import { usePanelStore, type ExplorerCheckoutContext } from "@/stores/panel-store";
|
import { usePanelStore } from "@/stores/panel-store";
|
||||||
|
import {
|
||||||
|
setActiveExplorerCheckout,
|
||||||
|
type ExplorerCheckoutContext,
|
||||||
|
} from "@/stores/explorer-checkout-context";
|
||||||
import { useSessionStore } from "@/stores/session-store";
|
import { useSessionStore } from "@/stores/session-store";
|
||||||
import {
|
import {
|
||||||
buildWorkspaceTabPersistenceKey,
|
buildWorkspaceTabPersistenceKey,
|
||||||
@@ -843,13 +847,14 @@ function WorkspaceScreenContent({
|
|||||||
|
|
||||||
const mobileView = usePanelStore((state) => state.mobileView);
|
const mobileView = usePanelStore((state) => state.mobileView);
|
||||||
const desktopFileExplorerOpen = usePanelStore((state) => state.desktop.fileExplorerOpen);
|
const desktopFileExplorerOpen = usePanelStore((state) => state.desktop.fileExplorerOpen);
|
||||||
const toggleFileExplorer = usePanelStore((state) => state.toggleFileExplorer);
|
const showMobileFileExplorer = usePanelStore((state) => state.showMobileFileExplorer);
|
||||||
const openFileExplorer = usePanelStore((state) => state.openFileExplorer);
|
const toggleMobileFileExplorer = usePanelStore((state) => state.toggleMobileFileExplorer);
|
||||||
|
const openDesktopFileExplorer = usePanelStore((state) => state.openDesktopFileExplorer);
|
||||||
|
const toggleDesktopFileExplorer = usePanelStore((state) => state.toggleDesktopFileExplorer);
|
||||||
const activateExplorerTabForCheckout = usePanelStore(
|
const activateExplorerTabForCheckout = usePanelStore(
|
||||||
(state) => state.activateExplorerTabForCheckout,
|
(state) => state.activateExplorerTabForCheckout,
|
||||||
);
|
);
|
||||||
const closeToAgent = usePanelStore((state) => state.closeToAgent);
|
const showMobileAgent = usePanelStore((state) => state.showMobileAgent);
|
||||||
const setActiveExplorerCheckout = usePanelStore((state) => state.setActiveExplorerCheckout);
|
|
||||||
|
|
||||||
const isExplorerOpen = isMobile ? mobileView === "file-explorer" : desktopFileExplorerOpen;
|
const isExplorerOpen = isMobile ? mobileView === "file-explorer" : desktopFileExplorerOpen;
|
||||||
|
|
||||||
@@ -876,16 +881,36 @@ function WorkspaceScreenContent({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
activateExplorerTabForCheckout(activeExplorerCheckout);
|
activateExplorerTabForCheckout(activeExplorerCheckout);
|
||||||
openFileExplorer();
|
if (isMobile) {
|
||||||
}, [activateExplorerTabForCheckout, activeExplorerCheckout, openFileExplorer]);
|
showMobileFileExplorer();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
openDesktopFileExplorer();
|
||||||
|
}, [
|
||||||
|
activateExplorerTabForCheckout,
|
||||||
|
activeExplorerCheckout,
|
||||||
|
isMobile,
|
||||||
|
openDesktopFileExplorer,
|
||||||
|
showMobileFileExplorer,
|
||||||
|
]);
|
||||||
|
|
||||||
const handleToggleExplorer = useCallback(() => {
|
const handleToggleExplorer = useCallback(() => {
|
||||||
if (isExplorerOpen) {
|
if (isExplorerOpen) {
|
||||||
toggleFileExplorer();
|
if (isMobile) {
|
||||||
|
toggleMobileFileExplorer();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
toggleDesktopFileExplorer();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
openExplorerForWorkspace();
|
openExplorerForWorkspace();
|
||||||
}, [isExplorerOpen, openExplorerForWorkspace, toggleFileExplorer]);
|
}, [
|
||||||
|
isExplorerOpen,
|
||||||
|
isMobile,
|
||||||
|
openExplorerForWorkspace,
|
||||||
|
toggleDesktopFileExplorer,
|
||||||
|
toggleMobileFileExplorer,
|
||||||
|
]);
|
||||||
|
|
||||||
const explorerOpenGesture = useExplorerOpenGesture({
|
const explorerOpenGesture = useExplorerOpenGesture({
|
||||||
enabled: isMobile && mobileView === "agent",
|
enabled: isMobile && mobileView === "agent",
|
||||||
@@ -899,14 +924,14 @@ function WorkspaceScreenContent({
|
|||||||
|
|
||||||
const handler = BackHandler.addEventListener("hardwareBackPress", () => {
|
const handler = BackHandler.addEventListener("hardwareBackPress", () => {
|
||||||
if (isExplorerOpen) {
|
if (isExplorerOpen) {
|
||||||
closeToAgent();
|
showMobileAgent();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
return () => handler.remove();
|
return () => handler.remove();
|
||||||
}, [closeToAgent, isExplorerOpen, isRouteFocused]);
|
}, [isExplorerOpen, isRouteFocused, showMobileAgent]);
|
||||||
|
|
||||||
const persistenceKey = useMemo(
|
const persistenceKey = useMemo(
|
||||||
() =>
|
() =>
|
||||||
@@ -1190,7 +1215,7 @@ function WorkspaceScreenContent({
|
|||||||
const handleOpenFileFromExplorer = useCallback(
|
const handleOpenFileFromExplorer = useCallback(
|
||||||
function handleOpenFileFromExplorer(filePath: string) {
|
function handleOpenFileFromExplorer(filePath: string) {
|
||||||
if (isMobile) {
|
if (isMobile) {
|
||||||
closeToAgent();
|
showMobileAgent();
|
||||||
}
|
}
|
||||||
if (!persistenceKey) {
|
if (!persistenceKey) {
|
||||||
return;
|
return;
|
||||||
@@ -1200,7 +1225,7 @@ function WorkspaceScreenContent({
|
|||||||
navigateToTabId(tabId);
|
navigateToTabId(tabId);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[closeToAgent, isMobile, navigateToTabId, openWorkspaceTabFocused, persistenceKey],
|
[isMobile, navigateToTabId, openWorkspaceTabFocused, persistenceKey, showMobileAgent],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleOpenFileFromChat = useCallback(
|
const handleOpenFileFromChat = useCallback(
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
export interface ExplorerCheckoutContext {
|
||||||
|
serverId: string;
|
||||||
|
cwd: string;
|
||||||
|
isGit: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
let activeExplorerCheckout: ExplorerCheckoutContext | null = null;
|
||||||
|
|
||||||
|
export function getActiveExplorerCheckout(): ExplorerCheckoutContext | null {
|
||||||
|
return activeExplorerCheckout;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setActiveExplorerCheckout(checkout: ExplorerCheckoutContext | null) {
|
||||||
|
if (
|
||||||
|
activeExplorerCheckout?.serverId === checkout?.serverId &&
|
||||||
|
activeExplorerCheckout?.cwd === checkout?.cwd &&
|
||||||
|
activeExplorerCheckout?.isGit === checkout?.isGit
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
activeExplorerCheckout = checkout;
|
||||||
|
}
|
||||||
@@ -8,8 +8,13 @@ import {
|
|||||||
resolveExplorerTabForCheckout,
|
resolveExplorerTabForCheckout,
|
||||||
type ExplorerTab,
|
type ExplorerTab,
|
||||||
} from "./explorer-tab-memory";
|
} from "./explorer-tab-memory";
|
||||||
|
import {
|
||||||
|
getActiveExplorerCheckout,
|
||||||
|
type ExplorerCheckoutContext,
|
||||||
|
} from "./explorer-checkout-context";
|
||||||
import { isWeb } from "@/constants/platform";
|
import { isWeb } from "@/constants/platform";
|
||||||
export type { ExplorerTab } from "./explorer-tab-memory";
|
export type { ExplorerTab } from "./explorer-tab-memory";
|
||||||
|
export type { ExplorerCheckoutContext } from "./explorer-checkout-context";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mobile panel state machine.
|
* Mobile panel state machine.
|
||||||
@@ -37,12 +42,6 @@ interface DesktopSidebarState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type SortOption = "name" | "modified" | "size";
|
export type SortOption = "name" | "modified" | "size";
|
||||||
export interface ExplorerCheckoutContext {
|
|
||||||
serverId: string;
|
|
||||||
cwd: string;
|
|
||||||
isGit: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const DEFAULT_SIDEBAR_WIDTH = 320;
|
export const DEFAULT_SIDEBAR_WIDTH = 320;
|
||||||
export const MIN_SIDEBAR_WIDTH = 200;
|
export const MIN_SIDEBAR_WIDTH = 200;
|
||||||
export const MAX_SIDEBAR_WIDTH = 600;
|
export const MAX_SIDEBAR_WIDTH = 600;
|
||||||
@@ -68,21 +67,25 @@ interface PanelState {
|
|||||||
explorerTabByCheckout: Record<string, ExplorerTab>;
|
explorerTabByCheckout: Record<string, ExplorerTab>;
|
||||||
expandedPathsByWorkspace: Record<string, string[]>;
|
expandedPathsByWorkspace: Record<string, string[]>;
|
||||||
diffExpandedPathsByWorkspace: Record<string, string[]>;
|
diffExpandedPathsByWorkspace: Record<string, string[]>;
|
||||||
activeExplorerCheckout: ExplorerCheckoutContext | null;
|
|
||||||
sidebarWidth: number;
|
sidebarWidth: number;
|
||||||
explorerWidth: number;
|
explorerWidth: number;
|
||||||
explorerSortOption: SortOption;
|
explorerSortOption: SortOption;
|
||||||
explorerFilesSplitRatio: number;
|
explorerFilesSplitRatio: number;
|
||||||
|
|
||||||
// Actions
|
// Actions
|
||||||
openAgentList: () => void;
|
|
||||||
openFileExplorer: () => void;
|
|
||||||
closeFileExplorer: () => void;
|
|
||||||
closeToAgent: () => void;
|
|
||||||
toggleAgentList: () => void;
|
|
||||||
toggleFileExplorer: () => void;
|
|
||||||
toggleBothSidebars: () => void;
|
|
||||||
toggleFocusMode: () => void;
|
toggleFocusMode: () => void;
|
||||||
|
showMobileAgent: () => void;
|
||||||
|
showMobileAgentList: () => void;
|
||||||
|
showMobileFileExplorer: () => void;
|
||||||
|
toggleMobileAgentList: () => void;
|
||||||
|
toggleMobileFileExplorer: () => void;
|
||||||
|
openDesktopAgentList: () => void;
|
||||||
|
closeDesktopAgentList: () => void;
|
||||||
|
toggleDesktopAgentList: () => void;
|
||||||
|
openDesktopFileExplorer: () => void;
|
||||||
|
closeDesktopFileExplorer: () => void;
|
||||||
|
toggleDesktopFileExplorer: () => void;
|
||||||
|
toggleDesktopSidebars: () => void;
|
||||||
|
|
||||||
// File explorer settings actions
|
// File explorer settings actions
|
||||||
setExplorerTab: (tab: ExplorerTab) => void;
|
setExplorerTab: (tab: ExplorerTab) => void;
|
||||||
@@ -90,7 +93,6 @@ interface PanelState {
|
|||||||
setExpandedPathsForWorkspace: (workspaceKey: string, paths: string[]) => void;
|
setExpandedPathsForWorkspace: (workspaceKey: string, paths: string[]) => void;
|
||||||
setDiffExpandedPathsForWorkspace: (workspaceKey: string, paths: string[]) => void;
|
setDiffExpandedPathsForWorkspace: (workspaceKey: string, paths: string[]) => void;
|
||||||
activateExplorerTabForCheckout: (checkout: ExplorerCheckoutContext) => void;
|
activateExplorerTabForCheckout: (checkout: ExplorerCheckoutContext) => void;
|
||||||
setActiveExplorerCheckout: (checkout: ExplorerCheckoutContext | null) => void;
|
|
||||||
setSidebarWidth: (width: number) => void;
|
setSidebarWidth: (width: number) => void;
|
||||||
setExplorerWidth: (width: number) => void;
|
setExplorerWidth: (width: number) => void;
|
||||||
setExplorerSortOption: (option: SortOption) => void;
|
setExplorerSortOption: (option: SortOption) => void;
|
||||||
@@ -116,14 +118,17 @@ function clampExplorerFilesSplitRatio(ratio: number): number {
|
|||||||
return clampNumber(ratio, MIN_EXPLORER_FILES_SPLIT_RATIO, MAX_EXPLORER_FILES_SPLIT_RATIO);
|
return clampNumber(ratio, MIN_EXPLORER_FILES_SPLIT_RATIO, MAX_EXPLORER_FILES_SPLIT_RATIO);
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveExplorerTabFromActiveCheckout(state: PanelState): ExplorerTab | null {
|
function resolveExplorerTabFromCheckout(
|
||||||
if (!state.activeExplorerCheckout) {
|
state: PanelState,
|
||||||
|
checkout: ExplorerCheckoutContext | null,
|
||||||
|
): ExplorerTab | null {
|
||||||
|
if (!checkout) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return resolveExplorerTabForCheckout({
|
return resolveExplorerTabForCheckout({
|
||||||
serverId: state.activeExplorerCheckout.serverId,
|
serverId: checkout.serverId,
|
||||||
cwd: state.activeExplorerCheckout.cwd,
|
cwd: checkout.cwd,
|
||||||
isGit: state.activeExplorerCheckout.isGit,
|
isGit: checkout.isGit,
|
||||||
explorerTabByCheckout: state.explorerTabByCheckout,
|
explorerTabByCheckout: state.explorerTabByCheckout,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -148,103 +153,118 @@ export const usePanelStore = create<PanelState>()(
|
|||||||
explorerTabByCheckout: {},
|
explorerTabByCheckout: {},
|
||||||
expandedPathsByWorkspace: {},
|
expandedPathsByWorkspace: {},
|
||||||
diffExpandedPathsByWorkspace: {},
|
diffExpandedPathsByWorkspace: {},
|
||||||
activeExplorerCheckout: null,
|
|
||||||
sidebarWidth: DEFAULT_SIDEBAR_WIDTH,
|
sidebarWidth: DEFAULT_SIDEBAR_WIDTH,
|
||||||
explorerWidth: DEFAULT_EXPLORER_SIDEBAR_WIDTH,
|
explorerWidth: DEFAULT_EXPLORER_SIDEBAR_WIDTH,
|
||||||
explorerSortOption: "name",
|
explorerSortOption: "name",
|
||||||
explorerFilesSplitRatio: DEFAULT_EXPLORER_FILES_SPLIT_RATIO,
|
explorerFilesSplitRatio: DEFAULT_EXPLORER_FILES_SPLIT_RATIO,
|
||||||
|
|
||||||
openAgentList: () =>
|
|
||||||
set((state) => ({
|
|
||||||
mobileView: "agent-list" as const,
|
|
||||||
desktop: { ...state.desktop, agentListOpen: true },
|
|
||||||
})),
|
|
||||||
|
|
||||||
openFileExplorer: () =>
|
|
||||||
set((state) => {
|
|
||||||
const resolvedTab = resolveExplorerTabFromActiveCheckout(state);
|
|
||||||
return {
|
|
||||||
mobileView: "file-explorer" as MobilePanelView,
|
|
||||||
desktop: { ...state.desktop, fileExplorerOpen: true },
|
|
||||||
...(resolvedTab ? { explorerTab: resolvedTab } : {}),
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
closeFileExplorer: () =>
|
|
||||||
set((state) => ({
|
|
||||||
mobileView: state.mobileView === "file-explorer" ? ("agent" as const) : state.mobileView,
|
|
||||||
desktop: {
|
|
||||||
...state.desktop,
|
|
||||||
fileExplorerOpen: false,
|
|
||||||
},
|
|
||||||
})),
|
|
||||||
|
|
||||||
closeToAgent: () =>
|
|
||||||
set((state) => ({
|
|
||||||
mobileView: "agent" as const,
|
|
||||||
// On desktop, closing depends on which panel triggered it
|
|
||||||
// This is called when closing via gesture/backdrop, so we close the currently active mobile panel
|
|
||||||
desktop: {
|
|
||||||
...state.desktop,
|
|
||||||
agentListOpen: state.mobileView === "agent-list" ? false : state.desktop.agentListOpen,
|
|
||||||
fileExplorerOpen:
|
|
||||||
state.mobileView === "file-explorer" ? false : state.desktop.fileExplorerOpen,
|
|
||||||
},
|
|
||||||
})),
|
|
||||||
|
|
||||||
toggleAgentList: () =>
|
|
||||||
set((state) => ({
|
|
||||||
// Mobile: toggle between agent and agent-list
|
|
||||||
mobileView: (state.mobileView === "agent-list"
|
|
||||||
? "agent"
|
|
||||||
: "agent-list") as MobilePanelView,
|
|
||||||
desktop: {
|
|
||||||
...state.desktop,
|
|
||||||
agentListOpen: !state.desktop.agentListOpen,
|
|
||||||
},
|
|
||||||
})),
|
|
||||||
|
|
||||||
toggleFileExplorer: () =>
|
|
||||||
set((state) => {
|
|
||||||
// Mobile: toggle between agent and file-explorer
|
|
||||||
const willOpenMobile = state.mobileView !== "file-explorer";
|
|
||||||
const willOpenDesktop = !state.desktop.fileExplorerOpen;
|
|
||||||
const nextMobileView: MobilePanelView = willOpenMobile ? "file-explorer" : "agent";
|
|
||||||
const nextDesktop = {
|
|
||||||
...state.desktop,
|
|
||||||
fileExplorerOpen: willOpenDesktop,
|
|
||||||
};
|
|
||||||
const nextState: Pick<PanelState, "mobileView" | "desktop"> &
|
|
||||||
Partial<Pick<PanelState, "explorerTab">> = {
|
|
||||||
mobileView: nextMobileView,
|
|
||||||
desktop: nextDesktop,
|
|
||||||
};
|
|
||||||
if (willOpenMobile || willOpenDesktop) {
|
|
||||||
const resolvedTab = resolveExplorerTabFromActiveCheckout(state);
|
|
||||||
if (resolvedTab) {
|
|
||||||
nextState.explorerTab = resolvedTab;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nextState;
|
|
||||||
}),
|
|
||||||
|
|
||||||
toggleFocusMode: () =>
|
toggleFocusMode: () =>
|
||||||
set((state) => ({
|
set((state) => ({
|
||||||
desktop: { ...state.desktop, focusModeEnabled: !state.desktop.focusModeEnabled },
|
desktop: { ...state.desktop, focusModeEnabled: !state.desktop.focusModeEnabled },
|
||||||
})),
|
})),
|
||||||
|
|
||||||
toggleBothSidebars: () =>
|
showMobileAgent: () =>
|
||||||
|
set((state) => {
|
||||||
|
if (state.mobileView === "agent") {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
return { mobileView: "agent" as const };
|
||||||
|
}),
|
||||||
|
|
||||||
|
showMobileAgentList: () =>
|
||||||
|
set((state) => {
|
||||||
|
if (state.mobileView === "agent-list") {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
return { mobileView: "agent-list" as const };
|
||||||
|
}),
|
||||||
|
|
||||||
|
showMobileFileExplorer: () =>
|
||||||
|
set((state) => {
|
||||||
|
const resolvedTab = resolveExplorerTabFromCheckout(state, getActiveExplorerCheckout());
|
||||||
|
return {
|
||||||
|
mobileView: "file-explorer" as const,
|
||||||
|
...(resolvedTab ? { explorerTab: resolvedTab } : {}),
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
|
||||||
|
toggleMobileAgentList: () =>
|
||||||
|
set((state) => ({
|
||||||
|
mobileView: state.mobileView === "agent-list" ? "agent" : "agent-list",
|
||||||
|
})),
|
||||||
|
|
||||||
|
toggleMobileFileExplorer: () =>
|
||||||
|
set((state) => {
|
||||||
|
if (state.mobileView === "file-explorer") {
|
||||||
|
return { mobileView: "agent" as const };
|
||||||
|
}
|
||||||
|
const resolvedTab = resolveExplorerTabFromCheckout(state, getActiveExplorerCheckout());
|
||||||
|
return {
|
||||||
|
mobileView: "file-explorer" as const,
|
||||||
|
...(resolvedTab ? { explorerTab: resolvedTab } : {}),
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
|
||||||
|
openDesktopAgentList: () =>
|
||||||
|
set((state) => {
|
||||||
|
if (state.desktop.agentListOpen) {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
return { desktop: { ...state.desktop, agentListOpen: true } };
|
||||||
|
}),
|
||||||
|
|
||||||
|
closeDesktopAgentList: () =>
|
||||||
|
set((state) => {
|
||||||
|
if (!state.desktop.agentListOpen) {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
return { desktop: { ...state.desktop, agentListOpen: false } };
|
||||||
|
}),
|
||||||
|
|
||||||
|
toggleDesktopAgentList: () =>
|
||||||
|
set((state) => ({
|
||||||
|
desktop: { ...state.desktop, agentListOpen: !state.desktop.agentListOpen },
|
||||||
|
})),
|
||||||
|
|
||||||
|
openDesktopFileExplorer: () =>
|
||||||
|
set((state) => {
|
||||||
|
const resolvedTab = resolveExplorerTabFromCheckout(state, getActiveExplorerCheckout());
|
||||||
|
return {
|
||||||
|
desktop: { ...state.desktop, fileExplorerOpen: true },
|
||||||
|
...(resolvedTab ? { explorerTab: resolvedTab } : {}),
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
|
||||||
|
closeDesktopFileExplorer: () =>
|
||||||
|
set((state) => {
|
||||||
|
if (!state.desktop.fileExplorerOpen) {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
return { desktop: { ...state.desktop, fileExplorerOpen: false } };
|
||||||
|
}),
|
||||||
|
|
||||||
|
toggleDesktopFileExplorer: () =>
|
||||||
|
set((state) => {
|
||||||
|
const willOpen = !state.desktop.fileExplorerOpen;
|
||||||
|
const resolvedTab = willOpen
|
||||||
|
? resolveExplorerTabFromCheckout(state, getActiveExplorerCheckout())
|
||||||
|
: null;
|
||||||
|
return {
|
||||||
|
desktop: { ...state.desktop, fileExplorerOpen: willOpen },
|
||||||
|
...(resolvedTab ? { explorerTab: resolvedTab } : {}),
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
|
||||||
|
toggleDesktopSidebars: () =>
|
||||||
set((state) => {
|
set((state) => {
|
||||||
// If either sidebar is open, close both. Otherwise, open both.
|
|
||||||
const anyOpen = state.desktop.agentListOpen || state.desktop.fileExplorerOpen;
|
const anyOpen = state.desktop.agentListOpen || state.desktop.fileExplorerOpen;
|
||||||
if (anyOpen) {
|
if (anyOpen) {
|
||||||
return {
|
return {
|
||||||
mobileView: "agent" as MobilePanelView,
|
|
||||||
desktop: { ...state.desktop, agentListOpen: false, fileExplorerOpen: false },
|
desktop: { ...state.desktop, agentListOpen: false, fileExplorerOpen: false },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const resolvedTab = resolveExplorerTabFromActiveCheckout(state);
|
const resolvedTab = resolveExplorerTabFromCheckout(state, getActiveExplorerCheckout());
|
||||||
return {
|
return {
|
||||||
mobileView: "agent" as MobilePanelView,
|
|
||||||
desktop: { ...state.desktop, agentListOpen: true, fileExplorerOpen: true },
|
desktop: { ...state.desktop, agentListOpen: true, fileExplorerOpen: true },
|
||||||
...(resolvedTab ? { explorerTab: resolvedTab } : {}),
|
...(resolvedTab ? { explorerTab: resolvedTab } : {}),
|
||||||
};
|
};
|
||||||
@@ -280,7 +300,6 @@ export const usePanelStore = create<PanelState>()(
|
|||||||
})),
|
})),
|
||||||
activateExplorerTabForCheckout: (checkout) =>
|
activateExplorerTabForCheckout: (checkout) =>
|
||||||
set((state) => ({
|
set((state) => ({
|
||||||
activeExplorerCheckout: checkout,
|
|
||||||
explorerTab: resolveExplorerTabForCheckout({
|
explorerTab: resolveExplorerTabForCheckout({
|
||||||
serverId: checkout.serverId,
|
serverId: checkout.serverId,
|
||||||
cwd: checkout.cwd,
|
cwd: checkout.cwd,
|
||||||
@@ -288,18 +307,6 @@ export const usePanelStore = create<PanelState>()(
|
|||||||
explorerTabByCheckout: state.explorerTabByCheckout,
|
explorerTabByCheckout: state.explorerTabByCheckout,
|
||||||
}),
|
}),
|
||||||
})),
|
})),
|
||||||
setActiveExplorerCheckout: (checkout) =>
|
|
||||||
set((state) => {
|
|
||||||
const current = state.activeExplorerCheckout;
|
|
||||||
if (
|
|
||||||
current?.serverId === checkout?.serverId &&
|
|
||||||
current?.cwd === checkout?.cwd &&
|
|
||||||
current?.isGit === checkout?.isGit
|
|
||||||
) {
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
return { activeExplorerCheckout: checkout };
|
|
||||||
}),
|
|
||||||
setSidebarWidth: (width) => set({ sidebarWidth: clampSidebarWidth(width) }),
|
setSidebarWidth: (width) => set({ sidebarWidth: clampSidebarWidth(width) }),
|
||||||
setExplorerWidth: (width) => set({ explorerWidth: clampWidth(width) }),
|
setExplorerWidth: (width) => set({ explorerWidth: clampWidth(width) }),
|
||||||
setExplorerSortOption: (option) => set({ explorerSortOption: option }),
|
setExplorerSortOption: (option) => set({ explorerSortOption: option }),
|
||||||
@@ -400,8 +407,6 @@ export const usePanelStore = create<PanelState>()(
|
|||||||
state.diffExpandedPathsByWorkspace = {};
|
state.diffExpandedPathsByWorkspace = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
state.activeExplorerCheckout = null;
|
|
||||||
|
|
||||||
return state as PanelState;
|
return state as PanelState;
|
||||||
},
|
},
|
||||||
partialize: (state) => ({
|
partialize: (state) => ({
|
||||||
@@ -435,12 +440,12 @@ export function usePanelState(isMobile: boolean) {
|
|||||||
return {
|
return {
|
||||||
isAgentListOpen: store.mobileView === "agent-list",
|
isAgentListOpen: store.mobileView === "agent-list",
|
||||||
isFileExplorerOpen: store.mobileView === "file-explorer",
|
isFileExplorerOpen: store.mobileView === "file-explorer",
|
||||||
openAgentList: store.openAgentList,
|
openAgentList: store.showMobileAgentList,
|
||||||
openFileExplorer: store.openFileExplorer,
|
openFileExplorer: store.showMobileFileExplorer,
|
||||||
closeAgentList: store.closeToAgent,
|
closeAgentList: store.showMobileAgent,
|
||||||
closeFileExplorer: store.closeToAgent,
|
closeFileExplorer: store.showMobileAgent,
|
||||||
toggleAgentList: store.toggleAgentList,
|
toggleAgentList: store.toggleMobileAgentList,
|
||||||
toggleFileExplorer: store.toggleFileExplorer,
|
toggleFileExplorer: store.toggleMobileFileExplorer,
|
||||||
// Explorer settings
|
// Explorer settings
|
||||||
explorerTab: store.explorerTab,
|
explorerTab: store.explorerTab,
|
||||||
explorerTabByCheckout: store.explorerTabByCheckout,
|
explorerTabByCheckout: store.explorerTabByCheckout,
|
||||||
@@ -450,7 +455,6 @@ export function usePanelState(isMobile: boolean) {
|
|||||||
setExplorerTab: store.setExplorerTab,
|
setExplorerTab: store.setExplorerTab,
|
||||||
setExplorerTabForCheckout: store.setExplorerTabForCheckout,
|
setExplorerTabForCheckout: store.setExplorerTabForCheckout,
|
||||||
activateExplorerTabForCheckout: store.activateExplorerTabForCheckout,
|
activateExplorerTabForCheckout: store.activateExplorerTabForCheckout,
|
||||||
setActiveExplorerCheckout: store.setActiveExplorerCheckout,
|
|
||||||
setExplorerWidth: store.setExplorerWidth,
|
setExplorerWidth: store.setExplorerWidth,
|
||||||
setExplorerSortOption: store.setExplorerSortOption,
|
setExplorerSortOption: store.setExplorerSortOption,
|
||||||
setExplorerFilesSplitRatio: store.setExplorerFilesSplitRatio,
|
setExplorerFilesSplitRatio: store.setExplorerFilesSplitRatio,
|
||||||
@@ -461,18 +465,12 @@ export function usePanelState(isMobile: boolean) {
|
|||||||
return {
|
return {
|
||||||
isAgentListOpen: store.desktop.agentListOpen,
|
isAgentListOpen: store.desktop.agentListOpen,
|
||||||
isFileExplorerOpen: store.desktop.fileExplorerOpen,
|
isFileExplorerOpen: store.desktop.fileExplorerOpen,
|
||||||
openAgentList: store.openAgentList,
|
openAgentList: store.openDesktopAgentList,
|
||||||
openFileExplorer: store.openFileExplorer,
|
openFileExplorer: store.openDesktopFileExplorer,
|
||||||
closeAgentList: () =>
|
closeAgentList: store.closeDesktopAgentList,
|
||||||
usePanelStore.setState((state) => ({
|
closeFileExplorer: store.closeDesktopFileExplorer,
|
||||||
desktop: { ...state.desktop, agentListOpen: false },
|
toggleAgentList: store.toggleDesktopAgentList,
|
||||||
})),
|
toggleFileExplorer: store.toggleDesktopFileExplorer,
|
||||||
closeFileExplorer: () =>
|
|
||||||
usePanelStore.setState((state) => ({
|
|
||||||
desktop: { ...state.desktop, fileExplorerOpen: false },
|
|
||||||
})),
|
|
||||||
toggleAgentList: store.toggleAgentList,
|
|
||||||
toggleFileExplorer: store.toggleFileExplorer,
|
|
||||||
// Explorer settings
|
// Explorer settings
|
||||||
explorerTab: store.explorerTab,
|
explorerTab: store.explorerTab,
|
||||||
explorerTabByCheckout: store.explorerTabByCheckout,
|
explorerTabByCheckout: store.explorerTabByCheckout,
|
||||||
@@ -482,7 +480,6 @@ export function usePanelState(isMobile: boolean) {
|
|||||||
setExplorerTab: store.setExplorerTab,
|
setExplorerTab: store.setExplorerTab,
|
||||||
setExplorerTabForCheckout: store.setExplorerTabForCheckout,
|
setExplorerTabForCheckout: store.setExplorerTabForCheckout,
|
||||||
activateExplorerTabForCheckout: store.activateExplorerTabForCheckout,
|
activateExplorerTabForCheckout: store.activateExplorerTabForCheckout,
|
||||||
setActiveExplorerCheckout: store.setActiveExplorerCheckout,
|
|
||||||
setExplorerWidth: store.setExplorerWidth,
|
setExplorerWidth: store.setExplorerWidth,
|
||||||
setExplorerSortOption: store.setExplorerSortOption,
|
setExplorerSortOption: store.setExplorerSortOption,
|
||||||
setExplorerFilesSplitRatio: store.setExplorerFilesSplitRatio,
|
setExplorerFilesSplitRatio: store.setExplorerFilesSplitRatio,
|
||||||
|
|||||||
Reference in New Issue
Block a user