Make workspace tab switching faster (#1251)
* Avoid workspace shell renders when toggling sidebar * Avoid rerendering inactive workspace screens * Avoid rerendering unchanged sidebar rows * Keep sidebar selection state in the list * Speed up workspace tab switching
This commit is contained in:
@@ -62,6 +62,7 @@ import {
|
||||
} from "@/screens/workspace/workspace-tab-menu";
|
||||
import type { WorkspaceTabDescriptor } from "@/screens/workspace/workspace-tabs-types";
|
||||
import type { Theme } from "@/styles/theme";
|
||||
import { RenderProfile } from "@/utils/render-profiler";
|
||||
|
||||
const DROPDOWN_WIDTH = 220;
|
||||
const LOADING_TAB_LABEL_SKELETON_WIDTH = 80;
|
||||
@@ -148,7 +149,6 @@ interface WorkspaceDesktopTabsRowProps {
|
||||
tabs: WorkspaceDesktopTabRowItem[];
|
||||
normalizedServerId: string;
|
||||
normalizedWorkspaceId: string;
|
||||
setHoveredTabKey: Dispatch<SetStateAction<string | null>>;
|
||||
setHoveredCloseTabKey: Dispatch<SetStateAction<string | null>>;
|
||||
onNavigateTab: (tabId: string) => void;
|
||||
onCloseTab: (tabId: string) => Promise<void> | void;
|
||||
@@ -255,7 +255,6 @@ function TabChip({
|
||||
presentation,
|
||||
tooltipLabel,
|
||||
resolvedTab,
|
||||
setHoveredTabKey,
|
||||
setHoveredCloseTabKey,
|
||||
onNavigateTab,
|
||||
onCloseTab,
|
||||
@@ -273,7 +272,6 @@ function TabChip({
|
||||
presentation: WorkspaceTabPresentation;
|
||||
tooltipLabel: string;
|
||||
resolvedTab: WorkspaceDesktopTabActions;
|
||||
setHoveredTabKey: Dispatch<SetStateAction<string | null>>;
|
||||
setHoveredCloseTabKey: Dispatch<SetStateAction<string | null>>;
|
||||
onNavigateTab: (tabId: string) => void;
|
||||
onCloseTab: (tabId: string) => Promise<void> | void;
|
||||
@@ -311,13 +309,11 @@ function TabChip({
|
||||
|
||||
const handleTabHoverIn = useCallback(() => {
|
||||
setHovered(true);
|
||||
setHoveredTabKey(tab.key);
|
||||
}, [setHoveredTabKey, tab.key]);
|
||||
}, []);
|
||||
|
||||
const handleTabHoverOut = useCallback(() => {
|
||||
setHovered(false);
|
||||
setHoveredTabKey((current) => (current === tab.key ? null : current));
|
||||
}, [setHoveredTabKey, tab.key]);
|
||||
}, []);
|
||||
|
||||
const handleNavigateTab = useCallback(() => {
|
||||
onNavigateTab(tab.tabId);
|
||||
@@ -328,14 +324,12 @@ function TabChip({
|
||||
}, []);
|
||||
|
||||
const handleCloseButtonHoverIn = useCallback(() => {
|
||||
setHoveredTabKey(tab.key);
|
||||
setHoveredCloseTabKey(tab.key);
|
||||
}, [setHoveredTabKey, setHoveredCloseTabKey, tab.key]);
|
||||
}, [setHoveredCloseTabKey, tab.key]);
|
||||
|
||||
const handleCloseButtonHoverOut = useCallback(() => {
|
||||
setHoveredTabKey((current) => (current === tab.key ? null : current));
|
||||
setHoveredCloseTabKey((current) => (current === tab.key ? null : current));
|
||||
}, [setHoveredTabKey, setHoveredCloseTabKey, tab.key]);
|
||||
}, [setHoveredCloseTabKey, tab.key]);
|
||||
|
||||
const handleCloseButtonPress = useCallback(
|
||||
(event: { stopPropagation?: () => void }) => {
|
||||
@@ -466,7 +460,6 @@ export function WorkspaceDesktopTabsRow({
|
||||
tabs,
|
||||
normalizedServerId,
|
||||
normalizedWorkspaceId,
|
||||
setHoveredTabKey,
|
||||
setHoveredCloseTabKey,
|
||||
onNavigateTab,
|
||||
onCloseTab,
|
||||
@@ -613,7 +606,6 @@ export function WorkspaceDesktopTabsRow({
|
||||
resolvedTabWidth={resolvedTabWidth}
|
||||
showLabel={showLabel}
|
||||
showCloseButton={shouldShowCloseButton}
|
||||
setHoveredTabKey={setHoveredTabKey}
|
||||
setHoveredCloseTabKey={setHoveredCloseTabKey}
|
||||
onNavigateTab={onNavigateTab}
|
||||
onCloseTab={onCloseTab}
|
||||
@@ -640,7 +632,6 @@ export function WorkspaceDesktopTabsRow({
|
||||
onReloadAgent,
|
||||
onRenameTab,
|
||||
setHoveredCloseTabKey,
|
||||
setHoveredTabKey,
|
||||
tabDropPreviewIndex,
|
||||
tabs.length,
|
||||
],
|
||||
@@ -656,7 +647,7 @@ export function WorkspaceDesktopTabsRow({
|
||||
[layout.requiresHorizontalScrollFallback],
|
||||
);
|
||||
|
||||
return (
|
||||
const row = (
|
||||
<View
|
||||
style={styles.tabsContainer}
|
||||
testID="workspace-tabs-row"
|
||||
@@ -787,8 +778,9 @@ export function WorkspaceDesktopTabsRow({
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return <RenderProfile id="WorkspaceDesktopTabsRow">{row}</RenderProfile>;
|
||||
}
|
||||
function ResolvedDesktopTabChip({
|
||||
item,
|
||||
isFocused,
|
||||
@@ -807,7 +799,6 @@ function ResolvedDesktopTabChip({
|
||||
resolvedTabWidth,
|
||||
showLabel,
|
||||
showCloseButton,
|
||||
setHoveredTabKey,
|
||||
setHoveredCloseTabKey,
|
||||
onNavigateTab,
|
||||
onCloseTab,
|
||||
@@ -832,7 +823,6 @@ function ResolvedDesktopTabChip({
|
||||
resolvedTabWidth: number;
|
||||
showLabel: boolean;
|
||||
showCloseButton: boolean;
|
||||
setHoveredTabKey: Dispatch<SetStateAction<string | null>>;
|
||||
setHoveredCloseTabKey: Dispatch<SetStateAction<string | null>>;
|
||||
onNavigateTab: (tabId: string) => void;
|
||||
onCloseTab: (tabId: string) => Promise<void> | void;
|
||||
@@ -896,7 +886,6 @@ function ResolvedDesktopTabChip({
|
||||
presentation={presentation}
|
||||
tooltipLabel={tooltipLabel}
|
||||
resolvedTab={resolvedTab}
|
||||
setHoveredTabKey={setHoveredTabKey}
|
||||
setHoveredCloseTabKey={setHoveredCloseTabKey}
|
||||
onNavigateTab={onNavigateTab}
|
||||
onCloseTab={onCloseTab}
|
||||
|
||||
@@ -6,9 +6,11 @@ import {
|
||||
PaneProvider,
|
||||
type PaneContextValue,
|
||||
} from "@/panels/pane-context";
|
||||
import { useStableEvent } from "@/hooks/use-stable-event";
|
||||
import { getPanelRegistration } from "@/panels/panel-registry";
|
||||
import { ensurePanelsRegistered } from "@/panels/register-panels";
|
||||
import type { WorkspaceTabDescriptor } from "@/screens/workspace/workspace-tabs-types";
|
||||
import { RenderProfile } from "@/utils/render-profiler";
|
||||
import type { WorkspaceFileOpenRequest } from "@/workspace/file-open";
|
||||
|
||||
export interface WorkspacePaneContentModel {
|
||||
@@ -72,6 +74,35 @@ export function WorkspacePaneContent({
|
||||
onFocusPane,
|
||||
}: WorkspacePaneContentProps) {
|
||||
const { Component, key, paneContextValue } = content;
|
||||
const openTab = useStableEvent(paneContextValue.openTab);
|
||||
const closeCurrentTab = useStableEvent(paneContextValue.closeCurrentTab);
|
||||
const retargetCurrentTab = useStableEvent(paneContextValue.retargetCurrentTab);
|
||||
const openFileInWorkspace = useStableEvent(paneContextValue.openFileInWorkspace);
|
||||
const openImportSheet = useStableEvent(paneContextValue.openImportSheet);
|
||||
const stablePaneContextValue = useMemo(
|
||||
() => ({
|
||||
serverId: paneContextValue.serverId,
|
||||
workspaceId: paneContextValue.workspaceId,
|
||||
tabId: paneContextValue.tabId,
|
||||
target: paneContextValue.target,
|
||||
openTab,
|
||||
closeCurrentTab,
|
||||
retargetCurrentTab,
|
||||
openFileInWorkspace,
|
||||
openImportSheet,
|
||||
}),
|
||||
[
|
||||
closeCurrentTab,
|
||||
openFileInWorkspace,
|
||||
openImportSheet,
|
||||
openTab,
|
||||
paneContextValue.serverId,
|
||||
paneContextValue.tabId,
|
||||
paneContextValue.target,
|
||||
paneContextValue.workspaceId,
|
||||
retargetCurrentTab,
|
||||
],
|
||||
);
|
||||
const paneFocusValue = useMemo(
|
||||
() =>
|
||||
createPaneFocusContextValue({
|
||||
@@ -83,10 +114,14 @@ export function WorkspacePaneContent({
|
||||
);
|
||||
|
||||
return (
|
||||
<PaneProvider value={paneContextValue}>
|
||||
<PaneFocusProvider value={paneFocusValue}>
|
||||
<Component key={key} />
|
||||
</PaneFocusProvider>
|
||||
</PaneProvider>
|
||||
<RenderProfile
|
||||
id={`WorkspacePaneContent:${paneContextValue.target.kind}:${paneContextValue.tabId}`}
|
||||
>
|
||||
<PaneProvider value={stablePaneContextValue}>
|
||||
<PaneFocusProvider value={paneFocusValue}>
|
||||
<Component key={key} />
|
||||
</PaneFocusProvider>
|
||||
</PaneProvider>
|
||||
</RenderProfile>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -177,6 +177,7 @@ import {
|
||||
type WorkspaceFileLocation,
|
||||
type WorkspaceFileOpenRequest,
|
||||
} from "@/workspace/file-open";
|
||||
import { RenderProfile } from "@/utils/render-profiler";
|
||||
|
||||
const WORKSPACE_SETUP_AUTO_OPEN_WINDOW_MS = 30_000;
|
||||
const WORKSPACE_FLOATING_PANEL_PORTAL_HOST_PREFIX = "workspace-floating-panels";
|
||||
@@ -734,16 +735,43 @@ const MobileMountedTabSlot = memo(function MobileMountedTabSlot({
|
||||
: styles.mobileMountedTabSlotHidden;
|
||||
|
||||
return (
|
||||
<View style={slotStyle} pointerEvents={isVisible ? "auto" : "none"}>
|
||||
<WorkspacePaneContent
|
||||
content={content}
|
||||
isWorkspaceFocused={isWorkspaceFocused}
|
||||
isPaneFocused={isPaneFocused}
|
||||
/>
|
||||
</View>
|
||||
<RenderProfile id={`MobileMountedTabSlot:${tabDescriptor.kind}:${tabDescriptor.tabId}`}>
|
||||
<View style={slotStyle} pointerEvents={isVisible ? "auto" : "none"}>
|
||||
<WorkspacePaneContent
|
||||
content={content}
|
||||
isWorkspaceFocused={isWorkspaceFocused}
|
||||
isPaneFocused={isPaneFocused}
|
||||
/>
|
||||
</View>
|
||||
</RenderProfile>
|
||||
);
|
||||
});
|
||||
|
||||
interface MobileExplorerOpenGestureSurfaceProps {
|
||||
children: ReactNode;
|
||||
onOpenExplorer: () => void;
|
||||
}
|
||||
|
||||
function MobileExplorerOpenGestureSurface({
|
||||
children,
|
||||
onOpenExplorer,
|
||||
}: MobileExplorerOpenGestureSurfaceProps) {
|
||||
const canOpenExplorerFromAgentView = usePanelStore(
|
||||
(state) =>
|
||||
state.mobileView === "agent" && !selectIsFileExplorerOpen(state, { isCompact: true }),
|
||||
);
|
||||
const explorerOpenGesture = useExplorerOpenGesture({
|
||||
enabled: canOpenExplorerFromAgentView,
|
||||
onOpen: onOpenExplorer,
|
||||
});
|
||||
|
||||
return (
|
||||
<GestureDetector gesture={explorerOpenGesture} touchAction={COMPACT_WEB_GESTURE_TOUCH_ACTION}>
|
||||
<View style={styles.content}>{children}</View>
|
||||
</GestureDetector>
|
||||
);
|
||||
}
|
||||
|
||||
function useStableTabDescriptorMap(tabDescriptors: WorkspaceTabDescriptor[]) {
|
||||
const cacheRef = useRef(new Map<string, WorkspaceTabDescriptor>());
|
||||
const tabDescriptorMap = useMemo(() => {
|
||||
@@ -770,7 +798,11 @@ function useStableTabDescriptorMap(tabDescriptors: WorkspaceTabDescriptor[]) {
|
||||
return tabDescriptorMap;
|
||||
}
|
||||
|
||||
export function WorkspaceScreen({ serverId, workspaceId, isRouteFocused }: WorkspaceScreenProps) {
|
||||
export const WorkspaceScreen = memo(function WorkspaceScreen({
|
||||
serverId,
|
||||
workspaceId,
|
||||
isRouteFocused,
|
||||
}: WorkspaceScreenProps) {
|
||||
const navigationFocused = useIsFocused();
|
||||
const effectiveRouteFocused = isRouteFocused ?? navigationFocused;
|
||||
|
||||
@@ -783,7 +815,7 @@ export function WorkspaceScreen({ serverId, workspaceId, isRouteFocused }: Works
|
||||
/>
|
||||
</ExplorerSidebarAnimationProvider>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
interface UseCloseTabsResult {
|
||||
closingTabIds: Set<string>;
|
||||
@@ -1657,10 +1689,6 @@ function WorkspaceScreenContent({
|
||||
const isExplorerOpen = usePanelStore((state) =>
|
||||
selectIsFileExplorerOpen(state, { isCompact: isMobile }),
|
||||
);
|
||||
const canOpenExplorerFromAgentView = usePanelStore(
|
||||
(state) =>
|
||||
state.mobileView === "agent" && !selectIsFileExplorerOpen(state, { isCompact: true }),
|
||||
);
|
||||
const openFileExplorerForCheckout = usePanelStore((state) => state.openFileExplorerForCheckout);
|
||||
const toggleFileExplorerForCheckout = usePanelStore(
|
||||
(state) => state.toggleFileExplorerForCheckout,
|
||||
@@ -1712,11 +1740,6 @@ function WorkspaceScreenContent({
|
||||
[isExplorerOpen],
|
||||
);
|
||||
|
||||
const explorerOpenGesture = useExplorerOpenGesture({
|
||||
enabled: isMobile && canOpenExplorerFromAgentView,
|
||||
onOpen: openExplorerForWorkspace,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!isRouteFocused || isWeb || !isExplorerOpen) {
|
||||
return;
|
||||
@@ -2178,7 +2201,31 @@ function WorkspaceScreenContent({
|
||||
],
|
||||
);
|
||||
|
||||
const [_hoveredTabKey, setHoveredTabKey] = useState<string | null>(null);
|
||||
const handleOpenWorkspaceFileFromPane = useStableEvent(function handleOpenWorkspaceFileFromPane({
|
||||
request,
|
||||
paneId,
|
||||
parentTabId,
|
||||
focusPaneBeforeOpen,
|
||||
}: {
|
||||
request: WorkspaceFileOpenRequest;
|
||||
paneId?: string | null;
|
||||
parentTabId: string;
|
||||
focusPaneBeforeOpen?: boolean;
|
||||
}) {
|
||||
if (focusPaneBeforeOpen && paneId && persistenceKey) {
|
||||
focusWorkspacePane(persistenceKey, paneId);
|
||||
}
|
||||
if (request.disposition === "side") {
|
||||
handleOpenFileFromChatInSidePane({
|
||||
location: request.location,
|
||||
sourcePaneId: paneId ?? undefined,
|
||||
parentTabId,
|
||||
});
|
||||
return;
|
||||
}
|
||||
handleOpenFileFromChat(request.location, { parentTabId });
|
||||
});
|
||||
|
||||
const [hoveredCloseTabKey, setHoveredCloseTabKey] = useState<string | null>(null);
|
||||
const { handleRenameTab, renamingTab, handleRenameModalSubmit, handleRenameModalClose } =
|
||||
useWorkspaceTabRename({
|
||||
@@ -2300,7 +2347,6 @@ function WorkspaceScreenContent({
|
||||
}
|
||||
|
||||
removeTerminalFromCache(terminalId);
|
||||
setHoveredTabKey((current) => (current === tabId ? null : current));
|
||||
setHoveredCloseTabKey((current) => (current === tabId ? null : current));
|
||||
if (persistenceKey) {
|
||||
closeWorkspaceTabWithCleanup({
|
||||
@@ -2349,7 +2395,6 @@ function WorkspaceScreenContent({
|
||||
}
|
||||
}
|
||||
|
||||
setHoveredTabKey((current) => (current === tabId ? null : current));
|
||||
setHoveredCloseTabKey((current) => (current === tabId ? null : current));
|
||||
if (persistenceKey) {
|
||||
closeWorkspaceTabWithCleanup({
|
||||
@@ -2374,7 +2419,6 @@ function WorkspaceScreenContent({
|
||||
tabId: string;
|
||||
target?: WorkspaceTabTarget | null;
|
||||
}) {
|
||||
setHoveredTabKey((current) => (current === input.tabId ? null : current));
|
||||
setHoveredCloseTabKey((current) => (current === input.tabId ? null : current));
|
||||
if (persistenceKey) {
|
||||
closeWorkspaceTabWithCleanup({ tabId: input.tabId, target: input.target });
|
||||
@@ -2556,7 +2600,6 @@ function WorkspaceScreenContent({
|
||||
});
|
||||
|
||||
const closedKeys = new Set(tabsToClose.map((tab) => tab.key));
|
||||
setHoveredTabKey((current) => (current && closedKeys.has(current) ? null : current));
|
||||
setHoveredCloseTabKey((current) => (current && closedKeys.has(current) ? null : current));
|
||||
},
|
||||
[client, closeTab, closeWorkspaceTabWithCleanup, persistenceKey],
|
||||
@@ -2851,26 +2894,19 @@ function WorkspaceScreenContent({
|
||||
retargetWorkspaceTab(persistenceKey, input.tab.tabId, target);
|
||||
},
|
||||
onOpenWorkspaceFile: (request: WorkspaceFileOpenRequest) => {
|
||||
if (input.focusPaneBeforeOpen && input.paneId && persistenceKey) {
|
||||
focusWorkspacePane(persistenceKey, input.paneId);
|
||||
}
|
||||
if (request.disposition === "side") {
|
||||
handleOpenFileFromChatInSidePane({
|
||||
location: request.location,
|
||||
sourcePaneId: input.paneId ?? undefined,
|
||||
parentTabId: input.tab.tabId,
|
||||
});
|
||||
return;
|
||||
}
|
||||
handleOpenFileFromChat(request.location, { parentTabId: input.tab.tabId });
|
||||
handleOpenWorkspaceFileFromPane({
|
||||
request,
|
||||
paneId: input.paneId,
|
||||
parentTabId: input.tab.tabId,
|
||||
focusPaneBeforeOpen: input.focusPaneBeforeOpen,
|
||||
});
|
||||
},
|
||||
onOpenImportSheet: openImportSheet,
|
||||
}),
|
||||
[
|
||||
handleCloseTabById,
|
||||
handleOpenFileFromChat,
|
||||
handleOpenFileFromChatInSidePane,
|
||||
focusWorkspacePane,
|
||||
handleOpenWorkspaceFileFromPane,
|
||||
navigateToTabId,
|
||||
normalizedServerId,
|
||||
normalizedWorkspaceId,
|
||||
@@ -3193,9 +3229,9 @@ function WorkspaceScreenContent({
|
||||
`${WORKSPACE_FLOATING_PANEL_PORTAL_HOST_PREFIX}:${normalizedServerId}:${normalizedWorkspaceId}`,
|
||||
[normalizedServerId, normalizedWorkspaceId],
|
||||
);
|
||||
const desktopContent = useMemo(() => {
|
||||
const desktopSplitContent = useMemo(() => {
|
||||
if (!canRenderDesktopPaneSplits || !workspaceLayout || !persistenceKey) {
|
||||
return content;
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<SplitContainer
|
||||
@@ -3207,7 +3243,6 @@ function WorkspaceScreenContent({
|
||||
isWorkspaceFocused={isRouteFocused}
|
||||
uiTabs={uiTabs}
|
||||
hoveredCloseTabKey={hoveredCloseTabKey}
|
||||
setHoveredTabKey={setHoveredTabKey}
|
||||
setHoveredCloseTabKey={setHoveredCloseTabKey}
|
||||
closingTabIds={closingTabIds}
|
||||
onNavigateTab={navigateToTabId}
|
||||
@@ -3234,7 +3269,6 @@ function WorkspaceScreenContent({
|
||||
/>
|
||||
);
|
||||
}, [
|
||||
content,
|
||||
canRenderDesktopPaneSplits,
|
||||
workspaceLayout,
|
||||
persistenceKey,
|
||||
@@ -3267,6 +3301,7 @@ function WorkspaceScreenContent({
|
||||
handleReorderTabsInPane,
|
||||
renderSplitPaneEmptyState,
|
||||
]);
|
||||
const desktopContent = desktopSplitContent ?? content;
|
||||
|
||||
const workspaceCenterColumn = (
|
||||
<View style={styles.centerColumn}>
|
||||
@@ -3343,7 +3378,6 @@ function WorkspaceScreenContent({
|
||||
tabs={desktopTabRowItems}
|
||||
normalizedServerId={normalizedServerId}
|
||||
normalizedWorkspaceId={normalizedWorkspaceId}
|
||||
setHoveredTabKey={setHoveredTabKey}
|
||||
setHoveredCloseTabKey={setHoveredCloseTabKey}
|
||||
onNavigateTab={navigateToTabId}
|
||||
onCloseTab={handleCloseTabById}
|
||||
@@ -3369,12 +3403,9 @@ function WorkspaceScreenContent({
|
||||
|
||||
<View style={styles.centerContent}>
|
||||
{isMobile ? (
|
||||
<GestureDetector
|
||||
gesture={explorerOpenGesture}
|
||||
touchAction={COMPACT_WEB_GESTURE_TOUCH_ACTION}
|
||||
>
|
||||
<View style={styles.content}>{content}</View>
|
||||
</GestureDetector>
|
||||
<MobileExplorerOpenGestureSurface onOpenExplorer={openExplorerForWorkspace}>
|
||||
{content}
|
||||
</MobileExplorerOpenGestureSurface>
|
||||
) : (
|
||||
<View style={styles.content}>{desktopContent}</View>
|
||||
)}
|
||||
@@ -3385,44 +3416,46 @@ function WorkspaceScreenContent({
|
||||
return (
|
||||
gatedWorkspaceScreen ?? (
|
||||
<WorkspaceFocusProvider workspaceKey={persistenceKey}>
|
||||
<View style={containerStyle}>
|
||||
<WorkspaceDocumentTitleEffectSlot
|
||||
tab={activeTabDescriptor}
|
||||
serverId={normalizedServerId}
|
||||
workspaceId={normalizedWorkspaceId}
|
||||
isRouteFocused={isRouteFocused}
|
||||
/>
|
||||
<View style={styles.threePaneRow}>
|
||||
<FloatingPanelPortalHostNameProvider hostName={workspaceFloatingPanelPortalHostName}>
|
||||
{workspaceCenterColumn}
|
||||
</FloatingPanelPortalHostNameProvider>
|
||||
<RenderProfile id="WorkspaceScreenContent">
|
||||
<View style={containerStyle}>
|
||||
<WorkspaceDocumentTitleEffectSlot
|
||||
tab={activeTabDescriptor}
|
||||
serverId={normalizedServerId}
|
||||
workspaceId={normalizedWorkspaceId}
|
||||
isRouteFocused={isRouteFocused}
|
||||
/>
|
||||
<View style={styles.threePaneRow}>
|
||||
<FloatingPanelPortalHostNameProvider hostName={workspaceFloatingPanelPortalHostName}>
|
||||
{workspaceCenterColumn}
|
||||
</FloatingPanelPortalHostNameProvider>
|
||||
|
||||
<FloatingPanelPortalHost name={workspaceFloatingPanelPortalHostName} />
|
||||
<FloatingPanelPortalHost name={workspaceFloatingPanelPortalHostName} />
|
||||
|
||||
{showExplorerSidebar && workspaceDirectory ? (
|
||||
<ExplorerSidebar
|
||||
serverId={normalizedServerId}
|
||||
workspaceId={normalizedWorkspaceId}
|
||||
workspaceRoot={workspaceDirectory}
|
||||
isGit={isGitCheckout}
|
||||
onOpenFile={handleOpenFileFromExplorer}
|
||||
/>
|
||||
) : null}
|
||||
{showExplorerSidebar && workspaceDirectory ? (
|
||||
<ExplorerSidebar
|
||||
serverId={normalizedServerId}
|
||||
workspaceId={normalizedWorkspaceId}
|
||||
workspaceRoot={workspaceDirectory}
|
||||
isGit={isGitCheckout}
|
||||
onOpenFile={handleOpenFileFromExplorer}
|
||||
/>
|
||||
) : null}
|
||||
</View>
|
||||
<ImportSessionSheet
|
||||
visible={isImportSheetVisible}
|
||||
client={client}
|
||||
serverId={normalizedServerId}
|
||||
cwd={workspaceDirectory}
|
||||
onClose={closeImportSheet}
|
||||
onImportedAgent={handleImportedAgent}
|
||||
/>
|
||||
<WorkspaceTabRenameModal
|
||||
renamingTab={renamingTab}
|
||||
onSubmit={handleRenameModalSubmit}
|
||||
onClose={handleRenameModalClose}
|
||||
/>
|
||||
</View>
|
||||
<ImportSessionSheet
|
||||
visible={isImportSheetVisible}
|
||||
client={client}
|
||||
serverId={normalizedServerId}
|
||||
cwd={workspaceDirectory}
|
||||
onClose={closeImportSheet}
|
||||
onImportedAgent={handleImportedAgent}
|
||||
/>
|
||||
<WorkspaceTabRenameModal
|
||||
renamingTab={renamingTab}
|
||||
onSubmit={handleRenameModalSubmit}
|
||||
onClose={handleRenameModalClose}
|
||||
/>
|
||||
</View>
|
||||
</RenderProfile>
|
||||
</WorkspaceFocusProvider>
|
||||
)
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user