@tangle-network/charts 0.6.0 → 0.8.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 +26 -7
- package/dist/figure.css +36 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +37 -291
- package/dist/react/index.d.ts +22 -6
- package/dist/react/index.js +60 -9
- package/dist/react/live.css +18 -1
- package/dist/{timeline-BAjzF-wL.d.ts → timeline-CCEJug7n.d.ts} +41 -6
- package/dist/timeline-CCWFvLxg.js +1130 -0
- package/package.json +1 -1
- package/dist/events-Cw6abvgR.js +0 -491
package/dist/react/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { F as hatchPath, R as markerPath, l as markName, o as eventsGap, r as MARK_HEADS, t as timeline, u as isRefusal } from "../timeline-CCWFvLxg.js";
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { Fragment as Fragment$1, useEffect, useId, useRef, useState } from "react";
|
|
3
|
+
import { Fragment as Fragment$1, useEffect, useId, useMemo, useRef, useState } from "react";
|
|
4
4
|
//#region src/react/sparkline.tsx
|
|
5
5
|
const DEFAULT_SPARKLINE_WIDTH = 96;
|
|
6
6
|
const DEFAULT_SPARKLINE_HEIGHT = 24;
|
|
@@ -247,7 +247,7 @@ function StackedBarChart(props) {
|
|
|
247
247
|
validate(props);
|
|
248
248
|
const bySeries = new Map(series.map((entry) => [entry.id, entry]));
|
|
249
249
|
const formatted = (value) => isValue(value) ? formatValue(value) : unavailableLabel;
|
|
250
|
-
const summary = (bucket) => `${bucket.label}: total ${formatted(bucket.total)}` + (hasGap(bucket) ? ` — ${unavailableLabel}` : "") + (bucket.segments.length ? ` — ${bucket.segments.map((segment) => `${bySeries.get(segment.seriesId).label} ${formatted(segment.value)}`).join(", ")}` : "");
|
|
250
|
+
const summary = (bucket) => `${bucket.label}: total ${formatted(bucket.total)}` + (hasGap(bucket) ? ` — ${unavailableLabel}` : "") + (bucket.segments.length ? ` — ${bucket.segments.map((segment) => `${bySeries.get(segment.seriesId).label} ${formatted(segment.value)}`).join(", ")}` : "") + (bucket.description ? ` — ${bucket.description}` : "");
|
|
251
251
|
const activeIndex = selectedBucketId === null ? -1 : buckets.findIndex(({ id }) => id === selectedBucketId);
|
|
252
252
|
const activeBucket = activeIndex >= 0 ? buckets[activeIndex] : null, marginTop = 12, marginRight = 16, marginLeft = 56;
|
|
253
253
|
const chartHeight = 220;
|
|
@@ -490,7 +490,8 @@ function StackedBarChart(props) {
|
|
|
490
490
|
bySeries.get(segment.seriesId).label,
|
|
491
491
|
": ",
|
|
492
492
|
formatted(segment.value)
|
|
493
|
-
] }, segment.seriesId))
|
|
493
|
+
] }, segment.seriesId)),
|
|
494
|
+
activeBucket.description && /* @__PURE__ */ jsx("div", { children: activeBucket.description })
|
|
494
495
|
]
|
|
495
496
|
}),
|
|
496
497
|
/* @__PURE__ */ jsx("div", {
|
|
@@ -1267,13 +1268,17 @@ function Band({ band, x, y, width, height }) {
|
|
|
1267
1268
|
]
|
|
1268
1269
|
});
|
|
1269
1270
|
}
|
|
1270
|
-
/** A vertical event rule with its label; kinds differ by stroke pattern
|
|
1271
|
+
/** A vertical event rule with its label; kinds differ by stroke pattern, the died cross and the release, steer, ruling
|
|
1272
|
+
* and wake head shapes as well as colour, and a recorded verdict colours the rule. */
|
|
1271
1273
|
function Mark({ mark, x, top, bottom, row, em, flip }) {
|
|
1272
1274
|
const s = Math.max(3, em / 4);
|
|
1275
|
+
const head = MARK_HEADS[mark.kind];
|
|
1273
1276
|
return /* @__PURE__ */ jsxs("g", {
|
|
1274
1277
|
"data-mark": mark.kind,
|
|
1278
|
+
"data-verdict": mark.verdict,
|
|
1279
|
+
className: mark.verdict ? `ov-verdict-${mark.verdict}` : void 0,
|
|
1275
1280
|
children: [
|
|
1276
|
-
/* @__PURE__ */ jsx("title", { children: mark
|
|
1281
|
+
/* @__PURE__ */ jsx("title", { children: markName(mark) }),
|
|
1277
1282
|
/* @__PURE__ */ jsx("line", {
|
|
1278
1283
|
x1: x,
|
|
1279
1284
|
x2: x,
|
|
@@ -1285,12 +1290,16 @@ function Mark({ mark, x, top, bottom, row, em, flip }) {
|
|
|
1285
1290
|
d: `M${x - s} ${bottom - 2 * s}L${x + s} ${bottom}M${x - s} ${bottom}L${x + s} ${bottom - 2 * s}`,
|
|
1286
1291
|
className: "ov-mark ov-mark-died"
|
|
1287
1292
|
}),
|
|
1293
|
+
head && /* @__PURE__ */ jsx("path", {
|
|
1294
|
+
d: markerPath(head, x, top + s, s),
|
|
1295
|
+
className: "ov-mark-head"
|
|
1296
|
+
}),
|
|
1288
1297
|
/* @__PURE__ */ jsx("text", {
|
|
1289
1298
|
x: flip ? x - em * .3 : x + em * .3,
|
|
1290
1299
|
y: top + em * (.9 + row),
|
|
1291
1300
|
textAnchor: flip ? "end" : "start",
|
|
1292
1301
|
className: "ov-mark-label",
|
|
1293
|
-
children: mark
|
|
1302
|
+
children: markName(mark)
|
|
1294
1303
|
})
|
|
1295
1304
|
]
|
|
1296
1305
|
});
|
|
@@ -1301,7 +1310,7 @@ function EventList({ marks, bands, format }) {
|
|
|
1301
1310
|
const items = [...marks.map((m) => ({
|
|
1302
1311
|
at: m.at,
|
|
1303
1312
|
kind: m.kind,
|
|
1304
|
-
text: `${m
|
|
1313
|
+
text: `${markName(m)} · ${format(m.at)}${m.verdict ? ` · ${m.verdict}` : ""}`
|
|
1305
1314
|
})), ...bands.map((b) => ({
|
|
1306
1315
|
at: b.from,
|
|
1307
1316
|
kind: b.kind,
|
|
@@ -1682,4 +1691,46 @@ function FigureView({ figure, presentation = "chart" }) {
|
|
|
1682
1691
|
});
|
|
1683
1692
|
}
|
|
1684
1693
|
//#endregion
|
|
1685
|
-
|
|
1694
|
+
//#region src/react/timeline-view.tsx
|
|
1695
|
+
/** The static `timeline` in React, with lanes that fold by subtree. A parent lane's label is a toggle: a click, Enter
|
|
1696
|
+
* or Space folds its descendants away, and the folded lane's ticks and counts then total its subtree. */
|
|
1697
|
+
function TimelineView({ lanes, options, defaultCollapsed = [], presentation }) {
|
|
1698
|
+
const [collapsed, setCollapsed] = useState(defaultCollapsed);
|
|
1699
|
+
const box = useRef(null);
|
|
1700
|
+
const refocus = useRef(null);
|
|
1701
|
+
const figure = useMemo(() => timeline(lanes, {
|
|
1702
|
+
...options,
|
|
1703
|
+
collapsed
|
|
1704
|
+
}), [
|
|
1705
|
+
lanes,
|
|
1706
|
+
options,
|
|
1707
|
+
collapsed
|
|
1708
|
+
]);
|
|
1709
|
+
useEffect(() => {
|
|
1710
|
+
const id = refocus.current;
|
|
1711
|
+
refocus.current = null;
|
|
1712
|
+
if (id === null || !box.current) return;
|
|
1713
|
+
Array.from(box.current.querySelectorAll("[data-toggle]")).find((element) => element.getAttribute("data-toggle") === id)?.focus();
|
|
1714
|
+
}, [figure]);
|
|
1715
|
+
const fold = (target, keyboard) => {
|
|
1716
|
+
const id = target instanceof Element ? target.closest("[data-toggle]")?.getAttribute("data-toggle") : null;
|
|
1717
|
+
if (!id) return false;
|
|
1718
|
+
if (keyboard) refocus.current = id;
|
|
1719
|
+
setCollapsed((list) => list.includes(id) ? list.filter((other) => other !== id) : [...list, id]);
|
|
1720
|
+
return true;
|
|
1721
|
+
};
|
|
1722
|
+
return /* @__PURE__ */ jsx("div", {
|
|
1723
|
+
ref: box,
|
|
1724
|
+
className: "tgc-timeline-view",
|
|
1725
|
+
onClick: (event) => fold(event.target, false),
|
|
1726
|
+
onKeyDown: (event) => {
|
|
1727
|
+
if ((event.key === "Enter" || event.key === " ") && fold(event.target, true)) event.preventDefault();
|
|
1728
|
+
},
|
|
1729
|
+
children: /* @__PURE__ */ jsx(FigureView, {
|
|
1730
|
+
figure,
|
|
1731
|
+
presentation
|
|
1732
|
+
})
|
|
1733
|
+
});
|
|
1734
|
+
}
|
|
1735
|
+
//#endregion
|
|
1736
|
+
export { DEFAULT_SPARKLINE_EMPTY_LABEL, DEFAULT_SPARKLINE_HEIGHT, DEFAULT_SPARKLINE_LABEL, DEFAULT_SPARKLINE_UNAVAILABLE_LABEL, DEFAULT_SPARKLINE_WIDTH, DayBars, FigureView, Gantt, HBars, Histogram, LIVE_SERIES, Lines, Meter, Spark, Sparkline, StackedBarChart, TimelineView, WaterfallBar, WaterfallHeader, WaterfallRow, WaterfallTimeAxis, formatCompact, formatSparklineValue, formatWaterfallDuration, sparklineGeometry, sparklineLabel, sparklinePointsAttribute, sparklineReadings, waterfallSpanGeometry, waterfallTicks };
|
package/dist/react/live.css
CHANGED
|
@@ -31,9 +31,23 @@ line.ov-gridline { stroke: color-mix(in srgb, var(--chart-live-faint, #777) 22%,
|
|
|
31
31
|
.ov-mark-deadline { stroke: var(--chart-live-fg, var(--chart-ink)); stroke-dasharray: 5 3; }
|
|
32
32
|
.ov-mark-died { stroke: var(--chart-live-danger, var(--chart-breach, var(--status-error))); stroke-width: 2; }
|
|
33
33
|
.ov-mark-event { stroke: var(--chart-live-muted, var(--chart-ink-muted)); stroke-dasharray: 1 3; stroke-linecap: round; }
|
|
34
|
+
.ov-mark-release { stroke: var(--chart-live-muted, var(--chart-ink-muted)); }
|
|
35
|
+
.ov-mark-steer { stroke: var(--chart-live-accent, var(--chart-accent)); stroke-dasharray: 1 3; stroke-linecap: round; }
|
|
36
|
+
.ov-mark-ruling { stroke: var(--chart-live-fg, var(--chart-ink)); stroke-dasharray: 6 2 1 2; }
|
|
37
|
+
.ov-mark-wake { stroke: var(--chart-live-muted, var(--chart-ink-muted)); stroke-dasharray: 1 3; stroke-linecap: round; }
|
|
38
|
+
.ov-mark-head { fill: var(--chart-live-muted, var(--chart-ink-muted)); stroke: var(--chart-live-surface, var(--chart-canvas)); stroke-width: 1; }
|
|
39
|
+
[data-mark="steer"] .ov-mark-head { fill: var(--chart-live-accent, var(--chart-accent)); }
|
|
40
|
+
[data-mark="ruling"] .ov-mark-head { fill: var(--chart-live-fg, var(--chart-ink)); }
|
|
41
|
+
.ov-verdict-pass .ov-mark { stroke: var(--chart-live-pass, var(--chart-pass, var(--status-running))); }
|
|
42
|
+
.ov-verdict-pass .ov-mark-head { fill: var(--chart-live-pass, var(--chart-pass, var(--status-running))); }
|
|
43
|
+
.ov-verdict-fail .ov-mark { stroke: var(--chart-live-danger, var(--chart-breach, var(--status-error))); }
|
|
44
|
+
.ov-verdict-fail .ov-mark-head { fill: var(--chart-live-danger, var(--chart-breach, var(--status-error))); }
|
|
45
|
+
.ov-verdict-unknown .ov-mark { stroke: var(--chart-live-faint, var(--chart-muted)); }
|
|
46
|
+
.ov-verdict-unknown .ov-mark-head { fill: var(--chart-live-faint, var(--chart-muted)); }
|
|
34
47
|
.ov-mark-label { fill: var(--chart-live-fg, var(--chart-ink)); font-size: .75em; paint-order: stroke; stroke: var(--chart-live-surface, var(--chart-canvas)); stroke-width: 3px; stroke-linejoin: round; }
|
|
35
48
|
.ov-band-after-pass { fill: color-mix(in srgb, var(--chart-live-pass, var(--chart-pass, var(--status-running))) 12%, transparent); }
|
|
36
49
|
.ov-band-idle { fill: var(--chart-live-hover, var(--chart-shade)); }
|
|
50
|
+
.ov-band-blocked { fill: color-mix(in srgb, var(--chart-live-danger, var(--chart-breach, var(--status-error))) 9%, transparent); }
|
|
37
51
|
/* Missing data is hatched, never drawn as zero. */
|
|
38
52
|
.ov-hatch-bg { fill: color-mix(in srgb, var(--chart-live-faint, var(--chart-muted)) 10%, transparent); }
|
|
39
53
|
.ov-hatch { fill: none; stroke: var(--chart-live-faint, var(--chart-muted)); stroke-width: 1; }
|
|
@@ -49,7 +63,10 @@ line.ov-gridline { stroke: color-mix(in srgb, var(--chart-live-faint, #777) 22%,
|
|
|
49
63
|
.ov-event-pass { border-left: 2px solid var(--chart-live-pass, var(--chart-pass, var(--status-running))); border-radius: 0; width: 0; }
|
|
50
64
|
.ov-event-deadline { border-left: 2px dashed var(--chart-live-fg, var(--chart-ink)); border-radius: 0; width: 0; }
|
|
51
65
|
.ov-event-died { border-left: 2px solid var(--chart-live-danger, var(--chart-breach, var(--status-error))); border-radius: 0; width: 0; }
|
|
52
|
-
.ov-event-event { border-left: 2px dotted var(--chart-live-muted, var(--chart-ink-muted)); border-radius: 0; width: 0; }
|
|
66
|
+
.ov-event-event, .ov-event-steer, .ov-event-wake { border-left: 2px dotted var(--chart-live-muted, var(--chart-ink-muted)); border-radius: 0; width: 0; }
|
|
67
|
+
.ov-event-release { border-left: 2px solid var(--chart-live-muted, var(--chart-ink-muted)); border-radius: 0; width: 0; }
|
|
68
|
+
.ov-event-ruling { border-left: 2px dashed var(--chart-live-fg, var(--chart-ink)); border-radius: 0; width: 0; }
|
|
69
|
+
.ov-event-blocked { background: color-mix(in srgb, var(--chart-live-danger, var(--chart-breach, var(--status-error))) 25%, transparent); }
|
|
53
70
|
.ov-event-after-pass { background: color-mix(in srgb, var(--chart-live-pass, var(--chart-pass, var(--status-running))) 25%, transparent); }
|
|
54
71
|
.ov-event-idle { background: var(--chart-live-hover, var(--chart-shade)); }
|
|
55
72
|
.ov-event-missing { background: repeating-linear-gradient(135deg, var(--chart-live-faint, var(--chart-muted)) 0 1px, transparent 1px 4px); }
|
|
@@ -133,15 +133,25 @@ interface Refusal {
|
|
|
133
133
|
declare function isRefusal(value: Figure | Refusal): value is Refusal;
|
|
134
134
|
//#endregion
|
|
135
135
|
//#region src/events.d.ts
|
|
136
|
-
/**
|
|
137
|
-
|
|
136
|
+
/**
|
|
137
|
+
* `pass` is solid, `deadline` dashed, `died` ends in a cross and `event` is dotted. `release`, `steer`, `ruling` and
|
|
138
|
+
* `wake` carry a head shape (diamond, triangle, square, circle), so every kind reads without colour.
|
|
139
|
+
*/
|
|
140
|
+
type MarkKind = "pass" | "deadline" | "died" | "event" | "release" | "steer" | "ruling" | "wake";
|
|
141
|
+
/** A recorded verdict, such as a release tag's check: pass and fail take the status tones, unknown the muted tone. */
|
|
142
|
+
type MarkVerdict = "pass" | "fail" | "unknown";
|
|
138
143
|
interface ChartMark {
|
|
139
144
|
at: number;
|
|
140
145
|
label: string;
|
|
141
146
|
kind: MarkKind;
|
|
147
|
+
verdict?: MarkVerdict;
|
|
148
|
+
/** Who made the event, such as the operator or the keeper for a steer. Shown with the label and in the table. */
|
|
149
|
+
source?: string;
|
|
150
|
+
/** `timeline` only: the lane the event belongs to. It is drawn on that lane instead of across every lane. */
|
|
151
|
+
lane?: string;
|
|
142
152
|
}
|
|
143
|
-
/** `missing` is hatched: a span with no data is never drawn as zero. */
|
|
144
|
-
type BandKind = "after-pass" | "idle" | "missing";
|
|
153
|
+
/** `missing` is hatched: a span with no data is never drawn as zero. `blocked` is a system-wide wall, such as a quota window. */
|
|
154
|
+
type BandKind = "after-pass" | "idle" | "missing" | "blocked";
|
|
145
155
|
interface ChartBand {
|
|
146
156
|
from: number;
|
|
147
157
|
to: number;
|
|
@@ -157,14 +167,33 @@ interface TimelineSpan {
|
|
|
157
167
|
state: string;
|
|
158
168
|
note?: string;
|
|
159
169
|
}
|
|
170
|
+
/** How one recorded attempt ended. `ok` succeeded; every other outcome counts as failed. */
|
|
171
|
+
type TickOutcome = "ok" | "quota" | "rate-limit" | "oom" | "refused" | "aborted" | "other";
|
|
172
|
+
/** One recorded attempt on a lane, such as a driver turn, at the time it ended. `note` (an error line) shows on hover. */
|
|
173
|
+
interface TimelineTick {
|
|
174
|
+
at: number;
|
|
175
|
+
outcome: TickOutcome;
|
|
176
|
+
note?: string;
|
|
177
|
+
}
|
|
160
178
|
interface TimelineLane {
|
|
161
179
|
id: string;
|
|
162
180
|
label: string;
|
|
163
181
|
spans: TimelineSpan[];
|
|
182
|
+
/** The lane that started this one. The lane is drawn under its parent with a tree connector. */
|
|
183
|
+
parent?: string;
|
|
184
|
+
/** Tree depth: 0 for a root. Defaults to the parent's depth plus one, or 0 without a parent. */
|
|
185
|
+
depth?: number;
|
|
186
|
+
/** Recorded attempts, drawn as ticks with ok and failed counts at the lane's end. Omit when attempts are not recorded. */
|
|
187
|
+
ticks?: TimelineTick[];
|
|
188
|
+
/** Caller-composed facts, one per hover line on the lane and each of its spans: profile, model, status, attempts, cost, top error. */
|
|
189
|
+
detail?: string[];
|
|
164
190
|
}
|
|
165
191
|
interface TimelineOptions {
|
|
166
192
|
measure: string;
|
|
167
|
-
/**
|
|
193
|
+
/**
|
|
194
|
+
* The recorded window; defaults to the extent of the data (spans, ticks and `now`). Spans, ticks and `now` must fall
|
|
195
|
+
* inside it. Marks outside it, such as a later deadline, are named at the edge they fall past; bands are clipped.
|
|
196
|
+
*/
|
|
168
197
|
start?: number;
|
|
169
198
|
end?: number;
|
|
170
199
|
/** The time an open span is drawn to. Required when any span is open. */
|
|
@@ -175,9 +204,15 @@ interface TimelineOptions {
|
|
|
175
204
|
hatch?: string[];
|
|
176
205
|
/** States drawn in the muted tone, such as idle. Default: idle. */
|
|
177
206
|
muted?: string[];
|
|
207
|
+
/**
|
|
208
|
+
* Lane ids whose subtrees are folded: descendants are hidden and the lane's ticks and counts include them. Passing
|
|
209
|
+
* it, even empty, makes each parent lane's label a fold toggle (`data-toggle`), which React `TimelineView` wires up.
|
|
210
|
+
* Ids that name no lane are ignored, so a fold state can outlive the lanes it was made for.
|
|
211
|
+
*/
|
|
212
|
+
collapsed?: string[];
|
|
178
213
|
formatTime?: (ms: number) => string;
|
|
179
214
|
id?: string;
|
|
180
215
|
}
|
|
181
216
|
declare function timeline(lanes: TimelineLane[], o: TimelineOptions): Figure | Refusal;
|
|
182
217
|
//#endregion
|
|
183
|
-
export {
|
|
218
|
+
export { Setup as C, isRefusal as E, Refusal as S, TierCounts as T, Figure as _, TimelineTick as a, MatrixCell as b, ChartBand as c, MarkVerdict as d, BreakdownInput as f, Exclusion as g, Estimate as h, TimelineSpan as i, ChartMark as l, CostBasis as m, TimelineLane as n, timeline as o, ComparisonRow as p, TimelineOptions as r, BandKind as s, TickOutcome as t, MarkKind as u, Interval as v, Tier as w, RateRow as x, IntervalMethod as y };
|