@camstack/addon-agent-ui 1.2.308 → 1.2.310

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  import path from "node:path";
2
2
  import { fileURLToPath } from "node:url";
3
- //#region ../types/dist/event-category-CaURIwQA.mjs
3
+ //#region ../types/dist/event-category-BmPm98n0.mjs
4
4
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
5
5
  EventCategory["SystemBoot"] = "system.boot";
6
6
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -484,6 +484,10 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
484
484
  EventCategory["RunningStarted"] = "running.started";
485
485
  /** Mirrors `runningStateCapability.events.onFinished`. */
486
486
  EventCategory["RunningFinished"] = "running.finished";
487
+ /** Mirrors `deviceRunsCapability.events.onRunOpened` - a durable run record opened. */
488
+ EventCategory["DeviceRunOpened"] = "device-run.opened";
489
+ /** Mirrors `deviceRunsCapability.events.onRunClosed` - a durable run record closed. */
490
+ EventCategory["DeviceRunClosed"] = "device-run.closed";
487
491
  /**
488
492
  * Cap event fired by every device that registers the `event-emitter`
489
493
  * capability. Mirrors `eventEmitterCapability.events.onEvent`. Carries
@@ -5832,7 +5836,7 @@ var ZodIssueCode = {
5832
5836
  var ZodFirstPartyTypeKind;
5833
5837
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5834
5838
  //#endregion
5835
- //#region ../types/dist/sleep-CSYuxssh.mjs
5839
+ //#region ../types/dist/sleep-BKzhQTSm.mjs
5836
5840
  /**
5837
5841
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5838
5842
  * window to float samples (D455).
@@ -9270,6 +9274,7 @@ var CAP_NAMES = Object.freeze([
9270
9274
  "device-ops",
9271
9275
  "device-provider",
9272
9276
  "device-removal-hook",
9277
+ "device-runs",
9273
9278
  "device-state",
9274
9279
  "device-status",
9275
9280
  "dishwasher",
@@ -11214,7 +11219,7 @@ object({
11214
11219
  params: record(string(), union([string(), number()])).optional()
11215
11220
  });
11216
11221
  //#endregion
11217
- //#region ../types/dist/composition-BBzVf2xd.mjs
11222
+ //#region ../types/dist/composition-BiKWlUCc.mjs
11218
11223
  /**
11219
11224
  * The ffmpeg build every CamStack node downloads, per platform and arch.
11220
11225
  *
@@ -12147,7 +12152,15 @@ var HelperSpecSchema = discriminatedUnion("kind", [
12147
12152
  thresholdWatts: number().positive(),
12148
12153
  startDwellMs: number().int().nonnegative(),
12149
12154
  stopDwellMs: number().int().nonnegative(),
12150
- member: HelperMemberSchema
12155
+ member: HelperMemberSchema,
12156
+ /**
12157
+ * The plug that powers the appliance (`switch.on`). Optional: when set, the
12158
+ * composition carries a `power-source` feature, so the hub can cut and restore
12159
+ * that plug (power-source link of a NEW-target composition).
12160
+ */
12161
+ powerSwitch: HelperMemberSchema.optional(),
12162
+ /** How long a forced restart keeps the plug off; the cap's default when unset. */
12163
+ offSeconds: number().optional()
12151
12164
  }),
