paperclip/ui/src/lib/issue-tree.ts

37 lines
1.3 KiB
TypeScript
Raw Normal View History

import type { Issue } from "@paperclipai/shared";
export interface IssueTree {
roots: Issue[];
childMap: Map<string, Issue[]>;
}
/**
* Builds a parentchildren tree from a flat list of issues.
*
* - `roots` contains issues whose parent is absent from the list (or have no
* parent at all), so orphaned sub-tasks are always visible at root level.
* - `childMap` maps each parent id to its direct children in list order.
*/
export function buildIssueTree(items: Issue[]): IssueTree {
const itemIds = new Set(items.map((i) => i.id));
const roots = items.filter((i) => !i.parentId || !itemIds.has(i.parentId));
const childMap = new Map<string, Issue[]>();
for (const item of items) {
if (item.parentId && itemIds.has(item.parentId)) {
const arr = childMap.get(item.parentId) ?? [];
arr.push(item);
childMap.set(item.parentId, arr);
}
}
return { roots, childMap };
}
/**
* Returns the total number of descendants (all depths) of `id` in `childMap`.
* Used to accurately label collapsed parent badges like "(3 sub-tasks)".
*/
export function countDescendants(id: string, childMap: Map<string, Issue[]>): number {
const children = childMap.get(id) ?? [];
return children.reduce((sum, c) => sum + 1 + countDescendants(c.id, childMap), 0);
}