@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.
- package/dist/assets/{AddLocationWizard-BNLzjRkS.js → AddLocationWizard-DzP-CYOi.js} +1 -1
- package/dist/assets/{AddonCollectionPage-CvyviITl.js → AddonCollectionPage-B5t3SHZE.js} +1 -1
- package/dist/assets/{Addons-B0nG62pB.js → Addons-DCR8DMgD.js} +1 -1
- package/dist/assets/{AdminTabs-V94RuaJP.js → AdminTabs-DTECFIAe.js} +1 -1
- package/dist/assets/{AiProfiles-CNda-xrz.js → AiProfiles-D0jpUF4v.js} +1 -1
- package/dist/assets/{Automation-DYV0gbiV.js → Automation-BX0bNbpp.js} +1 -1
- package/dist/assets/{BrokerForm-DX_RUCNg.js → BrokerForm-CROZPAB-.js} +1 -1
- package/dist/assets/{Capabilities-Cud2I1p1.js → Capabilities-DIGQ9fiv.js} +1 -1
- package/dist/assets/{CapabilityBadges-CaKz6Row.js → CapabilityBadges-B4vHw0qw.js} +1 -1
- package/dist/assets/{Cluster-Cx5dtvDp.js → Cluster-BnTT5Wsb.js} +1 -1
- package/dist/assets/{ClusterRecordingTab-BShu9AFE.js → ClusterRecordingTab-BVkyOEdI.js} +1 -1
- package/dist/assets/{Dashboard-CN0qzHHd.js → Dashboard-BlkR2NIh.js} +1 -1
- package/dist/assets/{Data-Cddnp6Uz.js → Data-CECcPfPj.js} +1 -1
- package/dist/assets/{DetectionIntelligence-C4g5DaCG.js → DetectionIntelligence-CzMadCA-.js} +1 -1
- package/dist/assets/{DeviceAggregateSection-H5AVeNJ0.js → DeviceAggregateSection-CbCIksD2.js} +1 -1
- package/dist/assets/{DeviceDetail-CLQTZBsf.js → DeviceDetail-oWNRSfva.js} +1 -1
- package/dist/assets/{Devices-Bp2S4_jq.js → Devices-COMVrlGU.js} +1 -1
- package/dist/assets/{EmbedPlayerPage-DVIbQ9_P.js → EmbedPlayerPage-B4Y1MxZ9.js} +1 -1
- package/dist/assets/Events-BIZWrXMY.js +1 -0
- package/dist/assets/{FormBuilder-B3G6L5El.js → FormBuilder-Cogt0U0A.js} +1 -1
- package/dist/assets/{Identity-D5YIw7nG.js → Identity-i_LhUVHo.js} +1 -1
- package/dist/assets/{IntegrationDetail-Dj2OdD1K.js → IntegrationDetail-CPE4VRwU.js} +1 -1
- package/dist/assets/{Integrations-DZKddVhD.js → Integrations-DhMaG2V3.js} +1 -1
- package/dist/assets/{Integrations-fadRG4Km.js → Integrations-qNIS4emE.js} +1 -1
- package/dist/assets/{Logs-zJNzZ183.js → Logs-rH1aVfpt.js} +1 -1
- package/dist/assets/{MotionZonesSettings-4IW50CRy.js → MotionZonesSettings-DDSnsNc9.js} +1 -1
- package/dist/assets/{MyAccess-CBfHhwSU.js → MyAccess-J8p1dKF3.js} +1 -1
- package/dist/assets/{Network-Dx9MFUR0.js → Network-C6bXHvxd.js} +1 -1
- package/dist/assets/{NodeAddonsSettingsPanel-C2NjwPws.js → NodeAddonsSettingsPanel-6Dzcc5in.js} +1 -1
- package/dist/assets/{NodeInferenceDevices-uPCEdvuj.js → NodeInferenceDevices-DraQNeS_.js} +1 -1
- package/dist/assets/{Notifications-C3Ng_pEz.js → Notifications-BL4Cp1b2.js} +1 -1
- package/dist/assets/{Pipeline-Daj8GJqM.js → Pipeline-Bf8P_Drx.js} +1 -1
- package/dist/assets/{Plates-CdBLHSjv.js → Plates-BkYxLI16.js} +1 -1
- package/dist/assets/{PrivacyMaskSettings-DOgtt7Eb.js → PrivacyMaskSettings-ByZ6t3aH.js} +1 -1
- package/dist/assets/{ProviderIcon-DpSmN8_h.js → ProviderIcon-9BELU-vo.js} +1 -1
- package/dist/assets/{Recordings-5kVeLC44.js → Recordings-OoJn-xbL.js} +1 -1
- package/dist/assets/{ScanNetworkModal-CVNem53G.js → ScanNetworkModal-DGnLpsYA.js} +1 -1
- package/dist/assets/{Settings-Dot1aUpP.js → Settings-DhIPBQcW.js} +1 -1
- package/dist/assets/{Showroom-CE0pD_JA.js → Showroom-C7QnFCQp.js} +1 -1
- package/dist/assets/{Terminal-Jn61QHqq.js → Terminal-DVjWHgq3.js} +1 -1
- 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
- package/dist/assets/{build-cluster-graph-oxCzI_GT.js → build-cluster-graph-BDFGSfk8.js} +1 -1
- package/dist/assets/circle-check-big-DX7P42Tw.js +1 -0
- package/dist/assets/clock-DMJpZrGI.js +1 -0
- package/dist/assets/{copy-BrMo-O0l.js → copy-oDpB_CYv.js} +1 -1
- package/dist/assets/{debounced-invalidate-DCfaNC1r.js → debounced-invalidate-CPxCM-Lt.js} +1 -1
- package/dist/assets/dist-CekX4Hra.js +7 -0
- package/dist/assets/{dist-w7XvHdqJ.js → dist-Dx0ACB1O.js} +1 -1
- package/dist/assets/{download-Bd71YsuA.js → download-c60BtWes.js} +1 -1
- package/dist/assets/{face-bbox-ByAacIlM.js → face-bbox-nkg8OmFa.js} +1 -1
- package/dist/assets/{hostInit-DhSUBWsx.js → hostInit-BpyXzSDR.js} +1 -1
- package/dist/assets/{index-BZA0u2Kc.js → index-2QX2zxyn.js} +3 -3
- package/dist/assets/{key-round-DZL9RdNY.js → key-round-BlSZq_ro.js} +1 -1
- package/dist/assets/{mf-entry-bootstrap-0-28bb7ad2.js → mf-entry-bootstrap-0-3845b4a0.js} +2 -2
- package/dist/assets/{pencil-TjwM9NpS.js → pencil-DUgcFYZU.js} +1 -1
- package/dist/assets/{player-overlays-CkAkhPbQ.js → player-overlays-CzjKRHin.js} +1 -1
- package/dist/assets/plus-C7qYd7DF.js +1 -0
- package/dist/assets/{radio-DOrncLmg.js → radio-eY0YHItP.js} +1 -1
- package/dist/assets/{refresh-cw-BYCB135v.js → refresh-cw-D_fKxMIe.js} +1 -1
- package/dist/assets/remoteEntry-CFMi51wk.js +1 -0
- package/dist/assets/{rotate-ccw-Db_qQ-Qx.js → rotate-ccw-DU4_rBQq.js} +1 -1
- package/dist/assets/rotate-cw-CktlNgLW.js +1 -0
- package/dist/assets/search-CY5Hv7Yv.js +1 -0
- package/dist/assets/{send-CosR7D5R.js → send-B9r8Lohp.js} +1 -1
- package/dist/assets/{server-CUNj6w6P.js → server-BhdxNAPC.js} +1 -1
- package/dist/assets/square-S_5NH0Gl.js +1 -0
- package/dist/assets/{square-check-big-yxLWkS9v.js → square-check-big-DMenPwwp.js} +1 -1
- package/dist/assets/{src-DOXkuCPk.js → src-BBe6PrXe.js} +10 -10
- package/dist/assets/src-DSZBcu6j.js +7 -0
- package/dist/assets/{upload-D0orNbud.js → upload-AwB-upJP.js} +1 -1
- package/dist/assets/{useEventInvalidation-DJ5h5Wvp.js → useEventInvalidation-qhbuBjhg.js} +1 -1
- 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
- package/dist/assets/{wifi-D0ItCC1K.js → wifi-DyeEKGI-.js} +1 -1
- package/dist/assets/{zap-CIK4k9g5.js → zap-C32Ix0E1.js} +1 -1
- package/dist/index.html +5 -5
- package/dist/server/addon.js +361 -12
- package/package.json +1 -1
- package/dist/assets/Events-C_TE39Tm.js +0 -1
- package/dist/assets/circle-check-big-bqZqQn_F.js +0 -1
- package/dist/assets/clock-BxBK96nq.js +0 -1
- package/dist/assets/dist-DPJBx5gf.js +0 -7
- package/dist/assets/plus-BgUAuoLj.js +0 -1
- package/dist/assets/remoteEntry-2xQrocPD.js +0 -1
- package/dist/assets/rotate-cw-vsmRF4Nv.js +0 -1
- package/dist/assets/search-BopXcdUz.js +0 -1
- package/dist/assets/square-C0Uc1Hub.js +0 -1
- package/dist/assets/src-Bh5CQXm7.js +0 -7
package/dist/server/addon.js
CHANGED
|
@@ -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
|
-
*
|
|
14638
|
-
*
|
|
14639
|
-
*
|
|
14640
|
-
* `
|
|
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.
|
|
28765
|
+
getVersion: async () => ({ version: "1.2.34" })
|
|
28417
28766
|
}
|
|
28418
28767
|
}];
|
|
28419
28768
|
}
|
package/package.json
CHANGED
|
@@ -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&<.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};
|