feat(desktop): add DDL shortcut and grid row delete action

This commit is contained in:
jean authored and GitHub committed 2026-08-04 13:01:50 +08:00
1 parent 70db5be257
commit 44784d664c
19 files changed
+157 -4

No files matched your search

+30 -1
View File
@@ -215,7 +215,16 @@ import { useQueryStore } from "@/stores/queryStore";
import { useSettingsStore } from "@/stores/settingsStore";
import { simpleDataGridOrderByMatchesSort, simpleDataGridOrderByReferencesMissingColumn, type DataGridSortDirection, type DataGridSortMode } from "@/lib/dataGrid/dataGridSort";
import { buildOrderedGridRows, type GridInsertRowPosition, type GridNewRowPlacement } from "@/lib/dataGrid/gridNewRowPlacement";
import { DATA_GRID_CONDITION_TOOLBAR_MIN_WIDTH, isDataGridToolbarCompact, type DataGridReloadIntent, type DataGridToolbarActionCapability, type DataGridToolbarAddRowCapability, type DataGridToolbarAutoRefreshCapability, type DataGridToolbarSaveCapability } from "@/lib/dataGrid/dataGridToolbar";
import {
DATA_GRID_CONDITION_TOOLBAR_MIN_WIDTH,
dataGridDeleteRowToolbarState,
isDataGridToolbarCompact,
type DataGridReloadIntent,
type DataGridToolbarActionCapability,
type DataGridToolbarAddRowCapability,
type DataGridToolbarAutoRefreshCapability,
type DataGridToolbarSaveCapability,
} from "@/lib/dataGrid/dataGridToolbar";
import { getTableMetadataCapabilities } from "@/lib/table/tableMetadataCapabilities";
import { getTableStructureCapabilities } from "@/lib/table/tableStructureCapabilities";
import { filterObjectBrowserTableColumns } from "@/lib/table/objectBrowserTableInfo";
@@ -3416,6 +3425,25 @@ const addRowToolbarCapability = computed<DataGridToolbarAddRowCapability>(() =>
onTrigger: addRow,
onSelect: handleAddRowMenuSelect,
}));
const deleteRowToolbarTargetCount = computed(() => deletableRowIds(selectedOrCurrentRowIds()).length);
const deleteRowToolbarState = computed(() =>
dataGridDeleteRowToolbarState({
editable: !!props.editable,
canDeleteRows: canDeleteRows.value,
canDeleteExistingRows: canDeleteExistingRows.value,
deletableTargetCount: deleteRowToolbarTargetCount.value,
isSaving: isSaving.value,
}),
);
const deleteRowToolbarCapability = computed<DataGridToolbarActionCapability>(() => ({
label: deleteRowToolbarTargetCount.value > 1 ? t("grid.deleteRows", { count: deleteRowToolbarTargetCount.value }) : t("grid.deleteRow"),
tooltip: `${t("grid.deleteRow")} (${formatShortcut(settingsStore.editorSettings.shortcuts.deleteCurrentRow)})`,
visible: deleteRowToolbarState.value.visible,
disabled: deleteRowToolbarState.value.disabled,
onTrigger: () => {
deleteCurrentRow();
},
}));
const previewToolbarCapability = computed<DataGridToolbarActionCapability>(() => ({
label: t(previewLabelKey.value),
visible: saveToolbarState.value.showActions && pendingChangeCount.value > 0,
@@ -8479,6 +8507,7 @@ const gridContextMenuItems = computed<ContextMenuItem[]>(() => {
:refresh="refreshToolbarCapability"
:auto-refresh="autoRefreshToolbarCapability"
:add-row="addRowToolbarCapability"
:delete-row="deleteRowToolbarCapability"
:preview="previewToolbarCapability"
:save="saveToolbarCapability"
:rollback="rollbackToolbarCapability"
@@ -1,6 +1,6 @@
<script setup lang="ts">
import { computed } from "vue";
import { Check, ChevronDown, Copy, Eye, Loader2, Plus, RefreshCcw, RotateCcw, Rows3, Save, TableProperties, Timer, Upload } from "@lucide/vue";
import { Check, ChevronDown, Copy, Eye, Loader2, Plus, RefreshCcw, RotateCcw, Rows3, Save, TableProperties, Timer, Trash2, Upload } from "@lucide/vue";
import { Button } from "@/components/ui/button";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
@@ -28,6 +28,7 @@ const props = defineProps<{
refresh: DataGridToolbarActionCapability;
autoRefresh?: DataGridToolbarAutoRefreshCapability;
addRow?: DataGridToolbarAddRowCapability;
deleteRow?: DataGridToolbarActionCapability;
copyData?: DataGridToolbarCopyCapability;
exportData?: DataGridToolbarExportCapability;
transpose?: DataGridToolbarActionCapability;
@@ -148,6 +149,16 @@ function actionLabelClass() {
</DropdownMenu>
</div>
<Tooltip v-if="isDataGridToolbarCapabilityVisible(deleteRow)">
<TooltipTrigger as-child>
<Button variant="ghost" size="sm" :class="actionButtonClass" :disabled="isDataGridToolbarCapabilityDisabled(deleteRow)" @click="void triggerDataGridToolbarAction(deleteRow)">
<Trash2 class="data-grid-topbar-action-icon h-3 w-3" />
<span class="data-grid-topbar-action-label" :class="actionLabelClass()">{{ deleteRow?.label }}</span>
</Button>
</TooltipTrigger>
<TooltipContent side="bottom">{{ deleteRow?.tooltip ?? deleteRow?.label }}</TooltipContent>
</Tooltip>
<DropdownMenu v-if="isDataGridToolbarCapabilityVisible(exportData)">
<Tooltip>
<TooltipTrigger as-child>
@@ -10,7 +10,8 @@ import type { ObjectSourceKind, TableInfo, TableNameFilter, TreeNode, TreeNodeTy
import { filterSidebarSearchRootsByConnectionState, filterSidebarTree, filterSidebarTreeToConnectedConnections, resolveSidebarFilterGuards, reuseLiveSidebarTreeNodes } from "@/lib/sidebar/sidebarSearchTree";
import { matchSidebarLabel } from "@/lib/sidebar/sidebarSearch";
import { buildTableTreeNodes } from "@/lib/table/tableTree";
import { isCancelSearchShortcut, isCopySidebarSelectionShortcut, isEditSidebarConnectionShortcut, isPasteSidebarSelectionShortcut } from "@/lib/editor/keyboardShortcuts";
import { isCancelSearchShortcut, isCopySidebarSelectionShortcut, isEditSidebarConnectionShortcut, isPasteSidebarSelectionShortcut, isViewTableDdlShortcut } from "@/lib/editor/keyboardShortcuts";
import { sidebarNodeSupportsDdlView } from "@/lib/sidebar/sidebarTreeDdlShortcut";
import { copyNameForTreeNode, objectSourceKindForTreeNode } from "@/lib/sidebar/treeNodeClick";
import { copyToClipboard } from "@/lib/common/clipboard";
import { connectionPasteTargetGroupId, copySelectedConnectionsToClipboards, selectedConnectionEditTarget } from "@/lib/sidebar/sidebarConnectionSelection";
@@ -1264,6 +1265,14 @@ function openSidebarDdl(node: TreeNode) {
sidebarDdlOpen.value = true;
}
function openSidebarDdlForSelection(): boolean {
const selectedNodeId = store.selectedTreeNodeId;
const node = selectedNodeId ? flatTreeIndex.value.nodeById.get(selectedNodeId) : null;
if (!node || !sidebarNodeSupportsDdlView(node)) return false;
openSidebarDdl(node);
return true;
}
function openSidebarObjectSource(node: TreeNode, initialEditing: boolean) {
if (!node.connectionId || !node.database || !objectSourceKindForTreeNode(node.type)) return;
const target = createSidebarActionTarget(node);
@@ -1530,6 +1539,13 @@ function onWindowKeydown(event: KeyboardEvent) {
}
return;
}
if (sidebarShortcutTargetAllowsAppShortcut(event.target) && isViewTableDdlShortcut(event, settingsStore.editorSettings.shortcuts)) {
if (openSidebarDdlForSelection()) {
event.preventDefault();
event.stopPropagation();
}
return;
}
}
if (!pointerInsideTree.value || isEditableSidebarTypeSearchTarget(event.target) || isEditableSidebarTypeSearchTarget(document.activeElement)) return;