diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx index 9c7ac2bad4..3dbf7ac3b6 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx @@ -887,14 +887,10 @@ const WorkflowContent = React.memo(() => { // 2. The workflow exists in the registry // 3. Workflows are not currently loading if (hasActiveWorkflow && hasWorkflowInRegistry && isNotLoading) { - // Add a small delay to ensure blocks state has settled - const timeoutId = setTimeout(() => { - setIsWorkflowReady(true) - }, 100) - - return () => clearTimeout(timeoutId) + setIsWorkflowReady(true) + } else { + setIsWorkflowReady(false) } - setIsWorkflowReady(false) }, [activeWorkflowId, params.workflowId, workflows, isLoading]) // Init workflow diff --git a/apps/sim/contexts/socket-context.tsx b/apps/sim/contexts/socket-context.tsx index 8da153805b..c363f28ee4 100644 --- a/apps/sim/contexts/socket-context.tsx +++ b/apps/sim/contexts/socket-context.tsx @@ -376,38 +376,24 @@ export function SocketProvider({ children, user }: SocketProviderProps) { ) }) - // Merge workflow store with server state (do not drop optimistic local state) - const existing = useWorkflowStore.getState() - const mergedBlocks = { - ...(existing.blocks || {}), - ...(workflowState.blocks || {}), - } - const edgeById = new Map() - ;(existing.edges || []).forEach((e: any) => edgeById.set(e.id, e)) - ;(workflowState.edges || []).forEach((e: any) => edgeById.set(e.id, e)) - const mergedEdges = Array.from(edgeById.values()) + // Replace local workflow store with authoritative server state useWorkflowStore.setState({ - blocks: mergedBlocks, - edges: mergedEdges, - loops: workflowState.loops || existing.loops || {}, - parallels: workflowState.parallels || existing.parallels || {}, - lastSaved: workflowState.lastSaved || existing.lastSaved || Date.now(), - isDeployed: workflowState.isDeployed ?? existing.isDeployed ?? false, - deployedAt: workflowState.deployedAt || existing.deployedAt, - deploymentStatuses: - workflowState.deploymentStatuses || existing.deploymentStatuses || {}, - hasActiveWebhook: - workflowState.hasActiveWebhook ?? existing.hasActiveWebhook ?? false, + blocks: workflowState.blocks || {}, + edges: workflowState.edges || [], + loops: workflowState.loops || {}, + parallels: workflowState.parallels || {}, + lastSaved: workflowState.lastSaved || Date.now(), + isDeployed: workflowState.isDeployed ?? false, + deployedAt: workflowState.deployedAt, + deploymentStatuses: workflowState.deploymentStatuses || {}, + hasActiveWebhook: workflowState.hasActiveWebhook ?? false, }) - // Merge subblock store values per workflow + // Replace subblock store values for this workflow useSubBlockStore.setState((state: any) => ({ workflowValues: { ...state.workflowValues, - [data.workflowId]: { - ...(state.workflowValues?.[data.workflowId] || {}), - ...subblockValues, - }, + [data.workflowId]: subblockValues, }, })) @@ -518,36 +504,24 @@ export function SocketProvider({ children, user }: SocketProviderProps) { }) }) - const existing = useWorkflowStore.getState() - const mergedBlocks = { - ...(existing.blocks || {}), - ...(workflowState.blocks || {}), - } - const edgeById = new Map() - ;(existing.edges || []).forEach((e: any) => edgeById.set(e.id, e)) - ;(workflowState.edges || []).forEach((e: any) => edgeById.set(e.id, e)) - const mergedEdges = Array.from(edgeById.values()) + // Replace local workflow store with authoritative server state useWorkflowStore.setState({ - blocks: mergedBlocks, - edges: mergedEdges, - loops: workflowState.loops || existing.loops || {}, - parallels: workflowState.parallels || existing.parallels || {}, - lastSaved: workflowState.lastSaved || existing.lastSaved || Date.now(), - isDeployed: workflowState.isDeployed ?? existing.isDeployed ?? false, - deployedAt: workflowState.deployedAt || existing.deployedAt, - deploymentStatuses: - workflowState.deploymentStatuses || existing.deploymentStatuses || {}, - hasActiveWebhook: - workflowState.hasActiveWebhook ?? existing.hasActiveWebhook ?? false, + blocks: workflowState.blocks || {}, + edges: workflowState.edges || [], + loops: workflowState.loops || {}, + parallels: workflowState.parallels || {}, + lastSaved: workflowState.lastSaved || Date.now(), + isDeployed: workflowState.isDeployed ?? false, + deployedAt: workflowState.deployedAt, + deploymentStatuses: workflowState.deploymentStatuses || {}, + hasActiveWebhook: workflowState.hasActiveWebhook ?? false, }) + // Replace subblock store values for this workflow useSubBlockStore.setState((state: any) => ({ workflowValues: { ...state.workflowValues, - [workflowData.id]: { - ...(state.workflowValues?.[workflowData.id] || {}), - ...subblockValues, - }, + [workflowData.id]: subblockValues, }, })) diff --git a/apps/sim/stores/workflows/registry/store.ts b/apps/sim/stores/workflows/registry/store.ts index c5edb5a068..7798cade53 100644 --- a/apps/sim/stores/workflows/registry/store.ts +++ b/apps/sim/stores/workflows/registry/store.ts @@ -124,27 +124,6 @@ async function fetchWorkflowsFromDB(workspaceId?: string): Promise { } } - // Initialize subblock values - const subblockValues: Record> = {} - if (state?.blocks) { - Object.entries(state.blocks).forEach(([blockId, block]) => { - const blockState = block as BlockState - subblockValues[blockId] = {} - - Object.entries(blockState.subBlocks || {}).forEach(([subblockId, subblock]) => { - subblockValues[blockId][subblockId] = subblock.value - }) - }) - } - - // Update subblock store - useSubBlockStore.setState((state) => ({ - workflowValues: { - ...state.workflowValues, - [id]: subblockValues, - }, - })) - if (variables && typeof variables === 'object') { useVariablesStore.setState((state) => { const withoutWorkflow = Object.fromEntries( @@ -506,22 +485,7 @@ export const useWorkflowRegistry = create()( }, } - // Extract and update subblock values - const subblockValues: Record> = {} - Object.entries(workflowState.blocks).forEach(([blockId, block]) => { - const blockState = block as any - subblockValues[blockId] = {} - Object.entries(blockState.subBlocks || {}).forEach(([subblockId, subblock]) => { - subblockValues[blockId][subblockId] = (subblock as any).value - }) - }) - - useSubBlockStore.setState((state) => ({ - workflowValues: { - ...state.workflowValues, - [id]: subblockValues, - }, - })) + // Subblock values will be initialized by initializeFromWorkflow below } else { // If no state in DB, use empty state - server should have created start block workflowState = { diff --git a/apps/sim/stores/workflows/subblock/store.ts b/apps/sim/stores/workflows/subblock/store.ts index 672cca20ec..f4e49e85ee 100644 --- a/apps/sim/stores/workflows/subblock/store.ts +++ b/apps/sim/stores/workflows/subblock/store.ts @@ -103,7 +103,7 @@ export const useSubBlockStore = create()( const values: Record> = {} Object.entries(blocks).forEach(([blockId, block]) => { values[blockId] = {} - Object.entries(block.subBlocks).forEach(([subBlockId, subBlock]) => { + Object.entries(block.subBlocks || {}).forEach(([subBlockId, subBlock]) => { values[blockId][subBlockId] = (subBlock as SubBlockConfig).value }) })