feat(structure): add view data entry to the DDL structure tab

This commit is contained in:
zipg authored and GitHub committed 2026-09-21 13:37:21 +08:00
1 parent 98d3209026
commit e74257b6e0
15 files changed
+41 -4

No files matched your search

@@ -11034,7 +11034,7 @@ function copyDdl() {
function openTableStructureEditor() {
if (!props.connectionId || !props.database || !props.tableMeta?.tableName || !canOpenTableStructureEditor.value) return;
queryStore.openTableStructure(props.connectionId, props.database, props.tableMeta.schema, props.tableMeta.tableName, activeTableInfoTab.value, undefined, props.tableMeta.catalog);
queryStore.openTableStructure(props.connectionId, props.database, props.tableMeta.schema, props.tableMeta.tableName, activeTableInfoTab.value, undefined, props.tableMeta.catalog, (props.tableMeta.tableType || "").toUpperCase() === "VIEW" ? "view" : "table");
}
function toggleDdlWrap() {
@@ -167,7 +167,7 @@ describe("DataGrid edit-table-structure shortcut", () => {
expect(event.defaultPrevented).toBe(true);
expect(bubbled).not.toHaveBeenCalled();
expect(openTableStructure).toHaveBeenCalledOnce();
expect(openTableStructure).toHaveBeenCalledWith("connection-1", "app", "public", "users", "ddl", undefined, "warehouse");
expect(openTableStructure).toHaveBeenCalledWith("connection-1", "app", "public", "users", "ddl", undefined, "warehouse", "table");
});
it("uses a configured shortcut and leaves the default key untouched", async () => {
@@ -964,6 +964,24 @@ function onHandleViewTableData(target: SqlObjectNavigationTarget) {
emit("viewTableData", props.activeTab.id, target);
}
/**
* The structure/DDL editor only owns the object identity, so build the
* navigation target from the active tab and reuse the same "view data" path as
* the SQL editor context menu (issue #6724).
*/
function onHandleStructureViewData() {
const tab = props.activeTab;
const meta = tab.tableMeta;
const tableName = tab.structureTableName || meta?.tableName;
if (!tableName) return;
emit("viewTableData", tab.id, {
name: tableName,
database: meta?.database || tab.database,
schema: meta?.schema || tab.schema,
type: tab.structureTableType === "view" ? "view" : "table",
});
}
function onHandleViewTableDdl(target: SqlObjectNavigationTarget) {
emit("viewTableDdl", props.activeTab.id, target);
}
@@ -2804,6 +2822,7 @@ defineExpose({
@saved="(commentChanged) => emit('structureEditorSaved', activeTab.id, commentChanged)"
@close="emit('structureEditorClose', activeTab.id)"
@open-settings="(initialTab, initialSection) => emit('openSettings', initialTab, initialSection)"
@view-data="onHandleStructureViewData"
/>
</div>
</template>
@@ -49,6 +49,7 @@ vi.mock("@lucide/vue", async () => {
Pencil: Icon,
Plus: Icon,
RefreshCw: Icon,
Rows3: Icon,
Save: Icon,
Search: Icon,
Settings: Icon,
@@ -55,6 +55,7 @@ vi.mock("@lucide/vue", async () => {
Maximize2: Icon,
Plus: Icon,
RefreshCw: Icon,
Rows3: Icon,
Save: Icon,
Search: Icon,
Settings: Icon,
@@ -10,7 +10,7 @@ import { Input } from "@/components/ui/input";
import { Badge } from "@/components/ui/badge";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { AlertTriangle, Check, ChevronDown, ChevronLeft, ChevronRight, ChevronUp, ClipboardList, Copy, Database, Info, KeyRound, ListChevronsUpDown, Loader2, Maximize2, Pencil, Plus, RefreshCw, RotateCcw, Save, Search, Settings, SlidersHorizontal, Trash2, UserRound, X } from "@lucide/vue";
import { AlertTriangle, Check, ChevronDown, ChevronLeft, ChevronRight, ChevronUp, ClipboardList, Copy, Database, Info, KeyRound, ListChevronsUpDown, Loader2, Maximize2, Pencil, Plus, RefreshCw, RotateCcw, Rows3, Save, Search, Settings, SlidersHorizontal, Trash2, UserRound, X } from "@lucide/vue";
import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
@@ -173,6 +173,8 @@ const emit = defineEmits<{
saved: [commentChanged: boolean];
close: [];
openSettings: [initialTab?: string, initialSection?: string];
/** Jump from the DDL view to the table's data tab (issue #6724). */
viewData: [];
}>();
const activeTab = ref<TableInfoTab>("columns");
@@ -4412,6 +4414,10 @@ watch(
<TabsTrigger v-if="tableMetadataCapabilities.triggers" value="triggers">{{ t("structureEditor.triggers") }}</TabsTrigger>
</TabsList>
<div class="flex shrink-0 items-center gap-1.5">
<Button v-if="!isCreateMode" size="sm" variant="outline" :class="structureToolbarButtonClass" data-structure-view-data @click="emit('viewData')">
<Rows3 :class="structureIconClass" />
{{ t("contextMenu.viewData") }}
</Button>
<div class="flex items-center gap-1.5">
<SlidersHorizontal :class="[structureIconClass, 'text-muted-foreground']" />
<div ref="structureDensityMenuRef" class="relative">
@@ -48,6 +48,7 @@ vi.mock("@lucide/vue", async () => {
Maximize2: Icon,
Plus: Icon,
RefreshCw: Icon,
Rows3: Icon,
Save: Icon,
Search: Icon,
Settings: Icon,
@@ -66,6 +66,7 @@ vi.mock("@lucide/vue", async () => {
Plus: Icon,
RefreshCw: Icon,
RotateCcw: Icon,
Rows3: Icon,
Save: Icon,
Search: Icon,
Settings: Icon,
@@ -50,6 +50,7 @@ vi.mock("@lucide/vue", async () => {
Plus: Icon,
RefreshCw: Icon,
RotateCcw: Icon,
Rows3: Icon,
Save: Icon,
Search: Icon,
Settings: Icon,
@@ -56,6 +56,7 @@ vi.mock("@lucide/vue", async () => {
Plus: Icon,
RefreshCw: Icon,
RotateCcw: Icon,
Rows3: Icon,
Save: Icon,
Search: Icon,
Settings: Icon,
@@ -59,6 +59,7 @@ vi.mock("@lucide/vue", async () => {
Plus: Icon,
RefreshCw: Icon,
RotateCcw: Icon,
Rows3: Icon,
Save: Icon,
Search: Icon,
Settings: Icon,
+4 -1
View File
@@ -2433,6 +2433,7 @@ export const useQueryStore = defineStore("query", () => {
resultAutoSave: t.resultAutoSave,
uiState: t.uiState,
structureTableName: t.structureTableName,
structureTableType: t.structureTableType,
structureDraft: t.structureDraft,
objectBrowser: t.objectBrowser,
objectSource: t.objectSource,
@@ -3680,7 +3681,7 @@ export const useQueryStore = defineStore("query", () => {
tab.structureInitialTabRequestId = (tab.structureInitialTabRequestId ?? 0) + 1;
}
function openTableStructure(connectionId: string, database: string, schema?: string, tableName?: string, initialTab?: TableInfoTab, initialTarget?: TableStructureEditorTarget, catalog?: string) {
function openTableStructure(connectionId: string, database: string, schema?: string, tableName?: string, initialTab?: TableInfoTab, initialTarget?: TableStructureEditorTarget, catalog?: string, tableType?: "table" | "view") {
const resolvedTableName = tableName || "";
if (resolvedTableName) {
const existing = tabs.value.find((tab) => tab.mode === "structure" && tab.connectionId === connectionId && tab.database === database && (tab.catalog || "") === (catalog || "") && (tab.schema || "") === (schema || "") && (tab.structureTableName || "") === resolvedTableName);
@@ -3706,6 +3707,7 @@ export const useQueryStore = defineStore("query", () => {
isExplaining: false,
mode: "structure",
structureTableName: resolvedTableName,
structureTableType: tableType,
structureInitialTab: initialTab,
structureInitialTabRequestId: initialTab || initialTarget?.name ? 1 : undefined,
structureInitialTarget: initialTarget?.name ? initialTarget : undefined,
@@ -4362,6 +4364,7 @@ export const useQueryStore = defineStore("query", () => {
nacosNamespace: original.nacosNamespace,
nacosNamespaceName: original.nacosNamespaceName,
structureTableName: original.structureTableName,
structureTableType: original.structureTableType,
structureDraft: original.structureDraft ? cloneTabDraft(original.structureDraft) : undefined,
objectBrowser: original.objectBrowser ? { ...original.objectBrowser } : undefined,
objectSource: original.objectSource ? { ...original.objectSource } : undefined,
+2
View File
@@ -1780,6 +1780,8 @@ export interface QueryTab {
nacosTargetRequestId?: number;
nacosConfigEditorViewport?: NacosConfigEditorViewport;
structureTableName?: string;
/** Navigation type of the opened structure object; views matter for "view data" routing. */
structureTableType?: "table" | "view";
structureInitialTab?: TableInfoTab;
structureInitialTabRequestId?: number;
structureInitialTarget?: TableStructureEditorTarget;
Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB