@devicechain/widgets 0.23.0 → 0.24.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 +8 -3
- package/dist/aggregate-fold.d.ts +3 -2
- package/dist/aggregate-strings.d.ts +1 -0
- package/dist/alarm-strings.d.ts +18 -0
- package/dist/binding-policy.d.ts +4 -0
- package/dist/bound-devices-notice.d.ts +30 -0
- package/dist/builtin-descriptors.d.ts +290 -249
- package/dist/builtin-option-docs.d.ts +2 -0
- package/dist/builtin-registry.d.ts +249 -226
- package/dist/category-geometry.d.ts +1 -0
- package/dist/chunks/{aggregate-feed-BD3CHNFU.js → aggregate-feed-4FSBQYJL.js} +39 -11
- package/dist/chunks/aggregate-feed-4FSBQYJL.js.map +7 -0
- package/dist/chunks/{aggregate-widgets-HZQI5HTX.js → aggregate-widgets-2ZQBW3YF.js} +376 -182
- package/dist/chunks/aggregate-widgets-2ZQBW3YF.js.map +7 -0
- package/dist/chunks/alarm-widgets-X4PX5MYJ.js +72 -0
- package/dist/chunks/alarm-widgets-X4PX5MYJ.js.map +7 -0
- package/dist/chunks/chunk-546TK2QG.js +722 -0
- package/dist/chunks/chunk-546TK2QG.js.map +7 -0
- package/dist/chunks/{chunk-WBKHYZU2.js → chunk-62CHYCHI.js} +6 -62
- package/dist/chunks/chunk-62CHYCHI.js.map +7 -0
- package/dist/chunks/chunk-BMFQOTYG.js +41 -0
- package/dist/chunks/chunk-BMFQOTYG.js.map +7 -0
- package/dist/chunks/{chunk-2D7JNKFE.js → chunk-JFH4QMLA.js} +28 -4
- package/dist/chunks/chunk-JFH4QMLA.js.map +7 -0
- package/dist/chunks/chunk-QMGKB6J3.js +84 -0
- package/dist/chunks/chunk-QMGKB6J3.js.map +7 -0
- package/dist/chunks/chunk-XNEBAY4J.js +19 -0
- package/dist/chunks/chunk-XNEBAY4J.js.map +7 -0
- package/dist/chunks/chunk-YYJV54BV.js +58 -0
- package/dist/chunks/chunk-YYJV54BV.js.map +7 -0
- package/dist/chunks/compare-feed-AY3CVKUZ.js +346 -0
- package/dist/chunks/compare-feed-AY3CVKUZ.js.map +7 -0
- package/dist/chunks/{control-widgets-3V2LSSRF.js → control-widgets-UCTJJJ2D.js} +267 -78
- package/dist/chunks/control-widgets-UCTJJJ2D.js.map +7 -0
- package/dist/chunks/event-markers-feed-GEGTIHXT.js +373 -0
- package/dist/chunks/event-markers-feed-GEGTIHXT.js.map +7 -0
- package/dist/chunks/{fleet-feed-5QGDLOV5.js → fleet-feed-2SKDR6ZQ.js} +47 -8
- package/dist/chunks/fleet-feed-2SKDR6ZQ.js.map +7 -0
- package/dist/chunks/presence-widgets-2LIUKN4Y.js +350 -0
- package/dist/chunks/presence-widgets-2LIUKN4Y.js.map +7 -0
- package/dist/command-control-strings.d.ts +5 -0
- package/dist/compare-feed.d.ts +13 -0
- package/dist/compare-model.d.ts +38 -0
- package/dist/compare-strings.d.ts +13 -0
- package/dist/documented-descriptors.d.ts +4826 -0
- package/dist/event-markers-feed.d.ts +11 -0
- package/dist/event-markers-model.d.ts +38 -0
- package/dist/event-markers-strings.d.ts +20 -0
- package/dist/event-markers-types.d.ts +7 -0
- package/dist/fleet-count-model.d.ts +13 -0
- package/dist/fleet-feed.d.ts +1 -0
- package/dist/fleet-model.d.ts +1 -0
- package/dist/fleet-strings.d.ts +11 -0
- package/dist/index.d.ts +6 -3
- package/dist/index.js +946 -398
- package/dist/index.js.map +4 -4
- package/dist/presence-feed.d.ts +24 -0
- package/dist/presence-model.d.ts +13 -0
- package/dist/presence-strings.d.ts +19 -0
- package/dist/sparkline.d.ts +23 -0
- package/dist/use-bound-devices.d.ts +26 -0
- package/dist/widgets/aggregate-lazy.d.ts +81 -46
- package/dist/widgets/aggregate-widgets.d.ts +1 -0
- package/dist/widgets/alarm-grouped.d.ts +17 -0
- package/dist/widgets/alarm-lazy.d.ts +63 -16
- package/dist/widgets/alarm-severity.d.ts +8 -0
- package/dist/widgets/alarm-table.d.ts +2 -0
- package/dist/widgets/alarm-type-tabs.d.ts +10 -0
- package/dist/widgets/alarm-widgets.d.ts +2 -0
- package/dist/widgets/command-stepper.d.ts +22 -0
- package/dist/widgets/control-lazy.d.ts +16 -24
- package/dist/widgets/device-status.d.ts +4 -0
- package/dist/widgets/fleet-count.d.ts +2 -0
- package/dist/widgets/gauge.d.ts +2 -15
- package/dist/widgets/image.d.ts +2 -6
- package/dist/widgets/label.d.ts +2 -6
- package/dist/widgets/latest-card.d.ts +2 -13
- package/dist/widgets/lazy-chunk.d.ts +7 -2
- package/dist/widgets/level-lazy.d.ts +14 -96
- package/dist/widgets/map.d.ts +8 -5
- package/dist/widgets/online-doughnut.d.ts +2 -0
- package/dist/widgets/presence-lazy.d.ts +27 -0
- package/dist/widgets/presence-widgets.d.ts +3 -0
- package/dist/widgets/selection-lazy.d.ts +2 -4
- package/dist/widgets/table-lazy.d.ts +2 -7
- package/dist/widgets/time-series-chart.d.ts +62 -12
- package/package.json +13 -13
- package/dist/chunks/aggregate-feed-BD3CHNFU.js.map +0 -7
- package/dist/chunks/aggregate-widgets-HZQI5HTX.js.map +0 -7
- package/dist/chunks/alarm-widgets-7UY6MIYZ.js +0 -9
- package/dist/chunks/alarm-widgets-7UY6MIYZ.js.map +0 -7
- package/dist/chunks/chunk-2D7JNKFE.js.map +0 -7
- package/dist/chunks/chunk-6OGI4UFJ.js +0 -367
- package/dist/chunks/chunk-6OGI4UFJ.js.map +0 -7
- package/dist/chunks/chunk-WBKHYZU2.js.map +0 -7
- package/dist/chunks/control-widgets-3V2LSSRF.js.map +0 -7
- package/dist/chunks/fleet-feed-5QGDLOV5.js.map +0 -7
|
@@ -5,10 +5,17 @@ import {
|
|
|
5
5
|
columnNames,
|
|
6
6
|
deviceBars,
|
|
7
7
|
deviceLabel,
|
|
8
|
-
fleetStrings,
|
|
9
8
|
pageCount,
|
|
10
9
|
sortMembers
|
|
11
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-62CHYCHI.js";
|
|
11
|
+
import {
|
|
12
|
+
niceDomain,
|
|
13
|
+
pieSlices,
|
|
14
|
+
wedgePath
|
|
15
|
+
} from "./chunk-YYJV54BV.js";
|
|
16
|
+
import {
|
|
17
|
+
fleetStrings
|
|
18
|
+
} from "./chunk-QMGKB6J3.js";
|
|
12
19
|
import "./chunk-BRH66T5F.js";
|
|
13
20
|
import {
|
|
14
21
|
LevelEmpty,
|
|
@@ -37,6 +44,7 @@ var AGGREGATE_STRINGS = {
|
|
|
37
44
|
noReadings: (span) => `No readings in the last ${span}`,
|
|
38
45
|
noData: "No data",
|
|
39
46
|
unbound: "Choose a device for this widget",
|
|
47
|
+
trend: (stat, span) => `${stat} trend over the last ${span}`,
|
|
40
48
|
noCategories: "Select the measurements to show",
|
|
41
49
|
pieNegative: "A pie needs values of zero or more",
|
|
42
50
|
pieNoShare: "Every value is zero, so there is no share to show"
|
|
@@ -49,6 +57,7 @@ var AGGREGATE_STRINGS = {
|
|
|
49
57
|
noReadings: (span) => `Sin lecturas en los \xFAltimos ${span}`,
|
|
50
58
|
noData: "Sin datos",
|
|
51
59
|
unbound: "Elija un dispositivo para este widget",
|
|
60
|
+
trend: (stat, span) => `Tendencia de ${stat.toLowerCase()} en los \xFAltimos ${span}`,
|
|
52
61
|
noCategories: "Seleccione las mediciones que mostrar",
|
|
53
62
|
pieNegative: "Un gr\xE1fico circular necesita valores de cero o m\xE1s",
|
|
54
63
|
pieNoShare: "Todos los valores son cero, no hay proporci\xF3n que mostrar"
|
|
@@ -87,50 +96,6 @@ function pieProblem(items) {
|
|
|
87
96
|
return void 0;
|
|
88
97
|
}
|
|
89
98
|
|
|
90
|
-
// src/category-geometry.ts
|
|
91
|
-
function niceDomain(values, intervals = 4) {
|
|
92
|
-
const finite = values.filter(Number.isFinite);
|
|
93
|
-
let lo = Math.min(0, ...finite);
|
|
94
|
-
let hi = Math.max(0, ...finite);
|
|
95
|
-
if (lo === hi) hi = lo + 1;
|
|
96
|
-
const raw = (hi - lo) / Math.max(1, intervals);
|
|
97
|
-
const magnitude = 10 ** Math.floor(Math.log10(raw));
|
|
98
|
-
const norm = raw / magnitude;
|
|
99
|
-
const step = (norm <= 1 ? 1 : norm <= 2 ? 2 : norm <= 2.5 ? 2.5 : norm <= 5 ? 5 : 10) * magnitude;
|
|
100
|
-
lo = Math.floor(lo / step + 1e-9) * step;
|
|
101
|
-
hi = Math.ceil(hi / step - 1e-9) * step;
|
|
102
|
-
const decimals = Math.max(0, -Math.floor(Math.log10(step)) + 1);
|
|
103
|
-
const round = (v) => Number(v.toFixed(decimals));
|
|
104
|
-
const ticks = [];
|
|
105
|
-
for (let i = 0; lo + i * step <= hi + step * 1e-9; i++) ticks.push(round(lo + i * step));
|
|
106
|
-
return { min: round(lo), max: round(hi), step, ticks };
|
|
107
|
-
}
|
|
108
|
-
function pieSlices(values) {
|
|
109
|
-
const positive = values.map((v) => v !== null && v > 0 ? v : 0);
|
|
110
|
-
const total = positive.reduce((a, v) => a + v, 0);
|
|
111
|
-
let at = 0;
|
|
112
|
-
return positive.map((v, index) => {
|
|
113
|
-
const fraction = total > 0 ? v / total : 0;
|
|
114
|
-
const slice = { index, fraction, from: at, to: at + fraction };
|
|
115
|
-
at += fraction;
|
|
116
|
-
return slice;
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
function polar(cx, cy, r, turns) {
|
|
120
|
-
const angle = turns * 2 * Math.PI;
|
|
121
|
-
return { x: cx + r * Math.sin(angle), y: cy - r * Math.cos(angle) };
|
|
122
|
-
}
|
|
123
|
-
function wedgePath(cx, cy, r, from, to) {
|
|
124
|
-
const span = to - from;
|
|
125
|
-
if (span <= 0) return void 0;
|
|
126
|
-
if (span >= 1 - 1e-9) {
|
|
127
|
-
return `M${cx},${cy - r}A${r},${r} 0 1 1 ${cx},${cy + r}A${r},${r} 0 1 1 ${cx},${cy - r}Z`;
|
|
128
|
-
}
|
|
129
|
-
const a = polar(cx, cy, r, from);
|
|
130
|
-
const b = polar(cx, cy, r, to);
|
|
131
|
-
return `M${cx},${cy}L${a.x},${a.y}A${r},${r} 0 ${span > 0.5 ? 1 : 0} 1 ${b.x},${b.y}Z`;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
99
|
// src/widgets/bar-chart.tsx
|
|
135
100
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
136
101
|
var CHAR_EM = 0.6;
|
|
@@ -295,30 +260,156 @@ function Bars({
|
|
|
295
260
|
);
|
|
296
261
|
}
|
|
297
262
|
|
|
298
|
-
// src/widgets/fleet-
|
|
299
|
-
import {
|
|
263
|
+
// src/widgets/fleet-count.tsx
|
|
264
|
+
import { useMemo as useMemo2 } from "react";
|
|
300
265
|
import {
|
|
301
|
-
ageSeconds,
|
|
302
|
-
bandAt,
|
|
303
266
|
css as css2,
|
|
267
|
+
FIT_MIN_FONT_PX,
|
|
304
268
|
fontVar,
|
|
269
|
+
levelColor,
|
|
270
|
+
optString as optString2,
|
|
271
|
+
optThresholds,
|
|
272
|
+
primaryMeasurementName,
|
|
273
|
+
spaceVar,
|
|
274
|
+
useSeverityColors,
|
|
275
|
+
WidgetFrame as WidgetFrame2
|
|
276
|
+
} from "@devicechain/widget-sdk";
|
|
277
|
+
|
|
278
|
+
// src/fleet-count-model.ts
|
|
279
|
+
import { bandAt, SEVERITY_LEVELS, isAlarmLevel } from "@devicechain/widget-sdk";
|
|
280
|
+
function attentionCount(members, measurement, thresholds) {
|
|
281
|
+
let flagged = 0;
|
|
282
|
+
let reporting = 0;
|
|
283
|
+
let pending = 0;
|
|
284
|
+
let unread = 0;
|
|
285
|
+
let notMeasured = 0;
|
|
286
|
+
let worst;
|
|
287
|
+
let band;
|
|
288
|
+
let mixed = false;
|
|
289
|
+
for (const m of members) {
|
|
290
|
+
const cell = cellFor(m, measurement);
|
|
291
|
+
if (cell.kind === "loading") pending++;
|
|
292
|
+
else if (cell.kind === "failed" || cell.kind === "unread") unread++;
|
|
293
|
+
else if (cell.kind === "not-reported") notMeasured++;
|
|
294
|
+
if (cell.kind !== "value") continue;
|
|
295
|
+
reporting++;
|
|
296
|
+
const hit = bandAt(thresholds, cell.value);
|
|
297
|
+
if (!hit || !isAlarmLevel(hit.level)) continue;
|
|
298
|
+
flagged++;
|
|
299
|
+
if (worst === void 0 || SEVERITY_LEVELS.indexOf(hit.level) > SEVERITY_LEVELS.indexOf(worst)) worst = hit.level;
|
|
300
|
+
if (band === void 0) band = hit;
|
|
301
|
+
else if (band !== hit) mixed = true;
|
|
302
|
+
}
|
|
303
|
+
return { members: members.length - notMeasured, notMeasured, flagged, reporting, pending, unread, worst, label: !mixed ? band?.label : void 0 };
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// src/widgets/fleet-count.tsx
|
|
307
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
308
|
+
var CAPTION_ROOM_PX = 22;
|
|
309
|
+
function FleetCount({ widget, data }) {
|
|
310
|
+
const strings = fleetStrings();
|
|
311
|
+
const severity = useSeverityColors();
|
|
312
|
+
const fleet = data.members;
|
|
313
|
+
const showDevices = optString2(widget.options, "show") === "devices";
|
|
314
|
+
const measurement = optString2(widget.options, "measurement") ?? primaryMeasurementName(widget);
|
|
315
|
+
const thresholds = useMemo2(() => optThresholds(widget.options, "thresholds"), [widget.options]);
|
|
316
|
+
const title = optString2(widget.options, "title");
|
|
317
|
+
const empty = (message) => /* @__PURE__ */ jsx2(WidgetFrame2, { title, children: /* @__PURE__ */ jsx2(LevelEmpty, { message }) });
|
|
318
|
+
if (!fleet || fleet.status === "loading") return empty(strings.loading);
|
|
319
|
+
if (fleet.status === "unbound") return empty(strings.unbound);
|
|
320
|
+
if (fleet.status === "forbidden") return empty(strings.forbidden);
|
|
321
|
+
if (fleet.status === "unsupported") return empty(strings.unsupported);
|
|
322
|
+
if (!showDevices) {
|
|
323
|
+
if (measurement === void 0) return empty(strings.noMeasurementCount);
|
|
324
|
+
if (thresholds.length === 0) return empty(strings.noBands);
|
|
325
|
+
}
|
|
326
|
+
const counted = showDevices ? void 0 : attentionCount(fleet.members, measurement ?? "", thresholds);
|
|
327
|
+
if (!showDevices && fleet.members.length === 0) return empty(strings.noMembers);
|
|
328
|
+
if (counted && counted.pending > 0) return empty(strings.loading);
|
|
329
|
+
if (counted && counted.members === 0) {
|
|
330
|
+
return empty(fleet.truncated ? strings.noneMeasuredShown(fleet.members.length, fleet.total) : strings.noneMeasured);
|
|
331
|
+
}
|
|
332
|
+
const figure = showDevices ? String(fleet.total) : String(counted.flagged);
|
|
333
|
+
const unit = showDevices ? void 0 : strings.countOf(counted.members);
|
|
334
|
+
const color = counted ? levelColor(severity, counted.worst) : void 0;
|
|
335
|
+
const caption2 = showDevices ? strings.devices : counted.flagged > 0 ? counted.label ?? strings.needAttention : strings.needAttention;
|
|
336
|
+
const notes = [];
|
|
337
|
+
if (counted) {
|
|
338
|
+
const silent = counted.members - counted.reporting - counted.unread;
|
|
339
|
+
if (silent > 0) notes.push(strings.notReporting(silent));
|
|
340
|
+
if (counted.unread > 0) notes.push(strings.notRead(counted.unread));
|
|
341
|
+
if (counted.notMeasured > 0) notes.push(strings.notMeasured(counted.notMeasured));
|
|
342
|
+
if (fleet.truncated) notes.push(strings.truncated(fleet.members.length, fleet.total));
|
|
343
|
+
}
|
|
344
|
+
return /* @__PURE__ */ jsx2(WidgetFrame2, { title, children: ({ size, scale }) => {
|
|
345
|
+
const room = Math.round(CAPTION_ROOM_PX * scale) * (1 + notes.length);
|
|
346
|
+
const fit = { width: size.width, height: Math.max(Math.round(FIT_MIN_FONT_PX * scale), size.height - room) };
|
|
347
|
+
return /* @__PURE__ */ jsxs2(
|
|
348
|
+
"div",
|
|
349
|
+
{
|
|
350
|
+
"data-fleet-count": showDevices ? "devices" : "attention",
|
|
351
|
+
"data-flagged": counted?.flagged,
|
|
352
|
+
"data-of": counted?.members,
|
|
353
|
+
"data-threshold-level": counted?.worst,
|
|
354
|
+
style: { display: "flex", flexDirection: "column", justifyContent: "safe center", height: "100%", overflow: "hidden" },
|
|
355
|
+
children: [
|
|
356
|
+
/* @__PURE__ */ jsx2("div", { style: { flex: "1 1 0", minHeight: 0, display: "flex", alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ jsx2(LevelReadout, { text: figure, unit, color, size: fit, scale }) }),
|
|
357
|
+
/* @__PURE__ */ jsx2(
|
|
358
|
+
"div",
|
|
359
|
+
{
|
|
360
|
+
"data-fleet-count-caption": "",
|
|
361
|
+
style: {
|
|
362
|
+
flex: "0 0 auto",
|
|
363
|
+
marginTop: spaceVar(1),
|
|
364
|
+
textAlign: "center",
|
|
365
|
+
fontSize: fontVar("sm"),
|
|
366
|
+
color: css2("muted-foreground"),
|
|
367
|
+
overflow: "hidden",
|
|
368
|
+
textOverflow: "ellipsis",
|
|
369
|
+
whiteSpace: "nowrap"
|
|
370
|
+
},
|
|
371
|
+
children: caption2
|
|
372
|
+
}
|
|
373
|
+
),
|
|
374
|
+
notes.map((note) => /* @__PURE__ */ jsx2(
|
|
375
|
+
"div",
|
|
376
|
+
{
|
|
377
|
+
"data-fleet-count-note": "",
|
|
378
|
+
style: { textAlign: "center", fontSize: fontVar("xs"), color: css2("muted-foreground"), overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" },
|
|
379
|
+
children: note
|
|
380
|
+
},
|
|
381
|
+
note
|
|
382
|
+
))
|
|
383
|
+
]
|
|
384
|
+
}
|
|
385
|
+
);
|
|
386
|
+
} });
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// src/widgets/fleet-table.tsx
|
|
390
|
+
import { useEffect, useMemo as useMemo3, useState } from "react";
|
|
391
|
+
import {
|
|
392
|
+
ageSeconds,
|
|
393
|
+
bandAt as bandAt2,
|
|
394
|
+
css as css3,
|
|
395
|
+
fontVar as fontVar2,
|
|
305
396
|
formatAge,
|
|
306
397
|
formatValue as formatValue2,
|
|
307
398
|
isStale,
|
|
308
|
-
levelColor,
|
|
399
|
+
levelColor as levelColor2,
|
|
309
400
|
optNumber as optNumber2,
|
|
310
401
|
optBoolean,
|
|
311
|
-
optString as
|
|
402
|
+
optString as optString3,
|
|
312
403
|
parseThresholds,
|
|
313
404
|
resolveStaleAfterSeconds,
|
|
314
|
-
spaceVar,
|
|
315
|
-
useSeverityColors,
|
|
405
|
+
spaceVar as spaceVar2,
|
|
406
|
+
useSeverityColors as useSeverityColors2,
|
|
316
407
|
useWidgetScale,
|
|
317
408
|
useWidgetSelect,
|
|
318
409
|
useWidgetTimeRange,
|
|
319
|
-
WidgetFrame as
|
|
410
|
+
WidgetFrame as WidgetFrame3
|
|
320
411
|
} from "@devicechain/widget-sdk";
|
|
321
|
-
import { jsx as
|
|
412
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
322
413
|
var AGE_TICK_MS = 5e3;
|
|
323
414
|
function isRecord(v) {
|
|
324
415
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
@@ -352,20 +443,20 @@ function columnBands(raw) {
|
|
|
352
443
|
for (const [name, items] of grouped) out.set(name, parseThresholds(items));
|
|
353
444
|
return out;
|
|
354
445
|
}
|
|
355
|
-
var cellBox = { padding: `${
|
|
446
|
+
var cellBox = { padding: `${spaceVar2(1)} ${spaceVar2(3)}`, textAlign: "left", whiteSpace: "nowrap", verticalAlign: "top" };
|
|
356
447
|
var headBox = {
|
|
357
448
|
...cellBox,
|
|
358
|
-
fontSize:
|
|
449
|
+
fontSize: fontVar2("xs"),
|
|
359
450
|
fontWeight: 600,
|
|
360
451
|
letterSpacing: "0.04em",
|
|
361
|
-
color:
|
|
362
|
-
borderBottom: `1px solid ${
|
|
363
|
-
background:
|
|
452
|
+
color: css3("muted-foreground"),
|
|
453
|
+
borderBottom: `1px solid ${css3("border")}`,
|
|
454
|
+
background: css3("card"),
|
|
364
455
|
position: "sticky",
|
|
365
456
|
top: 0,
|
|
366
457
|
zIndex: 1
|
|
367
458
|
};
|
|
368
|
-
var stickyFirst = { position: "sticky", left: 0, background:
|
|
459
|
+
var stickyFirst = { position: "sticky", left: 0, background: css3("card") };
|
|
369
460
|
var plainButton = {
|
|
370
461
|
padding: 0,
|
|
371
462
|
border: "none",
|
|
@@ -378,15 +469,15 @@ var plainButton = {
|
|
|
378
469
|
function FleetTable({ widget, data }) {
|
|
379
470
|
const strings = fleetStrings();
|
|
380
471
|
const fleet = data.members;
|
|
381
|
-
const title =
|
|
472
|
+
const title = optString3(widget.options, "title");
|
|
382
473
|
if (!fleet || fleet.status === "loading") {
|
|
383
|
-
return /* @__PURE__ */
|
|
474
|
+
return /* @__PURE__ */ jsx3(Frame, { title, children: /* @__PURE__ */ jsx3(LevelEmpty, { message: strings.loading }) });
|
|
384
475
|
}
|
|
385
|
-
if (fleet.status === "unbound") return /* @__PURE__ */
|
|
386
|
-
if (fleet.status === "forbidden") return /* @__PURE__ */
|
|
387
|
-
if (fleet.status === "unsupported") return /* @__PURE__ */
|
|
388
|
-
if (fleet.members.length === 0) return /* @__PURE__ */
|
|
389
|
-
return /* @__PURE__ */
|
|
476
|
+
if (fleet.status === "unbound") return /* @__PURE__ */ jsx3(Frame, { title, children: /* @__PURE__ */ jsx3(LevelEmpty, { message: strings.unbound }) });
|
|
477
|
+
if (fleet.status === "forbidden") return /* @__PURE__ */ jsx3(Frame, { title, children: /* @__PURE__ */ jsx3(LevelEmpty, { message: strings.forbidden }) });
|
|
478
|
+
if (fleet.status === "unsupported") return /* @__PURE__ */ jsx3(Frame, { title, children: /* @__PURE__ */ jsx3(LevelEmpty, { message: strings.unsupported }) });
|
|
479
|
+
if (fleet.members.length === 0) return /* @__PURE__ */ jsx3(Frame, { title, children: /* @__PURE__ */ jsx3(LevelEmpty, { message: strings.noMembers }) });
|
|
480
|
+
return /* @__PURE__ */ jsx3(Table, { widget, fleet, strings });
|
|
390
481
|
}
|
|
391
482
|
var STACK_BELOW_PX = 480;
|
|
392
483
|
function Responsive({ wide, narrow }) {
|
|
@@ -394,26 +485,26 @@ function Responsive({ wide, narrow }) {
|
|
|
394
485
|
return width > 0 && width < STACK_BELOW_PX ? narrow : wide;
|
|
395
486
|
}
|
|
396
487
|
function Frame({ title, children }) {
|
|
397
|
-
return /* @__PURE__ */
|
|
488
|
+
return /* @__PURE__ */ jsx3(WidgetFrame3, { title, flush: true, children });
|
|
398
489
|
}
|
|
399
490
|
function Table({
|
|
400
491
|
widget,
|
|
401
492
|
fleet,
|
|
402
493
|
strings
|
|
403
494
|
}) {
|
|
404
|
-
const colors =
|
|
495
|
+
const colors = useSeverityColors2();
|
|
405
496
|
const range = useWidgetTimeRange();
|
|
406
497
|
const select = useWidgetSelect();
|
|
407
|
-
const selectionTarget =
|
|
498
|
+
const selectionTarget = optString3(widget.options, "selectionTarget");
|
|
408
499
|
const drillTo = select && selectionTarget ? { select, slot: selectionTarget } : void 0;
|
|
409
|
-
const columns =
|
|
410
|
-
const formats =
|
|
411
|
-
const bands =
|
|
500
|
+
const columns = useMemo3(() => columnNames(widget.datasource?.measurements ?? [], fleet.members), [widget.datasource, fleet.members]);
|
|
501
|
+
const formats = useMemo3(() => columnFormats(widget.options?.columns), [widget.options?.columns]);
|
|
502
|
+
const bands = useMemo3(() => columnBands(widget.options?.thresholds), [widget.options?.thresholds]);
|
|
412
503
|
const staleAfter = resolveStaleAfterSeconds(widget.options);
|
|
413
504
|
const ageLag = positiveSeconds(optNumber2(widget.options, "ageLagSeconds"));
|
|
414
|
-
const newest =
|
|
505
|
+
const newest = useMemo3(() => ageLag === void 0 ? void 0 : newestShown(fleet.members, columns), [ageLag, fleet.members, columns]);
|
|
415
506
|
const pageSize = optNumber2(widget.options, "pageSize") ?? DEFAULT_PAGE_SIZE;
|
|
416
|
-
const authored = { by:
|
|
507
|
+
const authored = { by: optString3(widget.options, "sortBy") || null, descending: optBoolean(widget.options, "sortDescending") === true };
|
|
417
508
|
const [picked, setPicked] = useState(void 0);
|
|
418
509
|
const sort = picked ?? authored;
|
|
419
510
|
const [page, setPage] = useState(0);
|
|
@@ -423,7 +514,7 @@ function Table({
|
|
|
423
514
|
return () => clearInterval(id);
|
|
424
515
|
}, []);
|
|
425
516
|
const now = range?.paused ? range.pausedAt ?? tick : tick;
|
|
426
|
-
const sorted =
|
|
517
|
+
const sorted = useMemo3(() => sortMembers(fleet.members, sort), [fleet.members, sort.by, sort.descending]);
|
|
427
518
|
const shownPage = clampPage(page, sorted.length, pageSize);
|
|
428
519
|
const rows = sorted.slice(shownPage * pageSize, (shownPage + 1) * pageSize);
|
|
429
520
|
const pages = pageCount(sorted.length, pageSize);
|
|
@@ -433,35 +524,35 @@ function Table({
|
|
|
433
524
|
};
|
|
434
525
|
const ariaSort = (by) => sort.by === by ? sort.descending ? "descending" : "ascending" : "none";
|
|
435
526
|
const arrow = (by) => sort.by === by ? sort.descending ? " \u25BC" : " \u25B2" : "";
|
|
436
|
-
const wide = /* @__PURE__ */
|
|
437
|
-
/* @__PURE__ */
|
|
438
|
-
/* @__PURE__ */
|
|
527
|
+
const wide = /* @__PURE__ */ jsxs3("table", { style: { width: "100%", borderCollapse: "collapse", fontSize: fontVar2("md"), color: css3("foreground") }, children: [
|
|
528
|
+
/* @__PURE__ */ jsx3("thead", { children: /* @__PURE__ */ jsxs3("tr", { children: [
|
|
529
|
+
/* @__PURE__ */ jsx3("th", { scope: "col", "aria-sort": ariaSort(null), style: { ...headBox, ...stickyFirst, zIndex: 2 }, children: /* @__PURE__ */ jsxs3("button", { type: "button", style: plainButton, onClick: () => sortOn(null), title: strings.sortBy(strings.device), children: [
|
|
439
530
|
strings.device,
|
|
440
531
|
arrow(null)
|
|
441
532
|
] }) }),
|
|
442
533
|
columns.map((name) => {
|
|
443
534
|
const f = formats.get(name);
|
|
444
535
|
const heading = (f?.label ?? name) + (f?.unit ? ` (${f.unit})` : "");
|
|
445
|
-
return /* @__PURE__ */
|
|
536
|
+
return /* @__PURE__ */ jsx3("th", { scope: "col", "aria-sort": ariaSort(name), style: headBox, children: /* @__PURE__ */ jsxs3("button", { type: "button", style: plainButton, onClick: () => sortOn(name), title: strings.sortBy(heading), children: [
|
|
446
537
|
heading,
|
|
447
538
|
arrow(name)
|
|
448
539
|
] }) }, name);
|
|
449
540
|
})
|
|
450
541
|
] }) }),
|
|
451
|
-
/* @__PURE__ */
|
|
542
|
+
/* @__PURE__ */ jsx3("tbody", { children: rows.map((member) => {
|
|
452
543
|
const label = deviceLabel(member);
|
|
453
|
-
return /* @__PURE__ */
|
|
454
|
-
/* @__PURE__ */
|
|
544
|
+
return /* @__PURE__ */ jsxs3("tr", { "data-device": member.token, style: { borderBottom: `1px solid ${css3("border")}` }, children: [
|
|
545
|
+
/* @__PURE__ */ jsx3("th", { scope: "row", style: { ...cellBox, ...stickyFirst, fontWeight: 500 }, children: drillTo ? /* @__PURE__ */ jsx3(
|
|
455
546
|
"button",
|
|
456
547
|
{
|
|
457
548
|
type: "button",
|
|
458
|
-
style: { ...plainButton, color:
|
|
549
|
+
style: { ...plainButton, color: css3("primary"), textDecoration: "underline", textUnderlineOffset: 2 },
|
|
459
550
|
title: strings.drill(label),
|
|
460
551
|
onClick: () => drillTo.select({ slot: drillTo.slot, binding: { kind: "device", deviceToken: member.token } }),
|
|
461
552
|
children: label
|
|
462
553
|
}
|
|
463
554
|
) : label }),
|
|
464
|
-
columns.map((name) => /* @__PURE__ */
|
|
555
|
+
columns.map((name) => /* @__PURE__ */ jsx3("td", { "data-measurement": name, style: cellBox, children: /* @__PURE__ */ jsx3(
|
|
465
556
|
CellView,
|
|
466
557
|
{
|
|
467
558
|
cell: cellFor(member, name),
|
|
@@ -478,16 +569,16 @@ function Table({
|
|
|
478
569
|
] }, member.token);
|
|
479
570
|
}) })
|
|
480
571
|
] });
|
|
481
|
-
const narrow = /* @__PURE__ */
|
|
482
|
-
/* @__PURE__ */
|
|
572
|
+
const narrow = /* @__PURE__ */ jsxs3("div", { "data-fleet-stacked": "", style: { color: css3("foreground"), fontSize: fontVar2("md") }, children: [
|
|
573
|
+
/* @__PURE__ */ jsx3("div", { style: { display: "flex", flexWrap: "wrap", gap: spaceVar2(2), padding: `${spaceVar2(2)} ${spaceVar2(3)}` }, children: [null, ...columns].map((by) => {
|
|
483
574
|
const f = by === null ? void 0 : formats.get(by);
|
|
484
575
|
const heading = by === null ? strings.device : f?.label ?? by;
|
|
485
|
-
return /* @__PURE__ */
|
|
576
|
+
return /* @__PURE__ */ jsxs3(
|
|
486
577
|
"button",
|
|
487
578
|
{
|
|
488
579
|
type: "button",
|
|
489
580
|
"aria-pressed": sort.by === by,
|
|
490
|
-
style: { ...plainButton, fontSize:
|
|
581
|
+
style: { ...plainButton, fontSize: fontVar2("xs"), fontWeight: 600, color: css3("muted-foreground"), overflowWrap: "anywhere" },
|
|
491
582
|
onClick: () => sortOn(by),
|
|
492
583
|
title: strings.sortBy(heading),
|
|
493
584
|
children: [
|
|
@@ -500,12 +591,12 @@ function Table({
|
|
|
500
591
|
}) }),
|
|
501
592
|
rows.map((member) => {
|
|
502
593
|
const label = deviceLabel(member);
|
|
503
|
-
return /* @__PURE__ */
|
|
504
|
-
/* @__PURE__ */
|
|
594
|
+
return /* @__PURE__ */ jsxs3("div", { "data-device": member.token, style: { padding: `${spaceVar2(2)} ${spaceVar2(3)}`, borderTop: `1px solid ${css3("border")}` }, children: [
|
|
595
|
+
/* @__PURE__ */ jsx3("div", { style: { fontWeight: 500, overflowWrap: "anywhere" }, children: drillTo ? /* @__PURE__ */ jsx3(
|
|
505
596
|
"button",
|
|
506
597
|
{
|
|
507
598
|
type: "button",
|
|
508
|
-
style: { ...plainButton, color:
|
|
599
|
+
style: { ...plainButton, color: css3("primary"), textDecoration: "underline", textUnderlineOffset: 2, overflowWrap: "anywhere" },
|
|
509
600
|
title: strings.drill(label),
|
|
510
601
|
onClick: () => drillTo.select({ slot: drillTo.slot, binding: { kind: "device", deviceToken: member.token } }),
|
|
511
602
|
children: label
|
|
@@ -513,9 +604,9 @@ function Table({
|
|
|
513
604
|
) : label }),
|
|
514
605
|
columns.map((name) => {
|
|
515
606
|
const f = formats.get(name);
|
|
516
|
-
return /* @__PURE__ */
|
|
517
|
-
/* @__PURE__ */
|
|
518
|
-
/* @__PURE__ */
|
|
607
|
+
return /* @__PURE__ */ jsxs3("div", { "data-measurement": name, style: { display: "flex", justifyContent: "space-between", gap: spaceVar2(3), alignItems: "baseline" }, children: [
|
|
608
|
+
/* @__PURE__ */ jsx3("span", { style: { color: css3("muted-foreground"), fontSize: fontVar2("sm"), overflowWrap: "anywhere" }, children: f?.label ?? name }),
|
|
609
|
+
/* @__PURE__ */ jsx3("span", { style: { textAlign: "right", overflowWrap: "anywhere" }, children: /* @__PURE__ */ jsx3(
|
|
519
610
|
CellView,
|
|
520
611
|
{
|
|
521
612
|
cell: cellFor(member, name),
|
|
@@ -535,19 +626,19 @@ function Table({
|
|
|
535
626
|
] }, member.token);
|
|
536
627
|
})
|
|
537
628
|
] });
|
|
538
|
-
return /* @__PURE__ */
|
|
539
|
-
/* @__PURE__ */
|
|
629
|
+
return /* @__PURE__ */ jsx3(Frame, { title: optString3(widget.options, "title"), children: /* @__PURE__ */ jsxs3("div", { style: { display: "flex", flexDirection: "column", height: "100%", minHeight: 0 }, children: [
|
|
630
|
+
/* @__PURE__ */ jsx3(
|
|
540
631
|
"div",
|
|
541
632
|
{
|
|
542
633
|
role: "region",
|
|
543
|
-
"aria-label":
|
|
634
|
+
"aria-label": optString3(widget.options, "title") ?? strings.device,
|
|
544
635
|
tabIndex: 0,
|
|
545
636
|
"data-fleet-scroll": "",
|
|
546
637
|
style: { flex: 1, minHeight: 0, overflow: "auto" },
|
|
547
|
-
children: /* @__PURE__ */
|
|
638
|
+
children: /* @__PURE__ */ jsx3(Responsive, { wide, narrow })
|
|
548
639
|
}
|
|
549
640
|
),
|
|
550
|
-
(fleet.truncated || pages > 1) && /* @__PURE__ */
|
|
641
|
+
(fleet.truncated || pages > 1) && /* @__PURE__ */ jsxs3(
|
|
551
642
|
"div",
|
|
552
643
|
{
|
|
553
644
|
"data-fleet-footer": "",
|
|
@@ -556,18 +647,18 @@ function Table({
|
|
|
556
647
|
flexWrap: "wrap",
|
|
557
648
|
alignItems: "center",
|
|
558
649
|
justifyContent: "space-between",
|
|
559
|
-
gap:
|
|
560
|
-
padding: `${
|
|
561
|
-
fontSize:
|
|
562
|
-
color:
|
|
563
|
-
borderTop: `1px solid ${
|
|
650
|
+
gap: spaceVar2(2),
|
|
651
|
+
padding: `${spaceVar2(1)} ${spaceVar2(3)}`,
|
|
652
|
+
fontSize: fontVar2("sm"),
|
|
653
|
+
color: css3("muted-foreground"),
|
|
654
|
+
borderTop: `1px solid ${css3("border")}`
|
|
564
655
|
},
|
|
565
656
|
children: [
|
|
566
|
-
/* @__PURE__ */
|
|
567
|
-
pages > 1 && /* @__PURE__ */
|
|
568
|
-
/* @__PURE__ */
|
|
569
|
-
/* @__PURE__ */
|
|
570
|
-
/* @__PURE__ */
|
|
657
|
+
/* @__PURE__ */ jsx3("span", { "data-fleet-truncated": fleet.truncated ? "" : void 0, children: fleet.truncated ? strings.truncated(fleet.members.length, fleet.total) : "" }),
|
|
658
|
+
pages > 1 && /* @__PURE__ */ jsxs3("span", { style: { display: "inline-flex", alignItems: "center", gap: spaceVar2(2) }, children: [
|
|
659
|
+
/* @__PURE__ */ jsx3("button", { type: "button", style: pagerButton, disabled: shownPage === 0, onClick: () => setPage(shownPage - 1), "aria-label": strings.previous, children: "\u2039" }),
|
|
660
|
+
/* @__PURE__ */ jsx3("span", { children: strings.range(shownPage * pageSize + 1, shownPage * pageSize + rows.length, sorted.length) }),
|
|
661
|
+
/* @__PURE__ */ jsx3("button", { type: "button", style: pagerButton, disabled: shownPage >= pages - 1, onClick: () => setPage(shownPage + 1), "aria-label": strings.next, children: "\u203A" })
|
|
571
662
|
] })
|
|
572
663
|
]
|
|
573
664
|
}
|
|
@@ -590,8 +681,8 @@ function newestShown(members, columns) {
|
|
|
590
681
|
}
|
|
591
682
|
var pagerButton = {
|
|
592
683
|
minWidth: "2em",
|
|
593
|
-
padding: `0 ${
|
|
594
|
-
border: `1px solid ${
|
|
684
|
+
padding: `0 ${spaceVar2(2)}`,
|
|
685
|
+
border: `1px solid ${css3("border")}`,
|
|
595
686
|
borderRadius: 4,
|
|
596
687
|
background: "none",
|
|
597
688
|
color: "inherit",
|
|
@@ -610,31 +701,31 @@ function CellView({
|
|
|
610
701
|
strings,
|
|
611
702
|
wrap
|
|
612
703
|
}) {
|
|
613
|
-
const muted = { color:
|
|
704
|
+
const muted = { color: css3("muted-foreground"), fontSize: fontVar2("sm"), ...wrap ? { overflowWrap: "anywhere" } : {} };
|
|
614
705
|
switch (cell.kind) {
|
|
615
706
|
case "loading":
|
|
616
|
-
return /* @__PURE__ */
|
|
707
|
+
return /* @__PURE__ */ jsx3("span", { style: muted, title: strings.loading, "aria-label": strings.loading, children: "\u2026" });
|
|
617
708
|
case "failed":
|
|
618
|
-
return /* @__PURE__ */
|
|
709
|
+
return /* @__PURE__ */ jsx3("span", { style: muted, children: strings.failed });
|
|
619
710
|
case "not-reported":
|
|
620
|
-
return /* @__PURE__ */
|
|
711
|
+
return /* @__PURE__ */ jsx3("span", { style: muted, "data-cell-empty": "not-reported", children: strings.notReported });
|
|
621
712
|
case "unread":
|
|
622
|
-
return /* @__PURE__ */
|
|
713
|
+
return /* @__PURE__ */ jsx3("span", { style: muted, "data-cell-empty": "unread", children: strings.unread });
|
|
623
714
|
case "no-data":
|
|
624
|
-
return /* @__PURE__ */
|
|
715
|
+
return /* @__PURE__ */ jsx3("span", { style: muted, "data-cell-empty": "no-data", children: strings.noData });
|
|
625
716
|
case "value": {
|
|
626
|
-
const band = bands ?
|
|
627
|
-
const color =
|
|
717
|
+
const band = bands ? bandAt2(bands, cell.value) : void 0;
|
|
718
|
+
const color = levelColor2(colors, band?.level);
|
|
628
719
|
const at = cell.sample.occurredTime ? Date.parse(cell.sample.occurredTime) : Number.NaN;
|
|
629
720
|
const age = Number.isNaN(at) ? void 0 : ageSeconds(at, now);
|
|
630
721
|
const stale = age !== void 0 && isStale(age, staleAfter);
|
|
631
722
|
const showAge = age !== void 0 && (ageLag === void 0 || stale || newest === void 0 || newest - at >= ageLag * 1e3);
|
|
632
|
-
return /* @__PURE__ */
|
|
633
|
-
/* @__PURE__ */
|
|
723
|
+
return /* @__PURE__ */ jsxs3("span", { "data-stale": stale ? "" : void 0, style: { display: "inline-flex", flexDirection: "column", opacity: stale ? 0.6 : 1 }, children: [
|
|
724
|
+
/* @__PURE__ */ jsxs3("span", { "data-threshold-level": band?.level, style: { fontVariantNumeric: "tabular-nums", color }, children: [
|
|
634
725
|
formatValue2(cell.value, format?.precision),
|
|
635
726
|
format?.unit ? ` ${format.unit}` : ""
|
|
636
727
|
] }),
|
|
637
|
-
age !== void 0 && showAge && /* @__PURE__ */
|
|
728
|
+
age !== void 0 && showAge && /* @__PURE__ */ jsxs3("span", { style: muted, "data-cell-age": "", children: [
|
|
638
729
|
formatAge(age),
|
|
639
730
|
stale ? ` \xB7 ${strings.stale}` : ""
|
|
640
731
|
] })
|
|
@@ -644,18 +735,18 @@ function CellView({
|
|
|
644
735
|
}
|
|
645
736
|
|
|
646
737
|
// src/widgets/pie-chart.tsx
|
|
647
|
-
import { useMemo as
|
|
648
|
-
import { css as
|
|
649
|
-
import { jsx as
|
|
738
|
+
import { useMemo as useMemo4 } from "react";
|
|
739
|
+
import { css as css4, formatValue as formatValue3, optNumber as optNumber3, optString as optString4, fontVar as fontVar3, spaceVar as spaceVar3, WidgetFrame as WidgetFrame4 } from "@devicechain/widget-sdk";
|
|
740
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
650
741
|
var RAMP = ["chart-1", "chart-2", "chart-3", "chart-4", "chart-5"];
|
|
651
742
|
function PieChart({ widget, data }) {
|
|
652
|
-
const sort = parseSort(
|
|
653
|
-
const items =
|
|
654
|
-
const unit =
|
|
743
|
+
const sort = parseSort(optString4(widget.options, "sort"));
|
|
744
|
+
const items = useMemo4(() => categoryItems(widget, data, sort), [widget, data, sort]);
|
|
745
|
+
const unit = optString4(widget.options, "unit");
|
|
655
746
|
const precision = optNumber3(widget.options, "precision");
|
|
656
747
|
const strings = aggregateStrings();
|
|
657
748
|
const problem = items.length === 0 ? void 0 : pieProblem(items);
|
|
658
|
-
return /* @__PURE__ */
|
|
749
|
+
return /* @__PURE__ */ jsx4(WidgetFrame4, { title: optString4(widget.options, "title"), children: items.length === 0 ? /* @__PURE__ */ jsx4(LevelEmpty, { message: strings.noCategories }) : problem ? /* @__PURE__ */ jsx4(LevelEmpty, { message: problem === "negative" ? strings.pieNegative : problem === "noShare" ? strings.pieNoShare : strings.noData }) : /* @__PURE__ */ jsx4(Pie, { items, unit, precision }) });
|
|
659
750
|
}
|
|
660
751
|
function Pie({
|
|
661
752
|
items,
|
|
@@ -665,8 +756,8 @@ function Pie({
|
|
|
665
756
|
const slices = pieSlices(items.map((i) => i.value));
|
|
666
757
|
const fmt = (v) => `${formatValue3(v, precision)}${unit ? ` ${unit}` : ""}`;
|
|
667
758
|
const percent = (fraction) => `${Math.round(fraction * 100)}%`;
|
|
668
|
-
return /* @__PURE__ */
|
|
669
|
-
/* @__PURE__ */
|
|
759
|
+
return /* @__PURE__ */ jsxs4("div", { style: { display: "flex", flexDirection: "column", height: "100%", gap: spaceVar3(1) }, children: [
|
|
760
|
+
/* @__PURE__ */ jsx4(
|
|
670
761
|
"svg",
|
|
671
762
|
{
|
|
672
763
|
"data-pie": "",
|
|
@@ -678,21 +769,21 @@ function Pie({
|
|
|
678
769
|
children: slices.map((s) => {
|
|
679
770
|
const d = wedgePath(50, 50, 48, s.from, s.to);
|
|
680
771
|
const item = items[s.index];
|
|
681
|
-
return d ? /* @__PURE__ */
|
|
772
|
+
return d ? /* @__PURE__ */ jsx4(
|
|
682
773
|
"path",
|
|
683
774
|
{
|
|
684
775
|
"data-slice": item.label,
|
|
685
776
|
"data-fraction": s.fraction,
|
|
686
777
|
d,
|
|
687
|
-
style: { fill:
|
|
688
|
-
children: /* @__PURE__ */
|
|
778
|
+
style: { fill: css4(RAMP[s.index % RAMP.length]), stroke: css4("card"), strokeWidth: 1 },
|
|
779
|
+
children: /* @__PURE__ */ jsx4("title", { children: `${item.label}: ${item.value === null ? "\u2014" : fmt(item.value)} (${percent(s.fraction)})` })
|
|
689
780
|
},
|
|
690
781
|
item.label
|
|
691
782
|
) : null;
|
|
692
783
|
})
|
|
693
784
|
}
|
|
694
785
|
),
|
|
695
|
-
/* @__PURE__ */
|
|
786
|
+
/* @__PURE__ */ jsx4(
|
|
696
787
|
"ul",
|
|
697
788
|
{
|
|
698
789
|
"data-pie-legend": "",
|
|
@@ -706,12 +797,12 @@ function Pie({
|
|
|
706
797
|
display: "flex",
|
|
707
798
|
flexWrap: "wrap",
|
|
708
799
|
justifyContent: "center",
|
|
709
|
-
gap: `0 ${
|
|
710
|
-
fontSize:
|
|
711
|
-
color:
|
|
800
|
+
gap: `0 ${spaceVar3(3)}`,
|
|
801
|
+
fontSize: fontVar3("xs"),
|
|
802
|
+
color: css4("muted-foreground")
|
|
712
803
|
},
|
|
713
|
-
children: items.map((item, i) => /* @__PURE__ */
|
|
714
|
-
/* @__PURE__ */
|
|
804
|
+
children: items.map((item, i) => /* @__PURE__ */ jsxs4("li", { title: `${item.label}: ${item.value === null ? "\u2014" : fmt(item.value)}`, style: { whiteSpace: "nowrap" }, children: [
|
|
805
|
+
/* @__PURE__ */ jsx4(
|
|
715
806
|
"span",
|
|
716
807
|
{
|
|
717
808
|
"aria-hidden": "true",
|
|
@@ -721,7 +812,7 @@ function Pie({
|
|
|
721
812
|
height: "0.7em",
|
|
722
813
|
marginRight: "0.4em",
|
|
723
814
|
borderRadius: 2,
|
|
724
|
-
background:
|
|
815
|
+
background: css4(RAMP[i % RAMP.length])
|
|
725
816
|
}
|
|
726
817
|
}
|
|
727
818
|
),
|
|
@@ -735,32 +826,33 @@ function Pie({
|
|
|
735
826
|
}
|
|
736
827
|
|
|
737
828
|
// src/widgets/stat-card.tsx
|
|
738
|
-
import { useMemo as
|
|
739
|
-
import { spanLabel } from "@devicechain/dashboards";
|
|
829
|
+
import { useMemo as useMemo5 } from "react";
|
|
830
|
+
import { bucketSecondsFor, spanLabel } from "@devicechain/dashboards";
|
|
740
831
|
import {
|
|
741
|
-
bandAt as
|
|
742
|
-
css as
|
|
743
|
-
FIT_MIN_FONT_PX,
|
|
744
|
-
fontVar as
|
|
832
|
+
bandAt as bandAt3,
|
|
833
|
+
css as css6,
|
|
834
|
+
FIT_MIN_FONT_PX as FIT_MIN_FONT_PX2,
|
|
835
|
+
fontVar as fontVar4,
|
|
745
836
|
formatValue as formatValue4,
|
|
746
|
-
levelColor as
|
|
837
|
+
levelColor as levelColor3,
|
|
838
|
+
optBoolean as optBoolean2,
|
|
747
839
|
optNumber as optNumber4,
|
|
748
|
-
optString as
|
|
749
|
-
optThresholds,
|
|
750
|
-
spaceVar as
|
|
751
|
-
useSeverityColors as
|
|
752
|
-
WidgetFrame as
|
|
840
|
+
optString as optString5,
|
|
841
|
+
optThresholds as optThresholds2,
|
|
842
|
+
spaceVar as spaceVar4,
|
|
843
|
+
useSeverityColors as useSeverityColors3,
|
|
844
|
+
WidgetFrame as WidgetFrame5,
|
|
753
845
|
WidgetFreshnessProvider
|
|
754
846
|
} from "@devicechain/widget-sdk";
|
|
755
847
|
|
|
756
848
|
// src/aggregate-reading.ts
|
|
757
|
-
import { pickSample, primaryMeasurementName } from "@devicechain/widget-sdk";
|
|
849
|
+
import { pickSample, primaryMeasurementName as primaryMeasurementName2 } from "@devicechain/widget-sdk";
|
|
758
850
|
function parseStat(v) {
|
|
759
851
|
return AGGREGATE_STATS.find((s) => s === v) ?? "avg";
|
|
760
852
|
}
|
|
761
853
|
function statReading(widget, data, stat) {
|
|
762
854
|
const { aggregates } = data;
|
|
763
|
-
const pinned =
|
|
855
|
+
const pinned = primaryMeasurementName2(widget);
|
|
764
856
|
if (widget.datasource?.kind === "unbound") return { kind: "empty", reason: "unbound", name: pinned };
|
|
765
857
|
if (stat === "last") {
|
|
766
858
|
const sample = pickSample(data.latest, pinned);
|
|
@@ -786,35 +878,127 @@ function statReading(widget, data, stat) {
|
|
|
786
878
|
return { kind: "value", stat, name, value: a[stat], spanSeconds: aggregates.spanSeconds };
|
|
787
879
|
}
|
|
788
880
|
|
|
881
|
+
// src/sparkline.tsx
|
|
882
|
+
import { css as css5 } from "@devicechain/widget-sdk";
|
|
883
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
884
|
+
function trendValue(point, stat) {
|
|
885
|
+
switch (stat) {
|
|
886
|
+
case "min":
|
|
887
|
+
return point.min;
|
|
888
|
+
case "max":
|
|
889
|
+
return point.max;
|
|
890
|
+
case "sum":
|
|
891
|
+
return point.sum;
|
|
892
|
+
case "count":
|
|
893
|
+
return point.count;
|
|
894
|
+
case "avg":
|
|
895
|
+
case "last":
|
|
896
|
+
return point.avg;
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
function trendPoints(series, stat) {
|
|
900
|
+
if (!series) return [];
|
|
901
|
+
const out = [];
|
|
902
|
+
for (const p of series) {
|
|
903
|
+
const at = Date.parse(p.bucketStart);
|
|
904
|
+
const value = trendValue(p, stat);
|
|
905
|
+
if (Number.isFinite(at) && Number.isFinite(value)) out.push({ at, value });
|
|
906
|
+
}
|
|
907
|
+
return out.sort((a, b) => a.at - b.at);
|
|
908
|
+
}
|
|
909
|
+
var VIEW_WIDTH = 100;
|
|
910
|
+
var PAD = 3;
|
|
911
|
+
function sparklineGeometry(points, height, bucketSeconds) {
|
|
912
|
+
if (points.length === 0) return { d: "", end: void 0, points: 0 };
|
|
913
|
+
const t0 = points[0].at;
|
|
914
|
+
const t1 = points[points.length - 1].at;
|
|
915
|
+
let lo = Infinity;
|
|
916
|
+
let hi = -Infinity;
|
|
917
|
+
for (const p of points) {
|
|
918
|
+
lo = Math.min(lo, p.value);
|
|
919
|
+
hi = Math.max(hi, p.value);
|
|
920
|
+
}
|
|
921
|
+
const x = (at) => t1 === t0 ? VIEW_WIDTH / 2 : PAD + (at - t0) / (t1 - t0) * (VIEW_WIDTH - 2 * PAD);
|
|
922
|
+
const y = (v) => hi === lo ? height / 2 : PAD + (1 - (v - lo) / (hi - lo)) * (height - 2 * PAD);
|
|
923
|
+
const steps = points.slice(1).map((p, i) => p.at - points[i].at).sort((a, b) => a - b);
|
|
924
|
+
const usual = steps.length > 0 ? steps[Math.floor(steps.length / 2)] : 0;
|
|
925
|
+
const gap = Math.max(bucketSeconds * 2e3, usual * 3);
|
|
926
|
+
let d = "";
|
|
927
|
+
let prev;
|
|
928
|
+
for (const p of points) {
|
|
929
|
+
const cmd = prev === void 0 || p.at - prev > gap ? "M" : "L";
|
|
930
|
+
d += `${d ? " " : ""}${cmd}${x(p.at).toFixed(2)} ${y(p.value).toFixed(2)}`;
|
|
931
|
+
prev = p.at;
|
|
932
|
+
}
|
|
933
|
+
const last = points[points.length - 1];
|
|
934
|
+
return { d, end: { left: x(last.at) / VIEW_WIDTH * 100, top: y(last.value) / height * 100 }, points: points.length };
|
|
935
|
+
}
|
|
936
|
+
function Sparkline({
|
|
937
|
+
points,
|
|
938
|
+
height,
|
|
939
|
+
bucketSeconds,
|
|
940
|
+
label
|
|
941
|
+
}) {
|
|
942
|
+
const g = sparklineGeometry(points, height, bucketSeconds);
|
|
943
|
+
if (g.points === 0) return null;
|
|
944
|
+
return /* @__PURE__ */ jsxs5("div", { "data-sparkline": g.points, role: "img", "aria-label": label, title: label, style: { position: "relative", height, width: "100%", flex: "0 0 auto" }, children: [
|
|
945
|
+
/* @__PURE__ */ jsx5("svg", { viewBox: `0 0 ${VIEW_WIDTH} ${height}`, preserveAspectRatio: "none", width: "100%", height, style: { display: "block", overflow: "visible" }, "aria-hidden": "true", children: g.points > 1 ? /* @__PURE__ */ jsx5("path", { d: g.d, fill: "none", stroke: css5("muted-foreground"), strokeWidth: 1.5, strokeLinejoin: "round", strokeLinecap: "round", vectorEffect: "non-scaling-stroke" }) : null }),
|
|
946
|
+
g.end ? /* @__PURE__ */ jsx5(
|
|
947
|
+
"span",
|
|
948
|
+
{
|
|
949
|
+
"data-sparkline-end": "",
|
|
950
|
+
style: {
|
|
951
|
+
position: "absolute",
|
|
952
|
+
left: `${g.end.left}%`,
|
|
953
|
+
top: `${g.end.top}%`,
|
|
954
|
+
width: 6,
|
|
955
|
+
height: 6,
|
|
956
|
+
marginLeft: -3,
|
|
957
|
+
marginTop: -3,
|
|
958
|
+
borderRadius: "50%",
|
|
959
|
+
background: css5("muted-foreground")
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
) : null
|
|
963
|
+
] });
|
|
964
|
+
}
|
|
965
|
+
|
|
789
966
|
// src/widgets/stat-card.tsx
|
|
790
|
-
import { jsx as
|
|
791
|
-
var
|
|
967
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
968
|
+
var CAPTION_ROOM_PX2 = 22;
|
|
969
|
+
var SPARK_ROOM_PX = 28;
|
|
792
970
|
var BESIDE_FIGURE_SHARE = 0.6;
|
|
793
971
|
var AGE_ONLY = { at: void 0, staleAfterSeconds: void 0 };
|
|
794
972
|
function StatCard({ widget, data }) {
|
|
795
|
-
const severity =
|
|
973
|
+
const severity = useSeverityColors3();
|
|
796
974
|
const strings = aggregateStrings();
|
|
797
|
-
const stat = parseStat(
|
|
975
|
+
const stat = parseStat(optString5(widget.options, "stat"));
|
|
798
976
|
const reading = statReading(widget, data, stat);
|
|
799
|
-
const thresholds =
|
|
800
|
-
const unit =
|
|
977
|
+
const thresholds = useMemo5(() => optThresholds2(widget.options, "thresholds"), [widget.options]);
|
|
978
|
+
const unit = optString5(widget.options, "unit");
|
|
801
979
|
const precision = optNumber4(widget.options, "precision");
|
|
802
|
-
const title =
|
|
803
|
-
const
|
|
980
|
+
const title = optString5(widget.options, "title") ?? reading.name;
|
|
981
|
+
const wantsTrend = optBoolean2(widget.options, "sparkline");
|
|
982
|
+
const card = /* @__PURE__ */ jsx6(WidgetFrame5, { title, sampleTime: stat === "last" ? reading.kind === "value" ? reading.time ?? null : null : void 0, children: ({ size, scale }) => {
|
|
804
983
|
if (reading.kind === "empty") {
|
|
805
|
-
return /* @__PURE__ */
|
|
984
|
+
return /* @__PURE__ */ jsx6(LevelEmpty, { message: emptyMessage(reading, strings) });
|
|
806
985
|
}
|
|
807
986
|
const isCount = reading.stat === "count";
|
|
808
|
-
const band =
|
|
809
|
-
const room = Math.round(
|
|
810
|
-
const
|
|
811
|
-
const
|
|
812
|
-
|
|
987
|
+
const band = bandAt3(thresholds, reading.value);
|
|
988
|
+
const room = Math.round(CAPTION_ROOM_PX2 * scale);
|
|
989
|
+
const floor2 = 2 * Math.round(FIT_MIN_FONT_PX2 * scale);
|
|
990
|
+
const sparkHeight = Math.round(SPARK_ROOM_PX * scale);
|
|
991
|
+
const points = wantsTrend && data.aggregates.status === "ready" ? trendPoints(data.aggregates.series?.[reading.name ?? ""], reading.stat) : [];
|
|
992
|
+
const showTrend = points.length > 0 && size.height - room - sparkHeight >= floor2;
|
|
993
|
+
const beside = size.height > 0 && size.height - room < 2 * Math.round(FIT_MIN_FONT_PX2 * scale);
|
|
994
|
+
const figure = beside ? { width: Math.round(size.width * BESIDE_FIGURE_SHARE), height: size.height } : { width: size.width, height: Math.max(0, size.height - room - (showTrend ? sparkHeight : 0)) };
|
|
995
|
+
return /* @__PURE__ */ jsxs6(
|
|
813
996
|
"div",
|
|
814
997
|
{
|
|
815
998
|
"data-stat": reading.stat,
|
|
816
999
|
"data-stat-span": reading.spanSeconds,
|
|
817
1000
|
"data-stat-layout": beside ? "beside" : "under",
|
|
1001
|
+
"data-stat-trend": showTrend ? points.length : void 0,
|
|
818
1002
|
"data-threshold-level": band?.level,
|
|
819
1003
|
title: band?.label,
|
|
820
1004
|
style: {
|
|
@@ -822,38 +1006,47 @@ function StatCard({ widget, data }) {
|
|
|
822
1006
|
flexDirection: beside ? "row" : "column",
|
|
823
1007
|
alignItems: beside ? "center" : void 0,
|
|
824
1008
|
justifyContent: "safe center",
|
|
825
|
-
gap: beside ?
|
|
1009
|
+
gap: beside ? spaceVar4(2) : void 0,
|
|
826
1010
|
height: "100%",
|
|
827
1011
|
overflow: "hidden"
|
|
828
1012
|
},
|
|
829
1013
|
children: [
|
|
830
|
-
/* @__PURE__ */
|
|
1014
|
+
/* @__PURE__ */ jsx6(
|
|
831
1015
|
"div",
|
|
832
1016
|
{
|
|
833
1017
|
style: beside ? { flex: "0 1 auto", minWidth: 0, display: "flex", alignItems: "center" } : { flex: "1 1 0", minHeight: 0, display: "flex", alignItems: "center", justifyContent: "center" },
|
|
834
|
-
children: /* @__PURE__ */
|
|
1018
|
+
children: /* @__PURE__ */ jsx6(
|
|
835
1019
|
LevelReadout,
|
|
836
1020
|
{
|
|
837
1021
|
text: formatValue4(reading.value, isCount ? 0 : precision),
|
|
838
1022
|
unit: isCount ? void 0 : unit,
|
|
839
|
-
color:
|
|
1023
|
+
color: levelColor3(severity, band?.level),
|
|
840
1024
|
size: figure,
|
|
841
1025
|
scale
|
|
842
1026
|
}
|
|
843
1027
|
)
|
|
844
1028
|
}
|
|
845
1029
|
),
|
|
846
|
-
/* @__PURE__ */
|
|
1030
|
+
showTrend && data.aggregates.status === "ready" ? /* @__PURE__ */ jsx6(
|
|
1031
|
+
Sparkline,
|
|
1032
|
+
{
|
|
1033
|
+
points,
|
|
1034
|
+
height: sparkHeight,
|
|
1035
|
+
bucketSeconds: bucketSecondsFor(data.aggregates.spanSeconds),
|
|
1036
|
+
label: strings.trend(strings.stats[reading.stat === "last" ? "avg" : reading.stat], spanLabel(data.aggregates.spanSeconds))
|
|
1037
|
+
}
|
|
1038
|
+
) : null,
|
|
1039
|
+
/* @__PURE__ */ jsx6(
|
|
847
1040
|
"div",
|
|
848
1041
|
{
|
|
849
1042
|
"data-stat-caption": "",
|
|
850
1043
|
style: {
|
|
851
1044
|
flex: beside ? "0 1 auto" : "0 0 auto",
|
|
852
1045
|
minWidth: 0,
|
|
853
|
-
marginTop: beside ? void 0 :
|
|
1046
|
+
marginTop: beside ? void 0 : spaceVar4(1),
|
|
854
1047
|
textAlign: "center",
|
|
855
|
-
fontSize:
|
|
856
|
-
color:
|
|
1048
|
+
fontSize: fontVar4("sm"),
|
|
1049
|
+
color: css6("muted-foreground"),
|
|
857
1050
|
whiteSpace: "nowrap",
|
|
858
1051
|
overflow: "hidden",
|
|
859
1052
|
textOverflow: "ellipsis"
|
|
@@ -865,7 +1058,7 @@ function StatCard({ widget, data }) {
|
|
|
865
1058
|
}
|
|
866
1059
|
);
|
|
867
1060
|
} });
|
|
868
|
-
return stat === "last" ? /* @__PURE__ */
|
|
1061
|
+
return stat === "last" ? /* @__PURE__ */ jsx6(WidgetFreshnessProvider, { freshness: AGE_ONLY, children: card }) : card;
|
|
869
1062
|
}
|
|
870
1063
|
function caption(r, stats) {
|
|
871
1064
|
const name = stats[r.stat];
|
|
@@ -889,8 +1082,9 @@ function emptyMessage(r, strings) {
|
|
|
889
1082
|
}
|
|
890
1083
|
export {
|
|
891
1084
|
BarChart,
|
|
1085
|
+
FleetCount,
|
|
892
1086
|
FleetTable,
|
|
893
1087
|
PieChart,
|
|
894
1088
|
StatCard
|
|
895
1089
|
};
|
|
896
|
-
//# sourceMappingURL=aggregate-widgets-
|
|
1090
|
+
//# sourceMappingURL=aggregate-widgets-2ZQBW3YF.js.map
|