@tangle-network/charts 0.21.12 → 0.21.14
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/dist/react/flow-waterfall.css +5 -0
- package/dist/react/index.d.ts +21 -2
- package/dist/react/index.js +91 -18
- package/package.json +1 -1
|
@@ -222,6 +222,11 @@
|
|
|
222
222
|
.fw-root .fw-settle .fw-end { animation: fw-land 260ms var(--fw-ease); }
|
|
223
223
|
/* A live bar grows with the clock instead of stepping each tick. */
|
|
224
224
|
.fw-root .fw-row[data-running] .fw-bar { transition: width 120ms linear; }
|
|
225
|
+
/* The chain that gates the trace's end: an accent edge under its bars, so cutting latency there is visibly what moves the end. */
|
|
226
|
+
.fw-root .fw-row[data-critical] .fw-bar { box-shadow: inset 0 -2px 0 var(--fw-accent); }
|
|
227
|
+
/* While searching, ancestors shown only for context recede and the matching names stand out. */
|
|
228
|
+
.fw-root .fw-row[data-search="context"] .fw-label { opacity: 0.55; }
|
|
229
|
+
.fw-root .fw-row[data-search="match"] .fw-name-text { font-weight: 600; }
|
|
225
230
|
/* A restart: an amber notch through the bar at that moment; the bar keeps its own state. */
|
|
226
231
|
.fw-root .fw-mark { position: absolute; z-index: 2; left: calc(var(--x0) - 1px); width: 2px; top: calc(50% + var(--fw-bar-shift) - var(--fw-bar-h) / 2 - 4px); height: calc(var(--fw-bar-h) + 8px);
|
|
227
232
|
border-radius: 2px; background: var(--fw-amber); box-shadow: 0 0 0 1px var(--fw-surface); opacity: var(--on); pointer-events: auto; }
|
package/dist/react/index.d.ts
CHANGED
|
@@ -376,6 +376,12 @@ export declare function DotMap({ positions, radii, colors, palette, extent, rect
|
|
|
376
376
|
//#region src/react/flow-waterfall-row.d.ts
|
|
377
377
|
type FlowView = 'spans' | 'agents';
|
|
378
378
|
//#endregion
|
|
379
|
+
//#region src/react/flow-waterfall-time.d.ts
|
|
380
|
+
interface ViewWindow {
|
|
381
|
+
startMs: number;
|
|
382
|
+
endMs: number;
|
|
383
|
+
}
|
|
384
|
+
//#endregion
|
|
379
385
|
//#region src/react/flow-waterfall.d.ts
|
|
380
386
|
interface FlowWaterfallProps {
|
|
381
387
|
trace: FlowTrace;
|
|
@@ -412,9 +418,22 @@ interface FlowWaterfallProps {
|
|
|
412
418
|
onDeselect?: () => void;
|
|
413
419
|
/** Show the stat strip (default); a page with its own stat row passes false. */
|
|
414
420
|
summary?: boolean;
|
|
421
|
+
/** Mark the steps on the chain that gates the trace's end. */
|
|
422
|
+
criticalPath?: boolean;
|
|
423
|
+
/** Controlled search text; pass with `onQueryChange` to keep it in the host's state, such as the URL. */
|
|
424
|
+
query?: string;
|
|
425
|
+
onQueryChange?: (query: string) => void;
|
|
426
|
+
/** Controlled folded span ids; pass with `onCollapsedChange`. Overrides `defaultCollapsed`. */
|
|
427
|
+
collapsed?: ReadonlySet<string>;
|
|
428
|
+
onCollapsedChange?: (collapsed: ReadonlySet<string>) => void;
|
|
429
|
+
/** Controlled time window, `null` for the whole trace; pass with `onZoomChange`. */
|
|
430
|
+
zoom?: ViewWindow | null;
|
|
431
|
+
onZoomChange?: (zoom: ViewWindow | null) => void;
|
|
432
|
+
/** Replaces the built-in search match (name, model, kind, status), such as to search the host's attributes. */
|
|
433
|
+
matchSpan?: (span: FlowSpan, query: string) => boolean;
|
|
415
434
|
}
|
|
416
435
|
/** Shared trace inspector: the agent timeline and the span waterfall over one clock.
|
|
417
436
|
* Data remains producer-owned; playback, zoom and folding change presentation only. */
|
|
418
|
-
export declare function FlowWaterfall({ trace, live, startedAt, label, defaultCollapsed, defaultView, renderIcon, maxHeight, onSelect, markers, onTimeChange, agentFill: fillProp, selectedId, onDeselect, description, summary: showSummary }: FlowWaterfallProps): import("react").JSX.Element;
|
|
437
|
+
export declare function FlowWaterfall({ trace, live, startedAt, label, defaultCollapsed, defaultView, renderIcon, maxHeight, onSelect, markers, onTimeChange, agentFill: fillProp, selectedId, onDeselect, description, summary: showSummary, criticalPath, query: queryProp, onQueryChange, collapsed: collapsedProp, onCollapsedChange, zoom: zoomProp, onZoomChange, matchSpan }: FlowWaterfallProps): import("react").JSX.Element;
|
|
419
438
|
//#endregion
|
|
420
|
-
export type { BandKind, ChartBand, ChartMark, DotMapLabel, DotMapProps, DotMapRect, Figure, FigureAtWidth, FigureViewProps, FlowWaterfallProps, GapBand, GapProps, LineSeries, MarkKind, MarkVerdict, MarkerShape, MeterSegment, PointFields, PointGlyph, Refusal, SparklineDirection, SparklineGeometry, SparklineGeometryOptions, SparklineLabelOptions, SparklinePoint, SparklineProps, SparklineValues, StackedBarBucket, StackedBarChartProps, StackedBarSegment, StackedBarSeries, TickOutcome, TimelineLane, TimelineOptions, TimelineSpan, TimelineTick, TimelineViewProps, WaterfallBarProps, WaterfallHeaderProps, WaterfallRowProps, WaterfallSpanGeometry, WaterfallTimeAxisProps, WaterfallWindow, XCategory, YScale, YTarget, YTick };
|
|
439
|
+
export type { BandKind, ChartBand, ChartMark, DotMapLabel, DotMapProps, DotMapRect, Figure, FigureAtWidth, FigureViewProps, FlowWaterfallProps, ViewWindow as FlowWaterfallWindow, GapBand, GapProps, LineSeries, MarkKind, MarkVerdict, MarkerShape, MeterSegment, PointFields, PointGlyph, Refusal, SparklineDirection, SparklineGeometry, SparklineGeometryOptions, SparklineLabelOptions, SparklinePoint, SparklineProps, SparklineValues, StackedBarBucket, StackedBarChartProps, StackedBarSegment, StackedBarSeries, TickOutcome, TimelineLane, TimelineOptions, TimelineSpan, TimelineTick, TimelineViewProps, WaterfallBarProps, WaterfallHeaderProps, WaterfallRowProps, WaterfallSpanGeometry, WaterfallTimeAxisProps, WaterfallWindow, XCategory, YScale, YTarget, YTick };
|
package/dist/react/index.js
CHANGED
|
@@ -2590,15 +2590,19 @@ function segmentOf(row) {
|
|
|
2590
2590
|
name: row.name
|
|
2591
2591
|
};
|
|
2592
2592
|
}
|
|
2593
|
+
/** The rows a search term matches by themselves, before ancestor context is added. */
|
|
2594
|
+
function searchMatchIds(rows, query, matchSpan) {
|
|
2595
|
+
const term = query.trim();
|
|
2596
|
+
const lower = term.toLowerCase();
|
|
2597
|
+
return new Set(rows.filter((row) => matchSpan ? matchSpan(row.span, term) : `${row.name} ${row.span.detail ?? ""} ${row.kind} ${row.ok ? "" : "failed"} ${row.span.status ?? ""}`.toLowerCase().includes(lower)).map((row) => row.id));
|
|
2598
|
+
}
|
|
2593
2599
|
/** Search keeps ancestor context and deliberately reveals matches inside collapsed branches. */
|
|
2594
|
-
function visibleFlowWaterfallRows(rows, query, collapsed) {
|
|
2600
|
+
function visibleFlowWaterfallRows(rows, query, collapsed, matchSpan) {
|
|
2595
2601
|
const byId = new Map(rows.map((row) => [row.id, row]));
|
|
2596
|
-
|
|
2597
|
-
if (term) {
|
|
2602
|
+
if (query.trim()) {
|
|
2598
2603
|
const matching = /* @__PURE__ */ new Set();
|
|
2599
|
-
for (const
|
|
2600
|
-
|
|
2601
|
-
let cursor = row;
|
|
2604
|
+
for (const id of searchMatchIds(rows, query, matchSpan)) {
|
|
2605
|
+
let cursor = byId.get(id);
|
|
2602
2606
|
while (cursor && !matching.has(cursor.id)) {
|
|
2603
2607
|
matching.add(cursor.id);
|
|
2604
2608
|
cursor = cursor.parentId ? byId.get(cursor.parentId) : void 0;
|
|
@@ -2628,6 +2632,33 @@ function slowestRow(rows, clockMs) {
|
|
|
2628
2632
|
}
|
|
2629
2633
|
return best;
|
|
2630
2634
|
}
|
|
2635
|
+
/** The chain of steps that gates the trace's end: from each root, descend into the latest-ending child until a leaf; the root whose
|
|
2636
|
+
* chain ends last wins. Cutting latency anywhere else leaves the trace's end unchanged. */
|
|
2637
|
+
function criticalPathIds(rows) {
|
|
2638
|
+
const children = /* @__PURE__ */ new Map();
|
|
2639
|
+
for (const row of rows) {
|
|
2640
|
+
if (!row.parentId) continue;
|
|
2641
|
+
const siblings = children.get(row.parentId);
|
|
2642
|
+
if (siblings) siblings.push(row);
|
|
2643
|
+
else children.set(row.parentId, [row]);
|
|
2644
|
+
}
|
|
2645
|
+
let best;
|
|
2646
|
+
for (const root of rows) {
|
|
2647
|
+
if (root.parentId) continue;
|
|
2648
|
+
const chain = [];
|
|
2649
|
+
let end = root.span.endMs;
|
|
2650
|
+
for (let cursor = root; cursor;) {
|
|
2651
|
+
chain.push(cursor.id);
|
|
2652
|
+
end = Math.max(end, cursor.span.endMs);
|
|
2653
|
+
cursor = children.get(cursor.id)?.reduce((latest, child) => !latest || child.span.endMs > latest.span.endMs ? child : latest, void 0);
|
|
2654
|
+
}
|
|
2655
|
+
if (!best || end > best.end) best = {
|
|
2656
|
+
end,
|
|
2657
|
+
chain
|
|
2658
|
+
};
|
|
2659
|
+
}
|
|
2660
|
+
return new Set(best?.chain);
|
|
2661
|
+
}
|
|
2631
2662
|
/** The agents a reader should look at first: the longest one by the clock, and the costliest when two or more are priced. */
|
|
2632
2663
|
function agentCallouts(agents, clockMs) {
|
|
2633
2664
|
let slowest, slowestMs = -1, costliest, top = -1, priced = 0, timed = 0;
|
|
@@ -3324,7 +3355,7 @@ function endLabel(row, clockMs) {
|
|
|
3324
3355
|
}
|
|
3325
3356
|
/** One trace row. Geometry comes from CSS variables, so a row re-renders only when its own state changes. */
|
|
3326
3357
|
const FlowRow = memo(function FlowRow(props) {
|
|
3327
|
-
const { row, view, top, collapsed, searching, slowest, costliest, active, focusable, selected, sticky, clockMs, renderIcon, fillByAgent, motion } = props;
|
|
3358
|
+
const { row, view, top, collapsed, searching, slowest, costliest, critical, matched, active, focusable, selected, sticky, clockMs, renderIcon, fillByAgent, motion } = props;
|
|
3328
3359
|
const span = row.span;
|
|
3329
3360
|
const running = spanRunning(span);
|
|
3330
3361
|
const agentView = view === "agents";
|
|
@@ -3345,6 +3376,8 @@ const FlowRow = memo(function FlowRow(props) {
|
|
|
3345
3376
|
"data-span-id": row.id,
|
|
3346
3377
|
"data-span-kind": kind,
|
|
3347
3378
|
"data-slowest": slowest || void 0,
|
|
3379
|
+
"data-critical": critical || void 0,
|
|
3380
|
+
"data-search": searching ? matched ? "match" : "context" : void 0,
|
|
3348
3381
|
"data-running": running || void 0,
|
|
3349
3382
|
"aria-level": agentView ? void 0 : row.depth + 1,
|
|
3350
3383
|
"aria-expanded": row.hasChildren && !agentView ? !folded : void 0,
|
|
@@ -3477,7 +3510,7 @@ const FlowRow = memo(function FlowRow(props) {
|
|
|
3477
3510
|
role: "gridcell",
|
|
3478
3511
|
className: "fw-lane",
|
|
3479
3512
|
"data-waterfall-track": true,
|
|
3480
|
-
"aria-label": `${KIND_LABEL[span.kind]}, ${label}${slowest ? `, slowest ${agentView ? "agent" : "step"}` : ""}${costliest ? ", costliest agent" : ""}`,
|
|
3513
|
+
"aria-label": `${KIND_LABEL[span.kind]}, ${label}${slowest ? `, slowest ${agentView ? "agent" : "step"}` : ""}${costliest ? ", costliest agent" : ""}${critical ? ", critical path" : ""}`,
|
|
3481
3514
|
children: invalid ? /* @__PURE__ */ jsx("span", {
|
|
3482
3515
|
className: "fw-invalid",
|
|
3483
3516
|
children: "—"
|
|
@@ -3539,7 +3572,7 @@ const FlowRow = memo(function FlowRow(props) {
|
|
|
3539
3572
|
] })
|
|
3540
3573
|
})]
|
|
3541
3574
|
});
|
|
3542
|
-
}, (a, b) => a.row === b.row && a.view === b.view && a.top === b.top && a.collapsed === b.collapsed && a.searching === b.searching && a.slowest === b.slowest && a.costliest === b.costliest && a.active === b.active && a.focusable === b.focusable && a.selected === b.selected && a.sticky === b.sticky && a.motion === b.motion && a.renderIcon === b.renderIcon && a.fillByAgent === b.fillByAgent && a.sharedDetail === b.sharedDetail && a.expanded === b.expanded && (a.clockMs === b.clockMs || !open(a.row, a.clockMs) && !open(b.row, b.clockMs)));
|
|
3575
|
+
}, (a, b) => a.row === b.row && a.view === b.view && a.top === b.top && a.collapsed === b.collapsed && a.searching === b.searching && a.slowest === b.slowest && a.costliest === b.costliest && a.critical === b.critical && a.matched === b.matched && a.active === b.active && a.focusable === b.focusable && a.selected === b.selected && a.sticky === b.sticky && a.motion === b.motion && a.renderIcon === b.renderIcon && a.fillByAgent === b.fillByAgent && a.sharedDetail === b.sharedDetail && a.expanded === b.expanded && (a.clockMs === b.clockMs || !open(a.row, a.clockMs) && !open(b.row, b.clockMs)));
|
|
3543
3576
|
/** An elbow connector between two rows at one moment, drawn in the row's tone; appears when the clock reaches it. */
|
|
3544
3577
|
function LinkMark({ link, rowHeight, hot }) {
|
|
3545
3578
|
const upper = Math.min(link.from, link.to), lower = Math.max(link.from, link.to);
|
|
@@ -3751,6 +3784,12 @@ function FlowBody(props) {
|
|
|
3751
3784
|
props.byId,
|
|
3752
3785
|
view
|
|
3753
3786
|
]);
|
|
3787
|
+
const matched = useMemo(() => searching ? searchMatchIds(rows, props.query, props.matchSpan) : void 0, [
|
|
3788
|
+
searching,
|
|
3789
|
+
rows,
|
|
3790
|
+
props.query,
|
|
3791
|
+
props.matchSpan
|
|
3792
|
+
]);
|
|
3754
3793
|
const index = useMemo(() => new Map(rows.map((row, i) => [row.id, i])), [rows]);
|
|
3755
3794
|
const motion = useRowMotion(rows);
|
|
3756
3795
|
const [jumped, setJumped] = useState();
|
|
@@ -3824,13 +3863,24 @@ function FlowBody(props) {
|
|
|
3824
3863
|
}, []);
|
|
3825
3864
|
const first = Math.max(0, chunk * CHUNK - OVERSCAN);
|
|
3826
3865
|
const last = Math.min(rows.length, chunk * CHUNK + Math.ceil(viewport / rowHeight) + CHUNK + OVERSCAN);
|
|
3866
|
+
const scrollToRow = (i, element) => {
|
|
3867
|
+
const offset = (view === "spans" ? Math.min(STICKY_LEVELS, rows[i].depth) : 0) * rowHeight;
|
|
3868
|
+
if (i * rowHeight - offset < element.scrollTop) element.scrollTop = Math.max(0, i * rowHeight - offset);
|
|
3869
|
+
else if ((i + 1) * rowHeight > element.scrollTop + element.clientHeight) element.scrollTop = (i + 1) * rowHeight - element.clientHeight;
|
|
3870
|
+
};
|
|
3871
|
+
const shownSelection = useRef(void 0);
|
|
3872
|
+
useEffect(() => {
|
|
3873
|
+
if (!selectedId || selectedId === shownSelection.current) return;
|
|
3874
|
+
const i = index.get(selectedId);
|
|
3875
|
+
if (i === void 0 || !scroller.current) return;
|
|
3876
|
+
shownSelection.current = selectedId;
|
|
3877
|
+
scrollToRow(i, scroller.current);
|
|
3878
|
+
});
|
|
3827
3879
|
const focusRow = (id) => {
|
|
3828
3880
|
const i = index.get(id);
|
|
3829
3881
|
const element = scroller.current;
|
|
3830
3882
|
if (i === void 0 || !element) return;
|
|
3831
|
-
|
|
3832
|
-
if (i * rowHeight - offset < element.scrollTop) element.scrollTop = Math.max(0, i * rowHeight - offset);
|
|
3833
|
-
else if ((i + 1) * rowHeight > element.scrollTop + element.clientHeight) element.scrollTop = (i + 1) * rowHeight - element.clientHeight;
|
|
3883
|
+
scrollToRow(i, element);
|
|
3834
3884
|
props.onActiveChange(id);
|
|
3835
3885
|
requestAnimationFrame(() => element.querySelector(`.fw-canvas [data-span-id="${CSS.escape(id)}"]`)?.focus({ preventScroll: true }));
|
|
3836
3886
|
};
|
|
@@ -3997,6 +4047,8 @@ function FlowBody(props) {
|
|
|
3997
4047
|
searching,
|
|
3998
4048
|
slowest: item.id === slowestId,
|
|
3999
4049
|
costliest: item.id === props.costliestId,
|
|
4050
|
+
critical: props.criticalIds?.has(item.id),
|
|
4051
|
+
matched: matched?.has(item.id),
|
|
4000
4052
|
active: item.id === activeId,
|
|
4001
4053
|
focusable: !isSticky && (item.id === activeId || (activeId === void 0 || !index.has(activeId)) && i === 0),
|
|
4002
4054
|
selected: item.id === selectedId,
|
|
@@ -4372,6 +4424,22 @@ const NAME_WIDTH = {
|
|
|
4372
4424
|
spans: 320,
|
|
4373
4425
|
agents: 240
|
|
4374
4426
|
};
|
|
4427
|
+
/** State the host may own: its value wins when given, and every change is reported either way. */
|
|
4428
|
+
function useHostable(value, onChange, initial) {
|
|
4429
|
+
const [own, setOwn] = useState(initial);
|
|
4430
|
+
const current = value === void 0 ? own : value;
|
|
4431
|
+
const latest = useRef(current);
|
|
4432
|
+
latest.current = current;
|
|
4433
|
+
const report = useRef(onChange);
|
|
4434
|
+
report.current = onChange;
|
|
4435
|
+
const controlled = value !== void 0;
|
|
4436
|
+
return [current, useCallback((next) => {
|
|
4437
|
+
const resolved = typeof next === "function" ? next(latest.current) : next;
|
|
4438
|
+
latest.current = resolved;
|
|
4439
|
+
if (!controlled) setOwn(resolved);
|
|
4440
|
+
report.current?.(resolved);
|
|
4441
|
+
}, [controlled])];
|
|
4442
|
+
}
|
|
4375
4443
|
/** The summary strip: as of the playhead while scrubbing, the producer's totals otherwise. */
|
|
4376
4444
|
function summaryCells(trace, at, durationMs) {
|
|
4377
4445
|
const cost = costSummary(at ? at.costUsd : trace.costUsd, trace);
|
|
@@ -4474,7 +4542,7 @@ function OutcomeLegend({ agents }) {
|
|
|
4474
4542
|
}
|
|
4475
4543
|
/** Shared trace inspector: the agent timeline and the span waterfall over one clock.
|
|
4476
4544
|
* Data remains producer-owned; playback, zoom and folding change presentation only. */
|
|
4477
|
-
function FlowWaterfall({ trace, live, startedAt, label = "Trace waterfall", defaultCollapsed = false, defaultView = "spans", renderIcon, maxHeight, onSelect, markers, onTimeChange, agentFill: fillProp, selectedId, onDeselect, description, summary: showSummary = true }) {
|
|
4545
|
+
function FlowWaterfall({ trace, live, startedAt, label = "Trace waterfall", defaultCollapsed = false, defaultView = "spans", renderIcon, maxHeight, onSelect, markers, onTimeChange, agentFill: fillProp, selectedId, onDeselect, description, summary: showSummary = true, criticalPath = false, query: queryProp, onQueryChange, collapsed: collapsedProp, onCollapsedChange, zoom: zoomProp, onZoomChange, matchSpan }) {
|
|
4478
4546
|
const root = useRef(null);
|
|
4479
4547
|
const search = useRef(null);
|
|
4480
4548
|
const slider = useRef(null);
|
|
@@ -4483,12 +4551,12 @@ function FlowWaterfall({ trace, live, startedAt, label = "Trace waterfall", defa
|
|
|
4483
4551
|
const searchId = useId();
|
|
4484
4552
|
const cardId = useId();
|
|
4485
4553
|
const [view, setView] = useState(defaultView);
|
|
4486
|
-
const [query, setQuery] =
|
|
4487
|
-
const [collapsed, setCollapsed] =
|
|
4554
|
+
const [query, setQuery] = useHostable(queryProp, onQueryChange, "");
|
|
4555
|
+
const [collapsed, setCollapsed] = useHostable(collapsedProp, onCollapsedChange, () => new Set(defaultCollapsed ? trace.spans.flatMap((span) => span.parentId ? [span.parentId] : []) : []));
|
|
4488
4556
|
const [speed, setSpeed] = useState(1);
|
|
4489
4557
|
const [playing, setPlaying] = useState(false);
|
|
4490
4558
|
const [position, setPosition] = useState(null);
|
|
4491
|
-
const [zoom, setZoom] =
|
|
4559
|
+
const [zoom, setZoom] = useHostable(zoomProp, onZoomChange, null);
|
|
4492
4560
|
const [nameWidth, setNameWidth] = useState(NAME_WIDTH[defaultView]);
|
|
4493
4561
|
const [laneWidth, setLaneWidth] = useState(0);
|
|
4494
4562
|
const [card, setCard] = useState(null);
|
|
@@ -4544,6 +4612,7 @@ function FlowWaterfall({ trace, live, startedAt, label = "Trace waterfall", defa
|
|
|
4544
4612
|
resolution
|
|
4545
4613
|
]);
|
|
4546
4614
|
const byId = useMemo(() => new Map(rows.map((row) => [row.id, row])), [rows]);
|
|
4615
|
+
const critical = useMemo(() => criticalPathIds(rows), [rows]);
|
|
4547
4616
|
const agents = useMemo(() => {
|
|
4548
4617
|
const pipelines = rows.filter((row) => row.kind === "pipeline");
|
|
4549
4618
|
return pipelines.length ? pipelines : rows.filter((row) => !row.parentId);
|
|
@@ -4552,14 +4621,15 @@ function FlowWaterfall({ trace, live, startedAt, label = "Trace waterfall", defa
|
|
|
4552
4621
|
const [flippedFamilies, setFlippedFamilies] = useState(/* @__PURE__ */ new Set());
|
|
4553
4622
|
const openFamilies = useMemo(() => defaultOpenFamilies(agents, UNFOLD_ROWS, flippedFamilies), [agents, flippedFamilies]);
|
|
4554
4623
|
const [openSteps, setOpenSteps] = useState(/* @__PURE__ */ new Set());
|
|
4555
|
-
const visible = useMemo(() => view === "agents" ? agentViewRows(agents, rows, openFamilies, openSteps) : visibleFlowWaterfallRows(rows, query, collapsed), [
|
|
4624
|
+
const visible = useMemo(() => view === "agents" ? agentViewRows(agents, rows, openFamilies, openSteps) : visibleFlowWaterfallRows(rows, query, collapsed, matchSpan), [
|
|
4556
4625
|
view,
|
|
4557
4626
|
agents,
|
|
4558
4627
|
rows,
|
|
4559
4628
|
openFamilies,
|
|
4560
4629
|
openSteps,
|
|
4561
4630
|
query,
|
|
4562
|
-
collapsed
|
|
4631
|
+
collapsed,
|
|
4632
|
+
matchSpan
|
|
4563
4633
|
]);
|
|
4564
4634
|
const slowest = view === "spans" ? slowestRow(rows, clockMs) : void 0;
|
|
4565
4635
|
const callouts = useMemo(() => view === "agents" ? agentCallouts(visible, clockMs) : {}, [
|
|
@@ -4933,6 +5003,8 @@ function FlowWaterfall({ trace, live, startedAt, label = "Trace waterfall", defa
|
|
|
4933
5003
|
maxHeight: rowsHeight,
|
|
4934
5004
|
collapsed,
|
|
4935
5005
|
searching: Boolean(query.trim()),
|
|
5006
|
+
query,
|
|
5007
|
+
matchSpan,
|
|
4936
5008
|
pauses: trace.pauses,
|
|
4937
5009
|
cursorLine: position !== null || playing,
|
|
4938
5010
|
sharedDetail,
|
|
@@ -4940,6 +5012,7 @@ function FlowWaterfall({ trace, live, startedAt, label = "Trace waterfall", defa
|
|
|
4940
5012
|
holdHeight: isLive,
|
|
4941
5013
|
slowestId: slowest?.id ?? callouts.slowestId,
|
|
4942
5014
|
costliestId: callouts.costliestId,
|
|
5015
|
+
criticalIds: criticalPath && view === "spans" ? critical : void 0,
|
|
4943
5016
|
activeId,
|
|
4944
5017
|
selectedId: selection,
|
|
4945
5018
|
focusId: cardAgent?.id ?? (view === "agents" ? activeId : void 0),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangle-network/charts",
|
|
3
|
-
"version": "0.21.
|
|
3
|
+
"version": "0.21.14",
|
|
4
4
|
"description": "Static SVG and HTML figures for benchmarks and operational timing. Draws from producer data and refuses what it cannot draw honestly.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|