@camstack/addon-agent-ui 1.2.275 → 1.2.277
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/addon.js +274 -29
- package/dist/assets/{MotionZonesSettings-BJ7Yxusl.js → MotionZonesSettings-uUbAkmjZ.js} +1 -1
- package/dist/assets/{PrivacyMaskSettings-B2vgX-ox.js → PrivacyMaskSettings-B9TXHomV.js} +1 -1
- package/dist/assets/{SceneMonitorEditor-C5Pw47Ap.js → SceneMonitorEditor-CEf8URN2.js} +1 -1
- package/dist/assets/index-DD00yN8O.js +112 -0
- package/dist/index.html +1 -1
- package/package.json +1 -1
- package/dist/assets/index-DK4KYQh4.js +0 -112
package/dist/addon.js
CHANGED
|
@@ -5443,7 +5443,7 @@ var ZodIssueCode = {
|
|
|
5443
5443
|
var ZodFirstPartyTypeKind;
|
|
5444
5444
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5445
5445
|
//#endregion
|
|
5446
|
-
//#region ../types/dist/sleep-
|
|
5446
|
+
//#region ../types/dist/sleep-0sD_LHLI.mjs
|
|
5447
5447
|
/**
|
|
5448
5448
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5449
5449
|
* window to float samples (D455).
|
|
@@ -8605,6 +8605,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
8605
8605
|
"login-method",
|
|
8606
8606
|
"media-player",
|
|
8607
8607
|
"mesh-network",
|
|
8608
|
+
"meter",
|
|
8608
8609
|
"metrics-provider",
|
|
8609
8610
|
"model-convert",
|
|
8610
8611
|
"model-distributor",
|
|
@@ -9662,6 +9663,10 @@ Object.freeze({
|
|
|
9662
9663
|
]
|
|
9663
9664
|
}
|
|
9664
9665
|
],
|
|
9666
|
+
"meter": [{
|
|
9667
|
+
"path": "value",
|
|
9668
|
+
"valueType": "number"
|
|
9669
|
+
}],
|
|
9665
9670
|
"motion": [
|
|
9666
9671
|
{
|
|
9667
9672
|
"path": "detected",
|
|
@@ -10405,7 +10410,7 @@ object({
|
|
|
10405
10410
|
params: record(string(), union([string(), number()])).optional()
|
|
10406
10411
|
});
|
|
10407
10412
|
//#endregion
|
|
10408
|
-
//#region ../types/dist/err-msg-
|
|
10413
|
+
//#region ../types/dist/err-msg-DIorGYeC.mjs
|
|
10409
10414
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
10410
10415
|
DeviceType["Camera"] = "camera";
|
|
10411
10416
|
DeviceType["Hub"] = "hub";
|
|
@@ -10499,8 +10504,14 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
|
10499
10504
|
DeviceType["PetFeeder"] = "pet-feeder";
|
|
10500
10505
|
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
10501
10506
|
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
10502
|
-
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10507
|
+
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10508
|
+
* A plug-built dishwasher carries running-state and power instead. */
|
|
10503
10509
|
DeviceType["Dishwasher"] = "dishwasher";
|
|
10510
|
+
/** Washing machine. A plug-built one is running while its power stays
|
|
10511
|
+
* above a threshold. No program cap — that surface is the dishwasher's. */
|
|
10512
|
+
DeviceType["Washer"] = "washer";
|
|
10513
|
+
/** Tumble dryer. Same plug-built running surface as {@link Washer}. */
|
|
10514
|
+
DeviceType["Dryer"] = "dryer";
|
|
10504
10515
|
return DeviceType;
|
|
10505
10516
|
}({});
|
|
10506
10517
|
var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
|
|
@@ -10748,7 +10759,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
|
|
|
10748
10759
|
return DeviceRole;
|
|
10749
10760
|
}({});
|
|
10750
10761
|
//#endregion
|
|
10751
|
-
//#region ../types/dist/composition-
|
|
10762
|
+
//#region ../types/dist/composition-CpETZ4HL.mjs
|
|
10752
10763
|
/**
|
|
10753
10764
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
10754
10765
|
*
|
|
@@ -11504,6 +11515,97 @@ function validateExpressionSource(src) {
|
|
|
11504
11515
|
return null;
|
|
11505
11516
|
}
|
|
11506
11517
|
/**
|
|
11518
|
+
* One power reading becomes a washer, dryer or dishwasher (D944 helper).
|
|
11519
|
+
*
|
|
11520
|
+
* Standby of the control board is under 5 W; a motor or a heater is far
|
|
11521
|
+
* above that, so 5 W is the line. A door lock or a short pump spike is not
|
|
11522
|
+
* a cycle, so running starts only after 30 s above the line.
|
|
11523
|
+
*
|
|
11524
|
+
* A wash, dry or dishwasher pause (soak, heat-wait, heater off between
|
|
11525
|
+
* bursts) lasts several minutes. Ending the cycle on the first dip would
|
|
11526
|
+
* report "finished" in the middle of the program, so the stop dwell is
|
|
11527
|
+
* 10 minutes on every type. The number is stored per type so one machine
|
|
11528
|
+
* can move later without moving the others.
|
|
11529
|
+
*/
|
|
11530
|
+
var APPLIANCE_TEMPLATE_ID = "appliance";
|
|
11531
|
+
var APPLIANCE_KINDS = [
|
|
11532
|
+
"washer",
|
|
11533
|
+
"dryer",
|
|
11534
|
+
"dishwasher"
|
|
11535
|
+
];
|
|
11536
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
11537
|
+
/**
|
|
11538
|
+
* Statistics and integrals over a history read (D944).
|
|
11539
|
+
*
|
|
11540
|
+
* Pure: the same points always give the same answer, so a restart recomputes
|
|
11541
|
+
* rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
|
|
11542
|
+
* never the mean of the samples. A hole with no held value is not integrated
|
|
11543
|
+
* as zero. A truncated read is not published.
|
|
11544
|
+
*/
|
|
11545
|
+
var STATISTIC_STATS = [
|
|
11546
|
+
"min",
|
|
11547
|
+
"max",
|
|
11548
|
+
"mean",
|
|
11549
|
+
"sum",
|
|
11550
|
+
"count",
|
|
11551
|
+
"change"
|
|
11552
|
+
];
|
|
11553
|
+
/**
|
|
11554
|
+
* The range a statistics or integral helper asks history for (D944).
|
|
11555
|
+
*
|
|
11556
|
+
* Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
|
|
11557
|
+
* or 25 hours across a DST change. A tier is eligible only when its retention
|
|
11558
|
+
* is strictly longer than the longest that range can be. Forever qualifies.
|
|
11559
|
+
* Equal to a tier's retention is a refusal, not a short answer.
|
|
11560
|
+
*/
|
|
11561
|
+
var MINUTE_MS = 6e4;
|
|
11562
|
+
var HOUR_MS = 60 * MINUTE_MS;
|
|
11563
|
+
var DAY_MS = 24 * HOUR_MS;
|
|
11564
|
+
var ROLLING_SPANS = [
|
|
11565
|
+
"1h",
|
|
11566
|
+
"24h",
|
|
11567
|
+
"2d",
|
|
11568
|
+
"7d",
|
|
11569
|
+
"30d",
|
|
11570
|
+
"custom"
|
|
11571
|
+
];
|
|
11572
|
+
var CALENDAR_PERIODS = [
|
|
11573
|
+
"today",
|
|
11574
|
+
"yesterday",
|
|
11575
|
+
"this-week",
|
|
11576
|
+
"this-month"
|
|
11577
|
+
];
|
|
11578
|
+
var RESET_PERIODS = [
|
|
11579
|
+
"never",
|
|
11580
|
+
"daily",
|
|
11581
|
+
"weekly",
|
|
11582
|
+
"monthly"
|
|
11583
|
+
];
|
|
11584
|
+
5 * MINUTE_MS;
|
|
11585
|
+
24 * HOUR_MS, 2 * DAY_MS, 7 * DAY_MS, 30 * DAY_MS;
|
|
11586
|
+
7 * DAY_MS, 30 * DAY_MS, 365 * DAY_MS;
|
|
11587
|
+
var StatisticWindowSchema = discriminatedUnion("kind", [object({
|
|
11588
|
+
kind: literal("rolling"),
|
|
11589
|
+
span: _enum(ROLLING_SPANS),
|
|
11590
|
+
customMinutes: number().int().min(5).optional()
|
|
11591
|
+
}).check((payload) => {
|
|
11592
|
+
if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
|
|
11593
|
+
code: "custom",
|
|
11594
|
+
message: "a custom range needs a duration in minutes",
|
|
11595
|
+
path: ["customMinutes"],
|
|
11596
|
+
input: payload.value
|
|
11597
|
+
});
|
|
11598
|
+
if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
|
|
11599
|
+
code: "custom",
|
|
11600
|
+
message: "only a custom range carries a duration",
|
|
11601
|
+
path: ["customMinutes"],
|
|
11602
|
+
input: payload.value
|
|
11603
|
+
});
|
|
11604
|
+
}), object({
|
|
11605
|
+
kind: literal("calendar"),
|
|
11606
|
+
period: _enum(CALENDAR_PERIODS)
|
|
11607
|
+
})]);
|
|
11608
|
+
/**
|
|
11507
11609
|
* A composition source identity: `(addonId, stableId)`, never a numeric device
|
|
11508
11610
|
* id. Split out so helper schemas can name it without a cycle through
|
|
11509
11611
|
* `composition.ts` (D659).
|
|
@@ -11559,14 +11661,37 @@ var HelperMemberSchema = object({
|
|
|
11559
11661
|
cap: string().min(1),
|
|
11560
11662
|
fieldPath: string().min(1)
|
|
11561
11663
|
});
|
|
11562
|
-
var HelperSpecSchema = discriminatedUnion("kind", [
|
|
11563
|
-
|
|
11564
|
-
|
|
11565
|
-
|
|
11566
|
-
|
|
11567
|
-
|
|
11568
|
-
|
|
11569
|
-
|
|
11664
|
+
var HelperSpecSchema = discriminatedUnion("kind", [
|
|
11665
|
+
object({
|
|
11666
|
+
kind: literal("group"),
|
|
11667
|
+
templateId: GroupTemplateIdSchema,
|
|
11668
|
+
aggregate: AggregateReducerSchema,
|
|
11669
|
+
members: array(HelperMemberSchema).min(1).max(64),
|
|
11670
|
+
/** Actuator groups only. Readings leave this unset. */
|
|
11671
|
+
active: ActiveCriterionSchema.optional()
|
|
11672
|
+
}),
|
|
11673
|
+
object({
|
|
11674
|
+
kind: literal("appliance"),
|
|
11675
|
+
templateId: literal(APPLIANCE_TEMPLATE_ID),
|
|
11676
|
+
appliance: _enum(APPLIANCE_KINDS),
|
|
11677
|
+
thresholdWatts: number().positive(),
|
|
11678
|
+
startDwellMs: number().int().nonnegative(),
|
|
11679
|
+
stopDwellMs: number().int().nonnegative(),
|
|
11680
|
+
member: HelperMemberSchema
|
|
11681
|
+
}),
|
|
11682
|
+
object({
|
|
11683
|
+
kind: literal("statistic"),
|
|
11684
|
+
stat: _enum(STATISTIC_STATS),
|
|
11685
|
+
window: StatisticWindowSchema,
|
|
11686
|
+
source: HelperMemberSchema
|
|
11687
|
+
}),
|
|
11688
|
+
object({
|
|
11689
|
+
kind: literal("integral"),
|
|
11690
|
+
reset: _enum(RESET_PERIODS),
|
|
11691
|
+
output: _enum(["energy", "meter"]),
|
|
11692
|
+
source: HelperMemberSchema
|
|
11693
|
+
})
|
|
11694
|
+
]);
|
|
11570
11695
|
/** A composed device's stableId is this prefix plus the block id. */
|
|
11571
11696
|
var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
|
|
11572
11697
|
/** Longest snippet a `code` source may carry (slice 4). */
|
|
@@ -11640,6 +11765,26 @@ var CompositionFieldSourceSchema = discriminatedUnion("kind", [
|
|
|
11640
11765
|
"omit",
|
|
11641
11766
|
"offline"
|
|
11642
11767
|
])
|
|
11768
|
+
}),
|
|
11769
|
+
object({
|
|
11770
|
+
kind: literal("series"),
|
|
11771
|
+
read: CompositionFieldReadSchema,
|
|
11772
|
+
/** `value` is the statistic or the integral. The others are the gap counts. */
|
|
11773
|
+
publish: _enum([
|
|
11774
|
+
"value",
|
|
11775
|
+
"included",
|
|
11776
|
+
"excluded",
|
|
11777
|
+
"total"
|
|
11778
|
+
]),
|
|
11779
|
+
/**
|
|
11780
|
+
* What an unanswered `value` does. Counts ignore this. `offline` leaves the
|
|
11781
|
+
* device unseeded until history answers, so a restart cannot publish 0.
|
|
11782
|
+
*/
|
|
11783
|
+
empty: _enum([
|
|
11784
|
+
"null",
|
|
11785
|
+
"omit",
|
|
11786
|
+
"offline"
|
|
11787
|
+
])
|
|
11643
11788
|
})
|
|
11644
11789
|
]);
|
|
11645
11790
|
var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
|
|
@@ -17798,7 +17943,8 @@ var CompositionProblemSchema = object({
|
|
|
17798
17943
|
"native-capability-replace",
|
|
17799
17944
|
"mixed-quantity",
|
|
17800
17945
|
"helper-mismatch",
|
|
17801
|
-
"member-constraint"
|
|
17946
|
+
"member-constraint",
|
|
17947
|
+
"retention"
|
|
17802
17948
|
]),
|
|
17803
17949
|
path: string(),
|
|
17804
17950
|
message: string()
|
|
@@ -18038,7 +18184,7 @@ Object.freeze({
|
|
|
18038
18184
|
* One catalog row per base reading a group helper can build (D944 §3).
|
|
18039
18185
|
* Data, not a form default written into the block.
|
|
18040
18186
|
*/
|
|
18041
|
-
var NOW = {
|
|
18187
|
+
var NOW$1 = {
|
|
18042
18188
|
fieldPath: "lastFetchedAt",
|
|
18043
18189
|
expr: "now"
|
|
18044
18190
|
};
|
|
@@ -18084,7 +18230,7 @@ var GROUP_TEMPLATES = [
|
|
|
18084
18230
|
quantity: "temperature",
|
|
18085
18231
|
defaultAggregate: "mean",
|
|
18086
18232
|
empty: "null",
|
|
18087
|
-
companions: [NOW]
|
|
18233
|
+
companions: [NOW$1]
|
|
18088
18234
|
}),
|
|
18089
18235
|
numeric({
|
|
18090
18236
|
id: "humidity",
|
|
@@ -18095,7 +18241,7 @@ var GROUP_TEMPLATES = [
|
|
|
18095
18241
|
quantity: "humidity",
|
|
18096
18242
|
defaultAggregate: "mean",
|
|
18097
18243
|
empty: "null",
|
|
18098
|
-
companions: [NOW]
|
|
18244
|
+
companions: [NOW$1]
|
|
18099
18245
|
}),
|
|
18100
18246
|
numeric({
|
|
18101
18247
|
id: "pressure",
|
|
@@ -18106,7 +18252,7 @@ var GROUP_TEMPLATES = [
|
|
|
18106
18252
|
quantity: "pressure",
|
|
18107
18253
|
defaultAggregate: "mean",
|
|
18108
18254
|
empty: "null",
|
|
18109
|
-
companions: [NOW]
|
|
18255
|
+
companions: [NOW$1]
|
|
18110
18256
|
}),
|
|
18111
18257
|
numeric({
|
|
18112
18258
|
id: "illuminance",
|
|
@@ -18117,7 +18263,7 @@ var GROUP_TEMPLATES = [
|
|
|
18117
18263
|
quantity: "illuminance",
|
|
18118
18264
|
defaultAggregate: "mean",
|
|
18119
18265
|
empty: "null",
|
|
18120
|
-
companions: [NOW]
|
|
18266
|
+
companions: [NOW$1]
|
|
18121
18267
|
}),
|
|
18122
18268
|
numeric({
|
|
18123
18269
|
id: "power",
|
|
@@ -18128,7 +18274,7 @@ var GROUP_TEMPLATES = [
|
|
|
18128
18274
|
quantity: "power",
|
|
18129
18275
|
defaultAggregate: "sum",
|
|
18130
18276
|
empty: "omit",
|
|
18131
|
-
companions: [NOW]
|
|
18277
|
+
companions: [NOW$1]
|
|
18132
18278
|
}),
|
|
18133
18279
|
numeric({
|
|
18134
18280
|
id: "energy",
|
|
@@ -18139,7 +18285,7 @@ var GROUP_TEMPLATES = [
|
|
|
18139
18285
|
quantity: "energy",
|
|
18140
18286
|
defaultAggregate: "sum",
|
|
18141
18287
|
empty: "omit",
|
|
18142
|
-
companions: [NOW]
|
|
18288
|
+
companions: [NOW$1]
|
|
18143
18289
|
}),
|
|
18144
18290
|
numeric({
|
|
18145
18291
|
id: "battery",
|
|
@@ -18174,7 +18320,7 @@ var GROUP_TEMPLATES = [
|
|
|
18174
18320
|
quantity: "device",
|
|
18175
18321
|
defaultAggregate: "mean",
|
|
18176
18322
|
empty: "null",
|
|
18177
|
-
companions: [NOW]
|
|
18323
|
+
companions: [NOW$1]
|
|
18178
18324
|
}),
|
|
18179
18325
|
binary({
|
|
18180
18326
|
id: "motion",
|
|
@@ -18303,6 +18449,7 @@ function actuator(input) {
|
|
|
18303
18449
|
}
|
|
18304
18450
|
new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
|
|
18305
18451
|
DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
|
|
18452
|
+
DeviceType.Camera;
|
|
18306
18453
|
`${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
|
|
18307
18454
|
/**
|
|
18308
18455
|
* What a composition may BUILD on a device type (G2, D676): the caps a new
|
|
@@ -59094,6 +59241,11 @@ DeviceType.Lock, method(object({
|
|
|
59094
59241
|
kind: "mutation",
|
|
59095
59242
|
auth: "protected"
|
|
59096
59243
|
});
|
|
59244
|
+
object({
|
|
59245
|
+
value: number().nullable().meta(readingMeta("device", { label: "Total" })),
|
|
59246
|
+
lastFetchedAt: number()
|
|
59247
|
+
});
|
|
59248
|
+
DeviceType.Sensor;
|
|
59097
59249
|
/**
|
|
59098
59250
|
* Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
|
|
59099
59251
|
* Apple TV, Spotify, Roku, generic OTT receivers, …) on
|
|
@@ -61011,7 +61163,7 @@ object({
|
|
|
61011
61163
|
/** Ms epoch when the slice was last updated. */
|
|
61012
61164
|
lastFetchedAt: number()
|
|
61013
61165
|
});
|
|
61014
|
-
DeviceType.Sensor;
|
|
61166
|
+
DeviceType.Sensor, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
61015
61167
|
/**
|
|
61016
61168
|
* Presence cap. Models HA `person.*` and `device_tracker.*` entities
|
|
61017
61169
|
* on `DeviceType.Presence`. Read-only — no setters: presence is
|
|
@@ -61458,7 +61610,7 @@ object({
|
|
|
61458
61610
|
phase: string().nullable()
|
|
61459
61611
|
});
|
|
61460
61612
|
Object.values(DeviceType);
|
|
61461
|
-
DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
61613
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
61462
61614
|
DeviceType.Camera, DeviceType.Sensor, DeviceType.Switch, method(object({ deviceId: number().int().nonnegative() }), object({ success: literal(true) }), {
|
|
61463
61615
|
kind: "mutation",
|
|
61464
61616
|
auth: "admin"
|
|
@@ -65190,7 +65342,7 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
|
|
|
65190
65342
|
auth: "admin"
|
|
65191
65343
|
});
|
|
65192
65344
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
65193
|
-
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher, DeviceType.Camera, DeviceType.Camera, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
65345
|
+
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Dryer, DeviceType.Camera, DeviceType.Camera, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
65194
65346
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
65195
65347
|
DeviceRole.BinarySensor, DeviceRole.MotionSensor;
|
|
65196
65348
|
new Set(CAP_NAMES);
|
|
@@ -65243,7 +65395,7 @@ var AccessoryKind = {
|
|
|
65243
65395
|
PrivacyMask: DeviceRole.PrivacyMask
|
|
65244
65396
|
};
|
|
65245
65397
|
AccessoryKind.Siren, AccessoryKind.Floodlight, AccessoryKind.Spotlight, AccessoryKind.PirSensor, AccessoryKind.Chime, AccessoryKind.Autotrack, AccessoryKind.Nightvision, AccessoryKind.PrivacyMask;
|
|
65246
|
-
DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Camera, DeviceType.Hub, DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher;
|
|
65398
|
+
DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Camera, DeviceType.Hub, DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Dryer;
|
|
65247
65399
|
new Set(Object.values(DeviceType));
|
|
65248
65400
|
Object.freeze({
|
|
65249
65401
|
"accessories.getStatus": {
|
|
@@ -69432,6 +69584,13 @@ Object.freeze({
|
|
|
69432
69584
|
access: "create",
|
|
69433
69585
|
role: "admin"
|
|
69434
69586
|
},
|
|
69587
|
+
"meter.getStatus": {
|
|
69588
|
+
capName: "meter",
|
|
69589
|
+
capScope: "device",
|
|
69590
|
+
addonId: null,
|
|
69591
|
+
access: "view",
|
|
69592
|
+
role: "viewer"
|
|
69593
|
+
},
|
|
69435
69594
|
"metricsProvider.collectSnapshot": {
|
|
69436
69595
|
capName: "metrics-provider",
|
|
69437
69596
|
capScope: "system",
|
|
@@ -77530,7 +77689,39 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
77530
77689
|
phrase: t("When {device} finishes", "Quando {device} finisce"),
|
|
77531
77690
|
icon: "square"
|
|
77532
77691
|
}
|
|
77533
|
-
}
|
|
77692
|
+
},
|
|
77693
|
+
overrides: { byType: {
|
|
77694
|
+
[DeviceType.Washer]: {
|
|
77695
|
+
state: { running: {
|
|
77696
|
+
whenTrue: t("When the washing machine starts", "Quando la lavatrice inizia"),
|
|
77697
|
+
whenFalse: t("When the washing machine has finished", "Quando la lavatrice ha finito")
|
|
77698
|
+
} },
|
|
77699
|
+
events: {
|
|
77700
|
+
onStarted: { phrase: t("When the washing machine starts", "Quando la lavatrice inizia") },
|
|
77701
|
+
onFinished: { phrase: t("When the washing machine has finished", "Quando la lavatrice ha finito") }
|
|
77702
|
+
}
|
|
77703
|
+
},
|
|
77704
|
+
[DeviceType.Dryer]: {
|
|
77705
|
+
state: { running: {
|
|
77706
|
+
whenTrue: t("When the dryer starts", "Quando l'asciugatrice inizia"),
|
|
77707
|
+
whenFalse: t("When the dryer has finished", "Quando l'asciugatrice ha finito")
|
|
77708
|
+
} },
|
|
77709
|
+
events: {
|
|
77710
|
+
onStarted: { phrase: t("When the dryer starts", "Quando l'asciugatrice inizia") },
|
|
77711
|
+
onFinished: { phrase: t("When the dryer has finished", "Quando l'asciugatrice ha finito") }
|
|
77712
|
+
}
|
|
77713
|
+
},
|
|
77714
|
+
[DeviceType.Dishwasher]: {
|
|
77715
|
+
state: { running: {
|
|
77716
|
+
whenTrue: t("When the dishwasher starts", "Quando la lavastoviglie inizia"),
|
|
77717
|
+
whenFalse: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito")
|
|
77718
|
+
} },
|
|
77719
|
+
events: {
|
|
77720
|
+
onStarted: { phrase: t("When the dishwasher starts", "Quando la lavastoviglie inizia") },
|
|
77721
|
+
onFinished: { phrase: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito") }
|
|
77722
|
+
}
|
|
77723
|
+
}
|
|
77724
|
+
} }
|
|
77534
77725
|
},
|
|
77535
77726
|
update: {
|
|
77536
77727
|
scope: "device",
|
|
@@ -78358,6 +78549,17 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78358
78549
|
}],
|
|
78359
78550
|
events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
|
|
78360
78551
|
},
|
|
78552
|
+
meter: {
|
|
78553
|
+
scope: "device",
|
|
78554
|
+
noun: t("Meter", "Contatore"),
|
|
78555
|
+
state: [{
|
|
78556
|
+
kind: "numeric",
|
|
78557
|
+
field: "value",
|
|
78558
|
+
quantity: t("the total", "il totale"),
|
|
78559
|
+
label: t("Total", "Totale"),
|
|
78560
|
+
icon: "gauge"
|
|
78561
|
+
}]
|
|
78562
|
+
},
|
|
78361
78563
|
"numeric-sensor": {
|
|
78362
78564
|
scope: "device",
|
|
78363
78565
|
noun: t("Sensor", "Sensore"),
|
|
@@ -78830,8 +79032,47 @@ function projectAction(cap, action) {
|
|
|
78830
79032
|
};
|
|
78831
79033
|
}
|
|
78832
79034
|
Object.entries(CAP_VOCABULARY_BY_NAME).flatMap(([cap, entry]) => entry.scope === "device" ? (entry.actions ?? []).map((a) => projectAction(cap, a)) : []);
|
|
78833
|
-
DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher;
|
|
79035
|
+
DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Dryer;
|
|
78834
79036
|
DeviceFeature.BatteryOperated;
|
|
79037
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
79038
|
+
var HA_AS = "a power sensor (device_class power). Home Assistant has no laundry domain. running-state stays unexported until a null reading can be published as unavailable.";
|
|
79039
|
+
var HOMEKIT_REASON = "HomeKit has no laundry-appliance service. The export tab would pair an accessory with nothing on it: running-state is withheld until a null reading can be unavailable, and power is not a HomeKit service this export honours.";
|
|
79040
|
+
var ALEXA_REASON = "Alexa has no laundry category in this export, and neither power nor running has an Alexa interface.";
|
|
79041
|
+
var GOOGLE_REASON = "Google WASHER, DRYER and DISHWASHER require RunCycle. A power threshold is not that trait, and this export does not publish RunCycle.";
|
|
79042
|
+
var MATTER_REASON = "No Matter export is built. The closest device types are Laundry Washer (0x0073) and Laundry Dryer (0x0074); a power threshold is not the Laundry Washer Mode cluster.";
|
|
79043
|
+
function withheld(reason) {
|
|
79044
|
+
return {
|
|
79045
|
+
[DeviceType.Washer]: {
|
|
79046
|
+
exported: false,
|
|
79047
|
+
reason
|
|
79048
|
+
},
|
|
79049
|
+
[DeviceType.Dryer]: {
|
|
79050
|
+
exported: false,
|
|
79051
|
+
reason
|
|
79052
|
+
},
|
|
79053
|
+
[DeviceType.Dishwasher]: {
|
|
79054
|
+
exported: false,
|
|
79055
|
+
reason
|
|
79056
|
+
}
|
|
79057
|
+
};
|
|
79058
|
+
}
|
|
79059
|
+
function offered(received) {
|
|
79060
|
+
return {
|
|
79061
|
+
[DeviceType.Washer]: {
|
|
79062
|
+
exported: true,
|
|
79063
|
+
as: received
|
|
79064
|
+
},
|
|
79065
|
+
[DeviceType.Dryer]: {
|
|
79066
|
+
exported: true,
|
|
79067
|
+
as: received
|
|
79068
|
+
},
|
|
79069
|
+
[DeviceType.Dishwasher]: {
|
|
79070
|
+
exported: true,
|
|
79071
|
+
as: received
|
|
79072
|
+
}
|
|
79073
|
+
};
|
|
79074
|
+
}
|
|
79075
|
+
offered(HA_AS), withheld(HOMEKIT_REASON), withheld(ALEXA_REASON), withheld(GOOGLE_REASON), withheld(MATTER_REASON);
|
|
78835
79076
|
Object.freeze({
|
|
78836
79077
|
"accessories.getStatus": [{
|
|
78837
79078
|
name: "deviceId",
|
|
@@ -80008,6 +80249,11 @@ Object.freeze({
|
|
|
80008
80249
|
form: "single",
|
|
80009
80250
|
optional: false
|
|
80010
80251
|
}],
|
|
80252
|
+
"meter.getStatus": [{
|
|
80253
|
+
name: "deviceId",
|
|
80254
|
+
form: "single",
|
|
80255
|
+
optional: false
|
|
80256
|
+
}],
|
|
80011
80257
|
"motion.getStatus": [{
|
|
80012
80258
|
name: "deviceId",
|
|
80013
80259
|
form: "single",
|
|
@@ -81615,7 +81861,6 @@ Object.freeze({
|
|
|
81615
81861
|
"network-access": "ingress",
|
|
81616
81862
|
"smtp-provider": "email"
|
|
81617
81863
|
});
|
|
81618
|
-
DeviceType.Camera;
|
|
81619
81864
|
/**
|
|
81620
81865
|
* A saved Customize assignment (D936). The schema is the type: callers use
|
|
81621
81866
|
* `z.infer`, they do not restate the shape.
|
|
@@ -82942,7 +83187,7 @@ var AgentUIAddon = class extends BaseAddon {
|
|
|
82942
83187
|
capability: adminUiCapability,
|
|
82943
83188
|
provider: {
|
|
82944
83189
|
getStaticDir: async () => ({ staticDir: path.resolve(__dirname) }),
|
|
82945
|
-
getVersion: async () => ({ version: "1.2.
|
|
83190
|
+
getVersion: async () => ({ version: "1.2.277" })
|
|
82946
83191
|
}
|
|
82947
83192
|
}];
|
|
82948
83193
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as e,i as t,l as n,n as r,o as i}from"./scheduler-0XZJE03d.js";import{C as a,c as o,d as s,h as c,l,p as u,t as ee}from"./index-
|
|
1
|
+
import{a as e,i as t,l as n,n as r,o as i}from"./scheduler-0XZJE03d.js";import{C as a,c as o,d as s,h as c,l,p as u,t as ee}from"./index-DD00yN8O.js";import{MaskShapeCanvas as d}from"./MaskShapeCanvas-BTvl6Rin.js";var f=a(`grid-2x2`,[[`path`,{d:`M12 3v18`,key:`108xh3`}],[`path`,{d:`M3 12h18`,key:`1i2n21`}],[`rect`,{x:`3`,y:`3`,width:`18`,height:`18`,rx:`2`,key:`h1oib`}]]),p=n(i(),1),m=n(e(),1),h=110,g=`motion-zones`,_=0,te=[1,2,3],v=1,y=`rounded-md border border-border bg-surface px-2 py-1 text-[11px] font-medium text-foreground-subtle hover:bg-surface-hover disabled:opacity-40 transition-colors`,b=`rounded-md border border-primary/50 bg-primary/15 px-2.5 py-1 text-[11px] font-medium text-primary hover:bg-primary/25 disabled:opacity-40 transition-colors`;function x(e,t,n){let r=t*n,i=Array.from({length:r});for(let t=0;t<r;t+=1)i[t]=e[t]===!0;return i}function S(e,t){if(e.length!==t.length)return!1;for(let n=0;n<e.length;n+=1)if(e[n]!==t[n])return!1;return!0}function C(e,t){return Math.ceil(e/t)}function w(e,t,n){return Math.min(n-1,Math.floor((e+.5)/t*n))}function T(e,t,n,r){let i=C(t,r),a=C(n,r),o=Array.from({length:i*a},()=>!1);for(let r=0;r<n;r+=1){let s=w(r,n,a);for(let n=0;n<t;n+=1)e[r*t+n]===!0&&(o[s*i+w(n,t,i)]=!0)}return o}function E(e,t,n,r){let i=C(t,r),a=C(n,r),o=Array.from({length:t*n},()=>!1);for(let r=0;r<n;r+=1){let s=w(r,n,a);for(let n=0;n<t;n+=1)o[r*t+n]=e[s*i+w(n,t,i)]===!0}return o}function D({deviceId:e}){let n=t(),i=s(c().trpcClient,e),[a,w]=(0,p.useState)(null),[D,O]=(0,p.useState)(!1),[k,A]=(0,p.useState)(null),[j,M]=(0,p.useState)(null),[N,P]=(0,p.useState)(v),[F,I]=(0,p.useState)(!1),[L,R]=(0,p.useState)(!1),z=(0,p.useRef)(!1);(0,p.useEffect)(()=>{if(!i)return;let e=!1;return z.current=!1,w(null),O(!1),A(null),M(null),P(v),R(!1),(async()=>{try{let t=await i.motionZones?.getOptions({});if(e)return;if(!t)throw Error(`device proxy not ready`);if(w(t),z.current)return;let n=await i.motionZones?.getStatus({});if(e)return;if(!n)throw Error(`device proxy not ready`);z.current=!0;let r=n.regions.find(e=>e.shape.kind===`grid`),a=x(r?r.shape.cells:[],t.grid.width,t.grid.height);M(a),A(T(a,t.grid.width,t.grid.height,v))}catch(t){if(e)return;l(t)?O(!0):console.error(`Motion Zones load failed`,t)}})(),()=>{e=!0}},[i]);let B=a?a.grid.width:0,V=a?a.grid.height:0,H=C(B,N),U=C(V,N),W=(0,p.useMemo)(()=>k&&a?E(k,B,V,N):null,[k,a,B,V,N]),G=(0,p.useMemo)(()=>W!==null&&j!==null&&!S(W,j),[W,j]),K=(0,p.useMemo)(()=>W?W.reduce((e,t)=>t?e+1:e,0):0,[W]),q=B*V,J=H*U,Y=(0,p.useCallback)(e=>{J>0&&A(Array.from({length:J},()=>e))},[J]),X=(0,p.useCallback)(()=>{A(e=>e&&e.map(e=>!e))},[]),Z=(0,p.useCallback)(()=>{j&&a&&A(T(j,B,V,N))},[j,a,B,V,N]),ne=(0,p.useCallback)(e=>{e===N||!a||A(t=>{if(!t)return P(e),t;let n=T(E(t,B,V,N),B,V,e);return P(e),n})},[N,a,B,V]),Q=(0,p.useMemo)(()=>a&&k?[{id:_,shape:{kind:`grid`,gridWidth:H,gridHeight:U,cells:[...k]}}]:[],[a,k,H,U]),$=(0,p.useCallback)((e,t)=>{t.kind===`grid`&&A(t.cells)},[]),re=(0,p.useCallback)(async()=>{if(!(!i||!k||!a)){I(!0);try{let e=E(k,a.grid.width,a.grid.height,N),t={kind:`grid`,gridWidth:a.grid.width,gridHeight:a.grid.height,cells:e};await i.motionZones?.setZone({patch:{regions:[{id:_,enabled:!0,shape:t}]}});let n=await i.motionZones?.getStatus({});if(n){let e=n.regions.find(e=>e.shape.kind===`grid`),t=x(e?e.shape.cells:[],a.grid.width,a.grid.height);M(t),A(T(t,a.grid.width,a.grid.height,N))}}catch(e){console.error(`Motion Zones save failed`,e)}finally{I(!1)}}},[i,k,a,N]);ee((0,p.useMemo)(()=>L&&!D&&a&&k?{id:g,order:h,node:(0,m.jsx)(d,{transparent:!0,items:Q,supportedShapes:[`grid`],grid:{width:H,height:U},selectedId:_,onSelect:()=>{},onShapeChange:$,onDrawComplete:()=>{},drawingKind:null})}:null,[L,D,a,k,Q,$,H,U]));let ie=!D&&a!==null&&k!==null;return i?(0,m.jsx)(u,{title:n(`uiLibrary.motionZones.title`,`Motion Zones`),icon:(0,m.jsx)(f,{className:`h-3.5 w-3.5 text-foreground-subtle`}),children:(0,m.jsx)(`div`,{className:`flex flex-col gap-3`,children:D?(0,m.jsx)(`p`,{className:`${o} leading-relaxed`,children:n(`uiLibrary.motionZones.unsupported`,`This camera doesn't expose an on-board motion zones grid.`)}):ie?(0,m.jsxs)(m.Fragment,{children:[(0,m.jsx)(`p`,{className:`${o} leading-relaxed`,children:(0,m.jsx)(r,{uiKey:`uiLibrary.motionZones.intro`,fallback:`Toggle <0>Edit grid</0> to paint the region directly on the live frame, then <1>Save</1> to push the mask to the camera. Pick a bigger <2>Cell size</2> for quicker, broad-stroke painting — it's resampled to the camera's native {{width}}×{{height}} grid on save (×1 is the finest).`,components:[(0,m.jsx)(`strong`,{className:`text-foreground`},`e`),(0,m.jsx)(`strong`,{className:`text-foreground`},`s`),(0,m.jsx)(`strong`,{className:`text-foreground`},`c`)],values:{width:a.grid.width,height:a.grid.height}})}),(0,m.jsxs)(`div`,{className:`flex items-center gap-2 flex-wrap`,children:[(0,m.jsx)(`button`,{type:`button`,onClick:()=>R(e=>!e),disabled:F,"aria-pressed":L,className:L?b:y,children:L?n(`uiLibrary.motionZones.doneEditing`,`Done editing`):n(`uiLibrary.motionZones.editGrid`,`Edit grid`)}),(0,m.jsx)(`button`,{type:`button`,onClick:()=>Y(!0),disabled:F,className:y,children:n(`uiLibrary.motionZones.allOn`,`All on`)}),(0,m.jsx)(`button`,{type:`button`,onClick:()=>Y(!1),disabled:F,className:y,children:n(`uiLibrary.motionZones.allOff`,`All off`)}),(0,m.jsx)(`button`,{type:`button`,onClick:X,disabled:F,className:y,children:n(`uiLibrary.motionZones.invert`,`Invert`)}),(0,m.jsxs)(`div`,{className:`flex items-center gap-1 ml-1`,role:`group`,"aria-label":n(`uiLibrary.motionZones.cellSize`,`Cell size`),children:[(0,m.jsx)(`span`,{className:`${o} mr-0.5`,children:n(`uiLibrary.motionZones.cellSize`,`Cell size`)}),te.map(e=>(0,m.jsxs)(`button`,{type:`button`,onClick:()=>ne(e),disabled:F,"aria-pressed":N===e,title:e===1?n(`uiLibrary.motionZones.cameraGrid`,`Camera grid {{width}}×{{height}} (finest)`,{width:B,height:V}):n(`uiLibrary.motionZones.paintingGrid`,`{{width}}×{{height}} painting grid · cells ×{{factor}} bigger`,{width:C(B,e),height:C(V,e),factor:e}),className:N===e?b:y,children:[`×`,e]},e))]}),(0,m.jsxs)(`span`,{className:`${o} ml-1 tabular-nums`,children:[n(`uiLibrary.motionZones.cells`,`{{active}} / {{total}} cells · {{width}}×{{height}}`,{active:K,total:q,width:a.grid.width,height:a.grid.height}),N===1?``:n(`uiLibrary.motionZones.paintSuffix`,` · paint {{width}}×{{height}}`,{width:H,height:U})]}),(0,m.jsx)(`span`,{className:`flex-1`}),(0,m.jsx)(`button`,{type:`button`,onClick:Z,disabled:F||!G,className:`rounded-md border border-border bg-surface px-2 py-1 text-[11px] text-foreground-subtle hover:bg-surface-hover disabled:opacity-40 transition-colors`,children:n(`uiLibrary.motionZones.revert`,`Revert`)}),(0,m.jsx)(`button`,{type:`button`,onClick:()=>void re(),disabled:F||!G,className:b,children:F?n(`uiLibrary.motionZones.saving`,`Saving…`):n(`uiLibrary.motionZones.save`,`Save`)})]})]}):(0,m.jsx)(`p`,{className:`${o} leading-relaxed`,children:n(`uiLibrary.motionZones.loading`,`Loading the camera's grid…`)})})}):null}export{D as MotionZonesSettings};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as e,i as t,l as n,n as r,o as i}from"./scheduler-0XZJE03d.js";import{C as a,_ as ee,c as o,d as te,g as ne,h as s,l as c,p as re,t as l,x as u,y as d}from"./index-DK4KYQh4.js";import{MaskShapeCanvas as ie}from"./MaskShapeCanvas-BTvl6Rin.js";var ae=a(`hexagon`,[[`path`,{d:`M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z`,key:`yt0hxn`}]]),oe=a(`mic-off`,[[`path`,{d:`M12 19v3`,key:`npa21l`}],[`path`,{d:`M15 9.34V5a3 3 0 0 0-5.68-1.33`,key:`1gzdoj`}],[`path`,{d:`M16.95 16.95A7 7 0 0 1 5 12v-2`,key:`cqa7eg`}],[`path`,{d:`M18.89 13.23A7 7 0 0 0 19 12v-2`,key:`16hl24`}],[`path`,{d:`m2 2 20 20`,key:`1ooewy`}],[`path`,{d:`M9 9v3a3 3 0 0 0 5.12 2.12`,key:`r2i35w`}]]),f=n(i(),1),p=`Microphone`,m=`The camera encodes no audio at all — live view, recordings, exports and the audio analyzer are all silent.`;function se(e){let t=e.supportsAudioMute===!0,n=t?e.audioEnabled:null,r=e.pendingOn??null;return{label:p,supported:t,on:n===null?null:r??n,available:t&&n!==null,costWhenOff:m}}function ce(e){return!e.available||e.on===null?null:{enabled:!e.on}}var h=n(e(),1),le=120,ue=`privacy-mask`,g=`rounded-md border border-border bg-surface px-2 py-1 text-[11px] font-medium text-foreground-subtle hover:bg-surface-hover disabled:opacity-40 transition-colors`,_=`rounded-md border border-primary/50 bg-primary/15 px-2.5 py-1 text-[11px] font-medium text-primary hover:bg-primary/25 disabled:opacity-40 transition-colors`;function v(e){return e.kind===`rect`||e.kind===`polygon`?e:null}function de(e){let t=new Set(e.map(e=>e.id)),n=0;for(;t.has(n);)n+=1;return n}function fe(e,t){if(e.length!==t.length)return!1;for(let n=0;n<e.length;n+=1)if(JSON.stringify(e[n])!==JSON.stringify(t[n]))return!1;return!0}function y({deviceId:e}){let n=t(),i=te(s().trpcClient,e),[a,p]=(0,f.useState)(null),[m,y]=(0,f.useState)(!1),[b,x]=(0,f.useState)(!1),[S,C]=(0,f.useState)(null),[w,T]=(0,f.useState)(null),[E,D]=(0,f.useState)(!1),[O,k]=(0,f.useState)(!1),[A,j]=(0,f.useState)(null),[M,N]=(0,f.useState)(null),[pe,P]=(0,f.useState)(null),[F,I]=(0,f.useState)(null),[L,R]=(0,f.useState)(null),z=(0,f.useRef)(!1);(0,f.useEffect)(()=>{if(!i)return;let e=!1;return z.current=!1,p(null),y(!1),x(!1),C(null),T(null),k(!1),j(null),N(null),P(null),I(null),R(null),(async()=>{try{let t=await i.privacyMask?.getOptions({});if(e)return;if(!t)throw Error(`device proxy not ready`);if(p(t),z.current)return;let n=await i.privacyMask?.getStatus({});if(e)return;if(!n)throw Error(`device proxy not ready`);if(n.regions===null){x(!0),P(n.audioEnabled);return}z.current=!0;let r={enabled:n.enabled,regions:n.regions};T(r),C(r),P(n.audioEnabled)}catch(t){if(e)return;c(t)?y(!0):console.error(`Privacy Mask load failed`,t)}})(),()=>{e=!0}},[i]);let B=(0,f.useMemo)(()=>S!==null&&w!==null&&(S.enabled!==w.enabled||!fe(S.regions,w.regions)),[S,w]),V=S?S.regions.length:0,H=a?a.maxRegions:0,U=(0,f.useRef)(0);(0,f.useEffect)(()=>{U.current=H},[H]);let W=H>0&&V>=H,me=(0,f.useCallback)(()=>{C(e=>e&&{...e,enabled:!e.enabled})},[]),G=(0,f.useCallback)(e=>{j(typeof e==`number`?e:null)},[]),K=(0,f.useMemo)(()=>S?S.regions.map(e=>({id:e.id,shape:e.shape,enabled:e.enabled,label:n(`uiLibrary.privacyMaskSettings.zoneN`,`Zone {{id}}`,{id:e.id})})):[],[S,n]),q=(0,f.useCallback)((e,t)=>{let n=v(t);n&&C(t=>t&&{...t,regions:t.regions.map(t=>t.id===e?{...t,shape:n}:t)})},[]),J=(0,f.useCallback)(e=>{let t=v(e);t&&(N(null),C(e=>{if(!e)return e;let n=U.current;if(n>0&&e.regions.length>=n)return e;let r=de(e.regions),i={id:r,enabled:!0,shape:t};return j(r),{...e,regions:[...e.regions,i]}}))},[]),Y=(0,f.useCallback)(e=>{k(!0),j(null),N(e)},[]),he=(0,f.useCallback)(e=>{k(!0),N(null),j(e)},[]),ge=(0,f.useCallback)(e=>{j(t=>t===e?null:t),C(t=>t&&{...t,regions:t.regions.filter(t=>t.id!==e)})},[]),_e=(0,f.useCallback)(()=>{N(null),j(null),w&&C({enabled:w.enabled,regions:w.regions})},[w]),X=(0,f.useCallback)(async()=>{if(!(!i||!S)){D(!0);try{await i.privacyMask?.setMask({patch:{enabled:S.enabled,regions:[...S.regions]}});let e=await i.privacyMask?.getStatus({});if(e&&e.regions!==null){let t={enabled:e.enabled,regions:e.regions};T(t),C(t)}}catch(e){console.error(`Privacy Mask save failed`,e)}finally{D(!1)}}},[i,S]),Z=se({supportsAudioMute:a===null?null:a.supportsAudioMute,audioEnabled:pe,pendingOn:F}),ve=(0,f.useCallback)(async()=>{let e=ce(Z);if(!(!i||e===null)){I(e.enabled),R(null);try{await i.privacyMask?.setAudioEnabled(e);let t=await i.privacyMask?.getStatus({});t&&P(t.audioEnabled)}catch(e){console.error(`Privacy microphone write failed — reverting`,e),R(e instanceof Error?e.message:String(e))}finally{I(null)}}},[i,Z]),ye=(0,f.useCallback)(()=>{k(e=>(e&&(N(null),j(null)),!e))},[]),Q=a?.supportedShapes??[];l((0,f.useMemo)(()=>O&&!m&&a&&S?{id:ue,order:le,node:(0,h.jsx)(ie,{transparent:!0,items:K,supportedShapes:Q,polygonVertices:a.polygonVertices,selectedId:A,onSelect:G,onShapeChange:q,onDrawComplete:J,drawingKind:M})}:null,[O,m,a,S,K,Q,A,G,q,J,M]));let be=a?.supportedShapes.includes(`rect`)??!1,xe=a?.supportedShapes.includes(`polygon`)??!1,$=a!==null&&(a.maxRegions<=0||a.supportedShapes.length===0),Se=!m&&!$&&!b&&a!==null&&S!==null;return i?(0,h.jsx)(re,{title:n(`uiLibrary.privacyMaskSettings.title`,`Privacy Mask`),icon:(0,h.jsx)(u,{className:`h-3.5 w-3.5 text-foreground-subtle`}),children:(0,h.jsxs)(`div`,{className:`flex flex-col gap-3`,children:[m||$?(0,h.jsx)(`p`,{className:`${o} leading-relaxed`,children:n(`uiLibrary.privacyMaskSettings.unsupported`,`This camera doesn't support an on-board privacy mask.`)}):b?(0,h.jsx)(`p`,{className:`${o} leading-relaxed`,children:n(`uiLibrary.privacyMaskSettings.unreadable`,`This camera hasn't answered, so what it currently masks is unknown — the editor stays closed rather than showing an empty frame you could save over. A battery camera answers once it wakes; otherwise check that it is reachable.`)}):Se?(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(`p`,{className:`${o} leading-relaxed`,children:(0,h.jsx)(r,{uiKey:`uiLibrary.privacyMaskSettings.help`,fallback:`Toggle <0>Edit mask</0> to draw blanked-out zones on the live frame, then <1>Save</1> to push them to the camera. Drag a rectangle to move, its corner to resize; drag polygon vertices, click an edge midpoint to add one, or right-click a vertex to remove it.`,components:[(0,h.jsx)(`strong`,{className:`text-foreground`},`edit`),(0,h.jsx)(`strong`,{className:`text-foreground`},`save`)]})}),(0,h.jsxs)(`div`,{className:`flex items-center gap-2 flex-wrap`,children:[(0,h.jsx)(`button`,{type:`button`,onClick:ye,disabled:E,"aria-pressed":O,className:O?_:g,children:O?n(`uiLibrary.privacyMaskSettings.doneEditing`,`Done editing`):n(`uiLibrary.privacyMaskSettings.editMask`,`Edit mask`)}),(0,h.jsx)(`button`,{type:`button`,onClick:me,disabled:E,"aria-pressed":S.enabled,className:S.enabled?_:g,children:S.enabled?n(`uiLibrary.privacyMaskSettings.maskOn`,`Mask on`):n(`uiLibrary.privacyMaskSettings.maskOff`,`Mask off`)}),be&&(0,h.jsx)(`button`,{type:`button`,onClick:()=>Y(`rect`),disabled:E||W,"aria-pressed":M===`rect`,className:M===`rect`?_:g,title:W?n(`uiLibrary.privacyMaskSettings.maxZones`,`Maximum zones reached`):n(`uiLibrary.privacyMaskSettings.addRect`,`Add a rectangle zone`),children:n(`uiLibrary.privacyMaskSettings.rectButton`,`+ Rect`)}),xe&&(0,h.jsx)(`button`,{type:`button`,onClick:()=>Y(`polygon`),disabled:E||W,"aria-pressed":M===`polygon`,className:M===`polygon`?_:g,title:W?n(`uiLibrary.privacyMaskSettings.maxZones`,`Maximum zones reached`):n(`uiLibrary.privacyMaskSettings.addPolygon`,`Add a polygon zone`),children:n(`uiLibrary.privacyMaskSettings.polygonButton`,`+ Polygon`)}),(0,h.jsx)(`span`,{className:`${o} ml-1 tabular-nums`,children:n(`uiLibrary.privacyMaskSettings.zoneCount`,`{{active}} / {{max}} zones`,{active:V,max:H})}),(0,h.jsx)(`span`,{className:`flex-1`}),(0,h.jsx)(`button`,{type:`button`,onClick:_e,disabled:E||!B,className:`rounded-md border border-border bg-surface px-2 py-1 text-[11px] text-foreground-subtle hover:bg-surface-hover disabled:opacity-40 transition-colors`,children:n(`uiLibrary.privacyMaskSettings.revert`,`Revert`)}),(0,h.jsx)(`button`,{type:`button`,onClick:()=>void X(),disabled:E||!B,className:_,children:E?n(`uiLibrary.privacyMaskSettings.saving`,`Saving…`):n(`uiLibrary.privacyMaskSettings.save`,`Save`)})]}),V>0?(0,h.jsx)(`div`,{className:`flex flex-col gap-1`,children:S.regions.map(e=>{let t=A===e.id,r=e.shape.kind===`polygon`?ae:ee;return(0,h.jsxs)(`div`,{className:`flex items-center gap-2 rounded-md border px-2 py-1 transition-colors ${t?`border-primary/50 bg-primary/10`:`border-border bg-surface`}`,children:[(0,h.jsxs)(`button`,{type:`button`,onClick:()=>he(e.id),disabled:E,className:`flex flex-1 items-center gap-2 text-left text-[11px] font-medium text-foreground-subtle hover:text-foreground disabled:opacity-40 transition-colors`,children:[(0,h.jsx)(r,{className:`h-3.5 w-3.5 shrink-0`}),(0,h.jsx)(`span`,{children:n(`uiLibrary.privacyMaskSettings.zoneN`,`Zone {{id}}`,{id:e.id})}),(0,h.jsx)(`span`,{className:`text-foreground-faint capitalize`,children:e.shape.kind})]}),(0,h.jsx)(`button`,{type:`button`,onClick:()=>ge(e.id),disabled:E,"aria-label":n(`uiLibrary.privacyMaskSettings.deleteZoneN`,`Delete zone {{id}}`,{id:e.id}),title:n(`uiLibrary.privacyMaskSettings.deleteZone`,`Delete zone`),className:`inline-flex h-6 w-6 items-center justify-center rounded border border-border bg-surface text-foreground-subtle hover:border-red-400/40 hover:bg-red-500/10 hover:text-red-400 disabled:opacity-40 transition-colors`,children:(0,h.jsx)(ne,{className:`h-3.5 w-3.5`})})]},e.id)})}):null]}):(0,h.jsx)(`p`,{className:`${o} leading-relaxed`,children:n(`uiLibrary.privacyMaskSettings.loading`,`Loading the camera's privacy mask…`)}),Z.supported&&(0,h.jsxs)(`div`,{className:`flex items-start gap-3 rounded-md border border-border bg-surface px-2 py-2`,children:[(0,h.jsx)(`button`,{type:`button`,role:`switch`,"aria-label":Z.label,"aria-checked":Z.on===!0,disabled:!Z.available||F!==null,onClick:()=>void ve(),title:Z.on===null?n(`uiLibrary.privacyMaskSettings.micTitleUnknown`,`Microphone — state unknown; the camera did not answer.`):Z.on?n(`uiLibrary.privacyMaskSettings.micTitleOn`,`The camera is capturing sound. Turning it off: {{cost}}`,{cost:Z.costWhenOff}):n(`uiLibrary.privacyMaskSettings.micTitleOff`,`The camera is silent. {{cost}}`,{cost:Z.costWhenOff}),className:Z.on===!1||Z.on===null?g:_,children:(0,h.jsxs)(`span`,{className:`inline-flex items-center gap-1.5`,children:[Z.on===!1?(0,h.jsx)(oe,{className:`h-3.5 w-3.5`}):(0,h.jsx)(d,{className:`h-3.5 w-3.5`}),Z.on===null?n(`uiLibrary.privacyMaskSettings.micUnknown`,`Microphone unknown`):Z.on?n(`uiLibrary.privacyMaskSettings.micOn`,`Microphone on`):n(`uiLibrary.privacyMaskSettings.micOff`,`Microphone off`)]})}),(0,h.jsx)(`p`,{className:`text-[10px] text-foreground-subtle flex-1 leading-relaxed`,children:L===null?Z.on===null?n(`uiLibrary.privacyMaskSettings.micNotReported`,`The camera did not report its microphone, so this state is unknown.`):Z.costWhenOff:n(`uiLibrary.privacyMaskSettings.writeFailed`,`Write failed: {{reason}}`,{reason:L})})]})]})}):null}export{y as PrivacyMaskSettings};
|
|
1
|
+
import{a as e,i as t,l as n,n as r,o as i}from"./scheduler-0XZJE03d.js";import{C as a,_ as ee,c as o,d as te,g as ne,h as s,l as c,p as re,t as l,x as u,y as d}from"./index-DD00yN8O.js";import{MaskShapeCanvas as ie}from"./MaskShapeCanvas-BTvl6Rin.js";var ae=a(`hexagon`,[[`path`,{d:`M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z`,key:`yt0hxn`}]]),oe=a(`mic-off`,[[`path`,{d:`M12 19v3`,key:`npa21l`}],[`path`,{d:`M15 9.34V5a3 3 0 0 0-5.68-1.33`,key:`1gzdoj`}],[`path`,{d:`M16.95 16.95A7 7 0 0 1 5 12v-2`,key:`cqa7eg`}],[`path`,{d:`M18.89 13.23A7 7 0 0 0 19 12v-2`,key:`16hl24`}],[`path`,{d:`m2 2 20 20`,key:`1ooewy`}],[`path`,{d:`M9 9v3a3 3 0 0 0 5.12 2.12`,key:`r2i35w`}]]),f=n(i(),1),p=`Microphone`,m=`The camera encodes no audio at all — live view, recordings, exports and the audio analyzer are all silent.`;function se(e){let t=e.supportsAudioMute===!0,n=t?e.audioEnabled:null,r=e.pendingOn??null;return{label:p,supported:t,on:n===null?null:r??n,available:t&&n!==null,costWhenOff:m}}function ce(e){return!e.available||e.on===null?null:{enabled:!e.on}}var h=n(e(),1),le=120,ue=`privacy-mask`,g=`rounded-md border border-border bg-surface px-2 py-1 text-[11px] font-medium text-foreground-subtle hover:bg-surface-hover disabled:opacity-40 transition-colors`,_=`rounded-md border border-primary/50 bg-primary/15 px-2.5 py-1 text-[11px] font-medium text-primary hover:bg-primary/25 disabled:opacity-40 transition-colors`;function v(e){return e.kind===`rect`||e.kind===`polygon`?e:null}function de(e){let t=new Set(e.map(e=>e.id)),n=0;for(;t.has(n);)n+=1;return n}function fe(e,t){if(e.length!==t.length)return!1;for(let n=0;n<e.length;n+=1)if(JSON.stringify(e[n])!==JSON.stringify(t[n]))return!1;return!0}function y({deviceId:e}){let n=t(),i=te(s().trpcClient,e),[a,p]=(0,f.useState)(null),[m,y]=(0,f.useState)(!1),[b,x]=(0,f.useState)(!1),[S,C]=(0,f.useState)(null),[w,T]=(0,f.useState)(null),[E,D]=(0,f.useState)(!1),[O,k]=(0,f.useState)(!1),[A,j]=(0,f.useState)(null),[M,N]=(0,f.useState)(null),[pe,P]=(0,f.useState)(null),[F,I]=(0,f.useState)(null),[L,R]=(0,f.useState)(null),z=(0,f.useRef)(!1);(0,f.useEffect)(()=>{if(!i)return;let e=!1;return z.current=!1,p(null),y(!1),x(!1),C(null),T(null),k(!1),j(null),N(null),P(null),I(null),R(null),(async()=>{try{let t=await i.privacyMask?.getOptions({});if(e)return;if(!t)throw Error(`device proxy not ready`);if(p(t),z.current)return;let n=await i.privacyMask?.getStatus({});if(e)return;if(!n)throw Error(`device proxy not ready`);if(n.regions===null){x(!0),P(n.audioEnabled);return}z.current=!0;let r={enabled:n.enabled,regions:n.regions};T(r),C(r),P(n.audioEnabled)}catch(t){if(e)return;c(t)?y(!0):console.error(`Privacy Mask load failed`,t)}})(),()=>{e=!0}},[i]);let B=(0,f.useMemo)(()=>S!==null&&w!==null&&(S.enabled!==w.enabled||!fe(S.regions,w.regions)),[S,w]),V=S?S.regions.length:0,H=a?a.maxRegions:0,U=(0,f.useRef)(0);(0,f.useEffect)(()=>{U.current=H},[H]);let W=H>0&&V>=H,me=(0,f.useCallback)(()=>{C(e=>e&&{...e,enabled:!e.enabled})},[]),G=(0,f.useCallback)(e=>{j(typeof e==`number`?e:null)},[]),K=(0,f.useMemo)(()=>S?S.regions.map(e=>({id:e.id,shape:e.shape,enabled:e.enabled,label:n(`uiLibrary.privacyMaskSettings.zoneN`,`Zone {{id}}`,{id:e.id})})):[],[S,n]),q=(0,f.useCallback)((e,t)=>{let n=v(t);n&&C(t=>t&&{...t,regions:t.regions.map(t=>t.id===e?{...t,shape:n}:t)})},[]),J=(0,f.useCallback)(e=>{let t=v(e);t&&(N(null),C(e=>{if(!e)return e;let n=U.current;if(n>0&&e.regions.length>=n)return e;let r=de(e.regions),i={id:r,enabled:!0,shape:t};return j(r),{...e,regions:[...e.regions,i]}}))},[]),Y=(0,f.useCallback)(e=>{k(!0),j(null),N(e)},[]),he=(0,f.useCallback)(e=>{k(!0),N(null),j(e)},[]),ge=(0,f.useCallback)(e=>{j(t=>t===e?null:t),C(t=>t&&{...t,regions:t.regions.filter(t=>t.id!==e)})},[]),_e=(0,f.useCallback)(()=>{N(null),j(null),w&&C({enabled:w.enabled,regions:w.regions})},[w]),X=(0,f.useCallback)(async()=>{if(!(!i||!S)){D(!0);try{await i.privacyMask?.setMask({patch:{enabled:S.enabled,regions:[...S.regions]}});let e=await i.privacyMask?.getStatus({});if(e&&e.regions!==null){let t={enabled:e.enabled,regions:e.regions};T(t),C(t)}}catch(e){console.error(`Privacy Mask save failed`,e)}finally{D(!1)}}},[i,S]),Z=se({supportsAudioMute:a===null?null:a.supportsAudioMute,audioEnabled:pe,pendingOn:F}),ve=(0,f.useCallback)(async()=>{let e=ce(Z);if(!(!i||e===null)){I(e.enabled),R(null);try{await i.privacyMask?.setAudioEnabled(e);let t=await i.privacyMask?.getStatus({});t&&P(t.audioEnabled)}catch(e){console.error(`Privacy microphone write failed — reverting`,e),R(e instanceof Error?e.message:String(e))}finally{I(null)}}},[i,Z]),ye=(0,f.useCallback)(()=>{k(e=>(e&&(N(null),j(null)),!e))},[]),Q=a?.supportedShapes??[];l((0,f.useMemo)(()=>O&&!m&&a&&S?{id:ue,order:le,node:(0,h.jsx)(ie,{transparent:!0,items:K,supportedShapes:Q,polygonVertices:a.polygonVertices,selectedId:A,onSelect:G,onShapeChange:q,onDrawComplete:J,drawingKind:M})}:null,[O,m,a,S,K,Q,A,G,q,J,M]));let be=a?.supportedShapes.includes(`rect`)??!1,xe=a?.supportedShapes.includes(`polygon`)??!1,$=a!==null&&(a.maxRegions<=0||a.supportedShapes.length===0),Se=!m&&!$&&!b&&a!==null&&S!==null;return i?(0,h.jsx)(re,{title:n(`uiLibrary.privacyMaskSettings.title`,`Privacy Mask`),icon:(0,h.jsx)(u,{className:`h-3.5 w-3.5 text-foreground-subtle`}),children:(0,h.jsxs)(`div`,{className:`flex flex-col gap-3`,children:[m||$?(0,h.jsx)(`p`,{className:`${o} leading-relaxed`,children:n(`uiLibrary.privacyMaskSettings.unsupported`,`This camera doesn't support an on-board privacy mask.`)}):b?(0,h.jsx)(`p`,{className:`${o} leading-relaxed`,children:n(`uiLibrary.privacyMaskSettings.unreadable`,`This camera hasn't answered, so what it currently masks is unknown — the editor stays closed rather than showing an empty frame you could save over. A battery camera answers once it wakes; otherwise check that it is reachable.`)}):Se?(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(`p`,{className:`${o} leading-relaxed`,children:(0,h.jsx)(r,{uiKey:`uiLibrary.privacyMaskSettings.help`,fallback:`Toggle <0>Edit mask</0> to draw blanked-out zones on the live frame, then <1>Save</1> to push them to the camera. Drag a rectangle to move, its corner to resize; drag polygon vertices, click an edge midpoint to add one, or right-click a vertex to remove it.`,components:[(0,h.jsx)(`strong`,{className:`text-foreground`},`edit`),(0,h.jsx)(`strong`,{className:`text-foreground`},`save`)]})}),(0,h.jsxs)(`div`,{className:`flex items-center gap-2 flex-wrap`,children:[(0,h.jsx)(`button`,{type:`button`,onClick:ye,disabled:E,"aria-pressed":O,className:O?_:g,children:O?n(`uiLibrary.privacyMaskSettings.doneEditing`,`Done editing`):n(`uiLibrary.privacyMaskSettings.editMask`,`Edit mask`)}),(0,h.jsx)(`button`,{type:`button`,onClick:me,disabled:E,"aria-pressed":S.enabled,className:S.enabled?_:g,children:S.enabled?n(`uiLibrary.privacyMaskSettings.maskOn`,`Mask on`):n(`uiLibrary.privacyMaskSettings.maskOff`,`Mask off`)}),be&&(0,h.jsx)(`button`,{type:`button`,onClick:()=>Y(`rect`),disabled:E||W,"aria-pressed":M===`rect`,className:M===`rect`?_:g,title:W?n(`uiLibrary.privacyMaskSettings.maxZones`,`Maximum zones reached`):n(`uiLibrary.privacyMaskSettings.addRect`,`Add a rectangle zone`),children:n(`uiLibrary.privacyMaskSettings.rectButton`,`+ Rect`)}),xe&&(0,h.jsx)(`button`,{type:`button`,onClick:()=>Y(`polygon`),disabled:E||W,"aria-pressed":M===`polygon`,className:M===`polygon`?_:g,title:W?n(`uiLibrary.privacyMaskSettings.maxZones`,`Maximum zones reached`):n(`uiLibrary.privacyMaskSettings.addPolygon`,`Add a polygon zone`),children:n(`uiLibrary.privacyMaskSettings.polygonButton`,`+ Polygon`)}),(0,h.jsx)(`span`,{className:`${o} ml-1 tabular-nums`,children:n(`uiLibrary.privacyMaskSettings.zoneCount`,`{{active}} / {{max}} zones`,{active:V,max:H})}),(0,h.jsx)(`span`,{className:`flex-1`}),(0,h.jsx)(`button`,{type:`button`,onClick:_e,disabled:E||!B,className:`rounded-md border border-border bg-surface px-2 py-1 text-[11px] text-foreground-subtle hover:bg-surface-hover disabled:opacity-40 transition-colors`,children:n(`uiLibrary.privacyMaskSettings.revert`,`Revert`)}),(0,h.jsx)(`button`,{type:`button`,onClick:()=>void X(),disabled:E||!B,className:_,children:E?n(`uiLibrary.privacyMaskSettings.saving`,`Saving…`):n(`uiLibrary.privacyMaskSettings.save`,`Save`)})]}),V>0?(0,h.jsx)(`div`,{className:`flex flex-col gap-1`,children:S.regions.map(e=>{let t=A===e.id,r=e.shape.kind===`polygon`?ae:ee;return(0,h.jsxs)(`div`,{className:`flex items-center gap-2 rounded-md border px-2 py-1 transition-colors ${t?`border-primary/50 bg-primary/10`:`border-border bg-surface`}`,children:[(0,h.jsxs)(`button`,{type:`button`,onClick:()=>he(e.id),disabled:E,className:`flex flex-1 items-center gap-2 text-left text-[11px] font-medium text-foreground-subtle hover:text-foreground disabled:opacity-40 transition-colors`,children:[(0,h.jsx)(r,{className:`h-3.5 w-3.5 shrink-0`}),(0,h.jsx)(`span`,{children:n(`uiLibrary.privacyMaskSettings.zoneN`,`Zone {{id}}`,{id:e.id})}),(0,h.jsx)(`span`,{className:`text-foreground-faint capitalize`,children:e.shape.kind})]}),(0,h.jsx)(`button`,{type:`button`,onClick:()=>ge(e.id),disabled:E,"aria-label":n(`uiLibrary.privacyMaskSettings.deleteZoneN`,`Delete zone {{id}}`,{id:e.id}),title:n(`uiLibrary.privacyMaskSettings.deleteZone`,`Delete zone`),className:`inline-flex h-6 w-6 items-center justify-center rounded border border-border bg-surface text-foreground-subtle hover:border-red-400/40 hover:bg-red-500/10 hover:text-red-400 disabled:opacity-40 transition-colors`,children:(0,h.jsx)(ne,{className:`h-3.5 w-3.5`})})]},e.id)})}):null]}):(0,h.jsx)(`p`,{className:`${o} leading-relaxed`,children:n(`uiLibrary.privacyMaskSettings.loading`,`Loading the camera's privacy mask…`)}),Z.supported&&(0,h.jsxs)(`div`,{className:`flex items-start gap-3 rounded-md border border-border bg-surface px-2 py-2`,children:[(0,h.jsx)(`button`,{type:`button`,role:`switch`,"aria-label":Z.label,"aria-checked":Z.on===!0,disabled:!Z.available||F!==null,onClick:()=>void ve(),title:Z.on===null?n(`uiLibrary.privacyMaskSettings.micTitleUnknown`,`Microphone — state unknown; the camera did not answer.`):Z.on?n(`uiLibrary.privacyMaskSettings.micTitleOn`,`The camera is capturing sound. Turning it off: {{cost}}`,{cost:Z.costWhenOff}):n(`uiLibrary.privacyMaskSettings.micTitleOff`,`The camera is silent. {{cost}}`,{cost:Z.costWhenOff}),className:Z.on===!1||Z.on===null?g:_,children:(0,h.jsxs)(`span`,{className:`inline-flex items-center gap-1.5`,children:[Z.on===!1?(0,h.jsx)(oe,{className:`h-3.5 w-3.5`}):(0,h.jsx)(d,{className:`h-3.5 w-3.5`}),Z.on===null?n(`uiLibrary.privacyMaskSettings.micUnknown`,`Microphone unknown`):Z.on?n(`uiLibrary.privacyMaskSettings.micOn`,`Microphone on`):n(`uiLibrary.privacyMaskSettings.micOff`,`Microphone off`)]})}),(0,h.jsx)(`p`,{className:`text-[10px] text-foreground-subtle flex-1 leading-relaxed`,children:L===null?Z.on===null?n(`uiLibrary.privacyMaskSettings.micNotReported`,`The camera did not report its microphone, so this state is unknown.`):Z.costWhenOff:n(`uiLibrary.privacyMaskSettings.writeFailed`,`Write failed: {{reason}}`,{reason:L})})]})]})}):null}export{y as PrivacyMaskSettings};
|