({ data, selected, id }: NodeProps<NodeData>)
| 78 | * Enhanced WorkflowNode - Visual representation with timeline states |
| 79 | */ |
| 80 | export const WorkflowNode = ({ data, selected, id }: NodeProps<NodeData>) => { |
| 81 | // Store hooks |
| 82 | const { getComponent, loading } = useComponentStore(); |
| 83 | const secrets = useSecretStore((state) => state.secrets); |
| 84 | const { getNodes, getEdges, setNodes, deleteElements } = useReactFlow(); |
| 85 | const updateNodeInternals = useUpdateNodeInternals(); |
| 86 | const { nodeStates, selectedRunId, selectNode, isPlaying, playbackMode, isLiveFollowing } = |
| 87 | useExecutionTimelineStore(); |
| 88 | const { markDirty } = useWorkflowStore(); |
| 89 | const { mode, focusedTerminalNodeId, bringTerminalToFront, openHumanInputDialog } = |
| 90 | useWorkflowUiStore(); |
| 91 | const prefetchTerminal = useExecutionStore((state) => state.prefetchTerminal); |
| 92 | const terminalSession = useExecutionStore((state) => state.getTerminalSession(id, 'pty')); |
| 93 | const theme = useThemeStore((state) => state.theme); |
| 94 | const { lastCreatedKey } = useApiKeyStore(); |
| 95 | // @ts-expect-error - FIXME: Check actual store structure |
| 96 | const workflowIdFromStore = useWorkflowStore((state) => state.workflow?.id); |
| 97 | const { |
| 98 | onOpenScheduleSidebar, |
| 99 | onOpenWebhooksSidebar, |
| 100 | setPlacement: _setPlacement, |
| 101 | selectEntryPoint, |
| 102 | } = useEntryPointActions(); |
| 103 | |
| 104 | // Local state |
| 105 | const [isTerminalOpen, setIsTerminalOpen] = useState(false); |
| 106 | const [isTerminalLoading, setIsTerminalLoading] = useState(false); |
| 107 | const nodeRef = useRef<HTMLDivElement | null>(null); |
| 108 | const [isEditingLabel, setIsEditingLabel] = useState(false); |
| 109 | const [editingLabelValue, setEditingLabelValue] = useState(''); |
| 110 | const labelInputRef = useRef<HTMLInputElement | null>(null); |
| 111 | const navigate = useNavigate(); |
| 112 | const [showWebhookDialog, setShowWebhookDialog] = useState(false); |
| 113 | const [showErrorDetails, setShowErrorDetails] = useState(false); |
| 114 | const isMobile = useIsMobile(); |
| 115 | const activeApiKey = lastCreatedKey; |
| 116 | |
| 117 | const [textSize, setTextSize] = useState<{ width: number; height: number }>(() => { |
| 118 | const uiSize = (data as any)?.ui?.size as { width?: number; height?: number } | undefined; |
| 119 | return { |
| 120 | width: uiSize?.width ?? DEFAULT_TEXT_WIDTH, |
| 121 | height: uiSize?.height ?? DEFAULT_TEXT_HEIGHT, |
| 122 | }; |
| 123 | }); |
| 124 | |
| 125 | // Terminal loading effect |
| 126 | useEffect(() => { |
| 127 | if (!isTerminalOpen) return; |
| 128 | |
| 129 | let cancelled = false; |
| 130 | const loadTerminal = async () => { |
| 131 | setIsTerminalLoading(true); |
| 132 | try { |
| 133 | await prefetchTerminal(id, 'pty', selectedRunId ?? undefined); |
| 134 | } catch (error) { |
| 135 | console.error('Failed to prefetch terminal output', error); |
| 136 | } finally { |
| 137 | if (!cancelled) setIsTerminalLoading(false); |
nothing calls this directly
no test coverage detected