mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
fix(logs): include subfolders when filtering logs by folder (#4525)
* fix(logs): include subfolders when filtering logs by folder * fix(logs): use pop() for O(1) dequeue in folder BFS * fix(logs): move folder expansion to server-only module to fix client bundle build
This commit is contained in:
@@ -6,6 +6,7 @@ import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { getSession } from '@/lib/auth'
|
||||
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
|
||||
import { buildFilterConditions, LogFilterParamsSchema } from '@/lib/logs/filters'
|
||||
import { expandFolderIdsWithDescendants } from '@/lib/logs/folder-expansion'
|
||||
|
||||
const logger = createLogger('LogsExportAPI')
|
||||
|
||||
@@ -45,6 +46,10 @@ export const GET = withRouteHandler(async (request: NextRequest) => {
|
||||
workflowName: sql<string>`COALESCE(${workflow.name}, 'Deleted Workflow')`,
|
||||
}
|
||||
|
||||
if (params.folderIds) {
|
||||
params.folderIds = await expandFolderIdsWithDescendants(params.workspaceId, params.folderIds)
|
||||
}
|
||||
|
||||
const workspaceCondition = eq(workflowExecutionLogs.workspaceId, params.workspaceId)
|
||||
const filterConditions = buildFilterConditions(params)
|
||||
const conditions = filterConditions
|
||||
|
||||
@@ -32,6 +32,7 @@ import { parseRequest } from '@/lib/api/server'
|
||||
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
|
||||
import { buildFilterConditions } from '@/lib/logs/filters'
|
||||
import { expandFolderIdsWithDescendants } from '@/lib/logs/folder-expansion'
|
||||
|
||||
const logger = createLogger('LogsAPI')
|
||||
|
||||
@@ -162,6 +163,10 @@ export const GET = withRouteHandler(async (request: NextRequest) => {
|
||||
}
|
||||
}
|
||||
|
||||
if (params.folderIds) {
|
||||
params.folderIds = await expandFolderIdsWithDescendants(params.workspaceId, params.folderIds)
|
||||
}
|
||||
|
||||
const commonFilters = buildFilterConditions(params, { useSimpleLevelFilter: false })
|
||||
if (commonFilters) workflowConditions.push(commonFilters)
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import { getSession } from '@/lib/auth'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
|
||||
import { buildFilterConditions } from '@/lib/logs/filters'
|
||||
import { expandFolderIdsWithDescendants } from '@/lib/logs/folder-expansion'
|
||||
|
||||
const logger = createLogger('LogsStatsAPI')
|
||||
|
||||
@@ -37,6 +38,13 @@ export const GET = withRouteHandler(async (request: NextRequest) => {
|
||||
|
||||
const workspaceFilter = eq(workflowExecutionLogs.workspaceId, params.workspaceId)
|
||||
|
||||
if (params.folderIds) {
|
||||
params.folderIds = await expandFolderIdsWithDescendants(
|
||||
params.workspaceId,
|
||||
params.folderIds
|
||||
)
|
||||
}
|
||||
|
||||
const commonFilters = buildFilterConditions(params, { useSimpleLevelFilter: true })
|
||||
const whereCondition = commonFilters ? and(workspaceFilter, commonFilters) : workspaceFilter
|
||||
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
import { db } from '@sim/db'
|
||||
import { workflowFolder } from '@sim/db/schema'
|
||||
import { and, eq, isNull } from 'drizzle-orm'
|
||||
|
||||
/**
|
||||
* Expands a CSV of selected folder IDs to include every descendant folder in the
|
||||
* workspace, so that filtering by a parent folder also matches workflows that
|
||||
* live in nested subfolders.
|
||||
*
|
||||
* Returns the original CSV when there are no descendants (or when the input is
|
||||
* empty / undefined). Unknown IDs are preserved so the caller's `inArray` check
|
||||
* behaves the same as today (matches nothing).
|
||||
*
|
||||
* Server-only: pulls in the database client. Keep separate from `filters.ts`
|
||||
* (imported by client hooks) to avoid leaking postgres into the browser bundle.
|
||||
*/
|
||||
export async function expandFolderIdsWithDescendants(
|
||||
workspaceId: string,
|
||||
folderIdsCsv: string | undefined
|
||||
): Promise<string | undefined> {
|
||||
if (!folderIdsCsv) return folderIdsCsv
|
||||
const seedIds = folderIdsCsv.split(',').filter(Boolean)
|
||||
if (seedIds.length === 0) return folderIdsCsv
|
||||
|
||||
const rows = await db
|
||||
.select({ id: workflowFolder.id, parentId: workflowFolder.parentId })
|
||||
.from(workflowFolder)
|
||||
.where(and(eq(workflowFolder.workspaceId, workspaceId), isNull(workflowFolder.archivedAt)))
|
||||
|
||||
const childrenByParent = new Map<string, string[]>()
|
||||
for (const row of rows) {
|
||||
if (!row.parentId) continue
|
||||
const list = childrenByParent.get(row.parentId)
|
||||
if (list) list.push(row.id)
|
||||
else childrenByParent.set(row.parentId, [row.id])
|
||||
}
|
||||
|
||||
const expanded = new Set<string>(seedIds)
|
||||
const queue = [...seedIds]
|
||||
while (queue.length > 0) {
|
||||
const current = queue.pop() as string
|
||||
const children = childrenByParent.get(current)
|
||||
if (!children) continue
|
||||
for (const childId of children) {
|
||||
if (!expanded.has(childId)) {
|
||||
expanded.add(childId)
|
||||
queue.push(childId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Array.from(expanded).join(',')
|
||||
}
|
||||
Reference in New Issue
Block a user