feat: Remember panel state per workspace (Vibe Kanban) (#2064)

* I've successfully implemented workspace-specific panel state persistence. Here's a summary of the changes:

## Summary

### Changes Made

1. **`frontend/src/stores/useUiPreferencesStore.ts`**
   - Added `WorkspacePanelState` type to track `rightMainPanelMode` and `isLeftMainPanelVisible` per workspace
   - Added `workspacePanelStates: Record<string, WorkspacePanelState>` to store state keyed by workspace ID
   - Updated `toggleLeftMainPanel`, `toggleRightMainPanelMode`, `setRightMainPanelMode`, and `setLeftMainPanelVisible` to accept an optional `workspaceId` parameter
   - Added `getWorkspacePanelState` and `setWorkspacePanelState` actions
   - Added `useWorkspacePanelState(workspaceId)` hook for easy consumption
   - Updated `partialize` to persist `workspacePanelStates` to localStorage

2. **`frontend/src/components/ui-new/containers/WorkspacesLayout.tsx`**
   - Changed from using `useUiPreferencesStore` directly to using `useWorkspacePanelState(workspaceId)` hook
   - Panel state is now workspace-specific

3. **`frontend/src/components/ui-new/actions/useActionVisibility.ts`**
   - Updated to use `useWorkspacePanelState` for visibility context

4. **`frontend/src/components/ui-new/actions/index.ts`**
   - Updated `ToggleLeftMainPanel`, `ToggleChangesMode`, `ToggleLogsMode`, `TogglePreviewMode`, and `ToggleDevServer` actions to pass `currentWorkspaceId` when toggling panel modes

### Scope

**Workspace-specific:**
- `rightMainPanelMode` - Which panel (Preview/Changes/Logs) is open
- `isLeftMainPanelVisible` - Whether the chat panel is visible

**Stays global:**
- `isLeftSidebarVisible` - Workspace list sidebar (navigation element)
- `isRightSidebarVisible` - Git/Settings sidebar (global actions)
- Panel sizes (already work correctly)

### Testing

Verified the feature works:
1. Opened Preview panel in Workspace A
2. Navigated to Workspace B → Preview panel is closed (default state)
3. Navigated back to Workspace A → Preview panel is still open ✓

* Cleanup script changes for workspace c8b73e59-ac41-4c0f-be78-7b6499d514f9

* The refactoring is complete. Let me provide a summary of the changes:

## Summary

Refactored `useUiPreferencesStore.ts` to remove duplicate code paths for workspace-specific panel state:

### Changes Made

1. **`frontend/src/stores/useUiPreferencesStore.ts`**
   - Removed legacy global state (`isLeftMainPanelVisible`, `rightMainPanelMode`) from State type and initialization
   - Simplified 4 panel state actions by removing `else` branches for legacy behavior:
     - `toggleLeftMainPanel` - now early-returns if no workspaceId
     - `toggleRightMainPanelMode` - simplified to single set() call
     - `setRightMainPanelMode` - simplified to single set() call
     - `setLeftMainPanelVisible` - simplified
   - Removed `resetForCreateMode` action (was only setting legacy state)
   - Removed unused `useIsRightMainPanelVisible` hook

2. **`frontend/src/contexts/WorkspaceContext.tsx`**
   - Removed the `useEffect` that called `resetForCreateMode()` on create mode
   - Removed unused `useUiPreferencesStore` import

3. **`frontend/src/contexts/LogsPanelContext.tsx`**
   - Updated to use `useWorkspacePanelState` with workspace ID from context

4. **`frontend/src/components/ui-new/containers/SessionChatBoxContainer.tsx`**
   - Updated to use `useWorkspacePanelState` with workspace ID

### Impact

- **~50 lines removed** from the codebase
- **Cleaner code** - no more `if (workspaceId) ... else ...` branching in every action
- **Same behavior** - all callers were already passing workspaceId

* Cleanup script changes for workspace c8b73e59-ac41-4c0f-be78-7b6499d514f9
This commit is contained in:
Louis Knight-Webb
2026-01-15 12:29:17 +00:00
committed by GitHub
parent 1e8783331c
commit e1b0ef70a4
7 changed files with 273 additions and 101 deletions

View File

@@ -478,17 +478,18 @@ export const Actions = {
ToggleLeftMainPanel: {
id: 'toggle-left-main-panel',
label: () =>
useUiPreferencesStore.getState().isLeftMainPanelVisible
? 'Hide Chat Panel'
: 'Show Chat Panel',
label: 'Toggle Chat Panel',
icon: ChatsTeardropIcon,
requiresTarget: false,
isActive: (ctx) => ctx.isLeftMainPanelVisible,
isEnabled: (ctx) =>
!(ctx.isLeftMainPanelVisible && ctx.rightMainPanelMode === null),
execute: () => {
useUiPreferencesStore.getState().toggleLeftMainPanel();
getLabel: (ctx) =>
ctx.isLeftMainPanelVisible ? 'Hide Chat Panel' : 'Show Chat Panel',
execute: (ctx) => {
useUiPreferencesStore
.getState()
.toggleLeftMainPanel(ctx.currentWorkspaceId ?? undefined);
},
},
@@ -508,60 +509,69 @@ export const Actions = {
ToggleChangesMode: {
id: 'toggle-changes-mode',
label: () =>
useUiPreferencesStore.getState().rightMainPanelMode ===
RIGHT_MAIN_PANEL_MODES.CHANGES
? 'Hide Changes Panel'
: 'Show Changes Panel',
label: 'Toggle Changes Panel',
icon: GitDiffIcon,
requiresTarget: false,
isVisible: (ctx) => !ctx.isCreateMode,
isActive: (ctx) =>
ctx.rightMainPanelMode === RIGHT_MAIN_PANEL_MODES.CHANGES,
isEnabled: (ctx) => !ctx.isCreateMode,
execute: () => {
getLabel: (ctx) =>
ctx.rightMainPanelMode === RIGHT_MAIN_PANEL_MODES.CHANGES
? 'Hide Changes Panel'
: 'Show Changes Panel',
execute: (ctx) => {
useUiPreferencesStore
.getState()
.toggleRightMainPanelMode(RIGHT_MAIN_PANEL_MODES.CHANGES);
.toggleRightMainPanelMode(
RIGHT_MAIN_PANEL_MODES.CHANGES,
ctx.currentWorkspaceId ?? undefined
);
},
},
ToggleLogsMode: {
id: 'toggle-logs-mode',
label: () =>
useUiPreferencesStore.getState().rightMainPanelMode ===
RIGHT_MAIN_PANEL_MODES.LOGS
? 'Hide Logs Panel'
: 'Show Logs Panel',
label: 'Toggle Logs Panel',
icon: TerminalIcon,
requiresTarget: false,
isVisible: (ctx) => !ctx.isCreateMode,
isActive: (ctx) => ctx.rightMainPanelMode === RIGHT_MAIN_PANEL_MODES.LOGS,
isEnabled: (ctx) => !ctx.isCreateMode,
execute: () => {
getLabel: (ctx) =>
ctx.rightMainPanelMode === RIGHT_MAIN_PANEL_MODES.LOGS
? 'Hide Logs Panel'
: 'Show Logs Panel',
execute: (ctx) => {
useUiPreferencesStore
.getState()
.toggleRightMainPanelMode(RIGHT_MAIN_PANEL_MODES.LOGS);
.toggleRightMainPanelMode(
RIGHT_MAIN_PANEL_MODES.LOGS,
ctx.currentWorkspaceId ?? undefined
);
},
},
TogglePreviewMode: {
id: 'toggle-preview-mode',
label: () =>
useUiPreferencesStore.getState().rightMainPanelMode ===
RIGHT_MAIN_PANEL_MODES.PREVIEW
? 'Hide Preview Panel'
: 'Show Preview Panel',
label: 'Toggle Preview Panel',
icon: DesktopIcon,
requiresTarget: false,
isVisible: (ctx) => !ctx.isCreateMode,
isActive: (ctx) =>
ctx.rightMainPanelMode === RIGHT_MAIN_PANEL_MODES.PREVIEW,
isEnabled: (ctx) => !ctx.isCreateMode,
execute: () => {
getLabel: (ctx) =>
ctx.rightMainPanelMode === RIGHT_MAIN_PANEL_MODES.PREVIEW
? 'Hide Preview Panel'
: 'Show Preview Panel',
execute: (ctx) => {
useUiPreferencesStore
.getState()
.toggleRightMainPanelMode(RIGHT_MAIN_PANEL_MODES.PREVIEW);
.toggleRightMainPanelMode(
RIGHT_MAIN_PANEL_MODES.PREVIEW,
ctx.currentWorkspaceId ?? undefined
);
},
},
@@ -707,7 +717,10 @@ export const Actions = {
// Auto-open preview mode when starting dev server
useUiPreferencesStore
.getState()
.setRightMainPanelMode(RIGHT_MAIN_PANEL_MODES.PREVIEW);
.setRightMainPanelMode(
RIGHT_MAIN_PANEL_MODES.PREVIEW,
ctx.currentWorkspaceId ?? undefined
);
}
},
},

View File

@@ -1,5 +1,8 @@
import { useMemo } from 'react';
import { useUiPreferencesStore } from '@/stores/useUiPreferencesStore';
import {
useUiPreferencesStore,
useWorkspacePanelState,
} from '@/stores/useUiPreferencesStore';
import { useDiffViewStore, useDiffViewMode } from '@/stores/useDiffViewStore';
import { useWorkspaceContext } from '@/contexts/WorkspaceContext';
import { useUserSystem } from '@/components/ConfigProvider';
@@ -22,8 +25,11 @@ import type { CommandBarPage } from './pages';
* action visibility and state conditions.
*/
export function useActionVisibilityContext(): ActionVisibilityContext {
const layout = useUiPreferencesStore();
const { workspace, workspaceId, isCreateMode, repos } = useWorkspaceContext();
// Use workspace-specific panel state (pass undefined when in create mode)
const panelState = useWorkspacePanelState(
isCreateMode ? undefined : workspaceId
);
const diffPaths = useDiffViewStore((s) => s.diffPaths);
const diffViewMode = useDiffViewMode();
const expanded = useUiPreferencesStore((s) => s.expanded);
@@ -61,10 +67,10 @@ export function useActionVisibilityContext(): ActionVisibilityContext {
false;
return {
rightMainPanelMode: layout.rightMainPanelMode,
isLeftSidebarVisible: layout.isLeftSidebarVisible,
isLeftMainPanelVisible: layout.isLeftMainPanelVisible,
isRightSidebarVisible: layout.isRightSidebarVisible,
rightMainPanelMode: panelState.rightMainPanelMode,
isLeftSidebarVisible: panelState.isLeftSidebarVisible,
isLeftMainPanelVisible: panelState.isLeftMainPanelVisible,
isRightSidebarVisible: panelState.isRightSidebarVisible,
isCreateMode,
hasWorkspace: !!workspace,
workspaceArchived: workspace?.archived ?? false,
@@ -81,10 +87,10 @@ export function useActionVisibilityContext(): ActionVisibilityContext {
isAttemptRunning: isAttemptRunningVisible,
};
}, [
layout.rightMainPanelMode,
layout.isLeftSidebarVisible,
layout.isLeftMainPanelVisible,
layout.isRightSidebarVisible,
panelState.rightMainPanelMode,
panelState.isLeftSidebarVisible,
panelState.isLeftMainPanelVisible,
panelState.isRightSidebarVisible,
isCreateMode,
workspace,
repos,

View File

@@ -29,7 +29,7 @@ import {
type ExecutionStatus,
} from '../primitives/SessionChatBox';
import {
useUiPreferencesStore,
useWorkspacePanelState,
RIGHT_MAIN_PANEL_MODES,
} from '@/stores/useUiPreferencesStore';
import { Actions, type ActionDefinition } from '../actions';
@@ -102,7 +102,8 @@ export function SessionChatBoxContainer({
const { executeAction } = useActions();
const actionCtx = useActionVisibilityContext();
const { rightMainPanelMode, setRightMainPanelMode } = useUiPreferencesStore();
const { rightMainPanelMode, setRightMainPanelMode } =
useWorkspacePanelState(workspaceId);
const handleViewCode = useCallback(() => {
setRightMainPanelMode(

View File

@@ -20,7 +20,7 @@ import { useUserSystem } from '@/components/ConfigProvider';
import {
PERSIST_KEYS,
usePaneSize,
useUiPreferencesStore,
useWorkspacePanelState,
RIGHT_MAIN_PANEL_MODES,
} from '@/stores/useUiPreferencesStore';
@@ -60,6 +60,7 @@ function ModeProvider({
export function WorkspacesLayout() {
const {
workspaceId,
workspace: selectedWorkspace,
isLoading,
isCreateMode,
@@ -72,6 +73,7 @@ export function WorkspacesLayout() {
startNewSession,
} = useWorkspaceContext();
// Use workspace-specific panel state (pass undefined when in create mode)
const {
isLeftSidebarVisible,
isLeftMainPanelVisible,
@@ -79,7 +81,7 @@ export function WorkspacesLayout() {
rightMainPanelMode,
setLeftSidebarVisible,
setLeftMainPanelVisible,
} = useUiPreferencesStore();
} = useWorkspacePanelState(isCreateMode ? undefined : workspaceId);
const {
config,

View File

@@ -9,9 +9,10 @@ import {
} from 'react';
import type { LogsPanelContent } from '@/components/ui-new/containers/LogsContentContainer';
import {
useUiPreferencesStore,
useWorkspacePanelState,
RIGHT_MAIN_PANEL_MODES,
} from '@/stores/useUiPreferencesStore';
import { useWorkspaceContext } from '@/contexts/WorkspaceContext';
interface LogsPanelContextValue {
logsPanelContent: LogsPanelContent | null;
@@ -50,7 +51,10 @@ interface LogsPanelProviderProps {
}
export function LogsPanelProvider({ children }: LogsPanelProviderProps) {
const { rightMainPanelMode, setRightMainPanelMode } = useUiPreferencesStore();
const { workspaceId, isCreateMode } = useWorkspaceContext();
const { rightMainPanelMode, setRightMainPanelMode } = useWorkspacePanelState(
isCreateMode ? undefined : workspaceId
);
const [logsPanelContent, setLogsPanelContent] =
useState<LogsPanelContent | null>(null);

View File

@@ -22,7 +22,6 @@ import {
} from '@/hooks/useGitHubComments';
import { useDiffStream } from '@/hooks/useDiffStream';
import { attemptsApi } from '@/lib/api';
import { useUiPreferencesStore } from '@/stores/useUiPreferencesStore';
import { useDiffViewStore } from '@/stores/useDiffViewStore';
import type {
Workspace as ApiWorkspace,
@@ -91,13 +90,6 @@ export function WorkspaceProvider({ children }: WorkspaceProviderProps) {
// Derive isCreateMode from URL path instead of prop to allow provider to persist across route changes
const isCreateMode = location.pathname === '/workspaces/create';
// Reset UI state when entering create mode
useEffect(() => {
if (isCreateMode) {
useUiPreferencesStore.getState().resetForCreateMode();
}
}, [isCreateMode]);
// Fetch workspaces for sidebar display
const {
workspaces: activeWorkspaces,

View File

@@ -20,6 +20,17 @@ export type ContextBarPosition =
| 'bottom-left'
| 'bottom-right';
// Workspace-specific panel state
export type WorkspacePanelState = {
rightMainPanelMode: RightMainPanelMode | null;
isLeftMainPanelVisible: boolean;
};
const DEFAULT_WORKSPACE_PANEL_STATE: WorkspacePanelState = {
rightMainPanelMode: null,
isLeftMainPanelVisible: true,
};
// Centralized persist keys for type safety
export const PERSIST_KEYS = {
// Sidebar sections
@@ -76,13 +87,14 @@ type State = {
paneSizes: Record<string, number | string>;
collapsedPaths: Record<string, string[]>;
// Layout state
// Global layout state (applies across all workspaces)
isLeftSidebarVisible: boolean;
isLeftMainPanelVisible: boolean;
isRightSidebarVisible: boolean;
rightMainPanelMode: RightMainPanelMode | null;
previewRefreshKey: number;
// Workspace-specific panel state
workspacePanelStates: Record<string, WorkspacePanelState>;
// UI preferences actions
setRepoAction: (repoId: string, action: RepoAction) => void;
setExpanded: (key: string, value: boolean) => void;
@@ -94,14 +106,26 @@ type State = {
// Layout actions
toggleLeftSidebar: () => void;
toggleLeftMainPanel: () => void;
toggleLeftMainPanel: (workspaceId?: string) => void;
toggleRightSidebar: () => void;
toggleRightMainPanelMode: (mode: RightMainPanelMode) => void;
setRightMainPanelMode: (mode: RightMainPanelMode | null) => void;
toggleRightMainPanelMode: (
mode: RightMainPanelMode,
workspaceId?: string
) => void;
setRightMainPanelMode: (
mode: RightMainPanelMode | null,
workspaceId?: string
) => void;
setLeftSidebarVisible: (value: boolean) => void;
setLeftMainPanelVisible: (value: boolean) => void;
setLeftMainPanelVisible: (value: boolean, workspaceId?: string) => void;
triggerPreviewRefresh: () => void;
resetForCreateMode: () => void;
// Workspace-specific panel state actions
getWorkspacePanelState: (workspaceId: string) => WorkspacePanelState;
setWorkspacePanelState: (
workspaceId: string,
state: Partial<WorkspacePanelState>
) => void;
};
export const useUiPreferencesStore = create<State>()(
@@ -114,13 +138,14 @@ export const useUiPreferencesStore = create<State>()(
paneSizes: {},
collapsedPaths: {},
// Layout state
// Global layout state
isLeftSidebarVisible: true,
isLeftMainPanelVisible: true,
isRightSidebarVisible: true,
rightMainPanelMode: null,
previewRefreshKey: 0,
// Workspace-specific panel state
workspacePanelStates: {},
// UI preferences actions
setRepoAction: (repoId, action) =>
set((s) => ({ repoActions: { ...s.repoActions, [repoId]: action } })),
@@ -151,59 +176,123 @@ export const useUiPreferencesStore = create<State>()(
toggleLeftSidebar: () =>
set((s) => ({ isLeftSidebarVisible: !s.isLeftSidebarVisible })),
toggleLeftMainPanel: () => {
const { isLeftMainPanelVisible, rightMainPanelMode } = get();
if (isLeftMainPanelVisible && rightMainPanelMode === null) return;
set({ isLeftMainPanelVisible: !isLeftMainPanelVisible });
toggleLeftMainPanel: (workspaceId) => {
if (!workspaceId) return;
const state = get();
const wsState =
state.workspacePanelStates[workspaceId] ??
DEFAULT_WORKSPACE_PANEL_STATE;
if (
wsState.isLeftMainPanelVisible &&
wsState.rightMainPanelMode === null
)
return;
set({
workspacePanelStates: {
...state.workspacePanelStates,
[workspaceId]: {
...wsState,
isLeftMainPanelVisible: !wsState.isLeftMainPanelVisible,
},
},
});
},
toggleRightSidebar: () =>
set((s) => ({ isRightSidebarVisible: !s.isRightSidebarVisible })),
toggleRightMainPanelMode: (mode) => {
const { rightMainPanelMode } = get();
const isCurrentlyActive = rightMainPanelMode === mode;
toggleRightMainPanelMode: (mode, workspaceId) => {
if (!workspaceId) return;
const state = get();
const wsState =
state.workspacePanelStates[workspaceId] ??
DEFAULT_WORKSPACE_PANEL_STATE;
const isCurrentlyActive = wsState.rightMainPanelMode === mode;
if (isCurrentlyActive) {
set({
rightMainPanelMode: null,
isLeftSidebarVisible: true,
});
} else {
set({
rightMainPanelMode: mode,
isLeftSidebarVisible: isWideScreen()
? get().isLeftSidebarVisible
set({
workspacePanelStates: {
...state.workspacePanelStates,
[workspaceId]: {
...wsState,
rightMainPanelMode: isCurrentlyActive ? null : mode,
},
},
isLeftSidebarVisible: isCurrentlyActive
? true
: isWideScreen()
? state.isLeftSidebarVisible
: false,
});
}
});
},
setRightMainPanelMode: (mode) => {
if (mode !== null) {
set({
rightMainPanelMode: mode,
setRightMainPanelMode: (mode, workspaceId) => {
if (!workspaceId) return;
const state = get();
const wsState =
state.workspacePanelStates[workspaceId] ??
DEFAULT_WORKSPACE_PANEL_STATE;
set({
workspacePanelStates: {
...state.workspacePanelStates,
[workspaceId]: {
...wsState,
rightMainPanelMode: mode,
},
},
...(mode !== null && {
isLeftSidebarVisible: isWideScreen()
? get().isLeftSidebarVisible
? state.isLeftSidebarVisible
: false,
});
} else {
set({ rightMainPanelMode: null });
}
}),
});
},
setLeftSidebarVisible: (value) => set({ isLeftSidebarVisible: value }),
setLeftMainPanelVisible: (value) =>
set({ isLeftMainPanelVisible: value }),
setLeftMainPanelVisible: (value, workspaceId) => {
if (!workspaceId) return;
const state = get();
const wsState =
state.workspacePanelStates[workspaceId] ??
DEFAULT_WORKSPACE_PANEL_STATE;
set({
workspacePanelStates: {
...state.workspacePanelStates,
[workspaceId]: {
...wsState,
isLeftMainPanelVisible: value,
},
},
});
},
triggerPreviewRefresh: () =>
set((s) => ({ previewRefreshKey: s.previewRefreshKey + 1 })),
resetForCreateMode: () =>
// Workspace-specific panel state actions
getWorkspacePanelState: (workspaceId) => {
const state = get();
return (
state.workspacePanelStates[workspaceId] ??
DEFAULT_WORKSPACE_PANEL_STATE
);
},
setWorkspacePanelState: (workspaceId, panelState) => {
const state = get();
const currentWsState =
state.workspacePanelStates[workspaceId] ??
DEFAULT_WORKSPACE_PANEL_STATE;
set({
rightMainPanelMode: null,
}),
workspacePanelStates: {
...state.workspacePanelStates,
[workspaceId]: {
...currentWsState,
...panelState,
},
},
});
},
}),
{
name: 'ui-preferences',
@@ -214,10 +303,11 @@ export const useUiPreferencesStore = create<State>()(
contextBarPosition: state.contextBarPosition,
paneSizes: state.paneSizes,
collapsedPaths: state.collapsedPaths,
// Layout (only persist panel visibility, not mode states)
// Global layout (persist sidebar visibility)
isLeftSidebarVisible: state.isLeftSidebarVisible,
isLeftMainPanelVisible: state.isLeftMainPanelVisible,
isRightSidebarVisible: state.isRightSidebarVisible,
// Workspace-specific panel state (persisted)
workspacePanelStates: state.workspacePanelStates,
}),
}
)
@@ -301,6 +391,70 @@ export function usePersistedCollapsedPaths(
return [pathSet, setPathSet];
}
// Layout convenience hooks
export const useIsRightMainPanelVisible = () =>
useUiPreferencesStore((s) => s.rightMainPanelMode !== null);
// Hook for workspace-specific panel state
export function useWorkspacePanelState(workspaceId: string | undefined) {
// Get workspace-specific state (falls back to defaults when no workspaceId)
const workspacePanelStates = useUiPreferencesStore(
(s) => s.workspacePanelStates
);
const wsState = workspaceId
? (workspacePanelStates[workspaceId] ?? DEFAULT_WORKSPACE_PANEL_STATE)
: DEFAULT_WORKSPACE_PANEL_STATE;
// Global state (sidebars are global)
const isLeftSidebarVisible = useUiPreferencesStore(
(s) => s.isLeftSidebarVisible
);
const isRightSidebarVisible = useUiPreferencesStore(
(s) => s.isRightSidebarVisible
);
// Actions from store
const toggleRightMainPanelMode = useUiPreferencesStore(
(s) => s.toggleRightMainPanelMode
);
const setRightMainPanelMode = useUiPreferencesStore(
(s) => s.setRightMainPanelMode
);
const setLeftMainPanelVisible = useUiPreferencesStore(
(s) => s.setLeftMainPanelVisible
);
const setLeftSidebarVisible = useUiPreferencesStore(
(s) => s.setLeftSidebarVisible
);
// Memoized callbacks that include workspaceId
const toggleRightMainPanelModeForWorkspace = useCallback(
(mode: RightMainPanelMode) => toggleRightMainPanelMode(mode, workspaceId),
[toggleRightMainPanelMode, workspaceId]
);
const setRightMainPanelModeForWorkspace = useCallback(
(mode: RightMainPanelMode | null) =>
setRightMainPanelMode(mode, workspaceId),
[setRightMainPanelMode, workspaceId]
);
const setLeftMainPanelVisibleForWorkspace = useCallback(
(value: boolean) => setLeftMainPanelVisible(value, workspaceId),
[setLeftMainPanelVisible, workspaceId]
);
return {
// Workspace-specific state
rightMainPanelMode: wsState.rightMainPanelMode,
isLeftMainPanelVisible: wsState.isLeftMainPanelVisible,
// Global state (sidebars)
isLeftSidebarVisible,
isRightSidebarVisible,
// Workspace-specific actions
toggleRightMainPanelMode: toggleRightMainPanelModeForWorkspace,
setRightMainPanelMode: setRightMainPanelModeForWorkspace,
setLeftMainPanelVisible: setLeftMainPanelVisibleForWorkspace,
// Global actions
setLeftSidebarVisible,
};
}