@camstack/ui-library 1.2.304 → 1.2.306
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{MotionZonesSettings-C3Tj12yc.js → MotionZonesSettings-DR1g9ja3.js} +1 -1
- package/dist/{PrivacyMaskSettings-C9wfHkiB.js → PrivacyMaskSettings-CtetT6Jl.js} +1 -1
- package/dist/{SceneMonitorEditor-30H29vN4.js → SceneMonitorEditor-BQhVO2F2.js} +1 -1
- package/dist/composites/cap-settings/EventHeatmap.d.ts +8 -2
- package/dist/composites/charts/BarSeries.d.ts +49 -0
- package/dist/composites/charts/Sparkline.d.ts +26 -0
- package/dist/composites/charts/StateTimeline.d.ts +47 -0
- package/dist/composites/charts/TimeSeriesChart.d.ts +48 -0
- package/dist/composites/charts/bar-series-model.d.ts +25 -0
- package/dist/composites/charts/chart-data.d.ts +87 -0
- package/dist/composites/charts/chart-frame.d.ts +53 -0
- package/dist/composites/charts/chart-palette.d.ts +46 -0
- package/dist/composites/charts/chart-scale.d.ts +29 -0
- package/dist/composites/charts/chart-uplot.d.ts +44 -0
- package/dist/composites/charts/chart-window.d.ts +19 -0
- package/dist/composites/charts/index.d.ts +16 -0
- package/dist/composites/charts/time-series-model.d.ts +47 -0
- package/dist/composites/charts/uplot-host.d.ts +34 -0
- package/dist/composites/device-history/DeviceHistoryView.d.ts +26 -0
- package/dist/composites/device-history/HistoryChart.d.ts +31 -0
- package/dist/composites/device-history/HistoryWindowBar.d.ts +16 -0
- package/dist/composites/device-history/history-model.d.ts +121 -0
- package/dist/composites/device-history/history-reads.d.ts +43 -0
- package/dist/composites/device-history/history-selection.d.ts +55 -0
- package/dist/composites/device-history/history-window.d.ts +31 -0
- package/dist/composites/device-history/index.d.ts +14 -0
- package/dist/composites/device-history/use-device-history.d.ts +37 -0
- package/dist/composites/device-history/use-history-panels.d.ts +10 -0
- package/dist/composites/index.d.ts +2 -0
- package/dist/composites/log-history-paging.d.ts +62 -0
- package/dist/composites/log-stream.d.ts +6 -10
- package/dist/generated/system-hooks.d.ts +2 -0
- package/dist/hooks/use-log-history.d.ts +26 -0
- package/dist/{icons-B1AFXUaZ.cjs → icons-BTux33dH.cjs} +2 -35
- package/dist/{icons-BT8c2hxp.js → icons-D178phML.js} +1 -34
- package/dist/index.cjs +3509 -122
- package/dist/index.js +3430 -129
- package/dist/uPlot.esm-BbxBUnav.cjs +3767 -0
- package/dist/uPlot.esm-C_8LiAPm.js +3767 -0
- package/package.json +2 -1
- package/src/tailwind/camstack-theme.css +104 -2
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DeviceHistoryView — a device's recorded history (device-history, D850):
|
|
3
|
+
* the device page's History tab, and — with `fixedWindow="24h"` — the last
|
|
4
|
+
* day on a camera's Live Stats tab. One code path for both.
|
|
5
|
+
*
|
|
6
|
+
* Grouping mirrors the State panel: one collapsible section per capability
|
|
7
|
+
* (catalog order), then per producer addon; inside, one chart per unit and
|
|
8
|
+
* one timeline per state. Every chart shares one cursor. A chart's ⋯ menu
|
|
9
|
+
* opens its series on the History page or hides it (remembered in the
|
|
10
|
+
* user's account preferences).
|
|
11
|
+
*
|
|
12
|
+
* Absent and pending are different screens (D315): device-history not
|
|
13
|
+
* installed, the list not answered yet, and "nothing recorded" each say so.
|
|
14
|
+
*/
|
|
15
|
+
import { type JSX } from "react";
|
|
16
|
+
import { type HistoryWindowId } from "./history-window";
|
|
17
|
+
export interface DeviceHistoryViewProps {
|
|
18
|
+
readonly deviceId: number;
|
|
19
|
+
/** A fixed window with no window controls (the Live Stats tab's last day). */
|
|
20
|
+
readonly fixedWindow?: Exclude<HistoryWindowId, "custom">;
|
|
21
|
+
/** In-app navigation (react-router); default a page load under the mount. */
|
|
22
|
+
readonly onNavigate?: (path: string) => void;
|
|
23
|
+
}
|
|
24
|
+
/** `climate-control` → `Climate control`. */
|
|
25
|
+
export declare function humanizeName(name: string): string;
|
|
26
|
+
export declare function DeviceHistoryView({ deviceId, fixedWindow, onNavigate }: DeviceHistoryViewProps): JSX.Element;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One chart of a device's History view, from its spec and the reads.
|
|
3
|
+
* Lines → `TimeSeriesChart`, states → `StateTimeline`, energy → `BarSeries`
|
|
4
|
+
* with the window total, occupancy → one `TimeSeriesChart` of every
|
|
5
|
+
* (zone × class) scope with zone and class filters.
|
|
6
|
+
*
|
|
7
|
+
* A read that failed says so in place of the chart; a read that answered no
|
|
8
|
+
* point is the empty state — never a flat zero.
|
|
9
|
+
*/
|
|
10
|
+
import { type JSX, type ReactNode } from "react";
|
|
11
|
+
import type { DeviceHistoryQueryManyEntry } from "@camstack/types";
|
|
12
|
+
import { type UiTextFn } from "../../contexts/ui-text";
|
|
13
|
+
import { type HistoryChartSpec } from "./history-model";
|
|
14
|
+
import type { HistoryReads } from "./use-device-history";
|
|
15
|
+
import type { HistoryWindow } from "./history-window";
|
|
16
|
+
export interface HistoryChartProps {
|
|
17
|
+
readonly spec: HistoryChartSpec;
|
|
18
|
+
/** Entry for a series key (all scopes), current and previous period. */
|
|
19
|
+
readonly entryFor: (key: string, previous: boolean) => DeviceHistoryQueryManyEntry | undefined;
|
|
20
|
+
readonly reads: HistoryReads | null;
|
|
21
|
+
readonly window: HistoryWindow;
|
|
22
|
+
readonly compare: boolean;
|
|
23
|
+
readonly syncKey: string;
|
|
24
|
+
readonly actions?: ReactNode;
|
|
25
|
+
}
|
|
26
|
+
/** Operator words for a boolean field's two states. */
|
|
27
|
+
export declare function booleanLabels(key: string, t: UiTextFn): {
|
|
28
|
+
readonly on: string;
|
|
29
|
+
readonly off: string;
|
|
30
|
+
};
|
|
31
|
+
export declare function HistoryChart({ spec, entryFor, reads, window, compare, syncKey, actions }: HistoryChartProps): JSX.Element;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The window controls on top of a History view: 24h | 7d | 30d | 1y | custom,
|
|
3
|
+
* a custom from/to when picked, and "compare with previous period".
|
|
4
|
+
*/
|
|
5
|
+
import { type JSX } from "react";
|
|
6
|
+
import type { CustomWindow, HistoryWindowId } from "./history-window";
|
|
7
|
+
export interface HistoryWindowBarProps {
|
|
8
|
+
readonly value: HistoryWindowId;
|
|
9
|
+
readonly onChange: (id: HistoryWindowId) => void;
|
|
10
|
+
readonly custom: CustomWindow | null;
|
|
11
|
+
readonly onCustomChange: (w: CustomWindow) => void;
|
|
12
|
+
/** Omit to hide the compare control. */
|
|
13
|
+
readonly compare?: boolean;
|
|
14
|
+
readonly onCompareChange?: (on: boolean) => void;
|
|
15
|
+
}
|
|
16
|
+
export declare function HistoryWindowBar({ value, onChange, custom, onCustomChange, compare, onCompareChange }: HistoryWindowBarProps): JSX.Element;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The pure half of a device's History view: which charts a device's series
|
|
3
|
+
* make, in which sections, and how a `query` answer becomes chart data.
|
|
4
|
+
*
|
|
5
|
+
* Grouping mirrors the State panel: one section per capability in
|
|
6
|
+
* `HISTORY_CATALOG` order (its fields in catalog order), then one section per
|
|
7
|
+
* producer addon, sorted. Inside a section: one line chart per UNIT (never
|
|
8
|
+
* two units on one axis), one state timeline per boolean or enum, the
|
|
9
|
+
* derived energy as bars. A camera's occupancy is ONE chart of every
|
|
10
|
+
* (zone × class) scope.
|
|
11
|
+
*/
|
|
12
|
+
import { type DeviceHistoryQueryResult, type DeviceHistorySeriesInfo } from "@camstack/types";
|
|
13
|
+
import type { BarBucket } from "../charts/bar-series-model";
|
|
14
|
+
import type { StateSegment, TimePoint } from "../charts/chart-data";
|
|
15
|
+
/** The producer series a camera's occupancy chart reads. */
|
|
16
|
+
export declare const OCCUPANCY_KEY = "addon:pipeline-analytics/occupancy";
|
|
17
|
+
export type HistoryChartSpec = {
|
|
18
|
+
readonly type: "lines";
|
|
19
|
+
readonly id: string;
|
|
20
|
+
readonly title: string;
|
|
21
|
+
readonly unit: string | null;
|
|
22
|
+
readonly series: readonly DeviceHistorySeriesInfo[];
|
|
23
|
+
} | {
|
|
24
|
+
readonly type: "states";
|
|
25
|
+
readonly id: string;
|
|
26
|
+
readonly title: string;
|
|
27
|
+
readonly series: DeviceHistorySeriesInfo;
|
|
28
|
+
} | {
|
|
29
|
+
readonly type: "energy";
|
|
30
|
+
readonly id: string;
|
|
31
|
+
readonly title: string;
|
|
32
|
+
readonly series: DeviceHistorySeriesInfo;
|
|
33
|
+
} | {
|
|
34
|
+
readonly type: "occupancy";
|
|
35
|
+
readonly id: string;
|
|
36
|
+
readonly title: string;
|
|
37
|
+
readonly series: readonly DeviceHistorySeriesInfo[];
|
|
38
|
+
};
|
|
39
|
+
export interface HistorySection {
|
|
40
|
+
readonly id: string;
|
|
41
|
+
/** `cap` — a capability's fields; `producer` — an addon's declared series. */
|
|
42
|
+
readonly kind: "cap" | "producer";
|
|
43
|
+
/** Capability name or producer addon id. */
|
|
44
|
+
readonly name: string;
|
|
45
|
+
readonly charts: readonly HistoryChartSpec[];
|
|
46
|
+
}
|
|
47
|
+
/** `cap:<capName>.<fieldPath>` → its parts; `null` for any other key. */
|
|
48
|
+
export declare function parseCapKey(key: string): {
|
|
49
|
+
readonly cap: string;
|
|
50
|
+
readonly field: string;
|
|
51
|
+
} | null;
|
|
52
|
+
/** `addon:<addonId>/<name>` → its parts; `null` for any other key. */
|
|
53
|
+
export declare function parseProducerKey(key: string): {
|
|
54
|
+
readonly addonId: string;
|
|
55
|
+
readonly name: string;
|
|
56
|
+
} | null;
|
|
57
|
+
/**
|
|
58
|
+
* Group a device's series into sections. Energy (a derived key) joins the
|
|
59
|
+
* `power-meter` section when the device has one, else gets its own.
|
|
60
|
+
*/
|
|
61
|
+
export declare function groupDeviceSeries(series: readonly DeviceHistorySeriesInfo[], capTitle: (cap: string) => string): readonly HistorySection[];
|
|
62
|
+
/** The unique keys a set of charts reads (one `queryMany` item each: every scope comes back). */
|
|
63
|
+
export declare function chartKeys(charts: readonly HistoryChartSpec[]): readonly string[];
|
|
64
|
+
/** One series of a `query` answer, found by scope. */
|
|
65
|
+
export declare function seriesOf(result: DeviceHistoryQueryResult | undefined, scope: string): DeviceHistoryQueryResult["series"][number] | undefined;
|
|
66
|
+
/**
|
|
67
|
+
* Line points for a gauge or counter. A rolled-up answer carries its
|
|
68
|
+
* min/max (a band). A CAP series is change-only and held, so the window
|
|
69
|
+
* opens on the value in force (`before`); a producer's buckets are not held
|
|
70
|
+
* and an absent bucket is a hole.
|
|
71
|
+
*/
|
|
72
|
+
export declare function linePoints(info: DeviceHistorySeriesInfo, result: DeviceHistoryQueryResult | undefined, from: number): {
|
|
73
|
+
readonly points: readonly TimePoint[];
|
|
74
|
+
readonly gapMs: number | undefined;
|
|
75
|
+
readonly held: boolean;
|
|
76
|
+
};
|
|
77
|
+
/** Shift every point by `shiftMs` (a previous period laid over the current one). */
|
|
78
|
+
export declare function shiftPoints(points: readonly TimePoint[], shiftMs: number): readonly TimePoint[];
|
|
79
|
+
/** The state names a boolean series takes, `false` first. */
|
|
80
|
+
export declare const BOOLEAN_STATES: readonly ["false", "true"];
|
|
81
|
+
/**
|
|
82
|
+
* A state series as segments plus the exact time spent in each state.
|
|
83
|
+
*
|
|
84
|
+
* Raw points are changes. A rollup bucket is drawn in its DOMINANT state
|
|
85
|
+
* (the one held longest in it), while the totals add the bucket's real
|
|
86
|
+
* per-state milliseconds — so "open 2h 14m" stays exact at any zoom.
|
|
87
|
+
*/
|
|
88
|
+
export declare function stateRow(info: DeviceHistorySeriesInfo, result: DeviceHistoryQueryResult | undefined, from: number, to: number): {
|
|
89
|
+
readonly segments: readonly StateSegment[];
|
|
90
|
+
readonly totals: ReadonlyMap<string, number>;
|
|
91
|
+
readonly states: readonly string[];
|
|
92
|
+
};
|
|
93
|
+
/** Energy bars: one bucket per point, the kWh used in it (`delta`). */
|
|
94
|
+
export declare function energyBuckets(result: DeviceHistoryQueryResult | undefined): {
|
|
95
|
+
readonly buckets: readonly BarBucket[];
|
|
96
|
+
readonly bucketMs: number;
|
|
97
|
+
};
|
|
98
|
+
export interface OccupancyScopeLine {
|
|
99
|
+
readonly scope: string;
|
|
100
|
+
/** `''` = the whole frame. */
|
|
101
|
+
readonly zoneId: string;
|
|
102
|
+
/** `undefined` = every class. */
|
|
103
|
+
readonly className: string | undefined;
|
|
104
|
+
}
|
|
105
|
+
export declare function occupancyLines(series: readonly DeviceHistorySeriesInfo[]): readonly OccupancyScopeLine[];
|
|
106
|
+
/** The filter values an occupancy chart offers: zones and classes that exist. */
|
|
107
|
+
export declare function occupancyFacets(lines: readonly OccupancyScopeLine[]): {
|
|
108
|
+
readonly zones: readonly string[];
|
|
109
|
+
readonly classes: readonly string[];
|
|
110
|
+
};
|
|
111
|
+
/** `null` = all. */
|
|
112
|
+
export interface OccupancyFilter {
|
|
113
|
+
readonly zone: string | null;
|
|
114
|
+
readonly className: string | null;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* The lines a filter keeps. With no class picked the per-zone AGGREGATE lines
|
|
118
|
+
* show (summing classes again would double count); a class shows that class
|
|
119
|
+
* in every (or the picked) zone.
|
|
120
|
+
*/
|
|
121
|
+
export declare function filterOccupancyLines(lines: readonly OccupancyScopeLine[], filter: OccupancyFilter): readonly OccupancyScopeLine[];
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Batched history reads. `queryMany` answers up to 24 reads over one window
|
|
3
|
+
* in one call — but it is admin-only (its subjects are nested where the
|
|
4
|
+
* device scope gate cannot see them). A principal it refuses reads each
|
|
5
|
+
* DEVICE series through `query` instead; a node series has no other door and
|
|
6
|
+
* is reported as refused.
|
|
7
|
+
*
|
|
8
|
+
* Every item gets an entry, in order: an answer, or the error that item met.
|
|
9
|
+
* A failed item never hides the others, and is never an empty series.
|
|
10
|
+
*/
|
|
11
|
+
import { type DeviceHistoryQueryManyEntry, type DeviceHistoryQueryManyItem, type DeviceHistoryQueryResult } from "@camstack/types";
|
|
12
|
+
export interface HistoryReadWindow {
|
|
13
|
+
readonly from: number;
|
|
14
|
+
readonly to: number;
|
|
15
|
+
readonly maxPoints?: number;
|
|
16
|
+
}
|
|
17
|
+
/** The two doors `readHistory` uses — the tRPC client in the app, a fake in a spec. */
|
|
18
|
+
export interface HistoryReader {
|
|
19
|
+
queryMany(input: {
|
|
20
|
+
readonly items: DeviceHistoryQueryManyItem[];
|
|
21
|
+
readonly from: number;
|
|
22
|
+
readonly to: number;
|
|
23
|
+
readonly resolution: "auto";
|
|
24
|
+
readonly maxPoints: number;
|
|
25
|
+
}): Promise<{
|
|
26
|
+
readonly results: readonly DeviceHistoryQueryManyEntry[];
|
|
27
|
+
}>;
|
|
28
|
+
query(input: {
|
|
29
|
+
readonly deviceId: number;
|
|
30
|
+
readonly key: string;
|
|
31
|
+
readonly scope?: string;
|
|
32
|
+
readonly from: number;
|
|
33
|
+
readonly to: number;
|
|
34
|
+
readonly resolution: "auto";
|
|
35
|
+
readonly maxPoints: number;
|
|
36
|
+
}): Promise<DeviceHistoryQueryResult>;
|
|
37
|
+
}
|
|
38
|
+
/** Split into batches of at most `size`. */
|
|
39
|
+
export declare function chunk<T>(items: readonly T[], size: number): readonly (readonly T[])[];
|
|
40
|
+
/** Did the hub refuse this principal (rather than fail)? */
|
|
41
|
+
export declare function isRefusal(err: unknown): boolean;
|
|
42
|
+
/** Read every item over one window; one entry per item, in order. */
|
|
43
|
+
export declare function readHistory(reader: HistoryReader, items: readonly DeviceHistoryQueryManyItem[], window: HistoryReadWindow): Promise<readonly DeviceHistoryQueryManyEntry[]>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { type HistoryWindowId } from "./history-window";
|
|
2
|
+
export type HistorySubject = {
|
|
3
|
+
readonly kind: "device";
|
|
4
|
+
readonly deviceId: number;
|
|
5
|
+
} | {
|
|
6
|
+
readonly kind: "node";
|
|
7
|
+
readonly nodeId: string;
|
|
8
|
+
};
|
|
9
|
+
export interface HistorySeriesRef {
|
|
10
|
+
readonly subject: HistorySubject;
|
|
11
|
+
readonly key: string;
|
|
12
|
+
readonly scope: string;
|
|
13
|
+
}
|
|
14
|
+
/** The most series one overlay may carry — one `queryMany` batch. */
|
|
15
|
+
export declare const HISTORY_SELECTION_MAX = 24;
|
|
16
|
+
/** Stable identity of a series ref (React key, dedup, colour slot). */
|
|
17
|
+
export declare function seriesRefId(ref: HistorySeriesRef): string;
|
|
18
|
+
/** One `?s=` value: `d,<deviceId>,<key>,<scope>` or `n,<nodeId>,<key>,<scope>`, each part URI-encoded. */
|
|
19
|
+
export declare function encodeSeriesRef(ref: HistorySeriesRef): string;
|
|
20
|
+
export declare function decodeSeriesRef(raw: string): HistorySeriesRef | null;
|
|
21
|
+
/** Unique refs, in order, capped at {@link HISTORY_SELECTION_MAX}. */
|
|
22
|
+
export declare function normalizeSelection(refs: readonly HistorySeriesRef[]): readonly HistorySeriesRef[];
|
|
23
|
+
/** The History page path showing `refs` over `window`. */
|
|
24
|
+
export declare function historyPageHref(refs: readonly HistorySeriesRef[], window?: HistoryWindowId): string;
|
|
25
|
+
/** The cross-device History page's route. */
|
|
26
|
+
export declare const HISTORY_PAGE_PATH = "/system/history";
|
|
27
|
+
/** The account preference namespace that holds saved panels and hidden charts. */
|
|
28
|
+
export declare const HISTORY_PANELS_NAMESPACE = "admin.history-panels";
|
|
29
|
+
export interface HistoryPanel {
|
|
30
|
+
readonly id: string;
|
|
31
|
+
readonly name: string;
|
|
32
|
+
readonly window: HistoryWindowId;
|
|
33
|
+
readonly selection: readonly HistorySeriesRef[];
|
|
34
|
+
}
|
|
35
|
+
export interface HistoryPanelsValue {
|
|
36
|
+
readonly version: 1;
|
|
37
|
+
readonly panels: readonly HistoryPanel[];
|
|
38
|
+
/** Chart ids an operator hid on a device's History tab, per device id. */
|
|
39
|
+
readonly hidden: Readonly<Record<string, readonly string[]>>;
|
|
40
|
+
}
|
|
41
|
+
export declare const EMPTY_HISTORY_PANELS: HistoryPanelsValue;
|
|
42
|
+
/**
|
|
43
|
+
* Read a stored row's value. A row this client cannot read (another
|
|
44
|
+
* version, a hand edit) is answered as empty rather than throwing — and the
|
|
45
|
+
* caller must not write over it blindly: `parsed: false` says so.
|
|
46
|
+
*/
|
|
47
|
+
export declare function readHistoryPanels(value: unknown): {
|
|
48
|
+
readonly value: HistoryPanelsValue;
|
|
49
|
+
readonly parsed: boolean;
|
|
50
|
+
};
|
|
51
|
+
/** A copy of `value` with chart `chartId` hidden (or shown again) on device `deviceId`. */
|
|
52
|
+
export declare function withHiddenChart(value: HistoryPanelsValue, deviceId: number, chartId: string, hidden: boolean): HistoryPanelsValue;
|
|
53
|
+
/** A copy of `value` with `panel` saved (replacing one with the same id). */
|
|
54
|
+
export declare function withPanel(value: HistoryPanelsValue, panel: HistoryPanel): HistoryPanelsValue;
|
|
55
|
+
export declare function withoutPanel(value: HistoryPanelsValue, panelId: string): HistoryPanelsValue;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The time windows a history view offers, and the "previous period" a
|
|
3
|
+
* comparison reads. Pure: the caller supplies `now`.
|
|
4
|
+
*/
|
|
5
|
+
export type HistoryWindowId = "24h" | "7d" | "30d" | "1y" | "custom";
|
|
6
|
+
export declare const HISTORY_WINDOW_IDS: readonly ["24h", "7d", "30d", "1y", "custom"];
|
|
7
|
+
export declare const HISTORY_WINDOW_MS: Readonly<Record<Exclude<HistoryWindowId, "custom">, number>>;
|
|
8
|
+
export interface HistoryWindow {
|
|
9
|
+
readonly from: number;
|
|
10
|
+
readonly to: number;
|
|
11
|
+
}
|
|
12
|
+
export interface CustomWindow {
|
|
13
|
+
readonly from: number;
|
|
14
|
+
readonly to: number;
|
|
15
|
+
}
|
|
16
|
+
export declare function isHistoryWindowId(v: string | null | undefined): v is HistoryWindowId;
|
|
17
|
+
/**
|
|
18
|
+
* The window a preset means at `now`. `custom` without a valid range (from
|
|
19
|
+
* before to) falls back to the last 24 hours rather than an empty window.
|
|
20
|
+
*/
|
|
21
|
+
export declare function resolveHistoryWindow(id: HistoryWindowId, now: number, custom?: CustomWindow | null): HistoryWindow;
|
|
22
|
+
/** The period of the same length just before `w`, and the shift that lays it over `w`. */
|
|
23
|
+
export declare function previousWindow(w: HistoryWindow): {
|
|
24
|
+
readonly window: HistoryWindow;
|
|
25
|
+
readonly shiftMs: number;
|
|
26
|
+
};
|
|
27
|
+
/** Encode a custom range for the URL: `<fromMs>-<toMs>`. */
|
|
28
|
+
export declare function encodeCustomWindow(w: CustomWindow): string;
|
|
29
|
+
export declare function decodeCustomWindow(raw: string | null | undefined): CustomWindow | null;
|
|
30
|
+
/** Milliseconds a rollup bucket of a resolution covers (`1d` is nominal across DST). */
|
|
31
|
+
export declare const RESOLUTION_BUCKET_MS: Readonly<Record<"5m" | "1h" | "1d", number>>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Device history views (D850, D896): the device History tab / Live Stats
|
|
3
|
+
* last day (`DeviceHistoryView`) and the building blocks the cross-device
|
|
4
|
+
* History page composes.
|
|
5
|
+
*/
|
|
6
|
+
export { DeviceHistoryView, humanizeName, type DeviceHistoryViewProps } from "./DeviceHistoryView";
|
|
7
|
+
export { HistoryChart, booleanLabels, type HistoryChartProps } from "./HistoryChart";
|
|
8
|
+
export { HistoryWindowBar, type HistoryWindowBarProps } from "./HistoryWindowBar";
|
|
9
|
+
export { BOOLEAN_STATES, OCCUPANCY_KEY, chartKeys, energyBuckets, filterOccupancyLines, groupDeviceSeries, linePoints, occupancyFacets, occupancyLines, parseCapKey, parseProducerKey, shiftPoints, stateRow, type HistoryChartSpec, type HistorySection, type OccupancyFilter, type OccupancyScopeLine } from "./history-model";
|
|
10
|
+
export { chunk, isRefusal, readHistory, type HistoryReader, type HistoryReadWindow } from "./history-reads";
|
|
11
|
+
export { EMPTY_HISTORY_PANELS, HISTORY_PAGE_PATH, HISTORY_PANELS_NAMESPACE, HISTORY_SELECTION_MAX, decodeSeriesRef, encodeSeriesRef, historyPageHref, normalizeSelection, readHistoryPanels, seriesRefId, withHiddenChart, withPanel, withoutPanel, type HistoryPanel, type HistoryPanelsValue, type HistorySeriesRef, type HistorySubject } from "./history-selection";
|
|
12
|
+
export { HISTORY_WINDOW_IDS, HISTORY_WINDOW_MS, RESOLUTION_BUCKET_MS, decodeCustomWindow, encodeCustomWindow, isHistoryWindowId, previousWindow, resolveHistoryWindow, type CustomWindow, type HistoryWindow, type HistoryWindowId } from "./history-window";
|
|
13
|
+
export { anchorNow, readItemId, useDeviceSeriesList, useHistoryReader, useHistoryReads, type HistoryReads, type HistoryStage } from "./use-device-history";
|
|
14
|
+
export { useHistoryPanels, type HistoryPanelsState } from "./use-history-panels";
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { DeviceHistoryQueryManyEntry, DeviceHistoryQueryManyItem, DeviceHistorySeriesInfo } from "@camstack/types";
|
|
2
|
+
import { type CapabilityPresence } from "../../hooks/use-capability-presence";
|
|
3
|
+
import { type HistoryReader } from "./history-reads";
|
|
4
|
+
import { type HistoryWindow } from "./history-window";
|
|
5
|
+
/** How a stage of the view stands. */
|
|
6
|
+
export type HistoryStage<T> = {
|
|
7
|
+
readonly status: "pending";
|
|
8
|
+
} | {
|
|
9
|
+
readonly status: "error";
|
|
10
|
+
readonly error: string;
|
|
11
|
+
} | {
|
|
12
|
+
readonly status: "ok";
|
|
13
|
+
readonly data: T;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* The instant a window ends at, rounded so the query key is stable between
|
|
17
|
+
* renders and the view refreshes at a pace its width justifies.
|
|
18
|
+
*/
|
|
19
|
+
export declare function anchorNow(now: number, spanMs: number): number;
|
|
20
|
+
/** The tRPC client as the two doors `readHistory` needs. */
|
|
21
|
+
export declare function useHistoryReader(): HistoryReader;
|
|
22
|
+
/** A device's series list, gated on device-history being present. */
|
|
23
|
+
export declare function useDeviceSeriesList(deviceId: number): {
|
|
24
|
+
readonly presence: CapabilityPresence;
|
|
25
|
+
readonly list: HistoryStage<readonly DeviceHistorySeriesInfo[]>;
|
|
26
|
+
};
|
|
27
|
+
export interface HistoryReads {
|
|
28
|
+
/** Entry per item id (see {@link readItemId}). */
|
|
29
|
+
readonly current: ReadonlyMap<string, DeviceHistoryQueryManyEntry>;
|
|
30
|
+
/** The previous period, when comparing; shifted by `shiftMs` to overlay. */
|
|
31
|
+
readonly previous: ReadonlyMap<string, DeviceHistoryQueryManyEntry> | null;
|
|
32
|
+
readonly shiftMs: number;
|
|
33
|
+
}
|
|
34
|
+
/** Identity of a read item: subject + key (+ scope when narrowed). */
|
|
35
|
+
export declare function readItemId(item: DeviceHistoryQueryManyItem): string;
|
|
36
|
+
/** Read `items` over `window` (and the previous period when `compare`). */
|
|
37
|
+
export declare function useHistoryReads(items: readonly DeviceHistoryQueryManyItem[], window: HistoryWindow, compare: boolean, enabled?: boolean): HistoryStage<HistoryReads>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type HistoryPanelsValue } from "./history-selection";
|
|
2
|
+
export interface HistoryPanelsState {
|
|
3
|
+
/** `pending` until the row answered; `error` when the read failed (never "no panels"). */
|
|
4
|
+
readonly status: "pending" | "error" | "ok";
|
|
5
|
+
readonly value: HistoryPanelsValue;
|
|
6
|
+
/** False when the stored row could not be read: writing would destroy it. */
|
|
7
|
+
readonly writable: boolean;
|
|
8
|
+
readonly update: (change: (current: HistoryPanelsValue) => HistoryPanelsValue) => Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
export declare function useHistoryPanels(): HistoryPanelsState;
|
|
@@ -223,3 +223,5 @@ export * from "./device-picker/index.js";
|
|
|
223
223
|
export * from "./unit-picker/index.js";
|
|
224
224
|
export * from "./placeholder-field/index.js";
|
|
225
225
|
export { type RetrainReviewBadgeKind, type RetrainReviewBadgeLook, type RetrainReviewBadgeProps, RetrainReviewBadge, retrainReviewBadgeLook } from "./training/retrain-review-badge";
|
|
226
|
+
export * from "./charts/index.js";
|
|
227
|
+
export * from "./device-history/index.js";
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure paging logic for the server-served log history (D898).
|
|
3
|
+
*
|
|
4
|
+
* The server answers one TIME-BOUNDED slice per call: `done: false` with fewer
|
|
5
|
+
* than `limit` entries means "the budget ran out, still searching". The client
|
|
6
|
+
* keeps calling with `before: nextBefore` until it holds a full page, the
|
|
7
|
+
* source says `done`, or the operator cancels. Kept free of React and tRPC so
|
|
8
|
+
* the loop is unit-testable.
|
|
9
|
+
*/
|
|
10
|
+
export interface LogWireEntry {
|
|
11
|
+
readonly id?: string;
|
|
12
|
+
readonly timestamp: string;
|
|
13
|
+
readonly level: string;
|
|
14
|
+
readonly message: string;
|
|
15
|
+
readonly scope?: string;
|
|
16
|
+
readonly tags?: Record<string, string | undefined>;
|
|
17
|
+
readonly meta?: Record<string, unknown>;
|
|
18
|
+
}
|
|
19
|
+
export interface LogWirePage {
|
|
20
|
+
/** NEWEST FIRST. */
|
|
21
|
+
readonly entries: readonly LogWireEntry[];
|
|
22
|
+
readonly nextBefore: string | null;
|
|
23
|
+
readonly nextAfter: string | null;
|
|
24
|
+
readonly scannedBytes: number;
|
|
25
|
+
readonly done: boolean;
|
|
26
|
+
readonly cancelled?: boolean;
|
|
27
|
+
readonly source: string;
|
|
28
|
+
}
|
|
29
|
+
/** Fetches one slice older than `before` (undefined = the first page). */
|
|
30
|
+
export type FetchLogSlice = (before: string | undefined, remaining: number, signal: AbortSignal) => Promise<LogWirePage>;
|
|
31
|
+
export interface CollectedPage {
|
|
32
|
+
/** NEWEST FIRST, across every slice the loop made. */
|
|
33
|
+
readonly entries: readonly LogWireEntry[];
|
|
34
|
+
/** Cursor for the next older page; null when nothing older exists. */
|
|
35
|
+
readonly nextBefore: string | null;
|
|
36
|
+
readonly done: boolean;
|
|
37
|
+
readonly cancelled: boolean;
|
|
38
|
+
readonly scannedBytes: number;
|
|
39
|
+
readonly source: string | undefined;
|
|
40
|
+
}
|
|
41
|
+
export interface CollectPageOptions {
|
|
42
|
+
readonly fetchSlice: FetchLogSlice;
|
|
43
|
+
readonly limit: number;
|
|
44
|
+
readonly before?: string;
|
|
45
|
+
readonly signal: AbortSignal;
|
|
46
|
+
/** Called after every slice with the bytes scanned so far. */
|
|
47
|
+
readonly onProgress?: (scannedBytes: number) => void;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Accumulate slices until `limit` entries, `done`, or an abort. An abort keeps
|
|
51
|
+
* what was already collected and the cursor reached, so "Load older" resumes
|
|
52
|
+
* where the scan stopped instead of starting again.
|
|
53
|
+
*/
|
|
54
|
+
export declare function collectPage(options: CollectPageOptions): Promise<CollectedPage>;
|
|
55
|
+
/** Stable identity of an entry: the server id, else the legacy composite key. */
|
|
56
|
+
export declare function logEntryKey(entry: LogWireEntry): string;
|
|
57
|
+
/**
|
|
58
|
+
* History (newest first, as paged) merged with live entries (arrival order),
|
|
59
|
+
* deduped by key — a live entry wins (richer tags/meta) — and returned
|
|
60
|
+
* chronologically, newest LAST. Ties keep insertion order.
|
|
61
|
+
*/
|
|
62
|
+
export declare function mergeLogEntries(history: readonly LogWireEntry[], live: readonly LogWireEntry[]): LogWireEntry[];
|
|
@@ -10,14 +10,8 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { type JSX } from "react";
|
|
12
12
|
import { type LiveBuffer } from "../hooks/use-live-buffer";
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
readonly level: string;
|
|
16
|
-
readonly message: string;
|
|
17
|
-
readonly scope?: string;
|
|
18
|
-
readonly tags?: Record<string, string | undefined>;
|
|
19
|
-
readonly meta?: Record<string, unknown>;
|
|
20
|
-
}
|
|
13
|
+
import { type LogWireEntry } from "./log-history-paging";
|
|
14
|
+
type LogEntry = LogWireEntry;
|
|
21
15
|
export interface LogStreamProps {
|
|
22
16
|
/** Lock to a specific agent. When set, the agent selector is hidden. */
|
|
23
17
|
readonly agentId?: string;
|
|
@@ -65,7 +59,9 @@ export interface LogStreamProps {
|
|
|
65
59
|
readonly showDeviceChip?: boolean;
|
|
66
60
|
/** Show the filter bar with selectors. Set false for compact inline use. */
|
|
67
61
|
readonly showFilters?: boolean;
|
|
68
|
-
/**
|
|
62
|
+
/** Show the history source selector (default: follows `showFilters`). */
|
|
63
|
+
readonly showSourceSelect?: boolean;
|
|
64
|
+
/** Entries per history page (default: 100). */
|
|
69
65
|
readonly limit?: number;
|
|
70
66
|
/**
|
|
71
67
|
* Optional controlled live buffer. When provided, the stream reads
|
|
@@ -79,7 +75,7 @@ export interface LogStreamProps {
|
|
|
79
75
|
readonly onClose?: () => void;
|
|
80
76
|
readonly className?: string;
|
|
81
77
|
}
|
|
82
|
-
export declare function LogStream({ agentId: propsAgentId, addonId: propsAddonId, deviceId: propsDeviceId, containerDeviceId: propsContainerDeviceId, integrationId: propsIntegrationId, requestId: propsRequestId, level: initialLevel, maxHeight, showScope, showDeviceChip, showFilters, limit, liveBuffer: externalBuffer, onClose, className }: LogStreamProps): JSX.Element;
|
|
78
|
+
export declare function LogStream({ agentId: propsAgentId, addonId: propsAddonId, deviceId: propsDeviceId, containerDeviceId: propsContainerDeviceId, integrationId: propsIntegrationId, requestId: propsRequestId, level: initialLevel, maxHeight, showScope, showDeviceChip, showFilters, showSourceSelect, limit, liveBuffer: externalBuffer, onClose, className }: LogStreamProps): JSX.Element;
|
|
83
79
|
export interface FloatingLogStreamProps extends LogStreamProps {
|
|
84
80
|
/** Position: 'bottom' anchors to parent bottom, 'overlay' is absolute positioned. */
|
|
85
81
|
readonly position?: "bottom" | "overlay";
|
|
@@ -487,6 +487,8 @@ export declare const useDeviceHistoryListNodeSeries: typeof trpc.deviceHistory.l
|
|
|
487
487
|
export declare const useDeviceHistoryQuery: typeof trpc.deviceHistory.query.useQuery;
|
|
488
488
|
/** Generated alias around `trpc.deviceHistory.queryNode.useQuery`. */
|
|
489
489
|
export declare const useDeviceHistoryQueryNode: typeof trpc.deviceHistory.queryNode.useQuery;
|
|
490
|
+
/** Generated alias around `trpc.deviceHistory.queryMany.useQuery`. */
|
|
491
|
+
export declare const useDeviceHistoryQueryMany: typeof trpc.deviceHistory.queryMany.useQuery;
|
|
490
492
|
/** Generated alias around `trpc.deviceHistory.declareSeries.useMutation`. */
|
|
491
493
|
export declare const useDeviceHistoryDeclareSeries: typeof trpc.deviceHistory.declareSeries.useMutation;
|
|
492
494
|
/** Generated alias around `trpc.deviceHistory.record.useMutation`. */
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type LogWireEntry } from "../composites/log-history-paging";
|
|
2
|
+
export type LogHistoryLevel = "debug" | "info" | "warn" | "error";
|
|
3
|
+
/** The filters the SERVER applies; everything but paging. */
|
|
4
|
+
export interface LogHistoryQuery {
|
|
5
|
+
/** A log-destination addonId or `ring`; undefined = the server default. */
|
|
6
|
+
readonly source?: string;
|
|
7
|
+
readonly level: LogHistoryLevel;
|
|
8
|
+
readonly text?: string;
|
|
9
|
+
readonly tags?: Record<string, string | number>;
|
|
10
|
+
}
|
|
11
|
+
export type LogHistoryStatus = "idle" | "loading";
|
|
12
|
+
export interface LogHistory {
|
|
13
|
+
/** Newest first, as paged. */
|
|
14
|
+
readonly entries: readonly LogWireEntry[];
|
|
15
|
+
readonly status: LogHistoryStatus;
|
|
16
|
+
/** True when nothing older exists ("Beginning of logs"). */
|
|
17
|
+
readonly done: boolean;
|
|
18
|
+
/** Bytes scanned by the scan in flight (0 until its first slice answers). */
|
|
19
|
+
readonly scannedBytes: number;
|
|
20
|
+
/** The source that answered (the server may fall back to `ring`). */
|
|
21
|
+
readonly source: string | undefined;
|
|
22
|
+
readonly error: string | null;
|
|
23
|
+
readonly loadOlder: () => void;
|
|
24
|
+
readonly cancel: () => void;
|
|
25
|
+
}
|
|
26
|
+
export declare function useLogHistory(query: LogHistoryQuery, limit: number): LogHistory;
|
|
@@ -7414,19 +7414,6 @@ var ChartGantt = require_createLucideIcon.createLucideIcon("chart-gantt", [
|
|
|
7414
7414
|
* This source code is licensed under the ISC license.
|
|
7415
7415
|
* See the LICENSE file in the root directory of this source tree.
|
|
7416
7416
|
*/
|
|
7417
|
-
var ChartLine = require_createLucideIcon.createLucideIcon("chart-line", [["path", {
|
|
7418
|
-
d: "M3 3v16a2 2 0 0 0 2 2h16",
|
|
7419
|
-
key: "c24i48"
|
|
7420
|
-
}], ["path", {
|
|
7421
|
-
d: "m19 9-5 5-4-4-3 3",
|
|
7422
|
-
key: "2osh9i"
|
|
7423
|
-
}]]);
|
|
7424
|
-
/**
|
|
7425
|
-
* @license lucide-react v0.576.0 - ISC
|
|
7426
|
-
*
|
|
7427
|
-
* This source code is licensed under the ISC license.
|
|
7428
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
7429
|
-
*/
|
|
7430
7417
|
var ChartNetwork = require_createLucideIcon.createLucideIcon("chart-network", [
|
|
7431
7418
|
["path", {
|
|
7432
7419
|
d: "m13.11 7.664 1.78 2.672",
|
|
@@ -18204,26 +18191,6 @@ var Highlighter = require_createLucideIcon.createLucideIcon("highlighter", [["pa
|
|
|
18204
18191
|
* This source code is licensed under the ISC license.
|
|
18205
18192
|
* See the LICENSE file in the root directory of this source tree.
|
|
18206
18193
|
*/
|
|
18207
|
-
var History = require_createLucideIcon.createLucideIcon("history", [
|
|
18208
|
-
["path", {
|
|
18209
|
-
d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",
|
|
18210
|
-
key: "1357e3"
|
|
18211
|
-
}],
|
|
18212
|
-
["path", {
|
|
18213
|
-
d: "M3 3v5h5",
|
|
18214
|
-
key: "1xhq8a"
|
|
18215
|
-
}],
|
|
18216
|
-
["path", {
|
|
18217
|
-
d: "M12 7v5l4 2",
|
|
18218
|
-
key: "1fdv2h"
|
|
18219
|
-
}]
|
|
18220
|
-
]);
|
|
18221
|
-
/**
|
|
18222
|
-
* @license lucide-react v0.576.0 - ISC
|
|
18223
|
-
*
|
|
18224
|
-
* This source code is licensed under the ISC license.
|
|
18225
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
18226
|
-
*/
|
|
18227
18194
|
var HopOff = require_createLucideIcon.createLucideIcon("hop-off", [
|
|
18228
18195
|
["path", {
|
|
18229
18196
|
d: "M10.82 16.12c1.69.6 3.91.79 5.18.85.28.01.53-.09.7-.27",
|
|
@@ -38164,7 +38131,7 @@ exports.ChartColumnDecreasing = ChartColumnDecreasing;
|
|
|
38164
38131
|
exports.ChartColumnIncreasing = ChartColumnIncreasing;
|
|
38165
38132
|
exports.ChartColumnStacked = ChartColumnStacked;
|
|
38166
38133
|
exports.ChartGantt = ChartGantt;
|
|
38167
|
-
exports.ChartLine = ChartLine;
|
|
38134
|
+
exports.ChartLine = require_index.ChartLine;
|
|
38168
38135
|
exports.ChartNetwork = ChartNetwork;
|
|
38169
38136
|
exports.ChartNoAxesColumn = ChartNoAxesColumn;
|
|
38170
38137
|
exports.ChartNoAxesColumnDecreasing = ChartNoAxesColumnDecreasing;
|
|
@@ -38662,7 +38629,7 @@ exports.Heater = require_index.Heater;
|
|
|
38662
38629
|
exports.Helicopter = Helicopter;
|
|
38663
38630
|
exports.Hexagon = require_mic_off.Hexagon;
|
|
38664
38631
|
exports.Highlighter = Highlighter;
|
|
38665
|
-
exports.History = History;
|
|
38632
|
+
exports.History = require_index.History;
|
|
38666
38633
|
exports.Hop = Hop;
|
|
38667
38634
|
exports.HopOff = HopOff;
|
|
38668
38635
|
exports.Hospital = Hospital;
|