diff --git a/web/src/tree.test.ts b/web/src/tree.test.ts index 0c6153f..ffd9f83 100644 --- a/web/src/tree.test.ts +++ b/web/src/tree.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from "vitest"; -import { buildTree, mergeLinear, type TreeFolder, type TreeNode } from "./tree.js"; +import { buildTree, compareNodes, mergeLinear, type TreeFolder, type TreeNode } from "./tree.js"; import type { Session } from "./types.js"; function session(id: string, cwd: string, command = "bash"): Session { @@ -67,6 +67,42 @@ describe("buildTree", () => { expect(root.children[0].kind).toBe("folder"); expect(root.children[1].kind).toBe("leaf"); }); + + // #168, docs/SIDEBAR.md: a dormant session takes the lowest precedence in + // the ordering, so live work always sorts above it, even a name that would + // otherwise sort first. + it("sorts a dormant session after live ones in the same folder, name notwithstanding", () => { + const dormant = { ...session("aaa-dormant", "/home/n/work"), status: "Dormant" } as Session; + const live = session("zzz-live", "/home/n/work"); + const root = buildTree([dormant, live], "/home/n") as TreeFolder; + const folder = root.children[0] as TreeFolder; + const ids = folder.children.map((c) => (c.kind === "leaf" ? c.session.id : c.name)); + expect(ids).toEqual(["zzz-live", "aaa-dormant"]); + }); + + it("still sorts dormant sessions by name against each other", () => { + const a = { + ...session("a", "/home/n/work"), + status: "Dormant", + metadata: { name: "a" }, + } as Session; + const b = { + ...session("b", "/home/n/work"), + status: "Dormant", + metadata: { name: "b" }, + } as Session; + const root = buildTree([b, a], "/home/n") as TreeFolder; + const folder = root.children[0] as TreeFolder; + const ids = folder.children.map((c) => (c.kind === "leaf" ? c.session.id : c.name)); + expect(ids).toEqual(["a", "b"]); + }); + + it("exposes the leaf/name precedence directly via compareNodes", () => { + const dormant: TreeNode = { kind: "leaf", session: { ...session("a", "/x"), status: "Dormant" } }; + const live: TreeNode = { kind: "leaf", session: session("b", "/x") }; + expect(compareNodes(dormant, live)).toBeGreaterThan(0); + expect(compareNodes(live, dormant)).toBeLessThan(0); + }); }); describe("mergeLinear", () => { diff --git a/web/src/tree.ts b/web/src/tree.ts index 0842849..72373a0 100644 --- a/web/src/tree.ts +++ b/web/src/tree.ts @@ -18,8 +18,16 @@ export interface TreeLeaf { export type TreeNode = TreeFolder | TreeLeaf; +/** docs/SIDEBAR.md: a dormant session takes the lowest precedence in the + * ordering, so live work always sorts above it regardless of name. */ +function dormantRank(node: TreeNode): number { + return node.kind === "leaf" && node.session.status === "Dormant" ? 1 : 0; +} + export function compareNodes(a: TreeNode, b: TreeNode): number { if (a.kind !== b.kind) return a.kind === "folder" ? -1 : 1; + const rank = dormantRank(a) - dormantRank(b); + if (rank !== 0) return rank; const an = a.kind === "folder" ? a.name : sessionName(a.session); const bn = b.kind === "folder" ? b.name : sessionName(b.session); return an.localeCompare(bn);