footprint-explainable-ui 0.3.1 → 0.4.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 CHANGED
@@ -137,9 +137,34 @@ function PipelineChart({ spec }) {
137
137
  }
138
138
  ```
139
139
 
140
- ### With execution overlay (time-travel)
140
+ ### Self-contained traced flowchart (recommended)
141
141
 
142
- The overlay highlights which stages have executed, which is active, and the execution path like a Google Maps route overlay.
142
+ `TracedFlowchartView` handles everything overlay computation, subflow drill-down, breadcrumbs. Just pass `spec` + `snapshots`:
143
+
144
+ ```tsx
145
+ import { TracedFlowchartView } from "footprint-explainable-ui/flowchart";
146
+
147
+ function MyDebugger({ spec, snapshots }) {
148
+ const [idx, setIdx] = useState(0);
149
+
150
+ return (
151
+ <div style={{ height: 400 }}>
152
+ <TracedFlowchartView
153
+ spec={spec}
154
+ snapshots={snapshots}
155
+ snapshotIndex={idx}
156
+ onNodeClick={(i) => setIdx(i as number)}
157
+ />
158
+ </div>
159
+ );
160
+ }
161
+ ```
162
+
163
+ Without `snapshots`, it renders a plain static flowchart. With `snapshots`, it shows the execution trace path.
164
+
165
+ ### With execution overlay (manual control)
166
+
167
+ For full control, use `specToReactFlow` directly. The overlay highlights which stages have executed, which is active, and the execution path — like a Google Maps route overlay.
143
168
 
144
169
  ```tsx
145
170
  import { specToReactFlow, type ExecutionOverlay } from "footprint-explainable-ui/flowchart";
