From 71027f141216a72a3687c573246f75f1a40657d3 Mon Sep 17 00:00:00 2001 From: t8y2 Date: Sun, 27 Sep 2026 14:57:36 +0800 Subject: [PATCH] fix(sql-library): hydrate restored tabs after startup --- apps/desktop/src/App.vue | 12 +++++-- .../app-tests/externalSqlFileStartup.test.ts | 2 ++ packages/app-tests/queryStore.test.ts | 36 +++++++++++++++++++ 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/apps/desktop/src/App.vue b/apps/desktop/src/App.vue index bcf4e533b7..85cbcf7dc3 100644 --- a/apps/desktop/src/App.vue +++ b/apps/desktop/src/App.vue @@ -3895,13 +3895,14 @@ function onLoginSuccess() { async function initApp() { const t0 = performance.now(); console.log("[STARTUP] initApp begin"); - void Promise.all([initSavedSqlEditorPositions(), savedSqlStore.initFromStorage()]) + const savedSqlInitialization = Promise.all([initSavedSqlEditorPositions(), savedSqlStore.initFromStorage()]) .then(() => { console.log(`[STARTUP] savedSqlStore.initFromStorage: ${(performance.now() - t0).toFixed(0)}ms`); - void queryStore.hydrateSavedSqlTabs(); + return true; }) .catch((e: any) => { toast(t("connection.loadFailed", { message: e?.message || String(e) }), 5000); + return false; }); const restoreOpenTabs = async () => { @@ -3931,6 +3932,13 @@ async function initApp() { onOptionalStateError: (error) => console.error("[STARTUP] settingsStore.initAiConfigs failed", error), }); } + void savedSqlInitialization + .then((initialized) => { + if (initialized) return queryStore.hydrateSavedSqlTabs(); + }) + .catch((e: any) => { + toast(t("connection.loadFailed", { message: e?.message || String(e) }), 5000); + }); await runPendingComponentUpdatesBeforePluginReconnect({ hasPendingComponentUpdates: () => !isDetachedWindowContext && hasPendingComponentUpdatesAfterAppRestart(), prepareStartup: async () => { diff --git a/packages/app-tests/externalSqlFileStartup.test.ts b/packages/app-tests/externalSqlFileStartup.test.ts index 0fd8fe9442..75624a1fbb 100644 --- a/packages/app-tests/externalSqlFileStartup.test.ts +++ b/packages/app-tests/externalSqlFileStartup.test.ts @@ -65,11 +65,13 @@ test("web startup uses the guarded initializer behind the existing authenticatio const webInitialization = initAppSource.indexOf("await initializeOpenTabs({"); const optionalInitialization = initAppSource.indexOf("initializeOptionalState: () => settingsStore.initAiConfigs()", webInitialization); const requiredRestoration = initAppSource.indexOf("restoreOpenTabs,", optionalInitialization); + const savedSqlHydration = initAppSource.indexOf("queryStore.hydrateSavedSqlTabs()", requiredRestoration); assert.ok(savedSqlInitialization >= 0); assert.ok(webInitialization >= 0); assert.ok(savedSqlInitialization < webInitialization); assert.ok(optionalInitialization > webInitialization); assert.ok(requiredRestoration > optionalInitialization); + assert.ok(savedSqlHydration > requiredRestoration); assert.equal(initAppSource.includes("if (!desktopOpenTabsRestorationBarrier) await settingsStore.initAiConfigs()"), false); const mountedStart = appSource.indexOf("onMounted(async () =>"); diff --git a/packages/app-tests/queryStore.test.ts b/packages/app-tests/queryStore.test.ts index 70de04b937..e63b2f2c9f 100644 --- a/packages/app-tests/queryStore.test.ts +++ b/packages/app-tests/queryStore.test.ts @@ -379,6 +379,42 @@ test("clean saved SQL tabs persist without duplicating SQL text", async () => { } }); +test("clean saved SQL tabs hydrate after their tabs finish restoring", async () => { + const restoreStorage = installMemoryStorage(); + const fullFile = { + id: "saved-startup-race", + connectionId: "conn-1", + name: "startup.sql", + database: "db", + sql: "SELECT 1;", + sqlLoaded: true, + createdAt: "2026-09-27T00:00:00.000Z", + updatedAt: "2026-09-27T00:00:00.000Z", + }; + try { + setActivePinia(createPinia()); + let store = useQueryStore(); + store.openSavedSql(fullFile); + await store.flushPendingPersist(); + + disposePinia(getActivePinia()!); + setActivePinia(createPinia()); + store = useQueryStore(); + const savedSqlStore = useSavedSqlStore(); + savedSqlStore.files = [fullFile]; + + await store.hydrateSavedSqlTabs(); + await store.initOpenTabs(); + await store.hydrateSavedSqlTabs(); + + const restored = store.tabs.find((tab) => tab.savedSqlId === fullFile.id); + assert.equal(restored?.sql, fullFile.sql); + assert.equal(restored?.originalSql, fullFile.sql); + } finally { + restoreStorage(); + } +}); + test("saved SQL opens with its saved execution target by default", async () => { const restoreStorage = installMemoryStorage(); try {