@camstack/ui-library 1.2.191 → 1.2.193
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/composites/clips/ClipBandBar.d.ts +16 -0
- package/dist/composites/clips/clip-band.d.ts +58 -0
- package/dist/composites/clips/clip-day-window.d.ts +21 -22
- package/dist/composites/clips/clip-still-retry.d.ts +50 -0
- package/dist/composites/clips/clip-tile-media.d.ts +25 -7
- package/dist/composites/clips/clip-view-state.d.ts +26 -2
- package/dist/generated/system-hooks.d.ts +2 -0
- package/dist/index.cjs +885 -505
- package/dist/index.js +886 -507
- package/dist/lib/format-duration.d.ts +14 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -13,7 +13,7 @@ import * as __mfHostReactDOMClient from "react-dom/client";
|
|
|
13
13
|
import { createRoot } from "react-dom/client";
|
|
14
14
|
import * as __mfHostTrpcClient from "@trpc/client";
|
|
15
15
|
import { createTRPCClient, createWSClient, httpLink, splitLink, wsLink } from "@trpc/client";
|
|
16
|
-
import { ALL_CAPABILITY_DEFINITIONS, CAM_PROFILE_ORDER, CONTAINER_CHILD_PRIORITY, DEFAULT_EVENTS_BAND_BUFFER_SEC, DEFAULT_EVENT_COLOR, DEVICE_TYPE_CONTROL_KIND, DeviceExportStatusSchema, DeviceFeature, DeviceRole, DeviceType, EVENT_TAXONOMY, EventCategory, ExposedDeviceSchema, FIRST_LEVEL_MACRO_CLASSES, KNOWN_CAP_NAMES, MAX_SENSOR_TRIGGER_DEVICES, MODEL_PROVIDER_IDS, NAVIGATION_LIGHT_LEVEL_MAX, NAVIGATION_LIGHT_LEVEL_MIN, PET_FEEDER_MANUAL_FEED_MAX, PET_FEEDER_MANUAL_FEED_MIN, RECORDING_AUDIO_TRIGGER_OFFERED_DBFS, RecordingConfigSchema, RecordingStatusSchema, SOURCE_CAP_ACTIVE_FIELD, STATIONARY_OVERLAY_STYLE, TIMEZONES, buildModelVariantGroups, canConvertUnit, clusterStepSettingFieldsFor, createDeviceProxy, createLazyTrpcSource, createSliceHandle, deriveRecordingMode, describeModelVariant, findTimezone, formatParkedFor, resolveContainerPrimaryChild, resolveDeviceControlKind, resolveRecordingProfiles, resolveVariantModelId, resolveViewableDeviceIds, selectAssignedProfileSlots, tryConvertUnit } from "@camstack/types";
|
|
16
|
+
import { ALL_CAPABILITY_DEFINITIONS, CAM_PROFILE_ORDER, CLIP_STILL_DISPOSITION_HEADER, CLIP_STILL_REASON_CODE_HEADER, CLIP_STILL_REASON_HEADER, CONTAINER_CHILD_PRIORITY, DEFAULT_EVENTS_BAND_BUFFER_SEC, DEFAULT_EVENT_COLOR, DEVICE_TYPE_CONTROL_KIND, DeviceExportStatusSchema, DeviceFeature, DeviceRole, DeviceType, EVENT_TAXONOMY, EventCategory, ExposedDeviceSchema, FIRST_LEVEL_MACRO_CLASSES, KNOWN_CAP_NAMES, MAX_SENSOR_TRIGGER_DEVICES, MODEL_PROVIDER_IDS, NAVIGATION_LIGHT_LEVEL_MAX, NAVIGATION_LIGHT_LEVEL_MIN, PET_FEEDER_MANUAL_FEED_MAX, PET_FEEDER_MANUAL_FEED_MIN, RECORDING_AUDIO_TRIGGER_OFFERED_DBFS, RecordingConfigSchema, RecordingStatusSchema, SOURCE_CAP_ACTIVE_FIELD, STATIONARY_OVERLAY_STYLE, TIMEZONES, buildModelVariantGroups, canConvertUnit, clusterStepSettingFieldsFor, createDeviceProxy, createLazyTrpcSource, createSliceHandle, deriveRecordingMode, describeModelVariant, findTimezone, formatParkedFor, resolveContainerPrimaryChild, resolveDeviceControlKind, resolveRecordingProfiles, resolveVariantModelId, resolveViewableDeviceIds, selectAssignedProfileSlots, tryConvertUnit } from "@camstack/types";
|
|
17
17
|
import { createSystem } from "@camstack/sdk";
|
|
18
18
|
import { z } from "zod";
|
|
19
19
|
//#region ../../node_modules/lucide-react/dist/esm/shared/src/utils/mergeClasses.js
|
|
@@ -6383,6 +6383,8 @@ var usePipelineAnalyticsGetTrackMedia = trpc.pipelineAnalytics.getTrackMedia.use
|
|
|
6383
6383
|
var usePipelineAnalyticsListTrackMedia = trpc.pipelineAnalytics.listTrackMedia.useQuery;
|
|
6384
6384
|
/** Generated alias around `trpc.pipelineAnalytics.listEventMedia.useQuery`. */
|
|
6385
6385
|
var usePipelineAnalyticsListEventMedia = trpc.pipelineAnalytics.listEventMedia.useQuery;
|
|
6386
|
+
/** Generated alias around `trpc.pipelineAnalytics.ownersWithMedia.useQuery`. */
|
|
6387
|
+
var usePipelineAnalyticsOwnersWithMedia = trpc.pipelineAnalytics.ownersWithMedia.useQuery;
|
|
6386
6388
|
/** Generated alias around `trpc.pipelineAnalytics.searchObjectEvents.useQuery`. */
|
|
6387
6389
|
var usePipelineAnalyticsSearchObjectEvents = trpc.pipelineAnalytics.searchObjectEvents.useQuery;
|
|
6388
6390
|
/** Generated alias around `trpc.pipelineAnalytics.wipeObjectEmbeddings.useMutation`. */
|
|
@@ -17770,6 +17772,201 @@ var Skeleton = forwardRef(({ className, ...props }, ref) => {
|
|
|
17770
17772
|
});
|
|
17771
17773
|
Skeleton.displayName = "Skeleton";
|
|
17772
17774
|
//#endregion
|
|
17775
|
+
//#region src/composites/cap-settings/recording-timeline-model.ts
|
|
17776
|
+
/** Tie-break precedence for a bucket's dominant kind (first wins on equal count). */
|
|
17777
|
+
var KIND_PRECEDENCE = [
|
|
17778
|
+
"object",
|
|
17779
|
+
"motion",
|
|
17780
|
+
"audio"
|
|
17781
|
+
];
|
|
17782
|
+
/**
|
|
17783
|
+
* Convert server-side density rows into `DensityBucket[]` for the timeline
|
|
17784
|
+
* heatmap. Rows with total === 0 are skipped (defensive; server already omits
|
|
17785
|
+
* them). Returns a sparse, ascending-by-index array — EventHeatmap positions
|
|
17786
|
+
* each bar by `b.startMs` rather than array index, so gaps are fine.
|
|
17787
|
+
*/
|
|
17788
|
+
function densityRowsToBuckets(rows, windowFrom, bucketMs) {
|
|
17789
|
+
const buckets = [];
|
|
17790
|
+
for (const row of rows) {
|
|
17791
|
+
const counts = {
|
|
17792
|
+
motion: row.motion,
|
|
17793
|
+
object: row.object,
|
|
17794
|
+
audio: row.audio
|
|
17795
|
+
};
|
|
17796
|
+
const total = counts.motion + counts.object + counts.audio;
|
|
17797
|
+
if (total === 0) continue;
|
|
17798
|
+
const index = Math.floor((row.bucketStart - windowFrom) / bucketMs);
|
|
17799
|
+
let dominant = null;
|
|
17800
|
+
let best = -1;
|
|
17801
|
+
for (const kind of KIND_PRECEDENCE) if (counts[kind] > best) {
|
|
17802
|
+
best = counts[kind];
|
|
17803
|
+
dominant = kind;
|
|
17804
|
+
}
|
|
17805
|
+
buckets.push({
|
|
17806
|
+
index,
|
|
17807
|
+
startMs: row.bucketStart,
|
|
17808
|
+
endMs: row.bucketStart + bucketMs,
|
|
17809
|
+
counts,
|
|
17810
|
+
total,
|
|
17811
|
+
dominant
|
|
17812
|
+
});
|
|
17813
|
+
}
|
|
17814
|
+
return buckets.toSorted((a, b) => a.index - b.index);
|
|
17815
|
+
}
|
|
17816
|
+
/** Distance from `ms` to the interval `[startMs, endMs]` (0 if inside). */
|
|
17817
|
+
function distanceToSpan(ms, span) {
|
|
17818
|
+
if (ms < span.startMs) return span.startMs - ms;
|
|
17819
|
+
if (ms > span.endMs) return ms - span.endMs;
|
|
17820
|
+
return 0;
|
|
17821
|
+
}
|
|
17822
|
+
/**
|
|
17823
|
+
* Resolve a playback window for a click at `clickMs` against recorded `spans`.
|
|
17824
|
+
* Inside a span → play from the click to that span's end. In a gap / outside →
|
|
17825
|
+
* snap to the WHOLE nearest span. No spans → null (nothing to play).
|
|
17826
|
+
* `spans` are expected ascending by start (as `mergeAvailabilitySpans` returns).
|
|
17827
|
+
*/
|
|
17828
|
+
function seekTargetForSpans(clickMs, spans) {
|
|
17829
|
+
if (spans.length === 0) return null;
|
|
17830
|
+
const containing = spans.find((s) => clickMs >= s.startMs && clickMs <= s.endMs);
|
|
17831
|
+
if (containing) return {
|
|
17832
|
+
fromMs: clickMs,
|
|
17833
|
+
toMs: containing.endMs
|
|
17834
|
+
};
|
|
17835
|
+
let nearest = null;
|
|
17836
|
+
let bestDist = Infinity;
|
|
17837
|
+
for (const s of spans) {
|
|
17838
|
+
const d = distanceToSpan(clickMs, s);
|
|
17839
|
+
if (d < bestDist) {
|
|
17840
|
+
bestDist = d;
|
|
17841
|
+
nearest = s;
|
|
17842
|
+
}
|
|
17843
|
+
}
|
|
17844
|
+
return nearest ? {
|
|
17845
|
+
fromMs: nearest.startMs,
|
|
17846
|
+
toMs: nearest.endMs
|
|
17847
|
+
} : null;
|
|
17848
|
+
}
|
|
17849
|
+
/**
|
|
17850
|
+
* Position `ms` inside the window `[fromMs, toMs]` as a clamped percentage
|
|
17851
|
+
* (0–100). A zero/negative-width window yields 0. Callers use this for `left:`.
|
|
17852
|
+
*/
|
|
17853
|
+
function pctForMs(ms, fromMs, toMs) {
|
|
17854
|
+
const span = toMs - fromMs;
|
|
17855
|
+
if (span <= 0) return 0;
|
|
17856
|
+
const pct = (ms - fromMs) / span * 100;
|
|
17857
|
+
if (pct < 0) return 0;
|
|
17858
|
+
if (pct > 100) return 100;
|
|
17859
|
+
return pct;
|
|
17860
|
+
}
|
|
17861
|
+
/**
|
|
17862
|
+
* Build a DayWindow for the given calendar `date` using local time.
|
|
17863
|
+
* For any day strictly in the past: `fromMs` = local midnight, `toMs` =
|
|
17864
|
+
* next local midnight (exactly 24 h).
|
|
17865
|
+
* For today (or any future day that contains `nowMs`): `toMs = nowMs` so the
|
|
17866
|
+
* window never extends into the future.
|
|
17867
|
+
*/
|
|
17868
|
+
function dayWindow(date, nowMs) {
|
|
17869
|
+
const fromMs = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0, 0).getTime();
|
|
17870
|
+
const nextMidnight = new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1, 0, 0, 0, 0).getTime();
|
|
17871
|
+
return {
|
|
17872
|
+
fromMs,
|
|
17873
|
+
toMs: Math.max(fromMs, Math.min(nextMidnight, nowMs))
|
|
17874
|
+
};
|
|
17875
|
+
}
|
|
17876
|
+
/** Available zoom levels in ms, from widest (24h) to narrowest (15 min). */
|
|
17877
|
+
var ZOOM_LEVELS = [
|
|
17878
|
+
24 * 36e5,
|
|
17879
|
+
12 * 36e5,
|
|
17880
|
+
6 * 36e5,
|
|
17881
|
+
36e5,
|
|
17882
|
+
15 * 6e4
|
|
17883
|
+
];
|
|
17884
|
+
/**
|
|
17885
|
+
* Produce a `levelMs`-wide window whose RIGHT edge stays anchored at
|
|
17886
|
+
* `rightEdgeMs` (clamped within `dayBounds`), rather than centring on the view
|
|
17887
|
+
* midpoint. On today's timeline the view's right edge is "now", so zooming this
|
|
17888
|
+
* way keeps the most recent footage pinned to the right instead of drifting to
|
|
17889
|
+
* a midday range that no longer contains now. Panning then moves back/forward.
|
|
17890
|
+
*
|
|
17891
|
+
* Falls back to `dayBounds` when `levelMs` meets or exceeds the day span (can't
|
|
17892
|
+
* show a wider window than the day holds — e.g. early morning with little
|
|
17893
|
+
* elapsed time).
|
|
17894
|
+
*/
|
|
17895
|
+
function zoomWindowAnchoredRight(dayBounds, levelMs, rightEdgeMs) {
|
|
17896
|
+
if (levelMs >= dayBounds.toMs - dayBounds.fromMs) return dayBounds;
|
|
17897
|
+
const toMs = Math.min(Math.max(rightEdgeMs, dayBounds.fromMs + levelMs), dayBounds.toMs);
|
|
17898
|
+
return {
|
|
17899
|
+
fromMs: toMs - levelMs,
|
|
17900
|
+
toMs
|
|
17901
|
+
};
|
|
17902
|
+
}
|
|
17903
|
+
/**
|
|
17904
|
+
* Shift `win` by `deltaMs`, preserving width, clamped within `dayBounds`.
|
|
17905
|
+
*/
|
|
17906
|
+
function panWindow(win, dayBounds, deltaMs) {
|
|
17907
|
+
const width = win.toMs - win.fromMs;
|
|
17908
|
+
let fromMs = win.fromMs + deltaMs;
|
|
17909
|
+
let toMs = win.toMs + deltaMs;
|
|
17910
|
+
if (fromMs < dayBounds.fromMs) {
|
|
17911
|
+
fromMs = dayBounds.fromMs;
|
|
17912
|
+
toMs = fromMs + width;
|
|
17913
|
+
}
|
|
17914
|
+
if (toMs > dayBounds.toMs) {
|
|
17915
|
+
toMs = dayBounds.toMs;
|
|
17916
|
+
fromMs = toMs - width;
|
|
17917
|
+
}
|
|
17918
|
+
return {
|
|
17919
|
+
fromMs,
|
|
17920
|
+
toMs
|
|
17921
|
+
};
|
|
17922
|
+
}
|
|
17923
|
+
/** Candidate bucket sizes in ms (coarsest first). */
|
|
17924
|
+
var BUCKET_CANDIDATES = [
|
|
17925
|
+
15 * 6e4,
|
|
17926
|
+
5 * 6e4,
|
|
17927
|
+
6e4,
|
|
17928
|
+
3e4,
|
|
17929
|
+
15e3,
|
|
17930
|
+
5e3
|
|
17931
|
+
];
|
|
17932
|
+
/**
|
|
17933
|
+
* Choose a sensible heatmap bucket size for a visible span of `spanMs`,
|
|
17934
|
+
* targeting ~96-120 buckets. Always picks from `BUCKET_CANDIDATES`.
|
|
17935
|
+
*/
|
|
17936
|
+
function bucketMsForSpan(spanMs) {
|
|
17937
|
+
const targetBucket = spanMs / 100;
|
|
17938
|
+
for (const candidate of BUCKET_CANDIDATES) if (candidate <= targetBucket) return candidate;
|
|
17939
|
+
return BUCKET_CANDIDATES[BUCKET_CANDIDATES.length - 1] ?? 5e3;
|
|
17940
|
+
}
|
|
17941
|
+
/**
|
|
17942
|
+
* Produce `count` evenly-spaced axis ticks spanning [fromMs, toMs].
|
|
17943
|
+
* - `pct` is via pctForMs (first=0, last=100).
|
|
17944
|
+
* - `label` is a localised HH:MM clock string.
|
|
17945
|
+
*/
|
|
17946
|
+
function axisTicks(fromMs, toMs, count) {
|
|
17947
|
+
if (count <= 1) return [{
|
|
17948
|
+
pct: 0,
|
|
17949
|
+
label: new Date(fromMs).toLocaleTimeString(void 0, {
|
|
17950
|
+
hour: "2-digit",
|
|
17951
|
+
minute: "2-digit"
|
|
17952
|
+
})
|
|
17953
|
+
}];
|
|
17954
|
+
const ticks = [];
|
|
17955
|
+
for (let i = 0; i < count; i++) {
|
|
17956
|
+
const ms = fromMs + i / (count - 1) * (toMs - fromMs);
|
|
17957
|
+
const pct = pctForMs(ms, fromMs, toMs);
|
|
17958
|
+
const label = new Date(ms).toLocaleTimeString(void 0, {
|
|
17959
|
+
hour: "2-digit",
|
|
17960
|
+
minute: "2-digit"
|
|
17961
|
+
});
|
|
17962
|
+
ticks.push({
|
|
17963
|
+
pct,
|
|
17964
|
+
label
|
|
17965
|
+
});
|
|
17966
|
+
}
|
|
17967
|
+
return ticks;
|
|
17968
|
+
}
|
|
17969
|
+
//#endregion
|
|
17773
17970
|
//#region src/hooks/use-is-mobile.ts
|
|
17774
17971
|
var MOBILE_QUERY = "(max-width: 767px)";
|
|
17775
17972
|
/**
|
|
@@ -18406,6 +18603,266 @@ function ErrorBox({ message, title, onRetry, action, variant = "danger", classNa
|
|
|
18406
18603
|
});
|
|
18407
18604
|
}
|
|
18408
18605
|
//#endregion
|
|
18606
|
+
//#region src/composites/cap-settings/EventHeatmap.tsx
|
|
18607
|
+
var KIND_BG = {
|
|
18608
|
+
motion: "bg-emerald-500",
|
|
18609
|
+
object: "bg-violet-500",
|
|
18610
|
+
audio: "bg-orange-500"
|
|
18611
|
+
};
|
|
18612
|
+
function EventHeatmap({ windowFrom, windowTo, buckets, selectedIndex, onSelectBucket }) {
|
|
18613
|
+
const peak = buckets.reduce((m, b) => Math.max(m, b.total), 0);
|
|
18614
|
+
const firstBucket = buckets[0];
|
|
18615
|
+
const bucketWidthPct = firstBucket ? pctForMs(firstBucket.endMs, windowFrom, windowTo) - pctForMs(firstBucket.startMs, windowFrom, windowTo) : 0;
|
|
18616
|
+
return /* @__PURE__ */ jsx("div", {
|
|
18617
|
+
className: "relative h-6 rounded bg-background/40",
|
|
18618
|
+
children: buckets.map((b) => {
|
|
18619
|
+
if (b.total === 0 || b.dominant === null) return null;
|
|
18620
|
+
const heightPct = peak > 0 ? Math.max(15, b.total / peak * 100) : 0;
|
|
18621
|
+
const left = pctForMs(b.startMs, windowFrom, windowTo);
|
|
18622
|
+
const selected = b.index === selectedIndex;
|
|
18623
|
+
return /* @__PURE__ */ jsx("button", {
|
|
18624
|
+
type: "button",
|
|
18625
|
+
"data-testid": "heatmap-bar",
|
|
18626
|
+
title: `${new Date(b.startMs).toLocaleTimeString(void 0, {
|
|
18627
|
+
hour: "2-digit",
|
|
18628
|
+
minute: "2-digit"
|
|
18629
|
+
})} · motion ${b.counts.motion} · object ${b.counts.object}`,
|
|
18630
|
+
onClick: () => onSelectBucket(b.index),
|
|
18631
|
+
className: `absolute bottom-0 rounded-t-sm transition-opacity ${KIND_BG[b.dominant]} ${selected ? "opacity-100 ring-1 ring-amber-400" : "opacity-80 hover:opacity-100"}`,
|
|
18632
|
+
style: {
|
|
18633
|
+
left: `${left}%`,
|
|
18634
|
+
width: `${Math.max(.6, bucketWidthPct)}%`,
|
|
18635
|
+
height: `${heightPct}%`
|
|
18636
|
+
}
|
|
18637
|
+
}, b.index);
|
|
18638
|
+
})
|
|
18639
|
+
});
|
|
18640
|
+
}
|
|
18641
|
+
//#endregion
|
|
18642
|
+
//#region src/composites/cap-settings/TimelineControls.tsx
|
|
18643
|
+
/** Format a Date as "YYYY-MM-DD" for <input type="date">. */
|
|
18644
|
+
function formatDateInput(date) {
|
|
18645
|
+
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
|
|
18646
|
+
}
|
|
18647
|
+
/** Parse "YYYY-MM-DD" from <input type="date"> into a local-midnight Date. */
|
|
18648
|
+
function parseDateInput(value) {
|
|
18649
|
+
const parts = value.split("-");
|
|
18650
|
+
const y = parts[0] !== void 0 ? parseInt(parts[0], 10) : NaN;
|
|
18651
|
+
const m = parts[1] !== void 0 ? parseInt(parts[1], 10) : NaN;
|
|
18652
|
+
const d = parts[2] !== void 0 ? parseInt(parts[2], 10) : NaN;
|
|
18653
|
+
if (isNaN(y) || isNaN(m) || isNaN(d)) return null;
|
|
18654
|
+
return new Date(y, m - 1, d);
|
|
18655
|
+
}
|
|
18656
|
+
/**
|
|
18657
|
+
* Date selector + prev/next pan + zoom-in / zoom-out buttons for the recording
|
|
18658
|
+
* timeline. Zoom cycles through ZOOM_LEVELS (widest → narrowest), anchored on
|
|
18659
|
+
* the view's RIGHT edge — so on today's timeline "now" stays pinned to the right
|
|
18660
|
+
* instead of drifting to a midday range. The ◀ / ▶ buttons step the visible
|
|
18661
|
+
* window earlier/later within the day (the discoverable equivalent of the
|
|
18662
|
+
* horizontal wheel-pan wired in RecordingTimeline), so a zoomed-in day can be
|
|
18663
|
+
* navigated back and forth without a mouse wheel.
|
|
18664
|
+
*/
|
|
18665
|
+
function TimelineControls({ day, onDayChange, view, dayBounds, onViewChange }) {
|
|
18666
|
+
const handleDateChange = (e) => {
|
|
18667
|
+
const parsed = parseDateInput(e.target.value);
|
|
18668
|
+
if (parsed !== null) onDayChange(parsed);
|
|
18669
|
+
};
|
|
18670
|
+
const viewSpan = view.toMs - view.fromMs;
|
|
18671
|
+
const currentLevelIdx = (() => {
|
|
18672
|
+
let best = 0;
|
|
18673
|
+
let bestDiff = Infinity;
|
|
18674
|
+
for (let i = 0; i < ZOOM_LEVELS.length; i++) {
|
|
18675
|
+
const level = ZOOM_LEVELS[i];
|
|
18676
|
+
if (level === void 0) continue;
|
|
18677
|
+
const diff = Math.abs(level - viewSpan);
|
|
18678
|
+
if (diff < bestDiff) {
|
|
18679
|
+
bestDiff = diff;
|
|
18680
|
+
best = i;
|
|
18681
|
+
}
|
|
18682
|
+
}
|
|
18683
|
+
return best;
|
|
18684
|
+
})();
|
|
18685
|
+
const rightEdgeMs = view.toMs;
|
|
18686
|
+
const handleZoomIn = () => {
|
|
18687
|
+
const nextLevel = ZOOM_LEVELS[Math.min(currentLevelIdx + 1, ZOOM_LEVELS.length - 1)];
|
|
18688
|
+
if (nextLevel === void 0) return;
|
|
18689
|
+
onViewChange(zoomWindowAnchoredRight(dayBounds, nextLevel, rightEdgeMs));
|
|
18690
|
+
};
|
|
18691
|
+
const handleZoomOut = () => {
|
|
18692
|
+
const nextLevel = ZOOM_LEVELS[Math.max(currentLevelIdx - 1, 0)];
|
|
18693
|
+
if (nextLevel === void 0) return;
|
|
18694
|
+
onViewChange(zoomWindowAnchoredRight(dayBounds, nextLevel, rightEdgeMs));
|
|
18695
|
+
};
|
|
18696
|
+
const canZoomIn = currentLevelIdx < ZOOM_LEVELS.length - 1;
|
|
18697
|
+
const canZoomOut = currentLevelIdx > 0;
|
|
18698
|
+
const panStepMs = Math.max(1, Math.round(viewSpan * .9));
|
|
18699
|
+
const canPanPrev = view.fromMs > dayBounds.fromMs;
|
|
18700
|
+
const canPanNext = view.toMs < dayBounds.toMs;
|
|
18701
|
+
const handlePanPrev = () => {
|
|
18702
|
+
onViewChange(panWindow(view, dayBounds, -panStepMs));
|
|
18703
|
+
};
|
|
18704
|
+
const handlePanNext = () => {
|
|
18705
|
+
onViewChange(panWindow(view, dayBounds, panStepMs));
|
|
18706
|
+
};
|
|
18707
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
18708
|
+
className: "flex items-center gap-2",
|
|
18709
|
+
children: [
|
|
18710
|
+
/* @__PURE__ */ jsx("input", {
|
|
18711
|
+
type: "date",
|
|
18712
|
+
value: formatDateInput(day),
|
|
18713
|
+
max: formatDateInput(/* @__PURE__ */ new Date()),
|
|
18714
|
+
onChange: handleDateChange,
|
|
18715
|
+
className: "rounded border border-border bg-background px-2 py-0.5 text-[11px] text-foreground focus:outline-none focus:ring-1 focus:ring-primary",
|
|
18716
|
+
"aria-label": "Select recording day"
|
|
18717
|
+
}),
|
|
18718
|
+
/* @__PURE__ */ jsxs("div", {
|
|
18719
|
+
className: "ml-auto flex items-center gap-1",
|
|
18720
|
+
children: [
|
|
18721
|
+
/* @__PURE__ */ jsx("button", {
|
|
18722
|
+
type: "button",
|
|
18723
|
+
onClick: handlePanPrev,
|
|
18724
|
+
disabled: !canPanPrev,
|
|
18725
|
+
title: "Earlier (pan back)",
|
|
18726
|
+
"aria-label": "Pan earlier",
|
|
18727
|
+
className: "rounded p-1 text-foreground-subtle transition-colors hover:bg-background/60 hover:text-foreground disabled:cursor-not-allowed disabled:opacity-40",
|
|
18728
|
+
children: /* @__PURE__ */ jsx(ChevronLeft, { size: 14 })
|
|
18729
|
+
}),
|
|
18730
|
+
/* @__PURE__ */ jsx("button", {
|
|
18731
|
+
type: "button",
|
|
18732
|
+
onClick: handlePanNext,
|
|
18733
|
+
disabled: !canPanNext,
|
|
18734
|
+
title: "Later (pan forward)",
|
|
18735
|
+
"aria-label": "Pan later",
|
|
18736
|
+
className: "rounded p-1 text-foreground-subtle transition-colors hover:bg-background/60 hover:text-foreground disabled:cursor-not-allowed disabled:opacity-40",
|
|
18737
|
+
children: /* @__PURE__ */ jsx(ChevronRight, { size: 14 })
|
|
18738
|
+
}),
|
|
18739
|
+
/* @__PURE__ */ jsx("span", {
|
|
18740
|
+
className: "mx-0.5 h-3 w-px bg-border",
|
|
18741
|
+
"aria-hidden": "true"
|
|
18742
|
+
}),
|
|
18743
|
+
/* @__PURE__ */ jsx("button", {
|
|
18744
|
+
type: "button",
|
|
18745
|
+
onClick: handleZoomOut,
|
|
18746
|
+
disabled: !canZoomOut,
|
|
18747
|
+
title: "Zoom out",
|
|
18748
|
+
"aria-label": "Zoom out",
|
|
18749
|
+
className: "rounded p-1 text-foreground-subtle transition-colors hover:bg-background/60 hover:text-foreground disabled:cursor-not-allowed disabled:opacity-40",
|
|
18750
|
+
children: /* @__PURE__ */ jsx(ZoomOut, { size: 13 })
|
|
18751
|
+
}),
|
|
18752
|
+
/* @__PURE__ */ jsx("button", {
|
|
18753
|
+
type: "button",
|
|
18754
|
+
onClick: handleZoomIn,
|
|
18755
|
+
disabled: !canZoomIn,
|
|
18756
|
+
title: "Zoom in",
|
|
18757
|
+
"aria-label": "Zoom in",
|
|
18758
|
+
className: "rounded p-1 text-foreground-subtle transition-colors hover:bg-background/60 hover:text-foreground disabled:cursor-not-allowed disabled:opacity-40",
|
|
18759
|
+
children: /* @__PURE__ */ jsx(ZoomIn, { size: 13 })
|
|
18760
|
+
})
|
|
18761
|
+
]
|
|
18762
|
+
}),
|
|
18763
|
+
/* @__PURE__ */ jsx("span", {
|
|
18764
|
+
className: "text-[9px] text-foreground-subtle",
|
|
18765
|
+
children: zoomLabel(viewSpan)
|
|
18766
|
+
})
|
|
18767
|
+
]
|
|
18768
|
+
});
|
|
18769
|
+
}
|
|
18770
|
+
function zoomLabel(spanMs) {
|
|
18771
|
+
const h = spanMs / 36e5;
|
|
18772
|
+
if (h >= 24) return "24h";
|
|
18773
|
+
if (h >= 1) return `${Math.round(h)}h`;
|
|
18774
|
+
const m = spanMs / 6e4;
|
|
18775
|
+
return `${Math.round(m)}m`;
|
|
18776
|
+
}
|
|
18777
|
+
//#endregion
|
|
18778
|
+
//#region src/composites/clips/ClipBandBar.tsx
|
|
18779
|
+
/**
|
|
18780
|
+
* The clips section's timebar — the recording section's own controls, driving
|
|
18781
|
+
* a clip list instead of a player (D564).
|
|
18782
|
+
*
|
|
18783
|
+
* *"Possiamo utilizzare lo stesso componente della sezione recording con la
|
|
18784
|
+
* timebar dove selezionare un periodo e mostrare le clip solo di quella banda
|
|
18785
|
+
* selezionata, espandibile."* — the operator, 2026-09-20. So this is not a
|
|
18786
|
+
* second timebar: it is `TimelineControls` and `EventHeatmap`, the two pieces
|
|
18787
|
+
* `RecordingTimeline` is itself built from, over the same
|
|
18788
|
+
* `recording-timeline-model` (`dayWindow`, `panWindow`,
|
|
18789
|
+
* `zoomWindowAnchoredRight`, `bucketMsForSpan`, `axisTicks`). One
|
|
18790
|
+
* implementation, one model, two surfaces.
|
|
18791
|
+
*
|
|
18792
|
+
* ## What it does NOT take from the recording timeline
|
|
18793
|
+
*
|
|
18794
|
+
* `CoverageTrack` stays behind. There it is the seek surface — a click drives
|
|
18795
|
+
* the hero player through the `camstack-control` channel or an HLS VOD
|
|
18796
|
+
* request. A copy here would either be a dead bar or a SECOND thing claiming
|
|
18797
|
+
* to move the playhead, and two components holding two ideas of the same
|
|
18798
|
+
* position is the defect this repo keeps paying for. The clips section plays a
|
|
18799
|
+
* clip through `ClipPanel`, which is its own, already-shipped path.
|
|
18800
|
+
*
|
|
18801
|
+
* ## This component is presentational
|
|
18802
|
+
*
|
|
18803
|
+
* It holds no state. The day, the visible window and the picked bucket all
|
|
18804
|
+
* live in `ClipsSection`, because that is where the band is turned into the
|
|
18805
|
+
* `listClips` argument — a bar that kept its own copy of the selection would
|
|
18806
|
+
* be the second authority again, one component down.
|
|
18807
|
+
*/
|
|
18808
|
+
/**
|
|
18809
|
+
* How many ms one pixel of horizontal wheel delta pans.
|
|
18810
|
+
*
|
|
18811
|
+
* The same calibration `RecordingTimeline` uses — a standard wheel tick
|
|
18812
|
+
* (~100 px of `deltaX`) pans ~30 min. Two timebars that panned at different
|
|
18813
|
+
* rates would read as two different controls.
|
|
18814
|
+
*/
|
|
18815
|
+
var PAN_MS_PER_PX$1 = 18e3 / 100;
|
|
18816
|
+
function ClipBandBar({ day, onDayChange, view, dayBounds, onViewChange, buckets, selectedBucketIndex, onSelectBucket, densityLoading }) {
|
|
18817
|
+
const trackAreaRef = useRef(null);
|
|
18818
|
+
const handleWheel = useCallback((e) => {
|
|
18819
|
+
const deltaX = Math.abs(e.deltaX) > Math.abs(e.deltaY) ? e.deltaX : e.shiftKey ? e.deltaY : 0;
|
|
18820
|
+
if (deltaX === 0) return;
|
|
18821
|
+
e.preventDefault();
|
|
18822
|
+
onViewChange(panWindow(view, dayBounds, deltaX * PAN_MS_PER_PX$1));
|
|
18823
|
+
}, [
|
|
18824
|
+
view,
|
|
18825
|
+
dayBounds,
|
|
18826
|
+
onViewChange
|
|
18827
|
+
]);
|
|
18828
|
+
const ticks = axisTicks(view.fromMs, view.toMs, 5);
|
|
18829
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
18830
|
+
className: "space-y-1",
|
|
18831
|
+
children: [/* @__PURE__ */ jsx(TimelineControls, {
|
|
18832
|
+
day,
|
|
18833
|
+
onDayChange,
|
|
18834
|
+
view,
|
|
18835
|
+
dayBounds,
|
|
18836
|
+
onViewChange
|
|
18837
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
18838
|
+
ref: trackAreaRef,
|
|
18839
|
+
onWheel: handleWheel,
|
|
18840
|
+
className: "space-y-1",
|
|
18841
|
+
children: [
|
|
18842
|
+
/* @__PURE__ */ jsx("div", {
|
|
18843
|
+
className: "text-[10px] font-semibold uppercase tracking-wider text-foreground-subtle",
|
|
18844
|
+
children: "Events · density"
|
|
18845
|
+
}),
|
|
18846
|
+
densityLoading ? /* @__PURE__ */ jsx("div", { className: "h-6 animate-pulse rounded bg-background/40" }) : /* @__PURE__ */ jsx(EventHeatmap, {
|
|
18847
|
+
windowFrom: view.fromMs,
|
|
18848
|
+
windowTo: view.toMs,
|
|
18849
|
+
buckets,
|
|
18850
|
+
selectedIndex: selectedBucketIndex,
|
|
18851
|
+
onSelectBucket
|
|
18852
|
+
}),
|
|
18853
|
+
/* @__PURE__ */ jsx("div", {
|
|
18854
|
+
className: "relative h-3",
|
|
18855
|
+
children: ticks.map((tick) => /* @__PURE__ */ jsx("span", {
|
|
18856
|
+
className: "absolute -translate-x-1/2 text-[9px] text-foreground-subtle",
|
|
18857
|
+
style: { left: `${String(tick.pct)}%` },
|
|
18858
|
+
children: tick.label
|
|
18859
|
+
}, tick.pct))
|
|
18860
|
+
})
|
|
18861
|
+
]
|
|
18862
|
+
})]
|
|
18863
|
+
});
|
|
18864
|
+
}
|
|
18865
|
+
//#endregion
|
|
18409
18866
|
//#region src/contexts/vod-playback.tsx
|
|
18410
18867
|
/**
|
|
18411
18868
|
* VodPlayback — shared context coordinating recorded (VOD) playback between a
|
|
@@ -18564,24 +19021,58 @@ function ClipPanel({ deviceId, clip, profile, onProfileChange }) {
|
|
|
18564
19021
|
});
|
|
18565
19022
|
}
|
|
18566
19023
|
//#endregion
|
|
19024
|
+
//#region src/lib/format-duration.ts
|
|
19025
|
+
/**
|
|
19026
|
+
* How long something lasted, the way this product says it.
|
|
19027
|
+
*
|
|
19028
|
+
* Promoted verbatim from `composites/cap-settings/RecordingPanel.tsx`, which
|
|
19029
|
+
* had been the only place answering this question about MEDIA. It is now the
|
|
19030
|
+
* only place, so a clip's length and a recording's retention read the same.
|
|
19031
|
+
*
|
|
19032
|
+
* Two other private formatters stay where they are, on purpose:
|
|
19033
|
+
* `config-form-field.tsx` formats a config VALUE (sub-second `ms`, `—` for a
|
|
19034
|
+
* value that is not a number), and `scene-monitor-copy.ts`'s `humanDuration`
|
|
19035
|
+
* is deliberately single-unit and coarse for a sentence. Neither is a media
|
|
19036
|
+
* length, and folding them in here would change what they say.
|
|
19037
|
+
*/
|
|
19038
|
+
function formatDurationMs(ms) {
|
|
19039
|
+
const totalSec = Math.round(ms / 1e3);
|
|
19040
|
+
const h = Math.floor(totalSec / 3600);
|
|
19041
|
+
const m = Math.floor(totalSec % 3600 / 60);
|
|
19042
|
+
const s = totalSec % 60;
|
|
19043
|
+
if (h > 0) return `${h}h ${m}m`;
|
|
19044
|
+
if (m > 0) return `${m}m ${s}s`;
|
|
19045
|
+
return `${s}s`;
|
|
19046
|
+
}
|
|
19047
|
+
//#endregion
|
|
18567
19048
|
//#region src/composites/clips/clip-tile-media.ts
|
|
18568
19049
|
/**
|
|
18569
|
-
* Why no still exists, in words
|
|
18570
|
-
*
|
|
19050
|
+
* Why no still exists, in words, keyed by the refusal CODE.
|
|
19051
|
+
*
|
|
19052
|
+
* A code this table does not know falls back to the provider's own prose, so a
|
|
19053
|
+
* firmware inventing a refusal reaches the operator rather than becoming a
|
|
19054
|
+
* blank tile.
|
|
18571
19055
|
*/
|
|
18572
19056
|
var REFUSAL_TEXT = {
|
|
18573
|
-
sleeping: "The camera is asleep — a still would cost a wake",
|
|
18574
|
-
"camera-refused":
|
|
18575
|
-
"no-keyframe": "No decodable frame inside this window",
|
|
18576
|
-
unsupported: "This source cannot produce stills",
|
|
18577
|
-
"queue-full": "
|
|
18578
|
-
"
|
|
19057
|
+
sleeping: () => "The camera is asleep — a still would cost a wake",
|
|
19058
|
+
"camera-refused": (reason) => `The camera refused — ${reason}`,
|
|
19059
|
+
"no-keyframe": () => "No decodable frame inside this window",
|
|
19060
|
+
unsupported: () => "This source cannot produce stills",
|
|
19061
|
+
"queue-full": () => "Waiting for the camera — its still queue is full",
|
|
19062
|
+
"camera-backoff": () => "The camera is resting after refusing — trying again shortly",
|
|
19063
|
+
"no-catalog-row": () => "This clip is no longer in the catalog",
|
|
19064
|
+
"unknown-device": () => "This camera is not served here",
|
|
19065
|
+
"uid-missing": () => "The camera’s id is not known yet"
|
|
18579
19066
|
};
|
|
18580
|
-
function
|
|
19067
|
+
function wordsFor(code, reason) {
|
|
19068
|
+
const known = code === void 0 ? void 0 : REFUSAL_TEXT[code];
|
|
19069
|
+
return known === void 0 ? reason : known(reason);
|
|
19070
|
+
}
|
|
19071
|
+
function refusal(reason, code) {
|
|
18581
19072
|
return {
|
|
18582
19073
|
kind: "unavailable",
|
|
18583
19074
|
reason,
|
|
18584
|
-
text:
|
|
19075
|
+
text: wordsFor(code, reason)
|
|
18585
19076
|
};
|
|
18586
19077
|
}
|
|
18587
19078
|
/** What to draw for one clip's tile. */
|
|
@@ -18590,7 +19081,7 @@ function resolveTileMedia(clip) {
|
|
|
18590
19081
|
kind: "vouched",
|
|
18591
19082
|
url: clip.thumbnail
|
|
18592
19083
|
};
|
|
18593
|
-
if (clip.thumbnailUnavailable !== void 0) return refusal(clip.thumbnailUnavailable.reason);
|
|
19084
|
+
if (clip.thumbnailUnavailable !== void 0) return refusal(clip.thumbnailUnavailable.reason, clip.thumbnailUnavailable.reason);
|
|
18594
19085
|
if (clip.thumbnailMint !== void 0) return {
|
|
18595
19086
|
kind: "mint",
|
|
18596
19087
|
url: clip.thumbnailMint
|
|
@@ -18601,26 +19092,32 @@ function resolveTileMedia(clip) {
|
|
|
18601
19092
|
};
|
|
18602
19093
|
}
|
|
18603
19094
|
/**
|
|
18604
|
-
* A
|
|
19095
|
+
* A 204, as something the tile can draw.
|
|
18605
19096
|
*
|
|
18606
|
-
*
|
|
18607
|
-
*
|
|
18608
|
-
*
|
|
18609
|
-
*
|
|
19097
|
+
* `deferred` is the ONLY answer that comes back, and only because the server
|
|
19098
|
+
* said so. Everything else — an unknown disposition, an absent one, a code
|
|
19099
|
+
* this build has never heard of — is final, so the failure mode of a
|
|
19100
|
+
* vocabulary that moves is a tile that stops early, never one that asks for
|
|
19101
|
+
* ever.
|
|
18610
19102
|
*/
|
|
18611
|
-
function
|
|
18612
|
-
|
|
19103
|
+
function describeRefusal(headers) {
|
|
19104
|
+
if (headers.disposition === "deferred") return {
|
|
19105
|
+
kind: "deferred",
|
|
19106
|
+
reason: headers.reason,
|
|
19107
|
+
text: wordsFor(headers.code, headers.reason),
|
|
19108
|
+
retryAfterMs: headers.retryAfterMs ?? null
|
|
19109
|
+
};
|
|
19110
|
+
return refusal(headers.reason, headers.code);
|
|
18613
19111
|
}
|
|
18614
19112
|
//#endregion
|
|
18615
19113
|
//#region src/composites/clips/clip-thumbnail-fetch.ts
|
|
18616
19114
|
/**
|
|
18617
|
-
* Asking a `thumbnailMint` route for a still — and hearing
|
|
19115
|
+
* Asking a `thumbnailMint` route for a still — and hearing what it says.
|
|
18618
19116
|
*
|
|
18619
|
-
* The route answers **200** with a JPEG or **204** with
|
|
18620
|
-
* `
|
|
18621
|
-
*
|
|
18622
|
-
*
|
|
18623
|
-
* anonymous broken tile. So a mint goes through `fetch`.
|
|
19117
|
+
* The route answers **200** with a JPEG or **204** with a refusal. An
|
|
19118
|
+
* `<img src>` cannot read a 204's headers: it fires `onerror` with nothing to
|
|
19119
|
+
* say, turning a named refusal into an anonymous broken tile. So a mint goes
|
|
19120
|
+
* through `fetch`.
|
|
18624
19121
|
*
|
|
18625
19122
|
* **Nothing is appended to the URL.** Both data-plane routes are registered
|
|
18626
19123
|
* `access: 'authenticated'` and the hub's `/addon/<id>/<prefix>` proxy takes
|
|
@@ -18628,8 +19125,18 @@ function latchMintRefusal(reason) {
|
|
|
18628
19125
|
* credential (D549 decision 22) — it may sit in history or a `Referer` and
|
|
18629
19126
|
* open nothing.
|
|
18630
19127
|
*
|
|
18631
|
-
*
|
|
18632
|
-
*
|
|
19128
|
+
* ## Three headers, one of which decides everything (D563)
|
|
19129
|
+
*
|
|
19130
|
+
* `x-camstack-reason-code` is the token the tile keys its words on,
|
|
19131
|
+
* `x-camstack-reason` is the camera's own prose, and
|
|
19132
|
+
* `x-camstack-disposition` says whether to come back. This module reads them;
|
|
19133
|
+
* it does not classify them. A response with no disposition — every
|
|
19134
|
+
* provider-reolink build before D563 — is FINAL, which is precisely the
|
|
19135
|
+
* behaviour that shipped.
|
|
19136
|
+
*
|
|
19137
|
+
* A thrown fetch is DEFERRED: nothing refused anything, one request lost a
|
|
19138
|
+
* race, and a tile that goes permanently blank for that is the same defect
|
|
19139
|
+
* with a different cause.
|
|
18633
19140
|
*/
|
|
18634
19141
|
/**
|
|
18635
19142
|
* Ask a mint route for one still.
|
|
@@ -18643,19 +19150,56 @@ async function fetchMintedThumbnail(url, fetcher) {
|
|
|
18643
19150
|
try {
|
|
18644
19151
|
response = await fetcher(url, { credentials: "same-origin" });
|
|
18645
19152
|
} catch (err) {
|
|
18646
|
-
return
|
|
19153
|
+
return deferredNetworkFailure(err);
|
|
18647
19154
|
}
|
|
18648
|
-
if (response.status === 204) return
|
|
18649
|
-
if (!response.ok) return
|
|
19155
|
+
if (response.status === 204) return describeRefusal(refusalHeadersOf(response));
|
|
19156
|
+
if (!response.ok) return describeRefusal({
|
|
19157
|
+
code: void 0,
|
|
19158
|
+
reason: `HTTP ${String(response.status)}`,
|
|
19159
|
+
disposition: void 0
|
|
19160
|
+
});
|
|
18650
19161
|
try {
|
|
18651
19162
|
return {
|
|
18652
19163
|
kind: "image",
|
|
18653
19164
|
blob: await response.blob()
|
|
18654
19165
|
};
|
|
18655
19166
|
} catch (err) {
|
|
18656
|
-
return
|
|
19167
|
+
return deferredNetworkFailure(err);
|
|
18657
19168
|
}
|
|
18658
19169
|
}
|
|
19170
|
+
function refusalHeadersOf(response) {
|
|
19171
|
+
const retryAfter = response.headers.get("retry-after");
|
|
19172
|
+
const seconds = retryAfter === null ? NaN : Number(retryAfter);
|
|
19173
|
+
return {
|
|
19174
|
+
code: response.headers.get(CLIP_STILL_REASON_CODE_HEADER) ?? void 0,
|
|
19175
|
+
reason: response.headers.get(CLIP_STILL_REASON_HEADER) ?? "no reason given",
|
|
19176
|
+
disposition: response.headers.get(CLIP_STILL_DISPOSITION_HEADER) ?? void 0,
|
|
19177
|
+
retryAfterMs: Number.isFinite(seconds) && seconds > 0 ? seconds * 1e3 : null
|
|
19178
|
+
};
|
|
19179
|
+
}
|
|
19180
|
+
function deferredNetworkFailure(err) {
|
|
19181
|
+
return describeRefusal({
|
|
19182
|
+
code: void 0,
|
|
19183
|
+
reason: err instanceof Error ? err.message : String(err),
|
|
19184
|
+
disposition: "deferred"
|
|
19185
|
+
});
|
|
19186
|
+
}
|
|
19187
|
+
/** First wait, doubling from there. */
|
|
19188
|
+
var STILL_RETRY_BASE_MS = 4e3;
|
|
19189
|
+
/** No single wait is longer than this, whatever the server hints. */
|
|
19190
|
+
var STILL_RETRY_MAX_WAIT_MS = 3e4;
|
|
19191
|
+
/** ±25 %: enough to break a synchronised herd, not enough to stop being a
|
|
19192
|
+
* schedule. */
|
|
19193
|
+
var JITTER_FRACTION = .25;
|
|
19194
|
+
/** The next wait, or `null` when the budget is spent. */
|
|
19195
|
+
function planStillRetry(input) {
|
|
19196
|
+
if (input.attempt >= 4 || input.attempt < 0) return null;
|
|
19197
|
+
const curve = STILL_RETRY_BASE_MS * 2 ** input.attempt;
|
|
19198
|
+
const chosen = Math.max(curve, input.serverHintMs ?? 0);
|
|
19199
|
+
const bounded = Math.min(chosen, STILL_RETRY_MAX_WAIT_MS);
|
|
19200
|
+
const jitter = 1 + (input.random() * 2 - 1) * JITTER_FRACTION;
|
|
19201
|
+
return { waitMs: Math.round(bounded * jitter) };
|
|
19202
|
+
}
|
|
18659
19203
|
//#endregion
|
|
18660
19204
|
//#region src/composites/clips/ClipTile.tsx
|
|
18661
19205
|
/**
|
|
@@ -18686,7 +19230,7 @@ function clockOf(ms) {
|
|
|
18686
19230
|
});
|
|
18687
19231
|
}
|
|
18688
19232
|
/**
|
|
18689
|
-
* Ask a mint route
|
|
19233
|
+
* Ask a mint route, and come back only for the answers that say to.
|
|
18690
19234
|
*
|
|
18691
19235
|
* The offer is memoised on the three fields it is derived from, not rebuilt
|
|
18692
19236
|
* per render: `resolveTileMedia` returns a fresh object every call, and an
|
|
@@ -18694,8 +19238,12 @@ function clockOf(ms) {
|
|
|
18694
19238
|
* effect sets state, is an infinite render loop. It was one here, and it hung
|
|
18695
19239
|
* the suite rather than failing it.
|
|
18696
19240
|
*
|
|
18697
|
-
*
|
|
18698
|
-
* "
|
|
19241
|
+
* A FINAL refusal is latched for the life of the tile: a camera that just said
|
|
19242
|
+
* "asleep" is not asked again behind the operator's back. A DEFERRED one is
|
|
19243
|
+
* not a refusal at all — the still is queued — so the tile keeps showing
|
|
19244
|
+
* loading and re-asks on `planStillRetry`'s bounded, jittered schedule. When
|
|
19245
|
+
* that budget runs out the deferred answer becomes what the tile SAYS, so the
|
|
19246
|
+
* end state is words, never a blank box and never another request (D563).
|
|
18699
19247
|
*/
|
|
18700
19248
|
function useMintedStill(clip) {
|
|
18701
19249
|
const offered = useMemo(() => resolveTileMedia(clip), [
|
|
@@ -18710,7 +19258,8 @@ function useMintedStill(clip) {
|
|
|
18710
19258
|
if (mintUrl === null || typeof fetch !== "function") return void 0;
|
|
18711
19259
|
let objectUrl = null;
|
|
18712
19260
|
let cancelled = false;
|
|
18713
|
-
|
|
19261
|
+
let timer;
|
|
19262
|
+
const ask = async (attempt) => {
|
|
18714
19263
|
const answer = await fetchMintedThumbnail(hubPath(mintUrl), fetch);
|
|
18715
19264
|
if (cancelled) return;
|
|
18716
19265
|
if (answer.kind === "image") {
|
|
@@ -18721,10 +19270,31 @@ function useMintedStill(clip) {
|
|
|
18721
19270
|
});
|
|
18722
19271
|
return;
|
|
18723
19272
|
}
|
|
18724
|
-
|
|
18725
|
-
|
|
19273
|
+
if (answer.kind !== "deferred") {
|
|
19274
|
+
setLatched(answer);
|
|
19275
|
+
return;
|
|
19276
|
+
}
|
|
19277
|
+
const plan = planStillRetry({
|
|
19278
|
+
attempt,
|
|
19279
|
+
serverHintMs: answer.retryAfterMs,
|
|
19280
|
+
random: Math.random
|
|
19281
|
+
});
|
|
19282
|
+
if (plan === null) {
|
|
19283
|
+
setLatched({
|
|
19284
|
+
kind: "unavailable",
|
|
19285
|
+
reason: answer.reason,
|
|
19286
|
+
text: answer.text
|
|
19287
|
+
});
|
|
19288
|
+
return;
|
|
19289
|
+
}
|
|
19290
|
+
timer = setTimeout(() => {
|
|
19291
|
+
ask(attempt + 1);
|
|
19292
|
+
}, plan.waitMs);
|
|
19293
|
+
};
|
|
19294
|
+
ask(0);
|
|
18726
19295
|
return () => {
|
|
18727
19296
|
cancelled = true;
|
|
19297
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
18728
19298
|
if (objectUrl !== null) URL.revokeObjectURL(objectUrl);
|
|
18729
19299
|
};
|
|
18730
19300
|
}, [mintUrl]);
|
|
@@ -18748,16 +19318,27 @@ function ClipTile({ clip, selected, onSelect }) {
|
|
|
18748
19318
|
src: media.url,
|
|
18749
19319
|
alt: "",
|
|
18750
19320
|
className: "h-full w-full object-cover"
|
|
18751
|
-
}) : media.kind === "mint"
|
|
19321
|
+
}) : media.kind === "mint" || media.kind === "deferred" ? /* @__PURE__ */ jsx("span", {
|
|
19322
|
+
role: "status",
|
|
19323
|
+
"aria-label": media.kind === "mint" ? "Loading the still" : media.text,
|
|
19324
|
+
className: "h-full w-full",
|
|
19325
|
+
children: /* @__PURE__ */ jsx(Skeleton, { className: "h-full w-full rounded-none" })
|
|
19326
|
+
}) : /* @__PURE__ */ jsx("span", {
|
|
18752
19327
|
className: "px-1 text-center leading-tight",
|
|
18753
19328
|
children: media.text
|
|
18754
19329
|
})
|
|
18755
19330
|
}), /* @__PURE__ */ jsxs("div", {
|
|
18756
19331
|
className: "min-w-0 flex-1 space-y-1",
|
|
18757
19332
|
children: [
|
|
18758
|
-
/* @__PURE__ */
|
|
18759
|
-
className: "
|
|
18760
|
-
children:
|
|
19333
|
+
/* @__PURE__ */ jsxs("div", {
|
|
19334
|
+
className: "flex items-baseline gap-2",
|
|
19335
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
19336
|
+
className: "text-sm font-medium text-foreground",
|
|
19337
|
+
children: clockOf(clip.timeRange.startMs)
|
|
19338
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
19339
|
+
className: "text-[11px] text-foreground-subtle",
|
|
19340
|
+
children: clip.inProgress === true ? "Recording…" : formatDurationMs(clip.timeRange.endMs - clip.timeRange.startMs)
|
|
19341
|
+
})]
|
|
18761
19342
|
}),
|
|
18762
19343
|
/* @__PURE__ */ jsx("div", {
|
|
18763
19344
|
className: "text-[10px] text-foreground-subtle",
|
|
@@ -18784,6 +19365,29 @@ function ClipTile({ clip, selected, onSelect }) {
|
|
|
18784
19365
|
}
|
|
18785
19366
|
//#endregion
|
|
18786
19367
|
//#region src/composites/clips/clip-day-window.ts
|
|
19368
|
+
/**
|
|
19369
|
+
* LOCAL calendar-day arithmetic for the clips browser.
|
|
19370
|
+
*
|
|
19371
|
+
* The browser no longer NAVIGATES days — it follows a band selected on the
|
|
19372
|
+
* recording timebar (D564) — but the local day survived the move as the unit
|
|
19373
|
+
* the COST is counted in: a Reolink search is clamped to one camera-local day
|
|
19374
|
+
* per call, so `clip-band.ts` counts a band's local days to decide whether it
|
|
19375
|
+
* may be asked for. The window builder this file used to own went with the day
|
|
19376
|
+
* picker; `recording-timeline-model.ts`'s `dayWindow(date, nowMs)` is the one
|
|
19377
|
+
* that builds windows now, and one directory holding two functions of that
|
|
19378
|
+
* name was the confusion worth deleting.
|
|
19379
|
+
*
|
|
19380
|
+
* Two properties are pinned by spec because both are invisible until they are
|
|
19381
|
+
* wrong:
|
|
19382
|
+
*
|
|
19383
|
+
* - Deriving the day in UTC shifts every band by the browser's offset, and an
|
|
19384
|
+
* operator in Berlin would see a 22:00 clip filed under the next day.
|
|
19385
|
+
* - Walking days by adding 86 400 000 ms repeats or skips a calendar day
|
|
19386
|
+
* across a DST change. The walk goes through `Date`'s own day arithmetic.
|
|
19387
|
+
*
|
|
19388
|
+
* A day id is `YYYY-MM-DD` — it orders lexicographically, which is what lets
|
|
19389
|
+
* the band's day walk terminate on a comparison rather than on a count.
|
|
19390
|
+
*/
|
|
18787
19391
|
function pad2(value) {
|
|
18788
19392
|
return value < 10 ? `0${String(value)}` : String(value);
|
|
18789
19393
|
}
|
|
@@ -18796,16 +19400,6 @@ function startOfDay(dayId) {
|
|
|
18796
19400
|
function toDayId(instant) {
|
|
18797
19401
|
return `${String(instant.getFullYear())}-${pad2(instant.getMonth() + 1)}-${pad2(instant.getDate())}`;
|
|
18798
19402
|
}
|
|
18799
|
-
/** The half-open local-wall-clock window of one day. */
|
|
18800
|
-
function dayWindow$1(dayId) {
|
|
18801
|
-
const start = startOfDay(dayId);
|
|
18802
|
-
const end = startOfDay(dayId);
|
|
18803
|
-
end.setDate(end.getDate() + 1);
|
|
18804
|
-
return {
|
|
18805
|
-
since: start.getTime(),
|
|
18806
|
-
until: end.getTime()
|
|
18807
|
-
};
|
|
18808
|
-
}
|
|
18809
19403
|
/** Walk `days` calendar days from `dayId` — DST-safe, because `Date` does it. */
|
|
18810
19404
|
function shiftDay(dayId, days) {
|
|
18811
19405
|
const moved = startOfDay(dayId);
|
|
@@ -18813,11 +19407,12 @@ function shiftDay(dayId, days) {
|
|
|
18813
19407
|
return toDayId(moved);
|
|
18814
19408
|
}
|
|
18815
19409
|
/**
|
|
18816
|
-
* The day, spelled out
|
|
19410
|
+
* The day, spelled out — the calendar half of a band's label.
|
|
18817
19411
|
*
|
|
18818
|
-
* An empty list has to say WHICH
|
|
18819
|
-
* beside it is the ambiguity this surface exists to remove
|
|
18820
|
-
*
|
|
19412
|
+
* An empty list has to say WHICH period it is empty for; "no clips" with no
|
|
19413
|
+
* date beside it is the ambiguity this surface exists to remove. `formatBandLabel`
|
|
19414
|
+
* puts the times around it, and every state renders the result, not only the
|
|
19415
|
+
* populated one.
|
|
18821
19416
|
*/
|
|
18822
19417
|
function formatDayLabel(dayId) {
|
|
18823
19418
|
return startOfDay(dayId).toLocaleDateString(void 0, {
|
|
@@ -18827,6 +19422,77 @@ function formatDayLabel(dayId) {
|
|
|
18827
19422
|
day: "numeric"
|
|
18828
19423
|
});
|
|
18829
19424
|
}
|
|
19425
|
+
/** Defensive ceiling on the day walk so an inverted band can never loop. */
|
|
19426
|
+
var MAX_WALK_DAYS = 366;
|
|
19427
|
+
/**
|
|
19428
|
+
* How many LOCAL calendar days the half-open band touches.
|
|
19429
|
+
*
|
|
19430
|
+
* The end instant is exclusive, so a band that ends exactly at the next local
|
|
19431
|
+
* midnight is one day, not two — otherwise every whole-day band would report
|
|
19432
|
+
* double what it costs.
|
|
19433
|
+
*/
|
|
19434
|
+
function localDaysInBand(band) {
|
|
19435
|
+
const lastInstant = Math.max(band.fromMs, band.toMs - 1);
|
|
19436
|
+
const endDay = toDayId(new Date(lastInstant));
|
|
19437
|
+
let cursor = toDayId(new Date(band.fromMs));
|
|
19438
|
+
let days = 0;
|
|
19439
|
+
while (cursor <= endDay && days < MAX_WALK_DAYS) {
|
|
19440
|
+
days += 1;
|
|
19441
|
+
cursor = shiftDay(cursor, 1);
|
|
19442
|
+
}
|
|
19443
|
+
return days;
|
|
19444
|
+
}
|
|
19445
|
+
/** Whether this band may be asked for, and what it costs, in one value. */
|
|
19446
|
+
function planClipBand(band) {
|
|
19447
|
+
const localDays = localDaysInBand(band);
|
|
19448
|
+
if (localDays > 2) return {
|
|
19449
|
+
kind: "too-wide",
|
|
19450
|
+
band,
|
|
19451
|
+
localDays,
|
|
19452
|
+
maxLocalDays: 2
|
|
19453
|
+
};
|
|
19454
|
+
return {
|
|
19455
|
+
kind: "askable",
|
|
19456
|
+
band,
|
|
19457
|
+
localDays
|
|
19458
|
+
};
|
|
19459
|
+
}
|
|
19460
|
+
/**
|
|
19461
|
+
* The band for the current selection: the picked bucket, or — when nothing is
|
|
19462
|
+
* picked — the whole visible window.
|
|
19463
|
+
*
|
|
19464
|
+
* "Nothing picked means everything visible" is safe here and only here,
|
|
19465
|
+
* because the visible window is itself bounded by the timebar. It is never
|
|
19466
|
+
* "everything the camera holds" (D382's unstated ask).
|
|
19467
|
+
*/
|
|
19468
|
+
function bandForSelection(view, bucket) {
|
|
19469
|
+
if (bucket === null) return {
|
|
19470
|
+
fromMs: view.fromMs,
|
|
19471
|
+
toMs: view.toMs
|
|
19472
|
+
};
|
|
19473
|
+
return {
|
|
19474
|
+
fromMs: Math.max(bucket.startMs, view.fromMs),
|
|
19475
|
+
toMs: Math.min(bucket.endMs, view.toMs)
|
|
19476
|
+
};
|
|
19477
|
+
}
|
|
19478
|
+
function formatTime$2(instant) {
|
|
19479
|
+
return new Date(instant).toLocaleTimeString(void 0, {
|
|
19480
|
+
hour: "2-digit",
|
|
19481
|
+
minute: "2-digit"
|
|
19482
|
+
});
|
|
19483
|
+
}
|
|
19484
|
+
/**
|
|
19485
|
+
* The band, spelled out.
|
|
19486
|
+
*
|
|
19487
|
+
* Every state renders it — an empty list has to say WHICH period it is empty
|
|
19488
|
+
* for, the same rule the day label carried before the band replaced it.
|
|
19489
|
+
*/
|
|
19490
|
+
function formatBandLabel(band) {
|
|
19491
|
+
const fromDay = toDayId(new Date(band.fromMs));
|
|
19492
|
+
const toDay = toDayId(new Date(Math.max(band.fromMs, band.toMs - 1)));
|
|
19493
|
+
if (fromDay === toDay) return `${formatDayLabel(fromDay)}, ${formatTime$2(band.fromMs)} – ${formatTime$2(band.toMs)}`;
|
|
19494
|
+
return `${formatDayLabel(fromDay)} ${formatTime$2(band.fromMs)} – ${formatDayLabel(toDay)} ${formatTime$2(band.toMs)}`;
|
|
19495
|
+
}
|
|
18830
19496
|
//#endregion
|
|
18831
19497
|
//#region src/composites/clips/clip-source-state.ts
|
|
18832
19498
|
var STATE_COPY = {
|
|
@@ -18889,6 +19555,12 @@ function formatCatalogAge(catalogAsOf, now) {
|
|
|
18889
19555
|
//#endregion
|
|
18890
19556
|
//#region src/composites/clips/clip-view-state.ts
|
|
18891
19557
|
function resolveClipsView(input) {
|
|
19558
|
+
if (input.plan.kind === "too-wide") return {
|
|
19559
|
+
kind: "refused",
|
|
19560
|
+
band: input.plan.band,
|
|
19561
|
+
localDays: input.plan.localDays,
|
|
19562
|
+
maxLocalDays: input.plan.maxLocalDays
|
|
19563
|
+
};
|
|
18892
19564
|
if (input.clipsStatus === "error") return {
|
|
18893
19565
|
kind: "failed",
|
|
18894
19566
|
message: input.clipsError ?? "The clip list could not be read"
|
|
@@ -18897,14 +19569,21 @@ function resolveClipsView(input) {
|
|
|
18897
19569
|
kind: "failed",
|
|
18898
19570
|
message: input.sourcesError ?? "The source list could not be read"
|
|
18899
19571
|
};
|
|
18900
|
-
if (input.clipsStatus === "pending" || input.sourcesStatus === "pending") return { kind: "loading" };
|
|
18901
19572
|
const notices = input.sources.map(describeSource);
|
|
18902
19573
|
const answered = notices.filter((notice) => notice.answered);
|
|
18903
19574
|
const silent = notices.filter((notice) => !notice.answered);
|
|
18904
19575
|
const clips = input.clips;
|
|
19576
|
+
if (input.provider === null && input.sourcesStatus === "success") return {
|
|
19577
|
+
kind: "empty",
|
|
19578
|
+
band: input.plan.band,
|
|
19579
|
+
answered,
|
|
19580
|
+
silent,
|
|
19581
|
+
nobodyAnswered: true
|
|
19582
|
+
};
|
|
19583
|
+
if (input.clipsStatus === "pending" || input.sourcesStatus === "pending") return { kind: "loading" };
|
|
18905
19584
|
if (clips.length === 0) return {
|
|
18906
19585
|
kind: "empty",
|
|
18907
|
-
|
|
19586
|
+
band: input.plan.band,
|
|
18908
19587
|
answered,
|
|
18909
19588
|
silent,
|
|
18910
19589
|
nobodyAnswered: answered.length === 0
|
|
@@ -18955,6 +19634,28 @@ function resolveClipsView(input) {
|
|
|
18955
19634
|
* camera whose own index disagrees with its own calendar (618, 6–20
|
|
18956
19635
|
* September) is not quiet either.
|
|
18957
19636
|
*
|
|
19637
|
+
* ## The period comes from the recording section's timebar, not a day picker
|
|
19638
|
+
*
|
|
19639
|
+
* It shipped with its own `‹ day ›` pair and the operator replaced it the same
|
|
19640
|
+
* way he replaced the chrome: *"Possiamo utilizzare lo stesso componente della
|
|
19641
|
+
* sezione recording con la timebar dove selezionare un periodo e mostrare le
|
|
19642
|
+
* clip solo di quella banda selezionata, espandibile."* So the list follows a
|
|
19643
|
+
* BAND (D564) — `TimelineControls` for the day, the zoom and the pan,
|
|
19644
|
+
* `EventHeatmap` for picking a narrower window out of it, both of them the
|
|
19645
|
+
* pieces `RecordingTimeline` is itself built from, over the same
|
|
19646
|
+
* `recording-timeline-model`. Three things that are decisions, not details:
|
|
19647
|
+
*
|
|
19648
|
+
* - **The band lives HERE, once.** `ClipBandBar` is presentational. Two
|
|
19649
|
+
* components holding two ideas of the selected period is the defect this
|
|
19650
|
+
* repo keeps paying for, and the period is what the query is made of.
|
|
19651
|
+
* - **`CoverageTrack` stayed behind**, because there it is the seek surface
|
|
19652
|
+
* that moves the hero player's playhead. A copy here would be a dead bar or
|
|
19653
|
+
* a second claimant on that position.
|
|
19654
|
+
* - **A band is asked for only if it is affordable.** `clip-band.ts` counts
|
|
19655
|
+
* the LOCAL days it touches — the camera's own search is clamped to one per
|
|
19656
|
+
* call, and a day listing is 4.3–6.0 s on 592 — and refuses past the bound
|
|
19657
|
+
* by name rather than asking and rendering whichever days answered.
|
|
19658
|
+
*
|
|
18958
19659
|
* ## The picker WRITES nothing, and there is nothing for it to write
|
|
18959
19660
|
*
|
|
18960
19661
|
* A clip source is not enabled or disabled — it EXISTS, because of a
|
|
@@ -18971,23 +19672,34 @@ function resolveClipsView(input) {
|
|
|
18971
19672
|
* ## Why the picker is a SELECT and not a multiselect
|
|
18972
19673
|
*
|
|
18973
19674
|
* The operator asked for *"un multiselect common"* while `listClips` still
|
|
18974
|
-
* took `sources?: string[]`. It now takes ONE `provider` —
|
|
18975
|
-
*
|
|
18976
|
-
*
|
|
18977
|
-
*
|
|
18978
|
-
*
|
|
18979
|
-
*
|
|
18980
|
-
*
|
|
18981
|
-
*
|
|
19675
|
+
* took `sources?: string[]`. It now takes ONE `provider` —
|
|
19676
|
+
* *"l'utilizzatore è uno solo"* — and a multi-pick control over a
|
|
19677
|
+
* one-at-a-time argument offers a sum the hub cannot answer. So the control is
|
|
19678
|
+
* the shared single-choice one, `Select`: the same component the Recordings
|
|
19679
|
+
* page's own camera picker uses, which is what *"segue la nostra UI"* means
|
|
19680
|
+
* here.
|
|
19681
|
+
*
|
|
19682
|
+
* ## The control's value is ALWAYS what the query carries
|
|
19683
|
+
*
|
|
19684
|
+
* There is no "default" option and no empty value. This section used to send
|
|
19685
|
+
* no `provider` at all until the operator chose, because the cap documented
|
|
19686
|
+
* absence as "the device's bound provider, which is CamStack on every camera".
|
|
19687
|
+
* No code implemented that: measured on device 592 (2026-09-20, bound to
|
|
19688
|
+
* `recorder` AND `provider-reolink`) a bare `listClips` with `limit: 3`
|
|
19689
|
+
* answered SIX rows — three per source, merged — while the default option read
|
|
19690
|
+
* "CamStack recordings". The label named one thing and the query asked two.
|
|
19691
|
+
*
|
|
19692
|
+
* Naming a provider is now required (D554 amended), and the default is this surface's
|
|
19693
|
+
* to make: the FIRST source the camera lists, shown selected in the control, so
|
|
19694
|
+
* what is on screen and what was asked are the same fact. A camera that lists
|
|
19695
|
+
* no source is asked NOTHING — the query never fires and the body says nobody
|
|
19696
|
+
* answered, rather than spinning against a question with no addressee.
|
|
18982
19697
|
*
|
|
18983
19698
|
* ## One provider is a fleet STATE
|
|
18984
19699
|
*
|
|
18985
|
-
* `listSources` derives from `deviceManager.getBindings
|
|
18986
|
-
*
|
|
18987
|
-
*
|
|
18988
|
-
* single-entry control would read as a defect; the binding store learning to
|
|
18989
|
-
* hold several providers for a collection cap is what changes this, and
|
|
18990
|
-
* nothing here needs to change with it.
|
|
19700
|
+
* `listSources` derives from `deviceManager.getBindings`. A camera bound to one
|
|
19701
|
+
* provider makes the selector inert, and it SAYS why: an empty or silently
|
|
19702
|
+
* single-entry control would read as a defect.
|
|
18991
19703
|
*/
|
|
18992
19704
|
/** Newest-first, and bounded: a busy day on 592 lists 546 clips. */
|
|
18993
19705
|
var CLIP_PAGE_LIMIT = 500;
|
|
@@ -19074,24 +19786,54 @@ function SilentSources({ silent }) {
|
|
|
19074
19786
|
});
|
|
19075
19787
|
}
|
|
19076
19788
|
function ClipsSection({ deviceId }) {
|
|
19077
|
-
const [
|
|
19789
|
+
const [day, setDay] = useState(() => /* @__PURE__ */ new Date());
|
|
19790
|
+
const [view, setView] = useState(() => dayWindow(/* @__PURE__ */ new Date(), Date.now()));
|
|
19791
|
+
const [selectedBucket, setSelectedBucket] = useState(null);
|
|
19078
19792
|
const [provider, setProvider] = useState("");
|
|
19079
19793
|
const [page, setPage] = useState(1);
|
|
19080
19794
|
const [selectedClip, setSelectedClip] = useState(null);
|
|
19081
19795
|
const [profile, setProfile] = useState("low");
|
|
19082
19796
|
const presence = useCapabilityPresence("videoclips");
|
|
19083
|
-
const
|
|
19797
|
+
const dayBounds = useMemo(() => dayWindow(day, Date.now()), [day]);
|
|
19798
|
+
const bucketMs = bucketMsForSpan(view.toMs - view.fromMs);
|
|
19799
|
+
const density = usePipelineAnalyticsGetEventDensity({
|
|
19800
|
+
deviceId,
|
|
19801
|
+
since: view.fromMs,
|
|
19802
|
+
until: view.toMs,
|
|
19803
|
+
bucketMs
|
|
19804
|
+
});
|
|
19805
|
+
const buckets = useMemo(() => densityRowsToBuckets(density.data ?? [], view.fromMs, bucketMs), [
|
|
19806
|
+
density.data,
|
|
19807
|
+
view.fromMs,
|
|
19808
|
+
bucketMs
|
|
19809
|
+
]);
|
|
19810
|
+
const selected = selectedBucket === null ? void 0 : buckets.find((b) => b.index === selectedBucket);
|
|
19811
|
+
const band = useMemo(() => bandForSelection(view, selected === void 0 ? null : {
|
|
19812
|
+
startMs: selected.startMs,
|
|
19813
|
+
endMs: selected.endMs
|
|
19814
|
+
}), [view, selected]);
|
|
19815
|
+
const plan = planClipBand(band);
|
|
19084
19816
|
const sources = useVideoclipsListSources({ deviceId });
|
|
19817
|
+
const sourceRows = sources.data ?? [];
|
|
19818
|
+
/**
|
|
19819
|
+
* The provider the list is ASKED of: the operator's pick, else the first
|
|
19820
|
+
* source the camera lists. Empty only while the camera has no source at all
|
|
19821
|
+
* — and then nothing is asked, because there is nobody to ask.
|
|
19822
|
+
*/
|
|
19823
|
+
const askedProvider = useMemo(() => {
|
|
19824
|
+
if (provider !== "") return provider;
|
|
19825
|
+
return sourceRows.find((row) => row.addonId !== void 0)?.addonId ?? "";
|
|
19826
|
+
}, [provider, sourceRows]);
|
|
19085
19827
|
const clips = useVideoclipsListClips({
|
|
19086
19828
|
deviceId,
|
|
19087
|
-
since:
|
|
19088
|
-
until:
|
|
19829
|
+
since: band.fromMs,
|
|
19830
|
+
until: band.toMs,
|
|
19089
19831
|
limit: CLIP_PAGE_LIMIT,
|
|
19090
|
-
|
|
19091
|
-
});
|
|
19092
|
-
const
|
|
19093
|
-
|
|
19094
|
-
|
|
19832
|
+
provider: askedProvider
|
|
19833
|
+
}, { enabled: plan.kind === "askable" && askedProvider !== "" });
|
|
19834
|
+
const clipsView = resolveClipsView({
|
|
19835
|
+
plan,
|
|
19836
|
+
provider: askedProvider === "" ? null : askedProvider,
|
|
19095
19837
|
clipsStatus: clips.status,
|
|
19096
19838
|
clips: clips.data ?? [],
|
|
19097
19839
|
sourcesStatus: sources.status,
|
|
@@ -19109,23 +19851,29 @@ function ClipsSection({ deviceId }) {
|
|
|
19109
19851
|
if (labels === void 0) byAddon.set(addonId, [row.label]);
|
|
19110
19852
|
else labels.push(row.label);
|
|
19111
19853
|
}
|
|
19112
|
-
|
|
19854
|
+
return [...byAddon].map(([value, labels]) => ({
|
|
19113
19855
|
value,
|
|
19114
19856
|
label: labels.join(" · ")
|
|
19115
19857
|
}));
|
|
19116
|
-
const first = rest[0];
|
|
19117
|
-
return [{
|
|
19118
|
-
value: "",
|
|
19119
|
-
label: first === void 0 ? "The camera’s bound provider" : first.label
|
|
19120
|
-
}, ...rest.slice(1)];
|
|
19121
19858
|
}, [sourceRows]);
|
|
19122
19859
|
const tableRows = useMemo(() => sourceRows.map((row) => ({
|
|
19123
19860
|
notice: describeSource(row),
|
|
19124
19861
|
catalogAge: formatCatalogAge(row.availability.catalogAsOf, now)
|
|
19125
19862
|
})), [sourceRows]);
|
|
19126
|
-
|
|
19127
|
-
setDayId(next);
|
|
19863
|
+
useEffect(() => {
|
|
19128
19864
|
setPage(1);
|
|
19865
|
+
}, [band.fromMs, band.toMs]);
|
|
19866
|
+
const handleDayChange = (next) => {
|
|
19867
|
+
setDay(next);
|
|
19868
|
+
setView(dayWindow(next, Date.now()));
|
|
19869
|
+
setSelectedBucket(null);
|
|
19870
|
+
};
|
|
19871
|
+
const handleViewChange = (next) => {
|
|
19872
|
+
setView(next);
|
|
19873
|
+
setSelectedBucket(null);
|
|
19874
|
+
};
|
|
19875
|
+
const handleSelectBucket = (index) => {
|
|
19876
|
+
setSelectedBucket((current) => current === index ? null : index);
|
|
19129
19877
|
};
|
|
19130
19878
|
const pick = (next) => {
|
|
19131
19879
|
setProvider(next);
|
|
@@ -19152,18 +19900,25 @@ function ClipsSection({ deviceId }) {
|
|
|
19152
19900
|
description: "Nothing is installed that could list a camera's stored clips."
|
|
19153
19901
|
})
|
|
19154
19902
|
});
|
|
19155
|
-
const visible =
|
|
19903
|
+
const visible = clipsView.kind === "listed" ? clipsView.clips : [];
|
|
19156
19904
|
const pageClips = visible.slice((page - 1) * TILES_PER_PAGE, page * TILES_PER_PAGE);
|
|
19157
19905
|
return /* @__PURE__ */ jsxs("div", {
|
|
19158
19906
|
className: "space-y-3",
|
|
19159
19907
|
children: [
|
|
19160
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
19161
|
-
|
|
19162
|
-
|
|
19163
|
-
|
|
19164
|
-
|
|
19165
|
-
|
|
19166
|
-
|
|
19908
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
19909
|
+
/* @__PURE__ */ jsx("h3", {
|
|
19910
|
+
className: "text-sm font-semibold text-foreground",
|
|
19911
|
+
children: "Clips"
|
|
19912
|
+
}),
|
|
19913
|
+
/* @__PURE__ */ jsx("p", {
|
|
19914
|
+
className: "mt-1 text-[11px] text-foreground-subtle",
|
|
19915
|
+
children: "Every source this camera has, side by side — CamStack's own recordings and whatever the camera or an export keeps of its own. A source is listed because it exists, not because it was switched on here; pick sources to narrow the view."
|
|
19916
|
+
}),
|
|
19917
|
+
/* @__PURE__ */ jsx("p", {
|
|
19918
|
+
className: "mt-1 text-[11px] text-foreground-subtle",
|
|
19919
|
+
children: "The list follows the period selected on the timebar below — the recording section's own control. Zoom out to widen it, pan or pick a day to move it, click a density bar to narrow it to that window."
|
|
19920
|
+
})
|
|
19921
|
+
] }),
|
|
19167
19922
|
/* @__PURE__ */ jsxs("div", {
|
|
19168
19923
|
className: "flex flex-wrap items-center gap-2",
|
|
19169
19924
|
children: [
|
|
@@ -19177,7 +19932,7 @@ function ClipsSection({ deviceId }) {
|
|
|
19177
19932
|
children: /* @__PURE__ */ jsx(Select, {
|
|
19178
19933
|
id: "clips-provider",
|
|
19179
19934
|
options,
|
|
19180
|
-
value:
|
|
19935
|
+
value: askedProvider,
|
|
19181
19936
|
disabled: options.length < 2,
|
|
19182
19937
|
onChange: (e) => pick(e.target.value)
|
|
19183
19938
|
})
|
|
@@ -19188,32 +19943,28 @@ function ClipsSection({ deviceId }) {
|
|
|
19188
19943
|
}) : null,
|
|
19189
19944
|
/* @__PURE__ */ jsxs("div", {
|
|
19190
19945
|
className: "ml-auto flex items-center gap-1",
|
|
19191
|
-
children: [
|
|
19192
|
-
|
|
19193
|
-
|
|
19194
|
-
|
|
19195
|
-
|
|
19196
|
-
|
|
19197
|
-
|
|
19198
|
-
|
|
19199
|
-
className: "px-1 text-xs font-medium text-foreground",
|
|
19200
|
-
children: formatDayLabel(dayId)
|
|
19201
|
-
}),
|
|
19202
|
-
/* @__PURE__ */ jsx(Button, {
|
|
19203
|
-
variant: "ghost",
|
|
19204
|
-
"aria-label": "Next day",
|
|
19205
|
-
onClick: () => goToDay(shiftDay(dayId, 1)),
|
|
19206
|
-
children: "›"
|
|
19207
|
-
}),
|
|
19208
|
-
/* @__PURE__ */ jsx(Button, {
|
|
19209
|
-
variant: "outline",
|
|
19210
|
-
onClick: () => goToDay(toDayId(/* @__PURE__ */ new Date())),
|
|
19211
|
-
children: "Today"
|
|
19212
|
-
})
|
|
19213
|
-
]
|
|
19946
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
19947
|
+
className: "px-1 text-xs font-medium text-foreground",
|
|
19948
|
+
children: formatBandLabel(band)
|
|
19949
|
+
}), selectedBucket === null ? null : /* @__PURE__ */ jsx(Button, {
|
|
19950
|
+
variant: "outline",
|
|
19951
|
+
onClick: () => setSelectedBucket(null),
|
|
19952
|
+
children: "Expand to the visible window"
|
|
19953
|
+
})]
|
|
19214
19954
|
})
|
|
19215
19955
|
]
|
|
19216
19956
|
}),
|
|
19957
|
+
/* @__PURE__ */ jsx(ClipBandBar, {
|
|
19958
|
+
day,
|
|
19959
|
+
onDayChange: handleDayChange,
|
|
19960
|
+
view,
|
|
19961
|
+
dayBounds,
|
|
19962
|
+
onViewChange: handleViewChange,
|
|
19963
|
+
buckets,
|
|
19964
|
+
selectedBucketIndex: selectedBucket,
|
|
19965
|
+
onSelectBucket: handleSelectBucket,
|
|
19966
|
+
densityLoading: density.status === "pending"
|
|
19967
|
+
}),
|
|
19217
19968
|
/* @__PURE__ */ jsx("section", {
|
|
19218
19969
|
"aria-label": "Clip sources",
|
|
19219
19970
|
className: "space-y-1",
|
|
@@ -19230,26 +19981,30 @@ function ClipsSection({ deviceId }) {
|
|
|
19230
19981
|
/* @__PURE__ */ jsx("section", {
|
|
19231
19982
|
"aria-label": "Clips",
|
|
19232
19983
|
className: "space-y-2",
|
|
19233
|
-
children:
|
|
19984
|
+
children: clipsView.kind === "refused" ? /* @__PURE__ */ jsx(ErrorBox, {
|
|
19985
|
+
variant: "warning",
|
|
19986
|
+
title: "That period is too wide to list",
|
|
19987
|
+
message: `${formatBandLabel(clipsView.band)} covers ${String(clipsView.localDays)} local days, and a clip listing is asked one local day at a time — at most ${String(clipsView.maxLocalDays)}. Nothing was asked for; narrow the band and the list follows it.`
|
|
19988
|
+
}) : clipsView.kind === "loading" ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("div", {
|
|
19234
19989
|
role: "status",
|
|
19235
19990
|
className: "text-xs text-foreground-subtle",
|
|
19236
19991
|
children: [
|
|
19237
19992
|
"Loading clips for ",
|
|
19238
|
-
|
|
19993
|
+
formatBandLabel(band),
|
|
19239
19994
|
"…"
|
|
19240
19995
|
]
|
|
19241
|
-
}), /* @__PURE__ */ jsx(Skeleton, { className: "h-24 w-full" })] }) :
|
|
19996
|
+
}), /* @__PURE__ */ jsx(Skeleton, { className: "h-24 w-full" })] }) : clipsView.kind === "failed" ? /* @__PURE__ */ jsx(ErrorBox, {
|
|
19242
19997
|
title: "The clip list could not be read",
|
|
19243
|
-
message:
|
|
19244
|
-
}) :
|
|
19998
|
+
message: clipsView.message
|
|
19999
|
+
}) : clipsView.kind === "empty" ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("div", {
|
|
19245
20000
|
role: "status",
|
|
19246
20001
|
children: /* @__PURE__ */ jsx(EmptyState, {
|
|
19247
20002
|
icon: Film,
|
|
19248
|
-
title:
|
|
19249
|
-
...
|
|
20003
|
+
title: clipsView.nobodyAnswered ? `No source could answer for ${formatBandLabel(clipsView.band)}` : `No clips in ${formatBandLabel(clipsView.band)}`,
|
|
20004
|
+
...clipsView.nobodyAnswered ? {} : { description: `Asked ${clipsView.answered.map((notice) => notice.label).join(", ")}.` }
|
|
19250
20005
|
})
|
|
19251
|
-
}), /* @__PURE__ */ jsx(SilentSources, { silent:
|
|
19252
|
-
/* @__PURE__ */ jsx(SilentSources, { silent:
|
|
20006
|
+
}), /* @__PURE__ */ jsx(SilentSources, { silent: clipsView.silent })] }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
20007
|
+
/* @__PURE__ */ jsx(SilentSources, { silent: clipsView.silent }),
|
|
19253
20008
|
/* @__PURE__ */ jsx("ul", {
|
|
19254
20009
|
className: "grid grid-cols-1 gap-2 sm:grid-cols-2 xl:grid-cols-3",
|
|
19255
20010
|
children: pageClips.map((clip) => /* @__PURE__ */ jsx(ClipTile, {
|
|
@@ -21445,201 +22200,6 @@ function formatBytes(bytes) {
|
|
|
21445
22200
|
return `${value >= 100 ? Math.round(value).toString() : value.toFixed(1)} ${unit}`;
|
|
21446
22201
|
}
|
|
21447
22202
|
//#endregion
|
|
21448
|
-
//#region src/composites/cap-settings/recording-timeline-model.ts
|
|
21449
|
-
/** Tie-break precedence for a bucket's dominant kind (first wins on equal count). */
|
|
21450
|
-
var KIND_PRECEDENCE = [
|
|
21451
|
-
"object",
|
|
21452
|
-
"motion",
|
|
21453
|
-
"audio"
|
|
21454
|
-
];
|
|
21455
|
-
/**
|
|
21456
|
-
* Convert server-side density rows into `DensityBucket[]` for the timeline
|
|
21457
|
-
* heatmap. Rows with total === 0 are skipped (defensive; server already omits
|
|
21458
|
-
* them). Returns a sparse, ascending-by-index array — EventHeatmap positions
|
|
21459
|
-
* each bar by `b.startMs` rather than array index, so gaps are fine.
|
|
21460
|
-
*/
|
|
21461
|
-
function densityRowsToBuckets(rows, windowFrom, bucketMs) {
|
|
21462
|
-
const buckets = [];
|
|
21463
|
-
for (const row of rows) {
|
|
21464
|
-
const counts = {
|
|
21465
|
-
motion: row.motion,
|
|
21466
|
-
object: row.object,
|
|
21467
|
-
audio: row.audio
|
|
21468
|
-
};
|
|
21469
|
-
const total = counts.motion + counts.object + counts.audio;
|
|
21470
|
-
if (total === 0) continue;
|
|
21471
|
-
const index = Math.floor((row.bucketStart - windowFrom) / bucketMs);
|
|
21472
|
-
let dominant = null;
|
|
21473
|
-
let best = -1;
|
|
21474
|
-
for (const kind of KIND_PRECEDENCE) if (counts[kind] > best) {
|
|
21475
|
-
best = counts[kind];
|
|
21476
|
-
dominant = kind;
|
|
21477
|
-
}
|
|
21478
|
-
buckets.push({
|
|
21479
|
-
index,
|
|
21480
|
-
startMs: row.bucketStart,
|
|
21481
|
-
endMs: row.bucketStart + bucketMs,
|
|
21482
|
-
counts,
|
|
21483
|
-
total,
|
|
21484
|
-
dominant
|
|
21485
|
-
});
|
|
21486
|
-
}
|
|
21487
|
-
return buckets.toSorted((a, b) => a.index - b.index);
|
|
21488
|
-
}
|
|
21489
|
-
/** Distance from `ms` to the interval `[startMs, endMs]` (0 if inside). */
|
|
21490
|
-
function distanceToSpan(ms, span) {
|
|
21491
|
-
if (ms < span.startMs) return span.startMs - ms;
|
|
21492
|
-
if (ms > span.endMs) return ms - span.endMs;
|
|
21493
|
-
return 0;
|
|
21494
|
-
}
|
|
21495
|
-
/**
|
|
21496
|
-
* Resolve a playback window for a click at `clickMs` against recorded `spans`.
|
|
21497
|
-
* Inside a span → play from the click to that span's end. In a gap / outside →
|
|
21498
|
-
* snap to the WHOLE nearest span. No spans → null (nothing to play).
|
|
21499
|
-
* `spans` are expected ascending by start (as `mergeAvailabilitySpans` returns).
|
|
21500
|
-
*/
|
|
21501
|
-
function seekTargetForSpans(clickMs, spans) {
|
|
21502
|
-
if (spans.length === 0) return null;
|
|
21503
|
-
const containing = spans.find((s) => clickMs >= s.startMs && clickMs <= s.endMs);
|
|
21504
|
-
if (containing) return {
|
|
21505
|
-
fromMs: clickMs,
|
|
21506
|
-
toMs: containing.endMs
|
|
21507
|
-
};
|
|
21508
|
-
let nearest = null;
|
|
21509
|
-
let bestDist = Infinity;
|
|
21510
|
-
for (const s of spans) {
|
|
21511
|
-
const d = distanceToSpan(clickMs, s);
|
|
21512
|
-
if (d < bestDist) {
|
|
21513
|
-
bestDist = d;
|
|
21514
|
-
nearest = s;
|
|
21515
|
-
}
|
|
21516
|
-
}
|
|
21517
|
-
return nearest ? {
|
|
21518
|
-
fromMs: nearest.startMs,
|
|
21519
|
-
toMs: nearest.endMs
|
|
21520
|
-
} : null;
|
|
21521
|
-
}
|
|
21522
|
-
/**
|
|
21523
|
-
* Position `ms` inside the window `[fromMs, toMs]` as a clamped percentage
|
|
21524
|
-
* (0–100). A zero/negative-width window yields 0. Callers use this for `left:`.
|
|
21525
|
-
*/
|
|
21526
|
-
function pctForMs(ms, fromMs, toMs) {
|
|
21527
|
-
const span = toMs - fromMs;
|
|
21528
|
-
if (span <= 0) return 0;
|
|
21529
|
-
const pct = (ms - fromMs) / span * 100;
|
|
21530
|
-
if (pct < 0) return 0;
|
|
21531
|
-
if (pct > 100) return 100;
|
|
21532
|
-
return pct;
|
|
21533
|
-
}
|
|
21534
|
-
/**
|
|
21535
|
-
* Build a DayWindow for the given calendar `date` using local time.
|
|
21536
|
-
* For any day strictly in the past: `fromMs` = local midnight, `toMs` =
|
|
21537
|
-
* next local midnight (exactly 24 h).
|
|
21538
|
-
* For today (or any future day that contains `nowMs`): `toMs = nowMs` so the
|
|
21539
|
-
* window never extends into the future.
|
|
21540
|
-
*/
|
|
21541
|
-
function dayWindow(date, nowMs) {
|
|
21542
|
-
const fromMs = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0, 0).getTime();
|
|
21543
|
-
const nextMidnight = new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1, 0, 0, 0, 0).getTime();
|
|
21544
|
-
return {
|
|
21545
|
-
fromMs,
|
|
21546
|
-
toMs: Math.max(fromMs, Math.min(nextMidnight, nowMs))
|
|
21547
|
-
};
|
|
21548
|
-
}
|
|
21549
|
-
/** Available zoom levels in ms, from widest (24h) to narrowest (15 min). */
|
|
21550
|
-
var ZOOM_LEVELS = [
|
|
21551
|
-
24 * 36e5,
|
|
21552
|
-
12 * 36e5,
|
|
21553
|
-
6 * 36e5,
|
|
21554
|
-
36e5,
|
|
21555
|
-
15 * 6e4
|
|
21556
|
-
];
|
|
21557
|
-
/**
|
|
21558
|
-
* Produce a `levelMs`-wide window whose RIGHT edge stays anchored at
|
|
21559
|
-
* `rightEdgeMs` (clamped within `dayBounds`), rather than centring on the view
|
|
21560
|
-
* midpoint. On today's timeline the view's right edge is "now", so zooming this
|
|
21561
|
-
* way keeps the most recent footage pinned to the right instead of drifting to
|
|
21562
|
-
* a midday range that no longer contains now. Panning then moves back/forward.
|
|
21563
|
-
*
|
|
21564
|
-
* Falls back to `dayBounds` when `levelMs` meets or exceeds the day span (can't
|
|
21565
|
-
* show a wider window than the day holds — e.g. early morning with little
|
|
21566
|
-
* elapsed time).
|
|
21567
|
-
*/
|
|
21568
|
-
function zoomWindowAnchoredRight(dayBounds, levelMs, rightEdgeMs) {
|
|
21569
|
-
if (levelMs >= dayBounds.toMs - dayBounds.fromMs) return dayBounds;
|
|
21570
|
-
const toMs = Math.min(Math.max(rightEdgeMs, dayBounds.fromMs + levelMs), dayBounds.toMs);
|
|
21571
|
-
return {
|
|
21572
|
-
fromMs: toMs - levelMs,
|
|
21573
|
-
toMs
|
|
21574
|
-
};
|
|
21575
|
-
}
|
|
21576
|
-
/**
|
|
21577
|
-
* Shift `win` by `deltaMs`, preserving width, clamped within `dayBounds`.
|
|
21578
|
-
*/
|
|
21579
|
-
function panWindow(win, dayBounds, deltaMs) {
|
|
21580
|
-
const width = win.toMs - win.fromMs;
|
|
21581
|
-
let fromMs = win.fromMs + deltaMs;
|
|
21582
|
-
let toMs = win.toMs + deltaMs;
|
|
21583
|
-
if (fromMs < dayBounds.fromMs) {
|
|
21584
|
-
fromMs = dayBounds.fromMs;
|
|
21585
|
-
toMs = fromMs + width;
|
|
21586
|
-
}
|
|
21587
|
-
if (toMs > dayBounds.toMs) {
|
|
21588
|
-
toMs = dayBounds.toMs;
|
|
21589
|
-
fromMs = toMs - width;
|
|
21590
|
-
}
|
|
21591
|
-
return {
|
|
21592
|
-
fromMs,
|
|
21593
|
-
toMs
|
|
21594
|
-
};
|
|
21595
|
-
}
|
|
21596
|
-
/** Candidate bucket sizes in ms (coarsest first). */
|
|
21597
|
-
var BUCKET_CANDIDATES = [
|
|
21598
|
-
15 * 6e4,
|
|
21599
|
-
5 * 6e4,
|
|
21600
|
-
6e4,
|
|
21601
|
-
3e4,
|
|
21602
|
-
15e3,
|
|
21603
|
-
5e3
|
|
21604
|
-
];
|
|
21605
|
-
/**
|
|
21606
|
-
* Choose a sensible heatmap bucket size for a visible span of `spanMs`,
|
|
21607
|
-
* targeting ~96-120 buckets. Always picks from `BUCKET_CANDIDATES`.
|
|
21608
|
-
*/
|
|
21609
|
-
function bucketMsForSpan(spanMs) {
|
|
21610
|
-
const targetBucket = spanMs / 100;
|
|
21611
|
-
for (const candidate of BUCKET_CANDIDATES) if (candidate <= targetBucket) return candidate;
|
|
21612
|
-
return BUCKET_CANDIDATES[BUCKET_CANDIDATES.length - 1] ?? 5e3;
|
|
21613
|
-
}
|
|
21614
|
-
/**
|
|
21615
|
-
* Produce `count` evenly-spaced axis ticks spanning [fromMs, toMs].
|
|
21616
|
-
* - `pct` is via pctForMs (first=0, last=100).
|
|
21617
|
-
* - `label` is a localised HH:MM clock string.
|
|
21618
|
-
*/
|
|
21619
|
-
function axisTicks(fromMs, toMs, count) {
|
|
21620
|
-
if (count <= 1) return [{
|
|
21621
|
-
pct: 0,
|
|
21622
|
-
label: new Date(fromMs).toLocaleTimeString(void 0, {
|
|
21623
|
-
hour: "2-digit",
|
|
21624
|
-
minute: "2-digit"
|
|
21625
|
-
})
|
|
21626
|
-
}];
|
|
21627
|
-
const ticks = [];
|
|
21628
|
-
for (let i = 0; i < count; i++) {
|
|
21629
|
-
const ms = fromMs + i / (count - 1) * (toMs - fromMs);
|
|
21630
|
-
const pct = pctForMs(ms, fromMs, toMs);
|
|
21631
|
-
const label = new Date(ms).toLocaleTimeString(void 0, {
|
|
21632
|
-
hour: "2-digit",
|
|
21633
|
-
minute: "2-digit"
|
|
21634
|
-
});
|
|
21635
|
-
ticks.push({
|
|
21636
|
-
pct,
|
|
21637
|
-
label
|
|
21638
|
-
});
|
|
21639
|
-
}
|
|
21640
|
-
return ticks;
|
|
21641
|
-
}
|
|
21642
|
-
//#endregion
|
|
21643
22203
|
//#region src/composites/cap-settings/CoverageTrack.tsx
|
|
21644
22204
|
function CoverageTrack({ windowFrom, windowTo, spans, playheadMs, onSeek, onScrubStart, onScrubMove, onScrubEnd }) {
|
|
21645
22205
|
const [hoverInfo, setHoverInfo] = useState(null);
|
|
@@ -21750,42 +22310,6 @@ function CoverageTrack({ windowFrom, windowTo, spans, playheadMs, onSeek, onScru
|
|
|
21750
22310
|
});
|
|
21751
22311
|
}
|
|
21752
22312
|
//#endregion
|
|
21753
|
-
//#region src/composites/cap-settings/EventHeatmap.tsx
|
|
21754
|
-
var KIND_BG = {
|
|
21755
|
-
motion: "bg-emerald-500",
|
|
21756
|
-
object: "bg-violet-500",
|
|
21757
|
-
audio: "bg-orange-500"
|
|
21758
|
-
};
|
|
21759
|
-
function EventHeatmap({ windowFrom, windowTo, buckets, selectedIndex, onSelectBucket }) {
|
|
21760
|
-
const peak = buckets.reduce((m, b) => Math.max(m, b.total), 0);
|
|
21761
|
-
const firstBucket = buckets[0];
|
|
21762
|
-
const bucketWidthPct = firstBucket ? pctForMs(firstBucket.endMs, windowFrom, windowTo) - pctForMs(firstBucket.startMs, windowFrom, windowTo) : 0;
|
|
21763
|
-
return /* @__PURE__ */ jsx("div", {
|
|
21764
|
-
className: "relative h-6 rounded bg-background/40",
|
|
21765
|
-
children: buckets.map((b) => {
|
|
21766
|
-
if (b.total === 0 || b.dominant === null) return null;
|
|
21767
|
-
const heightPct = peak > 0 ? Math.max(15, b.total / peak * 100) : 0;
|
|
21768
|
-
const left = pctForMs(b.startMs, windowFrom, windowTo);
|
|
21769
|
-
const selected = b.index === selectedIndex;
|
|
21770
|
-
return /* @__PURE__ */ jsx("button", {
|
|
21771
|
-
type: "button",
|
|
21772
|
-
"data-testid": "heatmap-bar",
|
|
21773
|
-
title: `${new Date(b.startMs).toLocaleTimeString(void 0, {
|
|
21774
|
-
hour: "2-digit",
|
|
21775
|
-
minute: "2-digit"
|
|
21776
|
-
})} · motion ${b.counts.motion} · object ${b.counts.object}`,
|
|
21777
|
-
onClick: () => onSelectBucket(b.index),
|
|
21778
|
-
className: `absolute bottom-0 rounded-t-sm transition-opacity ${KIND_BG[b.dominant]} ${selected ? "opacity-100 ring-1 ring-amber-400" : "opacity-80 hover:opacity-100"}`,
|
|
21779
|
-
style: {
|
|
21780
|
-
left: `${left}%`,
|
|
21781
|
-
width: `${Math.max(.6, bucketWidthPct)}%`,
|
|
21782
|
-
height: `${heightPct}%`
|
|
21783
|
-
}
|
|
21784
|
-
}, b.index);
|
|
21785
|
-
})
|
|
21786
|
-
});
|
|
21787
|
-
}
|
|
21788
|
-
//#endregion
|
|
21789
22313
|
//#region src/composites/cap-settings/event-thumb.tsx
|
|
21790
22314
|
function EventThumb({ mediaUrl, kind }) {
|
|
21791
22315
|
const [failed, setFailed] = useState(false);
|
|
@@ -21910,142 +22434,6 @@ function EventBucketStrip({ clips, loading, busyKey, onPlay, enabledKinds, onTog
|
|
|
21910
22434
|
});
|
|
21911
22435
|
}
|
|
21912
22436
|
//#endregion
|
|
21913
|
-
//#region src/composites/cap-settings/TimelineControls.tsx
|
|
21914
|
-
/** Format a Date as "YYYY-MM-DD" for <input type="date">. */
|
|
21915
|
-
function formatDateInput(date) {
|
|
21916
|
-
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
|
|
21917
|
-
}
|
|
21918
|
-
/** Parse "YYYY-MM-DD" from <input type="date"> into a local-midnight Date. */
|
|
21919
|
-
function parseDateInput(value) {
|
|
21920
|
-
const parts = value.split("-");
|
|
21921
|
-
const y = parts[0] !== void 0 ? parseInt(parts[0], 10) : NaN;
|
|
21922
|
-
const m = parts[1] !== void 0 ? parseInt(parts[1], 10) : NaN;
|
|
21923
|
-
const d = parts[2] !== void 0 ? parseInt(parts[2], 10) : NaN;
|
|
21924
|
-
if (isNaN(y) || isNaN(m) || isNaN(d)) return null;
|
|
21925
|
-
return new Date(y, m - 1, d);
|
|
21926
|
-
}
|
|
21927
|
-
/**
|
|
21928
|
-
* Date selector + prev/next pan + zoom-in / zoom-out buttons for the recording
|
|
21929
|
-
* timeline. Zoom cycles through ZOOM_LEVELS (widest → narrowest), anchored on
|
|
21930
|
-
* the view's RIGHT edge — so on today's timeline "now" stays pinned to the right
|
|
21931
|
-
* instead of drifting to a midday range. The ◀ / ▶ buttons step the visible
|
|
21932
|
-
* window earlier/later within the day (the discoverable equivalent of the
|
|
21933
|
-
* horizontal wheel-pan wired in RecordingTimeline), so a zoomed-in day can be
|
|
21934
|
-
* navigated back and forth without a mouse wheel.
|
|
21935
|
-
*/
|
|
21936
|
-
function TimelineControls({ day, onDayChange, view, dayBounds, onViewChange }) {
|
|
21937
|
-
const handleDateChange = (e) => {
|
|
21938
|
-
const parsed = parseDateInput(e.target.value);
|
|
21939
|
-
if (parsed !== null) onDayChange(parsed);
|
|
21940
|
-
};
|
|
21941
|
-
const viewSpan = view.toMs - view.fromMs;
|
|
21942
|
-
const currentLevelIdx = (() => {
|
|
21943
|
-
let best = 0;
|
|
21944
|
-
let bestDiff = Infinity;
|
|
21945
|
-
for (let i = 0; i < ZOOM_LEVELS.length; i++) {
|
|
21946
|
-
const level = ZOOM_LEVELS[i];
|
|
21947
|
-
if (level === void 0) continue;
|
|
21948
|
-
const diff = Math.abs(level - viewSpan);
|
|
21949
|
-
if (diff < bestDiff) {
|
|
21950
|
-
bestDiff = diff;
|
|
21951
|
-
best = i;
|
|
21952
|
-
}
|
|
21953
|
-
}
|
|
21954
|
-
return best;
|
|
21955
|
-
})();
|
|
21956
|
-
const rightEdgeMs = view.toMs;
|
|
21957
|
-
const handleZoomIn = () => {
|
|
21958
|
-
const nextLevel = ZOOM_LEVELS[Math.min(currentLevelIdx + 1, ZOOM_LEVELS.length - 1)];
|
|
21959
|
-
if (nextLevel === void 0) return;
|
|
21960
|
-
onViewChange(zoomWindowAnchoredRight(dayBounds, nextLevel, rightEdgeMs));
|
|
21961
|
-
};
|
|
21962
|
-
const handleZoomOut = () => {
|
|
21963
|
-
const nextLevel = ZOOM_LEVELS[Math.max(currentLevelIdx - 1, 0)];
|
|
21964
|
-
if (nextLevel === void 0) return;
|
|
21965
|
-
onViewChange(zoomWindowAnchoredRight(dayBounds, nextLevel, rightEdgeMs));
|
|
21966
|
-
};
|
|
21967
|
-
const canZoomIn = currentLevelIdx < ZOOM_LEVELS.length - 1;
|
|
21968
|
-
const canZoomOut = currentLevelIdx > 0;
|
|
21969
|
-
const panStepMs = Math.max(1, Math.round(viewSpan * .9));
|
|
21970
|
-
const canPanPrev = view.fromMs > dayBounds.fromMs;
|
|
21971
|
-
const canPanNext = view.toMs < dayBounds.toMs;
|
|
21972
|
-
const handlePanPrev = () => {
|
|
21973
|
-
onViewChange(panWindow(view, dayBounds, -panStepMs));
|
|
21974
|
-
};
|
|
21975
|
-
const handlePanNext = () => {
|
|
21976
|
-
onViewChange(panWindow(view, dayBounds, panStepMs));
|
|
21977
|
-
};
|
|
21978
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
21979
|
-
className: "flex items-center gap-2",
|
|
21980
|
-
children: [
|
|
21981
|
-
/* @__PURE__ */ jsx("input", {
|
|
21982
|
-
type: "date",
|
|
21983
|
-
value: formatDateInput(day),
|
|
21984
|
-
max: formatDateInput(/* @__PURE__ */ new Date()),
|
|
21985
|
-
onChange: handleDateChange,
|
|
21986
|
-
className: "rounded border border-border bg-background px-2 py-0.5 text-[11px] text-foreground focus:outline-none focus:ring-1 focus:ring-primary",
|
|
21987
|
-
"aria-label": "Select recording day"
|
|
21988
|
-
}),
|
|
21989
|
-
/* @__PURE__ */ jsxs("div", {
|
|
21990
|
-
className: "ml-auto flex items-center gap-1",
|
|
21991
|
-
children: [
|
|
21992
|
-
/* @__PURE__ */ jsx("button", {
|
|
21993
|
-
type: "button",
|
|
21994
|
-
onClick: handlePanPrev,
|
|
21995
|
-
disabled: !canPanPrev,
|
|
21996
|
-
title: "Earlier (pan back)",
|
|
21997
|
-
"aria-label": "Pan earlier",
|
|
21998
|
-
className: "rounded p-1 text-foreground-subtle transition-colors hover:bg-background/60 hover:text-foreground disabled:cursor-not-allowed disabled:opacity-40",
|
|
21999
|
-
children: /* @__PURE__ */ jsx(ChevronLeft, { size: 14 })
|
|
22000
|
-
}),
|
|
22001
|
-
/* @__PURE__ */ jsx("button", {
|
|
22002
|
-
type: "button",
|
|
22003
|
-
onClick: handlePanNext,
|
|
22004
|
-
disabled: !canPanNext,
|
|
22005
|
-
title: "Later (pan forward)",
|
|
22006
|
-
"aria-label": "Pan later",
|
|
22007
|
-
className: "rounded p-1 text-foreground-subtle transition-colors hover:bg-background/60 hover:text-foreground disabled:cursor-not-allowed disabled:opacity-40",
|
|
22008
|
-
children: /* @__PURE__ */ jsx(ChevronRight, { size: 14 })
|
|
22009
|
-
}),
|
|
22010
|
-
/* @__PURE__ */ jsx("span", {
|
|
22011
|
-
className: "mx-0.5 h-3 w-px bg-border",
|
|
22012
|
-
"aria-hidden": "true"
|
|
22013
|
-
}),
|
|
22014
|
-
/* @__PURE__ */ jsx("button", {
|
|
22015
|
-
type: "button",
|
|
22016
|
-
onClick: handleZoomOut,
|
|
22017
|
-
disabled: !canZoomOut,
|
|
22018
|
-
title: "Zoom out",
|
|
22019
|
-
"aria-label": "Zoom out",
|
|
22020
|
-
className: "rounded p-1 text-foreground-subtle transition-colors hover:bg-background/60 hover:text-foreground disabled:cursor-not-allowed disabled:opacity-40",
|
|
22021
|
-
children: /* @__PURE__ */ jsx(ZoomOut, { size: 13 })
|
|
22022
|
-
}),
|
|
22023
|
-
/* @__PURE__ */ jsx("button", {
|
|
22024
|
-
type: "button",
|
|
22025
|
-
onClick: handleZoomIn,
|
|
22026
|
-
disabled: !canZoomIn,
|
|
22027
|
-
title: "Zoom in",
|
|
22028
|
-
"aria-label": "Zoom in",
|
|
22029
|
-
className: "rounded p-1 text-foreground-subtle transition-colors hover:bg-background/60 hover:text-foreground disabled:cursor-not-allowed disabled:opacity-40",
|
|
22030
|
-
children: /* @__PURE__ */ jsx(ZoomIn, { size: 13 })
|
|
22031
|
-
})
|
|
22032
|
-
]
|
|
22033
|
-
}),
|
|
22034
|
-
/* @__PURE__ */ jsx("span", {
|
|
22035
|
-
className: "text-[9px] text-foreground-subtle",
|
|
22036
|
-
children: zoomLabel(viewSpan)
|
|
22037
|
-
})
|
|
22038
|
-
]
|
|
22039
|
-
});
|
|
22040
|
-
}
|
|
22041
|
-
function zoomLabel(spanMs) {
|
|
22042
|
-
const h = spanMs / 36e5;
|
|
22043
|
-
if (h >= 24) return "24h";
|
|
22044
|
-
if (h >= 1) return `${Math.round(h)}h`;
|
|
22045
|
-
const m = spanMs / 6e4;
|
|
22046
|
-
return `${Math.round(m)}m`;
|
|
22047
|
-
}
|
|
22048
|
-
//#endregion
|
|
22049
22437
|
//#region src/composites/cap-settings/RecordingTimeline.tsx
|
|
22050
22438
|
var ALL_KINDS = [
|
|
22051
22439
|
"motion",
|
|
@@ -22441,15 +22829,6 @@ function RecordingTimeline({ deviceId }) {
|
|
|
22441
22829
|
//#endregion
|
|
22442
22830
|
//#region src/composites/cap-settings/RecordingPanel.tsx
|
|
22443
22831
|
var DAY_MS$1 = 1440 * 60 * 1e3;
|
|
22444
|
-
function formatDuration$1(ms) {
|
|
22445
|
-
const totalSec = Math.round(ms / 1e3);
|
|
22446
|
-
const h = Math.floor(totalSec / 3600);
|
|
22447
|
-
const m = Math.floor(totalSec % 3600 / 60);
|
|
22448
|
-
const s = totalSec % 60;
|
|
22449
|
-
if (h > 0) return `${h}h ${m}m`;
|
|
22450
|
-
if (m > 0) return `${m}m ${s}s`;
|
|
22451
|
-
return `${s}s`;
|
|
22452
|
-
}
|
|
22453
22832
|
function RecordingPanel({ deviceId }) {
|
|
22454
22833
|
const queryClient = useQueryClient();
|
|
22455
22834
|
const statusQuery = useRecordingGetStatus({ deviceId });
|
|
@@ -22549,7 +22928,7 @@ function RecordingPanel({ deviceId }) {
|
|
|
22549
22928
|
label: "Recorded (24h)",
|
|
22550
22929
|
icon: /* @__PURE__ */ jsx(Clock, { className: "h-3.5 w-3.5" }),
|
|
22551
22930
|
footer: `${ranges.length} segment range${ranges.length === 1 ? "" : "s"}`,
|
|
22552
|
-
children: availabilityQuery.isLoading ? "…" :
|
|
22931
|
+
children: availabilityQuery.isLoading ? "…" : formatDurationMs(recordedMs)
|
|
22553
22932
|
})
|
|
22554
22933
|
]
|
|
22555
22934
|
}),
|
|
@@ -53370,4 +53749,4 @@ var SceneMonitorEditor = lazy(() => import("./SceneMonitorEditor-BvDy3x3k.js").t
|
|
|
53370
53749
|
/** Lazy-wrapped `PrivacyMaskSettings` — code-split off the main bundle. */
|
|
53371
53750
|
var PrivacyMaskSettings = lazy(() => import("./PrivacyMaskSettings-PkYs077O.js").then((m) => ({ default: m.PrivacyMaskSettings })));
|
|
53372
53751
|
//#endregion
|
|
53373
|
-
export { AddonGlobalSettingsForm, AgentStepEditor, AlarmHeroCard, AlarmInlineControl as AlarmPanelInlineControl, AppShell, ArcKnob, AudioClassificationList, AudioLevelWaveform, AudioWaveform, AutomationHeroCard, AutomationInlineControl, AutotrackSection, BTN_COMPACT, BTN_COMPACT_DANGER, BTN_COMPACT_PRIMARY, BTN_COMPACT_WARNING, Badge, BatteryBadge, BottomSheet, Breadcrumb, BrightnessPanel, Button, ButtonControl, ButtonHeroCard, CARD_MODE_MIN_COLUMNS, CENTER, CHIP_ACTIVE, CHIP_BASE, CHIP_INACTIVE, CLASS_COLORS, COLUMN_BREAKPOINT_CLASS, COLUMN_PRIORITY, COMMIT_DEDUPE_TOLERANCE_MS, COMMIT_DEDUPE_WINDOW_MS, CONTROL_CAP_NAMES, CONTROL_FILLS, CameraStreamPlayer, Card, Checkbox, ChildSectionAccordion, ClimatePanel, CodeBlock, CollapsibleCard, ConfigFormBuilder, FormField as ConfigFormField, ConfigSchemaField, ConfirmActionButton, ConfirmDialogProvider, ConsumablesPanel, ContainerChildrenProvider, ContainerPrimaryHero, ControlColumn, ControlHeroCard, ControlInlineControl, ControlPanel, CopyButton, CoverHeroCard, CoverInlineControl, CoverPanel, CustomFieldRenderersProvider, DEFAULT_COLOR, DEVICE_COLUMNS, DEVICE_LIST_PAGE_SIZE_KEY, DEVICE_LIST_PAGE_SIZE_OPTIONS, DEVICE_ROLE_META, DEVICE_TYPE_CONTROL, DEVICE_TYPE_META, DISPLAY_ICON_REGISTRY, DataTable, DetectionCanvas, DetectionOverlay, DetectionResultTree, DevShell, DeviceActivityPanel, DeviceBatchToolbar, DeviceCard, DeviceContextProvider, DeviceExportPanel, DeviceGrid, DeviceItem, DeviceList, DeviceMultiSelectField, DeviceSelectField, DeviceSelectorPicker, DeviceStepMatrix, Dialog, DialogBody, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, DiscoveryPanel, DoorbellRecentPanel, Dropdown, DropdownContent, DropdownItem, DropdownTrigger, DummyHeroCard, DummyInline, EVENT_KIND_ICONS, EmptyState, ErrorBox, EventKindGlyph, EventStream, FILL, FLEET_LIST_GC_TIME_MS, FLEET_LIST_QUERY_KEY, FLEET_LIST_STALE_TIME_MS, FanHeroCard, FanInlineControl, FanPanel, FilterBar, FloatingEventStream, FloatingLogStream, FloatingPanel, FormField$1 as FormField, GRID_GAP, GRID_PAIRED, GRID_QUICK_STATS, GripTrack, GroupedModelSelector, HOST_WIDGETS, HlsVideo, HoverZoomImage, HumidifierHeroCard, HumidifierInlineControl, INPUT_COMPACT, IconAction, IconButton, ImageHeroCard, ImageInlineControl, ImageSelector, InferenceConfigSelector, Input, KebabMenu, KeyValueList, LIST_ROW, Label, LawnMowerHeroCard, LawnMowerInlineControl, LightHeroCard, LightInlineControl, LockHeroCard, LockInlineControl, LockPanel, LogStream, LoginForm, MODE_COLOR, MaskShapeCanvas, MediaPlayerHeroCard, MediaPlayerInlineControl, MediaPlayerPanel, MobileDrawer, ModelPicker, MotionZonesSettings, NAVIGATION_DRIVE_INTERVAL_MS, NavigationPanel, NetworkLinkBadge, NodeMultiSelectField, NodePicker, NodeSelectField, OfflineBadge, PHASE_CONFIG, PRIORITY, PTZOverlay, PageHeader, PhaseIcon, PipelineBuilder, PipelineRuntimeSelector, PipelineStep, PipelineTreeMatrix, PlayerOverlaysProvider, Popover, PopoverContent, PopoverRowAction, PopoverTrigger, PrimaryChildPicker, PrivacyMaskSettings, ProviderBadge, PtzPanel, QrCode, RECONNECT_POLICY, RECORDED_PLAYBACK_MODES, RIGHT, ROI_AREA_WARN_FRACTION, ROLE_DESCRIPTOR, RadialGauge, RecordedPlaybackProvider, RecordingPanel, ResponseLog, SCENE_CAPTURE_VARIANTS, SECTION_BODY, SECTION_CARD, SECTION_HEADER, SETTING_ROW, SETTING_ROW_LABEL, SETTING_ROW_STACK_BREAKPOINT, SETTING_ROW_VALUE, SETTING_ROW_VALUE_TEXT, SNAPSHOT_MEDIA_PATH, SPLIT_PANEL_OUTER, SPLIT_PANEL_SIDE, STACK_GAP, STATE_COLOR, SceneMonitorEditor, ScopePicker, ScriptHeroCard, ScriptInlineControl, ScrollArea, Select, SemanticBadge, SensorHeroCard, SensorInlineControl, SensorValueAtom, Separator, SettingRow, Sidebar, SidebarItem, Skeleton, SlideOverPanel, SlideToggle, SnapshotButton, SortHeaderButton, StatCard, StateValuesStream, StatusBadge, StepTimings, StepTreeMaster, Stepper, StreamBrokerSelector, StreamDebugOverlay, StreamPanel, Switch, SwitchHeroCard, SwitchInlineControl, SwitchPanel, SystemProvider, TABLE_SCROLL_MAX_H, TEXT_FIELD_LABEL, TEXT_HINT, TEXT_METRIC, TEXT_SECTION_LABEL, TEXT_VALUE, TIMEZONES, Tabs, TabsContent, TabsList, TabsTrigger, TapToggle, ThemeProvider, ThermostatHeroCard, ThermostatInlineControl, TimezoneSelector, Tooltip, TooltipContent, TooltipTrigger, VacuumHeroCard, VacuumInlineControl, ValueReadout, ValveHeroCard, ValveInlineControl, VersionBadge, VodPlaybackProvider, WaterHeaterHeroCard, WaterHeaterInlineControl, WeatherHeroCard, WeatherInlineControl, WidgetMetricCard, WidgetPanel, WidgetRegistryProvider, WidgetSlot, ZoneEditingProvider, ImageOff as a, agentColumnKey, allDeviceTypeFilterOptions, applyFleetQueryDefaults, ariaSortForColumn, badgeFor, buildStepTreeFromSchema, Camera as c, childEntityId, childListName, classifyCapability, cn, columnsForContext, containerChildToRef, countableDevices, coverHighlight, coverageLine, createSharedContext, createTheme, cursorFractionFor, darkColors, defaultTheme, deriveDeviceKind, deriveWebrtcDebugStats, describeDeviceSelector, deviceMatchesFilter, deviceOptionLabel, deviceRoleMeta, deviceRoleMetaOf, deviceTypeLabel, deviceTypeMeta, deviceTypeMetaOf, devicesToOptions, ensureMfHostInit, eventKindLabel, filterDeviceOptions, findTimezone, formatControlDateTime, formatLastSeen, formatNumeric, freezeVerdict, fuzzyMatch, getClassColor, getPhaseVisual, groupAgentColumns, groupChildrenByLayout, hardwareLabel, hubOrigin, hubPath, hubUrl, hubWsUrl, humanDuration, humidifierTint, Mic as i, initialScrubState, isAbsentProvider, isFieldVisible, createLucideIcon as l, lawnMowerActivityMeta, lightColors, loadRemoteBundle, makeScrubBridge, metadataEntries, metadataString, mirror, mountAddonPage, mountPath, Square as n, nextReconnectAction, nextSort, nextSortDirection, nextTableSort, normalizeForSearch, Grid2x2 as o, openTopLayer, overrideEntityIdFromLink, parseRecordedServerMessage, providerIcons, RotateCcw as r, resetHubMountForTests, resolveContainerPrimary, resolveControlAlign, resolveDeviceControl, resolveDisplayIcon, resolveEffectiveDefaultModel, resolveEffectiveStepModel, resolveEventKindIcon, resolvePrimaryChild, resolveSensorDisplay, resolveStepDefaultModel, resolveTableLayout, roiTooLarge, routerBasename, EyeOff as s, scrubReducer, selectedDeviceOptions, serializeRecordedCommand, shouldCommit, shouldEmit, shouldUseSingleNode, sortRows, sortRowsByColumn, statusIcons, statusLine, stepHasModelForFormat, stepModelOptions, stripParentNamePrefix, Trash2 as t, tabForSelector, tankAlert, themeToCss, toStationaryOverlayBox, trpc, useAccessoriesGetStatus, useAccessoriesSetChildHidden, useAddonPagesListPages, useAddonSettingsGetDeviceSettings, useAddonSettingsGetGlobalSettings, useAddonSettingsGetIntegrationSettings, useAddonSettingsUpdateDeviceSettings, useAddonSettingsUpdateGlobalSettings, useAddonWidgetsListWidgets, useAddonsApplyAutoUpdateToAll, useAddonsCancelJob, useAddonsCustom, useAddonsForceRefresh, useAddonsGetAddonAutoUpdate, useAddonsGetAutoUpdateSettings, useAddonsGetJob, useAddonsGetLastRestart, useAddonsGetLogs, useAddonsGetVersions, useAddonsInstallFromWorkspace, useAddonsInstallPackage, useAddonsIsWorkspaceAvailable, useAddonsList, useAddonsListCapabilityProviders, useAddonsListFrameworkPackages, useAddonsListJobs, useAddonsListPackages, useAddonsListUpdates, useAddonsListWorkspacePackages, useAddonsOnAddonLogs, useAddonsReloadPackages, useAddonsRestartAddon, useAddonsRestartServer, useAddonsRetryLoad, useAddonsRollbackPackage, useAddonsSearchAvailable, useAddonsSetAddonAutoUpdate, useAddonsSetAutoUpdateSettings, useAddonsSetCapabilityProviderEnabled, useAddonsStartJob, useAddonsUninstallPackage, useAddonsUpdatePackage, useAirQualitySensorGetStatus, useAlarmPanelArm, useAlarmPanelDisarm, useAlarmPanelGetStatus, useAlarmPanelTrigger, useAlert, useAlertsDismiss, useAlertsEmit, useAlertsGetUnreadCount, useAlertsList, useAlertsMarkAllRead, useAlertsMarkRead, useAlertsUpdate, useAllWidgets, useAmbientLightSensorGetStatus, useAudioAnalysisApplyDeviceSettingsPatch, useAudioAnalysisGetDeviceLiveContribution, useAudioAnalysisGetDeviceSettingsContribution, useAudioAnalysisResolveDeviceSettings, useAudioAnalyzerAnalyseChunk, useAudioAnalyzerAttachDevice, useAudioAnalyzerClassify, useAudioAnalyzerDetachDevice, useAudioAnalyzerDispose, useAudioAnalyzerIsReady, useAudioAnalyzerReprobeAudioEngine, useAudioCodecCanHandle, useAudioCodecCloseSession, useAudioCodecCreateDecodeSession, useAudioCodecCreateEncodeSession, useAudioCodecFlushEncode, useAudioCodecListActiveSessions, useAudioCodecListSupportedCodecs, useAudioCodecPullEncoded, useAudioCodecPullPcm, useAudioCodecPushEncodedFrame, useAudioCodecPushPcm, useAudioMetricsGetCurrentSnapshot, useAudioMetricsGetHistory, useAutomationControlDisable, useAutomationControlEnable, useAutomationControlGetStatus, useAutomationControlTrigger, useBackupCancel, useBackupDelete, useBackupDeleteSchedule, useBackupGetEntries, useBackupList, useBackupListArchives, useBackupListDestinations, useBackupListLocations, useBackupListRuns, useBackupListSchedules, useBackupPreviewSchedule, useBackupRestore, useBackupTrigger, useBackupUpsertDestinationPolicy, useBackupUpsertSchedule, useBatteryGetStatus, useBatteryWakeForStream, useBinaryGetStatus, useBrightnessGetStatus, useBrightnessSetBrightness, useBrokerAdd, useBrokerGet, useBrokerGetBrokerConfig, useBrokerGetSettings, useBrokerGetSettingsSchema, useBrokerGetState, useBrokerGetStatus, useBrokerList, useBrokerListProviders, useBrokerPublish, useBrokerRemove, useBrokerSetSettings, useBrokerSubscribe, useBrokerTestConnection, useBrokerTestSettings, useBrokerUnsubscribe, useButtonPress, useCameraCredentialsGetCredentials, useCameraCredentialsGetStatus, useCameraGridLayoutApplyDeviceSettingsPatch, useCameraGridLayoutGetDeviceLiveContribution, useCameraGridLayoutGetDeviceSettingsContribution, useCameraGridLayoutGetLayout, useCameraGridLayoutSaveLayout, useCameraPipelineConfigApplyDeviceSettingsPatch, useCameraPipelineConfigGetDeviceLiveContribution, useCameraPipelineConfigGetDeviceSettingsContribution, useCameraStreamsGetBrokerStreams, useCameraStreamsGetCameraStreams, useCameraStreamsGetProfileRtspEntries, useCameraStreamsGetRtspEntries, useCameraStreamsPickStream, useCapabilityPresence, useCarbonMonoxideGetStatus, useClimateControlGetStatus, useClimateControlSetFanMode, useClimateControlSetMode, useClimateControlSetPreset, useClimateControlSetSwingHorizontal, useClimateControlSetSwingVertical, useClimateControlSetTarget, useClimateControlSetTargetHumidity, useClimateControlSetTargetRange, useClusterNodes, useClusterTopology, useColorGetStatus, useColorSetColor, useConfirm, useConnectionTestDescribeTest, useConnectionTestTestSettings, useConnectivityGetStatus, useConsumablesGetStatus, useConsumablesReset, useContactGetStatus, useContainerChildren, useControlGetStatus, useControlSetValue, useCoreBlocksCompile, useCoreBlocksCreate, useCoreBlocksDelete, useCoreBlocksGet, useCoreBlocksGetTypeDefs, useCoreBlocksList, useCoreBlocksRestart, useCoreBlocksSetEnabled, useCoreBlocksUpdate, useCoverClose, useCoverGetStatus, useCoverOpen, useCoverSetPosition, useCoverSetTiltPosition, useCoverStop, useCustomFieldRenderer, useDayNightGetOptions, useDayNightGetStatus, useDayNightSetSettings, useDebouncedString, useDecoderCreateSession, useDecoderDestroySession, useDecoderGetFrame, useDecoderGetInfo, useDecoderGetShmStats, useDecoderGetStats, useDecoderListActiveSessions, useDecoderOpenStream, useDecoderPullFrames, useDecoderPullHandles, useDecoderPushPacket, useDecoderReprobeHwaccel, useDecoderSupportsCodec, useDecoderUpdateConfig, useDetectionPipelineApplyDeviceSettingsPatch, useDetectionPipelineGetDeviceLiveContribution, useDetectionPipelineGetDeviceSettingsContribution, useDevShell, useDevice, useDeviceAdoptionAdopt, useDeviceAdoptionGetCandidate, useDeviceAdoptionGetStatus, useDeviceAdoptionListCandidateFilters, useDeviceAdoptionListCandidates, useDeviceAdoptionRefresh, useDeviceAdoptionRelease, useDeviceAdoptionResync, useDeviceAutotrack, useDeviceBattery, useDeviceCapSlice, useDeviceCapability, useDeviceDetections, useDeviceDiscoveryAdoptDevice, useDeviceDiscoveryGetStatus, useDeviceDiscoveryListDiscovered, useDeviceDiscoveryRefreshDiscovery, useDeviceDiscoveryReleaseDevice, useDeviceExportApplyDeviceSettingsPatch, useDeviceExportExposeDevice, useDeviceExportGetDeviceLiveContribution, useDeviceExportGetDeviceSettingsContribution, useDeviceExportGetStatus, useDeviceExportListExposedDevices, useDeviceExportListSupportedDeviceKinds, useDeviceExportUnexposeDevice, useDeviceId, useDeviceListPageSize, useDeviceManagerAddLocation, useDeviceManagerAdoptDevice, useDeviceManagerAdoptionAdopt, useDeviceManagerAdoptionCancelJob, useDeviceManagerAdoptionListCandidateFilters, useDeviceManagerAdoptionListCandidates, useDeviceManagerAdoptionListJobs, useDeviceManagerAdoptionRefresh, useDeviceManagerAdoptionRelease, useDeviceManagerAdoptionResync, useDeviceManagerAdoptionStartJob, useDeviceManagerAllocateDeviceId, useDeviceManagerApplyDeviceSettingsPatch, useDeviceManagerApplyInitialMeta, useDeviceManagerCreateDevice, useDeviceManagerDisable, useDeviceManagerDiscoverAllProviders, useDeviceManagerDiscoverDevices, useDeviceManagerDiscoverProvider, useDeviceManagerDiscoveryProviders, useDeviceManagerEnable, useDeviceManagerGetAllBindings, useDeviceManagerGetBindings, useDeviceManagerGetBindingsBatch, useDeviceManagerGetChildren, useDeviceManagerGetChildrenBatch, useDeviceManagerGetConfigSchema, useDeviceManagerGetCreationSchema, useDeviceManagerGetDevice, useDeviceManagerGetDeviceAggregate, useDeviceManagerGetDeviceLiveContribution, useDeviceManagerGetDeviceLiveInfoAggregate, useDeviceManagerGetDeviceSettingsAggregate, useDeviceManagerGetDeviceSettingsContribution, useDeviceManagerGetDeviceStatusAggregate, useDeviceManagerGetDeviceStatusAggregateBatch, useDeviceManagerGetLinkedDevices, useDeviceManagerGetLinkedDevicesBatch, useDeviceManagerGetRoleDisplayDefaults, useDeviceManagerGetSettingsSchema, useDeviceManagerGetStreamProfileMap, useDeviceManagerGetStreamSources, useDeviceManagerGetWireableFields, useDeviceManagerListAll, useDeviceManagerListBindableCapsForDeviceType, useDeviceManagerListLocationDescriptions, useDeviceManagerListLocationIcons, useDeviceManagerListLocations, useDeviceManagerListPersistedByAddon, useDeviceManagerListSiteZones, useDeviceManagerListWrappersForCap, useDeviceManagerLoadConfig, useDeviceManagerLoadMeta, useDeviceManagerLoadRuntimeState, useDeviceManagerMigrateDevice, useDeviceManagerPersistConfig, useDeviceManagerProbeStreams, useDeviceManagerProviderCreationType, useDeviceManagerProviderDiscoveryParamsSchema, useDeviceManagerRegisterDevice, useDeviceManagerRemove, useDeviceManagerRemoveByIntegration, useDeviceManagerRemoveDevice, useDeviceManagerRemoveLocation, useDeviceManagerRemoveSiteZone, useDeviceManagerRenameLocation, useDeviceManagerRenameSiteZone, useDeviceManagerRunDeviceAction, useDeviceManagerSetChildLayout, useDeviceManagerSetDisabled, useDeviceManagerSetDisplay, useDeviceManagerSetIntegrationId, useDeviceManagerSetLinkDeviceId, useDeviceManagerSetLocation, useDeviceManagerSetLocationDescription, useDeviceManagerSetLocationIcon, useDeviceManagerSetLocationZone, useDeviceManagerSetMetadata, useDeviceManagerSetName, useDeviceManagerSetPrimaryChildEntityId, useDeviceManagerSetRole, useDeviceManagerSetRoleDisplayDefaults, useDeviceManagerSetSiteZone, useDeviceManagerSetStreamProfileMap, useDeviceManagerSetType, useDeviceManagerSetWrapperActive, useDeviceManagerTestCreationField, useDeviceManagerTestField, useDeviceManagerUpdateConfig, useDeviceManagerUpdateDeviceField, useDeviceManagerUpdateDeviceFieldsBatch, useDeviceNetworkLink, useDeviceOpsGetConfigEntries, useDeviceOpsGetRawState, useDeviceOpsGetSettingsSchema, useDeviceOpsGetStreamSources, useDeviceOpsRemoveDevice, useDeviceOpsRunAction, useDeviceOpsSetConfig, useDeviceProviderAdoptDiscoveredDevice, useDeviceProviderCreateDevice, useDeviceProviderDiscoverDevices, useDeviceProviderGetChildCreationSchema, useDeviceProviderGetDevices, useDeviceProviderGetDiscoveryParamsSchema, useDeviceProviderGetManualCreationType, useDeviceProviderGetStatus, useDeviceProviderReloadDevice, useDeviceProviderStart, useDeviceProviderStop, useDeviceProviderSupportsDiscovery, useDeviceProviderSupportsManualCreation, useDeviceProviderTestCreationField, useDeviceProxy, useDeviceSnapshot, useDeviceSnapshotImage, useDeviceState, useDeviceStateGetAllSnapshots, useDeviceStateGetCapSlice, useDeviceStateGetSnapshot, useDeviceStateSetCapSlice, useDeviceStateSlice, useDeviceStatusGetStatus, useDeviceWebrtc, useDevices, useDoorbellApplyDeviceSettingsPatch, useDoorbellEvents, useDoorbellGetDeviceLiveContribution, useDoorbellGetDeviceSettingsContribution, useDoorbellGetStatus, useEnumSensorGetStatus, useEventEmitterGetStatus, useEventInvalidation, useEventStreamLatest, useEventStreamMap, useEventsGetEventClipUrl, useEventsGetEventThumbnail, useEventsGetEvents, useFaceGalleryAssignFace, useFaceGalleryAssignFaces, useFaceGalleryAuditIdentitySamples, useFaceGalleryCreateIdentity, useFaceGalleryDeleteFace, useFaceGalleryDeleteIdentity, useFaceGalleryGetFaceByTrack, useFaceGalleryGetFaceMedia, useFaceGalleryListIdentities, useFaceGalleryListIdentitySamples, useFaceGalleryListRecentFaces, useFaceGalleryRemoveSample, useFaceGalleryRenameIdentity, useFaceGallerySuggestFaceClusters, useFaceGalleryUnassignFace, useFaceGalleryUnassignFaces, useFanControlGetStatus, useFanControlSetDirection, useFanControlSetOscillating, useFanControlSetPercentage, useFanControlSetPreset, useFeatureProbeGetStatus, useFloodGetStatus, useGasGetStatus, useHumidifierGetStatus, useHumidifierSetMode, useHumidifierSetOn, useHumidifierSetTargetHumidity, useHumiditySensorGetStatus, useImageGetStatus, useImageSettingsGetOptions, useImageSettingsGetStatus, useImageSettingsSetSettings, useIntegrationsCreate, useIntegrationsDelete, useIntegrationsGet, useIntegrationsGetAvailableTypes, useIntegrationsGetByAddonId, useIntegrationsGetSettings, useIntegrationsList, useIntegrationsSetSettings, useIntegrationsTestConnection, useIntegrationsUpdate, useIntercomEndTalkSession, useIntercomGetStatus, useIntercomHandleAnswer, useIntercomPushTalkAudio, useIntercomStartSession, useIntercomStartTalkSession, useIntercomStopSession, useIsMidWidth, useIsMobile, useLawnMowerControlDock, useLawnMowerControlGetStatus, useLawnMowerControlPause, useLawnMowerControlStartMowing, useLiveBuffer, useLiveEvent, useLlmCancel, useLlmDeleteModel, useLlmDeleteProfile, useLlmGenerate, useLlmGenerateVision, useLlmGetDefaults, useLlmGetRuntimeStatus, useLlmGetUsage, useLlmInstallModel, useLlmListModelCatalog, useLlmListModels, useLlmListNodeModels, useLlmListProfileKinds, useLlmListProfiles, useLlmListRuntimeNodes, useLlmResolveModelRef, useLlmSetDefault, useLlmStartRuntime, useLlmStopRuntime, useLlmTestProfile, useLlmUpsertProfile, useLocalNetworkDownloadCa, useLocalNetworkGetAllowedAddresses, useLocalNetworkGetConnectionEndpoints, useLocalNetworkGetNotificationEndpoint, useLocalNetworkGetPreferred, useLocalNetworkGetTlsStatus, useLocalNetworkGetViewerEndpoints, useLocalNetworkList, useLocalNetworkRegenerateCertificate, useLocalNetworkResetAllowlistToBestMatch, useLocalNetworkRevertToGeneratedCertificate, useLocalNetworkSetAllowedAddresses, useLocalNetworkSetNotificationEndpoint, useLocalNetworkSetViewerEndpoints, useLocalNetworkUploadCertificate, useLockControlGetStatus, useLockControlLock, useLockControlOpen, useLockControlUnlock, useMediaPlayerGetStatus, useMediaPlayerNext, useMediaPlayerPause, useMediaPlayerPlay, useMediaPlayerPlayMedia, useMediaPlayerPrevious, useMediaPlayerSeek, useMediaPlayerSelectSource, useMediaPlayerSetMute, useMediaPlayerSetRepeat, useMediaPlayerSetShuffle, useMediaPlayerSetVolume, useMediaPlayerStop, useMeshNetworkGetStatus, useMeshNetworkJoin, useMeshNetworkLeave, useMeshNetworkListPeers, useMeshNetworkLogout, useMeshNetworkStartLogin, useMeshNetworkTestConnection, useMetricsProviderCollectSnapshot, useMetricsProviderGetAddonStats, useMetricsProviderGetCached, useMetricsProviderGetCpuTemperature, useMetricsProviderGetCurrent, useMetricsProviderGetDiskSpace, useMetricsProviderGetGpuInfo, useMetricsProviderGetLoadSeries, useMetricsProviderGetProcessStats, useMetricsProviderListAddonInstances, useMetricsProviderListNodeProcesses, useMotionDetectionAnalyze, useMotionDetectionApplyDeviceSettingsPatch, useMotionDetectionGetDeviceLiveContribution, useMotionDetectionGetDeviceSettingsContribution, useMotionDetectionRemoveCamera, useMotionDetectionReset, useMotionGetStatus, useMotionIsDetected, useMotionTriggerGetStatus, useMotionTriggerSetMotionTrigger, useMotionZonesGetOptions, useMotionZonesGetStatus, useMotionZonesSetZone, useMqttBrokerAddBroker, useMqttBrokerGetBrokerConfig, useMqttBrokerGetStatus, useMqttBrokerListBrokers, useMqttBrokerRemoveBroker, useMqttBrokerStartEmbeddedBroker, useMqttBrokerStopEmbeddedBroker, useMqttBrokerTestConnection, useNativeObjectDetectionGetOptions, useNativeObjectDetectionGetStatus, useNativeObjectDetectionSetEnabled, useNativeObjectDetectionSetSettings, useNavigation, useNavigationGetFeatures, useNavigationGetStatus, useNavigationGoToPoint, useNavigationListActions, useNavigationMove, useNavigationPlaySound, useNavigationRunAction, useNavigationSetLightLevel, useNavigationSetLightMode, useNavigationSetLightOn, useNavigationStop, useNetworkAccessGetEndpoint, useNetworkAccessGetStatus, useNetworkAccessListEndpoints, useNetworkAccessStart, useNetworkAccessStop, useNetworkLinkGetStatus, useNetworkQualityGetAllStats, useNetworkQualityGetDeviceStats, useNetworkQualityReportClientStats, useNodesClusterAddonStatus, useNodesDeployAddon, useNodesExecuteQuery, useNodesGetCapUsageGraph, useNodesGetNodeAddons, useNodesRenameNode, useNodesRestartAddon, useNodesRestartNode, useNodesRestartProcess, useNodesSetProcessLogLevel, useNodesShutdownNode, useNodesTopology, useNodesUndeployAddon, useNotificationOutputDeleteTarget, useNotificationOutputDiscoverTargets, useNotificationOutputListTargetKinds, useNotificationOutputListTargets, useNotificationOutputSend, useNotificationOutputSetTargetEnabled, useNotificationOutputTestTarget, useNotificationOutputUpsertTarget, useNotificationRulesCancelSnooze, useNotificationRulesCreateRule, useNotificationRulesCreateSnooze, useNotificationRulesDeleteRule, useNotificationRulesGetAlarmConfig, useNotificationRulesGetClipRetentionAsks, useNotificationRulesGetConditionCatalog, useNotificationRulesGetHistory, useNotificationRulesGetRule, useNotificationRulesListDeviceMutes, useNotificationRulesListRules, useNotificationRulesListSnoozes, useNotificationRulesResolveArtifactUrl, useNotificationRulesSetAlarmConfig, useNotificationRulesSetDeviceMuted, useNotificationRulesSetRuleEnabled, useNotificationRulesTestRule, useNotificationRulesUpdateRule, useNotifierCancel, useNotifierGetStatus, useNotifierSend, useNumericSensorGetStatus, useOptimisticSlice, useOptionalSystem, useOptionalWidgetRegistry, useOsdGetStatus, useOsdManagerClearSlotBinding, useOsdManagerCopyDeviceConfiguration, useOsdManagerGetConditionSupport, useOsdManagerGetDeviceOsd, useOsdManagerGetSourceCatalog, useOsdManagerPreviewSlot, useOsdManagerRenderDevice, useOsdManagerSetSlotBinding, useOsdSetOverlay, usePTZ, usePetFeederCallPet, usePetFeederCancelFeed, usePetFeederFeed, usePetFeederGetStatus, usePetFeederMarkFoodReplenished, usePetFeederPlaySound, usePetFeederResetDesiccant, usePetFeederSetChildLock, usePetFeederSetFeedSound, usePetFeederSetIndicatorLight, usePetFeederSetVolume, usePipelineAnalyticsApplyDeviceSettingsPatch, usePipelineAnalyticsCancelRelocateMedia, usePipelineAnalyticsCancelStorageMigrationMove, usePipelineAnalyticsClearTracks, usePipelineAnalyticsCompleteRetrainTrack, usePipelineAnalyticsCountRelocatableMedia, usePipelineAnalyticsCountUnstampedEventMedia, usePipelineAnalyticsDeleteDeviceEvents, usePipelineAnalyticsDeleteTracks, usePipelineAnalyticsDeselectRetrainFrame, usePipelineAnalyticsGetActiveTracks, usePipelineAnalyticsGetAudioEvents, usePipelineAnalyticsGetDeviceLiveContribution, usePipelineAnalyticsGetDeviceSettingsContribution, usePipelineAnalyticsGetEventDensity, usePipelineAnalyticsGetEventDensityBatch, usePipelineAnalyticsGetEventMedia, usePipelineAnalyticsGetEventMediaFootprintByKind, usePipelineAnalyticsGetEventStoreFootprint, usePipelineAnalyticsGetKeyEvents, usePipelineAnalyticsGetKeyEventsBatch, usePipelineAnalyticsGetMediaReclaimStatus, usePipelineAnalyticsGetMotionEvents, usePipelineAnalyticsGetObjectEmbeddingRebuildStatus, usePipelineAnalyticsGetObjectEvents, usePipelineAnalyticsGetRetrainExportUrl, usePipelineAnalyticsGetRetrainFrameImage, usePipelineAnalyticsGetSensorEvents, usePipelineAnalyticsGetStorageMigrationMoveStatus, usePipelineAnalyticsGetSummary, usePipelineAnalyticsGetTrack, usePipelineAnalyticsGetTrackMedia, usePipelineAnalyticsGetTrainingExportSummary, usePipelineAnalyticsGetTrainingExportUrl, usePipelineAnalyticsListArchivedDebugNotes, usePipelineAnalyticsListBirthDecisions, usePipelineAnalyticsListEventKinds, usePipelineAnalyticsListEventKindsBatch, usePipelineAnalyticsListEventMedia, usePipelineAnalyticsListOpsLog, usePipelineAnalyticsListRecentSummaries, usePipelineAnalyticsListRecentTracks, usePipelineAnalyticsListRelocateMediaJobs, usePipelineAnalyticsListRetrainAnnotations, usePipelineAnalyticsListRetrainFrames, usePipelineAnalyticsListRetrainStaging, usePipelineAnalyticsListSummaries, usePipelineAnalyticsListTrackMedia, usePipelineAnalyticsListTracks, usePipelineAnalyticsPauseForStorageMigration, usePipelineAnalyticsProposeRetrainAnnotations, usePipelineAnalyticsPruneEvents, usePipelineAnalyticsPruneEventsBefore, usePipelineAnalyticsPruneTracksBefore, usePipelineAnalyticsReadLongTermSeries, usePipelineAnalyticsRebuildObjectEmbeddings, usePipelineAnalyticsReclaimDebugMedia, usePipelineAnalyticsReconcileFromDisk, usePipelineAnalyticsRefreshStorageLocationsForMigration, usePipelineAnalyticsRelocateMedia, usePipelineAnalyticsRestageRetrainTrack, usePipelineAnalyticsResumeForStorageMigration, usePipelineAnalyticsRunReplayFrameProcessor, usePipelineAnalyticsSaveRetrainAnnotations, usePipelineAnalyticsSearchObjectEvents, usePipelineAnalyticsSelectRetrainFrames, usePipelineAnalyticsSetTrackFlags, usePipelineAnalyticsStartStorageMigrationMove, usePipelineAnalyticsWipeAllAnalytics, usePipelineAnalyticsWipeObjectEmbeddings, usePipelineExecutorCacheFrameInPool, usePipelineExecutorClearDeviceOverrides, usePipelineExecutorDeleteModel, usePipelineExecutorDeleteTemplate, usePipelineExecutorDownloadModel, usePipelineExecutorGetAddonModels, usePipelineExecutorGetAudioCapabilities, usePipelineExecutorGetAvailableEngines, usePipelineExecutorGetCapabilities, usePipelineExecutorGetDefaultSteps, usePipelineExecutorGetDetectionConfigSchema, usePipelineExecutorGetEffectiveTuning, usePipelineExecutorGetEngineProvisioning, usePipelineExecutorGetGlobalPipelineConfig, usePipelineExecutorGetGlobalSteps, usePipelineExecutorGetInferenceDeviceHealth, usePipelineExecutorGetOrchestratorConfigSchema, usePipelineExecutorGetReferenceAudio, usePipelineExecutorGetReferenceAudioFiles, usePipelineExecutorGetReferenceImage, usePipelineExecutorGetSchema, usePipelineExecutorGetSelectedEngine, usePipelineExecutorGetVideoPipelineSteps, usePipelineExecutorInferCached, usePipelineExecutorKillEngine, usePipelineExecutorListLoadedEngines, usePipelineExecutorListReferenceImages, usePipelineExecutorListTemplates, usePipelineExecutorRearmInferenceDevice, usePipelineExecutorRunAudioTest, usePipelineExecutorRunPipeline, usePipelineExecutorRunPipelineBatch, usePipelineExecutorSaveTemplate, usePipelineExecutorSetVideoPipelineSteps, usePipelineExecutorSpinEngine, usePipelineExecutorUncacheFrame, usePipelineExecutorUpdateTemplate, usePipelineExecutorValidatePipeline, usePipelineOrchestratorApplyDeviceSettingsPatch, usePipelineOrchestratorAssignAudio, usePipelineOrchestratorAssignPipeline, usePipelineOrchestratorDeleteTemplate, usePipelineOrchestratorGetAgentLoad, usePipelineOrchestratorGetAgentSettings, usePipelineOrchestratorGetAudioAssignment, usePipelineOrchestratorGetAudioAssignments, usePipelineOrchestratorGetAudioNodeLoad, usePipelineOrchestratorGetCameraMetrics, usePipelineOrchestratorGetCameraSettings, usePipelineOrchestratorGetCameraStatus, usePipelineOrchestratorGetCameraStatuses, usePipelineOrchestratorGetCameraStepOverrides, usePipelineOrchestratorGetCameraSwitches, usePipelineOrchestratorGetCapabilityBindings, usePipelineOrchestratorGetDeviceLiveContribution, usePipelineOrchestratorGetDeviceSettingsContribution, usePipelineOrchestratorGetGlobalMetrics, usePipelineOrchestratorGetIngestOwner, usePipelineOrchestratorGetNodeInferenceDevices, usePipelineOrchestratorGetPipelineAssignment, usePipelineOrchestratorGetPipelineAssignments, usePipelineOrchestratorGetPipelineDevicePin, usePipelineOrchestratorGetReconcileFromDiskStatus, usePipelineOrchestratorListAgentSettings, usePipelineOrchestratorListTemplates, usePipelineOrchestratorPauseForStorageMigration, usePipelineOrchestratorRebalance, usePipelineOrchestratorReconcileFromDisk, usePipelineOrchestratorRemoveAgentSettings, usePipelineOrchestratorResetNodePipelineDefaults, usePipelineOrchestratorResolvePipeline, usePipelineOrchestratorResumeForStorageMigration, usePipelineOrchestratorSaveTemplate, usePipelineOrchestratorSetAgentCapabilities, usePipelineOrchestratorSetAgentDecodeLimits, usePipelineOrchestratorSetAgentDetectWeight, usePipelineOrchestratorSetAgentInferenceDevices, usePipelineOrchestratorSetAgentMaxCameras, usePipelineOrchestratorSetAgentReachableHost, usePipelineOrchestratorSetCameraPipelineForAgent, usePipelineOrchestratorSetCameraStepOverride, usePipelineOrchestratorSetCameraStepToggle, usePipelineOrchestratorSetCameraSwitch, usePipelineOrchestratorSetCapabilityBinding, usePipelineOrchestratorSetPipelineDevicePin, usePipelineOrchestratorUnassignAudio, usePipelineOrchestratorUnassignPipeline, usePipelineOrchestratorUpdateTemplate, usePipelineRunnerAttachCamera, usePipelineRunnerDetachCamera, usePipelineRunnerGetAllCameraMetrics, usePipelineRunnerGetCameraMetrics, usePipelineRunnerGetLocalCameras, usePipelineRunnerGetLocalLoad, usePipelineRunnerGetLocalMetrics, usePipelineRunnerGetNativeCrop, usePipelineRunnerGetParkedTrackFrame, usePipelineRunnerParkTrackFrame, usePipelineRunnerReleaseParkedTrackFrames, usePipelineRunnerReportMotion, usePipelineRunnerRequestOccupancyBurst, usePipelineRunnerRunDetailSubtree, usePipelineRunnerRunStatelessStep, usePlateGalleryAssignPlate, usePlateGalleryAssignPlates, usePlateGalleryCorrectPlateText, usePlateGalleryCreateVehicle, usePlateGalleryDeletePlate, usePlateGalleryDeleteVehicle, usePlateGalleryGetPlateByTrack, usePlateGalleryGetPlateMedia, usePlateGalleryListPlates, usePlateGalleryListVehicleSamples, usePlateGalleryListVehicles, usePlateGalleryRemoveVehicleSample, usePlateGalleryRenameVehicle, usePlateGallerySearchPlates, usePlateGallerySuggestPlateClusters, usePlateGalleryUnassignPlate, usePlateGalleryUnassignPlates, usePlayerOverlayLayer, usePlayerOverlayLayers, usePlayerToolbarButton, usePlayerToolbarButtons, usePowerMeterGetStatus, usePresenceGetStatus, usePressureSensorGetStatus, usePrivacyMaskGetOptions, usePrivacyMaskGetStatus, usePrivacyMaskSetAudioEnabled, usePrivacyMaskSetMask, usePrompt, usePtzAutotrackGetSettings, usePtzAutotrackGetStatus, usePtzAutotrackSetEnabled, usePtzAutotrackSetSettings, usePtzCaptureHomeHere, usePtzContinuousMove, usePtzDeletePreset, usePtzGetHomePreset, usePtzGetHomeReturn, usePtzGetOptions, usePtzGetPosition, usePtzGetPresets, usePtzGetStatus, usePtzGoHome, usePtzGoToPreset, usePtzMove, usePtzSavePreset, usePtzSetAutofocus, usePtzSetHomePreset, usePtzSetHomeReturn, usePtzStop, useRebootReboot, useRecordedPlayback, useRecordingApplyDeviceSettingsPatch, useRecordingCancelRelocateJob, useRecordingCancelStorageMigrationMove, useRecordingDeleteFootprint, useRecordingExportCancelExport, useRecordingExportCreateExport, useRecordingExportDeleteExport, useRecordingExportGetDownloadUrl, useRecordingExportGetExport, useRecordingExportListExports, useRecordingExportReadExportBytes, useRecordingGetAvailability, useRecordingGetAvailabilityBatch, useRecordingGetDaysWithRecordings, useRecordingGetDaysWithRecordingsBatch, useRecordingGetDeviceConfig, useRecordingGetDeviceLiveContribution, useRecordingGetDeviceSettingsContribution, useRecordingGetPlacement, useRecordingGetPlaybackManifest, useRecordingGetRelocateResidue, useRecordingGetStatus, useRecordingGetStorageMigrationMoveStatus, useRecordingGetStorageUsage, useRecordingListOpsLog, useRecordingListRelocateJobs, useRecordingLocateSegment, useRecordingPauseForStorageMigration, useRecordingPlanStorageRebalance, useRecordingPruneFootage, useRecordingReadGopBytes, useRecordingReadSegmentBytes, useRecordingReadWindowBytes, useRecordingReconcileLedgerAgainstDisk, useRecordingRefreshStorageLocationsForMigration, useRecordingRelocateFootage, useRecordingRenderClip, useRecordingRenderGif, useRecordingRescanStorage, useRecordingResumeForStorageMigration, useRecordingSetDeviceConfig, useRecordingSetDevicePlacement, useRecordingSignalGetStatus, useRecordingStartStorageMigrationMove, useRecordingStartStorageRebalance, useRemoteComponent, useSceneMonitorCaptureReference, useSceneMonitorCreateScene, useSceneMonitorDeleteReference, useSceneMonitorDeleteScene, useSceneMonitorGetStatus, useSceneMonitorListScenes, useSceneMonitorListScenesBatch, useSceneMonitorRecheckNow, useSceneMonitorResetScene, useSceneMonitorUpdateScene, useScriptRunnerGetStatus, useScriptRunnerRun, useScriptRunnerStop, useScrubController, useServerManagementApplyServerUpdate, useServerManagementCheckServerUpdate, useServerManagementGetServerPackageStatus, useServerManagementRestartServer, useServerManagementRollbackServerUpdate, useSettingsStoreAggregate, useSettingsStoreCount, useSettingsStoreDeclareCollection, useSettingsStoreDelete, useSettingsStoreDeleteWhere, useSettingsStoreGet, useSettingsStoreHistogram, useSettingsStoreInsert, useSettingsStoreInsertMany, useSettingsStoreIsEmpty, useSettingsStoreQuery, useSettingsStoreSet, useSettingsStoreUpdate, useSettingsStoreUpdateWhere, useSettingsStoreUpsert, useSmokeGetStatus, useSnapshotApplyDeviceSettingsPatch, useSnapshotGetDebugState, useSnapshotGetDeviceLiveContribution, useSnapshotGetDeviceSettingsContribution, useSnapshotGetSnapshot, useSnapshotGetSnapshotLinks, useSnapshotGetSnapshotOverview, useSnapshotGetStatus, useSnapshotInvalidateCache, useStationaryOverlay, useStorageAbortUpload, useStorageBeginDownload, useStorageBeginUpload, useStorageDelete, useStorageDeleteLocation, useStorageEndDownload, useStorageExists, useStorageFinalizeUpload, useStorageGetAvailableSpace, useStorageList, useStorageListDrainProgress, useStorageListLocationDeclarations, useStorageListLocations, useStorageListProviders, useStorageMigrationCancel, useStorageMigrationCleanupCancel, useStorageMigrationCleanupStart, useStorageMigrationCleanupStatus, useStorageMigrationDrain, useStorageMigrationHistory, useStorageMigrationMovers, useStorageMigrationPlan, useStorageMigrationResidue, useStorageMigrationStart, useStorageMigrationStatus, useStorageRead, useStorageReadChunk, useStorageResolve, useStorageTestConfig, useStorageTestLocation, useStorageUpsertLocation, useStorageWrite, useStorageWriteChunk, useStreamBrokerAcquireEgressTranscode, useStreamBrokerApplyDeviceSettingsPatch, useStreamBrokerAssignProfile, useStreamBrokerFetchEventMedia, useStreamBrokerForgetDeviceHardware, useStreamBrokerGetAllRtspEntries, useStreamBrokerGetBrokerStats, useStreamBrokerGetDeviceAudioMute, useStreamBrokerGetDeviceLiveContribution, useStreamBrokerGetDeviceSettingsContribution, useStreamBrokerGetPreBufferInfo, useStreamBrokerGetRtspEntry, useStreamBrokerGetRtspPort, useStreamBrokerGetStreamUrl, useStreamBrokerGetStreamWithCodec, useStreamBrokerIsRtspEnabled, useStreamBrokerKillClient, useStreamBrokerListAllCameraStreams, useStreamBrokerListAllProfileSlots, useStreamBrokerListClients, useStreamBrokerProbeStream, useStreamBrokerProduceEventMedia, useStreamBrokerPublishCameraStream, useStreamBrokerPullAudioChunks, useStreamBrokerPullFrameHandles, useStreamBrokerRegenerateRtspToken, useStreamBrokerReleaseEgressTranscode, useStreamBrokerReleaseStreamWithCodec, useStreamBrokerRenderPreBufferClip, useStreamBrokerReportStreamSignal, useStreamBrokerRestartProfile, useStreamBrokerRetractCameraStream, useStreamBrokerSetDeviceAudioMute, useStreamBrokerSetPreBufferDuration, useStreamBrokerSetRtspEnabled, useStreamBrokerSubscribeAudioChunks, useStreamBrokerSubscribeFrames, useStreamBrokerUnassignProfile, useStreamBrokerUnsubscribeAudioChunks, useStreamBrokerUnsubscribeFrames, useStreamCatalogGetCatalog, useStreamParamsGetConfigSchema, useStreamParamsGetOptions, useStreamParamsGetStatus, useStreamParamsSetProfile, useStreamSignalsListSignals, useSwitchGetStatus, useSwitchSetState, useSystem, useSystemDetectSiteLocation, useSystemFeatureFlags, useSystemForceRetentionCleanup, useSystemGetFailureContributions, useSystemGetLoadContributions, useSystemGetLoggingSettings, useSystemGetRequestCensus, useSystemGetRetentionConfig, useSystemGetSiteLocation, useSystemHealth, useSystemInfo, useSystemMutation, useSystemNetworkAddresses, useSystemQuery, useSystemSetLoggingSettings, useSystemSetRetentionConfig, useSystemSetSiteLocation, useTamperGetStatus, useTemperatureSensorGetStatus, useTerminalSessionAdoptLegacyMonitor, useTerminalSessionClose, useTerminalSessionCreateInstance, useTerminalSessionDeleteInstance, useTerminalSessionListInstances, useTerminalSessionListLegacyCameras, useTerminalSessionListProfiles, useTerminalSessionListSessions, useTerminalSessionOpenSession, useTerminalSessionPullOutput, useTerminalSessionResize, useTerminalSessionSetInstanceEnabled, useTerminalSessionUpdateInstance, useTerminalSessionWriteInput, useThemeMode, useToastOnToast, useTurnProviderGetTurnServers, useUpdateGetStatus, useUpdateInstallUpdate, useUserManagementConfirmTotp, useUserManagementCreateApiKey, useUserManagementCreateScopedToken, useUserManagementCreateUser, useUserManagementDeleteUser, useUserManagementDisableTotp, useUserManagementGetTotpStatus, useUserManagementListApiKeys, useUserManagementListOauthSessions, useUserManagementListScopedTokens, useUserManagementListUsers, useUserManagementOauthExchangeCode, useUserManagementOauthIssueCode, useUserManagementOauthRefresh, useUserManagementOauthVerifyAccessToken, useUserManagementResetPassword, useUserManagementRevokeApiKey, useUserManagementRevokeOauthSession, useUserManagementRevokeScopedToken, useUserManagementSetUserScopes, useUserManagementSetupTotp, useUserManagementUpdateUser, useUserManagementValidateApiKey, useUserManagementValidateCredentials, useUserManagementValidateScopedToken, useUserManagementVerifyTotp, useVacuumControlGetStatus, useVacuumControlLocate, useVacuumControlPause, useVacuumControlReturnToBase, useVacuumControlSetFanSpeed, useVacuumControlStart, useVacuumControlStop, useValveClose, useValveGetStatus, useValveOpen, useValveSetPosition, useValveStop, useVibrationGetStatus, useVideoclipsGetClipPlayback, useVideoclipsListClips, useVideoclipsListSources, useVodPlayback, useWaterHeaterGetStatus, useWaterHeaterSetAway, useWaterHeaterSetOperationMode, useWaterHeaterSetTargetTemp, useWeatherGetStatus, useWebrtcSessionAddIceCandidate, useWebrtcSessionCloseSession, useWebrtcSessionCreateSession, useWebrtcSessionGetIceCandidates, useWebrtcSessionGetSessionDebug, useWebrtcSessionGetSessionState, useWebrtcSessionHandleAnswer, useWebrtcSessionHandleOffer, useWebrtcSessionHasAdaptiveBitrate, useWebrtcSessionListStreams, useWidget, useWidgetMetadata, useWidgetRegistry, useZoneAnalyticsGetCameraHistory, useZoneAnalyticsGetCurrentSnapshot, useZoneAnalyticsGetCurrentSnapshotBatch, useZoneAnalyticsGetUnzonedHistory, useZoneAnalyticsGetZoneHistory, useZoneEditing, useZoneRulesListRules, useZoneRulesSetRules, useZonesAddZone, useZonesListZones, useZonesRemoveZone, useZonesUpdateZone, vacuumStateMeta, validateScopes, valveStateMeta, variantLabel, waterHeaterPhase, waterHeaterTint, weatherConditionMeta, weatherTint };
|
|
53752
|
+
export { AddonGlobalSettingsForm, AgentStepEditor, AlarmHeroCard, AlarmInlineControl as AlarmPanelInlineControl, AppShell, ArcKnob, AudioClassificationList, AudioLevelWaveform, AudioWaveform, AutomationHeroCard, AutomationInlineControl, AutotrackSection, BTN_COMPACT, BTN_COMPACT_DANGER, BTN_COMPACT_PRIMARY, BTN_COMPACT_WARNING, Badge, BatteryBadge, BottomSheet, Breadcrumb, BrightnessPanel, Button, ButtonControl, ButtonHeroCard, CARD_MODE_MIN_COLUMNS, CENTER, CHIP_ACTIVE, CHIP_BASE, CHIP_INACTIVE, CLASS_COLORS, COLUMN_BREAKPOINT_CLASS, COLUMN_PRIORITY, COMMIT_DEDUPE_TOLERANCE_MS, COMMIT_DEDUPE_WINDOW_MS, CONTROL_CAP_NAMES, CONTROL_FILLS, CameraStreamPlayer, Card, Checkbox, ChildSectionAccordion, ClimatePanel, CodeBlock, CollapsibleCard, ConfigFormBuilder, FormField as ConfigFormField, ConfigSchemaField, ConfirmActionButton, ConfirmDialogProvider, ConsumablesPanel, ContainerChildrenProvider, ContainerPrimaryHero, ControlColumn, ControlHeroCard, ControlInlineControl, ControlPanel, CopyButton, CoverHeroCard, CoverInlineControl, CoverPanel, CustomFieldRenderersProvider, DEFAULT_COLOR, DEVICE_COLUMNS, DEVICE_LIST_PAGE_SIZE_KEY, DEVICE_LIST_PAGE_SIZE_OPTIONS, DEVICE_ROLE_META, DEVICE_TYPE_CONTROL, DEVICE_TYPE_META, DISPLAY_ICON_REGISTRY, DataTable, DetectionCanvas, DetectionOverlay, DetectionResultTree, DevShell, DeviceActivityPanel, DeviceBatchToolbar, DeviceCard, DeviceContextProvider, DeviceExportPanel, DeviceGrid, DeviceItem, DeviceList, DeviceMultiSelectField, DeviceSelectField, DeviceSelectorPicker, DeviceStepMatrix, Dialog, DialogBody, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, DiscoveryPanel, DoorbellRecentPanel, Dropdown, DropdownContent, DropdownItem, DropdownTrigger, DummyHeroCard, DummyInline, EVENT_KIND_ICONS, EmptyState, ErrorBox, EventKindGlyph, EventStream, FILL, FLEET_LIST_GC_TIME_MS, FLEET_LIST_QUERY_KEY, FLEET_LIST_STALE_TIME_MS, FanHeroCard, FanInlineControl, FanPanel, FilterBar, FloatingEventStream, FloatingLogStream, FloatingPanel, FormField$1 as FormField, GRID_GAP, GRID_PAIRED, GRID_QUICK_STATS, GripTrack, GroupedModelSelector, HOST_WIDGETS, HlsVideo, HoverZoomImage, HumidifierHeroCard, HumidifierInlineControl, INPUT_COMPACT, IconAction, IconButton, ImageHeroCard, ImageInlineControl, ImageSelector, InferenceConfigSelector, Input, KebabMenu, KeyValueList, LIST_ROW, Label, LawnMowerHeroCard, LawnMowerInlineControl, LightHeroCard, LightInlineControl, LockHeroCard, LockInlineControl, LockPanel, LogStream, LoginForm, MODE_COLOR, MaskShapeCanvas, MediaPlayerHeroCard, MediaPlayerInlineControl, MediaPlayerPanel, MobileDrawer, ModelPicker, MotionZonesSettings, NAVIGATION_DRIVE_INTERVAL_MS, NavigationPanel, NetworkLinkBadge, NodeMultiSelectField, NodePicker, NodeSelectField, OfflineBadge, PHASE_CONFIG, PRIORITY, PTZOverlay, PageHeader, PhaseIcon, PipelineBuilder, PipelineRuntimeSelector, PipelineStep, PipelineTreeMatrix, PlayerOverlaysProvider, Popover, PopoverContent, PopoverRowAction, PopoverTrigger, PrimaryChildPicker, PrivacyMaskSettings, ProviderBadge, PtzPanel, QrCode, RECONNECT_POLICY, RECORDED_PLAYBACK_MODES, RIGHT, ROI_AREA_WARN_FRACTION, ROLE_DESCRIPTOR, RadialGauge, RecordedPlaybackProvider, RecordingPanel, ResponseLog, SCENE_CAPTURE_VARIANTS, SECTION_BODY, SECTION_CARD, SECTION_HEADER, SETTING_ROW, SETTING_ROW_LABEL, SETTING_ROW_STACK_BREAKPOINT, SETTING_ROW_VALUE, SETTING_ROW_VALUE_TEXT, SNAPSHOT_MEDIA_PATH, SPLIT_PANEL_OUTER, SPLIT_PANEL_SIDE, STACK_GAP, STATE_COLOR, SceneMonitorEditor, ScopePicker, ScriptHeroCard, ScriptInlineControl, ScrollArea, Select, SemanticBadge, SensorHeroCard, SensorInlineControl, SensorValueAtom, Separator, SettingRow, Sidebar, SidebarItem, Skeleton, SlideOverPanel, SlideToggle, SnapshotButton, SortHeaderButton, StatCard, StateValuesStream, StatusBadge, StepTimings, StepTreeMaster, Stepper, StreamBrokerSelector, StreamDebugOverlay, StreamPanel, Switch, SwitchHeroCard, SwitchInlineControl, SwitchPanel, SystemProvider, TABLE_SCROLL_MAX_H, TEXT_FIELD_LABEL, TEXT_HINT, TEXT_METRIC, TEXT_SECTION_LABEL, TEXT_VALUE, TIMEZONES, Tabs, TabsContent, TabsList, TabsTrigger, TapToggle, ThemeProvider, ThermostatHeroCard, ThermostatInlineControl, TimezoneSelector, Tooltip, TooltipContent, TooltipTrigger, VacuumHeroCard, VacuumInlineControl, ValueReadout, ValveHeroCard, ValveInlineControl, VersionBadge, VodPlaybackProvider, WaterHeaterHeroCard, WaterHeaterInlineControl, WeatherHeroCard, WeatherInlineControl, WidgetMetricCard, WidgetPanel, WidgetRegistryProvider, WidgetSlot, ZoneEditingProvider, ImageOff as a, agentColumnKey, allDeviceTypeFilterOptions, applyFleetQueryDefaults, ariaSortForColumn, badgeFor, buildStepTreeFromSchema, Camera as c, childEntityId, childListName, classifyCapability, cn, columnsForContext, containerChildToRef, countableDevices, coverHighlight, coverageLine, createSharedContext, createTheme, cursorFractionFor, darkColors, defaultTheme, deriveDeviceKind, deriveWebrtcDebugStats, describeDeviceSelector, deviceMatchesFilter, deviceOptionLabel, deviceRoleMeta, deviceRoleMetaOf, deviceTypeLabel, deviceTypeMeta, deviceTypeMetaOf, devicesToOptions, ensureMfHostInit, eventKindLabel, filterDeviceOptions, findTimezone, formatControlDateTime, formatLastSeen, formatNumeric, freezeVerdict, fuzzyMatch, getClassColor, getPhaseVisual, groupAgentColumns, groupChildrenByLayout, hardwareLabel, hubOrigin, hubPath, hubUrl, hubWsUrl, humanDuration, humidifierTint, Mic as i, initialScrubState, isAbsentProvider, isFieldVisible, createLucideIcon as l, lawnMowerActivityMeta, lightColors, loadRemoteBundle, makeScrubBridge, metadataEntries, metadataString, mirror, mountAddonPage, mountPath, Square as n, nextReconnectAction, nextSort, nextSortDirection, nextTableSort, normalizeForSearch, Grid2x2 as o, openTopLayer, overrideEntityIdFromLink, parseRecordedServerMessage, providerIcons, RotateCcw as r, resetHubMountForTests, resolveContainerPrimary, resolveControlAlign, resolveDeviceControl, resolveDisplayIcon, resolveEffectiveDefaultModel, resolveEffectiveStepModel, resolveEventKindIcon, resolvePrimaryChild, resolveSensorDisplay, resolveStepDefaultModel, resolveTableLayout, roiTooLarge, routerBasename, EyeOff as s, scrubReducer, selectedDeviceOptions, serializeRecordedCommand, shouldCommit, shouldEmit, shouldUseSingleNode, sortRows, sortRowsByColumn, statusIcons, statusLine, stepHasModelForFormat, stepModelOptions, stripParentNamePrefix, Trash2 as t, tabForSelector, tankAlert, themeToCss, toStationaryOverlayBox, trpc, useAccessoriesGetStatus, useAccessoriesSetChildHidden, useAddonPagesListPages, useAddonSettingsGetDeviceSettings, useAddonSettingsGetGlobalSettings, useAddonSettingsGetIntegrationSettings, useAddonSettingsUpdateDeviceSettings, useAddonSettingsUpdateGlobalSettings, useAddonWidgetsListWidgets, useAddonsApplyAutoUpdateToAll, useAddonsCancelJob, useAddonsCustom, useAddonsForceRefresh, useAddonsGetAddonAutoUpdate, useAddonsGetAutoUpdateSettings, useAddonsGetJob, useAddonsGetLastRestart, useAddonsGetLogs, useAddonsGetVersions, useAddonsInstallFromWorkspace, useAddonsInstallPackage, useAddonsIsWorkspaceAvailable, useAddonsList, useAddonsListCapabilityProviders, useAddonsListFrameworkPackages, useAddonsListJobs, useAddonsListPackages, useAddonsListUpdates, useAddonsListWorkspacePackages, useAddonsOnAddonLogs, useAddonsReloadPackages, useAddonsRestartAddon, useAddonsRestartServer, useAddonsRetryLoad, useAddonsRollbackPackage, useAddonsSearchAvailable, useAddonsSetAddonAutoUpdate, useAddonsSetAutoUpdateSettings, useAddonsSetCapabilityProviderEnabled, useAddonsStartJob, useAddonsUninstallPackage, useAddonsUpdatePackage, useAirQualitySensorGetStatus, useAlarmPanelArm, useAlarmPanelDisarm, useAlarmPanelGetStatus, useAlarmPanelTrigger, useAlert, useAlertsDismiss, useAlertsEmit, useAlertsGetUnreadCount, useAlertsList, useAlertsMarkAllRead, useAlertsMarkRead, useAlertsUpdate, useAllWidgets, useAmbientLightSensorGetStatus, useAudioAnalysisApplyDeviceSettingsPatch, useAudioAnalysisGetDeviceLiveContribution, useAudioAnalysisGetDeviceSettingsContribution, useAudioAnalysisResolveDeviceSettings, useAudioAnalyzerAnalyseChunk, useAudioAnalyzerAttachDevice, useAudioAnalyzerClassify, useAudioAnalyzerDetachDevice, useAudioAnalyzerDispose, useAudioAnalyzerIsReady, useAudioAnalyzerReprobeAudioEngine, useAudioCodecCanHandle, useAudioCodecCloseSession, useAudioCodecCreateDecodeSession, useAudioCodecCreateEncodeSession, useAudioCodecFlushEncode, useAudioCodecListActiveSessions, useAudioCodecListSupportedCodecs, useAudioCodecPullEncoded, useAudioCodecPullPcm, useAudioCodecPushEncodedFrame, useAudioCodecPushPcm, useAudioMetricsGetCurrentSnapshot, useAudioMetricsGetHistory, useAutomationControlDisable, useAutomationControlEnable, useAutomationControlGetStatus, useAutomationControlTrigger, useBackupCancel, useBackupDelete, useBackupDeleteSchedule, useBackupGetEntries, useBackupList, useBackupListArchives, useBackupListDestinations, useBackupListLocations, useBackupListRuns, useBackupListSchedules, useBackupPreviewSchedule, useBackupRestore, useBackupTrigger, useBackupUpsertDestinationPolicy, useBackupUpsertSchedule, useBatteryGetStatus, useBatteryWakeForStream, useBinaryGetStatus, useBrightnessGetStatus, useBrightnessSetBrightness, useBrokerAdd, useBrokerGet, useBrokerGetBrokerConfig, useBrokerGetSettings, useBrokerGetSettingsSchema, useBrokerGetState, useBrokerGetStatus, useBrokerList, useBrokerListProviders, useBrokerPublish, useBrokerRemove, useBrokerSetSettings, useBrokerSubscribe, useBrokerTestConnection, useBrokerTestSettings, useBrokerUnsubscribe, useButtonPress, useCameraCredentialsGetCredentials, useCameraCredentialsGetStatus, useCameraGridLayoutApplyDeviceSettingsPatch, useCameraGridLayoutGetDeviceLiveContribution, useCameraGridLayoutGetDeviceSettingsContribution, useCameraGridLayoutGetLayout, useCameraGridLayoutSaveLayout, useCameraPipelineConfigApplyDeviceSettingsPatch, useCameraPipelineConfigGetDeviceLiveContribution, useCameraPipelineConfigGetDeviceSettingsContribution, useCameraStreamsGetBrokerStreams, useCameraStreamsGetCameraStreams, useCameraStreamsGetProfileRtspEntries, useCameraStreamsGetRtspEntries, useCameraStreamsPickStream, useCapabilityPresence, useCarbonMonoxideGetStatus, useClimateControlGetStatus, useClimateControlSetFanMode, useClimateControlSetMode, useClimateControlSetPreset, useClimateControlSetSwingHorizontal, useClimateControlSetSwingVertical, useClimateControlSetTarget, useClimateControlSetTargetHumidity, useClimateControlSetTargetRange, useClusterNodes, useClusterTopology, useColorGetStatus, useColorSetColor, useConfirm, useConnectionTestDescribeTest, useConnectionTestTestSettings, useConnectivityGetStatus, useConsumablesGetStatus, useConsumablesReset, useContactGetStatus, useContainerChildren, useControlGetStatus, useControlSetValue, useCoreBlocksCompile, useCoreBlocksCreate, useCoreBlocksDelete, useCoreBlocksGet, useCoreBlocksGetTypeDefs, useCoreBlocksList, useCoreBlocksRestart, useCoreBlocksSetEnabled, useCoreBlocksUpdate, useCoverClose, useCoverGetStatus, useCoverOpen, useCoverSetPosition, useCoverSetTiltPosition, useCoverStop, useCustomFieldRenderer, useDayNightGetOptions, useDayNightGetStatus, useDayNightSetSettings, useDebouncedString, useDecoderCreateSession, useDecoderDestroySession, useDecoderGetFrame, useDecoderGetInfo, useDecoderGetShmStats, useDecoderGetStats, useDecoderListActiveSessions, useDecoderOpenStream, useDecoderPullFrames, useDecoderPullHandles, useDecoderPushPacket, useDecoderReprobeHwaccel, useDecoderSupportsCodec, useDecoderUpdateConfig, useDetectionPipelineApplyDeviceSettingsPatch, useDetectionPipelineGetDeviceLiveContribution, useDetectionPipelineGetDeviceSettingsContribution, useDevShell, useDevice, useDeviceAdoptionAdopt, useDeviceAdoptionGetCandidate, useDeviceAdoptionGetStatus, useDeviceAdoptionListCandidateFilters, useDeviceAdoptionListCandidates, useDeviceAdoptionRefresh, useDeviceAdoptionRelease, useDeviceAdoptionResync, useDeviceAutotrack, useDeviceBattery, useDeviceCapSlice, useDeviceCapability, useDeviceDetections, useDeviceDiscoveryAdoptDevice, useDeviceDiscoveryGetStatus, useDeviceDiscoveryListDiscovered, useDeviceDiscoveryRefreshDiscovery, useDeviceDiscoveryReleaseDevice, useDeviceExportApplyDeviceSettingsPatch, useDeviceExportExposeDevice, useDeviceExportGetDeviceLiveContribution, useDeviceExportGetDeviceSettingsContribution, useDeviceExportGetStatus, useDeviceExportListExposedDevices, useDeviceExportListSupportedDeviceKinds, useDeviceExportUnexposeDevice, useDeviceId, useDeviceListPageSize, useDeviceManagerAddLocation, useDeviceManagerAdoptDevice, useDeviceManagerAdoptionAdopt, useDeviceManagerAdoptionCancelJob, useDeviceManagerAdoptionListCandidateFilters, useDeviceManagerAdoptionListCandidates, useDeviceManagerAdoptionListJobs, useDeviceManagerAdoptionRefresh, useDeviceManagerAdoptionRelease, useDeviceManagerAdoptionResync, useDeviceManagerAdoptionStartJob, useDeviceManagerAllocateDeviceId, useDeviceManagerApplyDeviceSettingsPatch, useDeviceManagerApplyInitialMeta, useDeviceManagerCreateDevice, useDeviceManagerDisable, useDeviceManagerDiscoverAllProviders, useDeviceManagerDiscoverDevices, useDeviceManagerDiscoverProvider, useDeviceManagerDiscoveryProviders, useDeviceManagerEnable, useDeviceManagerGetAllBindings, useDeviceManagerGetBindings, useDeviceManagerGetBindingsBatch, useDeviceManagerGetChildren, useDeviceManagerGetChildrenBatch, useDeviceManagerGetConfigSchema, useDeviceManagerGetCreationSchema, useDeviceManagerGetDevice, useDeviceManagerGetDeviceAggregate, useDeviceManagerGetDeviceLiveContribution, useDeviceManagerGetDeviceLiveInfoAggregate, useDeviceManagerGetDeviceSettingsAggregate, useDeviceManagerGetDeviceSettingsContribution, useDeviceManagerGetDeviceStatusAggregate, useDeviceManagerGetDeviceStatusAggregateBatch, useDeviceManagerGetLinkedDevices, useDeviceManagerGetLinkedDevicesBatch, useDeviceManagerGetRoleDisplayDefaults, useDeviceManagerGetSettingsSchema, useDeviceManagerGetStreamProfileMap, useDeviceManagerGetStreamSources, useDeviceManagerGetWireableFields, useDeviceManagerListAll, useDeviceManagerListBindableCapsForDeviceType, useDeviceManagerListLocationDescriptions, useDeviceManagerListLocationIcons, useDeviceManagerListLocations, useDeviceManagerListPersistedByAddon, useDeviceManagerListSiteZones, useDeviceManagerListWrappersForCap, useDeviceManagerLoadConfig, useDeviceManagerLoadMeta, useDeviceManagerLoadRuntimeState, useDeviceManagerMigrateDevice, useDeviceManagerPersistConfig, useDeviceManagerProbeStreams, useDeviceManagerProviderCreationType, useDeviceManagerProviderDiscoveryParamsSchema, useDeviceManagerRegisterDevice, useDeviceManagerRemove, useDeviceManagerRemoveByIntegration, useDeviceManagerRemoveDevice, useDeviceManagerRemoveLocation, useDeviceManagerRemoveSiteZone, useDeviceManagerRenameLocation, useDeviceManagerRenameSiteZone, useDeviceManagerRunDeviceAction, useDeviceManagerSetChildLayout, useDeviceManagerSetDisabled, useDeviceManagerSetDisplay, useDeviceManagerSetIntegrationId, useDeviceManagerSetLinkDeviceId, useDeviceManagerSetLocation, useDeviceManagerSetLocationDescription, useDeviceManagerSetLocationIcon, useDeviceManagerSetLocationZone, useDeviceManagerSetMetadata, useDeviceManagerSetName, useDeviceManagerSetPrimaryChildEntityId, useDeviceManagerSetRole, useDeviceManagerSetRoleDisplayDefaults, useDeviceManagerSetSiteZone, useDeviceManagerSetStreamProfileMap, useDeviceManagerSetType, useDeviceManagerSetWrapperActive, useDeviceManagerTestCreationField, useDeviceManagerTestField, useDeviceManagerUpdateConfig, useDeviceManagerUpdateDeviceField, useDeviceManagerUpdateDeviceFieldsBatch, useDeviceNetworkLink, useDeviceOpsGetConfigEntries, useDeviceOpsGetRawState, useDeviceOpsGetSettingsSchema, useDeviceOpsGetStreamSources, useDeviceOpsRemoveDevice, useDeviceOpsRunAction, useDeviceOpsSetConfig, useDeviceProviderAdoptDiscoveredDevice, useDeviceProviderCreateDevice, useDeviceProviderDiscoverDevices, useDeviceProviderGetChildCreationSchema, useDeviceProviderGetDevices, useDeviceProviderGetDiscoveryParamsSchema, useDeviceProviderGetManualCreationType, useDeviceProviderGetStatus, useDeviceProviderReloadDevice, useDeviceProviderStart, useDeviceProviderStop, useDeviceProviderSupportsDiscovery, useDeviceProviderSupportsManualCreation, useDeviceProviderTestCreationField, useDeviceProxy, useDeviceSnapshot, useDeviceSnapshotImage, useDeviceState, useDeviceStateGetAllSnapshots, useDeviceStateGetCapSlice, useDeviceStateGetSnapshot, useDeviceStateSetCapSlice, useDeviceStateSlice, useDeviceStatusGetStatus, useDeviceWebrtc, useDevices, useDoorbellApplyDeviceSettingsPatch, useDoorbellEvents, useDoorbellGetDeviceLiveContribution, useDoorbellGetDeviceSettingsContribution, useDoorbellGetStatus, useEnumSensorGetStatus, useEventEmitterGetStatus, useEventInvalidation, useEventStreamLatest, useEventStreamMap, useEventsGetEventClipUrl, useEventsGetEventThumbnail, useEventsGetEvents, useFaceGalleryAssignFace, useFaceGalleryAssignFaces, useFaceGalleryAuditIdentitySamples, useFaceGalleryCreateIdentity, useFaceGalleryDeleteFace, useFaceGalleryDeleteIdentity, useFaceGalleryGetFaceByTrack, useFaceGalleryGetFaceMedia, useFaceGalleryListIdentities, useFaceGalleryListIdentitySamples, useFaceGalleryListRecentFaces, useFaceGalleryRemoveSample, useFaceGalleryRenameIdentity, useFaceGallerySuggestFaceClusters, useFaceGalleryUnassignFace, useFaceGalleryUnassignFaces, useFanControlGetStatus, useFanControlSetDirection, useFanControlSetOscillating, useFanControlSetPercentage, useFanControlSetPreset, useFeatureProbeGetStatus, useFloodGetStatus, useGasGetStatus, useHumidifierGetStatus, useHumidifierSetMode, useHumidifierSetOn, useHumidifierSetTargetHumidity, useHumiditySensorGetStatus, useImageGetStatus, useImageSettingsGetOptions, useImageSettingsGetStatus, useImageSettingsSetSettings, useIntegrationsCreate, useIntegrationsDelete, useIntegrationsGet, useIntegrationsGetAvailableTypes, useIntegrationsGetByAddonId, useIntegrationsGetSettings, useIntegrationsList, useIntegrationsSetSettings, useIntegrationsTestConnection, useIntegrationsUpdate, useIntercomEndTalkSession, useIntercomGetStatus, useIntercomHandleAnswer, useIntercomPushTalkAudio, useIntercomStartSession, useIntercomStartTalkSession, useIntercomStopSession, useIsMidWidth, useIsMobile, useLawnMowerControlDock, useLawnMowerControlGetStatus, useLawnMowerControlPause, useLawnMowerControlStartMowing, useLiveBuffer, useLiveEvent, useLlmCancel, useLlmDeleteModel, useLlmDeleteProfile, useLlmGenerate, useLlmGenerateVision, useLlmGetDefaults, useLlmGetRuntimeStatus, useLlmGetUsage, useLlmInstallModel, useLlmListModelCatalog, useLlmListModels, useLlmListNodeModels, useLlmListProfileKinds, useLlmListProfiles, useLlmListRuntimeNodes, useLlmResolveModelRef, useLlmSetDefault, useLlmStartRuntime, useLlmStopRuntime, useLlmTestProfile, useLlmUpsertProfile, useLocalNetworkDownloadCa, useLocalNetworkGetAllowedAddresses, useLocalNetworkGetConnectionEndpoints, useLocalNetworkGetNotificationEndpoint, useLocalNetworkGetPreferred, useLocalNetworkGetTlsStatus, useLocalNetworkGetViewerEndpoints, useLocalNetworkList, useLocalNetworkRegenerateCertificate, useLocalNetworkResetAllowlistToBestMatch, useLocalNetworkRevertToGeneratedCertificate, useLocalNetworkSetAllowedAddresses, useLocalNetworkSetNotificationEndpoint, useLocalNetworkSetViewerEndpoints, useLocalNetworkUploadCertificate, useLockControlGetStatus, useLockControlLock, useLockControlOpen, useLockControlUnlock, useMediaPlayerGetStatus, useMediaPlayerNext, useMediaPlayerPause, useMediaPlayerPlay, useMediaPlayerPlayMedia, useMediaPlayerPrevious, useMediaPlayerSeek, useMediaPlayerSelectSource, useMediaPlayerSetMute, useMediaPlayerSetRepeat, useMediaPlayerSetShuffle, useMediaPlayerSetVolume, useMediaPlayerStop, useMeshNetworkGetStatus, useMeshNetworkJoin, useMeshNetworkLeave, useMeshNetworkListPeers, useMeshNetworkLogout, useMeshNetworkStartLogin, useMeshNetworkTestConnection, useMetricsProviderCollectSnapshot, useMetricsProviderGetAddonStats, useMetricsProviderGetCached, useMetricsProviderGetCpuTemperature, useMetricsProviderGetCurrent, useMetricsProviderGetDiskSpace, useMetricsProviderGetGpuInfo, useMetricsProviderGetLoadSeries, useMetricsProviderGetProcessStats, useMetricsProviderListAddonInstances, useMetricsProviderListNodeProcesses, useMotionDetectionAnalyze, useMotionDetectionApplyDeviceSettingsPatch, useMotionDetectionGetDeviceLiveContribution, useMotionDetectionGetDeviceSettingsContribution, useMotionDetectionRemoveCamera, useMotionDetectionReset, useMotionGetStatus, useMotionIsDetected, useMotionTriggerGetStatus, useMotionTriggerSetMotionTrigger, useMotionZonesGetOptions, useMotionZonesGetStatus, useMotionZonesSetZone, useMqttBrokerAddBroker, useMqttBrokerGetBrokerConfig, useMqttBrokerGetStatus, useMqttBrokerListBrokers, useMqttBrokerRemoveBroker, useMqttBrokerStartEmbeddedBroker, useMqttBrokerStopEmbeddedBroker, useMqttBrokerTestConnection, useNativeObjectDetectionGetOptions, useNativeObjectDetectionGetStatus, useNativeObjectDetectionSetEnabled, useNativeObjectDetectionSetSettings, useNavigation, useNavigationGetFeatures, useNavigationGetStatus, useNavigationGoToPoint, useNavigationListActions, useNavigationMove, useNavigationPlaySound, useNavigationRunAction, useNavigationSetLightLevel, useNavigationSetLightMode, useNavigationSetLightOn, useNavigationStop, useNetworkAccessGetEndpoint, useNetworkAccessGetStatus, useNetworkAccessListEndpoints, useNetworkAccessStart, useNetworkAccessStop, useNetworkLinkGetStatus, useNetworkQualityGetAllStats, useNetworkQualityGetDeviceStats, useNetworkQualityReportClientStats, useNodesClusterAddonStatus, useNodesDeployAddon, useNodesExecuteQuery, useNodesGetCapUsageGraph, useNodesGetNodeAddons, useNodesRenameNode, useNodesRestartAddon, useNodesRestartNode, useNodesRestartProcess, useNodesSetProcessLogLevel, useNodesShutdownNode, useNodesTopology, useNodesUndeployAddon, useNotificationOutputDeleteTarget, useNotificationOutputDiscoverTargets, useNotificationOutputListTargetKinds, useNotificationOutputListTargets, useNotificationOutputSend, useNotificationOutputSetTargetEnabled, useNotificationOutputTestTarget, useNotificationOutputUpsertTarget, useNotificationRulesCancelSnooze, useNotificationRulesCreateRule, useNotificationRulesCreateSnooze, useNotificationRulesDeleteRule, useNotificationRulesGetAlarmConfig, useNotificationRulesGetClipRetentionAsks, useNotificationRulesGetConditionCatalog, useNotificationRulesGetHistory, useNotificationRulesGetRule, useNotificationRulesListDeviceMutes, useNotificationRulesListRules, useNotificationRulesListSnoozes, useNotificationRulesResolveArtifactUrl, useNotificationRulesSetAlarmConfig, useNotificationRulesSetDeviceMuted, useNotificationRulesSetRuleEnabled, useNotificationRulesTestRule, useNotificationRulesUpdateRule, useNotifierCancel, useNotifierGetStatus, useNotifierSend, useNumericSensorGetStatus, useOptimisticSlice, useOptionalSystem, useOptionalWidgetRegistry, useOsdGetStatus, useOsdManagerClearSlotBinding, useOsdManagerCopyDeviceConfiguration, useOsdManagerGetConditionSupport, useOsdManagerGetDeviceOsd, useOsdManagerGetSourceCatalog, useOsdManagerPreviewSlot, useOsdManagerRenderDevice, useOsdManagerSetSlotBinding, useOsdSetOverlay, usePTZ, usePetFeederCallPet, usePetFeederCancelFeed, usePetFeederFeed, usePetFeederGetStatus, usePetFeederMarkFoodReplenished, usePetFeederPlaySound, usePetFeederResetDesiccant, usePetFeederSetChildLock, usePetFeederSetFeedSound, usePetFeederSetIndicatorLight, usePetFeederSetVolume, usePipelineAnalyticsApplyDeviceSettingsPatch, usePipelineAnalyticsCancelRelocateMedia, usePipelineAnalyticsCancelStorageMigrationMove, usePipelineAnalyticsClearTracks, usePipelineAnalyticsCompleteRetrainTrack, usePipelineAnalyticsCountRelocatableMedia, usePipelineAnalyticsCountUnstampedEventMedia, usePipelineAnalyticsDeleteDeviceEvents, usePipelineAnalyticsDeleteTracks, usePipelineAnalyticsDeselectRetrainFrame, usePipelineAnalyticsGetActiveTracks, usePipelineAnalyticsGetAudioEvents, usePipelineAnalyticsGetDeviceLiveContribution, usePipelineAnalyticsGetDeviceSettingsContribution, usePipelineAnalyticsGetEventDensity, usePipelineAnalyticsGetEventDensityBatch, usePipelineAnalyticsGetEventMedia, usePipelineAnalyticsGetEventMediaFootprintByKind, usePipelineAnalyticsGetEventStoreFootprint, usePipelineAnalyticsGetKeyEvents, usePipelineAnalyticsGetKeyEventsBatch, usePipelineAnalyticsGetMediaReclaimStatus, usePipelineAnalyticsGetMotionEvents, usePipelineAnalyticsGetObjectEmbeddingRebuildStatus, usePipelineAnalyticsGetObjectEvents, usePipelineAnalyticsGetRetrainExportUrl, usePipelineAnalyticsGetRetrainFrameImage, usePipelineAnalyticsGetSensorEvents, usePipelineAnalyticsGetStorageMigrationMoveStatus, usePipelineAnalyticsGetSummary, usePipelineAnalyticsGetTrack, usePipelineAnalyticsGetTrackMedia, usePipelineAnalyticsGetTrainingExportSummary, usePipelineAnalyticsGetTrainingExportUrl, usePipelineAnalyticsListArchivedDebugNotes, usePipelineAnalyticsListBirthDecisions, usePipelineAnalyticsListEventKinds, usePipelineAnalyticsListEventKindsBatch, usePipelineAnalyticsListEventMedia, usePipelineAnalyticsListOpsLog, usePipelineAnalyticsListRecentSummaries, usePipelineAnalyticsListRecentTracks, usePipelineAnalyticsListRelocateMediaJobs, usePipelineAnalyticsListRetrainAnnotations, usePipelineAnalyticsListRetrainFrames, usePipelineAnalyticsListRetrainStaging, usePipelineAnalyticsListSummaries, usePipelineAnalyticsListTrackMedia, usePipelineAnalyticsListTracks, usePipelineAnalyticsOwnersWithMedia, usePipelineAnalyticsPauseForStorageMigration, usePipelineAnalyticsProposeRetrainAnnotations, usePipelineAnalyticsPruneEvents, usePipelineAnalyticsPruneEventsBefore, usePipelineAnalyticsPruneTracksBefore, usePipelineAnalyticsReadLongTermSeries, usePipelineAnalyticsRebuildObjectEmbeddings, usePipelineAnalyticsReclaimDebugMedia, usePipelineAnalyticsReconcileFromDisk, usePipelineAnalyticsRefreshStorageLocationsForMigration, usePipelineAnalyticsRelocateMedia, usePipelineAnalyticsRestageRetrainTrack, usePipelineAnalyticsResumeForStorageMigration, usePipelineAnalyticsRunReplayFrameProcessor, usePipelineAnalyticsSaveRetrainAnnotations, usePipelineAnalyticsSearchObjectEvents, usePipelineAnalyticsSelectRetrainFrames, usePipelineAnalyticsSetTrackFlags, usePipelineAnalyticsStartStorageMigrationMove, usePipelineAnalyticsWipeAllAnalytics, usePipelineAnalyticsWipeObjectEmbeddings, usePipelineExecutorCacheFrameInPool, usePipelineExecutorClearDeviceOverrides, usePipelineExecutorDeleteModel, usePipelineExecutorDeleteTemplate, usePipelineExecutorDownloadModel, usePipelineExecutorGetAddonModels, usePipelineExecutorGetAudioCapabilities, usePipelineExecutorGetAvailableEngines, usePipelineExecutorGetCapabilities, usePipelineExecutorGetDefaultSteps, usePipelineExecutorGetDetectionConfigSchema, usePipelineExecutorGetEffectiveTuning, usePipelineExecutorGetEngineProvisioning, usePipelineExecutorGetGlobalPipelineConfig, usePipelineExecutorGetGlobalSteps, usePipelineExecutorGetInferenceDeviceHealth, usePipelineExecutorGetOrchestratorConfigSchema, usePipelineExecutorGetReferenceAudio, usePipelineExecutorGetReferenceAudioFiles, usePipelineExecutorGetReferenceImage, usePipelineExecutorGetSchema, usePipelineExecutorGetSelectedEngine, usePipelineExecutorGetVideoPipelineSteps, usePipelineExecutorInferCached, usePipelineExecutorKillEngine, usePipelineExecutorListLoadedEngines, usePipelineExecutorListReferenceImages, usePipelineExecutorListTemplates, usePipelineExecutorRearmInferenceDevice, usePipelineExecutorRunAudioTest, usePipelineExecutorRunPipeline, usePipelineExecutorRunPipelineBatch, usePipelineExecutorSaveTemplate, usePipelineExecutorSetVideoPipelineSteps, usePipelineExecutorSpinEngine, usePipelineExecutorUncacheFrame, usePipelineExecutorUpdateTemplate, usePipelineExecutorValidatePipeline, usePipelineOrchestratorApplyDeviceSettingsPatch, usePipelineOrchestratorAssignAudio, usePipelineOrchestratorAssignPipeline, usePipelineOrchestratorDeleteTemplate, usePipelineOrchestratorGetAgentLoad, usePipelineOrchestratorGetAgentSettings, usePipelineOrchestratorGetAudioAssignment, usePipelineOrchestratorGetAudioAssignments, usePipelineOrchestratorGetAudioNodeLoad, usePipelineOrchestratorGetCameraMetrics, usePipelineOrchestratorGetCameraSettings, usePipelineOrchestratorGetCameraStatus, usePipelineOrchestratorGetCameraStatuses, usePipelineOrchestratorGetCameraStepOverrides, usePipelineOrchestratorGetCameraSwitches, usePipelineOrchestratorGetCapabilityBindings, usePipelineOrchestratorGetDeviceLiveContribution, usePipelineOrchestratorGetDeviceSettingsContribution, usePipelineOrchestratorGetGlobalMetrics, usePipelineOrchestratorGetIngestOwner, usePipelineOrchestratorGetNodeInferenceDevices, usePipelineOrchestratorGetPipelineAssignment, usePipelineOrchestratorGetPipelineAssignments, usePipelineOrchestratorGetPipelineDevicePin, usePipelineOrchestratorGetReconcileFromDiskStatus, usePipelineOrchestratorListAgentSettings, usePipelineOrchestratorListTemplates, usePipelineOrchestratorPauseForStorageMigration, usePipelineOrchestratorRebalance, usePipelineOrchestratorReconcileFromDisk, usePipelineOrchestratorRemoveAgentSettings, usePipelineOrchestratorResetNodePipelineDefaults, usePipelineOrchestratorResolvePipeline, usePipelineOrchestratorResumeForStorageMigration, usePipelineOrchestratorSaveTemplate, usePipelineOrchestratorSetAgentCapabilities, usePipelineOrchestratorSetAgentDecodeLimits, usePipelineOrchestratorSetAgentDetectWeight, usePipelineOrchestratorSetAgentInferenceDevices, usePipelineOrchestratorSetAgentMaxCameras, usePipelineOrchestratorSetAgentReachableHost, usePipelineOrchestratorSetCameraPipelineForAgent, usePipelineOrchestratorSetCameraStepOverride, usePipelineOrchestratorSetCameraStepToggle, usePipelineOrchestratorSetCameraSwitch, usePipelineOrchestratorSetCapabilityBinding, usePipelineOrchestratorSetPipelineDevicePin, usePipelineOrchestratorUnassignAudio, usePipelineOrchestratorUnassignPipeline, usePipelineOrchestratorUpdateTemplate, usePipelineRunnerAttachCamera, usePipelineRunnerDetachCamera, usePipelineRunnerGetAllCameraMetrics, usePipelineRunnerGetCameraMetrics, usePipelineRunnerGetLocalCameras, usePipelineRunnerGetLocalLoad, usePipelineRunnerGetLocalMetrics, usePipelineRunnerGetNativeCrop, usePipelineRunnerGetParkedTrackFrame, usePipelineRunnerParkTrackFrame, usePipelineRunnerReleaseParkedTrackFrames, usePipelineRunnerReportMotion, usePipelineRunnerRequestOccupancyBurst, usePipelineRunnerRunDetailSubtree, usePipelineRunnerRunStatelessStep, usePlateGalleryAssignPlate, usePlateGalleryAssignPlates, usePlateGalleryCorrectPlateText, usePlateGalleryCreateVehicle, usePlateGalleryDeletePlate, usePlateGalleryDeleteVehicle, usePlateGalleryGetPlateByTrack, usePlateGalleryGetPlateMedia, usePlateGalleryListPlates, usePlateGalleryListVehicleSamples, usePlateGalleryListVehicles, usePlateGalleryRemoveVehicleSample, usePlateGalleryRenameVehicle, usePlateGallerySearchPlates, usePlateGallerySuggestPlateClusters, usePlateGalleryUnassignPlate, usePlateGalleryUnassignPlates, usePlayerOverlayLayer, usePlayerOverlayLayers, usePlayerToolbarButton, usePlayerToolbarButtons, usePowerMeterGetStatus, usePresenceGetStatus, usePressureSensorGetStatus, usePrivacyMaskGetOptions, usePrivacyMaskGetStatus, usePrivacyMaskSetAudioEnabled, usePrivacyMaskSetMask, usePrompt, usePtzAutotrackGetSettings, usePtzAutotrackGetStatus, usePtzAutotrackSetEnabled, usePtzAutotrackSetSettings, usePtzCaptureHomeHere, usePtzContinuousMove, usePtzDeletePreset, usePtzGetHomePreset, usePtzGetHomeReturn, usePtzGetOptions, usePtzGetPosition, usePtzGetPresets, usePtzGetStatus, usePtzGoHome, usePtzGoToPreset, usePtzMove, usePtzSavePreset, usePtzSetAutofocus, usePtzSetHomePreset, usePtzSetHomeReturn, usePtzStop, useRebootReboot, useRecordedPlayback, useRecordingApplyDeviceSettingsPatch, useRecordingCancelRelocateJob, useRecordingCancelStorageMigrationMove, useRecordingDeleteFootprint, useRecordingExportCancelExport, useRecordingExportCreateExport, useRecordingExportDeleteExport, useRecordingExportGetDownloadUrl, useRecordingExportGetExport, useRecordingExportListExports, useRecordingExportReadExportBytes, useRecordingGetAvailability, useRecordingGetAvailabilityBatch, useRecordingGetDaysWithRecordings, useRecordingGetDaysWithRecordingsBatch, useRecordingGetDeviceConfig, useRecordingGetDeviceLiveContribution, useRecordingGetDeviceSettingsContribution, useRecordingGetPlacement, useRecordingGetPlaybackManifest, useRecordingGetRelocateResidue, useRecordingGetStatus, useRecordingGetStorageMigrationMoveStatus, useRecordingGetStorageUsage, useRecordingListOpsLog, useRecordingListRelocateJobs, useRecordingLocateSegment, useRecordingPauseForStorageMigration, useRecordingPlanStorageRebalance, useRecordingPruneFootage, useRecordingReadGopBytes, useRecordingReadSegmentBytes, useRecordingReadWindowBytes, useRecordingReconcileLedgerAgainstDisk, useRecordingRefreshStorageLocationsForMigration, useRecordingRelocateFootage, useRecordingRenderClip, useRecordingRenderGif, useRecordingRescanStorage, useRecordingResumeForStorageMigration, useRecordingSetDeviceConfig, useRecordingSetDevicePlacement, useRecordingSignalGetStatus, useRecordingStartStorageMigrationMove, useRecordingStartStorageRebalance, useRemoteComponent, useSceneMonitorCaptureReference, useSceneMonitorCreateScene, useSceneMonitorDeleteReference, useSceneMonitorDeleteScene, useSceneMonitorGetStatus, useSceneMonitorListScenes, useSceneMonitorListScenesBatch, useSceneMonitorRecheckNow, useSceneMonitorResetScene, useSceneMonitorUpdateScene, useScriptRunnerGetStatus, useScriptRunnerRun, useScriptRunnerStop, useScrubController, useServerManagementApplyServerUpdate, useServerManagementCheckServerUpdate, useServerManagementGetServerPackageStatus, useServerManagementRestartServer, useServerManagementRollbackServerUpdate, useSettingsStoreAggregate, useSettingsStoreCount, useSettingsStoreDeclareCollection, useSettingsStoreDelete, useSettingsStoreDeleteWhere, useSettingsStoreGet, useSettingsStoreHistogram, useSettingsStoreInsert, useSettingsStoreInsertMany, useSettingsStoreIsEmpty, useSettingsStoreQuery, useSettingsStoreSet, useSettingsStoreUpdate, useSettingsStoreUpdateWhere, useSettingsStoreUpsert, useSmokeGetStatus, useSnapshotApplyDeviceSettingsPatch, useSnapshotGetDebugState, useSnapshotGetDeviceLiveContribution, useSnapshotGetDeviceSettingsContribution, useSnapshotGetSnapshot, useSnapshotGetSnapshotLinks, useSnapshotGetSnapshotOverview, useSnapshotGetStatus, useSnapshotInvalidateCache, useStationaryOverlay, useStorageAbortUpload, useStorageBeginDownload, useStorageBeginUpload, useStorageDelete, useStorageDeleteLocation, useStorageEndDownload, useStorageExists, useStorageFinalizeUpload, useStorageGetAvailableSpace, useStorageList, useStorageListDrainProgress, useStorageListLocationDeclarations, useStorageListLocations, useStorageListProviders, useStorageMigrationCancel, useStorageMigrationCleanupCancel, useStorageMigrationCleanupStart, useStorageMigrationCleanupStatus, useStorageMigrationDrain, useStorageMigrationHistory, useStorageMigrationMovers, useStorageMigrationPlan, useStorageMigrationResidue, useStorageMigrationStart, useStorageMigrationStatus, useStorageRead, useStorageReadChunk, useStorageResolve, useStorageTestConfig, useStorageTestLocation, useStorageUpsertLocation, useStorageWrite, useStorageWriteChunk, useStreamBrokerAcquireEgressTranscode, useStreamBrokerApplyDeviceSettingsPatch, useStreamBrokerAssignProfile, useStreamBrokerFetchEventMedia, useStreamBrokerForgetDeviceHardware, useStreamBrokerGetAllRtspEntries, useStreamBrokerGetBrokerStats, useStreamBrokerGetDeviceAudioMute, useStreamBrokerGetDeviceLiveContribution, useStreamBrokerGetDeviceSettingsContribution, useStreamBrokerGetPreBufferInfo, useStreamBrokerGetRtspEntry, useStreamBrokerGetRtspPort, useStreamBrokerGetStreamUrl, useStreamBrokerGetStreamWithCodec, useStreamBrokerIsRtspEnabled, useStreamBrokerKillClient, useStreamBrokerListAllCameraStreams, useStreamBrokerListAllProfileSlots, useStreamBrokerListClients, useStreamBrokerProbeStream, useStreamBrokerProduceEventMedia, useStreamBrokerPublishCameraStream, useStreamBrokerPullAudioChunks, useStreamBrokerPullFrameHandles, useStreamBrokerRegenerateRtspToken, useStreamBrokerReleaseEgressTranscode, useStreamBrokerReleaseStreamWithCodec, useStreamBrokerRenderPreBufferClip, useStreamBrokerReportStreamSignal, useStreamBrokerRestartProfile, useStreamBrokerRetractCameraStream, useStreamBrokerSetDeviceAudioMute, useStreamBrokerSetPreBufferDuration, useStreamBrokerSetRtspEnabled, useStreamBrokerSubscribeAudioChunks, useStreamBrokerSubscribeFrames, useStreamBrokerUnassignProfile, useStreamBrokerUnsubscribeAudioChunks, useStreamBrokerUnsubscribeFrames, useStreamCatalogGetCatalog, useStreamParamsGetConfigSchema, useStreamParamsGetOptions, useStreamParamsGetStatus, useStreamParamsSetProfile, useStreamSignalsListSignals, useSwitchGetStatus, useSwitchSetState, useSystem, useSystemDetectSiteLocation, useSystemFeatureFlags, useSystemForceRetentionCleanup, useSystemGetFailureContributions, useSystemGetLoadContributions, useSystemGetLoggingSettings, useSystemGetRequestCensus, useSystemGetRetentionConfig, useSystemGetSiteLocation, useSystemHealth, useSystemInfo, useSystemMutation, useSystemNetworkAddresses, useSystemQuery, useSystemSetLoggingSettings, useSystemSetRetentionConfig, useSystemSetSiteLocation, useTamperGetStatus, useTemperatureSensorGetStatus, useTerminalSessionAdoptLegacyMonitor, useTerminalSessionClose, useTerminalSessionCreateInstance, useTerminalSessionDeleteInstance, useTerminalSessionListInstances, useTerminalSessionListLegacyCameras, useTerminalSessionListProfiles, useTerminalSessionListSessions, useTerminalSessionOpenSession, useTerminalSessionPullOutput, useTerminalSessionResize, useTerminalSessionSetInstanceEnabled, useTerminalSessionUpdateInstance, useTerminalSessionWriteInput, useThemeMode, useToastOnToast, useTurnProviderGetTurnServers, useUpdateGetStatus, useUpdateInstallUpdate, useUserManagementConfirmTotp, useUserManagementCreateApiKey, useUserManagementCreateScopedToken, useUserManagementCreateUser, useUserManagementDeleteUser, useUserManagementDisableTotp, useUserManagementGetTotpStatus, useUserManagementListApiKeys, useUserManagementListOauthSessions, useUserManagementListScopedTokens, useUserManagementListUsers, useUserManagementOauthExchangeCode, useUserManagementOauthIssueCode, useUserManagementOauthRefresh, useUserManagementOauthVerifyAccessToken, useUserManagementResetPassword, useUserManagementRevokeApiKey, useUserManagementRevokeOauthSession, useUserManagementRevokeScopedToken, useUserManagementSetUserScopes, useUserManagementSetupTotp, useUserManagementUpdateUser, useUserManagementValidateApiKey, useUserManagementValidateCredentials, useUserManagementValidateScopedToken, useUserManagementVerifyTotp, useVacuumControlGetStatus, useVacuumControlLocate, useVacuumControlPause, useVacuumControlReturnToBase, useVacuumControlSetFanSpeed, useVacuumControlStart, useVacuumControlStop, useValveClose, useValveGetStatus, useValveOpen, useValveSetPosition, useValveStop, useVibrationGetStatus, useVideoclipsGetClipPlayback, useVideoclipsListClips, useVideoclipsListSources, useVodPlayback, useWaterHeaterGetStatus, useWaterHeaterSetAway, useWaterHeaterSetOperationMode, useWaterHeaterSetTargetTemp, useWeatherGetStatus, useWebrtcSessionAddIceCandidate, useWebrtcSessionCloseSession, useWebrtcSessionCreateSession, useWebrtcSessionGetIceCandidates, useWebrtcSessionGetSessionDebug, useWebrtcSessionGetSessionState, useWebrtcSessionHandleAnswer, useWebrtcSessionHandleOffer, useWebrtcSessionHasAdaptiveBitrate, useWebrtcSessionListStreams, useWidget, useWidgetMetadata, useWidgetRegistry, useZoneAnalyticsGetCameraHistory, useZoneAnalyticsGetCurrentSnapshot, useZoneAnalyticsGetCurrentSnapshotBatch, useZoneAnalyticsGetUnzonedHistory, useZoneAnalyticsGetZoneHistory, useZoneEditing, useZoneRulesListRules, useZoneRulesSetRules, useZonesAddZone, useZonesListZones, useZonesRemoveZone, useZonesUpdateZone, vacuumStateMeta, validateScopes, valveStateMeta, variantLabel, waterHeaterPhase, waterHeaterTint, weatherConditionMeta, weatherTint };
|