@@ -75,33 +75,50 @@ export async function GET(request: NextRequest) {
7575 const { searchParams } = new URL ( request . url )
7676 const params = QueryParamsSchema . parse ( Object . fromEntries ( searchParams . entries ( ) ) )
7777
78- const workflowConditions = and (
79- eq ( workflow . workspaceId , params . workspaceId ) ,
80- eq ( permissions . userId , userId ) ,
81- eq ( permissions . entityType , 'workspace' )
82- )
83-
84- const userWorkflows = await db
85- . select ( { id : workflow . id , folderId : workflow . folderId } )
86- . from ( workflow )
87- . leftJoin (
78+ const baseQuery = db
79+ . select ( {
80+ id : workflowExecutionLogs . id ,
81+ workflowId : workflowExecutionLogs . workflowId ,
82+ executionId : workflowExecutionLogs . executionId ,
83+ stateSnapshotId : workflowExecutionLogs . stateSnapshotId ,
84+ level : workflowExecutionLogs . level ,
85+ message : workflowExecutionLogs . message ,
86+ trigger : workflowExecutionLogs . trigger ,
87+ startedAt : workflowExecutionLogs . startedAt ,
88+ endedAt : workflowExecutionLogs . endedAt ,
89+ totalDurationMs : workflowExecutionLogs . totalDurationMs ,
90+ blockCount : workflowExecutionLogs . blockCount ,
91+ successCount : workflowExecutionLogs . successCount ,
92+ errorCount : workflowExecutionLogs . errorCount ,
93+ skippedCount : workflowExecutionLogs . skippedCount ,
94+ totalCost : workflowExecutionLogs . totalCost ,
95+ totalInputCost : workflowExecutionLogs . totalInputCost ,
96+ totalOutputCost : workflowExecutionLogs . totalOutputCost ,
97+ totalTokens : workflowExecutionLogs . totalTokens ,
98+ metadata : workflowExecutionLogs . metadata ,
99+ createdAt : workflowExecutionLogs . createdAt ,
100+ workflowName : workflow . name ,
101+ workflowDescription : workflow . description ,
102+ workflowColor : workflow . color ,
103+ workflowFolderId : workflow . folderId ,
104+ workflowUserId : workflow . userId ,
105+ workflowWorkspaceId : workflow . workspaceId ,
106+ workflowCreatedAt : workflow . createdAt ,
107+ workflowUpdatedAt : workflow . updatedAt ,
108+ } )
109+ . from ( workflowExecutionLogs )
110+ . innerJoin ( workflow , eq ( workflowExecutionLogs . workflowId , workflow . id ) )
111+ . innerJoin (
88112 permissions ,
89113 and (
90114 eq ( permissions . entityType , 'workspace' ) ,
91115 eq ( permissions . entityId , workflow . workspaceId ) ,
92116 eq ( permissions . userId , userId )
93117 )
94118 )
95- . where ( workflowConditions )
96119
97- const userWorkflowIds = userWorkflows . map ( ( w ) => w . id )
98-
99- if ( userWorkflowIds . length === 0 ) {
100- return NextResponse . json ( { data : [ ] , total : 0 } , { status : 200 } )
101- }
102-
103- // Build conditions for logs
104- let conditions : SQL | undefined = inArray ( workflowExecutionLogs . workflowId , userWorkflowIds )
120+ // Build conditions for the joined query
121+ let conditions : SQL | undefined = eq ( workflow . workspaceId , params . workspaceId )
105122
106123 // Filter by level
107124 if ( params . level && params . level !== 'all' ) {
@@ -111,27 +128,16 @@ export async function GET(request: NextRequest) {
111128 // Filter by specific workflow IDs
112129 if ( params . workflowIds ) {
113130 const workflowIds = params . workflowIds . split ( ',' ) . filter ( Boolean )
114- const filteredWorkflowIds = workflowIds . filter ( ( id ) => userWorkflowIds . includes ( id ) )
115- if ( filteredWorkflowIds . length > 0 ) {
116- conditions = and (
117- conditions ,
118- inArray ( workflowExecutionLogs . workflowId , filteredWorkflowIds )
119- )
131+ if ( workflowIds . length > 0 ) {
132+ conditions = and ( conditions , inArray ( workflow . id , workflowIds ) )
120133 }
121134 }
122135
123136 // Filter by folder IDs
124137 if ( params . folderIds ) {
125138 const folderIds = params . folderIds . split ( ',' ) . filter ( Boolean )
126- const workflowsInFolders = userWorkflows
127- . filter ( ( w ) => w . folderId && folderIds . includes ( w . folderId ) )
128- . map ( ( w ) => w . id )
129-
130- if ( workflowsInFolders . length > 0 ) {
131- conditions = and (
132- conditions ,
133- inArray ( workflowExecutionLogs . workflowId , workflowsInFolders )
134- )
139+ if ( folderIds . length > 0 ) {
140+ conditions = and ( conditions , inArray ( workflow . folderId , folderIds ) )
135141 }
136142 }
137143
@@ -166,21 +172,30 @@ export async function GET(request: NextRequest) {
166172 )
167173 }
168174
169- // Execute the query
170- const logs = await db
171- . select ( )
172- . from ( workflowExecutionLogs )
175+ // Execute the query using the optimized join
176+ const logs = await baseQuery
173177 . where ( conditions )
174178 . orderBy ( desc ( workflowExecutionLogs . startedAt ) )
175179 . limit ( params . limit )
176180 . offset ( params . offset )
177181
178- // Get total count for pagination
179- const countResult = await db
182+ // Get total count for pagination using the same join structure
183+ const countQuery = db
180184 . select ( { count : sql < number > `count(*)` } )
181185 . from ( workflowExecutionLogs )
186+ . innerJoin ( workflow , eq ( workflowExecutionLogs . workflowId , workflow . id ) )
187+ . innerJoin (
188+ permissions ,
189+ and (
190+ eq ( permissions . entityType , 'workspace' ) ,
191+ eq ( permissions . entityId , workflow . workspaceId ) ,
192+ eq ( permissions . userId , userId )
193+ )
194+ )
182195 . where ( conditions )
183196
197+ const countResult = await countQuery
198+
184199 const count = countResult [ 0 ] ?. count || 0
185200
186201 // Block executions are now extracted from trace spans instead of separate table
@@ -271,7 +286,7 @@ export async function GET(request: NextRequest) {
271286 }
272287 }
273288
274- // Transform to clean log format
289+ // Transform to clean log format with workflow data included
275290 const enhancedLogs = logs . map ( ( log ) => {
276291 const blockExecutions = blockExecutionsByExecution [ log . executionId ] || [ ]
277292
@@ -298,6 +313,19 @@ export async function GET(request: NextRequest) {
298313 models : ( log . metadata as any ) ?. models || { } ,
299314 }
300315
316+ // Build workflow object from joined data
317+ const workflow = {
318+ id : log . workflowId ,
319+ name : log . workflowName ,
320+ description : log . workflowDescription ,
321+ color : log . workflowColor ,
322+ folderId : log . workflowFolderId ,
323+ userId : log . workflowUserId ,
324+ workspaceId : log . workflowWorkspaceId ,
325+ createdAt : log . workflowCreatedAt ,
326+ updatedAt : log . workflowUpdatedAt ,
327+ }
328+
301329 return {
302330 id : log . id ,
303331 workflowId : log . workflowId ,
@@ -307,6 +335,7 @@ export async function GET(request: NextRequest) {
307335 duration : log . totalDurationMs ? `${ log . totalDurationMs } ms` : null ,
308336 trigger : log . trigger ,
309337 createdAt : log . startedAt . toISOString ( ) ,
338+ workflow : params . includeWorkflow ? workflow : undefined ,
310339 metadata : {
311340 totalDuration : log . totalDurationMs ,
312341 cost : costSummary ,
@@ -323,30 +352,6 @@ export async function GET(request: NextRequest) {
323352 }
324353 } )
325354
326- if ( params . includeWorkflow ) {
327- const workflowIds = [ ...new Set ( logs . map ( ( log ) => log . workflowId ) ) ]
328- const workflowConditions = inArray ( workflow . id , workflowIds )
329-
330- const workflowData = await db . select ( ) . from ( workflow ) . where ( workflowConditions )
331- const workflowMap = new Map ( workflowData . map ( ( w ) => [ w . id , w ] ) )
332-
333- const logsWithWorkflow = enhancedLogs . map ( ( log ) => ( {
334- ...log ,
335- workflow : workflowMap . get ( log . workflowId ) || null ,
336- } ) )
337-
338- return NextResponse . json (
339- {
340- data : logsWithWorkflow ,
341- total : Number ( count ) ,
342- page : Math . floor ( params . offset / params . limit ) + 1 ,
343- pageSize : params . limit ,
344- totalPages : Math . ceil ( Number ( count ) / params . limit ) ,
345- } ,
346- { status : 200 }
347- )
348- }
349-
350355 // Include block execution data if requested
351356 if ( params . includeBlocks ) {
352357 // Block executions are now extracted from stored trace spans in metadata
0 commit comments