'use client'; import * as React from 'react'; import { cn } from '../../lib/utils'; import { StatusBadge } from '../badge/StatusBadge'; import { DualPaneWorkspace } from '../workspace/DualPaneWorkspace'; import { ExecutionTimeline } from './ExecutionTimeline'; import { ExecNodeDetails } from './ExecNodeDetails'; import { RUN_STATUS_BADGE } from './exec-status'; import type { NodeExecView, WfExecutionView } from './types'; export interface WorkflowRunViewerProps { /** The current run snapshot. Pass a fresh object on each poll. */ execution: WfExecutionView; /** Initially-selected node id. */ initialNodeId?: string; className?: string; } function nodeList(execution: WfExecutionView): NodeExecView[] { return Object.values(execution.nodes ?? {}); } /** * Read-only run visualizer: an execution timeline beside a selected-node * detail panel (built on {@link DualPaneWorkspace}), with a run-status * header badge. Designed for polling — pass a fresh {@link WfExecutionView} * snapshot on each tick and the timeline + currently-selected detail panel * re-render against the latest data. */ export function WorkflowRunViewer({ execution, initialNodeId, className, }: WorkflowRunViewerProps) { const nodes = nodeList(execution); const [selectedId, setSelectedId] = React.useState( initialNodeId ?? null ); // Resolve the selected node against the LATEST snapshot so the detail // panel reflects new poll data without needing to re-select. const selectedNode = selectedId != null ? execution.nodes?.[selectedId] : null; const header = (
Workflow run {execution.executionId && ( {execution.executionId} )}
); return (
} right={} /> ); }