feat: add "reuse data tab" setting to avoid opening too many tabs when clicking table names
Add a configurable option in Settings > Navigation to reuse an existing data tab instead of creating a new one each time a table is clicked in the sidebar.
This commit is contained in:
parent
2a59304e02
commit
13e2cdde6f
|
|
@ -119,6 +119,7 @@ const editAutoSelectActiveSidebarNode = ref(settingsStore.editorSettings.autoSel
|
|||
const editDisconnectTabHandlingMode = ref<DisconnectTabHandlingMode>(
|
||||
settingsStore.editorSettings.disconnectTabHandlingMode,
|
||||
);
|
||||
const editReuseDataTab = ref(settingsStore.editorSettings.reuseDataTab);
|
||||
const editSidebarHiddenTablePrefixes = ref(settingsStore.editorSettings.sidebarHiddenTablePrefixes.join("\n"));
|
||||
const editSidebarHideTableComments = ref(settingsStore.editorSettings.sidebarHideTableComments);
|
||||
const editSidebarAllowHorizontalScroll = ref(settingsStore.editorSettings.sidebarAllowHorizontalScroll);
|
||||
|
|
@ -267,6 +268,7 @@ watch(
|
|||
editSidebarObjectDisplay.value = settingsStore.editorSettings.sidebarObjectDisplay;
|
||||
editAutoSelectActiveSidebarNode.value = settingsStore.editorSettings.autoSelectActiveSidebarNode;
|
||||
editDisconnectTabHandlingMode.value = settingsStore.editorSettings.disconnectTabHandlingMode;
|
||||
editReuseDataTab.value = settingsStore.editorSettings.reuseDataTab;
|
||||
editSidebarHiddenTablePrefixes.value = settingsStore.editorSettings.sidebarHiddenTablePrefixes.join("\n");
|
||||
editSidebarHideTableComments.value = settingsStore.editorSettings.sidebarHideTableComments;
|
||||
editSidebarAllowHorizontalScroll.value = settingsStore.editorSettings.sidebarAllowHorizontalScroll;
|
||||
|
|
@ -309,6 +311,7 @@ function hasChanges(): boolean {
|
|||
editSidebarObjectDisplay.value !== settingsStore.editorSettings.sidebarObjectDisplay ||
|
||||
editAutoSelectActiveSidebarNode.value !== settingsStore.editorSettings.autoSelectActiveSidebarNode ||
|
||||
editDisconnectTabHandlingMode.value !== settingsStore.editorSettings.disconnectTabHandlingMode ||
|
||||
editReuseDataTab.value !== settingsStore.editorSettings.reuseDataTab ||
|
||||
editSidebarHideTableComments.value !== settingsStore.editorSettings.sidebarHideTableComments ||
|
||||
editSidebarAllowHorizontalScroll.value !== settingsStore.editorSettings.sidebarAllowHorizontalScroll ||
|
||||
editExportBatchSize.value !== settingsStore.editorSettings.exportBatchSize ||
|
||||
|
|
@ -338,6 +341,7 @@ async function persistSettings() {
|
|||
sidebarObjectDisplay: editSidebarObjectDisplay.value,
|
||||
autoSelectActiveSidebarNode: editAutoSelectActiveSidebarNode.value,
|
||||
disconnectTabHandlingMode: editDisconnectTabHandlingMode.value,
|
||||
reuseDataTab: editReuseDataTab.value,
|
||||
sidebarHideTableComments: editSidebarHideTableComments.value,
|
||||
sidebarAllowHorizontalScroll: editSidebarAllowHorizontalScroll.value,
|
||||
sidebarHiddenTablePrefixes: normalizeSidebarHiddenTablePrefixes(editSidebarHiddenTablePrefixes.value),
|
||||
|
|
@ -380,6 +384,7 @@ function resetDefaults() {
|
|||
editSidebarObjectDisplay.value = DEFAULT_EDITOR_SETTINGS.sidebarObjectDisplay;
|
||||
editAutoSelectActiveSidebarNode.value = DEFAULT_EDITOR_SETTINGS.autoSelectActiveSidebarNode;
|
||||
editDisconnectTabHandlingMode.value = DEFAULT_EDITOR_SETTINGS.disconnectTabHandlingMode;
|
||||
editReuseDataTab.value = DEFAULT_EDITOR_SETTINGS.reuseDataTab;
|
||||
editSidebarHideTableComments.value = DEFAULT_EDITOR_SETTINGS.sidebarHideTableComments;
|
||||
editSidebarAllowHorizontalScroll.value = DEFAULT_EDITOR_SETTINGS.sidebarAllowHorizontalScroll;
|
||||
editSidebarHiddenTablePrefixes.value = DEFAULT_EDITOR_SETTINGS.sidebarHiddenTablePrefixes.join("\n");
|
||||
|
|
@ -1466,6 +1471,20 @@ watch(
|
|||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between gap-4 rounded-md border bg-muted/20 px-3 py-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<Label for="reuse-data-tab">{{ t("settings.reuseDataTab") }}</Label>
|
||||
<Tooltip>
|
||||
<TooltipTrigger as-child>
|
||||
<CircleHelp class="h-3.5 w-3.5 cursor-help text-muted-foreground hover:text-foreground" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent class="max-w-[320px] text-xs leading-relaxed" side="top" align="start">
|
||||
{{ t("settings.reuseDataTabDescription") }}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<Switch id="reuse-data-tab" v-model="editReuseDataTab" />
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<Label>{{ t("settings.sidebarObjectDisplay") }}</Label>
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
|
|
|
|||
|
|
@ -723,7 +723,20 @@ async function openData() {
|
|||
table: node.label,
|
||||
dbType: config?.db_type,
|
||||
});
|
||||
const tabId = queryStore.createTab(node.connectionId, node.database, node.label, "data", node.schema);
|
||||
const tabId = (() => {
|
||||
if (settingsStore.editorSettings.reuseDataTab) {
|
||||
const existing = queryStore.tabs.find(
|
||||
(tab) => tab.mode === "data" && tab.connectionId === node.connectionId && tab.database === node.database,
|
||||
);
|
||||
if (existing) {
|
||||
existing.title = node.label;
|
||||
existing.schema = node.schema;
|
||||
queryStore.activeTabId = existing.id;
|
||||
return existing.id;
|
||||
}
|
||||
}
|
||||
return queryStore.createTab(node.connectionId, node.database, node.label, "data", node.schema);
|
||||
})();
|
||||
console.info("[DBX][openData:tab-created]", { traceId, tabId, elapsed: elapsed() });
|
||||
queryStore.setExecuting(tabId, true);
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,20 @@ async function openTableTarget(target: NavigationTarget) {
|
|||
connectionStore.activeConnectionId = target.connectionId;
|
||||
const config = connectionStore.getConfig(target.connectionId);
|
||||
const tabTitle = target.schema ? `${target.schema}.${target.tableName}` : target.tableName;
|
||||
const tabId = queryStore.createTab(target.connectionId, target.database, tabTitle, "data", target.schema);
|
||||
const tabId = (() => {
|
||||
if (settingsStore.editorSettings.reuseDataTab) {
|
||||
const existing = queryStore.tabs.find(
|
||||
(tab) => tab.mode === "data" && tab.connectionId === target.connectionId && tab.database === target.database,
|
||||
);
|
||||
if (existing) {
|
||||
existing.title = tabTitle;
|
||||
existing.schema = target.schema;
|
||||
queryStore.activeTabId = existing.id;
|
||||
return existing.id;
|
||||
}
|
||||
}
|
||||
return queryStore.createTab(target.connectionId, target.database, tabTitle, "data", target.schema);
|
||||
})();
|
||||
queryStore.setExecuting(tabId, true);
|
||||
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -1637,6 +1637,9 @@ export default {
|
|||
disconnectTabHandlingModeKeepTabsKeepResults: "Do not close related tabs",
|
||||
disconnectTabHandlingModeKeepTabsKeepResultsDescription:
|
||||
"Keep related tabs, SQL text, and current results without extra cleanup.",
|
||||
reuseDataTab: "Reuse data tab",
|
||||
reuseDataTabDescription:
|
||||
"When clicking a table in the sidebar, reuse the existing data tab instead of creating a new one each time.",
|
||||
sidebarHiddenTablePrefixes: "Hidden table name prefixes",
|
||||
sidebarHiddenTablePrefixesDescription:
|
||||
"One prefix per line. Only sidebar table, view, and collection labels are shortened; tooltips and actions still use the full name.",
|
||||
|
|
|
|||
|
|
@ -1530,6 +1530,9 @@ export default {
|
|||
disconnectTabHandlingModeKeepTabsKeepResults: "No cerrar pestañas relacionadas",
|
||||
disconnectTabHandlingModeKeepTabsKeepResultsDescription:
|
||||
"Conserva las pestañas relacionadas, el texto SQL y los resultados actuales sin limpieza adicional.",
|
||||
reuseDataTab: "Reutilizar pestaña de datos",
|
||||
reuseDataTabDescription:
|
||||
"Al hacer clic en una tabla en la barra lateral, reutiliza la pestaña de datos existente en lugar de crear una nueva cada vez.",
|
||||
sidebarHiddenTablePrefixes: "Prefijos ocultos de tablas",
|
||||
sidebarHiddenTablePrefixesDescription:
|
||||
"Un prefijo por linea. Solo acorta etiquetas de tablas, vistas y colecciones en la barra lateral; las acciones y ayudas usan el nombre completo.",
|
||||
|
|
|
|||
|
|
@ -1602,6 +1602,8 @@ export default {
|
|||
"关闭表数据、对象浏览和结构等页签,保留 SQL 查询页签和 SQL 文本,同时清理执行状态与结果会话。",
|
||||
disconnectTabHandlingModeKeepTabsKeepResults: "不关闭相关页签",
|
||||
disconnectTabHandlingModeKeepTabsKeepResultsDescription: "保留相关页签、SQL 文本和当前结果,不做额外处理。",
|
||||
reuseDataTab: "复用数据标签页",
|
||||
reuseDataTabDescription: "单击侧边栏表名时,复用已有的数据标签页而不是创建新标签页,避免打开过多标签。",
|
||||
sidebarHiddenTablePrefixes: "隐藏表名前缀",
|
||||
sidebarHiddenTablePrefixesDescription:
|
||||
"每行一个前缀,仅影响侧边栏表、视图和集合的显示名称,悬浮提示和实际操作仍使用完整名称。",
|
||||
|
|
|
|||
|
|
@ -1580,6 +1580,8 @@ export default {
|
|||
"關閉資料表資料、物件瀏覽和結構等分頁,保留 SQL 查詢分頁與 SQL 文字,同時清理執行狀態與結果工作階段。",
|
||||
disconnectTabHandlingModeKeepTabsKeepResults: "不關閉相關分頁",
|
||||
disconnectTabHandlingModeKeepTabsKeepResultsDescription: "保留相關分頁、SQL 文字與目前結果,不另外做清理。",
|
||||
reuseDataTab: "重複使用資料分頁",
|
||||
reuseDataTabDescription: "點擊側邊欄資料表名稱時,重複使用現有的資料分頁而不是建立新分頁,避免開啟過多分頁。",
|
||||
sidebarHiddenTablePrefixes: "隱藏資料表名稱字首",
|
||||
sidebarHiddenTablePrefixesDescription:
|
||||
"每行一個字首。只縮短側邊欄中的資料表、檢視和集合標籤;工具提示和實際操作仍使用完整名稱。",
|
||||
|
|
|
|||
|
|
@ -214,6 +214,7 @@ export interface EditorSettings {
|
|||
sidebarObjectDisplay: "grouped" | "simple";
|
||||
autoSelectActiveSidebarNode: boolean;
|
||||
disconnectTabHandlingMode: DisconnectTabHandlingMode;
|
||||
reuseDataTab: boolean;
|
||||
sidebarHiddenTablePrefixes: string[];
|
||||
sidebarHideTableComments: boolean;
|
||||
sidebarAllowHorizontalScroll: boolean;
|
||||
|
|
@ -272,6 +273,7 @@ export const DEFAULT_EDITOR_SETTINGS: EditorSettings = {
|
|||
sidebarObjectDisplay: "grouped",
|
||||
autoSelectActiveSidebarNode: false,
|
||||
disconnectTabHandlingMode: "close-tabs",
|
||||
reuseDataTab: false,
|
||||
sidebarHiddenTablePrefixes: [],
|
||||
sidebarHideTableComments: false,
|
||||
sidebarAllowHorizontalScroll: false,
|
||||
|
|
@ -420,6 +422,7 @@ export function normalizeEditorSettings(settings: Partial<EditorSettings>, exist
|
|||
(settings as Partial<EditorSettings>).disconnectTabHandlingMode,
|
||||
(settings as Partial<EditorSettings> & { closeQueryTabsOnDisconnect?: boolean }).closeQueryTabsOnDisconnect,
|
||||
),
|
||||
reuseDataTab: settings.reuseDataTab ?? DEFAULT_EDITOR_SETTINGS.reuseDataTab,
|
||||
sidebarHiddenTablePrefixes: normalizeSidebarHiddenTablePrefixes(settings.sidebarHiddenTablePrefixes),
|
||||
sidebarHideTableComments: settings.sidebarHideTableComments ?? DEFAULT_EDITOR_SETTINGS.sidebarHideTableComments,
|
||||
sidebarAllowHorizontalScroll:
|
||||
|
|
@ -567,6 +570,7 @@ export const useSettingsStore = defineStore("settings", () => {
|
|||
editorSettings.value.disconnectTabHandlingMode = normalizeDisconnectTabHandlingMode(
|
||||
partial.disconnectTabHandlingMode,
|
||||
);
|
||||
if (partial.reuseDataTab !== undefined) editorSettings.value.reuseDataTab = partial.reuseDataTab;
|
||||
if (partial.sidebarHiddenTablePrefixes !== undefined)
|
||||
editorSettings.value.sidebarHiddenTablePrefixes = normalizeSidebarHiddenTablePrefixes(
|
||||
partial.sidebarHiddenTablePrefixes,
|
||||
|
|
|
|||
Loading…
Reference in New Issue