@camstack/addon-pipeline-analytics 0.1.1

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.
Files changed (56) hide show
  1. package/dist/@mf-types/compiled-types/widgets/AudioHistoryChart.d.ts +5 -0
  2. package/dist/@mf-types/compiled-types/widgets/AudioHistoryChart.d.ts.map +1 -0
  3. package/dist/@mf-types/compiled-types/widgets/AudioMetricsPanel.d.ts +11 -0
  4. package/dist/@mf-types/compiled-types/widgets/AudioMetricsPanel.d.ts.map +1 -0
  5. package/dist/@mf-types/compiled-types/widgets/DetectionHistoryChart.d.ts +5 -0
  6. package/dist/@mf-types/compiled-types/widgets/DetectionHistoryChart.d.ts.map +1 -0
  7. package/dist/@mf-types/compiled-types/widgets/MotionHistoryChart.d.ts +5 -0
  8. package/dist/@mf-types/compiled-types/widgets/MotionHistoryChart.d.ts.map +1 -0
  9. package/dist/@mf-types/compiled-types/widgets/OccupancyHistoryChart.d.ts +5 -0
  10. package/dist/@mf-types/compiled-types/widgets/OccupancyHistoryChart.d.ts.map +1 -0
  11. package/dist/@mf-types/compiled-types/widgets/OccupancyPanel.d.ts +11 -0
  12. package/dist/@mf-types/compiled-types/widgets/OccupancyPanel.d.ts.map +1 -0
  13. package/dist/@mf-types/compiled-types/widgets/chart-utils.d.ts +98 -0
  14. package/dist/@mf-types/compiled-types/widgets/chart-utils.d.ts.map +1 -0
  15. package/dist/@mf-types/compiled-types/widgets/index.d.ts +28 -0
  16. package/dist/@mf-types/compiled-types/widgets/index.d.ts.map +1 -0
  17. package/dist/@mf-types/widgets.d.ts +2 -0
  18. package/dist/@mf-types.d.ts +3 -0
  19. package/dist/@mf-types.zip +0 -0
  20. package/dist/__mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_sdk__loadShare__.mjs-CCBTZBOa.mjs +12 -0
  21. package/dist/__mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.mjs-OesvKBZV.mjs +16 -0
  22. package/dist/__mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.mjs-D0mniK1l.mjs +15 -0
  23. package/dist/__mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_tanstack_mf_1_react_mf_2_query__loadShare__.mjs-DoWbefqS.mjs +104 -0
  24. package/dist/__mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_trpc_mf_1_client__loadShare__.mjs-52bfkwC8.mjs +85 -0
  25. package/dist/__mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_trpc_mf_1_react_mf_2_query__loadShare__.mjs-CVrnrGED.mjs +62 -0
  26. package/dist/__mfe_internal__addon_pipeline_analytics_widgets__loadShare__react__loadShare__.mjs-DuO9h7li.mjs +85 -0
  27. package/dist/__mfe_internal__addon_pipeline_analytics_widgets__loadShare__react__loadShare__.mjs_commonjs-proxy-CmqNjq44.mjs +29 -0
  28. package/dist/__mfe_internal__addon_pipeline_analytics_widgets__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.mjs-BsyrX6NO.mjs +36 -0
  29. package/dist/__mfe_internal__addon_pipeline_analytics_widgets__loadShare__react_mf_2_dom__loadShare__.mjs-Dp8hqYOB.mjs +45 -0
  30. package/dist/__mfe_internal__addon_pipeline_analytics_widgets__loadShare__react_mf_2_dom__loadShare__.mjs_commonjs-proxy-CA8cCIEl.mjs +6 -0
  31. package/dist/__mfe_internal__addon_pipeline_analytics_widgets__loadShare__react_mf_2_dom_mf_1_client__loadShare__.mjs-BZjEt71l.mjs +34 -0
  32. package/dist/_stub.js +1397 -0
  33. package/dist/_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-Cm7MAUA1.mjs +157 -0
  34. package/dist/client-DdXDZxzK.mjs +10063 -0
  35. package/dist/getErrorShape-BPSzUA7W-TlK8ipWe.mjs +211 -0
  36. package/dist/hostInit-WKMmag4S.mjs +168 -0
  37. package/dist/index-B4OKsa9p.mjs +2603 -0
  38. package/dist/index-C3iAUQqS.mjs +533 -0
  39. package/dist/index-D0dNM7_R.mjs +2892 -0
  40. package/dist/index-DKqbmJDl.mjs +2464 -0
  41. package/dist/index-DnFVXz0U.mjs +14162 -0
  42. package/dist/index-DyYvUfc7.mjs +725 -0
  43. package/dist/index-Oq45bZIA.mjs +17936 -0
  44. package/dist/index-k0CA0h_r.mjs +185 -0
  45. package/dist/index-kIgjN-uq.mjs +435 -0
  46. package/dist/index-xncRG7-x.mjs +2713 -0
  47. package/dist/index.d.mts +190 -0
  48. package/dist/index.d.ts +190 -0
  49. package/dist/index.js +2623 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/index.mjs +2602 -0
  52. package/dist/index.mjs.map +1 -0
  53. package/dist/jsx-runtime-4ro1c69i.mjs +55 -0
  54. package/dist/remoteEntry.js +85 -0
  55. package/dist/virtualExposes-8FzWTdq3.mjs +42 -0
  56. package/package.json +89 -0
