| 15 | * (imported by client hooks) to avoid leaking postgres into the browser bundle. |
| 16 | */ |
| 17 | export async function expandFolderIdsWithDescendants( |
| 18 | workspaceId: string, |
| 19 | folderIdsCsv: string | undefined |
| 20 | ): Promise<string | undefined> { |
| 21 | if (!folderIdsCsv) return folderIdsCsv |
| 22 | const seedIds = folderIdsCsv.split(',').filter(Boolean) |
| 23 | if (seedIds.length === 0) return folderIdsCsv |
| 24 | |
| 25 | const rows = await db |
| 26 | .select({ id: workflowFolder.id, parentId: workflowFolder.parentId }) |
| 27 | .from(workflowFolder) |
| 28 | .where(and(eq(workflowFolder.workspaceId, workspaceId), isNull(workflowFolder.archivedAt))) |
| 29 | |
| 30 | const childrenByParent = new Map<string, string[]>() |
| 31 | for (const row of rows) { |
| 32 | if (!row.parentId) continue |
| 33 | const list = childrenByParent.get(row.parentId) |
| 34 | if (list) list.push(row.id) |
| 35 | else childrenByParent.set(row.parentId, [row.id]) |
| 36 | } |
| 37 | |
| 38 | const expanded = new Set<string>(seedIds) |
| 39 | const queue = [...seedIds] |
| 40 | while (queue.length > 0) { |
| 41 | const current = queue.pop() as string |
| 42 | const children = childrenByParent.get(current) |
| 43 | if (!children) continue |
| 44 | for (const childId of children) { |
| 45 | if (!expanded.has(childId)) { |
| 46 | expanded.add(childId) |
| 47 | queue.push(childId) |
| 48 | } |
| 49 | } |
| 50 | } |
| 51 | |
| 52 | return Array.from(expanded).join(',') |
| 53 | } |