export interface DocumentRecord { access_scope: "private" | "shared" | "public"; id: string; workspace_id: string; title: string | null; parent_id: string | null; sort_order: number | null; is_starred: boolean | null; is_template: boolean; created_at: string; updated_at: string | null; } export interface DocumentNode extends DocumentRecord { children: DocumentNode[]; } export function buildDocumentTree(records: DocumentRecord[]): DocumentNode[] { const nodeMap = new Map(); records.forEach((record) => { nodeMap.set(record.id, { ...record, children: [] }); }); const roots: DocumentNode[] = []; records.forEach((record) => { const node = nodeMap.get(record.id); if (!node) return; if (record.parent_id && nodeMap.has(record.parent_id)) { nodeMap.get(record.parent_id)!.children.push(node); } else { roots.push(node); } }); const sortTree = (nodes: DocumentNode[]) => { nodes.sort((a, b) => { const orderA = a.sort_order ?? Number.MAX_SAFE_INTEGER; const orderB = b.sort_order ?? Number.MAX_SAFE_INTEGER; if (orderA !== orderB) { return orderA - orderB; } return new Date(a.created_at).getTime() - new Date(b.created_at).getTime(); }); nodes.forEach((child) => sortTree(child.children)); }; sortTree(roots); return roots; } export function findBreadcrumb(records: DocumentRecord[], targetId: string): DocumentRecord[] { const map = new Map(); records.forEach((item) => map.set(item.id, item)); const path: DocumentRecord[] = []; let current: DocumentRecord | undefined = map.get(targetId); while (current) { path.unshift(current); current = current.parent_id ? map.get(current.parent_id) : undefined; } return path; }