@@ -348,7 +373,8 @@ interface ThemeTokens {
348
373
 
349
374
  | Export | Description |
350
375
  |---|---|
351
- | `FlowchartView` | ReactFlow pipeline visualization with execution overlay |
376
+ | `TracedFlowchartView` | Self-contained flowchart with trace overlay, subflow drill-down, breadcrumbs |
377
+ | `FlowchartView` | Lower-level ReactFlow wrapper with execution state coloring |
352
378
  | `StageNode` | Custom node with state-aware coloring, step badges, pulse rings |
353
379
  | `specToReactFlow` | Convert pipeline spec → ReactFlow nodes/edges with path overlay |
354
380
  | `TimeTravelDebugger` | Full debugger with flowchart + all panels |
@@ -373,6 +399,19 @@ All components accept a `size` prop: `"compact"`, `"default"`, or `"detailed"`.
373
399
  <MemoryInspector snapshots={snapshots} size="detailed" />
374
400
  ```
375
401
 
402
+ ### Collapsible GanttTimeline
403
+
404
+ By default, the Gantt timeline collapses to 5 rows with an expand toggle. Auto-scrolls to keep the active stage visible:
405
+
406
+ ```tsx
407
+ <GanttTimeline
408
+ snapshots={snapshots}
409
+ selectedIndex={idx}
410
+ onSelect={setIdx}
411
+ maxVisibleRows={5} // default — set 0 to disable collapse
412
+ />
413
+ ```
414
+
376
415
  ## Unstyled Mode
377
416
 
378
417
  Strip all built-in styles for full CSS control. Components render semantic `data-fp` attributes:
@@ -389,6 +428,175 @@ Strip all built-in styles for full CSS control. Components render semantic `data
389
428
 
390
429
  ---
391
430
 
431
+ ## Example: Build a Pipeline Playground
432
+
433
+ A complete example combining flowchart, time-travel controls, detail panel, and Gantt timeline — the same pattern used by the [FootPrint Playground](https://footprintjs.github.io/footprint-playground/).
434
+
435
+ ```tsx
436
+ import { useState, useMemo } from "react";
437
+ import { ReactFlow } from "@xyflow/react";
438
+ import "@xyflow/react/dist/style.css";
439
+ import {
440
+ toVisualizationSnapshots,
441
+ GanttTimeline,
442
+ ScopeDiff,
443
+ NarrativeTrace,
444
+ MemoryInspector,
445
+ FootprintTheme,
446
+ warmDark,
447
+ } from "footprint-explainable-ui";
448
+ import {
449
+ StageNode,
450
+ specToReactFlow,
451
+ useSubflowNavigation,
452
+ SubflowBreadcrumb,
453
+ type ExecutionOverlay,
454
+ type SpecNode,
455
+ } from "footprint-explainable-ui/flowchart";
456
+ import { FlowChartExecutor } from "footprint";
457
+
458
+ const nodeTypes = { stage: StageNode };
459
+
460
+ // ─── Hook: time-travel + overlay + subflow drill-down ────────────────
461
+ function useFlowchartData(spec: SpecNode | null, vizSnapshots: any[] | null) {
462
+ const [snapshotIdx, setSnapshotIdx] = useState(0);
463
+ const subflowNav = useSubflowNavigation(spec);
464
+
465
+ const activeSnapshots = vizSnapshots; // extend with subflow logic as needed
466
+
467
+ // Compute execution overlay from current scrubber position
468
+ const overlay = useMemo<ExecutionOverlay | undefined>(() => {
469
+ if (!activeSnapshots) return undefined;
470
+ const executionOrder = activeSnapshots
471
+ .slice(0, snapshotIdx + 1)
472
+ .map((s) => s.stageLabel);
473
+ const doneStages = new Set(
474
+ activeSnapshots.slice(0, snapshotIdx).map((s) => s.stageLabel)
475
+ );
476
+ const activeStage = activeSnapshots[snapshotIdx]?.stageLabel ?? null;
477
+ const executedStages = new Set([...doneStages]);
478
+ if (activeStage) executedStages.add(activeStage);
479
+ return { doneStages, activeStage, executedStages, executionOrder };
480
+ }, [activeSnapshots, snapshotIdx]);
481
+
482
+ // Derive ReactFlow nodes/edges with overlay applied
483
+ const currentSpec =
484
+ subflowNav.breadcrumbs[subflowNav.breadcrumbs.length - 1]?.spec ?? null;
485
+ const flowData = useMemo(() => {
486
+ if (!currentSpec || !activeSnapshots) return null;
487
+ return specToReactFlow(currentSpec, overlay);
488
+ }, [currentSpec, activeSnapshots, overlay]);
489
+
490
+ return {
491
+ subflowNav,
492
+ activeSnapshots,
493
+ snapshotIdx,
494
+ setSnapshotIdx,
495
+ currentSnap: activeSnapshots?.[snapshotIdx] ?? null,
496
+ flowData,
497
+ };
498
+ }
499
+
500
+ // ─── Main component ──────────────────────────────────────────────────
501
+ function PipelinePlayground({ chart, spec }: { chart: any; spec: SpecNode }) {
502
+ const [snapshots, setSnapshots] = useState<any[] | null>(null);
503
+
504
+ async function run() {
505
+ const executor = new FlowChartExecutor(chart);
506
+ await executor.run();
507
+ setSnapshots(toVisualizationSnapshots(executor.getSnapshot()));
508
+ }
509
+
510
+ const { subflowNav, activeSnapshots, snapshotIdx, setSnapshotIdx, currentSnap, flowData } =
511
+ useFlowchartData(spec, snapshots);
512
+
513
+ return (
514
+ <FootprintTheme tokens={warmDark}>
515
+ <button onClick={run}>Run Pipeline</button>
516
+
517
+ {/* Flowchart with execution overlay */}
518
+ <div style={{ height: 400 }}>
519
+ {subflowNav.isInSubflow && (
520
+ <SubflowBreadcrumb
521
+ breadcrumbs={subflowNav.breadcrumbs}
522
+ onNavigate={subflowNav.navigateTo}
523
+ />
524
+ )}
525
+ {flowData && (
526
+ <ReactFlow
527
+ nodes={flowData.nodes}
528
+ edges={flowData.edges}
529
+ nodeTypes={nodeTypes}
530
+ onNodeClick={(_, node) => subflowNav.handleNodeClick(node.id)}
531
+ fitView
532
+ />
533
+ )}
534
+ </div>
535
+
536
+ {activeSnapshots && (
537
+ <>
538
+ {/* Time-travel scrubber */}
539
+ <div style={{ display: "flex", gap: 8, alignItems: "center" }}>
540
+ <button
541
+ disabled={snapshotIdx <= 0}
542
+ onClick={() => setSnapshotIdx((i) => i - 1)}
543
+ >
544
+ Prev
545
+ </button>
546
+ <input
547
+ type="range"
548
+ min={0}
549
+ max={activeSnapshots.length - 1}
550
+ value={snapshotIdx}
551
+ onChange={(e) => setSnapshotIdx(Number(e.target.value))}
552
+ />
553
+ <button
554
+ disabled={snapshotIdx >= activeSnapshots.length - 1}
555
+ onClick={() => setSnapshotIdx((i) => i + 1)}
556
+ >
557
+ Next
558
+ </button>
559
+ <span>
560
+ {currentSnap?.stageLabel} ({snapshotIdx + 1}/{activeSnapshots.length})
561
+ </span>
562
+ </div>
563
+
564
+ {/* Detail panels */}
565
+ <MemoryInspector
566
+ snapshots={activeSnapshots}
567
+ selectedIndex={snapshotIdx}
568
+ />
569
+ <ScopeDiff
570
+ previous={snapshotIdx > 0 ? activeSnapshots[snapshotIdx - 1].memory : null}
571
+ current={currentSnap?.memory ?? {}}
572
+ hideUnchanged
573
+ />
574
+ <NarrativeTrace
575
+ narrative={activeSnapshots.map((s) => s.narrative)}
576
+ />
577
+ <GanttTimeline
578
+ snapshots={activeSnapshots}
579
+ selectedIndex={snapshotIdx}
580
+ onSelect={setSnapshotIdx}
581
+ />
582
+ </>
583
+ )}
584
+ </FootprintTheme>
585
+ );
586
+ }
587
+ ```
588
+
589
+ This gives you:
590
+ - Flowchart with Google Maps-style execution path overlay
591
+ - Click subflow nodes to drill down (breadcrumb navigation back)
592
+ - Prev/Next scrubber synced with flowchart highlighting
593
+ - Memory inspector, scope diffs, narrative trace, and Gantt timeline
594
+ - All themed via `FootprintTheme`
595
+
596
+ See the full implementation in the [footprint-playground](https://github.com/footprintjs/footprint-playground) repo.
597
+
598
+ ---
599
+
392
600
  ## License
393
601
 
394
602
  MIT