Skip to content

Commit 5a0a36b

Browse files
committed
consolidate more code
1 parent 59a5160 commit 5a0a36b

File tree

5 files changed

+66
-100
lines changed

5 files changed

+66
-100
lines changed

apps/sim/background/webhook-execution.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ async function executeWebhookJobInternal(
172172
const workflowVariables = (wfRows[0]?.variables as Record<string, any>) || {}
173173

174174
// Merge subblock states (matching workflow-execution pattern)
175-
const mergedStates = mergeSubblockState(blocks, {})
175+
const mergedStates = mergeSubblockState(blocks)
176176

177177
// Create serialized workflow
178178
const serializer = new Serializer()

apps/sim/lib/workflows/subblocks.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import type { BlockState, SubBlockState } from '@/stores/workflows/workflow/types'
2+
13
export const DEFAULT_SUBBLOCK_TYPE = 'short-input'
24

35
/**
@@ -33,3 +35,46 @@ export function mergeSubBlockValues(
3335

3436
return merged
3537
}
38+
39+
/**
40+
* Merges workflow block states with explicit subblock values while maintaining block structure.
41+
* Values that are null or undefined do not override existing subblock values.
42+
* @param blocks - Block configurations from workflow state
43+
* @param subBlockValues - Subblock values keyed by blockId -> subBlockId -> value
44+
* @param blockId - Optional specific block ID to merge (merges all if not provided)
45+
* @returns Merged block states with updated subblocks
46+
*/
47+
export function mergeSubblockStateWithValues(
48+
blocks: Record<string, BlockState>,
49+
subBlockValues: Record<string, Record<string, unknown>> = {},
50+
blockId?: string
51+
): Record<string, BlockState> {
52+
const blocksToProcess = blockId ? { [blockId]: blocks[blockId] } : blocks
53+
54+
return Object.entries(blocksToProcess).reduce(
55+
(acc, [id, block]) => {
56+
if (!block) {
57+
return acc
58+
}
59+
60+
const blockSubBlocks = block.subBlocks || {}
61+
const blockValues = subBlockValues[id] || {}
62+
const filteredValues = Object.fromEntries(
63+
Object.entries(blockValues).filter(([, value]) => value !== null && value !== undefined)
64+
)
65+
66+
const mergedSubBlocks = mergeSubBlockValues(blockSubBlocks, filteredValues) as Record<
67+
string,
68+
SubBlockState
69+
>
70+
71+
acc[id] = {
72+
...block,
73+
subBlocks: mergedSubBlocks,
74+
}
75+
76+
return acc
77+
},
78+
{} as Record<string, BlockState>
79+
)
80+
}

apps/sim/stores/workflows/server-utils.ts

Lines changed: 3 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
* or React hooks, making it safe for use in Next.js API routes.
99
*/
1010

11-
import type { BlockState, SubBlockState } from '@/stores/workflows/workflow/types'
11+
import { mergeSubblockStateWithValues } from '@/lib/workflows/subblocks'
12+
import type { BlockState } from '@/stores/workflows/workflow/types'
1213

1314
/**
1415
* Server-safe version of mergeSubblockState for API routes
@@ -26,72 +27,7 @@ export function mergeSubblockState(
2627
subBlockValues: Record<string, Record<string, any>> = {},
2728
blockId?: string
2829
): Record<string, BlockState> {
29-
const blocksToProcess = blockId ? { [blockId]: blocks[blockId] } : blocks
30-
31-
return Object.entries(blocksToProcess).reduce(
32-
(acc, [id, block]) => {
33-
// Skip if block is undefined
34-
if (!block) {
35-
return acc
36-
}
37-
38-
// Initialize subBlocks if not present
39-
const blockSubBlocks = block.subBlocks || {}
40-
41-
// Get stored values for this block
42-
const blockValues = subBlockValues[id] || {}
43-
44-
// Create a deep copy of the block's subBlocks to maintain structure
45-
const mergedSubBlocks = Object.entries(blockSubBlocks).reduce(
46-
(subAcc, [subBlockId, subBlock]) => {
47-
// Skip if subBlock is undefined
48-
if (!subBlock) {
49-
return subAcc
50-
}
51-
52-
// Get the stored value for this subblock
53-
const storedValue = blockValues[subBlockId]
54-
55-
// Create a new subblock object with the same structure but updated value
56-
subAcc[subBlockId] = {
57-
...subBlock,
58-
value: storedValue !== undefined && storedValue !== null ? storedValue : subBlock.value,
59-
}
60-
61-
return subAcc
62-
},
63-
{} as Record<string, SubBlockState>
64-
)
65-
66-
// Return the full block state with updated subBlocks
67-
acc[id] = {
68-
...block,
69-
subBlocks: mergedSubBlocks,
70-
}
71-
72-
// Add any values that exist in the provided values but aren't in the block structure
73-
// This handles cases where block config has been updated but values still exist
74-
Object.entries(blockValues).forEach(([subBlockId, value]) => {
75-
if (!mergedSubBlocks[subBlockId] && value !== null && value !== undefined) {
76-
// Create a minimal subblock structure
77-
mergedSubBlocks[subBlockId] = {
78-
id: subBlockId,
79-
type: 'short-input', // Default type that's safe to use
80-
value: value,
81-
}
82-
}
83-
})
84-
85-
// Update the block with the final merged subBlocks (including orphaned values)
86-
acc[id] = {
87-
...block,
88-
subBlocks: mergedSubBlocks,
89-
}
90-
91-
return acc
92-
},
93-
{} as Record<string, BlockState>
94-
)
30+
return mergeSubblockStateWithValues(blocks, subBlockValues, blockId)
9531
}
9632

9733
/**

apps/sim/stores/workflows/utils.ts

Lines changed: 15 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { Edge } from 'reactflow'
22
import { v4 as uuidv4 } from 'uuid'
33
import { getBlockOutputs } from '@/lib/workflows/blocks/block-outputs'
4-
import { mergeSubBlockValues } from '@/lib/workflows/subblocks'
4+
import { mergeSubBlockValues, mergeSubblockStateWithValues } from '@/lib/workflows/subblocks'
55
import { getBlock } from '@/blocks'
66
import { normalizeName } from '@/executor/constants'
77
import { useSubBlockStore } from '@/stores/workflows/subblock/store'
@@ -249,11 +249,16 @@ export function mergeSubblockState(
249249
workflowId?: string,
250250
blockId?: string
251251
): Record<string, BlockState> {
252-
const blocksToProcess = blockId ? { [blockId]: blocks[blockId] } : blocks
253252
const subBlockStore = useSubBlockStore.getState()
254253

255254
const workflowSubblockValues = workflowId ? subBlockStore.workflowValues[workflowId] || {} : {}
256255

256+
if (workflowId) {
257+
return mergeSubblockStateWithValues(blocks, workflowSubblockValues, blockId)
258+
}
259+
260+
const blocksToProcess = blockId ? { [blockId]: blocks[blockId] } : blocks
261+
257262
return Object.entries(blocksToProcess).reduce(
258263
(acc, [id, block]) => {
259264
if (!block) {
@@ -332,9 +337,15 @@ export async function mergeSubblockStateAsync(
332337
workflowId?: string,
333338
blockId?: string
334339
): Promise<Record<string, BlockState>> {
335-
const blocksToProcess = blockId ? { [blockId]: blocks[blockId] } : blocks
336340
const subBlockStore = useSubBlockStore.getState()
337341

342+
if (workflowId) {
343+
const workflowValues = subBlockStore.workflowValues[workflowId] || {}
344+
return mergeSubblockStateWithValues(blocks, workflowValues, blockId)
345+
}
346+
347+
const blocksToProcess = blockId ? { [blockId]: blocks[blockId] } : blocks
348+
338349
// Process blocks in parallel for better performance
339350
const processedBlockEntries = await Promise.all(
340351
Object.entries(blocksToProcess).map(async ([id, block]) => {
@@ -351,16 +362,7 @@ export async function mergeSubblockStateAsync(
351362
return null
352363
}
353364

354-
let storedValue = null
355-
356-
if (workflowId) {
357-
const workflowValues = subBlockStore.workflowValues[workflowId]
358-
if (workflowValues?.[id]) {
359-
storedValue = workflowValues[id][subBlockId]
360-
}
361-
} else {
362-
storedValue = subBlockStore.getValue(id, subBlockId)
363-
}
365+
const storedValue = subBlockStore.getValue(id, subBlockId)
364366

365367
return [
366368
subBlockId,
@@ -379,23 +381,6 @@ export async function mergeSubblockStateAsync(
379381
subBlockEntries.filter((entry): entry is readonly [string, SubBlockState] => entry !== null)
380382
) as Record<string, SubBlockState>
381383

382-
// Add any values that exist in the store but aren't in the block structure
383-
// This handles cases where block config has been updated but values still exist
384-
// IMPORTANT: This includes runtime subblock IDs like webhookId, triggerPath, etc.
385-
if (workflowId) {
386-
const workflowValues = subBlockStore.workflowValues[workflowId]
387-
const blockValues = workflowValues?.[id] || {}
388-
Object.entries(blockValues).forEach(([subBlockId, value]) => {
389-
if (!mergedSubBlocks[subBlockId] && value !== null && value !== undefined) {
390-
mergedSubBlocks[subBlockId] = {
391-
id: subBlockId,
392-
type: 'short-input',
393-
value: value as SubBlockState['value'],
394-
}
395-
}
396-
})
397-
}
398-
399384
// Return the full block state with updated subBlocks (including orphaned values)
400385
return [
401386
id,

apps/sim/stores/workflows/workflow/store.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -639,7 +639,8 @@ export const useWorkflowStore = create<WorkflowStore>()(
639639

640640
const newName = getUniqueBlockName(block.name, get().blocks)
641641

642-
const mergedBlock = mergeSubblockState(get().blocks, id)[id]
642+
const activeWorkflowId = useWorkflowRegistry.getState().activeWorkflowId
643+
const mergedBlock = mergeSubblockState(get().blocks, activeWorkflowId || undefined, id)[id]
643644

644645
const newSubBlocks = Object.entries(mergedBlock.subBlocks).reduce(
645646
(acc, [subId, subBlock]) => ({
@@ -668,7 +669,6 @@ export const useWorkflowStore = create<WorkflowStore>()(
668669
parallels: get().generateParallelBlocks(),
669670
}
670671

671-
const activeWorkflowId = useWorkflowRegistry.getState().activeWorkflowId
672672
if (activeWorkflowId) {
673673
const subBlockValues =
674674
useSubBlockStore.getState().workflowValues[activeWorkflowId]?.[id] || {}

0 commit comments

Comments
 (0)