@camstack/ui-library 1.2.332 → 1.2.333
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{MotionZonesSettings-DR1g9ja3.js → MotionZonesSettings-BCU2NW7w.js} +1 -1
- package/dist/{PrivacyMaskSettings-C9wfHkiB.js → PrivacyMaskSettings-VntwpB1u.js} +1 -1
- package/dist/{SceneMonitorEditor-CrxB3ZPL.js → SceneMonitorEditor-5N2xqurW.js} +1 -1
- package/dist/composites/device-item/header.d.ts +7 -1
- package/dist/composites/device-name/DeviceName.d.ts +17 -0
- package/dist/composites/device-name/device-fleet.d.ts +29 -0
- package/dist/composites/device-name/device-name-nouns.d.ts +27 -0
- package/dist/composites/device-name/format-device-name.d.ts +46 -0
- package/dist/composites/device-name/index.d.ts +10 -0
- package/dist/composites/device-name/use-device-label.d.ts +16 -0
- package/dist/composites/index.d.ts +1 -0
- package/dist/{icons-aFMzvquu.js → icons-Bd6sbDsv.js} +1 -35
- package/dist/{icons-pqV1UOV_.cjs → icons-CWmwnulO.cjs} +1 -35
- package/dist/index.cjs +1359 -67
- package/dist/index.js +1344 -73
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -40,6 +40,7 @@ let react_dom_client = require("react-dom/client");
|
|
|
40
40
|
react_dom_client = __toESM(react_dom_client, 1);
|
|
41
41
|
let _trpc_client = require("@trpc/client");
|
|
42
42
|
_trpc_client = __toESM(_trpc_client, 1);
|
|
43
|
+
let _camstack_types_client = require("@camstack/types/client");
|
|
43
44
|
let _camstack_sdk = require("@camstack/sdk");
|
|
44
45
|
let zod = require("zod");
|
|
45
46
|
//#region src/contexts/ui-text.tsx
|
|
@@ -4706,6 +4707,40 @@ var VolumeX = require_createLucideIcon.createLucideIcon("volume-x", [
|
|
|
4706
4707
|
* This source code is licensed under the ISC license.
|
|
4707
4708
|
* See the LICENSE file in the root directory of this source tree.
|
|
4708
4709
|
*/
|
|
4710
|
+
var WashingMachine = require_createLucideIcon.createLucideIcon("washing-machine", [
|
|
4711
|
+
["path", {
|
|
4712
|
+
d: "M3 6h3",
|
|
4713
|
+
key: "155dbl"
|
|
4714
|
+
}],
|
|
4715
|
+
["path", {
|
|
4716
|
+
d: "M17 6h.01",
|
|
4717
|
+
key: "e2y6kg"
|
|
4718
|
+
}],
|
|
4719
|
+
["rect", {
|
|
4720
|
+
width: "18",
|
|
4721
|
+
height: "20",
|
|
4722
|
+
x: "3",
|
|
4723
|
+
y: "2",
|
|
4724
|
+
rx: "2",
|
|
4725
|
+
key: "od3kk9"
|
|
4726
|
+
}],
|
|
4727
|
+
["circle", {
|
|
4728
|
+
cx: "12",
|
|
4729
|
+
cy: "13",
|
|
4730
|
+
r: "5",
|
|
4731
|
+
key: "nlbqau"
|
|
4732
|
+
}],
|
|
4733
|
+
["path", {
|
|
4734
|
+
d: "M12 18a2.5 2.5 0 0 0 0-5 2.5 2.5 0 0 1 0-5",
|
|
4735
|
+
key: "17lach"
|
|
4736
|
+
}]
|
|
4737
|
+
]);
|
|
4738
|
+
/**
|
|
4739
|
+
* @license lucide-react v0.576.0 - ISC
|
|
4740
|
+
*
|
|
4741
|
+
* This source code is licensed under the ISC license.
|
|
4742
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
4743
|
+
*/
|
|
4709
4744
|
var Waves = require_createLucideIcon.createLucideIcon("waves", [
|
|
4710
4745
|
["path", {
|
|
4711
4746
|
d: "M2 6c.6.5 1.2 1 2.5 1C7 7 7 5 9.5 5c2.6 0 2.4 2 5 2 2.5 0 2.5-2 5-2 1.3 0 1.9.5 2.5 1",
|
|
@@ -5369,6 +5404,16 @@ var DEVICE_TYPE_META = {
|
|
|
5369
5404
|
icon: Waves,
|
|
5370
5405
|
labelKey: "uiLibrary.deviceMeta.type.dishwasher",
|
|
5371
5406
|
labelFallback: "Dishwasher"
|
|
5407
|
+
},
|
|
5408
|
+
[_camstack_types.DeviceType.Washer]: {
|
|
5409
|
+
icon: WashingMachine,
|
|
5410
|
+
labelKey: "uiLibrary.deviceMeta.type.washer",
|
|
5411
|
+
labelFallback: "Washing machine"
|
|
5412
|
+
},
|
|
5413
|
+
[_camstack_types.DeviceType.Dryer]: {
|
|
5414
|
+
icon: Wind,
|
|
5415
|
+
labelKey: "uiLibrary.deviceMeta.type.dryer",
|
|
5416
|
+
labelFallback: "Dryer"
|
|
5372
5417
|
}
|
|
5373
5418
|
};
|
|
5374
5419
|
var DEVICE_ROLE_META = {
|
|
@@ -5850,7 +5895,7 @@ function lucideExportName(key) {
|
|
|
5850
5895
|
function loadIconGlyphs() {
|
|
5851
5896
|
if (fullTable !== void 0) return Promise.resolve();
|
|
5852
5897
|
if (failure$1 !== void 0) return Promise.reject(failure$1);
|
|
5853
|
-
pending ??= Promise.resolve().then(() => require("./icons-
|
|
5898
|
+
pending ??= Promise.resolve().then(() => require("./icons-CWmwnulO.cjs")).then((module) => {
|
|
5854
5899
|
fullTable = module;
|
|
5855
5900
|
publish();
|
|
5856
5901
|
}, (error) => {
|
|
@@ -19627,6 +19672,1151 @@ function AutotrackSection({ deviceId }) {
|
|
|
19627
19672
|
});
|
|
19628
19673
|
}
|
|
19629
19674
|
//#endregion
|
|
19675
|
+
//#region src/composites/device-name/device-fleet.tsx
|
|
19676
|
+
/**
|
|
19677
|
+
* One slim fleet, shared. A row reads its parent from this index — never a
|
|
19678
|
+
* `getDevice` per row (the Customize bounded-read rule). `null` is "not
|
|
19679
|
+
* answered yet": a label then keeps the stored name, so a list does not flash
|
|
19680
|
+
* `#id` while the fleet is in flight. An empty array is an answer.
|
|
19681
|
+
*/
|
|
19682
|
+
var DeviceNameIndexContext = (0, react$1.createContext)(null);
|
|
19683
|
+
function useDeviceNameIndex() {
|
|
19684
|
+
return (0, react$1.useContext)(DeviceNameIndexContext);
|
|
19685
|
+
}
|
|
19686
|
+
function copyDevice(device) {
|
|
19687
|
+
const label = device.display?.label;
|
|
19688
|
+
const trimmed = label === void 0 || label === null ? "" : label.trim();
|
|
19689
|
+
return {
|
|
19690
|
+
id: device.id,
|
|
19691
|
+
name: device.name,
|
|
19692
|
+
type: device.type,
|
|
19693
|
+
stableId: device.stableId,
|
|
19694
|
+
role: device.role ?? null,
|
|
19695
|
+
parentDeviceId: device.parentDeviceId ?? null,
|
|
19696
|
+
location: device.location ?? null,
|
|
19697
|
+
...trimmed.length > 0 ? { display: { label: trimmed } } : {},
|
|
19698
|
+
...device.primaryChildEntityId !== void 0 ? { primaryChildEntityId: device.primaryChildEntityId } : {},
|
|
19699
|
+
...device.userNamed === void 0 ? {} : { userNamed: device.userNamed }
|
|
19700
|
+
};
|
|
19701
|
+
}
|
|
19702
|
+
/** Build the parent/child maps once per fleet answer. */
|
|
19703
|
+
function indexDeviceNames(devices) {
|
|
19704
|
+
const byId = /* @__PURE__ */ new Map();
|
|
19705
|
+
const children = /* @__PURE__ */ new Map();
|
|
19706
|
+
for (const device of devices) {
|
|
19707
|
+
const fields = copyDevice(device);
|
|
19708
|
+
byId.set(fields.id, fields);
|
|
19709
|
+
const parentId = fields.parentDeviceId;
|
|
19710
|
+
if (parentId === null || parentId === void 0 || parentId === fields.id) continue;
|
|
19711
|
+
const list = children.get(parentId);
|
|
19712
|
+
if (list === void 0) children.set(parentId, [fields.id]);
|
|
19713
|
+
else list.push(fields.id);
|
|
19714
|
+
}
|
|
19715
|
+
return {
|
|
19716
|
+
byId,
|
|
19717
|
+
childIds: children
|
|
19718
|
+
};
|
|
19719
|
+
}
|
|
19720
|
+
function DeviceFleetProvider({ devices, children }) {
|
|
19721
|
+
const index = (0, react$1.useMemo)(() => devices === null ? null : indexDeviceNames(devices), [devices]);
|
|
19722
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DeviceNameIndexContext.Provider, {
|
|
19723
|
+
value: index,
|
|
19724
|
+
children
|
|
19725
|
+
});
|
|
19726
|
+
}
|
|
19727
|
+
/**
|
|
19728
|
+
* The one `deviceManager.listAll` subscriber for names. Same query key the
|
|
19729
|
+
* pickers already use, so a second observer does not fetch a second fleet.
|
|
19730
|
+
*/
|
|
19731
|
+
function DeviceFleetFromServer({ children }) {
|
|
19732
|
+
const query = useDeviceManagerListAll({ projection: "slim" });
|
|
19733
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DeviceFleetProvider, {
|
|
19734
|
+
devices: query.data === void 0 ? null : query.data,
|
|
19735
|
+
children
|
|
19736
|
+
});
|
|
19737
|
+
}
|
|
19738
|
+
//#endregion
|
|
19739
|
+
//#region src/composites/device-name/format-device-name.ts
|
|
19740
|
+
/**
|
|
19741
|
+
* One display name for a device.
|
|
19742
|
+
*
|
|
19743
|
+
* Canonical copy: `packages/ui-library/src/composites/device-name/format-device-name.ts`.
|
|
19744
|
+
* The viewer mirrors this file; `scripts/check-device-name-in-sync.ts` diffs the two.
|
|
19745
|
+
* Noun strings stay outside — this file only decides which noun to ask for.
|
|
19746
|
+
*/
|
|
19747
|
+
/** Middle dot used between a container and its noun, and before a room. */
|
|
19748
|
+
var DEVICE_NAME_JOIN = " · ";
|
|
19749
|
+
var DEVICE_NAME_FORMS = [
|
|
19750
|
+
"compact",
|
|
19751
|
+
"full",
|
|
19752
|
+
"nested",
|
|
19753
|
+
"with-location"
|
|
19754
|
+
];
|
|
19755
|
+
var PARENT_SEPARATORS = [" — ", " "];
|
|
19756
|
+
/**
|
|
19757
|
+
* Readings that are never what a container is. Matches the comment on
|
|
19758
|
+
* `CONTAINER_CHILD_ROLE_PRIORITY`: battery, temperature, humidity, illuminance,
|
|
19759
|
+
* signal, last-seen, plus numeric and enum. `update` is the same kind of row.
|
|
19760
|
+
*/
|
|
19761
|
+
var DIAGNOSTIC_ROLES = new Set([
|
|
19762
|
+
"battery-sensor",
|
|
19763
|
+
"temperature-sensor",
|
|
19764
|
+
"humidity-sensor",
|
|
19765
|
+
"ambient-light-sensor",
|
|
19766
|
+
"connectivity-sensor",
|
|
19767
|
+
"datetime-sensor",
|
|
19768
|
+
"numeric-sensor",
|
|
19769
|
+
"enum-sensor"
|
|
19770
|
+
]);
|
|
19771
|
+
/** Hyphen, underscore and whitespace fold together — the namesake comparison. */
|
|
19772
|
+
function foldDeviceName(value) {
|
|
19773
|
+
return value.toLowerCase().replace(/[-_\s]+/g, " ").trim();
|
|
19774
|
+
}
|
|
19775
|
+
function sameDeviceName(left, right) {
|
|
19776
|
+
return foldDeviceName(left) === foldDeviceName(right);
|
|
19777
|
+
}
|
|
19778
|
+
/**
|
|
19779
|
+
* Drop a parent prefix. `" — "` before a space, case-insensitive, so a provider
|
|
19780
|
+
* that capitalised the parent differently still strips, and an em-dash child
|
|
19781
|
+
* does not keep a dangling dash.
|
|
19782
|
+
*/
|
|
19783
|
+
function stripDeviceParentPrefix(name, parentName) {
|
|
19784
|
+
if (parentName.length === 0) return name;
|
|
19785
|
+
const nameFold = name.toLowerCase();
|
|
19786
|
+
const parentFold = parentName.toLowerCase();
|
|
19787
|
+
for (const separator of PARENT_SEPARATORS) {
|
|
19788
|
+
const prefix = `${parentFold}${separator}`;
|
|
19789
|
+
if (!nameFold.startsWith(prefix)) continue;
|
|
19790
|
+
return name.slice(prefix.length).trim();
|
|
19791
|
+
}
|
|
19792
|
+
return name;
|
|
19793
|
+
}
|
|
19794
|
+
function roleOf(device) {
|
|
19795
|
+
const role = device.role;
|
|
19796
|
+
if (role === void 0 || role === null || role.length === 0) return null;
|
|
19797
|
+
return role;
|
|
19798
|
+
}
|
|
19799
|
+
function isDiagnostic(device) {
|
|
19800
|
+
if (device.type === "update") return true;
|
|
19801
|
+
const role = roleOf(device);
|
|
19802
|
+
return role !== null && DIAGNOSTIC_ROLES.has(role);
|
|
19803
|
+
}
|
|
19804
|
+
function displayLabel(device) {
|
|
19805
|
+
const label = device.display?.label;
|
|
19806
|
+
if (label === void 0 || label === null) return "";
|
|
19807
|
+
return label.trim();
|
|
19808
|
+
}
|
|
19809
|
+
function nounOf(device, parent, nouns) {
|
|
19810
|
+
const caption = displayLabel(device);
|
|
19811
|
+
if (caption.length > 0) return caption;
|
|
19812
|
+
const stripped = stripDeviceParentPrefix(device.name, parent.name);
|
|
19813
|
+
const shown = stripped.length > 0 ? stripped : device.name;
|
|
19814
|
+
if (device.userNamed === true) return shown;
|
|
19815
|
+
if (stripped.length === 0 || sameDeviceName(stripped, parent.name) || nouns.isStockPhrase(shown, roleOf(device), device.type)) return nouns.shortNoun(roleOf(device), device.type);
|
|
19816
|
+
return shown;
|
|
19817
|
+
}
|
|
19818
|
+
function foldsIntoParent(device, parent, noun) {
|
|
19819
|
+
if (sameDeviceName(noun, parent.name)) return true;
|
|
19820
|
+
if (displayLabel(device).length > 0 || device.userNamed === true) return false;
|
|
19821
|
+
return sameDeviceName(stripDeviceParentPrefix(device.name, parent.name), parent.name);
|
|
19822
|
+
}
|
|
19823
|
+
function meaningfulChildCount(siblings) {
|
|
19824
|
+
let count = 0;
|
|
19825
|
+
for (const sibling of siblings) if (!isDiagnostic(sibling)) count += 1;
|
|
19826
|
+
return count;
|
|
19827
|
+
}
|
|
19828
|
+
function isContainerPrimary(device, parent, siblings) {
|
|
19829
|
+
const picked = (0, _camstack_types_client.resolveContainerPrimaryChild)(siblings.map((sibling) => {
|
|
19830
|
+
const role = roleOf(sibling);
|
|
19831
|
+
return {
|
|
19832
|
+
id: sibling.id,
|
|
19833
|
+
stableId: sibling.stableId,
|
|
19834
|
+
type: sibling.type,
|
|
19835
|
+
name: sibling.name,
|
|
19836
|
+
...role === null ? {} : { role }
|
|
19837
|
+
};
|
|
19838
|
+
}), parent.primaryChildEntityId, parent.name);
|
|
19839
|
+
return picked !== null && picked.id === device.id;
|
|
19840
|
+
}
|
|
19841
|
+
function childLine(device, parent, siblings, nouns, form) {
|
|
19842
|
+
const noun = nounOf(device, parent, nouns);
|
|
19843
|
+
if (foldsIntoParent(device, parent, noun)) return parent.name;
|
|
19844
|
+
if (form === "compact" && parent.type === "container" && isContainerPrimary(device, parent, siblings) && meaningfulChildCount(siblings) === 1) return parent.name;
|
|
19845
|
+
return `${parent.name}${DEVICE_NAME_JOIN}${noun}`;
|
|
19846
|
+
}
|
|
19847
|
+
function joinLocation(label, location) {
|
|
19848
|
+
if (location === void 0 || location === null) return label;
|
|
19849
|
+
const room = location.trim();
|
|
19850
|
+
if (room.length === 0) return label;
|
|
19851
|
+
if (label.split(" · ").some((segment) => sameDeviceName(segment, room))) return label;
|
|
19852
|
+
return `${label}${DEVICE_NAME_JOIN}${room}`;
|
|
19853
|
+
}
|
|
19854
|
+
function hasParent(device, parent) {
|
|
19855
|
+
if (parent === null) return false;
|
|
19856
|
+
const parentId = device.parentDeviceId;
|
|
19857
|
+
return parentId !== null && parentId !== void 0;
|
|
19858
|
+
}
|
|
19859
|
+
/**
|
|
19860
|
+
* The label for `form`. A top-level device keeps its stored name. A child uses
|
|
19861
|
+
* the noun: `compact` may stand in for the container when this child is what
|
|
19862
|
+
* the container is, `full` always names both unless they fold together,
|
|
19863
|
+
* `nested` is the noun alone, `with-location` is `compact` plus the room.
|
|
19864
|
+
*/
|
|
19865
|
+
function formatDeviceName(device, form, context, nouns) {
|
|
19866
|
+
if (!hasParent(device, context.parent)) return form === "with-location" ? joinLocation(device.name, device.location) : device.name;
|
|
19867
|
+
if (form === "nested") return nounOf(device, context.parent, nouns);
|
|
19868
|
+
const line = childLine(device, context.parent, context.siblings, nouns, form === "full" ? "full" : "compact");
|
|
19869
|
+
return form === "with-location" ? joinLocation(line, device.location) : line;
|
|
19870
|
+
}
|
|
19871
|
+
//#endregion
|
|
19872
|
+
//#region src/composites/device-name/device-name-nouns.ts
|
|
19873
|
+
/**
|
|
19874
|
+
* Short nouns and the stock words they replace.
|
|
19875
|
+
*
|
|
19876
|
+
* Long labels are the existing role and type names, both locales, so a stored
|
|
19877
|
+
* "Motion sensor" and a stored "Sensore di movimento" are the same stock word.
|
|
19878
|
+
* The short noun is what a list shows. Where the long label is already one
|
|
19879
|
+
* word it is the short noun. Aliases are provider stock words that are not the
|
|
19880
|
+
* label ("Illumination", "Last seen").
|
|
19881
|
+
*/
|
|
19882
|
+
var DEVICE_ROLE_NOUNS = [
|
|
19883
|
+
{
|
|
19884
|
+
id: "siren",
|
|
19885
|
+
key: "uiLibrary.deviceMeta.noun.role.siren",
|
|
19886
|
+
en: "Siren",
|
|
19887
|
+
it: "Sirena",
|
|
19888
|
+
shortEn: "Siren",
|
|
19889
|
+
shortIt: "Sirena",
|
|
19890
|
+
aliases: []
|
|
19891
|
+
},
|
|
19892
|
+
{
|
|
19893
|
+
id: "floodlight",
|
|
19894
|
+
key: "uiLibrary.deviceMeta.noun.role.floodlight",
|
|
19895
|
+
en: "Floodlight",
|
|
19896
|
+
it: "Faro",
|
|
19897
|
+
shortEn: "Floodlight",
|
|
19898
|
+
shortIt: "Faro",
|
|
19899
|
+
aliases: []
|
|
19900
|
+
},
|
|
19901
|
+
{
|
|
19902
|
+
id: "spotlight",
|
|
19903
|
+
key: "uiLibrary.deviceMeta.noun.role.spotlight",
|
|
19904
|
+
en: "Spotlight",
|
|
19905
|
+
it: "Faretto",
|
|
19906
|
+
shortEn: "Spotlight",
|
|
19907
|
+
shortIt: "Faretto",
|
|
19908
|
+
aliases: []
|
|
19909
|
+
},
|
|
19910
|
+
{
|
|
19911
|
+
id: "pir-sensor",
|
|
19912
|
+
key: "uiLibrary.deviceMeta.noun.role.pirSensor",
|
|
19913
|
+
en: "PIR sensor",
|
|
19914
|
+
it: "Sensore PIR",
|
|
19915
|
+
shortEn: "PIR",
|
|
19916
|
+
shortIt: "PIR",
|
|
19917
|
+
aliases: []
|
|
19918
|
+
},
|
|
19919
|
+
{
|
|
19920
|
+
id: "chime",
|
|
19921
|
+
key: "uiLibrary.deviceMeta.noun.role.chime",
|
|
19922
|
+
en: "Chime",
|
|
19923
|
+
it: "Campanello",
|
|
19924
|
+
shortEn: "Chime",
|
|
19925
|
+
shortIt: "Campanello",
|
|
19926
|
+
aliases: []
|
|
19927
|
+
},
|
|
19928
|
+
{
|
|
19929
|
+
id: "autotrack",
|
|
19930
|
+
key: "uiLibrary.deviceMeta.noun.role.autotrack",
|
|
19931
|
+
en: "Auto-track",
|
|
19932
|
+
it: "Auto-tracking",
|
|
19933
|
+
shortEn: "Auto-track",
|
|
19934
|
+
shortIt: "Auto-tracking",
|
|
19935
|
+
aliases: []
|
|
19936
|
+
},
|
|
19937
|
+
{
|
|
19938
|
+
id: "nightvision",
|
|
19939
|
+
key: "uiLibrary.deviceMeta.noun.role.nightvision",
|
|
19940
|
+
en: "Night vision",
|
|
19941
|
+
it: "Visione notturna",
|
|
19942
|
+
shortEn: "Night",
|
|
19943
|
+
shortIt: "Notturna",
|
|
19944
|
+
aliases: []
|
|
19945
|
+
},
|
|
19946
|
+
{
|
|
19947
|
+
id: "privacy-mask",
|
|
19948
|
+
key: "uiLibrary.deviceMeta.noun.role.privacyMask",
|
|
19949
|
+
en: "Privacy mask",
|
|
19950
|
+
it: "Maschera privacy",
|
|
19951
|
+
shortEn: "Privacy",
|
|
19952
|
+
shortIt: "Privacy",
|
|
19953
|
+
aliases: []
|
|
19954
|
+
},
|
|
19955
|
+
{
|
|
19956
|
+
id: "doorbell",
|
|
19957
|
+
key: "uiLibrary.deviceMeta.noun.role.doorbell",
|
|
19958
|
+
en: "Doorbell",
|
|
19959
|
+
it: "Campanello video",
|
|
19960
|
+
shortEn: "Doorbell",
|
|
19961
|
+
shortIt: "Campanello video",
|
|
19962
|
+
aliases: []
|
|
19963
|
+
},
|
|
19964
|
+
{
|
|
19965
|
+
id: "cover-blind",
|
|
19966
|
+
key: "uiLibrary.deviceMeta.noun.role.coverBlind",
|
|
19967
|
+
en: "Blind",
|
|
19968
|
+
it: "Tapparella",
|
|
19969
|
+
shortEn: "Blind",
|
|
19970
|
+
shortIt: "Tapparella",
|
|
19971
|
+
aliases: []
|
|
19972
|
+
},
|
|
19973
|
+
{
|
|
19974
|
+
id: "cover-shutter",
|
|
19975
|
+
key: "uiLibrary.deviceMeta.noun.role.coverShutter",
|
|
19976
|
+
en: "Shutter",
|
|
19977
|
+
it: "Persiana",
|
|
19978
|
+
shortEn: "Shutter",
|
|
19979
|
+
shortIt: "Persiana",
|
|
19980
|
+
aliases: []
|
|
19981
|
+
},
|
|
19982
|
+
{
|
|
19983
|
+
id: "cover-awning",
|
|
19984
|
+
key: "uiLibrary.deviceMeta.noun.role.coverAwning",
|
|
19985
|
+
en: "Awning",
|
|
19986
|
+
it: "Tenda da sole",
|
|
19987
|
+
shortEn: "Awning",
|
|
19988
|
+
shortIt: "Tenda da sole",
|
|
19989
|
+
aliases: []
|
|
19990
|
+
},
|
|
19991
|
+
{
|
|
19992
|
+
id: "cover-curtain",
|
|
19993
|
+
key: "uiLibrary.deviceMeta.noun.role.coverCurtain",
|
|
19994
|
+
en: "Curtain",
|
|
19995
|
+
it: "Tenda",
|
|
19996
|
+
shortEn: "Curtain",
|
|
19997
|
+
shortIt: "Tenda",
|
|
19998
|
+
aliases: []
|
|
19999
|
+
},
|
|
20000
|
+
{
|
|
20001
|
+
id: "cover-garage",
|
|
20002
|
+
key: "uiLibrary.deviceMeta.noun.role.coverGarage",
|
|
20003
|
+
en: "Garage door",
|
|
20004
|
+
it: "Porta del garage",
|
|
20005
|
+
shortEn: "Garage",
|
|
20006
|
+
shortIt: "Garage",
|
|
20007
|
+
aliases: []
|
|
20008
|
+
},
|
|
20009
|
+
{
|
|
20010
|
+
id: "cover-gate",
|
|
20011
|
+
key: "uiLibrary.deviceMeta.noun.role.coverGate",
|
|
20012
|
+
en: "Gate",
|
|
20013
|
+
it: "Cancello",
|
|
20014
|
+
shortEn: "Gate",
|
|
20015
|
+
shortIt: "Cancello",
|
|
20016
|
+
aliases: []
|
|
20017
|
+
},
|
|
20018
|
+
{
|
|
20019
|
+
id: "cover-door",
|
|
20020
|
+
key: "uiLibrary.deviceMeta.noun.role.coverDoor",
|
|
20021
|
+
en: "Door",
|
|
20022
|
+
it: "Porta",
|
|
20023
|
+
shortEn: "Door",
|
|
20024
|
+
shortIt: "Porta",
|
|
20025
|
+
aliases: []
|
|
20026
|
+
},
|
|
20027
|
+
{
|
|
20028
|
+
id: "cover-window",
|
|
20029
|
+
key: "uiLibrary.deviceMeta.noun.role.coverWindow",
|
|
20030
|
+
en: "Window",
|
|
20031
|
+
it: "Finestra",
|
|
20032
|
+
shortEn: "Window",
|
|
20033
|
+
shortIt: "Finestra",
|
|
20034
|
+
aliases: []
|
|
20035
|
+
},
|
|
20036
|
+
{
|
|
20037
|
+
id: "binary-helper",
|
|
20038
|
+
key: "uiLibrary.deviceMeta.noun.role.binaryHelper",
|
|
20039
|
+
en: "Binary helper",
|
|
20040
|
+
it: "Helper binario",
|
|
20041
|
+
shortEn: "Helper",
|
|
20042
|
+
shortIt: "Helper",
|
|
20043
|
+
aliases: []
|
|
20044
|
+
},
|
|
20045
|
+
{
|
|
20046
|
+
id: "outlet",
|
|
20047
|
+
key: "uiLibrary.deviceMeta.noun.role.outlet",
|
|
20048
|
+
en: "Outlet",
|
|
20049
|
+
it: "Presa",
|
|
20050
|
+
shortEn: "Outlet",
|
|
20051
|
+
shortIt: "Presa",
|
|
20052
|
+
aliases: []
|
|
20053
|
+
},
|
|
20054
|
+
{
|
|
20055
|
+
id: "motion-sensor",
|
|
20056
|
+
key: "uiLibrary.deviceMeta.noun.role.motionSensor",
|
|
20057
|
+
en: "Motion sensor",
|
|
20058
|
+
it: "Sensore di movimento",
|
|
20059
|
+
shortEn: "Motion",
|
|
20060
|
+
shortIt: "Movimento",
|
|
20061
|
+
aliases: []
|
|
20062
|
+
},
|
|
20063
|
+
{
|
|
20064
|
+
id: "contact-sensor",
|
|
20065
|
+
key: "uiLibrary.deviceMeta.noun.role.contactSensor",
|
|
20066
|
+
en: "Contact sensor",
|
|
20067
|
+
it: "Sensore di contatto",
|
|
20068
|
+
shortEn: "Contact",
|
|
20069
|
+
shortIt: "Contatto",
|
|
20070
|
+
aliases: []
|
|
20071
|
+
},
|
|
20072
|
+
{
|
|
20073
|
+
id: "leak-sensor",
|
|
20074
|
+
key: "uiLibrary.deviceMeta.noun.role.leakSensor",
|
|
20075
|
+
en: "Leak sensor",
|
|
20076
|
+
it: "Sensore di perdite",
|
|
20077
|
+
shortEn: "Leak",
|
|
20078
|
+
shortIt: "Perdita",
|
|
20079
|
+
aliases: []
|
|
20080
|
+
},
|
|
20081
|
+
{
|
|
20082
|
+
id: "smoke-sensor",
|
|
20083
|
+
key: "uiLibrary.deviceMeta.noun.role.smokeSensor",
|
|
20084
|
+
en: "Smoke sensor",
|
|
20085
|
+
it: "Sensore di fumo",
|
|
20086
|
+
shortEn: "Smoke",
|
|
20087
|
+
shortIt: "Fumo",
|
|
20088
|
+
aliases: []
|
|
20089
|
+
},
|
|
20090
|
+
{
|
|
20091
|
+
id: "co-sensor",
|
|
20092
|
+
key: "uiLibrary.deviceMeta.noun.role.cOSensor",
|
|
20093
|
+
en: "CO sensor",
|
|
20094
|
+
it: "Sensore di CO",
|
|
20095
|
+
shortEn: "CO",
|
|
20096
|
+
shortIt: "CO",
|
|
20097
|
+
aliases: []
|
|
20098
|
+
},
|
|
20099
|
+
{
|
|
20100
|
+
id: "gas-sensor",
|
|
20101
|
+
key: "uiLibrary.deviceMeta.noun.role.gasSensor",
|
|
20102
|
+
en: "Gas sensor",
|
|
20103
|
+
it: "Sensore di gas",
|
|
20104
|
+
shortEn: "Gas",
|
|
20105
|
+
shortIt: "Gas",
|
|
20106
|
+
aliases: []
|
|
20107
|
+
},
|
|
20108
|
+
{
|
|
20109
|
+
id: "tamper-sensor",
|
|
20110
|
+
key: "uiLibrary.deviceMeta.noun.role.tamperSensor",
|
|
20111
|
+
en: "Tamper sensor",
|
|
20112
|
+
it: "Sensore antimanomissione",
|
|
20113
|
+
shortEn: "Tamper",
|
|
20114
|
+
shortIt: "Manomissione",
|
|
20115
|
+
aliases: []
|
|
20116
|
+
},
|
|
20117
|
+
{
|
|
20118
|
+
id: "vibration-sensor",
|
|
20119
|
+
key: "uiLibrary.deviceMeta.noun.role.vibrationSensor",
|
|
20120
|
+
en: "Vibration sensor",
|
|
20121
|
+
it: "Sensore di vibrazione",
|
|
20122
|
+
shortEn: "Vibration",
|
|
20123
|
+
shortIt: "Vibrazione",
|
|
20124
|
+
aliases: []
|
|
20125
|
+
},
|
|
20126
|
+
{
|
|
20127
|
+
id: "connectivity-sensor",
|
|
20128
|
+
key: "uiLibrary.deviceMeta.noun.role.connectivitySensor",
|
|
20129
|
+
en: "Connectivity",
|
|
20130
|
+
it: "Connettività",
|
|
20131
|
+
shortEn: "Connectivity",
|
|
20132
|
+
shortIt: "Connettività",
|
|
20133
|
+
aliases: []
|
|
20134
|
+
},
|
|
20135
|
+
{
|
|
20136
|
+
id: "sound-sensor",
|
|
20137
|
+
key: "uiLibrary.deviceMeta.noun.role.soundSensor",
|
|
20138
|
+
en: "Sound sensor",
|
|
20139
|
+
it: "Sensore acustico",
|
|
20140
|
+
shortEn: "Sound",
|
|
20141
|
+
shortIt: "Suono",
|
|
20142
|
+
aliases: []
|
|
20143
|
+
},
|
|
20144
|
+
{
|
|
20145
|
+
id: "binary-sensor",
|
|
20146
|
+
key: "uiLibrary.deviceMeta.noun.role.binarySensor",
|
|
20147
|
+
en: "Binary sensor",
|
|
20148
|
+
it: "Sensore binario",
|
|
20149
|
+
shortEn: "Binary",
|
|
20150
|
+
shortIt: "Binario",
|
|
20151
|
+
aliases: []
|
|
20152
|
+
},
|
|
20153
|
+
{
|
|
20154
|
+
id: "temperature-sensor",
|
|
20155
|
+
key: "uiLibrary.deviceMeta.noun.role.temperatureSensor",
|
|
20156
|
+
en: "Temperature",
|
|
20157
|
+
it: "Temperatura",
|
|
20158
|
+
shortEn: "Temperature",
|
|
20159
|
+
shortIt: "Temperatura",
|
|
20160
|
+
aliases: []
|
|
20161
|
+
},
|
|
20162
|
+
{
|
|
20163
|
+
id: "humidity-sensor",
|
|
20164
|
+
key: "uiLibrary.deviceMeta.noun.role.humiditySensor",
|
|
20165
|
+
en: "Humidity",
|
|
20166
|
+
it: "Umidità",
|
|
20167
|
+
shortEn: "Humidity",
|
|
20168
|
+
shortIt: "Umidità",
|
|
20169
|
+
aliases: []
|
|
20170
|
+
},
|
|
20171
|
+
{
|
|
20172
|
+
id: "ambient-light-sensor",
|
|
20173
|
+
key: "uiLibrary.deviceMeta.noun.role.ambientLightSensor",
|
|
20174
|
+
en: "Ambient light",
|
|
20175
|
+
it: "Luce ambientale",
|
|
20176
|
+
shortEn: "Light",
|
|
20177
|
+
shortIt: "Luce",
|
|
20178
|
+
aliases: ["Illumination"]
|
|
20179
|
+
},
|
|
20180
|
+
{
|
|
20181
|
+
id: "pressure-sensor",
|
|
20182
|
+
key: "uiLibrary.deviceMeta.noun.role.pressureSensor",
|
|
20183
|
+
en: "Pressure",
|
|
20184
|
+
it: "Pressione",
|
|
20185
|
+
shortEn: "Pressure",
|
|
20186
|
+
shortIt: "Pressione",
|
|
20187
|
+
aliases: []
|
|
20188
|
+
},
|
|
20189
|
+
{
|
|
20190
|
+
id: "wind-sensor",
|
|
20191
|
+
key: "uiLibrary.deviceMeta.noun.role.windSensor",
|
|
20192
|
+
en: "Wind",
|
|
20193
|
+
it: "Vento",
|
|
20194
|
+
shortEn: "Wind",
|
|
20195
|
+
shortIt: "Vento",
|
|
20196
|
+
aliases: []
|
|
20197
|
+
},
|
|
20198
|
+
{
|
|
20199
|
+
id: "rain-sensor",
|
|
20200
|
+
key: "uiLibrary.deviceMeta.noun.role.rainSensor",
|
|
20201
|
+
en: "Rain",
|
|
20202
|
+
it: "Pioggia",
|
|
20203
|
+
shortEn: "Rain",
|
|
20204
|
+
shortIt: "Pioggia",
|
|
20205
|
+
aliases: []
|
|
20206
|
+
},
|
|
20207
|
+
{
|
|
20208
|
+
id: "uv-sensor",
|
|
20209
|
+
key: "uiLibrary.deviceMeta.noun.role.uvSensor",
|
|
20210
|
+
en: "UV index",
|
|
20211
|
+
it: "Indice UV",
|
|
20212
|
+
shortEn: "UV index",
|
|
20213
|
+
shortIt: "Indice UV",
|
|
20214
|
+
aliases: []
|
|
20215
|
+
},
|
|
20216
|
+
{
|
|
20217
|
+
id: "solar-radiation-sensor",
|
|
20218
|
+
key: "uiLibrary.deviceMeta.noun.role.solarRadiationSensor",
|
|
20219
|
+
en: "Solar radiation",
|
|
20220
|
+
it: "Radiazione solare",
|
|
20221
|
+
shortEn: "Solar radiation",
|
|
20222
|
+
shortIt: "Radiazione solare",
|
|
20223
|
+
aliases: []
|
|
20224
|
+
},
|
|
20225
|
+
{
|
|
20226
|
+
id: "soil-moisture-sensor",
|
|
20227
|
+
key: "uiLibrary.deviceMeta.noun.role.soilMoistureSensor",
|
|
20228
|
+
en: "Soil moisture",
|
|
20229
|
+
it: "Umidità del suolo",
|
|
20230
|
+
shortEn: "Soil moisture",
|
|
20231
|
+
shortIt: "Umidità del suolo",
|
|
20232
|
+
aliases: []
|
|
20233
|
+
},
|
|
20234
|
+
{
|
|
20235
|
+
id: "power-sensor",
|
|
20236
|
+
key: "uiLibrary.deviceMeta.noun.role.powerSensor",
|
|
20237
|
+
en: "Power",
|
|
20238
|
+
it: "Potenza",
|
|
20239
|
+
shortEn: "Power",
|
|
20240
|
+
shortIt: "Potenza",
|
|
20241
|
+
aliases: []
|
|
20242
|
+
},
|
|
20243
|
+
{
|
|
20244
|
+
id: "energy-sensor",
|
|
20245
|
+
key: "uiLibrary.deviceMeta.noun.role.energySensor",
|
|
20246
|
+
en: "Energy",
|
|
20247
|
+
it: "Energia",
|
|
20248
|
+
shortEn: "Energy",
|
|
20249
|
+
shortIt: "Energia",
|
|
20250
|
+
aliases: []
|
|
20251
|
+
},
|
|
20252
|
+
{
|
|
20253
|
+
id: "voltage-sensor",
|
|
20254
|
+
key: "uiLibrary.deviceMeta.noun.role.voltageSensor",
|
|
20255
|
+
en: "Voltage",
|
|
20256
|
+
it: "Tensione",
|
|
20257
|
+
shortEn: "Voltage",
|
|
20258
|
+
shortIt: "Tensione",
|
|
20259
|
+
aliases: []
|
|
20260
|
+
},
|
|
20261
|
+
{
|
|
20262
|
+
id: "current-sensor",
|
|
20263
|
+
key: "uiLibrary.deviceMeta.noun.role.currentSensor",
|
|
20264
|
+
en: "Current",
|
|
20265
|
+
it: "Corrente",
|
|
20266
|
+
shortEn: "Current",
|
|
20267
|
+
shortIt: "Corrente",
|
|
20268
|
+
aliases: []
|
|
20269
|
+
},
|
|
20270
|
+
{
|
|
20271
|
+
id: "air-quality-sensor",
|
|
20272
|
+
key: "uiLibrary.deviceMeta.noun.role.airQualitySensor",
|
|
20273
|
+
en: "Air quality",
|
|
20274
|
+
it: "Qualità dell’aria",
|
|
20275
|
+
shortEn: "Air quality",
|
|
20276
|
+
shortIt: "Qualità dell’aria",
|
|
20277
|
+
aliases: []
|
|
20278
|
+
},
|
|
20279
|
+
{
|
|
20280
|
+
id: "battery-sensor",
|
|
20281
|
+
key: "uiLibrary.deviceMeta.noun.role.batterySensor",
|
|
20282
|
+
en: "Battery",
|
|
20283
|
+
it: "Batteria",
|
|
20284
|
+
shortEn: "Battery",
|
|
20285
|
+
shortIt: "Batteria",
|
|
20286
|
+
aliases: []
|
|
20287
|
+
},
|
|
20288
|
+
{
|
|
20289
|
+
id: "numeric-sensor",
|
|
20290
|
+
key: "uiLibrary.deviceMeta.noun.role.numericSensor",
|
|
20291
|
+
en: "Numeric sensor",
|
|
20292
|
+
it: "Sensore numerico",
|
|
20293
|
+
shortEn: "Value",
|
|
20294
|
+
shortIt: "Numerico",
|
|
20295
|
+
aliases: []
|
|
20296
|
+
},
|
|
20297
|
+
{
|
|
20298
|
+
id: "enum-sensor",
|
|
20299
|
+
key: "uiLibrary.deviceMeta.noun.role.enumSensor",
|
|
20300
|
+
en: "Enum sensor",
|
|
20301
|
+
it: "Sensore a stati",
|
|
20302
|
+
shortEn: "State",
|
|
20303
|
+
shortIt: "Stato",
|
|
20304
|
+
aliases: []
|
|
20305
|
+
},
|
|
20306
|
+
{
|
|
20307
|
+
id: "datetime-sensor",
|
|
20308
|
+
key: "uiLibrary.deviceMeta.noun.role.dateTimeSensor",
|
|
20309
|
+
en: "Date / time",
|
|
20310
|
+
it: "Data / ora",
|
|
20311
|
+
shortEn: "Time",
|
|
20312
|
+
shortIt: "Ora",
|
|
20313
|
+
aliases: ["Last seen"]
|
|
20314
|
+
},
|
|
20315
|
+
{
|
|
20316
|
+
id: "generic-sensor",
|
|
20317
|
+
key: "uiLibrary.deviceMeta.noun.role.genericSensor",
|
|
20318
|
+
en: "Sensor",
|
|
20319
|
+
it: "Sensore",
|
|
20320
|
+
shortEn: "Sensor",
|
|
20321
|
+
shortIt: "Sensore",
|
|
20322
|
+
aliases: []
|
|
20323
|
+
},
|
|
20324
|
+
{
|
|
20325
|
+
id: "numeric-control",
|
|
20326
|
+
key: "uiLibrary.deviceMeta.noun.role.numericControl",
|
|
20327
|
+
en: "Numeric control",
|
|
20328
|
+
it: "Controllo numerico",
|
|
20329
|
+
shortEn: "Number",
|
|
20330
|
+
shortIt: "Numero",
|
|
20331
|
+
aliases: []
|
|
20332
|
+
},
|
|
20333
|
+
{
|
|
20334
|
+
id: "select-control",
|
|
20335
|
+
key: "uiLibrary.deviceMeta.noun.role.selectControl",
|
|
20336
|
+
en: "Select control",
|
|
20337
|
+
it: "Controllo a selezione",
|
|
20338
|
+
shortEn: "Select",
|
|
20339
|
+
shortIt: "Selezione",
|
|
20340
|
+
aliases: []
|
|
20341
|
+
},
|
|
20342
|
+
{
|
|
20343
|
+
id: "text-control",
|
|
20344
|
+
key: "uiLibrary.deviceMeta.noun.role.textControl",
|
|
20345
|
+
en: "Text control",
|
|
20346
|
+
it: "Controllo testo",
|
|
20347
|
+
shortEn: "Text",
|
|
20348
|
+
shortIt: "Testo",
|
|
20349
|
+
aliases: []
|
|
20350
|
+
},
|
|
20351
|
+
{
|
|
20352
|
+
id: "datetime-control",
|
|
20353
|
+
key: "uiLibrary.deviceMeta.noun.role.dateTimeControl",
|
|
20354
|
+
en: "Date / time control",
|
|
20355
|
+
it: "Controllo data / ora",
|
|
20356
|
+
shortEn: "Time",
|
|
20357
|
+
shortIt: "Ora",
|
|
20358
|
+
aliases: []
|
|
20359
|
+
},
|
|
20360
|
+
{
|
|
20361
|
+
id: "mobile-push-notifier",
|
|
20362
|
+
key: "uiLibrary.deviceMeta.noun.role.mobilePushNotifier",
|
|
20363
|
+
en: "Mobile push",
|
|
20364
|
+
it: "Push su mobile",
|
|
20365
|
+
shortEn: "Push",
|
|
20366
|
+
shortIt: "Push",
|
|
20367
|
+
aliases: []
|
|
20368
|
+
},
|
|
20369
|
+
{
|
|
20370
|
+
id: "messaging-notifier",
|
|
20371
|
+
key: "uiLibrary.deviceMeta.noun.role.messagingNotifier",
|
|
20372
|
+
en: "Messaging",
|
|
20373
|
+
it: "Messaggistica",
|
|
20374
|
+
shortEn: "Messaging",
|
|
20375
|
+
shortIt: "Messaggistica",
|
|
20376
|
+
aliases: []
|
|
20377
|
+
},
|
|
20378
|
+
{
|
|
20379
|
+
id: "email-notifier",
|
|
20380
|
+
key: "uiLibrary.deviceMeta.noun.role.emailNotifier",
|
|
20381
|
+
en: "Email",
|
|
20382
|
+
it: "Email",
|
|
20383
|
+
shortEn: "Email",
|
|
20384
|
+
shortIt: "Email",
|
|
20385
|
+
aliases: []
|
|
20386
|
+
},
|
|
20387
|
+
{
|
|
20388
|
+
id: "generic-notifier",
|
|
20389
|
+
key: "uiLibrary.deviceMeta.noun.role.genericNotifier",
|
|
20390
|
+
en: "Notifier",
|
|
20391
|
+
it: "Notificatore",
|
|
20392
|
+
shortEn: "Notifier",
|
|
20393
|
+
shortIt: "Notificatore",
|
|
20394
|
+
aliases: []
|
|
20395
|
+
}
|
|
20396
|
+
];
|
|
20397
|
+
var DEVICE_TYPE_NOUNS = [
|
|
20398
|
+
{
|
|
20399
|
+
id: "camera",
|
|
20400
|
+
key: "uiLibrary.deviceMeta.noun.type.camera",
|
|
20401
|
+
en: "Camera",
|
|
20402
|
+
it: "Telecamera",
|
|
20403
|
+
shortEn: "Camera",
|
|
20404
|
+
shortIt: "Telecamera",
|
|
20405
|
+
aliases: []
|
|
20406
|
+
},
|
|
20407
|
+
{
|
|
20408
|
+
id: "hub",
|
|
20409
|
+
key: "uiLibrary.deviceMeta.noun.type.hub",
|
|
20410
|
+
en: "Hub",
|
|
20411
|
+
it: "Hub",
|
|
20412
|
+
shortEn: "Hub",
|
|
20413
|
+
shortIt: "Hub",
|
|
20414
|
+
aliases: []
|
|
20415
|
+
},
|
|
20416
|
+
{
|
|
20417
|
+
id: "light",
|
|
20418
|
+
key: "uiLibrary.deviceMeta.noun.type.light",
|
|
20419
|
+
en: "Light",
|
|
20420
|
+
it: "Luce",
|
|
20421
|
+
shortEn: "Light",
|
|
20422
|
+
shortIt: "Luce",
|
|
20423
|
+
aliases: []
|
|
20424
|
+
},
|
|
20425
|
+
{
|
|
20426
|
+
id: "siren",
|
|
20427
|
+
key: "uiLibrary.deviceMeta.noun.type.siren",
|
|
20428
|
+
en: "Siren",
|
|
20429
|
+
it: "Sirena",
|
|
20430
|
+
shortEn: "Siren",
|
|
20431
|
+
shortIt: "Sirena",
|
|
20432
|
+
aliases: []
|
|
20433
|
+
},
|
|
20434
|
+
{
|
|
20435
|
+
id: "switch",
|
|
20436
|
+
key: "uiLibrary.deviceMeta.noun.type.switch",
|
|
20437
|
+
en: "Switch",
|
|
20438
|
+
it: "Interruttore",
|
|
20439
|
+
shortEn: "Switch",
|
|
20440
|
+
shortIt: "Interruttore",
|
|
20441
|
+
aliases: []
|
|
20442
|
+
},
|
|
20443
|
+
{
|
|
20444
|
+
id: "sensor",
|
|
20445
|
+
key: "uiLibrary.deviceMeta.noun.type.sensor",
|
|
20446
|
+
en: "Sensor",
|
|
20447
|
+
it: "Sensore",
|
|
20448
|
+
shortEn: "Sensor",
|
|
20449
|
+
shortIt: "Sensore",
|
|
20450
|
+
aliases: []
|
|
20451
|
+
},
|
|
20452
|
+
{
|
|
20453
|
+
id: "thermostat",
|
|
20454
|
+
key: "uiLibrary.deviceMeta.noun.type.thermostat",
|
|
20455
|
+
en: "Thermostat",
|
|
20456
|
+
it: "Termostato",
|
|
20457
|
+
shortEn: "Thermostat",
|
|
20458
|
+
shortIt: "Termostato",
|
|
20459
|
+
aliases: []
|
|
20460
|
+
},
|
|
20461
|
+
{
|
|
20462
|
+
id: "climate",
|
|
20463
|
+
key: "uiLibrary.deviceMeta.noun.type.climate",
|
|
20464
|
+
en: "Air conditioner",
|
|
20465
|
+
it: "Condizionatore",
|
|
20466
|
+
shortEn: "Climate",
|
|
20467
|
+
shortIt: "Condizionatore",
|
|
20468
|
+
aliases: []
|
|
20469
|
+
},
|
|
20470
|
+
{
|
|
20471
|
+
id: "button",
|
|
20472
|
+
key: "uiLibrary.deviceMeta.noun.type.button",
|
|
20473
|
+
en: "Button",
|
|
20474
|
+
it: "Pulsante",
|
|
20475
|
+
shortEn: "Button",
|
|
20476
|
+
shortIt: "Pulsante",
|
|
20477
|
+
aliases: []
|
|
20478
|
+
},
|
|
20479
|
+
{
|
|
20480
|
+
id: "event-emitter",
|
|
20481
|
+
key: "uiLibrary.deviceMeta.noun.type.eventEmitter",
|
|
20482
|
+
en: "Event Emitter",
|
|
20483
|
+
it: "Emettitore di eventi",
|
|
20484
|
+
shortEn: "Event",
|
|
20485
|
+
shortIt: "Evento",
|
|
20486
|
+
aliases: []
|
|
20487
|
+
},
|
|
20488
|
+
{
|
|
20489
|
+
id: "update",
|
|
20490
|
+
key: "uiLibrary.deviceMeta.noun.type.update",
|
|
20491
|
+
en: "Update",
|
|
20492
|
+
it: "Aggiornamento",
|
|
20493
|
+
shortEn: "Update",
|
|
20494
|
+
shortIt: "Aggiornamento",
|
|
20495
|
+
aliases: []
|
|
20496
|
+
},
|
|
20497
|
+
{
|
|
20498
|
+
id: "generic",
|
|
20499
|
+
key: "uiLibrary.deviceMeta.noun.type.generic",
|
|
20500
|
+
en: "Generic",
|
|
20501
|
+
it: "Generico",
|
|
20502
|
+
shortEn: "Generic",
|
|
20503
|
+
shortIt: "Generico",
|
|
20504
|
+
aliases: []
|
|
20505
|
+
},
|
|
20506
|
+
{
|
|
20507
|
+
id: "notifier",
|
|
20508
|
+
key: "uiLibrary.deviceMeta.noun.type.notifier",
|
|
20509
|
+
en: "Notifier",
|
|
20510
|
+
it: "Notificatore",
|
|
20511
|
+
shortEn: "Notifier",
|
|
20512
|
+
shortIt: "Notificatore",
|
|
20513
|
+
aliases: []
|
|
20514
|
+
},
|
|
20515
|
+
{
|
|
20516
|
+
id: "script",
|
|
20517
|
+
key: "uiLibrary.deviceMeta.noun.type.script",
|
|
20518
|
+
en: "Script",
|
|
20519
|
+
it: "Script",
|
|
20520
|
+
shortEn: "Script",
|
|
20521
|
+
shortIt: "Script",
|
|
20522
|
+
aliases: []
|
|
20523
|
+
},
|
|
20524
|
+
{
|
|
20525
|
+
id: "automation",
|
|
20526
|
+
key: "uiLibrary.deviceMeta.noun.type.automation",
|
|
20527
|
+
en: "Automation",
|
|
20528
|
+
it: "Automazione",
|
|
20529
|
+
shortEn: "Automation",
|
|
20530
|
+
shortIt: "Automazione",
|
|
20531
|
+
aliases: []
|
|
20532
|
+
},
|
|
20533
|
+
{
|
|
20534
|
+
id: "lock",
|
|
20535
|
+
key: "uiLibrary.deviceMeta.noun.type.lock",
|
|
20536
|
+
en: "Lock",
|
|
20537
|
+
it: "Serratura",
|
|
20538
|
+
shortEn: "Lock",
|
|
20539
|
+
shortIt: "Serratura",
|
|
20540
|
+
aliases: []
|
|
20541
|
+
},
|
|
20542
|
+
{
|
|
20543
|
+
id: "cover",
|
|
20544
|
+
key: "uiLibrary.deviceMeta.noun.type.cover",
|
|
20545
|
+
en: "Cover",
|
|
20546
|
+
it: "Copertura",
|
|
20547
|
+
shortEn: "Cover",
|
|
20548
|
+
shortIt: "Copertura",
|
|
20549
|
+
aliases: []
|
|
20550
|
+
},
|
|
20551
|
+
{
|
|
20552
|
+
id: "valve",
|
|
20553
|
+
key: "uiLibrary.deviceMeta.noun.type.valve",
|
|
20554
|
+
en: "Valve",
|
|
20555
|
+
it: "Valvola",
|
|
20556
|
+
shortEn: "Valve",
|
|
20557
|
+
shortIt: "Valvola",
|
|
20558
|
+
aliases: []
|
|
20559
|
+
},
|
|
20560
|
+
{
|
|
20561
|
+
id: "humidifier",
|
|
20562
|
+
key: "uiLibrary.deviceMeta.noun.type.humidifier",
|
|
20563
|
+
en: "Humidifier",
|
|
20564
|
+
it: "Umidificatore",
|
|
20565
|
+
shortEn: "Humidifier",
|
|
20566
|
+
shortIt: "Umidificatore",
|
|
20567
|
+
aliases: []
|
|
20568
|
+
},
|
|
20569
|
+
{
|
|
20570
|
+
id: "water-heater",
|
|
20571
|
+
key: "uiLibrary.deviceMeta.noun.type.waterHeater",
|
|
20572
|
+
en: "Water heater",
|
|
20573
|
+
it: "Scaldabagno",
|
|
20574
|
+
shortEn: "Heater",
|
|
20575
|
+
shortIt: "Scaldabagno",
|
|
20576
|
+
aliases: []
|
|
20577
|
+
},
|
|
20578
|
+
{
|
|
20579
|
+
id: "fan",
|
|
20580
|
+
key: "uiLibrary.deviceMeta.noun.type.fan",
|
|
20581
|
+
en: "Fan",
|
|
20582
|
+
it: "Ventilatore",
|
|
20583
|
+
shortEn: "Fan",
|
|
20584
|
+
shortIt: "Ventilatore",
|
|
20585
|
+
aliases: []
|
|
20586
|
+
},
|
|
20587
|
+
{
|
|
20588
|
+
id: "media-player",
|
|
20589
|
+
key: "uiLibrary.deviceMeta.noun.type.mediaPlayer",
|
|
20590
|
+
en: "Media player",
|
|
20591
|
+
it: "Lettore multimediale",
|
|
20592
|
+
shortEn: "Player",
|
|
20593
|
+
shortIt: "Lettore",
|
|
20594
|
+
aliases: []
|
|
20595
|
+
},
|
|
20596
|
+
{
|
|
20597
|
+
id: "alarm-panel",
|
|
20598
|
+
key: "uiLibrary.deviceMeta.noun.type.alarmPanel",
|
|
20599
|
+
en: "Alarm panel",
|
|
20600
|
+
it: "Pannello allarme",
|
|
20601
|
+
shortEn: "Alarm",
|
|
20602
|
+
shortIt: "Allarme",
|
|
20603
|
+
aliases: []
|
|
20604
|
+
},
|
|
20605
|
+
{
|
|
20606
|
+
id: "control",
|
|
20607
|
+
key: "uiLibrary.deviceMeta.noun.type.control",
|
|
20608
|
+
en: "Control",
|
|
20609
|
+
it: "Controllo",
|
|
20610
|
+
shortEn: "Control",
|
|
20611
|
+
shortIt: "Controllo",
|
|
20612
|
+
aliases: []
|
|
20613
|
+
},
|
|
20614
|
+
{
|
|
20615
|
+
id: "presence",
|
|
20616
|
+
key: "uiLibrary.deviceMeta.noun.type.presence",
|
|
20617
|
+
en: "Presence",
|
|
20618
|
+
it: "Presenza",
|
|
20619
|
+
shortEn: "Presence",
|
|
20620
|
+
shortIt: "Presenza",
|
|
20621
|
+
aliases: []
|
|
20622
|
+
},
|
|
20623
|
+
{
|
|
20624
|
+
id: "weather",
|
|
20625
|
+
key: "uiLibrary.deviceMeta.noun.type.weather",
|
|
20626
|
+
en: "Weather",
|
|
20627
|
+
it: "Meteo",
|
|
20628
|
+
shortEn: "Weather",
|
|
20629
|
+
shortIt: "Meteo",
|
|
20630
|
+
aliases: []
|
|
20631
|
+
},
|
|
20632
|
+
{
|
|
20633
|
+
id: "vacuum",
|
|
20634
|
+
key: "uiLibrary.deviceMeta.noun.type.vacuum",
|
|
20635
|
+
en: "Vacuum",
|
|
20636
|
+
it: "Aspirapolvere",
|
|
20637
|
+
shortEn: "Vacuum",
|
|
20638
|
+
shortIt: "Aspirapolvere",
|
|
20639
|
+
aliases: []
|
|
20640
|
+
},
|
|
20641
|
+
{
|
|
20642
|
+
id: "lawn-mower",
|
|
20643
|
+
key: "uiLibrary.deviceMeta.noun.type.lawnMower",
|
|
20644
|
+
en: "Lawn mower",
|
|
20645
|
+
it: "Tagliaerba",
|
|
20646
|
+
shortEn: "Mower",
|
|
20647
|
+
shortIt: "Tagliaerba",
|
|
20648
|
+
aliases: []
|
|
20649
|
+
},
|
|
20650
|
+
{
|
|
20651
|
+
id: "container",
|
|
20652
|
+
key: "uiLibrary.deviceMeta.noun.type.container",
|
|
20653
|
+
en: "Container",
|
|
20654
|
+
it: "Contenitore",
|
|
20655
|
+
shortEn: "Container",
|
|
20656
|
+
shortIt: "Contenitore",
|
|
20657
|
+
aliases: []
|
|
20658
|
+
},
|
|
20659
|
+
{
|
|
20660
|
+
id: "image",
|
|
20661
|
+
key: "uiLibrary.deviceMeta.noun.type.image",
|
|
20662
|
+
en: "Image",
|
|
20663
|
+
it: "Immagine",
|
|
20664
|
+
shortEn: "Image",
|
|
20665
|
+
shortIt: "Immagine",
|
|
20666
|
+
aliases: []
|
|
20667
|
+
},
|
|
20668
|
+
{
|
|
20669
|
+
id: "pet-feeder",
|
|
20670
|
+
key: "uiLibrary.deviceMeta.noun.type.petFeeder",
|
|
20671
|
+
en: "Pet feeder",
|
|
20672
|
+
it: "Distributore di cibo per animali",
|
|
20673
|
+
shortEn: "Feeder",
|
|
20674
|
+
shortIt: "Distributore",
|
|
20675
|
+
aliases: []
|
|
20676
|
+
},
|
|
20677
|
+
{
|
|
20678
|
+
id: "dishwasher",
|
|
20679
|
+
key: "uiLibrary.deviceMeta.noun.type.dishwasher",
|
|
20680
|
+
en: "Dishwasher",
|
|
20681
|
+
it: "Lavastoviglie",
|
|
20682
|
+
shortEn: "Dishwasher",
|
|
20683
|
+
shortIt: "Lavastoviglie",
|
|
20684
|
+
aliases: []
|
|
20685
|
+
}
|
|
20686
|
+
];
|
|
20687
|
+
var FALLBACK_NOUN = {
|
|
20688
|
+
id: "",
|
|
20689
|
+
key: "uiLibrary.deviceMeta.noun.fallback",
|
|
20690
|
+
en: "Device",
|
|
20691
|
+
it: "Dispositivo",
|
|
20692
|
+
shortEn: "Device",
|
|
20693
|
+
shortIt: "Dispositivo",
|
|
20694
|
+
aliases: []
|
|
20695
|
+
};
|
|
20696
|
+
function findNoun(list, id) {
|
|
20697
|
+
if (id === null || id.length === 0) return void 0;
|
|
20698
|
+
return list.find((spec) => spec.id === id);
|
|
20699
|
+
}
|
|
20700
|
+
/** Role wins when it has a noun; otherwise the type. Unknown types fall back. */
|
|
20701
|
+
function nounSpecFor(role, type) {
|
|
20702
|
+
if (role !== null) {
|
|
20703
|
+
const byRole = findNoun(DEVICE_ROLE_NOUNS, role);
|
|
20704
|
+
if (byRole !== void 0) return byRole;
|
|
20705
|
+
}
|
|
20706
|
+
return findNoun(DEVICE_TYPE_NOUNS, type) ?? FALLBACK_NOUN;
|
|
20707
|
+
}
|
|
20708
|
+
function stockPhrases(role, type) {
|
|
20709
|
+
const phrases = [];
|
|
20710
|
+
const specs = [findNoun(DEVICE_ROLE_NOUNS, role), findNoun(DEVICE_TYPE_NOUNS, type)];
|
|
20711
|
+
for (const spec of specs) {
|
|
20712
|
+
if (spec === void 0) continue;
|
|
20713
|
+
phrases.push(spec.en, spec.it, spec.shortEn, spec.shortIt, ...spec.aliases);
|
|
20714
|
+
}
|
|
20715
|
+
return phrases;
|
|
20716
|
+
}
|
|
20717
|
+
function isDeviceNameStock(text, role, type) {
|
|
20718
|
+
const folded = foldDeviceName(text);
|
|
20719
|
+
if (folded.length === 0) return true;
|
|
20720
|
+
return stockPhrases(role, type).some((phrase) => foldDeviceName(phrase) === folded);
|
|
20721
|
+
}
|
|
20722
|
+
/** Noun table for a locale. Tests and the viewer parity spec use this directly. */
|
|
20723
|
+
function deviceNameNouns(locale) {
|
|
20724
|
+
return {
|
|
20725
|
+
shortNoun(role, type) {
|
|
20726
|
+
const spec = nounSpecFor(role, type);
|
|
20727
|
+
return locale === "it" ? spec.shortIt : spec.shortEn;
|
|
20728
|
+
},
|
|
20729
|
+
isStockPhrase(text, role, type) {
|
|
20730
|
+
return isDeviceNameStock(text, role, type);
|
|
20731
|
+
}
|
|
20732
|
+
};
|
|
20733
|
+
}
|
|
20734
|
+
//#endregion
|
|
20735
|
+
//#region src/composites/device-name/use-device-label.ts
|
|
20736
|
+
/**
|
|
20737
|
+
* `useDeviceLabel` is the string `DeviceName` renders — sort keys, aria
|
|
20738
|
+
* labels, confirm copy and search titles call it instead of painting
|
|
20739
|
+
* `device.name`.
|
|
20740
|
+
*/
|
|
20741
|
+
function useDeviceNameNouns() {
|
|
20742
|
+
const t = useUiText();
|
|
20743
|
+
return {
|
|
20744
|
+
shortNoun(role, type) {
|
|
20745
|
+
const spec = nounSpecFor(role, type);
|
|
20746
|
+
return t(spec.key, spec.shortEn);
|
|
20747
|
+
},
|
|
20748
|
+
isStockPhrase(text, role, type) {
|
|
20749
|
+
return isDeviceNameStock(text, role, type);
|
|
20750
|
+
}
|
|
20751
|
+
};
|
|
20752
|
+
}
|
|
20753
|
+
function placeholderParent(id) {
|
|
20754
|
+
return {
|
|
20755
|
+
id,
|
|
20756
|
+
name: `#${String(id)}`,
|
|
20757
|
+
type: "unknown",
|
|
20758
|
+
stableId: "",
|
|
20759
|
+
role: null,
|
|
20760
|
+
parentDeviceId: null
|
|
20761
|
+
};
|
|
20762
|
+
}
|
|
20763
|
+
function parentFromIndex(device, index) {
|
|
20764
|
+
const parentId = device.parentDeviceId;
|
|
20765
|
+
if (parentId === null || parentId === void 0) return null;
|
|
20766
|
+
return index.byId.get(parentId) ?? placeholderParent(parentId);
|
|
20767
|
+
}
|
|
20768
|
+
function siblingsFromIndex(device, index) {
|
|
20769
|
+
const parentId = device.parentDeviceId;
|
|
20770
|
+
if (parentId === null || parentId === void 0) return [];
|
|
20771
|
+
const ids = index.childIds.get(parentId) ?? [];
|
|
20772
|
+
const siblings = [];
|
|
20773
|
+
for (const id of ids) {
|
|
20774
|
+
const row = index.byId.get(id);
|
|
20775
|
+
if (row !== void 0) siblings.push(row);
|
|
20776
|
+
}
|
|
20777
|
+
if (!siblings.some((sibling) => sibling.id === device.id)) siblings.push(device);
|
|
20778
|
+
return siblings;
|
|
20779
|
+
}
|
|
20780
|
+
/**
|
|
20781
|
+
* Label for a device the caller already holds. While the fleet has not
|
|
20782
|
+
* answered and no parent was passed, this is the stored name — not `#id`.
|
|
20783
|
+
*/
|
|
20784
|
+
function resolveDeviceLabel(device, form, index, nouns, scope) {
|
|
20785
|
+
const subject = index?.byId.get(device.id) ?? device;
|
|
20786
|
+
const parentId = subject.parentDeviceId;
|
|
20787
|
+
if (parentId !== null && parentId !== void 0 && index === null && scope?.parent === void 0) return subject.name;
|
|
20788
|
+
return formatDeviceName(subject, form, {
|
|
20789
|
+
parent: scope?.parent !== void 0 ? scope.parent : index === null ? null : parentFromIndex(subject, index),
|
|
20790
|
+
siblings: scope?.siblings ?? (index === null ? [] : siblingsFromIndex(subject, index))
|
|
20791
|
+
}, nouns);
|
|
20792
|
+
}
|
|
20793
|
+
function useDeviceLabel(device, form, scope) {
|
|
20794
|
+
return resolveDeviceLabel(device, form, useDeviceNameIndex(), useDeviceNameNouns(), scope);
|
|
20795
|
+
}
|
|
20796
|
+
/** `#id` until the fleet answers, and `#id` when the id is not in it. */
|
|
20797
|
+
function useDeviceLabelById(id, form, pendingName) {
|
|
20798
|
+
const index = useDeviceNameIndex();
|
|
20799
|
+
const nouns = useDeviceNameNouns();
|
|
20800
|
+
if (index === null) return pendingName ?? `#${String(id)}`;
|
|
20801
|
+
const device = index.byId.get(id);
|
|
20802
|
+
if (device === void 0) return `#${String(id)}`;
|
|
20803
|
+
return resolveDeviceLabel(device, form, index, nouns);
|
|
20804
|
+
}
|
|
20805
|
+
//#endregion
|
|
20806
|
+
//#region src/composites/device-name/DeviceName.tsx
|
|
20807
|
+
function DeviceName({ device, form, parent, siblings, className, testId }) {
|
|
20808
|
+
const label = useDeviceLabel(device, form, {
|
|
20809
|
+
...parent !== void 0 ? { parent } : {},
|
|
20810
|
+
...siblings !== void 0 ? { siblings } : {}
|
|
20811
|
+
});
|
|
20812
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
20813
|
+
className,
|
|
20814
|
+
title: label,
|
|
20815
|
+
"data-testid": testId,
|
|
20816
|
+
children: label
|
|
20817
|
+
});
|
|
20818
|
+
}
|
|
20819
|
+
//#endregion
|
|
19630
20820
|
//#region src/hooks/use-device-proxy.ts
|
|
19631
20821
|
/**
|
|
19632
20822
|
* useDeviceProxy — canonical React entry point for a device.
|
|
@@ -20529,6 +21719,9 @@ function GridCellBox({ cell, selected, onSelect, onDragStart }) {
|
|
|
20529
21719
|
}, handle))
|
|
20530
21720
|
});
|
|
20531
21721
|
}
|
|
21722
|
+
function CameraOptionLabel({ camera }) {
|
|
21723
|
+
return useDeviceLabel(camera, "compact");
|
|
21724
|
+
}
|
|
20532
21725
|
function CellInspector({ cell, index, cameras, onChange, onRemove }) {
|
|
20533
21726
|
const t = useUiText();
|
|
20534
21727
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -20559,7 +21752,7 @@ function CellInspector({ cell, index, cameras, onChange, onRemove }) {
|
|
|
20559
21752
|
className: "flex-1 rounded border border-border bg-transparent px-1 py-0.5",
|
|
20560
21753
|
children: cameras.map((camera) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
20561
21754
|
value: String(camera.id),
|
|
20562
|
-
children: camera
|
|
21755
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CameraOptionLabel, { camera })
|
|
20563
21756
|
}, camera.id))
|
|
20564
21757
|
})]
|
|
20565
21758
|
}),
|
|
@@ -48247,17 +49440,19 @@ function SensorHeroInner({ trpc, device }) {
|
|
|
48247
49440
|
if (resolution.kind === "quiet") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
48248
49441
|
className: "flex flex-col items-center justify-center gap-2 rounded-lg border border-border bg-surface p-4 min-h-[96px]",
|
|
48249
49442
|
"data-testid": "sensor-hero-quiet",
|
|
48250
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
48251
|
-
|
|
48252
|
-
|
|
49443
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DeviceName, {
|
|
49444
|
+
device,
|
|
49445
|
+
form: "full",
|
|
49446
|
+
className: "text-sm text-foreground-subtle"
|
|
48253
49447
|
})
|
|
48254
49448
|
});
|
|
48255
49449
|
const slice = resolution.kind === "value" ? resolution.slice : void 0;
|
|
48256
49450
|
if (descriptor === void 0 || slice === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
48257
49451
|
className: "flex flex-col items-center justify-center gap-2 rounded-lg border border-border bg-surface p-4 min-h-[96px]",
|
|
48258
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
48259
|
-
|
|
48260
|
-
|
|
49452
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DeviceName, {
|
|
49453
|
+
device,
|
|
49454
|
+
form: "full",
|
|
49455
|
+
className: "text-sm text-foreground-subtle"
|
|
48261
49456
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
48262
49457
|
className: "text-xs text-foreground-subtle italic",
|
|
48263
49458
|
children: t("uiLibrary.sensorHeroCard.awaiting", "Awaiting state…")
|
|
@@ -48297,9 +49492,10 @@ function SensorHeroInner({ trpc, device }) {
|
|
|
48297
49492
|
"data-testid": "sensor-hero-occupancy",
|
|
48298
49493
|
children: occupancyOn ? t("uiLibrary.sensorHeroCard.occupied", "Occupied") : t("uiLibrary.sensorHeroCard.clear", "Clear")
|
|
48299
49494
|
}),
|
|
48300
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
48301
|
-
|
|
48302
|
-
|
|
49495
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DeviceName, {
|
|
49496
|
+
device,
|
|
49497
|
+
form: "full",
|
|
49498
|
+
className: "text-sm text-foreground-subtle"
|
|
48303
49499
|
})
|
|
48304
49500
|
]
|
|
48305
49501
|
});
|
|
@@ -48314,9 +49510,10 @@ function SensorHeroInner({ trpc, device }) {
|
|
|
48314
49510
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
48315
49511
|
className: cn("inline-flex items-center rounded px-3 py-1.5 text-lg font-semibold", active ? "bg-warning/15 text-warning" : "bg-surface-subtle text-foreground-subtle"),
|
|
48316
49512
|
children: label
|
|
48317
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
48318
|
-
|
|
48319
|
-
|
|
49513
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DeviceName, {
|
|
49514
|
+
device,
|
|
49515
|
+
form: "full",
|
|
49516
|
+
className: "text-sm text-foreground-subtle"
|
|
48320
49517
|
})]
|
|
48321
49518
|
});
|
|
48322
49519
|
}
|
|
@@ -48324,9 +49521,10 @@ function SensorHeroInner({ trpc, device }) {
|
|
|
48324
49521
|
if (!isStringSliceValue(slice)) return null;
|
|
48325
49522
|
if (slice.value === "") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
48326
49523
|
className: "flex flex-col items-center justify-center gap-2 rounded-lg border border-border bg-surface p-4 min-h-[96px]",
|
|
48327
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
48328
|
-
|
|
48329
|
-
|
|
49524
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DeviceName, {
|
|
49525
|
+
device,
|
|
49526
|
+
form: "full",
|
|
49527
|
+
className: "text-sm text-foreground-subtle"
|
|
48330
49528
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
48331
49529
|
className: "text-xs text-foreground-subtle italic",
|
|
48332
49530
|
children: t("uiLibrary.sensorHeroCard.awaiting", "Awaiting state…")
|
|
@@ -48338,9 +49536,10 @@ function SensorHeroInner({ trpc, device }) {
|
|
|
48338
49536
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
48339
49537
|
className: "text-3xl font-semibold tabular-nums text-foreground",
|
|
48340
49538
|
children: formatControlDateTime(slice.value, format)
|
|
48341
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
48342
|
-
|
|
48343
|
-
|
|
49539
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DeviceName, {
|
|
49540
|
+
device,
|
|
49541
|
+
form: "full",
|
|
49542
|
+
className: "text-sm text-foreground-subtle"
|
|
48344
49543
|
})]
|
|
48345
49544
|
});
|
|
48346
49545
|
}
|
|
@@ -48352,9 +49551,10 @@ function SensorHeroInner({ trpc, device }) {
|
|
|
48352
49551
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
48353
49552
|
className: "text-xl font-semibold text-foreground",
|
|
48354
49553
|
children: slice.value
|
|
48355
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
48356
|
-
|
|
48357
|
-
|
|
49554
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DeviceName, {
|
|
49555
|
+
device,
|
|
49556
|
+
form: "full",
|
|
49557
|
+
className: "text-sm text-foreground-subtle"
|
|
48358
49558
|
})]
|
|
48359
49559
|
});
|
|
48360
49560
|
}
|
|
@@ -48365,9 +49565,10 @@ function SensorHeroInner({ trpc, device }) {
|
|
|
48365
49565
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
48366
49566
|
className: cn("inline-flex items-center rounded px-3 py-1.5 text-lg font-semibold", slice.state === "home" ? "bg-success/15 text-success" : "bg-surface-subtle text-foreground-subtle"),
|
|
48367
49567
|
children: label
|
|
48368
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
48369
|
-
|
|
48370
|
-
|
|
49568
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DeviceName, {
|
|
49569
|
+
device,
|
|
49570
|
+
form: "full",
|
|
49571
|
+
className: "text-sm text-foreground-subtle"
|
|
48371
49572
|
})]
|
|
48372
49573
|
});
|
|
48373
49574
|
}
|
|
@@ -55122,7 +56323,9 @@ var CONTROL_FILLS = {
|
|
|
55122
56323
|
[_camstack_types.DeviceType.Container]: false,
|
|
55123
56324
|
[_camstack_types.DeviceType.Image]: false,
|
|
55124
56325
|
[_camstack_types.DeviceType.PetFeeder]: false,
|
|
55125
|
-
[_camstack_types.DeviceType.Dishwasher]: false
|
|
56326
|
+
[_camstack_types.DeviceType.Dishwasher]: false,
|
|
56327
|
+
[_camstack_types.DeviceType.Washer]: false,
|
|
56328
|
+
[_camstack_types.DeviceType.Dryer]: false
|
|
55126
56329
|
};
|
|
55127
56330
|
var DEVICE_TYPE_VALUES = new Set(Object.values(_camstack_types.DeviceType));
|
|
55128
56331
|
/**
|
|
@@ -56378,6 +57581,7 @@ function useContainerChildren(deviceId) {
|
|
|
56378
57581
|
var SENSOR_VALUE_TYPES = new Set([_camstack_types.DeviceType.Sensor, _camstack_types.DeviceType.Presence]);
|
|
56379
57582
|
function DeviceItemActions({ trpc, device, controlPlacement }) {
|
|
56380
57583
|
const containerChildren = useContainerChildren(device.id);
|
|
57584
|
+
const deviceLabel = useDeviceLabel(device, "compact");
|
|
56381
57585
|
const placement = controlPlacement ?? "right";
|
|
56382
57586
|
if (!!device.disabled) return null;
|
|
56383
57587
|
if (device.type === _camstack_types.DeviceType.Container) {
|
|
@@ -56433,7 +57637,7 @@ function DeviceItemActions({ trpc, device, controlPlacement }) {
|
|
|
56433
57637
|
showReboot && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RebootQuickAction, {
|
|
56434
57638
|
trpc,
|
|
56435
57639
|
deviceId: device.id,
|
|
56436
|
-
deviceName:
|
|
57640
|
+
deviceName: deviceLabel
|
|
56437
57641
|
}),
|
|
56438
57642
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(AdminLinkQuickAction, {
|
|
56439
57643
|
trpc,
|
|
@@ -56669,9 +57873,16 @@ function ChildRow$1({ trpc, child, onNavigate, parentName }) {
|
|
|
56669
57873
|
running: runningSlice === void 0 || runningSlice.running === null ? null : runningSlice.running,
|
|
56670
57874
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChildIcon, { className: "h-3 w-3 text-foreground-subtle flex-shrink-0" })
|
|
56671
57875
|
}),
|
|
56672
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
56673
|
-
|
|
56674
|
-
|
|
57876
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DeviceName, {
|
|
57877
|
+
device: child,
|
|
57878
|
+
form: "nested",
|
|
57879
|
+
parent: {
|
|
57880
|
+
id: child.parentDeviceId ?? 0,
|
|
57881
|
+
name: parentName,
|
|
57882
|
+
type: "unknown",
|
|
57883
|
+
stableId: ""
|
|
57884
|
+
},
|
|
57885
|
+
className: "text-[10.5px] text-foreground flex-1 truncate"
|
|
56675
57886
|
}),
|
|
56676
57887
|
showMotionTrigger && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChildMotionTriggerToggle, {
|
|
56677
57888
|
trpc,
|
|
@@ -56778,8 +57989,9 @@ function IconAction({ icon: Icon, label, onClick, danger = false }) {
|
|
|
56778
57989
|
function DeviceDeleteAction({ device, onDelete }) {
|
|
56779
57990
|
const t = useUiText();
|
|
56780
57991
|
const confirm = useConfirm();
|
|
57992
|
+
const deviceLabel = useDeviceLabel(device, "full");
|
|
56781
57993
|
const requestDelete = async () => {
|
|
56782
|
-
const label =
|
|
57994
|
+
const label = deviceLabel.trim() !== "" ? deviceLabel : `#${String(device.id)}`;
|
|
56783
57995
|
if (await confirm({
|
|
56784
57996
|
title: t("uiLibrary.deviceDeleteAction.title", "Delete device?"),
|
|
56785
57997
|
message: t("uiLibrary.deviceDeleteAction.message", "This will remove \"{{label}}\" and all its settings. This action cannot be undone.", { label }),
|
|
@@ -57062,7 +58274,7 @@ var CHEVRON_SLOT_CLASS = {
|
|
|
57062
58274
|
horizontal: "h-3.5 w-3.5",
|
|
57063
58275
|
stacked: "h-4 w-4 mt-0.5"
|
|
57064
58276
|
};
|
|
57065
|
-
function DeviceItemHeader({ trpc, device, variant, flags, parent, integrationIcon, hasChildren, expanded, onToggleExpand, onNavigateToParent, stacked = false, nameOverflow = "truncate" }) {
|
|
58277
|
+
function DeviceItemHeader({ trpc, device, variant, flags, parent, integrationIcon, hasChildren, expanded, onToggleExpand, onNavigateToParent, stacked = false, nameOverflow = "truncate", nameForm = "compact" }) {
|
|
57066
58278
|
const t = useUiText();
|
|
57067
58279
|
const containerChildren = useContainerChildren(device.id);
|
|
57068
58280
|
const roleDefaults = useRoleDisplayDefaults();
|
|
@@ -57073,6 +58285,13 @@ function DeviceItemHeader({ trpc, device, variant, flags, parent, integrationIco
|
|
|
57073
58285
|
const slotClass = stacked ? CHEVRON_SLOT_CLASS.stacked : CHEVRON_SLOT_CLASS.horizontal;
|
|
57074
58286
|
const iconClass = cn("text-foreground-subtle flex-shrink-0", stacked ? "h-4 w-4 mt-0.5" : variant === "minimal" ? "h-3 w-3" : "h-3.5 w-3.5");
|
|
57075
58287
|
const lineClass = nameOverflow === "scroll" ? NAME_TEXT_CLASS : "truncate";
|
|
58288
|
+
const nameParent = nameForm === "nested" && parent !== null ? {
|
|
58289
|
+
id: parent.id,
|
|
58290
|
+
name: parent.name,
|
|
58291
|
+
type: parent.type ?? "unknown",
|
|
58292
|
+
stableId: ""
|
|
58293
|
+
} : void 0;
|
|
58294
|
+
const parentLabel = useDeviceLabelById(parent?.id ?? 0, "compact", parent?.name);
|
|
57076
58295
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
57077
58296
|
className: cn(stacked ? "flex items-start gap-2 w-full min-w-0" : "flex items-center gap-2 flex-1 min-w-0"),
|
|
57078
58297
|
children: [
|
|
@@ -57103,11 +58322,12 @@ function DeviceItemHeader({ trpc, device, variant, flags, parent, integrationIco
|
|
|
57103
58322
|
children: [flags.showIntegrationIcon && integrationIcon && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
57104
58323
|
className: "flex-shrink-0",
|
|
57105
58324
|
children: integrationIcon
|
|
57106
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
57107
|
-
|
|
57108
|
-
|
|
57109
|
-
|
|
57110
|
-
|
|
58325
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DeviceName, {
|
|
58326
|
+
device,
|
|
58327
|
+
form: nameForm,
|
|
58328
|
+
...nameParent !== void 0 ? { parent: nameParent } : {},
|
|
58329
|
+
testId: "device-name",
|
|
58330
|
+
className: cn("font-semibold text-foreground", stacked ? "text-[13px] leading-snug line-clamp-2 break-words" : cn(lineClass, variant === "minimal" ? "text-[10.5px]" : "text-[11px]"))
|
|
57111
58331
|
})]
|
|
57112
58332
|
}),
|
|
57113
58333
|
(flags.showId || flags.showStableId) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -57136,12 +58356,12 @@ function DeviceItemHeader({ trpc, device, variant, flags, parent, integrationIco
|
|
|
57136
58356
|
},
|
|
57137
58357
|
className: cn("mt-0.5 inline-flex items-center gap-1 text-[9px] text-foreground-subtle hover:text-primary transition-colors", nameOverflow === "scroll" ? "md:max-w-full" : "max-w-full"),
|
|
57138
58358
|
title: t("uiLibrary.deviceItemHeader.openParent", "Open parent: {{name}} (#{{id}})", {
|
|
57139
|
-
name:
|
|
58359
|
+
name: parentLabel,
|
|
57140
58360
|
id: parent.id
|
|
57141
58361
|
}),
|
|
57142
58362
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Network, { className: "h-2.5 w-2.5 shrink-0" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
57143
58363
|
className: lineClass,
|
|
57144
|
-
children: t("uiLibrary.deviceItemHeader.under", "Under: {{name}}", { name:
|
|
58364
|
+
children: t("uiLibrary.deviceItemHeader.under", "Under: {{name}}", { name: parentLabel })
|
|
57145
58365
|
})]
|
|
57146
58366
|
})
|
|
57147
58367
|
]
|
|
@@ -57270,7 +58490,9 @@ function HoverZoomImage({ src, alt, caption, placeholder = "No image", thumbClas
|
|
|
57270
58490
|
* the 288 px hover zoom. */
|
|
57271
58491
|
var PREVIEW_SNAPSHOT_WIDTH = 480;
|
|
57272
58492
|
function DeviceItemPreview({ trpc, device, status, enabled, showStatusPills = false }) {
|
|
57273
|
-
const
|
|
58493
|
+
const liveActive = enabled && device.online;
|
|
58494
|
+
const deviceLabel = useDeviceLabel(device, "compact");
|
|
58495
|
+
const snapshot = useDeviceSnapshotImage(liveActive ? device.id : null, { width: PREVIEW_SNAPSHOT_WIDTH });
|
|
57274
58496
|
const isBatteryOperated = (device.features ?? []).includes("battery-operated");
|
|
57275
58497
|
const wantPills = showStatusPills && isBatteryOperated && !device.disabled;
|
|
57276
58498
|
const batteryStatus = useDeviceBattery(trpc, wantPills ? device.id : null);
|
|
@@ -57286,7 +58508,7 @@ function DeviceItemPreview({ trpc, device, status, enabled, showStatusPills = fa
|
|
|
57286
58508
|
wantLinkPill && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NetworkLinkBadge, { status: linkStatus }),
|
|
57287
58509
|
enabled && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(HoverZoomImage, {
|
|
57288
58510
|
src: offline ? null : snapshot.src,
|
|
57289
|
-
alt:
|
|
58511
|
+
alt: deviceLabel,
|
|
57290
58512
|
placeholder,
|
|
57291
58513
|
thumbClassName: "h-7 w-7 rounded"
|
|
57292
58514
|
})
|
|
@@ -57509,6 +58731,14 @@ function DeviceItem(props) {
|
|
|
57509
58731
|
const flags = resolveFlags(props);
|
|
57510
58732
|
const variant = props.variant ?? "compact";
|
|
57511
58733
|
const view = props.view ?? "card";
|
|
58734
|
+
const nameForm = props.isAccessoryRow ? "nested" : "compact";
|
|
58735
|
+
const nameParent = nameForm === "nested" && parent ? {
|
|
58736
|
+
id: parent.id,
|
|
58737
|
+
name: parent.name,
|
|
58738
|
+
type: parent.type ?? "unknown",
|
|
58739
|
+
stableId: ""
|
|
58740
|
+
} : void 0;
|
|
58741
|
+
const rowLabel = useDeviceLabel(device, nameForm, nameParent !== void 0 ? { parent: nameParent } : void 0);
|
|
57512
58742
|
const enabled = !device.disabled;
|
|
57513
58743
|
const isCamera = device.isCamera ?? device.type.toLowerCase() === "camera";
|
|
57514
58744
|
const childrenList = props.children ?? [];
|
|
@@ -57584,7 +58814,7 @@ function DeviceItem(props) {
|
|
|
57584
58814
|
checked: selection.selected,
|
|
57585
58815
|
onChange: selection.onToggle,
|
|
57586
58816
|
onClick: (e) => e.stopPropagation(),
|
|
57587
|
-
"aria-label": t("uiLibrary.deviceItem.select", "Select {{name}}", { name:
|
|
58817
|
+
"aria-label": t("uiLibrary.deviceItem.select", "Select {{name}}", { name: rowLabel }),
|
|
57588
58818
|
className: "flex-shrink-0"
|
|
57589
58819
|
}),
|
|
57590
58820
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DeviceItemHeader, {
|
|
@@ -57593,6 +58823,7 @@ function DeviceItem(props) {
|
|
|
57593
58823
|
variant,
|
|
57594
58824
|
flags,
|
|
57595
58825
|
parent: parent ?? null,
|
|
58826
|
+
nameForm,
|
|
57596
58827
|
integrationIcon: integrationIcon ?? null,
|
|
57597
58828
|
hasChildren,
|
|
57598
58829
|
expanded,
|
|
@@ -57661,7 +58892,7 @@ function DeviceItem(props) {
|
|
|
57661
58892
|
checked: selection.selected,
|
|
57662
58893
|
onChange: selection.onToggle,
|
|
57663
58894
|
onClick: (e) => e.stopPropagation(),
|
|
57664
|
-
"aria-label": t("uiLibrary.deviceItem.select", "Select {{name}}", { name:
|
|
58895
|
+
"aria-label": t("uiLibrary.deviceItem.select", "Select {{name}}", { name: rowLabel }),
|
|
57665
58896
|
className: "flex-shrink-0 mt-0.5"
|
|
57666
58897
|
}),
|
|
57667
58898
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DeviceItemHeader, {
|
|
@@ -57670,6 +58901,7 @@ function DeviceItem(props) {
|
|
|
57670
58901
|
variant,
|
|
57671
58902
|
flags,
|
|
57672
58903
|
parent: parent ?? null,
|
|
58904
|
+
nameForm,
|
|
57673
58905
|
integrationIcon: integrationIcon ?? null,
|
|
57674
58906
|
hasChildren,
|
|
57675
58907
|
expanded,
|
|
@@ -57730,6 +58962,14 @@ function DeviceItemTableRow(props) {
|
|
|
57730
58962
|
const t = useUiText();
|
|
57731
58963
|
const { trpc, device, variant, flags, parent, integrationIcon, accessoryCount, adoptedCount, hasChildren, expanded, onToggleExpand, onNavigate, onRowClick, rowSelects, rowSelected, displayStatus, isCamera, showSnapshot, isAccessoryRow, indentLevel, className, renderRowAction, onDelete, selection, showTypeCell, showManufacturerCell, showFeaturesCell } = props;
|
|
57732
58964
|
const containerChildren = useContainerChildren(device.id);
|
|
58965
|
+
const nameForm = isAccessoryRow ? "nested" : "compact";
|
|
58966
|
+
const nameParent = nameForm === "nested" && parent ? {
|
|
58967
|
+
id: parent.id,
|
|
58968
|
+
name: parent.name,
|
|
58969
|
+
type: parent.type ?? "unknown",
|
|
58970
|
+
stableId: ""
|
|
58971
|
+
} : void 0;
|
|
58972
|
+
const rowLabel = useDeviceLabel(device, nameForm, nameParent !== void 0 ? { parent: nameParent } : void 0);
|
|
57733
58973
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", {
|
|
57734
58974
|
onClick: onRowClick,
|
|
57735
58975
|
...rowSelects ? {
|
|
@@ -57754,7 +58994,7 @@ function DeviceItemTableRow(props) {
|
|
|
57754
58994
|
checked: selection.selected,
|
|
57755
58995
|
onChange: selection.onToggle,
|
|
57756
58996
|
onClick: (e) => e.stopPropagation(),
|
|
57757
|
-
"aria-label": t("uiLibrary.deviceItem.select", "Select {{name}}", { name:
|
|
58997
|
+
"aria-label": t("uiLibrary.deviceItem.select", "Select {{name}}", { name: rowLabel }),
|
|
57758
58998
|
className: "flex-shrink-0"
|
|
57759
58999
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DeviceItemHeader, {
|
|
57760
59000
|
trpc,
|
|
@@ -57762,6 +59002,7 @@ function DeviceItemTableRow(props) {
|
|
|
57762
59002
|
variant,
|
|
57763
59003
|
flags,
|
|
57764
59004
|
parent,
|
|
59005
|
+
nameForm,
|
|
57765
59006
|
integrationIcon,
|
|
57766
59007
|
hasChildren,
|
|
57767
59008
|
expanded,
|
|
@@ -58500,13 +59741,13 @@ function TableRowGroup({ parent, accessories, hasAccessories, expanded, onToggle
|
|
|
58500
59741
|
function AccessorySubRow({ trpc, accessory, parentName, showType, showManufacturer, showFeatures, onNavigate, muted }) {
|
|
58501
59742
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DeviceItem, {
|
|
58502
59743
|
trpc,
|
|
58503
|
-
device:
|
|
58504
|
-
...accessory,
|
|
58505
|
-
name: childListName(accessory, parentName)
|
|
58506
|
-
},
|
|
59744
|
+
device: accessory,
|
|
58507
59745
|
view: "table",
|
|
58508
59746
|
integrationIcon: null,
|
|
58509
|
-
parent: null
|
|
59747
|
+
parent: accessory.parentDeviceId === null ? null : {
|
|
59748
|
+
id: accessory.parentDeviceId,
|
|
59749
|
+
name: parentName
|
|
59750
|
+
},
|
|
58510
59751
|
isAccessoryRow: true,
|
|
58511
59752
|
showChildrenAccordion: false,
|
|
58512
59753
|
onNavigate: onNavigate ?? void 0,
|
|
@@ -59305,6 +60546,15 @@ function DeviceExportSetup({ addonId }) {
|
|
|
59305
60546
|
}), status.setup && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SetupSection, { setup: status.setup })]
|
|
59306
60547
|
});
|
|
59307
60548
|
}
|
|
60549
|
+
function ExportSelectCell({ device, checked, onToggle }) {
|
|
60550
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
60551
|
+
type: "checkbox",
|
|
60552
|
+
checked,
|
|
60553
|
+
onChange: onToggle,
|
|
60554
|
+
onClick: (e) => e.stopPropagation(),
|
|
60555
|
+
"aria-label": useUiText()("uiLibrary.deviceExport.select", "Select {{name}}", { name: useDeviceLabel(device, "compact") })
|
|
60556
|
+
});
|
|
60557
|
+
}
|
|
59308
60558
|
/**
|
|
59309
60559
|
* Per-row Expose/Exposed toggle. Reflects whether the row's device is exposed
|
|
59310
60560
|
* to THIS exporter and flips it through the SAME runner the bulk buttons use —
|
|
@@ -59316,6 +60566,7 @@ function DeviceExportSetup({ addonId }) {
|
|
|
59316
60566
|
*/
|
|
59317
60567
|
function ExportRowToggle({ addonId, device, exposed, busy, onToggle }) {
|
|
59318
60568
|
const t = useUiText();
|
|
60569
|
+
const deviceLabel = useDeviceLabel(device, "compact");
|
|
59319
60570
|
const handleClick = (e) => {
|
|
59320
60571
|
e.stopPropagation();
|
|
59321
60572
|
if (busy) return;
|
|
@@ -59326,7 +60577,7 @@ function ExportRowToggle({ addonId, device, exposed, busy, onToggle }) {
|
|
|
59326
60577
|
variant: exposed ? "ghost" : "primary",
|
|
59327
60578
|
disabled: busy,
|
|
59328
60579
|
onClick: handleClick,
|
|
59329
|
-
"aria-label": exposed ? t("uiLibrary.deviceExport.unexposeDevice", "Unexpose {{name}}", { name:
|
|
60580
|
+
"aria-label": exposed ? t("uiLibrary.deviceExport.unexposeDevice", "Unexpose {{name}}", { name: deviceLabel }) : t("uiLibrary.deviceExport.exposeDevice", "Expose {{name}}", { name: deviceLabel }),
|
|
59330
60581
|
title: exposed ? t("uiLibrary.deviceExport.stopTitle", "Stop exposing to \"{{addon}}\"", { addon: addonId }) : t("uiLibrary.deviceExport.exposeTitle", "Expose to \"{{addon}}\"", { addon: addonId }),
|
|
59331
60582
|
children: exposed ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Unlink2, { className: "mr-1 h-3.5 w-3.5" }), t("uiLibrary.deviceExport.exposed", "Exposed")] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Share2, { className: "mr-1 h-3.5 w-3.5" }), t("uiLibrary.deviceExport.expose", "Expose")] })
|
|
59332
60583
|
});
|
|
@@ -59542,12 +60793,10 @@ function DeviceExportPanel({ addonId, onOpenDevice, showSetup = true }) {
|
|
|
59542
60793
|
key: "select",
|
|
59543
60794
|
header: "",
|
|
59544
60795
|
headerClassName: "w-8",
|
|
59545
|
-
cell: (device) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
59546
|
-
|
|
60796
|
+
cell: (device) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ExportSelectCell, {
|
|
60797
|
+
device,
|
|
59547
60798
|
checked: selectedIds.has(String(device.id)),
|
|
59548
|
-
|
|
59549
|
-
onClick: (e) => e.stopPropagation(),
|
|
59550
|
-
"aria-label": t("uiLibrary.deviceExport.select", "Select {{name}}", { name: device.name })
|
|
60799
|
+
onToggle: () => toggleSelection(String(device.id))
|
|
59551
60800
|
})
|
|
59552
60801
|
},
|
|
59553
60802
|
{
|
|
@@ -59566,9 +60815,10 @@ function DeviceExportPanel({ addonId, onOpenDevice, showSetup = true }) {
|
|
|
59566
60815
|
{
|
|
59567
60816
|
key: "name",
|
|
59568
60817
|
header: t("uiLibrary.deviceExport.colName", "Name"),
|
|
59569
|
-
cell: (device) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
59570
|
-
|
|
59571
|
-
|
|
60818
|
+
cell: (device) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DeviceName, {
|
|
60819
|
+
device,
|
|
60820
|
+
form: "compact",
|
|
60821
|
+
className: "text-xs font-medium text-foreground"
|
|
59572
60822
|
})
|
|
59573
60823
|
},
|
|
59574
60824
|
{
|
|
@@ -66381,6 +67631,26 @@ function deviceGroupTitle(group, t = defaultUiText) {
|
|
|
66381
67631
|
function isDeviceNoun(noun) {
|
|
66382
67632
|
return noun === "camera" || noun === "device";
|
|
66383
67633
|
}
|
|
67634
|
+
/** Compact label for a device id. String ids (nodes, packages) keep the stored text. */
|
|
67635
|
+
function usePickerDeviceLabel(id, stored) {
|
|
67636
|
+
const lookedUp = useDeviceLabelById(typeof id === "number" ? id : 0, "compact", stored);
|
|
67637
|
+
return typeof id === "number" ? lookedUp : stored;
|
|
67638
|
+
}
|
|
67639
|
+
function PickerDeviceName({ id, stored, className }) {
|
|
67640
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
67641
|
+
className,
|
|
67642
|
+
children: usePickerDeviceLabel(id, stored)
|
|
67643
|
+
});
|
|
67644
|
+
}
|
|
67645
|
+
function PickerChip({ id, stored, removed, onRemove }) {
|
|
67646
|
+
const label = usePickerDeviceLabel(id, stored);
|
|
67647
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelectedChip, {
|
|
67648
|
+
testId: `picker-chip-${String(id)}`,
|
|
67649
|
+
label,
|
|
67650
|
+
warning: removed,
|
|
67651
|
+
...onRemove !== void 0 ? { onRemove } : {}
|
|
67652
|
+
});
|
|
67653
|
+
}
|
|
66384
67654
|
function chipsOf(value, devices, fleet, noun, t) {
|
|
66385
67655
|
const byId = new Map(devices.map((device) => [device.id, device.name]));
|
|
66386
67656
|
const orphans = new Map(offListSelections(value, devices, fleet.devices, fleet.state).map((row) => [row.id, row]));
|
|
@@ -66416,7 +67686,7 @@ function DevicePicker({ devices: devicesIn, listState, fleet, value, onChange, s
|
|
|
66416
67686
|
const t = useUiText();
|
|
66417
67687
|
const groupTitle = groupTitleProp ?? ((group) => deviceGroupTitle(group, t));
|
|
66418
67688
|
const lockedNote = lockedNoteProp ?? t("uiLibrary.devicePicker.alreadyAdded", "Already added");
|
|
66419
|
-
const devices = (0, react$1.useMemo)(() => withResolvedParentDetail(devicesIn), [devicesIn]);
|
|
67689
|
+
const devices = (0, react$1.useMemo)(() => isDeviceNoun(noun) ? devicesIn : withResolvedParentDetail(devicesIn), [devicesIn, noun]);
|
|
66420
67690
|
const judge = fleet ?? {
|
|
66421
67691
|
state: listState,
|
|
66422
67692
|
devices: listState === "answered" ? devices : void 0
|
|
@@ -66451,10 +67721,10 @@ function DevicePicker({ devices: devicesIn, listState, fleet, value, onChange, s
|
|
|
66451
67721
|
chips.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
66452
67722
|
className: "text-[11px] text-foreground-subtle",
|
|
66453
67723
|
children: emptyLabel ?? (emptyMeansAll ? t("uiLibrary.devicePicker.everyNoRestriction", "Every {{noun}} — no restriction", { noun: pickerNounLabel(noun, t) }) : t("uiLibrary.devicePicker.noneSelected", "None selected"))
|
|
66454
|
-
}) : overflow.shown.map((chip) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
66455
|
-
|
|
66456
|
-
|
|
66457
|
-
|
|
67724
|
+
}) : overflow.shown.map((chip) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PickerChip, {
|
|
67725
|
+
id: chip.id,
|
|
67726
|
+
stored: chip.label,
|
|
67727
|
+
removed: chip.removed,
|
|
66458
67728
|
...!disabled ? { onRemove: () => onChange(value.filter((id) => id !== chip.id)) } : {}
|
|
66459
67729
|
}, chip.id)),
|
|
66460
67730
|
overflow.hidden > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
@@ -66747,9 +68017,10 @@ function PickerRowView({ row, value, onChange, onToggleGroup, annotate, groupTit
|
|
|
66747
68017
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
66748
68018
|
className: "flex min-w-0 flex-1 flex-col",
|
|
66749
68019
|
children: [
|
|
66750
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
66751
|
-
|
|
66752
|
-
|
|
68020
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PickerDeviceName, {
|
|
68021
|
+
id: row.device.id,
|
|
68022
|
+
stored: row.device.name,
|
|
68023
|
+
className: "truncate"
|
|
66753
68024
|
}),
|
|
66754
68025
|
second !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
66755
68026
|
className: "truncate text-[10px] text-foreground-subtle",
|
|
@@ -69840,10 +71111,14 @@ exports.DEVICE_COLUMNS = DEVICE_COLUMNS;
|
|
|
69840
71111
|
exports.DEVICE_EXPORT_PAGE_SIZE_KEY = DEVICE_EXPORT_PAGE_SIZE_KEY;
|
|
69841
71112
|
exports.DEVICE_LIST_PAGE_SIZE_KEY = DEVICE_LIST_PAGE_SIZE_KEY;
|
|
69842
71113
|
exports.DEVICE_LIST_PAGE_SIZE_OPTIONS = DEVICE_LIST_PAGE_SIZE_OPTIONS;
|
|
71114
|
+
exports.DEVICE_NAME_FORMS = DEVICE_NAME_FORMS;
|
|
71115
|
+
exports.DEVICE_NAME_JOIN = DEVICE_NAME_JOIN;
|
|
69843
71116
|
exports.DEVICE_PICKER_GROUP_STORAGE_KEY = DEVICE_PICKER_GROUP_STORAGE_KEY;
|
|
69844
71117
|
exports.DEVICE_ROLE_META = DEVICE_ROLE_META;
|
|
71118
|
+
exports.DEVICE_ROLE_NOUNS = DEVICE_ROLE_NOUNS;
|
|
69845
71119
|
exports.DEVICE_TYPE_CONTROL = DEVICE_TYPE_CONTROL;
|
|
69846
71120
|
exports.DEVICE_TYPE_META = DEVICE_TYPE_META;
|
|
71121
|
+
exports.DEVICE_TYPE_NOUNS = DEVICE_TYPE_NOUNS;
|
|
69847
71122
|
exports.DataRecordsHub = DataRecordsHub;
|
|
69848
71123
|
exports.DataTable = DataTable;
|
|
69849
71124
|
exports.DataTableFilterBar = DataTableFilterBar;
|
|
@@ -69860,11 +71135,14 @@ exports.DeviceContextProvider = DeviceContextProvider;
|
|
|
69860
71135
|
exports.DeviceExportPanel = DeviceExportPanel;
|
|
69861
71136
|
exports.DeviceExportSetup = DeviceExportSetup;
|
|
69862
71137
|
exports.DeviceFilterBar = DeviceFilterBar;
|
|
71138
|
+
exports.DeviceFleetFromServer = DeviceFleetFromServer;
|
|
71139
|
+
exports.DeviceFleetProvider = DeviceFleetProvider;
|
|
69863
71140
|
exports.DeviceGrid = DeviceGrid;
|
|
69864
71141
|
exports.DeviceHistoryView = DeviceHistoryView;
|
|
69865
71142
|
exports.DeviceItem = DeviceItem;
|
|
69866
71143
|
exports.DeviceList = DeviceList;
|
|
69867
71144
|
exports.DeviceMultiSelectField = DeviceMultiSelectField;
|
|
71145
|
+
exports.DeviceName = DeviceName;
|
|
69868
71146
|
exports.DevicePicker = DevicePicker;
|
|
69869
71147
|
exports.DeviceQuickDetailProvider = DeviceQuickDetailProvider;
|
|
69870
71148
|
exports.DeviceSelectField = DeviceSelectField;
|
|
@@ -70293,6 +71571,7 @@ exports.ViewSwitch = ViewSwitch;
|
|
|
70293
71571
|
exports.VodPlaybackProvider = VodPlaybackProvider;
|
|
70294
71572
|
exports.Volume2 = Volume2;
|
|
70295
71573
|
exports.VolumeX = VolumeX;
|
|
71574
|
+
exports.WashingMachine = WashingMachine;
|
|
70296
71575
|
exports.WaterHeaterHeroCard = WaterHeaterHeroCard;
|
|
70297
71576
|
exports.WaterHeaterInlineControl = WaterHeaterInlineControl;
|
|
70298
71577
|
exports.Waves = Waves;
|
|
@@ -70395,6 +71674,7 @@ exports.describeDeviceSelector = describeDeviceSelector;
|
|
|
70395
71674
|
exports.deviceIntegrationResolver = deviceIntegrationResolver;
|
|
70396
71675
|
exports.deviceListStateOf = deviceListStateOf;
|
|
70397
71676
|
exports.deviceMatchesFilter = deviceMatchesFilter;
|
|
71677
|
+
exports.deviceNameNouns = deviceNameNouns;
|
|
70398
71678
|
exports.deviceOptionLabel = deviceOptionLabel;
|
|
70399
71679
|
exports.deviceRoleMeta = deviceRoleMeta;
|
|
70400
71680
|
exports.deviceRoleMetaOf = deviceRoleMetaOf;
|
|
@@ -70422,10 +71702,12 @@ exports.findTimezone = _camstack_types.findTimezone;
|
|
|
70422
71702
|
exports.flattenPickerGrouping = flattenPickerGrouping;
|
|
70423
71703
|
exports.flattenPickerRows = flattenPickerRows;
|
|
70424
71704
|
exports.fleetViewOf = fleetViewOf;
|
|
71705
|
+
exports.foldDeviceName = foldDeviceName;
|
|
70425
71706
|
exports.formatChartBytes = formatChartBytes;
|
|
70426
71707
|
exports.formatChartNumber = formatChartNumber;
|
|
70427
71708
|
exports.formatChartValue = formatChartValue;
|
|
70428
71709
|
exports.formatControlDateTime = formatControlDateTime;
|
|
71710
|
+
exports.formatDeviceName = formatDeviceName;
|
|
70429
71711
|
exports.formatLastSeen = formatLastSeen;
|
|
70430
71712
|
exports.formatNumeric = formatNumeric;
|
|
70431
71713
|
exports.formatSettingValue = formatSettingValue;
|
|
@@ -70453,6 +71735,7 @@ exports.humanizeName = humanizeName;
|
|
|
70453
71735
|
exports.humidifierTint = humidifierTint;
|
|
70454
71736
|
exports.iconGlyphsFailed = iconGlyphsFailed;
|
|
70455
71737
|
exports.iconGlyphsLoaded = iconGlyphsLoaded;
|
|
71738
|
+
exports.indexDeviceNames = indexDeviceNames;
|
|
70456
71739
|
exports.initialScrubState = initialScrubState;
|
|
70457
71740
|
exports.insertAtSelection = insertAtSelection;
|
|
70458
71741
|
exports.isAbsentProvider = isAbsentProvider;
|
|
@@ -70460,6 +71743,7 @@ exports.isAbsentProvider$1 = isAbsentProvider;
|
|
|
70460
71743
|
exports.isByteUnit = isByteUnit;
|
|
70461
71744
|
exports.isConsumableLevelField = isConsumableLevelField;
|
|
70462
71745
|
exports.isDataTableFilterActive = isDataTableFilterActive;
|
|
71746
|
+
exports.isDeviceNameStock = isDeviceNameStock;
|
|
70463
71747
|
Object.defineProperty(exports, "isDrawableSubjectPath", {
|
|
70464
71748
|
enumerable: true,
|
|
70465
71749
|
get: function() {
|
|
@@ -70501,6 +71785,7 @@ exports.nodeTextColorClass = nodeTextColorClass;
|
|
|
70501
71785
|
exports.normalizeForSearch = normalizeForSearch;
|
|
70502
71786
|
exports.normalizeLanguage = normalizeLanguage;
|
|
70503
71787
|
exports.normalizeSelection = normalizeSelection;
|
|
71788
|
+
exports.nounSpecFor = nounSpecFor;
|
|
70504
71789
|
exports.occupancyFacets = occupancyFacets;
|
|
70505
71790
|
exports.occupancyLines = occupancyLines;
|
|
70506
71791
|
exports.offListSelections = offListSelections;
|
|
@@ -70555,6 +71840,7 @@ exports.resolveContainerPrimary = resolveContainerPrimary;
|
|
|
70555
71840
|
exports.resolveControlAlign = resolveControlAlign;
|
|
70556
71841
|
exports.resolveDeviceControl = resolveDeviceControl;
|
|
70557
71842
|
exports.resolveDeviceIntegration = resolveDeviceIntegration;
|
|
71843
|
+
exports.resolveDeviceLabel = resolveDeviceLabel;
|
|
70558
71844
|
exports.resolveDisplayIcon = resolveDisplayIcon;
|
|
70559
71845
|
exports.resolveEffectiveDefaultModel = resolveEffectiveDefaultModel;
|
|
70560
71846
|
exports.resolveEffectiveStepModel = resolveEffectiveStepModel;
|
|
@@ -70573,6 +71859,7 @@ exports.rootSourceState = rootSourceState;
|
|
|
70573
71859
|
exports.routerBasename = routerBasename;
|
|
70574
71860
|
exports.runningDurationSince = runningDurationSince;
|
|
70575
71861
|
exports.runningStatusParts = runningStatusParts;
|
|
71862
|
+
exports.sameDeviceName = sameDeviceName;
|
|
70576
71863
|
exports.sameLocationSuggestions = sameLocationSuggestions;
|
|
70577
71864
|
exports.scrubReducer = scrubReducer;
|
|
70578
71865
|
exports.searchSteps = searchSteps;
|
|
@@ -70606,6 +71893,7 @@ exports.stepFieldDomId = stepFieldDomId;
|
|
|
70606
71893
|
exports.stepHasModelForFormat = stepHasModelForFormat;
|
|
70607
71894
|
exports.stepLocalFields = stepLocalFields;
|
|
70608
71895
|
exports.stepModelOptions = stepModelOptions;
|
|
71896
|
+
exports.stripDeviceParentPrefix = stripDeviceParentPrefix;
|
|
70609
71897
|
exports.stripParentNamePrefix = stripParentNamePrefix;
|
|
70610
71898
|
Object.defineProperty(exports, "subjectPathSampleFromBox", {
|
|
70611
71899
|
enumerable: true,
|
|
@@ -70903,6 +72191,8 @@ exports.useDeviceHistoryRecord = useDeviceHistoryRecord;
|
|
|
70903
72191
|
exports.useDeviceHistoryRecordBuckets = useDeviceHistoryRecordBuckets;
|
|
70904
72192
|
exports.useDeviceHistorySetDeviceEnabled = useDeviceHistorySetDeviceEnabled;
|
|
70905
72193
|
exports.useDeviceId = useDeviceId;
|
|
72194
|
+
exports.useDeviceLabel = useDeviceLabel;
|
|
72195
|
+
exports.useDeviceLabelById = useDeviceLabelById;
|
|
70906
72196
|
exports.useDeviceListPageSize = useDeviceListPageSize;
|
|
70907
72197
|
exports.useDeviceManagerAddLocation = useDeviceManagerAddLocation;
|
|
70908
72198
|
exports.useDeviceManagerAdoptDevice = useDeviceManagerAdoptDevice;
|
|
@@ -70996,6 +72286,8 @@ exports.useDeviceManagerTestField = useDeviceManagerTestField;
|
|
|
70996
72286
|
exports.useDeviceManagerUpdateConfig = useDeviceManagerUpdateConfig;
|
|
70997
72287
|
exports.useDeviceManagerUpdateDeviceField = useDeviceManagerUpdateDeviceField;
|
|
70998
72288
|
exports.useDeviceManagerUpdateDeviceFieldsBatch = useDeviceManagerUpdateDeviceFieldsBatch;
|
|
72289
|
+
exports.useDeviceNameIndex = useDeviceNameIndex;
|
|
72290
|
+
exports.useDeviceNameNouns = useDeviceNameNouns;
|
|
70999
72291
|
exports.useDeviceNetworkLink = useDeviceNetworkLink;
|
|
71000
72292
|
exports.useDeviceOpsGetConfigEntries = useDeviceOpsGetConfigEntries;
|
|
71001
72293
|
exports.useDeviceOpsGetRawState = useDeviceOpsGetRawState;
|