fix(navigator): align object browser table sorting

This commit is contained in:
vrustx 2026-07-16 15:19:04 +08:00 committed by GitHub
parent 0a1efdcb85
commit 552e1741db
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 33 additions and 6 deletions

View File

@ -1,5 +1,5 @@
import type { ObjectInfo } from "@/types/database";
import { createDatabaseObjectNameComparator, normalizeDatabaseObjectName } from "@/lib/table/tableTree";
import { compareDatabaseObjectNames, normalizeDatabaseObjectName } from "@/lib/table/tableTree";
import { parseSlashDelimitedRegexQuery } from "@/lib/common/searchPattern";
export type ObjectBrowserRow = {
@ -122,11 +122,12 @@ export function filterObjectBrowserRows(rows: ObjectBrowserRow[], query: string)
export function sortObjectBrowserRows(rows: ObjectBrowserRow[], key: ObjectBrowserSortKey, direction: ObjectBrowserSortDirection): ObjectBrowserRow[] {
const multiplier = direction === "asc" ? 1 : -1;
const compareNames = createDatabaseObjectNameComparator(rows.map((row) => row.displayName));
// Sort by natural visible name, matching the sidebar tree ordering
// (see fix "keep tables sorted by visible name" and issue #3604).
return [...rows].sort((left, right) => {
const compared = key === "name" ? compareNames(left.displayName, right.displayName) : compareObjectBrowserValue(left[key], right[key], key, direction);
const compared = key === "name" ? compareDatabaseObjectNames(left.displayName, right.displayName) : compareObjectBrowserValue(left[key], right[key], key, direction);
if (compared !== 0) return compared * multiplier;
return compareNames(left.displayName, right.displayName);
return compareDatabaseObjectNames(left.displayName, right.displayName);
});
}

View File

@ -211,6 +211,12 @@ export function sortDatabaseObjectsByName<T>(items: readonly T[], getName: (item
return [...items].sort((left, right) => databaseObjectNameCollator.compare(getName(left), getName(right)));
}
// Shared with the object browser so both sides of the UI list objects in the
// same natural visible-name order as the sidebar tree (issue #3604).
export function compareDatabaseObjectNames(left: string, right: string): number {
return databaseObjectNameCollator.compare(left, right);
}
export function mergeTableInfosIntoObjects(objects: readonly ObjectInfo[], tables: readonly TableInfo[], schema?: string): ObjectInfo[] {
const merged = [...objects];
const seen = new Set(

View File

@ -193,7 +193,7 @@ test("object browser formats statistics for compact table cells", () => {
assert.equal(formatObjectBrowserBytes(null), "");
});
test("object browser name sort keeps base-prefixed tables before prefixed variants", () => {
test("object browser name sort keeps natural name order like the sidebar tree", () => {
const rows = buildObjectBrowserRows({
objects: [
{ name: "chat_staff", object_type: "TABLE", schema: "public" },
@ -208,7 +208,27 @@ test("object browser name sort keeps base-prefixed tables before prefixed varian
assert.deepEqual(
sortObjectBrowserRows(rows, "name", "asc").map((row) => row.name),
["staff", "staff_his", "chat_staff", "chat_staff_his"],
["chat_staff", "chat_staff_his", "staff", "staff_his"],
);
});
test("object browser name sort does not relocate prefixed business tables by suffix", () => {
// Mirrors the sidebar regression test from "keep tables sorted by visible
// name" — both sides must list tables identically (issue #3604).
const rows = buildObjectBrowserRows({
objects: [
{ name: "YonSuite_CurrentStock", object_type: "TABLE", schema: "dbo" },
{ name: "CurrentStock", object_type: "TABLE", schema: "dbo" },
{ name: "YonSuite_LocationStock", object_type: "TABLE", schema: "dbo" },
],
database: "app",
fallbackSchema: "dbo",
needsSchema: true,
});
assert.deepEqual(
sortObjectBrowserRows(rows, "name", "asc").map((row) => row.name),
["CurrentStock", "YonSuite_CurrentStock", "YonSuite_LocationStock"],
);
});