@tangle-network/charts 0.21.13 → 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 +3 -0
- package/dist/react/index.js +41 -11
- package/package.json +1 -1
|
@@ -224,6 +224,9 @@
|
|
|
224
224
|
.fw-root .fw-row[data-running] .fw-bar { transition: width 120ms linear; }
|
|
225
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
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; }
|
|
227
230
|
/* A restart: an amber notch through the bar at that moment; the bar keeps its own state. */
|
|
228
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);
|
|
229
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.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
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;
|
|
@@ -2632,7 +2636,12 @@ function slowestRow(rows, clockMs) {
|
|
|
2632
2636
|
* chain ends last wins. Cutting latency anywhere else leaves the trace's end unchanged. */
|
|
2633
2637
|
function criticalPathIds(rows) {
|
|
2634
2638
|
const children = /* @__PURE__ */ new Map();
|
|
2635
|
-
for (const row of rows)
|
|
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
|
+
}
|
|
2636
2645
|
let best;
|
|
2637
2646
|
for (const root of rows) {
|
|
2638
2647
|
if (root.parentId) continue;
|
|
@@ -3346,7 +3355,7 @@ function endLabel(row, clockMs) {
|
|
|
3346
3355
|
}
|
|
3347
3356
|
/** One trace row. Geometry comes from CSS variables, so a row re-renders only when its own state changes. */
|
|
3348
3357
|
const FlowRow = memo(function FlowRow(props) {
|
|
3349
|
-
const { row, view, top, collapsed, searching, slowest, costliest, critical, 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;
|
|
3350
3359
|
const span = row.span;
|
|
3351
3360
|
const running = spanRunning(span);
|
|
3352
3361
|
const agentView = view === "agents";
|
|
@@ -3368,6 +3377,7 @@ const FlowRow = memo(function FlowRow(props) {
|
|
|
3368
3377
|
"data-span-kind": kind,
|
|
3369
3378
|
"data-slowest": slowest || void 0,
|
|
3370
3379
|
"data-critical": critical || void 0,
|
|
3380
|
+
"data-search": searching ? matched ? "match" : "context" : void 0,
|
|
3371
3381
|
"data-running": running || void 0,
|
|
3372
3382
|
"aria-level": agentView ? void 0 : row.depth + 1,
|
|
3373
3383
|
"aria-expanded": row.hasChildren && !agentView ? !folded : void 0,
|
|
@@ -3562,7 +3572,7 @@ const FlowRow = memo(function FlowRow(props) {
|
|
|
3562
3572
|
] })
|
|
3563
3573
|
})]
|
|
3564
3574
|
});
|
|
3565
|
-
}, (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.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)));
|
|
3566
3576
|
/** An elbow connector between two rows at one moment, drawn in the row's tone; appears when the clock reaches it. */
|
|
3567
3577
|
function LinkMark({ link, rowHeight, hot }) {
|
|
3568
3578
|
const upper = Math.min(link.from, link.to), lower = Math.max(link.from, link.to);
|
|
@@ -3774,6 +3784,12 @@ function FlowBody(props) {
|
|
|
3774
3784
|
props.byId,
|
|
3775
3785
|
view
|
|
3776
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
|
+
]);
|
|
3777
3793
|
const index = useMemo(() => new Map(rows.map((row, i) => [row.id, i])), [rows]);
|
|
3778
3794
|
const motion = useRowMotion(rows);
|
|
3779
3795
|
const [jumped, setJumped] = useState();
|
|
@@ -3847,13 +3863,24 @@ function FlowBody(props) {
|
|
|
3847
3863
|
}, []);
|
|
3848
3864
|
const first = Math.max(0, chunk * CHUNK - OVERSCAN);
|
|
3849
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
|
+
});
|
|
3850
3879
|
const focusRow = (id) => {
|
|
3851
3880
|
const i = index.get(id);
|
|
3852
3881
|
const element = scroller.current;
|
|
3853
3882
|
if (i === void 0 || !element) return;
|
|
3854
|
-
|
|
3855
|
-
if (i * rowHeight - offset < element.scrollTop) element.scrollTop = Math.max(0, i * rowHeight - offset);
|
|
3856
|
-
else if ((i + 1) * rowHeight > element.scrollTop + element.clientHeight) element.scrollTop = (i + 1) * rowHeight - element.clientHeight;
|
|
3883
|
+
scrollToRow(i, element);
|
|
3857
3884
|
props.onActiveChange(id);
|
|
3858
3885
|
requestAnimationFrame(() => element.querySelector(`.fw-canvas [data-span-id="${CSS.escape(id)}"]`)?.focus({ preventScroll: true }));
|
|
3859
3886
|
};
|
|
@@ -4021,6 +4048,7 @@ function FlowBody(props) {
|
|
|
4021
4048
|
slowest: item.id === slowestId,
|
|
4022
4049
|
costliest: item.id === props.costliestId,
|
|
4023
4050
|
critical: props.criticalIds?.has(item.id),
|
|
4051
|
+
matched: matched?.has(item.id),
|
|
4024
4052
|
active: item.id === activeId,
|
|
4025
4053
|
focusable: !isSticky && (item.id === activeId || (activeId === void 0 || !index.has(activeId)) && i === 0),
|
|
4026
4054
|
selected: item.id === selectedId,
|
|
@@ -4975,6 +5003,8 @@ function FlowWaterfall({ trace, live, startedAt, label = "Trace waterfall", defa
|
|
|
4975
5003
|
maxHeight: rowsHeight,
|
|
4976
5004
|
collapsed,
|
|
4977
5005
|
searching: Boolean(query.trim()),
|
|
5006
|
+
query,
|
|
5007
|
+
matchSpan,
|
|
4978
5008
|
pauses: trace.pauses,
|
|
4979
5009
|
cursorLine: position !== null || playing,
|
|
4980
5010
|
sharedDetail,
|
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",
|