feat(desktop): add zen mode toggle for data tabs
This commit is contained in:
16 files changed
+105
-9
No files matched your search
@@ -88,6 +88,7 @@ import {
|
|||||||
isSwitchToPreviousTabShortcut,
|
isSwitchToPreviousTabShortcut,
|
||||||
isToggleResultsPaneShortcut,
|
isToggleResultsPaneShortcut,
|
||||||
isToggleSidebarShortcut,
|
isToggleSidebarShortcut,
|
||||||
|
isToggleZenModeShortcut,
|
||||||
isZoomInShortcut,
|
isZoomInShortcut,
|
||||||
isZoomOutShortcut,
|
isZoomOutShortcut,
|
||||||
switchToTabIndexFromShortcut,
|
switchToTabIndexFromShortcut,
|
||||||
@@ -254,6 +255,7 @@ const agentDriverUpdateCount = ref(0);
|
|||||||
const showHistory = ref(false);
|
const showHistory = ref(false);
|
||||||
const showAiPanel = ref(safeLocalStorageGet("dbx-ai-panel-open") === "true");
|
const showAiPanel = ref(safeLocalStorageGet("dbx-ai-panel-open") === "true");
|
||||||
const isAiPanelMaximized = ref(false);
|
const isAiPanelMaximized = ref(false);
|
||||||
|
const isZenMode = ref(false);
|
||||||
const showSqlLibraryPanel = ref(safeLocalStorageGet("dbx-sql-library-open") === "true");
|
const showSqlLibraryPanel = ref(safeLocalStorageGet("dbx-sql-library-open") === "true");
|
||||||
const showSqlFilePanel = ref(safeLocalStorageGet("dbx-sql-file-panel-open") === "true");
|
const showSqlFilePanel = ref(safeLocalStorageGet("dbx-sql-file-panel-open") === "true");
|
||||||
const rightSidebarPanelRefs: Record<RightSidebarPanelId, typeof showAiPanel> = {
|
const rightSidebarPanelRefs: Record<RightSidebarPanelId, typeof showAiPanel> = {
|
||||||
@@ -323,6 +325,18 @@ const activeTab = computed(() => queryStore.tabs.find((t) => t.id === queryStore
|
|||||||
const tabNavigationHistory = ref(createTabNavigationHistory());
|
const tabNavigationHistory = ref(createTabNavigationHistory());
|
||||||
let pendingTabHistoryNavigationId: string | null = null;
|
let pendingTabHistoryNavigationId: string | null = null;
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => activeTab.value?.mode,
|
||||||
|
(mode) => {
|
||||||
|
if (mode !== "data") isZenMode.value = false;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
function toggleZenMode() {
|
||||||
|
if (activeTab.value?.mode !== "data") return;
|
||||||
|
isZenMode.value = !isZenMode.value;
|
||||||
|
}
|
||||||
|
|
||||||
const externalSqlFileChanges = useExternalSqlFileChanges({
|
const externalSqlFileChanges = useExternalSqlFileChanges({
|
||||||
activeTab,
|
activeTab,
|
||||||
recreateFile: async (tab) => {
|
recreateFile: async (tab) => {
|
||||||
@@ -2610,6 +2624,12 @@ async function handleKeydown(e: KeyboardEvent) {
|
|||||||
setSidebarOpen(!sidebarOpen.value);
|
setSidebarOpen(!sidebarOpen.value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (isToggleZenModeShortcut(e, shortcuts) && activeTab.value?.mode === "data") {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
toggleZenMode();
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (switchTabIndex != null) {
|
if (switchTabIndex != null) {
|
||||||
if (activateTabByIndex(switchTabIndex)) {
|
if (activateTabByIndex(switchTabIndex)) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -2977,7 +2997,7 @@ onUnmounted(() => {
|
|||||||
|
|
||||||
<div :class="isClassicLayout ? 'app-layout-classic flex-1 flex min-h-0' : 'app-panel-gutter flex-1 flex min-h-0 gap-1 p-1'">
|
<div :class="isClassicLayout ? 'app-layout-classic flex-1 flex min-h-0' : 'app-panel-gutter flex-1 flex min-h-0 gap-1 p-1'">
|
||||||
<AppSidebar
|
<AppSidebar
|
||||||
v-show="sidebarOpen"
|
v-show="sidebarOpen && !isZenMode"
|
||||||
ref="appSidebarRef"
|
ref="appSidebarRef"
|
||||||
:sidebar-width="sidebarWidth"
|
:sidebar-width="sidebarWidth"
|
||||||
:classic-layout="isClassicLayout"
|
:classic-layout="isClassicLayout"
|
||||||
@@ -2988,13 +3008,13 @@ onUnmounted(() => {
|
|||||||
@open-settings="(initialTab) => openSettings(initialTab ?? 'appearance')"
|
@open-settings="(initialTab) => openSettings(initialTab ?? 'appearance')"
|
||||||
@add-to-ai="addToAi"
|
@add-to-ai="addToAi"
|
||||||
/>
|
/>
|
||||||
<div v-show="!sidebarOpen" class="flex h-full w-8 shrink-0 items-start justify-center border-r bg-background/80 pt-2" :class="isClassicLayout ? '' : 'rounded-md border border-border/80'">
|
<div v-show="!sidebarOpen && !isZenMode" class="flex h-full w-8 shrink-0 items-start justify-center border-r bg-background/80 pt-2" :class="isClassicLayout ? '' : 'rounded-md border border-border/80'">
|
||||||
<Button variant="ghost" size="icon" class="h-7 w-7" :title="t('sidebar.expand')" :aria-label="t('sidebar.expand')" @click="setSidebarOpen(true)">
|
<Button variant="ghost" size="icon" class="h-7 w-7" :title="t('sidebar.expand')" :aria-label="t('sidebar.expand')" @click="setSidebarOpen(true)">
|
||||||
<ChevronsRight class="h-4 w-4" />
|
<ChevronsRight class="h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-show="!isAiPanelMaximized" :class="isClassicLayout ? 'flex-1 min-w-0 overflow-hidden' : 'flex-1 min-w-0 overflow-hidden rounded-md border border-border/80 bg-background'">
|
<div v-show="!isAiPanelMaximized || isZenMode" :class="isClassicLayout ? 'flex-1 min-w-0 overflow-hidden' : 'flex-1 min-w-0 overflow-hidden rounded-md border border-border/80 bg-background'">
|
||||||
<div class="h-full flex flex-col min-w-0">
|
<div class="h-full flex flex-col min-w-0">
|
||||||
<AppTabBar
|
<AppTabBar
|
||||||
ref="appTabBarRef"
|
ref="appTabBarRef"
|
||||||
@@ -3003,6 +3023,7 @@ onUnmounted(() => {
|
|||||||
:settings-page-open="settingsPageTabOpen"
|
:settings-page-open="settingsPageTabOpen"
|
||||||
:settings-page-active="settingsStore.settingsPageActive"
|
:settings-page-active="settingsStore.settingsPageActive"
|
||||||
:agent-driver-update-count="toolbarAgentDriverUpdateCount"
|
:agent-driver-update-count="toolbarAgentDriverUpdateCount"
|
||||||
|
@toggle-zen-mode="toggleZenMode"
|
||||||
@activate-driver-store="openDriverStorePage"
|
@activate-driver-store="openDriverStorePage"
|
||||||
@activate-settings-page="activateSettingsPage"
|
@activate-settings-page="activateSettingsPage"
|
||||||
@locate-tab="locateTabInSidebar"
|
@locate-tab="locateTabInSidebar"
|
||||||
@@ -3168,6 +3189,7 @@ onUnmounted(() => {
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
v-if="showAiPanel"
|
v-if="showAiPanel"
|
||||||
|
v-show="!isZenMode"
|
||||||
:class="[isClassicLayout ? 'h-full relative z-30 isolate bg-background' : 'h-full relative z-30 isolate rounded-md border border-border/80 bg-background', isAiPanelMaximized ? 'min-w-0 flex-1' : 'min-w-[180px] max-w-full']"
|
:class="[isClassicLayout ? 'h-full relative z-30 isolate bg-background' : 'h-full relative z-30 isolate rounded-md border border-border/80 bg-background', isAiPanelMaximized ? 'min-w-0 flex-1' : 'min-w-[180px] max-w-full']"
|
||||||
:style="isAiPanelMaximized ? {} : { width: aiPanelWidth + 'px' }"
|
:style="isAiPanelMaximized ? {} : { width: aiPanelWidth + 'px' }"
|
||||||
>
|
>
|
||||||
@@ -3192,21 +3214,21 @@ onUnmounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="showHistory" v-show="!isAiPanelMaximized" :class="isClassicLayout ? 'h-full shrink-0 relative z-30 isolate bg-background' : 'h-full shrink-0 relative z-30 isolate rounded-md border border-border/80 bg-background'" :style="{ width: historyWidth + 'px' }">
|
<div v-if="showHistory" v-show="!isAiPanelMaximized && !isZenMode" :class="isClassicLayout ? 'h-full shrink-0 relative z-30 isolate bg-background' : 'h-full shrink-0 relative z-30 isolate rounded-md border border-border/80 bg-background'" :style="{ width: historyWidth + 'px' }">
|
||||||
<div class="panel-resize-handle panel-resize-handle--left" @mousedown="startHistoryResize" />
|
<div class="panel-resize-handle panel-resize-handle--left" @mousedown="startHistoryResize" />
|
||||||
<div class="h-full min-h-0 overflow-hidden rounded-[inherit]">
|
<div class="h-full min-h-0 overflow-hidden rounded-[inherit]">
|
||||||
<QueryHistory :current-connection-id="activeTab?.connectionId" :current-database="activeTab?.database" @restore="restoreHistorySql" @analyze-ai="analyzeHistoryWithAi" @close="closeRightSidebarPanel('history')" />
|
<QueryHistory :current-connection-id="activeTab?.connectionId" :current-database="activeTab?.database" @restore="restoreHistorySql" @analyze-ai="analyzeHistoryWithAi" @close="closeRightSidebarPanel('history')" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="showSqlLibraryPanel" v-show="!isAiPanelMaximized" :class="isClassicLayout ? 'h-full shrink-0 relative z-30 isolate bg-background' : 'h-full shrink-0 relative z-30 isolate rounded-md border border-border/80 bg-background'" :style="{ width: sqlLibraryWidth + 'px' }">
|
<div v-if="showSqlLibraryPanel" v-show="!isAiPanelMaximized && !isZenMode" :class="isClassicLayout ? 'h-full shrink-0 relative z-30 isolate bg-background' : 'h-full shrink-0 relative z-30 isolate rounded-md border border-border/80 bg-background'" :style="{ width: sqlLibraryWidth + 'px' }">
|
||||||
<div class="panel-resize-handle panel-resize-handle--left" @mousedown="startSqlLibraryResize" />
|
<div class="panel-resize-handle panel-resize-handle--left" @mousedown="startSqlLibraryResize" />
|
||||||
<div class="h-full min-h-0 overflow-hidden rounded-[inherit]">
|
<div class="h-full min-h-0 overflow-hidden rounded-[inherit]">
|
||||||
<SqlLibraryPanel @close="closeRightSidebarPanel('sqlLibrary')" />
|
<SqlLibraryPanel @close="closeRightSidebarPanel('sqlLibrary')" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="showSqlFilePanel" v-show="!isAiPanelMaximized" :class="isClassicLayout ? 'h-full shrink-0 relative z-30 isolate bg-background' : 'h-full shrink-0 relative z-30 isolate rounded-md border border-border/80 bg-background'" :style="{ width: sqlFilePanelWidth + 'px' }">
|
<div v-if="showSqlFilePanel" v-show="!isAiPanelMaximized && !isZenMode" :class="isClassicLayout ? 'h-full shrink-0 relative z-30 isolate bg-background' : 'h-full shrink-0 relative z-30 isolate rounded-md border border-border/80 bg-background'" :style="{ width: sqlFilePanelWidth + 'px' }">
|
||||||
<div class="panel-resize-handle panel-resize-handle--left" @mousedown="startSqlFilePanelResize" />
|
<div class="panel-resize-handle panel-resize-handle--left" @mousedown="startSqlFilePanelResize" />
|
||||||
<div class="h-full min-h-0 overflow-hidden rounded-[inherit]">
|
<div class="h-full min-h-0 overflow-hidden rounded-[inherit]">
|
||||||
<SqlFilePanel @close="closeRightSidebarPanel('sqlFile')" />
|
<SqlFilePanel @close="closeRightSidebarPanel('sqlFile')" />
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ const props = defineProps<{
|
|||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
"activate-tab": [];
|
"activate-tab": [];
|
||||||
|
"toggle-zen-mode": [];
|
||||||
"locate-tab": [tab: QueryTab];
|
"locate-tab": [tab: QueryTab];
|
||||||
"activate-driver-store": [];
|
"activate-driver-store": [];
|
||||||
"close-driver-store": [];
|
"close-driver-store": [];
|
||||||
@@ -577,6 +578,17 @@ function handleTabClick(tab: QueryTab) {
|
|||||||
activateTab(tab.id);
|
activateTab(tab.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleTabDoubleClick(tab: QueryTab, event: MouseEvent) {
|
||||||
|
event.stopPropagation();
|
||||||
|
if (tabDrag.state.suppressClick || (event.target instanceof Element && event.target.closest("button, input, [role='button']"))) return;
|
||||||
|
if (tab.mode === "data") {
|
||||||
|
if (tab.id !== queryStore.activeTabId) activateTab(tab.id);
|
||||||
|
emit("toggle-zen-mode");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
startRenameTab(tab);
|
||||||
|
}
|
||||||
|
|
||||||
function handleTabMouseDown(event: PointerEvent, tabId: string) {
|
function handleTabMouseDown(event: PointerEvent, tabId: string) {
|
||||||
if (event.button === 0) {
|
if (event.button === 0) {
|
||||||
dispatchBeforeTabSwitch(tabId);
|
dispatchBeforeTabSwitch(tabId);
|
||||||
@@ -697,7 +709,7 @@ function onOverflowItemKeydown(event: KeyboardEvent, tabId: string, kind: "regul
|
|||||||
:style="[tabColorStyle(tab), tabDropStyle(tab.id)]"
|
:style="[tabColorStyle(tab), tabDropStyle(tab.id)]"
|
||||||
:data-active-tab="tab.id === queryStore.activeTabId && !driverStoreActive && !settingsPageActive"
|
:data-active-tab="tab.id === queryStore.activeTabId && !driverStoreActive && !settingsPageActive"
|
||||||
@click="handleTabClick(tab)"
|
@click="handleTabClick(tab)"
|
||||||
@dblclick.stop="startRenameTab(tab)"
|
@dblclick="handleTabDoubleClick(tab, $event)"
|
||||||
@mousedown.middle.prevent="queryStore.closeTab(tab.id)"
|
@mousedown.middle.prevent="queryStore.closeTab(tab.id)"
|
||||||
@pointerdown="handleTabMouseDown($event, tab.id)"
|
@pointerdown="handleTabMouseDown($event, tab.id)"
|
||||||
@mouseenter="handleTabDragTarget($event, tab)"
|
@mouseenter="handleTabDragTarget($event, tab)"
|
||||||
@@ -902,7 +914,7 @@ function onOverflowItemKeydown(event: KeyboardEvent, tabId: string, kind: "regul
|
|||||||
:style="[tabColorStyle(tab), tabDropStyle(tab.id)]"
|
:style="[tabColorStyle(tab), tabDropStyle(tab.id)]"
|
||||||
:data-active-tab="tab.id === queryStore.activeTabId && !driverStoreActive && !settingsPageActive"
|
:data-active-tab="tab.id === queryStore.activeTabId && !driverStoreActive && !settingsPageActive"
|
||||||
@click="handleTabClick(tab)"
|
@click="handleTabClick(tab)"
|
||||||
@dblclick.stop="startRenameTab(tab)"
|
@dblclick="handleTabDoubleClick(tab, $event)"
|
||||||
@mousedown.middle.prevent="queryStore.closeTab(tab.id)"
|
@mousedown.middle.prevent="queryStore.closeTab(tab.id)"
|
||||||
@pointerdown="handleTabMouseDown($event, tab.id)"
|
@pointerdown="handleTabMouseDown($event, tab.id)"
|
||||||
@mouseenter="handleTabDragTarget($event, tab)"
|
@mouseenter="handleTabDragTarget($event, tab)"
|
||||||
|
|||||||
@@ -66,6 +66,19 @@ describe("AppTabBar locate-in-sidebar action", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("AppTabBar Zen mode interaction", () => {
|
||||||
|
it("switches Zen mode for data tabs while preserving query-tab renaming", () => {
|
||||||
|
const handler = sourceBetween("function handleTabDoubleClick", "function handleTabMouseDown");
|
||||||
|
|
||||||
|
expect(tabBarSource).toContain('"toggle-zen-mode": [];');
|
||||||
|
expect(handler).toContain('if (tab.mode === "data") {');
|
||||||
|
expect(handler).toContain('emit("toggle-zen-mode");');
|
||||||
|
expect(handler).toContain("startRenameTab(tab);");
|
||||||
|
expect(handler).toContain("event.target instanceof Element && event.target.closest(\"button, input, [role='button']\")");
|
||||||
|
expect(tabBarSource.match(/@dblclick="handleTabDoubleClick\(tab, \$event\)"/g)).toHaveLength(2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("AppTabBar right-side close action", () => {
|
describe("AppTabBar right-side close action", () => {
|
||||||
it("places the action after close-other and disables it when the target has no tabs to its right", () => {
|
it("places the action after close-other and disables it when the target has no tabs to its right", () => {
|
||||||
expect(tabBarSource).toContain('label: t("contextMenu.closeRightTabs")');
|
expect(tabBarSource).toContain('label: t("contextMenu.closeRightTabs")');
|
||||||
|
|||||||
@@ -6674,6 +6674,7 @@ export default {
|
|||||||
shortcutToggleTranspose: "Toggle transpose view",
|
shortcutToggleTranspose: "Toggle transpose view",
|
||||||
shortcutCancelSearch: "Cancel search",
|
shortcutCancelSearch: "Cancel search",
|
||||||
shortcutToggleSidebar: "Toggle sidebar",
|
shortcutToggleSidebar: "Toggle sidebar",
|
||||||
|
shortcutToggleZenMode: "Toggle Zen mode",
|
||||||
shortcutCopySidebarSelection: "Copy sidebar selection",
|
shortcutCopySidebarSelection: "Copy sidebar selection",
|
||||||
shortcutPasteSidebarSelection: "Paste into sidebar",
|
shortcutPasteSidebarSelection: "Paste into sidebar",
|
||||||
shortcutEditSidebarConnection: "Edit sidebar connection",
|
shortcutEditSidebarConnection: "Edit sidebar connection",
|
||||||
|
|||||||
@@ -6304,6 +6304,7 @@ export default withEnglishFallback({
|
|||||||
shortcutOpenSettings: "Abrir configuración",
|
shortcutOpenSettings: "Abrir configuración",
|
||||||
shortcutCloseTab: "Cerrar pestaña",
|
shortcutCloseTab: "Cerrar pestaña",
|
||||||
shortcutToggleSidebar: "Alternar barra lateral",
|
shortcutToggleSidebar: "Alternar barra lateral",
|
||||||
|
shortcutToggleZenMode: "Alternar modo Zen",
|
||||||
shortcutFocusSearch: "Enfocar búsqueda de la vista actual",
|
shortcutFocusSearch: "Enfocar búsqueda de la vista actual",
|
||||||
shortcutQuickOpen: "Abrir rápido (buscar todos los objetos de base de datos)",
|
shortcutQuickOpen: "Abrir rápido (buscar todos los objetos de base de datos)",
|
||||||
shortcutNavigateTabHistoryBack: "Volver a la pestaña vista anteriormente",
|
shortcutNavigateTabHistoryBack: "Volver a la pestaña vista anteriormente",
|
||||||
|
|||||||
@@ -6327,6 +6327,7 @@ export default withEnglishFallback({
|
|||||||
shortcutToggleTranspose: "Attiva/disattiva vista trasposta",
|
shortcutToggleTranspose: "Attiva/disattiva vista trasposta",
|
||||||
shortcutCancelSearch: "Annulla ricerca",
|
shortcutCancelSearch: "Annulla ricerca",
|
||||||
shortcutToggleSidebar: "Attiva/disattiva barra laterale",
|
shortcutToggleSidebar: "Attiva/disattiva barra laterale",
|
||||||
|
shortcutToggleZenMode: "Attiva/disattiva modalità Zen",
|
||||||
shortcutCopySidebarSelection: "Copia selezione barra laterale",
|
shortcutCopySidebarSelection: "Copia selezione barra laterale",
|
||||||
shortcutPasteSidebarSelection: "Incolla nella barra laterale",
|
shortcutPasteSidebarSelection: "Incolla nella barra laterale",
|
||||||
shortcutEditSidebarConnection: "Modifica connessione barra laterale",
|
shortcutEditSidebarConnection: "Modifica connessione barra laterale",
|
||||||
|
|||||||
@@ -6335,6 +6335,7 @@ export default withEnglishFallback({
|
|||||||
shortcutToggleTranspose: "転置ビューを切替",
|
shortcutToggleTranspose: "転置ビューを切替",
|
||||||
shortcutCancelSearch: "検索をキャンセル",
|
shortcutCancelSearch: "検索をキャンセル",
|
||||||
shortcutToggleSidebar: "サイドバーを切替",
|
shortcutToggleSidebar: "サイドバーを切替",
|
||||||
|
shortcutToggleZenMode: "Zenモードを切替",
|
||||||
shortcutCopySidebarSelection: "サイドバーの選択をコピー",
|
shortcutCopySidebarSelection: "サイドバーの選択をコピー",
|
||||||
shortcutPasteSidebarSelection: "サイドバーに貼り付け",
|
shortcutPasteSidebarSelection: "サイドバーに貼り付け",
|
||||||
shortcutEditSidebarConnection: "サイドバー接続を編集",
|
shortcutEditSidebarConnection: "サイドバー接続を編集",
|
||||||
|
|||||||
@@ -6050,6 +6050,7 @@ export default withEnglishFallback({
|
|||||||
shortcutToggleTranspose: "전치 보기 전환",
|
shortcutToggleTranspose: "전치 보기 전환",
|
||||||
shortcutCancelSearch: "검색 취소",
|
shortcutCancelSearch: "검색 취소",
|
||||||
shortcutToggleSidebar: "사이드바 전환",
|
shortcutToggleSidebar: "사이드바 전환",
|
||||||
|
shortcutToggleZenMode: "Zen 모드 전환",
|
||||||
shortcutCopySidebarSelection: "사이드바 선택 복사",
|
shortcutCopySidebarSelection: "사이드바 선택 복사",
|
||||||
shortcutPasteSidebarSelection: "사이드바에 붙여넣기",
|
shortcutPasteSidebarSelection: "사이드바에 붙여넣기",
|
||||||
shortcutEditSidebarConnection: "사이드바 연결 편집",
|
shortcutEditSidebarConnection: "사이드바 연결 편집",
|
||||||
|
|||||||
@@ -6306,6 +6306,7 @@ export default withEnglishFallback({
|
|||||||
shortcutOpenSettings: "Abrir configurações",
|
shortcutOpenSettings: "Abrir configurações",
|
||||||
shortcutCloseTab: "Fechar aba",
|
shortcutCloseTab: "Fechar aba",
|
||||||
shortcutToggleSidebar: "Alternar barra lateral",
|
shortcutToggleSidebar: "Alternar barra lateral",
|
||||||
|
shortcutToggleZenMode: "Alternar modo Zen",
|
||||||
shortcutFocusSearch: "Focar na pesquisa da tela atual",
|
shortcutFocusSearch: "Focar na pesquisa da tela atual",
|
||||||
shortcutQuickOpen: "Abrir rapidamente (pesquisar todos os objetos do banco de dados)",
|
shortcutQuickOpen: "Abrir rapidamente (pesquisar todos os objetos do banco de dados)",
|
||||||
shortcutNavigateTabHistoryBack: "Voltar para a aba visualizada anteriormente",
|
shortcutNavigateTabHistoryBack: "Voltar para a aba visualizada anteriormente",
|
||||||
|
|||||||
@@ -6637,6 +6637,7 @@ export default withEnglishFallback({
|
|||||||
shortcutOpenSettings: "打开设置",
|
shortcutOpenSettings: "打开设置",
|
||||||
shortcutCloseTab: "关闭标签页",
|
shortcutCloseTab: "关闭标签页",
|
||||||
shortcutToggleSidebar: "切换侧边栏",
|
shortcutToggleSidebar: "切换侧边栏",
|
||||||
|
shortcutToggleZenMode: "切换禅模式",
|
||||||
shortcutFocusSearch: "聚焦当前页面搜索",
|
shortcutFocusSearch: "聚焦当前页面搜索",
|
||||||
shortcutQuickOpen: "快速打开 (搜索所有数据库对象)",
|
shortcutQuickOpen: "快速打开 (搜索所有数据库对象)",
|
||||||
shortcutNavigateTabHistoryBack: "返回到上一个查看的标签页",
|
shortcutNavigateTabHistoryBack: "返回到上一个查看的标签页",
|
||||||
|
|||||||
@@ -5611,6 +5611,7 @@ export default withEnglishFallback({
|
|||||||
shortcutOpenSettings: "開啟設定",
|
shortcutOpenSettings: "開啟設定",
|
||||||
shortcutCloseTab: "關閉分頁",
|
shortcutCloseTab: "關閉分頁",
|
||||||
shortcutToggleSidebar: "切換側邊欄",
|
shortcutToggleSidebar: "切換側邊欄",
|
||||||
|
shortcutToggleZenMode: "切換禪模式",
|
||||||
shortcutFocusSearch: "聚焦目前頁面搜尋",
|
shortcutFocusSearch: "聚焦目前頁面搜尋",
|
||||||
shortcutQuickOpen: "快速開啟 (搜尋所有資料庫物件)",
|
shortcutQuickOpen: "快速開啟 (搜尋所有資料庫物件)",
|
||||||
shortcutNavigateTabHistoryBack: "返回到上一個檢視的分頁",
|
shortcutNavigateTabHistoryBack: "返回到上一個檢視的分頁",
|
||||||
|
|||||||
@@ -55,7 +55,20 @@ describe("right sidebar panel entry points", () => {
|
|||||||
expect(appSource).toContain(':maximized="isAiPanelMaximized"');
|
expect(appSource).toContain(':maximized="isAiPanelMaximized"');
|
||||||
expect(appSource).toContain('@toggle-maximize="toggleAiPanelMaximized"');
|
expect(appSource).toContain('@toggle-maximize="toggleAiPanelMaximized"');
|
||||||
expect(appSource).toContain("isAiPanelMaximized ? 'min-w-0 flex-1' : 'min-w-[180px] max-w-full'");
|
expect(appSource).toContain("isAiPanelMaximized ? 'min-w-0 flex-1' : 'min-w-[180px] max-w-full'");
|
||||||
expect(appSource).toContain('v-show="!isAiPanelMaximized"');
|
expect(appSource).toContain('v-show="!isAiPanelMaximized && !isZenMode"');
|
||||||
expect(functionSource("setRightSidebarPanelOpen", "toggleRightSidebarPanel")).toContain("isAiPanelMaximized.value = false;");
|
expect(functionSource("setRightSidebarPanelOpen", "toggleRightSidebarPanel")).toContain("isAiPanelMaximized.value = false;");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("keeps Zen mode as a temporary data-tab layout", () => {
|
||||||
|
expect(appSource).toContain("const isZenMode = ref(false);");
|
||||||
|
expect(appSource).toContain('if (mode !== "data") isZenMode.value = false;');
|
||||||
|
expect(appSource).toContain("function toggleZenMode() {");
|
||||||
|
expect(appSource).toContain('if (activeTab.value?.mode !== "data") return;');
|
||||||
|
expect(appSource).toContain('isToggleZenModeShortcut(e, shortcuts) && activeTab.value?.mode === "data"');
|
||||||
|
expect(appSource).toContain('@toggle-zen-mode="toggleZenMode"');
|
||||||
|
expect(appSource).toContain('v-show="sidebarOpen && !isZenMode"');
|
||||||
|
expect(appSource).toContain('v-show="!sidebarOpen && !isZenMode"');
|
||||||
|
expect(appSource).toContain('v-show="!isAiPanelMaximized || isZenMode"');
|
||||||
|
expect(appSource).toContain('v-show="!isZenMode"');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
isGoToLastPageShortcut,
|
isGoToLastPageShortcut,
|
||||||
isGoToNextPageShortcut,
|
isGoToNextPageShortcut,
|
||||||
isGoToPreviousPageShortcut,
|
isGoToPreviousPageShortcut,
|
||||||
|
isToggleZenModeShortcut,
|
||||||
matchesModifierOnlyShortcut,
|
matchesModifierOnlyShortcut,
|
||||||
matchesShortcut,
|
matchesShortcut,
|
||||||
tabSwitcherDirectionFromShortcut,
|
tabSwitcherDirectionFromShortcut,
|
||||||
@@ -98,6 +99,14 @@ describe("keyboard shortcut matching", () => {
|
|||||||
expect(isExecuteSqlInNewResultTabShortcut({ key: "\\", metaKey: true }, { executeSqlInNewResultTab: "Mod+\\" })).toBe(true);
|
expect(isExecuteSqlInNewResultTabShortcut({ key: "\\", metaKey: true }, { executeSqlInNewResultTab: "Mod+\\" })).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("matches the configurable Zen mode shortcut", () => {
|
||||||
|
const platformModEvent = isMacShortcutPlatform() ? { key: "F12", metaKey: true, shiftKey: true } : { key: "F12", ctrlKey: true, shiftKey: true };
|
||||||
|
|
||||||
|
expect(isToggleZenModeShortcut(platformModEvent, { toggleZenMode: "Shift+Mod+F12" })).toBe(true);
|
||||||
|
expect(isToggleZenModeShortcut({ ...platformModEvent, shiftKey: false }, { toggleZenMode: "Shift+Mod+F12" })).toBe(false);
|
||||||
|
expect(isToggleZenModeShortcut(platformModEvent, { toggleZenMode: "" })).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
it("matches legacy plus-key shortcuts saved with plus as a separator", () => {
|
it("matches legacy plus-key shortcuts saved with plus as a separator", () => {
|
||||||
expect(matchesShortcut({ key: "+", ctrlKey: true }, "Mod++", "Win32")).toBe(true);
|
expect(matchesShortcut({ key: "+", ctrlKey: true }, "Mod++", "Win32")).toBe(true);
|
||||||
expect(matchesShortcut({ key: "+", ctrlKey: true, shiftKey: true }, "Shift+Mod++", "Win32")).toBe(true);
|
expect(matchesShortcut({ key: "+", ctrlKey: true, shiftKey: true }, "Shift+Mod++", "Win32")).toBe(true);
|
||||||
|
|||||||
@@ -146,6 +146,14 @@ describe("shortcutRegistry editor actions", () => {
|
|||||||
expect(findShortcutConflict("find", DEFAULT_SHORTCUT_SETTINGS.find, DEFAULT_SHORTCUT_SETTINGS)).toBeNull();
|
expect(findShortcutConflict("find", DEFAULT_SHORTCUT_SETTINGS.find, DEFAULT_SHORTCUT_SETTINGS)).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("registers a conflict-free global shortcut for Zen mode", () => {
|
||||||
|
const definition = SHORTCUT_DEFINITIONS.find((item) => item.id === "toggleZenMode");
|
||||||
|
|
||||||
|
expect(definition).toMatchObject({ labelKey: "settings.shortcutToggleZenMode", scope: "global", defaultShortcut: "Shift+Mod+F12" });
|
||||||
|
expect(DEFAULT_SHORTCUT_SETTINGS.toggleZenMode).toBe("Shift+Mod+F12");
|
||||||
|
expect(findShortcutConflict("toggleZenMode", DEFAULT_SHORTCUT_SETTINGS.toggleZenMode, DEFAULT_SHORTCUT_SETTINGS)).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
it("uses Shift+Enter for inserting a complete line below", () => {
|
it("uses Shift+Enter for inserting a complete line below", () => {
|
||||||
const definition = SHORTCUT_DEFINITIONS.find((item) => item.id === "insertLineBelow");
|
const definition = SHORTCUT_DEFINITIONS.find((item) => item.id === "insertLineBelow");
|
||||||
|
|
||||||
|
|||||||
@@ -246,6 +246,10 @@ export function isToggleSidebarShortcut(event: ShortcutLikeEvent, shortcuts?: Pa
|
|||||||
return matchesShortcut(event, actionShortcut("toggleSidebar", shortcuts));
|
return matchesShortcut(event, actionShortcut("toggleSidebar", shortcuts));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isToggleZenModeShortcut(event: ShortcutLikeEvent, shortcuts?: Partial<ShortcutSettings>): boolean {
|
||||||
|
return matchesShortcut(event, actionShortcut("toggleZenMode", shortcuts));
|
||||||
|
}
|
||||||
|
|
||||||
export function isCopySidebarSelectionShortcut(event: ShortcutLikeEvent, shortcuts?: Partial<ShortcutSettings>): boolean {
|
export function isCopySidebarSelectionShortcut(event: ShortcutLikeEvent, shortcuts?: Partial<ShortcutSettings>): boolean {
|
||||||
return matchesShortcut(event, actionShortcut("copySidebarSelection", shortcuts));
|
return matchesShortcut(event, actionShortcut("copySidebarSelection", shortcuts));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ export type ShortcutActionId =
|
|||||||
| "toggleTranspose"
|
| "toggleTranspose"
|
||||||
| "cancelSearch"
|
| "cancelSearch"
|
||||||
| "toggleSidebar"
|
| "toggleSidebar"
|
||||||
|
| "toggleZenMode"
|
||||||
| "copySidebarSelection"
|
| "copySidebarSelection"
|
||||||
| "pasteSidebarSelection"
|
| "pasteSidebarSelection"
|
||||||
| "editSidebarConnection"
|
| "editSidebarConnection"
|
||||||
@@ -503,6 +504,12 @@ export const SHORTCUT_DEFINITIONS: ShortcutDefinition[] = [
|
|||||||
scope: "global",
|
scope: "global",
|
||||||
defaultShortcut: "Mod+B",
|
defaultShortcut: "Mod+B",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: "toggleZenMode",
|
||||||
|
labelKey: "settings.shortcutToggleZenMode",
|
||||||
|
scope: "global",
|
||||||
|
defaultShortcut: "Shift+Mod+F12",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: "copySidebarSelection",
|
id: "copySidebarSelection",
|
||||||
labelKey: "settings.shortcutCopySidebarSelection",
|
labelKey: "settings.shortcutCopySidebarSelection",
|
||||||
|
|||||||
Reference in new issue
Block a user