Skip to content

Commit 415acda

Browse files
committed
Allow run from block for triggers
1 parent 8dc45e6 commit 415acda

File tree

3 files changed

+36
-30
lines changed

3 files changed

+36
-30
lines changed

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/action-bar/action-bar.tsx

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -112,19 +112,13 @@ export const ActionBar = memo(
112112
const isInsideSubflow = parentId && (parentType === 'loop' || parentType === 'parallel')
113113

114114
const snapshot = activeWorkflowId ? getLastExecutionSnapshot(activeWorkflowId) : null
115-
const hasExecutionSnapshot = !!snapshot
116-
const dependenciesSatisfied = (() => {
117-
if (!snapshot) return false
118-
const incomingEdges = edges.filter((edge) => edge.target === blockId)
119-
if (incomingEdges.length === 0) return true
120-
return incomingEdges.every((edge) => snapshot.executedBlocks.includes(edge.source))
121-
})()
115+
const incomingEdges = edges.filter((edge) => edge.target === blockId)
116+
const isTriggerBlock = incomingEdges.length === 0
117+
const dependenciesSatisfied =
118+
isTriggerBlock ||
119+
(snapshot && incomingEdges.every((edge) => snapshot.executedBlocks.includes(edge.source)))
122120
const canRunFromBlock =
123-
hasExecutionSnapshot &&
124-
dependenciesSatisfied &&
125-
!isNoteBlock &&
126-
!isInsideSubflow &&
127-
!isExecuting
121+
dependenciesSatisfied && !isNoteBlock && !isInsideSubflow && !isExecuting
128122

129123
const handleRunFromBlockClick = useCallback(() => {
130124
if (!activeWorkflowId || !canRunFromBlock) return
@@ -176,9 +170,8 @@ export const ActionBar = memo(
176170
{(() => {
177171
if (disabled) return getTooltipMessage('Run from this block')
178172
if (isExecuting) return 'Execution in progress'
179-
if (!hasExecutionSnapshot) return 'Run workflow first'
180-
if (!dependenciesSatisfied) return 'Run upstream blocks first'
181173
if (isInsideSubflow) return 'Cannot run from inside subflow'
174+
if (!dependenciesSatisfied) return 'Run upstream blocks first'
182175
return 'Run from this block'
183176
})()}
184177
</Tooltip.Content>

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.ts

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1435,16 +1435,18 @@ export function useWorkflowExecution() {
14351435
const handleRunFromBlock = useCallback(
14361436
async (blockId: string, workflowId: string) => {
14371437
const snapshot = getLastExecutionSnapshot(workflowId)
1438-
if (!snapshot) {
1438+
const workflowEdges = useWorkflowStore.getState().edges
1439+
const incomingEdges = workflowEdges.filter((edge) => edge.target === blockId)
1440+
const isTriggerBlock = incomingEdges.length === 0
1441+
1442+
if (!snapshot && !isTriggerBlock) {
14391443
logger.error('No execution snapshot available for run-from-block', { workflowId, blockId })
14401444
return
14411445
}
14421446

1443-
const workflowEdges = useWorkflowStore.getState().edges
1444-
const incomingEdges = workflowEdges.filter((edge) => edge.target === blockId)
14451447
const dependenciesSatisfied =
1446-
incomingEdges.length === 0 ||
1447-
incomingEdges.every((edge) => snapshot.executedBlocks.includes(edge.source))
1448+
isTriggerBlock ||
1449+
(snapshot && incomingEdges.every((edge) => snapshot.executedBlocks.includes(edge.source)))
14481450

14491451
if (!dependenciesSatisfied) {
14501452
logger.error('Upstream dependencies not satisfied for run-from-block', {
@@ -1454,10 +1456,20 @@ export function useWorkflowExecution() {
14541456
return
14551457
}
14561458

1459+
// For trigger blocks with no snapshot, create an empty one
1460+
const effectiveSnapshot: SerializableExecutionState = snapshot || {
1461+
blockStates: {},
1462+
executedBlocks: [],
1463+
blockLogs: [],
1464+
decisions: { router: {}, condition: {} },
1465+
completedLoops: [],
1466+
activeExecutionPath: [],
1467+
}
1468+
14571469
logger.info('Starting run-from-block execution', {
14581470
workflowId,
14591471
startBlockId: blockId,
1460-
snapshotExecutedBlocks: snapshot.executedBlocks.length,
1472+
isTriggerBlock,
14611473
})
14621474

14631475
setIsExecuting(true)
@@ -1471,7 +1483,7 @@ export function useWorkflowExecution() {
14711483
await executionStream.executeFromBlock({
14721484
workflowId,
14731485
startBlockId: blockId,
1474-
sourceSnapshot: snapshot,
1486+
sourceSnapshot: effectiveSnapshot,
14751487
callbacks: {
14761488
onExecutionStarted: (data) => {
14771489
logger.info('Run-from-block execution started:', data)
@@ -1579,21 +1591,23 @@ export function useWorkflowExecution() {
15791591

15801592
onExecutionCompleted: (data) => {
15811593
if (data.success) {
1582-
const mergedBlockStates: Record<string, BlockState> = { ...snapshot.blockStates }
1594+
const mergedBlockStates: Record<string, BlockState> = {
1595+
...effectiveSnapshot.blockStates,
1596+
}
15831597
for (const [bId, state] of accumulatedBlockStates) {
15841598
mergedBlockStates[bId] = state
15851599
}
15861600

15871601
const mergedExecutedBlocks = new Set([
1588-
...snapshot.executedBlocks,
1602+
...effectiveSnapshot.executedBlocks,
15891603
...executedBlockIds,
15901604
])
15911605

15921606
const updatedSnapshot: SerializableExecutionState = {
1593-
...snapshot,
1607+
...effectiveSnapshot,
15941608
blockStates: mergedBlockStates,
15951609
executedBlocks: Array.from(mergedExecutedBlocks),
1596-
blockLogs: [...snapshot.blockLogs, ...accumulatedBlockLogs],
1610+
blockLogs: [...effectiveSnapshot.blockLogs, ...accumulatedBlockLogs],
15971611
activeExecutionPath: Array.from(mergedExecutedBlocks),
15981612
}
15991613
setLastExecutionSnapshot(workflowId, updatedSnapshot)

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,18 +1012,17 @@ const WorkflowContent = React.memo(() => {
10121012
}
10131013
const block = contextMenuBlocks[0]
10141014
const snapshot = getLastExecutionSnapshot(workflowIdParam)
1015-
if (!snapshot) return { canRun: false, reason: 'Run workflow first' }
1016-
10171015
const incomingEdges = edges.filter((edge) => edge.target === block.id)
1016+
const isTriggerBlock = incomingEdges.length === 0
10181017
const dependenciesSatisfied =
1019-
incomingEdges.length === 0 ||
1020-
incomingEdges.every((edge) => snapshot.executedBlocks.includes(edge.source))
1018+
isTriggerBlock ||
1019+
(snapshot && incomingEdges.every((edge) => snapshot.executedBlocks.includes(edge.source)))
10211020
const isNoteBlock = block.type === 'note'
10221021
const isInsideSubflow =
10231022
block.parentId && (block.parentType === 'loop' || block.parentType === 'parallel')
10241023

1025-
if (!dependenciesSatisfied) return { canRun: false, reason: 'Run upstream blocks first' }
10261024
if (isInsideSubflow) return { canRun: false, reason: 'Cannot run from inside subflow' }
1025+
if (!dependenciesSatisfied) return { canRun: false, reason: 'Run upstream blocks first' }
10271026
if (isNoteBlock) return { canRun: false, reason: undefined }
10281027
if (isExecuting) return { canRun: false, reason: undefined }
10291028

0 commit comments

Comments
 (0)