Skip to content

Commit 14f422e

Browse files
Vikhyath MondretiVikhyath Mondreti
authored andcommitted
fix frozen canvas trace span interpretation issue
1 parent f27cb18 commit 14f422e

File tree

2 files changed

+124
-27
lines changed

2 files changed

+124
-27
lines changed

apps/sim/app/workspace/[workspaceId]/logs/components/frozen-canvas/frozen-canvas.tsx

Lines changed: 110 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -148,16 +148,81 @@ function getCurrentIterationData(blockExecutionData: any) {
148148
}
149149
}
150150

151-
function PinnedLogs({ executionData, onClose }: { executionData: any; onClose: () => void }) {
151+
function PinnedLogs({
152+
executionData,
153+
blockId,
154+
workflowState,
155+
onClose
156+
}: {
157+
executionData: any | null;
158+
blockId: string;
159+
workflowState: any;
160+
onClose: () => void;
161+
}) {
162+
// ALL HOOKS MUST BE CALLED BEFORE ANY CONDITIONAL RETURNS
152163
const [currentIterationIndex, setCurrentIterationIndex] = useState(0)
153164

165+
// Reset iteration index when execution data changes
166+
useEffect(() => {
167+
setCurrentIterationIndex(0)
168+
}, [executionData])
169+
170+
// Handle case where block has no execution data (e.g., failed workflow)
171+
if (!executionData) {
172+
const blockInfo = workflowState?.blocks?.[blockId]
173+
const formatted = {
174+
blockName: blockInfo?.name || 'Unknown Block',
175+
blockType: blockInfo?.type || 'unknown',
176+
status: 'not_executed',
177+
duration: 'N/A',
178+
input: null,
179+
output: null,
180+
errorMessage: null,
181+
errorStackTrace: null,
182+
cost: null,
183+
tokens: null,
184+
}
185+
186+
return (
187+
<Card className='fixed top-4 right-4 z-[100] max-h-[calc(100vh-8rem)] w-96 overflow-y-auto border-border bg-background shadow-lg'>
188+
<CardHeader className='pb-3'>
189+
<div className='flex items-center justify-between'>
190+
<CardTitle className='flex items-center gap-2 text-foreground text-lg'>
191+
<Zap className='h-5 w-5' />
192+
{formatted.blockName}
193+
</CardTitle>
194+
<button onClick={onClose} className='rounded-sm p-1 text-foreground hover:bg-muted'>
195+
<X className='h-4 w-4' />
196+
</button>
197+
</div>
198+
<div className='flex items-center justify-between'>
199+
<div className='flex items-center gap-2'>
200+
<Badge variant='secondary'>
201+
{formatted.blockType}
202+
</Badge>
203+
<Badge variant='outline'>not executed</Badge>
204+
</div>
205+
</div>
206+
</CardHeader>
207+
208+
<CardContent className='space-y-4'>
209+
<div className='rounded-md bg-muted/50 p-4 text-center'>
210+
<div className='text-muted-foreground text-sm'>
211+
This block was not executed because the workflow failed before reaching it.
212+
</div>
213+
</div>
214+
</CardContent>
215+
</Card>
216+
)
217+
}
218+
219+
// Now we can safely use the execution data
154220
const iterationInfo = getCurrentIterationData({
155221
...executionData,
156222
currentIteration: currentIterationIndex,
157223
})
158224

159225
const formatted = formatExecutionData(iterationInfo.executionData)
160-
161226
const totalIterations = executionData.iterations?.length || 1
162227

163228
const goToPreviousIteration = () => {
@@ -172,10 +237,6 @@ function PinnedLogs({ executionData, onClose }: { executionData: any; onClose: (
172237
}
173238
}
174239

175-
useEffect(() => {
176-
setCurrentIterationIndex(0)
177-
}, [executionData])
178-
179240
return (
180241
<Card className='fixed top-4 right-4 z-[100] max-h-[calc(100vh-8rem)] w-96 overflow-y-auto border-border bg-background shadow-lg'>
181242
<CardHeader className='pb-3'>
@@ -337,17 +398,42 @@ export function FrozenCanvas({
337398
if (traceSpans && Array.isArray(traceSpans)) {
338399
const blockExecutionMap: Record<string, any> = {}
339400

340-
const workflowSpan = traceSpans[0]
341-
if (workflowSpan?.children && Array.isArray(workflowSpan.children)) {
342-
const traceSpansByBlockId = workflowSpan.children.reduce((acc: any, span: any) => {
401+
logger.debug('Processing trace spans for frozen canvas:', { traceSpans })
402+
403+
// Recursively collect all spans with blockId from the trace spans tree
404+
const collectBlockSpans = (spans: any[]): any[] => {
405+
const blockSpans: any[] = []
406+
407+
for (const span of spans) {
408+
// If this span has a blockId, it's a block execution
343409
if (span.blockId) {
344-
if (!acc[span.blockId]) {
345-
acc[span.blockId] = []
346-
}
347-
acc[span.blockId].push(span)
410+
blockSpans.push(span)
348411
}
349-
return acc
350-
}, {})
412+
413+
// Recursively check children
414+
if (span.children && Array.isArray(span.children)) {
415+
blockSpans.push(...collectBlockSpans(span.children))
416+
}
417+
}
418+
419+
return blockSpans
420+
}
421+
422+
const allBlockSpans = collectBlockSpans(traceSpans)
423+
logger.debug('Collected all block spans:', allBlockSpans)
424+
425+
// Group spans by blockId
426+
const traceSpansByBlockId = allBlockSpans.reduce((acc: any, span: any) => {
427+
if (span.blockId) {
428+
if (!acc[span.blockId]) {
429+
acc[span.blockId] = []
430+
}
431+
acc[span.blockId].push(span)
432+
}
433+
return acc
434+
}, {})
435+
436+
logger.debug('Grouped trace spans by blockId:', traceSpansByBlockId)
351437

352438
for (const [blockId, spans] of Object.entries(traceSpansByBlockId)) {
353439
const spanArray = spans as any[]
@@ -407,10 +493,9 @@ export function FrozenCanvas({
407493
totalIterations: iterations.length,
408494
}
409495
}
410-
}
411496

412-
setBlockExecutions(blockExecutionMap)
413-
}
497+
setBlockExecutions(blockExecutionMap)
498+
}
414499
}, [traceSpans])
415500

416501
useEffect(() => {
@@ -439,8 +524,6 @@ export function FrozenCanvas({
439524
fetchData()
440525
}, [executionId])
441526

442-
// No need to create a temporary workflow - just use the workflowState directly
443-
444527
if (loading) {
445528
return (
446529
<div className={cn('flex items-center justify-center', className)} style={{ height, width }}>
@@ -502,16 +585,18 @@ export function FrozenCanvas({
502585
showSubBlocks={true}
503586
isPannable={true}
504587
onNodeClick={(blockId) => {
505-
if (blockExecutions[blockId]) {
506-
setPinnedBlockId(blockId)
507-
}
588+
// Always allow clicking blocks, even if they don't have execution data
589+
// This is important for failed workflows where some blocks never executed
590+
setPinnedBlockId(blockId)
508591
}}
509592
/>
510593
</div>
511594

512-
{pinnedBlockId && blockExecutions[pinnedBlockId] && (
595+
{pinnedBlockId && (
513596
<PinnedLogs
514-
executionData={blockExecutions[pinnedBlockId]}
597+
executionData={blockExecutions[pinnedBlockId] || null}
598+
blockId={pinnedBlockId}
599+
workflowState={data.workflowState}
515600
onClose={() => setPinnedBlockId(null)}
516601
/>
517602
)}

apps/sim/lib/logs/enhanced-execution-logger.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,20 @@ export class EnhancedExecutionLogger implements IExecutionLoggerService {
218218

219219
logger.debug(`Completing workflow execution ${executionId}`)
220220

221-
const level = 'info'
222-
const message = `Workflow execution completed`
221+
// Determine if workflow failed by checking trace spans for errors
222+
const hasErrors = traceSpans && traceSpans.some((span: any) => {
223+
const checkSpanForErrors = (s: any): boolean => {
224+
if (s.status === 'error') return true
225+
if (s.children && Array.isArray(s.children)) {
226+
return s.children.some(checkSpanForErrors)
227+
}
228+
return false
229+
}
230+
return checkSpanForErrors(span)
231+
})
232+
233+
const level = hasErrors ? 'error' : 'info'
234+
const message = hasErrors ? 'Workflow execution failed' : 'Workflow execution completed'
223235

224236
const [updatedLog] = await db
225237
.update(workflowExecutionLogs)

0 commit comments

Comments
 (0)