authorgravatar for 123344143+AksharP5@users.noreply.github.comAkshar Patel <123344143+AksharP5@users.noreply.github.com> 2026-09-06 13:09:26-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-06 14:09:26-03:00
log64fafbdfcf91d3c44b533f5b8febbe8d6b19d482
treefd025b7c2d8e8c6ff8d88d3625cfd3b59a91f3a2
parent72cb638a8a6656d0b89899d9d62afaed0c2f7e5f
signature Signed by PGP key B5690EEEBB952194

perf(web): speed up folder menu sorting (#10190)


2 files changed, 12 insertions(+), 3 deletions(-)

apps/web/src/components/files/filePath.test.ts+9-2
...@@ -67,8 +67,15 @@ describe("fileBreadcrumbChildren", () => {...@@ -67,8 +67,15 @@ describe("fileBreadcrumbChildren", () => {
67 ]);67 ]);
68 });68 });
6969
70 it("uses natural file-name ordering", () => {70 it("uses natural file-name ordering and preserves input order for equivalent names", () => {
71 expect(fileBreadcrumbChildren(entries, "src/lib").map((entry) => entry.label)).toEqual([71 const files = ["file10.ts", "File2.ts", "file02.ts", "file2.ts"].map((name) => ({
72 path: `src/lib/${name}`,
73 kind: "file" as const,
74 }));
75
76 expect(fileBreadcrumbChildren(files, "src/lib").map((entry) => entry.label)).toEqual([
77 "File2.ts",
78 "file02.ts",
72 "file2.ts",79 "file2.ts",
73 "file10.ts",80 "file10.ts",
74 ]);81 ]);
apps/web/src/components/files/filePath.ts+3-1
...@@ -36,6 +36,7 @@ export function fileBreadcrumbChildren(...@@ -36,6 +36,7 @@ export function fileBreadcrumbChildren(
36 entries: readonly ProjectEntry[],36 entries: readonly ProjectEntry[],
37 directoryPath: string,37 directoryPath: string,
38): FileBreadcrumbChild[] {38): FileBreadcrumbChild[] {
39 let collator: Intl.Collator | undefined;
39 const prefix = directoryPath ? `${directoryPath}/` : "";40 const prefix = directoryPath ? `${directoryPath}/` : "";
40 return entries41 return entries
41 .flatMap((entry) => {42 .flatMap((entry) => {
...@@ -46,10 +47,11 @@ export function fileBreadcrumbChildren(...@@ -46,10 +47,11 @@ export function fileBreadcrumbChildren(
46 })47 })
47 .toSorted((left, right) => {48 .toSorted((left, right) => {
48 if (left.kind !== right.kind) return left.kind === "directory" ? -1 : 1;49 if (left.kind !== right.kind) return left.kind === "directory" ? -1 : 1;
49 return left.label.localeCompare(right.label, undefined, {50 collator ??= new Intl.Collator(undefined, {
50 numeric: true,51 numeric: true,
51 sensitivity: "base",52 sensitivity: "base",
52 });53 });
54 return collator.compare(left.label, right.label);
53 });55 });
54}56}
5557