@camstack/addon-admin-ui 1.2.33 → 1.2.34

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.
Files changed (87) hide show
  1. package/dist/assets/{AddLocationWizard-BNLzjRkS.js → AddLocationWizard-DzP-CYOi.js} +1 -1
  2. package/dist/assets/{AddonCollectionPage-CvyviITl.js → AddonCollectionPage-B5t3SHZE.js} +1 -1
  3. package/dist/assets/{Addons-B0nG62pB.js → Addons-DCR8DMgD.js} +1 -1
  4. package/dist/assets/{AdminTabs-V94RuaJP.js → AdminTabs-DTECFIAe.js} +1 -1
  5. package/dist/assets/{AiProfiles-CNda-xrz.js → AiProfiles-D0jpUF4v.js} +1 -1
  6. package/dist/assets/{Automation-DYV0gbiV.js → Automation-BX0bNbpp.js} +1 -1
  7. package/dist/assets/{BrokerForm-DX_RUCNg.js → BrokerForm-CROZPAB-.js} +1 -1
  8. package/dist/assets/{Capabilities-Cud2I1p1.js → Capabilities-DIGQ9fiv.js} +1 -1
  9. package/dist/assets/{CapabilityBadges-CaKz6Row.js → CapabilityBadges-B4vHw0qw.js} +1 -1
  10. package/dist/assets/{Cluster-Cx5dtvDp.js → Cluster-BnTT5Wsb.js} +1 -1
  11. package/dist/assets/{ClusterRecordingTab-BShu9AFE.js → ClusterRecordingTab-BVkyOEdI.js} +1 -1
  12. package/dist/assets/{Dashboard-CN0qzHHd.js → Dashboard-BlkR2NIh.js} +1 -1
  13. package/dist/assets/{Data-Cddnp6Uz.js → Data-CECcPfPj.js} +1 -1
  14. package/dist/assets/{DetectionIntelligence-C4g5DaCG.js → DetectionIntelligence-CzMadCA-.js} +1 -1
  15. package/dist/assets/{DeviceAggregateSection-H5AVeNJ0.js → DeviceAggregateSection-CbCIksD2.js} +1 -1
  16. package/dist/assets/{DeviceDetail-CLQTZBsf.js → DeviceDetail-oWNRSfva.js} +1 -1
  17. package/dist/assets/{Devices-Bp2S4_jq.js → Devices-COMVrlGU.js} +1 -1
  18. package/dist/assets/{EmbedPlayerPage-DVIbQ9_P.js → EmbedPlayerPage-B4Y1MxZ9.js} +1 -1
  19. package/dist/assets/Events-BIZWrXMY.js +1 -0
  20. package/dist/assets/{FormBuilder-B3G6L5El.js → FormBuilder-Cogt0U0A.js} +1 -1
  21. package/dist/assets/{Identity-D5YIw7nG.js → Identity-i_LhUVHo.js} +1 -1
  22. package/dist/assets/{IntegrationDetail-Dj2OdD1K.js → IntegrationDetail-CPE4VRwU.js} +1 -1
  23. package/dist/assets/{Integrations-DZKddVhD.js → Integrations-DhMaG2V3.js} +1 -1
  24. package/dist/assets/{Integrations-fadRG4Km.js → Integrations-qNIS4emE.js} +1 -1
  25. package/dist/assets/{Logs-zJNzZ183.js → Logs-rH1aVfpt.js} +1 -1
  26. package/dist/assets/{MotionZonesSettings-4IW50CRy.js → MotionZonesSettings-DDSnsNc9.js} +1 -1
  27. package/dist/assets/{MyAccess-CBfHhwSU.js → MyAccess-J8p1dKF3.js} +1 -1
  28. package/dist/assets/{Network-Dx9MFUR0.js → Network-C6bXHvxd.js} +1 -1
  29. package/dist/assets/{NodeAddonsSettingsPanel-C2NjwPws.js → NodeAddonsSettingsPanel-6Dzcc5in.js} +1 -1
  30. package/dist/assets/{NodeInferenceDevices-uPCEdvuj.js → NodeInferenceDevices-DraQNeS_.js} +1 -1
  31. package/dist/assets/{Notifications-C3Ng_pEz.js → Notifications-BL4Cp1b2.js} +1 -1
  32. package/dist/assets/{Pipeline-Daj8GJqM.js → Pipeline-Bf8P_Drx.js} +1 -1
  33. package/dist/assets/{Plates-CdBLHSjv.js → Plates-BkYxLI16.js} +1 -1
  34. package/dist/assets/{PrivacyMaskSettings-DOgtt7Eb.js → PrivacyMaskSettings-ByZ6t3aH.js} +1 -1
  35. package/dist/assets/{ProviderIcon-DpSmN8_h.js → ProviderIcon-9BELU-vo.js} +1 -1
  36. package/dist/assets/{Recordings-5kVeLC44.js → Recordings-OoJn-xbL.js} +1 -1
  37. package/dist/assets/{ScanNetworkModal-CVNem53G.js → ScanNetworkModal-DGnLpsYA.js} +1 -1
  38. package/dist/assets/{Settings-Dot1aUpP.js → Settings-DhIPBQcW.js} +1 -1
  39. package/dist/assets/{Showroom-CE0pD_JA.js → Showroom-C7QnFCQp.js} +1 -1
  40. package/dist/assets/{Terminal-Jn61QHqq.js → Terminal-DVjWHgq3.js} +1 -1
  41. package/dist/assets/{_virtual_mf-localSharedImportMap___mfe_internal__admin_ui_host-DfmS2X5b.js → _virtual_mf-localSharedImportMap___mfe_internal__admin_ui_host-DkbcXBBJ.js} +1 -1
  42. package/dist/assets/{build-cluster-graph-oxCzI_GT.js → build-cluster-graph-BDFGSfk8.js} +1 -1
  43. package/dist/assets/circle-check-big-DX7P42Tw.js +1 -0
  44. package/dist/assets/clock-DMJpZrGI.js +1 -0
  45. package/dist/assets/{copy-BrMo-O0l.js → copy-oDpB_CYv.js} +1 -1
  46. package/dist/assets/{debounced-invalidate-DCfaNC1r.js → debounced-invalidate-CPxCM-Lt.js} +1 -1
  47. package/dist/assets/dist-CekX4Hra.js +7 -0
  48. package/dist/assets/{dist-w7XvHdqJ.js → dist-Dx0ACB1O.js} +1 -1
  49. package/dist/assets/{download-Bd71YsuA.js → download-c60BtWes.js} +1 -1
  50. package/dist/assets/{face-bbox-ByAacIlM.js → face-bbox-nkg8OmFa.js} +1 -1
  51. package/dist/assets/{hostInit-DhSUBWsx.js → hostInit-BpyXzSDR.js} +1 -1
  52. package/dist/assets/{index-BZA0u2Kc.js → index-2QX2zxyn.js} +3 -3
  53. package/dist/assets/{key-round-DZL9RdNY.js → key-round-BlSZq_ro.js} +1 -1
  54. package/dist/assets/{mf-entry-bootstrap-0-28bb7ad2.js → mf-entry-bootstrap-0-3845b4a0.js} +2 -2
  55. package/dist/assets/{pencil-TjwM9NpS.js → pencil-DUgcFYZU.js} +1 -1
  56. package/dist/assets/{player-overlays-CkAkhPbQ.js → player-overlays-CzjKRHin.js} +1 -1
  57. package/dist/assets/plus-C7qYd7DF.js +1 -0
  58. package/dist/assets/{radio-DOrncLmg.js → radio-eY0YHItP.js} +1 -1
  59. package/dist/assets/{refresh-cw-BYCB135v.js → refresh-cw-D_fKxMIe.js} +1 -1
  60. package/dist/assets/remoteEntry-CFMi51wk.js +1 -0
  61. package/dist/assets/{rotate-ccw-Db_qQ-Qx.js → rotate-ccw-DU4_rBQq.js} +1 -1
  62. package/dist/assets/rotate-cw-CktlNgLW.js +1 -0
  63. package/dist/assets/search-CY5Hv7Yv.js +1 -0
  64. package/dist/assets/{send-CosR7D5R.js → send-B9r8Lohp.js} +1 -1
  65. package/dist/assets/{server-CUNj6w6P.js → server-BhdxNAPC.js} +1 -1
  66. package/dist/assets/square-S_5NH0Gl.js +1 -0
  67. package/dist/assets/{square-check-big-yxLWkS9v.js → square-check-big-DMenPwwp.js} +1 -1
  68. package/dist/assets/{src-DOXkuCPk.js → src-BBe6PrXe.js} +10 -10
  69. package/dist/assets/src-DSZBcu6j.js +7 -0
  70. package/dist/assets/{upload-D0orNbud.js → upload-AwB-upJP.js} +1 -1
  71. package/dist/assets/{useEventInvalidation-DJ5h5Wvp.js → useEventInvalidation-qhbuBjhg.js} +1 -1
  72. package/dist/assets/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__admin_ui_host__remoteEntry-_hash_-Cg_QybrP.js → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__admin_ui_host__remoteEntry-_hash_-CPcVkZQ0.js} +2 -2
  73. package/dist/assets/{wifi-D0ItCC1K.js → wifi-DyeEKGI-.js} +1 -1
  74. package/dist/assets/{zap-CIK4k9g5.js → zap-C32Ix0E1.js} +1 -1
  75. package/dist/index.html +5 -5
  76. package/dist/server/addon.js +361 -12
  77. package/package.json +1 -1
  78. package/dist/assets/Events-C_TE39Tm.js +0 -1
  79. package/dist/assets/circle-check-big-bqZqQn_F.js +0 -1
  80. package/dist/assets/clock-BxBK96nq.js +0 -1
  81. package/dist/assets/dist-DPJBx5gf.js +0 -7
  82. package/dist/assets/plus-BgUAuoLj.js +0 -1
  83. package/dist/assets/remoteEntry-2xQrocPD.js +0 -1
  84. package/dist/assets/rotate-cw-vsmRF4Nv.js +0 -1
  85. package/dist/assets/search-BopXcdUz.js +0 -1
  86. package/dist/assets/square-C0Uc1Hub.js +0 -1
  87. package/dist/assets/src-Bh5CQXm7.js +0 -7
