feat(grid): add go-to-column toolbar action
This commit is contained in:
parent
433907e96e
commit
9fc2e25fbf
|
|
@ -63,6 +63,7 @@ import {
|
|||
PanelRight,
|
||||
TableProperties,
|
||||
Database,
|
||||
Columns3,
|
||||
} from "@lucide/vue";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import QueryLoadingState from "@/components/common/QueryLoadingState.vue";
|
||||
|
|
@ -1648,6 +1649,9 @@ const nullColumnsHidden = ref(false);
|
|||
const autoHiddenNullColumnIndexes = ref<Set<number>>(new Set());
|
||||
const highlightedColumnIndex = ref<number | null>(null);
|
||||
let highlightedColumnTimer = 0;
|
||||
|
||||
const goToColumnOpen = ref(false);
|
||||
const goToColumnSearch = ref("");
|
||||
const columnOrderKeys = computed(() => uniqueDataGridColumnOrderKeys(props.result.columns, props.sourceColumns));
|
||||
const columnLayoutScopeKey = computed(() =>
|
||||
dataGridColumnLayoutScopeKey({
|
||||
|
|
@ -1669,6 +1673,18 @@ const displayableColumnIndexes = computed(() =>
|
|||
.filter(({ column }) => !isHiddenGridColumn(props.databaseType, column, props.tableMeta?.primaryKeys ?? []))
|
||||
.map(({ index }) => index),
|
||||
);
|
||||
const goToColumnItems = computed(() =>
|
||||
displayableColumnIndexes.value.map((index) => ({
|
||||
index,
|
||||
name: props.result.columns[index] ?? `#${index + 1}`,
|
||||
sourceName: props.sourceColumns?.[index],
|
||||
})),
|
||||
);
|
||||
const filteredGoToColumns = computed(() => {
|
||||
const query = goToColumnSearch.value.trim().toLocaleLowerCase();
|
||||
if (!query) return goToColumnItems.value;
|
||||
return goToColumnItems.value.filter((column) => column.name.toLocaleLowerCase().includes(query) || column.sourceName?.toLocaleLowerCase().includes(query));
|
||||
});
|
||||
const orderedDisplayableColumnIndexes = computed(() =>
|
||||
orderedColumnIndexes({
|
||||
availableIndexes: displayableColumnIndexes.value,
|
||||
|
|
@ -1780,12 +1796,33 @@ const firstVisibleColumnIndex = computed(() => visibleColumnIndexes.value[0] ??
|
|||
function actualColumnIndex(visibleColumnIndex: number): number {
|
||||
return visibleColumnIndexes.value[visibleColumnIndex] ?? visibleColumnIndex;
|
||||
}
|
||||
function scrollToColumn(columnIndex: number) {
|
||||
goToColumnOpen.value = false;
|
||||
goToColumnSearch.value = "";
|
||||
scrollToColumnIndex(columnIndex);
|
||||
gridRef.value?.focus();
|
||||
}
|
||||
|
||||
function onGoToColumnKeydown(event: KeyboardEvent) {
|
||||
if (event.key === "Escape") {
|
||||
goToColumnOpen.value = false;
|
||||
goToColumnSearch.value = "";
|
||||
}
|
||||
}
|
||||
|
||||
watch(goToColumnOpen, (open) => {
|
||||
if (!open) goToColumnSearch.value = "";
|
||||
});
|
||||
|
||||
function matchesTableInfoColumn(resultColumn: string, sourceColumn: string | undefined, columnName: string): boolean {
|
||||
const target = columnName.toLocaleLowerCase();
|
||||
return resultColumn.toLocaleLowerCase() === target || sourceColumn?.toLocaleLowerCase() === target;
|
||||
}
|
||||
function scrollToTableInfoColumn(columnName: string) {
|
||||
const columnIndex = props.result.columns.findIndex((column, index) => matchesTableInfoColumn(column, props.sourceColumns?.[index], columnName));
|
||||
scrollToColumnIndex(columnIndex);
|
||||
}
|
||||
function scrollToColumnIndex(columnIndex: number) {
|
||||
if (columnIndex < 0 || !displayableColumnIndexes.value.includes(columnIndex)) return;
|
||||
|
||||
if (hiddenColumnIndexes.value.has(columnIndex)) {
|
||||
|
|
@ -7165,6 +7202,35 @@ const gridContextMenuItems = computed<ContextMenuItem[]>(() => {
|
|||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom" class="max-w-sm"> {{ dataGridRenderMode === "canvas" ? t("grid.canvasRenderMode") : t("grid.domRenderMode") }} · {{ t("grid.renderModeHint") }} </TooltipContent>
|
||||
</Tooltip>
|
||||
<Tooltip v-if="props.result.columns.length">
|
||||
<TooltipTrigger as-child>
|
||||
<Popover v-model:open="goToColumnOpen">
|
||||
<PopoverTrigger as-child>
|
||||
<Button variant="ghost" size="sm" :class="['data-grid-topbar-action-button h-5 shrink-0 text-xs px-1.5', compactDataGridToolbar ? 'data-grid-topbar-action-button--compact' : '', goToColumnOpen ? 'text-primary bg-primary/10' : '']">
|
||||
<Columns3 class="data-grid-topbar-action-icon w-3 h-3" />
|
||||
<span class="data-grid-topbar-action-label" :class="{ 'data-grid-topbar-action-label--compact': compactDataGridToolbar }">{{ t("grid.goToColumn") }}</span>
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent align="end" class="w-56 p-2" @keydown="onGoToColumnKeydown">
|
||||
<div class="relative mb-1">
|
||||
<Search class="pointer-events-none absolute left-2 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground" />
|
||||
<input v-model="goToColumnSearch" :placeholder="t('grid.searchColumn')" class="h-8 w-full rounded-md border bg-transparent pl-7 pr-6 text-xs outline-none focus-visible:border-ring/50 focus-visible:ring-1 focus-visible:ring-ring/25" />
|
||||
<button v-if="goToColumnSearch" type="button" class="absolute right-1.5 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground" @click="goToColumnSearch = ''">
|
||||
<X class="h-3.5 w-3.5" />
|
||||
</button>
|
||||
</div>
|
||||
<div class="max-h-56 overflow-auto rounded border">
|
||||
<button v-for="column in filteredGoToColumns" :key="column.index" type="button" class="flex w-full items-center gap-1.5 px-2 py-1.5 text-left text-xs hover:bg-accent hover:text-accent-foreground" @click="scrollToColumn(column.index)">
|
||||
<span class="min-w-0 truncate">{{ column.name }}</span>
|
||||
<span class="ml-auto shrink-0 font-mono text-[10px] text-muted-foreground">#{{ column.index + 1 }}</span>
|
||||
</button>
|
||||
<div v-if="!filteredGoToColumns.length" class="px-2 py-3 text-center text-xs text-muted-foreground">{{ t("grid.noColumnsFound") }}</div>
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom">{{ t("grid.goToColumn") }}</TooltipContent>
|
||||
</Tooltip>
|
||||
<Tooltip v-if="editable && (tableMeta || customSaveHandler)">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="sm" :class="['data-grid-topbar-action-button h-5 shrink-0 text-xs px-1.5', compactDataGridToolbar ? 'data-grid-topbar-action-button--compact' : '']" @click="addRow">
|
||||
|
|
|
|||
|
|
@ -804,6 +804,9 @@ export default {
|
|||
tableInfoEmpty: "No metadata",
|
||||
tableInfoSearch: "Search...",
|
||||
tableInfoNoResults: "No results",
|
||||
goToColumn: "Go to column",
|
||||
searchColumn: "Search column...",
|
||||
noColumnsFound: "No columns found",
|
||||
queryError: "Query Error",
|
||||
dataUnavailable: "Table data needs to be reloaded.",
|
||||
dataUnavailableHintPrefix: "Press ",
|
||||
|
|
|
|||
|
|
@ -807,6 +807,9 @@ export default withEnglishFallback({
|
|||
tableInfoEmpty: "暂无元数据",
|
||||
tableInfoSearch: "搜索...",
|
||||
tableInfoNoResults: "无匹配结果",
|
||||
goToColumn: "跳转列",
|
||||
searchColumn: "搜索列...",
|
||||
noColumnsFound: "未找到列",
|
||||
queryError: "查询出错",
|
||||
dataUnavailable: "表数据需要重新加载。",
|
||||
dataUnavailableHintPrefix: "按 ",
|
||||
|
|
|
|||
Loading…
Reference in New Issue