Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 3 additions & 7 deletions apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
74 changes: 24 additions & 50 deletions apps/sim/contexts/socket-context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, any>()
;(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,
},
}))

Expand Down Expand Up @@ -518,36 +504,24 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
})
})

const existing = useWorkflowStore.getState()
const mergedBlocks = {
...(existing.blocks || {}),
...(workflowState.blocks || {}),
}
const edgeById = new Map<string, any>()
;(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,
},
}))

Expand Down
38 changes: 1 addition & 37 deletions apps/sim/stores/workflows/registry/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,27 +124,6 @@ async function fetchWorkflowsFromDB(workspaceId?: string): Promise<void> {
}
}

// Initialize subblock values
const subblockValues: Record<string, Record<string, any>> = {}
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(
Expand Down Expand Up @@ -506,22 +485,7 @@ export const useWorkflowRegistry = create<WorkflowRegistry>()(
},
}

// Extract and update subblock values
const subblockValues: Record<string, Record<string, any>> = {}
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 = {
Expand Down
2 changes: 1 addition & 1 deletion apps/sim/stores/workflows/subblock/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ export const useSubBlockStore = create<SubBlockStore>()(
const values: Record<string, Record<string, any>> = {}
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
})
})
Expand Down