@magic-marker/nurt 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +551 -0
- package/dist/flow-DqIejS_0.d.ts +306 -0
- package/dist/index.d.ts +136 -0
- package/dist/index.js +996 -0
- package/dist/index.js.map +1 -0
- package/dist/react/index.d.ts +123 -0
- package/dist/react/index.js +1234 -0
- package/dist/react/index.js.map +1 -0
- package/package.json +66 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/react/nurt-flow-chart.tsx","../../src/react/nurt-flow-chart-edges.tsx","../../src/react/nurt-flow-chart-layout.ts","../../src/react/nurt-flow-chart-utils.ts","../../src/react/nurt-flow-chart-nodes.tsx","../../src/react/nurt-flow-chart-with-panel.tsx","../../src/react/nurt-step-detail-panel.tsx"],"sourcesContent":["import type { FlowSnapshot } from \"../snapshot.js\";\nimport React, { useEffect, useState } from \"react\";\nimport { FlowEdge } from \"./nurt-flow-chart-edges\";\nimport { type LayoutResult, layoutSnapshot } from \"./nurt-flow-chart-layout\";\nimport { GroupNode, StepNode } from \"./nurt-flow-chart-nodes\";\n\nexport interface NurtFlowChartProps {\n className?: string;\n onNodeClick?: (nodeName: string) => void;\n snapshot: FlowSnapshot;\n}\n\nconst EMPTY_LAYOUT: LayoutResult = {\n edges: [],\n externalRefEdges: [],\n height: 400,\n nodes: [],\n width: 900,\n};\n\nexport const NurtFlowChart: React.FC<NurtFlowChartProps> = ({\n className,\n onNodeClick,\n snapshot,\n}) => {\n const [layout, setLayout] = useState<LayoutResult>(EMPTY_LAYOUT);\n const [hoveredId, setHoveredId] = useState<string | null>(null);\n\n useEffect(() => {\n let cancelled = false;\n layoutSnapshot(snapshot).then((result) => {\n if (!cancelled) setLayout(result);\n });\n return () => {\n cancelled = true;\n };\n }, [snapshot]);\n\n const { edges, externalRefEdges, height, nodes, width } = layout;\n\n return (\n <svg\n className={className}\n height={height}\n preserveAspectRatio=\"xMidYMin meet\"\n viewBox={`0 0 ${width} ${height}`}\n width=\"100%\"\n >\n <defs>\n <marker\n id=\"arrowhead\"\n markerHeight=\"6\"\n markerWidth=\"8\"\n orient=\"auto\"\n refX=\"8\"\n refY=\"3\"\n >\n <polygon fill=\"#4b5563\" points=\"0 0, 8 3, 0 6\" />\n </marker>\n <marker\n id=\"arrowhead-sm\"\n markerHeight=\"4\"\n markerWidth=\"6\"\n orient=\"auto\"\n refX=\"6\"\n refY=\"2\"\n >\n <polygon fill=\"#6b7280\" points=\"0 0, 6 2, 0 4\" />\n </marker>\n <style>{`\n @keyframes pulse-glow {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.6; }\n }\n .node-running { animation: pulse-glow 1.5s ease-in-out infinite; }\n `}</style>\n </defs>\n\n {/* Top-level edges */}\n {edges.map((e) => (\n <FlowEdge edge={e} key={`${e.source}-${e.target}`} />\n ))}\n\n {/* External reference edges (cross-boundary deps, rendered on top) */}\n {externalRefEdges.map((ref, i) => {\n const midY = (ref.y1 + ref.y2) / 2;\n const d = `M ${ref.x1} ${ref.y1} C ${ref.x1} ${midY}, ${ref.x2} ${midY}, ${ref.x2} ${ref.y2}`;\n return (\n <path\n d={d}\n fill=\"none\"\n key={`ref-${ref.sourceStepName}-${ref.targetMemberName}-${i}`}\n markerEnd=\"url(#arrowhead-sm)\"\n opacity={0.6}\n stroke=\"#a78bfa\"\n strokeDasharray=\"6 4\"\n strokeWidth={1.5}\n />\n );\n })}\n\n {/* Nodes (group nodes render their own internal subgraph edges) */}\n {nodes.map((node) =>\n node.type === \"group\" ? (\n <GroupNode\n hovered={hoveredId === node.id}\n key={node.id}\n node={node}\n onClick={onNodeClick}\n onHover={setHoveredId}\n />\n ) : (\n <StepNode\n hovered={hoveredId === node.id}\n key={node.id}\n node={node}\n onClick={onNodeClick}\n onHover={setHoveredId}\n />\n ),\n )}\n </svg>\n );\n};\n","import React from \"react\";\nimport type { LayoutEdge } from \"./nurt-flow-chart-layout\";\n\nexport const FlowEdge: React.FC<{\n edge: LayoutEdge;\n}> = ({ edge }) => {\n const { bendPoints, x1, x2, y1, y2 } = edge;\n\n if (bendPoints && bendPoints.length > 0) {\n // Spline through bend points\n const points = [{ x: x1, y: y1 }, ...bendPoints, { x: x2, y: y2 }];\n const d = buildSplinePath(points);\n\n return (\n <path\n d={d}\n fill=\"none\"\n markerEnd=\"url(#arrowhead)\"\n stroke=\"#4b5563\"\n strokeWidth={1.5}\n />\n );\n }\n\n // Simple straight line or curve\n if (Math.abs(x1 - x2) < 2) {\n return (\n <line\n markerEnd=\"url(#arrowhead)\"\n stroke=\"#4b5563\"\n strokeWidth={1.5}\n x1={x1}\n x2={x2}\n y1={y1}\n y2={y2}\n />\n );\n }\n\n // Bezier curve\n const midY = (y1 + y2) / 2;\n const d = `M ${x1} ${y1} C ${x1} ${midY}, ${x2} ${midY}, ${x2} ${y2}`;\n\n return (\n <path\n d={d}\n fill=\"none\"\n markerEnd=\"url(#arrowhead)\"\n stroke=\"#4b5563\"\n strokeWidth={1.5}\n />\n );\n};\n\nfunction buildSplinePath(points: Array<{ x: number; y: number }>): string {\n if (points.length < 2) return \"\";\n if (points.length === 2) {\n return `M ${points[0]!.x} ${points[0]!.y} L ${points[1]!.x} ${points[1]!.y}`;\n }\n\n // Build a smooth path through all points\n let d = `M ${points[0]!.x} ${points[0]!.y}`;\n\n for (let i = 1; i < points.length; i++) {\n const prev = points[i - 1]!;\n const curr = points[i]!;\n const midY = (prev.y + curr.y) / 2;\n d += ` C ${prev.x} ${midY}, ${curr.x} ${midY}, ${curr.x} ${curr.y}`;\n }\n\n return d;\n}\n","import type {\n FlowSnapshot,\n FlowSnapshotGroup,\n FlowSnapshotStep,\n} from \"../snapshot.js\";\nimport ELK from \"elkjs/lib/elk.bundled.js\";\nimport type { ElkEdgeSection, ElkNode } from \"elkjs/lib/elk.bundled.js\";\n\n/* ── Layout Types ───────────────────────────────────────── */\n\nexport interface LayoutNode {\n groupName?: string;\n height: number;\n id: string;\n label: string;\n members?: LayoutMemberNode[];\n status: string;\n step?: FlowSnapshotStep;\n type: \"step\" | \"group\";\n width: number;\n x: number;\n y: number;\n}\n\nexport interface LayoutMemberNode {\n durationMs?: number;\n error?: string;\n height: number;\n name: string;\n status: string;\n subgraphEdges?: LayoutSubgraphEdge[];\n subgraphSteps?: LayoutSubgraphStep[];\n type: \"single\" | \"subgraph\";\n width: number;\n x: number;\n y: number;\n}\n\nexport interface LayoutSubgraphStep {\n durationMs?: number;\n height: number;\n name: string;\n status: string;\n width: number;\n x: number;\n y: number;\n}\n\nexport interface LayoutSubgraphEdge {\n bendPoints?: Array<{ x: number; y: number }>;\n memberName: string;\n x1: number;\n x2: number;\n y1: number;\n y2: number;\n}\n\nexport interface LayoutEdge {\n bendPoints?: Array<{ x: number; y: number }>;\n source: string;\n target: string;\n x1: number;\n x2: number;\n y1: number;\n y2: number;\n}\n\n/* ── Constants ──────────────────────────────────────────── */\n\nconst NODE_W = 180;\nconst NODE_H = 58;\nconst MEMBER_W = 160;\nconst MEMBER_H = 28;\nconst SUBGRAPH_STEP_W = 110;\nconst SUBGRAPH_STEP_H = 30;\n\nexport { MEMBER_H, MEMBER_W, NODE_H, NODE_W, SUBGRAPH_STEP_H, SUBGRAPH_STEP_W };\n\n/* ── ELK Instance ───────────────────────────────────────── */\n\nconst elk = new ELK();\n\n/* ── Layout Algorithm ───────────────────────────────────── */\n\nexport interface ExternalRefEdge {\n sourceStepName: string;\n targetMemberName: string;\n x1: number;\n x2: number;\n y1: number;\n y2: number;\n}\n\nexport interface LayoutResult {\n edges: LayoutEdge[];\n externalRefEdges: ExternalRefEdge[];\n height: number;\n nodes: LayoutNode[];\n width: number;\n}\n\n/**\n * Computes a layered DAG layout using ELK.\n * Groups are compound nodes with member children.\n * Returns absolute coordinates for all elements.\n */\nexport async function layoutSnapshot(\n snapshot: FlowSnapshot,\n): Promise<LayoutResult> {\n const { groups, steps } = snapshot.flow;\n\n if (steps.length === 0 && groups.length === 0) {\n return { edges: [], externalRefEdges: [], height: 0, nodes: [], width: 0 };\n }\n\n const groupMap = new Map<string, FlowSnapshotGroup>();\n for (const g of groups) groupMap.set(g.name, g);\n\n // Build ELK graph\n const elkGraph = buildElkGraph(steps, groups, groupMap);\n const laid = await elk.layout(elkGraph);\n\n // Extract results\n return extractLayout(laid, steps, groupMap);\n}\n\n/* ── ELK Graph Construction ─────────────────────────────── */\n\nfunction buildElkGraph(\n steps: FlowSnapshotStep[],\n groups: FlowSnapshotGroup[],\n groupMap: Map<string, FlowSnapshotGroup>,\n): ElkNode {\n const allIds = new Set([\n ...steps.map((s) => s.name),\n ...groups.map((g) => g.name),\n ]);\n\n // Top-level children: steps + groups (as compound nodes)\n const children: ElkNode[] = [];\n\n for (const step of steps) {\n children.push({\n height: NODE_H,\n id: step.name,\n width: NODE_W,\n });\n }\n\n for (const g of groups) {\n const memberChildren: ElkNode[] = [];\n\n for (const m of g.members) {\n const memberId = `${g.name}/${m.name}`;\n\n if (\n m.type === \"subgraph\" &&\n m.subgraph &&\n m.subgraph.flow.steps.length > 0\n ) {\n // Subgraph member: compound node with sub-step children + internal edges\n const subSteps = m.subgraph.flow.steps;\n const subChildren: ElkNode[] = subSteps.map((s) => ({\n height: SUBGRAPH_STEP_H,\n id: `${memberId}/${s.name}`,\n width: SUBGRAPH_STEP_W,\n }));\n\n const subEdges: Array<{\n id: string;\n sources: string[];\n targets: string[];\n }> = [];\n let edgeIdx = 0;\n for (const s of subSteps) {\n for (const parent of s.parentNames) {\n subEdges.push({\n id: `pe-${memberId}-${edgeIdx++}`,\n sources: [`${memberId}/${parent}`],\n targets: [`${memberId}/${s.name}`],\n });\n }\n }\n\n memberChildren.push({\n children: subChildren,\n edges: subEdges,\n id: memberId,\n layoutOptions: {\n \"elk.algorithm\": \"layered\",\n \"elk.direction\": \"DOWN\",\n \"elk.edgeRouting\": \"SPLINES\",\n \"elk.layered.spacing.nodeNodeBetweenLayers\": \"30\",\n \"elk.padding\": \"[top=24,left=8,bottom=8,right=8]\",\n \"elk.spacing.nodeNode\": \"12\",\n },\n });\n } else {\n // Single member: simple node\n memberChildren.push({\n height: MEMBER_H,\n id: memberId,\n width: MEMBER_W,\n });\n }\n }\n\n const isEmpty = memberChildren.length === 0;\n\n children.push({\n children: memberChildren,\n // Empty groups get a minimum size so they render visibly\n ...(isEmpty ? { height: NODE_H, width: NODE_W } : {}),\n id: g.name,\n layoutOptions: {\n \"elk.padding\": \"[top=36,left=10,bottom=10,right=10]\",\n },\n });\n }\n\n // Build edges\n const edges: Array<{ id: string; sources: string[]; targets: string[] }> = [];\n let edgeId = 0;\n\n for (const step of steps) {\n for (const parent of step.parentNames) {\n if (allIds.has(parent)) {\n edges.push({\n id: `e${edgeId++}`,\n sources: [parent],\n targets: [step.name],\n });\n }\n }\n }\n\n for (const g of groups) {\n for (const dep of g.dependsOn) {\n if (allIds.has(dep)) {\n edges.push({\n id: `e${edgeId++}`,\n sources: [dep],\n targets: [g.name],\n });\n }\n }\n }\n\n return {\n children,\n edges,\n id: \"root\",\n layoutOptions: {\n \"elk.algorithm\": \"layered\",\n \"elk.direction\": \"DOWN\",\n \"elk.edgeRouting\": \"SPLINES\",\n \"elk.layered.spacing.edgeNodeBetweenLayers\": \"30\",\n \"elk.layered.spacing.nodeNodeBetweenLayers\": \"50\",\n \"elk.spacing.nodeNode\": \"20\",\n },\n };\n}\n\n/* ── Extract Layout Results ─────────────────────────────── */\n\nfunction extractLayout(\n laid: ElkNode,\n steps: FlowSnapshotStep[],\n groupMap: Map<string, FlowSnapshotGroup>,\n): LayoutResult {\n const nodes: LayoutNode[] = [];\n const edges: LayoutEdge[] = [];\n const stepMap = new Map(steps.map((s) => [s.name, s]));\n\n for (const child of laid.children ?? []) {\n const group = groupMap.get(child.id);\n const step = stepMap.get(child.id);\n const cx = child.x ?? 0;\n const cy = child.y ?? 0;\n const cw = child.width ?? NODE_W;\n const ch = child.height ?? NODE_H;\n\n if (group) {\n // Compound node — extract member positions (relative to group)\n const members: LayoutMemberNode[] = (child.children ?? []).map(\n (memberElk) => {\n const memberName = memberElk.id.split(\"/\").at(-1) ?? memberElk.id;\n const memberData = group.members.find((m) => m.name === memberName);\n const mx = (memberElk.x ?? 0) + cx;\n const my = (memberElk.y ?? 0) + cy;\n\n // Extract subgraph sub-steps if this is a compound member\n let subgraphSteps: LayoutSubgraphStep[] | undefined;\n let memberSubgraphEdges: LayoutSubgraphEdge[] | undefined;\n if (\n memberData?.type === \"subgraph\" &&\n memberData.subgraph &&\n memberElk.children &&\n memberElk.children.length > 0\n ) {\n const subSteps = memberData.subgraph.flow.steps;\n subgraphSteps = memberElk.children.map((subElk) => {\n const subName = subElk.id.split(\"/\").at(-1) ?? subElk.id;\n const subData = subSteps.find((s) => s.name === subName);\n return {\n durationMs: subData?.durationMs,\n height: subElk.height ?? SUBGRAPH_STEP_H,\n name: subName,\n status: subData?.status ?? \"pending\",\n width: subElk.width ?? SUBGRAPH_STEP_W,\n x: (subElk.x ?? 0) + mx,\n y: (subElk.y ?? 0) + my,\n };\n });\n\n // Collect subgraph internal edges on the member\n memberSubgraphEdges = [];\n for (const pEdge of memberElk.edges ?? []) {\n const sections = (pEdge.sections ?? []) as ElkEdgeSection[];\n if (sections.length > 0) {\n const sec = sections[0]!;\n memberSubgraphEdges.push({\n bendPoints: sec.bendPoints?.map((bp) => ({\n x: bp.x + mx,\n y: bp.y + my,\n })),\n memberName,\n x1: sec.startPoint.x + mx,\n x2: sec.endPoint.x + mx,\n y1: sec.startPoint.y + my,\n y2: sec.endPoint.y + my,\n });\n }\n }\n }\n\n return {\n durationMs: memberData?.durationMs,\n error: memberData?.error,\n height: memberElk.height ?? MEMBER_H,\n name: memberName,\n status: memberData?.status ?? \"pending\",\n subgraphEdges: memberSubgraphEdges,\n subgraphSteps,\n type: memberData?.type ?? \"single\",\n width: memberElk.width ?? MEMBER_W,\n x: mx,\n y: my,\n };\n },\n );\n\n nodes.push({\n groupName: group.name,\n height: ch,\n id: child.id,\n label: group.name,\n members,\n status: deriveGroupStatus(group),\n type: \"group\",\n width: cw,\n x: cx,\n y: cy,\n });\n } else if (step) {\n nodes.push({\n height: ch,\n id: child.id,\n label: step.name,\n status: step.status,\n step,\n type: \"step\",\n width: cw,\n x: cx,\n y: cy,\n });\n }\n }\n\n // Extract edges with bend points\n for (const elkEdge of laid.edges ?? []) {\n const source = elkEdge.sources?.[0] ?? \"\";\n const target = elkEdge.targets?.[0] ?? \"\";\n const sections = (elkEdge.sections ?? []) as ElkEdgeSection[];\n\n if (sections.length > 0) {\n const section = sections[0]!;\n const bendPoints = section.bendPoints?.map((bp) => ({\n x: bp.x,\n y: bp.y,\n }));\n\n edges.push({\n bendPoints,\n source,\n target,\n x1: section.startPoint.x,\n x2: section.endPoint.x,\n y1: section.startPoint.y,\n y2: section.endPoint.y,\n });\n } else {\n // Fallback: connect center-bottom to center-top\n const srcNode = nodes.find((n) => n.id === source);\n const tgtNode = nodes.find((n) => n.id === target);\n if (srcNode && tgtNode) {\n edges.push({\n source,\n target,\n x1: srcNode.x + srcNode.width / 2,\n x2: tgtNode.x + tgtNode.width / 2,\n y1: srcNode.y + srcNode.height,\n y2: tgtNode.y,\n });\n }\n }\n }\n\n // Compute external reference edges (cross-boundary deps)\n const externalRefEdges: ExternalRefEdge[] = [];\n const nodeMap = new Map(nodes.map((n) => [n.id, n]));\n for (const node of nodes) {\n if (node.type !== \"group\" || !node.members) continue;\n for (const member of node.members) {\n if (member.type !== \"subgraph\") continue;\n // Find the snapshot member to get externalDeps\n const group = groupMap.get(node.id);\n const memberData = group?.members.find((m) => m.name === member.name);\n if (!memberData?.externalDeps) continue;\n\n for (const [, parentStepName] of Object.entries(\n memberData.externalDeps,\n )) {\n const srcNode = nodeMap.get(parentStepName);\n if (srcNode) {\n externalRefEdges.push({\n sourceStepName: parentStepName,\n targetMemberName: member.name,\n x1: srcNode.x + srcNode.width / 2,\n x2: member.x + member.width / 2,\n y1: srcNode.y + srcNode.height,\n y2: member.y,\n });\n }\n }\n }\n }\n\n const totalWidth = laid.width ?? 900;\n const totalHeight = laid.height ?? 400;\n\n return {\n edges,\n externalRefEdges,\n height: Math.max(400, totalHeight + 40),\n nodes,\n width: Math.max(900, totalWidth + 40),\n };\n}\n\nfunction deriveGroupStatus(group: FlowSnapshotGroup): string {\n if (group.members.length === 0) return \"pending\";\n if (group.members.some((m) => m.status === \"running\")) return \"running\";\n if (group.members.every((m) => m.status === \"success\")) return \"success\";\n if (\n group.members.every((m) => m.status === \"success\" || m.status === \"error\")\n )\n return \"error\";\n return \"pending\";\n}\n","import type { StepStatus } from \"../types.js\";\n\nexport const formatDuration = (ms: number): string => {\n if (ms < 1000) return `${ms}ms`;\n return `${(ms / 1000).toFixed(1)}s`;\n};\n\nexport const statusIndicator = (status: StepStatus | string): string => {\n switch (status) {\n case \"success\":\n return \"\\u2713\";\n case \"error\":\n return \"\\u2717\";\n case \"running\":\n return \"\\u25CB\";\n case \"skipped\":\n return \"\\u2014\";\n case \"pending\":\n return \"\\u2022\";\n default:\n return \"\";\n }\n};\n\nexport const getNodeStyle = (\n status: string,\n hovered: boolean,\n): { fill: string; opacity: number; stroke: string; strokeWidth: number } => {\n switch (status) {\n case \"running\":\n return {\n fill: \"#1e3a5f\",\n opacity: 1,\n stroke: hovered ? \"#60a5fa\" : \"#3b82f6\",\n strokeWidth: hovered ? 2 : 1.5,\n };\n case \"pending\":\n return {\n fill: \"#1f2937\",\n opacity: 0.5,\n stroke: \"#374151\",\n strokeWidth: 1,\n };\n case \"error\":\n return {\n fill: \"#3b1c1c\",\n opacity: 1,\n stroke: hovered ? \"#f87171\" : \"#ef4444\",\n strokeWidth: hovered ? 2 : 1,\n };\n case \"skipped\":\n return {\n fill: \"#1f2937\",\n opacity: 0.6,\n stroke: \"#4b5563\",\n strokeWidth: 1,\n };\n default:\n // success\n return {\n fill: \"#374151\",\n opacity: 1,\n stroke: hovered ? \"#9ca3af\" : \"#6b7280\",\n strokeWidth: hovered ? 2 : 1,\n };\n }\n};\n\nexport const getMemberStyle = (\n status: string,\n): { fill: string; stroke: string } => {\n switch (status) {\n case \"success\":\n return { fill: \"#065f46\", stroke: \"#10b981\" };\n case \"error\":\n return { fill: \"#7f1d1d\", stroke: \"#ef4444\" };\n case \"running\":\n return { fill: \"#1e3a5f\", stroke: \"#3b82f6\" };\n default:\n return { fill: \"#374151\", stroke: \"#6b7280\" };\n }\n};\n\nexport const statusTextColor = (status: string): string => {\n switch (status) {\n case \"success\":\n return \"#34d399\";\n case \"error\":\n return \"#f87171\";\n case \"running\":\n return \"#60a5fa\";\n case \"skipped\":\n return \"#6b7280\";\n default:\n return \"#9ca3af\";\n }\n};\n","import React from \"react\";\nimport type {\n LayoutMemberNode,\n LayoutNode,\n LayoutSubgraphEdge,\n} from \"./nurt-flow-chart-layout\";\nimport {\n formatDuration,\n getMemberStyle,\n getNodeStyle,\n statusIndicator,\n statusTextColor,\n} from \"./nurt-flow-chart-utils\";\n\n/* ── Step Node ──────────────────────────────────────────── */\n\nexport const StepNode: React.FC<{\n hovered: boolean;\n node: LayoutNode;\n onClick?: (name: string) => void;\n onHover: (id: string | null) => void;\n}> = ({ hovered, node, onClick, onHover }) => {\n // ELK gives us top-left (x, y) coordinates\n const rectX = node.x;\n const rectY = node.y;\n const centerX = node.x + node.width / 2;\n const centerY = node.y + node.height / 2;\n const style = getNodeStyle(node.status, hovered);\n const step = node.step;\n const isClickable = node.status !== \"pending\" && node.status !== \"running\";\n\n let durationText = \"\";\n if (step?.status === \"running\") durationText = \"running\\u2026\";\n else if (step?.durationMs && step.durationMs > 0)\n durationText = formatDuration(step.durationMs);\n\n const hasSubline = durationText || step?.terminal;\n\n return (\n <g\n className={node.status === \"running\" ? \"node-running\" : undefined}\n onClick={() => isClickable && onClick?.(node.id)}\n onMouseEnter={() => onHover(node.id)}\n onMouseLeave={() => onHover(null)}\n style={{ cursor: isClickable ? \"pointer\" : \"default\" }}\n >\n <rect\n fill={style.fill}\n height={node.height}\n opacity={style.opacity}\n rx={6}\n stroke={style.stroke}\n strokeDasharray={node.status === \"skipped\" ? \"4 3\" : undefined}\n strokeWidth={style.strokeWidth}\n width={node.width}\n x={rectX}\n y={rectY}\n />\n <text\n dominantBaseline=\"central\"\n fill={node.status === \"pending\" ? \"#6b7280\" : \"#d1d5db\"}\n fontSize={11}\n opacity={style.opacity}\n textAnchor=\"middle\"\n x={centerX}\n y={centerY - (hasSubline ? 8 : 0)}\n >\n {statusIndicator(node.status)} {node.label}\n </text>\n {durationText && (\n <text\n dominantBaseline=\"central\"\n fill={statusTextColor(node.status)}\n fontSize={10}\n opacity={style.opacity}\n textAnchor=\"middle\"\n x={centerX}\n y={centerY + 10}\n >\n {durationText}\n {step?.terminal ? \" \\u25C6\" : \"\"}\n </text>\n )}\n {!durationText && step?.terminal && (\n <text\n dominantBaseline=\"central\"\n fill=\"#9ca3af\"\n fontSize={9}\n opacity={style.opacity}\n textAnchor=\"middle\"\n x={centerX}\n y={centerY + 10}\n >\n terminal {\"\\u25C6\"}\n </text>\n )}\n </g>\n );\n};\n\n/* ── Group Node ─────────────────────────────────────────── */\n\nexport const GroupNode: React.FC<{\n hovered: boolean;\n node: LayoutNode;\n onClick?: (name: string) => void;\n onHover: (id: string | null) => void;\n}> = ({ hovered, node, onClick, onHover }) => {\n // ELK gives us top-left (x, y) coordinates\n const rectX = node.x;\n const rectY = node.y;\n const centerX = node.x + node.width / 2;\n const centerY = node.y + node.height / 2;\n const style = getNodeStyle(node.status, hovered);\n const isEmpty = !node.members || node.members.length === 0;\n\n return (\n <g\n onMouseEnter={() => onHover(node.id)}\n onMouseLeave={() => onHover(null)}\n style={{ cursor: \"pointer\" }}\n >\n {/* Group container — clickable to show group details */}\n <rect\n fill={isEmpty ? \"none\" : style.fill}\n height={node.height}\n onClick={() => onClick?.(node.id)}\n opacity={isEmpty ? 0.4 : style.opacity}\n rx={8}\n stroke={isEmpty ? \"#4b5563\" : style.stroke}\n strokeDasharray={isEmpty ? \"4 4\" : \"6 3\"}\n strokeWidth={style.strokeWidth}\n width={node.width}\n x={rectX}\n y={rectY}\n />\n\n {isEmpty ? (\n <>\n {/* Empty group: icon + label */}\n <text\n dominantBaseline=\"central\"\n fill=\"#6b7280\"\n fontSize={16}\n opacity={0.5}\n textAnchor=\"middle\"\n x={centerX}\n y={centerY - 8}\n >\n …\n </text>\n <text\n dominantBaseline=\"central\"\n fill=\"#6b7280\"\n fontSize={9}\n opacity={0.5}\n textAnchor=\"middle\"\n x={centerX}\n y={centerY + 10}\n >\n {node.label}\n </text>\n </>\n ) : (\n <>\n {/* Group label */}\n <text\n dominantBaseline=\"central\"\n fill=\"#9ca3af\"\n fontSize={10}\n fontWeight=\"bold\"\n textAnchor=\"middle\"\n x={centerX}\n y={rectY + 18}\n >\n {node.label}\n </text>\n\n {/* Members — positioned with absolute coordinates from ELK */}\n {node.members?.map((member) => (\n <MemberNode key={member.name} member={member} onClick={onClick} />\n ))}\n </>\n )}\n </g>\n );\n};\n\n/* ── Member Node (inside group) ─────────────────────────── */\n\nconst MemberNode: React.FC<{\n member: LayoutMemberNode;\n onClick?: (name: string) => void;\n}> = ({ member, onClick }) => {\n const mStyle = getMemberStyle(member.status);\n const hasSubgraphSteps =\n member.type === \"subgraph\" &&\n member.subgraphSteps &&\n member.subgraphSteps.length > 0;\n\n if (hasSubgraphSteps) {\n // Subgraph member: render as container with internal edges + sub-step nodes\n return (\n <g\n className={member.status === \"running\" ? \"node-running\" : undefined}\n onClick={(e) => {\n e.stopPropagation();\n onClick?.(member.name);\n }}\n style={{ cursor: \"pointer\" }}\n >\n {/* Subgraph container */}\n <rect\n fill={mStyle.fill}\n height={member.height}\n opacity={0.6}\n rx={4}\n stroke={mStyle.stroke}\n strokeDasharray=\"3 2\"\n strokeWidth={0.5}\n width={member.width}\n x={member.x}\n y={member.y}\n />\n {/* Subgraph label + timing */}\n <text\n dominantBaseline=\"central\"\n fill=\"#9ca3af\"\n fontSize={8}\n textAnchor=\"middle\"\n x={member.x + member.width / 2}\n y={member.y + 10}\n >\n {member.name}\n {member.durationMs && member.durationMs > 0\n ? ` (${formatDuration(member.durationMs)})`\n : member.status === \"running\"\n ? \" (running\\u2026)\"\n : \"\"}\n </text>\n {/* Internal edges (render before nodes so nodes appear on top) */}\n {member.subgraphEdges?.map((se, i) => (\n <SubgraphInternalEdge edge={se} key={`${member.name}-e${i}`} />\n ))}\n {/* Sub-step nodes */}\n {member.subgraphSteps!.map((ps) => (\n <SubgraphStepNode key={ps.name} step={ps} />\n ))}\n </g>\n );\n }\n\n // Single member: simple node with optional timing\n const centerX = member.x + member.width / 2;\n const centerY = member.y + member.height / 2;\n\n let memberDurationText = \"\";\n if (member.status === \"running\") memberDurationText = \"running\\u2026\";\n else if (member.durationMs && member.durationMs > 0)\n memberDurationText = formatDuration(member.durationMs);\n\n return (\n <g\n className={member.status === \"running\" ? \"node-running\" : undefined}\n onClick={(e) => {\n e.stopPropagation();\n onClick?.(member.name);\n }}\n style={{ cursor: \"pointer\" }}\n >\n <rect\n fill={mStyle.fill}\n height={member.height}\n rx={4}\n stroke={mStyle.stroke}\n strokeWidth={0.5}\n width={member.width}\n x={member.x}\n y={member.y}\n />\n <text\n dominantBaseline=\"central\"\n fill=\"#d1d5db\"\n fontSize={9}\n textAnchor=\"middle\"\n x={centerX}\n y={memberDurationText ? centerY - 5 : centerY}\n >\n {statusIndicator(member.status)} {member.name}\n </text>\n {memberDurationText && (\n <text\n dominantBaseline=\"central\"\n fill={statusTextColor(member.status)}\n fontSize={8}\n textAnchor=\"middle\"\n x={centerX}\n y={centerY + 7}\n >\n {memberDurationText}\n </text>\n )}\n </g>\n );\n};\n\n/* ── Subgraph Step Node (inside subgraph member) ────────── */\n\nconst SubgraphStepNode: React.FC<{\n step: import(\"./nurt-flow-chart-layout\").LayoutSubgraphStep;\n}> = ({ step }) => {\n const style = getNodeStyle(step.status, false);\n const centerX = step.x + step.width / 2;\n const centerY = step.y + step.height / 2;\n\n let stepDurationText = \"\";\n if (step.status === \"running\") stepDurationText = \"running\\u2026\";\n else if (step.durationMs && step.durationMs > 0)\n stepDurationText = formatDuration(step.durationMs);\n\n return (\n <g className={step.status === \"running\" ? \"node-running\" : undefined}>\n <rect\n fill={style.fill}\n height={step.height}\n opacity={style.opacity}\n rx={4}\n stroke={style.stroke}\n strokeDasharray={step.status === \"skipped\" ? \"3 2\" : undefined}\n strokeWidth={0.75}\n width={step.width}\n x={step.x}\n y={step.y}\n />\n <text\n dominantBaseline=\"central\"\n fill={step.status === \"pending\" ? \"#6b7280\" : \"#d1d5db\"}\n fontSize={9}\n opacity={style.opacity}\n textAnchor=\"middle\"\n x={centerX}\n y={stepDurationText ? centerY - 5 : centerY}\n >\n {statusIndicator(step.status)} {step.name}\n </text>\n {stepDurationText && (\n <text\n dominantBaseline=\"central\"\n fill={statusTextColor(step.status)}\n fontSize={8}\n opacity={style.opacity}\n textAnchor=\"middle\"\n x={centerX}\n y={centerY + 7}\n >\n {stepDurationText}\n </text>\n )}\n </g>\n );\n};\n\n/* ── Subgraph Internal Edge ─────────────────────────────── */\n\nconst SubgraphInternalEdge: React.FC<{ edge: LayoutSubgraphEdge }> = ({\n edge,\n}) => {\n const { bendPoints, x1, x2, y1, y2 } = edge;\n\n if (bendPoints && bendPoints.length > 0) {\n const points = [{ x: x1, y: y1 }, ...bendPoints, { x: x2, y: y2 }];\n let d = `M ${points[0]!.x} ${points[0]!.y}`;\n for (let i = 1; i < points.length; i++) {\n const prev = points[i - 1]!;\n const curr = points[i]!;\n const midY = (prev.y + curr.y) / 2;\n d += ` C ${prev.x} ${midY}, ${curr.x} ${midY}, ${curr.x} ${curr.y}`;\n }\n\n return (\n <path\n d={d}\n fill=\"none\"\n markerEnd=\"url(#arrowhead-sm)\"\n stroke=\"#6b7280\"\n strokeWidth={1}\n />\n );\n }\n\n return (\n <line\n markerEnd=\"url(#arrowhead-sm)\"\n stroke=\"#6b7280\"\n strokeWidth={1}\n x1={x1}\n x2={x2}\n y1={y1}\n y2={y2}\n />\n );\n};\n","import type { FlowSnapshot } from \"../snapshot.js\";\nimport React, { useCallback, useEffect, useState } from \"react\";\nimport { NurtFlowChart } from \"./nurt-flow-chart\";\nimport { NurtStepDetailPanel } from \"./nurt-step-detail-panel\";\n\nexport interface NurtFlowChartWithPanelProps {\n className?: string;\n snapshot: FlowSnapshot;\n}\n\nexport const NurtFlowChartWithPanel: React.FC<NurtFlowChartWithPanelProps> = ({\n className,\n snapshot,\n}) => {\n const [selectedNode, setSelectedNode] = useState<string | null>(null);\n\n const handleNodeClick = useCallback((name: string) => {\n setSelectedNode((prev) => (prev === name ? null : name));\n }, []);\n\n const handleClose = useCallback(() => {\n setSelectedNode(null);\n }, []);\n\n const handleNavigate = useCallback((name: string) => {\n setSelectedNode(name);\n }, []);\n\n // Close on Escape\n useEffect(() => {\n if (!selectedNode) return;\n const handleKey = (e: KeyboardEvent): void => {\n if (e.key === \"Escape\") setSelectedNode(null);\n };\n document.addEventListener(\"keydown\", handleKey);\n return () => document.removeEventListener(\"keydown\", handleKey);\n }, [selectedNode]);\n\n const isOpen = selectedNode !== null;\n\n return (\n <div className={`flex overflow-hidden ${className ?? \"\"}`}>\n {/* Graph — transitions when panel opens/closes */}\n <div\n className=\"min-w-0 transition-all duration-200 ease-out\"\n style={{ flex: isOpen ? \"1 1 0%\" : \"1 1 100%\" }}\n >\n <NurtFlowChart onNodeClick={handleNodeClick} snapshot={snapshot} />\n </div>\n\n {/* Detail Panel — always in DOM, animated width */}\n <div\n className=\"shrink-0 overflow-hidden border-gray-700 bg-gray-900 transition-all duration-200 ease-out\"\n style={{\n borderLeftWidth: isOpen ? 1 : 0,\n opacity: isOpen ? 1 : 0,\n width: isOpen ? 320 : 0,\n }}\n >\n {selectedNode && (\n <div className=\"h-full w-80\">\n <NurtStepDetailPanel\n onClose={handleClose}\n onNavigate={handleNavigate}\n selectedNode={selectedNode}\n snapshot={snapshot}\n />\n </div>\n )}\n </div>\n </div>\n );\n};\n","import type {\n FlowSnapshot,\n FlowSnapshotGroup,\n FlowSnapshotGroupMember,\n FlowSnapshotStep,\n} from \"../snapshot.js\";\nimport React from \"react\";\nimport { formatDuration, statusIndicator } from \"./nurt-flow-chart-utils\";\n\n/* ── Status Dot ─────────────────────────────────────────── */\n\nconst STATUS_DOT: Record<string, string> = {\n error: \"bg-red-500\",\n pending: \"bg-gray-400\",\n running: \"bg-blue-500 animate-pulse\",\n skipped: \"bg-gray-400\",\n success: \"bg-green-500\",\n};\n\nconst StatusDot: React.FC<{ status: string }> = ({ status }) => (\n <span\n className={`inline-block h-2 w-2 rounded-full ${STATUS_DOT[status] ?? \"bg-gray-400\"}`}\n />\n);\n\n/* ── Props ──────────────────────────────────────────────── */\n\nexport interface NurtStepDetailPanelProps {\n onClose: () => void;\n onNavigate?: (nodeName: string) => void;\n selectedNode: string;\n snapshot: FlowSnapshot;\n}\n\n/* ── Panel ──────────────────────────────────────────────── */\n\nexport const NurtStepDetailPanel: React.FC<NurtStepDetailPanelProps> = ({\n onClose,\n onNavigate,\n selectedNode,\n snapshot,\n}) => {\n // Find the selected node — could be a step, a group, a group member, or a subgraph sub-step\n const step = snapshot.flow.steps.find((s) => s.name === selectedNode);\n const groupData = snapshot.flow.groups.find((g) => g.name === selectedNode);\n const member = findMember(snapshot, selectedNode);\n const subgraphStep = findSubgraphStep(snapshot, selectedNode);\n\n const status =\n step?.status ??\n subgraphStep?.step.status ??\n member?.status ??\n deriveGroupStatus(groupData) ??\n \"pending\";\n\n if (!step && !member && !groupData && !subgraphStep) {\n return (\n <div className=\"flex h-full items-center justify-center text-sm text-gray-500\">\n Node not found\n </div>\n );\n }\n\n return (\n <div className=\"flex h-full flex-col overflow-hidden\">\n {/* Header */}\n <div className=\"flex items-center justify-between border-b border-gray-700 px-4 py-3\">\n <div className=\"flex items-center gap-2\">\n <StatusDot status={status} />\n <span className=\"text-sm font-medium text-gray-200\">\n {selectedNode}\n </span>\n {groupData && (\n <span className=\"rounded bg-gray-700 px-1.5 py-0.5 text-xs text-gray-400\">\n group\n </span>\n )}\n {member?.type === \"subgraph\" && (\n <span className=\"rounded bg-gray-700 px-1.5 py-0.5 text-xs text-gray-400\">\n subgraph\n </span>\n )}\n {subgraphStep && (\n <span className=\"rounded bg-gray-700 px-1.5 py-0.5 text-xs text-gray-400\">\n {subgraphStep.memberName}\n </span>\n )}\n </div>\n <button\n className=\"rounded px-2 py-1 text-sm text-gray-400 hover:bg-gray-700 hover:text-gray-200\"\n onClick={onClose}\n >\n ×\n </button>\n </div>\n\n {/* Content */}\n <div className=\"flex-1 overflow-y-auto px-4 py-3\">\n {step && <StepDetails onNavigate={onNavigate} step={step} />}\n {!step && groupData && (\n <GroupDetails group={groupData} onNavigate={onNavigate} />\n )}\n {!step && !groupData && !subgraphStep && member && (\n <MemberDetails member={member} onNavigate={onNavigate} />\n )}\n {subgraphStep && (\n <SubgraphStepDetails\n memberName={subgraphStep.memberName}\n onNavigate={onNavigate}\n step={subgraphStep.step}\n />\n )}\n </div>\n </div>\n );\n};\n\n/* ── Step Details ───────────────────────────────────────── */\n\nconst StepDetails: React.FC<{\n onNavigate?: (name: string) => void;\n step: FlowSnapshotStep;\n}> = ({ onNavigate, step }) => (\n <div className=\"flex flex-col gap-4\">\n {/* Status & Timing */}\n <Section title=\"Status\">\n <Row label=\"Status\">\n <span className=\"font-mono\">\n {statusIndicator(step.status)} {step.status}\n </span>\n </Row>\n {step.durationMs != null && step.durationMs > 0 && (\n <Row label=\"Duration\">\n <span className=\"font-mono\">{formatDuration(step.durationMs)}</span>\n </Row>\n )}\n {step.startedAt != null && (\n <Row label=\"Started\">{formatTime(step.startedAt)}</Row>\n )}\n {step.completedAt != null && (\n <Row label=\"Completed\">{formatTime(step.completedAt)}</Row>\n )}\n {step.terminal && (\n <Row label=\"Terminal\">\n <span className=\"text-yellow-400\">◆ yes</span>\n </Row>\n )}\n {step.allowFailures && (\n <Row label=\"Allow failures\">\n <span className=\"text-blue-400\">yes</span>\n </Row>\n )}\n </Section>\n\n {/* Parents */}\n {step.parentNames.length > 0 && (\n <Section title=\"Parents\">\n <div className=\"flex flex-wrap gap-1\">\n {step.parentNames.map((p) => (\n <button\n className=\"rounded bg-gray-700 px-2 py-0.5 font-mono text-xs text-gray-300 hover:bg-gray-600\"\n key={p}\n onClick={() => onNavigate?.(p)}\n >\n {p}\n </button>\n ))}\n </div>\n </Section>\n )}\n\n {/* Error */}\n {step.error && (\n <Section title=\"Error\">\n <pre className=\"overflow-x-auto whitespace-pre-wrap rounded bg-red-950 p-2 font-mono text-xs text-red-300\">\n {step.error}\n </pre>\n </Section>\n )}\n\n {/* Output */}\n {step.output != null && (\n <Section title=\"Output\">\n <JsonBlock data={step.output} />\n </Section>\n )}\n\n {step.output == null && step.status === \"success\" && (\n <Section title=\"Output\">\n <span className=\"text-xs text-gray-500\">No output data</span>\n </Section>\n )}\n </div>\n);\n\n/* ── Group Details ──────────────────────────────────────── */\n\nconst GroupDetails: React.FC<{\n group: FlowSnapshotGroup;\n onNavigate?: (name: string) => void;\n}> = ({ group, onNavigate }) => (\n <div className=\"flex flex-col gap-4\">\n <Section title=\"Group Info\">\n <Row label=\"Sealed\">{group.sealed ? \"yes\" : \"no\"}</Row>\n <Row label=\"Members\">{group.members.length}</Row>\n </Section>\n\n {group.dependsOn.length > 0 && (\n <Section title=\"Depends On\">\n <div className=\"flex flex-wrap gap-1\">\n {group.dependsOn.map((d) => (\n <button\n className=\"rounded bg-gray-700 px-2 py-0.5 font-mono text-xs text-gray-300 hover:bg-gray-600\"\n key={d}\n onClick={() => onNavigate?.(d)}\n >\n {d}\n </button>\n ))}\n </div>\n </Section>\n )}\n\n {group.members.length > 0 && (\n <Section title=\"Members\">\n <div className=\"flex flex-col gap-1\">\n {group.members.map((m) => (\n <button\n className=\"flex items-center justify-between rounded bg-gray-800 px-2 py-1.5 text-left hover:bg-gray-750\"\n key={m.name}\n onClick={() => onNavigate?.(m.name)}\n >\n <div className=\"flex items-center gap-2\">\n <StatusDot status={m.status} />\n <span className=\"font-mono text-xs text-gray-300\">\n {m.name}\n </span>\n {m.type === \"subgraph\" && (\n <span className=\"rounded bg-gray-700 px-1 py-0.5 text-xs text-gray-500\">\n subgraph\n </span>\n )}\n </div>\n <div className=\"flex items-center gap-2\">\n {m.error && (\n <span className=\"text-xs text-red-400\">error</span>\n )}\n {m.durationMs != null && m.durationMs > 0 && (\n <span className=\"font-mono text-xs text-gray-500\">\n {formatDuration(m.durationMs)}\n </span>\n )}\n </div>\n </button>\n ))}\n </div>\n </Section>\n )}\n </div>\n);\n\n/* ── Member Details ─────────────────────────────────────── */\n\nconst MemberDetails: React.FC<{\n member: FlowSnapshotGroupMember;\n onNavigate?: (name: string) => void;\n}> = ({ member, onNavigate }) => (\n <div className=\"flex flex-col gap-4\">\n <Section title=\"Status\">\n <Row label=\"Status\">\n <span className=\"font-mono\">\n {statusIndicator(member.status)} {member.status}\n </span>\n </Row>\n <Row label=\"Type\">\n <span className=\"font-mono\">{member.type}</span>\n </Row>\n {member.durationMs != null && member.durationMs > 0 && (\n <Row label=\"Duration\">\n <span className=\"font-mono\">\n {formatDuration(member.durationMs)}\n </span>\n </Row>\n )}\n {member.startedAt != null && (\n <Row label=\"Started\">{formatTime(member.startedAt)}</Row>\n )}\n {member.completedAt != null && (\n <Row label=\"Completed\">{formatTime(member.completedAt)}</Row>\n )}\n </Section>\n\n {member.error && (\n <Section title=\"Error\">\n <pre className=\"overflow-x-auto whitespace-pre-wrap rounded bg-red-950 p-2 font-mono text-xs text-red-300\">\n {member.error}\n </pre>\n </Section>\n )}\n\n {member.output != null && (\n <Section title=\"Output\">\n <JsonBlock data={member.output} />\n </Section>\n )}\n\n {/* Subgraph steps summary */}\n {member.subgraph && member.subgraph.flow.steps.length > 0 && (\n <Section title=\"Subgraph Steps\">\n <div className=\"flex flex-col gap-1\">\n {member.subgraph.flow.steps.map((s) => (\n <button\n className=\"block w-full text-left\"\n key={s.name}\n onClick={() => onNavigate?.(s.name)}\n >\n <div className=\"flex items-center justify-between rounded bg-gray-800 px-2 py-1.5 hover:bg-gray-750\">\n <div className=\"flex items-center gap-2\">\n <StatusDot status={s.status} />\n <span className=\"font-mono text-xs text-gray-300\">\n {s.name}\n </span>\n </div>\n <div className=\"flex items-center gap-2\">\n {s.error && (\n <span className=\"text-xs text-red-400\">error</span>\n )}\n {s.durationMs != null && s.durationMs > 0 && (\n <span className=\"font-mono text-xs text-gray-500\">\n {formatDuration(s.durationMs)}\n </span>\n )}\n </div>\n </div>\n </button>\n ))}\n </div>\n </Section>\n )}\n </div>\n);\n\n/* ── Subgraph Step Details ──────────────────────────────── */\n\nconst SubgraphStepDetails: React.FC<{\n memberName: string;\n onNavigate?: (name: string) => void;\n step: FlowSnapshotStep;\n}> = ({ memberName, onNavigate, step }) => (\n <div className=\"flex flex-col gap-4\">\n <Section title=\"Status\">\n <Row label=\"Status\">\n <span className=\"font-mono\">\n {statusIndicator(step.status)} {step.status}\n </span>\n </Row>\n {step.durationMs != null && step.durationMs > 0 && (\n <Row label=\"Duration\">\n <span className=\"font-mono\">{formatDuration(step.durationMs)}</span>\n </Row>\n )}\n {step.startedAt != null && (\n <Row label=\"Started\">{formatTime(step.startedAt)}</Row>\n )}\n {step.completedAt != null && (\n <Row label=\"Completed\">{formatTime(step.completedAt)}</Row>\n )}\n </Section>\n\n {/* Back to parent member */}\n <Section title=\"Part of\">\n <button\n className=\"rounded bg-gray-700 px-2 py-0.5 font-mono text-xs text-gray-300 hover:bg-gray-600\"\n onClick={() => onNavigate?.(memberName)}\n >\n {memberName}\n </button>\n </Section>\n\n {/* Parents within the subgraph */}\n {step.parentNames.length > 0 && (\n <Section title=\"Parents\">\n <div className=\"flex flex-wrap gap-1\">\n {step.parentNames.map((p) => (\n <button\n className=\"rounded bg-gray-700 px-2 py-0.5 font-mono text-xs text-gray-300 hover:bg-gray-600\"\n key={p}\n onClick={() => onNavigate?.(p)}\n >\n {p}\n </button>\n ))}\n </div>\n </Section>\n )}\n\n {step.error && (\n <Section title=\"Error\">\n <pre className=\"overflow-x-auto whitespace-pre-wrap rounded bg-red-950 p-2 font-mono text-xs text-red-300\">\n {step.error}\n </pre>\n </Section>\n )}\n\n {step.output != null && (\n <Section title=\"Output\">\n <JsonBlock data={step.output} />\n </Section>\n )}\n\n {step.output == null && step.status === \"success\" && (\n <Section title=\"Output\">\n <span className=\"text-xs text-gray-500\">No output data</span>\n </Section>\n )}\n </div>\n);\n\n/* ── Shared UI Components ───────────────────────────────── */\n\nconst Section: React.FC<{\n children: React.ReactNode;\n title: string;\n}> = ({ children, title }) => (\n <div>\n <h3 className=\"mb-1.5 text-xs font-semibold uppercase tracking-wider text-gray-500\">\n {title}\n </h3>\n {children}\n </div>\n);\n\nconst Row: React.FC<{\n children: React.ReactNode;\n label: string;\n}> = ({ children, label }) => (\n <div className=\"flex items-center justify-between py-0.5 text-xs\">\n <span className=\"text-gray-500\">{label}</span>\n <span className=\"text-gray-300\">{children}</span>\n </div>\n);\n\nconst JsonBlock: React.FC<{ data: unknown }> = ({ data }) => (\n <pre className=\"max-h-64 overflow-auto whitespace-pre-wrap rounded bg-gray-800 p-2 font-mono text-xs text-gray-300\">\n {JSON.stringify(data, null, 2)}\n </pre>\n);\n\n/* ── Helpers ────────────────────────────────────────────── */\n\nfunction findMember(\n snapshot: FlowSnapshot,\n name: string,\n): FlowSnapshotGroupMember | undefined {\n for (const g of snapshot.flow.groups) {\n const m = g.members.find((m) => m.name === name);\n if (m) return m;\n }\n return undefined;\n}\n\nfunction findSubgraphStep(\n snapshot: FlowSnapshot,\n name: string,\n): { memberName: string; step: FlowSnapshotStep } | undefined {\n for (const g of snapshot.flow.groups) {\n for (const m of g.members) {\n if (m.subgraph) {\n const s = m.subgraph.flow.steps.find((s) => s.name === name);\n if (s) return { memberName: m.name, step: s };\n }\n }\n }\n return undefined;\n}\n\nfunction formatTime(ts: number): string {\n return new Date(ts).toLocaleTimeString();\n}\n\nfunction deriveGroupStatus(\n group: FlowSnapshotGroup | undefined,\n): string | undefined {\n if (!group) return undefined;\n if (group.members.length === 0) return \"pending\";\n if (group.members.some((m) => m.status === \"running\")) return \"running\";\n if (group.members.every((m) => m.status === \"success\")) return \"success\";\n if (\n group.members.every((m) => m.status === \"success\" || m.status === \"error\")\n )\n return \"error\";\n return \"pending\";\n}\n"],"mappings":"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","names":["d","jsx","jsx","jsxs","useEffect","useState","jsx","jsxs","deriveGroupStatus","m","s","jsx","jsxs","useState","useEffect"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@magic-marker/nurt",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "A type-safe, zero-dependency DAG execution engine for TypeScript",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"import": "./dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"./react": {
|
|
12
|
+
"types": "./dist/react/index.d.ts",
|
|
13
|
+
"import": "./dist/react/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"README.md"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsx scripts/build.ts",
|
|
22
|
+
"dev": "tsx scripts/build.ts --watch",
|
|
23
|
+
"lint": "eslint .",
|
|
24
|
+
"lint:fix": "eslint . --fix",
|
|
25
|
+
"typecheck": "tsc --noEmit",
|
|
26
|
+
"test": "vitest run",
|
|
27
|
+
"test:watch": "vitest",
|
|
28
|
+
"prepublishOnly": "pnpm build",
|
|
29
|
+
"storybook": "storybook dev -p 6006 --no-open",
|
|
30
|
+
"build-storybook": "storybook build -o storybook-static"
|
|
31
|
+
},
|
|
32
|
+
"peerDependencies": {
|
|
33
|
+
"elkjs": ">=0.9.0",
|
|
34
|
+
"react": "^18.0.0 || ^19.0.0"
|
|
35
|
+
},
|
|
36
|
+
"peerDependenciesMeta": {
|
|
37
|
+
"elkjs": {
|
|
38
|
+
"optional": true
|
|
39
|
+
},
|
|
40
|
+
"react": {
|
|
41
|
+
"optional": true
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@nkzw/eslint-config": "^3.0.1",
|
|
46
|
+
"@storybook/addon-docs": "^10.1.10",
|
|
47
|
+
"@storybook/addon-themes": "^10.1.10",
|
|
48
|
+
"@storybook/react-vite": "^10.1.10",
|
|
49
|
+
"@tailwindcss/vite": "^4.1.0",
|
|
50
|
+
"@types/react": "^19.2.7",
|
|
51
|
+
"elkjs": "^0.9.0",
|
|
52
|
+
"eslint": "^9.39.2",
|
|
53
|
+
"eslint-config-prettier": "^10.1.1",
|
|
54
|
+
"eslint-plugin-prettier": "^5.3.0",
|
|
55
|
+
"prettier": "^3.7.4",
|
|
56
|
+
"react": "^19.0.0",
|
|
57
|
+
"react-dom": "^19.0.0",
|
|
58
|
+
"storybook": "^10.1.10",
|
|
59
|
+
"tailwindcss": "^4.1.0",
|
|
60
|
+
"tsup": "^8.5.1",
|
|
61
|
+
"vite": "^6.3.0",
|
|
62
|
+
"tsx": "^4.21.0",
|
|
63
|
+
"typescript": "^5.9.3",
|
|
64
|
+
"vitest": "^4.0.16"
|
|
65
|
+
}
|
|
66
|
+
}
|