package/dist/_stub.js ADDED
@@ -0,0 +1,1397 @@
1
+ import { _ as r, a as i, b as ae } from "./__mfe_internal__addon_pipeline_analytics_widgets__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.mjs-BsyrX6NO.mjs";
2
+ import { a as Ie, b as fe, c as K, d as H, e as ge, f as N } from "./__mfe_internal__addon_pipeline_analytics_widgets__loadShare__react__loadShare__.mjs-DuO9h7li.mjs";
3
+ import { _ as le } from "./__mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_tanstack_mf_1_react_mf_2_query__loadShare__.mjs-DoWbefqS.mjs";
4
+ import { _ as z, a as Q, b as Be, c as ye } from "./__mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.mjs-D0mniK1l.mjs";
5
+ /**
6
+ * @license lucide-react v0.511.0 - ISC
7
+ *
8
+ * This source code is licensed under the ISC license.
9
+ * See the LICENSE file in the root directory of this source tree.
10
+ */
11
+ const Pe = (e) => e.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase(), ze = (e) => e.replace(
12
+ /^([A-Z])|[\s-_]+(\w)/g,
13
+ (t, o, n) => n ? n.toUpperCase() : o.toLowerCase()
14
+ ), Ne = (e) => {
15
+ const t = ze(e);
16
+ return t.charAt(0).toUpperCase() + t.slice(1);
17
+ }, Ae = (...e) => e.filter((t, o, n) => !!t && t.trim() !== "" && n.indexOf(t) === o).join(" ").trim(), Xe = (e) => {
18
+ for (const t in e)
19
+ if (t.startsWith("aria-") || t === "role" || t === "title")
20
+ return !0;
21
+ };
22
+ /**
23
+ * @license lucide-react v0.511.0 - ISC
24
+ *
25
+ * This source code is licensed under the ISC license.
26
+ * See the LICENSE file in the root directory of this source tree.
27
+ */
28
+ var Ye = {
29
+ xmlns: "http://www.w3.org/2000/svg",
30
+ width: 24,
31
+ height: 24,
32
+ viewBox: "0 0 24 24",
33
+ fill: "none",
34
+ stroke: "currentColor",
35
+ strokeWidth: 2,
36
+ strokeLinecap: "round",
37
+ strokeLinejoin: "round"
38
+ };
39
+ /**
40
+ * @license lucide-react v0.511.0 - ISC
41
+ *
42
+ * This source code is licensed under the ISC license.
43
+ * See the LICENSE file in the root directory of this source tree.
44
+ */
45
+ const qe = Ie(
46
+ ({
47
+ color: e = "currentColor",
48
+ size: t = 24,
49
+ strokeWidth: o = 2,
50
+ absoluteStrokeWidth: n,
51
+ className: a = "",
52
+ children: s,
53
+ iconNode: d,
54
+ ...l
55
+ }, f) => fe(
56
+ "svg",
57
+ {
58
+ ref: f,
59
+ ...Ye,
60
+ width: t,
61
+ height: t,
62
+ stroke: e,
63
+ strokeWidth: n ? Number(o) * 24 / Number(t) : o,
64
+ className: Ae("lucide", a),
65
+ ...!s && !Xe(l) && { "aria-hidden": "true" },
66
+ ...l
67
+ },
68
+ [
69
+ ...d.map(([u, k]) => fe(u, k)),
70
+ ...Array.isArray(s) ? s : [s]
71
+ ]
72
+ )
73
+ );
74
+ /**
75
+ * @license lucide-react v0.511.0 - ISC
76
+ *
77
+ * This source code is licensed under the ISC license.
78
+ * See the LICENSE file in the root directory of this source tree.
79
+ */
80
+ const W = (e, t) => {
81
+ const o = Ie(
82
+ ({ className: n, ...a }, s) => fe(qe, {
83
+ ref: s,
84
+ iconNode: t,
85
+ className: Ae(
86
+ `lucide-${Pe(Ne(e))}`,
87
+ `lucide-${e}`,
88
+ n
89
+ ),
90
+ ...a
91
+ })
92
+ );
93
+ return o.displayName = Ne(e), o;
94
+ };
95
+ /**
96
+ * @license lucide-react v0.511.0 - ISC
97
+ *
98
+ * This source code is licensed under the ISC license.
99
+ * See the LICENSE file in the root directory of this source tree.
100
+ */
101
+ const Ge = [
102
+ [
103
+ "path",
104
+ {
105
+ d: "M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2",
106
+ key: "169zse"
107
+ }
108
+ ]
109
+ ], Z = W("activity", Ge);
110
+ /**
111
+ * @license lucide-react v0.511.0 - ISC
112
+ *
113
+ * This source code is licensed under the ISC license.
114
+ * See the LICENSE file in the root directory of this source tree.
115
+ */
116
+ const Ue = [
117
+ [
118
+ "path",
119
+ {
120
+ d: "M2.97 12.92A2 2 0 0 0 2 14.63v3.24a2 2 0 0 0 .97 1.71l3 1.8a2 2 0 0 0 2.06 0L12 19v-5.5l-5-3-4.03 2.42Z",
121
+ key: "lc1i9w"
122
+ }
123
+ ],
124
+ ["path", { d: "m7 16.5-4.74-2.85", key: "1o9zyk" }],
125
+ ["path", { d: "m7 16.5 5-3", key: "va8pkn" }],
126
+ ["path", { d: "M7 16.5v5.17", key: "jnp8gn" }],
127
+ [
128
+ "path",
129
+ {
130
+ d: "M12 13.5V19l3.97 2.38a2 2 0 0 0 2.06 0l3-1.8a2 2 0 0 0 .97-1.71v-3.24a2 2 0 0 0-.97-1.71L17 10.5l-5 3Z",
131
+ key: "8zsnat"
132
+ }
133
+ ],
134
+ ["path", { d: "m17 16.5-5-3", key: "8arw3v" }],
135
+ ["path", { d: "m17 16.5 4.74-2.85", key: "8rfmw" }],
136
+ ["path", { d: "M17 16.5v5.17", key: "k6z78m" }],
137
+ [
138
+ "path",
139
+ {
140
+ d: "M7.97 4.42A2 2 0 0 0 7 6.13v4.37l5 3 5-3V6.13a2 2 0 0 0-.97-1.71l-3-1.8a2 2 0 0 0-2.06 0l-3 1.8Z",
141
+ key: "1xygjf"
142
+ }
143
+ ],
144
+ ["path", { d: "M12 8 7.26 5.15", key: "1vbdud" }],
145
+ ["path", { d: "m12 8 4.74-2.85", key: "3rx089" }],
146
+ ["path", { d: "M12 13.5V8", key: "1io7kd" }]
147
+ ], Ve = W("boxes", Ue);
148
+ /**
149
+ * @license lucide-react v0.511.0 - ISC
150
+ *
151
+ * This source code is licensed under the ISC license.
152
+ * See the LICENSE file in the root directory of this source tree.
153
+ */
154
+ const Ze = [
155
+ [
156
+ "path",
157
+ {
158
+ d: "M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0",
159
+ key: "1nclc0"
160
+ }
161
+ ],
162
+ ["circle", { cx: "12", cy: "12", r: "3", key: "1v7zrd" }]
163
+ ], Ke = W("eye", Ze);
164
+ /**
165
+ * @license lucide-react v0.511.0 - ISC
166
+ *
167
+ * This source code is licensed under the ISC license.
168
+ * See the LICENSE file in the root directory of this source tree.
169
+ */
170
+ const Qe = [
171
+ [
172
+ "path",
173
+ {
174
+ d: "M12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83z",
175
+ key: "zw3jo"
176
+ }
177
+ ],
178
+ [
179
+ "path",
180
+ {
181
+ d: "M2 12a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 12",
182
+ key: "1wduqc"
183
+ }
184
+ ],
185
+ [
186
+ "path",
187
+ {
188
+ d: "M2 17a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 17",
189
+ key: "kqbvx6"
190
+ }
191
+ ]
192
+ ], re = W("layers", Qe);
193
+ /**
194
+ * @license lucide-react v0.511.0 - ISC
195
+ *
196
+ * This source code is licensed under the ISC license.
197
+ * See the LICENSE file in the root directory of this source tree.
198
+ */
199
+ const Je = [
200
+ ["path", { d: "M12.75 7.09a3 3 0 0 1 2.16 2.16", key: "1d4wjd" }],
201
+ [
202
+ "path",
203
+ {
204
+ d: "M17.072 17.072c-1.634 2.17-3.527 3.912-4.471 4.727a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 1.432-4.568",
205
+ key: "12yil7"
206
+ }
207
+ ],
208
+ ["path", { d: "m2 2 20 20", key: "1ooewy" }],
209
+ ["path", { d: "M8.475 2.818A8 8 0 0 1 20 10c0 1.183-.31 2.377-.81 3.533", key: "lhrkcz" }],
210
+ ["path", { d: "M9.13 9.13a3 3 0 0 0 3.74 3.74", key: "13wojd" }]
211
+ ], et = W("map-pin-off", Je);
212
+ /**
213
+ * @license lucide-react v0.511.0 - ISC
214
+ *
215
+ * This source code is licensed under the ISC license.
216
+ * See the LICENSE file in the root directory of this source tree.
217
+ */
218
+ const tt = [
219
+ ["line", { x1: "2", x2: "22", y1: "2", y2: "22", key: "a6p6uj" }],
220
+ ["path", { d: "M18.89 13.23A7.12 7.12 0 0 0 19 12v-2", key: "80xlxr" }],
221
+ ["path", { d: "M5 10v2a7 7 0 0 0 12 5", key: "p2k8kg" }],
222
+ ["path", { d: "M15 9.34V5a3 3 0 0 0-5.68-1.33", key: "1gzdoj" }],
223
+ ["path", { d: "M9 9v3a3 3 0 0 0 5.12 2.12", key: "r2i35w" }],
224
+ ["line", { x1: "12", x2: "12", y1: "19", y2: "22", key: "x3vr5v" }]
225
+ ], nt = W("mic-off", tt);
226
+ /**
227
+ * @license lucide-react v0.511.0 - ISC
228
+ *
229
+ * This source code is licensed under the ISC license.
230
+ * See the LICENSE file in the root directory of this source tree.
231
+ */
232
+ const rt = [
233
+ ["path", { d: "M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z", key: "131961" }],
234
+ ["path", { d: "M19 10v2a7 7 0 0 1-14 0v-2", key: "1vc78b" }],
235
+ ["line", { x1: "12", x2: "12", y1: "19", y2: "22", key: "x3vr5v" }]
236
+ ], ot = W("mic", rt);
237
+ function ie({
238
+ presets: e,
239
+ value: t,
240
+ onChange: o
241
+ }) {
242
+ return /* @__PURE__ */ r("div", { className: "flex items-center gap-1 border border-border rounded-md p-0.5 bg-background", children: e.map(({ id: n, label: a }) => /* @__PURE__ */ r(
243
+ "button",
244
+ {
245
+ type: "button",
246
+ onClick: () => o(n),
247
+ className: `px-2 py-0.5 rounded text-[10px] font-medium transition-colors ${t === n ? "bg-primary/10 text-primary" : "text-foreground-subtle hover:text-foreground"}`,
248
+ children: a
249
+ },
250
+ n
251
+ )) });
252
+ }
253
+ function ce(e = 0) {
254
+ const t = K(null), [o, n] = H(0);
255
+ return ge(() => {
256
+ const a = t.current;
257
+ if (!a) return;
258
+ const s = (l) => n(Math.max(e, Math.floor(l)));
259
+ s(a.clientWidth);
260
+ const d = new ResizeObserver((l) => {
261
+ const f = l[0];
262
+ f && s(f.contentRect.width);
263
+ });
264
+ return d.observe(a), () => d.disconnect();
265
+ }, [e]), [t, o];
266
+ }
267
+ function st(e, t) {
268
+ const o = new Date(e), n = String(o.getHours()).padStart(2, "0"), a = String(o.getMinutes()).padStart(2, "0");
269
+ if (t <= 1440 * 60 * 1e3) return `${n}:${a}`;
270
+ const s = String(o.getDate()).padStart(2, "0"), d = String(o.getMonth() + 1).padStart(2, "0");
271
+ return `${s}/${d} ${n}:${a}`;
272
+ }
273
+ function Fe(e, t, o, n, a) {
274
+ if (t <= 1) return n;
275
+ const s = o - n - a;
276
+ return n + e / (t - 1) * s;
277
+ }
278
+ function ve(e, t, o, n, a, s) {
279
+ if (t <= e) return [];
280
+ const d = t - e, l = [], f = o - n - a;
281
+ for (let u = 0; u < s; u++) {
282
+ const k = u / Math.max(1, s - 1), $ = e + d * k;
283
+ l.push({
284
+ x: n + k * f,
285
+ label: st($, d)
286
+ });
287
+ }
288
+ return l;
289
+ }
290
+ const Me = [
291
+ "#3b82f6",
292
+ // blue-500
293
+ "#a855f7",
294
+ // purple-500
295
+ "#10b981",
296
+ // emerald-500
297
+ "#f59e0b",
298
+ // amber-500
299
+ "#ec4899",
300
+ // pink-500
301
+ "#14b8a6",
302
+ // teal-500
303
+ "#6366f1",
304
+ // indigo-500
305
+ "#ef4444"
306
+ // red-500
307
+ ];
308
+ function pe(e) {
309
+ return Me[e % Me.length] ?? "#64748b";
310
+ }
311
+ function de() {
312
+ const [e, t] = H(null);
313
+ return { state: e, bindHover: t };
314
+ }
315
+ function ue({ state: e, containerWidth: t }) {
316
+ if (!e) return null;
317
+ const n = 220 / 2, a = n + 4, s = Math.max(a, t - n - 4), d = Math.max(a, Math.min(s, e.anchorX)), l = e.anchorX - d;
318
+ return /* @__PURE__ */ i(
319
+ "div",
320
+ {
321
+ role: "tooltip",
322
+ style: {
323
+ position: "absolute",
324
+ left: d,
325
+ top: e.anchorY,
326
+ transform: "translate(-50%, calc(-100% - 8px))",
327
+ pointerEvents: "none"
328
+ },
329
+ className: "z-10 rounded-md border border-border bg-surface shadow-lg px-2.5 py-1.5 text-[10px] text-foreground min-w-[140px] max-w-[240px]",
330
+ children: [
331
+ /* @__PURE__ */ r("div", { className: "font-semibold mb-1 truncate", children: e.title }),
332
+ /* @__PURE__ */ r("div", { className: "space-y-0.5", children: e.rows.map((f, u) => /* @__PURE__ */ i("div", { className: "flex items-center justify-between gap-2", children: [
333
+ /* @__PURE__ */ i("span", { className: "flex items-center gap-1 text-foreground-subtle truncate", children: [
334
+ f.colour && /* @__PURE__ */ r("span", { className: "inline-block h-1.5 w-1.5 rounded-sm flex-shrink-0", style: { backgroundColor: f.colour } }),
335
+ /* @__PURE__ */ r("span", { className: "truncate", children: f.label })
336
+ ] }),
337
+ /* @__PURE__ */ r("span", { className: "tabular-nums", children: f.value })
338
+ ] }, u)) }),
339
+ /* @__PURE__ */ r(
340
+ "span",
341
+ {
342
+ "aria-hidden": !0,
343
+ style: { left: `calc(50% + ${l}px)` },
344
+ className: "absolute -bottom-1 -translate-x-1/2 h-2 w-2 rotate-45 bg-surface border-r border-b border-border"
345
+ }
346
+ )
347
+ ]
348
+ }
349
+ );
350
+ }
351
+ const J = {
352
+ "5m": { label: "5 min", windowSec: 300, sampleEveryMs: 1e3, pollIntervalMs: 5e3 },
353
+ "1h": { label: "1 h", windowSec: 3600, sampleEveryMs: 5e3, pollIntervalMs: 3e4 },
354
+ "24h": { label: "24 h", windowSec: 1440 * 60, sampleEveryMs: 6e4, pollIntervalMs: 3e5 }
355
+ }, at = [
356
+ { id: "5m", label: J["5m"].label },
357
+ { id: "1h", label: J["1h"].label },
358
+ { id: "24h", label: J["24h"].label }
359
+ ], G = 140, S = { top: 16, right: 12, bottom: 24, left: 38 }, lt = {
360
+ speech: "#3b82f6",
361
+ music: "#a855f7",
362
+ dog_bark: "#ec4899",
363
+ glass_break: "#f43f5e",
364
+ alarm: "#f59e0b",
365
+ baby_cry: "#10b981"
366
+ };
367
+ function $e(e) {
368
+ return e ? lt[e.toLowerCase()] ?? "#6366f1" : "#71717a";
369
+ }
370
+ function it({ deviceId: e }) {
371
+ const t = z(), o = Q(t.trpcClient, e), [n, a] = H("5m"), s = J[n], [d, l] = ce(), f = de(), u = K(null), k = (m) => {
372
+ const h = u.current;
373
+ if (!h) return m;
374
+ const g = h.getBoundingClientRect();
375
+ return g.width === 0 ? m : m / l * g.width;
376
+ }, $ = le({
377
+ queryKey: ["audio-metrics", e, "history", n],
378
+ queryFn: async () => o ? await o.audioMetrics?.getHistory({
379
+ windowSec: s.windowSec,
380
+ sampleEveryMs: s.sampleEveryMs
381
+ }) ?? null : null,
382
+ enabled: !!o,
383
+ refetchInterval: s.pollIntervalMs,
384
+ staleTime: Math.max(1e3, s.pollIntervalMs / 2)
385
+ }), F = $.data, b = F?.points ?? [], x = N(() => ut(b), [b]), C = N(() => ct(b, l, x), [b, l, x]), y = N(() => dt(b, l, x), [b, l, x]), L = N(() => ht(x), [x]), D = N(() => mt(b, l), [b, l]);
386
+ return /* @__PURE__ */ i("div", { className: "rounded-lg border border-border bg-surface overflow-hidden", children: [
387
+ /* @__PURE__ */ i("div", { className: "border-b border-border px-4 py-2 flex items-center justify-between gap-3", children: [
388
+ /* @__PURE__ */ i("div", { className: "flex items-center gap-1.5", children: [
389
+ /* @__PURE__ */ r(Z, { className: "h-3.5 w-3.5 text-foreground-subtle" }),
390
+ /* @__PURE__ */ r("h2", { className: "text-xs font-semibold text-foreground uppercase tracking-wider", children: "Audio Level History" })
391
+ ] }),
392
+ /* @__PURE__ */ r(ie, { presets: at, value: n, onChange: a })
393
+ ] }),
394
+ /* @__PURE__ */ i("div", { ref: d, className: "p-3 min-w-0 relative", children: [
395
+ b.length === 0 ? /* @__PURE__ */ r("div", { className: "flex items-center justify-center h-32 text-[11px] text-foreground-subtle italic", children: $.isLoading ? "Loading…" : "No audio history yet — analytics pipeline must be active." }) : l === 0 ? /* @__PURE__ */ r("div", { className: "h-32" }) : /* @__PURE__ */ i(ae, { children: [
396
+ /* @__PURE__ */ i(
397
+ "svg",
398
+ {
399
+ ref: u,
400
+ role: "img",
401
+ "aria-label": "Audio dBFS history",
402
+ width: "100%",
403
+ height: G,
404
+ viewBox: `0 0 ${l} ${G}`,
405
+ preserveAspectRatio: "none",
406
+ className: "block",
407
+ onMouseLeave: () => f.bindHover(null),
408
+ children: [
409
+ L.map(({ y: m, label: h }, g) => /* @__PURE__ */ i("g", { children: [
410
+ /* @__PURE__ */ r("line", { x1: S.left, x2: l - S.right, y1: m, y2: m, stroke: "currentColor", strokeOpacity: 0.08, strokeWidth: 0.5 }),
411
+ /* @__PURE__ */ r("text", { x: S.left - 6, y: m + 3, textAnchor: "end", className: "text-[9px] fill-foreground-subtle", children: h })
412
+ ] }, `y-${g}`)),
413
+ D.map(({ x: m, label: h }, g) => /* @__PURE__ */ r("text", { x: m, y: G - S.bottom + 12, textAnchor: "middle", className: "text-[9px] fill-foreground-subtle", children: h }, `x-${g}`)),
414
+ y && /* @__PURE__ */ r("path", { d: y, fill: "none", stroke: "currentColor", strokeOpacity: 0.25, strokeWidth: 1, strokeDasharray: "3 2" }),
415
+ C && /* @__PURE__ */ r("path", { d: C, fill: "none", stroke: "currentColor", className: "text-primary", strokeWidth: 1.5 }),
416
+ b.map((m, h) => {
417
+ if (m.topClass === null) return null;
418
+ const g = oe(h, b.length, l), _ = be(m.dbfs, x);
419
+ return /* @__PURE__ */ r(
420
+ "circle",
421
+ {
422
+ cx: g,
423
+ cy: _,
424
+ r: 3,
425
+ fill: $e(m.topClass),
426
+ stroke: "#000",
427
+ strokeOpacity: 0.3,
428
+ strokeWidth: 0.5
429
+ },
430
+ `dot-${h}`
431
+ );
432
+ }),
433
+ b.map((m, h) => {
434
+ const g = oe(h, b.length, l), _ = be(m.dbfs, x), p = G - S.top - S.bottom, v = b.length > 1 ? (l - S.left - S.right) / (b.length - 1) : 24;
435
+ return /* @__PURE__ */ r(
436
+ "rect",
437
+ {
438
+ x: g - v / 2,
439
+ y: S.top,
440
+ width: Math.max(2, v),
441
+ height: p,
442
+ fill: "transparent",
443
+ onMouseEnter: () => {
444
+ f.bindHover({
445
+ anchorX: k(g),
446
+ anchorY: _,
447
+ title: `${Te(m.ts)} · ${m.dbfs?.toFixed(1) ?? "—"} dB`,
448
+ rows: [
449
+ { label: "peak (window)", value: `${m.peakDbfs.toFixed(1)} dB` },
450
+ { label: "avg (window)", value: `${m.avgDbfs.toFixed(1)} dB` },
451
+ ...m.topClass !== null ? [{
452
+ label: m.topClass,
453
+ value: m.topScore != null ? `${(m.topScore * 100).toFixed(0)}%` : "—",
454
+ colour: $e(m.topClass)
455
+ }] : []
456
+ ]
457
+ });
458
+ }
459
+ },
460
+ `hit-${h}`
461
+ );
462
+ })
463
+ ]
464
+ }
465
+ ),
466
+ /* @__PURE__ */ r(ue, { state: f.state, containerWidth: l })
467
+ ] }),
468
+ b.length > 0 && /* @__PURE__ */ i("div", { className: "flex items-center justify-between text-[10px] text-foreground-subtle mt-1", children: [
469
+ /* @__PURE__ */ i("span", { children: [
470
+ b.length,
471
+ " samples · ~",
472
+ Math.round((F?.effectiveSampleEveryMs ?? s.sampleEveryMs) / 1e3),
473
+ "s spacing"
474
+ ] }),
475
+ /* @__PURE__ */ i("span", { children: [
476
+ "peak ",
477
+ b.reduce((m, h) => Math.max(m, h.peakDbfs), -1 / 0).toFixed(1),
478
+ " dB"
479
+ ] })
480
+ ] })
481
+ ] })
482
+ ] });
483
+ }
484
+ function oe(e, t, o) {
485
+ if (t <= 1) return S.left;
486
+ const n = o - S.left - S.right;
487
+ return S.left + e / (t - 1) * n;
488
+ }
489
+ function be(e, t) {
490
+ return e === null || !Number.isFinite(e) ? se(t.min, t) : se(Math.max(t.min, Math.min(t.max, e)), t);
491
+ }
492
+ function se(e, t) {
493
+ const o = G - S.top - S.bottom, n = Math.max(1, t.max - t.min), a = (e - t.min) / n;
494
+ return S.top + (1 - a) * o;
495
+ }
496
+ function ct(e, t, o) {
497
+ if (e.length === 0) return null;
498
+ const n = [];
499
+ for (let a = 0; a < e.length; a++) {
500
+ const s = oe(a, e.length, t), d = be(e[a].dbfs, o);
501
+ n.push(`${a === 0 ? "M" : "L"} ${s.toFixed(1)} ${d.toFixed(1)}`);
502
+ }
503
+ return n.join(" ");
504
+ }
505
+ function dt(e, t, o) {
506
+ if (e.length === 0) return null;
507
+ const n = [];
508
+ for (let a = 0; a < e.length; a++) {
509
+ const s = oe(a, e.length, t), d = se(Math.max(o.min, Math.min(o.max, e[a].peakDbfs)), o);
510
+ n.push(`${a === 0 ? "M" : "L"} ${s.toFixed(1)} ${d.toFixed(1)}`);
511
+ }
512
+ return n.join(" ");
513
+ }
514
+ function ut(e) {
515
+ if (e.length === 0) return { min: -80, max: -40 };
516
+ let t = Number.POSITIVE_INFINITY, o = Number.NEGATIVE_INFINITY;
517
+ for (const s of e)
518
+ s.dbfs !== null && Number.isFinite(s.dbfs) && (t = Math.min(t, s.dbfs), o = Math.max(o, s.dbfs)), Number.isFinite(s.peakDbfs) && (t = Math.min(t, s.peakDbfs), o = Math.max(o, s.peakDbfs));
519
+ if (!Number.isFinite(t) || !Number.isFinite(o)) return { min: -80, max: -40 };
520
+ let n = Math.max(-100, Math.floor(t - 1)), a = Math.min(0, Math.ceil(o));
521
+ return a - n < 5 && (n = Math.max(-100, a - 5)), { min: n, max: a };
522
+ }
523
+ function ht(e) {
524
+ const t = [];
525
+ for (let o = 0; o < 4; o++) {
526
+ const n = o / 3, a = e.min + (e.max - e.min) * n;
527
+ t.push({
528
+ y: se(a, e),
529
+ label: `${Math.round(a)}`
530
+ });
531
+ }
532
+ return t;
533
+ }
534
+ function mt(e, t) {
535
+ if (e.length === 0) return [];
536
+ const o = e[0], n = e[e.length - 1], a = [], s = Math.min(5, e.length);
537
+ for (let d = 0; d < s; d++) {
538
+ const l = d / Math.max(1, s - 1), f = o.ts + (n.ts - o.ts) * l;
539
+ a.push({
540
+ x: S.left + l * (t - S.left - S.right),
541
+ label: Te(f)
542
+ });
543
+ }
544
+ return a;
545
+ }
546
+ function Te(e) {
547
+ const t = new Date(e), o = String(t.getHours()).padStart(2, "0"), n = String(t.getMinutes()).padStart(2, "0");
548
+ return `${o}:${n}`;
549
+ }
550
+ function xe(e) {
551
+ return !Number.isFinite(e) || e <= 0 ? 60 : e > 600 ? Math.round(e / 1e3) : Math.round(e);
552
+ }
553
+ function ft({
554
+ dev: e,
555
+ deviceId: t,
556
+ title: o = "Audio Metrics",
557
+ variant: n = "full"
558
+ }) {
559
+ const a = z(), s = Be(
560
+ a.trpcClient,
561
+ e === void 0 && t !== void 0 ? t : null,
562
+ (f) => f.audioMetrics
563
+ ), d = ye(
564
+ e ? e.state.audioMetrics : void 0
565
+ ), l = e !== void 0 ? d : s;
566
+ return l ? /* @__PURE__ */ r(Ce, { title: o, variant: n, ts: l.ts, children: /* @__PURE__ */ i("div", { className: n === "compact" ? "space-y-2" : "grid grid-cols-1 2xl:grid-cols-3 gap-3", children: [
567
+ /* @__PURE__ */ r(bt, { snapshot: l }),
568
+ /* @__PURE__ */ r(xt, { snapshot: l }),
569
+ /* @__PURE__ */ r(gt, { snapshot: l })
570
+ ] }) }) : /* @__PURE__ */ r(Ce, { title: o, variant: n, children: /* @__PURE__ */ r(
571
+ pt,
572
+ {
573
+ icon: /* @__PURE__ */ r(nt, { className: "h-5 w-5 mb-2 opacity-30" }),
574
+ message: e || t !== void 0 ? "No audio data yet — analytics pipeline must be active and audio enabled for this device." : "Resolving device…"
575
+ }
576
+ ) });
577
+ }
578
+ function Ce({ title: e, variant: t, ts: o, children: n }) {
579
+ const a = o ? Math.max(0, Math.floor((Date.now() - o) / 1e3)) : null;
580
+ return /* @__PURE__ */ i("div", { className: t === "compact" ? "rounded-md border border-border/60 bg-surface/60 p-3" : "rounded-lg border border-border bg-surface overflow-hidden", children: [
581
+ /* @__PURE__ */ i("div", { className: t === "compact" ? "flex items-center justify-between mb-2" : "border-b border-border px-4 py-2 flex items-center justify-between", children: [
582
+ /* @__PURE__ */ r("h2", { className: "text-xs font-semibold text-foreground uppercase tracking-wider", children: e }),
583
+ a !== null && /* @__PURE__ */ r("span", { className: "text-[10px] text-foreground-subtle", children: a === 0 ? "just now" : `${a}s ago` })
584
+ ] }),
585
+ /* @__PURE__ */ r("div", { className: t === "compact" ? "" : "p-3", children: n })
586
+ ] });
587
+ }
588
+ function pt({ icon: e, message: t }) {
589
+ return /* @__PURE__ */ i("div", { className: "px-4 py-6 flex flex-col items-center text-center text-foreground-subtle", children: [
590
+ e,
591
+ /* @__PURE__ */ r("p", { className: "text-[11px]", children: t })
592
+ ] });
593
+ }
594
+ function bt({ snapshot: e }) {
595
+ const { dbfs: t } = e.level, o = Number.isFinite(t) ? t : -80, n = Math.max(-80, Math.min(0, o)), a = (n + 80) / 80 * 100, s = n > -10 ? "bg-danger" : n > -25 ? "bg-warning" : "bg-primary";
596
+ return /* @__PURE__ */ i("div", { className: "rounded-md border border-border/60 bg-background/40 px-3 py-2", children: [
597
+ /* @__PURE__ */ i("div", { className: "flex items-center gap-1.5 mb-1.5 text-[11px] uppercase tracking-wider text-foreground-subtle", children: [
598
+ /* @__PURE__ */ r(Z, { className: "h-3.5 w-3.5" }),
599
+ /* @__PURE__ */ r("span", { children: "Level" }),
600
+ /* @__PURE__ */ r("span", { className: "ml-auto text-base font-semibold text-foreground tabular-nums normal-case tracking-normal", children: Number.isFinite(t) ? `${t.toFixed(1)} dB` : "silent" })
601
+ ] }),
602
+ /* @__PURE__ */ r("div", { className: "h-1.5 rounded-full bg-foreground-subtle/15 overflow-hidden", children: /* @__PURE__ */ r(
603
+ "div",
604
+ {
605
+ className: `h-full ${s} transition-all`,
606
+ style: { width: `${a}%` }
607
+ }
608
+ ) }),
609
+ /* @__PURE__ */ i("div", { className: "flex justify-between text-[9px] text-foreground-subtle mt-1 tabular-nums", children: [
610
+ /* @__PURE__ */ i("span", { children: [
611
+ "peak ",
612
+ Number.isFinite(e.peakDbfs) ? e.peakDbfs.toFixed(1) : "—",
613
+ " dB"
614
+ ] }),
615
+ /* @__PURE__ */ i("span", { children: [
616
+ "avg ",
617
+ e.avgDbfs.toFixed(1),
618
+ " dB"
619
+ ] }),
620
+ /* @__PURE__ */ i("span", { children: [
621
+ xe(e.windowSec),
622
+ "s window"
623
+ ] })
624
+ ] })
625
+ ] });
626
+ }
627
+ function xt({ snapshot: e }) {
628
+ const { current: t } = e;
629
+ return /* @__PURE__ */ i("div", { className: "rounded-md border border-border/60 bg-background/40 px-3 py-2", children: [
630
+ /* @__PURE__ */ i("div", { className: "flex items-center gap-1.5 mb-1.5 text-[11px] uppercase tracking-wider text-foreground-subtle", children: [
631
+ /* @__PURE__ */ r(ot, { className: "h-3.5 w-3.5" }),
632
+ /* @__PURE__ */ r("span", { children: "Now" })
633
+ ] }),
634
+ t ? /* @__PURE__ */ i("div", { className: "flex flex-col gap-1", children: [
635
+ /* @__PURE__ */ r("span", { className: "text-sm font-semibold text-foreground", children: t.className }),
636
+ /* @__PURE__ */ i("span", { className: "text-[10px] text-foreground-subtle tabular-nums", children: [
637
+ "score ",
638
+ (t.score * 100).toFixed(0),
639
+ "% — ",
640
+ Math.max(0, Math.floor((Date.now() - t.timestamp) / 1e3)),
641
+ "s ago"
642
+ ] })
643
+ ] }) : /* @__PURE__ */ r("span", { className: "text-[10px] text-foreground-subtle italic", children: "silence / unclassified" })
644
+ ] });
645
+ }
646
+ function gt({ snapshot: e }) {
647
+ return e.byClass.length === 0 ? /* @__PURE__ */ i("div", { className: "rounded-md border border-border/40 bg-background/20 px-3 py-2", children: [
648
+ /* @__PURE__ */ i("div", { className: "flex items-center gap-1.5 mb-1.5 text-[11px] uppercase tracking-wider text-foreground-subtle", children: [
649
+ /* @__PURE__ */ r(Z, { className: "h-3.5 w-3.5" }),
650
+ /* @__PURE__ */ i("span", { children: [
651
+ "Last ",
652
+ xe(e.windowSec),
653
+ "s"
654
+ ] })
655
+ ] }),
656
+ /* @__PURE__ */ r("span", { className: "text-[10px] text-foreground-subtle italic", children: "no classified audio" })
657
+ ] }) : /* @__PURE__ */ i("div", { className: "rounded-md border border-border/60 bg-background/40", children: [
658
+ /* @__PURE__ */ i("div", { className: "px-3 py-1.5 border-b border-border/40 flex items-center gap-1.5 text-[11px] uppercase tracking-wider text-foreground-subtle", children: [
659
+ /* @__PURE__ */ r(Z, { className: "h-3.5 w-3.5" }),
660
+ /* @__PURE__ */ i("span", { children: [
661
+ "Last ",
662
+ xe(e.windowSec),
663
+ "s"
664
+ ] }),
665
+ /* @__PURE__ */ r("span", { className: "ml-auto text-[10px] normal-case tracking-normal", children: e.byClass.length })
666
+ ] }),
667
+ /* @__PURE__ */ r("div", { className: "divide-y divide-border/30", children: e.byClass.slice(0, 8).map((t) => /* @__PURE__ */ i("div", { className: "px-3 py-1.5 flex items-center justify-between text-xs", children: [
668
+ /* @__PURE__ */ r("span", { className: "font-medium text-foreground truncate", children: t.className }),
669
+ /* @__PURE__ */ i("span", { className: "flex items-center gap-2 tabular-nums text-foreground-subtle", children: [
670
+ /* @__PURE__ */ i("span", { children: [
671
+ t.hits,
672
+ "× hits"
673
+ ] }),
674
+ /* @__PURE__ */ i("span", { className: "rounded-full px-1.5 py-0.5 text-[10px] bg-primary/10 text-primary border border-primary/20", children: [
675
+ (t.peakScore * 100).toFixed(0),
676
+ "%"
677
+ ] })
678
+ ] })
679
+ ] }, t.className)) })
680
+ ] });
681
+ }
682
+ const ee = {
683
+ "5m": { label: "5 min", windowMs: 5 * 6e4, resolution: "minute", pollIntervalMs: 5e3 },
684
+ "30m": { label: "30 min", windowMs: 30 * 6e4, resolution: "minute", pollIntervalMs: 15e3 },
685
+ "1h": { label: "1 h", windowMs: 60 * 6e4, resolution: "5min", pollIntervalMs: 3e4 }
686
+ }, yt = [
687
+ { id: "5m", label: ee["5m"].label },
688
+ { id: "30m", label: ee["30m"].label },
689
+ { id: "1h", label: ee["1h"].label }
690
+ ], P = 140, M = { top: 14, right: 12, bottom: 24, left: 32 }, R = "__all__";
691
+ function vt({ deviceId: e }) {
692
+ const t = z(), o = Q(t.trpcClient, e), [n, a] = H("5m"), [s, d] = H(R), l = ee[n], [f, u] = ce(), k = de(), $ = K(null), F = (p) => {
693
+ const v = $.current;
694
+ if (!v) return p;
695
+ const c = v.getBoundingClientRect();
696
+ return c.width === 0 ? p : p / u * c.width;
697
+ }, b = ye(o?.state.zoneAnalytics), x = N(() => {
698
+ const p = /* @__PURE__ */ new Set();
699
+ if (b?.frame.byClass)
700
+ for (const v of Object.keys(b.frame.byClass)) p.add(v);
701
+ if (b?.zones)
702
+ for (const v of b.zones)
703
+ for (const c of Object.keys(v.byClass)) p.add(c);
704
+ return [...p].sort();
705
+ }, [b]);
706
+ ge(() => {
707
+ s !== R && !x.includes(s) && d(R);
708
+ }, [s, x]);
709
+ const C = le({
710
+ queryKey: ["zone-analytics", e, "cameraHistory", n, s],
711
+ queryFn: async () => {
712
+ if (!o) return [];
713
+ const p = Date.now();
714
+ return await o.zoneAnalytics?.getCameraHistory({
715
+ from: p - l.windowMs,
716
+ to: p,
717
+ resolution: l.resolution,
718
+ ...s === R ? {} : { className: s }
719
+ }) ?? [];
720
+ },
721
+ enabled: !!o,
722
+ refetchInterval: l.pollIntervalMs,
723
+ staleTime: Math.max(1e3, l.pollIntervalMs / 2)
724
+ }), y = C.data ?? [], L = C.dataUpdatedAt > 0 ? C.dataUpdatedAt : Date.now(), D = L - l.windowMs, m = N(() => {
725
+ if (y.length === 0) return 1;
726
+ const p = y.reduce((v, c) => Math.max(v, c.count), 0);
727
+ return Math.max(1, Math.ceil(p * 1.15));
728
+ }, [y]), h = N(
729
+ () => wt(y, u, m),
730
+ [y, u, m]
731
+ ), g = N(
732
+ () => ve(D, L, u, M.left, M.right, 5),
733
+ [D, L, u]
734
+ ), _ = N(() => kt(m), [m]);
735
+ return /* @__PURE__ */ i("div", { className: "rounded-lg border border-border bg-surface overflow-hidden", children: [
736
+ /* @__PURE__ */ i("div", { className: "border-b border-border px-4 py-2 flex items-center justify-between gap-3", children: [
737
+ /* @__PURE__ */ i("div", { className: "flex items-center gap-1.5", children: [
738
+ /* @__PURE__ */ r(re, { className: "h-3.5 w-3.5 text-foreground-subtle" }),
739
+ /* @__PURE__ */ r("h2", { className: "text-xs font-semibold text-foreground uppercase tracking-wider", children: "Occupancy History" })
740
+ ] }),
741
+ /* @__PURE__ */ i("div", { className: "flex items-center gap-2", children: [
742
+ x.length > 0 && /* @__PURE__ */ i(
743
+ "select",
744
+ {
745
+ value: s,
746
+ onChange: (p) => d(p.target.value),
747
+ className: "text-[10px] px-1.5 py-0.5 rounded border border-border bg-background text-foreground focus:outline-none focus:ring-1 focus:ring-primary/40",
748
+ title: "Filter by detected class",
749
+ children: [
750
+ /* @__PURE__ */ r("option", { value: R, children: "All classes" }),
751
+ x.map((p) => /* @__PURE__ */ r("option", { value: p, children: p }, p))
752
+ ]
753
+ }
754
+ ),
755
+ /* @__PURE__ */ r(ie, { presets: yt, value: n, onChange: a })
756
+ ] })
757
+ ] }),
758
+ /* @__PURE__ */ i("div", { ref: f, className: "p-3 min-w-0 relative", children: [
759
+ y.length === 0 ? /* @__PURE__ */ r("div", { className: "flex items-center justify-center h-32 text-[11px] text-foreground-subtle italic", children: C.isLoading ? "Loading…" : "No occupancy history yet — analytics pipeline must be active." }) : u === 0 ? /* @__PURE__ */ r("div", { className: "h-32" }) : /* @__PURE__ */ i(ae, { children: [
760
+ /* @__PURE__ */ i(
761
+ "svg",
762
+ {
763
+ ref: $,
764
+ role: "img",
765
+ "aria-label": "Frame occupancy history",
766
+ width: "100%",
767
+ height: P,
768
+ viewBox: `0 0 ${u} ${P}`,
769
+ preserveAspectRatio: "none",
770
+ className: "block",
771
+ onMouseLeave: () => k.bindHover(null),
772
+ children: [
773
+ _.map(({ y: p, label: v }, c) => /* @__PURE__ */ i("g", { children: [
774
+ /* @__PURE__ */ r("line", { x1: M.left, x2: u - M.right, y1: p, y2: p, stroke: "currentColor", strokeOpacity: 0.08, strokeWidth: 0.5 }),
775
+ /* @__PURE__ */ r("text", { x: M.left - 6, y: p + 3, textAnchor: "end", className: "text-[9px] fill-foreground-subtle", children: v })
776
+ ] }, `y-${c}`)),
777
+ g.map(({ x: p, label: v }, c) => /* @__PURE__ */ r("text", { x: p, y: P - M.bottom + 12, textAnchor: "middle", className: "text-[9px] fill-foreground-subtle", children: v }, `x-${c}`)),
778
+ h && /* @__PURE__ */ r("path", { d: h, fill: "none", stroke: "currentColor", className: "text-primary", strokeWidth: 1.5 }),
779
+ y.map((p, v) => {
780
+ const c = Fe(v, y.length, u, M.left, M.right), w = Le(p.count, m), I = P - M.top - M.bottom, O = y.length > 1 ? (u - M.left - M.right) / (y.length - 1) : 24;
781
+ return /* @__PURE__ */ i("g", { children: [
782
+ /* @__PURE__ */ r("circle", { cx: c, cy: w, r: 2, fill: "currentColor", className: "text-primary" }),
783
+ /* @__PURE__ */ r(
784
+ "rect",
785
+ {
786
+ x: c - O / 2,
787
+ y: M.top,
788
+ width: Math.max(2, O),
789
+ height: I,
790
+ fill: "transparent",
791
+ onMouseEnter: () => {
792
+ k.bindHover({
793
+ anchorX: F(c),
794
+ anchorY: w,
795
+ title: `${Nt(p.ts)} · ${p.count} object${p.count === 1 ? "" : "s"}`,
796
+ rows: [
797
+ { label: "Class", value: s === R ? "all" : s },
798
+ { label: "Bucket", value: l.resolution }
799
+ ]
800
+ });
801
+ }
802
+ }
803
+ )
804
+ ] }, `${p.ts}-${v}`);
805
+ })
806
+ ]
807
+ }
808
+ ),
809
+ /* @__PURE__ */ r(ue, { state: k.state, containerWidth: u })
810
+ ] }),
811
+ y.length > 0 && /* @__PURE__ */ i("div", { className: "flex items-center justify-between text-[10px] text-foreground-subtle mt-1", children: [
812
+ /* @__PURE__ */ i("span", { children: [
813
+ y.length,
814
+ " bucket",
815
+ y.length === 1 ? "" : "s",
816
+ " · ",
817
+ l.resolution,
818
+ " resolution"
819
+ ] }),
820
+ /* @__PURE__ */ i("span", { children: [
821
+ "peak ",
822
+ y.reduce((p, v) => Math.max(p, v.count), 0),
823
+ " obj"
824
+ ] })
825
+ ] })
826
+ ] })
827
+ ] });
828
+ }
829
+ function Le(e, t) {
830
+ const o = P - M.top - M.bottom, n = Math.min(1, e / t);
831
+ return M.top + (1 - n) * o;
832
+ }
833
+ function wt(e, t, o) {
834
+ if (e.length === 0) return null;
835
+ const n = [];
836
+ for (let a = 0; a < e.length; a++) {
837
+ const s = Fe(a, e.length, t, M.left, M.right), d = Le(e[a].count, o);
838
+ n.push(`${a === 0 ? "M" : "L"} ${s.toFixed(1)} ${d.toFixed(1)}`);
839
+ }
840
+ return n.join(" ");
841
+ }
842
+ function kt(e) {
843
+ const t = [];
844
+ for (let o = 0; o < 4; o++) {
845
+ const n = o / 3, a = Math.round(e * n), s = P - M.top - M.bottom;
846
+ t.push({
847
+ y: M.top + (1 - n) * s,
848
+ label: `${a}`
849
+ });
850
+ }
851
+ return t;
852
+ }
853
+ function Nt(e) {
854
+ const t = new Date(e), o = String(t.getHours()).padStart(2, "0"), n = String(t.getMinutes()).padStart(2, "0");
855
+ return `${o}:${n}`;
856
+ }
857
+ const te = {
858
+ "1h": { label: "1 h", windowMs: 60 * 6e4, bucketMs: 6e4, pollIntervalMs: 15e3 },
859
+ "6h": { label: "6 h", windowMs: 360 * 6e4, bucketMs: 5 * 6e4, pollIntervalMs: 6e4 },
860
+ "24h": { label: "24 h", windowMs: 1440 * 6e4, bucketMs: 15 * 6e4, pollIntervalMs: 3e5 }
861
+ }, Mt = [
862
+ { id: "1h", label: te["1h"].label },
863
+ { id: "6h", label: te["6h"].label },
864
+ { id: "24h", label: te["24h"].label }
865
+ ], $t = 5e3, U = 140, T = { top: 14, right: 12, bottom: 24, left: 32 };
866
+ function Ct({ deviceId: e }) {
867
+ const t = z(), o = Q(t.trpcClient, e), [n, a] = H("1h"), s = te[n], [d, l] = ce(), f = de(), u = K(null), k = (h) => {
868
+ const g = u.current;
869
+ if (!g) return h;
870
+ const _ = g.getBoundingClientRect();
871
+ return _.width === 0 ? h : h / l * _.width;
872
+ }, $ = le({
873
+ queryKey: ["pipeline-analytics", e, "motionEvents", n],
874
+ queryFn: async () => {
875
+ if (!o) return [];
876
+ const h = Date.now() - s.windowMs;
877
+ return await o.pipelineAnalytics?.getMotionEvents({
878
+ since: h,
879
+ limit: $t
880
+ }) ?? [];
881
+ },
882
+ enabled: !!o,
883
+ refetchInterval: s.pollIntervalMs,
884
+ staleTime: Math.max(1e3, s.pollIntervalMs / 2)
885
+ }), F = $.data ?? [], b = $.dataUpdatedAt > 0 ? $.dataUpdatedAt : Date.now(), x = b - s.windowMs, C = N(
886
+ () => _t(F, x, b, s.bucketMs),
887
+ [F, x, b, s.bucketMs]
888
+ ), y = N(() => {
889
+ if (C.length === 0) return 1;
890
+ const h = C.reduce((g, _) => Math.max(g, _.count), 0);
891
+ return Math.max(1, Math.ceil(h * 1.15));
892
+ }, [C]), L = N(
893
+ () => ve(x, b, l, T.left, T.right, 5),
894
+ [x, b, l]
895
+ ), D = N(() => It(y), [y]), m = F.length;
896
+ return /* @__PURE__ */ i("div", { className: "rounded-lg border border-border bg-surface overflow-hidden", children: [
897
+ /* @__PURE__ */ i("div", { className: "border-b border-border px-4 py-2 flex items-center justify-between gap-3", children: [
898
+ /* @__PURE__ */ i("div", { className: "flex items-center gap-1.5", children: [
899
+ /* @__PURE__ */ r(Z, { className: "h-3.5 w-3.5 text-foreground-subtle" }),
900
+ /* @__PURE__ */ r("h2", { className: "text-xs font-semibold text-foreground uppercase tracking-wider", children: "Motion History" })
901
+ ] }),
902
+ /* @__PURE__ */ r(ie, { presets: Mt, value: n, onChange: a })
903
+ ] }),
904
+ /* @__PURE__ */ i("div", { ref: d, className: "p-3 min-w-0 relative", children: [
905
+ m === 0 ? /* @__PURE__ */ r("div", { className: "flex items-center justify-center h-32 text-[11px] text-foreground-subtle italic", children: $.isLoading ? "Loading…" : "No motion events in the selected window." }) : l === 0 ? /* @__PURE__ */ r("div", { className: "h-32" }) : /* @__PURE__ */ i(ae, { children: [
906
+ /* @__PURE__ */ i(
907
+ "svg",
908
+ {
909
+ ref: u,
910
+ role: "img",
911
+ "aria-label": "Motion event histogram",
912
+ width: "100%",
913
+ height: U,
914
+ viewBox: `0 0 ${l} ${U}`,
915
+ preserveAspectRatio: "none",
916
+ className: "block",
917
+ onMouseLeave: () => f.bindHover(null),
918
+ children: [
919
+ D.map(({ y: h, label: g }, _) => /* @__PURE__ */ i("g", { children: [
920
+ /* @__PURE__ */ r("line", { x1: T.left, x2: l - T.right, y1: h, y2: h, stroke: "currentColor", strokeOpacity: 0.08, strokeWidth: 0.5 }),
921
+ /* @__PURE__ */ r("text", { x: T.left - 6, y: h + 3, textAnchor: "end", className: "text-[9px] fill-foreground-subtle", children: g })
922
+ ] }, `y-${_}`)),
923
+ L.map(({ x: h, label: g }, _) => /* @__PURE__ */ r("text", { x: h, y: U - T.bottom + 12, textAnchor: "middle", className: "text-[9px] fill-foreground-subtle", children: g }, `x-${_}`)),
924
+ C.map((h, g) => {
925
+ const { x: _, w: p } = St(h.bucketStart, s.bucketMs, x, b, l), v = U - T.top - T.bottom, c = h.count / y * v, w = T.top + (v - c), I = h.bucketStart + s.bucketMs;
926
+ return /* @__PURE__ */ i("g", { children: [
927
+ h.count > 0 && /* @__PURE__ */ r(
928
+ "rect",
929
+ {
930
+ x: _,
931
+ y: w,
932
+ width: Math.max(1, p - 1),
933
+ height: Math.max(1, c),
934
+ fill: "currentColor",
935
+ className: "text-primary",
936
+ opacity: 0.85
937
+ }
938
+ ),
939
+ /* @__PURE__ */ r(
940
+ "rect",
941
+ {
942
+ x: _,
943
+ y: T.top,
944
+ width: Math.max(2, p),
945
+ height: v,
946
+ fill: "transparent",
947
+ onMouseEnter: () => {
948
+ f.bindHover({
949
+ anchorX: k(_ + p / 2),
950
+ anchorY: w,
951
+ title: `${At(h.bucketStart, I)} · ${h.count} event${h.count === 1 ? "" : "s"}`,
952
+ rows: [
953
+ { label: "Bucket", value: _e(s.bucketMs) },
954
+ { label: "Count", value: `${h.count}` }
955
+ ]
956
+ });
957
+ }
958
+ }
959
+ )
960
+ ] }, `${h.bucketStart}-${g}`);
961
+ })
962
+ ]
963
+ }
964
+ ),
965
+ /* @__PURE__ */ r(ue, { state: f.state, containerWidth: l })
966
+ ] }),
967
+ m > 0 && /* @__PURE__ */ i("div", { className: "flex items-center justify-between text-[10px] text-foreground-subtle mt-1", children: [
968
+ /* @__PURE__ */ i("span", { children: [
969
+ m,
970
+ " event",
971
+ m === 1 ? "" : "s",
972
+ " · ",
973
+ _e(s.bucketMs),
974
+ " buckets"
975
+ ] }),
976
+ /* @__PURE__ */ i("span", { children: [
977
+ "peak ",
978
+ C.reduce((h, g) => Math.max(h, g.count), 0),
979
+ "/bucket"
980
+ ] })
981
+ ] })
982
+ ] })
983
+ ] });
984
+ }
985
+ function _t(e, t, o, n) {
986
+ if (o <= t) return [];
987
+ const a = Math.floor(t / n) * n, s = Math.floor(o / n) * n, d = /* @__PURE__ */ new Map();
988
+ for (let l = a; l <= s; l += n)
989
+ d.set(l, 0);
990
+ for (const l of e) {
991
+ if (l.timestamp < t || l.timestamp > o) continue;
992
+ const f = Math.floor(l.timestamp / n) * n;
993
+ d.set(f, (d.get(f) ?? 0) + 1);
994
+ }
995
+ return [...d.entries()].sort(([l], [f]) => l - f).map(([l, f]) => ({ bucketStart: l, count: f }));
996
+ }
997
+ function St(e, t, o, n, a) {
998
+ const s = Math.max(1, n - o), d = a - T.left - T.right, l = T.left + (e - o) / s * d, f = t / s * d;
999
+ return { x: l, w: f };
1000
+ }
1001
+ function It(e) {
1002
+ const t = [];
1003
+ for (let o = 0; o < 4; o++) {
1004
+ const n = o / 3, a = Math.round(e * n), s = U - T.top - T.bottom;
1005
+ t.push({
1006
+ y: T.top + (1 - n) * s,
1007
+ label: `${a}`
1008
+ });
1009
+ }
1010
+ return t;
1011
+ }
1012
+ function At(e, t) {
1013
+ const o = (n) => {
1014
+ const a = new Date(n), s = String(a.getHours()).padStart(2, "0"), d = String(a.getMinutes()).padStart(2, "0");
1015
+ return `${s}:${d}`;
1016
+ };
1017
+ return `${o(e)}–${o(t)}`;
1018
+ }
1019
+ function _e(e) {
1020
+ return e >= 60 * 6e4 ? `${Math.round(e / 6e4 / 60)}h` : e >= 6e4 ? `${Math.round(e / 6e4)}m` : `${Math.round(e / 1e3)}s`;
1021
+ }
1022
+ const ne = {
1023
+ "1h": { label: "1 h", windowMs: 60 * 6e4, bucketMs: 6e4, pollIntervalMs: 15e3 },
1024
+ "6h": { label: "6 h", windowMs: 360 * 6e4, bucketMs: 5 * 6e4, pollIntervalMs: 6e4 },
1025
+ "24h": { label: "24 h", windowMs: 1440 * 6e4, bucketMs: 15 * 6e4, pollIntervalMs: 3e5 }
1026
+ }, Ft = [
1027
+ { id: "1h", label: ne["1h"].label },
1028
+ { id: "6h", label: ne["6h"].label },
1029
+ { id: "24h", label: ne["24h"].label }
1030
+ ], Tt = 5e3, Lt = 4, j = "__other__", B = "__all__", V = 160, A = { top: 14, right: 12, bottom: 24, left: 32 };
1031
+ function Dt({ deviceId: e }) {
1032
+ const t = z(), o = Q(t.trpcClient, e), [n, a] = H("1h"), [s, d] = H(B), l = ne[n], [f, u] = ce(), k = de(), $ = K(null), F = le({
1033
+ queryKey: ["pipeline-analytics", e, "objectEvents", n],
1034
+ queryFn: async () => {
1035
+ if (!o) return [];
1036
+ const c = Date.now() - l.windowMs;
1037
+ return await o.pipelineAnalytics?.getObjectEvents({
1038
+ since: c,
1039
+ limit: Tt
1040
+ }) ?? [];
1041
+ },
1042
+ enabled: !!o,
1043
+ refetchInterval: l.pollIntervalMs,
1044
+ staleTime: Math.max(1e3, l.pollIntervalMs / 2)
1045
+ }), b = F.data ?? [], x = N(
1046
+ () => s === B ? b : b.filter((c) => c.className === s),
1047
+ [b, s]
1048
+ ), C = F.dataUpdatedAt > 0 ? F.dataUpdatedAt : Date.now(), y = C - l.windowMs, L = N(() => {
1049
+ const c = /* @__PURE__ */ new Set();
1050
+ for (const w of b) c.add(w.className);
1051
+ return s !== B && c.add(s), [...c].sort();
1052
+ }, [b, s]);
1053
+ ge(() => {
1054
+ s !== B && b.length > 0 && !L.includes(s) && d(B);
1055
+ }, [s, b, L]);
1056
+ const D = N(() => Et(x, Lt), [x]), m = N(
1057
+ () => Ht(x, y, C, l.bucketMs, D),
1058
+ [x, y, C, l.bucketMs, D]
1059
+ ), h = N(() => {
1060
+ if (m.length === 0) return 1;
1061
+ const c = m.reduce((w, I) => Math.max(w, I.total), 0);
1062
+ return Math.max(1, Math.ceil(c * 1.15));
1063
+ }, [m]), g = N(
1064
+ () => ve(y, C, u, A.left, A.right, 5),
1065
+ [y, C, u]
1066
+ ), _ = N(() => Wt(h), [h]), p = N(() => {
1067
+ const c = D.map((w) => w.className);
1068
+ return x.some((w) => !D.some((I) => I.className === w.className)) && c.push(j), c;
1069
+ }, [x, D]), v = (c) => {
1070
+ const w = $.current;
1071
+ if (!w) return c;
1072
+ const I = w.getBoundingClientRect();
1073
+ return I.width === 0 ? c : c / u * I.width;
1074
+ };
1075
+ return /* @__PURE__ */ i("div", { className: "rounded-lg border border-border bg-surface overflow-hidden", children: [
1076
+ /* @__PURE__ */ i("div", { className: "border-b border-border px-4 py-2 flex items-center justify-between gap-3", children: [
1077
+ /* @__PURE__ */ i("div", { className: "flex items-center gap-1.5", children: [
1078
+ /* @__PURE__ */ r(Ke, { className: "h-3.5 w-3.5 text-foreground-subtle" }),
1079
+ /* @__PURE__ */ r("h2", { className: "text-xs font-semibold text-foreground uppercase tracking-wider", children: "Detection History" })
1080
+ ] }),
1081
+ /* @__PURE__ */ i("div", { className: "flex items-center gap-2", children: [
1082
+ L.length > 0 && /* @__PURE__ */ i(
1083
+ "select",
1084
+ {
1085
+ value: s,
1086
+ onChange: (c) => d(c.target.value),
1087
+ className: "text-[10px] px-1.5 py-0.5 rounded border border-border bg-background text-foreground focus:outline-none focus:ring-1 focus:ring-primary/40",
1088
+ title: "Filter by detected class",
1089
+ children: [
1090
+ /* @__PURE__ */ r("option", { value: B, children: "All classes" }),
1091
+ L.map((c) => /* @__PURE__ */ r("option", { value: c, children: c }, c))
1092
+ ]
1093
+ }
1094
+ ),
1095
+ /* @__PURE__ */ r(ie, { presets: Ft, value: n, onChange: a })
1096
+ ] })
1097
+ ] }),
1098
+ /* @__PURE__ */ i("div", { ref: f, className: "p-3 min-w-0 relative", children: [
1099
+ x.length === 0 ? /* @__PURE__ */ r("div", { className: "flex items-center justify-center h-32 text-[11px] text-foreground-subtle italic", children: F.isLoading ? "Loading…" : "No detection events in the selected window." }) : u === 0 ? /* @__PURE__ */ r("div", { className: "h-32" }) : /* @__PURE__ */ i(ae, { children: [
1100
+ /* @__PURE__ */ i(
1101
+ "svg",
1102
+ {
1103
+ ref: $,
1104
+ role: "img",
1105
+ "aria-label": "Detection event histogram",
1106
+ width: "100%",
1107
+ height: V,
1108
+ viewBox: `0 0 ${u} ${V}`,
1109
+ preserveAspectRatio: "none",
1110
+ className: "block",
1111
+ onMouseLeave: () => k.bindHover(null),
1112
+ children: [
1113
+ _.map(({ y: c, label: w }, I) => /* @__PURE__ */ i("g", { children: [
1114
+ /* @__PURE__ */ r("line", { x1: A.left, x2: u - A.right, y1: c, y2: c, stroke: "currentColor", strokeOpacity: 0.08, strokeWidth: 0.5 }),
1115
+ /* @__PURE__ */ r("text", { x: A.left - 6, y: c + 3, textAnchor: "end", className: "text-[9px] fill-foreground-subtle", children: w })
1116
+ ] }, `y-${I}`)),
1117
+ g.map(({ x: c, label: w }, I) => /* @__PURE__ */ r("text", { x: c, y: V - A.bottom + 12, textAnchor: "middle", className: "text-[9px] fill-foreground-subtle", children: w }, `x-${I}`)),
1118
+ m.map((c, w) => {
1119
+ if (c.total === 0) return null;
1120
+ const { x: I, w: O } = jt(c.bucketStart, l.bucketMs, y, C, u), Y = V - A.top - A.bottom, Ee = c.total / h * Y, He = A.top + (Y - Ee);
1121
+ let ke = 0;
1122
+ const je = p.map((E, he) => {
1123
+ const q = c.byClass[E] ?? 0;
1124
+ if (q === 0) return null;
1125
+ const me = q / h * Y, Oe = A.top + (Y - ke - me);
1126
+ ke += me;
1127
+ const Re = E === j ? "#94a3b8" : pe(he);
1128
+ return /* @__PURE__ */ r(
1129
+ "rect",
1130
+ {
1131
+ x: I,
1132
+ y: Oe,
1133
+ width: Math.max(1, O - 1),
1134
+ height: Math.max(1, me),
1135
+ fill: Re,
1136
+ opacity: 0.9
1137
+ },
1138
+ `${c.bucketStart}-${E}`
1139
+ );
1140
+ }).filter((E) => E !== null), We = c.bucketStart + l.bucketMs;
1141
+ return /* @__PURE__ */ i("g", { children: [
1142
+ je,
1143
+ /* @__PURE__ */ r(
1144
+ "rect",
1145
+ {
1146
+ x: I,
1147
+ y: A.top,
1148
+ width: Math.max(2, O),
1149
+ height: Y,
1150
+ fill: "transparent",
1151
+ onMouseEnter: () => {
1152
+ k.bindHover({
1153
+ anchorX: v(I + O / 2),
1154
+ anchorY: He,
1155
+ title: `${Ot(c.bucketStart, We, l.bucketMs)} · ${c.total} detection${c.total === 1 ? "" : "s"}`,
1156
+ rows: p.map((E, he) => {
1157
+ const q = c.byClass[E] ?? 0;
1158
+ return q === 0 ? null : {
1159
+ label: E === j ? "other" : E,
1160
+ value: `${q}`,
1161
+ colour: E === j ? "#94a3b8" : pe(he)
1162
+ };
1163
+ }).filter((E) => E !== null)
1164
+ });
1165
+ }
1166
+ }
1167
+ )
1168
+ ] }, `g-${c.bucketStart}-${w}`);
1169
+ })
1170
+ ]
1171
+ }
1172
+ ),
1173
+ /* @__PURE__ */ r(ue, { state: k.state, containerWidth: u }),
1174
+ /* @__PURE__ */ r(Bt, { stackOrder: p })
1175
+ ] }),
1176
+ x.length > 0 && /* @__PURE__ */ i("div", { className: "flex items-center justify-between text-[10px] text-foreground-subtle mt-1", children: [
1177
+ /* @__PURE__ */ i("span", { children: [
1178
+ x.length,
1179
+ " detection",
1180
+ x.length === 1 ? "" : "s",
1181
+ " · ",
1182
+ Rt(l.bucketMs),
1183
+ " buckets"
1184
+ ] }),
1185
+ /* @__PURE__ */ i("span", { children: [
1186
+ "peak ",
1187
+ m.reduce((c, w) => Math.max(c, w.total), 0),
1188
+ "/bucket"
1189
+ ] })
1190
+ ] })
1191
+ ] })
1192
+ ] });
1193
+ }
1194
+ function Et(e, t) {
1195
+ const o = /* @__PURE__ */ new Map();
1196
+ for (const n of e)
1197
+ o.set(n.className, (o.get(n.className) ?? 0) + 1);
1198
+ return [...o.entries()].sort(([, n], [, a]) => a - n).slice(0, t).map(([n, a]) => ({ className: n, count: a }));
1199
+ }
1200
+ function Ht(e, t, o, n, a) {
1201
+ if (o <= t) return [];
1202
+ const s = new Set(a.map((u) => u.className)), d = Math.floor(t / n) * n, l = Math.floor(o / n) * n, f = /* @__PURE__ */ new Map();
1203
+ for (let u = d; u <= l; u += n)
1204
+ f.set(u, { total: 0, byClass: {} });
1205
+ for (const u of e) {
1206
+ if (u.timestamp < t || u.timestamp > o) continue;
1207
+ const k = Math.floor(u.timestamp / n) * n, $ = f.get(k);
1208
+ if (!$) continue;
1209
+ $.total += 1;
1210
+ const F = s.has(u.className) ? u.className : j;
1211
+ $.byClass[F] = ($.byClass[F] ?? 0) + 1;
1212
+ }
1213
+ return [...f.entries()].sort(([u], [k]) => u - k).map(([u, k]) => ({
1214
+ bucketStart: u,
1215
+ total: k.total,
1216
+ byClass: k.byClass
1217
+ }));
1218
+ }
1219
+ function jt(e, t, o, n, a) {
1220
+ const s = Math.max(1, n - o), d = a - A.left - A.right, l = A.left + (e - o) / s * d, f = t / s * d;
1221
+ return { x: l, w: f };
1222
+ }
1223
+ function Wt(e) {
1224
+ const t = [];
1225
+ for (let o = 0; o < 4; o++) {
1226
+ const n = o / 3, a = Math.round(e * n), s = V - A.top - A.bottom;
1227
+ t.push({
1228
+ y: A.top + (1 - n) * s,
1229
+ label: `${a}`
1230
+ });
1231
+ }
1232
+ return t;
1233
+ }
1234
+ function Ot(e, t, o) {
1235
+ const n = (a) => {
1236
+ const s = String(a.getHours()).padStart(2, "0"), d = String(a.getMinutes()).padStart(2, "0");
1237
+ return `${s}:${d}`;
1238
+ };
1239
+ return o >= 60 * 6e4 ? `${n(new Date(e))}–${n(new Date(t))}` : `${n(new Date(e))}–${n(new Date(t))}`;
1240
+ }
1241
+ function Rt(e) {
1242
+ return e >= 60 * 6e4 ? `${Math.round(e / 6e4 / 60)}h` : e >= 6e4 ? `${Math.round(e / 6e4)}m` : `${Math.round(e / 1e3)}s`;
1243
+ }
1244
+ function Bt({ stackOrder: e }) {
1245
+ return e.length === 0 ? null : /* @__PURE__ */ r("div", { className: "flex flex-wrap gap-2 mt-2 px-1", children: e.map((t, o) => {
1246
+ const n = t === j ? "#94a3b8" : pe(o);
1247
+ return /* @__PURE__ */ i("span", { className: "inline-flex items-center gap-1 text-[10px] text-foreground-subtle", children: [
1248
+ /* @__PURE__ */ r("span", { className: "inline-block h-2 w-2 rounded-sm", style: { backgroundColor: n } }),
1249
+ /* @__PURE__ */ r("span", { children: t === j ? "other" : t })
1250
+ ] }, t);
1251
+ }) });
1252
+ }
1253
+ function Pt({
1254
+ dev: e,
1255
+ deviceId: t,
1256
+ title: o = "Live Occupancy",
1257
+ variant: n = "full"
1258
+ }) {
1259
+ const a = z(), s = Q(
1260
+ a.trpcClient,
1261
+ e === void 0 && t !== void 0 ? t : null
1262
+ ), d = e ?? s, l = ye(d?.state.zoneAnalytics);
1263
+ return l ? /* @__PURE__ */ r(Se, { title: o, variant: n, ts: l.ts, children: /* @__PURE__ */ i("div", { className: n === "compact" ? "space-y-2" : "grid grid-cols-1 2xl:grid-cols-3 gap-3", children: [
1264
+ /* @__PURE__ */ r(Xt, { frame: l.frame }),
1265
+ /* @__PURE__ */ r(qt, { snapshot: l }),
1266
+ /* @__PURE__ */ r(Yt, { unzoned: l.unzoned })
1267
+ ] }) }) : /* @__PURE__ */ r(Se, { title: o, variant: n, children: /* @__PURE__ */ r(zt, { message: d ? "No occupancy data yet — analytics pipeline must be active for this device." : "Resolving device…" }) });
1268
+ }
1269
+ function Se({ title: e, variant: t, ts: o, children: n }) {
1270
+ const a = o ? Math.max(0, Math.floor((Date.now() - o) / 1e3)) : null;
1271
+ return /* @__PURE__ */ i("div", { className: t === "compact" ? "rounded-md border border-border/60 bg-surface/60 p-3" : "rounded-lg border border-border bg-surface overflow-hidden", children: [
1272
+ /* @__PURE__ */ i("div", { className: t === "compact" ? "flex items-center justify-between mb-2" : "border-b border-border px-4 py-2 flex items-center justify-between", children: [
1273
+ /* @__PURE__ */ r("h2", { className: "text-xs font-semibold text-foreground uppercase tracking-wider", children: e }),
1274
+ a !== null && /* @__PURE__ */ r("span", { className: "text-[10px] text-foreground-subtle", children: a === 0 ? "just now" : `${a}s ago` })
1275
+ ] }),
1276
+ /* @__PURE__ */ r("div", { className: t === "compact" ? "" : "p-3", children: n })
1277
+ ] });
1278
+ }
1279
+ function zt({ message: e }) {
1280
+ return /* @__PURE__ */ i("div", { className: "px-4 py-6 flex flex-col items-center text-center text-foreground-subtle", children: [
1281
+ /* @__PURE__ */ r(re, { className: "h-5 w-5 mb-2 opacity-30" }),
1282
+ /* @__PURE__ */ r("p", { className: "text-[11px]", children: e })
1283
+ ] });
1284
+ }
1285
+ function Xt({ frame: e }) {
1286
+ return /* @__PURE__ */ r(
1287
+ we,
1288
+ {
1289
+ icon: /* @__PURE__ */ r(Ve, { className: "h-3.5 w-3.5" }),
1290
+ label: "Frame total",
1291
+ total: e.totalObjects,
1292
+ byClass: e.byClass,
1293
+ tone: "default"
1294
+ }
1295
+ );
1296
+ }
1297
+ function Yt({ unzoned: e }) {
1298
+ return /* @__PURE__ */ r(
1299
+ we,
1300
+ {
1301
+ icon: /* @__PURE__ */ r(et, { className: "h-3.5 w-3.5" }),
1302
+ label: "Outside any zone",
1303
+ total: e.totalObjects,
1304
+ byClass: e.byClass,
1305
+ tone: "muted"
1306
+ }
1307
+ );
1308
+ }
1309
+ function qt({ snapshot: e }) {
1310
+ return e.zones.length === 0 ? /* @__PURE__ */ r(
1311
+ we,
1312
+ {
1313
+ icon: /* @__PURE__ */ r(re, { className: "h-3.5 w-3.5" }),
1314
+ label: "Per-zone",
1315
+ total: 0,
1316
+ byClass: {},
1317
+ tone: "muted",
1318
+ emptyMessage: "No zones defined for this camera."
1319
+ }
1320
+ ) : /* @__PURE__ */ i("div", { className: "rounded-md border border-border/60 bg-background/40", children: [
1321
+ /* @__PURE__ */ i("div", { className: "px-3 py-1.5 border-b border-border/40 flex items-center gap-1.5 text-[11px] uppercase tracking-wider text-foreground-subtle", children: [
1322
+ /* @__PURE__ */ r(re, { className: "h-3.5 w-3.5" }),
1323
+ /* @__PURE__ */ r("span", { children: "Per-zone" }),
1324
+ /* @__PURE__ */ r("span", { className: "ml-auto text-[10px] normal-case tracking-normal", children: e.zones.length })
1325
+ ] }),
1326
+ /* @__PURE__ */ r("div", { className: "divide-y divide-border/30", children: e.zones.map((t) => /* @__PURE__ */ i("div", { className: "px-3 py-2", children: [
1327
+ /* @__PURE__ */ i("div", { className: "flex items-center justify-between mb-1", children: [
1328
+ /* @__PURE__ */ r("span", { className: "text-xs font-medium text-foreground truncate", children: t.zoneName }),
1329
+ /* @__PURE__ */ r("span", { className: "rounded-full px-2 py-0.5 text-[10px] font-medium bg-foreground-subtle/10 text-foreground-subtle border border-border", children: t.totalObjects })
1330
+ ] }),
1331
+ /* @__PURE__ */ r(De, { byClass: t.byClass })
1332
+ ] }, t.zoneId)) })
1333
+ ] });
1334
+ }
1335
+ function we({ icon: e, label: t, total: o, byClass: n, tone: a, emptyMessage: s }) {
1336
+ const d = Object.keys(n).length;
1337
+ return /* @__PURE__ */ i("div", { className: a === "muted" ? "rounded-md border border-border/40 bg-background/20 px-3 py-2" : "rounded-md border border-border/60 bg-background/40 px-3 py-2", children: [
1338
+ /* @__PURE__ */ i("div", { className: "flex items-center gap-1.5 mb-1.5 text-[11px] uppercase tracking-wider text-foreground-subtle", children: [
1339
+ e,
1340
+ /* @__PURE__ */ r("span", { children: t }),
1341
+ /* @__PURE__ */ r("span", { className: "ml-auto text-base font-semibold text-foreground tabular-nums normal-case tracking-normal", children: o })
1342
+ ] }),
1343
+ d === 0 ? /* @__PURE__ */ r("span", { className: "text-[10px] text-foreground-subtle italic", children: s ?? "no objects" }) : /* @__PURE__ */ r(De, { byClass: n })
1344
+ ] });
1345
+ }
1346
+ function De({ byClass: e }) {
1347
+ const t = N(
1348
+ () => Object.entries(e).sort(([, o], [, n]) => n - o),
1349
+ [e]
1350
+ );
1351
+ return t.length === 0 ? /* @__PURE__ */ r("span", { className: "text-[10px] text-foreground-subtle italic", children: "no objects" }) : /* @__PURE__ */ r("div", { className: "flex flex-wrap gap-1", children: t.map(([o, n]) => /* @__PURE__ */ i(
1352
+ "span",
1353
+ {
1354
+ className: "inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[10px] font-medium bg-primary/10 text-primary border border-primary/20",
1355
+ children: [
1356
+ /* @__PURE__ */ r("span", { children: o }),
1357
+ /* @__PURE__ */ r("span", { className: "tabular-nums opacity-80", children: n })
1358
+ ]
1359
+ },
1360
+ o
1361
+ )) });
1362
+ }
1363
+ function X({ name: e }) {
1364
+ return /* @__PURE__ */ i("div", { className: "rounded-lg border border-warning/30 bg-warning/10 px-3 py-2 text-xs text-warning", children: [
1365
+ e,
1366
+ " requires a deviceId"
1367
+ ] });
1368
+ }
1369
+ function Gt(e) {
1370
+ return e.deviceId === void 0 ? /* @__PURE__ */ r(X, { name: "AudioHistoryChart" }) : /* @__PURE__ */ r(it, { deviceId: e.deviceId });
1371
+ }
1372
+ function Ut(e) {
1373
+ return e.deviceId === void 0 ? /* @__PURE__ */ r(X, { name: "AudioMetricsPanel" }) : /* @__PURE__ */ r(ft, { deviceId: e.deviceId });
1374
+ }
1375
+ function Vt(e) {
1376
+ return e.deviceId === void 0 ? /* @__PURE__ */ r(X, { name: "OccupancyHistoryChart" }) : /* @__PURE__ */ r(vt, { deviceId: e.deviceId });
1377
+ }
1378
+ function Zt(e) {
1379
+ return e.deviceId === void 0 ? /* @__PURE__ */ r(X, { name: "MotionHistoryChart" }) : /* @__PURE__ */ r(Ct, { deviceId: e.deviceId });
1380
+ }
1381
+ function Kt(e) {
1382
+ return e.deviceId === void 0 ? /* @__PURE__ */ r(X, { name: "DetectionHistoryChart" }) : /* @__PURE__ */ r(Dt, { deviceId: e.deviceId });
1383
+ }
1384
+ function Qt(e) {
1385
+ return e.deviceId === void 0 ? /* @__PURE__ */ r(X, { name: "LiveOccupancyPanel" }) : /* @__PURE__ */ r(Pt, { deviceId: e.deviceId });
1386
+ }
1387
+ const rn = {
1388
+ "audio-history-chart": Gt,
1389
+ "audio-metrics-panel": Ut,
1390
+ "occupancy-history-chart": Vt,
1391
+ "motion-history-chart": Zt,
1392
+ "detection-history-chart": Kt,
1393
+ "live-occupancy-panel": Qt
1394
+ };
1395
+ export {
1396
+ rn as default
1397
+ };