@devicechain/widgets 0.24.0 → 0.25.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 +11 -1
- package/dist/absolute-range-picker.d.ts +22 -0
- package/dist/binding-policy.d.ts +1 -0
- package/dist/builtin-descriptors.d.ts +69 -0
- package/dist/builtin-registry.d.ts +68 -0
- package/dist/chunks/absolute-range-picker-E57G2TPX.js +139 -0
- package/dist/chunks/absolute-range-picker-E57G2TPX.js.map +7 -0
- package/dist/chunks/{aggregate-feed-4FSBQYJL.js → aggregate-feed-XX36GNY6.js} +2 -2
- package/dist/chunks/{aggregate-widgets-2ZQBW3YF.js → aggregate-widgets-72HMPMBU.js} +99 -57
- package/dist/chunks/aggregate-widgets-72HMPMBU.js.map +7 -0
- package/dist/chunks/{chunk-USRYKW2J.js → chunk-7BUCJQFP.js} +10 -2
- package/dist/chunks/chunk-7BUCJQFP.js.map +7 -0
- package/dist/chunks/chunk-AF4M5OXQ.js +23 -0
- package/dist/chunks/chunk-AF4M5OXQ.js.map +7 -0
- package/dist/chunks/{chunk-XQQQNTBX.js → chunk-EQOWBDS7.js} +1 -1
- package/dist/chunks/{chunk-XQQQNTBX.js.map → chunk-EQOWBDS7.js.map} +1 -1
- package/dist/chunks/chunk-JVC6JYUR.js +48 -0
- package/dist/chunks/chunk-JVC6JYUR.js.map +7 -0
- package/dist/chunks/{chunk-JFH4QMLA.js → chunk-NYHNQ5VR.js} +5 -1
- package/dist/chunks/{chunk-JFH4QMLA.js.map → chunk-NYHNQ5VR.js.map} +2 -2
- package/dist/chunks/chunk-VTGKDO44.js +87 -0
- package/dist/chunks/chunk-VTGKDO44.js.map +7 -0
- package/dist/chunks/chunk-XJ7UF2CP.js +90 -0
- package/dist/chunks/chunk-XJ7UF2CP.js.map +7 -0
- package/dist/chunks/{compare-feed-AY3CVKUZ.js → compare-feed-5OLZHFRL.js} +48 -23
- package/dist/chunks/compare-feed-5OLZHFRL.js.map +7 -0
- package/dist/chunks/{event-markers-feed-GEGTIHXT.js → event-markers-feed-B3MVFYUT.js} +4 -4
- package/dist/chunks/export-rows-OEWIBIUY.js +11 -0
- package/dist/chunks/{fleet-feed-2SKDR6ZQ.js → fleet-feed-D4T3LC25.js} +10 -10
- package/dist/chunks/history-widgets-NSNXDKEC.js +336 -0
- package/dist/chunks/history-widgets-NSNXDKEC.js.map +7 -0
- package/dist/chunks/{level-widgets-MJB7TOLU.js → level-widgets-HE6EDSWC.js} +13 -9
- package/dist/chunks/level-widgets-HE6EDSWC.js.map +7 -0
- package/dist/chunks/no-reading-B4MPXAS2.js +22 -0
- package/dist/chunks/no-reading-B4MPXAS2.js.map +7 -0
- package/dist/chunks/{presence-widgets-2LIUKN4Y.js → presence-widgets-M5VGG3OO.js} +12 -8
- package/dist/chunks/presence-widgets-M5VGG3OO.js.map +7 -0
- package/dist/chunks/table-CEVB3JZS.js +8 -0
- package/dist/chunks/table-CEVB3JZS.js.map +7 -0
- package/dist/compare-model.d.ts +1 -1
- package/dist/documented-descriptors.d.ts +206 -0
- package/dist/export-rows.d.ts +24 -0
- package/dist/history-feed.d.ts +10 -0
- package/dist/history-model.d.ts +45 -0
- package/dist/history-strings.d.ts +20 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +544 -189
- package/dist/index.js.map +4 -4
- package/dist/level-reading.d.ts +1 -0
- package/dist/no-reading-core.d.ts +25 -0
- package/dist/no-reading.d.ts +10 -0
- package/dist/time-range-bar.d.ts +26 -2
- package/dist/widgets/history-lazy.d.ts +70 -0
- package/dist/widgets/history-table.d.ts +7 -0
- package/dist/widgets/history-widgets.d.ts +2 -0
- package/dist/widgets/no-reading-lazy.d.ts +7 -0
- package/package.json +8 -8
- package/dist/chunks/aggregate-widgets-2ZQBW3YF.js.map +0 -7
- package/dist/chunks/chunk-USRYKW2J.js.map +0 -7
- package/dist/chunks/compare-feed-AY3CVKUZ.js.map +0 -7
- package/dist/chunks/level-widgets-MJB7TOLU.js.map +0 -7
- package/dist/chunks/presence-widgets-2LIUKN4Y.js.map +0 -7
- package/dist/chunks/table-6EVV7QZH.js +0 -7
- /package/dist/chunks/{aggregate-feed-4FSBQYJL.js.map → aggregate-feed-XX36GNY6.js.map} +0 -0
- /package/dist/chunks/{event-markers-feed-GEGTIHXT.js.map → event-markers-feed-B3MVFYUT.js.map} +0 -0
- /package/dist/chunks/{table-6EVV7QZH.js.map → export-rows-OEWIBIUY.js.map} +0 -0
- /package/dist/chunks/{fleet-feed-2SKDR6ZQ.js.map → fleet-feed-D4T3LC25.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,21 +1,20 @@
|
|
|
1
|
+
import {
|
|
2
|
+
EntitySelector
|
|
3
|
+
} from "./chunks/chunk-FM7OI5TQ.js";
|
|
4
|
+
import {
|
|
5
|
+
readRange
|
|
6
|
+
} from "./chunks/chunk-ZR74ORIT.js";
|
|
1
7
|
import {
|
|
2
8
|
Table
|
|
3
|
-
} from "./chunks/chunk-
|
|
9
|
+
} from "./chunks/chunk-7BUCJQFP.js";
|
|
4
10
|
import {
|
|
5
11
|
ChunkLoadingFrame,
|
|
6
12
|
lazyChunk
|
|
7
13
|
} from "./chunks/chunk-BMFQOTYG.js";
|
|
8
14
|
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
measurementIsMembersOnly,
|
|
13
|
-
measurementSpan,
|
|
14
|
-
measurementWindow,
|
|
15
|
-
membersMode,
|
|
16
|
-
presenceMode,
|
|
17
|
-
wantsEventMarkers
|
|
18
|
-
} from "./chunks/chunk-JFH4QMLA.js";
|
|
15
|
+
useHeld
|
|
16
|
+
} from "./chunks/chunk-XNEBAY4J.js";
|
|
17
|
+
import "./chunks/chunk-JVC6JYUR.js";
|
|
19
18
|
import {
|
|
20
19
|
AlarmCount,
|
|
21
20
|
AlarmSeverity,
|
|
@@ -37,25 +36,29 @@ import {
|
|
|
37
36
|
validateParams
|
|
38
37
|
} from "./chunks/chunk-XSLFHCNI.js";
|
|
39
38
|
import {
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
alarmSubscription,
|
|
40
|
+
commandSubscription,
|
|
41
|
+
groupsAlarmsByDeviceType,
|
|
42
|
+
historyMode,
|
|
43
|
+
measurementIsMembersOnly,
|
|
44
|
+
measurementSpan,
|
|
45
|
+
measurementWindow,
|
|
46
|
+
membersMode,
|
|
47
|
+
presenceMode,
|
|
48
|
+
wantsEventMarkers
|
|
49
|
+
} from "./chunks/chunk-NYHNQ5VR.js";
|
|
42
50
|
import {
|
|
43
51
|
accessStrings
|
|
44
52
|
} from "./chunks/chunk-BRH66T5F.js";
|
|
45
|
-
import {
|
|
46
|
-
EntitySelector
|
|
47
|
-
} from "./chunks/chunk-FM7OI5TQ.js";
|
|
48
|
-
import {
|
|
49
|
-
readRange
|
|
50
|
-
} from "./chunks/chunk-ZR74ORIT.js";
|
|
51
53
|
import {
|
|
52
54
|
LevelReadout
|
|
53
|
-
} from "./chunks/chunk-
|
|
55
|
+
} from "./chunks/chunk-EQOWBDS7.js";
|
|
54
56
|
|
|
55
57
|
// src/dashboard-renderer.tsx
|
|
56
58
|
import {
|
|
57
59
|
anchorFraction,
|
|
58
60
|
DEFAULT_CANVAS_DENSITY,
|
|
61
|
+
DEFAULT_TIME_RANGE_SECONDS,
|
|
59
62
|
defaultHistoryWindow,
|
|
60
63
|
effectiveLayout,
|
|
61
64
|
historyWindowFor,
|
|
@@ -76,7 +79,7 @@ import {
|
|
|
76
79
|
WidgetTimeRangeProvider,
|
|
77
80
|
WidgetTokenStyles
|
|
78
81
|
} from "@devicechain/widget-sdk";
|
|
79
|
-
import { Fragment, useCallback as
|
|
82
|
+
import { Fragment, useCallback as useCallback3, useEffect as useEffect4, useLayoutEffect, useMemo as useMemo5, useRef as useRef2, useState as useState5 } from "react";
|
|
80
83
|
|
|
81
84
|
// src/connected-widget.tsx
|
|
82
85
|
import {
|
|
@@ -86,12 +89,14 @@ import {
|
|
|
86
89
|
newestSampleTime,
|
|
87
90
|
resolveStaleAfterSeconds,
|
|
88
91
|
WidgetCandidatesProvider,
|
|
92
|
+
WidgetDeclaredMetricsProvider,
|
|
89
93
|
WidgetFreshnessProvider,
|
|
90
94
|
WidgetSelectProvider,
|
|
95
|
+
useWidgetScale as useWidgetScale3,
|
|
91
96
|
useWidgetTimeRange as useWidgetTimeRange2
|
|
92
97
|
} from "@devicechain/widget-sdk";
|
|
93
98
|
import { isForbiddenError } from "@devicechain/client";
|
|
94
|
-
import { useEffect as
|
|
99
|
+
import { useCallback as useCallback2, useEffect as useEffect3, useMemo as useMemo4, useState as useState4 } from "react";
|
|
95
100
|
|
|
96
101
|
// src/builtin-registry.ts
|
|
97
102
|
import { createWidgetRegistry } from "@devicechain/widget-sdk";
|
|
@@ -1228,12 +1233,45 @@ var builtinWidgetDescriptors = {
|
|
|
1228
1233
|
freshness: true,
|
|
1229
1234
|
interactions: {},
|
|
1230
1235
|
layout: { defaultSpan: { cols: 4, rows: 4 }, minSpan: { cols: 3, rows: 3 }, maxSpan: { cols: 8, rows: 8 } }
|
|
1236
|
+
}),
|
|
1237
|
+
// One device's stored history as rows: a row per time bucket over the span, a column per
|
|
1238
|
+
// measurement, each cell the bucket's AVERAGE (the table says "avg per 5m"). It reads the store's
|
|
1239
|
+
// buckets (`binding.history`), never the live feed, so it is time-ranged and takes one device.
|
|
1240
|
+
"history-table": defineRuntimeDescriptor({
|
|
1241
|
+
id: "history-table",
|
|
1242
|
+
version: VERSION,
|
|
1243
|
+
sdkApiVersion: 1,
|
|
1244
|
+
optionsVersion: 1,
|
|
1245
|
+
display: { title: "History table", category: "Telemetry", titleId: "widgetTypeHistoryTable", categoryId: "widgetCategoryTelemetry" },
|
|
1246
|
+
channel: "measurement",
|
|
1247
|
+
datasource: { mode: "required", selectors: ONE_DEVICE },
|
|
1248
|
+
binding: { windowSeconds: { option: "windowSeconds" }, history: { const: true } },
|
|
1249
|
+
options: {
|
|
1250
|
+
title: TITLE,
|
|
1251
|
+
columns: FLEET_COLUMNS,
|
|
1252
|
+
precision: PRECISION,
|
|
1253
|
+
oldestFirst: { kind: "boolean", labelId: "widgetLabelOldestFirst" },
|
|
1254
|
+
pageSize: {
|
|
1255
|
+
kind: "number",
|
|
1256
|
+
integer: true,
|
|
1257
|
+
min: 5,
|
|
1258
|
+
max: 100,
|
|
1259
|
+
labelId: "widgetLabelRowsPerPage"
|
|
1260
|
+
},
|
|
1261
|
+
staleAfterSeconds: STALE_AFTER_SECONDS,
|
|
1262
|
+
windowSeconds: WINDOW_SECONDS
|
|
1263
|
+
},
|
|
1264
|
+
defaults: { title: "History table" },
|
|
1265
|
+
// The frame's age is the table's: when its buckets were last read.
|
|
1266
|
+
freshness: true,
|
|
1267
|
+
interactions: {},
|
|
1268
|
+
layout: { defaultSpan: { cols: 6, rows: 5 }, minSpan: { cols: 4, rows: 3 } }
|
|
1231
1269
|
})
|
|
1232
1270
|
};
|
|
1233
1271
|
var builtinWidgetCatalog = createWidgetCatalog(Object.values(builtinWidgetDescriptors));
|
|
1234
1272
|
|
|
1235
1273
|
// src/widgets/aggregate-lazy.tsx
|
|
1236
|
-
var chunk = lazyChunk(() => import("./chunks/aggregate-widgets-
|
|
1274
|
+
var chunk = lazyChunk(() => import("./chunks/aggregate-widgets-72HMPMBU.js"));
|
|
1237
1275
|
var loadAggregateWidgets = chunk.load;
|
|
1238
1276
|
var statCardWidget = defineWidget({
|
|
1239
1277
|
descriptor: builtinWidgetDescriptors["stat-card"],
|
|
@@ -1290,32 +1328,41 @@ var commandButtonWidget = defineWidget3({
|
|
|
1290
1328
|
implementation: { kind: "trusted-react", component: chunk3.component("CommandButton") }
|
|
1291
1329
|
});
|
|
1292
1330
|
|
|
1293
|
-
// src/widgets/
|
|
1331
|
+
// src/widgets/history-lazy.tsx
|
|
1294
1332
|
import { defineWidget as defineWidget4 } from "@devicechain/widget-sdk";
|
|
1295
|
-
var chunk4 = lazyChunk(() => import("./chunks/
|
|
1296
|
-
var
|
|
1297
|
-
var
|
|
1333
|
+
var chunk4 = lazyChunk(() => import("./chunks/history-widgets-NSNXDKEC.js"));
|
|
1334
|
+
var loadHistoryWidgets = chunk4.load;
|
|
1335
|
+
var historyTableWidget = defineWidget4({
|
|
1336
|
+
descriptor: builtinWidgetDescriptors["history-table"],
|
|
1337
|
+
implementation: { kind: "trusted-react", component: chunk4.component("HistoryTable") }
|
|
1338
|
+
});
|
|
1339
|
+
|
|
1340
|
+
// src/widgets/presence-lazy.tsx
|
|
1341
|
+
import { defineWidget as defineWidget5 } from "@devicechain/widget-sdk";
|
|
1342
|
+
var chunk5 = lazyChunk(() => import("./chunks/presence-widgets-M5VGG3OO.js"));
|
|
1343
|
+
var loadPresenceWidgets = chunk5.load;
|
|
1344
|
+
var deviceStatusWidget = defineWidget5({
|
|
1298
1345
|
descriptor: builtinWidgetDescriptors["device-status"],
|
|
1299
|
-
implementation: { kind: "trusted-react", component:
|
|
1346
|
+
implementation: { kind: "trusted-react", component: chunk5.component("DeviceStatus") }
|
|
1300
1347
|
});
|
|
1301
|
-
var onlineDoughnutWidget =
|
|
1348
|
+
var onlineDoughnutWidget = defineWidget5({
|
|
1302
1349
|
descriptor: builtinWidgetDescriptors["online-doughnut"],
|
|
1303
|
-
implementation: { kind: "trusted-react", component:
|
|
1350
|
+
implementation: { kind: "trusted-react", component: chunk5.component("OnlineDoughnut") }
|
|
1304
1351
|
});
|
|
1305
1352
|
|
|
1306
1353
|
// src/widgets/selection-lazy.tsx
|
|
1307
|
-
import { defineWidget as
|
|
1308
|
-
var
|
|
1309
|
-
var loadSelectionWidgets =
|
|
1310
|
-
var entitySelectorWidget =
|
|
1354
|
+
import { defineWidget as defineWidget6 } from "@devicechain/widget-sdk";
|
|
1355
|
+
var chunk6 = lazyChunk(() => import("./chunks/entity-selector-3JJFI4DT.js"));
|
|
1356
|
+
var loadSelectionWidgets = chunk6.load;
|
|
1357
|
+
var entitySelectorWidget = defineWidget6({
|
|
1311
1358
|
descriptor: builtinWidgetDescriptors["entity-selector"],
|
|
1312
|
-
implementation: { kind: "trusted-react", component:
|
|
1359
|
+
implementation: { kind: "trusted-react", component: chunk6.component("EntitySelector") }
|
|
1313
1360
|
});
|
|
1314
1361
|
|
|
1315
1362
|
// src/widgets/gauge.tsx
|
|
1316
1363
|
import { useMemo } from "react";
|
|
1317
1364
|
import {
|
|
1318
|
-
defineWidget as
|
|
1365
|
+
defineWidget as defineWidget7,
|
|
1319
1366
|
flashBackgroundStyle,
|
|
1320
1367
|
formatValue,
|
|
1321
1368
|
optBoolean,
|
|
@@ -1329,6 +1376,24 @@ import {
|
|
|
1329
1376
|
WidgetFrame
|
|
1330
1377
|
} from "@devicechain/widget-sdk";
|
|
1331
1378
|
import { buildGaugeOption, EChart, gaugeReadoutBox, loadChartEngine, useChartTheme } from "@devicechain/widget-sdk/echarts";
|
|
1379
|
+
|
|
1380
|
+
// src/widgets/no-reading-lazy.tsx
|
|
1381
|
+
import { useEffect, useState } from "react";
|
|
1382
|
+
var NoReading = lazyChunk(() => import("./chunks/no-reading-B4MPXAS2.js")).component("NoReading");
|
|
1383
|
+
function useSettledEmpty(empty, ms = 1500) {
|
|
1384
|
+
const [settled, setSettled] = useState(false);
|
|
1385
|
+
useEffect(() => {
|
|
1386
|
+
if (!empty) {
|
|
1387
|
+
setSettled(false);
|
|
1388
|
+
return;
|
|
1389
|
+
}
|
|
1390
|
+
const timer = setTimeout(() => setSettled(true), ms);
|
|
1391
|
+
return () => clearTimeout(timer);
|
|
1392
|
+
}, [empty, ms]);
|
|
1393
|
+
return empty && settled;
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
// src/widgets/gauge.tsx
|
|
1332
1397
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
1333
1398
|
function Gauge({ widget, data }) {
|
|
1334
1399
|
const name = primaryMeasurementName(widget);
|
|
@@ -1364,6 +1429,10 @@ function GaugeBody({ widget, data }) {
|
|
|
1364
1429
|
"aria-valuenow": Math.min(range.range.max, Math.max(range.range.min, value)),
|
|
1365
1430
|
"aria-valuetext": `${formatValue(value, precision)}${unit ? ` ${unit}` : ""}`
|
|
1366
1431
|
} : {};
|
|
1432
|
+
const explain = useSettledEmpty(value === void 0);
|
|
1433
|
+
if (explain) {
|
|
1434
|
+
return /* @__PURE__ */ jsx(NoReading, { unbound: widget.datasource?.kind === "unbound", measurement: name, waitMs: 0 });
|
|
1435
|
+
}
|
|
1367
1436
|
return /* @__PURE__ */ jsxs("div", { style: { position: "relative", width: "100%", height: "100%", ...flashBackgroundStyle(flashDirection) }, ...meter, children: [
|
|
1368
1437
|
/* @__PURE__ */ jsx(EChart, { option }),
|
|
1369
1438
|
/* @__PURE__ */ jsx(
|
|
@@ -1394,7 +1463,7 @@ function GaugeBody({ widget, data }) {
|
|
|
1394
1463
|
] });
|
|
1395
1464
|
}
|
|
1396
1465
|
Gauge.preload = loadChartEngine;
|
|
1397
|
-
var gaugeWidget =
|
|
1466
|
+
var gaugeWidget = defineWidget7({
|
|
1398
1467
|
descriptor: builtinWidgetDescriptors["gauge"],
|
|
1399
1468
|
implementation: { kind: "trusted-react", component: Gauge }
|
|
1400
1469
|
});
|
|
@@ -1402,7 +1471,7 @@ var gaugeWidget = defineWidget6({
|
|
|
1402
1471
|
// src/widgets/image.tsx
|
|
1403
1472
|
import {
|
|
1404
1473
|
css,
|
|
1405
|
-
defineWidget as
|
|
1474
|
+
defineWidget as defineWidget8,
|
|
1406
1475
|
fontVar,
|
|
1407
1476
|
optString as optString2,
|
|
1408
1477
|
WidgetFrame as WidgetFrame2
|
|
@@ -1429,7 +1498,7 @@ function Image({ widget }) {
|
|
|
1429
1498
|
}
|
|
1430
1499
|
) });
|
|
1431
1500
|
}
|
|
1432
|
-
var imageWidget =
|
|
1501
|
+
var imageWidget = defineWidget8({
|
|
1433
1502
|
descriptor: builtinWidgetDescriptors["image"],
|
|
1434
1503
|
implementation: { kind: "trusted-react", component: Image }
|
|
1435
1504
|
});
|
|
@@ -1437,7 +1506,7 @@ var imageWidget = defineWidget7({
|
|
|
1437
1506
|
// src/widgets/label.tsx
|
|
1438
1507
|
import {
|
|
1439
1508
|
css as css2,
|
|
1440
|
-
defineWidget as
|
|
1509
|
+
defineWidget as defineWidget9,
|
|
1441
1510
|
fontVar as fontVar2,
|
|
1442
1511
|
spaceVar,
|
|
1443
1512
|
optNumber as optNumber2,
|
|
@@ -1484,7 +1553,7 @@ function Label({ widget }) {
|
|
|
1484
1553
|
}
|
|
1485
1554
|
) });
|
|
1486
1555
|
}
|
|
1487
|
-
var labelWidget =
|
|
1556
|
+
var labelWidget = defineWidget9({
|
|
1488
1557
|
descriptor: builtinWidgetDescriptors["label"],
|
|
1489
1558
|
implementation: { kind: "trusted-react", component: Label }
|
|
1490
1559
|
});
|
|
@@ -1494,7 +1563,7 @@ import { useMemo as useMemo2 } from "react";
|
|
|
1494
1563
|
import {
|
|
1495
1564
|
bandAt,
|
|
1496
1565
|
css as css3,
|
|
1497
|
-
defineWidget as
|
|
1566
|
+
defineWidget as defineWidget10,
|
|
1498
1567
|
fitValueFont,
|
|
1499
1568
|
fitValueFontCss,
|
|
1500
1569
|
FIT_MIN_FONT_PX,
|
|
@@ -1537,6 +1606,9 @@ function LatestCard({ widget, data }) {
|
|
|
1537
1606
|
);
|
|
1538
1607
|
const chars = useStickyChars(display.length + (sample?.value != null && unit ? Math.ceil(unit.length / 2) + 1 : 0));
|
|
1539
1608
|
return /* @__PURE__ */ jsx4(WidgetFrame4, { title, sampleTime: sample?.occurredTime ?? null, children: ({ size, scale }) => {
|
|
1609
|
+
if (sample?.value == null) {
|
|
1610
|
+
return /* @__PURE__ */ jsx4(NoReading, { unbound: widget.datasource?.kind === "unbound", measurement: name });
|
|
1611
|
+
}
|
|
1540
1612
|
const floor = Math.round(FIT_MIN_FONT_PX * scale);
|
|
1541
1613
|
const measured = size.width > 0 && size.height > 0;
|
|
1542
1614
|
const valuePx = measured ? fitValueFont(size, chars, { floor }) : void 0;
|
|
@@ -1592,48 +1664,48 @@ function LatestCard({ widget, data }) {
|
|
|
1592
1664
|
);
|
|
1593
1665
|
} });
|
|
1594
1666
|
}
|
|
1595
|
-
var latestCardWidget =
|
|
1667
|
+
var latestCardWidget = defineWidget10({
|
|
1596
1668
|
descriptor: builtinWidgetDescriptors["latest-card"],
|
|
1597
1669
|
implementation: { kind: "trusted-react", component: LatestCard }
|
|
1598
1670
|
});
|
|
1599
1671
|
|
|
1600
1672
|
// src/widgets/level-lazy.tsx
|
|
1601
|
-
import { defineWidget as
|
|
1673
|
+
import { defineWidget as defineWidget11 } from "@devicechain/widget-sdk";
|
|
1602
1674
|
import { loadChartEngine as loadChartEngine2 } from "@devicechain/widget-sdk/echarts";
|
|
1603
|
-
var
|
|
1604
|
-
var loadLevelWidgets =
|
|
1605
|
-
var lazyComponent =
|
|
1606
|
-
var linearGaugeWidget =
|
|
1675
|
+
var chunk7 = lazyChunk(() => import("./chunks/level-widgets-HE6EDSWC.js"));
|
|
1676
|
+
var loadLevelWidgets = chunk7.load;
|
|
1677
|
+
var lazyComponent = chunk7.component;
|
|
1678
|
+
var linearGaugeWidget = defineWidget11({
|
|
1607
1679
|
descriptor: builtinWidgetDescriptors["linear-gauge"],
|
|
1608
1680
|
implementation: { kind: "trusted-react", component: lazyComponent("LinearGauge") }
|
|
1609
1681
|
});
|
|
1610
|
-
var levelGaugeWidget =
|
|
1682
|
+
var levelGaugeWidget = defineWidget11({
|
|
1611
1683
|
descriptor: builtinWidgetDescriptors["level-gauge"],
|
|
1612
1684
|
implementation: { kind: "trusted-react", component: lazyComponent("LevelGauge") }
|
|
1613
1685
|
});
|
|
1614
|
-
var batteryWidget =
|
|
1686
|
+
var batteryWidget = defineWidget11({
|
|
1615
1687
|
descriptor: builtinWidgetDescriptors["battery"],
|
|
1616
1688
|
implementation: { kind: "trusted-react", component: lazyComponent("Battery") }
|
|
1617
1689
|
});
|
|
1618
|
-
var statusLightWidget =
|
|
1690
|
+
var statusLightWidget = defineWidget11({
|
|
1619
1691
|
descriptor: builtinWidgetDescriptors["status-light"],
|
|
1620
1692
|
implementation: { kind: "trusted-react", component: lazyComponent("StatusLight") }
|
|
1621
1693
|
});
|
|
1622
|
-
var signalBarsWidget =
|
|
1694
|
+
var signalBarsWidget = defineWidget11({
|
|
1623
1695
|
descriptor: builtinWidgetDescriptors["signal-bars"],
|
|
1624
1696
|
implementation: { kind: "trusted-react", component: lazyComponent("SignalBars") }
|
|
1625
1697
|
});
|
|
1626
|
-
var compassWidget =
|
|
1698
|
+
var compassWidget = defineWidget11({
|
|
1627
1699
|
descriptor: builtinWidgetDescriptors["compass"],
|
|
1628
1700
|
implementation: { kind: "trusted-react", component: lazyComponent("Compass", loadChartEngine2) }
|
|
1629
1701
|
});
|
|
1630
|
-
var progressRingWidget =
|
|
1702
|
+
var progressRingWidget = defineWidget11({
|
|
1631
1703
|
descriptor: builtinWidgetDescriptors["progress-ring"],
|
|
1632
1704
|
implementation: { kind: "trusted-react", component: lazyComponent("ProgressRing") }
|
|
1633
1705
|
});
|
|
1634
1706
|
|
|
1635
1707
|
// src/widgets/map.tsx
|
|
1636
|
-
import { useEffect, useRef, useState } from "react";
|
|
1708
|
+
import { useEffect as useEffect2, useRef, useState as useState2 } from "react";
|
|
1637
1709
|
import { renderableBasemap, resolveBasemap } from "@devicechain/client";
|
|
1638
1710
|
|
|
1639
1711
|
// src/basemap-context.tsx
|
|
@@ -1668,7 +1740,7 @@ function useMapRuntime() {
|
|
|
1668
1740
|
import {
|
|
1669
1741
|
css as css4,
|
|
1670
1742
|
fontVar as fontVar4,
|
|
1671
|
-
defineWidget as
|
|
1743
|
+
defineWidget as defineWidget12,
|
|
1672
1744
|
optString as optString5,
|
|
1673
1745
|
useWidgetSelect,
|
|
1674
1746
|
WidgetFrame as WidgetFrame5
|
|
@@ -1897,13 +1969,13 @@ function LiveMap({
|
|
|
1897
1969
|
const containerRef = useRef(null);
|
|
1898
1970
|
const mapRef = useRef(null);
|
|
1899
1971
|
const markersRef = useRef([]);
|
|
1900
|
-
const [status, setStatus] =
|
|
1972
|
+
const [status, setStatus] = useState2("loading");
|
|
1901
1973
|
const pickRef = useRef(pick);
|
|
1902
1974
|
pickRef.current = pick;
|
|
1903
1975
|
const selectable = pick !== void 0;
|
|
1904
1976
|
const tileUrl = basemap?.tileUrl ?? null;
|
|
1905
1977
|
const attribution = basemap?.attribution ?? null;
|
|
1906
|
-
|
|
1978
|
+
useEffect2(() => {
|
|
1907
1979
|
let cancelled = false;
|
|
1908
1980
|
setStatus("loading");
|
|
1909
1981
|
Promise.all([
|
|
@@ -1931,7 +2003,7 @@ function LiveMap({
|
|
|
1931
2003
|
mapRef.current = null;
|
|
1932
2004
|
};
|
|
1933
2005
|
}, [tileUrl, attribution, runtime.workerUrl]);
|
|
1934
|
-
|
|
2006
|
+
useEffect2(() => {
|
|
1935
2007
|
const map = mapRef.current;
|
|
1936
2008
|
if (status !== "ready" || !map) return;
|
|
1937
2009
|
let live = true;
|
|
@@ -2065,18 +2137,18 @@ function MapNotice({ glyph, heading, detail }) {
|
|
|
2065
2137
|
}
|
|
2066
2138
|
);
|
|
2067
2139
|
}
|
|
2068
|
-
var mapWidget =
|
|
2140
|
+
var mapWidget = defineWidget12({
|
|
2069
2141
|
descriptor: builtinWidgetDescriptors["map"],
|
|
2070
2142
|
implementation: { kind: "trusted-react", component: MapWidget }
|
|
2071
2143
|
});
|
|
2072
2144
|
|
|
2073
2145
|
// src/widgets/table-lazy.tsx
|
|
2074
|
-
import { defineWidget as
|
|
2075
|
-
var
|
|
2076
|
-
var loadTableWidget =
|
|
2077
|
-
var tableWidget =
|
|
2146
|
+
import { defineWidget as defineWidget13 } from "@devicechain/widget-sdk";
|
|
2147
|
+
var chunk8 = lazyChunk(() => import("./chunks/table-CEVB3JZS.js"));
|
|
2148
|
+
var loadTableWidget = chunk8.load;
|
|
2149
|
+
var tableWidget = defineWidget13({
|
|
2078
2150
|
descriptor: builtinWidgetDescriptors["table"],
|
|
2079
|
-
implementation: { kind: "trusted-react", component:
|
|
2151
|
+
implementation: { kind: "trusted-react", component: chunk8.component("Table") }
|
|
2080
2152
|
});
|
|
2081
2153
|
|
|
2082
2154
|
// src/widgets/time-series-chart.tsx
|
|
@@ -2084,13 +2156,15 @@ import { useMemo as useMemo3 } from "react";
|
|
|
2084
2156
|
import { isValidSpanSeconds, spanLabel } from "@devicechain/dashboards";
|
|
2085
2157
|
import {
|
|
2086
2158
|
css as css5,
|
|
2087
|
-
defineWidget as
|
|
2159
|
+
defineWidget as defineWidget14,
|
|
2088
2160
|
fontVar as fontVar5,
|
|
2089
2161
|
formatDateTime,
|
|
2090
2162
|
formatTimestamp as formatTimestamp2,
|
|
2091
2163
|
optNumber as optNumber4,
|
|
2092
2164
|
optString as optString6,
|
|
2093
2165
|
optThresholds as optThresholds3,
|
|
2166
|
+
pickSample as pickSample3,
|
|
2167
|
+
primaryMeasurementName as primaryMeasurementName3,
|
|
2094
2168
|
spaceVar as spaceVar3,
|
|
2095
2169
|
useWidgetScale as useWidgetScale2,
|
|
2096
2170
|
useWidgetTimeRange,
|
|
@@ -2101,7 +2175,23 @@ import {
|
|
|
2101
2175
|
import { buildLineOption, EChart as EChart2, loadChartEngine as loadChartEngine3, useChartTheme as useChartTheme2 } from "@devicechain/widget-sdk/echarts";
|
|
2102
2176
|
import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
2103
2177
|
function TimeSeriesChart({ widget, data, markers }) {
|
|
2104
|
-
|
|
2178
|
+
const range = useWidgetTimeRange();
|
|
2179
|
+
const pinned = optNumber4(widget.options, "windowSeconds");
|
|
2180
|
+
const spanSeconds = isValidSpanSeconds(pinned) ? pinned : range?.spanSeconds;
|
|
2181
|
+
const exportRows = () => {
|
|
2182
|
+
const device = widget.datasource?.kind === "device" ? widget.datasource.deviceToken : void 0;
|
|
2183
|
+
return import("./chunks/export-rows-OEWIBIUY.js").then(
|
|
2184
|
+
(m) => m.samplesExport({
|
|
2185
|
+
subject: optString6(widget.options, "title") ?? device ?? "chart",
|
|
2186
|
+
samples: data.samples,
|
|
2187
|
+
unit: optString6(widget.options, "unit"),
|
|
2188
|
+
precision: optNumber4(widget.options, "precision"),
|
|
2189
|
+
seriesIs: "measurement",
|
|
2190
|
+
spanSeconds
|
|
2191
|
+
})
|
|
2192
|
+
);
|
|
2193
|
+
};
|
|
2194
|
+
return /* @__PURE__ */ jsx8(WidgetFrame6, { title: optString6(widget.options, "title"), flush: true, exportRows, children: /* @__PURE__ */ jsx8(TimeSeriesBody, { widget, data, markers }) });
|
|
2105
2195
|
}
|
|
2106
2196
|
function TimeSeriesBody({ widget, data, markers }) {
|
|
2107
2197
|
const theme = useChartTheme2();
|
|
@@ -2116,6 +2206,21 @@ function TimeSeriesBody({ widget, data, markers }) {
|
|
|
2116
2206
|
const base = buildLineOption(data.samples, theme, { measurements, unit, precision, thresholds, scale, gaps: data.gaps, min, max }, size);
|
|
2117
2207
|
return markers ? markers.decorate(base, size) : base;
|
|
2118
2208
|
}, [data.samples, data.gaps, theme, measurements, unit, precision, thresholds, scale, size, markers, min, max]);
|
|
2209
|
+
const name = measurements && measurements.length > 1 ? void 0 : primaryMeasurementName3(widget);
|
|
2210
|
+
const explain = useSettledEmpty(data.samples.length === 0);
|
|
2211
|
+
if (explain) {
|
|
2212
|
+
return /* @__PURE__ */ jsx8(
|
|
2213
|
+
NoReading,
|
|
2214
|
+
{
|
|
2215
|
+
unbound: widget.datasource?.kind === "unbound",
|
|
2216
|
+
measurement: name,
|
|
2217
|
+
lastSample: pickSample3(data.latest, name),
|
|
2218
|
+
unit,
|
|
2219
|
+
precision,
|
|
2220
|
+
waitMs: 0
|
|
2221
|
+
}
|
|
2222
|
+
);
|
|
2223
|
+
}
|
|
2119
2224
|
const chart = /* @__PURE__ */ jsxs4("div", { style: { position: "relative", width: "100%", height: "100%" }, children: [
|
|
2120
2225
|
/* @__PURE__ */ jsx8(EChart2, { option }),
|
|
2121
2226
|
/* @__PURE__ */ jsx8(SpanBadge, { widget, data })
|
|
@@ -2176,7 +2281,7 @@ function SpanBadge({ widget, data }) {
|
|
|
2176
2281
|
);
|
|
2177
2282
|
}
|
|
2178
2283
|
TimeSeriesChart.preload = loadChartEngine3;
|
|
2179
|
-
var timeSeriesChartWidget =
|
|
2284
|
+
var timeSeriesChartWidget = defineWidget14({
|
|
2180
2285
|
descriptor: builtinWidgetDescriptors["timeseries-chart"],
|
|
2181
2286
|
implementation: { kind: "trusted-react", component: TimeSeriesChart }
|
|
2182
2287
|
});
|
|
@@ -2210,7 +2315,8 @@ var builtinWidgetDefinitions = [
|
|
|
2210
2315
|
fleetTableWidget,
|
|
2211
2316
|
fleetCountWidget,
|
|
2212
2317
|
deviceStatusWidget,
|
|
2213
|
-
onlineDoughnutWidget
|
|
2318
|
+
onlineDoughnutWidget,
|
|
2319
|
+
historyTableWidget
|
|
2214
2320
|
];
|
|
2215
2321
|
function createBuiltinWidgetRegistry() {
|
|
2216
2322
|
return createWidgetRegistry(builtinWidgetDefinitions);
|
|
@@ -2225,7 +2331,11 @@ function defaultWidgetRegistry() {
|
|
|
2225
2331
|
|
|
2226
2332
|
// src/connected-widget.tsx
|
|
2227
2333
|
import {
|
|
2334
|
+
css as css6,
|
|
2335
|
+
fontVar as fontVar6,
|
|
2228
2336
|
optString as optString7,
|
|
2337
|
+
spaceVar as spaceVar4,
|
|
2338
|
+
viewerLocale as viewerLocale2,
|
|
2229
2339
|
useAlarmStream,
|
|
2230
2340
|
useCommandStream,
|
|
2231
2341
|
useDatasourceAvailability,
|
|
@@ -2237,7 +2347,7 @@ import {
|
|
|
2237
2347
|
} from "@devicechain/widget-sdk";
|
|
2238
2348
|
|
|
2239
2349
|
// src/widget-containment.tsx
|
|
2240
|
-
import { Component, createContext as createContext3, useCallback, useContext as useContext3, useState as
|
|
2350
|
+
import { Component, createContext as createContext3, useCallback, useContext as useContext3, useState as useState3 } from "react";
|
|
2241
2351
|
import { WidgetFrame as WidgetFrame7 } from "@devicechain/widget-sdk";
|
|
2242
2352
|
|
|
2243
2353
|
// src/widget-host.ts
|
|
@@ -2349,7 +2459,7 @@ var WidgetErrorBoundary = class extends Component {
|
|
|
2349
2459
|
}
|
|
2350
2460
|
};
|
|
2351
2461
|
function WidgetContainment({ title, resetKey, children }) {
|
|
2352
|
-
const [messages, setMessages] =
|
|
2462
|
+
const [messages, setMessages] = useState3([]);
|
|
2353
2463
|
const report = useCallback((message) => {
|
|
2354
2464
|
setMessages((prev) => prev.includes(message) ? prev : [...prev, message].slice(-3));
|
|
2355
2465
|
}, []);
|
|
@@ -2392,6 +2502,7 @@ function ConnectedWidget(props) {
|
|
|
2392
2502
|
return /* @__PURE__ */ jsx10(WidgetContainment, { title: optString7(widget.options, "title"), resetKey, children: /* @__PURE__ */ jsx10(ConnectedWidgetBody, { ...props, registry }) });
|
|
2393
2503
|
}
|
|
2394
2504
|
function ConnectedWidgetBody({ widget, hub, registry, actions, initialSamples, initialSamplesAsOf, onReconnect }) {
|
|
2505
|
+
const range = useWidgetTimeRange2();
|
|
2395
2506
|
const unresolved = widget.type === UNKNOWN_WIDGET_TYPE;
|
|
2396
2507
|
const descriptor = unresolved ? void 0 : registry.descriptor(widget.type);
|
|
2397
2508
|
const implementation = unresolved ? void 0 : registry.implementation(widget.type);
|
|
@@ -2416,7 +2527,7 @@ function ConnectedWidgetBody({ widget, hub, registry, actions, initialSamples, i
|
|
|
2416
2527
|
}
|
|
2417
2528
|
);
|
|
2418
2529
|
}
|
|
2419
|
-
|
|
2530
|
+
const body = /* @__PURE__ */ jsx10(DeclaredScope, { hub, datasource: widget.datasource, children: /* @__PURE__ */ jsx10(HostScope, { descriptor, actions, children: (hostActions) => /* @__PURE__ */ jsx10(
|
|
2420
2531
|
ChannelBody,
|
|
2421
2532
|
{
|
|
2422
2533
|
widget,
|
|
@@ -2428,12 +2539,50 @@ function ConnectedWidgetBody({ widget, hub, registry, actions, initialSamples, i
|
|
|
2428
2539
|
initialSamplesAsOf,
|
|
2429
2540
|
onReconnect
|
|
2430
2541
|
}
|
|
2431
|
-
) });
|
|
2542
|
+
) }) });
|
|
2543
|
+
return range?.absolute !== void 0 && showsCurrentStateOnly(descriptor) ? /* @__PURE__ */ jsx10(CurrentStateBadge, { children: body }) : body;
|
|
2544
|
+
}
|
|
2545
|
+
function showsCurrentStateOnly(descriptor) {
|
|
2546
|
+
return descriptor.channel === "alarm" || descriptor.channel === "location" || presenceMode(descriptor);
|
|
2547
|
+
}
|
|
2548
|
+
var CURRENT_STATE_STRINGS = {
|
|
2549
|
+
en: { label: "Now", title: "Shows the current state: the fixed time window does not apply to this widget." },
|
|
2550
|
+
es: { label: "Ahora", title: "Muestra el estado actual: la ventana de tiempo fija no se aplica a este widget." }
|
|
2551
|
+
};
|
|
2552
|
+
function CurrentStateBadge({ children }) {
|
|
2553
|
+
const words = viewerLocale2()?.toLowerCase().startsWith("es") ? CURRENT_STATE_STRINGS.es : CURRENT_STATE_STRINGS.en;
|
|
2554
|
+
return /* @__PURE__ */ jsxs6("div", { "data-current-state": "", style: { position: "relative", width: "100%", height: "100%", minWidth: 0, minHeight: 0 }, children: [
|
|
2555
|
+
children,
|
|
2556
|
+
/* @__PURE__ */ jsx10(
|
|
2557
|
+
"span",
|
|
2558
|
+
{
|
|
2559
|
+
"data-current-state-badge": "",
|
|
2560
|
+
role: "note",
|
|
2561
|
+
title: words.title,
|
|
2562
|
+
"aria-label": words.title,
|
|
2563
|
+
style: {
|
|
2564
|
+
position: "absolute",
|
|
2565
|
+
// Bottom LEFT: a map keeps its attribution bottom right, and a chart its span badge top right.
|
|
2566
|
+
bottom: spaceVar4(1),
|
|
2567
|
+
left: spaceVar4(2),
|
|
2568
|
+
padding: `0 ${spaceVar4(1)}`,
|
|
2569
|
+
fontSize: fontVar6("xs"),
|
|
2570
|
+
fontWeight: 600,
|
|
2571
|
+
whiteSpace: "nowrap",
|
|
2572
|
+
color: css6("background"),
|
|
2573
|
+
background: css6("foreground"),
|
|
2574
|
+
borderRadius: 4,
|
|
2575
|
+
zIndex: 1
|
|
2576
|
+
},
|
|
2577
|
+
children: words.label
|
|
2578
|
+
}
|
|
2579
|
+
)
|
|
2580
|
+
] });
|
|
2432
2581
|
}
|
|
2433
2582
|
function useDatasourceSupported(hub, datasource) {
|
|
2434
2583
|
const key = datasource ? JSON.stringify(datasource) : null;
|
|
2435
|
-
const [refused, setRefused] =
|
|
2436
|
-
|
|
2584
|
+
const [refused, setRefused] = useState4(null);
|
|
2585
|
+
useEffect3(() => {
|
|
2437
2586
|
if (!datasource || !hub.isDatasourceSupported) return;
|
|
2438
2587
|
let cancelled = false;
|
|
2439
2588
|
hub.isDatasourceSupported(datasource).then(
|
|
@@ -2450,6 +2599,26 @@ function useDatasourceSupported(hub, datasource) {
|
|
|
2450
2599
|
}, [hub, key]);
|
|
2451
2600
|
return refused === null || refused !== key;
|
|
2452
2601
|
}
|
|
2602
|
+
function DeclaredScope({ hub, datasource, children }) {
|
|
2603
|
+
const token = datasource?.kind === "device" && datasource.deviceToken ? datasource.deviceToken : void 0;
|
|
2604
|
+
const [asked, setAsked] = useState4(false);
|
|
2605
|
+
const [got, setGot] = useState4();
|
|
2606
|
+
const ask = useCallback2(() => setAsked(true), []);
|
|
2607
|
+
useEffect3(() => {
|
|
2608
|
+
if (!asked || !token || !hub.declaredMetricsForDevice) return;
|
|
2609
|
+
let live = true;
|
|
2610
|
+
hub.declaredMetricsForDevice(token).then(
|
|
2611
|
+
(names) => live && setGot({ token, names }),
|
|
2612
|
+
() => void 0
|
|
2613
|
+
);
|
|
2614
|
+
return () => {
|
|
2615
|
+
live = false;
|
|
2616
|
+
};
|
|
2617
|
+
}, [asked, token, hub]);
|
|
2618
|
+
const declared = got && got.token === token ? got.names : void 0;
|
|
2619
|
+
const value = useMemo4(() => ({ declared, ask }), [declared, ask]);
|
|
2620
|
+
return /* @__PURE__ */ jsx10(WidgetDeclaredMetricsProvider, { value, children });
|
|
2621
|
+
}
|
|
2453
2622
|
function HostScope({
|
|
2454
2623
|
descriptor,
|
|
2455
2624
|
actions,
|
|
@@ -2486,8 +2655,9 @@ function ChannelBody(props) {
|
|
|
2486
2655
|
function StaticConnectedWidget({ widget, Component: Component2, actions }) {
|
|
2487
2656
|
return /* @__PURE__ */ jsx10(Component2, { widget, data: null, actions });
|
|
2488
2657
|
}
|
|
2489
|
-
var FleetFeed = lazyChunk(() => import("./chunks/fleet-feed-
|
|
2490
|
-
var PresenceFeed = lazyChunk(() => import("./chunks/presence-widgets-
|
|
2658
|
+
var FleetFeed = lazyChunk(() => import("./chunks/fleet-feed-D4T3LC25.js")).component("default", void 0, ChunkLoadingFrame);
|
|
2659
|
+
var PresenceFeed = lazyChunk(() => import("./chunks/presence-widgets-M5VGG3OO.js")).component("PresenceFeed");
|
|
2660
|
+
var HistoryFeed = lazyChunk(() => import("./chunks/history-widgets-NSNXDKEC.js")).component("HistoryFeed");
|
|
2491
2661
|
function MeasurementConnectedWidget(props) {
|
|
2492
2662
|
if (presenceMode(props.descriptor)) {
|
|
2493
2663
|
return /* @__PURE__ */ jsx10(PresenceFeed, { hub: props.hub, widget: props.widget, descriptor: props.descriptor, Component: props.Component, actions: props.actions, ErrorFrame: WidgetErrorFrame });
|
|
@@ -2497,6 +2667,9 @@ function MeasurementConnectedWidget(props) {
|
|
|
2497
2667
|
if (members || widget.datasource?.kind === "anchor") {
|
|
2498
2668
|
return /* @__PURE__ */ jsx10(FleetFeed, { hub, widget, descriptor, Component: Component2, actions, ErrorFrame: WidgetErrorFrame, refuse: !members });
|
|
2499
2669
|
}
|
|
2670
|
+
if (historyMode(descriptor)) {
|
|
2671
|
+
return /* @__PURE__ */ jsx10(HistoryFeed, { hub, widget, descriptor, Component: Component2, actions });
|
|
2672
|
+
}
|
|
2500
2673
|
return /* @__PURE__ */ jsx10(StreamConnectedWidget, { ...props });
|
|
2501
2674
|
}
|
|
2502
2675
|
function StreamConnectedWidget({ widget, hub, descriptor, Component: Component2, actions, initialSamples, initialSamplesAsOf, onReconnect }) {
|
|
@@ -2523,8 +2696,8 @@ function StreamConnectedWidget({ widget, hub, descriptor, Component: Component2,
|
|
|
2523
2696
|
if (data.error) return /* @__PURE__ */ jsx10(WidgetErrorFrame, { widget, error: data.error });
|
|
2524
2697
|
return /* @__PURE__ */ jsx10(WidgetFreshnessProvider, { freshness, children: wantsEventMarkers(descriptor, widget) ? /* @__PURE__ */ jsx10(EventMarkersFeed, { hub, widget, descriptor, data, Component: Component2, actions }) : /* @__PURE__ */ jsx10(Component2, { widget, data, actions }) });
|
|
2525
2698
|
}
|
|
2526
|
-
var EventMarkersFeed = lazyChunk(() => import("./chunks/event-markers-feed-
|
|
2527
|
-
var AggregateFeed = lazyChunk(() => import("./chunks/aggregate-feed-
|
|
2699
|
+
var EventMarkersFeed = lazyChunk(() => import("./chunks/event-markers-feed-B3MVFYUT.js")).component("default");
|
|
2700
|
+
var AggregateFeed = lazyChunk(() => import("./chunks/aggregate-feed-XX36GNY6.js")).component("default");
|
|
2528
2701
|
function AggregateConnectedWidget({ widget, hub, descriptor, Component: Component2, actions }) {
|
|
2529
2702
|
const props = { hub, widget, descriptor, Component: Component2, actions, ErrorFrame: WidgetErrorFrame };
|
|
2530
2703
|
return widget.datasource?.kind === "anchor" ? /* @__PURE__ */ jsx10(FleetFeed, { ...props, refuse: true }) : /* @__PURE__ */ jsx10(AggregateFeed, { ...props });
|
|
@@ -2600,52 +2773,45 @@ function UnresolvedWidgetFrame({
|
|
|
2600
2773
|
}
|
|
2601
2774
|
) });
|
|
2602
2775
|
}
|
|
2776
|
+
function StatePane({
|
|
2777
|
+
widget,
|
|
2778
|
+
kind,
|
|
2779
|
+
glyph,
|
|
2780
|
+
title,
|
|
2781
|
+
detail
|
|
2782
|
+
}) {
|
|
2783
|
+
return /* @__PURE__ */ jsx10(WidgetFrame8, { title: optString7(widget.options, "title"), children: /* @__PURE__ */ jsx10(StateBody, { kind, glyph, title, detail }) });
|
|
2784
|
+
}
|
|
2785
|
+
function StateBody({ kind, glyph, title, detail }) {
|
|
2786
|
+
const { height } = useWidgetScale3().size;
|
|
2787
|
+
const measured = height > 0;
|
|
2788
|
+
return /* @__PURE__ */ jsxs6("div", { role: "status", "data-empty-state": kind, style: STATE_STYLE, children: [
|
|
2789
|
+
!measured || height >= 84 ? /* @__PURE__ */ jsx10("div", { style: { fontSize: 20, lineHeight: 1 }, "aria-hidden": "true", children: glyph }) : null,
|
|
2790
|
+
/* @__PURE__ */ jsx10("div", { style: { fontSize: 13, fontWeight: 600 }, children: title }),
|
|
2791
|
+
detail && (!measured || height >= 64) ? /* @__PURE__ */ jsx10("div", { style: { fontSize: 11, opacity: 0.8, wordBreak: "break-word" }, children: detail }) : null
|
|
2792
|
+
] });
|
|
2793
|
+
}
|
|
2603
2794
|
function WidgetForbiddenFrame({ widget }) {
|
|
2604
|
-
return /* @__PURE__ */ jsx10(
|
|
2605
|
-
/* @__PURE__ */ jsx10("div", { style: { fontSize: 20, lineHeight: 1 }, "aria-hidden": "true", children: "\u2298" }),
|
|
2606
|
-
/* @__PURE__ */ jsx10("div", { style: { fontSize: 13, fontWeight: 600 }, children: accessStrings().forbidden })
|
|
2607
|
-
] }) });
|
|
2795
|
+
return /* @__PURE__ */ jsx10(StatePane, { widget, kind: "forbidden", glyph: "\u2298", title: accessStrings().forbidden });
|
|
2608
2796
|
}
|
|
2609
2797
|
function WidgetUnavailableFrame({ widget }) {
|
|
2610
|
-
return /* @__PURE__ */ jsx10(
|
|
2611
|
-
"div",
|
|
2612
|
-
{
|
|
2613
|
-
style: STATE_STYLE,
|
|
2614
|
-
children: [
|
|
2615
|
-
/* @__PURE__ */ jsx10("div", { style: { fontSize: 20, lineHeight: 1 }, "aria-hidden": "true", children: "\u2298" }),
|
|
2616
|
-
/* @__PURE__ */ jsx10("div", { style: { fontSize: 13, fontWeight: 600 }, children: "Device unavailable" }),
|
|
2617
|
-
/* @__PURE__ */ jsx10("div", { style: { fontSize: 11, opacity: 0.8 }, children: "The bound device no longer exists." })
|
|
2618
|
-
]
|
|
2619
|
-
}
|
|
2620
|
-
) });
|
|
2798
|
+
return /* @__PURE__ */ jsx10(StatePane, { widget, kind: "gone", glyph: "\u2298", title: "Device unavailable", detail: "The bound device no longer exists." });
|
|
2621
2799
|
}
|
|
2622
2800
|
function WidgetNotForCustomerUsersFrame({ widget }) {
|
|
2623
|
-
return /* @__PURE__ */ jsx10(
|
|
2624
|
-
|
|
2801
|
+
return /* @__PURE__ */ jsx10(
|
|
2802
|
+
StatePane,
|
|
2625
2803
|
{
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
/* @__PURE__ */ jsx10("div", { style: { fontSize: 11, opacity: 0.8 }, children: "This widget is bound to an area or an asset, which customer users cannot view." })
|
|
2632
|
-
]
|
|
2804
|
+
widget,
|
|
2805
|
+
kind: "unsupported",
|
|
2806
|
+
glyph: "\u2298",
|
|
2807
|
+
title: "Not available for customer users",
|
|
2808
|
+
detail: "This widget is bound to an area or an asset, which customer users cannot view."
|
|
2633
2809
|
}
|
|
2634
|
-
)
|
|
2810
|
+
);
|
|
2635
2811
|
}
|
|
2636
2812
|
function WidgetErrorFrame({ widget, error }) {
|
|
2637
2813
|
if (isForbiddenError(error)) return /* @__PURE__ */ jsx10(WidgetForbiddenFrame, { widget });
|
|
2638
|
-
return /* @__PURE__ */ jsx10(
|
|
2639
|
-
"div",
|
|
2640
|
-
{
|
|
2641
|
-
style: STATE_STYLE,
|
|
2642
|
-
children: [
|
|
2643
|
-
/* @__PURE__ */ jsx10("div", { style: { fontSize: 20, lineHeight: 1 }, children: "\u26A0" }),
|
|
2644
|
-
/* @__PURE__ */ jsx10("div", { style: { fontSize: 13, fontWeight: 600 }, children: "Data unavailable" }),
|
|
2645
|
-
/* @__PURE__ */ jsx10("div", { style: { fontSize: 11, opacity: 0.8, wordBreak: "break-word" }, children: String(error) })
|
|
2646
|
-
]
|
|
2647
|
-
}
|
|
2648
|
-
) });
|
|
2814
|
+
return /* @__PURE__ */ jsx10(StatePane, { widget, kind: "error", glyph: "\u2026", title: "Data unavailable", detail: String(error) });
|
|
2649
2815
|
}
|
|
2650
2816
|
|
|
2651
2817
|
// src/dashboard-renderer.tsx
|
|
@@ -2680,12 +2846,13 @@ function DashboardRenderer({
|
|
|
2680
2846
|
[timeRange, defaultSeconds]
|
|
2681
2847
|
);
|
|
2682
2848
|
const { histories, reseed } = useWidgetHistories(widgets, seedHistory, registry, range);
|
|
2849
|
+
const windowKey = windowTag(range);
|
|
2683
2850
|
const { grid, background: bg, frame: canvasFrame } = definition.canvas;
|
|
2684
2851
|
const effectiveSizing = sizing ?? definition.canvas.sizing;
|
|
2685
2852
|
const effectiveDensity = density ?? definition.canvas.density ?? DEFAULT_CANVAS_DENSITY;
|
|
2686
2853
|
const scale = densityScale(effectiveDensity);
|
|
2687
2854
|
const { canvas } = definition;
|
|
2688
|
-
const shapeKey =
|
|
2855
|
+
const shapeKey = useCallback3((width) => JSON.stringify(layoutShape(canvas, width, scale)), [canvas, scale]);
|
|
2689
2856
|
const [boardRef, containerWidth] = useContainerWidth(shapeKey);
|
|
2690
2857
|
const layout = useMemo5(
|
|
2691
2858
|
() => effectiveLayout(definition, containerWidth, {
|
|
@@ -2737,7 +2904,8 @@ function DashboardRenderer({
|
|
|
2737
2904
|
initialSamples: histories[widget.id]?.samples,
|
|
2738
2905
|
initialSamplesAsOf: histories[widget.id]?.asOf,
|
|
2739
2906
|
onReconnect: () => reseed(widget.id)
|
|
2740
|
-
}
|
|
2907
|
+
},
|
|
2908
|
+
windowKey
|
|
2741
2909
|
) }) })
|
|
2742
2910
|
}
|
|
2743
2911
|
)
|
|
@@ -2854,9 +3022,9 @@ function widgetSubjectLabel(widget) {
|
|
|
2854
3022
|
}
|
|
2855
3023
|
function useContainerWidth(keyOf) {
|
|
2856
3024
|
const ref = useRef2(null);
|
|
2857
|
-
const [width, setWidth] =
|
|
3025
|
+
const [width, setWidth] = useState5(0);
|
|
2858
3026
|
const keyOfRef = useRef2(keyOf);
|
|
2859
|
-
const measure =
|
|
3027
|
+
const measure = useCallback3(() => {
|
|
2860
3028
|
const el = ref.current;
|
|
2861
3029
|
if (!el) return;
|
|
2862
3030
|
const next = el.clientWidth;
|
|
@@ -2875,6 +3043,9 @@ function useContainerWidth(keyOf) {
|
|
|
2875
3043
|
}, [measure]);
|
|
2876
3044
|
return [ref, width];
|
|
2877
3045
|
}
|
|
3046
|
+
function windowTag(range) {
|
|
3047
|
+
return range.absolute ? `${range.absolute.fromMs}-${range.absolute.toMs}` : "";
|
|
3048
|
+
}
|
|
2878
3049
|
var RESEED_RETRY_MS = 3e4;
|
|
2879
3050
|
function seedKey(widget, registry) {
|
|
2880
3051
|
if (widget.type === UNKNOWN_WIDGET_TYPE2 || registry.descriptor(widget.type)?.channel !== "measurement") {
|
|
@@ -2883,18 +3054,18 @@ function seedKey(widget, registry) {
|
|
|
2883
3054
|
return JSON.stringify(widget.datasource ?? null);
|
|
2884
3055
|
}
|
|
2885
3056
|
function useWidgetHistories(widgets, enabled, registry, range) {
|
|
2886
|
-
const [seeds, setSeeds] =
|
|
3057
|
+
const [seeds, setSeeds] = useState5({});
|
|
2887
3058
|
const requested = useRef2({});
|
|
2888
3059
|
const reseeds = useRef2({});
|
|
2889
|
-
const [reseedTick, bumpReseeds] =
|
|
3060
|
+
const [reseedTick, bumpReseeds] = useState5(0);
|
|
2890
3061
|
const mounted = useRef2(true);
|
|
2891
|
-
|
|
3062
|
+
useEffect4(() => {
|
|
2892
3063
|
mounted.current = true;
|
|
2893
3064
|
return () => {
|
|
2894
3065
|
mounted.current = false;
|
|
2895
3066
|
};
|
|
2896
3067
|
}, []);
|
|
2897
|
-
const reseed =
|
|
3068
|
+
const reseed = useCallback3((id) => {
|
|
2898
3069
|
reseeds.current[id] = (reseeds.current[id] ?? 0) + 1;
|
|
2899
3070
|
bumpReseeds((n) => n + 1);
|
|
2900
3071
|
}, []);
|
|
@@ -2905,8 +3076,9 @@ function useWidgetHistories(widgets, enabled, registry, range) {
|
|
|
2905
3076
|
const span = descriptor ? measurementSpan(descriptor, w, range.spanSeconds) ?? null : null;
|
|
2906
3077
|
return [[w.id, key, span]];
|
|
2907
3078
|
});
|
|
2908
|
-
const
|
|
2909
|
-
|
|
3079
|
+
const tag = windowTag(range);
|
|
3080
|
+
const wantedKey = JSON.stringify([tag, wanted]);
|
|
3081
|
+
useEffect4(() => {
|
|
2910
3082
|
if (!enabled) {
|
|
2911
3083
|
requested.current = {};
|
|
2912
3084
|
setSeeds({});
|
|
@@ -2916,7 +3088,7 @@ function useWidgetHistories(widgets, enabled, registry, range) {
|
|
|
2916
3088
|
const byId = new Map(widgets.map((w) => [w.id, w]));
|
|
2917
3089
|
const next = {};
|
|
2918
3090
|
for (const [id, key, span] of wanted) {
|
|
2919
|
-
const base = `${key}|${span ?? ""}|`;
|
|
3091
|
+
const base = `${key}|${span ?? ""}|${tag}|`;
|
|
2920
3092
|
const n = reseeds.current[id] ?? 0;
|
|
2921
3093
|
const asked = `${base}${range.paused && n ? "p" : n}`;
|
|
2922
3094
|
const previous = requested.current[id];
|
|
@@ -2928,12 +3100,12 @@ function useWidgetHistories(widgets, enabled, registry, range) {
|
|
|
2928
3100
|
const widget = byId.get(id);
|
|
2929
3101
|
if (widget?.datasource?.kind !== "device") continue;
|
|
2930
3102
|
const end = range.paused && range.pausedAt !== void 0 ? range.pausedAt : now;
|
|
2931
|
-
const historyWindow = span
|
|
3103
|
+
const historyWindow = span !== null ? historyWindowFor(span, end) : range.absolute ? historyWindowFor(DEFAULT_TIME_RANGE_SECONDS, end) : defaultHistoryWindow();
|
|
2932
3104
|
const current = () => mounted.current && requested.current[id] === asked;
|
|
2933
3105
|
void fetchWidgetHistory(widget, historyWindow, { rethrow: n > 0 }).then(
|
|
2934
3106
|
(samples) => {
|
|
2935
3107
|
if (!current()) return;
|
|
2936
|
-
setSeeds((prev) => ({ ...prev, [id]: { key, samples, asOf: end } }));
|
|
3108
|
+
setSeeds((prev) => ({ ...prev, [id]: { key, window: tag, samples, asOf: end } }));
|
|
2937
3109
|
},
|
|
2938
3110
|
() => {
|
|
2939
3111
|
setTimeout(() => current() && reseed(id), RESEED_RETRY_MS);
|
|
@@ -2947,45 +3119,80 @@ function useWidgetHistories(widgets, enabled, registry, range) {
|
|
|
2947
3119
|
if (!enabled) return out;
|
|
2948
3120
|
for (const w of widgets) {
|
|
2949
3121
|
const seed = seeds[w.id];
|
|
2950
|
-
out[w.id] = seed && seed.key === seedKey(w, registry) ? seed : void 0;
|
|
3122
|
+
out[w.id] = seed && seed.key === seedKey(w, registry) && seed.window === tag ? seed : void 0;
|
|
2951
3123
|
}
|
|
2952
3124
|
return out;
|
|
2953
|
-
}, [widgets, seeds, enabled, registry]);
|
|
3125
|
+
}, [widgets, seeds, enabled, registry, tag]);
|
|
2954
3126
|
return { histories, reseed };
|
|
2955
3127
|
}
|
|
2956
3128
|
|
|
2957
3129
|
// src/time-range-bar.tsx
|
|
2958
3130
|
import {
|
|
2959
|
-
DEFAULT_TIME_RANGE_SECONDS,
|
|
3131
|
+
DEFAULT_TIME_RANGE_SECONDS as DEFAULT_TIME_RANGE_SECONDS2,
|
|
2960
3132
|
TIME_RANGE_PRESETS,
|
|
3133
|
+
absoluteRange,
|
|
3134
|
+
absoluteToParams,
|
|
2961
3135
|
initialTimeRange as initialTimeRange2,
|
|
2962
3136
|
isValidSpanSeconds as isValidSpanSeconds2,
|
|
3137
|
+
leaveAbsolute,
|
|
2963
3138
|
pauseRange,
|
|
2964
3139
|
presetIdOf,
|
|
2965
3140
|
resumeRange,
|
|
2966
3141
|
spanLabel as spanLabel2,
|
|
2967
3142
|
withSpan
|
|
2968
3143
|
} from "@devicechain/dashboards";
|
|
2969
|
-
import { useCallback as
|
|
2970
|
-
import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
3144
|
+
import { useCallback as useCallback4, useEffect as useEffect5, useMemo as useMemo6, useRef as useRef3, useState as useState6 } from "react";
|
|
3145
|
+
import { Fragment as Fragment3, jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2971
3146
|
function useBoardTimeRange(defaultSeconds, link = {}) {
|
|
2972
|
-
const [state, setState] =
|
|
3147
|
+
const [state, setState] = useState6(() => initialTimeRange2(defaultSeconds, link));
|
|
2973
3148
|
const lastDefault = useRef3(defaultSeconds);
|
|
2974
|
-
|
|
3149
|
+
useEffect5(() => {
|
|
2975
3150
|
if (lastDefault.current === defaultSeconds) return;
|
|
2976
3151
|
lastDefault.current = defaultSeconds;
|
|
2977
|
-
setState((s) => withSpan(s, isValidSpanSeconds2(defaultSeconds) ? defaultSeconds :
|
|
3152
|
+
setState((s) => withSpan(s, isValidSpanSeconds2(defaultSeconds) ? defaultSeconds : DEFAULT_TIME_RANGE_SECONDS2));
|
|
2978
3153
|
}, [defaultSeconds]);
|
|
2979
3154
|
const controls = useMemo6(
|
|
2980
3155
|
() => ({
|
|
2981
|
-
|
|
3156
|
+
// A preset click while a fixed window is showing leaves it: back to live at that span.
|
|
3157
|
+
setSpan: (spanSeconds) => setState((s) => withSpan(leaveAbsolute(s), spanSeconds)),
|
|
2982
3158
|
pause: () => setState((s) => pauseRange(s, Date.now())),
|
|
2983
|
-
resume: () => setState((s) => resumeRange(s))
|
|
3159
|
+
resume: () => setState((s) => resumeRange(s)),
|
|
3160
|
+
setAbsolute: (fromMs, toMs) => {
|
|
3161
|
+
const made = absoluteRange(fromMs, toMs);
|
|
3162
|
+
if ("problem" in made) return made.problem;
|
|
3163
|
+
setState(made.state);
|
|
3164
|
+
return void 0;
|
|
3165
|
+
}
|
|
2984
3166
|
}),
|
|
2985
3167
|
[]
|
|
2986
3168
|
);
|
|
2987
3169
|
return [state, controls];
|
|
2988
3170
|
}
|
|
3171
|
+
var DEFAULT_ABSOLUTE_LABELS = {
|
|
3172
|
+
custom: "Custom range",
|
|
3173
|
+
from: "From",
|
|
3174
|
+
to: "To",
|
|
3175
|
+
apply: "Apply",
|
|
3176
|
+
cancel: "Cancel",
|
|
3177
|
+
zone: (zone, offset) => `Times are in ${zone} (${offset}). Shared links use UTC.`,
|
|
3178
|
+
problem: {
|
|
3179
|
+
unparseable: "Enter both a start and an end.",
|
|
3180
|
+
order: "The start must be before the end.",
|
|
3181
|
+
tooShort: "The window must be at least one minute.",
|
|
3182
|
+
tooLong: "The window can be at most 31 days.",
|
|
3183
|
+
future: "The end cannot be in the future.",
|
|
3184
|
+
tooEarly: "The start is too far in the past."
|
|
3185
|
+
},
|
|
3186
|
+
fixed: "Fixed window",
|
|
3187
|
+
backToLive: "Back to live",
|
|
3188
|
+
copyLink: "Copy link",
|
|
3189
|
+
linkCopied: "Link copied",
|
|
3190
|
+
loadFailed: "The range picker could not be loaded. Try again.",
|
|
3191
|
+
dismiss: "Dismiss",
|
|
3192
|
+
ignored: (reason, raw) => `The link's time window was ignored: ${reason} (${raw}). Showing the live board.`,
|
|
3193
|
+
incomplete: "both from and to are required",
|
|
3194
|
+
unzoned: "times must be ISO 8601 with a zone, such as 2026-10-22T02:00:00Z or +02:00"
|
|
3195
|
+
};
|
|
2989
3196
|
var DEFAULT_TIME_RANGE_LABELS = {
|
|
2990
3197
|
range: "Time range",
|
|
2991
3198
|
pause: "Pause",
|
|
@@ -2994,6 +3201,13 @@ var DEFAULT_TIME_RANGE_LABELS = {
|
|
|
2994
3201
|
pausedAt: (time) => `Paused at ${time}`,
|
|
2995
3202
|
actionsLive: "commands still send"
|
|
2996
3203
|
};
|
|
3204
|
+
var absoluteLabels = (labels) => ({ ...DEFAULT_ABSOLUTE_LABELS, ...labels.absolute });
|
|
3205
|
+
function rejectedLinkNote(rejected, labels = DEFAULT_TIME_RANGE_LABELS) {
|
|
3206
|
+
const l = absoluteLabels(labels);
|
|
3207
|
+
const raw = `from=${rejected.from || "-"} to=${rejected.to || "-"}`;
|
|
3208
|
+
const reason = rejected.reason === "incomplete" ? l.incomplete : rejected.reason === "unparseable" ? l.unzoned : l.problem[rejected.reason];
|
|
3209
|
+
return l.ignored(reason, raw);
|
|
3210
|
+
}
|
|
2997
3211
|
var button = (active) => ({
|
|
2998
3212
|
padding: "2px 8px",
|
|
2999
3213
|
fontSize: 12,
|
|
@@ -3038,40 +3252,169 @@ function PausedIndicator({
|
|
|
3038
3252
|
}
|
|
3039
3253
|
);
|
|
3040
3254
|
}
|
|
3041
|
-
function
|
|
3042
|
-
|
|
3043
|
-
|
|
3255
|
+
function formatAbsoluteRange(a) {
|
|
3256
|
+
const f = new Intl.DateTimeFormat(void 0, { year: "numeric", month: "short", day: "numeric", hour: "2-digit", minute: "2-digit", timeZoneName: "short" });
|
|
3257
|
+
return `${f.format(a.fromMs)} \u2013 ${f.format(a.toMs)}`;
|
|
3258
|
+
}
|
|
3259
|
+
function AbsoluteIndicator({
|
|
3260
|
+
absolute,
|
|
3044
3261
|
labels = DEFAULT_TIME_RANGE_LABELS
|
|
3045
3262
|
}) {
|
|
3046
|
-
const
|
|
3047
|
-
const
|
|
3263
|
+
const l = absoluteLabels(labels);
|
|
3264
|
+
const utc = absoluteToParams(absolute);
|
|
3048
3265
|
return /* @__PURE__ */ jsxs8(
|
|
3049
|
-
"
|
|
3266
|
+
"span",
|
|
3050
3267
|
{
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
style: {
|
|
3268
|
+
role: "status",
|
|
3269
|
+
"data-time-range-absolute": "",
|
|
3270
|
+
title: `${utc.from} \u2013 ${utc.to} (UTC)`,
|
|
3271
|
+
style: {
|
|
3272
|
+
display: "inline-flex",
|
|
3273
|
+
alignItems: "center",
|
|
3274
|
+
flexWrap: "wrap",
|
|
3275
|
+
gap: 4,
|
|
3276
|
+
padding: "2px 8px",
|
|
3277
|
+
fontSize: 12,
|
|
3278
|
+
fontWeight: 700,
|
|
3279
|
+
color: "hsl(var(--background))",
|
|
3280
|
+
background: "hsl(var(--foreground))",
|
|
3281
|
+
border: "2px solid hsl(var(--foreground))",
|
|
3282
|
+
borderRadius: 4
|
|
3283
|
+
},
|
|
3055
3284
|
children: [
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
{
|
|
3060
|
-
type: "button",
|
|
3061
|
-
"aria-pressed": p.id === preset,
|
|
3062
|
-
"data-range": p.id,
|
|
3063
|
-
onClick: () => controls.setSpan(p.seconds),
|
|
3064
|
-
style: button(p.id === preset),
|
|
3065
|
-
children: p.id
|
|
3066
|
-
},
|
|
3067
|
-
p.id
|
|
3068
|
-
)),
|
|
3069
|
-
/* @__PURE__ */ jsx12("button", { type: "button", "aria-pressed": state.paused, "data-time-range-pause": "", onClick: onPause, style: button(state.paused), children: state.paused ? labels.resume : labels.pause }),
|
|
3070
|
-
state.paused ? /* @__PURE__ */ jsx12(PausedIndicator, { pausedAt: state.pausedAt, labels }) : null
|
|
3285
|
+
/* @__PURE__ */ jsx12("span", { style: { letterSpacing: 0.4, textTransform: "uppercase" }, children: l.fixed }),
|
|
3286
|
+
/* @__PURE__ */ jsx12("span", { "data-time-range-window": "", style: { fontWeight: 400 }, children: formatAbsoluteRange(absolute) }),
|
|
3287
|
+
/* @__PURE__ */ jsx12("span", { "data-time-range-actions-live": "", style: { fontWeight: 400 }, children: `\xB7 ${labels.actionsLive}` })
|
|
3071
3288
|
]
|
|
3072
3289
|
}
|
|
3073
3290
|
);
|
|
3074
3291
|
}
|
|
3292
|
+
function absoluteLinkFor(href, a) {
|
|
3293
|
+
const url = new URL(href);
|
|
3294
|
+
const { from, to } = absoluteToParams(a);
|
|
3295
|
+
url.searchParams.delete("range");
|
|
3296
|
+
url.searchParams.delete("paused");
|
|
3297
|
+
url.searchParams.set("from", from);
|
|
3298
|
+
url.searchParams.set("to", to);
|
|
3299
|
+
return url.toString();
|
|
3300
|
+
}
|
|
3301
|
+
function TimeRangeBar({
|
|
3302
|
+
state,
|
|
3303
|
+
controls,
|
|
3304
|
+
labels = DEFAULT_TIME_RANGE_LABELS,
|
|
3305
|
+
notice
|
|
3306
|
+
}) {
|
|
3307
|
+
const abs = state.absolute;
|
|
3308
|
+
const preset = abs ? void 0 : presetIdOf(state.spanSeconds);
|
|
3309
|
+
const onPause = useCallback4(() => state.paused ? controls.resume() : controls.pause(), [state.paused, controls]);
|
|
3310
|
+
const l = absoluteLabels(labels);
|
|
3311
|
+
const [Picker, setPicker] = useState6();
|
|
3312
|
+
const [open, setOpen] = useState6(false);
|
|
3313
|
+
const [loadFailed, setLoadFailed] = useState6(false);
|
|
3314
|
+
const [copied, setCopied] = useState6(false);
|
|
3315
|
+
const [noticeShown, setNoticeShown] = useState6(true);
|
|
3316
|
+
useEffect5(() => setNoticeShown(true), [notice]);
|
|
3317
|
+
const openPicker = () => {
|
|
3318
|
+
if (open) {
|
|
3319
|
+
setOpen(false);
|
|
3320
|
+
return;
|
|
3321
|
+
}
|
|
3322
|
+
setLoadFailed(false);
|
|
3323
|
+
if (Picker) {
|
|
3324
|
+
setOpen(true);
|
|
3325
|
+
return;
|
|
3326
|
+
}
|
|
3327
|
+
import("./chunks/absolute-range-picker-E57G2TPX.js").then(
|
|
3328
|
+
(m) => {
|
|
3329
|
+
setPicker(() => m.default);
|
|
3330
|
+
setOpen(true);
|
|
3331
|
+
},
|
|
3332
|
+
() => setLoadFailed(true)
|
|
3333
|
+
);
|
|
3334
|
+
};
|
|
3335
|
+
const copyLink = () => {
|
|
3336
|
+
if (!abs) return;
|
|
3337
|
+
navigator.clipboard?.writeText(absoluteLinkFor(window.location.href, abs)).then(
|
|
3338
|
+
() => {
|
|
3339
|
+
setCopied(true);
|
|
3340
|
+
window.setTimeout(() => setCopied(false), 2e3);
|
|
3341
|
+
},
|
|
3342
|
+
() => void 0
|
|
3343
|
+
);
|
|
3344
|
+
};
|
|
3345
|
+
return /* @__PURE__ */ jsxs8("div", { style: { position: "relative", display: "inline-block", maxWidth: "100%" }, children: [
|
|
3346
|
+
/* @__PURE__ */ jsxs8(
|
|
3347
|
+
"div",
|
|
3348
|
+
{
|
|
3349
|
+
"data-time-range-bar": "",
|
|
3350
|
+
role: "group",
|
|
3351
|
+
"aria-label": labels.range,
|
|
3352
|
+
style: { display: "inline-flex", alignItems: "center", gap: 6, flexWrap: "wrap" },
|
|
3353
|
+
children: [
|
|
3354
|
+
!abs && preset === void 0 ? /* @__PURE__ */ jsx12("button", { type: "button", "aria-pressed": "true", "data-range": spanLabel2(state.spanSeconds), style: button(true), children: spanLabel2(state.spanSeconds) }) : null,
|
|
3355
|
+
TIME_RANGE_PRESETS.map((p) => /* @__PURE__ */ jsx12(
|
|
3356
|
+
"button",
|
|
3357
|
+
{
|
|
3358
|
+
type: "button",
|
|
3359
|
+
"aria-pressed": p.id === preset,
|
|
3360
|
+
"data-range": p.id,
|
|
3361
|
+
onClick: () => controls.setSpan(p.seconds),
|
|
3362
|
+
style: button(p.id === preset),
|
|
3363
|
+
children: p.id
|
|
3364
|
+
},
|
|
3365
|
+
p.id
|
|
3366
|
+
)),
|
|
3367
|
+
/* @__PURE__ */ jsx12(
|
|
3368
|
+
"button",
|
|
3369
|
+
{
|
|
3370
|
+
type: "button",
|
|
3371
|
+
"aria-pressed": abs !== void 0,
|
|
3372
|
+
"aria-expanded": open,
|
|
3373
|
+
"data-time-range-custom": "",
|
|
3374
|
+
onClick: openPicker,
|
|
3375
|
+
style: button(abs !== void 0),
|
|
3376
|
+
children: l.custom
|
|
3377
|
+
}
|
|
3378
|
+
),
|
|
3379
|
+
abs ? /* @__PURE__ */ jsxs8(Fragment3, { children: [
|
|
3380
|
+
/* @__PURE__ */ jsx12("button", { type: "button", "data-time-range-live": "", onClick: () => controls.resume(), style: button(false), children: l.backToLive }),
|
|
3381
|
+
/* @__PURE__ */ jsx12("button", { type: "button", "data-time-range-copy": "", onClick: copyLink, style: button(false), children: copied ? l.linkCopied : l.copyLink }),
|
|
3382
|
+
/* @__PURE__ */ jsx12(AbsoluteIndicator, { absolute: abs, labels })
|
|
3383
|
+
] }) : /* @__PURE__ */ jsxs8(Fragment3, { children: [
|
|
3384
|
+
/* @__PURE__ */ jsx12("button", { type: "button", "aria-pressed": state.paused, "data-time-range-pause": "", onClick: onPause, style: button(state.paused), children: state.paused ? labels.resume : labels.pause }),
|
|
3385
|
+
state.paused ? /* @__PURE__ */ jsx12(PausedIndicator, { pausedAt: state.pausedAt, labels }) : null
|
|
3386
|
+
] })
|
|
3387
|
+
]
|
|
3388
|
+
}
|
|
3389
|
+
),
|
|
3390
|
+
open && Picker ? /* @__PURE__ */ jsx12("div", { style: { position: "absolute", right: 0, top: "100%", marginTop: 6, zIndex: 30 }, children: /* @__PURE__ */ jsx12(
|
|
3391
|
+
Picker,
|
|
3392
|
+
{
|
|
3393
|
+
initial: abs,
|
|
3394
|
+
labels: l,
|
|
3395
|
+
onApply: (from, to) => {
|
|
3396
|
+
const problem = controls.setAbsolute(from, to);
|
|
3397
|
+
if (!problem) setOpen(false);
|
|
3398
|
+
return problem;
|
|
3399
|
+
},
|
|
3400
|
+
onCancel: () => setOpen(false)
|
|
3401
|
+
}
|
|
3402
|
+
) }) : null,
|
|
3403
|
+
loadFailed ? /* @__PURE__ */ jsx12("div", { role: "alert", "data-time-range-load-failed": "", style: { fontSize: 12, color: "hsl(var(--destructive))" }, children: l.loadFailed }) : null,
|
|
3404
|
+
notice && noticeShown ? /* @__PURE__ */ jsxs8(
|
|
3405
|
+
"div",
|
|
3406
|
+
{
|
|
3407
|
+
role: "status",
|
|
3408
|
+
"data-time-range-notice": "",
|
|
3409
|
+
style: { display: "flex", gap: 8, alignItems: "baseline", marginTop: 4, fontSize: 12, color: "hsl(var(--muted-foreground))" },
|
|
3410
|
+
children: [
|
|
3411
|
+
/* @__PURE__ */ jsx12("span", { style: { minWidth: 0, overflowWrap: "anywhere" }, children: notice }),
|
|
3412
|
+
/* @__PURE__ */ jsx12("button", { type: "button", onClick: () => setNoticeShown(false), style: { ...button(false), flex: "0 0 auto" }, children: l.dismiss })
|
|
3413
|
+
]
|
|
3414
|
+
}
|
|
3415
|
+
) : null
|
|
3416
|
+
] });
|
|
3417
|
+
}
|
|
3075
3418
|
|
|
3076
3419
|
// src/use-bound-devices.ts
|
|
3077
3420
|
import {
|
|
@@ -3082,7 +3425,7 @@ import {
|
|
|
3082
3425
|
validateBinds,
|
|
3083
3426
|
withBindParams
|
|
3084
3427
|
} from "@devicechain/dashboards";
|
|
3085
|
-
import { useCallback as
|
|
3428
|
+
import { useCallback as useCallback5, useEffect as useEffect6, useRef as useRef4, useState as useState7 } from "react";
|
|
3086
3429
|
var NO_PROBLEMS = { issues: [], missing: [], failed: [] };
|
|
3087
3430
|
function hasBindParams(search, definition) {
|
|
3088
3431
|
const { binds, issues } = parseBindParams(search, definition);
|
|
@@ -3094,16 +3437,16 @@ function useBoundDevices({
|
|
|
3094
3437
|
address,
|
|
3095
3438
|
enabled = true
|
|
3096
3439
|
}) {
|
|
3097
|
-
const [core, setCore] =
|
|
3440
|
+
const [core, setCore] = useState7(() => ({
|
|
3098
3441
|
selection: {},
|
|
3099
3442
|
synced: bindParamsOf(address.search)
|
|
3100
3443
|
}));
|
|
3101
3444
|
const { selection } = core;
|
|
3102
|
-
const [phase, setPhase] =
|
|
3445
|
+
const [phase, setPhase] = useState7(
|
|
3103
3446
|
() => hasBindParams(address.search, definition) ? "checking" : "ready"
|
|
3104
3447
|
);
|
|
3105
|
-
const [problems, setProblems] =
|
|
3106
|
-
const [okBinds, setOkBinds] =
|
|
3448
|
+
const [problems, setProblems] = useState7(null);
|
|
3449
|
+
const [okBinds, setOkBinds] = useState7({});
|
|
3107
3450
|
const definitionRef = useRef4(definition);
|
|
3108
3451
|
definitionRef.current = definition;
|
|
3109
3452
|
const resolverRef = useRef4(resolver);
|
|
@@ -3112,9 +3455,9 @@ function useBoundDevices({
|
|
|
3112
3455
|
replaceRef.current = address.replaceSearch;
|
|
3113
3456
|
const seenRef = useRef4(null);
|
|
3114
3457
|
const generation = useRef4(0);
|
|
3115
|
-
const [attempt, setAttempt] =
|
|
3458
|
+
const [attempt, setAttempt] = useState7(0);
|
|
3116
3459
|
const search = address.search;
|
|
3117
|
-
|
|
3460
|
+
useEffect6(() => {
|
|
3118
3461
|
if (!enabled) return;
|
|
3119
3462
|
const slice = bindParamsOf(search);
|
|
3120
3463
|
if (seenRef.current === slice) return;
|
|
@@ -3143,7 +3486,7 @@ function useBoundDevices({
|
|
|
3143
3486
|
}
|
|
3144
3487
|
});
|
|
3145
3488
|
}, [search, enabled, attempt]);
|
|
3146
|
-
|
|
3489
|
+
useEffect6(() => {
|
|
3147
3490
|
if (!enabled || phase !== "ready") return;
|
|
3148
3491
|
const current = bindParamsOf(search);
|
|
3149
3492
|
if (current !== core.synced) return;
|
|
@@ -3154,16 +3497,16 @@ function useBoundDevices({
|
|
|
3154
3497
|
setCore((c) => ({ ...c, synced: nextSlice }));
|
|
3155
3498
|
replaceRef.current(next);
|
|
3156
3499
|
}, [core, definition, phase, enabled, search]);
|
|
3157
|
-
const select =
|
|
3500
|
+
const select = useCallback5((t) => {
|
|
3158
3501
|
setCore((c) => ({ ...c, selection: { ...c.selection, [t.slot]: t.binding } }));
|
|
3159
3502
|
}, []);
|
|
3160
|
-
const reset =
|
|
3161
|
-
const dismiss =
|
|
3503
|
+
const reset = useCallback5(() => setCore((c) => ({ ...c, selection: {} })), []);
|
|
3504
|
+
const dismiss = useCallback5(() => {
|
|
3162
3505
|
setCore((c) => ({ ...c, selection: bindsToSelection(okBinds) }));
|
|
3163
3506
|
setProblems(null);
|
|
3164
3507
|
setPhase("ready");
|
|
3165
3508
|
}, [okBinds]);
|
|
3166
|
-
const retry =
|
|
3509
|
+
const retry = useCallback5(() => {
|
|
3167
3510
|
seenRef.current = null;
|
|
3168
3511
|
setAttempt((n) => n + 1);
|
|
3169
3512
|
}, []);
|
|
@@ -3171,17 +3514,17 @@ function useBoundDevices({
|
|
|
3171
3514
|
}
|
|
3172
3515
|
|
|
3173
3516
|
// src/bound-devices-notice.tsx
|
|
3174
|
-
import { css as
|
|
3517
|
+
import { css as css7, fontVar as fontVar7 } from "@devicechain/widget-sdk";
|
|
3175
3518
|
import { jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
3176
3519
|
function BoundDevicesNotice({ title, lines, dismissLabel, onDismiss, retryLabel, onRetry }) {
|
|
3177
3520
|
const button2 = {
|
|
3178
3521
|
minHeight: 44,
|
|
3179
3522
|
padding: "0 16px",
|
|
3180
3523
|
borderRadius: 8,
|
|
3181
|
-
border: `1px solid ${
|
|
3182
|
-
background:
|
|
3183
|
-
color:
|
|
3184
|
-
fontSize:
|
|
3524
|
+
border: `1px solid ${css7("border")}`,
|
|
3525
|
+
background: css7("card"),
|
|
3526
|
+
color: css7("foreground"),
|
|
3527
|
+
fontSize: fontVar7("md"),
|
|
3185
3528
|
cursor: "pointer"
|
|
3186
3529
|
};
|
|
3187
3530
|
return /* @__PURE__ */ jsxs9(
|
|
@@ -3199,13 +3542,13 @@ function BoundDevicesNotice({ title, lines, dismissLabel, onDismiss, retryLabel,
|
|
|
3199
3542
|
margin: "24px auto",
|
|
3200
3543
|
padding: 16,
|
|
3201
3544
|
borderRadius: 8,
|
|
3202
|
-
border: `1px solid ${
|
|
3203
|
-
background:
|
|
3204
|
-
color:
|
|
3545
|
+
border: `1px solid ${css7("border")}`,
|
|
3546
|
+
background: css7("card"),
|
|
3547
|
+
color: css7("foreground")
|
|
3205
3548
|
},
|
|
3206
3549
|
children: [
|
|
3207
|
-
/* @__PURE__ */ jsx13("div", { style: { fontSize:
|
|
3208
|
-
/* @__PURE__ */ jsx13("ul", { style: { margin: 0, paddingLeft: 20, display: "flex", flexDirection: "column", gap: 4, fontSize:
|
|
3550
|
+
/* @__PURE__ */ jsx13("div", { style: { fontSize: fontVar7("lg"), fontWeight: 600 }, children: title }),
|
|
3551
|
+
/* @__PURE__ */ jsx13("ul", { style: { margin: 0, paddingLeft: 20, display: "flex", flexDirection: "column", gap: 4, fontSize: fontVar7("md") }, children: lines.map((line, i) => /* @__PURE__ */ jsx13("li", { style: { overflowWrap: "anywhere" }, children: line }, i)) }),
|
|
3209
3552
|
/* @__PURE__ */ jsxs9("div", { style: { display: "flex", flexWrap: "wrap", gap: 8 }, children: [
|
|
3210
3553
|
retryLabel && onRetry ? /* @__PURE__ */ jsx13("button", { type: "button", style: button2, onClick: onRetry, "data-testid": "bound-devices-retry", children: retryLabel }) : null,
|
|
3211
3554
|
/* @__PURE__ */ jsx13("button", { type: "button", style: button2, onClick: onDismiss, "data-testid": "bound-devices-dismiss", children: dismissLabel })
|
|
@@ -3297,6 +3640,7 @@ var OPTION_DOCS = {
|
|
|
3297
3640
|
ageLagSeconds: "Show a reading's age under it only when the reading is at least this many seconds older than the newest reading in the table (or stale). Unset shows every reading's age.",
|
|
3298
3641
|
sortBy: "The measurement the table is ordered by. Blank orders by device name.",
|
|
3299
3642
|
sortDescending: "Largest first.",
|
|
3643
|
+
oldestFirst: "List the oldest bucket first. Unset lists the newest first.",
|
|
3300
3644
|
pageSize: "Devices per page. Default 20.",
|
|
3301
3645
|
maxSeries: "Most lines drawn when the chart shows one line per device. Default 5, at most 12. Each line costs one stored-history read, and the chart colours repeat after five; a group larger than this shows the first devices of the group and says how many it left out.",
|
|
3302
3646
|
show: "What to count: devices in an abnormal band of the measurement (default), or all devices."
|
|
@@ -3346,6 +3690,12 @@ var OPTION_DOC_OVERRIDES = {
|
|
|
3346
3690
|
"online-doughnut": {
|
|
3347
3691
|
staleAfterSeconds: "Marks the ring stale once the status of its devices has not been read for longer than this many seconds (it is re-read every 15 seconds, so only reads that keep failing make it stale). Unset, the age is shown and nothing is marked stale."
|
|
3348
3692
|
},
|
|
3693
|
+
"history-table": {
|
|
3694
|
+
columns: "Which measurements are columns, in order, with a heading, unit and precision each. With none, the columns are the datasource\u2019s measurements (or, when it names none, every measurement the device reported in the range). Every figure is the average of the readings in a time bucket.",
|
|
3695
|
+
precision: "Decimal places to round displayed averages to, for a column that sets none. Unset rounds to at most 3 decimals (4 significant digits under 1). The CSV export is rounded the same way.",
|
|
3696
|
+
pageSize: "Rows per page. Default 10. The CSV export holds every row, not just the page.",
|
|
3697
|
+
staleAfterSeconds: "Marks the table stale once its history has not been read for longer than this many seconds (it is re-read at the end of each time bucket, so only reads that keep failing make it stale). Unset, the age is shown and nothing is marked stale."
|
|
3698
|
+
},
|
|
3349
3699
|
"fleet-count": {
|
|
3350
3700
|
measurement: "The measurement whose bands flag a device. Defaults to the first the datasource selects."
|
|
3351
3701
|
},
|
|
@@ -3429,7 +3779,7 @@ var WIDGET_BINDS_DATASOURCE = Object.freeze(
|
|
|
3429
3779
|
);
|
|
3430
3780
|
|
|
3431
3781
|
// src/index.ts
|
|
3432
|
-
import { pickSample as
|
|
3782
|
+
import { pickSample as pickSample4, optBoolean as optBoolean3 } from "@devicechain/widget-sdk";
|
|
3433
3783
|
|
|
3434
3784
|
// src/options.ts
|
|
3435
3785
|
import {
|
|
@@ -3529,7 +3879,7 @@ import {
|
|
|
3529
3879
|
useResolvedBindings,
|
|
3530
3880
|
useSlotCandidates,
|
|
3531
3881
|
useCandidates,
|
|
3532
|
-
css as
|
|
3882
|
+
css as css8
|
|
3533
3883
|
} from "@devicechain/widget-sdk";
|
|
3534
3884
|
import {
|
|
3535
3885
|
EChart as EChart3,
|
|
@@ -3539,6 +3889,7 @@ import {
|
|
|
3539
3889
|
useChartTheme as useChartTheme3
|
|
3540
3890
|
} from "@devicechain/widget-sdk/echarts";
|
|
3541
3891
|
export {
|
|
3892
|
+
AbsoluteIndicator,
|
|
3542
3893
|
AlarmCount,
|
|
3543
3894
|
AlarmSeverity,
|
|
3544
3895
|
AlarmTable,
|
|
@@ -3546,6 +3897,7 @@ export {
|
|
|
3546
3897
|
BoundDevicesNotice,
|
|
3547
3898
|
CommandButton,
|
|
3548
3899
|
ConnectedWidget,
|
|
3900
|
+
DEFAULT_ABSOLUTE_LABELS,
|
|
3549
3901
|
DEFAULT_TIME_RANGE_LABELS,
|
|
3550
3902
|
DashboardRenderer,
|
|
3551
3903
|
EChart3 as EChart,
|
|
@@ -3572,6 +3924,7 @@ export {
|
|
|
3572
3924
|
WidgetSubjectProvider2 as WidgetSubjectProvider,
|
|
3573
3925
|
WidgetThemeRootProvider2 as WidgetThemeRootProvider,
|
|
3574
3926
|
WidgetTimeZoneProvider2 as WidgetTimeZoneProvider,
|
|
3927
|
+
absoluteLinkFor,
|
|
3575
3928
|
buildGaugeOption2 as buildGaugeOption,
|
|
3576
3929
|
buildLineOption2 as buildLineOption,
|
|
3577
3930
|
buildPayload,
|
|
@@ -3583,7 +3936,7 @@ export {
|
|
|
3583
3936
|
commandStatusColor,
|
|
3584
3937
|
commandStatusLabel,
|
|
3585
3938
|
createBuiltinWidgetRegistry2 as createBuiltinWidgetRegistry,
|
|
3586
|
-
|
|
3939
|
+
css8 as css,
|
|
3587
3940
|
defaultValues,
|
|
3588
3941
|
describeBoundDevicesProblems,
|
|
3589
3942
|
describePosition,
|
|
@@ -3591,6 +3944,7 @@ export {
|
|
|
3591
3944
|
fitValueFont2 as fitValueFont,
|
|
3592
3945
|
flashBackgroundStyle2 as flashBackgroundStyle,
|
|
3593
3946
|
flashTextStyle2 as flashTextStyle,
|
|
3947
|
+
formatAbsoluteRange,
|
|
3594
3948
|
formatDegrees,
|
|
3595
3949
|
highestSeverity,
|
|
3596
3950
|
isScalar,
|
|
@@ -3600,11 +3954,12 @@ export {
|
|
|
3600
3954
|
numberOptionSpec,
|
|
3601
3955
|
optBoolean3 as optBoolean,
|
|
3602
3956
|
parseParameterSchema,
|
|
3603
|
-
|
|
3957
|
+
pickSample4 as pickSample,
|
|
3604
3958
|
placeable,
|
|
3605
3959
|
preloadWidgets,
|
|
3606
3960
|
projectToPanel,
|
|
3607
3961
|
rasterStyleFor,
|
|
3962
|
+
rejectedLinkNote,
|
|
3608
3963
|
resolveChartTheme,
|
|
3609
3964
|
resolveWidgets,
|
|
3610
3965
|
severityColor,
|