fix(desktop): close database tabs with connection

This commit is contained in:
t8y2 2026-06-01 20:21:42 +08:00
parent b9fa36763e
commit b4c469a69f
3 changed files with 78 additions and 0 deletions

View File

@ -1478,6 +1478,7 @@ async function closeDatabaseConnection() {
if (node.type !== "database" || !node.connectionId || node.database == null) return;
try {
await connectionStore.closeDatabaseConnection(node.connectionId, node.database);
queryStore.closeDatabaseTabs(node.connectionId, node.database);
toast(t("connection.databaseConnectionClosed", { name: node.label }), 2000);
} catch (e: any) {
toast(t("connection.saveFailed", { message: e?.message || String(e) }), 5000);

View File

@ -303,6 +303,32 @@ export const useQueryStore = defineStore("query", () => {
activeTabId.value = next.activeTabId;
}
function closeDatabaseTabs(connectionId: string, database: string) {
const closingModes = new Set<QueryTab["mode"]>(["data", "objects", "structure", "mongo"]);
const closingIds = new Set(
tabs.value
.filter((tab) => tab.connectionId === connectionId && tab.database === database && closingModes.has(tab.mode))
.map((tab) => tab.id),
);
if (closingIds.size === 0) return;
tabs.value
.filter((tab) => closingIds.has(tab.id))
.forEach((tab) => {
if (tab.isExecuting) void cancelTabExecution(tab.id);
if (tab.isExplaining) void cancelTabExplain(tab.id);
void closeResultSession(tab);
void closeClientConnectionSession(tab);
clearResultPayload(tab);
});
const activeClosingIndex = tabs.value.findIndex((tab) => tab.id === activeTabId.value && closingIds.has(tab.id));
tabs.value = tabs.value.filter((tab) => !closingIds.has(tab.id));
if (activeClosingIndex >= 0) {
activeTabId.value = tabs.value[Math.min(activeClosingIndex, tabs.value.length - 1)]?.id ?? null;
}
}
function updateSql(id: string, sql: string) {
const tab = tabs.value.find((t) => t.id === id);
if (tab) {
@ -1221,6 +1247,7 @@ export const useQueryStore = defineStore("query", () => {
closeTab,
closeOtherTabs,
closeAllTabs,
closeDatabaseTabs,
updateSql,
renameTab,
openObjectBrowser,

View File

@ -310,6 +310,56 @@ test("closing tabs clears removed result payloads before dropping tab references
}
});
test("closing database tabs removes browser tabs for that database only", async () => {
const restoreStorage = installMemoryStorage();
const originalFetch = globalThis.fetch;
globalThis.fetch = (async () => {
return new Response(JSON.stringify(true), { status: 200, headers: { "Content-Type": "application/json" } });
}) as typeof fetch;
try {
setActivePinia(createPinia());
const store = useQueryStore();
const dataId = store.createTab("conn-1", "db", "users", "data", "public");
const objectsId = store.openObjectBrowser("conn-1", "db", "public");
const structureId = store.openTableStructure("conn-1", "db", "public", "users");
const mongoId = store.createTab("conn-1", "db", "orders", "mongo");
const queryId = store.createTab("conn-1", "db", "draft query", "query");
const otherDbId = store.createTab("conn-1", "analytics", "users", "data", "public");
const otherConnectionId = store.createTab("conn-2", "db", "users", "data", "public");
const structureTab = store.tabs.find((item) => item.id === structureId);
assert.ok(structureTab);
structureTab.result = {
columns: ["payload"],
rows: [["structure"]],
affected_rows: 0,
execution_time_ms: 1,
session_id: "session-structure",
};
structureTab.resultSessionId = "session-structure";
store.activeTabId = structureId;
store.closeDatabaseTabs("conn-1", "db");
await new Promise((resolve) => setTimeout(resolve, 0));
assert.deepEqual(
store.tabs.map((tab) => tab.id),
[queryId, otherDbId, otherConnectionId],
);
assert.equal(store.activeTabId, otherConnectionId);
assert.equal(
store.tabs.some((tab) => [dataId, objectsId, structureId, mongoId].includes(tab.id)),
false,
);
assert.equal(structureTab.result, undefined);
assert.equal(structureTab.resultSessionId, undefined);
} finally {
globalThis.fetch = originalFetch;
restoreStorage();
}
});
test("starting a new query clears the previous result payload immediately", async () => {
const restoreStorage = installMemoryStorage();
setActivePinia(createPinia());