12152
12165
  object({
12153
12166
  kind: literal("statistic"),
@@ -13545,7 +13558,13 @@ var MigrationLedgerEntrySchema = object({
13545
13558
  /** Why it is `blocked` or `held` (`dependency-failed`, `snapshot-refused`, …). */
13546
13559
  reason: string().nullable(),
13547
13560
  nodeId: string().nullable(),
13548
- bootId: string().nullable()
13561
+ bootId: string().nullable(),
13562
+ /**
13563
+ * The catalogued meta of this id (description, body kind, store, `dependsOn`…),
13564
+ * joined by the engine from the catalogues it knows this boot. Absent when no
13565
+ * catalogue lists the id (a newer database).
13566
+ */
13567
+ meta: MigrationMetaSchema.optional()
13549
13568
  });
13550
13569
  /** A catalogued migration that is not applied, with where it stands. */
13551
13570
  var MigrationPendingEntrySchema = object({
@@ -19352,6 +19371,14 @@ var APPLIANCE_CAP_VOCABULARY = {
19352
19371
  }
19353
19372
  } }
19354
19373
  },
19374
+ "device-runs": {
19375
+ scope: "device",
19376
+ noun: t("Runs", "Esecuzioni"),
19377
+ events: {
19378
+ onRunOpened: { notOperatorFacing: "the durable record of a run that the running-state start flip already announces" },
19379
+ onRunClosed: { notOperatorFacing: "the durable record of a run that the running-state finish flip already announces" }
19380
+ }
19381
+ },
19355
19382
  update: {
19356
19383
  scope: "device",
19357
19384
  noun: t("Firmware update", "Aggiornamento firmware"),
@@ -45768,6 +45795,49 @@ function actuator(input) {
45768
45795
  };
45769
45796
  }
45770
45797
  new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
45798
+ var PowerSourceRefusalReasonSchema = _enum([
45799
+ "no-power-source",
45800
+ "switch-missing",
45801
+ "switch-offline",
45802
+ "switch-unknown",
45803
+ "restart-in-progress",
45804
+ "switch-call-failed"
45805
+ ]);
45806
+ var PowerSourceActionResultSchema = discriminatedUnion("accepted", [object({ accepted: literal(true) }), object({
45807
+ accepted: literal(false),
45808
+ reason: PowerSourceRefusalReasonSchema,
45809
+ /** One line for the operator, naming the switch. */
45810
+ message: string()
45811
+ })]);
45812
+ var PowerSourceInfoSchema = object({
45813
+ /** False when the device has no power source linked; the rest is then empty. */
45814
+ linked: boolean(),
45815
+ switchDeviceId: number().nullable(),
45816
+ switchName: string().nullable(),
45817
+ /** The switch's on/off state, or null when it is unknown. Never false for unknown (D393). */
45818
+ switchOn: boolean().nullable(),
45819
+ switchOnline: boolean().nullable(),
45820
+ restartInProgress: boolean(),
45821
+ offSeconds: number().int()
45822
+ });
45823
+ object({
45824
+ /** Null while the switch has not reported: unknown is never `false` (D393). */
45825
+ switchOn: boolean().nullable(),
45826
+ offSeconds: number().int(),
45827
+ lastFetchedAt: number()
45828
+ });
45829
+ DeviceType.Gateway, DeviceType.Hub, DeviceType.Camera, DeviceType.Sensor, DeviceType.MediaPlayer, DeviceType.Vacuum, DeviceType.Generic, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.PetFountain, DeviceType.Fan, DeviceType.Humidifier, DeviceType.Climate, DeviceType.WaterHeater;
45830
+ var deviceInput$1 = object({ deviceId: number().int().nonnegative() });
45831
+ systemMethod(deviceInput$1, PowerSourceInfoSchema, { auth: "admin" }), systemMethod(deviceInput$1, PowerSourceActionResultSchema, {
45832
+ kind: "mutation",
45833
+ auth: "admin"
45834
+ }), systemMethod(deviceInput$1, PowerSourceActionResultSchema, {
45835
+ kind: "mutation",
45836
+ auth: "admin"
45837
+ }), systemMethod(deviceInput$1, PowerSourceActionResultSchema, {
45838
+ kind: "mutation",
45839
+ auth: "admin"
45840
+ });
45771
45841
  DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
45772
45842
  DeviceType.Camera;
45773
45843
  `${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
@@ -47193,6 +47263,101 @@ method(object({ deviceId: number().int() }), array(SeriesInfoSchema).readonly())
47193
47263
  kind: "mutation",
47194
47264
  auth: "admin"
47195
47265
  });
47266
+ /**
47267
+ * device-runs - the durable record of ONE run of a device: a washing cycle, a
47268
+ * dishwasher cycle, later a mow or a clean (D992).
47269
+ *
47270
+ * A run is a DOCUMENT (opened at one instant, closed at another, carrying what
47271
+ * was measured over it), never a sample - device-history keeps the numbers over
47272
+ * time and its `device-runs` provider keeps these documents beside them, because
47273
+ * the energy of a run is a question about device-history's own series. The
47274
+ * record is written from the `running-state` flip on `DeviceStateChanged`; it
47275
+ * survives a restart (the open row is on disk) and a missed flip (boot compares
47276
+ * the open rows against the live snapshots).
47277
+ *
47278
+ * Every measurement is `number | null` and `null` means "could not be
47279
+ * measured", never `0` (D393). A run closed by the boot reconcile because the
47280
+ * device stopped while nobody was watching has `outcome: 'unknown'`.
47281
+ */
47282
+ var DeviceRunKindSchema = _enum([
47283
+ "appliance",
47284
+ "mower",
47285
+ "vacuum"
47286
+ ]);
47287
+ var DeviceRunStateSchema = _enum(["open", "closed"]);
47288
+ var DeviceRunOutcomeSchema = _enum([
47289
+ "completed",
47290
+ "aborted",
47291
+ "error",
47292
+ "unknown"
47293
+ ]);
47294
+ /** What opened or closed the run. `reconcile` is the boot comparison against live state. */
47295
+ var DeviceRunSourceSchema = _enum([
47296
+ "running-state",
47297
+ "activity",
47298
+ "reconcile"
47299
+ ]);
47300
+ /** How the energy of a run was obtained; `null` when it could not be. */
47301
+ var DeviceRunEnergyMethodSchema = _enum(["counter-delta", "history-integral"]);
47302
+ var DeviceRunPhaseSchema = object({
47303
+ phase: string(),
47304
+ at: number()
47305
+ });
47306
+ /** The kind-specific block; a later phase adds a branch, nothing else changes. */
47307
+ var DeviceRunDetailSchema = discriminatedUnion("kind", [object({
47308
+ kind: literal("appliance"),
47309
+ /** kWh used over the run. */
47310
+ energyKwh: number().nullable().meta(readingMeta("energy")),
47311
+ energyMethod: DeviceRunEnergyMethodSchema.nullable(),
47312
+ /** Highest power seen while the run was open. */
47313
+ peakW: number().nullable().meta(readingMeta("power")),
47314
+ /** Time-weighted mean power while the run was open. */
47315
+ avgW: number().nullable().meta(readingMeta("power")),
47316
+ /** The program the appliance said it ran when the run opened. */
47317
+ program: string().nullable(),
47318
+ remainingAtStartSec: number().nullable().meta(readingMeta("duration")),
47319
+ /** The last phase the device reported before the run closed. */
47320
+ finalPhase: string().nullable(),
47321
+ /**
47322
+ * The meter's energy counter when the run opened; `null` when the meter had
47323
+ * not said (or the run was opened late, by the boot reconcile). It lives in
47324
+ * the row so a run that outlives a restart still ends with `end - start`.
47325
+ */
47326
+ energyStartKwh: number().nullable().meta(readingMeta("energy")),
47327
+ /** Milliseconds of power readings behind `avgW` - the weight a restart resumes the mean with. */
47328
+ powerObservedMs: number()
47329
+ })]);
47330
+ var DeviceRunSchema = object({
47331
+ /** `${deviceId}:${startedAt}`. */
47332
+ runId: string(),
47333
+ deviceId: number().int(),
47334
+ kind: DeviceRunKindSchema,
47335
+ state: DeviceRunStateSchema,
47336
+ startedAt: number(),
47337
+ endedAt: number().nullable(),
47338
+ durationMs: number().nullable(),
47339
+ outcome: DeviceRunOutcomeSchema.nullable(),
47340
+ startSource: DeviceRunSourceSchema,
47341
+ endSource: DeviceRunSourceSchema.nullable(),
47342
+ /** Where the device's running bit came from (`running-state.source`); `null` when it did not say. */
47343
+ runningSource: _enum(["native", "assigned"]).nullable(),
47344
+ phases: array(DeviceRunPhaseSchema),
47345
+ detail: DeviceRunDetailSchema
47346
+ });
47347
+ DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, method(object({
47348
+ deviceId: number().int(),
47349
+ outcome: DeviceRunOutcomeSchema.optional(),
47350
+ atFrom: number().optional(),
47351
+ atTo: number().optional(),
47352
+ limit: number().int().positive().max(200).default(50),
47353
+ cursor: string().optional()
47354
+ }), object({
47355
+ runs: array(DeviceRunSchema).readonly(),
47356
+ nextCursor: string().nullable()
47357
+ })), method(object({
47358
+ deviceId: number().int(),
47359
+ runId: string()
47360
+ }), DeviceRunSchema.nullable()), method(object({ deviceId: number().int() }), DeviceRunSchema.nullable());
47196
47361
  var DeviceCaStatusSchema = discriminatedUnion("state", [
47197
47362
  object({ state: literal("absent") }),
47198
47363
  object({
@@ -47328,8 +47493,8 @@ method(object({}), object({
47328
47493
  });
47329
47494
  var KeychainKeySourceSchema = object({
47330
47495
  kind: _enum([
47331
- "config-file",
47332
- "previous-config-file",
47496
+ "mounted-file",
47497
+ "previous-mounted-file",
47333
47498
  "platform",
47334
47499
  "default-file"
47335
47500
  ]),
@@ -51551,7 +51716,8 @@ var PALETTE_ENTRY_IDS = [
51551
51716
  "switch",
51552
51717
  "siren",
51553
51718
  "button",
51554
- "doorbell"
51719
+ "doorbell",
51720
+ "appliance-cycle"
51555
51721
  ];
51556
51722
  var AUDIO_ENTRY_ID = "audio";
51557
51723
  /** Six rungs, quiet → loud. The opaque end is the entry's hex. */
@@ -51622,7 +51788,8 @@ var CAMSTACK_HEX = {
51622
51788
  switch: "#7a812a",
51623
51789
  siren: "#ac5d7f",
51624
51790
  button: "#b276cd",
51625
- doorbell: "#0087ab"
51791
+ doorbell: "#0087ab",
51792
+ "appliance-cycle": "#2a8c8c"
51626
51793
  };
51627
51794
  var CAMSTACK_FALLBACK = [
51628
51795
  "#b34dc7",
@@ -51687,7 +51854,8 @@ var HIGH_CONTRAST_HEX = {
51687
51854
  switch: "#d05259",
51688
51855
  siren: "#cd67b3",
51689
51856
  button: "#c9746a",
51690
- doorbell: "#338eeb"
51857
+ doorbell: "#338eeb",
51858
+ "appliance-cycle": "#00848a"
51691
51859
  };
51692
51860
  var HIGH_CONTRAST_FALLBACK = [
51693
51861
  "#817f3b",
@@ -51752,7 +51920,8 @@ var OKABE_ITO_HEX = {
51752
51920
  switch: "#ad2c4e",
51753
51921
  siren: "#348e08",
51754
51922
  button: "#d27303",
51755
- doorbell: "#55770f"
51923
+ doorbell: "#55770f",
51924
+ "appliance-cycle": "#00737d"
51756
51925
  };
51757
51926
  var OKABE_ITO_FALLBACK = [
51758
51927
  "#9a3784",
@@ -51961,6 +52130,7 @@ sub("switch", "control", "control", "switch", "Switch");
51961
52130
  sub("siren", "control", "control", "siren", "Siren");
51962
52131
  sub("button", "control", "control", "button", "Button");
51963
52132
  sub("doorbell", "control", "control", "doorbell", "Doorbell");
52133
+ sub("appliance-cycle", "control", "control", "switch", "Appliance cycle");
51964
52134
  for (const l of AUDIO_MACRO_LABELS) {
51965
52135
  const kind = `audio-${l.id}`;
51966
52136
  if (entries.has(kind)) continue;
@@ -60504,7 +60674,8 @@ var CAP_TO_KIND = {
60504
60674
  cover: "cover",
60505
60675
  switch: "switch",
60506
60676
  button: "button",
60507
- doorbell: "doorbell"
60677
+ doorbell: "doorbell",
60678
+ "running-state": "appliance-cycle"
60508
60679
  };
60509
60680
  function buildDescriptor(capName, kind) {
60510
60681
  const t = EVENT_TAXONOMY[kind];
@@ -63601,10 +63772,7 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
63601
63772
  }), InstallPackageResultSchema, {
63602
63773
  kind: "mutation",
63603
63774
  auth: "admin"
63604
- }), method(object({ packageName: string() }), InstallPackageResultSchema, {
63605
- kind: "mutation",
63606
- auth: "admin"
63607
- }), method(_void(), boolean()), method(_void(), array(unknown()).readonly()), method(object({
63775
+ }), method(object({
63608
63776
  packageName: string().min(1),
63609
63777
  nodeId: string().optional(),
63610
63778
  everywhere: boolean().optional()
@@ -64453,19 +64621,19 @@ var RemoteSetConfigResultSchema = discriminatedUnion("status", [object({ status:
64453
64621
  reason: _enum(["unknown-template", "not-a-media-player"]),
64454
64622
  detail: string()
64455
64623
  })]);
64456
- var deviceInput$1 = object({ deviceId: number().int().nonnegative() });
64624
+ var deviceInput = object({ deviceId: number().int().nonnegative() });
64457
64625
  DeviceType.MediaPlayer;
64458
- method(deviceInput$1, RemoteConfigSchema, { auth: "admin" }), method(deviceInput$1.extend({ config: RemoteConfigSchema }), RemoteSetConfigResultSchema, {
64626
+ method(deviceInput, RemoteConfigSchema, { auth: "admin" }), method(deviceInput.extend({ config: RemoteConfigSchema }), RemoteSetConfigResultSchema, {
64459
64627
  kind: "mutation",
64460
64628
  auth: "admin"
64461
- }), method(deviceInput$1, RemoteCommandListSchema, { auth: "protected" }), method(deviceInput$1.extend({
64629
+ }), method(deviceInput, RemoteCommandListSchema, { auth: "protected" }), method(deviceInput.extend({
64462
64630
  role: RemoteRoleSchema,
64463
64631
  /** Sends in a row (volume steps). */
64464
64632
  repeat: number().int().min(1).max(50).default(1)
64465
64633
  }), RemoteSendResultSchema, {
64466
64634
  kind: "mutation",
64467
64635
  auth: "protected"
64468
- }), method(deviceInput$1.extend({
64636
+ }), method(deviceInput.extend({
64469
64637
  command: RemoteMediaCommandSchema,
64470
64638
  muted: boolean().optional(),
64471
64639
  source: string().optional(),
@@ -67377,49 +67545,6 @@ DeviceType.Lock, method(object({
67377
67545
  kind: "mutation",
67378
67546
  auth: "protected"
67379
67547
  });
67380
- var PowerSourceRefusalReasonSchema = _enum([
67381
- "no-power-source",
67382
- "switch-missing",
67383
- "switch-offline",
67384
- "switch-unknown",
67385
- "restart-in-progress",
67386
- "switch-call-failed"
67387
- ]);
67388
- var PowerSourceActionResultSchema = discriminatedUnion("accepted", [object({ accepted: literal(true) }), object({
67389
- accepted: literal(false),
67390
- reason: PowerSourceRefusalReasonSchema,
67391
- /** One line for the operator, naming the switch. */
67392
- message: string()
67393
- })]);
67394
- var PowerSourceInfoSchema = object({
67395
- /** False when the device has no power source linked; the rest is then empty. */
67396
- linked: boolean(),
67397
- switchDeviceId: number().nullable(),
67398
- switchName: string().nullable(),
67399
- /** The switch's on/off state, or null when it is unknown. Never false for unknown (D393). */
67400
- switchOn: boolean().nullable(),
67401
- switchOnline: boolean().nullable(),
67402
- restartInProgress: boolean(),
67403
- offSeconds: number().int()
67404
- });
67405
- object({
67406
- /** Null while the switch has not reported: unknown is never `false` (D393). */
67407
- switchOn: boolean().nullable(),
67408
- offSeconds: number().int(),
67409
- lastFetchedAt: number()
67410
- });
67411
- DeviceType.Gateway, DeviceType.Hub, DeviceType.Camera, DeviceType.Sensor, DeviceType.MediaPlayer, DeviceType.Vacuum, DeviceType.Generic, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.PetFountain, DeviceType.Fan, DeviceType.Humidifier, DeviceType.Climate, DeviceType.WaterHeater;
67412
- var deviceInput = object({ deviceId: number().int().nonnegative() });
67413
- systemMethod(deviceInput, PowerSourceInfoSchema, { auth: "admin" }), systemMethod(deviceInput, PowerSourceActionResultSchema, {
67414
- kind: "mutation",
67415
- auth: "admin"
67416
- }), systemMethod(deviceInput, PowerSourceActionResultSchema, {
67417
- kind: "mutation",
67418
- auth: "admin"
67419
- }), systemMethod(deviceInput, PowerSourceActionResultSchema, {
67420
- kind: "mutation",
67421
- auth: "admin"
67422
- });
67423
67548
  object({
67424
67549
  value: number().nullable().meta(readingMeta("device", { label: "Total" })),
67425
67550
  lastFetchedAt: number()
@@ -72657,7 +72782,7 @@ var ExternalIdentityKeySchema = object({
72657
72782
  provider: string().min(1),
72658
72783
  subject: string().min(1)
72659
72784
  });
72660
- method(_void(), array(UserSummarySchema), { auth: "admin" }), method(CreateUserInputSchema, UserSummarySchema, {
72785
+ method(_void(), array(UserSummarySchema), { auth: "admin" }), method(_void(), object({ defaultPasswordInUse: boolean() }), { auth: "admin" }), method(CreateUserInputSchema, UserSummarySchema, {
72661
72786
  kind: "mutation",
72662
72787
  auth: "admin",
72663
72788
  access: "create"
@@ -74056,13 +74181,6 @@ Object.freeze({
74056
74181
  access: "view",
74057
74182
  role: "admin"
74058
74183
  },
74059
- "addons.installFromWorkspace": {
74060
- capName: "addons",
74061
- capScope: "system",
74062
- addonId: null,
74063
- access: "create",
74064
- role: "admin"
74065
- },
74066
74184
  "addons.installPackage": {
74067
74185
  capName: "addons",
74068
74186
  capScope: "system",
@@ -74070,13 +74188,6 @@ Object.freeze({
74070
74188
  access: "create",
74071
74189
  role: "admin"
74072
74190
  },
74073
- "addons.isWorkspaceAvailable": {
74074
- capName: "addons",
74075
- capScope: "system",
74076
- addonId: null,
74077
- access: "view",
74078
- role: "admin"
74079
- },
74080
74191
  "addons.list": {
74081
74192
  capName: "addons",
74082
74193
  capScope: "system",
@@ -74126,13 +74237,6 @@ Object.freeze({
74126
74237
  access: "view",
74127
74238
  role: "admin"
74128
74239
  },
74129
- "addons.listWorkspacePackages": {
74130
- capName: "addons",
74131
- capScope: "system",
74132
- addonId: null,
74133
- access: "view",
74134
- role: "admin"
74135
- },
74136
74240
  "addons.onAddonLogs": {
74137
74241
  capName: "addons",
74138
74242
  capScope: "system",
@@ -76800,6 +76904,27 @@ Object.freeze({
76800
76904
  access: "create",
76801
76905
  role: "admin"
76802
76906
  },
76907
+ "deviceRuns.getCurrentRun": {
76908
+ capName: "device-runs",
76909
+ capScope: "device",
76910
+ addonId: null,
76911
+ access: "view",
76912
+ role: "viewer"
76913
+ },
76914
+ "deviceRuns.getRun": {
76915
+ capName: "device-runs",
76916
+ capScope: "device",
76917
+ addonId: null,
76918
+ access: "view",
76919
+ role: "viewer"
76920
+ },
76921
+ "deviceRuns.listRuns": {
76922
+ capName: "device-runs",
76923
+ capScope: "device",
76924
+ addonId: null,
76925
+ access: "view",
76926
+ role: "viewer"
76927
+ },
76803
76928
  "deviceState.claimFields": {
76804
76929
  capName: "device-state",
76805
76930
  capScope: "system",
@@ -83513,6 +83638,13 @@ Object.freeze({
83513
83638
  access: "view",
83514
83639
  role: "admin"
83515
83640
  },
83641
+ "userManagement.getAdminBootstrapStatus": {
83642
+ capName: "user-management",
83643
+ capScope: "system",
83644
+ addonId: null,
83645
+ access: "view",
83646
+ role: "admin"
83647
+ },
83516
83648
  "userManagement.getTotpStatus": {
83517
83649
  capName: "user-management",
83518
83650
  capScope: "system",
@@ -84998,6 +85130,21 @@ Object.freeze({
84998
85130
  form: "single",
84999
85131
  optional: false
85000
85132
  }],
85133
+ "deviceRuns.getCurrentRun": [{
85134
+ name: "deviceId",
85135
+ form: "single",
85136
+ optional: false
85137
+ }],
85138
+ "deviceRuns.getRun": [{
85139
+ name: "deviceId",
85140
+ form: "single",
85141
+ optional: false
85142
+ }],
85143
+ "deviceRuns.listRuns": [{
85144
+ name: "deviceId",
85145
+ form: "single",
85146
+ optional: false
85147
+ }],
85001
85148
  "deviceState.claimFields": [{
85002
85149
  name: "deviceId",
85003
85150
  form: "single",
@@ -87480,13 +87627,114 @@ NC_AUDIO_DEFAULTS.hitPercent, NC_AUDIO_DEFAULTS.samplingSeconds;
87480
87627
  *
87481
87628
  * Pure, RN-safe: the viewer imports the support rule from here.
87482
87629
  */
87630
+ /**
87631
+ * Control caps that still have a raise and a clear an operator names: an
87632
+ * appliance cycle raises when it STARTS and clears when it FINISHES. Kept out
87633
+ * of `SOURCE_CAP_ACTIVE_FIELD` on purpose — that table also makes a device a
87634
+ * camera-sensor / recorder-trigger source, and a dishwasher is neither.
87635
+ */
87636
+ var CYCLE_RAISED_FIELD_BY_CAP = { "running-state": "running" };
87483
87637
  /** Event kind → the boolean field of its cap slice that means "raised". */
87484
87638
  var NC_SENSOR_RAISED_FIELD_BY_KIND = Object.freeze(Object.fromEntries(Object.entries(EVENT_KIND_BY_CAP).flatMap(([capName, descriptor]) => {
87639
+ const cycleField = CYCLE_RAISED_FIELD_BY_CAP[capName];
87640
+ if (cycleField !== void 0) return [[descriptor.kind, cycleField]];
87485
87641
  const field = SOURCE_CAP_ACTIVE_FIELD[capName];
87486
87642
  if (field === void 0 || descriptor.category !== "sensor") return [];
87487
87643
  return [[descriptor.kind, field]];
87488
87644
  })));
87489
87645
  Object.freeze(Object.keys(NC_SENSOR_RAISED_FIELD_BY_KIND));
87646
+ Object.freeze({
87647
+ contact: {
87648
+ starts: {
87649
+ en: "opened",
87650
+ it: "si apre"
87651
+ },
87652
+ finishes: {
87653
+ en: "closed",
87654
+ it: "si chiude"
87655
+ }
87656
+ },
87657
+ "motion-sensor": {
87658
+ starts: {
87659
+ en: "motion detected",
87660
+ it: "movimento rilevato"
87661
+ },
87662
+ finishes: {
87663
+ en: "motion stopped",
87664
+ it: "movimento terminato"
87665
+ }
87666
+ },
87667
+ smoke: {
87668
+ starts: {
87669
+ en: "smoke detected",
87670
+ it: "fumo rilevato"
87671
+ },
87672
+ finishes: {
87673
+ en: "smoke gone",
87674
+ it: "fumo scomparso"
87675
+ }
87676
+ },
87677
+ flood: {
87678
+ starts: {
87679
+ en: "water detected",
87680
+ it: "acqua rilevata"
87681
+ },
87682
+ finishes: {
87683
+ en: "dry again",
87684
+ it: "di nuovo asciutto"
87685
+ }
87686
+ },
87687
+ gas: {
87688
+ starts: {
87689
+ en: "gas detected",
87690
+ it: "gas rilevato"
87691
+ },
87692
+ finishes: {
87693
+ en: "gas gone",
87694
+ it: "gas scomparso"
87695
+ }
87696
+ },
87697
+ "carbon-monoxide": {
87698
+ starts: {
87699
+ en: "carbon monoxide detected",
87700
+ it: "monossido rilevato"
87701
+ },
87702
+ finishes: {
87703
+ en: "carbon monoxide gone",
87704
+ it: "monossido scomparso"
87705
+ }
87706
+ },
87707
+ vibration: {
87708
+ starts: {
87709
+ en: "vibration detected",
87710
+ it: "vibrazione rilevata"
87711
+ },
87712
+ finishes: {
87713
+ en: "vibration stopped",
87714
+ it: "vibrazione terminata"
87715
+ }
87716
+ },
87717
+ tamper: {
87718
+ starts: {
87719
+ en: "tampered with",
87720
+ it: "manomesso"
87721
+ },
87722
+ finishes: {
87723
+ en: "tamper cleared",
87724
+ it: "manomissione rientrata"
87725
+ }
87726
+ },
87727
+ "appliance-cycle": {
87728
+ starts: {
87729
+ en: "the cycle started",
87730
+ it: "il ciclo parte"
87731
+ },
87732
+ finishes: {
87733
+ en: "the cycle finished",
87734
+ it: "il ciclo è terminato"
87735
+ }
87736
+ }
87737
+ });
87490
87738
  object({
87491
87739
  phase: _enum(["raised", "resolved"]),
87492
87740
  episodeId: string().min(1),
@@ -87693,6 +87941,10 @@ var STATE_SUMMARY_VARS = [
87693
87941
  [...RULE_TEXT],
87694
87942
  [...RULE_TEXT],
87695
87943
  [...RULE_TEXT],
87944
+ [...RULE_TEXT],
87945
+ [...RULE_TEXT],
87946
+ [...RULE_TEXT],
87947
+ [...RULE_TEXT],
87696
87948
  [...RULE_BODY_ONLY],
87697
87949
  [...RULE_TEXT],
87698
87950
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
@@ -87710,6 +87962,7 @@ var STATE_SUMMARY_VARS = [
87710
87962
  [...RULE_TEXT],
87711
87963
  [...RULE_TEXT],
87712
87964
  [...RULE_TEXT],
87965
+ [...RULE_TEXT],
87713
87966
  ([...RULE_TEXT], [...DEVICE_ATTENTION, ...ALERT_EPISODE]),
87714
87967
  [...RULE_TEXT],
87715
87968
  [...RULE_TEXT],
@@ -87954,6 +88207,7 @@ new Set([
87954
88207
  "siren",
87955
88208
  "button",
87956
88209
  "doorbell",
88210
+ "appliance-cycle",
87957
88211
  "audio-speech",
87958
88212
  "audio-scream",
87959
88213
  "audio-crying",
@@ -88430,7 +88684,7 @@ var AgentUIAddon = class extends BaseAddon {
88430
88684
  capability: adminUiCapability,
88431
88685
  provider: {
88432
88686
  getStaticDir: async () => ({ staticDir: path.resolve(__dirname) }),
88433
- getVersion: async () => ({ version: "1.2.308" })
88687
+ getVersion: async () => ({ version: "1.2.310" })
88434
88688
  }
88435
88689
  }];
88436
88690
  }
@@ -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,d as o,g as s,l as c,p as l,t as u,w as d}from"./index-DWH0ZLxX.js";import{MaskShapeCanvas as f}from"./MaskShapeCanvas-BTvl6Rin.js";var p=d(`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`}]]),m=n(i(),1),h=n(e(),1),g=110,_=`motion-zones`,v=0,y=[1,2,3],b=1,x=`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`,S=`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 C(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 w(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 T(e,t){return Math.ceil(e/t)}function E(e,t,n){return Math.min(n-1,Math.floor((e+.5)/t*n))}function D(e,t,n,r){let i=T(t,r),a=T(n,r),o=Array.from({length:i*a},()=>!1);for(let r=0;r<n;r+=1){let s=E(r,n,a);for(let n=0;n<t;n+=1)e[r*t+n]===!0&&(o[s*i+E(n,t,i)]=!0)}return o}function O(e,t,n,r){let i=T(t,r),a=T(n,r),o=Array.from({length:t*n},()=>!1);for(let r=0;r<n;r+=1){let s=E(r,n,a);for(let n=0;n<t;n+=1)o[r*t+n]=e[s*i+E(n,t,i)]===!0}return o}function k({deviceId:e}){let n=t(),i=o(s().trpcClient,e),[d,E]=(0,m.useState)(null),[k,A]=(0,m.useState)(!1),[j,M]=(0,m.useState)(null),[N,P]=(0,m.useState)(null),[F,I]=(0,m.useState)(b),[L,R]=(0,m.useState)(!1),[z,B]=(0,m.useState)(!1),V=(0,m.useRef)(!1);(0,m.useEffect)(()=>{if(!i)return;let e=!1;return V.current=!1,E(null),A(!1),M(null),P(null),I(b),B(!1),(async()=>{try{let t=await i.motionZones?.getOptions({});if(e)return;if(!t)throw Error(`device proxy not ready`);if(E(t),V.current)return;let n=await i.motionZones?.getStatus({});if(e)return;if(!n)throw Error(`device proxy not ready`);V.current=!0;let r=n.regions.find(e=>e.shape.kind===`grid`),a=C(r?r.shape.cells:[],t.grid.width,t.grid.height);P(a),M(D(a,t.grid.width,t.grid.height,b))}catch(t){if(e)return;c(t)?A(!0):console.error(`Motion Zones load failed`,t)}})(),()=>{e=!0}},[i]);let H=d?d.grid.width:0,U=d?d.grid.height:0,W=T(H,F),G=T(U,F),K=(0,m.useMemo)(()=>j&&d?O(j,H,U,F):null,[j,d,H,U,F]),q=(0,m.useMemo)(()=>K!==null&&N!==null&&!w(K,N),[K,N]),J=(0,m.useMemo)(()=>K?K.reduce((e,t)=>t?e+1:e,0):0,[K]),Y=H*U,X=W*G,Z=(0,m.useCallback)(e=>{X>0&&M(Array.from({length:X},()=>e))},[X]),ee=(0,m.useCallback)(()=>{M(e=>e&&e.map(e=>!e))},[]),te=(0,m.useCallback)(()=>{N&&d&&M(D(N,H,U,F))},[N,d,H,U,F]),ne=(0,m.useCallback)(e=>{e===F||!d||M(t=>{if(!t)return I(e),t;let n=D(O(t,H,U,F),H,U,e);return I(e),n})},[F,d,H,U]),Q=(0,m.useMemo)(()=>d&&j?[{id:v,shape:{kind:`grid`,gridWidth:W,gridHeight:G,cells:[...j]}}]:[],[d,j,W,G]),$=(0,m.useCallback)((e,t)=>{t.kind===`grid`&&M(t.cells)},[]),re=(0,m.useCallback)(async()=>{if(!(!i||!j||!d)){R(!0);try{let e=O(j,d.grid.width,d.grid.height,F),t={kind:`grid`,gridWidth:d.grid.width,gridHeight:d.grid.height,cells:e};await i.motionZones?.setZone({patch:{regions:[{id:v,enabled:!0,shape:t}]}});let n=await i.motionZones?.getStatus({});if(n){let e=n.regions.find(e=>e.shape.kind===`grid`),t=C(e?e.shape.cells:[],d.grid.width,d.grid.height);P(t),M(D(t,d.grid.width,d.grid.height,F))}}catch(e){console.error(`Motion Zones save failed`,e)}finally{R(!1)}}},[i,j,d,F]);u((0,m.useMemo)(()=>z&&!k&&d&&j?{id:_,order:g,node:(0,h.jsx)(f,{transparent:!0,items:Q,supportedShapes:[`grid`],grid:{width:W,height:G},selectedId:v,onSelect:()=>{},onShapeChange:$,onDrawComplete:()=>{},drawingKind:null})}:null,[z,k,d,j,Q,$,W,G]));let ie=!k&&d!==null&&j!==null;return i?(0,h.jsx)(l,{title:n(`uiLibrary.motionZones.title`,`Motion Zones`),icon:(0,h.jsx)(p,{className:`h-3.5 w-3.5 text-foreground-subtle`}),children:(0,h.jsx)(`div`,{className:`flex flex-col gap-3`,children:k?(0,h.jsx)(`p`,{className:`${a} leading-relaxed`,children:n(`uiLibrary.motionZones.unsupported`,`This camera doesn't expose an on-board motion zones grid.`)}):ie?(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(`p`,{className:`${a} leading-relaxed`,children:(0,h.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,h.jsx)(`strong`,{className:`text-foreground`},`e`),(0,h.jsx)(`strong`,{className:`text-foreground`},`s`),(0,h.jsx)(`strong`,{className:`text-foreground`},`c`)],values:{width:d.grid.width,height:d.grid.height}})}),(0,h.jsxs)(`div`,{className:`flex items-center gap-2 flex-wrap`,children:[(0,h.jsx)(`button`,{type:`button`,onClick:()=>B(e=>!e),disabled:L,"aria-pressed":z,className:z?S:x,children:z?n(`uiLibrary.motionZones.doneEditing`,`Done editing`):n(`uiLibrary.motionZones.editGrid`,`Edit grid`)}),(0,h.jsx)(`button`,{type:`button`,onClick:()=>Z(!0),disabled:L,className:x,children:n(`uiLibrary.motionZones.allOn`,`All on`)}),(0,h.jsx)(`button`,{type:`button`,onClick:()=>Z(!1),disabled:L,className:x,children:n(`uiLibrary.motionZones.allOff`,`All off`)}),(0,h.jsx)(`button`,{type:`button`,onClick:ee,disabled:L,className:x,children:n(`uiLibrary.motionZones.invert`,`Invert`)}),(0,h.jsxs)(`div`,{className:`flex items-center gap-1 ml-1`,role:`group`,"aria-label":n(`uiLibrary.motionZones.cellSize`,`Cell size`),children:[(0,h.jsx)(`span`,{className:`${a} mr-0.5`,children:n(`uiLibrary.motionZones.cellSize`,`Cell size`)}),y.map(e=>(0,h.jsxs)(`button`,{type:`button`,onClick:()=>ne(e),disabled:L,"aria-pressed":F===e,title:e===1?n(`uiLibrary.motionZones.cameraGrid`,`Camera grid {{width}}×{{height}} (finest)`,{width:H,height:U}):n(`uiLibrary.motionZones.paintingGrid`,`{{width}}×{{height}} painting grid · cells ×{{factor}} bigger`,{width:T(H,e),height:T(U,e),factor:e}),className:F===e?S:x,children:[`×`,e]},e))]}),(0,h.jsxs)(`span`,{className:`${a} ml-1 tabular-nums`,children:[n(`uiLibrary.motionZones.cells`,`{{active}} / {{total}} cells · {{width}}×{{height}}`,{active:J,total:Y,width:d.grid.width,height:d.grid.height}),F===1?``:n(`uiLibrary.motionZones.paintSuffix`,` · paint {{width}}×{{height}}`,{width:W,height:G})]}),(0,h.jsx)(`span`,{className:`flex-1`}),(0,h.jsx)(`button`,{type:`button`,onClick:te,disabled:L||!q,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,h.jsx)(`button`,{type:`button`,onClick:()=>void re(),disabled:L||!q,className:S,children:L?n(`uiLibrary.motionZones.saving`,`Saving…`):n(`uiLibrary.motionZones.save`,`Save`)})]})]}):(0,h.jsx)(`p`,{className:`${a} leading-relaxed`,children:n(`uiLibrary.motionZones.loading`,`Loading the camera's grid…`)})})}):null}export{k as MotionZonesSettings};
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,d as o,g as s,l as c,p as l,t as u,w as d}from"./index-g66ySSQI.js";import{MaskShapeCanvas as f}from"./MaskShapeCanvas-BTvl6Rin.js";var p=d(`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`}]]),m=n(i(),1),h=n(e(),1),g=110,_=`motion-zones`,v=0,y=[1,2,3],b=1,x=`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`,S=`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 C(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 w(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 T(e,t){return Math.ceil(e/t)}function E(e,t,n){return Math.min(n-1,Math.floor((e+.5)/t*n))}function D(e,t,n,r){let i=T(t,r),a=T(n,r),o=Array.from({length:i*a},()=>!1);for(let r=0;r<n;r+=1){let s=E(r,n,a);for(let n=0;n<t;n+=1)e[r*t+n]===!0&&(o[s*i+E(n,t,i)]=!0)}return o}function O(e,t,n,r){let i=T(t,r),a=T(n,r),o=Array.from({length:t*n},()=>!1);for(let r=0;r<n;r+=1){let s=E(r,n,a);for(let n=0;n<t;n+=1)o[r*t+n]=e[s*i+E(n,t,i)]===!0}return o}function k({deviceId:e}){let n=t(),i=o(s().trpcClient,e),[d,E]=(0,m.useState)(null),[k,A]=(0,m.useState)(!1),[j,M]=(0,m.useState)(null),[N,P]=(0,m.useState)(null),[F,I]=(0,m.useState)(b),[L,R]=(0,m.useState)(!1),[z,B]=(0,m.useState)(!1),V=(0,m.useRef)(!1);(0,m.useEffect)(()=>{if(!i)return;let e=!1;return V.current=!1,E(null),A(!1),M(null),P(null),I(b),B(!1),(async()=>{try{let t=await i.motionZones?.getOptions({});if(e)return;if(!t)throw Error(`device proxy not ready`);if(E(t),V.current)return;let n=await i.motionZones?.getStatus({});if(e)return;if(!n)throw Error(`device proxy not ready`);V.current=!0;let r=n.regions.find(e=>e.shape.kind===`grid`),a=C(r?r.shape.cells:[],t.grid.width,t.grid.height);P(a),M(D(a,t.grid.width,t.grid.height,b))}catch(t){if(e)return;c(t)?A(!0):console.error(`Motion Zones load failed`,t)}})(),()=>{e=!0}},[i]);let H=d?d.grid.width:0,U=d?d.grid.height:0,W=T(H,F),G=T(U,F),K=(0,m.useMemo)(()=>j&&d?O(j,H,U,F):null,[j,d,H,U,F]),q=(0,m.useMemo)(()=>K!==null&&N!==null&&!w(K,N),[K,N]),J=(0,m.useMemo)(()=>K?K.reduce((e,t)=>t?e+1:e,0):0,[K]),Y=H*U,X=W*G,Z=(0,m.useCallback)(e=>{X>0&&M(Array.from({length:X},()=>e))},[X]),ee=(0,m.useCallback)(()=>{M(e=>e&&e.map(e=>!e))},[]),te=(0,m.useCallback)(()=>{N&&d&&M(D(N,H,U,F))},[N,d,H,U,F]),ne=(0,m.useCallback)(e=>{e===F||!d||M(t=>{if(!t)return I(e),t;let n=D(O(t,H,U,F),H,U,e);return I(e),n})},[F,d,H,U]),Q=(0,m.useMemo)(()=>d&&j?[{id:v,shape:{kind:`grid`,gridWidth:W,gridHeight:G,cells:[...j]}}]:[],[d,j,W,G]),$=(0,m.useCallback)((e,t)=>{t.kind===`grid`&&M(t.cells)},[]),re=(0,m.useCallback)(async()=>{if(!(!i||!j||!d)){R(!0);try{let e=O(j,d.grid.width,d.grid.height,F),t={kind:`grid`,gridWidth:d.grid.width,gridHeight:d.grid.height,cells:e};await i.motionZones?.setZone({patch:{regions:[{id:v,enabled:!0,shape:t}]}});let n=await i.motionZones?.getStatus({});if(n){let e=n.regions.find(e=>e.shape.kind===`grid`),t=C(e?e.shape.cells:[],d.grid.width,d.grid.height);P(t),M(D(t,d.grid.width,d.grid.height,F))}}catch(e){console.error(`Motion Zones save failed`,e)}finally{R(!1)}}},[i,j,d,F]);u((0,m.useMemo)(()=>z&&!k&&d&&j?{id:_,order:g,node:(0,h.jsx)(f,{transparent:!0,items:Q,supportedShapes:[`grid`],grid:{width:W,height:G},selectedId:v,onSelect:()=>{},onShapeChange:$,onDrawComplete:()=>{},drawingKind:null})}:null,[z,k,d,j,Q,$,W,G]));let ie=!k&&d!==null&&j!==null;return i?(0,h.jsx)(l,{title:n(`uiLibrary.motionZones.title`,`Motion Zones`),icon:(0,h.jsx)(p,{className:`h-3.5 w-3.5 text-foreground-subtle`}),children:(0,h.jsx)(`div`,{className:`flex flex-col gap-3`,children:k?(0,h.jsx)(`p`,{className:`${a} leading-relaxed`,children:n(`uiLibrary.motionZones.unsupported`,`This camera doesn't expose an on-board motion zones grid.`)}):ie?(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(`p`,{className:`${a} leading-relaxed`,children:(0,h.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,h.jsx)(`strong`,{className:`text-foreground`},`e`),(0,h.jsx)(`strong`,{className:`text-foreground`},`s`),(0,h.jsx)(`strong`,{className:`text-foreground`},`c`)],values:{width:d.grid.width,height:d.grid.height}})}),(0,h.jsxs)(`div`,{className:`flex items-center gap-2 flex-wrap`,children:[(0,h.jsx)(`button`,{type:`button`,onClick:()=>B(e=>!e),disabled:L,"aria-pressed":z,className:z?S:x,children:z?n(`uiLibrary.motionZones.doneEditing`,`Done editing`):n(`uiLibrary.motionZones.editGrid`,`Edit grid`)}),(0,h.jsx)(`button`,{type:`button`,onClick:()=>Z(!0),disabled:L,className:x,children:n(`uiLibrary.motionZones.allOn`,`All on`)}),(0,h.jsx)(`button`,{type:`button`,onClick:()=>Z(!1),disabled:L,className:x,children:n(`uiLibrary.motionZones.allOff`,`All off`)}),(0,h.jsx)(`button`,{type:`button`,onClick:ee,disabled:L,className:x,children:n(`uiLibrary.motionZones.invert`,`Invert`)}),(0,h.jsxs)(`div`,{className:`flex items-center gap-1 ml-1`,role:`group`,"aria-label":n(`uiLibrary.motionZones.cellSize`,`Cell size`),children:[(0,h.jsx)(`span`,{className:`${a} mr-0.5`,children:n(`uiLibrary.motionZones.cellSize`,`Cell size`)}),y.map(e=>(0,h.jsxs)(`button`,{type:`button`,onClick:()=>ne(e),disabled:L,"aria-pressed":F===e,title:e===1?n(`uiLibrary.motionZones.cameraGrid`,`Camera grid {{width}}×{{height}} (finest)`,{width:H,height:U}):n(`uiLibrary.motionZones.paintingGrid`,`{{width}}×{{height}} painting grid · cells ×{{factor}} bigger`,{width:T(H,e),height:T(U,e),factor:e}),className:F===e?S:x,children:[`×`,e]},e))]}),(0,h.jsxs)(`span`,{className:`${a} ml-1 tabular-nums`,children:[n(`uiLibrary.motionZones.cells`,`{{active}} / {{total}} cells · {{width}}×{{height}}`,{active:J,total:Y,width:d.grid.width,height:d.grid.height}),F===1?``:n(`uiLibrary.motionZones.paintSuffix`,` · paint {{width}}×{{height}}`,{width:W,height:G})]}),(0,h.jsx)(`span`,{className:`flex-1`}),(0,h.jsx)(`button`,{type:`button`,onClick:te,disabled:L||!q,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,h.jsx)(`button`,{type:`button`,onClick:()=>void re(),disabled:L||!q,className:S,children:L?n(`uiLibrary.motionZones.saving`,`Saving…`):n(`uiLibrary.motionZones.save`,`Save`)})]})]}):(0,h.jsx)(`p`,{className:`${a} leading-relaxed`,children:n(`uiLibrary.motionZones.loading`,`Loading the camera's grid…`)})})}):null}export{k as MotionZonesSettings};