fix(sidebar): pin vgroup rows before flat rows on sort
This commit is contained in:
4 files changed
+115
-8
No files matched your search
+46
@@ -0,0 +1,46 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { sortSidebarTreeChildrenByNameKeepingTableVGroups } from "@/lib/sidebar/sidebarNodeOrdering";
|
||||
import { applyTableVGroupsToChildren, createTableVGroup, emptyTableVGroupLayout, moveTableToVGroup } from "@/lib/table/tableVGroup";
|
||||
import type { TreeNode } from "@/types/database";
|
||||
|
||||
const SCOPE = { connectionId: "conn-1", database: "db1" };
|
||||
|
||||
function tableNode(name: string): TreeNode {
|
||||
return { id: `table:${name}`, label: name, type: "table", connectionId: "conn-1", database: "db1" };
|
||||
}
|
||||
|
||||
/** Mirrors connectionStore.mergeLocatedTreeChildren: merge a page, then re-sort. */
|
||||
function mergePageLikeStore(parent: TreeNode, children: TreeNode[], page: TreeNode[]): TreeNode[] {
|
||||
return sortSidebarTreeChildrenByNameKeepingTableVGroups(parent, [...children, ...page], "mysql");
|
||||
}
|
||||
|
||||
describe("sidebar ordering keeps projected table groups pinned", () => {
|
||||
it("keeps a virtual table group at the top after a paged merge re-sorts children by name", () => {
|
||||
const created = createTableVGroup(emptyTableVGroupLayout(), "zzz-分组");
|
||||
const layout = moveTableToVGroup(created.layout, "t_order", created.groupId);
|
||||
const parent: TreeNode = { id: "group-tables:db1", label: "tables", type: "group-tables", connectionId: "conn-1", database: "db1" };
|
||||
|
||||
// What the sidebar shows after the layout projection runs.
|
||||
const projected = applyTableVGroupsToChildren([tableNode("t_user"), tableNode("t_order")], layout, SCOPE);
|
||||
expect(projected[0]!.type).toBe("table-vgroup");
|
||||
|
||||
// A sidebar page merge must not move the projected group out of the top
|
||||
// slot: the layout, not the alphabet, decides where a group sits.
|
||||
const merged = mergePageLikeStore(parent, projected, [tableNode("t_zzz")]);
|
||||
expect(merged[0]!.type).toBe("table-vgroup");
|
||||
expect(merged.slice(1).map((node) => node.label)).toEqual(["t_user", "t_zzz"]);
|
||||
expect(merged[0]!.children?.map((node) => node.label)).toEqual(["t_order"]);
|
||||
});
|
||||
|
||||
it("keeps projected groups in layout order when their labels sort differently", () => {
|
||||
const first = createTableVGroup(emptyTableVGroupLayout(), "b-组");
|
||||
let layout = moveTableToVGroup(first.layout, "t_order", first.groupId);
|
||||
const second = createTableVGroup(layout, "a-组");
|
||||
layout = moveTableToVGroup(second.layout, "t_pay", second.groupId);
|
||||
const parent: TreeNode = { id: "group-tables:db1", label: "tables", type: "group-tables", connectionId: "conn-1", database: "db1" };
|
||||
|
||||
const projected = applyTableVGroupsToChildren([tableNode("t_user"), tableNode("t_order"), tableNode("t_pay")], layout, SCOPE);
|
||||
const merged = mergePageLikeStore(parent, projected, [tableNode("t_zzz")]);
|
||||
expect(merged.filter((node) => node.type === "table-vgroup").map((node) => node.label)).toEqual(["b-组", "a-组"]);
|
||||
});
|
||||
});
|
||||
@@ -17,7 +17,38 @@ function sortRecursive(node: TreeNode, databaseType?: DatabaseType): TreeNode {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Virtual table groups are a display-level projection (see
|
||||
* `applyTableVGroupsToChildren`) whose order comes from the stored layout, not
|
||||
* from the alphabet. Every ordering pass therefore has to leave them ahead of
|
||||
* the flat rows: a name-sorted metadata merge would otherwise drop a group back
|
||||
* to its alphabetical slot, and the row would visibly jump from the top of the
|
||||
* list to the bottom until the next projection ran (issues #9644 / #9653).
|
||||
*/
|
||||
function hoistTableVGroupChildren(nodes: TreeNode[]): TreeNode[] {
|
||||
if (!nodes.some((node) => node.type === "table-vgroup")) return nodes;
|
||||
return [...nodes.filter((node) => node.type === "table-vgroup"), ...nodes.filter((node) => node.type !== "table-vgroup")];
|
||||
}
|
||||
|
||||
export function sortSidebarTreeChildrenForParent(parent: Pick<TreeNode, "type">, children: readonly TreeNode[], databaseType?: DatabaseType): TreeNode[] {
|
||||
return hoistTableVGroupChildren(orderSidebarTreeChildrenForParent(parent, children, databaseType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Orders a container whose rows are merged from paged metadata: only the flat
|
||||
* rows are sorted by label, while projected virtual table groups keep the
|
||||
* position (and relative order) the layout projection gave them. Sorting the
|
||||
* groups by name would move them out of the top slot they were projected into
|
||||
* (issues #9644 / #9653).
|
||||
*/
|
||||
export function sortSidebarTreeChildrenByNameKeepingTableVGroups(parent: Pick<TreeNode, "type">, children: readonly TreeNode[], databaseType?: DatabaseType): TreeNode[] {
|
||||
const groups = children.filter((node) => node.type === "table-vgroup");
|
||||
const flat = children.filter((node) => node.type !== "table-vgroup");
|
||||
const orderedFlat = [...flat].sort((left, right) => sidebarTreeCollator.compare(left.label, right.label));
|
||||
return sortSidebarTreeChildrenForParent(parent, [...groups, ...orderedFlat], databaseType);
|
||||
}
|
||||
|
||||
function orderSidebarTreeChildrenForParent(parent: Pick<TreeNode, "type">, children: readonly TreeNode[], databaseType?: DatabaseType): TreeNode[] {
|
||||
const normalized = children.map((child) => sortRecursive(child, databaseType));
|
||||
|
||||
if (parent.type === "mongo-db") {
|
||||
|
||||
Reference in new issue
Block a user