Skip to content

Commit 7c8c150

Browse files
committed
fix: refresh renderer stores after workspace change
When the user changes workspace via SystemSection, the main process re-initializes the database but the renderer's Zustand stores still hold stale data from the old workspace. This fix emits a 'workspace:changed' IPC event from the main process after the workspace swap succeeds. The renderer subscribes to this event and clears/re-hydrates task store, message store, dashboard store, usage store, and approval store so the UI reflects the new workspace contents without requiring a manual refresh or relaunch. Fixes #404
1 parent ec0d61a commit 7c8c150

4 files changed

Lines changed: 38 additions & 0 deletions

File tree

packages/desktop/src/main/ipc/workspace-handlers.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ export function registerWorkspaceHandlers(): void {
5656
await migrateWorkspace(oldPath, newWorkspacePath);
5757
reinitDatabase(newWorkspacePath);
5858
updateConfig({ workspacePath: newWorkspacePath });
59+
const win = BrowserWindow.getAllWindows()[0];
60+
if (win) win.webContents.send('workspace:changed', newWorkspacePath);
5961
return { ok: true };
6062
} catch (err) {
6163
reinitDatabase(oldPath);

packages/desktop/src/preload/clawwork.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,7 @@ export interface ClawWorkAPI {
350350
browseWorkspace: () => Promise<string | null>;
351351
setupWorkspace: (path: string) => Promise<IpcResult>;
352352
changeWorkspace: (path: string) => Promise<IpcResult>;
353+
onWorkspaceChanged: (callback: (newPath: string) => void) => () => void;
353354

354355
getSettings: () => Promise<AppSettings | null>;
355356
updateSettings: (partial: Partial<AppSettings>) => Promise<{ ok: boolean; config: AppSettings }>;

packages/desktop/src/preload/index.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,16 @@ function buildApi(): ClawWorkAPI {
345345

346346
setWindowButtonVisibility: (visible: boolean) => ipcRenderer.send('ui:set-window-button-visibility', visible),
347347

348+
onWorkspaceChanged: (callback) => {
349+
const listener = (_event: Electron.IpcRendererEvent, newPath: string): void => {
350+
callback(newPath);
351+
};
352+
ipcRenderer.on('workspace:changed', listener);
353+
return () => {
354+
ipcRenderer.removeListener('workspace:changed', listener);
355+
};
356+
},
357+
348358
getDeviceId: () => ipcRenderer.invoke('workspace:get-device-id') as Promise<string>,
349359

350360
selectContextFolder: () => ipcRenderer.invoke('context:select-folder'),

packages/desktop/src/renderer/layouts/Settings/sections/SystemSection.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
import { useState, useEffect, useCallback } from 'react';
2+
import { useTaskStore } from '../../../platform';
3+
import { useMessageStore } from '../../../platform';
4+
import { useDashboardStore } from '@/stores/dashboardStore';
5+
import { useUsageStore } from '@/stores/usageStore';
6+
import { useApprovalStore } from '@/stores/approvalStore';
27
import { MonitorDot, Zap, FolderOpen, Loader2, ExternalLink } from 'lucide-react';
38
import { useTranslation } from 'react-i18next';
49
import { toast } from '@/lib/toast';
@@ -64,6 +69,26 @@ export default function SystemSection() {
6469
[quickLaunchShortcut, t],
6570
);
6671

72+
// When main process signals workspace changed, clear and re-hydrate stores
73+
useEffect(() => {
74+
return window.clawwork.onWorkspaceChanged(async () => {
75+
// Clear task store and re-hydrate from new DB
76+
useTaskStore.setState({ tasks: [], activeTaskId: null, hydrated: false });
77+
useTaskStore.getState().hydrate();
78+
79+
// Clear message store
80+
useMessageStore.setState({ messagesByTask: {}, activeTurnBySession: {}, processingBySession: new Set() });
81+
82+
// Clear dashboard, usage, and approval caches
83+
useDashboardStore.getState().clear();
84+
useUsageStore.getState().clear();
85+
useApprovalStore.getState().clear();
86+
87+
// Refresh settings to pick up new workspace config
88+
await refreshSettings().catch(() => {});
89+
});
90+
}, [refreshSettings]);
91+
6792
const handleChangeWorkspace = useCallback(async () => {
6893
let selected: string | null = null;
6994
try {

0 commit comments

Comments
 (0)