@devicechain/widgets 0.24.0-rc.1 → 0.25.0-rc.2
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/README.md
CHANGED
|
@@ -65,7 +65,7 @@ bound to a slot needs its datasource resolved first (`resolveWidgets` or
|
|
|
65
65
|
|
|
66
66
|
| channel | widgets |
|
|
67
67
|
| --- | --- |
|
|
68
|
-
| measurement | `timeseries-chart`, `latest-card`, `gauge`, `linear-gauge`, `level-gauge`, `battery`, `status-light`, `signal-bars`, `compass`, `progress-ring`, `table`, `bar-chart`, `pie-chart`, `fleet-table`, `fleet-count`, `device-status`, `online-doughnut` |
|
|
68
|
+
| measurement | `timeseries-chart`, `latest-card`, `gauge`, `linear-gauge`, `level-gauge`, `battery`, `status-light`, `signal-bars`, `compass`, `progress-ring`, `table`, `bar-chart`, `pie-chart`, `fleet-table`, `fleet-count`, `device-status`, `online-doughnut`, `history-table` |
|
|
69
69
|
| aggregate | `stat-card` |
|
|
70
70
|
| none (static) | `label`, `image` |
|
|
71
71
|
| alarm | `alarm-table`, `alarm-count`, `alarm-severity` |
|
|
@@ -83,6 +83,16 @@ each was last active) from device-state, not their readings. They ride the measu
|
|
|
83
83
|
member feed (`data.members[].presence`), so the channel set is unchanged. `device-status` shows one
|
|
84
84
|
device; `online-doughnut` takes a group.
|
|
85
85
|
|
|
86
|
+
`history-table` lists one device's stored history as rows, one per time bucket over the board's
|
|
87
|
+
span, each cell the bucket's average (the table says "avg per 5m"). It reads the store's buckets
|
|
88
|
+
(`binding.history`), not the live feed, and refuses a group.
|
|
89
|
+
|
|
90
|
+
A frame offers a data download from its title bar when its widget opts in: `timeseries-chart`,
|
|
91
|
+
`fleet-table` and `history-table` hand it a table (CSV), and the charts drawn on a canvas
|
|
92
|
+
(`timeseries-chart`, `gauge`, `compass`) a PNG. The file holds what the widget shows, for the
|
|
93
|
+
span and bucket on screen, and its name says so. A widget of your own opts in with the
|
|
94
|
+
optional `exportRows` prop of `WidgetFrame` (see the widget SDK).
|
|
95
|
+
|
|
86
96
|
The time-series chart, the dial gauge and the compass are drawn with
|
|
87
97
|
[Apache ECharts](https://echarts.apache.org); the other widgets are plain DOM
|
|
88
98
|
and SVG. The map is [MapLibre GL](https://maplibre.org), loaded lazily so a board
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { AbsoluteRange, AbsoluteRangeProblem } from '@devicechain/dashboards';
|
|
2
|
+
export interface AbsolutePickerLabels {
|
|
3
|
+
custom: string;
|
|
4
|
+
from: string;
|
|
5
|
+
to: string;
|
|
6
|
+
apply: string;
|
|
7
|
+
cancel: string;
|
|
8
|
+
zone: (zone: string, offset: string) => string;
|
|
9
|
+
problem: Record<AbsoluteRangeProblem, string>;
|
|
10
|
+
}
|
|
11
|
+
export declare function toLocalInput(ms: number): string;
|
|
12
|
+
export declare function fromLocalInput(value: string): number;
|
|
13
|
+
export declare function zoneInfo(at?: number): {
|
|
14
|
+
zone: string;
|
|
15
|
+
offset: string;
|
|
16
|
+
};
|
|
17
|
+
export default function AbsoluteRangePicker({ initial, labels, onApply, onCancel, }: {
|
|
18
|
+
initial?: AbsoluteRange;
|
|
19
|
+
labels: AbsolutePickerLabels;
|
|
20
|
+
onApply: (fromMs: number, toMs: number) => AbsoluteRangeProblem | undefined;
|
|
21
|
+
onCancel: () => void;
|
|
22
|
+
}): import("react").JSX.Element;
|
package/dist/binding-policy.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export declare function measurementSpan(descriptor: WidgetDescriptor, widget: Wi
|
|
|
4
4
|
export declare function membersMode(descriptor: WidgetDescriptor, widget: WidgetInstance): boolean;
|
|
5
5
|
export declare function measurementIsMembersOnly(descriptor: WidgetDescriptor): boolean;
|
|
6
6
|
export declare function presenceMode(descriptor: WidgetDescriptor): boolean;
|
|
7
|
+
export declare function historyMode(descriptor: WidgetDescriptor): boolean;
|
|
7
8
|
export declare function alarmSubscription(descriptor: WidgetDescriptor, widget: WidgetInstance): AlarmSubscription;
|
|
8
9
|
export declare function groupsAlarmsByDeviceType(descriptor: WidgetDescriptor, widget: WidgetInstance): boolean;
|
|
9
10
|
export declare function commandSubscription(descriptor: WidgetDescriptor, widget: WidgetInstance): CommandSubscription;
|
|
@@ -1628,6 +1628,75 @@ export declare const builtinWidgetDescriptors: {
|
|
|
1628
1628
|
readonly helpId: 'widgetHintStaleAfter';
|
|
1629
1629
|
};
|
|
1630
1630
|
}>>;
|
|
1631
|
+
readonly 'history-table': WidgetDescriptor<"measurement", DocumentedSpecs<{
|
|
1632
|
+
readonly title: {
|
|
1633
|
+
readonly kind: 'string';
|
|
1634
|
+
readonly labelId: 'widgetLabelTitle';
|
|
1635
|
+
};
|
|
1636
|
+
readonly columns: {
|
|
1637
|
+
readonly kind: 'list';
|
|
1638
|
+
readonly maxItems: 24;
|
|
1639
|
+
readonly labelId: 'widgetLabelColumns';
|
|
1640
|
+
readonly helpId: 'widgetHintColumns';
|
|
1641
|
+
readonly item: {
|
|
1642
|
+
readonly measurement: {
|
|
1643
|
+
readonly kind: 'string';
|
|
1644
|
+
readonly required: true;
|
|
1645
|
+
readonly labelId: 'widgetLabelMeasurement';
|
|
1646
|
+
};
|
|
1647
|
+
readonly label: {
|
|
1648
|
+
readonly kind: 'string';
|
|
1649
|
+
readonly labelId: 'widgetLabelColumnHeading';
|
|
1650
|
+
};
|
|
1651
|
+
readonly unit: {
|
|
1652
|
+
readonly kind: 'string';
|
|
1653
|
+
readonly labelId: 'widgetLabelUnit';
|
|
1654
|
+
};
|
|
1655
|
+
readonly precision: {
|
|
1656
|
+
readonly kind: 'number';
|
|
1657
|
+
readonly integer: true;
|
|
1658
|
+
readonly min: 0;
|
|
1659
|
+
readonly max: 100;
|
|
1660
|
+
readonly labelId: 'widgetLabelPrecision';
|
|
1661
|
+
readonly helpId: 'widgetHintPrecision';
|
|
1662
|
+
};
|
|
1663
|
+
};
|
|
1664
|
+
};
|
|
1665
|
+
readonly precision: {
|
|
1666
|
+
readonly kind: 'number';
|
|
1667
|
+
readonly integer: true;
|
|
1668
|
+
readonly min: 0;
|
|
1669
|
+
readonly max: 100;
|
|
1670
|
+
readonly labelId: 'widgetLabelPrecision';
|
|
1671
|
+
readonly helpId: 'widgetHintPrecision';
|
|
1672
|
+
};
|
|
1673
|
+
readonly oldestFirst: {
|
|
1674
|
+
readonly kind: "boolean";
|
|
1675
|
+
readonly labelId: "widgetLabelOldestFirst";
|
|
1676
|
+
};
|
|
1677
|
+
readonly pageSize: {
|
|
1678
|
+
readonly kind: "number";
|
|
1679
|
+
readonly integer: true;
|
|
1680
|
+
readonly min: 5;
|
|
1681
|
+
readonly max: 100;
|
|
1682
|
+
readonly labelId: "widgetLabelRowsPerPage";
|
|
1683
|
+
};
|
|
1684
|
+
readonly staleAfterSeconds: {
|
|
1685
|
+
readonly kind: 'number';
|
|
1686
|
+
readonly integer: true;
|
|
1687
|
+
readonly min: 1;
|
|
1688
|
+
readonly labelId: 'widgetLabelStaleAfter';
|
|
1689
|
+
readonly helpId: 'widgetHintStaleAfter';
|
|
1690
|
+
};
|
|
1691
|
+
readonly windowSeconds: {
|
|
1692
|
+
readonly kind: 'number';
|
|
1693
|
+
readonly integer: true;
|
|
1694
|
+
readonly min: 60;
|
|
1695
|
+
readonly max: 604800;
|
|
1696
|
+
readonly labelId: 'widgetLabelWindowSeconds';
|
|
1697
|
+
readonly helpId: 'widgetHintWindowSeconds';
|
|
1698
|
+
};
|
|
1699
|
+
}>>;
|
|
1631
1700
|
};
|
|
1632
1701
|
export declare const builtinWidgetCatalog: import("@devicechain/dashboards").WidgetCatalog;
|
|
1633
1702
|
export {};
|
|
@@ -1586,5 +1586,73 @@ export declare const builtinWidgetDefinitions: readonly [import("@devicechain/wi
|
|
|
1586
1586
|
readonly labelId: 'widgetLabelStaleAfter';
|
|
1587
1587
|
readonly helpId: 'widgetHintStaleAfter';
|
|
1588
1588
|
};
|
|
1589
|
+
}>>, import("@devicechain/widget-sdk").WidgetDefinition<"measurement", import("./builtin-descriptors").DocumentedSpecs<{
|
|
1590
|
+
readonly title: {
|
|
1591
|
+
readonly kind: 'string';
|
|
1592
|
+
readonly labelId: 'widgetLabelTitle';
|
|
1593
|
+
};
|
|
1594
|
+
readonly columns: {
|
|
1595
|
+
readonly kind: 'list';
|
|
1596
|
+
readonly maxItems: 24;
|
|
1597
|
+
readonly labelId: 'widgetLabelColumns';
|
|
1598
|
+
readonly helpId: 'widgetHintColumns';
|
|
1599
|
+
readonly item: {
|
|
1600
|
+
readonly measurement: {
|
|
1601
|
+
readonly kind: 'string';
|
|
1602
|
+
readonly required: true;
|
|
1603
|
+
readonly labelId: 'widgetLabelMeasurement';
|
|
1604
|
+
};
|
|
1605
|
+
readonly label: {
|
|
1606
|
+
readonly kind: 'string';
|
|
1607
|
+
readonly labelId: 'widgetLabelColumnHeading';
|
|
1608
|
+
};
|
|
1609
|
+
readonly unit: {
|
|
1610
|
+
readonly kind: 'string';
|
|
1611
|
+
readonly labelId: 'widgetLabelUnit';
|
|
1612
|
+
};
|
|
1613
|
+
readonly precision: {
|
|
1614
|
+
readonly kind: 'number';
|
|
1615
|
+
readonly integer: true;
|
|
1616
|
+
readonly min: 0;
|
|
1617
|
+
readonly max: 100;
|
|
1618
|
+
readonly labelId: 'widgetLabelPrecision';
|
|
1619
|
+
readonly helpId: 'widgetHintPrecision';
|
|
1620
|
+
};
|
|
1621
|
+
};
|
|
1622
|
+
};
|
|
1623
|
+
readonly precision: {
|
|
1624
|
+
readonly kind: 'number';
|
|
1625
|
+
readonly integer: true;
|
|
1626
|
+
readonly min: 0;
|
|
1627
|
+
readonly max: 100;
|
|
1628
|
+
readonly labelId: 'widgetLabelPrecision';
|
|
1629
|
+
readonly helpId: 'widgetHintPrecision';
|
|
1630
|
+
};
|
|
1631
|
+
readonly oldestFirst: {
|
|
1632
|
+
readonly kind: "boolean";
|
|
1633
|
+
readonly labelId: "widgetLabelOldestFirst";
|
|
1634
|
+
};
|
|
1635
|
+
readonly pageSize: {
|
|
1636
|
+
readonly kind: "number";
|
|
1637
|
+
readonly integer: true;
|
|
1638
|
+
readonly min: 5;
|
|
1639
|
+
readonly max: 100;
|
|
1640
|
+
readonly labelId: "widgetLabelRowsPerPage";
|
|
1641
|
+
};
|
|
1642
|
+
readonly staleAfterSeconds: {
|
|
1643
|
+
readonly kind: 'number';
|
|
1644
|
+
readonly integer: true;
|
|
1645
|
+
readonly min: 1;
|
|
1646
|
+
readonly labelId: 'widgetLabelStaleAfter';
|
|
1647
|
+
readonly helpId: 'widgetHintStaleAfter';
|
|
1648
|
+
};
|
|
1649
|
+
readonly windowSeconds: {
|
|
1650
|
+
readonly kind: 'number';
|
|
1651
|
+
readonly integer: true;
|
|
1652
|
+
readonly min: 60;
|
|
1653
|
+
readonly max: 604800;
|
|
1654
|
+
readonly labelId: 'widgetLabelWindowSeconds';
|
|
1655
|
+
readonly helpId: 'widgetHintWindowSeconds';
|
|
1656
|
+
};
|
|
1589
1657
|
}>>];
|
|
1590
1658
|
export declare function createBuiltinWidgetRegistry(): WidgetRegistry;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
// src/absolute-range-picker.tsx
|
|
2
|
+
import { useId, useState } from "react";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
var pad = (n) => String(n).padStart(2, "0");
|
|
5
|
+
function toLocalInput(ms) {
|
|
6
|
+
const d = new Date(ms);
|
|
7
|
+
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;
|
|
8
|
+
}
|
|
9
|
+
function fromLocalInput(value) {
|
|
10
|
+
return value ? new Date(value).getTime() : Number.NaN;
|
|
11
|
+
}
|
|
12
|
+
function zoneInfo(at = Date.now()) {
|
|
13
|
+
const zone = Intl.DateTimeFormat().resolvedOptions().timeZone || "local";
|
|
14
|
+
const minutes = -new Date(at).getTimezoneOffset();
|
|
15
|
+
const sign = minutes < 0 ? "-" : "+";
|
|
16
|
+
const abs = Math.abs(minutes);
|
|
17
|
+
return { zone, offset: `UTC${sign}${pad(Math.floor(abs / 60))}:${pad(abs % 60)}` };
|
|
18
|
+
}
|
|
19
|
+
var field = {
|
|
20
|
+
display: "flex",
|
|
21
|
+
flexDirection: "column",
|
|
22
|
+
gap: 2,
|
|
23
|
+
fontSize: 12,
|
|
24
|
+
flex: "1 1 13rem",
|
|
25
|
+
minWidth: 0
|
|
26
|
+
};
|
|
27
|
+
var input = {
|
|
28
|
+
font: "inherit",
|
|
29
|
+
fontSize: 13,
|
|
30
|
+
padding: "3px 6px",
|
|
31
|
+
color: "hsl(var(--foreground))",
|
|
32
|
+
background: "hsl(var(--background))",
|
|
33
|
+
border: "1px solid hsl(var(--border))",
|
|
34
|
+
borderRadius: 4,
|
|
35
|
+
minWidth: 0
|
|
36
|
+
};
|
|
37
|
+
var action = (primary) => ({
|
|
38
|
+
padding: "3px 10px",
|
|
39
|
+
fontSize: 12,
|
|
40
|
+
cursor: "pointer",
|
|
41
|
+
color: primary ? "hsl(var(--background))" : "hsl(var(--foreground))",
|
|
42
|
+
background: primary ? "hsl(var(--foreground))" : "transparent",
|
|
43
|
+
border: "1px solid hsl(var(--border))",
|
|
44
|
+
borderRadius: 4
|
|
45
|
+
});
|
|
46
|
+
function AbsoluteRangePicker({
|
|
47
|
+
initial,
|
|
48
|
+
labels,
|
|
49
|
+
onApply,
|
|
50
|
+
onCancel
|
|
51
|
+
}) {
|
|
52
|
+
const id = useId();
|
|
53
|
+
const now = Date.now();
|
|
54
|
+
const [from, setFrom] = useState(() => toLocalInput(initial?.fromMs ?? now - 60 * 60 * 1e3));
|
|
55
|
+
const [to, setTo] = useState(() => toLocalInput(initial?.toMs ?? now));
|
|
56
|
+
const [problem, setProblem] = useState();
|
|
57
|
+
const { zone, offset } = zoneInfo();
|
|
58
|
+
const max = toLocalInput(now);
|
|
59
|
+
const submit = () => {
|
|
60
|
+
const p = onApply(fromLocalInput(from), fromLocalInput(to));
|
|
61
|
+
setProblem(p);
|
|
62
|
+
};
|
|
63
|
+
return /* @__PURE__ */ jsxs(
|
|
64
|
+
"form",
|
|
65
|
+
{
|
|
66
|
+
"data-absolute-picker": "",
|
|
67
|
+
"aria-label": labels.custom,
|
|
68
|
+
onSubmit: (e) => {
|
|
69
|
+
e.preventDefault();
|
|
70
|
+
submit();
|
|
71
|
+
},
|
|
72
|
+
onKeyDown: (e) => {
|
|
73
|
+
if (e.key === "Escape") onCancel();
|
|
74
|
+
},
|
|
75
|
+
style: {
|
|
76
|
+
display: "flex",
|
|
77
|
+
flexDirection: "column",
|
|
78
|
+
gap: 8,
|
|
79
|
+
padding: 10,
|
|
80
|
+
boxSizing: "border-box",
|
|
81
|
+
width: "min(24rem, calc(100vw - 32px))",
|
|
82
|
+
color: "hsl(var(--foreground))",
|
|
83
|
+
background: "hsl(var(--background))",
|
|
84
|
+
border: "1px solid hsl(var(--border))",
|
|
85
|
+
borderRadius: 6,
|
|
86
|
+
boxShadow: "0 4px 16px rgba(0,0,0,0.18)"
|
|
87
|
+
},
|
|
88
|
+
children: [
|
|
89
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 8, flexWrap: "wrap" }, children: [
|
|
90
|
+
/* @__PURE__ */ jsxs("label", { htmlFor: `${id}-from`, style: field, children: [
|
|
91
|
+
labels.from,
|
|
92
|
+
/* @__PURE__ */ jsx(
|
|
93
|
+
"input",
|
|
94
|
+
{
|
|
95
|
+
id: `${id}-from`,
|
|
96
|
+
"data-absolute-from": "",
|
|
97
|
+
type: "datetime-local",
|
|
98
|
+
value: from,
|
|
99
|
+
max,
|
|
100
|
+
required: true,
|
|
101
|
+
onChange: (e) => setFrom(e.target.value),
|
|
102
|
+
style: input
|
|
103
|
+
}
|
|
104
|
+
)
|
|
105
|
+
] }),
|
|
106
|
+
/* @__PURE__ */ jsxs("label", { htmlFor: `${id}-to`, style: field, children: [
|
|
107
|
+
labels.to,
|
|
108
|
+
/* @__PURE__ */ jsx(
|
|
109
|
+
"input",
|
|
110
|
+
{
|
|
111
|
+
id: `${id}-to`,
|
|
112
|
+
"data-absolute-to": "",
|
|
113
|
+
type: "datetime-local",
|
|
114
|
+
value: to,
|
|
115
|
+
max,
|
|
116
|
+
required: true,
|
|
117
|
+
onChange: (e) => setTo(e.target.value),
|
|
118
|
+
style: input
|
|
119
|
+
}
|
|
120
|
+
)
|
|
121
|
+
] })
|
|
122
|
+
] }),
|
|
123
|
+
/* @__PURE__ */ jsx("div", { "data-absolute-zone": "", style: { fontSize: 12, color: "hsl(var(--muted-foreground))" }, children: labels.zone(zone, offset) }),
|
|
124
|
+
problem ? /* @__PURE__ */ jsx("div", { role: "alert", "data-absolute-problem": problem, style: { fontSize: 12, color: "hsl(var(--destructive))" }, children: labels.problem[problem] }) : null,
|
|
125
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 6, justifyContent: "flex-end" }, children: [
|
|
126
|
+
/* @__PURE__ */ jsx("button", { type: "button", onClick: onCancel, style: action(false), children: labels.cancel }),
|
|
127
|
+
/* @__PURE__ */ jsx("button", { type: "submit", "data-absolute-apply": "", style: action(true), children: labels.apply })
|
|
128
|
+
] })
|
|
129
|
+
]
|
|
130
|
+
}
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
export {
|
|
134
|
+
AbsoluteRangePicker as default,
|
|
135
|
+
fromLocalInput,
|
|
136
|
+
toLocalInput,
|
|
137
|
+
zoneInfo
|
|
138
|
+
};
|
|
139
|
+
//# sourceMappingURL=absolute-range-picker-E57G2TPX.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/absolute-range-picker.tsx"],
|
|
4
|
+
"sourcesContent": ["// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The from-to picker for an absolute time range. Its own chunk: the time-range bar imports it on the\n// first click of \"Custom\", so a board that never opens it never downloads it (and the bar itself,\n// which every board with a header carries, stays small).\n//\n// The two fields are the browser's own `datetime-local` inputs, which read and write the VIEWER'S\n// zone. That zone is printed beside them, always, because \"02:00\" means nothing without one; the\n// window is stored as instants, and the link it offers is in UTC.\n\nimport type { AbsoluteRange, AbsoluteRangeProblem } from '@devicechain/dashboards';\nimport { useId, useState, type CSSProperties } from 'react';\n\nexport interface AbsolutePickerLabels {\n custom: string;\n from: string;\n to: string;\n apply: string;\n cancel: string;\n // \"Times are in Europe/Berlin (UTC+02:00). Shared links use UTC.\"\n zone: (zone: string, offset: string) => string;\n problem: Record<AbsoluteRangeProblem, string>;\n}\n\nconst pad = (n: number) => String(n).padStart(2, '0');\n\n// A `datetime-local` value (`2026-10-22T14:30`) for an instant, in the viewer's zone.\nexport function toLocalInput(ms: number): string {\n const d = new Date(ms);\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;\n}\n\n// The instant for a `datetime-local` value read in the viewer's zone, or NaN for an empty/invalid one.\nexport function fromLocalInput(value: string): number {\n return value ? new Date(value).getTime() : Number.NaN;\n}\n\nexport function zoneInfo(at: number = Date.now()): { zone: string; offset: string } {\n const zone = Intl.DateTimeFormat().resolvedOptions().timeZone || 'local';\n const minutes = -new Date(at).getTimezoneOffset();\n const sign = minutes < 0 ? '-' : '+';\n const abs = Math.abs(minutes);\n return { zone, offset: `UTC${sign}${pad(Math.floor(abs / 60))}:${pad(abs % 60)}` };\n}\n\nconst field: CSSProperties = {\n display: 'flex',\n flexDirection: 'column',\n gap: 2,\n fontSize: 12,\n flex: '1 1 13rem',\n minWidth: 0,\n};\nconst input: CSSProperties = {\n font: 'inherit',\n fontSize: 13,\n padding: '3px 6px',\n color: 'hsl(var(--foreground))',\n background: 'hsl(var(--background))',\n border: '1px solid hsl(var(--border))',\n borderRadius: 4,\n minWidth: 0,\n};\nconst action = (primary: boolean): CSSProperties => ({\n padding: '3px 10px',\n fontSize: 12,\n cursor: 'pointer',\n color: primary ? 'hsl(var(--background))' : 'hsl(var(--foreground))',\n background: primary ? 'hsl(var(--foreground))' : 'transparent',\n border: '1px solid hsl(var(--border))',\n borderRadius: 4,\n});\n\nexport default function AbsoluteRangePicker({\n initial,\n labels,\n onApply,\n onCancel,\n}: {\n initial?: AbsoluteRange;\n labels: AbsolutePickerLabels;\n // Returns why the window was refused, or undefined when it was taken.\n onApply: (fromMs: number, toMs: number) => AbsoluteRangeProblem | undefined;\n onCancel: () => void;\n}) {\n const id = useId();\n const now = Date.now();\n // Open on the window already in force, or on the last hour as a starting point to edit.\n const [from, setFrom] = useState(() => toLocalInput(initial?.fromMs ?? now - 60 * 60 * 1000));\n const [to, setTo] = useState(() => toLocalInput(initial?.toMs ?? now));\n const [problem, setProblem] = useState<AbsoluteRangeProblem | undefined>();\n const { zone, offset } = zoneInfo();\n const max = toLocalInput(now);\n\n const submit = () => {\n const p = onApply(fromLocalInput(from), fromLocalInput(to));\n setProblem(p);\n };\n\n return (\n <form\n data-absolute-picker=\"\"\n aria-label={labels.custom}\n onSubmit={(e) => {\n e.preventDefault();\n submit();\n }}\n onKeyDown={(e) => {\n if (e.key === 'Escape') onCancel();\n }}\n style={{\n display: 'flex',\n flexDirection: 'column',\n gap: 8,\n padding: 10,\n boxSizing: 'border-box',\n width: 'min(24rem, calc(100vw - 32px))',\n color: 'hsl(var(--foreground))',\n background: 'hsl(var(--background))',\n border: '1px solid hsl(var(--border))',\n borderRadius: 6,\n boxShadow: '0 4px 16px rgba(0,0,0,0.18)',\n }}\n >\n <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>\n <label htmlFor={`${id}-from`} style={field}>\n {labels.from}\n <input\n id={`${id}-from`}\n data-absolute-from=\"\"\n type=\"datetime-local\"\n value={from}\n max={max}\n required\n onChange={(e) => setFrom(e.target.value)}\n style={input}\n />\n </label>\n <label htmlFor={`${id}-to`} style={field}>\n {labels.to}\n <input\n id={`${id}-to`}\n data-absolute-to=\"\"\n type=\"datetime-local\"\n value={to}\n max={max}\n required\n onChange={(e) => setTo(e.target.value)}\n style={input}\n />\n </label>\n </div>\n <div data-absolute-zone=\"\" style={{ fontSize: 12, color: 'hsl(var(--muted-foreground))' }}>\n {labels.zone(zone, offset)}\n </div>\n {problem ? (\n <div role=\"alert\" data-absolute-problem={problem} style={{ fontSize: 12, color: 'hsl(var(--destructive))' }}>\n {labels.problem[problem]}\n </div>\n ) : null}\n <div style={{ display: 'flex', gap: 6, justifyContent: 'flex-end' }}>\n <button type=\"button\" onClick={onCancel} style={action(false)}>\n {labels.cancel}\n </button>\n <button type=\"submit\" data-absolute-apply=\"\" style={action(true)}>\n {labels.apply}\n </button>\n </div>\n </form>\n );\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
measurementSpan
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-NYHNQ5VR.js";
|
|
4
4
|
|
|
5
5
|
// src/aggregate-feed.tsx
|
|
6
6
|
import {
|
|
@@ -156,4 +156,4 @@ function AggregateFeed({ hub, widget, descriptor, Component, actions, ErrorFrame
|
|
|
156
156
|
export {
|
|
157
157
|
AggregateFeed as default
|
|
158
158
|
};
|
|
159
|
-
//# sourceMappingURL=aggregate-feed-
|
|
159
|
+
//# sourceMappingURL=aggregate-feed-XX36GNY6.js.map
|
|
@@ -1,13 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
DEFAULT_PAGE_SIZE,
|
|
3
|
-
cellFor,
|
|
4
|
-
clampPage,
|
|
5
|
-
columnNames,
|
|
6
|
-
deviceBars,
|
|
7
|
-
deviceLabel,
|
|
8
|
-
pageCount,
|
|
9
|
-
sortMembers
|
|
10
|
-
} from "./chunk-62CHYCHI.js";
|
|
11
1
|
import {
|
|
12
2
|
niceDomain,
|
|
13
3
|
pieSlices,
|
|
@@ -16,11 +6,31 @@ import {
|
|
|
16
6
|
import {
|
|
17
7
|
fleetStrings
|
|
18
8
|
} from "./chunk-QMGKB6J3.js";
|
|
9
|
+
import {
|
|
10
|
+
Explained
|
|
11
|
+
} from "./chunk-AF4M5OXQ.js";
|
|
12
|
+
import {
|
|
13
|
+
NoReading
|
|
14
|
+
} from "./chunk-JVC6JYUR.js";
|
|
15
|
+
import {
|
|
16
|
+
fleetExport
|
|
17
|
+
} from "./chunk-VTGKDO44.js";
|
|
19
18
|
import "./chunk-BRH66T5F.js";
|
|
20
19
|
import {
|
|
21
20
|
LevelEmpty,
|
|
22
21
|
LevelReadout
|
|
23
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-EQOWBDS7.js";
|
|
23
|
+
import "./chunk-XJ7UF2CP.js";
|
|
24
|
+
import {
|
|
25
|
+
DEFAULT_PAGE_SIZE,
|
|
26
|
+
cellFor,
|
|
27
|
+
clampPage,
|
|
28
|
+
columnNames,
|
|
29
|
+
deviceBars,
|
|
30
|
+
deviceLabel,
|
|
31
|
+
pageCount,
|
|
32
|
+
sortMembers
|
|
33
|
+
} from "./chunk-62CHYCHI.js";
|
|
24
34
|
|
|
25
35
|
// src/widgets/bar-chart.tsx
|
|
26
36
|
import { useMemo } from "react";
|
|
@@ -135,8 +145,8 @@ function DeviceBars({
|
|
|
135
145
|
);
|
|
136
146
|
if (!measurement) return /* @__PURE__ */ jsx(LevelEmpty, { message: strings.noMeasurement });
|
|
137
147
|
if (!fleet || fleet.status === "loading") return /* @__PURE__ */ jsx(LevelEmpty, { message: strings.loading });
|
|
138
|
-
if (fleet.status === "unbound") return /* @__PURE__ */ jsx(
|
|
139
|
-
if (fleet.status === "forbidden") return /* @__PURE__ */ jsx(
|
|
148
|
+
if (fleet.status === "unbound") return /* @__PURE__ */ jsx(Explained, { kind: "unbound", message: strings.unbound });
|
|
149
|
+
if (fleet.status === "forbidden") return /* @__PURE__ */ jsx(Explained, { kind: "forbidden", message: strings.forbidden });
|
|
140
150
|
if (fleet.status === "unsupported") return /* @__PURE__ */ jsx(LevelEmpty, { message: strings.unsupported });
|
|
141
151
|
if (bars.length === 0) return /* @__PURE__ */ jsx(LevelEmpty, { message: strings.noMembers });
|
|
142
152
|
const drawn = bars.slice(0, MAX_DEVICE_BARS);
|
|
@@ -314,10 +324,10 @@ function FleetCount({ widget, data }) {
|
|
|
314
324
|
const measurement = optString2(widget.options, "measurement") ?? primaryMeasurementName(widget);
|
|
315
325
|
const thresholds = useMemo2(() => optThresholds(widget.options, "thresholds"), [widget.options]);
|
|
316
326
|
const title = optString2(widget.options, "title");
|
|
317
|
-
const empty = (message) => /* @__PURE__ */ jsx2(WidgetFrame2, { title, children: /* @__PURE__ */ jsx2(LevelEmpty, { message }) });
|
|
327
|
+
const empty = (message, kind) => /* @__PURE__ */ jsx2(WidgetFrame2, { title, children: kind ? /* @__PURE__ */ jsx2(Explained, { kind, message }) : /* @__PURE__ */ jsx2(LevelEmpty, { message }) });
|
|
318
328
|
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);
|
|
329
|
+
if (fleet.status === "unbound") return empty(strings.unbound, "unbound");
|
|
330
|
+
if (fleet.status === "forbidden") return empty(strings.forbidden, "forbidden");
|
|
321
331
|
if (fleet.status === "unsupported") return empty(strings.unsupported);
|
|
322
332
|
if (!showDevices) {
|
|
323
333
|
if (measurement === void 0) return empty(strings.noMeasurementCount);
|
|
@@ -473,8 +483,8 @@ function FleetTable({ widget, data }) {
|
|
|
473
483
|
if (!fleet || fleet.status === "loading") {
|
|
474
484
|
return /* @__PURE__ */ jsx3(Frame, { title, children: /* @__PURE__ */ jsx3(LevelEmpty, { message: strings.loading }) });
|
|
475
485
|
}
|
|
476
|
-
if (fleet.status === "unbound") return /* @__PURE__ */ jsx3(Frame, { title, children: /* @__PURE__ */ jsx3(
|
|
477
|
-
if (fleet.status === "forbidden") return /* @__PURE__ */ jsx3(Frame, { title, children: /* @__PURE__ */ jsx3(
|
|
486
|
+
if (fleet.status === "unbound") return /* @__PURE__ */ jsx3(Frame, { title, children: /* @__PURE__ */ jsx3(Explained, { kind: "unbound", message: strings.unbound }) });
|
|
487
|
+
if (fleet.status === "forbidden") return /* @__PURE__ */ jsx3(Frame, { title, children: /* @__PURE__ */ jsx3(Explained, { kind: "forbidden", message: strings.forbidden }) });
|
|
478
488
|
if (fleet.status === "unsupported") return /* @__PURE__ */ jsx3(Frame, { title, children: /* @__PURE__ */ jsx3(LevelEmpty, { message: strings.unsupported }) });
|
|
479
489
|
if (fleet.members.length === 0) return /* @__PURE__ */ jsx3(Frame, { title, children: /* @__PURE__ */ jsx3(LevelEmpty, { message: strings.noMembers }) });
|
|
480
490
|
return /* @__PURE__ */ jsx3(Table, { widget, fleet, strings });
|
|
@@ -626,44 +636,61 @@ function Table({
|
|
|
626
636
|
] }, member.token);
|
|
627
637
|
})
|
|
628
638
|
] });
|
|
629
|
-
return /* @__PURE__ */ jsx3(
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
639
|
+
return /* @__PURE__ */ jsx3(
|
|
640
|
+
WidgetFrame3,
|
|
641
|
+
{
|
|
642
|
+
title: optString3(widget.options, "title"),
|
|
643
|
+
flush: true,
|
|
644
|
+
exportRows: () => fleetExport({
|
|
645
|
+
subject: optString3(widget.options, "title") ?? "fleet",
|
|
646
|
+
members: fleet.members,
|
|
647
|
+
total: fleet.total,
|
|
648
|
+
columns: columns.map((name) => {
|
|
649
|
+
const f = formats.get(name);
|
|
650
|
+
return { name, heading: (f?.label ?? name) + (f?.unit ? ` (${f.unit})` : ""), precision: f?.precision };
|
|
651
|
+
}),
|
|
652
|
+
sort
|
|
653
|
+
}),
|
|
654
|
+
children: /* @__PURE__ */ jsxs3("div", { style: { display: "flex", flexDirection: "column", height: "100%", minHeight: 0 }, children: [
|
|
655
|
+
/* @__PURE__ */ jsx3(
|
|
656
|
+
"div",
|
|
657
|
+
{
|
|
658
|
+
role: "region",
|
|
659
|
+
"aria-label": optString3(widget.options, "title") ?? strings.device,
|
|
660
|
+
tabIndex: 0,
|
|
661
|
+
"data-fleet-scroll": "",
|
|
662
|
+
style: { flex: 1, minHeight: 0, overflow: "auto" },
|
|
663
|
+
children: /* @__PURE__ */ jsx3(Responsive, { wide, narrow })
|
|
664
|
+
}
|
|
665
|
+
),
|
|
666
|
+
(fleet.truncated || pages > 1) && /* @__PURE__ */ jsxs3(
|
|
667
|
+
"div",
|
|
668
|
+
{
|
|
669
|
+
"data-fleet-footer": "",
|
|
670
|
+
style: {
|
|
671
|
+
display: "flex",
|
|
672
|
+
flexWrap: "wrap",
|
|
673
|
+
alignItems: "center",
|
|
674
|
+
justifyContent: "space-between",
|
|
675
|
+
gap: spaceVar2(2),
|
|
676
|
+
padding: `${spaceVar2(1)} ${spaceVar2(3)}`,
|
|
677
|
+
fontSize: fontVar2("sm"),
|
|
678
|
+
color: css3("muted-foreground"),
|
|
679
|
+
borderTop: `1px solid ${css3("border")}`
|
|
680
|
+
},
|
|
681
|
+
children: [
|
|
682
|
+
/* @__PURE__ */ jsx3("span", { "data-fleet-truncated": fleet.truncated ? "" : void 0, children: fleet.truncated ? strings.truncated(fleet.members.length, fleet.total) : "" }),
|
|
683
|
+
pages > 1 && /* @__PURE__ */ jsxs3("span", { style: { display: "inline-flex", alignItems: "center", gap: spaceVar2(2) }, children: [
|
|
684
|
+
/* @__PURE__ */ jsx3("button", { type: "button", style: pagerButton, disabled: shownPage === 0, onClick: () => setPage(shownPage - 1), "aria-label": strings.previous, children: "\u2039" }),
|
|
685
|
+
/* @__PURE__ */ jsx3("span", { children: strings.range(shownPage * pageSize + 1, shownPage * pageSize + rows.length, sorted.length) }),
|
|
686
|
+
/* @__PURE__ */ jsx3("button", { type: "button", style: pagerButton, disabled: shownPage >= pages - 1, onClick: () => setPage(shownPage + 1), "aria-label": strings.next, children: "\u203A" })
|
|
687
|
+
] })
|
|
688
|
+
]
|
|
689
|
+
}
|
|
690
|
+
)
|
|
691
|
+
] })
|
|
692
|
+
}
|
|
693
|
+
);
|
|
667
694
|
}
|
|
668
695
|
function positiveSeconds(v) {
|
|
669
696
|
return v !== void 0 && Number.isFinite(v) && v > 0 ? v : void 0;
|
|
@@ -839,6 +866,7 @@ import {
|
|
|
839
866
|
optNumber as optNumber4,
|
|
840
867
|
optString as optString5,
|
|
841
868
|
optThresholds as optThresholds2,
|
|
869
|
+
pickSample as pickSample2,
|
|
842
870
|
spaceVar as spaceVar4,
|
|
843
871
|
useSeverityColors as useSeverityColors3,
|
|
844
872
|
WidgetFrame as WidgetFrame5,
|
|
@@ -981,6 +1009,20 @@ function StatCard({ widget, data }) {
|
|
|
981
1009
|
const wantsTrend = optBoolean2(widget.options, "sparkline");
|
|
982
1010
|
const card = /* @__PURE__ */ jsx6(WidgetFrame5, { title, sampleTime: stat === "last" ? reading.kind === "value" ? reading.time ?? null : null : void 0, children: ({ size, scale }) => {
|
|
983
1011
|
if (reading.kind === "empty") {
|
|
1012
|
+
if (reading.reason === "unbound" || reading.reason === "noData" || reading.reason === "noReadings") {
|
|
1013
|
+
return /* @__PURE__ */ jsx6(
|
|
1014
|
+
NoReading,
|
|
1015
|
+
{
|
|
1016
|
+
unbound: reading.reason === "unbound",
|
|
1017
|
+
measurement: reading.name,
|
|
1018
|
+
lastSample: pickSample2(data.latest, reading.name),
|
|
1019
|
+
unit,
|
|
1020
|
+
precision,
|
|
1021
|
+
detail: reading.reason === "noReadings" ? emptyMessage(reading, strings) : void 0,
|
|
1022
|
+
waitMs: reading.reason === "noReadings" ? 0 : void 0
|
|
1023
|
+
}
|
|
1024
|
+
);
|
|
1025
|
+
}
|
|
984
1026
|
return /* @__PURE__ */ jsx6(LevelEmpty, { message: emptyMessage(reading, strings) });
|
|
985
1027
|
}
|
|
986
1028
|
const isCount = reading.stat === "count";
|
|
@@ -1087,4 +1129,4 @@ export {
|
|
|
1087
1129
|
PieChart,
|
|
1088
1130
|
StatCard
|
|
1089
1131
|
};
|
|
1090
|
-
//# sourceMappingURL=aggregate-widgets-
|
|
1132
|
+
//# sourceMappingURL=aggregate-widgets-72HMPMBU.js.map
|