mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-24 18:22:38 +00:00
* feat(app): restore compact Changes diff controls Keep the folder tree behind a view toggle while preserving the flat file list as the default. Move secondary diff options into the overflow menu so the Changes toolbar stays compact. * fix(app): mirror whitespace diff option copy * fix(app): polish diff controls review follow-up
135 lines
4.8 KiB
TypeScript
135 lines
4.8 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { buildDiffFlatItems, sumHeightsBefore, type DiffFlatItem } from "./diff-flat-items";
|
|
import type { ParsedDiffFile } from "@/git/use-diff-query";
|
|
|
|
function createFile(path: string, additions = 1, deletions = 0): ParsedDiffFile {
|
|
return { path, isNew: false, isDeleted: false, additions, deletions, hunks: [] };
|
|
}
|
|
|
|
function summarize(items: DiffFlatItem[]): string[] {
|
|
return items.map((item) => {
|
|
if (item.type === "folder") {
|
|
return `${" ".repeat(item.depth)}[${item.displayName}]${item.collapsed ? " (collapsed)" : ""}`;
|
|
}
|
|
const base = item.file.path.split("/").pop();
|
|
return `${" ".repeat(item.depth)}${item.type === "body" ? "body:" : ""}${base}`;
|
|
});
|
|
}
|
|
|
|
describe("buildDiffFlatItems", () => {
|
|
const files = [createFile("src/app/a.ts"), createFile("src/app/nested/b.ts")];
|
|
|
|
it("emits a body and a sticky index for each expanded file", () => {
|
|
const { items, stickyHeaderIndices } = buildDiffFlatItems({
|
|
files: [createFile("a.ts"), createFile("b.ts")],
|
|
viewMode: "tree",
|
|
collapsedFolders: new Set(),
|
|
expandedPaths: new Set(["a.ts"]),
|
|
});
|
|
// Root-level files (no folder): header, body (for expanded a.ts), header
|
|
expect(summarize(items)).toEqual(["a.ts", "body:a.ts", "b.ts"]);
|
|
// sticky points at the header (index 0), not the body
|
|
expect(stickyHeaderIndices).toEqual([0]);
|
|
expect(items[0].type).toBe("header");
|
|
});
|
|
|
|
it("emits the old flat list without folder rows or indentation", () => {
|
|
const { items, stickyHeaderIndices } = buildDiffFlatItems({
|
|
files,
|
|
viewMode: "flat",
|
|
collapsedFolders: new Set(),
|
|
expandedPaths: new Set(["src/app/a.ts"]),
|
|
});
|
|
|
|
expect(summarize(items)).toEqual(["a.ts", "body:a.ts", "b.ts"]);
|
|
expect(stickyHeaderIndices).toEqual([0]);
|
|
expect(items.every((item) => item.type !== "folder")).toBe(true);
|
|
});
|
|
|
|
it("groups files under compressed folder rows, all expanded by default", () => {
|
|
const { items } = buildDiffFlatItems({
|
|
files,
|
|
viewMode: "tree",
|
|
collapsedFolders: new Set(),
|
|
expandedPaths: new Set(),
|
|
});
|
|
// dirs sort before files within a level: [nested] precedes a.ts
|
|
expect(summarize(items)).toEqual(["[src/app]", " [nested]", " b.ts", " a.ts"]);
|
|
});
|
|
|
|
it("collapsing a folder hides its descendants but keeps the row", () => {
|
|
const { items } = buildDiffFlatItems({
|
|
files,
|
|
viewMode: "tree",
|
|
collapsedFolders: new Set(["src/app/nested"]),
|
|
expandedPaths: new Set(),
|
|
});
|
|
expect(summarize(items)).toEqual(["[src/app]", " [nested] (collapsed)", " a.ts"]);
|
|
});
|
|
|
|
it("collapsing an ancestor hides everything below it", () => {
|
|
const { items } = buildDiffFlatItems({
|
|
files,
|
|
viewMode: "tree",
|
|
collapsedFolders: new Set(["src/app"]),
|
|
expandedPaths: new Set(),
|
|
});
|
|
expect(summarize(items)).toEqual(["[src/app] (collapsed)"]);
|
|
});
|
|
|
|
it("derives sticky indices file-headers-only from the post-collapse list", () => {
|
|
// dirs-first: [src/app], [nested], b.ts, a.ts. Expanding a.ts puts its
|
|
// header at index 3, with the body right after.
|
|
const { items, stickyHeaderIndices } = buildDiffFlatItems({
|
|
files,
|
|
viewMode: "tree",
|
|
collapsedFolders: new Set(),
|
|
expandedPaths: new Set(["src/app/a.ts"]),
|
|
});
|
|
expect(summarize(items)).toEqual([
|
|
"[src/app]",
|
|
" [nested]",
|
|
" b.ts",
|
|
" a.ts",
|
|
" body:a.ts",
|
|
]);
|
|
expect(stickyHeaderIndices).toEqual([3]);
|
|
for (const idx of stickyHeaderIndices) {
|
|
expect(items[idx].type).toBe("header");
|
|
}
|
|
});
|
|
|
|
it("maps tree file rows back to their original files array index", () => {
|
|
const { items } = buildDiffFlatItems({
|
|
files,
|
|
viewMode: "tree",
|
|
collapsedFolders: new Set(),
|
|
expandedPaths: new Set(),
|
|
});
|
|
// Tree order is b.ts (fileIndex 1) then a.ts (fileIndex 0)
|
|
const headers = items.filter((i) => i.type === "header");
|
|
expect(headers.map((h) => (h.type === "header" ? h.fileIndex : -1))).toEqual([1, 0]);
|
|
});
|
|
});
|
|
|
|
describe("sumHeightsBefore", () => {
|
|
const items = buildDiffFlatItems({
|
|
files: [createFile("src/a.ts"), createFile("src/b.ts")],
|
|
viewMode: "tree",
|
|
collapsedFolders: new Set(),
|
|
expandedPaths: new Set(),
|
|
}).items; // [folder, a.ts, b.ts]
|
|
|
|
const heightFor = (item: DiffFlatItem) => (item.type === "folder" ? 10 : 20);
|
|
|
|
it("sums the heights of items before the index, counting folder rows", () => {
|
|
expect(sumHeightsBefore(items, 0, heightFor)).toBe(0);
|
|
expect(sumHeightsBefore(items, 1, heightFor)).toBe(10); // folder above a.ts
|
|
expect(sumHeightsBefore(items, 2, heightFor)).toBe(30); // folder + a.ts above b.ts
|
|
});
|
|
|
|
it("clamps an out-of-range index to the list length", () => {
|
|
expect(sumHeightsBefore(items, 999, heightFor)).toBe(50);
|
|
});
|
|
});
|