From e513c260b564d548f8c8e20316b7120a27bad56b Mon Sep 17 00:00:00 2001 From: t8y2 <1156263951@qq.com> Date: Wed, 13 May 2026 16:34:56 +0800 Subject: [PATCH] feat: driver store UX improvements and multi-row range copy - ESC key closes driver store before closing tabs - Auto-scroll to driver store tab when opened - Deactivate query tab highlight when driver store is open - Support copying range-selected rows as JSON - Add multiRowCount/isMultiRow computed properties for DataGrid --- src/App.vue | 6 ++- src/components/grid/DataGrid.vue | 56 +++++++++++++--------------- src/components/layout/AppTabBar.vue | 27 +++++++++++--- src/composables/useDataGridExport.ts | 13 +++++++ 4 files changed, 66 insertions(+), 36 deletions(-) diff --git a/src/App.vue b/src/App.vue index ad2acc34bd..3272c71401 100644 --- a/src/App.vue +++ b/src/App.vue @@ -411,7 +411,11 @@ function onAiRequestAutoExecuteSql(sql: string) { function handleKeydown(e: KeyboardEvent) { if (isCloseTabShortcut(e)) { e.preventDefault(); - if (queryStore.activeTabId) queryStore.closeTab(queryStore.activeTabId); + if (showDriverStore.value) { + showDriverStore.value = false; + } else if (queryStore.activeTabId) { + queryStore.closeTab(queryStore.activeTabId); + } return; } if ( diff --git a/src/components/grid/DataGrid.vue b/src/components/grid/DataGrid.vue index 813d85d194..9e436f97e8 100644 --- a/src/components/grid/DataGrid.vue +++ b/src/components/grid/DataGrid.vue @@ -1091,6 +1091,26 @@ const selectionSummary = computed(() => { return t("grid.selectedCells", { count: selectedCellCount.value }); }); +const multiRowCount = computed(() => { + if (hasRowSelection.value) return selectedRowCount.value; + const range = selectedRange.value; + if (range && range.startRow !== range.endRow) return range.endRow - range.startRow + 1; + return 1; +}); + +const isMultiRow = computed(() => multiRowCount.value > 1); + +function affectedRowIds(): number[] { + if (hasRowSelection.value && selectedRowCount.value > 0) { + return [...selectedRowIds.value]; + } + const range = selectedRange.value; + if (range && range.startRow !== range.endRow) { + return displayItems.value.slice(range.startRow, range.endRow + 1).map((item) => item.id); + } + return []; +} + function isRowActive(index: number): boolean { const item = displayItems.value[index]; if (item && isRowSelected(item.id)) return true; @@ -2570,18 +2590,10 @@ defineExpose({ {{ t("grid.copyCell") }} - {{ - hasRowSelection && selectedRowCount > 1 - ? t("grid.copyRows", { count: selectedRowCount }) - : t("grid.copyRow") - }} + {{ isMultiRow ? t("grid.copyRows", { count: multiRowCount }) : t("grid.copyRow") }} - {{ - hasRowSelection && selectedRowCount > 1 - ? t("grid.copyRowsInsert", { count: selectedRowCount }) - : t("grid.copyRowInsert") - }} + {{ isMultiRow ? t("grid.copyRowsInsert", { count: multiRowCount }) : t("grid.copyRowInsert") }} {{ t("grid.copyAll") }} @@ -2604,17 +2616,9 @@ defineExpose({ diff --git a/src/components/layout/AppTabBar.vue b/src/components/layout/AppTabBar.vue index 8d4b9468c9..393e93f80b 100644 --- a/src/components/layout/AppTabBar.vue +++ b/src/components/layout/AppTabBar.vue @@ -17,7 +17,7 @@ import { connectionColor, tabDisplayTitle, tabTooltipLines } from "@/lib/tabPres import { hexToRgba } from "@/lib/color"; import type { QueryTab } from "@/types/database"; -defineProps<{ +const props = defineProps<{ showDriverStore?: boolean; }>(); @@ -55,9 +55,25 @@ watch( }, ); +watch( + () => props.showDriverStore, + (show) => { + if (!show) return; + nextTick(() => { + const container = tabsContainerRef.value; + if (!container) return; + const el = container.querySelector("[data-driver-store-tab]"); + if (el) { + el.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "center" }); + } + updateScrollButtons(); + }); + }, +); + function tabColorStyle(tab: QueryTab) { const color = connectionColor(tab.connectionId); - const isActive = tab.id === queryStore.activeTabId; + const isActive = tab.id === queryStore.activeTabId && !props.showDriverStore; const isClassic = settingsStore.editorSettings.appLayout === "classic"; if (!color) { if (isClassic) { @@ -124,19 +140,19 @@ function tabIconClass(tab: QueryTab) { settingsStore.editorSettings.appLayout === 'classic' ? [ 'h-full border-r border-border/50', - tab.id === queryStore.activeTabId + tab.id === queryStore.activeTabId && !showDriverStore ? 'bg-background text-foreground font-medium' : 'text-foreground/70 hover:text-foreground/90', ] : [ 'h-7 rounded-md border', - tab.id === queryStore.activeTabId + tab.id === queryStore.activeTabId && !showDriverStore ? 'text-foreground font-medium' : 'border-border/60 text-foreground/70 hover:border-border hover:text-foreground/90', ] " :style="tabColorStyle(tab)" - :data-active-tab="tab.id === queryStore.activeTabId" + :data-active-tab="tab.id === queryStore.activeTabId && !showDriverStore" @click=" queryStore.activeTabId = tab.id; emit('close-driver-store'); @@ -202,6 +218,7 @@ function tabIconClass(tab: QueryTab) {