feat(sidebar): extend table grouping to all object containers
This commit is contained in:
1 parent
e1a512fd59
commit
591e8f4909
20 files changed
+607
-169
No files matched your search
@@ -23,8 +23,10 @@ function confirmCreate() {
|
||||
if (!scope || !name) return;
|
||||
const groupId = connectionStore.createTableVGroup(scope, name, tableVGroupDialogParentGroupId.value);
|
||||
if (groupId) {
|
||||
// scope 即右键的源行节点,其 type 就是这批待移入行的类别(多选保证同类型)。
|
||||
const rowType = scope.type;
|
||||
for (const tableName of tableVGroupDialogTableNames.value) {
|
||||
connectionStore.moveTableToVGroup(scope, tableName, groupId);
|
||||
connectionStore.moveTableToVGroup(scope, tableName, groupId, rowType);
|
||||
}
|
||||
emit("created", tableVGroupNodeId(groupId));
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ import { canTreeNodePin, canTreeNodeShowExpander } from "@/lib/sidebar/sidebarTr
|
||||
import { sidebarConnectionVisibleFilterMenu } from "@/lib/sidebar/sidebarVisibleFilterMenu";
|
||||
import { supportsSidebarObjectNameFilter } from "@/lib/sidebar/sidebarObjectNameFilter";
|
||||
import { connectionGroupDestinationRows } from "@/lib/sidebar/sidebarLayout";
|
||||
import { hasTableVGroupEntries, selectedTableVGroupMoveTargets, tableVGroupDestinationRows, tableVGroupPathForTable, tableVGroupsEnabled } from "@/lib/table/tableVGroup";
|
||||
import { hasTableVGroupEntries, isTableVGroupContainerNode, isTableVGroupGroupableRowType, resolveTableVGroupScopeFromNode, selectedTableVGroupMoveTargets, tableVGroupDestinationRows, tableVGroupPathForTable, tableVGroupScopeKey, tableVGroupsEnabled } from "@/lib/table/tableVGroup";
|
||||
import { objectTypesForGroupNode } from "@/lib/table/tableTree";
|
||||
import { loadSidebarObjectGroup } from "@/lib/sidebar/sidebarObjectGroupRouting";
|
||||
import { requestObjectBrowserSearchFocus } from "@/lib/tabs/objectBrowserSearchFocus";
|
||||
@@ -5958,6 +5958,11 @@ function buildSpecialSidebarMenu(context: SidebarMenuFactoryContext): boolean {
|
||||
|
||||
if (currentDatabaseType() === "hbase" && node.type === "table") {
|
||||
items.push({ label: t("contextMenu.copyName"), action: copyName, icon: Copy, shortcut: shortcutCopyName.value });
|
||||
// HBase 表行走本特化分支(先于 buildObjectSidebarMenu 的统一注入短路),分组移动入口需在此补齐。
|
||||
if (isTableVGroupGroupableRowType(node.type) && !!tableVGroupScopeKey(resolveTableVGroupScopeFromNode(connectionStore.treeNodes, node))) {
|
||||
const vgroupMoveItems = buildTableVGroupMoveMenuItems(node);
|
||||
if (vgroupMoveItems.length) items.push({ label: t("tableVGroup.moveToGroup"), icon: FolderInput, children: vgroupMoveItems });
|
||||
}
|
||||
items.push({ label: "", separator: true });
|
||||
items.push({ label: t("contextMenu.viewData"), action: openDataImmediately, icon: TableProperties });
|
||||
items.push({
|
||||
@@ -6150,6 +6155,15 @@ function buildSpecialSidebarMenu(context: SidebarMenuFactoryContext): boolean {
|
||||
|
||||
function buildObjectSidebarMenu(context: SidebarMenuFactoryContext): boolean {
|
||||
const { node, items, deleteMenuLabel, deleteMenuAction, truncateMenuLabel, truncateMenuAction, emptyMenuLabel, emptyMenuAction, batchAutoIncrementCount, autoIncrementMenuLabel, autoIncrementMenuAction } = context;
|
||||
// 虚拟分组移动入口:对所有可分组行类型统一注入(含 procedure/function/trigger/
|
||||
// sequence/event/synonym/job/package/type 等专属分支——它们各自 return true,
|
||||
// 若只在 table/view/mv 分支注入,这些行将没有任何分组入口)。表行保持原行为
|
||||
// (simple 模式也能经「移动到新分组」建组);其余行须已处于同类别分组容器内,
|
||||
// 否则解析不出 scope,菜单只会静默失败。
|
||||
if (isTableVGroupGroupableRowType(node.type) && (node.type === "table" || !!tableVGroupScopeKey(resolveTableVGroupScopeFromNode(connectionStore.treeNodes, node)))) {
|
||||
const vgroupMoveItems = buildTableVGroupMoveMenuItems(node);
|
||||
if (vgroupMoveItems.length) items.push({ label: t("tableVGroup.moveToGroup"), icon: FolderInput, children: vgroupMoveItems });
|
||||
}
|
||||
// 6. Table / View / Materialized View
|
||||
if (node.type === "table" || node.type === "view" || node.type === "materialized_view") {
|
||||
if (currentDatabaseType() === "victoriametrics" && node.type === "table") {
|
||||
@@ -6169,10 +6183,6 @@ function buildObjectSidebarMenu(context: SidebarMenuFactoryContext): boolean {
|
||||
}
|
||||
const destructiveActions: ContextMenuItem[] = [];
|
||||
items.push(copyNameMenuItem());
|
||||
if (node.type === "table") {
|
||||
const vgroupMoveItems = buildTableVGroupMoveMenuItems(node);
|
||||
if (vgroupMoveItems.length) items.push({ label: t("tableVGroup.moveToGroup"), icon: FolderInput, children: vgroupMoveItems });
|
||||
}
|
||||
items.push({ label: t("contextMenu.newQuery"), action: newQuery, icon: TerminalSquare });
|
||||
if (node.type === "table" && supportsAiAssistantContext(currentDatabaseType())) {
|
||||
items.push(addToAiMenuItem(node));
|
||||
@@ -6590,20 +6600,21 @@ function buildTableVGroupMoveMenuItems(node: TreeNode): ContextMenuItem[] {
|
||||
const layout = connectionStore.tableVGroupLayoutFor(node);
|
||||
const targets = selectedTableVGroupMoveTargets(node, selectedTreeNodesInVisibleOrder());
|
||||
const targetNames = targets.map((target) => target.label);
|
||||
const targetsInGroup = (groupId: string) => targetNames.every((name) => tableVGroupPathForTable(layout, name).includes(groupId));
|
||||
const targetRowType = targets[0]?.type;
|
||||
const targetsInGroup = (groupId: string) => targetNames.every((name) => tableVGroupPathForTable(layout, name, targetRowType).includes(groupId));
|
||||
const items: ContextMenuItem[] = tableVGroupDestinationRows(layout).map((row) => ({
|
||||
label: row.name,
|
||||
title: row.path.join(" / "),
|
||||
disabled: targetNames.length > 0 && targetsInGroup(row.id),
|
||||
action: () => {
|
||||
for (const name of targetNames) connectionStore.moveTableToVGroup(node, name, row.id);
|
||||
for (const name of targetNames) connectionStore.moveTableToVGroup(node, name, row.id, targetRowType);
|
||||
},
|
||||
}));
|
||||
if (targetNames.some((name) => tableVGroupPathForTable(layout, name).length > 0)) {
|
||||
if (targetNames.some((name) => tableVGroupPathForTable(layout, name, targetRowType).length > 0)) {
|
||||
items.push({
|
||||
label: t("tableVGroup.removeFromGroup"),
|
||||
action: () => {
|
||||
for (const name of targetNames) connectionStore.moveTableToVGroup(node, name, null);
|
||||
for (const name of targetNames) connectionStore.moveTableToVGroup(node, name, null, targetRowType);
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -6623,7 +6634,7 @@ function buildTableVGroupMoveMenuItems(node: TreeNode): ContextMenuItem[] {
|
||||
}
|
||||
|
||||
function appendTableVGroupContainerItems(node: TreeNode, items: ContextMenuItem[]) {
|
||||
if (node.type !== "database" && node.type !== "schema" && node.type !== "linked-server-schema" && node.type !== "group-tables") return;
|
||||
if (!isTableVGroupContainerNode(node)) return;
|
||||
const layout = connectionStore.tableVGroupLayoutFor(node);
|
||||
if (!hasTableVGroupEntries(layout)) return;
|
||||
const enabled = tableVGroupsEnabled(layout);
|
||||
|
||||
@@ -74,7 +74,7 @@ import { formatSidebarObjectStorage } from "@/lib/sidebar/sidebarDatabaseStorage
|
||||
import { effectiveRedisDatabaseIndex } from "@/lib/redis/redisDatabaseIndex";
|
||||
import { dataTabOpenModeFromTreeClick } from "@/lib/sidebar/dataTabOpenPolicy";
|
||||
import { effectiveDatabaseTypeForConnection } from "@/lib/database/jdbcDialect";
|
||||
import { selectedTableVGroupMoveTargets, tableVGroupIdFromNodeId } from "@/lib/table/tableVGroup";
|
||||
import { isTableVGroupGroupableRowType, selectedTableVGroupMoveTargets, tableVGroupIdFromNodeId } from "@/lib/table/tableVGroup";
|
||||
import { findTreeNodeById } from "@/lib/sql/newQueryContext";
|
||||
import { resolveTableVGroupDropTarget, setTableVGroupDropTargetNodeId, tableVGroupDropTargetNodeId } from "@/lib/sidebar/sidebarTableVGroupDrag";
|
||||
import { connectionDisplayUrlScheme } from "@/lib/connection/connectionPresentation";
|
||||
@@ -1375,9 +1375,10 @@ function tableReferenceDragPayload(): QueryEditorTableReferencePayload | null {
|
||||
|
||||
function startTableReferenceDrag(payload: QueryEditorTableReferencePayload) {
|
||||
draggingTableReferencePayload = payload;
|
||||
// 分组成员名单只收真实表:视图/物化视图投影不识别,入组会产生隐形脏数据。
|
||||
// 分组成员名单按可分组行类型收集(表/视图/物化视图/过程/函数/触发器/序列等);
|
||||
// 无匹配容器的行由 scope 解析兜底拒绝,不会产生隐形脏数据。
|
||||
vgroupDragTableNames = selectedTableVGroupMoveTargets(activeNode.value, selectedTreeNodesInVisibleOrder())
|
||||
.filter((node) => node.type === "table")
|
||||
.filter((node) => isTableVGroupGroupableRowType(node.type))
|
||||
.map((node) => node.label);
|
||||
setActiveTableReferencePayload(payload);
|
||||
document.getSelection()?.removeAllRanges();
|
||||
@@ -1402,7 +1403,8 @@ let vgroupDragTableNames: string[] = [];
|
||||
|
||||
function tableVGroupDropTargetFor(payload: QueryEditorTableReferencePayload, event: MouseEvent) {
|
||||
if (!vgroupDragTableNames.length) return null;
|
||||
return resolveTableVGroupDropTarget(event.clientX, event.clientY, connectionStore.treeNodes, payload);
|
||||
// 拖拽源是树行(多选同类型),落点解析按行类别过滤跨类别容器。
|
||||
return resolveTableVGroupDropTarget(event.clientX, event.clientY, connectionStore.treeNodes, { ...payload, objectType: activeNode.value.type });
|
||||
}
|
||||
|
||||
function onTableReferenceMouseMove(event: MouseEvent) {
|
||||
@@ -1431,7 +1433,7 @@ function onTableReferenceMouseUp(event: MouseEvent) {
|
||||
suppressNextTableReferenceClick = true;
|
||||
const dropTarget = tableVGroupDropTargetFor(payload, event);
|
||||
if (dropTarget) {
|
||||
for (const tableName of vgroupDragTableNames) connectionStore.moveTableToVGroup(dropTarget.node, tableName, dropTarget.groupId);
|
||||
for (const tableName of vgroupDragTableNames) connectionStore.moveTableToVGroup(dropTarget.node, tableName, dropTarget.groupId, activeNode.value.type);
|
||||
} else {
|
||||
const target = document.elementFromPoint(event.clientX, event.clientY);
|
||||
if (target instanceof Element && target.closest(`[data-query-editor-root], ${AI_ASSISTANT_TABLE_DROP_ROOT_SELECTOR}`)) {
|
||||
|
||||
@@ -24,7 +24,7 @@ export const deleteConnectionsWithGroup = ref(false);
|
||||
export const showTableVGroupDialog = ref(false);
|
||||
export const tableVGroupName = ref("");
|
||||
/** Scope snapshot + creation payload for the table vgroup naming dialog. */
|
||||
export const tableVGroupDialogScope = shallowRef<TableVGroupScope | null>(null);
|
||||
export const tableVGroupDialogScope = shallowRef<TreeNode | null>(null);
|
||||
export const tableVGroupDialogParentGroupId = ref<string | null>(null);
|
||||
export const tableVGroupDialogTableNames = ref<string[]>([]);
|
||||
export const showTableVGroupDeleteConfirm = ref(false);
|
||||
|
||||
Reference in new issue
Block a user