Flow Studio
Syncing to UI State
useNodeExecutionSync is the bridge between raw SignalR events and the visual state of the canvas. It translates incoming events into store mutations that trigger React re-renders.
useNodeExecutionSync
// useNodeExecutionSync.ts
export function useNodeExecutionSync(executionId: string) {
const { subscribeToNodeStream, subscribeToWorkflowStream } = useExecutionSignalR(executionId);
const designerStore = useDesignerModeStore();
const observerStore = useFlowObserverPanelStore();
useEffect(() => {
// Subscribe to node events
const unsubNode = subscribeToWorkflowStream((event) => {
switch (event.type) {
case 'NodeExecutionStarted':
designerStore.setNodeStatus(event.nodeId, {
status: 'running',
startedAt: event.startedAt
});
break;
case 'NodeExecutionCompleted':
designerStore.setNodeStatus(event.nodeId, {
status: 'completed',
durationMs: event.durationMs,
output: event.output
});
observerStore.incrementCompletedCount();
break;
case 'NodeExecutionFailed':
designerStore.setNodeStatus(event.nodeId, {
status: 'failed',
error: { message: event.errorMessage, type: event.errorType }
});
break;
case 'WorkflowExecutionCompleted':
designerStore.setExecutionComplete(event.status);
break;
}
});
return () => unsubNode();
}, [executionId]);
}
executionStateMapper
The executionStateMapper.ts utility converts raw event data into the NodeExecutionState format consumed by node components. It also handles the colour mapping:
// executionStateMapper.ts
export function mapEventToNodeState(event): NodeExecutionState {
return {
status: mapStatus(event.type),
borderColor: statusToColor(mapStatus(event.type)),
iconClass: statusToIcon(mapStatus(event.type)),
isAnimating: event.type === 'NodeExecutionStarted',
durationMs: event.durationMs,
errorSummary: event.errorMessage?.substring(0, 100)
};
}
function statusToColor(status: string): string {
const map = {
pending: '#4a5568',
running: '#60a5fa',
completed: '#34d399',
failed: '#f87171',
skipped: '#4a5568',
suspended: '#fbbf24'
};
return map[status] ?? '#4a5568';
}