fix(settings): preserve legacy browse-objects behavior on activation

This commit is contained in:
zipg authored and GitHub committed 2026-09-08 11:56:18 +08:00
1 parent 8642e1a599
commit 04ab5ec96e
3 files changed
+68 -6

No files matched your search

@@ -5,6 +5,7 @@ import {
AI_PROVIDER_PRESETS, AI_PROVIDER_PRESETS,
DEFAULT_EDITOR_SETTINGS, DEFAULT_EDITOR_SETTINGS,
EXECUTE_MODE_CURRENT_DEFAULT_VERSION, EXECUTE_MODE_CURRENT_DEFAULT_VERSION,
SIDEBAR_BROWSE_OBJECTS_MIGRATION_VERSION,
enforceRightSidebarPanelExclusivity, enforceRightSidebarPanelExclusivity,
normalizeAiConfig, normalizeAiConfig,
normalizeDesktopSettings, normalizeDesktopSettings,
@@ -1156,6 +1157,7 @@ describe("settingsStore editor settings persistence", () => {
const loadEditorSettings = vi.fn().mockResolvedValue({ const loadEditorSettings = vi.fn().mockResolvedValue({
ignoredUpdateVersion: "", ignoredUpdateVersion: "",
executeModeDefaultVersion: EXECUTE_MODE_CURRENT_DEFAULT_VERSION, executeModeDefaultVersion: EXECUTE_MODE_CURRENT_DEFAULT_VERSION,
sidebarBrowseObjectsOnDatabaseActivationMigrationVersion: SIDEBAR_BROWSE_OBJECTS_MIGRATION_VERSION,
}); });
const saveEditorSettings = vi.fn().mockRejectedValueOnce(new Error("save failed")).mockResolvedValueOnce(undefined); const saveEditorSettings = vi.fn().mockRejectedValueOnce(new Error("save failed")).mockResolvedValueOnce(undefined);
vi.doMock("@/lib/backend/api", () => ({ loadEditorSettings, saveEditorSettings })); vi.doMock("@/lib/backend/api", () => ({ loadEditorSettings, saveEditorSettings }));
@@ -1202,6 +1204,7 @@ describe("settingsStore editor settings persistence", () => {
const loadEditorSettings = vi.fn().mockResolvedValue({ const loadEditorSettings = vi.fn().mockResolvedValue({
ignoredUpdateVersion: "", ignoredUpdateVersion: "",
executeModeDefaultVersion: EXECUTE_MODE_CURRENT_DEFAULT_VERSION, executeModeDefaultVersion: EXECUTE_MODE_CURRENT_DEFAULT_VERSION,
sidebarBrowseObjectsOnDatabaseActivationMigrationVersion: SIDEBAR_BROWSE_OBJECTS_MIGRATION_VERSION,
}); });
const saveEditorSettings = vi.fn().mockImplementationOnce( const saveEditorSettings = vi.fn().mockImplementationOnce(
() => () =>
@@ -1237,6 +1240,7 @@ describe("settingsStore editor settings persistence", () => {
ignoredUpdateVersion: "", ignoredUpdateVersion: "",
theme: "system", theme: "system",
executeModeDefaultVersion: EXECUTE_MODE_CURRENT_DEFAULT_VERSION, executeModeDefaultVersion: EXECUTE_MODE_CURRENT_DEFAULT_VERSION,
sidebarBrowseObjectsOnDatabaseActivationMigrationVersion: SIDEBAR_BROWSE_OBJECTS_MIGRATION_VERSION,
}); });
const saveEditorSettings = vi.fn().mockImplementationOnce( const saveEditorSettings = vi.fn().mockImplementationOnce(
() => () =>
+18 -3
View File
@@ -823,6 +823,7 @@ export interface EditorSettings {
sidebarGlobalSearchLocal: boolean; sidebarGlobalSearchLocal: boolean;
autoSelectActiveSidebarNode: boolean; autoSelectActiveSidebarNode: boolean;
sidebarBrowseObjectsOnDatabaseActivation: boolean; sidebarBrowseObjectsOnDatabaseActivation: boolean;
sidebarBrowseObjectsOnDatabaseActivationMigrationVersion: number;
openTabsRestoreMode: OpenTabsRestoreMode; openTabsRestoreMode: OpenTabsRestoreMode;
disconnectTabHandlingMode: DisconnectTabHandlingMode; disconnectTabHandlingMode: DisconnectTabHandlingMode;
dataTabReuseMode: DataTabReuseMode; dataTabReuseMode: DataTabReuseMode;
@@ -951,6 +952,7 @@ export const EDITOR_THEMES: {
const EDITOR_THEME_VALUES = new Set<EditorTheme>(EDITOR_THEMES.map((theme) => theme.value)); const EDITOR_THEME_VALUES = new Set<EditorTheme>(EDITOR_THEMES.map((theme) => theme.value));
export const EXECUTE_MODE_CURRENT_DEFAULT_VERSION = 1; export const EXECUTE_MODE_CURRENT_DEFAULT_VERSION = 1;
export const SIDEBAR_BROWSE_OBJECTS_MIGRATION_VERSION = 1;
export const DEFAULT_EDITOR_SETTINGS: EditorSettings = { export const DEFAULT_EDITOR_SETTINGS: EditorSettings = {
fontFamily: "'Fira Code', 'Cascadia Code', 'Cascadia Mono', 'JetBrains Mono', monospace", fontFamily: "'Fira Code', 'Cascadia Code', 'Cascadia Mono', 'JetBrains Mono', monospace",
@@ -1055,6 +1057,7 @@ export const DEFAULT_EDITOR_SETTINGS: EditorSettings = {
sidebarGlobalSearchLocal: false, sidebarGlobalSearchLocal: false,
autoSelectActiveSidebarNode: false, autoSelectActiveSidebarNode: false,
sidebarBrowseObjectsOnDatabaseActivation: false, sidebarBrowseObjectsOnDatabaseActivation: false,
sidebarBrowseObjectsOnDatabaseActivationMigrationVersion: SIDEBAR_BROWSE_OBJECTS_MIGRATION_VERSION,
openTabsRestoreMode: "all", openTabsRestoreMode: "all",
disconnectTabHandlingMode: "close-tabs", disconnectTabHandlingMode: "close-tabs",
dataTabReuseMode: DEFAULT_DATA_TAB_REUSE_MODE, dataTabReuseMode: DEFAULT_DATA_TAB_REUSE_MODE,
@@ -1359,6 +1362,7 @@ function normalizeTableInfoTab(value: unknown): TableInfoTab {
export function normalizeEditorSettings(settings: Partial<EditorSettings>, existing?: EditorSettings): EditorSettings { export function normalizeEditorSettings(settings: Partial<EditorSettings>, existing?: EditorSettings): EditorSettings {
const legacyTimeoutSettings = settings as Partial<EditorSettings> & { queryTimeoutSecs?: unknown; queryTimeoutInheritanceMigrationVersion?: unknown }; const legacyTimeoutSettings = settings as Partial<EditorSettings> & { queryTimeoutSecs?: unknown; queryTimeoutInheritanceMigrationVersion?: unknown };
const legacySidebarOpenDatabaseOnSingleClick = (settings as Partial<EditorSettings> & { sidebarOpenDatabaseOnSingleClick?: unknown }).sidebarOpenDatabaseOnSingleClick;
const sqlSemanticDiagnosticsMode = normalizeSqlSemanticDiagnosticsMode(settings.sqlSemanticDiagnosticsMode, settings.sqlSemanticDiagnosticsEnabled); const sqlSemanticDiagnosticsMode = normalizeSqlSemanticDiagnosticsMode(settings.sqlSemanticDiagnosticsMode, settings.sqlSemanticDiagnosticsEnabled);
const savedExecuteModeDefaultVersion = settings.executeModeDefaultVersion; const savedExecuteModeDefaultVersion = settings.executeModeDefaultVersion;
const executeModeDefaultVersion = typeof savedExecuteModeDefaultVersion === "number" && savedExecuteModeDefaultVersion >= EXECUTE_MODE_CURRENT_DEFAULT_VERSION ? savedExecuteModeDefaultVersion : EXECUTE_MODE_CURRENT_DEFAULT_VERSION; const executeModeDefaultVersion = typeof savedExecuteModeDefaultVersion === "number" && savedExecuteModeDefaultVersion >= EXECUTE_MODE_CURRENT_DEFAULT_VERSION ? savedExecuteModeDefaultVersion : EXECUTE_MODE_CURRENT_DEFAULT_VERSION;
@@ -1504,9 +1508,14 @@ export function normalizeEditorSettings(settings: Partial<EditorSettings>, exist
sidebarBrowseObjectsOnDatabaseActivation: sidebarBrowseObjectsOnDatabaseActivation:
typeof settings.sidebarBrowseObjectsOnDatabaseActivation === "boolean" typeof settings.sidebarBrowseObjectsOnDatabaseActivation === "boolean"
? settings.sidebarBrowseObjectsOnDatabaseActivation ? settings.sidebarBrowseObjectsOnDatabaseActivation
: typeof (settings as Partial<EditorSettings> & { sidebarOpenDatabaseOnSingleClick?: unknown }).sidebarOpenDatabaseOnSingleClick === "boolean" : typeof legacySidebarOpenDatabaseOnSingleClick === "boolean"
? (settings as Partial<EditorSettings> & { sidebarOpenDatabaseOnSingleClick: boolean }).sidebarOpenDatabaseOnSingleClick ? // The legacy false value only disabled single-click browsing; double-click still opened the browser.
true
: DEFAULT_EDITOR_SETTINGS.sidebarBrowseObjectsOnDatabaseActivation, : DEFAULT_EDITOR_SETTINGS.sidebarBrowseObjectsOnDatabaseActivation,
sidebarBrowseObjectsOnDatabaseActivationMigrationVersion:
typeof settings.sidebarBrowseObjectsOnDatabaseActivationMigrationVersion === "number" && settings.sidebarBrowseObjectsOnDatabaseActivationMigrationVersion >= SIDEBAR_BROWSE_OBJECTS_MIGRATION_VERSION
? Math.floor(settings.sidebarBrowseObjectsOnDatabaseActivationMigrationVersion)
: SIDEBAR_BROWSE_OBJECTS_MIGRATION_VERSION,
openTabsRestoreMode: normalizeOpenTabsRestoreMode( openTabsRestoreMode: normalizeOpenTabsRestoreMode(
(settings as Partial<EditorSettings>).openTabsRestoreMode, (settings as Partial<EditorSettings>).openTabsRestoreMode,
( (
@@ -1739,11 +1748,17 @@ export const useSettingsStore = defineStore("settings", () => {
if (saved && typeof saved === "object" && !Array.isArray(saved)) { if (saved && typeof saved === "object" && !Array.isArray(saved)) {
const savedSettings = saved as Partial<EditorSettings>; const savedSettings = saved as Partial<EditorSettings>;
const normalized = normalizeEditorSettings(savedSettings); const normalized = normalizeEditorSettings(savedSettings);
const needsSidebarBrowseObjectsMigration = typeof savedSettings.sidebarBrowseObjectsOnDatabaseActivationMigrationVersion !== "number" || savedSettings.sidebarBrowseObjectsOnDatabaseActivationMigrationVersion < SIDEBAR_BROWSE_OBJECTS_MIGRATION_VERSION;
if (needsSidebarBrowseObjectsMigration) {
// Before this migration, a false value still preserved double-click browsing.
normalized.sidebarBrowseObjectsOnDatabaseActivation = true;
normalized.sidebarBrowseObjectsOnDatabaseActivationMigrationVersion = SIDEBAR_BROWSE_OBJECTS_MIGRATION_VERSION;
}
editorSettings.value = normalized; editorSettings.value = normalized;
const needsExecuteModeDefaultMigration = typeof savedSettings.executeModeDefaultVersion !== "number" || savedSettings.executeModeDefaultVersion < EXECUTE_MODE_CURRENT_DEFAULT_VERSION; const needsExecuteModeDefaultMigration = typeof savedSettings.executeModeDefaultVersion !== "number" || savedSettings.executeModeDefaultVersion < EXECUTE_MODE_CURRENT_DEFAULT_VERSION;
const needsTabNavigationShortcutMigration = needsTabNavigationHistoryShortcutMigration(savedSettings.shortcuts); const needsTabNavigationShortcutMigration = needsTabNavigationHistoryShortcutMigration(savedSettings.shortcuts);
const savedUpdateDownloadSource = (saved as { updateDownloadSource?: unknown }).updateDownloadSource; const savedUpdateDownloadSource = (saved as { updateDownloadSource?: unknown }).updateDownloadSource;
if (savedUpdateDownloadSource === "atomgit" || needsExecuteModeDefaultMigration || needsTabNavigationShortcutMigration) { if (savedUpdateDownloadSource === "atomgit" || needsExecuteModeDefaultMigration || needsTabNavigationShortcutMigration || needsSidebarBrowseObjectsMigration) {
// Persist one-time migrations so removed or unsafe defaults cannot reappear. // Persist one-time migrations so removed or unsafe defaults cannot reappear.
await enqueueEditorSettingsSave().catch(() => {}); await enqueueEditorSettingsSave().catch(() => {});
} }
+46 -3
View File
@@ -6,7 +6,18 @@ import { DEFAULT_SQL_FORMATTER_SETTINGS } from "../../apps/desktop/src/lib/sql/s
import { DEFAULT_TABLE_COLUMN_TEMPLATE_FIELDS } from "../../apps/desktop/src/lib/table/tableColumnTemplates.ts"; import { DEFAULT_TABLE_COLUMN_TEMPLATE_FIELDS } from "../../apps/desktop/src/lib/table/tableColumnTemplates.ts";
import { DEFAULT_DATA_GRID_FONT_FAMILY, DEFAULT_UI_FONT_FAMILY, SYSTEM_UI_FONT_FAMILY } from "../../apps/desktop/src/lib/app/appFonts.ts"; import { DEFAULT_DATA_GRID_FONT_FAMILY, DEFAULT_UI_FONT_FAMILY, SYSTEM_UI_FONT_FAMILY } from "../../apps/desktop/src/lib/app/appFonts.ts";
import { tableOpenPageLimit } from "../../apps/desktop/src/lib/table/tableOpenPageLimit.ts"; import { tableOpenPageLimit } from "../../apps/desktop/src/lib/table/tableOpenPageLimit.ts";
import { AI_PROVIDER_PARTNER_PRESETS, AI_PROVIDER_PRESETS, DEFAULT_EDITOR_SETTINGS, EXECUTE_MODE_CURRENT_DEFAULT_VERSION, getAiProviderPreset, getAiProviderPresetId, normalizeAiConfig, normalizeEditorSettings, useSettingsStore } from "../../apps/desktop/src/stores/settingsStore.ts"; import {
AI_PROVIDER_PARTNER_PRESETS,
AI_PROVIDER_PRESETS,
DEFAULT_EDITOR_SETTINGS,
EXECUTE_MODE_CURRENT_DEFAULT_VERSION,
SIDEBAR_BROWSE_OBJECTS_MIGRATION_VERSION,
getAiProviderPreset,
getAiProviderPresetId,
normalizeAiConfig,
normalizeEditorSettings,
useSettingsStore,
} from "../../apps/desktop/src/stores/settingsStore.ts";
import { DEFAULT_SHORTCUT_SETTINGS, tabNavigationHistoryDefaultShortcut, type ShortcutSettings } from "../../apps/desktop/src/lib/editor/shortcutRegistry.ts"; import { DEFAULT_SHORTCUT_SETTINGS, tabNavigationHistoryDefaultShortcut, type ShortcutSettings } from "../../apps/desktop/src/lib/editor/shortcutRegistry.ts";
const saveEditorSettingsMock = vi.hoisted(() => vi.fn()); const saveEditorSettingsMock = vi.hoisted(() => vi.fn());
@@ -506,13 +517,45 @@ test("defaults sidebar activation to single click", () => {
assert.equal(normalizeEditorSettings({}).sidebarActivation, "single"); assert.equal(normalizeEditorSettings({}).sidebarActivation, "single");
}); });
test("defaults database activation browsing to off and migrates the previous single-click setting", () => { test("preserves object browsing for legacy sidebar settings", () => {
assert.equal(DEFAULT_EDITOR_SETTINGS.sidebarBrowseObjectsOnDatabaseActivation, false); assert.equal(DEFAULT_EDITOR_SETTINGS.sidebarBrowseObjectsOnDatabaseActivation, false);
assert.equal(DEFAULT_EDITOR_SETTINGS.sidebarBrowseObjectsOnDatabaseActivationMigrationVersion, SIDEBAR_BROWSE_OBJECTS_MIGRATION_VERSION);
assert.equal(normalizeEditorSettings({}).sidebarBrowseObjectsOnDatabaseActivation, false); assert.equal(normalizeEditorSettings({}).sidebarBrowseObjectsOnDatabaseActivation, false);
assert.equal(normalizeEditorSettings({ sidebarBrowseObjectsOnDatabaseActivation: true }).sidebarBrowseObjectsOnDatabaseActivation, true); assert.equal(normalizeEditorSettings({ sidebarBrowseObjectsOnDatabaseActivation: true }).sidebarBrowseObjectsOnDatabaseActivation, true);
assert.equal(normalizeEditorSettings({ sidebarBrowseObjectsOnDatabaseActivation: false }).sidebarBrowseObjectsOnDatabaseActivation, false);
assert.equal(normalizeEditorSettings({ sidebarBrowseObjectsOnDatabaseActivation: "yes" as any }).sidebarBrowseObjectsOnDatabaseActivation, false); assert.equal(normalizeEditorSettings({ sidebarBrowseObjectsOnDatabaseActivation: "yes" as any }).sidebarBrowseObjectsOnDatabaseActivation, false);
assert.equal(normalizeEditorSettings({ sidebarOpenDatabaseOnSingleClick: true } as any).sidebarBrowseObjectsOnDatabaseActivation, true); assert.equal(normalizeEditorSettings({ sidebarOpenDatabaseOnSingleClick: true } as any).sidebarBrowseObjectsOnDatabaseActivation, true);
assert.equal(normalizeEditorSettings({ sidebarOpenDatabaseOnSingleClick: false } as any).sidebarBrowseObjectsOnDatabaseActivation, false); assert.equal(normalizeEditorSettings({ sidebarOpenDatabaseOnSingleClick: false } as any).sidebarBrowseObjectsOnDatabaseActivation, true);
assert.equal(normalizeEditorSettings({ sidebarBrowseObjectsOnDatabaseActivation: false, sidebarOpenDatabaseOnSingleClick: true } as any).sidebarBrowseObjectsOnDatabaseActivation, false);
});
test("migrates existing settings once and preserves a later explicit opt-out", async () => {
await withMockLocalStorage(
{
"dbx-app-state:editor_settings": JSON.stringify({ sidebarBrowseObjectsOnDatabaseActivation: false }),
},
async () => {
setActivePinia(createPinia());
const migratedStore = useSettingsStore();
await migratedStore.initEditorSettings();
assert.equal(migratedStore.editorSettings.sidebarBrowseObjectsOnDatabaseActivation, true);
assert.equal(migratedStore.editorSettings.sidebarBrowseObjectsOnDatabaseActivationMigrationVersion, SIDEBAR_BROWSE_OBJECTS_MIGRATION_VERSION);
await vi.waitFor(() => {
const saved = JSON.parse(localStorage.getItem("dbx-app-state:editor_settings") || "{}") as Record<string, unknown>;
assert.equal(saved.sidebarBrowseObjectsOnDatabaseActivation, true);
assert.equal(saved.sidebarBrowseObjectsOnDatabaseActivationMigrationVersion, SIDEBAR_BROWSE_OBJECTS_MIGRATION_VERSION);
});
migratedStore.updateEditorSettings({ sidebarBrowseObjectsOnDatabaseActivation: false });
await vi.waitFor(() => assert.equal(migratedStore.editorSettings.sidebarBrowseObjectsOnDatabaseActivation, false));
setActivePinia(createPinia());
const reloadedStore = useSettingsStore();
await reloadedStore.initEditorSettings();
assert.equal(reloadedStore.editorSettings.sidebarBrowseObjectsOnDatabaseActivation, false);
},
);
}); });
test("defaults active tab sidebar selection to off", () => { test("defaults active tab sidebar selection to off", () => {