mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-21 06:00:39 +00:00
feat(sidebar): browse objects on database single click
This commit is contained in:
@@ -394,6 +394,7 @@ const dataTabReuseModeHelp = ref<DataTabReuseMode | null>(null);
|
||||
const editRoutineSourceOpenMode = ref(settingsStore.editorSettings.routineSourceOpenMode);
|
||||
const editSidebarTableSearchEnabled = ref(settingsStore.editorSettings.sidebarTableSearchEnabled);
|
||||
const editAutoSelectActiveSidebarNode = ref(settingsStore.editorSettings.autoSelectActiveSidebarNode);
|
||||
const editSidebarOpenDatabaseOnSingleClick = ref(settingsStore.editorSettings.sidebarOpenDatabaseOnSingleClick);
|
||||
const editOpenTabsRestoreMode = ref<OpenTabsRestoreMode>(settingsStore.editorSettings.openTabsRestoreMode);
|
||||
const editDisconnectTabHandlingMode = ref<DisconnectTabHandlingMode>(settingsStore.editorSettings.disconnectTabHandlingMode);
|
||||
const editDataTabReuseMode = ref<DataTabReuseMode>(settingsStore.editorSettings.dataTabReuseMode);
|
||||
@@ -514,6 +515,7 @@ function currentEditorSettingsDraft(): EditorSettingsDraft {
|
||||
routineSourceOpenMode: editRoutineSourceOpenMode.value,
|
||||
sidebarTableSearchEnabled: editSidebarTableSearchEnabled.value,
|
||||
autoSelectActiveSidebarNode: editAutoSelectActiveSidebarNode.value,
|
||||
sidebarOpenDatabaseOnSingleClick: editSidebarOpenDatabaseOnSingleClick.value,
|
||||
openTabsRestoreMode: editOpenTabsRestoreMode.value,
|
||||
disconnectTabHandlingMode: editDisconnectTabHandlingMode.value,
|
||||
dataTabReuseMode: editDataTabReuseMode.value,
|
||||
@@ -791,6 +793,7 @@ function syncEditorSettingsDraftFromStore() {
|
||||
editRoutineSourceOpenMode.value = settingsStore.editorSettings.routineSourceOpenMode;
|
||||
editSidebarTableSearchEnabled.value = settingsStore.editorSettings.sidebarTableSearchEnabled;
|
||||
editAutoSelectActiveSidebarNode.value = settingsStore.editorSettings.autoSelectActiveSidebarNode;
|
||||
editSidebarOpenDatabaseOnSingleClick.value = settingsStore.editorSettings.sidebarOpenDatabaseOnSingleClick;
|
||||
editOpenTabsRestoreMode.value = settingsStore.editorSettings.openTabsRestoreMode;
|
||||
editDisconnectTabHandlingMode.value = settingsStore.editorSettings.disconnectTabHandlingMode;
|
||||
editDataTabReuseMode.value = settingsStore.editorSettings.dataTabReuseMode;
|
||||
@@ -1003,6 +1006,7 @@ function resetDefaultsForTab(tab: SettingsCategory) {
|
||||
editRoutineSourceOpenMode.value = DEFAULT_EDITOR_SETTINGS.routineSourceOpenMode;
|
||||
editSidebarTableSearchEnabled.value = DEFAULT_EDITOR_SETTINGS.sidebarTableSearchEnabled;
|
||||
editAutoSelectActiveSidebarNode.value = DEFAULT_EDITOR_SETTINGS.autoSelectActiveSidebarNode;
|
||||
editSidebarOpenDatabaseOnSingleClick.value = DEFAULT_EDITOR_SETTINGS.sidebarOpenDatabaseOnSingleClick;
|
||||
editOpenTabsRestoreMode.value = DEFAULT_EDITOR_SETTINGS.openTabsRestoreMode;
|
||||
editDisconnectTabHandlingMode.value = DEFAULT_EDITOR_SETTINGS.disconnectTabHandlingMode;
|
||||
editDataTabReuseMode.value = DEFAULT_EDITOR_SETTINGS.dataTabReuseMode;
|
||||
@@ -1110,6 +1114,7 @@ function resetAllDefaults() {
|
||||
editRoutineSourceOpenMode.value = DEFAULT_EDITOR_SETTINGS.routineSourceOpenMode;
|
||||
editSidebarTableSearchEnabled.value = DEFAULT_EDITOR_SETTINGS.sidebarTableSearchEnabled;
|
||||
editAutoSelectActiveSidebarNode.value = DEFAULT_EDITOR_SETTINGS.autoSelectActiveSidebarNode;
|
||||
editSidebarOpenDatabaseOnSingleClick.value = DEFAULT_EDITOR_SETTINGS.sidebarOpenDatabaseOnSingleClick;
|
||||
editOpenTabsRestoreMode.value = DEFAULT_EDITOR_SETTINGS.openTabsRestoreMode;
|
||||
editDisconnectTabHandlingMode.value = DEFAULT_EDITOR_SETTINGS.disconnectTabHandlingMode;
|
||||
editDataTabReuseMode.value = DEFAULT_EDITOR_SETTINGS.dataTabReuseMode;
|
||||
@@ -4633,6 +4638,15 @@ onUnmounted(() => {
|
||||
</div>
|
||||
<Switch id="auto-select-active-sidebar-node" v-model="editAutoSelectActiveSidebarNode" />
|
||||
</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="sidebar-open-database-on-single-click">{{ t("settings.sidebarOpenDatabaseOnSingleClick") }}</Label>
|
||||
<HelpTooltip :label="t('settings.sidebarOpenDatabaseOnSingleClick')">
|
||||
{{ t("settings.sidebarOpenDatabaseOnSingleClickDescription") }}
|
||||
</HelpTooltip>
|
||||
</div>
|
||||
<Switch id="sidebar-open-database-on-single-click" v-model="editSidebarOpenDatabaseOnSingleClick" />
|
||||
</div>
|
||||
<div class="space-y-2 rounded-md border bg-muted/20 px-3 py-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<Label for="open-tabs-restore-mode">{{ t("settings.openTabsRestoreMode") }}</Label>
|
||||
|
||||
@@ -894,10 +894,15 @@ function runRowClickAction(clickDetail: number) {
|
||||
openMongoTreeData(node);
|
||||
return;
|
||||
}
|
||||
const action = treeNodeRowAction(node.type, canExpand.value, settingsStore.editorSettings.sidebarActivation, currentDatabaseType());
|
||||
const action = treeNodeRowAction(node.type, canExpand.value, settingsStore.editorSettings.sidebarActivation, currentDatabaseType(), settingsStore.editorSettings.sidebarOpenDatabaseOnSingleClick, canOpenObjectBrowser.value);
|
||||
if (!shouldRunTreeNodeRowAction(action, clickDetail, isGroupLabel(node))) return;
|
||||
if (action === "open-data") {
|
||||
scheduleOpenData(node);
|
||||
} else if (action === "open-object-browser") {
|
||||
void openObjectBrowser();
|
||||
} else if (action === "open-object-browser-and-expand") {
|
||||
void openObjectBrowser();
|
||||
if (!node.isExpanded) void toggle();
|
||||
} else if (action === "open-source") {
|
||||
openObjectSourceDialog(false);
|
||||
} else if (action === "open-extension-details") {
|
||||
@@ -1231,7 +1236,7 @@ function requestDeleteSelectedNode(): boolean {
|
||||
|
||||
function onDoubleClick(event: MouseEvent) {
|
||||
if (dataTabOpenModeFromTreeClick(activeNode.value.type, event, settingsStore.editorSettings.shortcuts.openDataInNewTab) === "new-tab") return;
|
||||
const action = treeNodeRowDoubleClickAction(activeNode.value.type, canOpenObjectBrowser.value, settingsStore.editorSettings.sidebarActivation, canExpand.value, currentDatabaseType(), canOpenConnectionDatabaseBrowser.value);
|
||||
const action = treeNodeRowDoubleClickAction(activeNode.value.type, canOpenObjectBrowser.value, settingsStore.editorSettings.sidebarActivation, canExpand.value, currentDatabaseType(), canOpenConnectionDatabaseBrowser.value, settingsStore.editorSettings.sidebarOpenDatabaseOnSingleClick);
|
||||
if (action === "open-database-browser") {
|
||||
void openDatabaseBrowser();
|
||||
} else if (action === "open-object-browser") {
|
||||
|
||||
@@ -77,7 +77,7 @@ import { sidebarTreeRuntimeKey } from "@/lib/sidebar/sidebarTreeRuntime";
|
||||
import { treeNodePinKey } from "@/lib/app/pinnedItems";
|
||||
import { isTreeGroupNodeType } from "@/lib/sidebar/treeNodeGroup";
|
||||
import { customTypeCapabilities } from "@/lib/database/databaseObjectCapabilities";
|
||||
import { shouldActivateTreeNodeOnSingleClick } from "@/lib/sidebar/treeNodeClick";
|
||||
import { shouldActivateTreeNodeOnSingleClick, shouldOpenObjectBrowserOnSingleClick } from "@/lib/sidebar/treeNodeClick";
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
@@ -1188,6 +1188,10 @@ function onClick(event: MouseEvent) {
|
||||
}
|
||||
selectSingleTreeNode(props.node);
|
||||
rowRef.value?.focus({ preventScroll: true });
|
||||
if (shouldOpenObjectBrowserOnSingleClick(props.node.type, settingsStore.editorSettings.sidebarOpenDatabaseOnSingleClick)) {
|
||||
treeRuntime.handleRowClick(props.node, event.detail);
|
||||
return;
|
||||
}
|
||||
if (!shouldActivateTreeNodeOnSingleClick(props.node.type, settingsStore.editorSettings.sidebarActivation) && props.node.type !== "load-more") return;
|
||||
treeRuntime.handleRowClick(props.node, event.detail);
|
||||
}
|
||||
|
||||
@@ -5737,6 +5737,8 @@ export default {
|
||||
routineSourceOpenModeDialogDescription: "Open source in a popup dialog for quick viewing and editing.",
|
||||
autoSelectActiveSidebarNode: "Always select opened item",
|
||||
autoSelectActiveSidebarNodeDescription: "When switching tabs, select the matching visible table, collection, or SQL file in the sidebar.",
|
||||
sidebarOpenDatabaseOnSingleClick: "Browse objects on database single click",
|
||||
sidebarOpenDatabaseOnSingleClickDescription: 'When enabled, single-clicking a database or schema node also expands the sidebar and opens the "Browse Objects" tab.',
|
||||
openTabsRestoreMode: "Restore tabs on launch",
|
||||
openTabsRestoreModeDescription: "Choose how DBX restores tabs that were open last time.",
|
||||
openTabsRestoreModeAll: "Keep all tabs",
|
||||
|
||||
@@ -5481,6 +5481,8 @@ export default withEnglishFallback({
|
||||
sidebarObjectDisplaySimpleDescription: "Muestra tablas y vistas directamente bajo cada base de datos o esquema para reducir niveles intermedios.",
|
||||
autoSelectActiveSidebarNode: "Seleccionar siempre el elemento abierto",
|
||||
autoSelectActiveSidebarNodeDescription: "Al cambiar de pestaña, selecciona la tabla, colección o archivo SQL visible correspondiente en la barra lateral.",
|
||||
sidebarOpenDatabaseOnSingleClick: "Explorar objetos al hacer clic en la base de datos",
|
||||
sidebarOpenDatabaseOnSingleClickDescription: 'Si está activado, al hacer un solo clic en un nodo de base de datos o esquema se expande la barra lateral y se abre la pestaña "Explorar objetos".',
|
||||
openTabsRestoreMode: "Restaurar pestañas al iniciar",
|
||||
openTabsRestoreModeDescription: "Elige cómo DBX restaura las pestañas que estaban abiertas la última vez.",
|
||||
openTabsRestoreModeAll: "Conservar todas las pestañas",
|
||||
|
||||
@@ -5481,6 +5481,8 @@ export default withEnglishFallback({
|
||||
sidebarObjectDisplaySimpleDescription: "Elenca tabelle e viste direttamente sotto ogni database o schema per ridurre i livelli intermedi.",
|
||||
autoSelectActiveSidebarNode: "Seleziona sempre l'elemento aperto",
|
||||
autoSelectActiveSidebarNodeDescription: "Quando passi da una scheda all'altra, seleziona la tabella, la collezione o il file SQL visibile corrispondente nella barra laterale.",
|
||||
sidebarOpenDatabaseOnSingleClick: "Sfoglia oggetti al clic sul database",
|
||||
sidebarOpenDatabaseOnSingleClickDescription: 'Se abilitato, un singolo clic su un nodo database o schema espande la barra laterale e apre la scheda "Esplora Oggetti".',
|
||||
openTabsRestoreMode: "Ripristina schede all'avvio",
|
||||
openTabsRestoreModeDescription: "Scegli come DBX ripristina le schede aperte l'ultima volta.",
|
||||
openTabsRestoreModeAll: "Mantieni tutte le schede",
|
||||
|
||||
@@ -5508,6 +5508,8 @@ export default withEnglishFallback({
|
||||
sidebarObjectDisplaySimpleDescription: "中間レベルを減らすために、各データベースまたはスキーマの直下にテーブルとビューを一覧表示します。",
|
||||
autoSelectActiveSidebarNode: "開いた項目を常に選択",
|
||||
autoSelectActiveSidebarNodeDescription: "タブ切替時に、サイドバーで一致する表示中のテーブル、コレクション、またはSQLファイルを選択します。",
|
||||
sidebarOpenDatabaseOnSingleClick: "データベースのシングルクリックでオブジェクトを参照",
|
||||
sidebarOpenDatabaseOnSingleClickDescription: "有効にすると、データベースまたはスキーマノードをシングルクリックした際に、サイドバーを展開すると同時に「オブジェクトを参照」タブを開きます。",
|
||||
openTabsRestoreMode: "起動時にタブを復元",
|
||||
openTabsRestoreModeDescription: "DBX 起動時に前回開いていたタブをどのように復元するかを選択します。",
|
||||
openTabsRestoreModeAll: "すべてのタブを保持",
|
||||
|
||||
@@ -5220,6 +5220,8 @@ export default withEnglishFallback({
|
||||
sidebarObjectDisplaySimpleDescription: "중간 수준을 줄이기 위해 각 데이터베이스나 스키마 아래에 테이블과 뷰를 직접 나열합니다.",
|
||||
autoSelectActiveSidebarNode: "열린 항목 항상 선택",
|
||||
autoSelectActiveSidebarNodeDescription: "탭을 전환할 때 사이드바에서 일치하는 표시된 테이블, 컬렉션 또는 SQL 파일을 선택합니다.",
|
||||
sidebarOpenDatabaseOnSingleClick: "데이터베이스 클릭 시 객체 탐색",
|
||||
sidebarOpenDatabaseOnSingleClickDescription: '활성화하면 데이터베이스 또는 스키마 노드를 한 번 클릭할 때 사이드바를 펼치면서 "객체 탐색" 탭을 엽니다.',
|
||||
openTabsRestoreMode: "실행 시 탭 복원",
|
||||
openTabsRestoreModeDescription: "DBX가 지난번에 열려 있던 탭을 복원하는 방법을 선택하세요.",
|
||||
openTabsRestoreModeAll: "모든 탭 유지",
|
||||
|
||||
@@ -5483,6 +5483,8 @@ export default withEnglishFallback({
|
||||
sidebarObjectDisplaySimpleDescription: "Listar tabelas e views diretamente sob cada banco de dados ou schema para reduzir os níveis intermediários.",
|
||||
autoSelectActiveSidebarNode: "Sempre selecionar o item aberto",
|
||||
autoSelectActiveSidebarNodeDescription: "Ao alternar abas, selecionar a tabela, coleção ou arquivo SQL correspondente visível na barra lateral.",
|
||||
sidebarOpenDatabaseOnSingleClick: "Explorar objetos ao clicar no banco de dados",
|
||||
sidebarOpenDatabaseOnSingleClickDescription: 'Quando ativado, um clique único em um nó de banco de dados ou esquema expande a barra lateral e abre a aba "Explorar Objetos".',
|
||||
openTabsRestoreMode: "Restaurar abas ao iniciar",
|
||||
openTabsRestoreModeDescription: "Escolha como o DBX restaura as abas que estavam abertas na última vez.",
|
||||
openTabsRestoreModeAll: "Manter todas as abas",
|
||||
|
||||
@@ -5724,6 +5724,8 @@ export default withEnglishFallback({
|
||||
routineSourceOpenModeDialogDescription: "在弹出对话框中打开源码,方便快速查看和编辑。",
|
||||
autoSelectActiveSidebarNode: "始终选中已打开项目",
|
||||
autoSelectActiveSidebarNodeDescription: "切换标签页时,在侧边栏选中匹配的可见表、集合或 SQL 文件。",
|
||||
sidebarOpenDatabaseOnSingleClick: "单击数据库时浏览对象",
|
||||
sidebarOpenDatabaseOnSingleClickDescription: "开启后,单击数据库或模式节点时,会同时展开侧边栏并打开“浏览对象”标签页。",
|
||||
openTabsRestoreMode: "启动时恢复标签页",
|
||||
openTabsRestoreModeDescription: "选择 DBX 启动时如何恢复上次打开的标签页。",
|
||||
openTabsRestoreModeAll: "保留所有标签",
|
||||
|
||||
@@ -4818,6 +4818,8 @@ export default withEnglishFallback({
|
||||
sidebarObjectDisplaySimpleDescription: "直接在每個資料庫或 schema 下列出資料表與檢視,減少中間層級。",
|
||||
autoSelectActiveSidebarNode: "一律選取已開啟項目",
|
||||
autoSelectActiveSidebarNodeDescription: "切換分頁時,在側邊欄選取相符的可見資料表、集合或 SQL 檔案。",
|
||||
sidebarOpenDatabaseOnSingleClick: "單擊資料庫時瀏覽物件",
|
||||
sidebarOpenDatabaseOnSingleClickDescription: "開啟後,單擊資料庫或結構描述節點時,會同時展開側邊欄並開啟「瀏覽物件」分頁。",
|
||||
openTabsRestoreMode: "啟動時還原分頁",
|
||||
openTabsRestoreModeDescription: "選擇 DBX 啟動時如何還原上次開啟的分頁。",
|
||||
openTabsRestoreModeAll: "保留所有分頁",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { isDirectNavigationTreeNode, objectSourceKindForTreeNode, objectSourceTargetForTreeNode, shouldActivateTreeNodeOnSingleClick, treeNodeRowAction, treeNodeRowDoubleClickAction } from "@/lib/sidebar/treeNodeClick";
|
||||
import { isDirectNavigationTreeNode, objectSourceKindForTreeNode, objectSourceTargetForTreeNode, shouldActivateTreeNodeOnSingleClick, shouldOpenObjectBrowserOnSingleClick, treeNodeRowAction, treeNodeRowDoubleClickAction } from "@/lib/sidebar/treeNodeClick";
|
||||
|
||||
describe("treeNodeClick", () => {
|
||||
it("opens synonym nodes as synonym source", () => {
|
||||
@@ -49,6 +49,45 @@ describe("treeNodeClick", () => {
|
||||
expect(treeNodeRowDoubleClickAction("connection", false, "double", true, "postgres", false)).toBe("toggle");
|
||||
});
|
||||
|
||||
it("opens the object browser on single click when the database single-click switch is on", () => {
|
||||
expect(treeNodeRowAction("database", true, "single", "postgres", true, true)).toBe("open-object-browser-and-expand");
|
||||
expect(treeNodeRowAction("database", false, "single", "postgres", true, true)).toBe("open-object-browser");
|
||||
expect(treeNodeRowAction("schema", true, "single", "postgres", true, true)).toBe("open-object-browser-and-expand");
|
||||
expect(treeNodeRowAction("object-browser", false, "single", "postgres", true, true)).toBe("open-object-browser");
|
||||
});
|
||||
|
||||
it("lets the database single-click switch override double-click activation", () => {
|
||||
expect(treeNodeRowAction("database", true, "double", "postgres", true, true)).toBe("open-object-browser-and-expand");
|
||||
expect(treeNodeRowAction("schema", false, "double", "postgres", true, true)).toBe("open-object-browser");
|
||||
});
|
||||
|
||||
it("does not reopen the object browser when the single-click switch already handled the gesture", () => {
|
||||
expect(treeNodeRowDoubleClickAction("database", true, "single", true, "postgres", false, true)).toBe("none");
|
||||
expect(treeNodeRowDoubleClickAction("schema", true, "double", true, "postgres", false, true)).toBe("none");
|
||||
expect(treeNodeRowDoubleClickAction("object-browser", true, "single", false, "postgres", false, true)).toBe("none");
|
||||
});
|
||||
|
||||
it("keeps the existing double-click fallback when single-click browsing is unavailable", () => {
|
||||
expect(treeNodeRowDoubleClickAction("database", true, "single", true, "postgres", false, false)).toBe("open-object-browser");
|
||||
expect(treeNodeRowDoubleClickAction("database", false, "double", true, "postgres", false, true)).toBe("toggle");
|
||||
});
|
||||
|
||||
it("keeps the original single-click behavior when the database single-click switch is off or unsupported", () => {
|
||||
expect(treeNodeRowAction("database", true, "single", "postgres", false, true)).toBe("toggle");
|
||||
expect(treeNodeRowAction("database", true, "double", "postgres", false, true)).toBe("none");
|
||||
// Capability off (e.g. unsupported database type) falls back to the previous behavior.
|
||||
expect(treeNodeRowAction("database", true, "single", "postgres", true, false)).toBe("toggle");
|
||||
expect(treeNodeRowAction("database", true, "double", "postgres", true, false)).toBe("none");
|
||||
});
|
||||
|
||||
it("does not route non-database nodes through the database single-click switch", () => {
|
||||
expect(treeNodeRowAction("table", false, "single", "postgres", true, true)).toBe("open-data");
|
||||
expect(treeNodeRowAction("table", false, "double", "postgres", true, true)).toBe("none");
|
||||
expect(shouldOpenObjectBrowserOnSingleClick("table", true)).toBe(false);
|
||||
expect(shouldOpenObjectBrowserOnSingleClick("database", true)).toBe(true);
|
||||
expect(shouldOpenObjectBrowserOnSingleClick("database", false)).toBe(false);
|
||||
});
|
||||
|
||||
it("expands package containers while preserving source behavior for leaf packages", () => {
|
||||
expect(treeNodeRowAction("package", true)).toBe("toggle");
|
||||
expect(treeNodeRowAction("package", false)).toBe("open-source");
|
||||
|
||||
@@ -54,6 +54,7 @@ export const EDITOR_SETTINGS_DRAFT_KEYS = [
|
||||
"routineSourceOpenMode",
|
||||
"sidebarTableSearchEnabled",
|
||||
"autoSelectActiveSidebarNode",
|
||||
"sidebarOpenDatabaseOnSingleClick",
|
||||
"openTabsRestoreMode",
|
||||
"disconnectTabHandlingMode",
|
||||
"dataTabReuseMode",
|
||||
|
||||
@@ -163,6 +163,7 @@ export const SETTINGS_SEARCH_DEFINITIONS: readonly SettingsSearchDefinition[] =
|
||||
{ id: "navigation-object-info", category: "navigation", titleKey: "settings.sidebarObjectInfoMode", descriptionKey: "settings.sidebarObjectInfoModeDescription", targetId: "navigation" },
|
||||
{ id: "navigation-table-search", category: "navigation", titleKey: "settings.sidebarTableSearchEnabled", descriptionKey: "settings.sidebarTableSearchEnabledDescription", targetId: "navigation" },
|
||||
{ id: "navigation-active-node", category: "navigation", titleKey: "settings.autoSelectActiveSidebarNode", descriptionKey: "settings.autoSelectActiveSidebarNodeDescription", targetId: "navigation" },
|
||||
{ id: "navigation-open-database-on-single-click", category: "navigation", titleKey: "settings.sidebarOpenDatabaseOnSingleClick", descriptionKey: "settings.sidebarOpenDatabaseOnSingleClickDescription", targetId: "navigation" },
|
||||
{ id: "navigation-tabs-restore", category: "navigation", titleKey: "settings.openTabsRestoreMode", descriptionKey: "settings.openTabsRestoreModeDescription", targetId: "navigation" },
|
||||
{ id: "navigation-sidebar-scroll", category: "navigation", titleKey: "settings.sidebarAllowHorizontalScroll", descriptionKey: "settings.sidebarAllowHorizontalScrollDescription", targetId: "navigation" },
|
||||
{ id: "navigation-hidden-tables", category: "navigation", titleKey: "settings.sidebarHiddenTablePrefixes", descriptionKey: "settings.sidebarHiddenTablePrefixesDescription", targetId: "navigation" },
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { DatabaseType, ObjectSourceKind, TreeNode, TreeNodeType } from "@/t
|
||||
import { customTypeCapabilities, supportsTypeObjectSource } from "@/lib/database/databaseObjectCapabilities";
|
||||
import { matchesShortcut, type ShortcutLikeEvent } from "@/lib/editor/keyboardShortcuts";
|
||||
|
||||
export type TreeNodeRowAction = "open-data" | "open-source" | "open-extension-details" | "open-saved-sql" | "toggle" | "none";
|
||||
export type TreeNodeRowAction = "open-data" | "open-source" | "open-extension-details" | "open-saved-sql" | "open-object-browser" | "open-object-browser-and-expand" | "toggle" | "none";
|
||||
export type TreeNodeRowDoubleClickAction = "open-data" | "activate-data" | "open-database-browser" | "open-object-browser" | "open-object-browser-and-expand" | "open-source" | "open-extension-details" | "open-saved-sql" | "toggle" | "none";
|
||||
export type SidebarSelectionCopyAction = "copy-name" | "none";
|
||||
export type SidebarActivation = "single" | "double";
|
||||
@@ -41,6 +41,11 @@ export function shouldActivateTreeNodeOnSingleClick(type: TreeNodeType, activati
|
||||
return activation !== "double" || isDirectNavigationTreeNode(type);
|
||||
}
|
||||
const objectBrowserNodeTypes = new Set<TreeNodeType>(["database", "schema", "object-browser"]);
|
||||
|
||||
/** 开关“单击数据库同时打开数据库项目”命中时,单击数据库类节点直接打开对象浏览器标签页。 */
|
||||
export function shouldOpenObjectBrowserOnSingleClick(type: TreeNodeType, enabled: boolean): boolean {
|
||||
return enabled && objectBrowserNodeTypes.has(type);
|
||||
}
|
||||
const sourceNodeTypes = new Set<TreeNodeType>(["materialized_view", "procedure", "function", "trigger", "sequence", "synonym", "package", "package-body", "type", "type-body"]);
|
||||
const savedSqlNodeTypes = new Set<TreeNodeType>(["saved-sql-file"]);
|
||||
const tableChildGroupNodeTypes = new Set<TreeNodeType>(["group-columns", "group-indexes", "group-fkeys", "group-triggers", "group-constraints", "group-partitions", "group-table-partitions", "group-table-subpartitions"]);
|
||||
@@ -102,7 +107,11 @@ function canOpenTreeNodeSource(type: TreeNodeType, dbType?: DatabaseType): boole
|
||||
return true;
|
||||
}
|
||||
|
||||
export function treeNodeRowAction(type: TreeNodeType, canExpand: boolean, activation: SidebarActivation = "single", dbType?: DatabaseType): TreeNodeRowAction {
|
||||
export function treeNodeRowAction(type: TreeNodeType, canExpand: boolean, activation: SidebarActivation = "single", dbType?: DatabaseType, openDatabaseOnSingleClick = false, canOpenObjectBrowser = false): TreeNodeRowAction {
|
||||
// “单击数据库同时打开数据库项目”开关优先于激活方式:单击即等效双击的打开行为。
|
||||
if (openDatabaseOnSingleClick && canOpenObjectBrowser && shouldOpenObjectBrowserOnSingleClick(type, true)) {
|
||||
return canExpand ? "open-object-browser-and-expand" : "open-object-browser";
|
||||
}
|
||||
if (!shouldActivateTreeNodeOnSingleClick(type, activation)) return "none";
|
||||
if (type === "extension") return "open-extension-details";
|
||||
if (savedSqlNodeTypes.has(type)) return "open-saved-sql";
|
||||
@@ -124,10 +133,11 @@ export function shouldRunTreeNodeRowAction(action: TreeNodeRowAction, clickDetai
|
||||
return action !== "none" && clickDetail <= 1;
|
||||
}
|
||||
|
||||
export function treeNodeRowDoubleClickAction(type: TreeNodeType, canOpenObjectBrowser: boolean, activation: SidebarActivation = "single", canExpand = false, dbType?: DatabaseType, canOpenDatabaseBrowser = false): TreeNodeRowDoubleClickAction {
|
||||
export function treeNodeRowDoubleClickAction(type: TreeNodeType, canOpenObjectBrowser: boolean, activation: SidebarActivation = "single", canExpand = false, dbType?: DatabaseType, canOpenDatabaseBrowser = false, openDatabaseOnSingleClick = false): TreeNodeRowDoubleClickAction {
|
||||
// Single-click activation already handles the first click in a dblclick
|
||||
// sequence. Only double-click activation needs a second-stage table action.
|
||||
if (type === "table") return activation === "double" ? "activate-data" : "none";
|
||||
if (openDatabaseOnSingleClick && canOpenObjectBrowser && shouldOpenObjectBrowserOnSingleClick(type, true)) return "none";
|
||||
if (type === "connection" && canOpenDatabaseBrowser) return "open-database-browser";
|
||||
if (activation === "double") {
|
||||
if (type === "extension") return "open-extension-details";
|
||||
|
||||
@@ -576,6 +576,7 @@ export interface EditorSettings {
|
||||
sidebarTableSearchLocal: boolean;
|
||||
sidebarGlobalSearchLocal: boolean;
|
||||
autoSelectActiveSidebarNode: boolean;
|
||||
sidebarOpenDatabaseOnSingleClick: boolean;
|
||||
openTabsRestoreMode: OpenTabsRestoreMode;
|
||||
disconnectTabHandlingMode: DisconnectTabHandlingMode;
|
||||
dataTabReuseMode: DataTabReuseMode;
|
||||
@@ -772,6 +773,7 @@ export const DEFAULT_EDITOR_SETTINGS: EditorSettings = {
|
||||
sidebarTableSearchLocal: true,
|
||||
sidebarGlobalSearchLocal: false,
|
||||
autoSelectActiveSidebarNode: false,
|
||||
sidebarOpenDatabaseOnSingleClick: false,
|
||||
openTabsRestoreMode: "all",
|
||||
disconnectTabHandlingMode: "close-tabs",
|
||||
dataTabReuseMode: DEFAULT_DATA_TAB_REUSE_MODE,
|
||||
@@ -1113,6 +1115,7 @@ export function normalizeEditorSettings(settings: Partial<EditorSettings>, exist
|
||||
sidebarTableSearchLocal: typeof settings.sidebarTableSearchLocal === "boolean" ? settings.sidebarTableSearchLocal : DEFAULT_EDITOR_SETTINGS.sidebarTableSearchLocal,
|
||||
sidebarGlobalSearchLocal: typeof settings.sidebarGlobalSearchLocal === "boolean" ? settings.sidebarGlobalSearchLocal : DEFAULT_EDITOR_SETTINGS.sidebarGlobalSearchLocal,
|
||||
autoSelectActiveSidebarNode: settings.autoSelectActiveSidebarNode ?? DEFAULT_EDITOR_SETTINGS.autoSelectActiveSidebarNode,
|
||||
sidebarOpenDatabaseOnSingleClick: typeof settings.sidebarOpenDatabaseOnSingleClick === "boolean" ? settings.sidebarOpenDatabaseOnSingleClick : DEFAULT_EDITOR_SETTINGS.sidebarOpenDatabaseOnSingleClick,
|
||||
openTabsRestoreMode: normalizeOpenTabsRestoreMode(
|
||||
(settings as Partial<EditorSettings>).openTabsRestoreMode,
|
||||
(
|
||||
@@ -1692,6 +1695,7 @@ export const useSettingsStore = defineStore("settings", () => {
|
||||
if (partial.sidebarTableSearchLocal !== undefined) editorSettings.value.sidebarTableSearchLocal = partial.sidebarTableSearchLocal;
|
||||
if (partial.sidebarGlobalSearchLocal !== undefined) editorSettings.value.sidebarGlobalSearchLocal = partial.sidebarGlobalSearchLocal;
|
||||
if (partial.autoSelectActiveSidebarNode !== undefined) editorSettings.value.autoSelectActiveSidebarNode = partial.autoSelectActiveSidebarNode;
|
||||
if (partial.sidebarOpenDatabaseOnSingleClick !== undefined) editorSettings.value.sidebarOpenDatabaseOnSingleClick = partial.sidebarOpenDatabaseOnSingleClick === true;
|
||||
if (partial.openTabsRestoreMode !== undefined) editorSettings.value.openTabsRestoreMode = normalizeOpenTabsRestoreMode(partial.openTabsRestoreMode);
|
||||
if (partial.disconnectTabHandlingMode !== undefined) editorSettings.value.disconnectTabHandlingMode = normalizeDisconnectTabHandlingMode(partial.disconnectTabHandlingMode);
|
||||
if (partial.dataTabReuseMode !== undefined) editorSettings.value.dataTabReuseMode = normalizeDataTabReuseMode(partial.dataTabReuseMode);
|
||||
|
||||
Reference in New Issue
Block a user