@camstack/ui-library 1.2.248 → 1.2.250
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/config-icon-field.d.ts +11 -0
- package/dist/composites/config-secret-field.d.ts +22 -0
- package/dist/composites/device-export-panel.d.ts +19 -1
- package/dist/composites/device-list/generic-mode.d.ts +12 -0
- package/dist/composites/device-list/index.d.ts +2 -1
- package/dist/composites/device-list/page-size-select.d.ts +10 -0
- package/dist/composites/index.d.ts +5 -1
- package/dist/composites/training/send-frame-to-training.d.ts +6 -0
- package/dist/composites/training/training-collection-picker.d.ts +5 -0
- package/dist/composites/training/training-refusal-text.d.ts +10 -0
- package/dist/generated/system-hooks.d.ts +70 -0
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/use-device-list-page-size.d.ts +2 -1
- package/dist/hooks/use-persisted-page-size.d.ts +18 -0
- package/dist/index.cjs +2499 -1768
- package/dist/index.js +2453 -1771
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { ThemeProvider, createTheme, darkColors, defaultTheme, lightColors, themeToCss, useThemeMode } from "./theme/index.js";
|
|
2
2
|
import * as __mfHostReact from "react";
|
|
3
3
|
import React, { Fragment, Suspense, createContext, createElement, forwardRef, lazy, useCallback, useContext, useEffect, useId, useImperativeHandle, useLayoutEffect, useMemo, useReducer, useRef, useState, useSyncExternalStore } from "react";
|
|
4
|
+
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, DISPLAY_ICON_GROUPS, DeviceExportStatusSchema, DeviceFeature, DeviceRole, DeviceType, EVENT_TAXONOMY, EXTENSION_SLOTS, EXTENSION_SLOT_IDS, 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, RECORDING_SOURCE_CAMSTACK_ADDON, RecordingConfigSchema, RecordingStatusSchema, SECRET_CLEAR, SOURCE_CAP_ACTIVE_FIELD, STATIONARY_OVERLAY_STYLE, TIMEZONES, USE_ROOT_MODEL_SETTING_KEY, buildModelVariantGroups, canConvertUnit, clearModelBoundOverrides, clearModelBoundSetting, clusterStepSettingFieldsFor, collectModelBoundKeys, createDeviceProxy, createLazyTrpcSource, createSliceHandle, deriveRecordingMode, describeModelVariant, effectiveStepSettings, findTimezone, formatParkedFor, hasModelBoundOverrides, isKeychainStoredField, isRootSuppliableStepId, isSecretClear, isSecretFieldView, modelBindingKey, normalizeUnit, publicEventCategories, resolveContainerPrimaryChild, resolveDeviceControlKind, resolveDisplayIconKey, resolveModelBoundSetting, resolveRecordingProfiles, resolveRootSupply, resolveVariantModelId, resolveViewableDeviceIds, searchDisplayIcons, selectAssignedProfileSlots, stepSettingSource, tryConvertUnit, unitsForDimension, withFieldFrom, withoutField, writeModelBoundSetting } from "@camstack/types";
|
|
4
5
|
import * as __mfHostTrpcReactQuery from "@trpc/react-query";
|
|
5
6
|
import { createTRPCReact } from "@trpc/react-query";
|
|
6
7
|
import * as __mfHostReactJsxRuntime from "react/jsx-runtime";
|
|
7
8
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
8
9
|
import * as __mfHostReactDOM from "react-dom";
|
|
9
10
|
import { createPortal } from "react-dom";
|
|
10
|
-
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, DISPLAY_ICON_GROUPS, DeviceExportStatusSchema, DeviceFeature, DeviceRole, DeviceType, EVENT_TAXONOMY, EXTENSION_SLOTS, EXTENSION_SLOT_IDS, 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, RECORDING_SOURCE_CAMSTACK_ADDON, RecordingConfigSchema, RecordingStatusSchema, SOURCE_CAP_ACTIVE_FIELD, STATIONARY_OVERLAY_STYLE, TIMEZONES, USE_ROOT_MODEL_SETTING_KEY, buildModelVariantGroups, canConvertUnit, clearModelBoundOverrides, clearModelBoundSetting, clusterStepSettingFieldsFor, collectModelBoundKeys, createDeviceProxy, createLazyTrpcSource, createSliceHandle, deriveRecordingMode, describeModelVariant, effectiveStepSettings, findTimezone, formatParkedFor, hasModelBoundOverrides, isRootSuppliableStepId, modelBindingKey, normalizeUnit, publicEventCategories, resolveContainerPrimaryChild, resolveDeviceControlKind, resolveModelBoundSetting, resolveRecordingProfiles, resolveRootSupply, resolveVariantModelId, resolveViewableDeviceIds, searchDisplayIcons, selectAssignedProfileSlots, stepSettingSource, tryConvertUnit, unitsForDimension, withFieldFrom, withoutField, writeModelBoundSetting } from "@camstack/types";
|
|
11
11
|
import * as __mfHostTanstackQuery from "@tanstack/react-query";
|
|
12
12
|
import { QueryClient, QueryClientProvider, useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
13
13
|
import * as __mfHostReactDOMClient from "react-dom/client";
|
|
@@ -2430,6 +2430,26 @@ var Gauge = createLucideIcon("gauge", [["path", {
|
|
|
2430
2430
|
* This source code is licensed under the ISC license.
|
|
2431
2431
|
* See the LICENSE file in the root directory of this source tree.
|
|
2432
2432
|
*/
|
|
2433
|
+
var GraduationCap = createLucideIcon("graduation-cap", [
|
|
2434
|
+
["path", {
|
|
2435
|
+
d: "M21.42 10.922a1 1 0 0 0-.019-1.838L12.83 5.18a2 2 0 0 0-1.66 0L2.6 9.08a1 1 0 0 0 0 1.832l8.57 3.908a2 2 0 0 0 1.66 0z",
|
|
2436
|
+
key: "j76jl0"
|
|
2437
|
+
}],
|
|
2438
|
+
["path", {
|
|
2439
|
+
d: "M22 10v6",
|
|
2440
|
+
key: "1lu8f3"
|
|
2441
|
+
}],
|
|
2442
|
+
["path", {
|
|
2443
|
+
d: "M6 12.5V16a6 3 0 0 0 12 0v-3.5",
|
|
2444
|
+
key: "1r8lef"
|
|
2445
|
+
}]
|
|
2446
|
+
]);
|
|
2447
|
+
/**
|
|
2448
|
+
* @license lucide-react v0.576.0 - ISC
|
|
2449
|
+
*
|
|
2450
|
+
* This source code is licensed under the ISC license.
|
|
2451
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
2452
|
+
*/
|
|
2433
2453
|
var Grid2x2 = createLucideIcon("grid-2x2", [
|
|
2434
2454
|
["path", {
|
|
2435
2455
|
d: "M12 3v18",
|
|
@@ -6442,140 +6462,1063 @@ function useClusterNodes() {
|
|
|
6442
6462
|
};
|
|
6443
6463
|
}
|
|
6444
6464
|
//#endregion
|
|
6445
|
-
//#region src/
|
|
6465
|
+
//#region src/composites/device-meta.ts
|
|
6466
|
+
var DEVICE_TYPE_META = {
|
|
6467
|
+
[DeviceType.Camera]: {
|
|
6468
|
+
icon: Camera,
|
|
6469
|
+
label: "Camera"
|
|
6470
|
+
},
|
|
6471
|
+
[DeviceType.Hub]: {
|
|
6472
|
+
icon: Network,
|
|
6473
|
+
label: "Hub"
|
|
6474
|
+
},
|
|
6475
|
+
[DeviceType.Light]: {
|
|
6476
|
+
icon: Lightbulb,
|
|
6477
|
+
label: "Light"
|
|
6478
|
+
},
|
|
6479
|
+
[DeviceType.Siren]: {
|
|
6480
|
+
icon: Siren,
|
|
6481
|
+
label: "Siren"
|
|
6482
|
+
},
|
|
6483
|
+
[DeviceType.Switch]: {
|
|
6484
|
+
icon: ToggleLeft,
|
|
6485
|
+
label: "Switch"
|
|
6486
|
+
},
|
|
6487
|
+
[DeviceType.Sensor]: {
|
|
6488
|
+
icon: Activity,
|
|
6489
|
+
label: "Sensor"
|
|
6490
|
+
},
|
|
6491
|
+
[DeviceType.Thermostat]: {
|
|
6492
|
+
icon: Thermometer,
|
|
6493
|
+
label: "Thermostat"
|
|
6494
|
+
},
|
|
6495
|
+
[DeviceType.Climate]: {
|
|
6496
|
+
icon: AirVent,
|
|
6497
|
+
label: "Air conditioner"
|
|
6498
|
+
},
|
|
6499
|
+
[DeviceType.Button]: {
|
|
6500
|
+
icon: CircleDot,
|
|
6501
|
+
label: "Button"
|
|
6502
|
+
},
|
|
6503
|
+
[DeviceType.EventEmitter]: {
|
|
6504
|
+
icon: Zap,
|
|
6505
|
+
label: "Event Emitter"
|
|
6506
|
+
},
|
|
6507
|
+
[DeviceType.Update]: {
|
|
6508
|
+
icon: RefreshCw,
|
|
6509
|
+
label: "Update"
|
|
6510
|
+
},
|
|
6511
|
+
[DeviceType.Generic]: {
|
|
6512
|
+
icon: Box,
|
|
6513
|
+
label: "Generic"
|
|
6514
|
+
},
|
|
6515
|
+
[DeviceType.Notifier]: {
|
|
6516
|
+
icon: Bell,
|
|
6517
|
+
label: "Notifier"
|
|
6518
|
+
},
|
|
6519
|
+
[DeviceType.Script]: {
|
|
6520
|
+
icon: ScrollText,
|
|
6521
|
+
label: "Script"
|
|
6522
|
+
},
|
|
6523
|
+
[DeviceType.Automation]: {
|
|
6524
|
+
icon: Workflow,
|
|
6525
|
+
label: "Automation"
|
|
6526
|
+
},
|
|
6527
|
+
[DeviceType.Lock]: {
|
|
6528
|
+
icon: Lock,
|
|
6529
|
+
label: "Lock"
|
|
6530
|
+
},
|
|
6531
|
+
[DeviceType.Cover]: {
|
|
6532
|
+
icon: Blinds,
|
|
6533
|
+
label: "Cover"
|
|
6534
|
+
},
|
|
6535
|
+
[DeviceType.Valve]: {
|
|
6536
|
+
icon: Pipette,
|
|
6537
|
+
label: "Valve"
|
|
6538
|
+
},
|
|
6539
|
+
[DeviceType.Humidifier]: {
|
|
6540
|
+
icon: Waves,
|
|
6541
|
+
label: "Humidifier"
|
|
6542
|
+
},
|
|
6543
|
+
[DeviceType.WaterHeater]: {
|
|
6544
|
+
icon: Bath,
|
|
6545
|
+
label: "Water heater"
|
|
6546
|
+
},
|
|
6547
|
+
[DeviceType.Fan]: {
|
|
6548
|
+
icon: Fan,
|
|
6549
|
+
label: "Fan"
|
|
6550
|
+
},
|
|
6551
|
+
[DeviceType.MediaPlayer]: {
|
|
6552
|
+
icon: MonitorPlay,
|
|
6553
|
+
label: "Media player"
|
|
6554
|
+
},
|
|
6555
|
+
[DeviceType.AlarmPanel]: {
|
|
6556
|
+
icon: ShieldAlert,
|
|
6557
|
+
label: "Alarm panel"
|
|
6558
|
+
},
|
|
6559
|
+
[DeviceType.Control]: {
|
|
6560
|
+
icon: SlidersHorizontal,
|
|
6561
|
+
label: "Control"
|
|
6562
|
+
},
|
|
6563
|
+
[DeviceType.Presence]: {
|
|
6564
|
+
icon: MapPin,
|
|
6565
|
+
label: "Presence"
|
|
6566
|
+
},
|
|
6567
|
+
[DeviceType.Weather]: {
|
|
6568
|
+
icon: CloudSun,
|
|
6569
|
+
label: "Weather"
|
|
6570
|
+
},
|
|
6571
|
+
[DeviceType.Vacuum]: {
|
|
6572
|
+
icon: Bot,
|
|
6573
|
+
label: "Vacuum"
|
|
6574
|
+
},
|
|
6575
|
+
[DeviceType.LawnMower]: {
|
|
6576
|
+
icon: Tractor,
|
|
6577
|
+
label: "Lawn mower"
|
|
6578
|
+
},
|
|
6579
|
+
[DeviceType.Container]: {
|
|
6580
|
+
icon: Box,
|
|
6581
|
+
label: "Container"
|
|
6582
|
+
},
|
|
6583
|
+
[DeviceType.Image]: {
|
|
6584
|
+
icon: Image,
|
|
6585
|
+
label: "Image"
|
|
6586
|
+
},
|
|
6587
|
+
[DeviceType.PetFeeder]: {
|
|
6588
|
+
icon: Bone,
|
|
6589
|
+
label: "Pet feeder"
|
|
6590
|
+
}
|
|
6591
|
+
};
|
|
6592
|
+
var DEVICE_ROLE_META = {
|
|
6593
|
+
[DeviceRole.Siren]: {
|
|
6594
|
+
icon: Siren,
|
|
6595
|
+
label: "Siren"
|
|
6596
|
+
},
|
|
6597
|
+
[DeviceRole.Floodlight]: {
|
|
6598
|
+
icon: Lightbulb,
|
|
6599
|
+
label: "Floodlight"
|
|
6600
|
+
},
|
|
6601
|
+
[DeviceRole.Spotlight]: {
|
|
6602
|
+
icon: Flashlight,
|
|
6603
|
+
label: "Spotlight"
|
|
6604
|
+
},
|
|
6605
|
+
[DeviceRole.PirSensor]: {
|
|
6606
|
+
icon: Radar,
|
|
6607
|
+
label: "PIR sensor"
|
|
6608
|
+
},
|
|
6609
|
+
[DeviceRole.Chime]: {
|
|
6610
|
+
icon: Bell,
|
|
6611
|
+
label: "Chime"
|
|
6612
|
+
},
|
|
6613
|
+
[DeviceRole.Autotrack]: {
|
|
6614
|
+
icon: Crosshair,
|
|
6615
|
+
label: "Auto-track"
|
|
6616
|
+
},
|
|
6617
|
+
[DeviceRole.Nightvision]: {
|
|
6618
|
+
icon: Moon,
|
|
6619
|
+
label: "Night vision"
|
|
6620
|
+
},
|
|
6621
|
+
[DeviceRole.PrivacyMask]: {
|
|
6622
|
+
icon: EyeOff,
|
|
6623
|
+
label: "Privacy mask"
|
|
6624
|
+
},
|
|
6625
|
+
[DeviceRole.Doorbell]: {
|
|
6626
|
+
icon: DoorClosed,
|
|
6627
|
+
label: "Doorbell"
|
|
6628
|
+
},
|
|
6629
|
+
[DeviceRole.BinaryHelper]: {
|
|
6630
|
+
icon: ToggleLeft,
|
|
6631
|
+
label: "Binary helper"
|
|
6632
|
+
},
|
|
6633
|
+
[DeviceRole.MotionSensor]: {
|
|
6634
|
+
icon: Footprints,
|
|
6635
|
+
label: "Motion sensor"
|
|
6636
|
+
},
|
|
6637
|
+
[DeviceRole.ContactSensor]: {
|
|
6638
|
+
icon: DoorOpen,
|
|
6639
|
+
label: "Contact sensor"
|
|
6640
|
+
},
|
|
6641
|
+
[DeviceRole.LeakSensor]: {
|
|
6642
|
+
icon: Droplet,
|
|
6643
|
+
label: "Leak sensor"
|
|
6644
|
+
},
|
|
6645
|
+
[DeviceRole.SmokeSensor]: {
|
|
6646
|
+
icon: AlarmSmoke,
|
|
6647
|
+
label: "Smoke sensor"
|
|
6648
|
+
},
|
|
6649
|
+
[DeviceRole.COSensor]: {
|
|
6650
|
+
icon: Wind,
|
|
6651
|
+
label: "CO sensor"
|
|
6652
|
+
},
|
|
6653
|
+
[DeviceRole.GasSensor]: {
|
|
6654
|
+
icon: Flame,
|
|
6655
|
+
label: "Gas sensor"
|
|
6656
|
+
},
|
|
6657
|
+
[DeviceRole.TamperSensor]: {
|
|
6658
|
+
icon: ShieldAlert,
|
|
6659
|
+
label: "Tamper sensor"
|
|
6660
|
+
},
|
|
6661
|
+
[DeviceRole.VibrationSensor]: {
|
|
6662
|
+
icon: Vibrate,
|
|
6663
|
+
label: "Vibration sensor"
|
|
6664
|
+
},
|
|
6665
|
+
[DeviceRole.ConnectivitySensor]: {
|
|
6666
|
+
icon: Wifi,
|
|
6667
|
+
label: "Connectivity"
|
|
6668
|
+
},
|
|
6669
|
+
[DeviceRole.SoundSensor]: {
|
|
6670
|
+
icon: Volume2,
|
|
6671
|
+
label: "Sound sensor"
|
|
6672
|
+
},
|
|
6673
|
+
[DeviceRole.BinarySensor]: {
|
|
6674
|
+
icon: ToggleLeft,
|
|
6675
|
+
label: "Binary sensor"
|
|
6676
|
+
},
|
|
6677
|
+
[DeviceRole.TemperatureSensor]: {
|
|
6678
|
+
icon: Thermometer,
|
|
6679
|
+
label: "Temperature"
|
|
6680
|
+
},
|
|
6681
|
+
[DeviceRole.HumiditySensor]: {
|
|
6682
|
+
icon: Droplets,
|
|
6683
|
+
label: "Humidity"
|
|
6684
|
+
},
|
|
6685
|
+
[DeviceRole.AmbientLightSensor]: {
|
|
6686
|
+
icon: Sun,
|
|
6687
|
+
label: "Ambient light"
|
|
6688
|
+
},
|
|
6689
|
+
[DeviceRole.PressureSensor]: {
|
|
6690
|
+
icon: Gauge,
|
|
6691
|
+
label: "Pressure"
|
|
6692
|
+
},
|
|
6693
|
+
[DeviceRole.WindSensor]: {
|
|
6694
|
+
icon: Wind,
|
|
6695
|
+
label: "Wind"
|
|
6696
|
+
},
|
|
6697
|
+
[DeviceRole.RainSensor]: {
|
|
6698
|
+
icon: CloudRain,
|
|
6699
|
+
label: "Rain"
|
|
6700
|
+
},
|
|
6701
|
+
[DeviceRole.UvSensor]: {
|
|
6702
|
+
icon: SunMedium,
|
|
6703
|
+
label: "UV index"
|
|
6704
|
+
},
|
|
6705
|
+
[DeviceRole.SolarRadiationSensor]: {
|
|
6706
|
+
icon: Sunrise,
|
|
6707
|
+
label: "Solar radiation"
|
|
6708
|
+
},
|
|
6709
|
+
[DeviceRole.SoilMoistureSensor]: {
|
|
6710
|
+
icon: Sprout,
|
|
6711
|
+
label: "Soil moisture"
|
|
6712
|
+
},
|
|
6713
|
+
[DeviceRole.PowerSensor]: {
|
|
6714
|
+
icon: Zap,
|
|
6715
|
+
label: "Power"
|
|
6716
|
+
},
|
|
6717
|
+
[DeviceRole.EnergySensor]: {
|
|
6718
|
+
icon: Zap,
|
|
6719
|
+
label: "Energy"
|
|
6720
|
+
},
|
|
6721
|
+
[DeviceRole.VoltageSensor]: {
|
|
6722
|
+
icon: Zap,
|
|
6723
|
+
label: "Voltage"
|
|
6724
|
+
},
|
|
6725
|
+
[DeviceRole.CurrentSensor]: {
|
|
6726
|
+
icon: Zap,
|
|
6727
|
+
label: "Current"
|
|
6728
|
+
},
|
|
6729
|
+
[DeviceRole.AirQualitySensor]: {
|
|
6730
|
+
icon: Wind,
|
|
6731
|
+
label: "Air quality"
|
|
6732
|
+
},
|
|
6733
|
+
[DeviceRole.BatterySensor]: {
|
|
6734
|
+
icon: Gauge,
|
|
6735
|
+
label: "Battery"
|
|
6736
|
+
},
|
|
6737
|
+
[DeviceRole.NumericSensor]: {
|
|
6738
|
+
icon: Hash,
|
|
6739
|
+
label: "Numeric sensor"
|
|
6740
|
+
},
|
|
6741
|
+
[DeviceRole.EnumSensor]: {
|
|
6742
|
+
icon: List,
|
|
6743
|
+
label: "Enum sensor"
|
|
6744
|
+
},
|
|
6745
|
+
[DeviceRole.DateTimeSensor]: {
|
|
6746
|
+
icon: Clock,
|
|
6747
|
+
label: "Date / time"
|
|
6748
|
+
},
|
|
6749
|
+
[DeviceRole.GenericSensor]: {
|
|
6750
|
+
icon: Gauge,
|
|
6751
|
+
label: "Sensor"
|
|
6752
|
+
},
|
|
6753
|
+
[DeviceRole.NumericControl]: {
|
|
6754
|
+
icon: SlidersHorizontal,
|
|
6755
|
+
label: "Numeric control"
|
|
6756
|
+
},
|
|
6757
|
+
[DeviceRole.SelectControl]: {
|
|
6758
|
+
icon: ListChecks,
|
|
6759
|
+
label: "Select control"
|
|
6760
|
+
},
|
|
6761
|
+
[DeviceRole.TextControl]: {
|
|
6762
|
+
icon: Type,
|
|
6763
|
+
label: "Text control"
|
|
6764
|
+
},
|
|
6765
|
+
[DeviceRole.DateTimeControl]: {
|
|
6766
|
+
icon: Clock,
|
|
6767
|
+
label: "Date / time control"
|
|
6768
|
+
},
|
|
6769
|
+
[DeviceRole.MobilePushNotifier]: {
|
|
6770
|
+
icon: Smartphone,
|
|
6771
|
+
label: "Mobile push"
|
|
6772
|
+
},
|
|
6773
|
+
[DeviceRole.MessagingNotifier]: {
|
|
6774
|
+
icon: MessageSquare,
|
|
6775
|
+
label: "Messaging"
|
|
6776
|
+
},
|
|
6777
|
+
[DeviceRole.EmailNotifier]: {
|
|
6778
|
+
icon: Mail,
|
|
6779
|
+
label: "Email"
|
|
6780
|
+
},
|
|
6781
|
+
[DeviceRole.GenericNotifier]: {
|
|
6782
|
+
icon: Bell,
|
|
6783
|
+
label: "Notifier"
|
|
6784
|
+
}
|
|
6785
|
+
};
|
|
6786
|
+
var DEVICE_TYPE_VALUES$1 = new Set(Object.values(DeviceType));
|
|
6787
|
+
var DEVICE_ROLE_VALUES = new Set(Object.values(DeviceRole));
|
|
6788
|
+
function isDeviceType(value) {
|
|
6789
|
+
return DEVICE_TYPE_VALUES$1.has(value);
|
|
6790
|
+
}
|
|
6791
|
+
function isDeviceRole(value) {
|
|
6792
|
+
return DEVICE_ROLE_VALUES.has(value);
|
|
6793
|
+
}
|
|
6794
|
+
/** Meta for a known `DeviceType`. */
|
|
6795
|
+
function deviceTypeMeta(type) {
|
|
6796
|
+
return DEVICE_TYPE_META[type];
|
|
6797
|
+
}
|
|
6798
|
+
/** Meta for a known `DeviceRole`. */
|
|
6799
|
+
function deviceRoleMeta(role) {
|
|
6800
|
+
return DEVICE_ROLE_META[role];
|
|
6801
|
+
}
|
|
6802
|
+
var FALLBACK_DEVICE_TYPE_META = DEVICE_TYPE_META[DeviceType.Generic];
|
|
6803
|
+
var FALLBACK_DEVICE_ROLE_META = DEVICE_ROLE_META[DeviceRole.GenericSensor];
|
|
6446
6804
|
/**
|
|
6447
|
-
*
|
|
6805
|
+
* Runtime-string-safe lookup: device data crosses process / network boundaries
|
|
6806
|
+
* as plain strings, so an unrecognised value falls back to the `Generic` meta
|
|
6807
|
+
* instead of throwing.
|
|
6448
6808
|
*
|
|
6449
|
-
*
|
|
6450
|
-
*
|
|
6451
|
-
*
|
|
6452
|
-
|
|
6453
|
-
|
|
6809
|
+
* This also guards mixed-version module-federation loads where the host
|
|
6810
|
+
* `@camstack/types` enum has a new member before the loaded ui-library bundle
|
|
6811
|
+
* has the matching `DEVICE_TYPE_META` entry.
|
|
6812
|
+
*/
|
|
6813
|
+
function deviceTypeMetaOf(type) {
|
|
6814
|
+
if (!isDeviceType(type)) return FALLBACK_DEVICE_TYPE_META;
|
|
6815
|
+
return DEVICE_TYPE_META[type] ?? FALLBACK_DEVICE_TYPE_META;
|
|
6816
|
+
}
|
|
6817
|
+
/** Runtime-string-safe role lookup; unknown roles fall back to `GenericSensor`. */
|
|
6818
|
+
function deviceRoleMetaOf(role) {
|
|
6819
|
+
if (!isDeviceRole(role)) return FALLBACK_DEVICE_ROLE_META;
|
|
6820
|
+
return DEVICE_ROLE_META[role] ?? FALLBACK_DEVICE_ROLE_META;
|
|
6821
|
+
}
|
|
6822
|
+
/**
|
|
6823
|
+
* Icons an operator may pick for a per-device `display.icon` override (and for
|
|
6824
|
+
* a per-role default), keyed by a stable kebab-case name. Named imports only —
|
|
6825
|
+
* no dynamic indexing into lucide, so the bundle carries exactly this set.
|
|
6826
|
+
* Unknown keys resolve to `undefined` (caller falls through to the next level).
|
|
6454
6827
|
*
|
|
6455
|
-
*
|
|
6456
|
-
*
|
|
6457
|
-
*
|
|
6458
|
-
*
|
|
6459
|
-
*
|
|
6460
|
-
*
|
|
6828
|
+
* The vocabulary is the one the VIEWER draws from too (its own icon module,
|
|
6829
|
+
* keyed by these same strings): a key added here that the phone cannot draw
|
|
6830
|
+
* falls through to the next resolution level there, which reads as "my change
|
|
6831
|
+
* did nothing". So the KEY is the contract — a stable kebab-case string, never
|
|
6832
|
+
* a glyph identity — and `device-meta.test.ts` pins that every key resolves
|
|
6833
|
+
* and that the set never loses a key an operator may already have persisted.
|
|
6834
|
+
*
|
|
6835
|
+
* Grouped by what an operator is naming: a device, a light or appliance, a
|
|
6836
|
+
* sensor or the weather it reads, a room, or what moves through it. `gauge2`
|
|
6837
|
+
* is a legacy alias kept for rows that persisted it.
|
|
6461
6838
|
*/
|
|
6462
|
-
|
|
6463
|
-
|
|
6464
|
-
|
|
6465
|
-
|
|
6466
|
-
|
|
6467
|
-
|
|
6468
|
-
|
|
6469
|
-
|
|
6470
|
-
|
|
6471
|
-
|
|
6472
|
-
|
|
6473
|
-
|
|
6474
|
-
|
|
6475
|
-
|
|
6476
|
-
|
|
6477
|
-
|
|
6478
|
-
|
|
6479
|
-
|
|
6480
|
-
|
|
6481
|
-
|
|
6482
|
-
|
|
6483
|
-
|
|
6484
|
-
|
|
6485
|
-
|
|
6486
|
-
|
|
6487
|
-
|
|
6488
|
-
|
|
6489
|
-
|
|
6490
|
-
|
|
6491
|
-
|
|
6492
|
-
|
|
6493
|
-
|
|
6494
|
-
|
|
6495
|
-
|
|
6496
|
-
|
|
6497
|
-
|
|
6498
|
-
|
|
6499
|
-
|
|
6500
|
-
|
|
6501
|
-
|
|
6502
|
-
|
|
6503
|
-
|
|
6504
|
-
|
|
6505
|
-
|
|
6506
|
-
|
|
6507
|
-
|
|
6508
|
-
|
|
6509
|
-
|
|
6510
|
-
|
|
6511
|
-
|
|
6512
|
-
|
|
6513
|
-
|
|
6514
|
-
|
|
6515
|
-
|
|
6516
|
-
|
|
6517
|
-
|
|
6518
|
-
|
|
6519
|
-
|
|
6520
|
-
|
|
6521
|
-
|
|
6522
|
-
|
|
6523
|
-
|
|
6524
|
-
|
|
6525
|
-
|
|
6526
|
-
|
|
6527
|
-
|
|
6528
|
-
|
|
6529
|
-
|
|
6530
|
-
|
|
6531
|
-
|
|
6532
|
-
|
|
6533
|
-
|
|
6534
|
-
|
|
6535
|
-
|
|
6536
|
-
|
|
6537
|
-
|
|
6538
|
-
|
|
6539
|
-
|
|
6540
|
-
|
|
6541
|
-
|
|
6542
|
-
|
|
6543
|
-
|
|
6544
|
-
|
|
6545
|
-
|
|
6546
|
-
|
|
6547
|
-
|
|
6548
|
-
|
|
6549
|
-
|
|
6550
|
-
|
|
6551
|
-
|
|
6552
|
-
|
|
6553
|
-
|
|
6554
|
-
|
|
6555
|
-
|
|
6556
|
-
|
|
6557
|
-
|
|
6558
|
-
|
|
6559
|
-
|
|
6560
|
-
|
|
6561
|
-
|
|
6562
|
-
|
|
6563
|
-
|
|
6564
|
-
|
|
6565
|
-
|
|
6566
|
-
|
|
6567
|
-
|
|
6568
|
-
|
|
6569
|
-
|
|
6570
|
-
|
|
6571
|
-
|
|
6572
|
-
|
|
6573
|
-
|
|
6574
|
-
|
|
6575
|
-
|
|
6576
|
-
|
|
6577
|
-
|
|
6578
|
-
|
|
6839
|
+
var DISPLAY_ICON_REGISTRY = {
|
|
6840
|
+
camera: Camera,
|
|
6841
|
+
network: Network,
|
|
6842
|
+
"toggle-left": ToggleLeft,
|
|
6843
|
+
"toggle-right": ToggleRight,
|
|
6844
|
+
"circle-dot": CircleDot,
|
|
6845
|
+
"refresh-cw": RefreshCw,
|
|
6846
|
+
box: Box,
|
|
6847
|
+
"scroll-text": ScrollText,
|
|
6848
|
+
workflow: Workflow,
|
|
6849
|
+
lock: Lock,
|
|
6850
|
+
"lock-open": LockOpen,
|
|
6851
|
+
blinds: Blinds,
|
|
6852
|
+
"air-vent": AirVent,
|
|
6853
|
+
"monitor-play": MonitorPlay,
|
|
6854
|
+
"sliders-horizontal": SlidersHorizontal,
|
|
6855
|
+
"map-pin": MapPin,
|
|
6856
|
+
bot: Bot,
|
|
6857
|
+
tractor: Tractor,
|
|
6858
|
+
image: Image,
|
|
6859
|
+
bone: Bone,
|
|
6860
|
+
"door-closed": DoorClosed,
|
|
6861
|
+
"door-open": DoorOpen,
|
|
6862
|
+
crosshair: Crosshair,
|
|
6863
|
+
eye: Eye,
|
|
6864
|
+
"eye-off": EyeOff,
|
|
6865
|
+
smartphone: Smartphone,
|
|
6866
|
+
phone: Phone,
|
|
6867
|
+
tablet: Tablet,
|
|
6868
|
+
laptop: Laptop,
|
|
6869
|
+
monitor: Monitor,
|
|
6870
|
+
tv: Tv,
|
|
6871
|
+
speaker: Speaker,
|
|
6872
|
+
printer: Printer,
|
|
6873
|
+
projector: Projector,
|
|
6874
|
+
"gamepad-2": Gamepad2,
|
|
6875
|
+
radio: Radio,
|
|
6876
|
+
router: Router,
|
|
6877
|
+
bluetooth: Bluetooth,
|
|
6878
|
+
cpu: Cpu,
|
|
6879
|
+
"hard-drive": HardDrive,
|
|
6880
|
+
server: Server,
|
|
6881
|
+
mic: Mic,
|
|
6882
|
+
"mic-off": MicOff,
|
|
6883
|
+
video: Video,
|
|
6884
|
+
"video-off": VideoOff,
|
|
6885
|
+
music: Music,
|
|
6886
|
+
plug: Plug,
|
|
6887
|
+
"plug-zap": PlugZap,
|
|
6888
|
+
power: Power,
|
|
6889
|
+
"power-off": PowerOff,
|
|
6890
|
+
cable: Cable,
|
|
6891
|
+
battery: Battery,
|
|
6892
|
+
"battery-charging": BatteryCharging,
|
|
6893
|
+
"battery-full": BatteryFull,
|
|
6894
|
+
"battery-low": BatteryLow,
|
|
6895
|
+
key: Key,
|
|
6896
|
+
"key-round": KeyRound,
|
|
6897
|
+
mailbox: Mailbox,
|
|
6898
|
+
package: Package,
|
|
6899
|
+
shield: Shield,
|
|
6900
|
+
"shield-check": ShieldCheck,
|
|
6901
|
+
"shield-off": ShieldOff,
|
|
6902
|
+
lightbulb: Lightbulb,
|
|
6903
|
+
lamp: Lamp,
|
|
6904
|
+
"lamp-ceiling": LampCeiling,
|
|
6905
|
+
"lamp-desk": LampDesk,
|
|
6906
|
+
"lamp-floor": LampFloor,
|
|
6907
|
+
flashlight: Flashlight,
|
|
6908
|
+
heater: Heater,
|
|
6909
|
+
snowflake: Snowflake,
|
|
6910
|
+
"thermometer-sun": ThermometerSun,
|
|
6911
|
+
"thermometer-snowflake": ThermometerSnowflake,
|
|
6912
|
+
refrigerator: Refrigerator,
|
|
6913
|
+
microwave: Microwave,
|
|
6914
|
+
"washing-machine": WashingMachine,
|
|
6915
|
+
"cooking-pot": CookingPot,
|
|
6916
|
+
utensils: Utensils,
|
|
6917
|
+
thermometer: Thermometer,
|
|
6918
|
+
droplets: Droplets,
|
|
6919
|
+
droplet: Droplet,
|
|
6920
|
+
gauge: Gauge,
|
|
6921
|
+
gauge2: Gauge,
|
|
6922
|
+
sun: Sun,
|
|
6923
|
+
"sun-medium": SunMedium,
|
|
6924
|
+
sunrise: Sunrise,
|
|
6925
|
+
moon: Moon,
|
|
6926
|
+
wind: Wind,
|
|
6927
|
+
cloud: Cloud,
|
|
6928
|
+
"cloud-rain": CloudRain,
|
|
6929
|
+
"cloud-sun": CloudSun,
|
|
6930
|
+
waves: Waves,
|
|
6931
|
+
sprout: Sprout,
|
|
6932
|
+
leaf: Leaf,
|
|
6933
|
+
flower: Flower,
|
|
6934
|
+
zap: Zap,
|
|
6935
|
+
flame: Flame,
|
|
6936
|
+
bell: Bell,
|
|
6937
|
+
"bell-ring": BellRing,
|
|
6938
|
+
"bell-off": BellOff,
|
|
6939
|
+
siren: Siren,
|
|
6940
|
+
radar: Radar,
|
|
6941
|
+
activity: Activity,
|
|
6942
|
+
hash: Hash,
|
|
6943
|
+
clock: Clock,
|
|
6944
|
+
timer: Timer,
|
|
6945
|
+
calendar: Calendar,
|
|
6946
|
+
pipette: Pipette,
|
|
6947
|
+
fan: Fan,
|
|
6948
|
+
bath: Bath,
|
|
6949
|
+
footprints: Footprints,
|
|
6950
|
+
"alarm-smoke": AlarmSmoke,
|
|
6951
|
+
"shield-alert": ShieldAlert,
|
|
6952
|
+
vibrate: Vibrate,
|
|
6953
|
+
wifi: Wifi,
|
|
6954
|
+
"wifi-off": WifiOff,
|
|
6955
|
+
"volume-2": Volume2,
|
|
6956
|
+
"volume-x": VolumeX,
|
|
6957
|
+
heart: Heart,
|
|
6958
|
+
"heart-pulse": HeartPulse,
|
|
6959
|
+
star: Star,
|
|
6960
|
+
sparkles: Sparkles,
|
|
6961
|
+
house: House,
|
|
6962
|
+
sofa: Sofa,
|
|
6963
|
+
"bed-double": BedDouble,
|
|
6964
|
+
bed: Bed,
|
|
6965
|
+
warehouse: Warehouse,
|
|
6966
|
+
trees: Trees,
|
|
6967
|
+
"tree-pine": TreePine,
|
|
6968
|
+
fence: Fence,
|
|
6969
|
+
store: Store,
|
|
6970
|
+
building: Building,
|
|
6971
|
+
"building-2": Building2,
|
|
6972
|
+
mountain: Mountain,
|
|
6973
|
+
umbrella: Umbrella,
|
|
6974
|
+
dumbbell: Dumbbell,
|
|
6975
|
+
wrench: Wrench,
|
|
6976
|
+
hammer: Hammer,
|
|
6977
|
+
drill: Drill,
|
|
6978
|
+
"waves-ladder": WavesLadder,
|
|
6979
|
+
"circle-parking": CircleParking,
|
|
6980
|
+
briefcase: Briefcase,
|
|
6981
|
+
route: Route,
|
|
6982
|
+
car: Car,
|
|
6983
|
+
bike: Bike,
|
|
6984
|
+
bus: Bus,
|
|
6985
|
+
truck: Truck,
|
|
6986
|
+
plane: Plane,
|
|
6987
|
+
"train-front": TrainFront,
|
|
6988
|
+
sailboat: Sailboat,
|
|
6989
|
+
dog: Dog,
|
|
6990
|
+
cat: Cat,
|
|
6991
|
+
bird: Bird,
|
|
6992
|
+
"paw-print": PawPrint,
|
|
6993
|
+
baby: Baby,
|
|
6994
|
+
user: User,
|
|
6995
|
+
users: Users,
|
|
6996
|
+
"person-standing": PersonStanding
|
|
6997
|
+
};
|
|
6998
|
+
/** Resolve a `display.icon` name to a lucide component, or `undefined` when the
|
|
6999
|
+
* name is not in the curated `DISPLAY_ICON_REGISTRY`. */
|
|
7000
|
+
function resolveDisplayIcon(name) {
|
|
7001
|
+
return Object.hasOwn(DISPLAY_ICON_REGISTRY, name) ? DISPLAY_ICON_REGISTRY[name] : void 0;
|
|
7002
|
+
}
|
|
7003
|
+
/**
|
|
7004
|
+
* EXHAUSTIVE device-type filter options — one entry per `DeviceType` member,
|
|
7005
|
+
* derived from `DEVICE_TYPE_META` so the set is always complete and a newly
|
|
7006
|
+
* added `DeviceType` automatically appears in every type filter (Devices page,
|
|
7007
|
+
* adoption modal, …) without touching any consumer.
|
|
7008
|
+
*
|
|
7009
|
+
* The previous per-consumer logic built options from the types PRESENT in the
|
|
7010
|
+
* list (or a hand-maintained subset), so recently-added types (vacuum, lawn
|
|
7011
|
+
* mower, valve, humidifier, water heater, weather, image, …) were silently
|
|
7012
|
+
* missing from the dropdown. This is the single source of truth instead.
|
|
7013
|
+
*
|
|
7014
|
+
* `id` is the raw `DeviceType` string (matches the filtering predicate, which
|
|
7015
|
+
* compares against `device.type`); `label` + `icon` come from the meta map.
|
|
7016
|
+
* Ordered by `DeviceType` declaration order for a stable, intentional layout.
|
|
7017
|
+
*/
|
|
7018
|
+
var ALL_DEVICE_TYPE_FILTER_OPTIONS = Object.values(DeviceType).map((type) => {
|
|
7019
|
+
const meta = deviceTypeMetaOf(type);
|
|
7020
|
+
return {
|
|
7021
|
+
id: type,
|
|
7022
|
+
label: meta.label,
|
|
7023
|
+
icon: meta.icon
|
|
7024
|
+
};
|
|
7025
|
+
});
|
|
7026
|
+
function allDeviceTypeFilterOptions() {
|
|
7027
|
+
return ALL_DEVICE_TYPE_FILTER_OPTIONS;
|
|
7028
|
+
}
|
|
7029
|
+
//#endregion
|
|
7030
|
+
//#region src/composites/icon-picker.tsx
|
|
7031
|
+
/**
|
|
7032
|
+
* icon-picker — the ONE control for choosing an icon, wherever admin-ui asks.
|
|
7033
|
+
*
|
|
7034
|
+
* There were two: a device one over `DISPLAY_ICON_REGISTRY` and a room one
|
|
7035
|
+
* over `LOCATION_ICON_IDS`, identical apart from the vocabulary they walked.
|
|
7036
|
+
* That was tolerable while the device set was 56 glyphs in a flat grid. It is
|
|
7037
|
+
* not at 157: a picker that only lets the operator HUNT is a picker they stop
|
|
7038
|
+
* using, and the two copies were already drifting — only one of them had an
|
|
7039
|
+
* i18n'd label.
|
|
7040
|
+
*
|
|
7041
|
+
* So the vocabulary, the grouping and the search all come from
|
|
7042
|
+
* `@camstack/types`' `display-icon-vocabulary`, which is the same module the
|
|
7043
|
+
* viewer's sheet searches. What is left here is the web half: a popover, a
|
|
7044
|
+
* grid, and a text field.
|
|
7045
|
+
*
|
|
7046
|
+
* ## What it does NOT own
|
|
7047
|
+
*
|
|
7048
|
+
* - **The glyphs.** `resolveGlyph` is a prop, because this package's table is
|
|
7049
|
+
* `lucide-react` and the viewer's is `lucide-react-native`. A key this build
|
|
7050
|
+
* cannot draw is SKIPPED rather than rendered as a hole — an empty tile
|
|
7051
|
+
* reads as a rendering bug, not as a missing choice.
|
|
7052
|
+
* - **The words.** Every string is a prop. This package has no i18n (one file
|
|
7053
|
+
* in it imports react-i18next, and that is the exception), and a control
|
|
7054
|
+
* that reached for a translation would force it on every consumer.
|
|
7055
|
+
* - **The write.** `onPick` is called and that is all; whether it is a form
|
|
7056
|
+
* value or an immediate mutation is the caller's business, as it already was
|
|
7057
|
+
* in both pickers this replaces.
|
|
7058
|
+
*
|
|
7059
|
+
* ## The clear tile is never filtered away
|
|
7060
|
+
*
|
|
7061
|
+
* The "inherit" / "no icon" choice sits above the sections and ignores the
|
|
7062
|
+
* search. A query that hid it would strand the operator on a glyph they picked
|
|
7063
|
+
* by accident with no way back to the default — the one action a picker must
|
|
7064
|
+
* always offer.
|
|
7065
|
+
*/
|
|
7066
|
+
function IconPicker({ value, onPick, resolveGlyph, fallbackGlyph, labels, only, extraWords, clearGlyph, labelFor, disabled = false }) {
|
|
7067
|
+
const [open, setOpen] = useState(false);
|
|
7068
|
+
const [query, setQuery] = useState("");
|
|
7069
|
+
const allowed = useMemo(() => only === void 0 ? null : new Set(only), [only]);
|
|
7070
|
+
const sections = useMemo(() => {
|
|
7071
|
+
const hits = searchDisplayIcons(query, extraWords);
|
|
7072
|
+
const byGroup = /* @__PURE__ */ new Map();
|
|
7073
|
+
for (const hit of hits) {
|
|
7074
|
+
const { key, group } = hit.entry;
|
|
7075
|
+
if (allowed !== null && !allowed.has(key)) continue;
|
|
7076
|
+
if (resolveGlyph(key) === void 0) continue;
|
|
7077
|
+
const bucket = byGroup.get(group);
|
|
7078
|
+
if (bucket === void 0) byGroup.set(group, [key]);
|
|
7079
|
+
else bucket.push(key);
|
|
7080
|
+
}
|
|
7081
|
+
return DISPLAY_ICON_GROUPS.flatMap((group) => {
|
|
7082
|
+
const keys = byGroup.get(group);
|
|
7083
|
+
return keys === void 0 || keys.length === 0 ? [] : [{
|
|
7084
|
+
group,
|
|
7085
|
+
keys
|
|
7086
|
+
}];
|
|
7087
|
+
});
|
|
7088
|
+
}, [
|
|
7089
|
+
query,
|
|
7090
|
+
extraWords,
|
|
7091
|
+
allowed,
|
|
7092
|
+
resolveGlyph
|
|
7093
|
+
]);
|
|
7094
|
+
const Current = (value === null ? void 0 : resolveGlyph(value)) ?? fallbackGlyph;
|
|
7095
|
+
const choose = async (next) => {
|
|
7096
|
+
setOpen(false);
|
|
7097
|
+
setQuery("");
|
|
7098
|
+
await onPick(next);
|
|
7099
|
+
};
|
|
7100
|
+
const Clear = clearGlyph ?? fallbackGlyph;
|
|
7101
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
7102
|
+
className: "relative flex shrink-0 items-center gap-2",
|
|
7103
|
+
children: [/* @__PURE__ */ jsx("button", {
|
|
7104
|
+
type: "button",
|
|
7105
|
+
disabled,
|
|
7106
|
+
onClick: () => setOpen((o) => !o),
|
|
7107
|
+
"aria-expanded": open,
|
|
7108
|
+
"aria-label": labels.trigger,
|
|
7109
|
+
title: labels.trigger,
|
|
7110
|
+
className: "rounded border border-border p-1 text-foreground-muted hover:bg-surface-hover disabled:opacity-50",
|
|
7111
|
+
children: /* @__PURE__ */ jsx(Current, { className: "h-4 w-4" })
|
|
7112
|
+
}), open && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("button", {
|
|
7113
|
+
type: "button",
|
|
7114
|
+
"aria-label": labels.close,
|
|
7115
|
+
onClick: () => setOpen(false),
|
|
7116
|
+
className: "fixed inset-0 z-10 cursor-default"
|
|
7117
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
7118
|
+
role: "group",
|
|
7119
|
+
"aria-label": labels.panel,
|
|
7120
|
+
className: "absolute left-0 top-full z-20 mt-1 max-h-80 w-72 overflow-y-auto rounded-md border border-border bg-surface p-2 shadow-lg",
|
|
7121
|
+
children: [
|
|
7122
|
+
/* @__PURE__ */ jsx("input", {
|
|
7123
|
+
type: "search",
|
|
7124
|
+
value: query,
|
|
7125
|
+
autoFocus: true,
|
|
7126
|
+
onChange: (e) => setQuery(e.target.value),
|
|
7127
|
+
placeholder: labels.searchPlaceholder,
|
|
7128
|
+
"aria-label": labels.searchPlaceholder,
|
|
7129
|
+
className: "mb-2 w-full rounded border border-border bg-surface-raised px-2 py-1 text-xs text-foreground placeholder:text-foreground-subtle"
|
|
7130
|
+
}),
|
|
7131
|
+
/* @__PURE__ */ jsxs("button", {
|
|
7132
|
+
type: "button",
|
|
7133
|
+
onClick: () => void choose(null),
|
|
7134
|
+
"aria-pressed": value === null,
|
|
7135
|
+
className: "mb-2 flex w-full items-center gap-1.5 rounded px-1.5 py-1 text-[11px] text-foreground-subtle hover:bg-surface-hover",
|
|
7136
|
+
children: [/* @__PURE__ */ jsx(Clear, { className: "h-3.5 w-3.5" }), labels.clear]
|
|
7137
|
+
}),
|
|
7138
|
+
sections.length === 0 ? /* @__PURE__ */ jsx("p", {
|
|
7139
|
+
className: "px-1.5 py-2 text-[11px] text-foreground-subtle",
|
|
7140
|
+
children: labels.noMatches
|
|
7141
|
+
}) : sections.map(({ group, keys }) => /* @__PURE__ */ jsxs("section", {
|
|
7142
|
+
className: "mb-2 last:mb-0",
|
|
7143
|
+
children: [/* @__PURE__ */ jsx("h4", {
|
|
7144
|
+
className: "px-1.5 pb-1 text-[10px] uppercase tracking-wide text-foreground-subtle",
|
|
7145
|
+
children: labels.groups[group]
|
|
7146
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
7147
|
+
className: "grid grid-cols-7 gap-1",
|
|
7148
|
+
children: keys.map((key) => {
|
|
7149
|
+
const Glyph = resolveGlyph(key);
|
|
7150
|
+
if (Glyph === void 0) return null;
|
|
7151
|
+
const selected = value === key;
|
|
7152
|
+
return /* @__PURE__ */ jsx("button", {
|
|
7153
|
+
type: "button",
|
|
7154
|
+
onClick: () => void choose(key),
|
|
7155
|
+
"aria-pressed": selected,
|
|
7156
|
+
"aria-label": labelFor?.(key) ?? key,
|
|
7157
|
+
title: labelFor?.(key) ?? key,
|
|
7158
|
+
className: selected ? "flex items-center justify-center rounded border border-primary bg-primary/10 p-1.5 text-foreground" : "flex items-center justify-center rounded border border-transparent p-1.5 text-foreground-muted hover:bg-surface-hover",
|
|
7159
|
+
children: /* @__PURE__ */ jsx(Glyph, { className: "h-4 w-4" })
|
|
7160
|
+
}, key);
|
|
7161
|
+
})
|
|
7162
|
+
})]
|
|
7163
|
+
}, group))
|
|
7164
|
+
]
|
|
7165
|
+
})] })]
|
|
7166
|
+
});
|
|
7167
|
+
}
|
|
7168
|
+
//#endregion
|
|
7169
|
+
//#region src/composites/config-icon-field.tsx
|
|
7170
|
+
/**
|
|
7171
|
+
* The control behind a `type: 'icon'` settings field (D780).
|
|
7172
|
+
*
|
|
7173
|
+
* The shared `<IconPicker>` over the display-icon vocabulary, with the device
|
|
7174
|
+
* glyph table — the same control and the same keys the device and room
|
|
7175
|
+
* pickers use. An icon field always draws something, so clearing is "back to
|
|
7176
|
+
* the field's default", and a stored value the vocabulary does not know (a
|
|
7177
|
+
* free-text lucide name from before D780) is drawn as that default.
|
|
7178
|
+
*/
|
|
7179
|
+
function labelsFor(label) {
|
|
7180
|
+
return {
|
|
7181
|
+
trigger: `Choose an icon for ${label}`,
|
|
7182
|
+
panel: `${label} icon`,
|
|
7183
|
+
close: "Close",
|
|
7184
|
+
searchPlaceholder: "Search icons",
|
|
7185
|
+
clear: "Default icon",
|
|
7186
|
+
noMatches: "No icon matches",
|
|
7187
|
+
groups: {
|
|
7188
|
+
device: "Devices",
|
|
7189
|
+
lighting: "Lighting",
|
|
7190
|
+
sensing: "Sensing",
|
|
7191
|
+
place: "Places",
|
|
7192
|
+
life: "Life"
|
|
7193
|
+
}
|
|
7194
|
+
};
|
|
7195
|
+
}
|
|
7196
|
+
function ConfigIconFieldControl({ label, value, defaultKey, disabled, onChange }) {
|
|
7197
|
+
const key = resolveDisplayIconKey(value, defaultKey);
|
|
7198
|
+
const DefaultGlyph = resolveDisplayIcon(defaultKey) ?? ShieldCheck;
|
|
7199
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
7200
|
+
className: "flex items-center gap-2",
|
|
7201
|
+
children: [/* @__PURE__ */ jsx(IconPicker, {
|
|
7202
|
+
value: key === "" ? null : key,
|
|
7203
|
+
onPick: (next) => onChange(next ?? defaultKey),
|
|
7204
|
+
resolveGlyph: resolveDisplayIcon,
|
|
7205
|
+
fallbackGlyph: DefaultGlyph,
|
|
7206
|
+
labels: labelsFor(label),
|
|
7207
|
+
disabled
|
|
7208
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
7209
|
+
className: "text-[11px] text-foreground-subtle font-mono",
|
|
7210
|
+
children: key
|
|
7211
|
+
})]
|
|
7212
|
+
});
|
|
7213
|
+
}
|
|
7214
|
+
//#endregion
|
|
7215
|
+
//#region src/composites/config-secret-field.tsx
|
|
7216
|
+
/**
|
|
7217
|
+
* A keychain-stored secret in a settings form (D787, D789).
|
|
7218
|
+
*
|
|
7219
|
+
* The form never holds the value. It receives the field's VIEW —
|
|
7220
|
+
* `{ $secret, v, set: true }` when something is stored, `null` when nothing
|
|
7221
|
+
* is — and sends back exactly one of three things:
|
|
7222
|
+
*
|
|
7223
|
+
* - the view, unchanged ........ KEEP (also what an untouched form saves);
|
|
7224
|
+
* - a non-empty typed string ... CHANGE (the owner stores it in the keychain);
|
|
7225
|
+
* - `{ $secretClear: true }` ... CLEAR (the only thing that removes it).
|
|
7226
|
+
*
|
|
7227
|
+
* `''` is never sent for "remove": the save path reads it as KEEP, because an
|
|
7228
|
+
* empty string is what a defaults fallback writes back.
|
|
7229
|
+
*
|
|
7230
|
+
* Reveal shows the stored value for a few seconds, through the host's audited
|
|
7231
|
+
* `keychain-admin.reveal` (provided with {@link SecretRevealProvider}); a host
|
|
7232
|
+
* that provides none has no Reveal button.
|
|
7233
|
+
*/
|
|
7234
|
+
/** How long a revealed value stays on screen. */
|
|
7235
|
+
var SECRET_REVEAL_MS = 1e4;
|
|
7236
|
+
var SecretRevealContext = createSharedContext("camstack:secret-reveal", null);
|
|
7237
|
+
function SecretRevealProvider({ reveal, children }) {
|
|
7238
|
+
return /* @__PURE__ */ jsx(SecretRevealContext.Provider, {
|
|
7239
|
+
value: reveal,
|
|
7240
|
+
children
|
|
7241
|
+
});
|
|
7242
|
+
}
|
|
7243
|
+
/** Does this value belong to the keychain rendering (a view, or "not set")? */
|
|
7244
|
+
function isKeychainFieldValue(value) {
|
|
7245
|
+
return value === null || isSecretFieldView(value) || isSecretClear(value);
|
|
7246
|
+
}
|
|
7247
|
+
var BUTTON$1 = "inline-flex items-center gap-1 rounded border border-border bg-surface px-2 py-0.5 text-[11px] font-medium text-foreground hover:border-primary/40 hover:bg-primary/5 disabled:opacity-40 disabled:cursor-not-allowed";
|
|
7248
|
+
var INPUT = "w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-xs text-foreground focus:border-primary focus:ring-1 focus:ring-primary/30 outline-none disabled:opacity-50";
|
|
7249
|
+
function SecretFieldControl({ field, value, onChange, disabled, multiline }) {
|
|
7250
|
+
const reveal = useContext(SecretRevealContext);
|
|
7251
|
+
const [original] = useState(() => isSecretFieldView(value) ? value : null);
|
|
7252
|
+
const [mode, setMode] = useState(() => typeof value === "string" && value.length > 0 ? {
|
|
7253
|
+
kind: "editing",
|
|
7254
|
+
text: value
|
|
7255
|
+
} : isSecretClear(value) ? { kind: "clearing" } : { kind: "idle" });
|
|
7256
|
+
const [shown, setShown] = useState(null);
|
|
7257
|
+
const [revealError, setRevealError] = useState(null);
|
|
7258
|
+
const [showTyped, setShowTyped] = useState(false);
|
|
7259
|
+
useEffect(() => {
|
|
7260
|
+
if (shown === null) return;
|
|
7261
|
+
const timer = setTimeout(() => setShown(null), SECRET_REVEAL_MS);
|
|
7262
|
+
return () => clearTimeout(timer);
|
|
7263
|
+
}, [shown]);
|
|
7264
|
+
const isSet = original !== null;
|
|
7265
|
+
const ref = original?.$secret ?? null;
|
|
7266
|
+
const keep = () => {
|
|
7267
|
+
setMode({ kind: "idle" });
|
|
7268
|
+
onChange(original);
|
|
7269
|
+
};
|
|
7270
|
+
const label = "label" in field ? field.label : "";
|
|
7271
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
7272
|
+
className: "space-y-1",
|
|
7273
|
+
"data-secret-field": "key" in field ? field.key : void 0,
|
|
7274
|
+
children: [
|
|
7275
|
+
mode.kind === "editing" ? /* @__PURE__ */ jsxs("div", {
|
|
7276
|
+
className: "flex items-start gap-1.5",
|
|
7277
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
7278
|
+
className: "relative flex-1",
|
|
7279
|
+
children: [multiline ? /* @__PURE__ */ jsx("textarea", {
|
|
7280
|
+
className: `${INPUT} min-h-[60px] font-mono`,
|
|
7281
|
+
"aria-label": label,
|
|
7282
|
+
value: mode.text,
|
|
7283
|
+
autoComplete: "off",
|
|
7284
|
+
spellCheck: false,
|
|
7285
|
+
disabled,
|
|
7286
|
+
onChange: (e) => {
|
|
7287
|
+
setMode({
|
|
7288
|
+
kind: "editing",
|
|
7289
|
+
text: e.target.value
|
|
7290
|
+
});
|
|
7291
|
+
onChange(e.target.value.length > 0 ? e.target.value : original);
|
|
7292
|
+
}
|
|
7293
|
+
}) : /* @__PURE__ */ jsx("input", {
|
|
7294
|
+
type: showTyped ? "text" : "password",
|
|
7295
|
+
className: `${INPUT} pr-8`,
|
|
7296
|
+
"aria-label": label,
|
|
7297
|
+
value: mode.text,
|
|
7298
|
+
autoComplete: "new-password",
|
|
7299
|
+
spellCheck: false,
|
|
7300
|
+
disabled,
|
|
7301
|
+
autoFocus: true,
|
|
7302
|
+
onChange: (e) => {
|
|
7303
|
+
setMode({
|
|
7304
|
+
kind: "editing",
|
|
7305
|
+
text: e.target.value
|
|
7306
|
+
});
|
|
7307
|
+
onChange(e.target.value.length > 0 ? e.target.value : original);
|
|
7308
|
+
}
|
|
7309
|
+
}), !multiline && /* @__PURE__ */ jsx("button", {
|
|
7310
|
+
type: "button",
|
|
7311
|
+
className: "absolute right-2 top-1/2 -translate-y-1/2 text-foreground-subtle hover:text-foreground",
|
|
7312
|
+
tabIndex: -1,
|
|
7313
|
+
"aria-label": showTyped ? "Hide" : "Show",
|
|
7314
|
+
onClick: () => setShowTyped((s) => !s),
|
|
7315
|
+
children: showTyped ? /* @__PURE__ */ jsx(EyeOff, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx(Eye, { className: "h-3.5 w-3.5" })
|
|
7316
|
+
})]
|
|
7317
|
+
}), /* @__PURE__ */ jsx("button", {
|
|
7318
|
+
type: "button",
|
|
7319
|
+
className: BUTTON$1,
|
|
7320
|
+
onClick: keep,
|
|
7321
|
+
disabled,
|
|
7322
|
+
children: "Cancel"
|
|
7323
|
+
})]
|
|
7324
|
+
}) : /* @__PURE__ */ jsxs("div", {
|
|
7325
|
+
className: "flex flex-wrap items-center gap-1.5",
|
|
7326
|
+
children: [/* @__PURE__ */ jsxs("span", {
|
|
7327
|
+
className: `inline-flex items-center gap-1 rounded-md border px-2 py-1 text-xs ${mode.kind === "clearing" ? "border-danger/40 text-danger" : isSet ? "border-border text-foreground" : "border-dashed border-border text-foreground-subtle"}`,
|
|
7328
|
+
children: [/* @__PURE__ */ jsx(KeyRound, { className: "h-3 w-3" }), mode.kind === "clearing" ? "will be removed on save" : shown !== null ? /* @__PURE__ */ jsx("code", {
|
|
7329
|
+
className: "font-mono break-all",
|
|
7330
|
+
children: shown
|
|
7331
|
+
}) : isSet ? "●●●●●● set" : "not set"]
|
|
7332
|
+
}), mode.kind === "clearing" ? /* @__PURE__ */ jsx("button", {
|
|
7333
|
+
type: "button",
|
|
7334
|
+
className: BUTTON$1,
|
|
7335
|
+
onClick: keep,
|
|
7336
|
+
disabled,
|
|
7337
|
+
children: "Undo"
|
|
7338
|
+
}) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
7339
|
+
/* @__PURE__ */ jsx("button", {
|
|
7340
|
+
type: "button",
|
|
7341
|
+
className: BUTTON$1,
|
|
7342
|
+
disabled,
|
|
7343
|
+
onClick: () => setMode({
|
|
7344
|
+
kind: "editing",
|
|
7345
|
+
text: ""
|
|
7346
|
+
}),
|
|
7347
|
+
children: isSet ? "Change" : "Set"
|
|
7348
|
+
}),
|
|
7349
|
+
isSet && /* @__PURE__ */ jsx("button", {
|
|
7350
|
+
type: "button",
|
|
7351
|
+
className: BUTTON$1,
|
|
7352
|
+
disabled,
|
|
7353
|
+
onClick: () => {
|
|
7354
|
+
setShown(null);
|
|
7355
|
+
setMode({ kind: "clearing" });
|
|
7356
|
+
onChange(SECRET_CLEAR);
|
|
7357
|
+
},
|
|
7358
|
+
children: "Clear"
|
|
7359
|
+
}),
|
|
7360
|
+
isSet && ref !== null && reveal !== null && /* @__PURE__ */ jsx("button", {
|
|
7361
|
+
type: "button",
|
|
7362
|
+
className: BUTTON$1,
|
|
7363
|
+
disabled,
|
|
7364
|
+
onClick: () => {
|
|
7365
|
+
if (shown !== null) {
|
|
7366
|
+
setShown(null);
|
|
7367
|
+
return;
|
|
7368
|
+
}
|
|
7369
|
+
setRevealError(null);
|
|
7370
|
+
reveal(ref).then(setShown, (err) => setRevealError(err instanceof Error ? err.message : String(err)));
|
|
7371
|
+
},
|
|
7372
|
+
children: shown !== null ? "Hide" : "Reveal"
|
|
7373
|
+
})
|
|
7374
|
+
] })]
|
|
7375
|
+
}),
|
|
7376
|
+
original?.inline === true && mode.kind === "idle" && /* @__PURE__ */ jsx("p", {
|
|
7377
|
+
className: "text-[10px] text-foreground-subtle",
|
|
7378
|
+
children: "Stored before the keychain; it moves there the next time it is changed."
|
|
7379
|
+
}),
|
|
7380
|
+
revealError !== null && /* @__PURE__ */ jsx("p", {
|
|
7381
|
+
className: "text-[10px] text-danger",
|
|
7382
|
+
children: revealError
|
|
7383
|
+
})
|
|
7384
|
+
]
|
|
7385
|
+
});
|
|
7386
|
+
}
|
|
7387
|
+
//#endregion
|
|
7388
|
+
//#region src/generated/system-hooks.ts
|
|
7389
|
+
/**
|
|
7390
|
+
* Per-method React-Query hooks for every `scope: 'system'` capability.
|
|
7391
|
+
*
|
|
7392
|
+
* Each hook is a thin pass-through to `trpc.<cap>.<method>.useQuery` /
|
|
7393
|
+
* `.useMutation` / `.useSubscription` so the typed inference + RQ
|
|
7394
|
+
* cache/dedup keep working — the generator only contributes a consistent
|
|
7395
|
+
* name and stable export surface so admin-ui pages can write
|
|
7396
|
+
* `useAddonsList()` instead of `trpc.addons.list.useQuery()`.
|
|
7397
|
+
*
|
|
7398
|
+
* Push-subscription methods (`kind: 'subscription'`) emit a typeof
|
|
7399
|
+
* alias over `useSubscription`, so the call shape is
|
|
7400
|
+
* `useToastOnToast(input, { onData: cb })` — same as the underlying
|
|
7401
|
+
* tRPC hook. The eventBus-backed `useLiveEvent` (see
|
|
7402
|
+
* `../hooks/use-live-event.ts`) covers events that don't ride a tRPC
|
|
7403
|
+
* subscription; the two surfaces coexist by design.
|
|
7404
|
+
*/
|
|
7405
|
+
/** Generated alias around `trpc.accessories.setChildHidden.useMutation`. */
|
|
7406
|
+
var useAccessoriesSetChildHidden = trpc.accessories.setChildHidden.useMutation;
|
|
7407
|
+
/** Generated alias around `trpc.accessories.getStatus.useQuery`. */
|
|
7408
|
+
var useAccessoriesGetStatus = trpc.accessories.getStatus.useQuery;
|
|
7409
|
+
/** Generated alias around `trpc.addonPages.listPages.useQuery`. */
|
|
7410
|
+
var useAddonPagesListPages = trpc.addonPages.listPages.useQuery;
|
|
7411
|
+
/** Generated alias around `trpc.addons.list.useQuery`. */
|
|
7412
|
+
var useAddonsList = trpc.addons.list.useQuery;
|
|
7413
|
+
/** Generated alias around `trpc.addons.getLogs.useQuery`. */
|
|
7414
|
+
var useAddonsGetLogs = trpc.addons.getLogs.useQuery;
|
|
7415
|
+
/** Generated alias around `trpc.addons.listPackages.useQuery`. */
|
|
7416
|
+
var useAddonsListPackages = trpc.addons.listPackages.useQuery;
|
|
7417
|
+
/** Generated alias around `trpc.addons.installPackage.useMutation`. */
|
|
7418
|
+
var useAddonsInstallPackage = trpc.addons.installPackage.useMutation;
|
|
7419
|
+
/** Generated alias around `trpc.addons.installFromWorkspace.useMutation`. */
|
|
7420
|
+
var useAddonsInstallFromWorkspace = trpc.addons.installFromWorkspace.useMutation;
|
|
7421
|
+
/** Generated alias around `trpc.addons.isWorkspaceAvailable.useQuery`. */
|
|
7422
|
+
var useAddonsIsWorkspaceAvailable = trpc.addons.isWorkspaceAvailable.useQuery;
|
|
7423
|
+
/** Generated alias around `trpc.addons.listWorkspacePackages.useQuery`. */
|
|
7424
|
+
var useAddonsListWorkspacePackages = trpc.addons.listWorkspacePackages.useQuery;
|
|
7425
|
+
/** Generated alias around `trpc.addons.uninstallPackage.useMutation`. */
|
|
7426
|
+
var useAddonsUninstallPackage = trpc.addons.uninstallPackage.useMutation;
|
|
7427
|
+
/** Generated alias around `trpc.addons.listInstallations.useQuery`. */
|
|
7428
|
+
var useAddonsListInstallations = trpc.addons.listInstallations.useQuery;
|
|
7429
|
+
/** Generated alias around `trpc.addons.reloadPackages.useMutation`. */
|
|
7430
|
+
var useAddonsReloadPackages = trpc.addons.reloadPackages.useMutation;
|
|
7431
|
+
/** Generated alias around `trpc.addons.searchAvailable.useQuery`. */
|
|
7432
|
+
var useAddonsSearchAvailable = trpc.addons.searchAvailable.useQuery;
|
|
7433
|
+
/** Generated alias around `trpc.addons.listUpdates.useQuery`. */
|
|
7434
|
+
var useAddonsListUpdates = trpc.addons.listUpdates.useQuery;
|
|
7435
|
+
/** Generated alias around `trpc.addons.updatePackage.useMutation`. */
|
|
7436
|
+
var useAddonsUpdatePackage = trpc.addons.updatePackage.useMutation;
|
|
7437
|
+
/** Generated alias around `trpc.addons.rollbackPackage.useMutation`. */
|
|
7438
|
+
var useAddonsRollbackPackage = trpc.addons.rollbackPackage.useMutation;
|
|
7439
|
+
/** Generated alias around `trpc.addons.forceRefresh.useMutation`. */
|
|
7440
|
+
var useAddonsForceRefresh = trpc.addons.forceRefresh.useMutation;
|
|
7441
|
+
/** Generated alias around `trpc.addons.restartServer.useMutation`. */
|
|
7442
|
+
var useAddonsRestartServer = trpc.addons.restartServer.useMutation;
|
|
7443
|
+
/** Generated alias around `trpc.addons.getLastRestart.useQuery`. */
|
|
7444
|
+
var useAddonsGetLastRestart = trpc.addons.getLastRestart.useQuery;
|
|
7445
|
+
/** Generated alias around `trpc.addons.listFrameworkPackages.useQuery`. */
|
|
7446
|
+
var useAddonsListFrameworkPackages = trpc.addons.listFrameworkPackages.useQuery;
|
|
7447
|
+
/** Generated alias around `trpc.addons.listCapabilityProviders.useQuery`. */
|
|
7448
|
+
var useAddonsListCapabilityProviders = trpc.addons.listCapabilityProviders.useQuery;
|
|
7449
|
+
/** Generated alias around `trpc.addons.setCapabilityProviderEnabled.useMutation`. */
|
|
7450
|
+
var useAddonsSetCapabilityProviderEnabled = trpc.addons.setCapabilityProviderEnabled.useMutation;
|
|
7451
|
+
/** Generated alias around `trpc.addons.getVersions.useQuery`. */
|
|
7452
|
+
var useAddonsGetVersions = trpc.addons.getVersions.useQuery;
|
|
7453
|
+
/** Generated alias around `trpc.addons.restartAddon.useMutation`. */
|
|
7454
|
+
var useAddonsRestartAddon = trpc.addons.restartAddon.useMutation;
|
|
7455
|
+
/** Generated alias around `trpc.addons.retryLoad.useMutation`. */
|
|
7456
|
+
var useAddonsRetryLoad = trpc.addons.retryLoad.useMutation;
|
|
7457
|
+
/** Generated alias around `trpc.addons.getAutoUpdateSettings.useQuery`. */
|
|
7458
|
+
var useAddonsGetAutoUpdateSettings = trpc.addons.getAutoUpdateSettings.useQuery;
|
|
7459
|
+
/** Generated alias around `trpc.addons.setAutoUpdateSettings.useMutation`. */
|
|
7460
|
+
var useAddonsSetAutoUpdateSettings = trpc.addons.setAutoUpdateSettings.useMutation;
|
|
7461
|
+
/** Generated alias around `trpc.addons.getAddonAutoUpdate.useQuery`. */
|
|
7462
|
+
var useAddonsGetAddonAutoUpdate = trpc.addons.getAddonAutoUpdate.useQuery;
|
|
7463
|
+
/** Generated alias around `trpc.addons.setAddonAutoUpdate.useMutation`. */
|
|
7464
|
+
var useAddonsSetAddonAutoUpdate = trpc.addons.setAddonAutoUpdate.useMutation;
|
|
7465
|
+
/** Generated alias around `trpc.addons.applyAutoUpdateToAll.useMutation`. */
|
|
7466
|
+
var useAddonsApplyAutoUpdateToAll = trpc.addons.applyAutoUpdateToAll.useMutation;
|
|
7467
|
+
/** Generated alias around `trpc.addons.custom.useMutation`. */
|
|
7468
|
+
var useAddonsCustom = trpc.addons.custom.useMutation;
|
|
7469
|
+
/** Generated alias around `trpc.addons.startJob.useMutation`. */
|
|
7470
|
+
var useAddonsStartJob = trpc.addons.startJob.useMutation;
|
|
7471
|
+
/** Generated alias around `trpc.addons.getJob.useQuery`. */
|
|
7472
|
+
var useAddonsGetJob = trpc.addons.getJob.useQuery;
|
|
7473
|
+
/** Generated alias around `trpc.addons.listJobs.useQuery`. */
|
|
7474
|
+
var useAddonsListJobs = trpc.addons.listJobs.useQuery;
|
|
7475
|
+
/** Generated alias around `trpc.addons.cancelJob.useMutation`. */
|
|
7476
|
+
var useAddonsCancelJob = trpc.addons.cancelJob.useMutation;
|
|
7477
|
+
/** Generated alias around `trpc.addons.onAddonLogs.useSubscription`. */
|
|
7478
|
+
var useAddonsOnAddonLogs = trpc.addons.onAddonLogs.useSubscription;
|
|
7479
|
+
/** Generated alias around `trpc.addonSettings.getGlobalSettings.useQuery`. */
|
|
7480
|
+
var useAddonSettingsGetGlobalSettings = trpc.addonSettings.getGlobalSettings.useQuery;
|
|
7481
|
+
/** Generated alias around `trpc.addonSettings.updateGlobalSettings.useMutation`. */
|
|
7482
|
+
var useAddonSettingsUpdateGlobalSettings = trpc.addonSettings.updateGlobalSettings.useMutation;
|
|
7483
|
+
/** Generated alias around `trpc.addonSettings.getIntegrationSettings.useQuery`. */
|
|
7484
|
+
var useAddonSettingsGetIntegrationSettings = trpc.addonSettings.getIntegrationSettings.useQuery;
|
|
7485
|
+
/** Generated alias around `trpc.addonSettings.getDeviceSettings.useQuery`. */
|
|
7486
|
+
var useAddonSettingsGetDeviceSettings = trpc.addonSettings.getDeviceSettings.useQuery;
|
|
7487
|
+
/** Generated alias around `trpc.addonSettings.updateDeviceSettings.useMutation`. */
|
|
7488
|
+
var useAddonSettingsUpdateDeviceSettings = trpc.addonSettings.updateDeviceSettings.useMutation;
|
|
7489
|
+
/** Generated alias around `trpc.addonWidgets.listWidgets.useQuery`. */
|
|
7490
|
+
var useAddonWidgetsListWidgets = trpc.addonWidgets.listWidgets.useQuery;
|
|
7491
|
+
/** Generated alias around `trpc.airQualitySensor.getStatus.useQuery`. */
|
|
7492
|
+
var useAirQualitySensorGetStatus = trpc.airQualitySensor.getStatus.useQuery;
|
|
7493
|
+
/** Generated alias around `trpc.alarmPanel.arm.useMutation`. */
|
|
7494
|
+
var useAlarmPanelArm = trpc.alarmPanel.arm.useMutation;
|
|
7495
|
+
/** Generated alias around `trpc.alarmPanel.disarm.useMutation`. */
|
|
7496
|
+
var useAlarmPanelDisarm = trpc.alarmPanel.disarm.useMutation;
|
|
7497
|
+
/** Generated alias around `trpc.alarmPanel.trigger.useMutation`. */
|
|
7498
|
+
var useAlarmPanelTrigger = trpc.alarmPanel.trigger.useMutation;
|
|
7499
|
+
/** Generated alias around `trpc.alarmPanel.getStatus.useQuery`. */
|
|
7500
|
+
var useAlarmPanelGetStatus = trpc.alarmPanel.getStatus.useQuery;
|
|
7501
|
+
/** Generated alias around `trpc.alerts.emit.useMutation`. */
|
|
7502
|
+
var useAlertsEmit = trpc.alerts.emit.useMutation;
|
|
7503
|
+
/** Generated alias around `trpc.alerts.update.useMutation`. */
|
|
7504
|
+
var useAlertsUpdate = trpc.alerts.update.useMutation;
|
|
7505
|
+
/** Generated alias around `trpc.alerts.list.useQuery`. */
|
|
7506
|
+
var useAlertsList = trpc.alerts.list.useQuery;
|
|
7507
|
+
/** Generated alias around `trpc.alerts.getUnreadCount.useQuery`. */
|
|
7508
|
+
var useAlertsGetUnreadCount = trpc.alerts.getUnreadCount.useQuery;
|
|
7509
|
+
/** Generated alias around `trpc.alerts.markRead.useMutation`. */
|
|
7510
|
+
var useAlertsMarkRead = trpc.alerts.markRead.useMutation;
|
|
7511
|
+
/** Generated alias around `trpc.alerts.markAllRead.useMutation`. */
|
|
7512
|
+
var useAlertsMarkAllRead = trpc.alerts.markAllRead.useMutation;
|
|
7513
|
+
/** Generated alias around `trpc.alerts.dismiss.useMutation`. */
|
|
7514
|
+
var useAlertsDismiss = trpc.alerts.dismiss.useMutation;
|
|
7515
|
+
/** Generated alias around `trpc.ambientLightSensor.getStatus.useQuery`. */
|
|
7516
|
+
var useAmbientLightSensorGetStatus = trpc.ambientLightSensor.getStatus.useQuery;
|
|
7517
|
+
/** Generated alias around `trpc.audioAnalysis.resolveDeviceSettings.useQuery`. */
|
|
7518
|
+
var useAudioAnalysisResolveDeviceSettings = trpc.audioAnalysis.resolveDeviceSettings.useQuery;
|
|
7519
|
+
/** Generated alias around `trpc.audioAnalysis.getDeviceSettingsContribution.useQuery`. */
|
|
7520
|
+
var useAudioAnalysisGetDeviceSettingsContribution = trpc.audioAnalysis.getDeviceSettingsContribution.useQuery;
|
|
7521
|
+
/** Generated alias around `trpc.audioAnalysis.getDeviceLiveContribution.useQuery`. */
|
|
6579
7522
|
var useAudioAnalysisGetDeviceLiveContribution = trpc.audioAnalysis.getDeviceLiveContribution.useQuery;
|
|
6580
7523
|
/** Generated alias around `trpc.audioAnalysis.applyDeviceSettingsPatch.useMutation`. */
|
|
6581
7524
|
var useAudioAnalysisApplyDeviceSettingsPatch = trpc.audioAnalysis.applyDeviceSettingsPatch.useMutation;
|
|
@@ -7243,6 +8186,24 @@ var useIntercomPushTalkAudio = trpc.intercom.pushTalkAudio.useMutation;
|
|
|
7243
8186
|
var useIntercomEndTalkSession = trpc.intercom.endTalkSession.useMutation;
|
|
7244
8187
|
/** Generated alias around `trpc.intercom.getStatus.useQuery`. */
|
|
7245
8188
|
var useIntercomGetStatus = trpc.intercom.getStatus.useQuery;
|
|
8189
|
+
/** Generated alias around `trpc.keychainAdmin.status.useQuery`. */
|
|
8190
|
+
var useKeychainAdminStatus = trpc.keychainAdmin.status.useQuery;
|
|
8191
|
+
/** Generated alias around `trpc.keychainAdmin.listSecrets.useQuery`. */
|
|
8192
|
+
var useKeychainAdminListSecrets = trpc.keychainAdmin.listSecrets.useQuery;
|
|
8193
|
+
/** Generated alias around `trpc.keychainAdmin.listAudit.useQuery`. */
|
|
8194
|
+
var useKeychainAdminListAudit = trpc.keychainAdmin.listAudit.useQuery;
|
|
8195
|
+
/** Generated alias around `trpc.keychainAdmin.reveal.useMutation`. */
|
|
8196
|
+
var useKeychainAdminReveal = trpc.keychainAdmin.reveal.useMutation;
|
|
8197
|
+
/** Generated alias around `trpc.keychainAdmin.deleteOrphans.useMutation`. */
|
|
8198
|
+
var useKeychainAdminDeleteOrphans = trpc.keychainAdmin.deleteOrphans.useMutation;
|
|
8199
|
+
/** Generated alias around `trpc.keychainAdmin.rotateMasterKey.useMutation`. */
|
|
8200
|
+
var useKeychainAdminRotateMasterKey = trpc.keychainAdmin.rotateMasterKey.useMutation;
|
|
8201
|
+
/** Generated alias around `trpc.keychainAdmin.purgeRetiredKeys.useMutation`. */
|
|
8202
|
+
var useKeychainAdminPurgeRetiredKeys = trpc.keychainAdmin.purgeRetiredKeys.useMutation;
|
|
8203
|
+
/** Generated alias around `trpc.keychainAdmin.downloadRecoveryKey.useMutation`. */
|
|
8204
|
+
var useKeychainAdminDownloadRecoveryKey = trpc.keychainAdmin.downloadRecoveryKey.useMutation;
|
|
8205
|
+
/** Generated alias around `trpc.keychainAdmin.resetKeychain.useMutation`. */
|
|
8206
|
+
var useKeychainAdminResetKeychain = trpc.keychainAdmin.resetKeychain.useMutation;
|
|
7246
8207
|
/** Generated alias around `trpc.lawnMowerControl.startMowing.useMutation`. */
|
|
7247
8208
|
var useLawnMowerControlStartMowing = trpc.lawnMowerControl.startMowing.useMutation;
|
|
7248
8209
|
/** Generated alias around `trpc.lawnMowerControl.pause.useMutation`. */
|
|
@@ -7779,6 +8740,30 @@ var usePipelineAnalyticsCompleteRetrainTrack = trpc.pipelineAnalytics.completeRe
|
|
|
7779
8740
|
var usePipelineAnalyticsRestageRetrainTrack = trpc.pipelineAnalytics.restageRetrainTrack.useMutation;
|
|
7780
8741
|
/** Generated alias around `trpc.pipelineAnalytics.getRetrainExportUrl.useQuery`. */
|
|
7781
8742
|
var usePipelineAnalyticsGetRetrainExportUrl = trpc.pipelineAnalytics.getRetrainExportUrl.useQuery;
|
|
8743
|
+
/** Generated alias around `trpc.pipelineAnalytics.setRetrainFrameComplete.useMutation`. */
|
|
8744
|
+
var usePipelineAnalyticsSetRetrainFrameComplete = trpc.pipelineAnalytics.setRetrainFrameComplete.useMutation;
|
|
8745
|
+
/** Generated alias around `trpc.pipelineAnalytics.writeRetrainArchive.useMutation`. */
|
|
8746
|
+
var usePipelineAnalyticsWriteRetrainArchive = trpc.pipelineAnalytics.writeRetrainArchive.useMutation;
|
|
8747
|
+
/** Generated alias around `trpc.pipelineAnalytics.listRetrainAssistProfiles.useQuery`. */
|
|
8748
|
+
var usePipelineAnalyticsListRetrainAssistProfiles = trpc.pipelineAnalytics.listRetrainAssistProfiles.useQuery;
|
|
8749
|
+
/** Generated alias around `trpc.pipelineAnalytics.proposeRetrainAnnotationsWithLlm.useMutation`. */
|
|
8750
|
+
var usePipelineAnalyticsProposeRetrainAnnotationsWithLlm = trpc.pipelineAnalytics.proposeRetrainAnnotationsWithLlm.useMutation;
|
|
8751
|
+
/** Generated alias around `trpc.pipelineAnalytics.createRetrainCollection.useMutation`. */
|
|
8752
|
+
var usePipelineAnalyticsCreateRetrainCollection = trpc.pipelineAnalytics.createRetrainCollection.useMutation;
|
|
8753
|
+
/** Generated alias around `trpc.pipelineAnalytics.listRetrainCollections.useQuery`. */
|
|
8754
|
+
var usePipelineAnalyticsListRetrainCollections = trpc.pipelineAnalytics.listRetrainCollections.useQuery;
|
|
8755
|
+
/** Generated alias around `trpc.pipelineAnalytics.renameRetrainCollection.useMutation`. */
|
|
8756
|
+
var usePipelineAnalyticsRenameRetrainCollection = trpc.pipelineAnalytics.renameRetrainCollection.useMutation;
|
|
8757
|
+
/** Generated alias around `trpc.pipelineAnalytics.deleteRetrainCollection.useMutation`. */
|
|
8758
|
+
var usePipelineAnalyticsDeleteRetrainCollection = trpc.pipelineAnalytics.deleteRetrainCollection.useMutation;
|
|
8759
|
+
/** Generated alias around `trpc.pipelineAnalytics.addRetrainFrameFromRecording.useMutation`. */
|
|
8760
|
+
var usePipelineAnalyticsAddRetrainFrameFromRecording = trpc.pipelineAnalytics.addRetrainFrameFromRecording.useMutation;
|
|
8761
|
+
/** Generated alias around `trpc.pipelineAnalytics.addRetrainFramesToCollection.useMutation`. */
|
|
8762
|
+
var usePipelineAnalyticsAddRetrainFramesToCollection = trpc.pipelineAnalytics.addRetrainFramesToCollection.useMutation;
|
|
8763
|
+
/** Generated alias around `trpc.pipelineAnalytics.removeRetrainFrameFromCollection.useMutation`. */
|
|
8764
|
+
var usePipelineAnalyticsRemoveRetrainFrameFromCollection = trpc.pipelineAnalytics.removeRetrainFrameFromCollection.useMutation;
|
|
8765
|
+
/** Generated alias around `trpc.pipelineAnalytics.listRetrainCollectionFrames.useQuery`. */
|
|
8766
|
+
var usePipelineAnalyticsListRetrainCollectionFrames = trpc.pipelineAnalytics.listRetrainCollectionFrames.useQuery;
|
|
7782
8767
|
/** Generated alias around `trpc.pipelineAnalytics.getEventMedia.useQuery`. */
|
|
7783
8768
|
var usePipelineAnalyticsGetEventMedia = trpc.pipelineAnalytics.getEventMedia.useQuery;
|
|
7784
8769
|
/** Generated alias around `trpc.pipelineAnalytics.getTrackMedia.useQuery`. */
|
|
@@ -7951,6 +8936,20 @@ var usePipelineOrchestratorSuggestShares = trpc.pipelineOrchestrator.suggestShar
|
|
|
7951
8936
|
var usePipelineOrchestratorGetEffectiveShares = trpc.pipelineOrchestrator.getEffectiveShares.useQuery;
|
|
7952
8937
|
/** Generated alias around `trpc.pipelineOrchestrator.setShareSource.useMutation`. */
|
|
7953
8938
|
var usePipelineOrchestratorSetShareSource = trpc.pipelineOrchestrator.setShareSource.useMutation;
|
|
8939
|
+
/** Generated alias around `trpc.pipelineOrchestrator.getNodeBenchmarkPreflight.useQuery`. */
|
|
8940
|
+
var usePipelineOrchestratorGetNodeBenchmarkPreflight = trpc.pipelineOrchestrator.getNodeBenchmarkPreflight.useQuery;
|
|
8941
|
+
/** Generated alias around `trpc.pipelineOrchestrator.startNodeBenchmark.useMutation`. */
|
|
8942
|
+
var usePipelineOrchestratorStartNodeBenchmark = trpc.pipelineOrchestrator.startNodeBenchmark.useMutation;
|
|
8943
|
+
/** Generated alias around `trpc.pipelineOrchestrator.getNodeBenchmarkStatus.useQuery`. */
|
|
8944
|
+
var usePipelineOrchestratorGetNodeBenchmarkStatus = trpc.pipelineOrchestrator.getNodeBenchmarkStatus.useQuery;
|
|
8945
|
+
/** Generated alias around `trpc.pipelineOrchestrator.abortNodeBenchmark.useMutation`. */
|
|
8946
|
+
var usePipelineOrchestratorAbortNodeBenchmark = trpc.pipelineOrchestrator.abortNodeBenchmark.useMutation;
|
|
8947
|
+
/** Generated alias around `trpc.pipelineOrchestrator.getNodeBenchmarkCandidates.useQuery`. */
|
|
8948
|
+
var usePipelineOrchestratorGetNodeBenchmarkCandidates = trpc.pipelineOrchestrator.getNodeBenchmarkCandidates.useQuery;
|
|
8949
|
+
/** Generated alias around `trpc.pipelineOrchestrator.listNodeBenchmarkResults.useQuery`. */
|
|
8950
|
+
var usePipelineOrchestratorListNodeBenchmarkResults = trpc.pipelineOrchestrator.listNodeBenchmarkResults.useQuery;
|
|
8951
|
+
/** Generated alias around `trpc.pipelineOrchestrator.deleteNodeBenchmarkResult.useMutation`. */
|
|
8952
|
+
var usePipelineOrchestratorDeleteNodeBenchmarkResult = trpc.pipelineOrchestrator.deleteNodeBenchmarkResult.useMutation;
|
|
7954
8953
|
/** Generated alias around `trpc.pipelineOrchestrator.getCameraSettings.useQuery`. */
|
|
7955
8954
|
var usePipelineOrchestratorGetCameraSettings = trpc.pipelineOrchestrator.getCameraSettings.useQuery;
|
|
7956
8955
|
/** Generated alias around `trpc.pipelineOrchestrator.setCameraStepToggle.useMutation`. */
|
|
@@ -8015,6 +9014,12 @@ var usePipelineRunnerParkTrackFrame = trpc.pipelineRunner.parkTrackFrame.useMuta
|
|
|
8015
9014
|
var usePipelineRunnerGetParkedTrackFrame = trpc.pipelineRunner.getParkedTrackFrame.useQuery;
|
|
8016
9015
|
/** Generated alias around `trpc.pipelineRunner.releaseParkedTrackFrames.useMutation`. */
|
|
8017
9016
|
var usePipelineRunnerReleaseParkedTrackFrames = trpc.pipelineRunner.releaseParkedTrackFrames.useMutation;
|
|
9017
|
+
/** Generated alias around `trpc.pipelineRunner.startNodeBench.useMutation`. */
|
|
9018
|
+
var usePipelineRunnerStartNodeBench = trpc.pipelineRunner.startNodeBench.useMutation;
|
|
9019
|
+
/** Generated alias around `trpc.pipelineRunner.getNodeBenchStatus.useQuery`. */
|
|
9020
|
+
var usePipelineRunnerGetNodeBenchStatus = trpc.pipelineRunner.getNodeBenchStatus.useQuery;
|
|
9021
|
+
/** Generated alias around `trpc.pipelineRunner.abortNodeBench.useMutation`. */
|
|
9022
|
+
var usePipelineRunnerAbortNodeBench = trpc.pipelineRunner.abortNodeBench.useMutation;
|
|
8018
9023
|
/** Generated alias around `trpc.plateGallery.listPlates.useQuery`. */
|
|
8019
9024
|
var usePlateGalleryListPlates = trpc.plateGallery.listPlates.useQuery;
|
|
8020
9025
|
/** Generated alias around `trpc.plateGallery.getPlateByTrack.useQuery`. */
|
|
@@ -8567,6 +9572,14 @@ var useUserManagementOauthExchangeCode = trpc.userManagement.oauthExchangeCode.u
|
|
|
8567
9572
|
var useUserManagementOauthRefresh = trpc.userManagement.oauthRefresh.useMutation;
|
|
8568
9573
|
/** Generated alias around `trpc.userManagement.oauthVerifyAccessToken.useQuery`. */
|
|
8569
9574
|
var useUserManagementOauthVerifyAccessToken = trpc.userManagement.oauthVerifyAccessToken.useQuery;
|
|
9575
|
+
/** Generated alias around `trpc.userManagement.listExternalIdentities.useQuery`. */
|
|
9576
|
+
var useUserManagementListExternalIdentities = trpc.userManagement.listExternalIdentities.useQuery;
|
|
9577
|
+
/** Generated alias around `trpc.userManagement.findUserByExternalIdentity.useQuery`. */
|
|
9578
|
+
var useUserManagementFindUserByExternalIdentity = trpc.userManagement.findUserByExternalIdentity.useQuery;
|
|
9579
|
+
/** Generated alias around `trpc.userManagement.linkExternalIdentity.useMutation`. */
|
|
9580
|
+
var useUserManagementLinkExternalIdentity = trpc.userManagement.linkExternalIdentity.useMutation;
|
|
9581
|
+
/** Generated alias around `trpc.userManagement.unlinkExternalIdentity.useMutation`. */
|
|
9582
|
+
var useUserManagementUnlinkExternalIdentity = trpc.userManagement.unlinkExternalIdentity.useMutation;
|
|
8570
9583
|
/** Generated alias around `trpc.userManagement.listOauthSessions.useQuery`. */
|
|
8571
9584
|
var useUserManagementListOauthSessions = trpc.userManagement.listOauthSessions.useQuery;
|
|
8572
9585
|
/** Generated alias around `trpc.userManagement.revokeOauthSession.useMutation`. */
|
|
@@ -20852,7 +21865,7 @@ function formatDurationMs(ms) {
|
|
|
20852
21865
|
* firmware inventing a refusal reaches the operator rather than becoming a
|
|
20853
21866
|
* blank tile.
|
|
20854
21867
|
*/
|
|
20855
|
-
var REFUSAL_TEXT = {
|
|
21868
|
+
var REFUSAL_TEXT$1 = {
|
|
20856
21869
|
sleeping: () => "The camera is asleep — a still would cost a wake",
|
|
20857
21870
|
"camera-refused": (reason) => `The camera refused — ${reason}`,
|
|
20858
21871
|
"no-keyframe": () => "No decodable frame inside this window",
|
|
@@ -20864,7 +21877,7 @@ var REFUSAL_TEXT = {
|
|
|
20864
21877
|
"uid-missing": () => "The camera’s id is not known yet"
|
|
20865
21878
|
};
|
|
20866
21879
|
function wordsFor(code, reason) {
|
|
20867
|
-
const known = code === void 0 ? void 0 : REFUSAL_TEXT[code];
|
|
21880
|
+
const known = code === void 0 ? void 0 : REFUSAL_TEXT$1[code];
|
|
20868
21881
|
return known === void 0 ? reason : known(reason);
|
|
20869
21882
|
}
|
|
20870
21883
|
function refusal(reason, code) {
|
|
@@ -24447,6 +25460,426 @@ function useScrubController(sink, isPlayerLive = () => false) {
|
|
|
24447
25460
|
};
|
|
24448
25461
|
}
|
|
24449
25462
|
//#endregion
|
|
25463
|
+
//#region src/primitives/dialog.tsx
|
|
25464
|
+
var DialogContext = createContext(null);
|
|
25465
|
+
function useDialogContext() {
|
|
25466
|
+
const ctx = useContext(DialogContext);
|
|
25467
|
+
if (!ctx) throw new Error("Dialog compound components must be used within <Dialog>");
|
|
25468
|
+
return ctx;
|
|
25469
|
+
}
|
|
25470
|
+
function Dialog({ children, open: controlledOpen, onOpenChange }) {
|
|
25471
|
+
const [uncontrolledOpen, setUncontrolledOpen] = useState(false);
|
|
25472
|
+
const open = controlledOpen ?? uncontrolledOpen;
|
|
25473
|
+
const contentId = useId();
|
|
25474
|
+
const setOpen = useCallback((next) => {
|
|
25475
|
+
onOpenChange?.(next);
|
|
25476
|
+
if (controlledOpen === void 0) setUncontrolledOpen(next);
|
|
25477
|
+
}, [controlledOpen, onOpenChange]);
|
|
25478
|
+
return /* @__PURE__ */ jsx(DialogContext.Provider, {
|
|
25479
|
+
value: {
|
|
25480
|
+
open,
|
|
25481
|
+
setOpen,
|
|
25482
|
+
contentId
|
|
25483
|
+
},
|
|
25484
|
+
children
|
|
25485
|
+
});
|
|
25486
|
+
}
|
|
25487
|
+
function DialogTrigger({ children, ...props }) {
|
|
25488
|
+
const { setOpen } = useDialogContext();
|
|
25489
|
+
return /* @__PURE__ */ jsx("button", {
|
|
25490
|
+
type: "button",
|
|
25491
|
+
onClick: () => setOpen(true),
|
|
25492
|
+
...props,
|
|
25493
|
+
children
|
|
25494
|
+
});
|
|
25495
|
+
}
|
|
25496
|
+
/**
|
|
25497
|
+
* A native <dialog> opened with showModal() is promoted to the top layer, so
|
|
25498
|
+
* ancestor transform/overflow can't clip it — but it relies on the UA
|
|
25499
|
+
* stylesheet's `dialog { margin: auto }` for modal centering. Tailwind's
|
|
25500
|
+
* preflight resets `margin: 0` on every element, which defeats that centering
|
|
25501
|
+
* and pins the modal to the top-left. We therefore center deterministically:
|
|
25502
|
+
* a top-layer dialog with `position: fixed` is viewport-relative, and a
|
|
25503
|
+
* self-transform is fine, so `fixed left-1/2 top-1/2 -translate-x-1/2
|
|
25504
|
+
* -translate-y-1/2 m-0` always centers regardless of any margin reset. Width
|
|
25505
|
+
* is capped to the viewport (`w-[calc(100vw-2rem)]`) rather than a bare
|
|
25506
|
+
* `w-full` (which would overflow/clip a centered dialog); the per-variant
|
|
25507
|
+
* `max-w-*` keeps small dialogs small while the cap prevents overflow.
|
|
25508
|
+
*
|
|
25509
|
+
* Height is capped against the SAFE viewport, not the raw one. A top-layer
|
|
25510
|
+
* `fixed` dialog is viewport-relative, and under `viewport-fit=cover` the
|
|
25511
|
+
* viewport extends behind the iOS notch/Dynamic Island and home indicator —
|
|
25512
|
+
* so a dialog tall enough to hit its `max-h` put its header under the clock.
|
|
25513
|
+
* Because the box is centred on the viewport (not on the safe area), the cap
|
|
25514
|
+
* has to subtract TWICE the LARGER of the two insets for the box to clear
|
|
25515
|
+
* both edges; using each inset once would still overflow the taller side
|
|
25516
|
+
* whenever they are asymmetric (they are: ~59px top vs ~34px bottom). Every
|
|
25517
|
+
* term collapses to the previous `100dvh - 2rem` where the insets are 0.
|
|
25518
|
+
*/
|
|
25519
|
+
var contentVariants = cva("fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 m-0 w-[calc(100vw-2rem)] bg-background-elevated text-foreground border border-border rounded-lg p-4 backdrop:bg-black/50 backdrop:backdrop-blur-sm max-h-[calc(100dvh-2rem-2*max(env(safe-area-inset-top),env(safe-area-inset-bottom)))] [&:not([open])]:hidden", {
|
|
25520
|
+
variants: {
|
|
25521
|
+
width: {
|
|
25522
|
+
sm: "max-w-sm",
|
|
25523
|
+
md: "max-w-md",
|
|
25524
|
+
lg: "max-w-lg"
|
|
25525
|
+
},
|
|
25526
|
+
/**
|
|
25527
|
+
* WHICH box scrolls when the content is taller than the height cap.
|
|
25528
|
+
*
|
|
25529
|
+
* `content` (default) scrolls the whole dialog: the title, any tab strip
|
|
25530
|
+
* and the Save/Cancel row travel with the fields. That is fine for a
|
|
25531
|
+
* short form and wrong for a long one — the operator scrolls to the
|
|
25532
|
+
* bottom of a rule editor and the buttons are somewhere above him, the
|
|
25533
|
+
* tab strip is gone, and the only way back to either is to scroll the
|
|
25534
|
+
* form he was reading.
|
|
25535
|
+
*
|
|
25536
|
+
* `body` makes the dialog a flex column that does not scroll at all and
|
|
25537
|
+
* hands the scrolling to `<DialogBody>`. The chrome around the body —
|
|
25538
|
+
* header, tab strip, footer — stays put at every height. The dialog
|
|
25539
|
+
* keeps its own padding either way, so `sheet-on-mobile`'s
|
|
25540
|
+
* safe-area bottom padding still applies to the footer.
|
|
25541
|
+
*
|
|
25542
|
+
* `body` also takes a DEFINITE height below `md` — see the
|
|
25543
|
+
* `scroll: 'body'` compound variants. That is not a style choice; the
|
|
25544
|
+
* flex chain does not resolve without it on iOS Safari.
|
|
25545
|
+
*/
|
|
25546
|
+
scroll: {
|
|
25547
|
+
content: "overflow-y-auto",
|
|
25548
|
+
body: "flex flex-col overflow-hidden"
|
|
25549
|
+
},
|
|
25550
|
+
placement: {
|
|
25551
|
+
center: "",
|
|
25552
|
+
"sheet-on-mobile": "bottom-0 left-0 right-0 top-auto w-full max-w-full translate-x-0 translate-y-0 rounded-b-none max-h-[92dvh] pb-[calc(1rem+env(safe-area-inset-bottom))] md:left-1/2 md:top-1/2 md:-translate-x-1/2 md:-translate-y-1/2 md:rounded-lg md:bottom-auto md:pb-4 md:max-h-[calc(100dvh-2rem-2*max(env(safe-area-inset-top),env(safe-area-inset-bottom)))]"
|
|
25553
|
+
}
|
|
25554
|
+
},
|
|
25555
|
+
compoundVariants: [
|
|
25556
|
+
{
|
|
25557
|
+
placement: "sheet-on-mobile",
|
|
25558
|
+
width: "sm",
|
|
25559
|
+
class: "md:w-[calc(100vw-2rem)] md:max-w-sm"
|
|
25560
|
+
},
|
|
25561
|
+
{
|
|
25562
|
+
placement: "sheet-on-mobile",
|
|
25563
|
+
width: "md",
|
|
25564
|
+
class: "md:w-[calc(100vw-2rem)] md:max-w-md"
|
|
25565
|
+
},
|
|
25566
|
+
{
|
|
25567
|
+
placement: "sheet-on-mobile",
|
|
25568
|
+
width: "lg",
|
|
25569
|
+
class: "md:w-[calc(100vw-2rem)] md:max-w-lg"
|
|
25570
|
+
},
|
|
25571
|
+
{
|
|
25572
|
+
scroll: "body",
|
|
25573
|
+
placement: "sheet-on-mobile",
|
|
25574
|
+
class: "h-[92dvh] md:h-auto"
|
|
25575
|
+
},
|
|
25576
|
+
{
|
|
25577
|
+
scroll: "body",
|
|
25578
|
+
placement: "center",
|
|
25579
|
+
class: "h-[calc(100dvh-2rem-2*max(env(safe-area-inset-top),env(safe-area-inset-bottom)))] md:h-auto"
|
|
25580
|
+
}
|
|
25581
|
+
],
|
|
25582
|
+
defaultVariants: {
|
|
25583
|
+
width: "md",
|
|
25584
|
+
placement: "center",
|
|
25585
|
+
scroll: "content"
|
|
25586
|
+
}
|
|
25587
|
+
});
|
|
25588
|
+
var DialogContent = forwardRef(({ className, width, placement, scroll, children, ...props }, ref) => {
|
|
25589
|
+
const { open, setOpen, contentId } = useDialogContext();
|
|
25590
|
+
const innerRef = useRef(null);
|
|
25591
|
+
const dialogRef = ref ?? innerRef;
|
|
25592
|
+
useEffect(() => {
|
|
25593
|
+
const el = dialogRef.current;
|
|
25594
|
+
if (!el) return;
|
|
25595
|
+
if (open && !el.open) el.showModal();
|
|
25596
|
+
if (!open && el.open) el.close();
|
|
25597
|
+
}, [open, dialogRef]);
|
|
25598
|
+
return /* @__PURE__ */ jsx("dialog", {
|
|
25599
|
+
ref: dialogRef,
|
|
25600
|
+
id: contentId,
|
|
25601
|
+
className: cn(contentVariants({
|
|
25602
|
+
width,
|
|
25603
|
+
placement,
|
|
25604
|
+
scroll
|
|
25605
|
+
}), className),
|
|
25606
|
+
onClose: () => setOpen(false),
|
|
25607
|
+
...props,
|
|
25608
|
+
children
|
|
25609
|
+
});
|
|
25610
|
+
});
|
|
25611
|
+
DialogContent.displayName = "DialogContent";
|
|
25612
|
+
/** `shrink-0` is inert outside a flex column and load-bearing inside one:
|
|
25613
|
+
* under `scroll="body"` the header must keep its height while the body gives
|
|
25614
|
+
* ground, or a long form squeezes its own title to nothing. */
|
|
25615
|
+
function DialogHeader({ className, ...props }) {
|
|
25616
|
+
return /* @__PURE__ */ jsx("div", {
|
|
25617
|
+
className: cn("flex flex-col gap-1 mb-3 shrink-0", className),
|
|
25618
|
+
...props
|
|
25619
|
+
});
|
|
25620
|
+
}
|
|
25621
|
+
/**
|
|
25622
|
+
* The scrolling middle of a `scroll="body"` dialog.
|
|
25623
|
+
*
|
|
25624
|
+
* `min-h-0` is what makes it work: a flex item's default `min-height: auto`
|
|
25625
|
+
* refuses to shrink below its content, so without it the body pushes the
|
|
25626
|
+
* footer out of the dialog instead of scrolling — the exact failure this
|
|
25627
|
+
* variant exists to remove. Anything sticky INSIDE a dialog body pins against
|
|
25628
|
+
* this element, since it is the scroll container.
|
|
25629
|
+
*
|
|
25630
|
+
* It only bounds a scroll area if every ancestor up to the dialog has a
|
|
25631
|
+
* resolved height. `DialogContent` supplies the top of that chain (see the
|
|
25632
|
+
* `scroll: 'body'` compound variants); an intermediate wrapper between them —
|
|
25633
|
+
* a `<Tabs>` that owns the tab strip, say — must carry `flex-1 min-h-0` too,
|
|
25634
|
+
* or it collapses and takes the body with it.
|
|
25635
|
+
*/
|
|
25636
|
+
function DialogBody({ className, ...props }) {
|
|
25637
|
+
return /* @__PURE__ */ jsx("div", {
|
|
25638
|
+
className: cn("flex-1 min-h-0 overflow-y-auto", className),
|
|
25639
|
+
...props
|
|
25640
|
+
});
|
|
25641
|
+
}
|
|
25642
|
+
function DialogFooter({ className, ...props }) {
|
|
25643
|
+
return /* @__PURE__ */ jsx("div", {
|
|
25644
|
+
className: cn("flex justify-end gap-2 mt-4 shrink-0", className),
|
|
25645
|
+
...props
|
|
25646
|
+
});
|
|
25647
|
+
}
|
|
25648
|
+
function DialogTitle({ className, ...props }) {
|
|
25649
|
+
return /* @__PURE__ */ jsx("h2", {
|
|
25650
|
+
className: cn("text-sm font-semibold text-foreground", className),
|
|
25651
|
+
...props
|
|
25652
|
+
});
|
|
25653
|
+
}
|
|
25654
|
+
function DialogDescription({ className, ...props }) {
|
|
25655
|
+
return /* @__PURE__ */ jsx("p", {
|
|
25656
|
+
className: cn("text-xs text-foreground-muted", className),
|
|
25657
|
+
...props
|
|
25658
|
+
});
|
|
25659
|
+
}
|
|
25660
|
+
//#endregion
|
|
25661
|
+
//#region src/primitives/input.tsx
|
|
25662
|
+
/**
|
|
25663
|
+
* `disabled:opacity-50 disabled:cursor-not-allowed` for the same reason as
|
|
25664
|
+
* `Select` — an explicit `bg-surface` / `text-foreground` overrides the greying
|
|
25665
|
+
* a browser would otherwise apply, leaving an inert field indistinguishable
|
|
25666
|
+
* from a live one. See `disabled-affordance.test.tsx`.
|
|
25667
|
+
*/
|
|
25668
|
+
var inputVariants = cva("h-7 w-full px-2.5 text-xs bg-surface border rounded-md text-foreground placeholder:text-foreground-subtle focus:outline-none focus:ring-1 focus:ring-primary transition-colors disabled:opacity-50 disabled:cursor-not-allowed", {
|
|
25669
|
+
variants: { state: {
|
|
25670
|
+
default: "border-border",
|
|
25671
|
+
error: "border-danger"
|
|
25672
|
+
} },
|
|
25673
|
+
defaultVariants: { state: "default" }
|
|
25674
|
+
});
|
|
25675
|
+
var Input = forwardRef(({ className, state, leftSlot, rightSlot, ...props }, ref) => {
|
|
25676
|
+
if (leftSlot || rightSlot) return /* @__PURE__ */ jsxs("div", {
|
|
25677
|
+
className: "relative flex items-center w-full",
|
|
25678
|
+
children: [
|
|
25679
|
+
leftSlot && /* @__PURE__ */ jsx("div", {
|
|
25680
|
+
className: "absolute left-2.5 flex items-center pointer-events-none",
|
|
25681
|
+
children: leftSlot
|
|
25682
|
+
}),
|
|
25683
|
+
/* @__PURE__ */ jsx("input", {
|
|
25684
|
+
ref,
|
|
25685
|
+
className: cn(inputVariants({ state }), leftSlot ? "pl-7" : "", rightSlot ? "pr-7" : "", className),
|
|
25686
|
+
...props
|
|
25687
|
+
}),
|
|
25688
|
+
rightSlot && /* @__PURE__ */ jsx("div", {
|
|
25689
|
+
className: "absolute right-2.5 flex items-center pointer-events-none",
|
|
25690
|
+
children: rightSlot
|
|
25691
|
+
})
|
|
25692
|
+
]
|
|
25693
|
+
});
|
|
25694
|
+
return /* @__PURE__ */ jsx("input", {
|
|
25695
|
+
ref,
|
|
25696
|
+
className: cn(inputVariants({ state }), className),
|
|
25697
|
+
...props
|
|
25698
|
+
});
|
|
25699
|
+
});
|
|
25700
|
+
Input.displayName = "Input";
|
|
25701
|
+
//#endregion
|
|
25702
|
+
//#region src/composites/training/training-collection-picker.tsx
|
|
25703
|
+
/**
|
|
25704
|
+
* <TrainingCollectionPicker> — choose a named training collection, or create
|
|
25705
|
+
* one in place.
|
|
25706
|
+
*
|
|
25707
|
+
* A collection is a named set over the retrain corpus ("packages porch
|
|
25708
|
+
* night"). The picker lists them (newest first, with their frame counts) and
|
|
25709
|
+
* offers a name field for a new one; the hub refuses an empty or duplicate
|
|
25710
|
+
* name, and the refusal is shown here rather than swallowed.
|
|
25711
|
+
*/
|
|
25712
|
+
var CREATE_REFUSAL = {
|
|
25713
|
+
"empty-name": "Give the collection a name.",
|
|
25714
|
+
"duplicate-name": "A collection with that name already exists."
|
|
25715
|
+
};
|
|
25716
|
+
function TrainingCollectionPicker({ value, onChange }) {
|
|
25717
|
+
const collections = usePipelineAnalyticsListRetrainCollections({});
|
|
25718
|
+
const create = usePipelineAnalyticsCreateRetrainCollection();
|
|
25719
|
+
const [name, setName] = useState("");
|
|
25720
|
+
const [error, setError] = useState(null);
|
|
25721
|
+
const list = collections.data ?? [];
|
|
25722
|
+
const onCreate = async () => {
|
|
25723
|
+
setError(null);
|
|
25724
|
+
const result = await create.mutateAsync({ name });
|
|
25725
|
+
if (result.kind === "refused") {
|
|
25726
|
+
setError(CREATE_REFUSAL[result.reason]);
|
|
25727
|
+
return;
|
|
25728
|
+
}
|
|
25729
|
+
setName("");
|
|
25730
|
+
await collections.refetch();
|
|
25731
|
+
onChange(result.collection.id);
|
|
25732
|
+
};
|
|
25733
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
25734
|
+
className: "space-y-2",
|
|
25735
|
+
"data-testid": "training-collection-picker",
|
|
25736
|
+
children: [
|
|
25737
|
+
list.length > 0 ? /* @__PURE__ */ jsx(Select, {
|
|
25738
|
+
"aria-label": "Collection",
|
|
25739
|
+
value: value ?? "",
|
|
25740
|
+
options: [{
|
|
25741
|
+
value: "",
|
|
25742
|
+
label: "Choose a collection…"
|
|
25743
|
+
}, ...list.map((c) => ({
|
|
25744
|
+
value: c.id,
|
|
25745
|
+
label: `${c.name} (${String(c.frameCount)})`
|
|
25746
|
+
}))],
|
|
25747
|
+
onChange: (event) => {
|
|
25748
|
+
if (event.target.value !== "") onChange(event.target.value);
|
|
25749
|
+
}
|
|
25750
|
+
}) : /* @__PURE__ */ jsx("p", {
|
|
25751
|
+
className: "text-xs text-foreground-subtle",
|
|
25752
|
+
children: collections.isLoading ? "Reading the collections…" : "No collection yet — create one."
|
|
25753
|
+
}),
|
|
25754
|
+
/* @__PURE__ */ jsxs("div", {
|
|
25755
|
+
className: "flex items-center gap-2",
|
|
25756
|
+
children: [/* @__PURE__ */ jsx(Input, {
|
|
25757
|
+
className: "flex-1",
|
|
25758
|
+
"aria-label": "New collection name",
|
|
25759
|
+
placeholder: "New collection (e.g. missed at night)",
|
|
25760
|
+
value: name,
|
|
25761
|
+
onChange: (event) => {
|
|
25762
|
+
setName(event.target.value);
|
|
25763
|
+
}
|
|
25764
|
+
}), /* @__PURE__ */ jsxs(Button, {
|
|
25765
|
+
type: "button",
|
|
25766
|
+
variant: "secondary",
|
|
25767
|
+
size: "sm",
|
|
25768
|
+
disabled: create.isPending || name.trim() === "",
|
|
25769
|
+
onClick: () => void onCreate(),
|
|
25770
|
+
children: [/* @__PURE__ */ jsx(Plus, { className: "h-3 w-3" }), "Create"]
|
|
25771
|
+
})]
|
|
25772
|
+
}),
|
|
25773
|
+
error !== null && /* @__PURE__ */ jsx("p", {
|
|
25774
|
+
className: "text-xs text-danger",
|
|
25775
|
+
children: error
|
|
25776
|
+
})
|
|
25777
|
+
]
|
|
25778
|
+
});
|
|
25779
|
+
}
|
|
25780
|
+
//#endregion
|
|
25781
|
+
//#region src/composites/training/training-refusal-text.ts
|
|
25782
|
+
var REFUSAL_TEXT = {
|
|
25783
|
+
"unknown-collection": "That collection no longer exists — pick another one.",
|
|
25784
|
+
"still-unavailable": "No frame could be taken from the recording at that moment.",
|
|
25785
|
+
"still-busy": "The recorder is busy decoding other frames. Try again in a moment.",
|
|
25786
|
+
"unreadable-image": "The recorder returned something that is not a picture.",
|
|
25787
|
+
"write-failed": "The frame could not be stored. Check the artifacts storage."
|
|
25788
|
+
};
|
|
25789
|
+
/** One sentence for a refusal, with the hub's own detail appended. */
|
|
25790
|
+
function trainingRefusalText(reason, detail) {
|
|
25791
|
+
const base = REFUSAL_TEXT[reason];
|
|
25792
|
+
return detail !== void 0 && detail !== "" ? `${base} (${detail})` : base;
|
|
25793
|
+
}
|
|
25794
|
+
//#endregion
|
|
25795
|
+
//#region src/composites/training/send-frame-to-training.tsx
|
|
25796
|
+
/**
|
|
25797
|
+
* <SendFrameToTrainingButton> — "Send frame to training" from a recording
|
|
25798
|
+
* playhead.
|
|
25799
|
+
*
|
|
25800
|
+
* The frame a detector most needs to learn from is often one where it saw
|
|
25801
|
+
* NOTHING — no event, no track, nothing to mark. From the recording, the
|
|
25802
|
+
* operator stops on that moment and sends it: the hub re-decodes the native
|
|
25803
|
+
* frame at the playhead instant and adds it to a named training collection,
|
|
25804
|
+
* where the Retrain page annotates it like any other frame.
|
|
25805
|
+
*
|
|
25806
|
+
* Draws NOTHING for a session that cannot curate training data: the
|
|
25807
|
+
* collection list is admin-only, and a button that 403s is worse than no
|
|
25808
|
+
* button. It is disabled, with the reason, while there is no playhead.
|
|
25809
|
+
*/
|
|
25810
|
+
function SendFrameToTrainingButton({ deviceId, epochMs }) {
|
|
25811
|
+
const collections = usePipelineAnalyticsListRetrainCollections({}, { retry: false });
|
|
25812
|
+
const send = usePipelineAnalyticsAddRetrainFrameFromRecording();
|
|
25813
|
+
const [open, setOpen] = useState(false);
|
|
25814
|
+
const [collectionId, setCollectionId] = useState(null);
|
|
25815
|
+
const [instant, setInstant] = useState(null);
|
|
25816
|
+
const [outcome, setOutcome] = useState(null);
|
|
25817
|
+
if (collections.isError) return null;
|
|
25818
|
+
const onSend = async () => {
|
|
25819
|
+
if (collectionId === null || instant === null) return;
|
|
25820
|
+
const result = await send.mutateAsync({
|
|
25821
|
+
collectionId,
|
|
25822
|
+
deviceId,
|
|
25823
|
+
epochMs: instant
|
|
25824
|
+
});
|
|
25825
|
+
const name = collections.data?.find((c) => c.id === collectionId)?.name ?? "the collection";
|
|
25826
|
+
setOutcome(result.kind === "added" ? {
|
|
25827
|
+
kind: "added",
|
|
25828
|
+
reused: result.reused,
|
|
25829
|
+
collection: name
|
|
25830
|
+
} : {
|
|
25831
|
+
kind: "refused",
|
|
25832
|
+
text: trainingRefusalText(result.reason, result.detail)
|
|
25833
|
+
});
|
|
25834
|
+
if (result.kind === "added") await collections.refetch();
|
|
25835
|
+
};
|
|
25836
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs(Button, {
|
|
25837
|
+
type: "button",
|
|
25838
|
+
variant: "secondary",
|
|
25839
|
+
size: "sm",
|
|
25840
|
+
"data-testid": "send-frame-to-training",
|
|
25841
|
+
disabled: epochMs === null,
|
|
25842
|
+
title: epochMs === null ? "Play back a recording first — the frame at the playhead is the one sent" : "Add the frame at the playhead to a training collection",
|
|
25843
|
+
onClick: () => {
|
|
25844
|
+
setInstant(epochMs);
|
|
25845
|
+
setOutcome(null);
|
|
25846
|
+
setOpen(true);
|
|
25847
|
+
},
|
|
25848
|
+
children: [/* @__PURE__ */ jsx(GraduationCap, { className: "h-3.5 w-3.5" }), "Send frame to training"]
|
|
25849
|
+
}), /* @__PURE__ */ jsx(Dialog, {
|
|
25850
|
+
open,
|
|
25851
|
+
onOpenChange: (next) => !send.isPending && setOpen(next),
|
|
25852
|
+
children: /* @__PURE__ */ jsxs(DialogContent, { children: [
|
|
25853
|
+
/* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsx(DialogTitle, { children: "Send this frame to training" }), /* @__PURE__ */ jsx(DialogDescription, { children: instant !== null ? `The camera's frame at ${new Date(instant).toLocaleString()} is taken from the recording at full resolution and added to the collection. Annotate it on the Retrain page — including what the model missed.` : "" })] }),
|
|
25854
|
+
/* @__PURE__ */ jsx(TrainingCollectionPicker, {
|
|
25855
|
+
value: collectionId,
|
|
25856
|
+
onChange: setCollectionId
|
|
25857
|
+
}),
|
|
25858
|
+
outcome !== null && /* @__PURE__ */ jsx("p", {
|
|
25859
|
+
className: `mt-2 text-xs ${outcome.kind === "added" ? "text-success" : "text-danger"}`,
|
|
25860
|
+
role: "status",
|
|
25861
|
+
children: outcome.kind === "added" ? outcome.reused ? `That moment was already in the dataset; it is now in ${outcome.collection}.` : `Added to ${outcome.collection}.` : outcome.text
|
|
25862
|
+
}),
|
|
25863
|
+
/* @__PURE__ */ jsxs(DialogFooter, { children: [/* @__PURE__ */ jsx(Button, {
|
|
25864
|
+
type: "button",
|
|
25865
|
+
variant: "ghost",
|
|
25866
|
+
size: "sm",
|
|
25867
|
+
disabled: send.isPending,
|
|
25868
|
+
onClick: () => {
|
|
25869
|
+
setOpen(false);
|
|
25870
|
+
},
|
|
25871
|
+
children: outcome?.kind === "added" ? "Done" : "Cancel"
|
|
25872
|
+
}), /* @__PURE__ */ jsxs(Button, {
|
|
25873
|
+
type: "button",
|
|
25874
|
+
size: "sm",
|
|
25875
|
+
disabled: collectionId === null || send.isPending || outcome?.kind === "added",
|
|
25876
|
+
onClick: () => void onSend(),
|
|
25877
|
+
children: [send.isPending && /* @__PURE__ */ jsx(LoaderCircle, { className: "h-3.5 w-3.5 animate-spin" }), "Send"]
|
|
25878
|
+
})] })
|
|
25879
|
+
] })
|
|
25880
|
+
})] });
|
|
25881
|
+
}
|
|
25882
|
+
//#endregion
|
|
24450
25883
|
//#region src/composites/cap-settings/CoverageTrack.tsx
|
|
24451
25884
|
function CoverageTrack({ windowFrom, windowTo, spans, playheadMs, onSeek, onScrubStart, onScrubMove, onScrubEnd }) {
|
|
24452
25885
|
const [hoverInfo, setHoverInfo] = useState(null);
|
|
@@ -25025,6 +26458,13 @@ function RecordingTimeline({ deviceId }) {
|
|
|
25025
26458
|
dayBounds: computedDayBounds,
|
|
25026
26459
|
onViewChange: handleViewChange
|
|
25027
26460
|
}),
|
|
26461
|
+
/* @__PURE__ */ jsx("div", {
|
|
26462
|
+
className: "flex justify-end",
|
|
26463
|
+
children: /* @__PURE__ */ jsx(SendFrameToTrainingButton, {
|
|
26464
|
+
deviceId,
|
|
26465
|
+
epochMs: displayPlayheadMs
|
|
26466
|
+
})
|
|
26467
|
+
}),
|
|
25028
26468
|
recorded.channelOpen ? /* @__PURE__ */ jsxs("div", {
|
|
25029
26469
|
"data-testid": "frame-push-status-row",
|
|
25030
26470
|
className: "flex flex-wrap items-center gap-2 text-[10px]",
|
|
@@ -26622,6 +28062,32 @@ function FieldWrapper({ label, description, required, span, children, translatio
|
|
|
26622
28062
|
]
|
|
26623
28063
|
});
|
|
26624
28064
|
}
|
|
28065
|
+
/**
|
|
28066
|
+
* A keychain-stored secret (D787) arrives as its VIEW — `{ $secret, set }` —
|
|
28067
|
+
* or `null`, never as a value; it renders as "set · Change · Clear · Reveal".
|
|
28068
|
+
* Decided ONCE, at mount, from what the form was hydrated with: once the
|
|
28069
|
+
* operator types, the value is a plain string and the field must stay the
|
|
28070
|
+
* same control. A form that was not hydrated from a keychain-aware store (a
|
|
28071
|
+
* create dialog seeding `''`) keeps the plain input.
|
|
28072
|
+
*/
|
|
28073
|
+
function KeychainOr({ field, value, onChange, disabled, translationFn, multiline, children }) {
|
|
28074
|
+
const [keychain] = useState(() => isKeychainStoredField(field) && isKeychainFieldValue(value));
|
|
28075
|
+
if (!keychain) return /* @__PURE__ */ jsx(Fragment$1, { children });
|
|
28076
|
+
return /* @__PURE__ */ jsx(FieldWrapper, {
|
|
28077
|
+
label: "label" in field ? field.label : void 0,
|
|
28078
|
+
description: "description" in field ? field.description : void 0,
|
|
28079
|
+
required: "required" in field ? field.required : void 0,
|
|
28080
|
+
span: "span" in field ? field.span : void 0,
|
|
28081
|
+
translationFn,
|
|
28082
|
+
children: /* @__PURE__ */ jsx(SecretFieldControl, {
|
|
28083
|
+
field,
|
|
28084
|
+
value,
|
|
28085
|
+
onChange,
|
|
28086
|
+
disabled,
|
|
28087
|
+
multiline
|
|
28088
|
+
})
|
|
28089
|
+
});
|
|
28090
|
+
}
|
|
26625
28091
|
function TextField({ field, value, onChange, disabled, translationFn }) {
|
|
26626
28092
|
return /* @__PURE__ */ jsx(FieldWrapper, {
|
|
26627
28093
|
label: field.label,
|
|
@@ -27142,6 +28608,23 @@ function ColorField({ field, value, onChange, disabled, translationFn }) {
|
|
|
27142
28608
|
})]
|
|
27143
28609
|
});
|
|
27144
28610
|
}
|
|
28611
|
+
function IconField({ field, value, onChange, disabled, translationFn }) {
|
|
28612
|
+
const defaultKey = typeof field.default === "string" ? field.default : "";
|
|
28613
|
+
return /* @__PURE__ */ jsx(FieldWrapper, {
|
|
28614
|
+
label: field.label,
|
|
28615
|
+
description: field.description,
|
|
28616
|
+
required: field.required,
|
|
28617
|
+
span: field.span,
|
|
28618
|
+
translationFn,
|
|
28619
|
+
children: /* @__PURE__ */ jsx(ConfigIconFieldControl, {
|
|
28620
|
+
label: resolveLabel(field.label, translationFn) ?? field.label,
|
|
28621
|
+
value,
|
|
28622
|
+
defaultKey,
|
|
28623
|
+
disabled: disabled || field.disabled,
|
|
28624
|
+
onChange
|
|
28625
|
+
})
|
|
28626
|
+
});
|
|
28627
|
+
}
|
|
27145
28628
|
function ProbeField({ field, value, onChange, disabled, translationFn, onTestField, onAction, externalProbe }) {
|
|
27146
28629
|
const [localStatus, setLocalStatus] = useState("idle");
|
|
27147
28630
|
const [localResult, setLocalResult] = useState(null);
|
|
@@ -27677,7 +29160,7 @@ function resolveActionParams(field, values) {
|
|
|
27677
29160
|
const params = { ...field.paramsStatic };
|
|
27678
29161
|
if (field.paramsFromForm) for (const [paramKey, formKey] of Object.entries(field.paramsFromForm)) {
|
|
27679
29162
|
const v = values[formKey];
|
|
27680
|
-
if (v !== void 0 && v !== null && v !== "") params[paramKey] = v;
|
|
29163
|
+
if (v !== void 0 && v !== null && v !== "" && !isSecretClear(v)) params[paramKey] = v;
|
|
27681
29164
|
}
|
|
27682
29165
|
return params;
|
|
27683
29166
|
}
|
|
@@ -27776,8 +29259,16 @@ function AddonActionButtonField({ field, values, disabled, onAction }) {
|
|
|
27776
29259
|
const [loading, setLoading] = useState(false);
|
|
27777
29260
|
const [status, setStatus] = useState(null);
|
|
27778
29261
|
const confirm = useConfirm();
|
|
29262
|
+
const prompt = usePrompt();
|
|
27779
29263
|
const deviceId = useDeviceId();
|
|
27780
29264
|
const handleClick = async () => {
|
|
29265
|
+
const asked = field.prompt ? await prompt({
|
|
29266
|
+
title: field.prompt.title ?? field.label,
|
|
29267
|
+
...field.prompt.message !== void 0 ? { message: field.prompt.message } : {},
|
|
29268
|
+
...field.prompt.placeholder !== void 0 ? { placeholder: field.prompt.placeholder } : {},
|
|
29269
|
+
confirmLabel: field.buttonLabel
|
|
29270
|
+
}) : null;
|
|
29271
|
+
if (field.prompt && asked === null) return;
|
|
27781
29272
|
if (field.confirmMessage) {
|
|
27782
29273
|
if (!await confirm({
|
|
27783
29274
|
title: field.label,
|
|
@@ -27788,6 +29279,7 @@ function AddonActionButtonField({ field, values, disabled, onAction }) {
|
|
|
27788
29279
|
}
|
|
27789
29280
|
if (!onAction) return;
|
|
27790
29281
|
const params = resolveActionParams(field, values);
|
|
29282
|
+
if (field.prompt && asked !== null) params[field.prompt.param] = asked;
|
|
27791
29283
|
if (field.includeDeviceId === true && deviceId !== null && deviceId !== void 0) params["deviceId"] = deviceId;
|
|
27792
29284
|
setLoading(true);
|
|
27793
29285
|
setStatus(null);
|
|
@@ -28164,12 +29656,19 @@ function FormField({ field, values, onChange, disabled, translationFn, onTestFie
|
|
|
28164
29656
|
const handleChange = (v) => onChange(field.key, v);
|
|
28165
29657
|
const customRenderer = useCustomFieldRenderer(field.type);
|
|
28166
29658
|
switch (field.type) {
|
|
28167
|
-
case "text": return /* @__PURE__ */ jsx(
|
|
29659
|
+
case "text": return /* @__PURE__ */ jsx(KeychainOr, {
|
|
28168
29660
|
field,
|
|
28169
29661
|
value,
|
|
28170
29662
|
onChange: handleChange,
|
|
28171
29663
|
disabled,
|
|
28172
|
-
translationFn
|
|
29664
|
+
translationFn,
|
|
29665
|
+
children: /* @__PURE__ */ jsx(TextField, {
|
|
29666
|
+
field,
|
|
29667
|
+
value,
|
|
29668
|
+
onChange: handleChange,
|
|
29669
|
+
disabled,
|
|
29670
|
+
translationFn
|
|
29671
|
+
})
|
|
28173
29672
|
});
|
|
28174
29673
|
case "number": return /* @__PURE__ */ jsx(NumberField, {
|
|
28175
29674
|
field,
|
|
@@ -28213,19 +29712,34 @@ function FormField({ field, values, onChange, disabled, translationFn, onTestFie
|
|
|
28213
29712
|
disabled,
|
|
28214
29713
|
translationFn
|
|
28215
29714
|
});
|
|
28216
|
-
case "password": return /* @__PURE__ */ jsx(
|
|
29715
|
+
case "password": return /* @__PURE__ */ jsx(KeychainOr, {
|
|
28217
29716
|
field,
|
|
28218
29717
|
value,
|
|
28219
29718
|
onChange: handleChange,
|
|
28220
29719
|
disabled,
|
|
28221
|
-
translationFn
|
|
29720
|
+
translationFn,
|
|
29721
|
+
children: /* @__PURE__ */ jsx(PasswordField, {
|
|
29722
|
+
field,
|
|
29723
|
+
value,
|
|
29724
|
+
onChange: handleChange,
|
|
29725
|
+
disabled,
|
|
29726
|
+
translationFn
|
|
29727
|
+
})
|
|
28222
29728
|
});
|
|
28223
|
-
case "textarea": return /* @__PURE__ */ jsx(
|
|
29729
|
+
case "textarea": return /* @__PURE__ */ jsx(KeychainOr, {
|
|
28224
29730
|
field,
|
|
28225
29731
|
value,
|
|
28226
29732
|
onChange: handleChange,
|
|
28227
29733
|
disabled,
|
|
28228
|
-
translationFn
|
|
29734
|
+
translationFn,
|
|
29735
|
+
multiline: true,
|
|
29736
|
+
children: /* @__PURE__ */ jsx(TextAreaField, {
|
|
29737
|
+
field,
|
|
29738
|
+
value,
|
|
29739
|
+
onChange: handleChange,
|
|
29740
|
+
disabled,
|
|
29741
|
+
translationFn
|
|
29742
|
+
})
|
|
28229
29743
|
});
|
|
28230
29744
|
case "slider": return /* @__PURE__ */ jsx(SliderField, {
|
|
28231
29745
|
field,
|
|
@@ -28248,6 +29762,13 @@ function FormField({ field, values, onChange, disabled, translationFn, onTestFie
|
|
|
28248
29762
|
disabled,
|
|
28249
29763
|
translationFn
|
|
28250
29764
|
});
|
|
29765
|
+
case "icon": return /* @__PURE__ */ jsx(IconField, {
|
|
29766
|
+
field,
|
|
29767
|
+
value,
|
|
29768
|
+
onChange: handleChange,
|
|
29769
|
+
disabled,
|
|
29770
|
+
translationFn
|
|
29771
|
+
});
|
|
28251
29772
|
case "node-select": return /* @__PURE__ */ jsx(NodeSelectField, {
|
|
28252
29773
|
field,
|
|
28253
29774
|
value,
|
|
@@ -30020,47 +31541,6 @@ var Separator = forwardRef(({ className, orientation, ...props }, ref) => {
|
|
|
30020
31541
|
});
|
|
30021
31542
|
Separator.displayName = "Separator";
|
|
30022
31543
|
//#endregion
|
|
30023
|
-
//#region src/primitives/input.tsx
|
|
30024
|
-
/**
|
|
30025
|
-
* `disabled:opacity-50 disabled:cursor-not-allowed` for the same reason as
|
|
30026
|
-
* `Select` — an explicit `bg-surface` / `text-foreground` overrides the greying
|
|
30027
|
-
* a browser would otherwise apply, leaving an inert field indistinguishable
|
|
30028
|
-
* from a live one. See `disabled-affordance.test.tsx`.
|
|
30029
|
-
*/
|
|
30030
|
-
var inputVariants = cva("h-7 w-full px-2.5 text-xs bg-surface border rounded-md text-foreground placeholder:text-foreground-subtle focus:outline-none focus:ring-1 focus:ring-primary transition-colors disabled:opacity-50 disabled:cursor-not-allowed", {
|
|
30031
|
-
variants: { state: {
|
|
30032
|
-
default: "border-border",
|
|
30033
|
-
error: "border-danger"
|
|
30034
|
-
} },
|
|
30035
|
-
defaultVariants: { state: "default" }
|
|
30036
|
-
});
|
|
30037
|
-
var Input = forwardRef(({ className, state, leftSlot, rightSlot, ...props }, ref) => {
|
|
30038
|
-
if (leftSlot || rightSlot) return /* @__PURE__ */ jsxs("div", {
|
|
30039
|
-
className: "relative flex items-center w-full",
|
|
30040
|
-
children: [
|
|
30041
|
-
leftSlot && /* @__PURE__ */ jsx("div", {
|
|
30042
|
-
className: "absolute left-2.5 flex items-center pointer-events-none",
|
|
30043
|
-
children: leftSlot
|
|
30044
|
-
}),
|
|
30045
|
-
/* @__PURE__ */ jsx("input", {
|
|
30046
|
-
ref,
|
|
30047
|
-
className: cn(inputVariants({ state }), leftSlot ? "pl-7" : "", rightSlot ? "pr-7" : "", className),
|
|
30048
|
-
...props
|
|
30049
|
-
}),
|
|
30050
|
-
rightSlot && /* @__PURE__ */ jsx("div", {
|
|
30051
|
-
className: "absolute right-2.5 flex items-center pointer-events-none",
|
|
30052
|
-
children: rightSlot
|
|
30053
|
-
})
|
|
30054
|
-
]
|
|
30055
|
-
});
|
|
30056
|
-
return /* @__PURE__ */ jsx("input", {
|
|
30057
|
-
ref,
|
|
30058
|
-
className: cn(inputVariants({ state }), className),
|
|
30059
|
-
...props
|
|
30060
|
-
});
|
|
30061
|
-
});
|
|
30062
|
-
Input.displayName = "Input";
|
|
30063
|
-
//#endregion
|
|
30064
31544
|
//#region src/primitives/checkbox.tsx
|
|
30065
31545
|
var Checkbox = forwardRef(({ className, ...props }, ref) => {
|
|
30066
31546
|
return /* @__PURE__ */ jsx("input", {
|
|
@@ -30093,204 +31573,6 @@ var Switch = forwardRef(({ className, checked, onCheckedChange, label, ...props
|
|
|
30093
31573
|
});
|
|
30094
31574
|
Switch.displayName = "Switch";
|
|
30095
31575
|
//#endregion
|
|
30096
|
-
//#region src/primitives/dialog.tsx
|
|
30097
|
-
var DialogContext = createContext(null);
|
|
30098
|
-
function useDialogContext() {
|
|
30099
|
-
const ctx = useContext(DialogContext);
|
|
30100
|
-
if (!ctx) throw new Error("Dialog compound components must be used within <Dialog>");
|
|
30101
|
-
return ctx;
|
|
30102
|
-
}
|
|
30103
|
-
function Dialog({ children, open: controlledOpen, onOpenChange }) {
|
|
30104
|
-
const [uncontrolledOpen, setUncontrolledOpen] = useState(false);
|
|
30105
|
-
const open = controlledOpen ?? uncontrolledOpen;
|
|
30106
|
-
const contentId = useId();
|
|
30107
|
-
const setOpen = useCallback((next) => {
|
|
30108
|
-
onOpenChange?.(next);
|
|
30109
|
-
if (controlledOpen === void 0) setUncontrolledOpen(next);
|
|
30110
|
-
}, [controlledOpen, onOpenChange]);
|
|
30111
|
-
return /* @__PURE__ */ jsx(DialogContext.Provider, {
|
|
30112
|
-
value: {
|
|
30113
|
-
open,
|
|
30114
|
-
setOpen,
|
|
30115
|
-
contentId
|
|
30116
|
-
},
|
|
30117
|
-
children
|
|
30118
|
-
});
|
|
30119
|
-
}
|
|
30120
|
-
function DialogTrigger({ children, ...props }) {
|
|
30121
|
-
const { setOpen } = useDialogContext();
|
|
30122
|
-
return /* @__PURE__ */ jsx("button", {
|
|
30123
|
-
type: "button",
|
|
30124
|
-
onClick: () => setOpen(true),
|
|
30125
|
-
...props,
|
|
30126
|
-
children
|
|
30127
|
-
});
|
|
30128
|
-
}
|
|
30129
|
-
/**
|
|
30130
|
-
* A native <dialog> opened with showModal() is promoted to the top layer, so
|
|
30131
|
-
* ancestor transform/overflow can't clip it — but it relies on the UA
|
|
30132
|
-
* stylesheet's `dialog { margin: auto }` for modal centering. Tailwind's
|
|
30133
|
-
* preflight resets `margin: 0` on every element, which defeats that centering
|
|
30134
|
-
* and pins the modal to the top-left. We therefore center deterministically:
|
|
30135
|
-
* a top-layer dialog with `position: fixed` is viewport-relative, and a
|
|
30136
|
-
* self-transform is fine, so `fixed left-1/2 top-1/2 -translate-x-1/2
|
|
30137
|
-
* -translate-y-1/2 m-0` always centers regardless of any margin reset. Width
|
|
30138
|
-
* is capped to the viewport (`w-[calc(100vw-2rem)]`) rather than a bare
|
|
30139
|
-
* `w-full` (which would overflow/clip a centered dialog); the per-variant
|
|
30140
|
-
* `max-w-*` keeps small dialogs small while the cap prevents overflow.
|
|
30141
|
-
*
|
|
30142
|
-
* Height is capped against the SAFE viewport, not the raw one. A top-layer
|
|
30143
|
-
* `fixed` dialog is viewport-relative, and under `viewport-fit=cover` the
|
|
30144
|
-
* viewport extends behind the iOS notch/Dynamic Island and home indicator —
|
|
30145
|
-
* so a dialog tall enough to hit its `max-h` put its header under the clock.
|
|
30146
|
-
* Because the box is centred on the viewport (not on the safe area), the cap
|
|
30147
|
-
* has to subtract TWICE the LARGER of the two insets for the box to clear
|
|
30148
|
-
* both edges; using each inset once would still overflow the taller side
|
|
30149
|
-
* whenever they are asymmetric (they are: ~59px top vs ~34px bottom). Every
|
|
30150
|
-
* term collapses to the previous `100dvh - 2rem` where the insets are 0.
|
|
30151
|
-
*/
|
|
30152
|
-
var contentVariants = cva("fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 m-0 w-[calc(100vw-2rem)] bg-background-elevated text-foreground border border-border rounded-lg p-4 backdrop:bg-black/50 backdrop:backdrop-blur-sm max-h-[calc(100dvh-2rem-2*max(env(safe-area-inset-top),env(safe-area-inset-bottom)))] [&:not([open])]:hidden", {
|
|
30153
|
-
variants: {
|
|
30154
|
-
width: {
|
|
30155
|
-
sm: "max-w-sm",
|
|
30156
|
-
md: "max-w-md",
|
|
30157
|
-
lg: "max-w-lg"
|
|
30158
|
-
},
|
|
30159
|
-
/**
|
|
30160
|
-
* WHICH box scrolls when the content is taller than the height cap.
|
|
30161
|
-
*
|
|
30162
|
-
* `content` (default) scrolls the whole dialog: the title, any tab strip
|
|
30163
|
-
* and the Save/Cancel row travel with the fields. That is fine for a
|
|
30164
|
-
* short form and wrong for a long one — the operator scrolls to the
|
|
30165
|
-
* bottom of a rule editor and the buttons are somewhere above him, the
|
|
30166
|
-
* tab strip is gone, and the only way back to either is to scroll the
|
|
30167
|
-
* form he was reading.
|
|
30168
|
-
*
|
|
30169
|
-
* `body` makes the dialog a flex column that does not scroll at all and
|
|
30170
|
-
* hands the scrolling to `<DialogBody>`. The chrome around the body —
|
|
30171
|
-
* header, tab strip, footer — stays put at every height. The dialog
|
|
30172
|
-
* keeps its own padding either way, so `sheet-on-mobile`'s
|
|
30173
|
-
* safe-area bottom padding still applies to the footer.
|
|
30174
|
-
*
|
|
30175
|
-
* `body` also takes a DEFINITE height below `md` — see the
|
|
30176
|
-
* `scroll: 'body'` compound variants. That is not a style choice; the
|
|
30177
|
-
* flex chain does not resolve without it on iOS Safari.
|
|
30178
|
-
*/
|
|
30179
|
-
scroll: {
|
|
30180
|
-
content: "overflow-y-auto",
|
|
30181
|
-
body: "flex flex-col overflow-hidden"
|
|
30182
|
-
},
|
|
30183
|
-
placement: {
|
|
30184
|
-
center: "",
|
|
30185
|
-
"sheet-on-mobile": "bottom-0 left-0 right-0 top-auto w-full max-w-full translate-x-0 translate-y-0 rounded-b-none max-h-[92dvh] pb-[calc(1rem+env(safe-area-inset-bottom))] md:left-1/2 md:top-1/2 md:-translate-x-1/2 md:-translate-y-1/2 md:rounded-lg md:bottom-auto md:pb-4 md:max-h-[calc(100dvh-2rem-2*max(env(safe-area-inset-top),env(safe-area-inset-bottom)))]"
|
|
30186
|
-
}
|
|
30187
|
-
},
|
|
30188
|
-
compoundVariants: [
|
|
30189
|
-
{
|
|
30190
|
-
placement: "sheet-on-mobile",
|
|
30191
|
-
width: "sm",
|
|
30192
|
-
class: "md:w-[calc(100vw-2rem)] md:max-w-sm"
|
|
30193
|
-
},
|
|
30194
|
-
{
|
|
30195
|
-
placement: "sheet-on-mobile",
|
|
30196
|
-
width: "md",
|
|
30197
|
-
class: "md:w-[calc(100vw-2rem)] md:max-w-md"
|
|
30198
|
-
},
|
|
30199
|
-
{
|
|
30200
|
-
placement: "sheet-on-mobile",
|
|
30201
|
-
width: "lg",
|
|
30202
|
-
class: "md:w-[calc(100vw-2rem)] md:max-w-lg"
|
|
30203
|
-
},
|
|
30204
|
-
{
|
|
30205
|
-
scroll: "body",
|
|
30206
|
-
placement: "sheet-on-mobile",
|
|
30207
|
-
class: "h-[92dvh] md:h-auto"
|
|
30208
|
-
},
|
|
30209
|
-
{
|
|
30210
|
-
scroll: "body",
|
|
30211
|
-
placement: "center",
|
|
30212
|
-
class: "h-[calc(100dvh-2rem-2*max(env(safe-area-inset-top),env(safe-area-inset-bottom)))] md:h-auto"
|
|
30213
|
-
}
|
|
30214
|
-
],
|
|
30215
|
-
defaultVariants: {
|
|
30216
|
-
width: "md",
|
|
30217
|
-
placement: "center",
|
|
30218
|
-
scroll: "content"
|
|
30219
|
-
}
|
|
30220
|
-
});
|
|
30221
|
-
var DialogContent = forwardRef(({ className, width, placement, scroll, children, ...props }, ref) => {
|
|
30222
|
-
const { open, setOpen, contentId } = useDialogContext();
|
|
30223
|
-
const innerRef = useRef(null);
|
|
30224
|
-
const dialogRef = ref ?? innerRef;
|
|
30225
|
-
useEffect(() => {
|
|
30226
|
-
const el = dialogRef.current;
|
|
30227
|
-
if (!el) return;
|
|
30228
|
-
if (open && !el.open) el.showModal();
|
|
30229
|
-
if (!open && el.open) el.close();
|
|
30230
|
-
}, [open, dialogRef]);
|
|
30231
|
-
return /* @__PURE__ */ jsx("dialog", {
|
|
30232
|
-
ref: dialogRef,
|
|
30233
|
-
id: contentId,
|
|
30234
|
-
className: cn(contentVariants({
|
|
30235
|
-
width,
|
|
30236
|
-
placement,
|
|
30237
|
-
scroll
|
|
30238
|
-
}), className),
|
|
30239
|
-
onClose: () => setOpen(false),
|
|
30240
|
-
...props,
|
|
30241
|
-
children
|
|
30242
|
-
});
|
|
30243
|
-
});
|
|
30244
|
-
DialogContent.displayName = "DialogContent";
|
|
30245
|
-
/** `shrink-0` is inert outside a flex column and load-bearing inside one:
|
|
30246
|
-
* under `scroll="body"` the header must keep its height while the body gives
|
|
30247
|
-
* ground, or a long form squeezes its own title to nothing. */
|
|
30248
|
-
function DialogHeader({ className, ...props }) {
|
|
30249
|
-
return /* @__PURE__ */ jsx("div", {
|
|
30250
|
-
className: cn("flex flex-col gap-1 mb-3 shrink-0", className),
|
|
30251
|
-
...props
|
|
30252
|
-
});
|
|
30253
|
-
}
|
|
30254
|
-
/**
|
|
30255
|
-
* The scrolling middle of a `scroll="body"` dialog.
|
|
30256
|
-
*
|
|
30257
|
-
* `min-h-0` is what makes it work: a flex item's default `min-height: auto`
|
|
30258
|
-
* refuses to shrink below its content, so without it the body pushes the
|
|
30259
|
-
* footer out of the dialog instead of scrolling — the exact failure this
|
|
30260
|
-
* variant exists to remove. Anything sticky INSIDE a dialog body pins against
|
|
30261
|
-
* this element, since it is the scroll container.
|
|
30262
|
-
*
|
|
30263
|
-
* It only bounds a scroll area if every ancestor up to the dialog has a
|
|
30264
|
-
* resolved height. `DialogContent` supplies the top of that chain (see the
|
|
30265
|
-
* `scroll: 'body'` compound variants); an intermediate wrapper between them —
|
|
30266
|
-
* a `<Tabs>` that owns the tab strip, say — must carry `flex-1 min-h-0` too,
|
|
30267
|
-
* or it collapses and takes the body with it.
|
|
30268
|
-
*/
|
|
30269
|
-
function DialogBody({ className, ...props }) {
|
|
30270
|
-
return /* @__PURE__ */ jsx("div", {
|
|
30271
|
-
className: cn("flex-1 min-h-0 overflow-y-auto", className),
|
|
30272
|
-
...props
|
|
30273
|
-
});
|
|
30274
|
-
}
|
|
30275
|
-
function DialogFooter({ className, ...props }) {
|
|
30276
|
-
return /* @__PURE__ */ jsx("div", {
|
|
30277
|
-
className: cn("flex justify-end gap-2 mt-4 shrink-0", className),
|
|
30278
|
-
...props
|
|
30279
|
-
});
|
|
30280
|
-
}
|
|
30281
|
-
function DialogTitle({ className, ...props }) {
|
|
30282
|
-
return /* @__PURE__ */ jsx("h2", {
|
|
30283
|
-
className: cn("text-sm font-semibold text-foreground", className),
|
|
30284
|
-
...props
|
|
30285
|
-
});
|
|
30286
|
-
}
|
|
30287
|
-
function DialogDescription({ className, ...props }) {
|
|
30288
|
-
return /* @__PURE__ */ jsx("p", {
|
|
30289
|
-
className: cn("text-xs text-foreground-muted", className),
|
|
30290
|
-
...props
|
|
30291
|
-
});
|
|
30292
|
-
}
|
|
30293
|
-
//#endregion
|
|
30294
31576
|
//#region src/primitives/tooltip.tsx
|
|
30295
31577
|
var TooltipContext = createContext(null);
|
|
30296
31578
|
function useTooltipContext() {
|
|
@@ -49397,1248 +50679,683 @@ function SwitchInlineControl({ trpc, deviceId, features, optimistic }) {
|
|
|
49397
50679
|
optimistic
|
|
49398
50680
|
});
|
|
49399
50681
|
}
|
|
49400
|
-
function useLockCapGuard(trpc, deviceId) {
|
|
49401
|
-
const { cap } = useDeviceCapability({
|
|
49402
|
-
trpc,
|
|
49403
|
-
deviceId,
|
|
49404
|
-
cap: (d) => d.lockControl,
|
|
49405
|
-
slice: (d) => d.state.lockControl
|
|
49406
|
-
});
|
|
49407
|
-
return cap !== void 0;
|
|
49408
|
-
}
|
|
49409
|
-
function LockInlineControl({ trpc, deviceId, features, optimistic }) {
|
|
49410
|
-
if (!useLockCapGuard(trpc, deviceId)) return null;
|
|
49411
|
-
return /* @__PURE__ */ jsx(LockPanel, {
|
|
49412
|
-
trpc,
|
|
49413
|
-
deviceId,
|
|
49414
|
-
features,
|
|
49415
|
-
layout: "compact",
|
|
49416
|
-
optimistic
|
|
49417
|
-
});
|
|
49418
|
-
}
|
|
49419
|
-
function LightInlineControl({ trpc, deviceId, features, optimistic }) {
|
|
49420
|
-
if (!useSwitchCapGuard(trpc, deviceId)) return null;
|
|
49421
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
49422
|
-
className: "inline-flex items-center gap-2",
|
|
49423
|
-
children: [/* @__PURE__ */ jsx(SwitchPanel, {
|
|
49424
|
-
trpc,
|
|
49425
|
-
deviceId,
|
|
49426
|
-
features,
|
|
49427
|
-
layout: "compact",
|
|
49428
|
-
optimistic
|
|
49429
|
-
}), /* @__PURE__ */ jsx(BrightnessPanel, {
|
|
49430
|
-
trpc,
|
|
49431
|
-
deviceId,
|
|
49432
|
-
features,
|
|
49433
|
-
layout: "compact",
|
|
49434
|
-
optimistic
|
|
49435
|
-
})]
|
|
49436
|
-
});
|
|
49437
|
-
}
|
|
49438
|
-
function useFanCapGuard(trpc, deviceId) {
|
|
49439
|
-
const { cap } = useDeviceCapability({
|
|
49440
|
-
trpc,
|
|
49441
|
-
deviceId,
|
|
49442
|
-
cap: (d) => d.fanControl,
|
|
49443
|
-
slice: (d) => d.state.fanControl
|
|
49444
|
-
});
|
|
49445
|
-
return cap !== void 0;
|
|
49446
|
-
}
|
|
49447
|
-
function FanInlineControl({ trpc, deviceId, features, optimistic }) {
|
|
49448
|
-
if (!useFanCapGuard(trpc, deviceId)) return null;
|
|
49449
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
49450
|
-
className: "inline-flex items-center gap-2",
|
|
49451
|
-
children: [/* @__PURE__ */ jsx(SwitchPanel, {
|
|
49452
|
-
trpc,
|
|
49453
|
-
deviceId,
|
|
49454
|
-
features,
|
|
49455
|
-
layout: "compact",
|
|
49456
|
-
optimistic
|
|
49457
|
-
}), /* @__PURE__ */ jsx(FanPanel, {
|
|
49458
|
-
trpc,
|
|
49459
|
-
deviceId,
|
|
49460
|
-
features,
|
|
49461
|
-
layout: "compact",
|
|
49462
|
-
optimistic
|
|
49463
|
-
})]
|
|
49464
|
-
});
|
|
49465
|
-
}
|
|
49466
|
-
function useClimateCapGuard(trpc, deviceId) {
|
|
49467
|
-
const { cap } = useDeviceCapability({
|
|
49468
|
-
trpc,
|
|
49469
|
-
deviceId,
|
|
49470
|
-
cap: (d) => d.climateControl,
|
|
49471
|
-
slice: (d) => d.state.climateControl
|
|
49472
|
-
});
|
|
49473
|
-
return cap !== void 0;
|
|
49474
|
-
}
|
|
49475
|
-
function ThermostatInlineControl({ trpc, deviceId, features, optimistic }) {
|
|
49476
|
-
if (!useClimateCapGuard(trpc, deviceId)) return null;
|
|
49477
|
-
return /* @__PURE__ */ jsx(ClimatePanel, {
|
|
49478
|
-
trpc,
|
|
49479
|
-
deviceId,
|
|
49480
|
-
features,
|
|
49481
|
-
layout: "compact",
|
|
49482
|
-
optimistic
|
|
49483
|
-
});
|
|
49484
|
-
}
|
|
49485
|
-
function AcInlineControl({ trpc, deviceId, features, optimistic }) {
|
|
49486
|
-
if (!useClimateCapGuard(trpc, deviceId)) return null;
|
|
49487
|
-
return /* @__PURE__ */ jsx(AcPanel, {
|
|
49488
|
-
trpc,
|
|
49489
|
-
deviceId,
|
|
49490
|
-
features,
|
|
49491
|
-
layout: "compact",
|
|
49492
|
-
optimistic
|
|
49493
|
-
});
|
|
49494
|
-
}
|
|
49495
|
-
function AcHeroCard({ trpc, deviceId, features, optimistic }) {
|
|
49496
|
-
if (!useClimateCapGuard(trpc, deviceId)) return null;
|
|
49497
|
-
return /* @__PURE__ */ jsx(AcPanel, {
|
|
49498
|
-
trpc,
|
|
49499
|
-
deviceId,
|
|
49500
|
-
features,
|
|
49501
|
-
layout: "full",
|
|
49502
|
-
optimistic
|
|
49503
|
-
});
|
|
49504
|
-
}
|
|
49505
|
-
function useMediaPlayerCapGuard(trpc, deviceId) {
|
|
49506
|
-
const { cap } = useDeviceCapability({
|
|
49507
|
-
trpc,
|
|
49508
|
-
deviceId,
|
|
49509
|
-
cap: (d) => d.mediaPlayer,
|
|
49510
|
-
slice: (d) => d.state.mediaPlayer
|
|
49511
|
-
});
|
|
49512
|
-
return cap !== void 0;
|
|
49513
|
-
}
|
|
49514
|
-
function MediaPlayerInlineControl({ trpc, deviceId, features, optimistic }) {
|
|
49515
|
-
if (!useMediaPlayerCapGuard(trpc, deviceId)) return null;
|
|
49516
|
-
return /* @__PURE__ */ jsx(MediaPlayerPanel, {
|
|
49517
|
-
trpc,
|
|
49518
|
-
deviceId,
|
|
49519
|
-
features,
|
|
49520
|
-
layout: "compact",
|
|
49521
|
-
optimistic
|
|
49522
|
-
});
|
|
49523
|
-
}
|
|
49524
|
-
function useControlCapGuard(trpc, deviceId) {
|
|
49525
|
-
const { cap } = useDeviceCapability({
|
|
49526
|
-
trpc,
|
|
49527
|
-
deviceId,
|
|
49528
|
-
cap: (d) => d.control,
|
|
49529
|
-
slice: (d) => d.state.control
|
|
49530
|
-
});
|
|
49531
|
-
return cap !== void 0;
|
|
49532
|
-
}
|
|
49533
|
-
function ControlInlineControl({ trpc, deviceId, features, optimistic }) {
|
|
49534
|
-
if (!useControlCapGuard(trpc, deviceId)) return null;
|
|
49535
|
-
return /* @__PURE__ */ jsx(ControlPanel, {
|
|
49536
|
-
trpc,
|
|
49537
|
-
deviceId,
|
|
49538
|
-
features,
|
|
49539
|
-
layout: "compact",
|
|
49540
|
-
optimistic
|
|
49541
|
-
});
|
|
49542
|
-
}
|
|
49543
|
-
function ControlHeroCard({ trpc, deviceId, features, optimistic }) {
|
|
49544
|
-
if (!useControlCapGuard(trpc, deviceId)) return null;
|
|
49545
|
-
return /* @__PURE__ */ jsx(HeroShell, { children: /* @__PURE__ */ jsx(ControlPanel, {
|
|
49546
|
-
trpc,
|
|
49547
|
-
deviceId,
|
|
49548
|
-
features,
|
|
49549
|
-
layout: "full",
|
|
49550
|
-
optimistic
|
|
49551
|
-
}) });
|
|
49552
|
-
}
|
|
49553
|
-
//#endregion
|
|
49554
|
-
//#region src/composites/device-controls/control-registry.tsx
|
|
49555
|
-
/**
|
|
49556
|
-
* Presentation binding: the shared `DeviceControlKind` (decided in
|
|
49557
|
-
* `@camstack/types` `resolveDeviceControlKind`) → this platform's web
|
|
49558
|
-
* components. Exhaustive over `DeviceControlKind` — omitting a kind fails the
|
|
49559
|
-
* build here. The type→kind DECISION is single-sourced in `@camstack/types`;
|
|
49560
|
-
* this map only binds a kind to its web widgets.
|
|
49561
|
-
*/
|
|
49562
|
-
var CONTROL_KIND_COMPONENTS = {
|
|
49563
|
-
cover: {
|
|
49564
|
-
InlineControl: CoverInlineControl,
|
|
49565
|
-
HeroCard: CoverHeroCard
|
|
49566
|
-
},
|
|
49567
|
-
valve: {
|
|
49568
|
-
InlineControl: ValveInlineControl,
|
|
49569
|
-
HeroCard: ValveHeroCard
|
|
49570
|
-
},
|
|
49571
|
-
humidifier: {
|
|
49572
|
-
InlineControl: HumidifierInlineControl,
|
|
49573
|
-
HeroCard: HumidifierHeroCard
|
|
49574
|
-
},
|
|
49575
|
-
"water-heater": {
|
|
49576
|
-
InlineControl: WaterHeaterInlineControl,
|
|
49577
|
-
HeroCard: WaterHeaterHeroCard
|
|
49578
|
-
},
|
|
49579
|
-
switch: {
|
|
49580
|
-
InlineControl: SwitchInlineControl,
|
|
49581
|
-
HeroCard: SwitchHeroCard
|
|
49582
|
-
},
|
|
49583
|
-
light: {
|
|
49584
|
-
InlineControl: LightInlineControl,
|
|
49585
|
-
HeroCard: LightHeroCard
|
|
49586
|
-
},
|
|
49587
|
-
fan: {
|
|
49588
|
-
InlineControl: FanInlineControl,
|
|
49589
|
-
HeroCard: FanHeroCard
|
|
49590
|
-
},
|
|
49591
|
-
sensor: {
|
|
49592
|
-
InlineControl: SensorInlineControl,
|
|
49593
|
-
HeroCard: SensorHeroCard
|
|
49594
|
-
},
|
|
49595
|
-
thermostat: {
|
|
49596
|
-
InlineControl: ThermostatInlineControl,
|
|
49597
|
-
HeroCard: ThermostatHeroCard
|
|
49598
|
-
},
|
|
49599
|
-
climate: {
|
|
49600
|
-
InlineControl: AcInlineControl,
|
|
49601
|
-
HeroCard: AcHeroCard
|
|
49602
|
-
},
|
|
49603
|
-
button: {
|
|
49604
|
-
InlineControl: ButtonControl,
|
|
49605
|
-
HeroCard: ButtonHeroCard
|
|
49606
|
-
},
|
|
49607
|
-
update: {
|
|
49608
|
-
InlineControl: UpdateInlineControl,
|
|
49609
|
-
HeroCard: UpdateHeroCard
|
|
49610
|
-
},
|
|
49611
|
-
lock: {
|
|
49612
|
-
InlineControl: LockInlineControl,
|
|
49613
|
-
HeroCard: LockHeroCard
|
|
49614
|
-
},
|
|
49615
|
-
"media-player": {
|
|
49616
|
-
InlineControl: MediaPlayerInlineControl,
|
|
49617
|
-
HeroCard: MediaPlayerHeroCard
|
|
49618
|
-
},
|
|
49619
|
-
alarm: {
|
|
49620
|
-
InlineControl: AlarmInlineControl,
|
|
49621
|
-
HeroCard: AlarmHeroCard
|
|
49622
|
-
},
|
|
49623
|
-
control: {
|
|
49624
|
-
InlineControl: ControlInlineControl,
|
|
49625
|
-
HeroCard: ControlHeroCard
|
|
49626
|
-
},
|
|
49627
|
-
weather: {
|
|
49628
|
-
InlineControl: WeatherInlineControl,
|
|
49629
|
-
HeroCard: WeatherHeroCard
|
|
49630
|
-
},
|
|
49631
|
-
vacuum: {
|
|
49632
|
-
InlineControl: VacuumInlineControl,
|
|
49633
|
-
HeroCard: VacuumHeroCard
|
|
49634
|
-
},
|
|
49635
|
-
"lawn-mower": {
|
|
49636
|
-
InlineControl: LawnMowerInlineControl,
|
|
49637
|
-
HeroCard: LawnMowerHeroCard
|
|
49638
|
-
},
|
|
49639
|
-
image: {
|
|
49640
|
-
InlineControl: ImageInlineControl,
|
|
49641
|
-
HeroCard: ImageHeroCard
|
|
49642
|
-
},
|
|
49643
|
-
"pet-feeder": {
|
|
49644
|
-
InlineControl: PetFeederInlineControl,
|
|
49645
|
-
HeroCard: PetFeederHeroCard
|
|
49646
|
-
},
|
|
49647
|
-
script: {
|
|
49648
|
-
InlineControl: ScriptInlineControl,
|
|
49649
|
-
HeroCard: ScriptHeroCard
|
|
49650
|
-
},
|
|
49651
|
-
automation: {
|
|
49652
|
-
InlineControl: AutomationInlineControl,
|
|
49653
|
-
HeroCard: AutomationHeroCard
|
|
49654
|
-
},
|
|
49655
|
-
dummy: {
|
|
49656
|
-
InlineControl: DummyInline,
|
|
49657
|
-
HeroCard: DummyHeroCard
|
|
49658
|
-
}
|
|
49659
|
-
};
|
|
49660
|
-
/**
|
|
49661
|
-
* Exhaustive record over DeviceType, DERIVED from the shared decision
|
|
49662
|
-
* (`DEVICE_TYPE_CONTROL_KIND`) composed with the web `CONTROL_KIND_COMPONENTS`
|
|
49663
|
-
* binding — so the type→control mapping can never diverge from the single
|
|
49664
|
-
* source in `@camstack/types`. Preserved as a public export for consumers/tests
|
|
49665
|
-
* that index it by `DeviceType`.
|
|
49666
|
-
*
|
|
49667
|
-
* The `Object.fromEntries` result is a `{ [k: string]: DeviceTypeControl }`;
|
|
49668
|
-
* `Object.values(DeviceType)` (a string enum) yields exactly the enum's members,
|
|
49669
|
-
* so the record is fully populated — the assertion narrows that documented
|
|
49670
|
-
* enum-record projection boundary.
|
|
49671
|
-
*/
|
|
49672
|
-
var DEVICE_TYPE_CONTROL = Object.fromEntries(Object.values(DeviceType).map((type) => [type, CONTROL_KIND_COMPONENTS[DEVICE_TYPE_CONTROL_KIND[type]]]));
|
|
49673
|
-
/**
|
|
49674
|
-
* Per-type FILL flag.
|
|
49675
|
-
*
|
|
49676
|
-
* true — range / choice / button controls (cover ▲■▼ triad, thermostat
|
|
49677
|
-
* setpoint stepper, media/control/button action buttons, alarm
|
|
49678
|
-
* segmented control). The child STRETCHES to the full column width.
|
|
49679
|
-
* false — readouts, tap-toggles, icon controls (lock), and dummy/placeholder
|
|
49680
|
-
* types. The child keeps its NATURAL width; where it sits in the
|
|
49681
|
-
* column (flush right vs centered) is decided by the caller via a
|
|
49682
|
-
* `ControlPlacement` — see `resolveControlAlign`.
|
|
49683
|
-
*
|
|
49684
|
-
* Dummy types (Camera, Hub, Generic, Weather, Vacuum, Container, and placeholder
|
|
49685
|
-
* types Notifier/Script/Automation whose InlineControl renders "—") are `false` —
|
|
49686
|
-
* the dash placeholder must not be stretched to the full column width. (AlarmPanel
|
|
49687
|
-
* has a real segmented inline control and is `true`.) When a later task gives a
|
|
49688
|
-
* remaining placeholder type a real stretchy inline control, flip its flag to true.
|
|
49689
|
-
*
|
|
49690
|
-
* Exhaustive over DeviceType — a missing member is a TypeScript build error.
|
|
49691
|
-
*/
|
|
49692
|
-
var CONTROL_FILLS = {
|
|
49693
|
-
[DeviceType.Cover]: true,
|
|
49694
|
-
[DeviceType.Valve]: true,
|
|
49695
|
-
[DeviceType.Thermostat]: true,
|
|
49696
|
-
[DeviceType.Climate]: true,
|
|
49697
|
-
[DeviceType.Control]: true,
|
|
49698
|
-
[DeviceType.Button]: true,
|
|
49699
|
-
[DeviceType.MediaPlayer]: true,
|
|
49700
|
-
[DeviceType.AlarmPanel]: true,
|
|
49701
|
-
[DeviceType.Lock]: false,
|
|
49702
|
-
[DeviceType.Vacuum]: false,
|
|
49703
|
-
[DeviceType.LawnMower]: false,
|
|
49704
|
-
[DeviceType.Humidifier]: false,
|
|
49705
|
-
[DeviceType.Switch]: false,
|
|
49706
|
-
[DeviceType.Siren]: false,
|
|
49707
|
-
[DeviceType.Light]: false,
|
|
49708
|
-
[DeviceType.Fan]: false,
|
|
49709
|
-
[DeviceType.WaterHeater]: false,
|
|
49710
|
-
[DeviceType.Sensor]: false,
|
|
49711
|
-
[DeviceType.Presence]: false,
|
|
49712
|
-
[DeviceType.EventEmitter]: false,
|
|
49713
|
-
[DeviceType.Notifier]: false,
|
|
49714
|
-
[DeviceType.Script]: false,
|
|
49715
|
-
[DeviceType.Automation]: false,
|
|
49716
|
-
[DeviceType.Camera]: false,
|
|
49717
|
-
[DeviceType.Hub]: false,
|
|
49718
|
-
[DeviceType.Update]: false,
|
|
49719
|
-
[DeviceType.Generic]: false,
|
|
49720
|
-
[DeviceType.Weather]: false,
|
|
49721
|
-
[DeviceType.Container]: false,
|
|
49722
|
-
[DeviceType.Image]: false,
|
|
49723
|
-
[DeviceType.PetFeeder]: false
|
|
49724
|
-
};
|
|
49725
|
-
var DEVICE_TYPE_VALUES$1 = new Set(Object.values(DeviceType));
|
|
49726
|
-
/**
|
|
49727
|
-
* Runtime-string-safe lookup: a device row's `type` crosses the wire as a plain
|
|
49728
|
-
* string. The type→control-kind DECISION is single-sourced in `@camstack/types`
|
|
49729
|
-
* (`resolveDeviceControlKind`, null for an unrecognised type); this maps the
|
|
49730
|
-
* resolved kind onto the web components.
|
|
49731
|
-
*/
|
|
49732
|
-
function resolveDeviceControl(type) {
|
|
49733
|
-
const kind = resolveDeviceControlKind(type);
|
|
49734
|
-
return kind ? CONTROL_KIND_COMPONENTS[kind] : null;
|
|
49735
|
-
}
|
|
49736
|
-
/**
|
|
49737
|
-
* Runtime-string-safe alignment lookup for the fixed-width control column.
|
|
49738
|
-
*
|
|
49739
|
-
* A device's `type` crosses the wire as a plain string;
|
|
49740
|
-
* `DEVICE_TYPE_VALUES.has(type)` narrows it to `DeviceType` before indexing
|
|
49741
|
-
* `CONTROL_FILLS`, making the cast sound. The `'table'` placement is
|
|
49742
|
-
* content-width for EVERY type (returns `FIT`), so a wide control never
|
|
49743
|
-
* overflows a fixed box — the FILL flag is irrelevant there. For the fixed-box
|
|
49744
|
-
* placements a FILL type always stretches (`FILL`) and a natural-width type is
|
|
49745
|
-
* placed by the caller's `placement` — `'center'` → `CENTER`, `'right'` →
|
|
49746
|
-
* `RIGHT` (card / minimal view). An unrecognised type falls back to
|
|
49747
|
-
* natural-width placement.
|
|
49748
|
-
*/
|
|
49749
|
-
function resolveControlAlign(type, placement) {
|
|
49750
|
-
if (placement === "table") return "fit";
|
|
49751
|
-
return DEVICE_TYPE_VALUES$1.has(type) && CONTROL_FILLS[type] ? FILL : placement === "center" ? CENTER : RIGHT;
|
|
49752
|
-
}
|
|
49753
|
-
//#endregion
|
|
49754
|
-
//#region src/lib/format-last-seen.ts
|
|
49755
|
-
/**
|
|
49756
|
-
* Relative "last seen" formatter for the offline affordance.
|
|
49757
|
-
*
|
|
49758
|
-
* Renders a short relative-time label from a millisecond epoch:
|
|
49759
|
-
* "just now", "5m ago", "3h ago", "2d ago". Returns `null` for missing
|
|
49760
|
-
* inputs, or inputs below {@link MIN_PLAUSIBLE_TIMESTAMP_MS} (a
|
|
49761
|
-
* placeholder or a seeded "known value, unknown change time" stamp), so
|
|
49762
|
-
* callers can render nothing rather than a misleading "—", "NaN ago", or
|
|
49763
|
-
* (for a seeded `1`) "20000 days ago".
|
|
49764
|
-
*
|
|
49765
|
-
* Future timestamps (clock skew between the device and the browser)
|
|
49766
|
-
* collapse to "just now" instead of a negative duration.
|
|
49767
|
-
*/
|
|
49768
|
-
var SECOND_MS = 1e3;
|
|
49769
|
-
var MINUTE_MS = 60 * SECOND_MS;
|
|
49770
|
-
var HOUR_MS = 60 * MINUTE_MS;
|
|
49771
|
-
var DAY_MS = 24 * HOUR_MS;
|
|
49772
|
-
var JUST_NOW_MS = 30 * SECOND_MS;
|
|
49773
|
-
/**
|
|
49774
|
-
* The earliest timestamp a real "last seen" could plausibly carry. Below
|
|
49775
|
-
* this, a value is a placeholder or a seeded "known value, unknown change
|
|
49776
|
-
* time" stamp (e.g. Homematic's `HM_SEEDED_CHANGED_AT = 1`) — never a real
|
|
49777
|
-
* instant. Year 2000 predates every device this renders.
|
|
49778
|
-
*/
|
|
49779
|
-
var MIN_PLAUSIBLE_TIMESTAMP_MS = Date.UTC(2e3, 0, 1);
|
|
49780
|
-
function formatLastSeen(timestampMs) {
|
|
49781
|
-
if (timestampMs === null || timestampMs === void 0 || timestampMs < MIN_PLAUSIBLE_TIMESTAMP_MS) return null;
|
|
49782
|
-
const delta = Date.now() - timestampMs;
|
|
49783
|
-
if (delta < JUST_NOW_MS) return "just now";
|
|
49784
|
-
if (delta < HOUR_MS) return `${String(Math.floor(delta / MINUTE_MS))}m ago`;
|
|
49785
|
-
if (delta < DAY_MS) return `${String(Math.floor(delta / HOUR_MS))}h ago`;
|
|
49786
|
-
return `${String(Math.floor(delta / DAY_MS))}d ago`;
|
|
49787
|
-
}
|
|
49788
|
-
//#endregion
|
|
49789
|
-
//#region src/composites/device-controls/offline-badge.tsx
|
|
49790
|
-
function OfflineBadge({ lastChangedAt, className }) {
|
|
49791
|
-
const lastSeen = formatLastSeen(lastChangedAt);
|
|
49792
|
-
return /* @__PURE__ */ jsxs("span", {
|
|
49793
|
-
title: lastSeen === null ? "Unavailable" : `Unavailable · last seen ${lastSeen}`,
|
|
49794
|
-
className: cn("inline-flex items-center gap-1 rounded-full px-2 py-0.5", "bg-surface-hover text-foreground-subtle text-[10px] font-medium", "border border-border", className),
|
|
49795
|
-
children: [
|
|
49796
|
-
/* @__PURE__ */ jsx(WifiOff, {
|
|
49797
|
-
className: "h-3 w-3 flex-shrink-0",
|
|
49798
|
-
"aria-hidden": "true"
|
|
49799
|
-
}),
|
|
49800
|
-
/* @__PURE__ */ jsx("span", { children: "Unavailable" }),
|
|
49801
|
-
lastSeen !== null ? /* @__PURE__ */ jsx("span", {
|
|
49802
|
-
className: "text-foreground-subtle/70",
|
|
49803
|
-
children: `· last seen ${lastSeen}`
|
|
49804
|
-
}) : null
|
|
49805
|
-
]
|
|
49806
|
-
});
|
|
49807
|
-
}
|
|
49808
|
-
//#endregion
|
|
49809
|
-
//#region src/composites/device-controls/primary-child.ts
|
|
49810
|
-
/**
|
|
49811
|
-
* Which child a container is rendered AS — this surface's name for the shared
|
|
49812
|
-
* rule.
|
|
49813
|
-
*
|
|
49814
|
-
* The list and the resolution used to live here, in a COPY that carried a
|
|
49815
|
-
* comment asking the Home Assistant adoption mapping and the viewer's panel to
|
|
49816
|
-
* stay in sync with it. Three lists and three comments is not one rule, it is
|
|
49817
|
-
* three chances to drift. Both now come from `@camstack/types`, which all of
|
|
49818
|
-
* them already depend on; what remains here is the adapter for this module's
|
|
49819
|
-
* historical `ChildRef` shape.
|
|
49820
|
-
*/
|
|
49821
|
-
/** The shared precedence, under this module's historical name. */
|
|
49822
|
-
var PRIORITY = CONTAINER_CHILD_PRIORITY;
|
|
49823
|
-
/**
|
|
49824
|
-
* Resolve a container's primary child: the operator's pick when it still
|
|
49825
|
-
* matches a live child, else the highest-priority type.
|
|
49826
|
-
*
|
|
49827
|
-
* `entityId` here is `sourceInfo?.id ?? stableId` (see `containerChildToRef`).
|
|
49828
|
-
* The shared resolver matches its canonical `stableId` key first and accepts
|
|
49829
|
-
* that legacy value too, so a pick stored under either keeps resolving.
|
|
49830
|
-
*/
|
|
49831
|
-
function resolvePrimaryChild(children, overrideEntityId, containerName) {
|
|
49832
|
-
const picked = resolveContainerPrimaryChild(children.map((c) => ({
|
|
49833
|
-
id: c.id,
|
|
49834
|
-
stableId: c.entityId,
|
|
49835
|
-
type: c.type,
|
|
49836
|
-
...c.role !== void 0 ? { role: c.role } : {},
|
|
49837
|
-
...c.name !== void 0 ? { name: c.name } : {}
|
|
49838
|
-
})), overrideEntityId, containerName);
|
|
49839
|
-
return picked === null ? null : children.find((c) => c.id === picked.id) ?? null;
|
|
49840
|
-
}
|
|
49841
|
-
//#endregion
|
|
49842
|
-
//#region src/composites/device-controls/container-primary.ts
|
|
49843
|
-
/**
|
|
49844
|
-
* Re-sync-stable identity of a child. Prefers the upstream-system dispatch key
|
|
49845
|
-
* (`sourceInfo.id` — e.g. HA `entity_id`); falls back to `stableId` for
|
|
49846
|
-
* providers that never populated SourceInfo. Both survive a re-sync that may
|
|
49847
|
-
* reallocate the numeric `id`.
|
|
49848
|
-
*/
|
|
49849
|
-
function childEntityId(child) {
|
|
49850
|
-
return child.sourceInfo?.id ?? child.stableId;
|
|
49851
|
-
}
|
|
49852
|
-
/** Project a raw child row onto the pure resolver's {@link ChildRef} shape. */
|
|
49853
|
-
function containerChildToRef(child) {
|
|
49854
|
-
return {
|
|
49855
|
-
id: child.id,
|
|
49856
|
-
entityId: childEntityId(child),
|
|
49857
|
-
type: child.type,
|
|
49858
|
-
...child.role !== void 0 && child.role !== null ? { role: child.role } : {},
|
|
49859
|
-
...child.name !== void 0 ? { name: child.name } : {}
|
|
49860
|
-
};
|
|
49861
|
-
}
|
|
49862
|
-
/**
|
|
49863
|
-
* Resolve the entityId override from the container's persisted `linkDeviceId`.
|
|
49864
|
-
* Returns the linked child's stable entityId, or `undefined` when there is no
|
|
49865
|
-
* link or the link is stale (points to a numeric id no longer present) — in
|
|
49866
|
-
* which case the resolver falls back to the priority default.
|
|
49867
|
-
*/
|
|
49868
|
-
function overrideEntityIdFromLink(children, linkDeviceId) {
|
|
49869
|
-
if (linkDeviceId === null || linkDeviceId === void 0) return void 0;
|
|
49870
|
-
const linked = children.find((c) => c.id === linkDeviceId);
|
|
49871
|
-
return linked === void 0 ? void 0 : childEntityId(linked);
|
|
49872
|
-
}
|
|
49873
|
-
/**
|
|
49874
|
-
* Full container → primary-child resolution: project children to refs, resolve
|
|
49875
|
-
* the override entityId, and delegate to the pure resolver. Returns `null` for a
|
|
49876
|
-
* container with no children (caller degrades gracefully).
|
|
49877
|
-
*
|
|
49878
|
-
* Override precedence:
|
|
49879
|
-
* 1. `primaryChildEntityId` — the DURABLE override (re-sync/rename-stable),
|
|
49880
|
-
* passed straight to the resolver which matches on `entityId`. Wins when a
|
|
49881
|
-
* non-empty string is supplied.
|
|
49882
|
-
* 2. `linkDeviceId` — LEGACY numeric override, re-derived to an entityId from
|
|
49883
|
-
* the live child set. Consulted only when there is no durable override.
|
|
49884
|
-
*
|
|
49885
|
-
* When neither resolves to a live child, the resolver falls back to the
|
|
49886
|
-
* priority default.
|
|
49887
|
-
*/
|
|
49888
|
-
function resolveContainerPrimary(children, linkDeviceId, primaryChildEntityId) {
|
|
49889
|
-
return resolvePrimaryChild(children.map(containerChildToRef), primaryChildEntityId !== null && primaryChildEntityId !== void 0 && primaryChildEntityId !== "" ? primaryChildEntityId : overrideEntityIdFromLink(children, linkDeviceId));
|
|
49890
|
-
}
|
|
49891
|
-
//#endregion
|
|
49892
|
-
//#region src/composites/device-controls/container-primary-hero.tsx
|
|
49893
|
-
function ContainerPrimaryHero({ trpc, children, linkDeviceId, primaryChildEntityId }) {
|
|
49894
|
-
const primary = resolveContainerPrimary(children, linkDeviceId, primaryChildEntityId);
|
|
49895
|
-
const primaryChild = primary === null ? void 0 : children.find((c) => c.id === primary.id);
|
|
49896
|
-
if (primaryChild === void 0) return /* @__PURE__ */ jsx("div", {
|
|
49897
|
-
className: "flex h-full w-full items-center justify-center p-4 text-[11px] italic text-foreground-subtle",
|
|
49898
|
-
children: "No child entities to display."
|
|
50682
|
+
function useLockCapGuard(trpc, deviceId) {
|
|
50683
|
+
const { cap } = useDeviceCapability({
|
|
50684
|
+
trpc,
|
|
50685
|
+
deviceId,
|
|
50686
|
+
cap: (d) => d.lockControl,
|
|
50687
|
+
slice: (d) => d.state.lockControl
|
|
49899
50688
|
});
|
|
49900
|
-
return
|
|
49901
|
-
|
|
49902
|
-
|
|
50689
|
+
return cap !== void 0;
|
|
50690
|
+
}
|
|
50691
|
+
function LockInlineControl({ trpc, deviceId, features, optimistic }) {
|
|
50692
|
+
if (!useLockCapGuard(trpc, deviceId)) return null;
|
|
50693
|
+
return /* @__PURE__ */ jsx(LockPanel, {
|
|
50694
|
+
trpc,
|
|
50695
|
+
deviceId,
|
|
50696
|
+
features,
|
|
50697
|
+
layout: "compact",
|
|
50698
|
+
optimistic
|
|
50699
|
+
});
|
|
50700
|
+
}
|
|
50701
|
+
function LightInlineControl({ trpc, deviceId, features, optimistic }) {
|
|
50702
|
+
if (!useSwitchCapGuard(trpc, deviceId)) return null;
|
|
50703
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
50704
|
+
className: "inline-flex items-center gap-2",
|
|
50705
|
+
children: [/* @__PURE__ */ jsx(SwitchPanel, {
|
|
49903
50706
|
trpc,
|
|
49904
|
-
deviceId
|
|
49905
|
-
features
|
|
49906
|
-
|
|
50707
|
+
deviceId,
|
|
50708
|
+
features,
|
|
50709
|
+
layout: "compact",
|
|
50710
|
+
optimistic
|
|
50711
|
+
}), /* @__PURE__ */ jsx(BrightnessPanel, {
|
|
50712
|
+
trpc,
|
|
50713
|
+
deviceId,
|
|
50714
|
+
features,
|
|
50715
|
+
layout: "compact",
|
|
50716
|
+
optimistic
|
|
50717
|
+
})]
|
|
49907
50718
|
});
|
|
49908
50719
|
}
|
|
49909
|
-
|
|
49910
|
-
|
|
49911
|
-
|
|
49912
|
-
|
|
49913
|
-
|
|
49914
|
-
|
|
49915
|
-
disabled,
|
|
49916
|
-
onChange: (e) => {
|
|
49917
|
-
const nextId = Number(e.target.value);
|
|
49918
|
-
if (!Number.isFinite(nextId) || nextId === selectedId) return;
|
|
49919
|
-
const picked = childrenList.find((c) => c.id === nextId);
|
|
49920
|
-
if (picked !== void 0) onSetPrimary(picked.stableId);
|
|
49921
|
-
},
|
|
49922
|
-
className: className === void 0 ? BASE_SELECT_CLASS : `${BASE_SELECT_CLASS} ${className}`,
|
|
49923
|
-
children: childrenList.map((c) => /* @__PURE__ */ jsxs("option", {
|
|
49924
|
-
value: c.id,
|
|
49925
|
-
children: [
|
|
49926
|
-
c.name,
|
|
49927
|
-
" (",
|
|
49928
|
-
c.type,
|
|
49929
|
-
")"
|
|
49930
|
-
]
|
|
49931
|
-
}, c.id))
|
|
50720
|
+
function useFanCapGuard(trpc, deviceId) {
|
|
50721
|
+
const { cap } = useDeviceCapability({
|
|
50722
|
+
trpc,
|
|
50723
|
+
deviceId,
|
|
50724
|
+
cap: (d) => d.fanControl,
|
|
50725
|
+
slice: (d) => d.state.fanControl
|
|
49932
50726
|
});
|
|
50727
|
+
return cap !== void 0;
|
|
49933
50728
|
}
|
|
49934
|
-
|
|
49935
|
-
|
|
49936
|
-
function DeviceBatchToolbar({ selectedIds, onClear, remove, disable, enable }) {
|
|
49937
|
-
const [pendingDelete, setPendingDelete] = useState(false);
|
|
49938
|
-
if (selectedIds.size === 0) return null;
|
|
49939
|
-
const ids = [...selectedIds];
|
|
49940
|
-
const count = ids.length;
|
|
49941
|
-
const handleDisable = () => {
|
|
49942
|
-
for (const id of ids) disable({ deviceId: id });
|
|
49943
|
-
onClear();
|
|
49944
|
-
};
|
|
49945
|
-
const handleEnable = () => {
|
|
49946
|
-
for (const id of ids) enable({ deviceId: id });
|
|
49947
|
-
onClear();
|
|
49948
|
-
};
|
|
49949
|
-
const handleDeleteFirst = () => {
|
|
49950
|
-
setPendingDelete(true);
|
|
49951
|
-
};
|
|
49952
|
-
const handleDeleteConfirm = () => {
|
|
49953
|
-
for (const id of ids) remove({ deviceId: id });
|
|
49954
|
-
setPendingDelete(false);
|
|
49955
|
-
onClear();
|
|
49956
|
-
};
|
|
49957
|
-
const handleDeleteCancel = () => {
|
|
49958
|
-
setPendingDelete(false);
|
|
49959
|
-
};
|
|
49960
|
-
const handleClear = () => {
|
|
49961
|
-
setPendingDelete(false);
|
|
49962
|
-
onClear();
|
|
49963
|
-
};
|
|
50729
|
+
function FanInlineControl({ trpc, deviceId, features, optimistic }) {
|
|
50730
|
+
if (!useFanCapGuard(trpc, deviceId)) return null;
|
|
49964
50731
|
return /* @__PURE__ */ jsxs("div", {
|
|
49965
|
-
className: "flex items-center gap-2
|
|
49966
|
-
children: [
|
|
49967
|
-
|
|
49968
|
-
|
|
49969
|
-
|
|
49970
|
-
|
|
49971
|
-
|
|
49972
|
-
|
|
49973
|
-
|
|
49974
|
-
|
|
49975
|
-
|
|
49976
|
-
|
|
49977
|
-
|
|
49978
|
-
|
|
49979
|
-
type: "button",
|
|
49980
|
-
onClick: handleDisable,
|
|
49981
|
-
className: cn("inline-flex items-center h-6 px-2.5 rounded-md border text-[10.5px] font-medium transition-colors", "border-border bg-surface text-foreground-subtle hover:text-foreground hover:bg-surface"),
|
|
49982
|
-
children: "Disable"
|
|
49983
|
-
}),
|
|
49984
|
-
/* @__PURE__ */ jsx("button", {
|
|
49985
|
-
type: "button",
|
|
49986
|
-
onClick: handleEnable,
|
|
49987
|
-
className: cn("inline-flex items-center h-6 px-2.5 rounded-md border text-[10.5px] font-medium transition-colors", "border-border bg-surface text-foreground-subtle hover:text-foreground hover:bg-surface"),
|
|
49988
|
-
children: "Enable"
|
|
49989
|
-
}),
|
|
49990
|
-
pendingDelete ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("button", {
|
|
49991
|
-
type: "button",
|
|
49992
|
-
onClick: handleDeleteConfirm,
|
|
49993
|
-
className: cn("inline-flex items-center h-6 px-2.5 rounded-md border text-[10.5px] font-medium transition-colors", "border-red-500/50 bg-red-500/10 text-red-400 hover:bg-red-500/20"),
|
|
49994
|
-
children: [
|
|
49995
|
-
"Confirm delete ",
|
|
49996
|
-
count,
|
|
49997
|
-
"?"
|
|
49998
|
-
]
|
|
49999
|
-
}), /* @__PURE__ */ jsx("button", {
|
|
50000
|
-
type: "button",
|
|
50001
|
-
onClick: handleDeleteCancel,
|
|
50002
|
-
className: cn("inline-flex items-center h-6 px-2.5 rounded-md border text-[10.5px] font-medium transition-colors", "border-border bg-surface text-foreground-subtle hover:text-foreground hover:bg-surface"),
|
|
50003
|
-
children: "Cancel"
|
|
50004
|
-
})] }) : /* @__PURE__ */ jsx("button", {
|
|
50005
|
-
type: "button",
|
|
50006
|
-
onClick: handleDeleteFirst,
|
|
50007
|
-
className: cn("inline-flex items-center h-6 px-2.5 rounded-md border text-[10.5px] font-medium transition-colors", "border-red-500/40 bg-red-500/10 text-red-400 hover:bg-red-500/20"),
|
|
50008
|
-
children: "Delete"
|
|
50009
|
-
}),
|
|
50010
|
-
/* @__PURE__ */ jsx("button", {
|
|
50011
|
-
type: "button",
|
|
50012
|
-
onClick: handleClear,
|
|
50013
|
-
className: cn("inline-flex items-center h-6 px-2.5 rounded-md border text-[10.5px] font-medium transition-colors", "border-border bg-surface text-foreground-subtle hover:text-foreground hover:bg-surface"),
|
|
50014
|
-
children: "Clear"
|
|
50015
|
-
})
|
|
50016
|
-
]
|
|
50017
|
-
})
|
|
50018
|
-
]
|
|
50732
|
+
className: "inline-flex items-center gap-2",
|
|
50733
|
+
children: [/* @__PURE__ */ jsx(SwitchPanel, {
|
|
50734
|
+
trpc,
|
|
50735
|
+
deviceId,
|
|
50736
|
+
features,
|
|
50737
|
+
layout: "compact",
|
|
50738
|
+
optimistic
|
|
50739
|
+
}), /* @__PURE__ */ jsx(FanPanel, {
|
|
50740
|
+
trpc,
|
|
50741
|
+
deviceId,
|
|
50742
|
+
features,
|
|
50743
|
+
layout: "compact",
|
|
50744
|
+
optimistic
|
|
50745
|
+
})]
|
|
50019
50746
|
});
|
|
50020
50747
|
}
|
|
50021
|
-
|
|
50022
|
-
|
|
50023
|
-
|
|
50024
|
-
|
|
50025
|
-
|
|
50026
|
-
|
|
50027
|
-
|
|
50028
|
-
|
|
50029
|
-
* hosts the SAME <DeviceBatchToolbar>, so the action logic (inline
|
|
50030
|
-
* delete-confirm, clear) is reused verbatim — never forked.
|
|
50031
|
-
*
|
|
50032
|
-
* Renders nothing while the selection is empty (delegated to the toolbar).
|
|
50033
|
-
*/
|
|
50034
|
-
function DeviceBatchActionsBar(props) {
|
|
50035
|
-
const [open, setOpen] = useState(false);
|
|
50036
|
-
const rootRef = useRef(null);
|
|
50037
|
-
const count = props.selectedIds.size;
|
|
50038
|
-
useEffect(() => {
|
|
50039
|
-
if (!open) return;
|
|
50040
|
-
const onOutside = (e) => {
|
|
50041
|
-
const target = e.target instanceof Node ? e.target : null;
|
|
50042
|
-
if (target && rootRef.current && !rootRef.current.contains(target)) setOpen(false);
|
|
50043
|
-
};
|
|
50044
|
-
const onKey = (e) => {
|
|
50045
|
-
if (e.key === "Escape") setOpen(false);
|
|
50046
|
-
};
|
|
50047
|
-
document.addEventListener("mousedown", onOutside);
|
|
50048
|
-
document.addEventListener("touchstart", onOutside);
|
|
50049
|
-
document.addEventListener("keydown", onKey);
|
|
50050
|
-
return () => {
|
|
50051
|
-
document.removeEventListener("mousedown", onOutside);
|
|
50052
|
-
document.removeEventListener("touchstart", onOutside);
|
|
50053
|
-
document.removeEventListener("keydown", onKey);
|
|
50054
|
-
};
|
|
50055
|
-
}, [open]);
|
|
50056
|
-
if (count === 0) return null;
|
|
50057
|
-
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("div", {
|
|
50058
|
-
className: "hidden sm:block",
|
|
50059
|
-
children: /* @__PURE__ */ jsx(DeviceBatchToolbar, { ...props })
|
|
50060
|
-
}), /* @__PURE__ */ jsxs("div", {
|
|
50061
|
-
ref: rootRef,
|
|
50062
|
-
"data-testid": "batch-actions-compact",
|
|
50063
|
-
className: "relative sm:hidden",
|
|
50064
|
-
children: [/* @__PURE__ */ jsxs("button", {
|
|
50065
|
-
type: "button",
|
|
50066
|
-
onClick: () => setOpen((v) => !v),
|
|
50067
|
-
"aria-haspopup": "menu",
|
|
50068
|
-
"aria-expanded": open,
|
|
50069
|
-
className: "inline-flex items-center gap-1.5 h-7 px-2.5 rounded-full border border-primary/40 bg-primary/15 text-[10.5px] font-medium text-primary",
|
|
50070
|
-
children: [/* @__PURE__ */ jsxs("span", { children: ["Actions · ", String(count)] }), /* @__PURE__ */ jsx(ChevronDown, { className: `h-3 w-3 transition-transform ${open ? "rotate-180" : ""}` })]
|
|
50071
|
-
}), open && /* @__PURE__ */ jsx("div", {
|
|
50072
|
-
role: "menu",
|
|
50073
|
-
className: "absolute left-0 top-full mt-1 z-30 rounded-lg border border-border bg-surface shadow-md",
|
|
50074
|
-
children: /* @__PURE__ */ jsx(DeviceBatchToolbar, { ...props })
|
|
50075
|
-
})]
|
|
50076
|
-
})] });
|
|
50748
|
+
function useClimateCapGuard(trpc, deviceId) {
|
|
50749
|
+
const { cap } = useDeviceCapability({
|
|
50750
|
+
trpc,
|
|
50751
|
+
deviceId,
|
|
50752
|
+
cap: (d) => d.climateControl,
|
|
50753
|
+
slice: (d) => d.state.climateControl
|
|
50754
|
+
});
|
|
50755
|
+
return cap !== void 0;
|
|
50077
50756
|
}
|
|
50078
|
-
|
|
50079
|
-
|
|
50080
|
-
|
|
50081
|
-
|
|
50082
|
-
|
|
50083
|
-
|
|
50084
|
-
|
|
50085
|
-
|
|
50086
|
-
|
|
50087
|
-
|
|
50088
|
-
|
|
50089
|
-
|
|
50090
|
-
|
|
50091
|
-
|
|
50092
|
-
|
|
50093
|
-
|
|
50094
|
-
|
|
50095
|
-
|
|
50096
|
-
}
|
|
50097
|
-
|
|
50098
|
-
|
|
50099
|
-
|
|
50100
|
-
|
|
50101
|
-
|
|
50102
|
-
|
|
50103
|
-
|
|
50104
|
-
|
|
50105
|
-
|
|
50106
|
-
|
|
50107
|
-
|
|
50108
|
-
|
|
50109
|
-
|
|
50110
|
-
|
|
50111
|
-
|
|
50112
|
-
|
|
50113
|
-
|
|
50114
|
-
|
|
50115
|
-
|
|
50116
|
-
|
|
50117
|
-
|
|
50118
|
-
|
|
50119
|
-
|
|
50120
|
-
|
|
50121
|
-
|
|
50122
|
-
|
|
50123
|
-
|
|
50124
|
-
|
|
50125
|
-
|
|
50126
|
-
|
|
50127
|
-
|
|
50128
|
-
}
|
|
50129
|
-
|
|
50130
|
-
|
|
50131
|
-
|
|
50132
|
-
|
|
50133
|
-
|
|
50134
|
-
|
|
50135
|
-
|
|
50136
|
-
|
|
50137
|
-
|
|
50138
|
-
|
|
50139
|
-
|
|
50140
|
-
|
|
50141
|
-
|
|
50142
|
-
|
|
50143
|
-
|
|
50144
|
-
}
|
|
50145
|
-
|
|
50146
|
-
|
|
50147
|
-
|
|
50148
|
-
|
|
50149
|
-
|
|
50150
|
-
|
|
50151
|
-
|
|
50152
|
-
|
|
50153
|
-
|
|
50154
|
-
|
|
50155
|
-
|
|
50156
|
-
|
|
50157
|
-
|
|
50158
|
-
|
|
50159
|
-
|
|
50160
|
-
|
|
50161
|
-
|
|
50162
|
-
|
|
50163
|
-
|
|
50164
|
-
|
|
50165
|
-
|
|
50166
|
-
|
|
50167
|
-
|
|
50168
|
-
|
|
50169
|
-
[DeviceType.AlarmPanel]: {
|
|
50170
|
-
icon: ShieldAlert,
|
|
50171
|
-
label: "Alarm panel"
|
|
50172
|
-
},
|
|
50173
|
-
[DeviceType.Control]: {
|
|
50174
|
-
icon: SlidersHorizontal,
|
|
50175
|
-
label: "Control"
|
|
50176
|
-
},
|
|
50177
|
-
[DeviceType.Presence]: {
|
|
50178
|
-
icon: MapPin,
|
|
50179
|
-
label: "Presence"
|
|
50180
|
-
},
|
|
50181
|
-
[DeviceType.Weather]: {
|
|
50182
|
-
icon: CloudSun,
|
|
50183
|
-
label: "Weather"
|
|
50184
|
-
},
|
|
50185
|
-
[DeviceType.Vacuum]: {
|
|
50186
|
-
icon: Bot,
|
|
50187
|
-
label: "Vacuum"
|
|
50188
|
-
},
|
|
50189
|
-
[DeviceType.LawnMower]: {
|
|
50190
|
-
icon: Tractor,
|
|
50191
|
-
label: "Lawn mower"
|
|
50192
|
-
},
|
|
50193
|
-
[DeviceType.Container]: {
|
|
50194
|
-
icon: Box,
|
|
50195
|
-
label: "Container"
|
|
50196
|
-
},
|
|
50197
|
-
[DeviceType.Image]: {
|
|
50198
|
-
icon: Image,
|
|
50199
|
-
label: "Image"
|
|
50200
|
-
},
|
|
50201
|
-
[DeviceType.PetFeeder]: {
|
|
50202
|
-
icon: Bone,
|
|
50203
|
-
label: "Pet feeder"
|
|
50204
|
-
}
|
|
50205
|
-
};
|
|
50206
|
-
var DEVICE_ROLE_META = {
|
|
50207
|
-
[DeviceRole.Siren]: {
|
|
50208
|
-
icon: Siren,
|
|
50209
|
-
label: "Siren"
|
|
50210
|
-
},
|
|
50211
|
-
[DeviceRole.Floodlight]: {
|
|
50212
|
-
icon: Lightbulb,
|
|
50213
|
-
label: "Floodlight"
|
|
50214
|
-
},
|
|
50215
|
-
[DeviceRole.Spotlight]: {
|
|
50216
|
-
icon: Flashlight,
|
|
50217
|
-
label: "Spotlight"
|
|
50218
|
-
},
|
|
50219
|
-
[DeviceRole.PirSensor]: {
|
|
50220
|
-
icon: Radar,
|
|
50221
|
-
label: "PIR sensor"
|
|
50222
|
-
},
|
|
50223
|
-
[DeviceRole.Chime]: {
|
|
50224
|
-
icon: Bell,
|
|
50225
|
-
label: "Chime"
|
|
50226
|
-
},
|
|
50227
|
-
[DeviceRole.Autotrack]: {
|
|
50228
|
-
icon: Crosshair,
|
|
50229
|
-
label: "Auto-track"
|
|
50230
|
-
},
|
|
50231
|
-
[DeviceRole.Nightvision]: {
|
|
50232
|
-
icon: Moon,
|
|
50233
|
-
label: "Night vision"
|
|
50234
|
-
},
|
|
50235
|
-
[DeviceRole.PrivacyMask]: {
|
|
50236
|
-
icon: EyeOff,
|
|
50237
|
-
label: "Privacy mask"
|
|
50238
|
-
},
|
|
50239
|
-
[DeviceRole.Doorbell]: {
|
|
50240
|
-
icon: DoorClosed,
|
|
50241
|
-
label: "Doorbell"
|
|
50242
|
-
},
|
|
50243
|
-
[DeviceRole.BinaryHelper]: {
|
|
50244
|
-
icon: ToggleLeft,
|
|
50245
|
-
label: "Binary helper"
|
|
50246
|
-
},
|
|
50247
|
-
[DeviceRole.MotionSensor]: {
|
|
50248
|
-
icon: Footprints,
|
|
50249
|
-
label: "Motion sensor"
|
|
50250
|
-
},
|
|
50251
|
-
[DeviceRole.ContactSensor]: {
|
|
50252
|
-
icon: DoorOpen,
|
|
50253
|
-
label: "Contact sensor"
|
|
50254
|
-
},
|
|
50255
|
-
[DeviceRole.LeakSensor]: {
|
|
50256
|
-
icon: Droplet,
|
|
50257
|
-
label: "Leak sensor"
|
|
50258
|
-
},
|
|
50259
|
-
[DeviceRole.SmokeSensor]: {
|
|
50260
|
-
icon: AlarmSmoke,
|
|
50261
|
-
label: "Smoke sensor"
|
|
50262
|
-
},
|
|
50263
|
-
[DeviceRole.COSensor]: {
|
|
50264
|
-
icon: Wind,
|
|
50265
|
-
label: "CO sensor"
|
|
50266
|
-
},
|
|
50267
|
-
[DeviceRole.GasSensor]: {
|
|
50268
|
-
icon: Flame,
|
|
50269
|
-
label: "Gas sensor"
|
|
50270
|
-
},
|
|
50271
|
-
[DeviceRole.TamperSensor]: {
|
|
50272
|
-
icon: ShieldAlert,
|
|
50273
|
-
label: "Tamper sensor"
|
|
50274
|
-
},
|
|
50275
|
-
[DeviceRole.VibrationSensor]: {
|
|
50276
|
-
icon: Vibrate,
|
|
50277
|
-
label: "Vibration sensor"
|
|
50278
|
-
},
|
|
50279
|
-
[DeviceRole.ConnectivitySensor]: {
|
|
50280
|
-
icon: Wifi,
|
|
50281
|
-
label: "Connectivity"
|
|
50282
|
-
},
|
|
50283
|
-
[DeviceRole.SoundSensor]: {
|
|
50284
|
-
icon: Volume2,
|
|
50285
|
-
label: "Sound sensor"
|
|
50286
|
-
},
|
|
50287
|
-
[DeviceRole.BinarySensor]: {
|
|
50288
|
-
icon: ToggleLeft,
|
|
50289
|
-
label: "Binary sensor"
|
|
50290
|
-
},
|
|
50291
|
-
[DeviceRole.TemperatureSensor]: {
|
|
50292
|
-
icon: Thermometer,
|
|
50293
|
-
label: "Temperature"
|
|
50294
|
-
},
|
|
50295
|
-
[DeviceRole.HumiditySensor]: {
|
|
50296
|
-
icon: Droplets,
|
|
50297
|
-
label: "Humidity"
|
|
50298
|
-
},
|
|
50299
|
-
[DeviceRole.AmbientLightSensor]: {
|
|
50300
|
-
icon: Sun,
|
|
50301
|
-
label: "Ambient light"
|
|
50302
|
-
},
|
|
50303
|
-
[DeviceRole.PressureSensor]: {
|
|
50304
|
-
icon: Gauge,
|
|
50305
|
-
label: "Pressure"
|
|
50757
|
+
function ThermostatInlineControl({ trpc, deviceId, features, optimistic }) {
|
|
50758
|
+
if (!useClimateCapGuard(trpc, deviceId)) return null;
|
|
50759
|
+
return /* @__PURE__ */ jsx(ClimatePanel, {
|
|
50760
|
+
trpc,
|
|
50761
|
+
deviceId,
|
|
50762
|
+
features,
|
|
50763
|
+
layout: "compact",
|
|
50764
|
+
optimistic
|
|
50765
|
+
});
|
|
50766
|
+
}
|
|
50767
|
+
function AcInlineControl({ trpc, deviceId, features, optimistic }) {
|
|
50768
|
+
if (!useClimateCapGuard(trpc, deviceId)) return null;
|
|
50769
|
+
return /* @__PURE__ */ jsx(AcPanel, {
|
|
50770
|
+
trpc,
|
|
50771
|
+
deviceId,
|
|
50772
|
+
features,
|
|
50773
|
+
layout: "compact",
|
|
50774
|
+
optimistic
|
|
50775
|
+
});
|
|
50776
|
+
}
|
|
50777
|
+
function AcHeroCard({ trpc, deviceId, features, optimistic }) {
|
|
50778
|
+
if (!useClimateCapGuard(trpc, deviceId)) return null;
|
|
50779
|
+
return /* @__PURE__ */ jsx(AcPanel, {
|
|
50780
|
+
trpc,
|
|
50781
|
+
deviceId,
|
|
50782
|
+
features,
|
|
50783
|
+
layout: "full",
|
|
50784
|
+
optimistic
|
|
50785
|
+
});
|
|
50786
|
+
}
|
|
50787
|
+
function useMediaPlayerCapGuard(trpc, deviceId) {
|
|
50788
|
+
const { cap } = useDeviceCapability({
|
|
50789
|
+
trpc,
|
|
50790
|
+
deviceId,
|
|
50791
|
+
cap: (d) => d.mediaPlayer,
|
|
50792
|
+
slice: (d) => d.state.mediaPlayer
|
|
50793
|
+
});
|
|
50794
|
+
return cap !== void 0;
|
|
50795
|
+
}
|
|
50796
|
+
function MediaPlayerInlineControl({ trpc, deviceId, features, optimistic }) {
|
|
50797
|
+
if (!useMediaPlayerCapGuard(trpc, deviceId)) return null;
|
|
50798
|
+
return /* @__PURE__ */ jsx(MediaPlayerPanel, {
|
|
50799
|
+
trpc,
|
|
50800
|
+
deviceId,
|
|
50801
|
+
features,
|
|
50802
|
+
layout: "compact",
|
|
50803
|
+
optimistic
|
|
50804
|
+
});
|
|
50805
|
+
}
|
|
50806
|
+
function useControlCapGuard(trpc, deviceId) {
|
|
50807
|
+
const { cap } = useDeviceCapability({
|
|
50808
|
+
trpc,
|
|
50809
|
+
deviceId,
|
|
50810
|
+
cap: (d) => d.control,
|
|
50811
|
+
slice: (d) => d.state.control
|
|
50812
|
+
});
|
|
50813
|
+
return cap !== void 0;
|
|
50814
|
+
}
|
|
50815
|
+
function ControlInlineControl({ trpc, deviceId, features, optimistic }) {
|
|
50816
|
+
if (!useControlCapGuard(trpc, deviceId)) return null;
|
|
50817
|
+
return /* @__PURE__ */ jsx(ControlPanel, {
|
|
50818
|
+
trpc,
|
|
50819
|
+
deviceId,
|
|
50820
|
+
features,
|
|
50821
|
+
layout: "compact",
|
|
50822
|
+
optimistic
|
|
50823
|
+
});
|
|
50824
|
+
}
|
|
50825
|
+
function ControlHeroCard({ trpc, deviceId, features, optimistic }) {
|
|
50826
|
+
if (!useControlCapGuard(trpc, deviceId)) return null;
|
|
50827
|
+
return /* @__PURE__ */ jsx(HeroShell, { children: /* @__PURE__ */ jsx(ControlPanel, {
|
|
50828
|
+
trpc,
|
|
50829
|
+
deviceId,
|
|
50830
|
+
features,
|
|
50831
|
+
layout: "full",
|
|
50832
|
+
optimistic
|
|
50833
|
+
}) });
|
|
50834
|
+
}
|
|
50835
|
+
//#endregion
|
|
50836
|
+
//#region src/composites/device-controls/control-registry.tsx
|
|
50837
|
+
/**
|
|
50838
|
+
* Presentation binding: the shared `DeviceControlKind` (decided in
|
|
50839
|
+
* `@camstack/types` `resolveDeviceControlKind`) → this platform's web
|
|
50840
|
+
* components. Exhaustive over `DeviceControlKind` — omitting a kind fails the
|
|
50841
|
+
* build here. The type→kind DECISION is single-sourced in `@camstack/types`;
|
|
50842
|
+
* this map only binds a kind to its web widgets.
|
|
50843
|
+
*/
|
|
50844
|
+
var CONTROL_KIND_COMPONENTS = {
|
|
50845
|
+
cover: {
|
|
50846
|
+
InlineControl: CoverInlineControl,
|
|
50847
|
+
HeroCard: CoverHeroCard
|
|
50306
50848
|
},
|
|
50307
|
-
|
|
50308
|
-
|
|
50309
|
-
|
|
50849
|
+
valve: {
|
|
50850
|
+
InlineControl: ValveInlineControl,
|
|
50851
|
+
HeroCard: ValveHeroCard
|
|
50310
50852
|
},
|
|
50311
|
-
|
|
50312
|
-
|
|
50313
|
-
|
|
50853
|
+
humidifier: {
|
|
50854
|
+
InlineControl: HumidifierInlineControl,
|
|
50855
|
+
HeroCard: HumidifierHeroCard
|
|
50314
50856
|
},
|
|
50315
|
-
|
|
50316
|
-
|
|
50317
|
-
|
|
50857
|
+
"water-heater": {
|
|
50858
|
+
InlineControl: WaterHeaterInlineControl,
|
|
50859
|
+
HeroCard: WaterHeaterHeroCard
|
|
50318
50860
|
},
|
|
50319
|
-
|
|
50320
|
-
|
|
50321
|
-
|
|
50861
|
+
switch: {
|
|
50862
|
+
InlineControl: SwitchInlineControl,
|
|
50863
|
+
HeroCard: SwitchHeroCard
|
|
50322
50864
|
},
|
|
50323
|
-
|
|
50324
|
-
|
|
50325
|
-
|
|
50865
|
+
light: {
|
|
50866
|
+
InlineControl: LightInlineControl,
|
|
50867
|
+
HeroCard: LightHeroCard
|
|
50326
50868
|
},
|
|
50327
|
-
|
|
50328
|
-
|
|
50329
|
-
|
|
50869
|
+
fan: {
|
|
50870
|
+
InlineControl: FanInlineControl,
|
|
50871
|
+
HeroCard: FanHeroCard
|
|
50330
50872
|
},
|
|
50331
|
-
|
|
50332
|
-
|
|
50333
|
-
|
|
50873
|
+
sensor: {
|
|
50874
|
+
InlineControl: SensorInlineControl,
|
|
50875
|
+
HeroCard: SensorHeroCard
|
|
50334
50876
|
},
|
|
50335
|
-
|
|
50336
|
-
|
|
50337
|
-
|
|
50877
|
+
thermostat: {
|
|
50878
|
+
InlineControl: ThermostatInlineControl,
|
|
50879
|
+
HeroCard: ThermostatHeroCard
|
|
50338
50880
|
},
|
|
50339
|
-
|
|
50340
|
-
|
|
50341
|
-
|
|
50881
|
+
climate: {
|
|
50882
|
+
InlineControl: AcInlineControl,
|
|
50883
|
+
HeroCard: AcHeroCard
|
|
50342
50884
|
},
|
|
50343
|
-
|
|
50344
|
-
|
|
50345
|
-
|
|
50885
|
+
button: {
|
|
50886
|
+
InlineControl: ButtonControl,
|
|
50887
|
+
HeroCard: ButtonHeroCard
|
|
50346
50888
|
},
|
|
50347
|
-
|
|
50348
|
-
|
|
50349
|
-
|
|
50889
|
+
update: {
|
|
50890
|
+
InlineControl: UpdateInlineControl,
|
|
50891
|
+
HeroCard: UpdateHeroCard
|
|
50350
50892
|
},
|
|
50351
|
-
|
|
50352
|
-
|
|
50353
|
-
|
|
50893
|
+
lock: {
|
|
50894
|
+
InlineControl: LockInlineControl,
|
|
50895
|
+
HeroCard: LockHeroCard
|
|
50354
50896
|
},
|
|
50355
|
-
|
|
50356
|
-
|
|
50357
|
-
|
|
50897
|
+
"media-player": {
|
|
50898
|
+
InlineControl: MediaPlayerInlineControl,
|
|
50899
|
+
HeroCard: MediaPlayerHeroCard
|
|
50358
50900
|
},
|
|
50359
|
-
|
|
50360
|
-
|
|
50361
|
-
|
|
50901
|
+
alarm: {
|
|
50902
|
+
InlineControl: AlarmInlineControl,
|
|
50903
|
+
HeroCard: AlarmHeroCard
|
|
50362
50904
|
},
|
|
50363
|
-
|
|
50364
|
-
|
|
50365
|
-
|
|
50905
|
+
control: {
|
|
50906
|
+
InlineControl: ControlInlineControl,
|
|
50907
|
+
HeroCard: ControlHeroCard
|
|
50366
50908
|
},
|
|
50367
|
-
|
|
50368
|
-
|
|
50369
|
-
|
|
50909
|
+
weather: {
|
|
50910
|
+
InlineControl: WeatherInlineControl,
|
|
50911
|
+
HeroCard: WeatherHeroCard
|
|
50370
50912
|
},
|
|
50371
|
-
|
|
50372
|
-
|
|
50373
|
-
|
|
50913
|
+
vacuum: {
|
|
50914
|
+
InlineControl: VacuumInlineControl,
|
|
50915
|
+
HeroCard: VacuumHeroCard
|
|
50374
50916
|
},
|
|
50375
|
-
|
|
50376
|
-
|
|
50377
|
-
|
|
50917
|
+
"lawn-mower": {
|
|
50918
|
+
InlineControl: LawnMowerInlineControl,
|
|
50919
|
+
HeroCard: LawnMowerHeroCard
|
|
50378
50920
|
},
|
|
50379
|
-
|
|
50380
|
-
|
|
50381
|
-
|
|
50921
|
+
image: {
|
|
50922
|
+
InlineControl: ImageInlineControl,
|
|
50923
|
+
HeroCard: ImageHeroCard
|
|
50382
50924
|
},
|
|
50383
|
-
|
|
50384
|
-
|
|
50385
|
-
|
|
50925
|
+
"pet-feeder": {
|
|
50926
|
+
InlineControl: PetFeederInlineControl,
|
|
50927
|
+
HeroCard: PetFeederHeroCard
|
|
50386
50928
|
},
|
|
50387
|
-
|
|
50388
|
-
|
|
50389
|
-
|
|
50929
|
+
script: {
|
|
50930
|
+
InlineControl: ScriptInlineControl,
|
|
50931
|
+
HeroCard: ScriptHeroCard
|
|
50390
50932
|
},
|
|
50391
|
-
|
|
50392
|
-
|
|
50393
|
-
|
|
50933
|
+
automation: {
|
|
50934
|
+
InlineControl: AutomationInlineControl,
|
|
50935
|
+
HeroCard: AutomationHeroCard
|
|
50394
50936
|
},
|
|
50395
|
-
|
|
50396
|
-
|
|
50397
|
-
|
|
50937
|
+
dummy: {
|
|
50938
|
+
InlineControl: DummyInline,
|
|
50939
|
+
HeroCard: DummyHeroCard
|
|
50398
50940
|
}
|
|
50399
50941
|
};
|
|
50942
|
+
/**
|
|
50943
|
+
* Exhaustive record over DeviceType, DERIVED from the shared decision
|
|
50944
|
+
* (`DEVICE_TYPE_CONTROL_KIND`) composed with the web `CONTROL_KIND_COMPONENTS`
|
|
50945
|
+
* binding — so the type→control mapping can never diverge from the single
|
|
50946
|
+
* source in `@camstack/types`. Preserved as a public export for consumers/tests
|
|
50947
|
+
* that index it by `DeviceType`.
|
|
50948
|
+
*
|
|
50949
|
+
* The `Object.fromEntries` result is a `{ [k: string]: DeviceTypeControl }`;
|
|
50950
|
+
* `Object.values(DeviceType)` (a string enum) yields exactly the enum's members,
|
|
50951
|
+
* so the record is fully populated — the assertion narrows that documented
|
|
50952
|
+
* enum-record projection boundary.
|
|
50953
|
+
*/
|
|
50954
|
+
var DEVICE_TYPE_CONTROL = Object.fromEntries(Object.values(DeviceType).map((type) => [type, CONTROL_KIND_COMPONENTS[DEVICE_TYPE_CONTROL_KIND[type]]]));
|
|
50955
|
+
/**
|
|
50956
|
+
* Per-type FILL flag.
|
|
50957
|
+
*
|
|
50958
|
+
* true — range / choice / button controls (cover ▲■▼ triad, thermostat
|
|
50959
|
+
* setpoint stepper, media/control/button action buttons, alarm
|
|
50960
|
+
* segmented control). The child STRETCHES to the full column width.
|
|
50961
|
+
* false — readouts, tap-toggles, icon controls (lock), and dummy/placeholder
|
|
50962
|
+
* types. The child keeps its NATURAL width; where it sits in the
|
|
50963
|
+
* column (flush right vs centered) is decided by the caller via a
|
|
50964
|
+
* `ControlPlacement` — see `resolveControlAlign`.
|
|
50965
|
+
*
|
|
50966
|
+
* Dummy types (Camera, Hub, Generic, Weather, Vacuum, Container, and placeholder
|
|
50967
|
+
* types Notifier/Script/Automation whose InlineControl renders "—") are `false` —
|
|
50968
|
+
* the dash placeholder must not be stretched to the full column width. (AlarmPanel
|
|
50969
|
+
* has a real segmented inline control and is `true`.) When a later task gives a
|
|
50970
|
+
* remaining placeholder type a real stretchy inline control, flip its flag to true.
|
|
50971
|
+
*
|
|
50972
|
+
* Exhaustive over DeviceType — a missing member is a TypeScript build error.
|
|
50973
|
+
*/
|
|
50974
|
+
var CONTROL_FILLS = {
|
|
50975
|
+
[DeviceType.Cover]: true,
|
|
50976
|
+
[DeviceType.Valve]: true,
|
|
50977
|
+
[DeviceType.Thermostat]: true,
|
|
50978
|
+
[DeviceType.Climate]: true,
|
|
50979
|
+
[DeviceType.Control]: true,
|
|
50980
|
+
[DeviceType.Button]: true,
|
|
50981
|
+
[DeviceType.MediaPlayer]: true,
|
|
50982
|
+
[DeviceType.AlarmPanel]: true,
|
|
50983
|
+
[DeviceType.Lock]: false,
|
|
50984
|
+
[DeviceType.Vacuum]: false,
|
|
50985
|
+
[DeviceType.LawnMower]: false,
|
|
50986
|
+
[DeviceType.Humidifier]: false,
|
|
50987
|
+
[DeviceType.Switch]: false,
|
|
50988
|
+
[DeviceType.Siren]: false,
|
|
50989
|
+
[DeviceType.Light]: false,
|
|
50990
|
+
[DeviceType.Fan]: false,
|
|
50991
|
+
[DeviceType.WaterHeater]: false,
|
|
50992
|
+
[DeviceType.Sensor]: false,
|
|
50993
|
+
[DeviceType.Presence]: false,
|
|
50994
|
+
[DeviceType.EventEmitter]: false,
|
|
50995
|
+
[DeviceType.Notifier]: false,
|
|
50996
|
+
[DeviceType.Script]: false,
|
|
50997
|
+
[DeviceType.Automation]: false,
|
|
50998
|
+
[DeviceType.Camera]: false,
|
|
50999
|
+
[DeviceType.Hub]: false,
|
|
51000
|
+
[DeviceType.Update]: false,
|
|
51001
|
+
[DeviceType.Generic]: false,
|
|
51002
|
+
[DeviceType.Weather]: false,
|
|
51003
|
+
[DeviceType.Container]: false,
|
|
51004
|
+
[DeviceType.Image]: false,
|
|
51005
|
+
[DeviceType.PetFeeder]: false
|
|
51006
|
+
};
|
|
50400
51007
|
var DEVICE_TYPE_VALUES = new Set(Object.values(DeviceType));
|
|
50401
|
-
|
|
50402
|
-
|
|
50403
|
-
|
|
50404
|
-
|
|
50405
|
-
|
|
50406
|
-
|
|
50407
|
-
|
|
50408
|
-
|
|
50409
|
-
|
|
50410
|
-
return DEVICE_TYPE_META[type];
|
|
50411
|
-
}
|
|
50412
|
-
/** Meta for a known `DeviceRole`. */
|
|
50413
|
-
function deviceRoleMeta(role) {
|
|
50414
|
-
return DEVICE_ROLE_META[role];
|
|
51008
|
+
/**
|
|
51009
|
+
* Runtime-string-safe lookup: a device row's `type` crosses the wire as a plain
|
|
51010
|
+
* string. The type→control-kind DECISION is single-sourced in `@camstack/types`
|
|
51011
|
+
* (`resolveDeviceControlKind`, null for an unrecognised type); this maps the
|
|
51012
|
+
* resolved kind onto the web components.
|
|
51013
|
+
*/
|
|
51014
|
+
function resolveDeviceControl(type) {
|
|
51015
|
+
const kind = resolveDeviceControlKind(type);
|
|
51016
|
+
return kind ? CONTROL_KIND_COMPONENTS[kind] : null;
|
|
50415
51017
|
}
|
|
50416
|
-
var FALLBACK_DEVICE_TYPE_META = DEVICE_TYPE_META[DeviceType.Generic];
|
|
50417
|
-
var FALLBACK_DEVICE_ROLE_META = DEVICE_ROLE_META[DeviceRole.GenericSensor];
|
|
50418
51018
|
/**
|
|
50419
|
-
* Runtime-string-safe lookup
|
|
50420
|
-
* as plain strings, so an unrecognised value falls back to the `Generic` meta
|
|
50421
|
-
* instead of throwing.
|
|
51019
|
+
* Runtime-string-safe alignment lookup for the fixed-width control column.
|
|
50422
51020
|
*
|
|
50423
|
-
*
|
|
50424
|
-
*
|
|
50425
|
-
*
|
|
51021
|
+
* A device's `type` crosses the wire as a plain string;
|
|
51022
|
+
* `DEVICE_TYPE_VALUES.has(type)` narrows it to `DeviceType` before indexing
|
|
51023
|
+
* `CONTROL_FILLS`, making the cast sound. The `'table'` placement is
|
|
51024
|
+
* content-width for EVERY type (returns `FIT`), so a wide control never
|
|
51025
|
+
* overflows a fixed box — the FILL flag is irrelevant there. For the fixed-box
|
|
51026
|
+
* placements a FILL type always stretches (`FILL`) and a natural-width type is
|
|
51027
|
+
* placed by the caller's `placement` — `'center'` → `CENTER`, `'right'` →
|
|
51028
|
+
* `RIGHT` (card / minimal view). An unrecognised type falls back to
|
|
51029
|
+
* natural-width placement.
|
|
50426
51030
|
*/
|
|
50427
|
-
function
|
|
50428
|
-
if (
|
|
50429
|
-
return
|
|
50430
|
-
}
|
|
50431
|
-
/** Runtime-string-safe role lookup; unknown roles fall back to `GenericSensor`. */
|
|
50432
|
-
function deviceRoleMetaOf(role) {
|
|
50433
|
-
if (!isDeviceRole(role)) return FALLBACK_DEVICE_ROLE_META;
|
|
50434
|
-
return DEVICE_ROLE_META[role] ?? FALLBACK_DEVICE_ROLE_META;
|
|
51031
|
+
function resolveControlAlign(type, placement) {
|
|
51032
|
+
if (placement === "table") return "fit";
|
|
51033
|
+
return DEVICE_TYPE_VALUES.has(type) && CONTROL_FILLS[type] ? FILL : placement === "center" ? CENTER : RIGHT;
|
|
50435
51034
|
}
|
|
51035
|
+
//#endregion
|
|
51036
|
+
//#region src/lib/format-last-seen.ts
|
|
50436
51037
|
/**
|
|
50437
|
-
*
|
|
50438
|
-
* a per-role default), keyed by a stable kebab-case name. Named imports only —
|
|
50439
|
-
* no dynamic indexing into lucide, so the bundle carries exactly this set.
|
|
50440
|
-
* Unknown keys resolve to `undefined` (caller falls through to the next level).
|
|
51038
|
+
* Relative "last seen" formatter for the offline affordance.
|
|
50441
51039
|
*
|
|
50442
|
-
*
|
|
50443
|
-
*
|
|
50444
|
-
*
|
|
50445
|
-
*
|
|
50446
|
-
*
|
|
50447
|
-
*
|
|
51040
|
+
* Renders a short relative-time label from a millisecond epoch:
|
|
51041
|
+
* "just now", "5m ago", "3h ago", "2d ago". Returns `null` for missing
|
|
51042
|
+
* inputs, or inputs below {@link MIN_PLAUSIBLE_TIMESTAMP_MS} (a
|
|
51043
|
+
* placeholder or a seeded "known value, unknown change time" stamp), so
|
|
51044
|
+
* callers can render nothing rather than a misleading "—", "NaN ago", or
|
|
51045
|
+
* (for a seeded `1`) "20000 days ago".
|
|
50448
51046
|
*
|
|
50449
|
-
*
|
|
50450
|
-
*
|
|
50451
|
-
* is a legacy alias kept for rows that persisted it.
|
|
51047
|
+
* Future timestamps (clock skew between the device and the browser)
|
|
51048
|
+
* collapse to "just now" instead of a negative duration.
|
|
50452
51049
|
*/
|
|
50453
|
-
var
|
|
50454
|
-
|
|
50455
|
-
|
|
50456
|
-
|
|
50457
|
-
|
|
50458
|
-
|
|
50459
|
-
|
|
50460
|
-
|
|
50461
|
-
|
|
50462
|
-
|
|
50463
|
-
|
|
50464
|
-
|
|
50465
|
-
|
|
50466
|
-
|
|
50467
|
-
|
|
50468
|
-
"
|
|
50469
|
-
|
|
50470
|
-
|
|
50471
|
-
|
|
50472
|
-
|
|
50473
|
-
|
|
50474
|
-
|
|
50475
|
-
|
|
50476
|
-
|
|
50477
|
-
|
|
50478
|
-
|
|
50479
|
-
|
|
50480
|
-
|
|
50481
|
-
|
|
50482
|
-
|
|
50483
|
-
|
|
50484
|
-
|
|
50485
|
-
|
|
50486
|
-
|
|
50487
|
-
|
|
50488
|
-
|
|
50489
|
-
|
|
50490
|
-
|
|
50491
|
-
|
|
50492
|
-
cpu: Cpu,
|
|
50493
|
-
"hard-drive": HardDrive,
|
|
50494
|
-
server: Server,
|
|
50495
|
-
mic: Mic,
|
|
50496
|
-
"mic-off": MicOff,
|
|
50497
|
-
video: Video,
|
|
50498
|
-
"video-off": VideoOff,
|
|
50499
|
-
music: Music,
|
|
50500
|
-
plug: Plug,
|
|
50501
|
-
"plug-zap": PlugZap,
|
|
50502
|
-
power: Power,
|
|
50503
|
-
"power-off": PowerOff,
|
|
50504
|
-
cable: Cable,
|
|
50505
|
-
battery: Battery,
|
|
50506
|
-
"battery-charging": BatteryCharging,
|
|
50507
|
-
"battery-full": BatteryFull,
|
|
50508
|
-
"battery-low": BatteryLow,
|
|
50509
|
-
key: Key,
|
|
50510
|
-
"key-round": KeyRound,
|
|
50511
|
-
mailbox: Mailbox,
|
|
50512
|
-
package: Package,
|
|
50513
|
-
shield: Shield,
|
|
50514
|
-
"shield-check": ShieldCheck,
|
|
50515
|
-
"shield-off": ShieldOff,
|
|
50516
|
-
lightbulb: Lightbulb,
|
|
50517
|
-
lamp: Lamp,
|
|
50518
|
-
"lamp-ceiling": LampCeiling,
|
|
50519
|
-
"lamp-desk": LampDesk,
|
|
50520
|
-
"lamp-floor": LampFloor,
|
|
50521
|
-
flashlight: Flashlight,
|
|
50522
|
-
heater: Heater,
|
|
50523
|
-
snowflake: Snowflake,
|
|
50524
|
-
"thermometer-sun": ThermometerSun,
|
|
50525
|
-
"thermometer-snowflake": ThermometerSnowflake,
|
|
50526
|
-
refrigerator: Refrigerator,
|
|
50527
|
-
microwave: Microwave,
|
|
50528
|
-
"washing-machine": WashingMachine,
|
|
50529
|
-
"cooking-pot": CookingPot,
|
|
50530
|
-
utensils: Utensils,
|
|
50531
|
-
thermometer: Thermometer,
|
|
50532
|
-
droplets: Droplets,
|
|
50533
|
-
droplet: Droplet,
|
|
50534
|
-
gauge: Gauge,
|
|
50535
|
-
gauge2: Gauge,
|
|
50536
|
-
sun: Sun,
|
|
50537
|
-
"sun-medium": SunMedium,
|
|
50538
|
-
sunrise: Sunrise,
|
|
50539
|
-
moon: Moon,
|
|
50540
|
-
wind: Wind,
|
|
50541
|
-
cloud: Cloud,
|
|
50542
|
-
"cloud-rain": CloudRain,
|
|
50543
|
-
"cloud-sun": CloudSun,
|
|
50544
|
-
waves: Waves,
|
|
50545
|
-
sprout: Sprout,
|
|
50546
|
-
leaf: Leaf,
|
|
50547
|
-
flower: Flower,
|
|
50548
|
-
zap: Zap,
|
|
50549
|
-
flame: Flame,
|
|
50550
|
-
bell: Bell,
|
|
50551
|
-
"bell-ring": BellRing,
|
|
50552
|
-
"bell-off": BellOff,
|
|
50553
|
-
siren: Siren,
|
|
50554
|
-
radar: Radar,
|
|
50555
|
-
activity: Activity,
|
|
50556
|
-
hash: Hash,
|
|
50557
|
-
clock: Clock,
|
|
50558
|
-
timer: Timer,
|
|
50559
|
-
calendar: Calendar,
|
|
50560
|
-
pipette: Pipette,
|
|
50561
|
-
fan: Fan,
|
|
50562
|
-
bath: Bath,
|
|
50563
|
-
footprints: Footprints,
|
|
50564
|
-
"alarm-smoke": AlarmSmoke,
|
|
50565
|
-
"shield-alert": ShieldAlert,
|
|
50566
|
-
vibrate: Vibrate,
|
|
50567
|
-
wifi: Wifi,
|
|
50568
|
-
"wifi-off": WifiOff,
|
|
50569
|
-
"volume-2": Volume2,
|
|
50570
|
-
"volume-x": VolumeX,
|
|
50571
|
-
heart: Heart,
|
|
50572
|
-
"heart-pulse": HeartPulse,
|
|
50573
|
-
star: Star,
|
|
50574
|
-
sparkles: Sparkles,
|
|
50575
|
-
house: House,
|
|
50576
|
-
sofa: Sofa,
|
|
50577
|
-
"bed-double": BedDouble,
|
|
50578
|
-
bed: Bed,
|
|
50579
|
-
warehouse: Warehouse,
|
|
50580
|
-
trees: Trees,
|
|
50581
|
-
"tree-pine": TreePine,
|
|
50582
|
-
fence: Fence,
|
|
50583
|
-
store: Store,
|
|
50584
|
-
building: Building,
|
|
50585
|
-
"building-2": Building2,
|
|
50586
|
-
mountain: Mountain,
|
|
50587
|
-
umbrella: Umbrella,
|
|
50588
|
-
dumbbell: Dumbbell,
|
|
50589
|
-
wrench: Wrench,
|
|
50590
|
-
hammer: Hammer,
|
|
50591
|
-
drill: Drill,
|
|
50592
|
-
"waves-ladder": WavesLadder,
|
|
50593
|
-
"circle-parking": CircleParking,
|
|
50594
|
-
briefcase: Briefcase,
|
|
50595
|
-
route: Route,
|
|
50596
|
-
car: Car,
|
|
50597
|
-
bike: Bike,
|
|
50598
|
-
bus: Bus,
|
|
50599
|
-
truck: Truck,
|
|
50600
|
-
plane: Plane,
|
|
50601
|
-
"train-front": TrainFront,
|
|
50602
|
-
sailboat: Sailboat,
|
|
50603
|
-
dog: Dog,
|
|
50604
|
-
cat: Cat,
|
|
50605
|
-
bird: Bird,
|
|
50606
|
-
"paw-print": PawPrint,
|
|
50607
|
-
baby: Baby,
|
|
50608
|
-
user: User,
|
|
50609
|
-
users: Users,
|
|
50610
|
-
"person-standing": PersonStanding
|
|
50611
|
-
};
|
|
50612
|
-
/** Resolve a `display.icon` name to a lucide component, or `undefined` when the
|
|
50613
|
-
* name is not in the curated `DISPLAY_ICON_REGISTRY`. */
|
|
50614
|
-
function resolveDisplayIcon(name) {
|
|
50615
|
-
return Object.hasOwn(DISPLAY_ICON_REGISTRY, name) ? DISPLAY_ICON_REGISTRY[name] : void 0;
|
|
51050
|
+
var SECOND_MS = 1e3;
|
|
51051
|
+
var MINUTE_MS = 60 * SECOND_MS;
|
|
51052
|
+
var HOUR_MS = 60 * MINUTE_MS;
|
|
51053
|
+
var DAY_MS = 24 * HOUR_MS;
|
|
51054
|
+
var JUST_NOW_MS = 30 * SECOND_MS;
|
|
51055
|
+
/**
|
|
51056
|
+
* The earliest timestamp a real "last seen" could plausibly carry. Below
|
|
51057
|
+
* this, a value is a placeholder or a seeded "known value, unknown change
|
|
51058
|
+
* time" stamp (e.g. Homematic's `HM_SEEDED_CHANGED_AT = 1`) — never a real
|
|
51059
|
+
* instant. Year 2000 predates every device this renders.
|
|
51060
|
+
*/
|
|
51061
|
+
var MIN_PLAUSIBLE_TIMESTAMP_MS = Date.UTC(2e3, 0, 1);
|
|
51062
|
+
function formatLastSeen(timestampMs) {
|
|
51063
|
+
if (timestampMs === null || timestampMs === void 0 || timestampMs < MIN_PLAUSIBLE_TIMESTAMP_MS) return null;
|
|
51064
|
+
const delta = Date.now() - timestampMs;
|
|
51065
|
+
if (delta < JUST_NOW_MS) return "just now";
|
|
51066
|
+
if (delta < HOUR_MS) return `${String(Math.floor(delta / MINUTE_MS))}m ago`;
|
|
51067
|
+
if (delta < DAY_MS) return `${String(Math.floor(delta / HOUR_MS))}h ago`;
|
|
51068
|
+
return `${String(Math.floor(delta / DAY_MS))}d ago`;
|
|
51069
|
+
}
|
|
51070
|
+
//#endregion
|
|
51071
|
+
//#region src/composites/device-controls/offline-badge.tsx
|
|
51072
|
+
function OfflineBadge({ lastChangedAt, className }) {
|
|
51073
|
+
const lastSeen = formatLastSeen(lastChangedAt);
|
|
51074
|
+
return /* @__PURE__ */ jsxs("span", {
|
|
51075
|
+
title: lastSeen === null ? "Unavailable" : `Unavailable · last seen ${lastSeen}`,
|
|
51076
|
+
className: cn("inline-flex items-center gap-1 rounded-full px-2 py-0.5", "bg-surface-hover text-foreground-subtle text-[10px] font-medium", "border border-border", className),
|
|
51077
|
+
children: [
|
|
51078
|
+
/* @__PURE__ */ jsx(WifiOff, {
|
|
51079
|
+
className: "h-3 w-3 flex-shrink-0",
|
|
51080
|
+
"aria-hidden": "true"
|
|
51081
|
+
}),
|
|
51082
|
+
/* @__PURE__ */ jsx("span", { children: "Unavailable" }),
|
|
51083
|
+
lastSeen !== null ? /* @__PURE__ */ jsx("span", {
|
|
51084
|
+
className: "text-foreground-subtle/70",
|
|
51085
|
+
children: `· last seen ${lastSeen}`
|
|
51086
|
+
}) : null
|
|
51087
|
+
]
|
|
51088
|
+
});
|
|
50616
51089
|
}
|
|
51090
|
+
//#endregion
|
|
51091
|
+
//#region src/composites/device-controls/primary-child.ts
|
|
50617
51092
|
/**
|
|
50618
|
-
*
|
|
50619
|
-
*
|
|
50620
|
-
* added `DeviceType` automatically appears in every type filter (Devices page,
|
|
50621
|
-
* adoption modal, …) without touching any consumer.
|
|
51093
|
+
* Which child a container is rendered AS — this surface's name for the shared
|
|
51094
|
+
* rule.
|
|
50622
51095
|
*
|
|
50623
|
-
* The
|
|
50624
|
-
*
|
|
50625
|
-
*
|
|
50626
|
-
*
|
|
51096
|
+
* The list and the resolution used to live here, in a COPY that carried a
|
|
51097
|
+
* comment asking the Home Assistant adoption mapping and the viewer's panel to
|
|
51098
|
+
* stay in sync with it. Three lists and three comments is not one rule, it is
|
|
51099
|
+
* three chances to drift. Both now come from `@camstack/types`, which all of
|
|
51100
|
+
* them already depend on; what remains here is the adapter for this module's
|
|
51101
|
+
* historical `ChildRef` shape.
|
|
51102
|
+
*/
|
|
51103
|
+
/** The shared precedence, under this module's historical name. */
|
|
51104
|
+
var PRIORITY = CONTAINER_CHILD_PRIORITY;
|
|
51105
|
+
/**
|
|
51106
|
+
* Resolve a container's primary child: the operator's pick when it still
|
|
51107
|
+
* matches a live child, else the highest-priority type.
|
|
50627
51108
|
*
|
|
50628
|
-
* `
|
|
50629
|
-
*
|
|
50630
|
-
*
|
|
51109
|
+
* `entityId` here is `sourceInfo?.id ?? stableId` (see `containerChildToRef`).
|
|
51110
|
+
* The shared resolver matches its canonical `stableId` key first and accepts
|
|
51111
|
+
* that legacy value too, so a pick stored under either keeps resolving.
|
|
50631
51112
|
*/
|
|
50632
|
-
|
|
50633
|
-
const
|
|
51113
|
+
function resolvePrimaryChild(children, overrideEntityId, containerName) {
|
|
51114
|
+
const picked = resolveContainerPrimaryChild(children.map((c) => ({
|
|
51115
|
+
id: c.id,
|
|
51116
|
+
stableId: c.entityId,
|
|
51117
|
+
type: c.type,
|
|
51118
|
+
...c.role !== void 0 ? { role: c.role } : {},
|
|
51119
|
+
...c.name !== void 0 ? { name: c.name } : {}
|
|
51120
|
+
})), overrideEntityId, containerName);
|
|
51121
|
+
return picked === null ? null : children.find((c) => c.id === picked.id) ?? null;
|
|
51122
|
+
}
|
|
51123
|
+
//#endregion
|
|
51124
|
+
//#region src/composites/device-controls/container-primary.ts
|
|
51125
|
+
/**
|
|
51126
|
+
* Re-sync-stable identity of a child. Prefers the upstream-system dispatch key
|
|
51127
|
+
* (`sourceInfo.id` — e.g. HA `entity_id`); falls back to `stableId` for
|
|
51128
|
+
* providers that never populated SourceInfo. Both survive a re-sync that may
|
|
51129
|
+
* reallocate the numeric `id`.
|
|
51130
|
+
*/
|
|
51131
|
+
function childEntityId(child) {
|
|
51132
|
+
return child.sourceInfo?.id ?? child.stableId;
|
|
51133
|
+
}
|
|
51134
|
+
/** Project a raw child row onto the pure resolver's {@link ChildRef} shape. */
|
|
51135
|
+
function containerChildToRef(child) {
|
|
50634
51136
|
return {
|
|
50635
|
-
id:
|
|
50636
|
-
|
|
50637
|
-
|
|
51137
|
+
id: child.id,
|
|
51138
|
+
entityId: childEntityId(child),
|
|
51139
|
+
type: child.type,
|
|
51140
|
+
...child.role !== void 0 && child.role !== null ? { role: child.role } : {},
|
|
51141
|
+
...child.name !== void 0 ? { name: child.name } : {}
|
|
50638
51142
|
};
|
|
50639
|
-
}
|
|
50640
|
-
|
|
50641
|
-
|
|
51143
|
+
}
|
|
51144
|
+
/**
|
|
51145
|
+
* Resolve the entityId override from the container's persisted `linkDeviceId`.
|
|
51146
|
+
* Returns the linked child's stable entityId, or `undefined` when there is no
|
|
51147
|
+
* link or the link is stale (points to a numeric id no longer present) — in
|
|
51148
|
+
* which case the resolver falls back to the priority default.
|
|
51149
|
+
*/
|
|
51150
|
+
function overrideEntityIdFromLink(children, linkDeviceId) {
|
|
51151
|
+
if (linkDeviceId === null || linkDeviceId === void 0) return void 0;
|
|
51152
|
+
const linked = children.find((c) => c.id === linkDeviceId);
|
|
51153
|
+
return linked === void 0 ? void 0 : childEntityId(linked);
|
|
51154
|
+
}
|
|
51155
|
+
/**
|
|
51156
|
+
* Full container → primary-child resolution: project children to refs, resolve
|
|
51157
|
+
* the override entityId, and delegate to the pure resolver. Returns `null` for a
|
|
51158
|
+
* container with no children (caller degrades gracefully).
|
|
51159
|
+
*
|
|
51160
|
+
* Override precedence:
|
|
51161
|
+
* 1. `primaryChildEntityId` — the DURABLE override (re-sync/rename-stable),
|
|
51162
|
+
* passed straight to the resolver which matches on `entityId`. Wins when a
|
|
51163
|
+
* non-empty string is supplied.
|
|
51164
|
+
* 2. `linkDeviceId` — LEGACY numeric override, re-derived to an entityId from
|
|
51165
|
+
* the live child set. Consulted only when there is no durable override.
|
|
51166
|
+
*
|
|
51167
|
+
* When neither resolves to a live child, the resolver falls back to the
|
|
51168
|
+
* priority default.
|
|
51169
|
+
*/
|
|
51170
|
+
function resolveContainerPrimary(children, linkDeviceId, primaryChildEntityId) {
|
|
51171
|
+
return resolvePrimaryChild(children.map(containerChildToRef), primaryChildEntityId !== null && primaryChildEntityId !== void 0 && primaryChildEntityId !== "" ? primaryChildEntityId : overrideEntityIdFromLink(children, linkDeviceId));
|
|
51172
|
+
}
|
|
51173
|
+
//#endregion
|
|
51174
|
+
//#region src/composites/device-controls/container-primary-hero.tsx
|
|
51175
|
+
function ContainerPrimaryHero({ trpc, children, linkDeviceId, primaryChildEntityId }) {
|
|
51176
|
+
const primary = resolveContainerPrimary(children, linkDeviceId, primaryChildEntityId);
|
|
51177
|
+
const primaryChild = primary === null ? void 0 : children.find((c) => c.id === primary.id);
|
|
51178
|
+
if (primaryChild === void 0) return /* @__PURE__ */ jsx("div", {
|
|
51179
|
+
className: "flex h-full w-full items-center justify-center p-4 text-[11px] italic text-foreground-subtle",
|
|
51180
|
+
children: "No child entities to display."
|
|
51181
|
+
});
|
|
51182
|
+
return /* @__PURE__ */ jsx("div", {
|
|
51183
|
+
className: "flex h-full w-full flex-col items-stretch gap-3 p-3 sm:p-4",
|
|
51184
|
+
children: /* @__PURE__ */ jsx(resolveDeviceControl(primaryChild.type)?.HeroCard ?? DummyHeroCard, {
|
|
51185
|
+
trpc,
|
|
51186
|
+
deviceId: primaryChild.id,
|
|
51187
|
+
features: primaryChild.features
|
|
51188
|
+
})
|
|
51189
|
+
});
|
|
51190
|
+
}
|
|
51191
|
+
//#endregion
|
|
51192
|
+
//#region src/composites/device-controls/primary-child-picker.tsx
|
|
51193
|
+
var BASE_SELECT_CLASS = "rounded-md border border-border bg-surface px-1.5 py-0.5 text-[11px] text-foreground";
|
|
51194
|
+
function PrimaryChildPicker({ childrenList, selectedId, onSetPrimary, disabled, className }) {
|
|
51195
|
+
return /* @__PURE__ */ jsx("select", {
|
|
51196
|
+
value: selectedId,
|
|
51197
|
+
disabled,
|
|
51198
|
+
onChange: (e) => {
|
|
51199
|
+
const nextId = Number(e.target.value);
|
|
51200
|
+
if (!Number.isFinite(nextId) || nextId === selectedId) return;
|
|
51201
|
+
const picked = childrenList.find((c) => c.id === nextId);
|
|
51202
|
+
if (picked !== void 0) onSetPrimary(picked.stableId);
|
|
51203
|
+
},
|
|
51204
|
+
className: className === void 0 ? BASE_SELECT_CLASS : `${BASE_SELECT_CLASS} ${className}`,
|
|
51205
|
+
children: childrenList.map((c) => /* @__PURE__ */ jsxs("option", {
|
|
51206
|
+
value: c.id,
|
|
51207
|
+
children: [
|
|
51208
|
+
c.name,
|
|
51209
|
+
" (",
|
|
51210
|
+
c.type,
|
|
51211
|
+
")"
|
|
51212
|
+
]
|
|
51213
|
+
}, c.id))
|
|
51214
|
+
});
|
|
51215
|
+
}
|
|
51216
|
+
//#endregion
|
|
51217
|
+
//#region src/composites/device-list/batch-toolbar.tsx
|
|
51218
|
+
function DeviceBatchToolbar({ selectedIds, onClear, remove, disable, enable }) {
|
|
51219
|
+
const [pendingDelete, setPendingDelete] = useState(false);
|
|
51220
|
+
if (selectedIds.size === 0) return null;
|
|
51221
|
+
const ids = [...selectedIds];
|
|
51222
|
+
const count = ids.length;
|
|
51223
|
+
const handleDisable = () => {
|
|
51224
|
+
for (const id of ids) disable({ deviceId: id });
|
|
51225
|
+
onClear();
|
|
51226
|
+
};
|
|
51227
|
+
const handleEnable = () => {
|
|
51228
|
+
for (const id of ids) enable({ deviceId: id });
|
|
51229
|
+
onClear();
|
|
51230
|
+
};
|
|
51231
|
+
const handleDeleteFirst = () => {
|
|
51232
|
+
setPendingDelete(true);
|
|
51233
|
+
};
|
|
51234
|
+
const handleDeleteConfirm = () => {
|
|
51235
|
+
for (const id of ids) remove({ deviceId: id });
|
|
51236
|
+
setPendingDelete(false);
|
|
51237
|
+
onClear();
|
|
51238
|
+
};
|
|
51239
|
+
const handleDeleteCancel = () => {
|
|
51240
|
+
setPendingDelete(false);
|
|
51241
|
+
};
|
|
51242
|
+
const handleClear = () => {
|
|
51243
|
+
setPendingDelete(false);
|
|
51244
|
+
onClear();
|
|
51245
|
+
};
|
|
51246
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
51247
|
+
className: "flex items-center gap-2 px-3 py-2 rounded-lg border border-border bg-surface-hover",
|
|
51248
|
+
children: [
|
|
51249
|
+
/* @__PURE__ */ jsxs("span", {
|
|
51250
|
+
className: "text-xs font-medium text-foreground-subtle shrink-0",
|
|
51251
|
+
children: [count, " selected"]
|
|
51252
|
+
}),
|
|
51253
|
+
/* @__PURE__ */ jsx("div", {
|
|
51254
|
+
className: "h-3.5 w-px bg-border shrink-0",
|
|
51255
|
+
"aria-hidden": "true"
|
|
51256
|
+
}),
|
|
51257
|
+
/* @__PURE__ */ jsxs("div", {
|
|
51258
|
+
className: "flex items-center gap-1.5 flex-wrap",
|
|
51259
|
+
children: [
|
|
51260
|
+
/* @__PURE__ */ jsx("button", {
|
|
51261
|
+
type: "button",
|
|
51262
|
+
onClick: handleDisable,
|
|
51263
|
+
className: cn("inline-flex items-center h-6 px-2.5 rounded-md border text-[10.5px] font-medium transition-colors", "border-border bg-surface text-foreground-subtle hover:text-foreground hover:bg-surface"),
|
|
51264
|
+
children: "Disable"
|
|
51265
|
+
}),
|
|
51266
|
+
/* @__PURE__ */ jsx("button", {
|
|
51267
|
+
type: "button",
|
|
51268
|
+
onClick: handleEnable,
|
|
51269
|
+
className: cn("inline-flex items-center h-6 px-2.5 rounded-md border text-[10.5px] font-medium transition-colors", "border-border bg-surface text-foreground-subtle hover:text-foreground hover:bg-surface"),
|
|
51270
|
+
children: "Enable"
|
|
51271
|
+
}),
|
|
51272
|
+
pendingDelete ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("button", {
|
|
51273
|
+
type: "button",
|
|
51274
|
+
onClick: handleDeleteConfirm,
|
|
51275
|
+
className: cn("inline-flex items-center h-6 px-2.5 rounded-md border text-[10.5px] font-medium transition-colors", "border-red-500/50 bg-red-500/10 text-red-400 hover:bg-red-500/20"),
|
|
51276
|
+
children: [
|
|
51277
|
+
"Confirm delete ",
|
|
51278
|
+
count,
|
|
51279
|
+
"?"
|
|
51280
|
+
]
|
|
51281
|
+
}), /* @__PURE__ */ jsx("button", {
|
|
51282
|
+
type: "button",
|
|
51283
|
+
onClick: handleDeleteCancel,
|
|
51284
|
+
className: cn("inline-flex items-center h-6 px-2.5 rounded-md border text-[10.5px] font-medium transition-colors", "border-border bg-surface text-foreground-subtle hover:text-foreground hover:bg-surface"),
|
|
51285
|
+
children: "Cancel"
|
|
51286
|
+
})] }) : /* @__PURE__ */ jsx("button", {
|
|
51287
|
+
type: "button",
|
|
51288
|
+
onClick: handleDeleteFirst,
|
|
51289
|
+
className: cn("inline-flex items-center h-6 px-2.5 rounded-md border text-[10.5px] font-medium transition-colors", "border-red-500/40 bg-red-500/10 text-red-400 hover:bg-red-500/20"),
|
|
51290
|
+
children: "Delete"
|
|
51291
|
+
}),
|
|
51292
|
+
/* @__PURE__ */ jsx("button", {
|
|
51293
|
+
type: "button",
|
|
51294
|
+
onClick: handleClear,
|
|
51295
|
+
className: cn("inline-flex items-center h-6 px-2.5 rounded-md border text-[10.5px] font-medium transition-colors", "border-border bg-surface text-foreground-subtle hover:text-foreground hover:bg-surface"),
|
|
51296
|
+
children: "Clear"
|
|
51297
|
+
})
|
|
51298
|
+
]
|
|
51299
|
+
})
|
|
51300
|
+
]
|
|
51301
|
+
});
|
|
51302
|
+
}
|
|
51303
|
+
//#endregion
|
|
51304
|
+
//#region src/composites/device-list/batch-actions-bar.tsx
|
|
51305
|
+
/**
|
|
51306
|
+
* <DeviceBatchActionsBar> — responsive wrapper around <DeviceBatchToolbar>.
|
|
51307
|
+
*
|
|
51308
|
+
* Surfaces the available bulk actions once devices are selected:
|
|
51309
|
+
* - L2+ (`sm` and up): the toolbar renders inline as a row of buttons.
|
|
51310
|
+
* - L1 (`< sm`): a compact "Actions · N" trigger opens a popover that
|
|
51311
|
+
* hosts the SAME <DeviceBatchToolbar>, so the action logic (inline
|
|
51312
|
+
* delete-confirm, clear) is reused verbatim — never forked.
|
|
51313
|
+
*
|
|
51314
|
+
* Renders nothing while the selection is empty (delegated to the toolbar).
|
|
51315
|
+
*/
|
|
51316
|
+
function DeviceBatchActionsBar(props) {
|
|
51317
|
+
const [open, setOpen] = useState(false);
|
|
51318
|
+
const rootRef = useRef(null);
|
|
51319
|
+
const count = props.selectedIds.size;
|
|
51320
|
+
useEffect(() => {
|
|
51321
|
+
if (!open) return;
|
|
51322
|
+
const onOutside = (e) => {
|
|
51323
|
+
const target = e.target instanceof Node ? e.target : null;
|
|
51324
|
+
if (target && rootRef.current && !rootRef.current.contains(target)) setOpen(false);
|
|
51325
|
+
};
|
|
51326
|
+
const onKey = (e) => {
|
|
51327
|
+
if (e.key === "Escape") setOpen(false);
|
|
51328
|
+
};
|
|
51329
|
+
document.addEventListener("mousedown", onOutside);
|
|
51330
|
+
document.addEventListener("touchstart", onOutside);
|
|
51331
|
+
document.addEventListener("keydown", onKey);
|
|
51332
|
+
return () => {
|
|
51333
|
+
document.removeEventListener("mousedown", onOutside);
|
|
51334
|
+
document.removeEventListener("touchstart", onOutside);
|
|
51335
|
+
document.removeEventListener("keydown", onKey);
|
|
51336
|
+
};
|
|
51337
|
+
}, [open]);
|
|
51338
|
+
if (count === 0) return null;
|
|
51339
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("div", {
|
|
51340
|
+
className: "hidden sm:block",
|
|
51341
|
+
children: /* @__PURE__ */ jsx(DeviceBatchToolbar, { ...props })
|
|
51342
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
51343
|
+
ref: rootRef,
|
|
51344
|
+
"data-testid": "batch-actions-compact",
|
|
51345
|
+
className: "relative sm:hidden",
|
|
51346
|
+
children: [/* @__PURE__ */ jsxs("button", {
|
|
51347
|
+
type: "button",
|
|
51348
|
+
onClick: () => setOpen((v) => !v),
|
|
51349
|
+
"aria-haspopup": "menu",
|
|
51350
|
+
"aria-expanded": open,
|
|
51351
|
+
className: "inline-flex items-center gap-1.5 h-7 px-2.5 rounded-full border border-primary/40 bg-primary/15 text-[10.5px] font-medium text-primary",
|
|
51352
|
+
children: [/* @__PURE__ */ jsxs("span", { children: ["Actions · ", String(count)] }), /* @__PURE__ */ jsx(ChevronDown, { className: `h-3 w-3 transition-transform ${open ? "rotate-180" : ""}` })]
|
|
51353
|
+
}), open && /* @__PURE__ */ jsx("div", {
|
|
51354
|
+
role: "menu",
|
|
51355
|
+
className: "absolute left-0 top-full mt-1 z-30 rounded-lg border border-border bg-surface shadow-md",
|
|
51356
|
+
children: /* @__PURE__ */ jsx(DeviceBatchToolbar, { ...props })
|
|
51357
|
+
})]
|
|
51358
|
+
})] });
|
|
50642
51359
|
}
|
|
50643
51360
|
//#endregion
|
|
50644
51361
|
//#region src/hooks/use-debounced-string.ts
|
|
@@ -50659,6 +51376,59 @@ function useDebouncedString(value, delayMs) {
|
|
|
50659
51376
|
return debounced;
|
|
50660
51377
|
}
|
|
50661
51378
|
//#endregion
|
|
51379
|
+
//#region src/hooks/use-persisted-page-size.ts
|
|
51380
|
+
/**
|
|
51381
|
+
* usePersistedPageSize — a "rows per page" choice remembered per viewer.
|
|
51382
|
+
*
|
|
51383
|
+
* The caller names the storage key, the allowed sizes and the default. Each
|
|
51384
|
+
* surface with its own default or option set keeps its own key, so one
|
|
51385
|
+
* surface's choice never lands on another that cannot show it (the device
|
|
51386
|
+
* list's global key stays `useDeviceListPageSize`'s, with its own options).
|
|
51387
|
+
*
|
|
51388
|
+
* `PAGE_SIZE_ALL` (0) is the "All" option: one page holding every row.
|
|
51389
|
+
*
|
|
51390
|
+
* Storage is a convenience, never a requirement: every read and write is
|
|
51391
|
+
* guarded, and a blocked / private-mode / missing storage simply means the
|
|
51392
|
+
* choice lasts until the page is left. A stored value that is not one of the
|
|
51393
|
+
* options (an older option set, a hand-edited value) is ignored.
|
|
51394
|
+
*/
|
|
51395
|
+
/** The "All" option — one page holding every row. */
|
|
51396
|
+
var PAGE_SIZE_ALL = 0;
|
|
51397
|
+
function readStored(key, options, fallback) {
|
|
51398
|
+
if (key === null || typeof window === "undefined") return fallback;
|
|
51399
|
+
try {
|
|
51400
|
+
const raw = window.localStorage.getItem(key);
|
|
51401
|
+
if (raw === null) return fallback;
|
|
51402
|
+
const parsed = Number.parseInt(raw, 10);
|
|
51403
|
+
return Number.isFinite(parsed) && options.includes(parsed) ? parsed : fallback;
|
|
51404
|
+
} catch {
|
|
51405
|
+
return fallback;
|
|
51406
|
+
}
|
|
51407
|
+
}
|
|
51408
|
+
function writeStored(key, value) {
|
|
51409
|
+
if (key === null || typeof window === "undefined") return;
|
|
51410
|
+
try {
|
|
51411
|
+
window.localStorage.setItem(key, String(value));
|
|
51412
|
+
} catch {}
|
|
51413
|
+
}
|
|
51414
|
+
/** @returns `[size, setSize]`; `setSize` ignores a size that is not an option. */
|
|
51415
|
+
function usePersistedPageSize({ storageKey, options, defaultSize }) {
|
|
51416
|
+
const seed = options.includes(defaultSize) ? defaultSize : options[0] ?? defaultSize;
|
|
51417
|
+
const [size, setSize] = useState(() => readStored(storageKey, options, seed));
|
|
51418
|
+
return [size, useCallback((next) => {
|
|
51419
|
+
if (!options.includes(next)) return;
|
|
51420
|
+
setSize(next);
|
|
51421
|
+
writeStored(storageKey, next);
|
|
51422
|
+
}, [options, storageKey])];
|
|
51423
|
+
}
|
|
51424
|
+
/**
|
|
51425
|
+
* The number of rows one page holds for a chosen size: "All" is every row
|
|
51426
|
+
* (at least 1, so the pager arithmetic never divides by zero).
|
|
51427
|
+
*/
|
|
51428
|
+
function effectivePageSize(size, totalItems) {
|
|
51429
|
+
return size === 0 ? Math.max(1, totalItems) : size;
|
|
51430
|
+
}
|
|
51431
|
+
//#endregion
|
|
50662
51432
|
//#region src/hooks/use-device-list-page-size.ts
|
|
50663
51433
|
/**
|
|
50664
51434
|
* useDeviceListPageSize — global page-size preference for the device-list
|
|
@@ -50669,8 +51439,9 @@ function useDebouncedString(value, delayMs) {
|
|
|
50669
51439
|
* value is validated against {@link DEVICE_LIST_PAGE_SIZE_OPTIONS}; any
|
|
50670
51440
|
* garbage / out-of-range value falls back to the provided default.
|
|
50671
51441
|
*
|
|
50672
|
-
*
|
|
50673
|
-
* a
|
|
51442
|
+
* A thin binding of `usePersistedPageSize` to that key and option set; a
|
|
51443
|
+
* surface with a different default or options uses the generic hook with a
|
|
51444
|
+
* key of its own.
|
|
50674
51445
|
*/
|
|
50675
51446
|
/** Selectable per-page sizes. The table default (50) is intentionally one of them. */
|
|
50676
51447
|
var DEVICE_LIST_PAGE_SIZE_OPTIONS = [
|
|
@@ -50681,33 +51452,6 @@ var DEVICE_LIST_PAGE_SIZE_OPTIONS = [
|
|
|
50681
51452
|
];
|
|
50682
51453
|
/** Single global key shared across every device-list surface. */
|
|
50683
51454
|
var DEVICE_LIST_PAGE_SIZE_KEY = "camstack.device-list.pageSize";
|
|
50684
|
-
function isAllowed(value) {
|
|
50685
|
-
return DEVICE_LIST_PAGE_SIZE_OPTIONS.includes(value);
|
|
50686
|
-
}
|
|
50687
|
-
/**
|
|
50688
|
-
* Normalize a caller-supplied `defaultSize` to an allowed option, falling back
|
|
50689
|
-
* to the canonical default so a stray value can never seed a phantom size.
|
|
50690
|
-
*/
|
|
50691
|
-
function safeDefault(defaultSize) {
|
|
50692
|
-
return isAllowed(defaultSize) ? defaultSize : 50;
|
|
50693
|
-
}
|
|
50694
|
-
function readStored(defaultSize) {
|
|
50695
|
-
if (typeof window === "undefined") return defaultSize;
|
|
50696
|
-
try {
|
|
50697
|
-
const raw = window.localStorage.getItem(DEVICE_LIST_PAGE_SIZE_KEY);
|
|
50698
|
-
if (raw === null) return defaultSize;
|
|
50699
|
-
const parsed = Number.parseInt(raw, 10);
|
|
50700
|
-
return Number.isFinite(parsed) && isAllowed(parsed) ? parsed : defaultSize;
|
|
50701
|
-
} catch {
|
|
50702
|
-
return defaultSize;
|
|
50703
|
-
}
|
|
50704
|
-
}
|
|
50705
|
-
function writeStored(value) {
|
|
50706
|
-
if (typeof window === "undefined") return;
|
|
50707
|
-
try {
|
|
50708
|
-
window.localStorage.setItem(DEVICE_LIST_PAGE_SIZE_KEY, String(value));
|
|
50709
|
-
} catch {}
|
|
50710
|
-
}
|
|
50711
51455
|
/**
|
|
50712
51456
|
* @param defaultSize fallback when nothing valid is stored. If it is not itself
|
|
50713
51457
|
* a member of {@link DEVICE_LIST_PAGE_SIZE_OPTIONS}, it is replaced by
|
|
@@ -50715,13 +51459,11 @@ function writeStored(value) {
|
|
|
50715
51459
|
* @returns `[size, setSize]` — `setSize` ignores values outside the allowed set.
|
|
50716
51460
|
*/
|
|
50717
51461
|
function useDeviceListPageSize(defaultSize) {
|
|
50718
|
-
|
|
50719
|
-
|
|
50720
|
-
|
|
50721
|
-
|
|
50722
|
-
|
|
50723
|
-
writeStored(next);
|
|
50724
|
-
}, [])];
|
|
51462
|
+
return usePersistedPageSize({
|
|
51463
|
+
storageKey: DEVICE_LIST_PAGE_SIZE_KEY,
|
|
51464
|
+
options: DEVICE_LIST_PAGE_SIZE_OPTIONS,
|
|
51465
|
+
defaultSize: DEVICE_LIST_PAGE_SIZE_OPTIONS.includes(defaultSize) ? defaultSize : 50
|
|
51466
|
+
});
|
|
50725
51467
|
}
|
|
50726
51468
|
//#endregion
|
|
50727
51469
|
//#region src/composites/device-item/helpers.ts
|
|
@@ -53019,6 +53761,29 @@ function groupTopLevelAndAccessories(devices, options) {
|
|
|
53019
53761
|
};
|
|
53020
53762
|
}
|
|
53021
53763
|
//#endregion
|
|
53764
|
+
//#region src/composites/device-list/page-size-select.tsx
|
|
53765
|
+
function pageSizeLabel(size) {
|
|
53766
|
+
return size === 0 ? "All" : String(size);
|
|
53767
|
+
}
|
|
53768
|
+
function PageSizeSelect({ value, options, onChange, ariaLabel }) {
|
|
53769
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
53770
|
+
className: "inline-flex items-center gap-1.5",
|
|
53771
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
53772
|
+
"aria-hidden": "true",
|
|
53773
|
+
children: "Per page"
|
|
53774
|
+
}), /* @__PURE__ */ jsx("select", {
|
|
53775
|
+
"aria-label": ariaLabel,
|
|
53776
|
+
value,
|
|
53777
|
+
onChange: (e) => onChange(Number.parseInt(e.target.value, 10)),
|
|
53778
|
+
className: "h-7 px-1.5 rounded-md border border-border bg-surface text-[11px] text-foreground focus:outline-none focus:ring-1 focus:ring-primary/40",
|
|
53779
|
+
children: options.map((opt) => /* @__PURE__ */ jsx("option", {
|
|
53780
|
+
value: opt,
|
|
53781
|
+
children: pageSizeLabel(opt)
|
|
53782
|
+
}, opt))
|
|
53783
|
+
})]
|
|
53784
|
+
});
|
|
53785
|
+
}
|
|
53786
|
+
//#endregion
|
|
53022
53787
|
//#region src/composites/device-list/multi-select.tsx
|
|
53023
53788
|
/**
|
|
53024
53789
|
* Compact multi-select dropdown — a single chip-sized trigger ("Label · N")
|
|
@@ -53933,23 +54698,11 @@ function DeviceModeList(props) {
|
|
|
53933
54698
|
totalItems,
|
|
53934
54699
|
" ",
|
|
53935
54700
|
totalItems === 1 ? "device" : "devices"
|
|
53936
|
-
] }), /* @__PURE__ */
|
|
53937
|
-
|
|
53938
|
-
|
|
53939
|
-
|
|
53940
|
-
|
|
53941
|
-
}), /* @__PURE__ */ jsx("select", {
|
|
53942
|
-
"aria-label": "Devices per page",
|
|
53943
|
-
value: tablePageSize,
|
|
53944
|
-
onChange: (e) => {
|
|
53945
|
-
setTablePageSize(Number.parseInt(e.target.value, 10));
|
|
53946
|
-
},
|
|
53947
|
-
className: "h-7 px-1.5 rounded-md border border-border bg-surface text-[11px] text-foreground focus:outline-none focus:ring-1 focus:ring-primary/40",
|
|
53948
|
-
children: DEVICE_LIST_PAGE_SIZE_OPTIONS.map((opt) => /* @__PURE__ */ jsx("option", {
|
|
53949
|
-
value: opt,
|
|
53950
|
-
children: opt
|
|
53951
|
-
}, opt))
|
|
53952
|
-
})]
|
|
54701
|
+
] }), /* @__PURE__ */ jsx(PageSizeSelect, {
|
|
54702
|
+
ariaLabel: "Devices per page",
|
|
54703
|
+
value: tablePageSize,
|
|
54704
|
+
options: DEVICE_LIST_PAGE_SIZE_OPTIONS,
|
|
54705
|
+
onChange: setTablePageSize
|
|
53953
54706
|
})]
|
|
53954
54707
|
}), /* @__PURE__ */ jsx(Pagination, {
|
|
53955
54708
|
currentPage: safePage,
|
|
@@ -53993,6 +54746,7 @@ function useDeviceListRealtimeSync() {
|
|
|
53993
54746
|
}
|
|
53994
54747
|
//#endregion
|
|
53995
54748
|
//#region src/composites/device-list/generic-mode.tsx
|
|
54749
|
+
var FIXED_PAGE_SIZE = 100;
|
|
53996
54750
|
/**
|
|
53997
54751
|
* Generic render-prop list: search + pagination chrome shared with the device
|
|
53998
54752
|
* list, over an arbitrary item type. Local (non-URL) state — intended for
|
|
@@ -54000,7 +54754,12 @@ function useDeviceListRealtimeSync() {
|
|
|
54000
54754
|
* `renderItem`.
|
|
54001
54755
|
*/
|
|
54002
54756
|
function GenericModeList(props) {
|
|
54003
|
-
const { items, getKey, getSearchText, renderItem, getFilterType, mapFilterOption, filterOptions, filterLabel = "Type", initialTypeFilters = [], columns, renderExpanded, isExpanded, rowClassName, onRowClick, isLoading = false, searchPlaceholder = "Search", emptyLabel = "No items found.", pageSize =
|
|
54757
|
+
const { items, getKey, getSearchText, renderItem, getFilterType, mapFilterOption, filterOptions, filterLabel = "Type", initialTypeFilters = [], columns, renderExpanded, isExpanded, rowClassName, onRowClick, isLoading = false, searchPlaceholder = "Search", emptyLabel = "No items found.", pageSize: fixedPageSize = FIXED_PAGE_SIZE, pageSizeSelector, toolbar } = props;
|
|
54758
|
+
const [chosenPageSize, setChosenPageSize] = usePersistedPageSize(pageSizeSelector ?? {
|
|
54759
|
+
storageKey: null,
|
|
54760
|
+
options: [fixedPageSize],
|
|
54761
|
+
defaultSize: fixedPageSize
|
|
54762
|
+
});
|
|
54004
54763
|
const [searchInput, setSearchInput] = useState("");
|
|
54005
54764
|
const debouncedSearch = useDebouncedString(searchInput, 300);
|
|
54006
54765
|
const [typeFilters, setTypeFilters] = useState(() => [...initialTypeFilters]);
|
|
@@ -54049,6 +54808,7 @@ function GenericModeList(props) {
|
|
|
54049
54808
|
getFilterType
|
|
54050
54809
|
]);
|
|
54051
54810
|
const totalItems = filtered.length;
|
|
54811
|
+
const pageSize = pageSizeSelector ? effectivePageSize(chosenPageSize, totalItems) : fixedPageSize;
|
|
54052
54812
|
const totalPages = Math.max(1, Math.ceil(totalItems / pageSize));
|
|
54053
54813
|
const safePage = Math.min(page, totalPages);
|
|
54054
54814
|
const startIdx = (safePage - 1) * pageSize;
|
|
@@ -54132,7 +54892,23 @@ function GenericModeList(props) {
|
|
|
54132
54892
|
}),
|
|
54133
54893
|
/* @__PURE__ */ jsx("div", {
|
|
54134
54894
|
className: "shrink-0",
|
|
54135
|
-
children: /* @__PURE__ */
|
|
54895
|
+
children: pageSizeSelector && totalItems > 0 ? /* @__PURE__ */ jsxs("div", {
|
|
54896
|
+
className: "flex items-center justify-between gap-4 flex-wrap pt-2 text-[11px] text-foreground-subtle",
|
|
54897
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
54898
|
+
className: "inline-flex items-center gap-2",
|
|
54899
|
+
children: [totalItems <= pageSize && /* @__PURE__ */ jsxs("span", { children: [totalItems, " total"] }), /* @__PURE__ */ jsx(PageSizeSelect, {
|
|
54900
|
+
ariaLabel: "Rows per page",
|
|
54901
|
+
value: chosenPageSize,
|
|
54902
|
+
options: pageSizeSelector.options,
|
|
54903
|
+
onChange: setChosenPageSize
|
|
54904
|
+
})]
|
|
54905
|
+
}), /* @__PURE__ */ jsx(Pagination, {
|
|
54906
|
+
currentPage: safePage,
|
|
54907
|
+
totalItems,
|
|
54908
|
+
pageSize,
|
|
54909
|
+
onPageChange: setPage
|
|
54910
|
+
})]
|
|
54911
|
+
}) : /* @__PURE__ */ jsx(Pagination, {
|
|
54136
54912
|
currentPage: safePage,
|
|
54137
54913
|
totalItems,
|
|
54138
54914
|
pageSize,
|
|
@@ -54261,6 +55037,24 @@ var DeviceItemRowSchema = z.object({
|
|
|
54261
55037
|
});
|
|
54262
55038
|
var SupportedKindsSchema = z.array(z.string());
|
|
54263
55039
|
var STATUS_POLL_INTERVAL_MS = 1e4;
|
|
55040
|
+
/** Where the viewer's "rows per page" choice for this table is remembered. */
|
|
55041
|
+
var DEVICE_EXPORT_PAGE_SIZE_KEY = "camstack.device-export.pageSize";
|
|
55042
|
+
/**
|
|
55043
|
+
* The exposed-devices table's page sizes. Its own key and options, not the
|
|
55044
|
+
* Devices page's (25/50/100/200, default 50): the operator asked for a short
|
|
55045
|
+
* default here (25) and an "All" for a quick scan of every exportable device.
|
|
55046
|
+
*/
|
|
55047
|
+
var DEVICE_EXPORT_PAGE_SIZE = {
|
|
55048
|
+
options: [
|
|
55049
|
+
10,
|
|
55050
|
+
25,
|
|
55051
|
+
50,
|
|
55052
|
+
100,
|
|
55053
|
+
0
|
|
55054
|
+
],
|
|
55055
|
+
defaultSize: 25,
|
|
55056
|
+
storageKey: DEVICE_EXPORT_PAGE_SIZE_KEY
|
|
55057
|
+
};
|
|
54264
55058
|
/**
|
|
54265
55059
|
* The fleet-list poll. Deliberately the same 30 s as the window
|
|
54266
55060
|
* `applyFleetQueryDefaults` registers for `deviceManager.listAll` (D274) —
|
|
@@ -54345,6 +55139,35 @@ function SetupSection({ setup }) {
|
|
|
54345
55139
|
})]
|
|
54346
55140
|
});
|
|
54347
55141
|
}
|
|
55142
|
+
/** Parse `getStatus` against the canonical cap schema (loose wire output). */
|
|
55143
|
+
function parseStatus(data) {
|
|
55144
|
+
const parsed = DeviceExportStatusSchema.safeParse(data);
|
|
55145
|
+
return parsed.success ? parsed.data : null;
|
|
55146
|
+
}
|
|
55147
|
+
/**
|
|
55148
|
+
* The exporter's error and Setup block on their own — for a page that shows
|
|
55149
|
+
* them above its settings while the devices table sits at the bottom. Renders
|
|
55150
|
+
* nothing when the exporter reports neither. Shares `getStatus`'s query key
|
|
55151
|
+
* with the panel, so mounting both costs one request.
|
|
55152
|
+
*/
|
|
55153
|
+
function DeviceExportSetup({ addonId }) {
|
|
55154
|
+
const statusQuery = useDeviceExportGetStatus({
|
|
55155
|
+
nodeId: "hub",
|
|
55156
|
+
addonId
|
|
55157
|
+
}, {
|
|
55158
|
+
refetchInterval: STATUS_POLL_INTERVAL_MS,
|
|
55159
|
+
retry: false
|
|
55160
|
+
});
|
|
55161
|
+
const status = useMemo(() => parseStatus(statusQuery.data), [statusQuery.data]);
|
|
55162
|
+
if (!status?.error && !status?.setup) return null;
|
|
55163
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
55164
|
+
className: "rounded-lg border border-border bg-surface overflow-hidden",
|
|
55165
|
+
children: [status.error && /* @__PURE__ */ jsx("div", {
|
|
55166
|
+
className: "px-2 sm:px-4 py-3 border-b border-border",
|
|
55167
|
+
children: /* @__PURE__ */ jsx(ErrorBox, { message: status.error })
|
|
55168
|
+
}), status.setup && /* @__PURE__ */ jsx(SetupSection, { setup: status.setup })]
|
|
55169
|
+
});
|
|
55170
|
+
}
|
|
54348
55171
|
/**
|
|
54349
55172
|
* Per-row Expose/Exposed toggle. Reflects whether the row's device is exposed
|
|
54350
55173
|
* to THIS exporter and flips it through the SAME runner the bulk buttons use —
|
|
@@ -54423,7 +55246,7 @@ function BulkSummary({ outcome, onDismiss }) {
|
|
|
54423
55246
|
* Generic device-export panel. Addon-agnostic — only the `device-export`
|
|
54424
55247
|
* cap drives it.
|
|
54425
55248
|
*/
|
|
54426
|
-
function DeviceExportPanel({ addonId, onOpenDevice }) {
|
|
55249
|
+
function DeviceExportPanel({ addonId, onOpenDevice, showSetup = true }) {
|
|
54427
55250
|
const queryClient = useQueryClient();
|
|
54428
55251
|
const statusQuery = useDeviceExportGetStatus({
|
|
54429
55252
|
nodeId: "hub",
|
|
@@ -54449,10 +55272,7 @@ function DeviceExportPanel({ addonId, onOpenDevice }) {
|
|
|
54449
55272
|
}, [queryClient]);
|
|
54450
55273
|
const exposeMutation = useDeviceExportExposeDevice({ onSuccess: invalidate });
|
|
54451
55274
|
const unexposeMutation = useDeviceExportUnexposeDevice({ onSuccess: invalidate });
|
|
54452
|
-
const status = useMemo(() =>
|
|
54453
|
-
const parsed = DeviceExportStatusSchema.safeParse(statusQuery.data);
|
|
54454
|
-
return parsed.success ? parsed.data : null;
|
|
54455
|
-
}, [statusQuery.data]);
|
|
55275
|
+
const status = useMemo(() => parseStatus(statusQuery.data), [statusQuery.data]);
|
|
54456
55276
|
const exposed = useMemo(() => {
|
|
54457
55277
|
const parsed = ExposedDeviceArraySchema.safeParse(exposedQuery.data);
|
|
54458
55278
|
return parsed.success ? parsed.data : [];
|
|
@@ -54675,11 +55495,11 @@ function DeviceExportPanel({ addonId, onOpenDevice }) {
|
|
|
54675
55495
|
]
|
|
54676
55496
|
}), loading && /* @__PURE__ */ jsx(LoaderCircle, { className: "h-3.5 w-3.5 animate-spin text-foreground-subtle" })]
|
|
54677
55497
|
}),
|
|
54678
|
-
status?.error && /* @__PURE__ */ jsx("div", {
|
|
55498
|
+
showSetup && status?.error && /* @__PURE__ */ jsx("div", {
|
|
54679
55499
|
className: "px-2 sm:px-4 py-3 border-b border-border",
|
|
54680
55500
|
children: /* @__PURE__ */ jsx(ErrorBox, { message: status.error })
|
|
54681
55501
|
}),
|
|
54682
|
-
status?.setup && /* @__PURE__ */ jsx(SetupSection, { setup: status.setup }),
|
|
55502
|
+
showSetup && status?.setup && /* @__PURE__ */ jsx(SetupSection, { setup: status.setup }),
|
|
54683
55503
|
outcome !== null && /* @__PURE__ */ jsx(BulkSummary, {
|
|
54684
55504
|
outcome,
|
|
54685
55505
|
onDismiss: dismissOutcome
|
|
@@ -54699,6 +55519,7 @@ function DeviceExportPanel({ addonId, onOpenDevice }) {
|
|
|
54699
55519
|
columns,
|
|
54700
55520
|
onRowClick: onOpenDevice ? onRowClick : void 0,
|
|
54701
55521
|
toolbar: selectionToolbar,
|
|
55522
|
+
pageSizeSelector: DEVICE_EXPORT_PAGE_SIZE,
|
|
54702
55523
|
searchPlaceholder: "Search by name or stableId",
|
|
54703
55524
|
emptyLabel: "No device matches this search."
|
|
54704
55525
|
}) : /* @__PURE__ */ jsx(EmptyState, {
|
|
@@ -54724,145 +55545,6 @@ function DeviceGrid({ children, minCardWidth = 220, gap = 3, className }) {
|
|
|
54724
55545
|
});
|
|
54725
55546
|
}
|
|
54726
55547
|
//#endregion
|
|
54727
|
-
//#region src/composites/icon-picker.tsx
|
|
54728
|
-
/**
|
|
54729
|
-
* icon-picker — the ONE control for choosing an icon, wherever admin-ui asks.
|
|
54730
|
-
*
|
|
54731
|
-
* There were two: a device one over `DISPLAY_ICON_REGISTRY` and a room one
|
|
54732
|
-
* over `LOCATION_ICON_IDS`, identical apart from the vocabulary they walked.
|
|
54733
|
-
* That was tolerable while the device set was 56 glyphs in a flat grid. It is
|
|
54734
|
-
* not at 157: a picker that only lets the operator HUNT is a picker they stop
|
|
54735
|
-
* using, and the two copies were already drifting — only one of them had an
|
|
54736
|
-
* i18n'd label.
|
|
54737
|
-
*
|
|
54738
|
-
* So the vocabulary, the grouping and the search all come from
|
|
54739
|
-
* `@camstack/types`' `display-icon-vocabulary`, which is the same module the
|
|
54740
|
-
* viewer's sheet searches. What is left here is the web half: a popover, a
|
|
54741
|
-
* grid, and a text field.
|
|
54742
|
-
*
|
|
54743
|
-
* ## What it does NOT own
|
|
54744
|
-
*
|
|
54745
|
-
* - **The glyphs.** `resolveGlyph` is a prop, because this package's table is
|
|
54746
|
-
* `lucide-react` and the viewer's is `lucide-react-native`. A key this build
|
|
54747
|
-
* cannot draw is SKIPPED rather than rendered as a hole — an empty tile
|
|
54748
|
-
* reads as a rendering bug, not as a missing choice.
|
|
54749
|
-
* - **The words.** Every string is a prop. This package has no i18n (one file
|
|
54750
|
-
* in it imports react-i18next, and that is the exception), and a control
|
|
54751
|
-
* that reached for a translation would force it on every consumer.
|
|
54752
|
-
* - **The write.** `onPick` is called and that is all; whether it is a form
|
|
54753
|
-
* value or an immediate mutation is the caller's business, as it already was
|
|
54754
|
-
* in both pickers this replaces.
|
|
54755
|
-
*
|
|
54756
|
-
* ## The clear tile is never filtered away
|
|
54757
|
-
*
|
|
54758
|
-
* The "inherit" / "no icon" choice sits above the sections and ignores the
|
|
54759
|
-
* search. A query that hid it would strand the operator on a glyph they picked
|
|
54760
|
-
* by accident with no way back to the default — the one action a picker must
|
|
54761
|
-
* always offer.
|
|
54762
|
-
*/
|
|
54763
|
-
function IconPicker({ value, onPick, resolveGlyph, fallbackGlyph, labels, only, extraWords, clearGlyph, labelFor, disabled = false }) {
|
|
54764
|
-
const [open, setOpen] = useState(false);
|
|
54765
|
-
const [query, setQuery] = useState("");
|
|
54766
|
-
const allowed = useMemo(() => only === void 0 ? null : new Set(only), [only]);
|
|
54767
|
-
const sections = useMemo(() => {
|
|
54768
|
-
const hits = searchDisplayIcons(query, extraWords);
|
|
54769
|
-
const byGroup = /* @__PURE__ */ new Map();
|
|
54770
|
-
for (const hit of hits) {
|
|
54771
|
-
const { key, group } = hit.entry;
|
|
54772
|
-
if (allowed !== null && !allowed.has(key)) continue;
|
|
54773
|
-
if (resolveGlyph(key) === void 0) continue;
|
|
54774
|
-
const bucket = byGroup.get(group);
|
|
54775
|
-
if (bucket === void 0) byGroup.set(group, [key]);
|
|
54776
|
-
else bucket.push(key);
|
|
54777
|
-
}
|
|
54778
|
-
return DISPLAY_ICON_GROUPS.flatMap((group) => {
|
|
54779
|
-
const keys = byGroup.get(group);
|
|
54780
|
-
return keys === void 0 || keys.length === 0 ? [] : [{
|
|
54781
|
-
group,
|
|
54782
|
-
keys
|
|
54783
|
-
}];
|
|
54784
|
-
});
|
|
54785
|
-
}, [
|
|
54786
|
-
query,
|
|
54787
|
-
extraWords,
|
|
54788
|
-
allowed,
|
|
54789
|
-
resolveGlyph
|
|
54790
|
-
]);
|
|
54791
|
-
const Current = (value === null ? void 0 : resolveGlyph(value)) ?? fallbackGlyph;
|
|
54792
|
-
const choose = async (next) => {
|
|
54793
|
-
setOpen(false);
|
|
54794
|
-
setQuery("");
|
|
54795
|
-
await onPick(next);
|
|
54796
|
-
};
|
|
54797
|
-
const Clear = clearGlyph ?? fallbackGlyph;
|
|
54798
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
54799
|
-
className: "relative flex shrink-0 items-center gap-2",
|
|
54800
|
-
children: [/* @__PURE__ */ jsx("button", {
|
|
54801
|
-
type: "button",
|
|
54802
|
-
disabled,
|
|
54803
|
-
onClick: () => setOpen((o) => !o),
|
|
54804
|
-
"aria-expanded": open,
|
|
54805
|
-
"aria-label": labels.trigger,
|
|
54806
|
-
title: labels.trigger,
|
|
54807
|
-
className: "rounded border border-border p-1 text-foreground-muted hover:bg-surface-hover disabled:opacity-50",
|
|
54808
|
-
children: /* @__PURE__ */ jsx(Current, { className: "h-4 w-4" })
|
|
54809
|
-
}), open && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("button", {
|
|
54810
|
-
type: "button",
|
|
54811
|
-
"aria-label": labels.close,
|
|
54812
|
-
onClick: () => setOpen(false),
|
|
54813
|
-
className: "fixed inset-0 z-10 cursor-default"
|
|
54814
|
-
}), /* @__PURE__ */ jsxs("div", {
|
|
54815
|
-
role: "group",
|
|
54816
|
-
"aria-label": labels.panel,
|
|
54817
|
-
className: "absolute left-0 top-full z-20 mt-1 max-h-80 w-72 overflow-y-auto rounded-md border border-border bg-surface p-2 shadow-lg",
|
|
54818
|
-
children: [
|
|
54819
|
-
/* @__PURE__ */ jsx("input", {
|
|
54820
|
-
type: "search",
|
|
54821
|
-
value: query,
|
|
54822
|
-
autoFocus: true,
|
|
54823
|
-
onChange: (e) => setQuery(e.target.value),
|
|
54824
|
-
placeholder: labels.searchPlaceholder,
|
|
54825
|
-
"aria-label": labels.searchPlaceholder,
|
|
54826
|
-
className: "mb-2 w-full rounded border border-border bg-surface-raised px-2 py-1 text-xs text-foreground placeholder:text-foreground-subtle"
|
|
54827
|
-
}),
|
|
54828
|
-
/* @__PURE__ */ jsxs("button", {
|
|
54829
|
-
type: "button",
|
|
54830
|
-
onClick: () => void choose(null),
|
|
54831
|
-
"aria-pressed": value === null,
|
|
54832
|
-
className: "mb-2 flex w-full items-center gap-1.5 rounded px-1.5 py-1 text-[11px] text-foreground-subtle hover:bg-surface-hover",
|
|
54833
|
-
children: [/* @__PURE__ */ jsx(Clear, { className: "h-3.5 w-3.5" }), labels.clear]
|
|
54834
|
-
}),
|
|
54835
|
-
sections.length === 0 ? /* @__PURE__ */ jsx("p", {
|
|
54836
|
-
className: "px-1.5 py-2 text-[11px] text-foreground-subtle",
|
|
54837
|
-
children: labels.noMatches
|
|
54838
|
-
}) : sections.map(({ group, keys }) => /* @__PURE__ */ jsxs("section", {
|
|
54839
|
-
className: "mb-2 last:mb-0",
|
|
54840
|
-
children: [/* @__PURE__ */ jsx("h4", {
|
|
54841
|
-
className: "px-1.5 pb-1 text-[10px] uppercase tracking-wide text-foreground-subtle",
|
|
54842
|
-
children: labels.groups[group]
|
|
54843
|
-
}), /* @__PURE__ */ jsx("div", {
|
|
54844
|
-
className: "grid grid-cols-7 gap-1",
|
|
54845
|
-
children: keys.map((key) => {
|
|
54846
|
-
const Glyph = resolveGlyph(key);
|
|
54847
|
-
if (Glyph === void 0) return null;
|
|
54848
|
-
const selected = value === key;
|
|
54849
|
-
return /* @__PURE__ */ jsx("button", {
|
|
54850
|
-
type: "button",
|
|
54851
|
-
onClick: () => void choose(key),
|
|
54852
|
-
"aria-pressed": selected,
|
|
54853
|
-
"aria-label": labelFor?.(key) ?? key,
|
|
54854
|
-
title: labelFor?.(key) ?? key,
|
|
54855
|
-
className: selected ? "flex items-center justify-center rounded border border-primary bg-primary/10 p-1.5 text-foreground" : "flex items-center justify-center rounded border border-transparent p-1.5 text-foreground-muted hover:bg-surface-hover",
|
|
54856
|
-
children: /* @__PURE__ */ jsx(Glyph, { className: "h-4 w-4" })
|
|
54857
|
-
}, key);
|
|
54858
|
-
})
|
|
54859
|
-
})]
|
|
54860
|
-
}, group))
|
|
54861
|
-
]
|
|
54862
|
-
})] })]
|
|
54863
|
-
});
|
|
54864
|
-
}
|
|
54865
|
-
//#endregion
|
|
54866
55548
|
//#region src/composites/device-selector-picker.tsx
|
|
54867
55549
|
/**
|
|
54868
55550
|
* <DeviceSelectorPicker> — the operator-facing editor for a v3
|
|
@@ -60996,4 +61678,4 @@ var SceneMonitorEditor = lazy(() => import("./SceneMonitorEditor-vfWTm6qv.js").t
|
|
|
60996
61678
|
/** Lazy-wrapped `PrivacyMaskSettings` — code-split off the main bundle. */
|
|
60997
61679
|
var PrivacyMaskSettings = lazy(() => import("./PrivacyMaskSettings-DMkchqO1.js").then((m) => ({ default: m.PrivacyMaskSettings })));
|
|
60998
61680
|
//#endregion
|
|
60999
|
-
export { AddonGlobalSettingsForm, AdminLinkQuickAction, AgentStepEditor, AlarmHeroCard, AlarmInlineControl as AlarmPanelInlineControl, AppShell, ArcKnob, AudioClassificationList, AudioLevelWaveform, AudioWaveform, AutomationHeroCard, AutomationInlineControl, AutotrackSection, BTN_COMPACT, BTN_COMPACT_DANGER, BTN_COMPACT_PRIMARY, BTN_COMPACT_WARNING, BackToStepsButton, 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, ConfigNotificationTargetMultiSelectFieldView, ConfigNotificationTargetSelectFieldView, 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_PICKER_GROUP_STORAGE_KEY, DEVICE_ROLE_META, DEVICE_TYPE_CONTROL, DEVICE_TYPE_META, DISPLAY_ICON_REGISTRY, DataTable, DataTableFilterBar, DetectionCanvas, DetectionOverlay, DetectionResultTree, DevShell, DeviceActivityPanel, DeviceBatchToolbar, DeviceCard, DeviceContextProvider, DeviceExportPanel, DeviceFilterBar, DeviceGrid, DeviceItem, DeviceList, DeviceMultiSelectField, DevicePicker, DeviceQuickDetailProvider, DeviceSelectField, DeviceSelectorPicker, DeviceStepMatrix, DevicesFailedLine, DevicesLoadingLine, DevicesWidenWarning, Dialog, DialogBody, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, DiscoveryPanel, DoorbellRecentPanel, Dropdown, DropdownContent, DropdownItem, DropdownTrigger, DummyHeroCard, DummyInline, EMPTY_DATA_TABLE_FILTER, EVENT_KIND_ICONS, EmptyState, EndpointResultsCard, EndpointTestCard, ErrorBox, EventKindGlyph, EventStream, ExtensionsPanel, 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, GateBadge, GateControl, GripTrack, GroupedModelSelector, HOST_WIDGETS, HUB_SESSION_RUN_MS, HlsVideo, HoverZoomImage, HubSessionTestCard, HumidifierHeroCard, HumidifierInlineControl, INPUT_COMPACT, INPUT_SHELL, IconAction, IconButton, IconPicker, ImageHeroCard, ImageInlineControl, ImageSelector, InferenceConfigSelector, Input, KebabMenu, KeyValueList, LIST_ROW, Label, LawnMowerHeroCard, LawnMowerInlineControl, LayeredSettingsForm, LightHeroCard, LightInlineControl, LockHeroCard, LockInlineControl, LockPanel, LogStream, LoginForm, MODE_COLOR, MaskShapeCanvas, MediaPlayerHeroCard, MediaPlayerInlineControl, MediaPlayerPanel, MobileDrawer, ModelPicker, MotionZonesSettings, NAVIGATION_DRIVE_INTERVAL_MS, NatResultCard, NavigationPanel, NetworkLinkBadge, NodeMultiSelectField, NodePicker, NodeSelectField, NotificationTargetSelectField, NotificationTargetsField, OPTION_SELECT_SEARCH_MIN_OPTIONS, OfflineBadge, OptionSelect, PHASE_CONFIG, PICKER_CHIP_LIMIT, PICKER_DEFAULT_GROUP_BY, PICKER_GROUP_BY_MODES, PICKER_GROUP_COLLAPSE_AT, PICKER_NONE_KEY, PICKER_NOUN_PLURAL, PICKER_NO_FILTERS, PICKER_PAGE_SIZE, PICKER_SEARCH_DEBOUNCE_MS, PICKER_WINDOW, PRIORITY, PTZOverlay, PageHeader, PhaseIcon, PipelineBuilder, PipelineRuntimeSelector, PipelineStep, PlaceholderChipField, 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, RoleDisplayDefaultsFromServer, RoleDisplayDefaultsProvider, RootModelSourceControl, RootSuppliedModelNote, RunReport, 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, STEP_DOCK_WIDTH_PX, SceneMonitorEditor, ScopePicker, ScriptHeroCard, ScriptInlineControl, ScrollArea, SectionCard, SegmentedChoice, Select, SelectedChip, SemanticBadge, SensorHeroCard, SensorInlineControl, SensorValueAtom, Separator, SettingRow, Sidebar, SidebarItem, Skeleton, SlideToggle, SnapshotButton, SortHeaderButton, StatCard, StateValuesStream, StatusBadge, StepDetailDock, StepInspectorPanel, StepModelRow, StepTimings, 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, UnitPicker, VacuumHeroCard, VacuumInlineControl, ValueReadout, ValveHeroCard, ValveInlineControl, VersionBadge, VodPlaybackProvider, WaterHeaterHeroCard, WaterHeaterInlineControl, WeatherHeroCard, WeatherInlineControl, WidgetMetricCard, WidgetPanel, WidgetRegistryProvider, WidgetSlot, ZoneEditingProvider, MicOff as a, acceleratorLabel, acceleratorShortLabel, agentColumnKey, allDeviceTypeFilterOptions, applyFleetQueryDefaults, applyPickerFilters, ariaSortForColumn, badgeFor, bindsToModel, buildPeerConnectionConfig, buildStepTreeFromSchema, EyeOff as c, catalogHasDraft, childEntityId, childListName, chipOverflow, classifyAddressScope, classifyCapability, classifySessionVerdict, clearPickerGroup, cn, columnsForContext, compareSrflxMappings, containerChildToRef, countableDevices, coverHighlight, coverageLine, createSharedContext, createTheme, cursorFractionFor, darkColors, dataTableFacets, defaultOfField, defaultTheme, deriveDeviceKind, deriveWebrtcDebugStats, describeDeviceSelector, deviceIntegrationResolver, deviceListStateOf, deviceMatchesFilter, deviceOptionLabel, deviceRoleMeta, deviceRoleMetaOf, deviceTypeLabel, deviceTypeMeta, deviceTypeMetaOf, devicesToOptions, dockBox, draftFromQuery, emptyDevicesWidens, emptySessionRun, ensureMfHostInit, eventKindLabel, filterDataTableRows, filterDeviceOptions, filterOptions as filterOptionSelectOptions, filterPickerDevices, finalizeSessionRun, findTimezone, flattenPickerGrouping, flattenPickerRows, fleetViewOf, formatControlDateTime, formatLastSeen, formatNumeric, formatSettingValue, freezeVerdict, fuzzyMatch, getClassColor, getPhaseVisual, groupAgentColumns, groupChildrenByLayout, groupPickerDevices, groupPickerDevicesBy, hardwareLabel, hubOrigin, hubPath, hubUrl, hubWsUrl, humanDuration, humidifierTint, Mic as i, initialScrubState, insertAtSelection, isAbsentProvider, isDataTableFilterActive, isFieldVisible, isGroupExpanded, isValueField, Camera as l, lawnMowerActivityMeta, lightColors, loadRemoteBundle, makeScrubBridge, metadataEntries, metadataString, mirror, mountAddonPage, mountPath, Square as n, nextGridPosition, nextReconnectAction, nextSort, nextSortDirection, nextTableSort, normalizeForSearch, ImageOff as o, offListSelections, openTopLayer, optionSearchText as optionSelectSearchText, orphanDeviceLabel, overrideEntityIdFromLink, pageRows, parentDetailOf, parseIceCandidate, parsePickerGroupBy, parseRecordedServerMessage, partitionSelected as partitionOptionSelectSelected, partitionSuggested, pickerFacetFilterShown, pickerFacetKey, pickerFacetOptions, pickerFiltersActive, pickerGroupKey, pickerHiddenSelectedCount, pickerLocationKey, pickerQueryTokens, pickerRowFacts, pickerSearchText, pickerZoneFilterSuspended, pinnedStreamChoices, providerIcons, RotateCcw as r, readStoredGroupBy, reduceSessionRun, resetHubMountForTests, resetPickerFilters, resolveContainerPrimary, resolveControlAlign, resolveDeviceControl, resolveDeviceIntegration, resolveDisplayIcon, resolveEffectiveDefaultModel, resolveEffectiveStepModel, resolveEventKindIcon, resolveSearchable as resolveOptionSelectSearchable, resolveParentNames, resolvePrimaryChild, resolveSelectedDevices, resolveSensorDisplay, resolveStepDefaultModel, resolveTableLayout, roiTooLarge, rootSourceState, routerBasename, Grid2x2 as s, sameLocationSuggestions, scrubReducer, searchSteps, selectPickerGroup, selectedDeviceOptions, serializeRecordedCommand, settingsModelIdFor, shouldCommit, shouldEmit, shouldShowAddNewFooter, shouldShowUseQueryRow, shouldUseSingleNode, showsNoCamerasHint, sortRows, sortRowsByColumn, statusIcons, statusLine, stepFieldDomId, stepHasModelForFormat, stepLocalFields, stepModelOptions, stripParentNamePrefix, summarizeHubCandidates, Trash2 as t, tabForSelector, tankAlert, themeToCss, toStationaryOverlayBox, toggleDataTableFacet, togglePickerDevice, togglePickerKey, trpc, typeLabel, createLucideIcon as u, 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, useAddonsListInstallations, 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, useCalendarsGetPreferences, useCalendarsListCalendars, useCalendarsListEvents, useCalendarsSetCalendarPreference, 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, useCoreBlocksCreateComposition, useCoreBlocksDelete, useCoreBlocksGet, useCoreBlocksGetBlockSettings, useCoreBlocksGetComposition, useCoreBlocksGetCustomization, useCoreBlocksGetTypeDefs, useCoreBlocksList, useCoreBlocksListComposableCaps, useCoreBlocksListCompositions, useCoreBlocksRestart, useCoreBlocksSetEnabled, useCoreBlocksUpdate, useCoreBlocksUpdateBlockSettings, useCoreBlocksUpdateComposition, useCoreBlocksValidateComposition, useCoverClose, useCoverGetStatus, useCoverOpen, useCoverSetPosition, useCoverSetTiltPosition, useCoverStop, useCustomFieldRenderer, useDataTableFilter, useDayNightGetOptions, useDayNightGetStatus, useDayNightSetSettings, useDebouncedString, useDecoderGetInfo, useDecoderReprobeHwaccel, useDetectionPipelineApplyDeviceSettingsPatch, useDetectionPipelineGetDeviceLiveContribution, useDetectionPipelineGetDeviceSettingsContribution, useDevShell, useDevice, useDeviceAdminLink, useDeviceAdminLinkGetAdminLink, 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, useDeviceExtensionListCandidates, useDeviceExtensionListSlots, useDeviceExtensionListSources, useDeviceExtensionSetSlot, useDeviceId, useDeviceListPageSize, useDeviceManagerAddLocation, useDeviceManagerAdoptDevice, useDeviceManagerAdoptionAdopt, useDeviceManagerAdoptionCancelJob, useDeviceManagerAdoptionListCandidateFilters, useDeviceManagerAdoptionListCandidates, useDeviceManagerAdoptionListJobs, useDeviceManagerAdoptionRefresh, useDeviceManagerAdoptionRelease, useDeviceManagerAdoptionResync, useDeviceManagerAdoptionStartJob, useDeviceManagerAllocateDeviceId, useDeviceManagerApplyInitialMeta, useDeviceManagerCreateDevice, useDeviceManagerDisable, useDeviceManagerDiscoverAllProviders, useDeviceManagerDiscoverDevices, useDeviceManagerDiscoverProvider, useDeviceManagerDiscoveryProviders, useDeviceManagerEnable, useDeviceManagerGetAllBindings, useDeviceManagerGetBindings, useDeviceManagerGetBindingsBatch, useDeviceManagerGetChildren, useDeviceManagerGetChildrenBatch, useDeviceManagerGetConfigSchema, useDeviceManagerGetCreationSchema, useDeviceManagerGetDevice, useDeviceManagerGetDeviceAggregate, useDeviceManagerGetDeviceLiveInfoAggregate, useDeviceManagerGetDeviceSettingsAggregate, useDeviceManagerGetDeviceStatusAggregate, useDeviceManagerGetDeviceStatusAggregateBatch, useDeviceManagerGetLinkedDevices, useDeviceManagerGetLinkedDevicesBatch, useDeviceManagerGetRoleDisplayDefaults, useDeviceManagerGetSettingsSchema, useDeviceManagerGetStreamProfileMap, useDeviceManagerGetStreamSources, useDeviceManagerGetWireableFields, useDeviceManagerGetWrapperActivation, useDeviceManagerListAll, useDeviceManagerListBindableCapsForDeviceType, useDeviceManagerListDeviceIdsByCaps, 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, useDeviceQuickDetailOpen, useDeviceSnapshot, useDeviceSnapshotImage, useDeviceState, useDeviceStateClaimFields, useDeviceStateGetAllSnapshots, useDeviceStateGetCapSlice, useDeviceStateGetNativeCapSlice, useDeviceStateGetSnapshot, useDeviceStateListClaims, useDeviceStatePatchOwnedFields, useDeviceStateReleaseClaim, useDeviceStateSetCapSlice, useDeviceStateSlice, useDeviceStatusGetStatus, useDeviceWebrtc, useDevices, useDoorbellEvents, useDoorbellGetStatus, useEnumSensorGetStatus, useEventEmitterGetStatus, useEventInvalidation, useEventStreamLatest, useEventStreamMap, 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, useLocalNetworkAddCustomAddress, useLocalNetworkDownloadCa, useLocalNetworkGetAddresses, useLocalNetworkGetAllowedAddresses, useLocalNetworkGetConnectionEndpoints, useLocalNetworkGetHubAddresses, useLocalNetworkGetNotificationEndpoint, useLocalNetworkGetPreferred, useLocalNetworkGetTlsStatus, useLocalNetworkGetViewerEndpoints, useLocalNetworkList, useLocalNetworkRegenerateCertificate, useLocalNetworkRemoveCustomAddress, useLocalNetworkResetAllowlistToBestMatch, useLocalNetworkRevertToGeneratedCertificate, useLocalNetworkSetAddressRole, 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, useNodesDirectory, useNodesExecuteQuery, useNodesGetCapUsageGraph, useNodesGetNodeAddons, useNodesRenameNode, useNodesRestartAddon, useNodesRestartNode, useNodesRestartProcess, useNodesSetProcessLogLevel, useNodesShutdownNode, useNodesTopology, useNodesUndeployAddon, useNotificationOutputDeleteTarget, useNotificationOutputDiscoverTargets, useNotificationOutputGetTarget, useNotificationOutputListTargetKinds, useNotificationOutputListTargets, useNotificationOutputProbeTargetConfig, useNotificationOutputSend, useNotificationOutputSetTargetEnabled, useNotificationOutputTestTarget, useNotificationOutputUpsertTarget, useNotificationRulesActivateAlarmProfile, useNotificationRulesCancelSnooze, useNotificationRulesCreateAlarmProfile, useNotificationRulesCreateRule, useNotificationRulesCreateSequence, useNotificationRulesCreateSnooze, useNotificationRulesDeleteAlarmProfile, useNotificationRulesDeleteRule, useNotificationRulesDeleteSequence, useNotificationRulesGetAlarmConfig, useNotificationRulesGetAlarmSensors, useNotificationRulesGetClipRetentionAsks, useNotificationRulesGetConditionCatalog, useNotificationRulesGetHistory, useNotificationRulesGetRule, useNotificationRulesGetRuleLastRuns, useNotificationRulesGetSequence, useNotificationRulesGetTemplateCatalog, useNotificationRulesListDeviceMutes, useNotificationRulesListRules, useNotificationRulesListSequences, useNotificationRulesListSnoozes, useNotificationRulesPreviewStateSummary, useNotificationRulesPreviewTemplate, useNotificationRulesRenameAlarmProfile, useNotificationRulesResolveArtifactUrl, useNotificationRulesSetAlarmConfig, useNotificationRulesSetDeviceMuted, useNotificationRulesSetRuleEnabled, useNotificationRulesTestRule, useNotificationRulesUpdateRule, useNotificationRulesUpdateSequence, useNotifierCancel, useNotifierGetStatus, useNotifierSend, useNumericSensorGetStatus, useOptimisticSlice, useOptionalSystem, useOptionalWidgetRegistry, useOsdGetStatus, useOsdManagerClearSlotBinding, useOsdManagerCopyDeviceConfiguration, useOsdManagerDeleteTemplate, useOsdManagerGetConditionSupport, useOsdManagerGetDeviceOsd, useOsdManagerGetSourceCatalog, useOsdManagerListTemplates, useOsdManagerPreviewSlot, useOsdManagerRenderDevice, useOsdManagerSetSlotBinding, useOsdManagerUpsertTemplate, useOsdSetOverlay, usePTZ, usePetFeederCallPet, usePetFeederCancelFeed, usePetFeederFeed, usePetFeederGetStatus, usePetFeederMarkFoodReplenished, usePetFeederPlaySound, usePetFeederResetDesiccant, usePetFeederSetChildLock, usePetFeederSetFeedSound, usePetFeederSetIndicatorLight, usePetFeederSetVolume, usePickerSiteZones, usePipelineAnalyticsApplyDeviceSettingsPatch, usePipelineAnalyticsCancelRelocateMedia, usePipelineAnalyticsCancelStorageMigrationMove, usePipelineAnalyticsClearTrackRelation, 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, usePipelineAnalyticsGetTrack, usePipelineAnalyticsGetTrackMedia, usePipelineAnalyticsGetTrainingExportSummary, usePipelineAnalyticsGetTrainingExportUrl, usePipelineAnalyticsListArchivedDebugNotes, usePipelineAnalyticsListBirthDecisions, usePipelineAnalyticsListEventKinds, usePipelineAnalyticsListEventKindsBatch, usePipelineAnalyticsListEventMedia, usePipelineAnalyticsListOpsLog, usePipelineAnalyticsListRecentTracks, usePipelineAnalyticsListRelocateMediaJobs, usePipelineAnalyticsListRetrainAnnotations, usePipelineAnalyticsListRetrainFrames, usePipelineAnalyticsListRetrainStaging, usePipelineAnalyticsListTrackMedia, usePipelineAnalyticsListTrackRelations, usePipelineAnalyticsListTracks, usePipelineAnalyticsOwnersWithMedia, usePipelineAnalyticsPauseForStorageMigration, usePipelineAnalyticsProposeRetrainAnnotations, usePipelineAnalyticsPruneEvents, usePipelineAnalyticsPruneEventsBefore, usePipelineAnalyticsPruneTracksBefore, usePipelineAnalyticsReadLongTermSeries, usePipelineAnalyticsRebuildObjectEmbeddings, usePipelineAnalyticsReclaimDebugMedia, usePipelineAnalyticsReconcileFromDisk, usePipelineAnalyticsRefreshStorageLocationsForMigration, usePipelineAnalyticsRelocateMedia, usePipelineAnalyticsRestageRetrainTrack, usePipelineAnalyticsResumeForStorageMigration, usePipelineAnalyticsSaveRetrainAnnotations, usePipelineAnalyticsSearchObjectEvents, usePipelineAnalyticsSelectRetrainFrames, usePipelineAnalyticsSetTrackFlags, usePipelineAnalyticsSetTrackPurity, usePipelineAnalyticsSetTrackRelation, usePipelineAnalyticsStartStorageMigrationMove, usePipelineAnalyticsWipeAllAnalytics, usePipelineAnalyticsWipeObjectEmbeddings, usePipelineExecutorCacheFrameInPool, usePipelineExecutorClearDeviceOverrides, usePipelineExecutorClearModelBoundDeviceOverrides, usePipelineExecutorDeleteModel, usePipelineExecutorDownloadModel, usePipelineExecutorGetAddonModels, usePipelineExecutorGetAudioCapabilities, usePipelineExecutorGetAvailableEngines, usePipelineExecutorGetCapabilities, usePipelineExecutorGetDefaultSteps, usePipelineExecutorGetDetectionConfigSchema, usePipelineExecutorGetEffectiveTuning, usePipelineExecutorGetEngineProvisioning, usePipelineExecutorGetGlobalPipelineConfig, usePipelineExecutorGetGlobalSteps, usePipelineExecutorGetInferenceDeviceHealth, usePipelineExecutorGetOrchestratorConfigSchema, usePipelineExecutorGetReferenceAudio, usePipelineExecutorGetReferenceAudioFiles, usePipelineExecutorGetReferenceImage, usePipelineExecutorGetSchema, usePipelineExecutorGetSelectedEngine, usePipelineExecutorGetVideoPipelineSteps, usePipelineExecutorInferCached, usePipelineExecutorKillEngine, usePipelineExecutorListLoadedEngines, usePipelineExecutorListReferenceImages, usePipelineExecutorRearmInferenceDevice, usePipelineExecutorRunAudioTest, usePipelineExecutorRunPipeline, usePipelineExecutorRunPipelineBatch, usePipelineExecutorSetVideoPipelineSteps, usePipelineExecutorSpinEngine, usePipelineExecutorUncacheFrame, usePipelineExecutorValidatePipeline, usePipelineOrchestratorApplyAutoTune, usePipelineOrchestratorApplyDeviceSettingsPatch, usePipelineOrchestratorAssignAudio, usePipelineOrchestratorAssignPipeline, usePipelineOrchestratorGetAgentLoad, usePipelineOrchestratorGetAgentSettings, usePipelineOrchestratorGetAudioAssignment, usePipelineOrchestratorGetAudioAssignments, usePipelineOrchestratorGetAudioNodeLoad, usePipelineOrchestratorGetCameraMetrics, usePipelineOrchestratorGetCameraSettings, usePipelineOrchestratorGetCameraStatus, usePipelineOrchestratorGetCameraStatuses, usePipelineOrchestratorGetCameraStepOverrides, usePipelineOrchestratorGetCameraSwitches, usePipelineOrchestratorGetCapabilityBindings, usePipelineOrchestratorGetClusterModelChoice, usePipelineOrchestratorGetDeviceLiveContribution, usePipelineOrchestratorGetDeviceSettingsContribution, usePipelineOrchestratorGetEffectiveShares, usePipelineOrchestratorGetGlobalMetrics, usePipelineOrchestratorGetIngestOwner, usePipelineOrchestratorGetNodeInferenceDevices, usePipelineOrchestratorGetPipelineAssignment, usePipelineOrchestratorGetPipelineAssignments, usePipelineOrchestratorGetPipelineDevicePin, usePipelineOrchestratorGetPlacementStats, usePipelineOrchestratorGetReconcileFromDiskStatus, usePipelineOrchestratorListAgentSettings, usePipelineOrchestratorPauseForStorageMigration, usePipelineOrchestratorPlanAutoTune, usePipelineOrchestratorRebalance, usePipelineOrchestratorReconcileFromDisk, usePipelineOrchestratorRemoveAgentSettings, usePipelineOrchestratorRequestOccupancyLook, usePipelineOrchestratorResetNodePipelineDefaults, usePipelineOrchestratorResolvePipeline, usePipelineOrchestratorResumeForStorageMigration, usePipelineOrchestratorSetAgentCapabilities, usePipelineOrchestratorSetAgentDecodeLimits, usePipelineOrchestratorSetAgentInferenceDevices, usePipelineOrchestratorSetAgentMaxCameras, usePipelineOrchestratorSetAgentReachableHost, usePipelineOrchestratorSetCameraPipelineForAgent, usePipelineOrchestratorSetCameraSensors, usePipelineOrchestratorSetCameraStepOverride, usePipelineOrchestratorSetCameraStepSettings, usePipelineOrchestratorSetCameraStepToggle, usePipelineOrchestratorSetCameraSwitch, usePipelineOrchestratorSetCapabilityBinding, usePipelineOrchestratorSetLoadBalancingShares, usePipelineOrchestratorSetPipelineDevicePin, usePipelineOrchestratorSetShareSource, usePipelineOrchestratorSuggestShares, usePipelineOrchestratorUnassignAudio, usePipelineOrchestratorUnassignPipeline, 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, useRecordingArchiveApplyDeviceSettingsPatch, useRecordingArchiveCancelRelocateJob, useRecordingArchiveCancelStorageMigrationMove, useRecordingArchiveDeleteFootprint, useRecordingArchiveGetAvailabilityBatch, useRecordingArchiveGetDaysWithRecordingsBatch, useRecordingArchiveGetDeviceConfig, useRecordingArchiveGetDeviceLiveContribution, useRecordingArchiveGetDeviceSettingsContribution, useRecordingArchiveGetPlacement, useRecordingArchiveGetRelocateResidue, useRecordingArchiveGetStatus, useRecordingArchiveGetStorageMigrationMoveStatus, useRecordingArchiveGetStorageUsage, useRecordingArchiveListOpsLog, useRecordingArchiveListRelocateJobs, useRecordingArchiveLocateSegment, useRecordingArchivePauseForStorageMigration, useRecordingArchivePlanStorageRebalance, useRecordingArchivePruneFootage, useRecordingArchiveReadGopBytes, useRecordingArchiveReadSegmentBytes, useRecordingArchiveReadWindowBytes, useRecordingArchiveReconcileLedgerAgainstDisk, useRecordingArchiveRefreshStorageLocationsForMigration, useRecordingArchiveRelocateFootage, useRecordingArchiveRenderClip, useRecordingArchiveRenderGif, useRecordingArchiveRescanStorage, useRecordingArchiveResumeForStorageMigration, useRecordingArchiveSetDeviceConfig, useRecordingArchiveSetDevicePlacement, useRecordingArchiveStartStorageMigrationMove, useRecordingArchiveStartStorageRebalance, useRecordingExportCancelExport, useRecordingExportCreateExport, useRecordingExportDeleteExport, useRecordingExportGetDownloadUrl, useRecordingExportGetExport, useRecordingExportListExports, useRecordingExportReadExportBytes, useRecordingGetAvailability, useRecordingGetDaysWithRecordings, useRecordingGetPlayback, useRecordingGetPlaybackOptions, useRecordingListSources, useRecordingOnboardGetOptions, useRecordingOnboardGetStatus, useRecordingOnboardSetSettings, useRecordingSignalGetStatus, useRemoteComponent, useRoleDisplayDefaults, 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, useStoredGroupBy, useStreamBrokerAcquireEgressTranscode, useStreamBrokerApplyDeviceSettingsPatch, useStreamBrokerAssignProfile, useStreamBrokerFetchEventMedia, useStreamBrokerForgetDeviceHardware, useStreamBrokerGetAllRtspEntries, useStreamBrokerGetBrokerStats, useStreamBrokerGetDeviceAudioMute, useStreamBrokerGetDeviceLiveContribution, useStreamBrokerGetDeviceSettingsContribution, useStreamBrokerGetPreBufferInfo, useStreamBrokerGetRtspEntry, useStreamBrokerGetRtspPort, useStreamBrokerGetStreamUrl, useStreamBrokerGetStreamWithCodec, useStreamBrokerIsRtspEnabled, useStreamBrokerKillClient, useStreamBrokerListAllCameraStreams, useStreamBrokerListAllProfileSlots, useStreamBrokerListClients, useStreamBrokerProbeStream, useStreamBrokerProduceEventMedia, useStreamBrokerPublishCameraStream, useStreamBrokerPullAudioChunks, useStreamBrokerRegenerateRtspToken, useStreamBrokerReleaseEgressTranscode, useStreamBrokerReleaseStreamWithCodec, useStreamBrokerRenderPreBufferClip, useStreamBrokerReportStreamSignal, useStreamBrokerRestartProfile, useStreamBrokerRetractCameraStream, useStreamBrokerSetDeviceAudioMute, useStreamBrokerSetPreBufferDuration, useStreamBrokerSetRtspEnabled, useStreamBrokerSubscribeAudioChunks, useStreamBrokerUnassignProfile, useStreamBrokerUnsubscribeAudioChunks, 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, useUrlQueryParam, 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, useVideoclipsDialClipStream, useVideoclipsGetClipPlayback, useVideoclipsGetPlaybackOptions, useVideoclipsListClips, useVideoclipsListSources, useVideoclipsOfferClipBytes, useVideoclipsReadClipBytes, useVodPlayback, useWaterHeaterGetStatus, useWaterHeaterSetAway, useWaterHeaterSetOperationMode, useWaterHeaterSetTargetTemp, useWeatherGetStatus, useWebrtcSessionAddIceCandidate, useWebrtcSessionApplyDownlinkProbe, 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, withResolvedParentDetail, withUseRootModel, writeStoredGroupBy };
|
|
61681
|
+
export { AddonGlobalSettingsForm, AdminLinkQuickAction, AgentStepEditor, AlarmHeroCard, AlarmInlineControl as AlarmPanelInlineControl, AppShell, ArcKnob, AudioClassificationList, AudioLevelWaveform, AudioWaveform, AutomationHeroCard, AutomationInlineControl, AutotrackSection, BTN_COMPACT, BTN_COMPACT_DANGER, BTN_COMPACT_PRIMARY, BTN_COMPACT_WARNING, BackToStepsButton, 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, ConfigNotificationTargetMultiSelectFieldView, ConfigNotificationTargetSelectFieldView, ConfigSchemaField, ConfirmActionButton, ConfirmDialogProvider, ConsumablesPanel, ContainerChildrenProvider, ContainerPrimaryHero, ControlColumn, ControlHeroCard, ControlInlineControl, ControlPanel, CopyButton, CoverHeroCard, CoverInlineControl, CoverPanel, CustomFieldRenderersProvider, DEFAULT_COLOR, DEVICE_COLUMNS, DEVICE_EXPORT_PAGE_SIZE_KEY, DEVICE_LIST_PAGE_SIZE_KEY, DEVICE_LIST_PAGE_SIZE_OPTIONS, DEVICE_PICKER_GROUP_STORAGE_KEY, DEVICE_ROLE_META, DEVICE_TYPE_CONTROL, DEVICE_TYPE_META, DISPLAY_ICON_REGISTRY, DataTable, DataTableFilterBar, DetectionCanvas, DetectionOverlay, DetectionResultTree, DevShell, DeviceActivityPanel, DeviceBatchToolbar, DeviceCard, DeviceContextProvider, DeviceExportPanel, DeviceExportSetup, DeviceFilterBar, DeviceGrid, DeviceItem, DeviceList, DeviceMultiSelectField, DevicePicker, DeviceQuickDetailProvider, DeviceSelectField, DeviceSelectorPicker, DeviceStepMatrix, DevicesFailedLine, DevicesLoadingLine, DevicesWidenWarning, Dialog, DialogBody, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, DiscoveryPanel, DoorbellRecentPanel, Dropdown, DropdownContent, DropdownItem, DropdownTrigger, DummyHeroCard, DummyInline, EMPTY_DATA_TABLE_FILTER, EVENT_KIND_ICONS, EmptyState, EndpointResultsCard, EndpointTestCard, ErrorBox, EventKindGlyph, EventStream, ExtensionsPanel, 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, GateBadge, GateControl, GripTrack, GroupedModelSelector, HOST_WIDGETS, HUB_SESSION_RUN_MS, HlsVideo, HoverZoomImage, HubSessionTestCard, HumidifierHeroCard, HumidifierInlineControl, INPUT_COMPACT, INPUT_SHELL, IconAction, IconButton, IconPicker, ImageHeroCard, ImageInlineControl, ImageSelector, InferenceConfigSelector, Input, KebabMenu, KeyValueList, LIST_ROW, Label, LawnMowerHeroCard, LawnMowerInlineControl, LayeredSettingsForm, LightHeroCard, LightInlineControl, LockHeroCard, LockInlineControl, LockPanel, LogStream, LoginForm, MODE_COLOR, MaskShapeCanvas, MediaPlayerHeroCard, MediaPlayerInlineControl, MediaPlayerPanel, MobileDrawer, ModelPicker, MotionZonesSettings, NAVIGATION_DRIVE_INTERVAL_MS, NatResultCard, NavigationPanel, NetworkLinkBadge, NodeMultiSelectField, NodePicker, NodeSelectField, NotificationTargetSelectField, NotificationTargetsField, OPTION_SELECT_SEARCH_MIN_OPTIONS, OfflineBadge, OptionSelect, PAGE_SIZE_ALL, PHASE_CONFIG, PICKER_CHIP_LIMIT, PICKER_DEFAULT_GROUP_BY, PICKER_GROUP_BY_MODES, PICKER_GROUP_COLLAPSE_AT, PICKER_NONE_KEY, PICKER_NOUN_PLURAL, PICKER_NO_FILTERS, PICKER_PAGE_SIZE, PICKER_SEARCH_DEBOUNCE_MS, PICKER_WINDOW, PRIORITY, PTZOverlay, PageHeader, PageSizeSelect, PhaseIcon, PipelineBuilder, PipelineRuntimeSelector, PipelineStep, PlaceholderChipField, 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, RoleDisplayDefaultsFromServer, RoleDisplayDefaultsProvider, RootModelSourceControl, RootSuppliedModelNote, RunReport, SCENE_CAPTURE_VARIANTS, SECRET_REVEAL_MS, 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, STEP_DOCK_WIDTH_PX, SceneMonitorEditor, ScopePicker, ScriptHeroCard, ScriptInlineControl, ScrollArea, SecretFieldControl, SecretRevealProvider, SectionCard, SegmentedChoice, Select, SelectedChip, SemanticBadge, SendFrameToTrainingButton, SensorHeroCard, SensorInlineControl, SensorValueAtom, Separator, SettingRow, Sidebar, SidebarItem, Skeleton, SlideToggle, SnapshotButton, SortHeaderButton, StatCard, StateValuesStream, StatusBadge, StepDetailDock, StepInspectorPanel, StepModelRow, StepTimings, 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, TrainingCollectionPicker, UnitPicker, VacuumHeroCard, VacuumInlineControl, ValueReadout, ValveHeroCard, ValveInlineControl, VersionBadge, VodPlaybackProvider, WaterHeaterHeroCard, WaterHeaterInlineControl, WeatherHeroCard, WeatherInlineControl, WidgetMetricCard, WidgetPanel, WidgetRegistryProvider, WidgetSlot, ZoneEditingProvider, MicOff as a, acceleratorLabel, acceleratorShortLabel, agentColumnKey, allDeviceTypeFilterOptions, applyFleetQueryDefaults, applyPickerFilters, ariaSortForColumn, badgeFor, bindsToModel, buildPeerConnectionConfig, buildStepTreeFromSchema, EyeOff as c, catalogHasDraft, childEntityId, childListName, chipOverflow, classifyAddressScope, classifyCapability, classifySessionVerdict, clearPickerGroup, cn, columnsForContext, compareSrflxMappings, containerChildToRef, countableDevices, coverHighlight, coverageLine, createSharedContext, createTheme, cursorFractionFor, darkColors, dataTableFacets, defaultOfField, defaultTheme, deriveDeviceKind, deriveWebrtcDebugStats, describeDeviceSelector, deviceIntegrationResolver, deviceListStateOf, deviceMatchesFilter, deviceOptionLabel, deviceRoleMeta, deviceRoleMetaOf, deviceTypeLabel, deviceTypeMeta, deviceTypeMetaOf, devicesToOptions, dockBox, draftFromQuery, effectivePageSize, emptyDevicesWidens, emptySessionRun, ensureMfHostInit, eventKindLabel, filterDataTableRows, filterDeviceOptions, filterOptions as filterOptionSelectOptions, filterPickerDevices, finalizeSessionRun, findTimezone, flattenPickerGrouping, flattenPickerRows, fleetViewOf, formatControlDateTime, formatLastSeen, formatNumeric, formatSettingValue, freezeVerdict, fuzzyMatch, getClassColor, getPhaseVisual, groupAgentColumns, groupChildrenByLayout, groupPickerDevices, groupPickerDevicesBy, hardwareLabel, hubOrigin, hubPath, hubUrl, hubWsUrl, humanDuration, humidifierTint, Mic as i, initialScrubState, insertAtSelection, isAbsentProvider, isDataTableFilterActive, isFieldVisible, isGroupExpanded, isKeychainFieldValue, isValueField, Camera as l, lawnMowerActivityMeta, lightColors, loadRemoteBundle, makeScrubBridge, metadataEntries, metadataString, mirror, mountAddonPage, mountPath, Square as n, nextGridPosition, nextReconnectAction, nextSort, nextSortDirection, nextTableSort, normalizeForSearch, ImageOff as o, offListSelections, openTopLayer, optionSearchText as optionSelectSearchText, orphanDeviceLabel, overrideEntityIdFromLink, pageRows, pageSizeLabel, parentDetailOf, parseIceCandidate, parsePickerGroupBy, parseRecordedServerMessage, partitionSelected as partitionOptionSelectSelected, partitionSuggested, pickerFacetFilterShown, pickerFacetKey, pickerFacetOptions, pickerFiltersActive, pickerGroupKey, pickerHiddenSelectedCount, pickerLocationKey, pickerQueryTokens, pickerRowFacts, pickerSearchText, pickerZoneFilterSuspended, pinnedStreamChoices, providerIcons, RotateCcw as r, readStoredGroupBy, reduceSessionRun, resetHubMountForTests, resetPickerFilters, resolveContainerPrimary, resolveControlAlign, resolveDeviceControl, resolveDeviceIntegration, resolveDisplayIcon, resolveEffectiveDefaultModel, resolveEffectiveStepModel, resolveEventKindIcon, resolveSearchable as resolveOptionSelectSearchable, resolveParentNames, resolvePrimaryChild, resolveSelectedDevices, resolveSensorDisplay, resolveStepDefaultModel, resolveTableLayout, roiTooLarge, rootSourceState, routerBasename, Grid2x2 as s, sameLocationSuggestions, scrubReducer, searchSteps, selectPickerGroup, selectedDeviceOptions, serializeRecordedCommand, settingsModelIdFor, shouldCommit, shouldEmit, shouldShowAddNewFooter, shouldShowUseQueryRow, shouldUseSingleNode, showsNoCamerasHint, sortRows, sortRowsByColumn, statusIcons, statusLine, stepFieldDomId, stepHasModelForFormat, stepLocalFields, stepModelOptions, stripParentNamePrefix, summarizeHubCandidates, Trash2 as t, tabForSelector, tankAlert, themeToCss, toStationaryOverlayBox, toggleDataTableFacet, togglePickerDevice, togglePickerKey, trainingRefusalText, trpc, typeLabel, createLucideIcon as u, 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, useAddonsListInstallations, 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, useCalendarsGetPreferences, useCalendarsListCalendars, useCalendarsListEvents, useCalendarsSetCalendarPreference, 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, useCoreBlocksCreateComposition, useCoreBlocksDelete, useCoreBlocksGet, useCoreBlocksGetBlockSettings, useCoreBlocksGetComposition, useCoreBlocksGetCustomization, useCoreBlocksGetTypeDefs, useCoreBlocksList, useCoreBlocksListComposableCaps, useCoreBlocksListCompositions, useCoreBlocksRestart, useCoreBlocksSetEnabled, useCoreBlocksUpdate, useCoreBlocksUpdateBlockSettings, useCoreBlocksUpdateComposition, useCoreBlocksValidateComposition, useCoverClose, useCoverGetStatus, useCoverOpen, useCoverSetPosition, useCoverSetTiltPosition, useCoverStop, useCustomFieldRenderer, useDataTableFilter, useDayNightGetOptions, useDayNightGetStatus, useDayNightSetSettings, useDebouncedString, useDecoderGetInfo, useDecoderReprobeHwaccel, useDetectionPipelineApplyDeviceSettingsPatch, useDetectionPipelineGetDeviceLiveContribution, useDetectionPipelineGetDeviceSettingsContribution, useDevShell, useDevice, useDeviceAdminLink, useDeviceAdminLinkGetAdminLink, 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, useDeviceExtensionListCandidates, useDeviceExtensionListSlots, useDeviceExtensionListSources, useDeviceExtensionSetSlot, useDeviceId, useDeviceListPageSize, useDeviceManagerAddLocation, useDeviceManagerAdoptDevice, useDeviceManagerAdoptionAdopt, useDeviceManagerAdoptionCancelJob, useDeviceManagerAdoptionListCandidateFilters, useDeviceManagerAdoptionListCandidates, useDeviceManagerAdoptionListJobs, useDeviceManagerAdoptionRefresh, useDeviceManagerAdoptionRelease, useDeviceManagerAdoptionResync, useDeviceManagerAdoptionStartJob, useDeviceManagerAllocateDeviceId, useDeviceManagerApplyInitialMeta, useDeviceManagerCreateDevice, useDeviceManagerDisable, useDeviceManagerDiscoverAllProviders, useDeviceManagerDiscoverDevices, useDeviceManagerDiscoverProvider, useDeviceManagerDiscoveryProviders, useDeviceManagerEnable, useDeviceManagerGetAllBindings, useDeviceManagerGetBindings, useDeviceManagerGetBindingsBatch, useDeviceManagerGetChildren, useDeviceManagerGetChildrenBatch, useDeviceManagerGetConfigSchema, useDeviceManagerGetCreationSchema, useDeviceManagerGetDevice, useDeviceManagerGetDeviceAggregate, useDeviceManagerGetDeviceLiveInfoAggregate, useDeviceManagerGetDeviceSettingsAggregate, useDeviceManagerGetDeviceStatusAggregate, useDeviceManagerGetDeviceStatusAggregateBatch, useDeviceManagerGetLinkedDevices, useDeviceManagerGetLinkedDevicesBatch, useDeviceManagerGetRoleDisplayDefaults, useDeviceManagerGetSettingsSchema, useDeviceManagerGetStreamProfileMap, useDeviceManagerGetStreamSources, useDeviceManagerGetWireableFields, useDeviceManagerGetWrapperActivation, useDeviceManagerListAll, useDeviceManagerListBindableCapsForDeviceType, useDeviceManagerListDeviceIdsByCaps, 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, useDeviceQuickDetailOpen, useDeviceSnapshot, useDeviceSnapshotImage, useDeviceState, useDeviceStateClaimFields, useDeviceStateGetAllSnapshots, useDeviceStateGetCapSlice, useDeviceStateGetNativeCapSlice, useDeviceStateGetSnapshot, useDeviceStateListClaims, useDeviceStatePatchOwnedFields, useDeviceStateReleaseClaim, useDeviceStateSetCapSlice, useDeviceStateSlice, useDeviceStatusGetStatus, useDeviceWebrtc, useDevices, useDoorbellEvents, useDoorbellGetStatus, useEnumSensorGetStatus, useEventEmitterGetStatus, useEventInvalidation, useEventStreamLatest, useEventStreamMap, 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, useKeychainAdminDeleteOrphans, useKeychainAdminDownloadRecoveryKey, useKeychainAdminListAudit, useKeychainAdminListSecrets, useKeychainAdminPurgeRetiredKeys, useKeychainAdminResetKeychain, useKeychainAdminReveal, useKeychainAdminRotateMasterKey, useKeychainAdminStatus, 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, useLocalNetworkAddCustomAddress, useLocalNetworkDownloadCa, useLocalNetworkGetAddresses, useLocalNetworkGetAllowedAddresses, useLocalNetworkGetConnectionEndpoints, useLocalNetworkGetHubAddresses, useLocalNetworkGetNotificationEndpoint, useLocalNetworkGetPreferred, useLocalNetworkGetTlsStatus, useLocalNetworkGetViewerEndpoints, useLocalNetworkList, useLocalNetworkRegenerateCertificate, useLocalNetworkRemoveCustomAddress, useLocalNetworkResetAllowlistToBestMatch, useLocalNetworkRevertToGeneratedCertificate, useLocalNetworkSetAddressRole, 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, useNodesDirectory, useNodesExecuteQuery, useNodesGetCapUsageGraph, useNodesGetNodeAddons, useNodesRenameNode, useNodesRestartAddon, useNodesRestartNode, useNodesRestartProcess, useNodesSetProcessLogLevel, useNodesShutdownNode, useNodesTopology, useNodesUndeployAddon, useNotificationOutputDeleteTarget, useNotificationOutputDiscoverTargets, useNotificationOutputGetTarget, useNotificationOutputListTargetKinds, useNotificationOutputListTargets, useNotificationOutputProbeTargetConfig, useNotificationOutputSend, useNotificationOutputSetTargetEnabled, useNotificationOutputTestTarget, useNotificationOutputUpsertTarget, useNotificationRulesActivateAlarmProfile, useNotificationRulesCancelSnooze, useNotificationRulesCreateAlarmProfile, useNotificationRulesCreateRule, useNotificationRulesCreateSequence, useNotificationRulesCreateSnooze, useNotificationRulesDeleteAlarmProfile, useNotificationRulesDeleteRule, useNotificationRulesDeleteSequence, useNotificationRulesGetAlarmConfig, useNotificationRulesGetAlarmSensors, useNotificationRulesGetClipRetentionAsks, useNotificationRulesGetConditionCatalog, useNotificationRulesGetHistory, useNotificationRulesGetRule, useNotificationRulesGetRuleLastRuns, useNotificationRulesGetSequence, useNotificationRulesGetTemplateCatalog, useNotificationRulesListDeviceMutes, useNotificationRulesListRules, useNotificationRulesListSequences, useNotificationRulesListSnoozes, useNotificationRulesPreviewStateSummary, useNotificationRulesPreviewTemplate, useNotificationRulesRenameAlarmProfile, useNotificationRulesResolveArtifactUrl, useNotificationRulesSetAlarmConfig, useNotificationRulesSetDeviceMuted, useNotificationRulesSetRuleEnabled, useNotificationRulesTestRule, useNotificationRulesUpdateRule, useNotificationRulesUpdateSequence, useNotifierCancel, useNotifierGetStatus, useNotifierSend, useNumericSensorGetStatus, useOptimisticSlice, useOptionalSystem, useOptionalWidgetRegistry, useOsdGetStatus, useOsdManagerClearSlotBinding, useOsdManagerCopyDeviceConfiguration, useOsdManagerDeleteTemplate, useOsdManagerGetConditionSupport, useOsdManagerGetDeviceOsd, useOsdManagerGetSourceCatalog, useOsdManagerListTemplates, useOsdManagerPreviewSlot, useOsdManagerRenderDevice, useOsdManagerSetSlotBinding, useOsdManagerUpsertTemplate, useOsdSetOverlay, usePTZ, usePersistedPageSize, usePetFeederCallPet, usePetFeederCancelFeed, usePetFeederFeed, usePetFeederGetStatus, usePetFeederMarkFoodReplenished, usePetFeederPlaySound, usePetFeederResetDesiccant, usePetFeederSetChildLock, usePetFeederSetFeedSound, usePetFeederSetIndicatorLight, usePetFeederSetVolume, usePickerSiteZones, usePipelineAnalyticsAddRetrainFrameFromRecording, usePipelineAnalyticsAddRetrainFramesToCollection, usePipelineAnalyticsApplyDeviceSettingsPatch, usePipelineAnalyticsCancelRelocateMedia, usePipelineAnalyticsCancelStorageMigrationMove, usePipelineAnalyticsClearTrackRelation, usePipelineAnalyticsClearTracks, usePipelineAnalyticsCompleteRetrainTrack, usePipelineAnalyticsCountRelocatableMedia, usePipelineAnalyticsCountUnstampedEventMedia, usePipelineAnalyticsCreateRetrainCollection, usePipelineAnalyticsDeleteDeviceEvents, usePipelineAnalyticsDeleteRetrainCollection, usePipelineAnalyticsDeleteTracks, usePipelineAnalyticsDeselectRetrainFrame, usePipelineAnalyticsGetActiveTracks, usePipelineAnalyticsGetAudioEvents, usePipelineAnalyticsGetDeviceLiveContribution, usePipelineAnalyticsGetDeviceSettingsContribution, usePipelineAnalyticsGetEventDensity, usePipelineAnalyticsGetEventDensityBatch, usePipelineAnalyticsGetEventMedia, usePipelineAnalyticsGetEventMediaFootprintByKind, usePipelineAnalyticsGetEventStoreFootprint, usePipelineAnalyticsGetKeyEvents, usePipelineAnalyticsGetKeyEventsBatch, usePipelineAnalyticsGetMediaReclaimStatus, usePipelineAnalyticsGetMotionEvents, usePipelineAnalyticsGetObjectEmbeddingRebuildStatus, usePipelineAnalyticsGetObjectEvents, usePipelineAnalyticsGetRetrainExportUrl, usePipelineAnalyticsGetRetrainFrameImage, usePipelineAnalyticsGetSensorEvents, usePipelineAnalyticsGetStorageMigrationMoveStatus, usePipelineAnalyticsGetTrack, usePipelineAnalyticsGetTrackMedia, usePipelineAnalyticsGetTrainingExportSummary, usePipelineAnalyticsGetTrainingExportUrl, usePipelineAnalyticsListArchivedDebugNotes, usePipelineAnalyticsListBirthDecisions, usePipelineAnalyticsListEventKinds, usePipelineAnalyticsListEventKindsBatch, usePipelineAnalyticsListEventMedia, usePipelineAnalyticsListOpsLog, usePipelineAnalyticsListRecentTracks, usePipelineAnalyticsListRelocateMediaJobs, usePipelineAnalyticsListRetrainAnnotations, usePipelineAnalyticsListRetrainAssistProfiles, usePipelineAnalyticsListRetrainCollectionFrames, usePipelineAnalyticsListRetrainCollections, usePipelineAnalyticsListRetrainFrames, usePipelineAnalyticsListRetrainStaging, usePipelineAnalyticsListTrackMedia, usePipelineAnalyticsListTrackRelations, usePipelineAnalyticsListTracks, usePipelineAnalyticsOwnersWithMedia, usePipelineAnalyticsPauseForStorageMigration, usePipelineAnalyticsProposeRetrainAnnotations, usePipelineAnalyticsProposeRetrainAnnotationsWithLlm, usePipelineAnalyticsPruneEvents, usePipelineAnalyticsPruneEventsBefore, usePipelineAnalyticsPruneTracksBefore, usePipelineAnalyticsReadLongTermSeries, usePipelineAnalyticsRebuildObjectEmbeddings, usePipelineAnalyticsReclaimDebugMedia, usePipelineAnalyticsReconcileFromDisk, usePipelineAnalyticsRefreshStorageLocationsForMigration, usePipelineAnalyticsRelocateMedia, usePipelineAnalyticsRemoveRetrainFrameFromCollection, usePipelineAnalyticsRenameRetrainCollection, usePipelineAnalyticsRestageRetrainTrack, usePipelineAnalyticsResumeForStorageMigration, usePipelineAnalyticsSaveRetrainAnnotations, usePipelineAnalyticsSearchObjectEvents, usePipelineAnalyticsSelectRetrainFrames, usePipelineAnalyticsSetRetrainFrameComplete, usePipelineAnalyticsSetTrackFlags, usePipelineAnalyticsSetTrackPurity, usePipelineAnalyticsSetTrackRelation, usePipelineAnalyticsStartStorageMigrationMove, usePipelineAnalyticsWipeAllAnalytics, usePipelineAnalyticsWipeObjectEmbeddings, usePipelineAnalyticsWriteRetrainArchive, usePipelineExecutorCacheFrameInPool, usePipelineExecutorClearDeviceOverrides, usePipelineExecutorClearModelBoundDeviceOverrides, usePipelineExecutorDeleteModel, usePipelineExecutorDownloadModel, usePipelineExecutorGetAddonModels, usePipelineExecutorGetAudioCapabilities, usePipelineExecutorGetAvailableEngines, usePipelineExecutorGetCapabilities, usePipelineExecutorGetDefaultSteps, usePipelineExecutorGetDetectionConfigSchema, usePipelineExecutorGetEffectiveTuning, usePipelineExecutorGetEngineProvisioning, usePipelineExecutorGetGlobalPipelineConfig, usePipelineExecutorGetGlobalSteps, usePipelineExecutorGetInferenceDeviceHealth, usePipelineExecutorGetOrchestratorConfigSchema, usePipelineExecutorGetReferenceAudio, usePipelineExecutorGetReferenceAudioFiles, usePipelineExecutorGetReferenceImage, usePipelineExecutorGetSchema, usePipelineExecutorGetSelectedEngine, usePipelineExecutorGetVideoPipelineSteps, usePipelineExecutorInferCached, usePipelineExecutorKillEngine, usePipelineExecutorListLoadedEngines, usePipelineExecutorListReferenceImages, usePipelineExecutorRearmInferenceDevice, usePipelineExecutorRunAudioTest, usePipelineExecutorRunPipeline, usePipelineExecutorRunPipelineBatch, usePipelineExecutorSetVideoPipelineSteps, usePipelineExecutorSpinEngine, usePipelineExecutorUncacheFrame, usePipelineExecutorValidatePipeline, usePipelineOrchestratorAbortNodeBenchmark, usePipelineOrchestratorApplyAutoTune, usePipelineOrchestratorApplyDeviceSettingsPatch, usePipelineOrchestratorAssignAudio, usePipelineOrchestratorAssignPipeline, usePipelineOrchestratorDeleteNodeBenchmarkResult, usePipelineOrchestratorGetAgentLoad, usePipelineOrchestratorGetAgentSettings, usePipelineOrchestratorGetAudioAssignment, usePipelineOrchestratorGetAudioAssignments, usePipelineOrchestratorGetAudioNodeLoad, usePipelineOrchestratorGetCameraMetrics, usePipelineOrchestratorGetCameraSettings, usePipelineOrchestratorGetCameraStatus, usePipelineOrchestratorGetCameraStatuses, usePipelineOrchestratorGetCameraStepOverrides, usePipelineOrchestratorGetCameraSwitches, usePipelineOrchestratorGetCapabilityBindings, usePipelineOrchestratorGetClusterModelChoice, usePipelineOrchestratorGetDeviceLiveContribution, usePipelineOrchestratorGetDeviceSettingsContribution, usePipelineOrchestratorGetEffectiveShares, usePipelineOrchestratorGetGlobalMetrics, usePipelineOrchestratorGetIngestOwner, usePipelineOrchestratorGetNodeBenchmarkCandidates, usePipelineOrchestratorGetNodeBenchmarkPreflight, usePipelineOrchestratorGetNodeBenchmarkStatus, usePipelineOrchestratorGetNodeInferenceDevices, usePipelineOrchestratorGetPipelineAssignment, usePipelineOrchestratorGetPipelineAssignments, usePipelineOrchestratorGetPipelineDevicePin, usePipelineOrchestratorGetPlacementStats, usePipelineOrchestratorGetReconcileFromDiskStatus, usePipelineOrchestratorListAgentSettings, usePipelineOrchestratorListNodeBenchmarkResults, usePipelineOrchestratorPauseForStorageMigration, usePipelineOrchestratorPlanAutoTune, usePipelineOrchestratorRebalance, usePipelineOrchestratorReconcileFromDisk, usePipelineOrchestratorRemoveAgentSettings, usePipelineOrchestratorRequestOccupancyLook, usePipelineOrchestratorResetNodePipelineDefaults, usePipelineOrchestratorResolvePipeline, usePipelineOrchestratorResumeForStorageMigration, usePipelineOrchestratorSetAgentCapabilities, usePipelineOrchestratorSetAgentDecodeLimits, usePipelineOrchestratorSetAgentInferenceDevices, usePipelineOrchestratorSetAgentMaxCameras, usePipelineOrchestratorSetAgentReachableHost, usePipelineOrchestratorSetCameraPipelineForAgent, usePipelineOrchestratorSetCameraSensors, usePipelineOrchestratorSetCameraStepOverride, usePipelineOrchestratorSetCameraStepSettings, usePipelineOrchestratorSetCameraStepToggle, usePipelineOrchestratorSetCameraSwitch, usePipelineOrchestratorSetCapabilityBinding, usePipelineOrchestratorSetLoadBalancingShares, usePipelineOrchestratorSetPipelineDevicePin, usePipelineOrchestratorSetShareSource, usePipelineOrchestratorStartNodeBenchmark, usePipelineOrchestratorSuggestShares, usePipelineOrchestratorUnassignAudio, usePipelineOrchestratorUnassignPipeline, usePipelineRunnerAbortNodeBench, usePipelineRunnerAttachCamera, usePipelineRunnerDetachCamera, usePipelineRunnerGetAllCameraMetrics, usePipelineRunnerGetCameraMetrics, usePipelineRunnerGetLocalCameras, usePipelineRunnerGetLocalLoad, usePipelineRunnerGetLocalMetrics, usePipelineRunnerGetNativeCrop, usePipelineRunnerGetNodeBenchStatus, usePipelineRunnerGetParkedTrackFrame, usePipelineRunnerParkTrackFrame, usePipelineRunnerReleaseParkedTrackFrames, usePipelineRunnerReportMotion, usePipelineRunnerRequestOccupancyBurst, usePipelineRunnerRunDetailSubtree, usePipelineRunnerRunStatelessStep, usePipelineRunnerStartNodeBench, 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, useRecordingArchiveApplyDeviceSettingsPatch, useRecordingArchiveCancelRelocateJob, useRecordingArchiveCancelStorageMigrationMove, useRecordingArchiveDeleteFootprint, useRecordingArchiveGetAvailabilityBatch, useRecordingArchiveGetDaysWithRecordingsBatch, useRecordingArchiveGetDeviceConfig, useRecordingArchiveGetDeviceLiveContribution, useRecordingArchiveGetDeviceSettingsContribution, useRecordingArchiveGetPlacement, useRecordingArchiveGetRelocateResidue, useRecordingArchiveGetStatus, useRecordingArchiveGetStorageMigrationMoveStatus, useRecordingArchiveGetStorageUsage, useRecordingArchiveListOpsLog, useRecordingArchiveListRelocateJobs, useRecordingArchiveLocateSegment, useRecordingArchivePauseForStorageMigration, useRecordingArchivePlanStorageRebalance, useRecordingArchivePruneFootage, useRecordingArchiveReadGopBytes, useRecordingArchiveReadSegmentBytes, useRecordingArchiveReadWindowBytes, useRecordingArchiveReconcileLedgerAgainstDisk, useRecordingArchiveRefreshStorageLocationsForMigration, useRecordingArchiveRelocateFootage, useRecordingArchiveRenderClip, useRecordingArchiveRenderGif, useRecordingArchiveRescanStorage, useRecordingArchiveResumeForStorageMigration, useRecordingArchiveSetDeviceConfig, useRecordingArchiveSetDevicePlacement, useRecordingArchiveStartStorageMigrationMove, useRecordingArchiveStartStorageRebalance, useRecordingExportCancelExport, useRecordingExportCreateExport, useRecordingExportDeleteExport, useRecordingExportGetDownloadUrl, useRecordingExportGetExport, useRecordingExportListExports, useRecordingExportReadExportBytes, useRecordingGetAvailability, useRecordingGetDaysWithRecordings, useRecordingGetPlayback, useRecordingGetPlaybackOptions, useRecordingListSources, useRecordingOnboardGetOptions, useRecordingOnboardGetStatus, useRecordingOnboardSetSettings, useRecordingSignalGetStatus, useRemoteComponent, useRoleDisplayDefaults, 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, useStoredGroupBy, useStreamBrokerAcquireEgressTranscode, useStreamBrokerApplyDeviceSettingsPatch, useStreamBrokerAssignProfile, useStreamBrokerFetchEventMedia, useStreamBrokerForgetDeviceHardware, useStreamBrokerGetAllRtspEntries, useStreamBrokerGetBrokerStats, useStreamBrokerGetDeviceAudioMute, useStreamBrokerGetDeviceLiveContribution, useStreamBrokerGetDeviceSettingsContribution, useStreamBrokerGetPreBufferInfo, useStreamBrokerGetRtspEntry, useStreamBrokerGetRtspPort, useStreamBrokerGetStreamUrl, useStreamBrokerGetStreamWithCodec, useStreamBrokerIsRtspEnabled, useStreamBrokerKillClient, useStreamBrokerListAllCameraStreams, useStreamBrokerListAllProfileSlots, useStreamBrokerListClients, useStreamBrokerProbeStream, useStreamBrokerProduceEventMedia, useStreamBrokerPublishCameraStream, useStreamBrokerPullAudioChunks, useStreamBrokerRegenerateRtspToken, useStreamBrokerReleaseEgressTranscode, useStreamBrokerReleaseStreamWithCodec, useStreamBrokerRenderPreBufferClip, useStreamBrokerReportStreamSignal, useStreamBrokerRestartProfile, useStreamBrokerRetractCameraStream, useStreamBrokerSetDeviceAudioMute, useStreamBrokerSetPreBufferDuration, useStreamBrokerSetRtspEnabled, useStreamBrokerSubscribeAudioChunks, useStreamBrokerUnassignProfile, useStreamBrokerUnsubscribeAudioChunks, 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, useUrlQueryParam, useUserManagementConfirmTotp, useUserManagementCreateApiKey, useUserManagementCreateScopedToken, useUserManagementCreateUser, useUserManagementDeleteUser, useUserManagementDisableTotp, useUserManagementFindUserByExternalIdentity, useUserManagementGetTotpStatus, useUserManagementLinkExternalIdentity, useUserManagementListApiKeys, useUserManagementListExternalIdentities, useUserManagementListOauthSessions, useUserManagementListScopedTokens, useUserManagementListUsers, useUserManagementOauthExchangeCode, useUserManagementOauthIssueCode, useUserManagementOauthRefresh, useUserManagementOauthVerifyAccessToken, useUserManagementResetPassword, useUserManagementRevokeApiKey, useUserManagementRevokeOauthSession, useUserManagementRevokeScopedToken, useUserManagementSetUserScopes, useUserManagementSetupTotp, useUserManagementUnlinkExternalIdentity, useUserManagementUpdateUser, useUserManagementValidateApiKey, useUserManagementValidateCredentials, useUserManagementValidateScopedToken, useUserManagementVerifyTotp, useVacuumControlGetStatus, useVacuumControlLocate, useVacuumControlPause, useVacuumControlReturnToBase, useVacuumControlSetFanSpeed, useVacuumControlStart, useVacuumControlStop, useValveClose, useValveGetStatus, useValveOpen, useValveSetPosition, useValveStop, useVibrationGetStatus, useVideoclipsDialClipStream, useVideoclipsGetClipPlayback, useVideoclipsGetPlaybackOptions, useVideoclipsListClips, useVideoclipsListSources, useVideoclipsOfferClipBytes, useVideoclipsReadClipBytes, useVodPlayback, useWaterHeaterGetStatus, useWaterHeaterSetAway, useWaterHeaterSetOperationMode, useWaterHeaterSetTargetTemp, useWeatherGetStatus, useWebrtcSessionAddIceCandidate, useWebrtcSessionApplyDownlinkProbe, 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, withResolvedParentDetail, withUseRootModel, writeStoredGroupBy };
|