@@ -6462,7 +6462,20 @@ var BrokerStatsSchema = object({
6462
6462
  sampleRate: number(),
6463
6463
  channels: number(),
6464
6464
  supported: boolean()
6465
- }).nullable().optional()
6465
+ }).nullable().optional(),
6466
+ /**
6467
+ * BROKER-SIDE AUDIO MUTE (D83). `true` = this broker is deliberately
6468
+ * distributing none of the device's audio, on live or recording.
6469
+ *
6470
+ * Present so a silent camera can be told apart from a broken one on the
6471
+ * stream panel itself, without cross-referencing the switch group: a
6472
+ * broker holding an `audio` track descriptor while `audioMuted` is true is
6473
+ * working exactly as asked. `audioMutedDropped` counts the audio units
6474
+ * thrown away since the current dial — it is how you confirm from stats
6475
+ * alone that the mute is on the packet path and not merely persisted.
6476
+ */
6477
+ audioMuted: boolean().optional(),
6478
+ audioMutedDropped: number().optional()
6466
6479
  });
6467
6480
  /**
6468
6481
  * Exporter-facing "profile restream" entry. Returned by
@@ -7100,6 +7113,19 @@ object({
7100
7113
  * | `notifications` | `notificationRules.setDeviceMuted` | `NotificationCenter.evaluateAndEnqueue` returns before any rule is evaluated |
7101
7114
  * | `privacy-mask` | `privacyMask.setMask({ enabled })` → the CAMERA | the camera blanks the masked regions itself; every stream and recording carries the black boxes |
7102
7115
  * | `device-audio` | `privacyMask.setAudioEnabled` → the CAMERA | the camera stops encoding an audio track at all; every consumer sees silent video |
7116
+ * | `broker-audio` | `streamBroker.setDeviceAudioMute` → `DeviceOverride.audioMuted` | `StreamBroker.setAudioMuted` drops the audio plane at the source: no `type:'audio'` packet leaves `fanOutEncoded`, no RTP reaches the restreamer, and the restreamer serves the video-only SDP |
7117
+ *
7118
+ * ## `device-audio` and `broker-audio` are two functions, not two knobs
7119
+ *
7120
+ * They look adjacent and they are not the same control ([D83](../../../../docs/decisions/adr-0083.md)):
7121
+ * `device-audio` writes the CAMERA, so it is hardware privacy — the microphone
7122
+ * genuinely stops, it survives CamStack entirely, and it costs a multi-second
7123
+ * encoder restart on every flip. `broker-audio` writes THIS server, so it is
7124
+ * instant, vendor-independent and reversible without touching the camera, and
7125
+ * a camera that ignores or lacks the ISAPI/Reolink control is still silenced.
7126
+ * D62 forbids a second switch that *disagrees* with the first; these two
7127
+ * cannot disagree, because neither reads the other's store — the camera holds
7128
+ * one, the broker holds the other, and each reports its own fact.
7103
7129
  *
7104
7130
  * ## The two switches whose authority is not on this server
7105
7131
  *
@@ -7161,6 +7187,7 @@ var CameraSwitchIdSchema = _enum([
7161
7187
  "object-detection",
7162
7188
  "privacy-mask",
7163
7189
  "device-audio",
7190
+ "broker-audio",
7164
7191
  "audio-analysis",
7165
7192
  "recording",
7166
7193
  "notifications"
@@ -7186,7 +7213,8 @@ var CameraSwitchAuthoritySchema = discriminatedUnion("kind", [
7186
7213
  object({
7187
7214
  kind: literal("camera-mask"),
7188
7215
  capName: string()
7189
- })
7216
+ }),
7217
+ object({ kind: literal("broker-audio-mute") })
7190
7218
  ]);
7191
7219
  /**
7192
7220
  * Why a switch is not offered for this camera. Rendered instead of the
@@ -9383,7 +9411,25 @@ method(object({
9383
9411
  }), _void(), {
9384
9412
  kind: "mutation",
9385
9413
  auth: "admin"
9386
- }), method(object({ brokerId: string() }), boolean()), object({
9414
+ }), method(object({ brokerId: string() }), boolean()), method(object({ deviceId: number().int() }), object({
9415
+ muted: boolean(),
9416
+ /**
9417
+ * How many live non-derived brokers currently hold the mute. Purely
9418
+ * diagnostic: `muted` is the policy and is authoritative on its own
9419
+ * (it applies to brokers that do not exist yet), while this says
9420
+ * whether anything is presently being silenced.
9421
+ */
9422
+ appliedBrokers: number().int().nonnegative()
9423
+ })), method(object({
9424
+ deviceId: number().int(),
9425
+ muted: boolean()
9426
+ }), object({
9427
+ muted: boolean(),
9428
+ appliedBrokers: number().int().nonnegative()
9429
+ }), {
9430
+ kind: "mutation",
9431
+ auth: "admin"
9432
+ }), object({
9387
9433
  deviceId: number().int().nonnegative(),
9388
9434
  camStreamId: string(),
9389
9435
  profile: CamProfileSchema
@@ -14625,6 +14671,30 @@ var TrackSourceSchema = _enum([
14625
14671
  "audio"
14626
14672
  ]);
14627
14673
  /**
14674
+ * Where a track sits in the RETRAIN lifecycle (D81).
14675
+ *
14676
+ * - `none` — never marked, or un-marked. Evictable.
14677
+ * - `staging` — the operator wants this track as training material and has not
14678
+ * finished with it. **This is the only state retention holds**: the track and
14679
+ * everything it owns (object events, crops, keyframes, CLIP vector) survive
14680
+ * the device's age window.
14681
+ * - `trained` — the retrain page has taken what it needed. The frames it chose
14682
+ * were COPIED into the retrain dataset at selection time, so the dataset no
14683
+ * longer depends on the track's media and the track becomes EVICTABLE again.
14684
+ * Terminal for the plain `markForTrain` toggle: returning it to `staging` is
14685
+ * a deliberate action of the retrain page, not a side effect of a checkbox.
14686
+ *
14687
+ * There is no `null`. The state is stored `TEXT NOT NULL DEFAULT 'none'` because
14688
+ * the store's filter language has only positive equality and `whereIn` — no
14689
+ * negation, no IS NULL — so a NULL would be unselectable by ANY predicate and
14690
+ * would make the entire pre-column history immortal in one deploy.
14691
+ */
14692
+ var RetrainStatusSchema = _enum([
14693
+ "none",
14694
+ "staging",
14695
+ "trained"
14696
+ ]);
14697
+ /**
14628
14698
  * Per-track OPERATOR flags — set by hand from the admin UI or the viewer, never
14629
14699
  * by the pipeline. Spread into `TrackSchema` and `KeyEventSchema` from one place
14630
14700
  * so the two surfaces cannot drift.
@@ -14634,18 +14704,31 @@ var TrackSourceSchema = _enum([
14634
14704
  * columns existed read as absent, and a consumer that needs a boolean should say
14635
14705
  * `flag === true`, not `flag !== false`.
14636
14706
  *
14637
- * What the flags DO is deliberately UNDEFINED at the time of writing: they are
14638
- * operator curation, and the behaviour they drive will be specified separately.
14639
- * In particular a `markForTrain` track is NOT pinned against retention — see
14640
- * `docs/decisions/adr-0059.md` for why that is a store-level change, not a flag.
14707
+ * `markForTrain` is the WIRE FACE of {@link RetrainStatusSchema}, not a column:
14708
+ * it is exactly `retrainStatus === 'staging'`, in both directions. Writing
14709
+ * `true` moves `none → staging`, writing `false` moves `staging none`, and a
14710
+ * `trained` track reports `false` while refusing both writes. The boolean is
14711
+ * kept because three surfaces drive a toggle off it; anything that needs to tell
14712
+ * "never marked" from "already trained" must read `retrainStatus`.
14713
+ *
14714
+ * `debug` does NOT pin; it is attention, not durability.
14641
14715
  */
14642
14716
  var TrackFlagFields = {
14643
- /** Operator marked this track as training material. */
14717
+ /** Operator marked this track as training material — i.e. `retrainStatus` is
14718
+ * `'staging'`. */
14644
14719
  markForTrain: boolean().optional(),
14645
14720
  /** Operator marked this track for diagnostic attention. */
14646
14721
  debug: boolean().optional()
14647
14722
  };
14648
14723
  /**
14724
+ * The lifecycle field itself, on the READ surfaces only (`Track`, `KeyEvent`).
14725
+ * Deliberately NOT part of {@link TrackFlagFields}: that group also builds the
14726
+ * write patch, and the status is not something the toggle sets — it is what the
14727
+ * toggle's boolean is derived from. Absent on an in-RAM track never touched;
14728
+ * always present on a persisted row (the column default materialises `'none'`).
14729
+ */
14730
+ var TrackRetrainFields = { retrainStatus: RetrainStatusSchema.optional() };
14731
+ /**
14649
14732
  * The write half: a PARTIAL patch. An omitted key is left untouched, so setting
14650
14733
  * one flag can never clear the other — the toggles are independent and are
14651
14734
  * driven from three surfaces that do not know about each other.
@@ -14659,7 +14742,32 @@ var TrackFlagsPatchSchema = object(TrackFlagFields);
14659
14742
  var TrackFlagsSchema = object({
14660
14743
  trackId: string(),
14661
14744
  markForTrain: boolean(),
14662
- debug: boolean()
14745
+ debug: boolean(),
14746
+ /** The lifecycle state the boolean was derived from. Required here (unlike on
14747
+ * a track row) because this shape is only ever produced by the write body,
14748
+ * which always knows it — and a surface that has just written needs to render
14749
+ * `trained` without a re-fetch. */
14750
+ retrainStatus: RetrainStatusSchema
14751
+ });
14752
+ /** Per-camera slice of a training-export estimate. */
14753
+ var TrainingExportDeviceTotalsSchema = object({
14754
+ deviceId: number(),
14755
+ tracks: number().int(),
14756
+ files: number().int(),
14757
+ bytes: number().int()
14758
+ });
14759
+ /**
14760
+ * What a training export WOULD contain. Computed from media index rows only —
14761
+ * no blob is read to produce this.
14762
+ */
14763
+ var TrainingExportSummarySchema = object({
14764
+ generatedAt: number(),
14765
+ trackCount: number().int(),
14766
+ fileCount: number().int(),
14767
+ byteCount: number().int(),
14768
+ /** More marked tracks exist than a single pass carries. */
14769
+ truncated: boolean(),
14770
+ devices: array(TrainingExportDeviceTotalsSchema).readonly()
14663
14771
  });
