@@ -26,10 +26,12 @@ import { cn } from '@/lib/utils'
2626import { useCurrentWorkflow } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-current-workflow'
2727import { useWorkflowExecution } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution'
2828import { getBlock } from '@/blocks'
29+ import { useDebugCanvasStore } from '@/stores/execution/debug-canvas/store'
2930import { useDebugSnapshotStore } from '@/stores/execution/debug-snapshots/store'
3031import { useExecutionStore } from '@/stores/execution/store'
3132import { useVariablesStore } from '@/stores/panel/variables/store'
3233import { useEnvironmentStore } from '@/stores/settings/environment/store'
34+ import { useWorkflowDiffStore } from '@/stores/workflow-diff/store'
3335import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
3436import { useSubBlockStore } from '@/stores/workflows/subblock/store'
3537import { mergeSubblockState } from '@/stores/workflows/utils'
@@ -38,7 +40,6 @@ import { getTool } from '@/tools/utils'
3840import { getTrigger , getTriggersByProvider } from '@/triggers'
3941import { useParams } from 'next/navigation'
4042import { Select , SelectContent , SelectItem , SelectTrigger , SelectValue } from '@/components/ui/select'
41- import { useDebugCanvasStore } from '@/stores/execution/debug-canvas/store'
4243import type { WorkflowState } from '@/stores/workflows/workflow/types'
4344
4445// Token render cache (LRU-style)
@@ -1737,13 +1738,30 @@ export function DebugPanel() {
17371738 return Object . entries ( allEnvVars ) . filter ( ( [ key ] ) => blockEnvVarRefs . has ( key ) )
17381739 } , [ allEnvVars , scopedVariables , focusedBlock , focusedBlockId , activeWorkflowId , blocksList ] )
17391740
1740- // Reset hasStartedRef when debug mode is deactivated
1741+ // Reset hasStartedRef and clear debug canvas when debug mode is deactivated
17411742 useEffect ( ( ) => {
17421743 if ( ! isDebugging ) {
17431744 hasStartedRef . current = false
17441745 setPanelFocusedBlockId ( null )
1746+ setSelectedExecutionKey ( undefined )
1747+ // Clear debug canvas when exiting debug mode
1748+ console . log ( '[Debug] Clearing debug canvas - debug mode deactivated' )
1749+ useDebugCanvasStore . getState ( ) . clear ( )
1750+
1751+ // Restore original subblock values
1752+ if ( originalSubblockValuesRef . current && activeWorkflowId ) {
1753+ const valuesToRestore = originalSubblockValuesRef . current
1754+ console . log ( '[Debug] Restoring original subblock values on debug exit' )
1755+ useSubBlockStore . setState ( ( state ) => ( {
1756+ workflowValues : {
1757+ ...state . workflowValues ,
1758+ [ activeWorkflowId ] : valuesToRestore
1759+ }
1760+ } ) )
1761+ originalSubblockValuesRef . current = null
1762+ }
17451763 }
1746- } , [ isDebugging , setPanelFocusedBlockId ] )
1764+ } , [ isDebugging , setPanelFocusedBlockId , activeWorkflowId ] )
17471765
17481766 // Clear init pending when debug context and initial pending arrive
17491767 useEffect ( ( ) => {
@@ -1752,9 +1770,29 @@ export function DebugPanel() {
17521770 }
17531771 } , [ debugContext , pendingBlocks ] )
17541772
1773+ // Cleanup debug canvas on unmount
1774+ useEffect ( ( ) => {
1775+ return ( ) => {
1776+ console . log ( '[Debug] Component unmounting - clearing debug canvas' )
1777+ useDebugCanvasStore . getState ( ) . clear ( )
1778+
1779+ // Restore original subblock values on unmount
1780+ if ( originalSubblockValuesRef . current && activeWorkflowId ) {
1781+ const valuesToRestore = originalSubblockValuesRef . current
1782+ console . log ( '[Debug] Restoring original subblock values on unmount' )
1783+ useSubBlockStore . setState ( ( state ) => ( {
1784+ workflowValues : {
1785+ ...state . workflowValues ,
1786+ [ activeWorkflowId ] : valuesToRestore
1787+ }
1788+ } ) )
1789+ }
1790+ }
1791+ } , [ activeWorkflowId ] )
1792+
17551793 // Load recent executions for this workflow
17561794 useEffect ( ( ) => {
1757- if ( ! workspaceId || ! workflowId ) return
1795+ if ( ! isDebugging || ! workspaceId || ! workflowId ) return
17581796 let canceled = false
17591797 const load = async ( ) => {
17601798 try {
@@ -1777,9 +1815,6 @@ export function DebugPanel() {
17771815 } ) )
17781816 : [ ]
17791817 setExecutions ( items )
1780- if ( ! selectedExecutionKey && items . length > 0 ) {
1781- setSelectedExecutionKey ( items [ 0 ] . id )
1782- }
17831818 } catch {
17841819 } finally {
17851820 if ( ! canceled ) setIsLoadingExecutions ( false )
@@ -1789,27 +1824,173 @@ export function DebugPanel() {
17891824 return ( ) => {
17901825 canceled = true
17911826 }
1792- } , [ workspaceId , workflowId ] )
1827+ } , [ isDebugging , workspaceId , workflowId ] )
17931828
1829+ // Track original subblock values to restore when clearing debug canvas
1830+ const originalSubblockValuesRef = useRef < Record < string , Record < string , any > > | null > ( null )
1831+
17941832 // Load selected execution's workflow into debug canvas
17951833 useEffect ( ( ) => {
1796- if ( ! selectedExecutionKey ) return
1834+ if ( ! selectedExecutionKey ) {
1835+ // Clear debug canvas and restore original subblock values when no execution is selected
1836+ console . log ( '[Debug] Clearing debug canvas - no selection' )
1837+ useDebugCanvasStore . getState ( ) . clear ( )
1838+
1839+ // Restore original subblock values if we saved them
1840+ if ( originalSubblockValuesRef . current && activeWorkflowId ) {
1841+ const valuesToRestore = originalSubblockValuesRef . current
1842+ console . log ( '[Debug] Restoring original subblock values' )
1843+ useSubBlockStore . setState ( ( state ) => ( {
1844+ workflowValues : {
1845+ ...state . workflowValues ,
1846+ [ activeWorkflowId ] : valuesToRestore
1847+ }
1848+ } ) )
1849+ originalSubblockValuesRef . current = null
1850+ }
1851+ return
1852+ }
17971853 const selected = executions . find ( ( e ) => e . id === selectedExecutionKey )
17981854 const execId = selected ?. executionId
1799- if ( ! execId ) return
1855+ if ( ! execId ) {
1856+ console . log ( '[Debug] No executionId for selected item' )
1857+ return
1858+ }
18001859
18011860 let canceled = false
18021861 const load = async ( ) => {
18031862 try {
1863+ console . log ( '[Debug] Loading frozen canvas for execution:' , execId )
18041864 const response = await fetch ( `/api/logs/${ encodeURIComponent ( execId ) } /frozen-canvas` )
1865+ if ( ! response . ok ) {
1866+ console . error ( '[Debug] Failed to fetch frozen canvas:' , response . status )
1867+ return
1868+ }
18051869 const json = await response . json ( )
18061870 if ( canceled ) return
1807- const state = json ?. data ?. workflowState as WorkflowState | undefined
1808- if ( state ) {
1871+
1872+ // Try multiple possible response formats
1873+ const state = ( json ?. workflowState || json ?. data ?. workflowState || json ) as WorkflowState | undefined
1874+ console . log ( '[Debug] Parsed workflow state:' , {
1875+ hasState : ! ! state ,
1876+ hasBlocks : ! ! ( state ?. blocks ) ,
1877+ blockCount : state ?. blocks ? Object . keys ( state . blocks ) . length : 0 ,
1878+ hasEdges : ! ! ( state ?. edges ) ,
1879+ edgeCount : state ?. edges ? state . edges . length : 0
1880+ } )
1881+ console . log ( '[Debug] Blocks:' , state ?. blocks )
1882+ console . log ( '[Debug] Edges:' , state ?. edges )
1883+ console . log ( '[Debug] Full state:' , state )
1884+
1885+ if ( state && state . blocks && Object . keys ( state . blocks ) . length > 0 ) {
1886+ // Ensure edges array exists (it might be missing from old snapshots)
1887+ if ( ! state . edges ) {
1888+ console . log ( '[Debug] No edges in state, creating empty array' )
1889+ state . edges = [ ]
1890+ }
1891+
1892+ // Ensure loops and parallels exist
1893+ if ( ! state . loops ) state . loops = { }
1894+ if ( ! state . parallels ) state . parallels = { }
1895+
1896+ // Clear any active diff mode first
1897+ try {
1898+ const diffStore = useWorkflowDiffStore . getState ( )
1899+ if ( diffStore . isShowingDiff ) {
1900+ diffStore . clearDiff ( )
1901+ }
1902+ } catch ( e ) {
1903+ console . error ( '[Debug] Error clearing diff:' , e )
1904+ }
1905+
1906+ // Activate debug canvas with the fetched workflow state
1907+ console . log ( '[Debug] Activating debug canvas with state' )
1908+ console . log ( '[Debug] State to activate:' , {
1909+ blocks : Object . keys ( state . blocks ) ,
1910+ edges : state . edges ,
1911+ loops : state . loops ,
1912+ parallels : state . parallels
1913+ } )
1914+
1915+ // Extract and load subblock values from the frozen state
1916+ const subblockValues : Record < string , Record < string , any > > = { }
1917+ Object . entries ( state . blocks ) . forEach ( ( [ blockId , block ] ) => {
1918+ const blockState = block as any
1919+ if ( blockState . subBlocks ) {
1920+ subblockValues [ blockId ] = { }
1921+ Object . entries ( blockState . subBlocks ) . forEach ( ( [ subblockId , subblock ] ) => {
1922+ const subblockData = subblock as any
1923+ if ( subblockData && 'value' in subblockData ) {
1924+ subblockValues [ blockId ] [ subblockId ] = subblockData . value
1925+ }
1926+ } )
1927+ }
1928+ } )
1929+
1930+ console . log ( '[Debug] Extracted subblock values:' , subblockValues )
1931+
1932+ // Load subblock values into the store for the current workflow
1933+ if ( activeWorkflowId && Object . keys ( subblockValues ) . length > 0 ) {
1934+ // Save original values if not already saved
1935+ if ( ! originalSubblockValuesRef . current ) {
1936+ const currentValues = useSubBlockStore . getState ( ) . workflowValues [ activeWorkflowId ]
1937+ if ( currentValues ) {
1938+ originalSubblockValuesRef . current = { ...currentValues }
1939+ console . log ( '[Debug] Saved original subblock values' )
1940+ }
1941+ }
1942+
1943+ console . log ( '[Debug] Loading subblock values for workflow:' , activeWorkflowId )
1944+ useSubBlockStore . setState ( ( state ) => ( {
1945+ workflowValues : {
1946+ ...state . workflowValues ,
1947+ [ activeWorkflowId ] : subblockValues
1948+ }
1949+ } ) )
1950+ }
1951+
18091952 useDebugCanvasStore . getState ( ) . activate ( state )
1953+
1954+ // Reset debug execution state to align with the new canvas
1955+ useDebugSnapshotStore . getState ( ) . clear ( )
1956+
1957+ const execStore = useExecutionStore . getState ( )
1958+ execStore . setIsExecuting ( false )
1959+ execStore . setIsDebugging ( true )
1960+ execStore . setExecutor ( null )
1961+ execStore . setDebugContext ( null )
1962+ execStore . setExecutingBlockIds ( new Set ( ) )
1963+ execStore . setActiveBlocks ( new Set ( ) )
1964+
1965+ // Determine starter block from the loaded state and set as pending/focused
1966+ const blocks = Object . values ( state . blocks || { } ) as any [ ]
1967+ const starterBlock = blocks . find ( ( b : any ) => b ?. type === 'starter' || b ?. metadata ?. id === 'starter' ) as any
1968+ const starterIdFromState = starterBlock ?. id as string | undefined
1969+ console . log ( '[Debug] Setting starter as pending:' , starterIdFromState )
1970+ execStore . setPendingBlocks ( starterIdFromState ? [ starterIdFromState ] : [ ] )
1971+ execStore . setPanelFocusedBlockId ( starterIdFromState || null )
1972+
1973+ // Verify the canvas was activated and trigger a re-render
1974+ setTimeout ( ( ) => {
1975+ const debugState = useDebugCanvasStore . getState ( )
1976+ console . log ( '[Debug] Debug canvas state after activation:' , {
1977+ isActive : debugState . isActive ,
1978+ hasWorkflowState : ! ! debugState . workflowState ,
1979+ workflowStateBlocks : debugState . workflowState ?. blocks ? Object . keys ( debugState . workflowState . blocks ) : null ,
1980+ workflowStateEdges : debugState . workflowState ?. edges
1981+ } )
1982+
1983+ // Try to trigger a re-render by updating the debug canvas again
1984+ if ( debugState . isActive && debugState . workflowState ) {
1985+ console . log ( '[Debug] Re-activating to force re-render' )
1986+ useDebugCanvasStore . getState ( ) . setWorkflowState ( debugState . workflowState )
1987+ }
1988+ } , 100 )
1989+ } else {
1990+ console . warn ( '[Debug] Invalid or empty workflow state received' )
18101991 }
18111992 } catch ( err ) {
1812- // Silently ignore load errors
1993+ console . error ( '[Debug] Error loading frozen canvas:' , err )
18131994 }
18141995 }
18151996 load ( )
@@ -2124,13 +2305,7 @@ export function DebugPanel() {
21242305 < Select value = { selectedExecutionKey } onValueChange = { ( v ) => setSelectedExecutionKey ( v ) } >
21252306 < SelectTrigger className = 'h-8 w-[220px] text-[11px] leading-4' >
21262307 < SelectValue
2127- placeholder = {
2128- isLoadingExecutions
2129- ? 'Loading executions...'
2130- : executions . length > 0
2131- ? 'Select execution'
2132- : 'No executions'
2133- }
2308+ placeholder = { isLoadingExecutions ? 'Loading executions...' : 'Select execution' }
21342309 />
21352310 </ SelectTrigger >
21362311 < SelectContent >
0 commit comments