Portal Community

Why a Separate Hook?

The designer's useExecutionSignalR hook manages the canvas-level connection — updating node border colours, triggering re-renders on the React Flow canvas. The Observer Panel has different needs:

In practice, when both are mounted together (the normal case), both hooks connect to the same SignalR hub and the same execution group. The server broadcasts to all group members, so both receive every event.

useFlowObserverSignalR

// flow-observer-core/src/hooks/useFlowObserverSignalR.ts
export function useFlowObserverSignalR(executionId: string) {
  const engine = useFlowObserverPanelEngine();
  const store = useFlowObserverPanelStore();

  useEffect(() => {
    const connection = new HubConnectionBuilder()
      .withUrl('/hubs/execution', {
        accessTokenFactory: () => getAuthToken()
      })
      .withAutomaticReconnect([1000, 2000, 5000, 10000])
      .build();

    connection.on('ExecutionEvent', (event: ExecutionEvent) => {
      // Route all events through the engine
      engine.pushExecutionEvent(event);

      // Also update store directly for status/progress
      if (event.type === 'WorkflowExecutionCompleted') {
        store.setStatus(event.status);
      }
      if (event.type === 'NodeExecutionCompleted') {
        store.incrementCompletedCount();
      }
    });

    connection.start()
      .then(() => connection.invoke('JoinExecutionGroup', executionId));

    return () => { connection.stop(); };
  }, [executionId]);
}

Connection Relationship Diagram

HookConsumerPurpose
useExecutionSignalRDesigner canvasUpdate node border colours and canvas execution overlays
useFlowObserverSignalRObserver PanelFeed log buffer, node list, status tab, Node Inspector
Two Connections, Same Group When both hooks are active, the browser maintains two separate WebSocket connections to /hubs/execution. Both join the same execution group. This is expected behaviour — SignalR groups are broadcast-based, so the server sends each event once to the group and both connections receive it. There is no duplication of events in the stores because each hook writes to a different store (designerModeStore vs flowObserverPanelStore).