14664
14772
  var TrackSchema = object({
14665
14773
  trackId: string(),
@@ -14704,7 +14812,8 @@ var TrackSchema = object({
14704
14812
  * Populated from the persisted envelope columns on historical reads;
14705
14813
  * absent on legacy rows, dims-less tracks and active (in-RAM) tracks. */
14706
14814
  envelope: TrackEnvelopeSchema.optional(),
14707
- ...TrackFlagFields
14815
+ ...TrackFlagFields,
14816
+ ...TrackRetrainFields
14708
14817
  });
14709
14818
  var BaseEventFields = {
14710
14819
  id: string(),
@@ -14918,7 +15027,8 @@ var KeyEventSchema = object({
14918
15027
  bestEventId: string(),
14919
15028
  /** Track lifetime in ms (lastSeen - firstSeen). */
14920
15029
  windowMs: number().optional(),
14921
- ...TrackFlagFields
15030
+ ...TrackFlagFields,
15031
+ ...TrackRetrainFields
14922
15032
  });
14923
15033
  object({
14924
15034
  trackId: string(),
@@ -15179,6 +15289,12 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
15179
15289
  }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
15180
15290
  kind: "query",
15181
15291
  auth: "admin"
15292
+ }), method(object({ deviceIds: array(number()).optional() }), TrainingExportSummarySchema, {
15293
+ kind: "query",
15294
+ auth: "admin"
15295
+ }), method(object({ deviceIds: array(number()).optional() }), object({ url: string() }), {
15296
+ kind: "query",
15297
+ auth: "admin"
15182
15298
  }), method(object({
15183
15299
  eventId: string(),
15184
15300
  kind: MediaFileKindEnum.optional()
@@ -20839,6 +20955,173 @@ DeviceType.Camera, method(object({
20839
20955
  status: OsdStatusSchema
20840
20956
  });
20841
20957
  /**
20958
+ * `osd-manager` — the ORCHESTRATOR over the device-scope `osd` cap.
20959
+ *
20960
+ * The `osd` cap is the firmware contract: it probes a camera's overlay
20961
+ * SLOTS and writes literal text into one. It has no idea WHERE that text
20962
+ * comes from, and it must not — a driver that grew a "show the temperature
20963
+ * here" feature would grow it once per vendor.
20964
+ *
20965
+ * This cap owns the other half: a per-(camera, slot) BINDING that says
20966
+ * which value feeds the slot, how it is formatted, and under which
20967
+ * conditions it is shown at all. One addon renders every binding on every
20968
+ * camera, so a new source costs zero driver code.
20969
+ *
20970
+ * Three deliberate choices, each with a rejected alternative:
20971
+ *
20972
+ * 1. A source is `(capName, valuePath)` over the kernel's device
20973
+ * runtime-state mirror — NOT a closed enum of source kinds. Every
20974
+ * cap-keyed slice a device publishes is bindable the day the cap
20975
+ * ships. The rejected alternative (one enum member per source, with
20976
+ * a resolver branch each) is what makes "add the humidity too" a
20977
+ * code change.
20978
+ * 2. The display gate reuses `NcConditionsSchema` verbatim — the
20979
+ * notification centre's condition vocabulary — rather than a parallel
20980
+ * model. An operator who has learned one condition editor has learned
20981
+ * both.
20982
+ * 3. Because the renderer's facts are device STATE and not a detection
20983
+ * record, only a SUBSET of that vocabulary can be answered here.
20984
+ * `setSlotBinding` REJECTS the rest at write time (see
20985
+ * `getConditionSupport`). It does not accept-then-fail-closed: a
20986
+ * condition that can never be true renders a permanently blank
20987
+ * overlay, and a blank overlay looks exactly like a broken camera.
20988
+ */
20989
+ /** Where a slot's value comes from. */
20990
+ var OsdSourceSchema = discriminatedUnion("kind", [
20991
+ object({
20992
+ kind: literal("static"),
20993
+ text: string().max(64)
20994
+ }),
20995
+ object({
20996
+ kind: literal("clock"),
20997
+ /** Token pattern: `YYYY MM DD HH mm ss`. Everything else is literal. */
20998
+ pattern: string().min(1).max(32).default("HH:mm"),
20999
+ /** IANA zone. Omitted = the server's zone. */
21000
+ timezone: string().min(1).max(64).optional()
21001
+ }),
21002
+ object({
21003
+ kind: literal("device-state"),
21004
+ deviceId: number().int().optional(),
21005
+ capName: string().min(1).max(64),
21006
+ /** Dot path inside the slice, e.g. `detected`, `value`, `mode`. */
21007
+ valuePath: string().min(1).max(64)
21008
+ })
21009
+ ]);
21010
+ var OsdSlotBindingSchema = object({
21011
+ /** Off = the manager stops driving this slot. It does NOT clear it. */
21012
+ enabled: boolean().default(true),
21013
+ source: OsdSourceSchema,
21014
+ /** `${value}` and `${unit}` are substituted; every occurrence. */
21015
+ template: string().max(96).default("${value}"),
21016
+ /** Truncate with an ellipsis past this length. Absent = no limit. */
21017
+ maxCharacters: number().int().min(4).max(64).optional(),
21018
+ /**
21019
+ * Decimal places for a numeric value. `0` yields an integer — the
21020
+ * documented workaround for firmwares that reject `.` in overlay text.
21021
+ */
21022
+ maxDecimals: number().int().min(0).max(4).default(1),
21023
+ /** Appended via `${unit}`. The state mirror does not carry units. */
21024
+ unitLabel: string().max(8).optional(),
21025
+ /** Raw value → display text, e.g. `{"true":"MOTION","false":""}`. */
21026
+ valueMap: record(string(), string()).optional(),
21027
+ /** Time windows in which the slot is shown. Absent = always. */
21028
+ schedule: NcScheduleSchema.optional(),
21029
+ /**
21030
+ * Display gate, in the notification centre's condition vocabulary.
21031
+ * Only the keys reported by `getConditionSupport` are accepted.
21032
+ */
21033
+ conditions: NcConditionsSchema.optional(),
21034
+ /** Rendered when the gate is closed or the value unreadable. Empty = hide. */
21035
+ fallbackText: string().max(64).default("")
21036
+ });
21037
+ /** One camera slot, as the operator sees it: firmware truth + our binding. */
21038
+ var OsdSlotViewSchema = object({
21039
+ slotId: string(),
21040
+ kind: OsdOverlayKindEnum,
21041
+ /** Firmware refuses text edits (a timestamp, the channel name). */
21042
+ readOnly: boolean(),
21043
+ cameraEnabled: boolean(),
21044
+ cameraText: string().optional(),
21045
+ binding: OsdSlotBindingSchema.nullable()
21046
+ });
21047
+ /**
21048
+ * What happened to one slot on one render pass. `unchanged` exists so the
21049
+ * operator can tell "we are driving this and the value is steady" from
21050
+ * "we never got there" — and so the loop can prove it is not rewriting
21051
+ * identical text to the camera every tick.
21052
+ */
21053
+ var OsdRenderOutcomeEnum = _enum([
21054
+ "written",
21055
+ "unchanged",
21056
+ "gated",
21057
+ "unreadable",
21058
+ "disabled",
21059
+ "unbound",
21060
+ "failed"
21061
+ ]);
21062
+ var OsdRenderResultSchema = object({
21063
+ slotId: string(),
21064
+ outcome: OsdRenderOutcomeEnum,
21065
+ /** The text the slot should carry. Empty = the slot is switched off. */
21066
+ text: string(),
21067
+ /** Why, whenever the outcome is not a plain write. Never silent. */
21068
+ reason: string().optional()
21069
+ });
21070
+ var OsdSourceValueTypeEnum = _enum([
21071
+ "number",
21072
+ "boolean",
21073
+ "string",
21074
+ "enum"
21075
+ ]);
21076
+ /**
21077
+ * One bindable value, derived from a cap's `runtimeState` schema — never
21078
+ * hand-listed. The editor renders from this, so a cap that ships a new
21079
+ * state field becomes bindable with no UI change.
21080
+ */
21081
+ var OsdSourceOptionSchema = object({
21082
+ deviceId: number().int(),
21083
+ deviceName: string(),
21084
+ capName: string(),
21085
+ valuePath: string(),
21086
+ label: string(),
21087
+ valueType: OsdSourceValueTypeEnum,
21088
+ /** Present for `enum`; the editor offers these as `valueMap` keys. */
21089
+ enumValues: array(string()).readonly().optional()
21090
+ });
21091
+ method(object({ deviceId: number().int() }), object({
21092
+ supported: boolean(),
21093
+ slots: array(OsdSlotViewSchema)
21094
+ }), { auth: "admin" }), method(object({ deviceId: number().int() }), object({ sources: array(OsdSourceOptionSchema) }), { auth: "admin" }), method(object({}), object({
21095
+ supported: array(string()),
21096
+ catalog: array(NcConditionDescriptorSchema)
21097
+ }), { auth: "admin" }), method(object({
21098
+ deviceId: number().int(),
21099
+ slotId: string().min(1),
21100
+ binding: OsdSlotBindingSchema
21101
+ }), object({
21102
+ slot: OsdSlotViewSchema,
21103
+ render: OsdRenderResultSchema
21104
+ }), {
21105
+ kind: "mutation",
21106
+ auth: "admin"
21107
+ }), method(object({
21108
+ deviceId: number().int(),
21109
+ slotId: string().min(1)
21110
+ }), object({ success: literal(true) }), {
21111
+ kind: "mutation",
21112
+ auth: "admin"
21113
+ }), method(object({
21114
+ deviceId: number().int(),
21115
+ slotId: string().min(1),
21116
+ binding: OsdSlotBindingSchema.optional()
21117
+ }), OsdRenderResultSchema, {
21118
+ kind: "mutation",
21119
+ auth: "admin"
21120
+ }), method(object({ deviceId: number().int() }), object({ results: array(OsdRenderResultSchema) }), {
21121
+ kind: "mutation",
21122
+ auth: "admin"
21123
+ });
21124
+ /**
20842
21125
  * Feeder connectivity / power status — mirrors the HA petkit device-status
20843
21126
  * enum: `normal` (online, mains), `offline` (not reaching PetKit cloud),
20844
21127
  * `on_batteries` (running on battery backup). `null` until first reported.
@@ -25794,6 +26077,48 @@ Object.freeze({
25794
26077
  addonId: null,
25795
26078
  access: "create"
25796
26079
  },
26080
+ "osdManager.clearSlotBinding": {
26081
+ capName: "osd-manager",
26082
+ capScope: "system",
26083
+ addonId: null,
26084
+ access: "delete"
26085
+ },
26086
+ "osdManager.getConditionSupport": {
26087
+ capName: "osd-manager",
26088
+ capScope: "system",
26089
+ addonId: null,
26090
+ access: "view"
26091
+ },
26092
+ "osdManager.getDeviceOsd": {
26093
+ capName: "osd-manager",
26094
+ capScope: "system",
26095
+ addonId: null,
26096
+ access: "view"
26097
+ },
26098
+ "osdManager.getSourceCatalog": {
26099
+ capName: "osd-manager",
26100
+ capScope: "system",
26101
+ addonId: null,
26102
+ access: "view"
26103
+ },
26104
+ "osdManager.previewSlot": {
26105
+ capName: "osd-manager",
26106
+ capScope: "system",
26107
+ addonId: null,
26108
+ access: "create"
26109
+ },
26110
+ "osdManager.renderDevice": {
26111
+ capName: "osd-manager",
26112
+ capScope: "system",
26113
+ addonId: null,
26114
+ access: "create"
26115
+ },
26116
+ "osdManager.setSlotBinding": {
26117
+ capName: "osd-manager",
26118
+ capScope: "system",
26119
+ addonId: null,
26120
+ access: "create"
26121
+ },
25797
26122
  "petFeeder.callPet": {
25798
26123
  capName: "pet-feeder",
25799
26124
  capScope: "device",
@@ -25956,6 +26281,18 @@ Object.freeze({
25956
26281
  addonId: null,
25957
26282
  access: "view"
25958
26283
  },
26284
+ "pipelineAnalytics.getTrainingExportSummary": {
26285
+ capName: "pipeline-analytics",
26286
+ capScope: "device",
26287
+ addonId: null,
26288
+ access: "view"
26289
+ },
26290
+ "pipelineAnalytics.getTrainingExportUrl": {
26291
+ capName: "pipeline-analytics",
26292
+ capScope: "device",
26293
+ addonId: null,
26294
+ access: "view"
26295
+ },
25959
26296
  "pipelineAnalytics.listEventKinds": {
25960
26297
  capName: "pipeline-analytics",
25961
26298
  capScope: "device",
@@ -27432,6 +27769,12 @@ Object.freeze({
27432
27769
  addonId: null,
27433
27770
  access: "view"
27434
27771
  },
27772
+ "streamBroker.getDeviceAudioMute": {
27773
+ capName: "stream-broker",
27774
+ capScope: "system",
27775
+ addonId: null,
27776
+ access: "view"
27777
+ },
27435
27778
  "streamBroker.getPreBufferInfo": {
27436
27779
  capName: "stream-broker",
27437
27780
  capScope: "system",
@@ -27552,6 +27895,12 @@ Object.freeze({
27552
27895
  addonId: null,
27553
27896
  access: "create"
27554
27897
  },
27898
+ "streamBroker.setDeviceAudioMute": {
27899
+ capName: "stream-broker",
27900
+ capScope: "system",
27901
+ addonId: null,
27902
+ access: "create"
27903
+ },
27555
27904
  "streamBroker.setPreBufferDuration": {
27556
27905
  capName: "stream-broker",
27557
27906
  capScope: "system",
@@ -28413,7 +28762,7 @@ var AdminUIAddon = class extends BaseAddon {
28413
28762
  capability: adminUiCapability,
28414
28763
  provider: {
28415
28764
  getStaticDir: async () => ({ staticDir: resolveAdminUiDistDir() }),
28416
- getVersion: async () => ({ version: "1.2.33" })
28765
+ getVersion: async () => ({ version: "1.2.34" })
28417
28766
  }
28418
28767
  }];
28419
28768
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-admin-ui",
3
- "version": "1.2.33",
3
+ "version": "1.2.34",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Admin UI — Vite frontend build and server-side addon",
@@ -1 +0,0 @@
1
- import{B as e,Co as t,Jr as n,Mn as r,No as i,Pr as a,So as o,Wa as s,Xr as c,Zr as l,ei as u,q as d,qr as f,ti as p,to as m,xt as h,z as g}from"./src-DOXkuCPk.js";import{I as _,K as v,Q as y,S as b,W as x,b as ee,i as S,o as C,q as w,x as T,z as E}from"./_virtual_mf___mfe_internal__admin_ui_host__loadShare___mf_0_tanstack_mf_1_react_mf_2_query__loadShare__.js-DTufy7Ue.js";import{E as D,Q as O,T as k,z as A}from"./src-Bh5CQXm7.js";import{p as j}from"./player-overlays-CkAkhPbQ.js";import{t as M}from"./clock-BxBK96nq.js";import{t as N}from"./copy-BrMo-O0l.js";import{a as te,c as ne,d as re,f as P,i as F,m as I,n as ie,o as ae,p as L,r as oe,s as R,t as z}from"./debounced-invalidate-DCfaNC1r.js";import{t as B}from"./search-BopXcdUz.js";import{t as V}from"./square-check-big-yxLWkS9v.js";import{t as H}from"./square-C0Uc1Hub.js";import{C as U,D as se,F as W,G,L as K,R as q,W as ce,c as le,i as ue,t as de}from"./index-BZA0u2Kc.js";import{t as fe}from"./AdminPage-Dq33XE9j.js";import{r as pe,t as me}from"./authed-media-XfBD4Ma-.js";var he=G(`arrow-down-wide-narrow`,[[`path`,{d:`m3 16 4 4 4-4`,key:`1co6wj`}],[`path`,{d:`M7 20V4`,key:`1yoxec`}],[`path`,{d:`M11 4h10`,key:`1w87gc`}],[`path`,{d:`M11 8h7`,key:`djye34`}],[`path`,{d:`M11 12h4`,key:`q8tih4`}]]),ge=G(`bug`,[[`path`,{d:`m8 2 1.88 1.88`,key:`fmnt4t`}],[`path`,{d:`M14.12 3.88 16 2`,key:`qol33r`}],[`path`,{d:`M9 7.13v-1a3.003 3.003 0 1 1 6 0v1`,key:`d7y7pr`}],[`path`,{d:`M12 20c-3.3 0-6-2.7-6-6v-3a4 4 0 0 1 4-4h4a4 4 0 0 1 4 4v3c0 3.3-2.7 6-6 6`,key:`xs1cw7`}],[`path`,{d:`M12 20v-9`,key:`1qisl0`}],[`path`,{d:`M6.53 9C4.6 8.8 3 7.1 3 5`,key:`32zzws`}],[`path`,{d:`M6 13H2`,key:`82j7cp`}],[`path`,{d:`M3 21c0-2.1 1.7-3.9 3.8-4`,key:`4p0ekp`}],[`path`,{d:`M20.97 5c0 2.1-1.6 3.8-3.5 4`,key:`18gb23`}],[`path`,{d:`M22 13h-4`,key:`1jl80f`}],[`path`,{d:`M17.2 17c2.1.1 3.8 1.9 3.8 4`,key:`k3fwyw`}]]),_e=G(`graduation-cap`,[[`path`,{d:`M21.42 10.922a1 1 0 0 0-.019-1.838L12.83 5.18a2 2 0 0 0-1.66 0L2.6 9.08a1 1 0 0 0 0 1.832l8.57 3.908a2 2 0 0 0 1.66 0z`,key:`j76jl0`}],[`path`,{d:`M22 10v6`,key:`1lu8f3`}],[`path`,{d:`M6 12.5V16a6 3 0 0 0 12 0v-3.5`,key:`1r8lef`}]]),ve=G(`square-parking`,[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,key:`afitv7`}],[`path`,{d:`M9 17V7h4a3 3 0 0 1 0 6H9`,key:`1dfk2c`}]]),ye=G(`tag`,[[`path`,{d:`M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z`,key:`vktsd0`}],[`circle`,{cx:`7.5`,cy:`7.5`,r:`.5`,fill:`currentColor`,key:`kqv944`}]]);y();var be=720*60*60*1e3;function xe(e){let t=[];for(let n of e)t.push(...n);return t}function Se(e,t){let n=[...e];return n.sort((e,n)=>t===`importance`?n.importance-e.importance:n.timestamp-e.timestamp),n}function Ce(e,t){return e.filter(e=>!(e.importance<t.minImportance||t.cameras.size>0&&!t.cameras.has(e.deviceId)||t.classes.size>0&&!t.classes.has(e.className)))}function J(e,t){return`${String(e)}:${t}`}function we(e,t){let n=new Map,r=new Set;for(let i of e){let e=J(i.deviceId,i.trackId);if(!t.has(e)||r.has(e))continue;r.add(e);let a=n.get(i.deviceId);a?a.push(i.trackId):n.set(i.deviceId,[i.trackId])}return n}function Te(e,t){return{since:e.fromMs??t-be,until:e.toMs??t}}var Y=typeof f==`function`,Ee=`Track deletion arrives with the next server update`;function De(){return{mutateAsync:async()=>{throw Error(`deleteTracks unavailable`)},isPending:!1}}var Oe=Y?f:De,ke=200,Ae=3e4;function je(e){let t=j(),n=S({queries:e.deviceIds.map(n=>({queryKey:[`events-feed`,n,e.since,e.until,e.minImportance??null,e.classFilter??null],staleTime:Ae,refetchInterval:Ae,queryFn:async()=>(await t.trpcClient.pipelineAnalytics.getKeyEvents.query({deviceId:n,since:e.since,until:e.until,limit:ke,...e.minImportance===void 0?{}:{minImportance:e.minImportance},...e.classFilter===void 0?{}:{classFilter:e.classFilter}})).map(e=>({...e,deviceId:n}))}))});return{rows:Se(xe(n.map(e=>e.data??[])),`importance`),isLoading:n.some(e=>e.isLoading)}}var Me=[`events-feed`],Ne=2e3;function Pe(e){let t=C(),n=e?.paused===!0,r=v(t);r.current=t;let i=v(n);i.current=n;let[a,o]=w(!1),s=_(()=>{r.current.invalidateQueries({queryKey:Me})},[]),c=v(void 0);c.current||=z({delayMs:Ne,invalidate:()=>{i.current?o(!0):s()}}),E(()=>()=>c.current?.cancel(),[]),E(()=>{n||!a||(o(!1),s())},[n,a,s]);let l=_(()=>{o(!1),s()},[s]);return m(O.PipelineAnalyticsDetectionEvent,()=>{c.current?.trigger()}),m(O.PipelineAnalyticsTrackEnded,()=>{c.current?.trigger()}),{pending:a,refreshNow:l}}y();function Fe(){return Object.values(k).filter(e=>e.level===`macro`).map(e=>({macro:e,subs:Object.values(k).filter(t=>t.parentKind===e.kind).sort((e,t)=>e.label.localeCompare(t.label))})).sort((e,t)=>e.macro.label.localeCompare(t.macro.label))}function Ie({selected:t,onChange:n}){let{t:r}=de(),[i,a]=w(!1),[o,s]=w(``),[c,l]=w(new Set),u=x(Fe,[]),d=o.trim().toLowerCase(),f=e=>d.length===0||g(e,r).toLowerCase().includes(d),p=x(()=>u.map(e=>({macro:e.macro,subs:e.subs.filter(t=>f(t)||f(e.macro))})).filter(e=>f(e.macro)||e.subs.length>0),[u,d]),m=e=>l(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n}),h=e=>{let r=new Set(t),i=t.has(e.macro.kind)&&e.subs.every(e=>t.has(e.kind)),a=[e.macro.kind,...e.subs.map(e=>e.kind)];if(i)for(let e of a)r.delete(e);else for(let e of a)r.add(e);n(r)},_=e=>{let r=new Set(t);r.has(e)?r.delete(e):r.add(e),n(r)},v=()=>n(new Set),y=t.size;return b(`div`,{className:`relative`,children:[b(`button`,{type:`button`,onClick:()=>a(e=>!e),className:`flex items-center gap-1 rounded-md px-2.5 py-1 text-xs transition-colors ${y>0?`bg-primary/12 text-primary font-medium`:`text-foreground-subtle hover:bg-surface-hover hover:text-foreground`}`,children:[T(ye,{className:`h-3.5 w-3.5`}),y>0?`Kinds (${String(y)})`:`Kinds`,T(K,{className:`h-3 w-3`})]}),i&&b(`div`,{className:`absolute z-20 mt-1 max-h-80 w-64 overflow-auto rounded-md border border-border bg-surface p-2 shadow-lg`,children:[b(`div`,{className:`mb-2 flex items-center gap-1 rounded border border-border px-1.5`,children:[T(B,{className:`h-3.5 w-3.5 text-foreground-subtle`}),T(`input`,{type:`text`,value:o,onChange:e=>s(e.target.value),placeholder:`Search kinds…`,className:`w-full bg-transparent py-1 text-xs outline-none`}),y>0&&T(`button`,{type:`button`,onClick:v,className:`text-[10px] text-foreground-subtle hover:text-foreground`,children:`Clear`})]}),p.map(n=>{let i=e(n.macro.iconId),a=c.has(n.macro.kind)||d.length>0,o=t.has(n.macro.kind);return b(`div`,{className:`mb-0.5`,children:[b(`div`,{className:`flex items-center gap-1`,children:[n.subs.length>0?T(`button`,{type:`button`,onClick:()=>m(n.macro.kind),className:`text-foreground-subtle hover:text-foreground`,"aria-label":`Expand`,children:T(a?K:W,{className:`h-3 w-3`})}):T(`span`,{className:`w-3`}),b(`label`,{className:`flex flex-1 cursor-pointer items-center gap-1.5 rounded px-1 py-0.5 text-xs hover:bg-surface-hover`,children:[T(`input`,{type:`checkbox`,checked:o,onChange:()=>h(n),className:`accent-primary`}),T(i,{className:`h-3.5 w-3.5`,style:{color:n.macro.color}}),T(`span`,{className:`font-medium`,children:g(n.macro,r)})]})]}),a&&n.subs.map(n=>{let i=e(n.iconId);return b(`label`,{className:`ml-5 flex cursor-pointer items-center gap-1.5 rounded px-1 py-0.5 text-xs hover:bg-surface-hover`,children:[T(`input`,{type:`checkbox`,checked:t.has(n.kind),onChange:()=>_(n.kind),className:`accent-primary`}),T(i,{className:`h-3.5 w-3.5`,style:{color:n.color}}),T(`span`,{children:g(n,r)})]},n.kind)})]},n.macro.kind)})]})]})}var X=100,Le=120,Re={polyline:``,points:[],snapshots:[],start:null,end:null,peakBox:null},Z=e=>e<0?0:e>1?1:e,Q=e=>Math.round(e*100)/100;function ze(e,t){if(e.length<=t)return[...e];let n=(e.length-1)/(t-1),r=[];for(let i=0;i<t;i++)r.push(e[Math.round(i*n)]);return r[r.length-1]=e[e.length-1],r}function Be(e,t,n){if(e.length===0||t===null)return Re;let{width:r,height:i}=t;if(!Number.isFinite(r)||!Number.isFinite(i)||r<=0||i<=0)return Re;let a=ze(e,n?.maxPoints??Le).map(e=>({x:Q(Z(e.x/r)*X),y:Q(Z(e.y/i)*X)})),o=a[0]??null,s=a[a.length-1]??null,c=a.length>=2?a.map(e=>`${e.x},${e.y}`).join(` `):``,l=(n?.snapshots??[]).map(e=>({x:Q(Z(e.x/r)*X),y:Q(Z(e.y/i)*X),mediaKey:e.mediaKey})),u=null,d=-1;for(let t of e){let e=Z(t.bbox.w/r)*Z(t.bbox.h/i);e>d&&(d=e,u=t)}return{polyline:c,points:a,snapshots:l,start:o,end:s,peakBox:u?{x:Q(Z(u.bbox.x/r)*X),y:Q(Z(u.bbox.y/i)*X),w:Q(Z(u.bbox.w/r)*X),h:Q(Z(u.bbox.h/i)*X)}:null}}var Ve=typeof p==`function`,He=`Track flags arrive with the next server update`;function Ue(){return{mutateAsync:async()=>{throw Error(`setTrackFlags unavailable`)},isPending:!1}}var We=Ve?p:Ue;function Ge(e){if(typeof e!=`object`||!e||!(`trackId`in e)||!(`markForTrain`in e)||!(`debug`in e))return null;let{trackId:t,markForTrain:n,debug:r}=e;return typeof t!=`string`||typeof n!=`boolean`||typeof r!=`boolean`?null:{trackId:t,markForTrain:n,debug:r}}y();function Ke({label:e,hint:t,checked:n,disabled:r,title:i,icon:a,onToggle:o}){return b(`button`,{type:`button`,role:`switch`,"aria-checked":n,"aria-label":e,disabled:r,title:i,onClick:o,className:`flex w-full items-center gap-2 rounded-md border px-2 py-1.5 text-left transition-colors disabled:opacity-50 ${n?`border-primary bg-primary/10`:`border-border bg-surface hover:bg-surface-hover`}`,children:[T(`span`,{className:n?`text-primary`:`text-foreground-subtle`,children:a}),b(`span`,{className:`min-w-0 flex-1`,children:[T(`span`,{className:`block text-[11px] font-medium text-foreground`,children:e}),T(`span`,{className:`block text-[10px] text-foreground-subtle`,children:t})]}),T(`span`,{"aria-hidden":`true`,className:`h-4 w-7 shrink-0 rounded-full p-0.5 transition-colors ${n?`bg-primary`:`bg-border`}`,children:T(`span`,{className:`block h-3 w-3 rounded-full bg-white transition-transform ${n?`translate-x-3`:``}`})})]})}function qe({deviceId:e,trackId:t,markForTrain:n,debug:r,onChange:i}){let a=We(),[o,s]=w(null),c=o?.markForTrain??n===!0,l=o?.debug??r===!0,u=!Ve||a.isPending,d=Ve?void 0:He,f=n=>{u||(async()=>{try{let r=Ge(await a.mutateAsync({deviceId:e,trackId:t,flags:n}));if(!r)return;s(r),i?.(r)}catch{window.alert(`Could not update this track. Check the server logs.`)}})()};return b(`div`,{className:`grid gap-1.5 sm:grid-cols-2`,children:[T(Ke,{label:`Mark for training`,hint:`Curation only — does not extend retention`,checked:c,disabled:u,...d===void 0?{}:{title:d},icon:T(_e,{className:`h-4 w-4`}),onToggle:()=>f({markForTrain:!c})}),T(Ke,{label:`Debug`,hint:`Flag this track for diagnostic attention`,checked:l,disabled:u,...d===void 0?{}:{title:d},icon:T(ge,{className:`h-4 w-4`}),onToggle:()=>f({debug:!l})})]})}var Je={firstFrame:`First frame (track start)`,lastFrame:`Last frame (track end)`,thumbnail:`Best detection`,thumbnailSmall:`Best detection (480)`,snapshot:`Snapshot`,keyFrame:`Key frame (native-res)`,keyFrameSmall:`Key frame (960)`,crop:`Object crop`,fullFrame:`Full frame`,fullFrameBoxed:`Full frame (boxed)`,faceCrop:`Face crop`,plateCrop:`Plate crop`};function Ye(e){return e in Je}function Xe(e){return Ye(e)?Je[e]:e}function Ze(e,t){return`${e}${me}/${encodeURIComponent(t)}`}y();var Qe=1400,$e=`Admin-gated URL — opens only inside an authenticated session`;function et({label:e,value:t,title:n}){let[r,i]=w(!1);return E(()=>{if(!r)return;let e=setTimeout(()=>i(!1),Qe);return()=>clearTimeout(e)},[r]),b(`button`,{type:`button`,onClick:_(()=>{(async()=>{try{await navigator.clipboard.writeText(t),i(!0)}catch{window.prompt(`Copy the media URL:`,t)}})()},[t]),title:n,"aria-label":`Copy ${e} URL`,className:`flex min-w-0 items-center gap-1 rounded border px-1.5 py-0.5 text-[10px] font-medium transition-colors ${r?`border-emerald-500/40 bg-emerald-500/10 text-emerald-700 dark:text-emerald-300`:`border-border text-foreground-subtle hover:border-primary hover:text-foreground`}`,children:[T(r?q:N,{className:`h-2.5 w-2.5 shrink-0`}),T(`span`,{className:`truncate`,children:r?`Copied`:e})]})}function tt({localUrl:e,publicUrl:t}){return b(`div`,{className:`flex flex-wrap gap-1`,children:[T(et,{label:`Local`,value:e,title:`Copy LAN URL — ${$e}`}),t&&T(et,{label:`Public`,value:t,title:`Copy public URL — ${$e}`})]})}y();var nt=3e4;function rt(e){let[t,n]=w(null),r=_(e=>{n(t=>t??e)},[]);return E(()=>{e||n(null)},[e]),{publicOrigin:t,probes:e?T(it,{onOrigin:r}):null}}function it({onOrigin:e}){let{data:t}=h({capName:`network-access`});return T(ee,{children:(t??[]).map(t=>T(at,{addonId:t.addonId,onOrigin:e},t.addonId))})}function at({addonId:e,onOrigin:t}){let{data:n}=a({addonId:e},{refetchInterval:nt,retry:!1});return E(()=>{let e=n?D.safeParse(n):null,r=e?.success?e.data.endpoint?.url:void 0;if(r)try{t(new URL(r).origin)}catch{}},[n,t]),null}y();var ot=15e3,st=window.location.origin,ct=new Set([`firstFrame`,`lastFrame`,`thumbnail`,`snapshot`]),lt=new Set([`keyFrame`,`fullFrame`,`fullFrameBoxed`,`firstFrame`,`lastFrame`,`thumbnail`,`snapshot`]);function ut(e){let[t,n]=w(null);return E(()=>{if(n(null),!e)return;let t=!1,r=new Image;return r.onload=()=>{t||n({width:r.naturalWidth,height:r.naturalHeight})},r.src=e,()=>{t=!0,r.onload=null}},[e]),t}function dt({overlay:e,onPickSnapshot:t}){return!e.polyline&&!e.peakBox&&e.snapshots.length===0?null:b(`svg`,{viewBox:`0 0 100 100`,preserveAspectRatio:`none`,className:`pointer-events-none absolute inset-0 h-full w-full`,children:[e.peakBox&&T(`rect`,{x:e.peakBox.x,y:e.peakBox.y,width:e.peakBox.w,height:e.peakBox.h,fill:`none`,stroke:`#f59e0b`,strokeWidth:2,vectorEffect:`non-scaling-stroke`,rx:1}),e.polyline&&T(`polyline`,{points:e.polyline,fill:`none`,stroke:`#38bdf8`,strokeWidth:2,strokeLinejoin:`round`,strokeLinecap:`round`,strokeOpacity:.85,vectorEffect:`non-scaling-stroke`}),e.points.map((e,t)=>T(`circle`,{cx:e.x,cy:e.y,r:1,fill:`#38bdf8`,fillOpacity:.6,vectorEffect:`non-scaling-stroke`},`${String(e.x)}-${String(e.y)}-${String(t)}`)),e.snapshots.map((e,n)=>T(`circle`,{cx:e.x,cy:e.y,r:1.9,fill:`#0ea5e9`,fillOpacity:.95,stroke:`#082f49`,strokeWidth:.7,vectorEffect:`non-scaling-stroke`,className:t?`pointer-events-auto cursor-pointer`:void 0,onClick:t?n=>{n.stopPropagation(),t(e.mediaKey)}:void 0,children:T(`title`,{children:`Snapshot checkpoint — click to view this frame`})},`snap-${e.mediaKey}-${String(n)}`)),e.start&&T(`circle`,{cx:e.start.x,cy:e.start.y,r:2.4,fill:`#22c55e`,stroke:`#052e16`,strokeWidth:.6,vectorEffect:`non-scaling-stroke`}),e.end&&T(`circle`,{cx:e.end.x,cy:e.end.y,r:2.4,fill:`#ef4444`,stroke:`#450a0a`,strokeWidth:.6,vectorEffect:`non-scaling-stroke`})]})}function $({label:e,value:t,mono:n}){return b(`div`,{className:`flex items-baseline justify-between gap-3 border-b border-border/60 py-1.5 last:border-0`,children:[T(`span`,{className:`shrink-0 text-[11px] uppercase tracking-wide text-foreground-subtle`,children:e}),T(`span`,{className:`min-w-0 truncate text-right text-xs font-medium text-foreground ${n?`font-mono text-[11px]`:``}`,title:t,children:t})]})}function ft({row:e,cameraName:r,deleteAvailable:a,onClose:u,onDeleted:d,onFlagsChanged:f}){let p=j(),m=Oe(),h=e!==null,g=e?.deviceId??0,v=e?.trackId??``,y=e?.bestEventId??``,S=e?.timestamp??0,C=e?.windowMs??0,{data:D}=c({deviceId:g,trackId:v},{enabled:h}),{data:O}=l({trackId:v},{enabled:h}),{data:k}=n({eventId:y},{enabled:h&&y!==``}),{data:A}=s({deviceId:g,since:S-ot,until:S+C+ot},{enabled:h}),[M,N]=w(null),[te,ne]=w(!1),{publicOrigin:P,probes:ie}=rt(h);E(()=>{N(null)},[g,v]);let ae=x(()=>{let e=O??[],t=k??[];return e.find(e=>e.kind===`keyFrame`)||t.find(e=>e.kind===`fullFrameBoxed`)||([...t,...e].find(e=>e.kind===`crop`)??null)},[O,k]),oe=pe(ae?`${me}/${encodeURIComponent(ae.key)}`:void 0),R=x(()=>{let e=new Set,t=[];for(let n of[...k??[],...O??[]])!n.base64||e.has(n.key)||(e.add(n.key),t.push(n));return t},[k,O]),z=x(()=>R.find(e=>ct.has(e.kind))??null,[R]),B=ut(z?`data:image/jpeg;base64,${z.base64}`:null),V=x(()=>Be(D?.positions??[],B,{snapshots:(D?.snapshots??[]).map(e=>({x:e.position.x,y:e.position.y,mediaKey:e.mediaKey}))}),[D?.positions,D?.snapshots,B]),H=_(e=>{let t=R.find(t=>t.key===e);t&&N(t)},[R]);if(e===null)return null;let W=M?`data:image/jpeg;base64,${M.base64}`:oe.src,G=M?.kind??ae?.kind,K=G!==void 0&&lt.has(G)&&B!==null&&(D?.positions.length??0)>=2,q=A&&A.length>0?A[0]:null,ce=()=>{q&&(ne(!0),(async()=>{try{let t=await p.trpcClient.videoclips.getClipPlayback.query({deviceId:e.deviceId,clipId:q.id});window.open(t.playbackUrl,`_blank`,`noopener`)}catch{window.alert(`Could not resolve clip playback. Check the server logs.`)}finally{ne(!1)}})())},de=()=>{!a||m.isPending||window.confirm(`Delete this track and all its media? This cannot be undone.`)&&(async()=>{try{await m.mutateAsync({deviceId:e.deviceId,trackIds:[e.trackId]}),d()}catch{window.alert(`Failed to delete this track. Check the server logs.`)}})()},fe=Math.round(e.importance*100),he=D?.importanceReason?`${String(fe)}% · ${D.importanceReason}`:`${String(fe)}%`,ge=D?.zonesVisited&&D.zonesVisited.length>0?D.zonesVisited.join(`, `):`—`,_e=D?.audioLabels&&D.audioLabels.length>0?D.audioLabels.map(e=>`${e.label} ×${String(e.count)} (${String(Math.round(e.peakScore*100))}%)`).join(` · `):`—`,ve=D?D.totalDistance.toFixed(2):`—`,ye=L(D?D.firstSeen:S),be=D?L(D.lastSeen):`—`;return T(o,{open:!0,onOpenChange:e=>!e&&u(),children:b(t,{width:`lg`,placement:`sheet-on-mobile`,"aria-label":`Event detail`,className:`flex h-[92dvh] flex-col gap-0 overflow-hidden p-0 bottom-0 left-0 right-0 top-auto w-full max-w-full translate-x-0 translate-y-0 rounded-b-none md:bottom-auto md:left-1/2 md:right-auto md:top-1/2 md:h-auto md:w-[calc(100vw-2rem)] md:max-w-xl md:-translate-x-1/2 md:-translate-y-1/2 md:rounded-lg md:max-h-[calc(100dvh-2rem)]`,children:[b(`header`,{className:`flex shrink-0 items-start justify-between gap-2 border-b border-border px-4 py-3`,children:[b(`div`,{className:`min-w-0`,children:[b(`div`,{className:`truncate text-sm font-semibold text-foreground`,children:[e.className,e.label?b(`span`,{className:`text-foreground-subtle`,children:[` · `,e.label]}):null]}),T(`div`,{className:`mt-0.5 truncate text-[11px] text-foreground-subtle`,children:r})]}),T(`button`,{type:`button`,onClick:u,className:`rounded p-1 text-foreground-subtle hover:bg-surface-hover hover:text-foreground`,"aria-label":`Close`,children:T(ue,{className:`h-4 w-4`})})]}),b(`div`,{className:`min-h-0 flex-1 space-y-3 overflow-y-auto overscroll-contain px-4 py-3`,children:[W?T(`div`,{className:`overflow-hidden rounded-lg border border-border bg-background`,children:T(F,{src:W,alt:`Key frame from ${r}`,fit:`natural`,className:`w-full`,overlay:K?T(dt,{overlay:V,onPickSnapshot:H}):void 0})}):T(`div`,{className:`flex aspect-video w-full flex-col items-center justify-center gap-1.5 rounded-lg border border-border bg-surface-hover text-foreground-subtle`,children:oe.failed?b(ee,{children:[T(I,{className:`h-8 w-8 opacity-60`}),T(`span`,{className:`text-[11px]`,children:`Key-frame media unavailable`})]}):T(U,{className:`h-6 w-6 animate-spin opacity-70`})}),R.length>0&&T(`div`,{className:`-mx-1 flex gap-2 overflow-x-auto px-1 pb-1`,children:R.map(e=>{let t=`data:image/jpeg;base64,${e.base64}`,n=Xe(e.kind),r=Ze(st,e.key),i=P?Ze(P,e.key):null;return b(`figure`,{className:`flex w-32 shrink-0 flex-col gap-1`,children:[T(`button`,{type:`button`,onClick:()=>N(e),className:`relative h-16 w-full overflow-hidden rounded border border-border hover:border-primary`,title:`${n} · ${L(e.timestamp)}`,children:T(`img`,{src:t,alt:n,className:`h-full w-full object-cover`})}),b(`figcaption`,{className:`min-w-0 px-0.5`,children:[T(`div`,{className:`truncate text-[10px] font-medium leading-tight text-foreground`,title:n,children:n}),T(`div`,{className:`text-[10px] leading-tight text-foreground-subtle`,title:L(e.timestamp),children:re(e.timestamp)})]}),T(tt,{localUrl:r,publicUrl:i})]},e.key)})}),ie,q&&b(i,{variant:`secondary`,onClick:ce,disabled:te,children:[te?T(U,{className:`h-3.5 w-3.5 animate-spin`}):T(se,{className:`h-3.5 w-3.5`}),` `,`View clip`]}),T(qe,{deviceId:e.deviceId,trackId:e.trackId,...(D?.markForTrain??e.markForTrain)===void 0?{}:{markForTrain:D?.markForTrain??e.markForTrain},...(D?.debug??e.debug)===void 0?{}:{debug:D?.debug??e.debug},onChange:f}),b(`div`,{className:`rounded-lg border border-border bg-surface px-3 py-1`,children:[T($,{label:`Camera`,value:r}),T($,{label:`Class`,value:e.className}),T($,{label:`Label`,value:e.label??`—`}),T($,{label:`Importance`,value:he}),T($,{label:`Zones visited`,value:ge}),T($,{label:`Audio heard`,value:_e}),T($,{label:`Total distance`,value:ve}),T($,{label:`First seen`,value:ye}),T($,{label:`Last seen`,value:be}),T($,{label:`Track`,value:e.trackId,mono:!0})]})]}),T(`footer`,{className:`flex shrink-0 items-center justify-end gap-2 border-t border-border px-4 py-3 pb-[max(0.75rem,env(safe-area-inset-bottom))]`,children:T(`span`,{title:a?void 0:Ee,children:b(i,{variant:`secondary`,onClick:de,disabled:!a||m.isPending,children:[m.isPending?T(U,{className:`h-3.5 w-3.5 animate-spin`}):T(le,{className:`h-3.5 w-3.5`}),` `,`Delete track`]})})})]})})}function pt(e){if(e===void 0||!Number.isFinite(e)||e<=0)return``;let t=e/1e3;if(t<60)return`${t.toFixed(1)}s`;let n=Math.floor(t/60),r=Math.round(t%60);return`${String(n)}m ${String(r).padStart(2,`0`)}s`}function mt({row:e,cameraName:t,nowMs:n,onOpenDetail:r,selected:i=!1,onToggleSelect:a,score:o}){let s=pe(e.bestEventId?`${me}/${e.bestEventId}`:void 0),c=Math.round(e.importance*100),l=o===void 0?void 0:Math.round(o*100),u=pt(e.windowMs),d=()=>r(e);return b(`div`,{className:`relative flex flex-col rounded-md border bg-surface overflow-hidden ${i?`border-primary ring-1 ring-primary`:`border-border`}`,children:[b(`div`,{className:`aspect-video relative overflow-hidden bg-surface-hover`,children:[s.src?T(`img`,{src:s.src,alt:`Event from ${t}`,onClick:d,className:`h-full w-full cursor-zoom-in object-cover`}):T(`button`,{type:`button`,onClick:d,className:`flex h-full w-full flex-col items-center justify-center gap-1 bg-surface-hover text-foreground-subtle`,title:s.failed?`Key-event media unavailable`:`No key-event media`,children:T(I,{className:`h-6 w-6 opacity-60`})}),a&&T(`button`,{type:`button`,onClick:t=>{t.stopPropagation(),a(J(e.deviceId,e.trackId))},className:`absolute left-0 top-0 z-10 rounded-br-md bg-black/50 p-1.5 text-white hover:bg-black/70`,"aria-label":i?`Deselect`:`Select`,children:i?T(V,{className:`h-4 w-4 text-primary`}):T(H,{className:`h-4 w-4`})}),l!==void 0&&b(`span`,{className:`absolute left-1 top-1 z-10 rounded bg-primary/85 px-1.5 py-0.5 text-[10px] font-semibold text-white tabular-nums`,title:`CLIP semantic-match score`,children:[String(l),`%`]}),c>0&&T(`span`,{className:`absolute right-1 top-1 z-10 rounded bg-black/60 px-1.5 py-0.5 text-[10px] font-semibold text-white`,children:String(c)}),(e.markForTrain===!0||e.debug===!0)&&b(`span`,{className:`absolute bottom-1 left-1 z-10 flex gap-1`,children:[e.markForTrain===!0&&T(`span`,{className:`rounded bg-primary/85 p-0.5 text-white`,title:`Marked for training`,"aria-label":`Marked for training`,children:T(_e,{className:`h-3 w-3`})}),e.debug===!0&&T(`span`,{className:`rounded bg-black/70 p-0.5 text-white`,title:`Flagged for debug`,"aria-label":`Flagged for debug`,children:T(ge,{className:`h-3 w-3`})})]})]}),b(`button`,{type:`button`,onClick:d,className:`min-w-0 px-2 py-1.5 text-left space-y-0.5`,children:[b(`p`,{className:`text-[11px] font-medium text-foreground truncate`,title:e.className,children:[e.className,e.label?b(`span`,{className:`text-foreground-subtle`,children:[` · `,e.label]}):null]}),T(`p`,{className:`text-[10px] text-foreground-subtle truncate`,title:t,children:t}),b(`div`,{className:`flex items-center justify-between gap-2`,children:[T(`span`,{className:`text-[10px] text-foreground-subtle truncate`,children:P(e.timestamp,n)}),u&&T(`span`,{className:`text-[10px] text-foreground-subtle shrink-0`,children:u})]})]})]})}y();function ht(){let[e,t]=w(!1),n=v(null),[r,i]=w(0),a=_(e=>{n.current!==e&&(n.current=e,i(e=>e+1))},[]);return E(()=>{let e=n.current;if(!e||typeof IntersectionObserver>`u`){t(!1);return}let r=new IntersectionObserver(e=>{let n=e[e.length-1];n&&t(!n.isIntersecting)},{rootMargin:`64px 0px 0px 0px`,threshold:0});return r.observe(e),()=>r.disconnect()},[r]),{ref:a,scrolledPast:e}}y();var gt=[`events-feed`],_t=60,vt=[{value:`importance`,label:`Importance`,icon:he},{value:`time`,label:`Recent`,icon:M}];function yt(){let e=C(),[t,n]=w(R),[a,o]=w(new Set),[s,c]=w(new Set),[l,u]=w(0),[d,f]=w(`time`),[p,m]=w(new Set),[h,g]=w(null),[_,v]=w(()=>Date.now());E(()=>{let e=setInterval(()=>v(Date.now()),6e4);return()=>clearInterval(e)},[]);let{since:y,until:S}=x(()=>Te({fromMs:t.fromMs,toMs:t.toMs},_),[t.fromMs,t.toMs,_]),D=ht(),{pending:O,refreshNow:k}=Pe({paused:h!==null||p.size>0||D.scrolledPast}),{data:j}=r({}),M=x(()=>(j??[]).filter(e=>e.type===A.Camera),[j]),N=x(()=>M.map(e=>e.id),[M]),re=Oe(),P=re.isPending,{rows:F,isLoading:I}=je({deviceIds:N,since:y,until:S,minImportance:l>0?l:void 0,classFilter:s.size===1?[...s][0]:void 0}),L=x(()=>{let e=new Map;for(let t of M??[])e.set(t.id,t.name);return e},[M]),z=e=>L.get(e)??`Camera #${String(e)}`,B=x(()=>ne(F).map(e=>({id:e,name:z(e)})).sort((e,t)=>e.name.localeCompare(t.name)),[F,L]),V=x(()=>Se(Ce(F,{cameras:a,classes:s,minImportance:l}),d),[F,a,s,l,d]),H=ie(V,_t,x(()=>JSON.stringify([[...a].sort((e,t)=>e-t),[...s].sort(),l,d,y,S]),[a,s,l,d,y,S])),se=()=>{e.invalidateQueries({queryKey:gt})},W=()=>m(new Set);function G(e){m(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})}function K(){if(p.size===0||!Y)return;let e=we(F,p),t=[...e.values()].reduce((e,t)=>e+t.length,0);if(t===0||!window.confirm(`Delete ${String(t)} track${t===1?``:`s`} and all their media? This cannot be undone.`))return;let n=[...e];Promise.allSettled(n.map(([e,t])=>re.mutateAsync({deviceId:e,trackIds:t}))).then(e=>{se();let t=[],r=new Set;if(e.forEach((e,i)=>{let a=n[i];if(!a)return;let[o,s]=a;if(e.status===`fulfilled`)for(let e of s)r.add(J(o,e));else t.push(o)}),m(e=>{let t=new Set(e);for(let e of r)t.delete(e);return t}),t.length>0){let e=t.map(e=>z(e)).join(`, `);window.alert(`Failed to delete tracks on: ${e}. They remain selected — retry, or check the server logs.`)}})}let q=V.length!==F.length;return b(`div`,{className:`relative space-y-3`,children:[b(`div`,{className:`flex flex-wrap items-center gap-1.5`,children:[T(te,{onChange:n}),T(ae,{cameras:B,selected:a,onChange:o}),T(Ie,{selected:s,onChange:c}),b(`label`,{className:`flex items-center gap-1.5 text-[11px] text-foreground-subtle`,children:[T(`span`,{children:`Min score`}),T(`input`,{type:`range`,min:0,max:1,step:.05,value:l,onChange:e=>u(Number(e.target.value)),className:`h-1 w-24 cursor-pointer accent-primary`,"aria-label":`Minimum importance`}),T(`span`,{className:`w-6 tabular-nums text-foreground`,children:Math.round(l*100)})]}),T(`div`,{className:`flex items-center gap-1 rounded-md border border-border p-0.5`,children:vt.map(e=>{let t=e.icon;return b(`button`,{type:`button`,onClick:()=>f(e.value),className:`flex items-center gap-1 rounded px-2 py-1 text-[11px] transition-colors ${d===e.value?`bg-primary/12 text-primary font-medium`:`text-foreground-subtle hover:bg-surface-hover hover:text-foreground`}`,children:[T(t,{className:`h-3.5 w-3.5`}),` `,e.label]},e.value)})}),!I&&T(`span`,{className:`ml-auto text-[10px] text-foreground-subtle`,children:q?`${String(V.length)} of ${String(F.length)} events`:`${String(V.length)} event${V.length===1?``:`s`}`})]}),p.size>0&&b(`div`,{className:`flex flex-wrap items-center gap-2 rounded-md border border-primary/40 bg-primary/8 px-3 py-2`,children:[b(`span`,{className:`text-xs font-medium text-foreground`,children:[p.size,` selected`]}),b(`div`,{className:`ml-auto flex flex-wrap items-center gap-1.5`,children:[T(`span`,{title:Y?void 0:`Track deletion arrives with the next server update`,children:b(i,{variant:`secondary`,onClick:K,disabled:!Y||P,children:[P?T(U,{className:`h-3.5 w-3.5 animate-spin`}):T(le,{className:`h-3.5 w-3.5`}),` `,`Delete`]})}),T(i,{variant:`ghost`,onClick:W,disabled:P,children:T(ue,{className:`h-3.5 w-3.5`})})]})]}),I&&b(`div`,{className:`flex items-center gap-2 py-4 text-xs text-foreground-subtle`,children:[T(U,{className:`h-4 w-4 animate-spin`}),` Loading events…`]}),!I&&V.length===0&&T(`p`,{className:`py-4 text-xs text-foreground-subtle`,children:`No key events in this window.`}),O&&T(`div`,{className:`sticky top-2 z-20 flex justify-center`,children:T(`button`,{type:`button`,onClick:k,className:`rounded-full border border-primary/40 bg-surface px-3 py-1 text-[11px] font-medium text-primary shadow-sm hover:bg-primary/10`,children:`New events — refresh`})}),!I&&V.length>0&&b(ee,{children:[T(`div`,{ref:D.ref,"aria-hidden":!0,className:`h-0`}),T(`div`,{className:`grid grid-cols-[repeat(auto-fill,minmax(11rem,1fr))] gap-2`,children:H.pageItems.map(e=>T(mt,{row:e,cameraName:z(e.deviceId),nowMs:_,selected:p.has(J(e.deviceId,e.trackId)),onToggleSelect:G,onOpenDetail:g},J(e.deviceId,e.trackId)))}),T(oe,{currentPage:H.page,totalItems:H.totalItems,pageSize:H.pageSize,onPageChange:H.setPage,itemNoun:`events`})]}),h&&T(ft,{row:h,cameraName:z(h.deviceId),deleteAvailable:Y,onClose:()=>g(null),onDeleted:()=>{se(),g(null)},onFlagsChanged:e=>{g(t=>t&&t.trackId===e.trackId?{...t,markForTrain:e.markForTrain,debug:e.debug}:t)}})]})}y();var bt=50,xt=350,St=[`person`,`vehicle`,`animal`],Ct=[{value:.2,label:`Loose`},{value:.25,label:`Balanced`},{value:.3,label:`Strict`}];function wt(e){return{id:e.id,trackId:e.trackId??e.id,deviceId:e.deviceId,timestamp:e.timestamp,className:e.className,label:e.label,importance:e.importance??0,bestEventId:e.mediaKey??e.trackId??e.id,windowMs:void 0}}function Tt({onActiveChange:e}){let[t,n]=w(``),[i,a]=w(.2),[o,s]=w(null),[c,l]=w(null),[f,p]=w(null),m=d(t,xt).trim(),h=m.length>0;E(()=>{e(h)},[h,e]);let[g,_]=w(()=>Date.now());E(()=>{let e=setInterval(()=>_(Date.now()),6e4);return()=>clearInterval(e)},[]);let{data:v}=r({}),y=x(()=>(v??[]).filter(e=>e.type===A.Camera),[v]),ee=x(()=>{let e=new Map;for(let t of v??[])e.set(t.id,t.name);return e},[v]),S=e=>ee.get(e)??`Camera #${String(e)}`,{data:C,isFetching:D,isError:O,error:k}=u({text:m,minScore:i,limit:bt,classFilter:o??void 0,deviceId:c??void 0},{enabled:h}),j=x(()=>[...C??[]].sort((e,t)=>t.score-e.score).map(e=>({...wt(e),score:e.score})),[C]);function M(e){s(t=>t===e?null:e)}return b(`div`,{className:`space-y-3`,children:[b(`div`,{className:`rounded-lg border border-border bg-surface p-3 space-y-3`,children:[b(`div`,{className:`flex flex-wrap items-center gap-2`,children:[b(`div`,{className:`relative min-w-[16rem] flex-1`,children:[T(B,{className:`pointer-events-none absolute left-2.5 top-1/2 h-4 w-4 -translate-y-1/2 text-foreground-subtle`}),T(`input`,{type:`text`,value:t,onChange:e=>n(e.target.value),placeholder:`Semantic search — describe what you're looking for…`,className:`h-9 w-full rounded-md border border-border bg-background pl-8 pr-8 text-sm text-foreground placeholder:text-foreground-subtle focus:border-primary focus:outline-none focus:ring-1 focus:ring-primary`,"aria-label":`Semantic event search`}),t&&T(`button`,{type:`button`,onClick:()=>n(``),className:`absolute right-2 top-1/2 -translate-y-1/2 rounded p-0.5 text-foreground-subtle hover:bg-surface-hover hover:text-foreground`,"aria-label":`Clear search`,children:T(ue,{className:`h-3.5 w-3.5`})})]}),D&&h&&T(U,{className:`h-4 w-4 shrink-0 animate-spin text-foreground-subtle`})]}),b(`div`,{className:`flex flex-wrap items-center gap-x-4 gap-y-2`,children:[T(`div`,{className:`flex items-center gap-1`,children:St.map(e=>T(`button`,{type:`button`,onClick:()=>M(e),className:`rounded-md px-2.5 py-1 text-xs capitalize transition-colors ${o===e?`bg-primary/12 text-primary font-medium`:`text-foreground-subtle hover:bg-surface-hover hover:text-foreground`}`,children:e},e))}),b(`label`,{className:`flex items-center gap-1.5 text-[11px] text-foreground-subtle`,children:[T(`span`,{children:`Camera`}),b(`select`,{value:c===null?``:String(c),onChange:e=>l(e.target.value===``?null:Number(e.target.value)),className:`h-7 rounded-md border border-border bg-background px-1.5 text-xs text-foreground focus:border-primary focus:outline-none`,"aria-label":`Filter by camera`,children:[T(`option`,{value:``,children:`All`}),y.map(e=>T(`option`,{value:String(e.id),children:e.name},e.id))]})]}),b(`div`,{className:`flex items-center gap-1.5 text-[11px] text-foreground-subtle`,children:[T(`span`,{children:`Match`}),T(`div`,{className:`flex items-center gap-1 rounded-md border border-border p-0.5`,children:Ct.map(e=>T(`button`,{type:`button`,onClick:()=>a(e.value),className:`rounded px-2 py-1 text-[11px] transition-colors ${i===e.value?`bg-primary/12 text-primary font-medium`:`text-foreground-subtle hover:bg-surface-hover hover:text-foreground`}`,title:`Minimum CLIP score ${e.value.toFixed(2)}`,children:e.label},e.value))})]}),h&&!D&&!O&&b(`span`,{className:`ml-auto text-[10px] text-foreground-subtle`,children:[j.length,` match`,j.length===1?``:`es`]})]})]}),h&&b(`div`,{className:`space-y-3`,children:[O&&b(`p`,{className:`py-4 text-xs text-danger`,children:[`Search failed: `,k instanceof Error?k.message:`unknown error`,`. Check that the CLIP embedding step is enabled.`]}),!O&&D&&j.length===0&&b(`div`,{className:`flex items-center gap-2 py-4 text-xs text-foreground-subtle`,children:[T(U,{className:`h-4 w-4 animate-spin`}),` Searching…`]}),!O&&!D&&j.length===0&&b(`p`,{className:`py-4 text-xs text-foreground-subtle`,children:[`No semantic matches for “`,m,`”. Try a looser match threshold or a different phrasing.`]}),!O&&j.length>0&&T(`div`,{className:`grid grid-cols-[repeat(auto-fill,minmax(11rem,1fr))] gap-2`,children:j.map(e=>T(mt,{row:e,cameraName:S(e.deviceId),nowMs:g,score:e.score,onOpenDetail:p},e.id))})]}),f&&T(ft,{row:f,cameraName:S(f.deviceId),deleteAvailable:Y,onClose:()=>p(null),onDeleted:()=>p(null)})]})}var Et=15e3;function Dt(e){let t=j(),n=S({queries:e.map(e=>({queryKey:[`stationary-objects`,e],staleTime:Et,refetchInterval:Et,queryFn:async()=>((await t.trpcClient.zoneAnalytics.getCurrentSnapshot.query({deviceId:e}))?.stationaryObjects??[]).map(t=>({...t,deviceId:e}))}))});return{rows:n.flatMap(e=>e.data??[]).toSorted((e,t)=>t.becameStationaryAt-e.becameStationaryAt),isLoading:n.some(e=>e.isLoading)}}y();function Ot(e,t){let n=Math.max(0,Math.round((e-t)/6e4));if(n<1)return`just now`;if(n<60)return`${String(n)}m`;let r=Math.floor(n/60);return`${String(r)}h ${String(n%60)}m`}function kt({row:e,cameraName:t,nowMs:n}){let r=e.keyFrameMediaKey?.startsWith(`track:`)?e.keyFrameMediaKey.split(`:`)[1]:e.keyFrameMediaKey,i=pe(r?`${me}/${r}`:void 0);return b(`div`,{className:`flex flex-col overflow-hidden rounded-md border border-border bg-surface`,children:[b(`div`,{className:`relative aspect-video overflow-hidden bg-surface-hover`,children:[i.src?T(`img`,{src:i.src,alt:`Parked ${e.className} on ${t}`,className:`h-full w-full object-cover`}):T(`div`,{className:`flex h-full w-full items-center justify-center text-foreground-subtle`,children:T(ve,{className:`h-6 w-6`})}),T(`span`,{className:`absolute left-1 top-1 rounded bg-black/60 px-1.5 py-0.5 text-[10px] font-medium capitalize text-white`,children:e.label??e.className})]}),b(`div`,{className:`flex flex-col gap-0.5 p-1.5`,children:[T(`span`,{className:`truncate text-[11px] text-foreground`,children:t}),b(`span`,{className:`text-[10px] text-foreground-subtle`,children:[`parked `,Ot(n,e.becameStationaryAt)]})]})]})}function At(){let[e,t]=w(!1),n=Date.now(),{data:i}=r({}),a=x(()=>(i??[]).filter(e=>e.type===A.Camera),[i]),o=x(()=>a.map(e=>e.id),[a]),s=x(()=>{let e=new Map;for(let t of a)e.set(t.id,t.name);return e},[a]),{rows:c}=Dt(o);return c.length===0?null:b(`div`,{className:`rounded-md border border-border bg-surface/40`,children:[b(`button`,{type:`button`,onClick:()=>t(e=>!e),className:`flex w-full items-center gap-2 px-3 py-2 text-left`,children:[T(e?K:W,{className:`h-4 w-4 text-foreground-subtle`}),T(ve,{className:`h-4 w-4 text-foreground-subtle`}),T(`span`,{className:`text-sm font-semibold text-foreground`,children:`Stationary`}),T(`span`,{className:`rounded-full bg-surface-hover px-2 py-0.5 text-[10px] font-medium text-foreground-subtle`,children:c.length}),T(`span`,{className:`ml-2 text-[11px] text-foreground-subtle`,children:`Parked objects — kept out of the event feed`})]}),e&&T(`div`,{className:`grid grid-cols-[repeat(auto-fill,minmax(9rem,1fr))] gap-2 p-3 pt-0`,children:c.map(e=>T(kt,{row:e,cameraName:s.get(e.deviceId)??`Camera #${String(e.deviceId)}`,nowMs:n},e.id))})]})}y();function jt(){let[e,t]=w(!1);return T(fe,{icon:ce,title:`Events`,subtitle:`Every captured key event across all cameras — trajectory, media, and clips.`,children:b(`section`,{className:`space-y-3`,children:[T(Tt,{onActiveChange:t}),!e&&T(At,{}),!e&&T(yt,{})]})})}export{jt as EventsPage};
@@ -1 +0,0 @@
1
- import{G as e}from"./index-BZA0u2Kc.js";var t=e(`circle-check-big`,[[`path`,{d:`M21.801 10A10 10 0 1 1 17 3.335`,key:`yps3ct`}],[`path`,{d:`m9 11 3 3L22 4`,key:`1pflzl`}]]);export{t};
@@ -1 +0,0 @@
1
- import{G as e}from"./index-BZA0u2Kc.js";var t=e(`clock`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`polyline`,{points:`12 6 12 12 16 14`,key:`68esgv`}]]);export{t};