@tangle-network/charts 0.20.0 → 0.20.1
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/{flow-trace-Sr8GtLm0.d.ts → flow-trace-DqCMrnTs.d.ts} +2 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +11 -1
- package/dist/react/flow-waterfall.css +10 -3
- package/dist/react/index.d.ts +5 -2
- package/dist/react/index.js +41 -7
- package/dist/react/live.css +24 -23
- package/package.json +1 -1
|
@@ -382,6 +382,8 @@ interface FlowTrace {
|
|
|
382
382
|
costUsd?: number;
|
|
383
383
|
/** `list`: priced from a model catalog's list prices, not a bill; the summary says so. */
|
|
384
384
|
costBasis?: 'billed' | 'list';
|
|
385
|
+
/** The list cost is at most this: the input counts include cached tokens priced as fresh input. */
|
|
386
|
+
costUpperBound?: boolean;
|
|
385
387
|
/** How many model calls `costUsd` covers; when `priced < total` the total is a lower bound and shown as one. */
|
|
386
388
|
costCoverage?: {
|
|
387
389
|
priced: number;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as BreakdownInput, B as Refusal, C as MarkKind, D as YScale, E as XCategory, F as Figure, H as Tier, I as Interval, L as IntervalMethod, M as CostBasis, N as Estimate, O as YTarget, P as Exclusion, R as MatrixCell, S as ChartMark, T as MarkerShape, U as TierCounts, V as Setup, W as isRefusal, _ as checkerColor, a as TimelineLane, b as BandKind, c as TimelineTick, d as ENDING_COLORS, f as ENDING_ORDER, g as TickOutcome, h as RunEnding, i as FlowTrace, j as ComparisonRow, k as YTick, l as timeline, m as OUTCOME_ORDER, n as FlowOutcome, o as TimelineOptions, p as OUTCOME_COLORS, r as FlowSpan, s as TimelineSpan, t as FlowMarker, u as CHECKER_HUES, v as PointFields, w as MarkVerdict, x as ChartBand, y as PointGlyph, z as RateRow } from "./flow-trace-
|
|
1
|
+
import { A as BreakdownInput, B as Refusal, C as MarkKind, D as YScale, E as XCategory, F as Figure, H as Tier, I as Interval, L as IntervalMethod, M as CostBasis, N as Estimate, O as YTarget, P as Exclusion, R as MatrixCell, S as ChartMark, T as MarkerShape, U as TierCounts, V as Setup, W as isRefusal, _ as checkerColor, a as TimelineLane, b as BandKind, c as TimelineTick, d as ENDING_COLORS, f as ENDING_ORDER, g as TickOutcome, h as RunEnding, i as FlowTrace, j as ComparisonRow, k as YTick, l as timeline, m as OUTCOME_ORDER, n as FlowOutcome, o as TimelineOptions, p as OUTCOME_COLORS, r as FlowSpan, s as TimelineSpan, t as FlowMarker, u as CHECKER_HUES, v as PointFields, w as MarkVerdict, x as ChartBand, y as PointGlyph, z as RateRow } from "./flow-trace-DqCMrnTs.js";
|
|
2
2
|
//#region src/block.d.ts
|
|
3
3
|
interface RenderFigureOptions {
|
|
4
4
|
/** Chart uses a closed data disclosure; plot keeps only the SVG and accessible data. */
|
package/dist/index.js
CHANGED
|
@@ -3337,6 +3337,13 @@ function unitDotLayout(groups, width, height, o = {}) {
|
|
|
3337
3337
|
}
|
|
3338
3338
|
//#endregion
|
|
3339
3339
|
//#region src/otlp-trace.ts
|
|
3340
|
+
/** Attributes that carry cached input apart from fresh input (OpenTelemetry GenAI and Anthropic-style names). */
|
|
3341
|
+
const CACHE_KEYS = [
|
|
3342
|
+
"gen_ai.usage.cache_read_input_tokens",
|
|
3343
|
+
"gen_ai.usage.cache_creation_input_tokens",
|
|
3344
|
+
"gen_ai.usage.input_tokens.cached",
|
|
3345
|
+
"tangle.llm.cache_read_tokens"
|
|
3346
|
+
];
|
|
3340
3347
|
/** Price model calls from an OpenAI-compatible model catalog (`data[].pricing.prompt|completion`, USD per token), such as
|
|
3341
3348
|
* the Router's `/v1/models`. Read the catalog at runtime; never copy its numbers. */
|
|
3342
3349
|
function catalogPrice(catalog) {
|
|
@@ -3475,6 +3482,7 @@ function otlpFlowTrace(input, options = {}) {
|
|
|
3475
3482
|
let cost = 0;
|
|
3476
3483
|
let unpriced = 0;
|
|
3477
3484
|
let priced = 0;
|
|
3485
|
+
let cacheSplit = false;
|
|
3478
3486
|
const offset = (iso) => time(iso) - origin;
|
|
3479
3487
|
const isSpawn = (span) => span.kind === "TOOL" && (attrs(span)["traces.agent.spawn"] === true || /spawn/i.test(str(attrs(span)["gen_ai.tool.name"]) ?? span.name));
|
|
3480
3488
|
const groupOfSpan = (span) => groupOf.get(rootOf(span).span_id);
|
|
@@ -3541,6 +3549,7 @@ function otlpFlowTrace(input, options = {}) {
|
|
|
3541
3549
|
if (listPrice !== void 0) {
|
|
3542
3550
|
cost += listPrice;
|
|
3543
3551
|
priced++;
|
|
3552
|
+
if (CACHE_KEYS.some((key) => a[key] !== void 0)) cacheSplit = true;
|
|
3544
3553
|
} else if (kind === "model" && !aggregate && (prompt || completion)) unpriced++;
|
|
3545
3554
|
out.push({
|
|
3546
3555
|
id: span.span_id,
|
|
@@ -3574,7 +3583,8 @@ function otlpFlowTrace(input, options = {}) {
|
|
|
3574
3583
|
costCoverage: {
|
|
3575
3584
|
priced,
|
|
3576
3585
|
total: priced + unpriced
|
|
3577
|
-
}
|
|
3586
|
+
},
|
|
3587
|
+
...cacheSplit ? {} : { costUpperBound: true }
|
|
3578
3588
|
} : {}
|
|
3579
3589
|
};
|
|
3580
3590
|
}
|
|
@@ -62,12 +62,12 @@
|
|
|
62
62
|
.fw-root [data-tone="3"] { --tone: var(--fw-h3); }
|
|
63
63
|
.fw-root [data-tone="4"] { --tone: var(--fw-h4); }
|
|
64
64
|
.fw-root [data-tone="5"] { --tone: var(--fw-h5); }
|
|
65
|
-
/* Light fills carry enough of the hue to tell agents apart on white (
|
|
65
|
+
/* Light fills carry enough of the hue to tell agents apart on white (24% and 42% both read as "pastel, washed out"); the outline is
|
|
66
66
|
the full hue, which passes 3:1 against the surface, so every mark keeps its edge. */
|
|
67
67
|
.fw-root [data-tone] {
|
|
68
|
-
--fill: light-dark(color-mix(in oklab, var(--tone)
|
|
68
|
+
--fill: light-dark(color-mix(in oklab, var(--tone) 58%, #fff), color-mix(in oklab, var(--tone) 86%, #000));
|
|
69
69
|
--line: light-dark(var(--tone), var(--tone));
|
|
70
|
-
--dim: light-dark(color-mix(in oklab, var(--tone)
|
|
70
|
+
--dim: light-dark(color-mix(in oklab, var(--tone) 30%, #fff), color-mix(in oklab, var(--tone) 40%, #17171d));
|
|
71
71
|
--dim-line: light-dark(color-mix(in oklab, var(--tone) 70%, #fff), color-mix(in oklab, var(--tone) 55%, #17171d));
|
|
72
72
|
}
|
|
73
73
|
|
|
@@ -231,6 +231,13 @@
|
|
|
231
231
|
.fw-root [data-outcome="neutral"], .fw-root [data-outcome="neutral"] [data-tone] { --tone: var(--fw-muted); }
|
|
232
232
|
.fw-root .fw-legend { display: flex; flex-wrap: wrap; gap: 4px 16px; margin: 8px 0 0; padding: 0; list-style: none; color: var(--fw-muted); font-size: 12px; line-height: 16px; }
|
|
233
233
|
.fw-root .fw-legend li { display: inline-flex; align-items: center; gap: 8px; }
|
|
234
|
+
.fw-root .fw-kinds { margin: 0; padding: 8px 24px 12px; justify-content: flex-end; }
|
|
235
|
+
.fw-root .fw-kinds .fw-swatch-model { width: 12px; height: 8px; border-radius: 2px; background: color-mix(in oklab, var(--fw-text) 40%, var(--fw-surface)); }
|
|
236
|
+
.fw-root .fw-kinds .fw-swatch-tool { width: 12px; height: 8px; border-radius: 2px; background: color-mix(in oklab, var(--fw-text) 16%, var(--fw-surface)); box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--fw-text) 30%, transparent); }
|
|
237
|
+
.fw-root .fw-kinds .fw-swatch-wait { width: 12px; height: 8px; border-radius: 2px; background: repeating-linear-gradient(-45deg, var(--fw-hatch) 0 1px, transparent 1px 4px); box-shadow: inset 0 0 0 1px var(--fw-hatch); }
|
|
238
|
+
.fw-root .fw-kinds .fw-swatch-handoff { width: 10px; height: 8px; border-left: 1.5px solid var(--fw-muted); border-bottom: 1.5px solid var(--fw-muted); border-bottom-left-radius: 3px; }
|
|
239
|
+
.fw-root .fw-kinds .fw-swatch-failed { width: 12px; height: 8px; border-radius: 2px; box-shadow: inset 0 0 0 1px var(--fw-failed); }
|
|
240
|
+
.fw-root .fw-description { margin: 0; color: var(--fw-muted); font-size: 14px; line-height: 20px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
234
241
|
.fw-root .fw-legend .fw-swatch { width: 12px; height: 8px; border-radius: 2px; background: var(--fill); box-shadow: inset 0 0 0 1px var(--line); }
|
|
235
242
|
.fw-root .fw-legend b { color: var(--fw-text); font-weight: 600; font-variant-numeric: tabular-nums; }
|
|
236
243
|
.fw-root .fw-legend .fw-swatch-step { display: inline-grid; place-items: center; width: 12px; height: 12px; border-radius: 3px; background: var(--fw-well); color: var(--fw-failed); box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--fw-failed) 50%, transparent); }
|
package/dist/react/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { B as Refusal, C as MarkKind, D as YScale, E as XCategory, F as Figure, O as YTarget, S as ChartMark, T as MarkerShape, a as TimelineLane, b as BandKind, c as TimelineTick, g as TickOutcome, i as FlowTrace, k as YTick, o as TimelineOptions, r as FlowSpan, s as TimelineSpan, t as FlowMarker, v as PointFields, w as MarkVerdict, x as ChartBand, y as PointGlyph } from "../flow-trace-
|
|
1
|
+
import { B as Refusal, C as MarkKind, D as YScale, E as XCategory, F as Figure, O as YTarget, S as ChartMark, T as MarkerShape, a as TimelineLane, b as BandKind, c as TimelineTick, g as TickOutcome, i as FlowTrace, k as YTick, o as TimelineOptions, r as FlowSpan, s as TimelineSpan, t as FlowMarker, v as PointFields, w as MarkVerdict, x as ChartBand, y as PointGlyph } from "../flow-trace-DqCMrnTs.js";
|
|
2
2
|
import { CSSProperties, ReactElement, ReactNode } from "react";
|
|
3
3
|
//#region src/react/sparkline.d.ts
|
|
4
4
|
type SparklineDirection = "rising" | "falling" | "flat";
|
|
@@ -175,6 +175,7 @@ export declare function HBars({ rows, format, color, max, limit }: {
|
|
|
175
175
|
note?: string;
|
|
176
176
|
color?: string;
|
|
177
177
|
href?: string;
|
|
178
|
+
title?: string;
|
|
178
179
|
}[];
|
|
179
180
|
format?: (v: number) => string;
|
|
180
181
|
color?: string;
|
|
@@ -376,6 +377,8 @@ interface FlowWaterfallProps {
|
|
|
376
377
|
/** What a bar's color means: the agent (default), whose hue its steps and handoffs share, with the outcome on the row dot, legend and
|
|
377
378
|
* crash glyph; or its `outcome`. */
|
|
378
379
|
agentFill?: 'outcome' | 'agent';
|
|
380
|
+
/** One line beside the title saying what the run was for, such as its goal. */
|
|
381
|
+
description?: string;
|
|
379
382
|
/** The row the host has selected, such as the agent whose transcript is open: it lifts and, in the agent view, its peers dim.
|
|
380
383
|
* A pinned card alone only highlights its row, so the rest of the run stays readable around it. */
|
|
381
384
|
selectedId?: string;
|
|
@@ -384,6 +387,6 @@ interface FlowWaterfallProps {
|
|
|
384
387
|
}
|
|
385
388
|
/** Shared trace inspector: the agent timeline and the span waterfall over one clock.
|
|
386
389
|
* Data remains producer-owned; playback, zoom and folding change presentation only. */
|
|
387
|
-
export declare function FlowWaterfall({ trace, live, startedAt, label, defaultCollapsed, defaultView, renderIcon, maxHeight, onSelect, markers, onTimeChange, agentFill, selectedId, onDeselect }: FlowWaterfallProps): import("react").JSX.Element;
|
|
390
|
+
export declare function FlowWaterfall({ trace, live, startedAt, label, defaultCollapsed, defaultView, renderIcon, maxHeight, onSelect, markers, onTimeChange, agentFill, selectedId, onDeselect, description }: FlowWaterfallProps): import("react").JSX.Element;
|
|
388
391
|
//#endregion
|
|
389
392
|
export type { BandKind, ChartBand, ChartMark, DotMapLabel, DotMapProps, DotMapRect, Figure, FigureAtWidth, FigureViewProps, FlowWaterfallProps, 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
|
@@ -1001,10 +1001,10 @@ function HBars({ rows, format = formatCompact, color = LIVE_SERIES[0], max, limi
|
|
|
1001
1001
|
return /* @__PURE__ */ jsxs("ol", {
|
|
1002
1002
|
className: "ov-hbars",
|
|
1003
1003
|
children: [rows.slice(0, limit).map((row) => {
|
|
1004
|
+
const title = row.title ?? `${row.label}: ${format(row.value)}`;
|
|
1004
1005
|
const content = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1005
1006
|
/* @__PURE__ */ jsx("span", {
|
|
1006
1007
|
className: "ov-hbar-label",
|
|
1007
|
-
title: row.label,
|
|
1008
1008
|
children: row.label
|
|
1009
1009
|
}),
|
|
1010
1010
|
/* @__PURE__ */ jsx("span", {
|
|
@@ -1025,8 +1025,12 @@ function HBars({ rows, format = formatCompact, color = LIVE_SERIES[0], max, limi
|
|
|
1025
1025
|
] });
|
|
1026
1026
|
return /* @__PURE__ */ jsx("li", { children: row.href ? /* @__PURE__ */ jsx("a", {
|
|
1027
1027
|
href: row.href,
|
|
1028
|
+
title,
|
|
1028
1029
|
children: content
|
|
1029
|
-
}) : /* @__PURE__ */ jsx("div", {
|
|
1030
|
+
}) : /* @__PURE__ */ jsx("div", {
|
|
1031
|
+
title,
|
|
1032
|
+
children: content
|
|
1033
|
+
}) }, row.label);
|
|
1030
1034
|
}), rest.length > 0 && /* @__PURE__ */ jsxs("li", {
|
|
1031
1035
|
className: "ov-hbars-more",
|
|
1032
1036
|
children: [
|
|
@@ -2575,11 +2579,13 @@ function costSummary(costUsd, trace) {
|
|
|
2575
2579
|
};
|
|
2576
2580
|
const coverage = trace.costCoverage;
|
|
2577
2581
|
const partial = coverage !== void 0 && coverage.priced < coverage.total;
|
|
2582
|
+
const upper = !partial && trace.costUpperBound === true;
|
|
2578
2583
|
return {
|
|
2579
|
-
value: `${partial ? "≥" : list ? "≈" : ""}${formatCost(costUsd)}${trace.billedUsd !== void 0 ? ` · ${formatCost(trace.billedUsd)} billed` : ""}`,
|
|
2584
|
+
value: `${partial ? "≥" : upper ? "≤" : list ? "≈" : ""}${formatCost(costUsd)}${trace.billedUsd !== void 0 ? ` · ${formatCost(trace.billedUsd)} billed` : ""}`,
|
|
2580
2585
|
title: [
|
|
2581
2586
|
partial ? `${coverage.priced} of ${coverage.total} model calls priced` : coverage ? `all ${coverage.total} model calls priced` : "",
|
|
2582
2587
|
list ? "at the model catalog list price; not a bill" : "",
|
|
2588
|
+
upper ? "cached input is not split out, so it is priced as fresh input: at most this" : "",
|
|
2583
2589
|
trace.billedUsd !== void 0 ? `billed ${formatCost(trace.billedUsd)} (the seat charge)` : ""
|
|
2584
2590
|
].filter(Boolean).join("; "),
|
|
2585
2591
|
label
|
|
@@ -2684,6 +2690,8 @@ const ZoomOutGlyph = () => svg(/* @__PURE__ */ jsxs(Fragment, { children: [/* @_
|
|
|
2684
2690
|
const FitGlyph = () => svg(/* @__PURE__ */ jsx("path", { d: "M2.5 6V3.5a1 1 0 0 1 1-1H6M10 2.5h2.5a1 1 0 0 1 1 1V6M13.5 10v2.5a1 1 0 0 1-1 1H10M6 13.5H3.5a1 1 0 0 1-1-1V10" }));
|
|
2685
2691
|
//#endregion
|
|
2686
2692
|
//#region src/react/flow-waterfall-card.tsx
|
|
2693
|
+
/** Names wrap between words, never at their hyphens ("memscale-engineer-" / "2" read as two names). */
|
|
2694
|
+
const keepWords = (name) => name.replace(/-/g, "‑");
|
|
2687
2695
|
const KIND_LABEL = {
|
|
2688
2696
|
pipeline: "Agent",
|
|
2689
2697
|
model: "LLM call",
|
|
@@ -2753,7 +2761,7 @@ function SpanCard({ id, row, agent, clockMs, left, top, pinned, onClose, renderI
|
|
|
2753
2761
|
}),
|
|
2754
2762
|
/* @__PURE__ */ jsx("span", {
|
|
2755
2763
|
className: "fw-card-who",
|
|
2756
|
-
children: who.name
|
|
2764
|
+
children: keepWords(who.name)
|
|
2757
2765
|
}),
|
|
2758
2766
|
outcome ? /* @__PURE__ */ jsx("span", {
|
|
2759
2767
|
className: "fw-pill fw-pill-outcome",
|
|
@@ -2840,7 +2848,7 @@ function SpanCard({ id, row, agent, clockMs, left, top, pinned, onClose, renderI
|
|
|
2840
2848
|
className: "fw-card-title",
|
|
2841
2849
|
children: [/* @__PURE__ */ jsx("div", {
|
|
2842
2850
|
className: "fw-card-name",
|
|
2843
|
-
children: span.name
|
|
2851
|
+
children: keepWords(span.name)
|
|
2844
2852
|
}), span.detail && /* @__PURE__ */ jsx("div", {
|
|
2845
2853
|
className: "fw-muted",
|
|
2846
2854
|
children: span.detail
|
|
@@ -2898,7 +2906,7 @@ const at = (startMs, endMs) => ({
|
|
|
2898
2906
|
"--e": Number.isFinite(endMs) ? endMs : OPEN_END
|
|
2899
2907
|
});
|
|
2900
2908
|
function Segment({ mark, events, agentView }) {
|
|
2901
|
-
const glyph = mark.kind === "failed" ? /* @__PURE__ */ jsx(FailGlyph, {}) : mark.retry ? /* @__PURE__ */ jsx(RetryGlyph, {}) : null;
|
|
2909
|
+
const glyph = mark.kind === "failed" ? agentView ? null : /* @__PURE__ */ jsx(FailGlyph, {}) : mark.retry ? /* @__PURE__ */ jsx(RetryGlyph, {}) : null;
|
|
2902
2910
|
return /* @__PURE__ */ jsx("span", {
|
|
2903
2911
|
className: `fw-seg fw-seg-${mark.kind}`,
|
|
2904
2912
|
"data-tone": toneKey(mark.tone),
|
|
@@ -3924,6 +3932,26 @@ const TONE_ORDER = [
|
|
|
3924
3932
|
"failed",
|
|
3925
3933
|
"neutral"
|
|
3926
3934
|
];
|
|
3935
|
+
/** What each mark means, as the agent view draws it; a key only for kinds the run has. */
|
|
3936
|
+
function KindLegend({ rows }) {
|
|
3937
|
+
const has = (kind) => rows.some((row) => row.own.some((mark) => mark.kind === kind) || row.span.kind === kind);
|
|
3938
|
+
const shown = [
|
|
3939
|
+
["model", "Model call"],
|
|
3940
|
+
["tool", "Tool call"],
|
|
3941
|
+
["waiting", "Waiting"],
|
|
3942
|
+
["handoff", "Handoff"],
|
|
3943
|
+
["failed", "Failed turn"]
|
|
3944
|
+
].filter(([kind]) => kind === "waiting" ? rows.some((row) => row.kind === "pipeline") : kind === "handoff" ? rows.some((row) => row.span.handoffTo || row.hasAgents) : has(kind));
|
|
3945
|
+
if (shown.length === 0) return null;
|
|
3946
|
+
return /* @__PURE__ */ jsx("ul", {
|
|
3947
|
+
className: "fw-legend fw-kinds",
|
|
3948
|
+
"aria-label": "Key",
|
|
3949
|
+
children: shown.map(([kind, name]) => /* @__PURE__ */ jsxs("li", { children: [/* @__PURE__ */ jsx("span", {
|
|
3950
|
+
className: `fw-swatch-${kind === "waiting" ? "wait" : kind}`,
|
|
3951
|
+
"aria-hidden": true
|
|
3952
|
+
}), name] }, kind))
|
|
3953
|
+
});
|
|
3954
|
+
}
|
|
3927
3955
|
function OutcomeLegend({ agents }) {
|
|
3928
3956
|
const items = /* @__PURE__ */ new Map();
|
|
3929
3957
|
for (const row of agents) {
|
|
@@ -3964,7 +3992,7 @@ function OutcomeLegend({ agents }) {
|
|
|
3964
3992
|
}
|
|
3965
3993
|
/** Shared trace inspector: the agent timeline and the span waterfall over one clock.
|
|
3966
3994
|
* Data remains producer-owned; playback, zoom and folding change presentation only. */
|
|
3967
|
-
function FlowWaterfall({ trace, live, startedAt, label = "Trace waterfall", defaultCollapsed = false, defaultView = "spans", renderIcon, maxHeight, onSelect, markers, onTimeChange, agentFill = "agent", selectedId, onDeselect }) {
|
|
3995
|
+
function FlowWaterfall({ trace, live, startedAt, label = "Trace waterfall", defaultCollapsed = false, defaultView = "spans", renderIcon, maxHeight, onSelect, markers, onTimeChange, agentFill = "agent", selectedId, onDeselect, description }) {
|
|
3968
3996
|
const root = useRef(null);
|
|
3969
3997
|
const search = useRef(null);
|
|
3970
3998
|
const slider = useRef(null);
|
|
@@ -4305,6 +4333,11 @@ function FlowWaterfall({ trace, live, startedAt, label = "Trace waterfall", defa
|
|
|
4305
4333
|
className: "fw-title",
|
|
4306
4334
|
children: label
|
|
4307
4335
|
}),
|
|
4336
|
+
description && /* @__PURE__ */ jsx("p", {
|
|
4337
|
+
className: "fw-description",
|
|
4338
|
+
title: description,
|
|
4339
|
+
children: description
|
|
4340
|
+
}),
|
|
4308
4341
|
isLive && /* @__PURE__ */ jsx("span", {
|
|
4309
4342
|
className: "fw-state fw-state-live",
|
|
4310
4343
|
children: "Live"
|
|
@@ -4450,6 +4483,7 @@ function FlowWaterfall({ trace, live, startedAt, label = "Trace waterfall", defa
|
|
|
4450
4483
|
compact: view === "agents"
|
|
4451
4484
|
})
|
|
4452
4485
|
}),
|
|
4486
|
+
view === "agents" && /* @__PURE__ */ jsx(KindLegend, { rows }),
|
|
4453
4487
|
view === "spans" && playback
|
|
4454
4488
|
]
|
|
4455
4489
|
});
|
package/dist/react/live.css
CHANGED
|
@@ -1,30 +1,31 @@
|
|
|
1
|
-
/* Shared live charts. Consumers may set --chart-live-* tokens on an ancestor.
|
|
2
|
-
|
|
1
|
+
/* Shared live charts. Consumers may set --chart-live-* tokens on an ancestor. Sizes are px on the 12/14 type scale and a
|
|
2
|
+
4 px grid, so a host's font size never rescales them. */
|
|
3
|
+
.ov-empty { margin: 0; color: var(--chart-live-faint, #777); font-size: 12px; }
|
|
3
4
|
.ov-plot { position: relative; min-width: 0; }
|
|
4
5
|
.ov-plot svg { display: block; overflow: visible; }
|
|
5
6
|
line.ov-gridline { stroke: color-mix(in srgb, var(--chart-live-faint, #777) 22%, transparent); stroke-width: 1; }
|
|
6
|
-
.ov-axis { fill: var(--chart-live-muted, #666); font:
|
|
7
|
+
.ov-axis { fill: var(--chart-live-muted, #666); font: 12px/16px var(--chart-live-font-mono, monospace); font-variant-numeric: tabular-nums; }
|
|
7
8
|
.ov-crosshair { stroke: var(--chart-live-faint, #777); stroke-dasharray: 3 3; }
|
|
8
|
-
.ov-tip { position: absolute; z-index: 4; display: grid; gap:
|
|
9
|
-
.ov-tip-line { display: grid; grid-template-columns: auto 1fr auto; gap:
|
|
9
|
+
.ov-tip { position: absolute; z-index: 4; display: grid; gap: 4px; min-width: 160px; max-width: 240px; padding: 8px 12px; background: var(--chart-live-raised, #fff); border: 1px solid var(--chart-live-border, #aaa); border-radius: 8px; box-shadow: 0 10px 24px -12px #000; font-size: 12px; line-height: 16px; pointer-events: none; }
|
|
10
|
+
.ov-tip-line { display: grid; grid-template-columns: auto 1fr auto; gap: 8px; align-items: center; color: var(--chart-live-muted, #666); }
|
|
10
11
|
.ov-tip-line b { color: var(--chart-live-fg, #222); font-variant-numeric: tabular-nums; }
|
|
11
|
-
.ov-hbars { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: minmax(0, max-content) minmax(33%, 1fr) max-content; gap:
|
|
12
|
+
.ov-hbars { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: minmax(0, max-content) minmax(33%, 1fr) max-content; gap: 4px 12px; }
|
|
12
13
|
.ov-hbars li { display: grid; grid-column: 1 / -1; grid-template-columns: subgrid; }
|
|
13
|
-
.ov-hbars li > a, .ov-hbars li > div { display: grid; grid-column: 1 / -1; grid-template-columns: subgrid; row-gap:
|
|
14
|
-
.ov-hbars-more { grid-column: 1 / -1; padding:
|
|
14
|
+
.ov-hbars li > a, .ov-hbars li > div { display: grid; grid-column: 1 / -1; grid-template-columns: subgrid; row-gap: 0; align-items: center; padding: 4px; border-radius: 6px; color: inherit; text-decoration: none; }
|
|
15
|
+
.ov-hbars-more { grid-column: 1 / -1; padding: 0 4px; font-size: 12px; color: var(--chart-live-faint, #777); }
|
|
15
16
|
.ov-hbars li > a:hover, .ov-hbars li > div:hover { background: var(--chart-live-hover, #eee); text-decoration: none; }
|
|
16
|
-
.ov-hbar-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size:
|
|
17
|
-
.ov-hbar-track { height:
|
|
17
|
+
.ov-hbar-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 14px; line-height: 20px; color: var(--chart-live-fg, #222); }
|
|
18
|
+
.ov-hbar-track { height: 8px; border-radius: 3px; background: color-mix(in srgb, var(--chart-live-faint, #777) 14%, transparent); overflow: hidden; }
|
|
18
19
|
.ov-hbar-track > span { display: block; height: 100%; border-radius: 3px; }
|
|
19
|
-
.ov-hbar-value { font:
|
|
20
|
-
.ov-hbar-note { grid-column: 1 / -1; font-size:
|
|
21
|
-
.ov-meter { display: grid; gap:
|
|
22
|
-
.ov-meter-track { display: block; height:
|
|
20
|
+
.ov-hbar-value { font: 12px/16px var(--chart-live-font-mono, monospace); font-variant-numeric: tabular-nums; text-align: right; color: var(--chart-live-fg, #222); }
|
|
21
|
+
.ov-hbar-note { grid-column: 1 / -1; font-size: 12px; color: var(--chart-live-faint, #777); }
|
|
22
|
+
.ov-meter { display: grid; gap: 4px; min-width: 0; }
|
|
23
|
+
.ov-meter-track { display: block; height: 8px; border-radius: 3px; background: color-mix(in srgb, var(--chart-live-faint, #777) 14%, transparent); overflow: hidden; }
|
|
23
24
|
.ov-meter-track > span { display: block; height: 100%; border-radius: 3px; }
|
|
24
|
-
.ov-meter-text { font:
|
|
25
|
-
.ov-spark { display: block; width:
|
|
26
|
-
.ov-spark-empty { font-size:
|
|
27
|
-
.ov-tip-line i { display: inline-block; width:
|
|
25
|
+
.ov-meter-text { font: 12px/16px var(--chart-live-font-mono, monospace); font-variant-numeric: tabular-nums; color: var(--chart-live-muted, #666); }
|
|
26
|
+
.ov-spark { display: block; width: 112px; height: 24px; }
|
|
27
|
+
.ov-spark-empty { font-size: 12px; color: var(--chart-live-faint, #777); }
|
|
28
|
+
.ov-tip-line i { display: inline-block; width: 8px; height: 8px; border-radius: 2px; margin-right: 4px; vertical-align: 0; }
|
|
28
29
|
/* Recorded events and spans. Colours come from Brand tokens; kinds also differ by stroke pattern and glyph. */
|
|
29
30
|
.ov-mark { stroke-width: 1.5; fill: none; }
|
|
30
31
|
.ov-mark-pass { stroke: var(--chart-live-pass, var(--chart-pass, var(--status-running))); }
|
|
@@ -44,7 +45,7 @@ line.ov-gridline { stroke: color-mix(in srgb, var(--chart-live-faint, #777) 22%,
|
|
|
44
45
|
.ov-verdict-fail .ov-mark-head { fill: var(--chart-live-danger, var(--chart-breach, var(--status-error))); }
|
|
45
46
|
.ov-verdict-unknown .ov-mark { stroke: var(--chart-live-faint, var(--chart-muted)); }
|
|
46
47
|
.ov-verdict-unknown .ov-mark-head { fill: var(--chart-live-faint, var(--chart-muted)); }
|
|
47
|
-
.ov-mark-label { fill: var(--chart-live-fg, var(--chart-ink)); font-size:
|
|
48
|
+
.ov-mark-label { fill: var(--chart-live-fg, var(--chart-ink)); font-size: 12px; paint-order: stroke; stroke: var(--chart-live-surface, var(--chart-canvas)); stroke-width: 3px; stroke-linejoin: round; }
|
|
48
49
|
.ov-band-after-pass { fill: color-mix(in srgb, var(--chart-live-pass, var(--chart-pass, var(--status-running))) 12%, transparent); }
|
|
49
50
|
.ov-band-idle { fill: var(--chart-live-hover, var(--chart-shade)); }
|
|
50
51
|
.ov-band-blocked { fill: color-mix(in srgb, var(--chart-live-danger, var(--chart-breach, var(--status-error))) 9%, transparent); }
|
|
@@ -56,10 +57,10 @@ line.ov-gridline { stroke: color-mix(in srgb, var(--chart-live-faint, #777) 22%,
|
|
|
56
57
|
.ov-hatched { background: repeating-linear-gradient(135deg, var(--chart-live-faint, var(--chart-muted)) 0 1px, transparent 1px 5px), color-mix(in srgb, var(--chart-live-faint, var(--chart-muted)) 10%, transparent); }
|
|
57
58
|
.ov-now { stroke: var(--chart-live-fg, var(--chart-ink)); stroke-width: 1.5; }
|
|
58
59
|
.ov-gantt-open { stroke: var(--chart-live-fg, var(--chart-ink)); stroke-width: 1.5; stroke-dasharray: 3 2; }
|
|
59
|
-
.ov-events, .ov-key, .ov-meter-key { list-style: none; margin:
|
|
60
|
-
.ov-key li, .ov-events li, .ov-meter-key li { display: inline-flex; align-items: center; gap:
|
|
60
|
+
.ov-events, .ov-key, .ov-meter-key { list-style: none; margin: 4px 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: 4px 16px; font-size: 12px; line-height: 16px; color: var(--chart-live-muted, var(--chart-ink-muted)); }
|
|
61
|
+
.ov-key li, .ov-events li, .ov-meter-key li { display: inline-flex; align-items: center; gap: 8px; }
|
|
61
62
|
.ov-meter-key b { font-weight: 500; color: var(--chart-live-fg, var(--chart-ink)); font-family: var(--chart-live-font-mono, monospace); font-variant-numeric: tabular-nums; }
|
|
62
|
-
.ov-meter-key i, .ov-event-swatch { display: inline-block; width:
|
|
63
|
+
.ov-meter-key i, .ov-event-swatch { display: inline-block; width: 12px; height: 12px; border-radius: 2px; }
|
|
63
64
|
[data-segmented] > .ov-meter-track { display: flex; }
|
|
64
65
|
[data-segmented] > .ov-meter-track > span { flex: none; border-radius: 0; }
|
|
65
66
|
.ov-event-pass { border-left: 2px solid var(--chart-live-pass, var(--chart-pass, var(--status-running))); border-radius: 0; width: 0; }
|
|
@@ -72,7 +73,7 @@ line.ov-gridline { stroke: color-mix(in srgb, var(--chart-live-faint, #777) 22%,
|
|
|
72
73
|
.ov-event-after-pass { background: color-mix(in srgb, var(--chart-live-pass, var(--chart-pass, var(--status-running))) 25%, transparent); }
|
|
73
74
|
.ov-event-idle { background: var(--chart-live-hover, var(--chart-shade)); }
|
|
74
75
|
.ov-event-missing { background: repeating-linear-gradient(135deg, var(--chart-live-faint, var(--chart-muted)) 0 1px, transparent 1px 4px); }
|
|
75
|
-
.ov-refusal { margin: 0; color: var(--chart-live-muted, var(--chart-ink-muted)); font-size:
|
|
76
|
+
.ov-refusal { margin: 0; color: var(--chart-live-muted, var(--chart-ink-muted)); font-size: 12px; }
|
|
76
77
|
|
|
77
78
|
/*
|
|
78
79
|
* DotMap: thousands of dots on one canvas. A categorical lens names at most three categories in colour, the first
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangle-network/charts",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.1",
|
|
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",
|