feat(updater): download and prepare desktop updates in background

This commit is contained in:
二丫讲梵 authored and GitHub committed 2026-09-10 11:44:18 +08:00
1 parent 7affad8ae0
commit e96af4aa30
77 files changed
+10536 -814

No files matched your search

+15 -8
View File
@@ -1,3 +1,4 @@
import { UPDATE_RESTORE_KEY, assertUpdateAllowsInteraction } from "@/lib/app/updatePreparation";
import { defineStore } from "pinia";
import { uuid } from "@/lib/common/utils";
import { computed, markRaw, nextTick, onScopeDispose, reactive, ref, watch } from "vue";
@@ -741,7 +742,7 @@ function restoreSavedTabsFromPayload(
payload: { tabs?: unknown; activeTabId?: unknown; groups?: unknown; focusedGroupId?: unknown; orientation?: unknown; sizes?: unknown } | null | undefined,
options: { validConnectionIds?: Iterable<string> } = {},
): { tabs: QueryTab[]; activeTabId: string | null; workspace?: unknown } {
const restoreMode = useSettingsStore().editorSettings.openTabsRestoreMode;
const restoreMode = safeLocalStorageGet(UPDATE_RESTORE_KEY) === "1" ? "all" : useSettingsStore().editorSettings.openTabsRestoreMode;
if (restoreMode === "none") {
return { tabs: [], activeTabId: null, workspace: undefined };
}
@@ -764,7 +765,7 @@ function restoreSavedTabsFromPayload(
}
function restoreLegacySavedTabs(options: { validConnectionIds?: Iterable<string> } = {}): { tabs: QueryTab[]; activeTabId: string | null; workspace?: undefined } {
const restoreMode = useSettingsStore().editorSettings.openTabsRestoreMode;
const restoreMode = safeLocalStorageGet(UPDATE_RESTORE_KEY) === "1" ? "all" : useSettingsStore().editorSettings.openTabsRestoreMode;
if (restoreMode === "none") {
return { tabs: [], activeTabId: null, workspace: undefined };
}
@@ -1034,6 +1035,7 @@ export const useQueryStore = defineStore("query", () => {
* the new tab ownerless until a post-flush watcher repaired the groups.
*/
function registerOpenTab(tab: QueryTab, options: { activate?: boolean; insertAfterTabId?: string } = {}): string {
assertUpdateAllowsInteraction();
const anchorIndex = options.insertAfterTabId ? tabs.value.findIndex((item) => item.id === options.insertAfterTabId) : -1;
if (anchorIndex >= 0) {
tabs.value.splice(anchorIndex + 1, 0, tab);
@@ -2215,7 +2217,7 @@ export const useQueryStore = defineStore("query", () => {
if (saved?.tabs && Array.isArray(saved.tabs)) {
const restored = restoreSavedTabsFromPayload(saved, options);
applyRestoredOpenTabs(restored);
if (useSettingsStore().editorSettings.openTabsRestoreMode === "none") {
if (safeLocalStorageGet(UPDATE_RESTORE_KEY) !== "1" && useSettingsStore().editorSettings.openTabsRestoreMode === "none") {
// Restore is explicitly disabled, so stale saved payloads should not
// reappear if the user later changes the setting.
clearLegacySavedTabs();
@@ -2223,6 +2225,7 @@ export const useQueryStore = defineStore("query", () => {
}
await recoverDetachedTabsToMain(options);
await saveTabs(tabs.value, activeTabId.value).catch(() => undefined);
safeLocalStorageRemove(UPDATE_RESTORE_KEY);
isOpenTabsLoaded.value = true;
scheduleResultCacheMaintenance();
return;
@@ -2232,7 +2235,7 @@ export const useQueryStore = defineStore("query", () => {
if (legacy.rawTabs || legacy.rawActiveTabId) {
const restored = restoreLegacySavedTabs(options);
applyRestoredOpenTabs(restored);
if (useSettingsStore().editorSettings.openTabsRestoreMode === "none") {
if (safeLocalStorageGet(UPDATE_RESTORE_KEY) !== "1" && useSettingsStore().editorSettings.openTabsRestoreMode === "none") {
// Restore is explicitly disabled, so keeping the legacy startup payload
// would resurrect old tabs if the user later changes the setting.
clearLegacySavedTabs();
@@ -2287,6 +2290,7 @@ export const useQueryStore = defineStore("query", () => {
autoCommit: t.autoCommit,
resultAutoSave: t.resultAutoSave,
structureTableName: t.structureTableName,
structureDraft: t.structureDraft,
objectBrowser: t.objectBrowser,
objectSource: t.objectSource,
sourceView: t.sourceView,
@@ -2431,7 +2435,7 @@ export const useQueryStore = defineStore("query", () => {
// A freshly created detached window never runs the main-window bootstrap that
// populates savedSqlStore's local file index, so useSavedSqlStore().ensureFileContent()
// can't find the file locally either — go straight to the backend instead.
if (restoredTab.savedSqlId && restoredTab.mode === "query" && !restoredTab.sql) {
if (restoredTab.savedSqlId && restoredTab.mode === "query" && !restoredTab.sql && restoredTab.originalSql === undefined) {
const file = await api.loadSavedSqlFile(restoredTab.savedSqlId).catch(() => undefined);
if (file) {
restoredTab.title = restoredTab.customTitle ? restoredTab.title : file.name;
@@ -3155,7 +3159,7 @@ export const useQueryStore = defineStore("query", () => {
return !!tab.structureDraft && tab.structureDraft.dirty !== false;
}
if (tab.mode !== "query") return false;
if (!tab.externalSqlPath && !tab.sql.trim()) return false;
if (!tab.externalSqlPath && !tab.sql.trim() && !(tab.savedSqlId && tab.originalSql !== undefined)) return false;
const original = tab.originalSql;
if (original === undefined) return !!tab.savedSqlId;
return tab.sql !== original;
@@ -4277,7 +4281,7 @@ export const useQueryStore = defineStore("query", () => {
const existing = tabs.value.find((tab) => tab.savedSqlId === file.id);
if (existing) {
persistSavedSqlEditorPosition(existing);
if (!existing.sql && file.sql) {
if (!existing.sql && file.sql && existing.originalSql === undefined) {
existing.sql = file.sql;
existing.originalSql = file.sql;
const restored = restoreSavedSqlEditorPosition(file.id, file.sql);
@@ -4317,7 +4321,7 @@ export const useQueryStore = defineStore("query", () => {
async function hydrateSavedSqlTabs() {
await initSavedSqlEditorPositions();
const savedSqlStore = useSavedSqlStore();
const linkedTabs = tabs.value.filter((tab) => tab.savedSqlId && tab.sql === "");
const linkedTabs = tabs.value.filter((tab) => tab.savedSqlId && tab.sql === "" && tab.originalSql === undefined);
for (const tab of linkedTabs) {
const file = await savedSqlStore.ensureFileContent(tab.savedSqlId!);
if (!file) continue;
@@ -4602,6 +4606,7 @@ export const useQueryStore = defineStore("query", () => {
}
async function executeCurrentTab() {
assertUpdateAllowsInteraction();
const tab = tabs.value.find((t) => t.id === activeTabId.value);
if (!tab || !tab.sql.trim()) return;
@@ -5525,6 +5530,7 @@ export const useQueryStore = defineStore("query", () => {
batchResume?: BatchSqlResumeOptions;
},
) {
assertUpdateAllowsInteraction();
const tab = findExecutionTab(id);
if (!tab || !sql.trim()) return;
@@ -6780,6 +6786,7 @@ export const useQueryStore = defineStore("query", () => {
}
async function explainTabSql(id: string, sql: string, databaseType?: DatabaseType, explainMode?: string) {
assertUpdateAllowsInteraction();
const tab = tabs.value.find((t) => t.id === id);
if (!tab) return { ok: false as const, reason: "empty" as const };
const conn = useConnectionStore().getConfig(tab.connectionId);