fix(desktop): stop windows from adopting each other's active project
Every window shares one server settings document, and every PUT returns the merged whole, so one window's activeProjectId write was adopted by the other on its next unrelated settings save — its sidebar then auto-selected a session in that project and wrote the pointer back, converging both windows onto one session. settings-synced now carries an adoptWorkspace flag: only bootstrap-grade syncs (startup, runtime switch) may adopt the shared workspace pointers; reconcile responses keep the window's own active project while it exists. Notification clicks and session deep links also stopped broadcasting the session switch to every window.
This commit is contained in:
@@ -199,11 +199,23 @@ const persistToLocalStorage = (settings: DesktopSettings) => {
|
||||
setOrRemoveLocalStorage('sttLanguage', typeof settings.sttLanguage === 'string' ? settings.sttLanguage : null);
|
||||
};
|
||||
|
||||
const dispatchSettingsSynced = (settings: DesktopSettings): void => {
|
||||
export interface SettingsSyncedDetail {
|
||||
settings: DesktopSettings;
|
||||
/** Whether listeners may adopt cross-window workspace pointers
|
||||
(activeProjectId / lastDirectory). True only for a bootstrap-grade sync:
|
||||
the settings document is shared by every window of this server, so a
|
||||
mid-session reconciliation adopting them would hijack this window's
|
||||
workspace with another window's choice. */
|
||||
adoptWorkspace: boolean;
|
||||
}
|
||||
|
||||
const dispatchSettingsSynced = (settings: DesktopSettings, adoptWorkspace: boolean): void => {
|
||||
if (typeof window === 'undefined') {
|
||||
return;
|
||||
}
|
||||
window.dispatchEvent(new CustomEvent<DesktopSettings>('openchamber:settings-synced', { detail: settings }));
|
||||
window.dispatchEvent(new CustomEvent<SettingsSyncedDetail>('openchamber:settings-synced', {
|
||||
detail: { settings, adoptWorkspace },
|
||||
}));
|
||||
};
|
||||
|
||||
type SettingsSaveState = 'idle' | 'saving' | 'error';
|
||||
@@ -1841,7 +1853,8 @@ export const invalidateSettingsCache = (): void => {
|
||||
_settingsCache = null;
|
||||
};
|
||||
|
||||
export const syncDesktopSettings = async (): Promise<void> => {
|
||||
export const syncDesktopSettings = async (options?: { adoptWorkspace?: boolean }): Promise<void> => {
|
||||
const adoptWorkspace = options?.adoptWorkspace !== false;
|
||||
if (typeof window === 'undefined') {
|
||||
return;
|
||||
}
|
||||
@@ -1970,7 +1983,7 @@ export const syncDesktopSettings = async (): Promise<void> => {
|
||||
if (!isSettingsRuntimeContextCurrent(context)) return;
|
||||
}
|
||||
|
||||
dispatchSettingsSynced(authoritativeSettings);
|
||||
dispatchSettingsSynced(authoritativeSettings, adoptWorkspace);
|
||||
};
|
||||
|
||||
try {
|
||||
@@ -2013,7 +2026,7 @@ async function _flushSettingsUpdate(): Promise<void> {
|
||||
if (updated) {
|
||||
const reconciled = _settingsMutationTracker.reconcile(updated, operation);
|
||||
applyDesktopUiPreferences(reconciled);
|
||||
dispatchSettingsSynced(reconciled);
|
||||
dispatchSettingsSynced(reconciled, false);
|
||||
_settingsCache = null;
|
||||
}
|
||||
dispatchSettingsSaveState(updated ? 'saved' : 'error');
|
||||
@@ -2047,7 +2060,7 @@ async function _flushSettingsUpdate(): Promise<void> {
|
||||
if (updated) {
|
||||
const reconciled = _settingsMutationTracker.reconcile(updated, operation);
|
||||
applyDesktopUiPreferences(reconciled);
|
||||
dispatchSettingsSynced(reconciled);
|
||||
dispatchSettingsSynced(reconciled, false);
|
||||
dispatchSettingsSaveState('saved');
|
||||
// Invalidate GET cache so next read sees the fresh data
|
||||
_settingsCache = null;
|
||||
|
||||
Reference in New Issue
Block a user