Skip to content

Commit b345cb2

Browse files
committed
fix(logs): include subfolders when filtering logs by folder
1 parent 630db5c commit b345cb2

4 files changed

Lines changed: 72 additions & 5 deletions

File tree

apps/sim/app/api/logs/export/route.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ import { and, desc, eq, sql } from 'drizzle-orm'
55
import { type NextRequest, NextResponse } from 'next/server'
66
import { getSession } from '@/lib/auth'
77
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
8-
import { buildFilterConditions, LogFilterParamsSchema } from '@/lib/logs/filters'
8+
import {
9+
buildFilterConditions,
10+
expandFolderIdsWithDescendants,
11+
LogFilterParamsSchema,
12+
} from '@/lib/logs/filters'
913

1014
const logger = createLogger('LogsExportAPI')
1115

@@ -45,6 +49,10 @@ export const GET = withRouteHandler(async (request: NextRequest) => {
4549
workflowName: sql<string>`COALESCE(${workflow.name}, 'Deleted Workflow')`,
4650
}
4751

52+
if (params.folderIds) {
53+
params.folderIds = await expandFolderIdsWithDescendants(params.workspaceId, params.folderIds)
54+
}
55+
4856
const workspaceCondition = eq(workflowExecutionLogs.workspaceId, params.workspaceId)
4957
const filterConditions = buildFilterConditions(params)
5058
const conditions = filterConditions

apps/sim/app/api/logs/route.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import { listLogsContract, type WorkflowLogSummary } from '@/lib/api/contracts/l
3131
import { parseRequest } from '@/lib/api/server'
3232
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
3333
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
34-
import { buildFilterConditions } from '@/lib/logs/filters'
34+
import { buildFilterConditions, expandFolderIdsWithDescendants } from '@/lib/logs/filters'
3535

3636
const logger = createLogger('LogsAPI')
3737

@@ -162,6 +162,10 @@ export const GET = withRouteHandler(async (request: NextRequest) => {
162162
}
163163
}
164164

165+
if (params.folderIds) {
166+
params.folderIds = await expandFolderIdsWithDescendants(params.workspaceId, params.folderIds)
167+
}
168+
165169
const commonFilters = buildFilterConditions(params, { useSimpleLevelFilter: false })
166170
if (commonFilters) workflowConditions.push(commonFilters)
167171

apps/sim/app/api/logs/stats/route.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { isZodError } from '@/lib/api/server'
1313
import { getSession } from '@/lib/auth'
1414
import { generateRequestId } from '@/lib/core/utils/request'
1515
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
16-
import { buildFilterConditions } from '@/lib/logs/filters'
16+
import { buildFilterConditions, expandFolderIdsWithDescendants } from '@/lib/logs/filters'
1717

1818
const logger = createLogger('LogsStatsAPI')
1919

@@ -37,6 +37,13 @@ export const GET = withRouteHandler(async (request: NextRequest) => {
3737

3838
const workspaceFilter = eq(workflowExecutionLogs.workspaceId, params.workspaceId)
3939

40+
if (params.folderIds) {
41+
params.folderIds = await expandFolderIdsWithDescendants(
42+
params.workspaceId,
43+
params.folderIds
44+
)
45+
}
46+
4047
const commonFilters = buildFilterConditions(params, { useSimpleLevelFilter: true })
4148
const whereCondition = commonFilters ? and(workspaceFilter, commonFilters) : workspaceFilter
4249

apps/sim/lib/logs/filters.ts

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { workflow, workflowExecutionLogs } from '@sim/db/schema'
2-
import { and, eq, gt, gte, inArray, lt, lte, ne, type SQL, sql } from 'drizzle-orm'
1+
import { db } from '@sim/db'
2+
import { workflow, workflowExecutionLogs, workflowFolder } from '@sim/db/schema'
3+
import { and, eq, gt, gte, inArray, isNull, lt, lte, ne, type SQL, sql } from 'drizzle-orm'
34
import { z } from 'zod'
45
import type { TimeRange } from '@/stores/logs/filters/types'
56

@@ -128,6 +129,53 @@ function buildWorkflowIdsCondition(workflowIds: string): SQL | undefined {
128129
return undefined
129130
}
130131

132+
/**
133+
* Expands a CSV of selected folder IDs to include every descendant folder in the
134+
* workspace, so that filtering by a parent folder also matches workflows that
135+
* live in nested subfolders.
136+
*
137+
* Returns the original CSV when there are no descendants (or when the input is
138+
* empty / undefined). Unknown IDs are preserved so the caller's `inArray` check
139+
* behaves the same as today (matches nothing).
140+
*/
141+
export async function expandFolderIdsWithDescendants(
142+
workspaceId: string,
143+
folderIdsCsv: string | undefined
144+
): Promise<string | undefined> {
145+
if (!folderIdsCsv) return folderIdsCsv
146+
const seedIds = folderIdsCsv.split(',').filter(Boolean)
147+
if (seedIds.length === 0) return folderIdsCsv
148+
149+
const rows = await db
150+
.select({ id: workflowFolder.id, parentId: workflowFolder.parentId })
151+
.from(workflowFolder)
152+
.where(and(eq(workflowFolder.workspaceId, workspaceId), isNull(workflowFolder.archivedAt)))
153+
154+
const childrenByParent = new Map<string, string[]>()
155+
for (const row of rows) {
156+
if (!row.parentId) continue
157+
const list = childrenByParent.get(row.parentId)
158+
if (list) list.push(row.id)
159+
else childrenByParent.set(row.parentId, [row.id])
160+
}
161+
162+
const expanded = new Set<string>(seedIds)
163+
const queue = [...seedIds]
164+
while (queue.length > 0) {
165+
const current = queue.shift() as string
166+
const children = childrenByParent.get(current)
167+
if (!children) continue
168+
for (const childId of children) {
169+
if (!expanded.has(childId)) {
170+
expanded.add(childId)
171+
queue.push(childId)
172+
}
173+
}
174+
}
175+
176+
return Array.from(expanded).join(',')
177+
}
178+
131179
function buildFolderIdsCondition(folderIds: string): SQL | undefined {
132180
const ids = folderIds.split(',').filter(Boolean)
133181
if (ids.length > 0) {

0 commit comments

Comments
 (0)