feat: confirm before closing unsaved SQL query tabs
This commit is contained in:
1 parent
51e2ef0d1f
commit
19b5b70fb7
6 files changed
+157
-5
No files matched your search
@@ -113,6 +113,8 @@ export const useQueryStore = defineStore("query", () => {
|
||||
const restored = loadSavedTabs();
|
||||
const tabs = ref<QueryTab[]>(restored.tabs);
|
||||
const activeTabId = ref<string | null>(restored.activeTabId);
|
||||
const showCloseConfirm = ref(false);
|
||||
const pendingCloseTabId = ref<string | null>(null);
|
||||
for (const tab of restored.tabs) {
|
||||
if (tab.mode === "data") void deleteTabResultSnapshot(tabResultCacheKey(tab.id));
|
||||
}
|
||||
@@ -263,6 +265,7 @@ export const useQueryStore = defineStore("query", () => {
|
||||
isExplaining: false,
|
||||
mode,
|
||||
};
|
||||
if (mode === "query") tab.originalSql = "";
|
||||
tabs.value.push(tab);
|
||||
activeTabId.value = id;
|
||||
return id;
|
||||
@@ -353,7 +356,26 @@ export const useQueryStore = defineStore("query", () => {
|
||||
return id;
|
||||
}
|
||||
|
||||
function closeTab(id: string) {
|
||||
function isTabDirty(tab: QueryTab): boolean {
|
||||
if (tab.mode !== "query") return false;
|
||||
if (!tab.sql.trim()) return false;
|
||||
const original = tab.originalSql;
|
||||
if (original === undefined) return !!tab.savedSqlId;
|
||||
return tab.sql !== original;
|
||||
}
|
||||
|
||||
function markTabClean(tab: QueryTab | undefined) {
|
||||
if (tab) tab.originalSql = tab.sql;
|
||||
}
|
||||
|
||||
function closeTab(id: string, { force = false }: { force?: boolean } = {}) {
|
||||
const tab = tabs.value.find((t) => t.id === id);
|
||||
if (!tab) return;
|
||||
if (!force && isTabDirty(tab)) {
|
||||
pendingCloseTabId.value = id;
|
||||
showCloseConfirm.value = true;
|
||||
return;
|
||||
}
|
||||
const idx = tabs.value.findIndex((t) => t.id === id);
|
||||
if (idx < 0) return;
|
||||
clearDataGridPendingSnapshotsForTab(id);
|
||||
@@ -368,6 +390,26 @@ export const useQueryStore = defineStore("query", () => {
|
||||
}
|
||||
}
|
||||
|
||||
function forceClosePendingTab() {
|
||||
const id = pendingCloseTabId.value;
|
||||
pendingCloseTabId.value = null;
|
||||
showCloseConfirm.value = false;
|
||||
if (id) closeTab(id, { force: true });
|
||||
}
|
||||
|
||||
function cancelClosePendingTab() {
|
||||
pendingCloseTabId.value = null;
|
||||
showCloseConfirm.value = false;
|
||||
}
|
||||
|
||||
function saveAndClosePendingTab() {
|
||||
const id = pendingCloseTabId.value;
|
||||
pendingCloseTabId.value = null;
|
||||
showCloseConfirm.value = false;
|
||||
if (id) return id;
|
||||
return null;
|
||||
}
|
||||
|
||||
function closeOtherTabs(id: string) {
|
||||
tabs.value
|
||||
.filter((tab) => tab.id !== id)
|
||||
@@ -568,6 +610,7 @@ export const useQueryStore = defineStore("query", () => {
|
||||
schema: file.schema,
|
||||
sql: file.sql,
|
||||
savedSqlId: file.id,
|
||||
originalSql: file.sql,
|
||||
isExecuting: false,
|
||||
isCancelling: false,
|
||||
isExplaining: false,
|
||||
@@ -1620,8 +1663,15 @@ export const useQueryStore = defineStore("query", () => {
|
||||
return {
|
||||
tabs,
|
||||
activeTabId,
|
||||
showCloseConfirm,
|
||||
pendingCloseTabId,
|
||||
createTab,
|
||||
closeTab,
|
||||
forceClosePendingTab,
|
||||
cancelClosePendingTab,
|
||||
saveAndClosePendingTab,
|
||||
isTabDirty,
|
||||
markTabClean,
|
||||
closeOtherTabs,
|
||||
closeAllTabs,
|
||||
duplicateTab,
|
||||
|
||||
Reference in new issue
Block a user