@camstack/addon-admin-ui 1.2.96 → 1.2.98

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 (101) hide show
  1. package/dist/assets/{AddLocationWizard-7HXgNBWJ.js → AddLocationWizard-BH8qzKUS.js} +1 -1
  2. package/dist/assets/{AddonCollectionPage-Tz6pUPgq.js → AddonCollectionPage-DBot-bgj.js} +1 -1
  3. package/dist/assets/{Addons-eviwvm1Q.js → Addons-D9EFNHE1.js} +1 -1
  4. package/dist/assets/{AdminTabs-BacD8YLL.js → AdminTabs-Dk1eLBgE.js} +1 -1
  5. package/dist/assets/{AiProfiles-C66qnr0a.js → AiProfiles-BQ_3LDPD.js} +1 -1
  6. package/dist/assets/{BrokerForm-D2uKDvTb.js → BrokerForm-GsfCv1ks.js} +1 -1
  7. package/dist/assets/{Build-OJqDm99i.js → Build-D3dp29Pc.js} +1 -1
  8. package/dist/assets/{Capabilities-pY76s-il.js → Capabilities-CoYla6oL.js} +1 -1
  9. package/dist/assets/{CapabilityBadges-BJnRgUWh.js → CapabilityBadges-DGA5_XiI.js} +1 -1
  10. package/dist/assets/{Cluster-DDDFrbT4.js → Cluster-DV1zGnLF.js} +1 -1
  11. package/dist/assets/{Data-BUC8oitr.js → Data-zSfgUsc7.js} +1 -1
  12. package/dist/assets/{DetectionIntelligence-BrpoaCw-.js → DetectionIntelligence-aHCL16Cy.js} +1 -1
  13. package/dist/assets/{DeviceAggregateSection-CzBiUH7Q.js → DeviceAggregateSection-BSMvAqDX.js} +1 -1
  14. package/dist/assets/{DeviceDetail-BJaUoh8P.js → DeviceDetail-DH0vN28R.js} +1 -1
  15. package/dist/assets/{Devices-CWvBcb7g.js → Devices-BYXPSPMY.js} +1 -1
  16. package/dist/assets/{EmbedPlayerPage-GCdMVPns.js → EmbedPlayerPage-Chq0wty0.js} +1 -1
  17. package/dist/assets/{Events-vE-EGnK8.js → Events-EROtLWJf.js} +1 -1
  18. package/dist/assets/{FormBuilder-D3fxAgRR.js → FormBuilder-C7GWtsAC.js} +1 -1
  19. package/dist/assets/{Identity-1PvF_DWd.js → Identity-CQZ5NPpO.js} +1 -1
  20. package/dist/assets/{IntegrationDetail-XUrYk1pF.js → IntegrationDetail-CWL7rGIm.js} +1 -1
  21. package/dist/assets/{Integrations-D4-8-Obx.js → Integrations-DAIDYD8x.js} +1 -1
  22. package/dist/assets/{Integrations-DpBQxr0I.js → Integrations-Defjpzw9.js} +1 -1
  23. package/dist/assets/{Logs-DN6_NKF5.js → Logs-DvLobSoL.js} +1 -1
  24. package/dist/assets/{MotionZonesSettings-XMPsARUd.js → MotionZonesSettings-B_MAiEkW.js} +1 -1
  25. package/dist/assets/{MyAccess-CKvI-Z0_.js → MyAccess-Ci2ZSSm5.js} +1 -1
  26. package/dist/assets/{Network-B95UTPbG.js → Network-BovHq3wO.js} +1 -1
  27. package/dist/assets/{NodeAddonsSettingsPanel-Bc7bSbqj.js → NodeAddonsSettingsPanel-kZjm-up8.js} +1 -1
  28. package/dist/assets/{NodeInferenceDevices-BByQ_HIP.js → NodeInferenceDevices-CW1MDnBG.js} +1 -1
  29. package/dist/assets/{Notifications-Bjfo5qwM.js → Notifications-C8I3Vz31.js} +1 -1
  30. package/dist/assets/{Pipeline-1-iGl6tS.js → Pipeline-BBVvpBCd.js} +1 -1
  31. package/dist/assets/Plates-qD8BtBqF.js +1 -0
  32. package/dist/assets/{PrivacyMaskSettings-CHvicgXi.js → PrivacyMaskSettings-axbq_wSU.js} +1 -1
  33. package/dist/assets/{ProviderIcon-BoVzH148.js → ProviderIcon-DllNEady.js} +1 -1
  34. package/dist/assets/{Recordings-D6LJy8Rc.js → Recordings-CzEDQqtj.js} +1 -1
  35. package/dist/assets/{ScanNetworkModal-MOAZa-jX.js → ScanNetworkModal-CW0yYE5R.js} +1 -1
  36. package/dist/assets/{SceneMonitorEditor-x5UklOIZ.js → SceneMonitorEditor-Cq2t8wbg.js} +1 -1
  37. package/dist/assets/{Scenes-DJFUGhWI.js → Scenes-Xn6O5H7e.js} +1 -1
  38. package/dist/assets/{Settings-CtH4Cg4r.js → Settings-D9Vlv2hw.js} +1 -1
  39. package/dist/assets/{Showroom-tGL0F9f_.js → Showroom-Bp6aCuMd.js} +1 -1
  40. package/dist/assets/{Terminal-BJpVPocr.js → Terminal-7vWKE2zb.js} +1 -1
  41. package/dist/assets/{_virtual_mf-localSharedImportMap___mfe_internal__admin_ui_host-DBMO3fsc.js → _virtual_mf-localSharedImportMap___mfe_internal__admin_ui_host-DrOgR36u.js} +1 -1
  42. package/dist/assets/{bell-ring-CzOT6NMB.js → bell-ring-D4Iz5fKj.js} +1 -1
  43. package/dist/assets/{boxes-DswpMqB1.js → boxes-BFsuQuon.js} +1 -1
  44. package/dist/assets/{build-cluster-graph-BrByHTLD.js → build-cluster-graph-Cl_uvOCR.js} +1 -1
  45. package/dist/assets/circle-check-big-HrHc_ipL.js +1 -0
  46. package/dist/assets/{circle-x-DyNv4OyW.js → circle-x-y_k7wCKw.js} +1 -1
  47. package/dist/assets/clock-D2qlcgwd.js +1 -0
  48. package/dist/assets/{copy-FYfDQ47B.js → copy-BrVxemF7.js} +1 -1
  49. package/dist/assets/{debounced-invalidate-BH1sC5jE.js → debounced-invalidate-CNZ2w-7t.js} +1 -1
  50. package/dist/assets/{dist-Co7g7F9h.js → dist-C7L1HtAB.js} +1 -1
  51. package/dist/assets/dist-JjXjac1y.js +349 -0
  52. package/dist/assets/{download-BC5TewX7.js → download-DPw0c0lm.js} +1 -1
  53. package/dist/assets/{face-bbox-Dn6UYckX.js → face-bbox-d1aWGz2s.js} +1 -1
  54. package/dist/assets/{hostInit-BBnsXvqc.js → hostInit-D5R1Qfsh.js} +1 -1
  55. package/dist/assets/{index-CEBJ8eMc.js → index-iNi1Y7nh.js} +3 -3
  56. package/dist/assets/{key-round-WwYx_tWB.js → key-round-fO7JDI-O.js} +1 -1
  57. package/dist/assets/{mf-entry-bootstrap-0-7adc4db4.js → mf-entry-bootstrap-0-f566460e.js} +2 -2
  58. package/dist/assets/{pencil-tOoSQgOe.js → pencil-B4i0ErRE.js} +1 -1
  59. package/dist/assets/play-BxkaaFOu.js +1 -0
  60. package/dist/assets/{player-overlays-DDdfjf3a.js → player-overlays-DLbOIwJR.js} +1 -1
  61. package/dist/assets/plus-DE5rskj6.js +1 -0
  62. package/dist/assets/power-CzV5Z-a_.js +1 -0
  63. package/dist/assets/{radio-DOXhded3.js → radio-CxioeWPp.js} +1 -1
  64. package/dist/assets/{refresh-cw-BUIUPFCx.js → refresh-cw-B8ABC_pB.js} +1 -1
  65. package/dist/assets/remoteEntry-DXwp0vbz.js +1 -0
  66. package/dist/assets/rotate-ccw-CD3wu9ON.js +1 -0
  67. package/dist/assets/rotate-cw-8vMRQVny.js +1 -0
  68. package/dist/assets/search-Dia6mspm.js +1 -0
  69. package/dist/assets/{send-XtWs9fvd.js → send-BqmuTM7o.js} +1 -1
  70. package/dist/assets/{server-mkNfNOY7.js → server-D9l8GGnn.js} +1 -1
  71. package/dist/assets/{shield-CBzh6N_L.js → shield-B_7hlY3B.js} +1 -1
  72. package/dist/assets/square-Cj45Ro71.js +1 -0
  73. package/dist/assets/{square-check-big-Dj6GBQ2z.js → square-check-big-B8iw67nQ.js} +1 -1
  74. package/dist/assets/src-CQrwlltP.js +349 -0
  75. package/dist/assets/{src-BZYWQYID.js → src-UiaZA05p.js} +17 -17
  76. package/dist/assets/{star-DHlHcHTP.js → star-BTw7N-6p.js} +1 -1
  77. package/dist/assets/{undo-2-Cjrq9n-U.js → undo-2-DG5MLTW-.js} +1 -1
  78. package/dist/assets/{upload-BTd5OdKC.js → upload-DAJfnCVB.js} +1 -1
  79. package/dist/assets/{use-scenes-feed-BfWfqf9H.js → use-scenes-feed-B6yeT27i.js} +1 -1
  80. package/dist/assets/useEventInvalidation-D7ElHW62.js +1 -0
  81. package/dist/assets/{video-FO1i6n6W.js → video-D4j_U5zK.js} +1 -1
  82. package/dist/assets/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__admin_ui_host__remoteEntry-_hash_-CQJelRoY.js → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__admin_ui_host__remoteEntry-_hash_-Di4hPkeF.js} +2 -2
  83. package/dist/assets/{wifi-CTIqltCN.js → wifi-BW00qcYq.js} +1 -1
  84. package/dist/assets/{zap-LGSGshyr.js → zap-BSOiEhX4.js} +1 -1
  85. package/dist/index.html +5 -5
  86. package/dist/server/addon.js +103 -27
  87. package/package.json +1 -1
  88. package/dist/assets/Plates-DQWBAsO7.js +0 -1
  89. package/dist/assets/circle-check-big-1XtyEULB.js +0 -1
  90. package/dist/assets/clock-Bj5qhvvB.js +0 -1
  91. package/dist/assets/dist-DNOH5tQa.js +0 -349
  92. package/dist/assets/play-CCCY3IiJ.js +0 -1
  93. package/dist/assets/plus-B3wRoz6c.js +0 -1
  94. package/dist/assets/power-BVqfHLBQ.js +0 -1
  95. package/dist/assets/remoteEntry-Bp_xGqaI.js +0 -1
  96. package/dist/assets/rotate-ccw-DZrozpxW.js +0 -1
  97. package/dist/assets/rotate-cw-CoHNvA24.js +0 -1
  98. package/dist/assets/search-Do5uPwT2.js +0 -1
  99. package/dist/assets/square-BI_w3nhL.js +0 -1
  100. package/dist/assets/src-Ddt6JS34.js +0 -349
  101. package/dist/assets/useEventInvalidation-BSkjRuXC.js +0 -1
@@ -5802,6 +5802,13 @@ var BaseAddon = class {
5802
5802
  _readinessGeneration = typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : Math.random().toString(36).slice(2, 14);
5803
5803
  /** Capability names this addon registered at init — used to emit matching `down` events on shutdown. */
5804
5804
  _registeredCapNames = [];
5805
+ /**
5806
+ * True only after `readAddonStore` actually answered. Constructor
5807
+ * defaults look like stored config when the store is down — a forked
5808
+ * addon that auto-starts from those defaults (cloudflare-tunnel quick
5809
+ * mode, 2026-08-25) is not "the operator chose this".
5810
+ */
5811
+ settingsStoreReady = false;
5805
5812
  /** Default config values. Provided via constructor. */
5806
5813
  defaults;
5807
5814
  constructor(defaults) {
@@ -6202,7 +6209,9 @@ var BaseAddon = class {
6202
6209
  ];
6203
6210
  let lastErr;
6204
6211
  for (let attempt = 0; attempt <= delaysMs.length; attempt++) try {
6205
- return await settings.readAddonStore() ?? {};
6212
+ const stored = await settings.readAddonStore() ?? {};
6213
+ this.settingsStoreReady = true;
6214
+ return stored;
6206
6215
  } catch (err) {
6207
6216
  lastErr = err;
6208
6217
  const msg = err instanceof Error ? err.message : String(err);
@@ -6210,6 +6219,7 @@ var BaseAddon = class {
6210
6219
  if (attempt === delaysMs.length) break;
6211
6220
  await new Promise((r) => setTimeout(r, delaysMs[attempt]));
6212
6221
  }
6222
+ this.settingsStoreReady = false;
6213
6223
  this._ctx?.logger?.warn?.("readAddonStore: settings-store unavailable after retries — using defaults", { meta: { error: lastErr instanceof Error ? lastErr.message : String(lastErr) } });
6214
6224
  return {};
6215
6225
  }
@@ -11742,6 +11752,27 @@ var LinkedDeviceSchema = object({
11742
11752
  features: array(string()),
11743
11753
  producesTrackedEvents: boolean().optional()
11744
11754
  });
11755
+ /** One camera's resolved linked set, tagged with the camera it belongs to.
11756
+ * The batch answer needs the tag; the single-device answer already has it
11757
+ * from the input, which is why `getLinkedDevices` keeps the untagged shape. */
11758
+ var LinkedDevicesForDeviceSchema = object({
11759
+ deviceId: number(),
11760
+ mode: LinkedDevicesModeSchema,
11761
+ devices: array(LinkedDeviceSchema)
11762
+ });
11763
+ /** One device's binding map — the shape `getBindings`, `getBindingsBatch` and
11764
+ * `getAllBindings` all answer in. Declared once: three copies of the same
11765
+ * object literal is exactly how the three drift apart. */
11766
+ var DeviceBindingsForDeviceSchema = object({
11767
+ deviceId: number(),
11768
+ entries: array(object({
11769
+ capName: string(),
11770
+ kind: _enum(["native", "wrapped"]),
11771
+ providerAddonId: string(),
11772
+ providerNodeId: string(),
11773
+ nativeAddonId: string()
11774
+ }))
11775
+ });
11745
11776
  var SavedDeviceRowSchema = object({
11746
11777
  /** Numeric id reserved at allocateDeviceId time. */
11747
11778
  id: number(),
@@ -11967,11 +11998,25 @@ method(object({
11967
11998
  projection: _enum(["full", "slim"]).optional(),
11968
11999
  /** Return only camera devices. Filtering server-side instead of
11969
12000
  * shipping 293 rows to find 12. */
11970
- isCamera: boolean().optional()
12001
+ isCamera: boolean().optional(),
12002
+ /**
12003
+ * Return only these device ids. For the caller that already KNOWS the
12004
+ * handful it wants and needs a field the id-bearing answer does not
12005
+ * carry — the viewer's linked-devices panel joins `type` and `online`
12006
+ * onto ~8 linked ids and, unfiltered, dragged the fleet across to do
12007
+ * it: 433 KB slim / 958 KB full for 967 devices, on a query that
12008
+ * refetches on the reconcile interval, on a phone.
12009
+ *
12010
+ * Safe to send at a hub that predates it: Zod STRIPS unknown input
12011
+ * keys rather than rejecting them (verified against the live hub
12012
+ * 2026-08-25 — 967 rows came back), so an old hub answers exactly what
12013
+ * it answers today and the caller filters as it already does.
12014
+ */
12015
+ deviceIds: array(number()).optional()
11971
12016
  }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), DeviceInfoSchema.nullable()), method(object({ parentDeviceId: number() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), object({
11972
12017
  mode: LinkedDevicesModeSchema,
11973
12018
  devices: array(LinkedDeviceSchema)
11974
- })), method(object({ deviceId: number() }), array(StreamSourceEntrySchema$1)), method(object({ deviceId: number() }), array(ConfigEntrySchema)), method(object({ deviceId: number() }), ConfigUISchemaOutput), method(object({
12019
+ })), method(object({ deviceIds: array(number()) }), array(LinkedDevicesForDeviceSchema)), method(object({ deviceId: number() }), array(StreamSourceEntrySchema$1)), method(object({ deviceId: number() }), array(ConfigEntrySchema)), method(object({ deviceId: number() }), ConfigUISchemaOutput), method(object({
11975
12020
  deviceId: number(),
11976
12021
  values: record(string(), unknown())
11977
12022
  }), object({ success: literal(true) }), {
@@ -11998,25 +12043,7 @@ method(object({
11998
12043
  }), method(object({ deviceId: number() }), array(StreamProbeResultSchema), {
11999
12044
  kind: "mutation",
12000
12045
  auth: "admin"
12001
- }), method(object({ deviceId: number() }), object({
12002
- deviceId: number(),
12003
- entries: array(object({
12004
- capName: string(),
12005
- kind: _enum(["native", "wrapped"]),
12006
- providerAddonId: string(),
12007
- providerNodeId: string(),
12008
- nativeAddonId: string()
12009
- }))
12010
- })), method(object({}), array(object({
12011
- deviceId: number(),
12012
- entries: array(object({
12013
- capName: string(),
12014
- kind: _enum(["native", "wrapped"]),
12015
- providerAddonId: string(),
12016
- providerNodeId: string(),
12017
- nativeAddonId: string()
12018
- }))
12019
- }))), method(object({
12046
+ }), method(object({ deviceId: number() }), DeviceBindingsForDeviceSchema), method(object({ deviceIds: array(number()) }), array(DeviceBindingsForDeviceSchema)), method(object({}), array(DeviceBindingsForDeviceSchema)), method(object({
12020
12047
  deviceId: number(),
12021
12048
  capName: string(),
12022
12049
  wrapperAddonId: string(),
@@ -23975,8 +24002,10 @@ var PlateInfoSchema = object({
23975
24002
  keyFrameMediaKey: string().optional(),
23976
24003
  base64: string().optional(),
23977
24004
  /**
23978
- * Same crop as a data-plane URL. `getPlateByTrack` returns this and
23979
- * never inlines JPEG; `listPlates` still inlines for the admin-ui.
24005
+ * Same crop as a data-plane URL, always present when the plate has a stored
24006
+ * crop. `getPlateByTrack` returns this and never inlines JPEG; `listPlates`
24007
+ * and `searchPlates` inline the crop only when their `includeCrops` input is
24008
+ * left at its `true` default.
23980
24009
  */
23981
24010
  cropUrl: string().optional()
23982
24011
  });
@@ -23996,14 +24025,34 @@ var PlateClusterSchema = object({
23996
24025
  });
23997
24026
  method(object({
23998
24027
  deviceId: number().int().optional(),
23999
- limit: number().int().positive().optional()
24028
+ limit: number().int().positive().optional(),
24029
+ /**
24030
+ * Inline the base64 crop on every row. Default `true` — the existing
24031
+ * behaviour, kept so no caller breaks.
24032
+ *
24033
+ * Set `false` once the caller renders {@link PlateInfo.cropUrl}.
24034
+ * Measured on the live hub at the 500 rows the Plates view asks for:
24035
+ * 879,403 B and 27.7 s with the crops inline, against a few KiB of
24036
+ * metadata without them — and the browser then caches the images.
24037
+ *
24038
+ * This is the plate twin of `faceGallery.listRecentFaces`'s option;
24039
+ * plates were the one gallery list left without it.
24040
+ *
24041
+ * **This is an INPUT field, so it does not reach the addon until the
24042
+ * next train.** The hub router validates cap inputs against its own
24043
+ * compiled Zod and strips a key it does not know. Until the train
24044
+ * ships, sending `false` is harmless and keeps the crops inline.
24045
+ */
24046
+ includeCrops: boolean().optional()
24000
24047
  }).optional(), array(PlateInfoSchema).readonly()), method(object({
24001
24048
  deviceId: number().int(),
24002
24049
  trackId: string()
24003
24050
  }), PlateInfoSchema.nullable()), method(object({ plateId: string() }), array(MediaFileLiteSchema).readonly()), method(object({
24004
24051
  text: string().min(1),
24005
24052
  maxDistance: number().int().min(0).optional(),
24006
- limit: number().int().positive().optional()
24053
+ limit: number().int().positive().optional(),
24054
+ /** See `listPlates.includeCrops`. Default `true`. */
24055
+ includeCrops: boolean().optional()
24007
24056
  }), array(PlateInfoSchema).readonly()), method(object({
24008
24057
  maxDistance: number().int().min(0).optional(),
24009
24058
  minClusterSize: number().int().min(2).optional(),
@@ -27618,6 +27667,12 @@ Object.freeze({
27618
27667
  addonId: null,
27619
27668
  access: "view"
27620
27669
  },
27670
+ "deviceManager.getBindingsBatch": {
27671
+ capName: "device-manager",
27672
+ capScope: "system",
27673
+ addonId: null,
27674
+ access: "view"
27675
+ },
27621
27676
  "deviceManager.getChildren": {
27622
27677
  capName: "device-manager",
27623
27678
  capScope: "system",
@@ -27678,6 +27733,12 @@ Object.freeze({
27678
27733
  addonId: null,
27679
27734
  access: "view"
27680
27735
  },
27736
+ "deviceManager.getLinkedDevicesBatch": {
27737
+ capName: "device-manager",
27738
+ capScope: "system",
27739
+ addonId: null,
27740
+ access: "view"
27741
+ },
27681
27742
  "deviceManager.getRoleDisplayDefaults": {
27682
27743
  capName: "device-manager",
27683
27744
  capScope: "system",
@@ -32325,6 +32386,11 @@ Object.freeze({
32325
32386
  form: "single",
32326
32387
  optional: false
32327
32388
  }],
32389
+ "deviceManager.getBindingsBatch": [{
32390
+ name: "deviceIds",
32391
+ form: "array",
32392
+ optional: false
32393
+ }],
32328
32394
  "deviceManager.getChildren": [{
32329
32395
  name: "parentDeviceId",
32330
32396
  form: "single",
@@ -32370,6 +32436,11 @@ Object.freeze({
32370
32436
  form: "single",
32371
32437
  optional: false
32372
32438
  }],
32439
+ "deviceManager.getLinkedDevicesBatch": [{
32440
+ name: "deviceIds",
32441
+ form: "array",
32442
+ optional: false
32443
+ }],
32373
32444
  "deviceManager.getSettingsSchema": [{
32374
32445
  name: "deviceId",
32375
32446
  form: "single",
@@ -32390,6 +32461,11 @@ Object.freeze({
32390
32461
  form: "single",
32391
32462
  optional: false
32392
32463
  }],
32464
+ "deviceManager.listAll": [{
32465
+ name: "deviceIds",
32466
+ form: "array",
32467
+ optional: true
32468
+ }],
32393
32469
  "deviceManager.loadConfig": [{
32394
32470
  name: "deviceId",
32395
32471
  form: "single",
@@ -34242,7 +34318,7 @@ var AdminUIAddon = class extends BaseAddon {
34242
34318
  capability: adminUiCapability,
34243
34319
  provider: {
34244
34320
  getStaticDir: async () => ({ staticDir: resolveAdminUiDistDir() }),
34245
- getVersion: async () => ({ version: "1.2.96" })
34321
+ getVersion: async () => ({ version: "1.2.98" })
34246
34322
  }
34247
34323
  }];
34248
34324
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-admin-ui",
3
- "version": "1.2.96",
3
+ "version": "1.2.98",
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{K as e,Q as t,S as n,W as r,b as i,o as a,q as o,x as s,z as c}from"./_virtual_mf___mfe_internal__admin_ui_host__loadShare___mf_0_tanstack_mf_1_react_mf_2_query__loadShare__.js-DhP-Lgiq.js";import{At as l,Br as u,Co as d,Dt as f,Et as p,Fs as m,It as h,Lt as g,Ot as _,Pt as v,So as y,_o as b,bo as x,fo as S,go as C,ho as w,kt as T,mo as E,po as D,vo as O,wo as k,wt as A,xo as j,yo as M}from"./src-BZYWQYID.js";import{Rt as N}from"./src-Ddt6JS34.js";import{a as P,i as ee,n as F,r as I,t as L}from"./face-bbox-Dn6UYckX.js";import{a as R,c as z,f as B,i as te,l as ne,m as V,n as H,o as re,p as ie,r as U,s as ae,t as W,u as oe}from"./debounced-invalidate-BH1sC5jE.js";import{t as G}from"./pencil-tOoSQgOe.js";import{t as K}from"./plus-B3wRoz6c.js";import{t as se}from"./square-check-big-Dj6GBQ2z.js";import{t as q}from"./square-BI_w3nhL.js";import{B as J,C as Y,I as ce,K as le,R as ue,i as X,s as Z,z as de}from"./index-CEBJ8eMc.js";import{t as fe}from"./AdminPage-CCD07UMs.js";import{r as pe,t as me}from"./authed-media-BPd_L9jr.js";var he=le(`badge-check`,[[`path`,{d:`M3.85 8.62a4 4 0 0 1 4.78-4.77 4 4 0 0 1 6.74 0 4 4 0 0 1 4.78 4.78 4 4 0 0 1 0 6.74 4 4 0 0 1-4.77 4.78 4 4 0 0 1-6.75 0 4 4 0 0 1-4.78-4.77 4 4 0 0 1 0-6.76Z`,key:`3c2336`}],[`path`,{d:`m9 12 2 2 4-4`,key:`dzmm74`}]]);t();var Q=[[`plateGallery`]];function ge({vehicleId:e}){let t=a(),{data:r,isLoading:i}=M({vehicleId:e}),o=j();function c(n){o.mutate({vehicleId:e,sampleId:n.id},{onSettled:()=>{t.invalidateQueries({queryKey:Q})}})}return i?n(`div`,{className:`flex items-center gap-2 py-3 text-xs text-foreground-subtle`,children:[s(Y,{className:`h-3.5 w-3.5 animate-spin`}),`Loading plates…`]}):!r||r.length===0?s(`p`,{className:`py-2 text-xs text-foreground-subtle`,children:`No plates yet.`}):s(`div`,{className:`mt-2 grid grid-cols-3 gap-2 sm:grid-cols-4 md:grid-cols-6`,children:r.map(e=>n(`div`,{className:`group relative overflow-hidden rounded-md border border-border bg-surface`,children:[n(`div`,{className:`relative aspect-[2/1] overflow-hidden bg-surface-hover`,children:[e.base64?s(`img`,{src:`data:image/jpeg;base64,${e.base64}`,alt:e.text,className:`h-full w-full object-cover`}):s(`div`,{className:`flex h-full w-full items-center justify-center text-foreground-subtle`,children:s(J,{className:`h-6 w-6`})}),s(`button`,{type:`button`,onClick:()=>c(e),disabled:o.isPending,className:`absolute inset-0 flex items-center justify-center bg-black/50 opacity-0 transition-opacity group-hover:opacity-100 disabled:cursor-not-allowed`,"aria-label":`Remove plate sample`,children:s(X,{className:`h-4 w-4 text-white`})})]}),s(`p`,{className:`truncate px-1.5 py-1 text-center font-mono text-[11px] font-semibold tracking-wide text-foreground`,title:e.text,children:e.text})]},e.id))})}function _e({vehicle:e,expanded:t,onToggle:r}){let c=a(),[u,d]=o(``),[m,b]=o(!1),[x,S]=o(!1),w=y(),E=C();function D(){d(e.name),b(!0)}function O(){b(!1),d(``)}function k(){let t=u.trim();if(!t||t===e.name){O();return}w.mutate({id:e.id,name:t},{onSettled:()=>{c.invalidateQueries({queryKey:Q}),O()}})}function j(){E.mutate({id:e.id},{onSettled:()=>{c.invalidateQueries({queryKey:Q}),S(!1)}})}return n(`div`,{className:`rounded-md border border-border bg-surface`,children:[n(`div`,{className:`flex items-center gap-2 px-3 py-2`,children:[s(`div`,{className:`h-8 w-12 shrink-0 overflow-hidden rounded border border-border bg-surface-hover`,children:e.coverBase64?s(`img`,{src:`data:image/jpeg;base64,${e.coverBase64}`,alt:e.name,className:`h-full w-full object-cover`}):s(`div`,{className:`flex h-full w-full items-center justify-center`,children:s(J,{className:`h-4 w-4 text-foreground-subtle`})})}),s(`div`,{className:`flex flex-1 min-w-0 items-center gap-2`,children:m?n(i,{children:[s(v,{value:u,onChange:e=>d(e.target.value),onKeyDown:e=>{e.key===`Enter`&&k(),e.key===`Escape`&&O()},className:`h-6 text-xs`,autoFocus:!0}),s(`button`,{type:`button`,onClick:k,disabled:w.isPending,className:`text-success hover:text-success/80 disabled:opacity-50`,"aria-label":`Confirm rename`,children:s(de,{className:`h-3.5 w-3.5`})}),s(`button`,{type:`button`,onClick:O,className:`text-foreground-subtle hover:text-foreground`,"aria-label":`Cancel rename`,children:s(X,{className:`h-3.5 w-3.5`})})]}):s(`span`,{className:`truncate text-sm font-medium text-foreground`,children:e.name})}),s(h,{variant:`default`,className:`text-[10px]`,children:e.sampleCount}),!m&&n(`div`,{className:`flex items-center gap-1`,children:[s(`button`,{type:`button`,onClick:D,className:`p-1 rounded hover:bg-surface-hover text-foreground-subtle hover:text-foreground`,"aria-label":`Rename`,children:s(G,{className:`h-3.5 w-3.5`})}),s(`button`,{type:`button`,onClick:()=>S(!0),className:`p-1 rounded hover:bg-danger/10 text-foreground-subtle hover:text-danger`,"aria-label":`Delete`,children:s(Z,{className:`h-3.5 w-3.5`})})]}),s(`button`,{type:`button`,onClick:r,className:`p-1 rounded hover:bg-surface-hover text-foreground-subtle`,"aria-label":t?`Collapse`:`Expand`,children:s(t?ue:ce,{className:`h-3.5 w-3.5`})})]}),t&&s(`div`,{className:`border-t border-border px-3 pb-3 pt-2`,children:s(ge,{vehicleId:e.id})}),s(A,{open:x,onOpenChange:e=>!e&&S(!1),children:n(p,{children:[n(T,{children:[s(l,{children:`Delete vehicle`}),n(f,{children:[`Delete `,s(`strong`,{children:e.name}),` and all its plate samples? This cannot be undone.`]})]}),n(_,{children:[s(g,{variant:`secondary`,onClick:()=>S(!1),children:`Cancel`}),n(g,{variant:`danger`,onClick:j,disabled:E.isPending,children:[E.isPending?s(Y,{className:`h-3.5 w-3.5 animate-spin`}):null,`Delete`]})]})]})})]})}function ve(){let e=a(),[t,r]=o(``),i=E();function c(){let n=t.trim();n&&i.mutate({name:n},{onSettled:()=>{e.invalidateQueries({queryKey:Q}),r(``)}})}return n(`div`,{className:`flex items-center gap-2 pt-2`,children:[s(v,{placeholder:`New vehicle name…`,value:t,onChange:e=>r(e.target.value),onKeyDown:e=>{e.key===`Enter`&&c()},className:`h-7 text-xs flex-1`}),n(g,{variant:`primary`,size:`sm`,onClick:c,disabled:i.isPending||!t.trim(),children:[i.isPending?s(Y,{className:`h-3.5 w-3.5 animate-spin`}):s(K,{className:`h-3.5 w-3.5`}),`Add`]})]})}function ye(){let{data:e,isLoading:t}=x(),[r,i]=o(null);function a(e){i(t=>t===e?null:e)}return t?n(`div`,{className:`flex items-center gap-2 py-4 text-xs text-foreground-subtle`,children:[s(Y,{className:`h-4 w-4 animate-spin`}),`Loading vehicles…`]}):n(`div`,{className:`space-y-2`,children:[(!e||e.length===0)&&s(`p`,{className:`py-2 text-xs text-foreground-subtle`,children:`No vehicles enrolled yet. Add one below.`}),e?.map(e=>s(_e,{vehicle:e,expanded:r===e.id,onToggle:()=>a(e.id)},e.id)),s(ve,{})]})}t();var be=[[`plateGallery`]];function xe(e){let[t,n]=o(null),[r,i]=o(null),[a,s]=o(!1);return c(()=>{if(n(null),i(null),s(!1),!e)return;let t=!1,r=null;return(async()=>{try{let i=await pe(`${me}/${encodeURIComponent(e)}`);if(t)return;r=URL.createObjectURL(i),n(r)}catch{t||s(!0)}})(),()=>{t=!0,r&&URL.revokeObjectURL(r)}},[e]),c(()=>{if(!t)return;let e=new Image;return e.onload=()=>i({width:e.naturalWidth,height:e.naturalHeight}),e.onerror=()=>s(!0),e.src=t,()=>{e.onload=null,e.onerror=null}},[t]),{frameSrc:t,naturalWidth:r?.width??null,naturalHeight:r?.height??null,failed:a}}function Se(e){let t=e.filter(e=>e.base64.length>0);return t.length===0?null:t.find(e=>/crop|plate/i.test(e.kind))??t[0]}function $({label:e,value:t,mono:r}){return n(`div`,{className:`flex items-baseline justify-between gap-3 py-1.5 border-b border-border/60 last:border-0`,children:[s(`span`,{className:`shrink-0 text-[11px] uppercase tracking-wide text-foreground-subtle`,children:e}),s(`span`,{className:`min-w-0 truncate text-right text-xs font-medium text-foreground ${r?`font-mono`:``}`,title:t,children:t})]})}function Ce({box:e}){return s(`div`,{className:`pointer-events-none absolute rounded-[3px] border-2 border-primary shadow-[0_0_0_9999px_rgba(0,0,0,0.28)]`,style:{left:`${String(e.x*100)}%`,top:`${String(e.y*100)}%`,width:`${String(e.width*100)}%`,height:`${String(e.height*100)}%`},children:s(`span`,{className:`absolute -top-4 left-0 rounded bg-primary px-1 text-[9px] font-semibold uppercase tracking-wide text-white`,children:`Plate`})})}function we({plate:e,cameraName:t,onClose:i,onAssign:l,onUnassign:u,onDelete:d,actionsPending:f}){let m=a(),{data:h,isFetching:_}=b({plateId:e?.plateId??``},{enabled:e!==null}),y=D(),[x,S]=o(`frame`),[C,w]=o(!1),[T,E]=o(``),{frameSrc:O,naturalWidth:k,naturalHeight:j,failed:M}=xe(e?.keyFrameMediaKey);c(()=>{w(!1),E(``),S(`frame`)},[e?.plateId]);let N=r(()=>{let t=Se(h??[]);return t?`data:image/jpeg;base64,${t.base64}`:e?.base64?`data:image/jpeg;base64,${e.base64}`:null},[h,e]),R=r(()=>!e?.plateBbox||k===null||j===null?null:L(e.plateBbox,k,j),[e?.plateBbox,k,j]);if(e===null)return null;let z=typeof e.keyFrameMediaKey==`string`&&e.keyFrameMediaKey.length>0&&!M,B=z&&x===`frame`,te=e.assigned?e.vehicleName??`Assigned`:e.recognizedVehicleId?`${e.vehicleName??`Recognized`} (suggested)`:`Unassigned`,ne=`${String(Math.round(e.score*100))}%${e.corrected?` · corrected`:``}`;function re(){e&&(E(e.text),w(!0))}function U(){if(!e)return;let t=T.trim().toUpperCase();if(!t||t===e.text){w(!1);return}y.mutate({plateId:e.plateId,text:t},{onSettled:()=>{m.invalidateQueries({queryKey:be}),w(!1)}})}return s(A,{open:!0,onOpenChange:e=>!e&&i(),children:n(p,{width:`lg`,placement:`sheet-on-mobile`,"aria-label":`Plate 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:[n(`header`,{className:`flex shrink-0 items-start justify-between gap-2 border-b border-border px-4 py-3`,children:[n(`div`,{className:`min-w-0`,children:[s(`div`,{className:`truncate font-mono text-sm font-semibold tracking-wide text-foreground`,children:e.text||`Plate detail`}),s(`div`,{className:`mt-0.5 truncate text-[11px] text-foreground-subtle`,children:t})]}),s(`button`,{type:`button`,onClick:i,className:`rounded p-1 text-foreground-subtle hover:bg-surface-hover hover:text-foreground`,"aria-label":`Close`,children:s(X,{className:`h-4 w-4`})})]}),n(`div`,{className:`min-h-0 flex-1 space-y-3 overflow-y-auto overscroll-contain px-4 py-3`,children:[z&&n(`div`,{className:`flex items-center gap-1 rounded-md border border-border p-0.5 text-xs`,children:[n(`button`,{type:`button`,onClick:()=>S(`frame`),className:`flex flex-1 items-center justify-center gap-1 rounded px-2 py-1 transition-colors ${x===`frame`?`bg-primary/12 font-medium text-primary`:`text-foreground-subtle hover:bg-surface-hover hover:text-foreground`}`,children:[s(ee,{className:`h-3.5 w-3.5`}),` Full frame`]}),n(`button`,{type:`button`,onClick:()=>S(`crop`),className:`flex flex-1 items-center justify-center gap-1 rounded px-2 py-1 transition-colors ${x===`crop`?`bg-primary/12 font-medium text-primary`:`text-foreground-subtle hover:bg-surface-hover hover:text-foreground`}`,children:[s(P,{className:`h-3.5 w-3.5`}),` Crop`]})]}),B&&O?s(`div`,{className:`overflow-hidden rounded-lg border border-border bg-background`,children:s(H,{src:O,alt:`Full frame with detected plate`,fit:`natural`,className:`w-full`,overlay:R?s(Ce,{box:R}):void 0})}):N?n(`div`,{className:`relative aspect-[2/1] w-full overflow-hidden rounded-lg border border-border bg-background`,children:[s(H,{src:N,alt:`Detected plate`,className:`h-full w-full`}),_&&s(`div`,{className:`absolute right-2 top-2 rounded-full bg-black/50 p-1 text-white`,children:s(Y,{className:`h-3.5 w-3.5 animate-spin`})})]}):n(`div`,{className:`flex aspect-[2/1] w-full flex-col items-center justify-center gap-1.5 rounded-lg border border-border bg-warning/5 text-foreground-subtle`,children:[s(V,{className:`h-8 w-8 text-warning/70`}),s(`span`,{className:`text-[11px] font-medium uppercase tracking-wide text-warning/80`,children:`No image`}),s(`span`,{className:`px-6 text-center text-[10px] text-foreground-subtle`,children:`The crop media for this plate could not be resolved. Safe to delete.`})]}),s(`div`,{className:`rounded-lg border border-border bg-surface px-3 py-2`,children:n(`div`,{className:`flex items-center justify-between gap-3`,children:[s(`span`,{className:`shrink-0 text-[11px] uppercase tracking-wide text-foreground-subtle`,children:`Plate text`}),C?n(`div`,{className:`flex min-w-0 flex-1 items-center justify-end gap-1.5`,children:[s(v,{value:T,onChange:e=>E(e.target.value),onKeyDown:e=>{e.key===`Enter`&&U(),e.key===`Escape`&&w(!1)},className:`h-7 max-w-[10rem] text-right font-mono text-xs uppercase`,autoFocus:!0}),s(`button`,{type:`button`,onClick:U,disabled:y.isPending,className:`text-success hover:text-success/80 disabled:opacity-50`,"aria-label":`Save corrected text`,children:y.isPending?s(Y,{className:`h-3.5 w-3.5 animate-spin`}):s(de,{className:`h-3.5 w-3.5`})}),s(`button`,{type:`button`,onClick:()=>w(!1),className:`text-foreground-subtle hover:text-foreground`,"aria-label":`Cancel`,children:s(X,{className:`h-3.5 w-3.5`})})]}):n(`button`,{type:`button`,onClick:re,className:`group flex min-w-0 items-center gap-1.5`,title:`Correct the OCR reading`,children:[s(`span`,{className:`truncate font-mono text-sm font-semibold tracking-wide text-foreground`,children:e.text||`—`}),s(G,{className:`h-3 w-3 shrink-0 text-foreground-subtle group-hover:text-foreground`})]})]})}),n(`div`,{className:`rounded-lg border border-border bg-surface px-3 py-1`,children:[s($,{label:`Camera`,value:t}),s($,{label:`Captured`,value:ie(e.timestamp)}),s($,{label:`Confidence`,value:ne}),s($,{label:`Vehicle`,value:te}),s($,{label:`Track`,value:e.trackId,mono:!0})]})]}),n(`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:[e.assigned?n(g,{variant:`secondary`,onClick:()=>u(e.plateId),disabled:f,children:[s(F,{className:`h-3.5 w-3.5`}),` Detach`]}):n(g,{variant:`primary`,onClick:()=>l(e.plateId),disabled:f,children:[s(I,{className:`h-3.5 w-3.5`}),` Assign`]}),n(g,{variant:`secondary`,onClick:()=>d(e.plateId),disabled:f,children:[s(Z,{className:`h-3.5 w-3.5`}),` Delete`]})]})]})})}t();var Te=[[`plateGallery`]];function Ee({plateIds:e,vehicles:t,onDone:r}){let i=a(),c=S(),u=E(),[d,m]=o(``),[h,y]=o(!1),[b,x]=o(null),C=e!==null&&e.length>0,w=e?.length??0;function D(){y(!1),m(``),x(null)}function O(){D(),r()}function k(t){!e||e.length===0||c.mutate({plateIds:[...e],vehicleId:t},{onSettled:()=>{i.invalidateQueries({queryKey:Te}),O()}})}function j(){!e||!d.trim()||u.mutate({name:d.trim()},{onSuccess:e=>{e?.id&&k(e.id)},onError:()=>{i.invalidateQueries({queryKey:Te}),O()}})}let M=c.isPending||u.isPending;return s(A,{open:C,onOpenChange:e=>!e&&O(),children:n(p,{children:[n(T,{children:[s(l,{children:w>1?`Assign ${String(w)} plates to vehicle`:`Assign plate to vehicle`}),s(f,{children:`Select an existing vehicle or create a new one.`})]}),s(`div`,{className:`space-y-1 max-h-56 overflow-y-auto`,children:t.map(e=>n(`button`,{type:`button`,onClick:()=>x(e.id),className:`w-full rounded-md px-3 py-2 text-left text-xs transition-colors ${b===e.id?`bg-primary/12 text-primary`:`hover:bg-surface-hover text-foreground`}`,children:[s(`span`,{className:`font-medium`,children:e.name}),n(`span`,{className:`ml-2 text-foreground-subtle`,children:[e.sampleCount,` plates`]})]},e.id))}),h?s(`div`,{className:`flex items-center gap-2 pt-2 border-t border-border`,children:s(v,{placeholder:`New vehicle name…`,value:d,onChange:e=>m(e.target.value),onKeyDown:e=>{e.key===`Enter`&&j()},autoFocus:!0,className:`flex-1`})}):s(`button`,{type:`button`,onClick:()=>{x(null),y(!0)},className:`mt-2 w-full rounded-md border border-dashed border-border px-3 py-2 text-left text-xs text-foreground-subtle hover:border-primary hover:text-primary transition-colors`,children:`+ New vehicle…`}),n(_,{children:[s(g,{variant:`secondary`,onClick:O,disabled:M,children:`Cancel`}),h?n(g,{variant:`primary`,onClick:j,disabled:M||!d.trim(),children:[M&&s(Y,{className:`h-3.5 w-3.5 animate-spin`}),`Create & assign`]}):n(g,{variant:`primary`,onClick:()=>b&&k(b),disabled:M||!b,children:[M&&s(Y,{className:`h-3.5 w-3.5 animate-spin`}),`Assign`,w>1?` ${String(w)}`:``]})]})]})})}t();var De=[[`plateGallery`]],Oe=500,ke=120;function Ae({plate:e,cameraName:t,nowMs:r,selected:i,onToggleSelect:o,onAssign:c,onOpenDetail:l}){let u=a(),f=d(),p=w(),m=()=>{u.invalidateQueries({queryKey:De})},h=()=>l(e.plateId);return n(`div`,{className:`relative flex flex-col overflow-hidden rounded-md border bg-surface ${i?`border-primary ring-1 ring-primary`:`border-border`}`,children:[n(`div`,{className:`relative aspect-[2/1] overflow-hidden bg-surface-hover`,children:[e.base64?s(`img`,{src:`data:image/jpeg;base64,${e.base64}`,alt:`Plate ${e.text} from ${t}`,onClick:h,className:`h-full w-full cursor-zoom-in object-cover`}):n(`button`,{type:`button`,onClick:h,className:`flex h-full w-full flex-col items-center justify-center gap-1 bg-warning/5 text-foreground-subtle`,title:`No crop image — the plate's crop media is missing. Safe to delete.`,children:[s(V,{className:`h-7 w-7 text-warning/70`}),s(`span`,{className:`text-[9px] font-medium uppercase tracking-wide text-warning/80`,children:`No crop`})]}),s(`button`,{type:`button`,onClick:t=>{t.stopPropagation(),o(e.plateId)},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?s(se,{className:`h-4 w-4 text-primary`}):s(q,{className:`h-4 w-4`})}),e.corrected&&n(`span`,{className:`absolute right-0 top-0 z-10 flex items-center gap-0.5 rounded-bl-md bg-primary/80 px-1 py-0.5 text-[8px] font-semibold uppercase tracking-wide text-white`,title:`Manually corrected`,children:[s(he,{className:`h-3 w-3`}),` Fixed`]})]}),n(`div`,{className:`min-w-0 px-2 pt-1.5 space-y-0.5`,children:[s(`p`,{className:`truncate font-mono text-xs font-bold tracking-wide text-foreground`,title:e.text,children:e.text||`—`}),s(`p`,{className:`truncate text-[10px] text-foreground-subtle`,title:t,children:t}),s(`p`,{className:`truncate text-[10px] text-foreground-subtle`,children:B(e.timestamp,r)}),e.vehicleName&&s(`p`,{className:`truncate text-[10px] font-medium text-primary`,title:e.vehicleName,children:e.vehicleName})]}),n(`div`,{className:`mt-1 flex items-center gap-0.5 border-t border-border/60 px-1 py-0.5`,children:[e.assigned?s(`button`,{type:`button`,onClick:t=>{t.stopPropagation(),f.mutate({plateId:e.plateId},{onSettled:m})},disabled:f.isPending,className:`rounded p-1.5 text-foreground-subtle transition-colors hover:bg-warning/10 hover:text-warning disabled:opacity-40`,"aria-label":`Detach plate`,title:`Detach`,children:f.isPending?s(Y,{className:`h-4 w-4 animate-spin`}):s(F,{className:`h-4 w-4`})}):s(`button`,{type:`button`,onClick:t=>{t.stopPropagation(),c(e.plateId)},className:`rounded p-1.5 text-foreground-subtle transition-colors hover:bg-primary/10 hover:text-primary`,"aria-label":`Assign plate to vehicle`,title:`Assign to vehicle`,children:s(I,{className:`h-4 w-4`})}),s(`button`,{type:`button`,onClick:t=>{t.stopPropagation(),p.mutate({plateId:e.plateId},{onSettled:m})},disabled:p.isPending,className:`ml-auto rounded p-1.5 text-foreground-subtle transition-colors hover:bg-danger/10 hover:text-danger disabled:opacity-40`,"aria-label":`Delete plate`,title:`Delete plate`,children:p.isPending?s(Y,{className:`h-4 w-4 animate-spin`}):s(Z,{className:`h-4 w-4`})})]})]})}var je=[{label:`All`,value:`all`},{label:`Unassigned`,value:`unassigned`},{label:`Assigned`,value:`assigned`}];function Me(e,t){return t===`unassigned`?e.filter(e=>!e.assigned):t===`assigned`?e.filter(e=>e.assigned):e}function Ne(){let e=a(),[t,c]=o(`all`),[l,f]=o(ae),[p,m]=o(new Set),[h,_]=o(new Set),[v,y]=o(null),[b,S]=o(null),{data:C,isLoading:T}=O({limit:Oe},{refetchInterval:3e4}),{data:E=[]}=x(),{data:D}=u({}),A=d(),j=k(),M=w(),N=Date.now(),P=C??[],ee=r(()=>{let e=new Map;for(let t of D??[])e.set(t.id,t.name);return e},[D]),L=e=>ee.get(e)??`Camera #${String(e)}`,B=r(()=>z(P).map(e=>({id:e,name:L(e)})).sort((e,t)=>e.name.localeCompare(t.name)),[P,ee]),V=r(()=>ne(oe(Me(P,t),l),p),[P,t,l,p]),H=re(V,ke,r(()=>JSON.stringify([t,l.fromMs,l.toMs,[...p].sort((e,t)=>e-t)]),[t,l.fromMs,l.toMs,p])),ie=r(()=>new Map(P.map(e=>[e.plateId,e])),[P]),W=b===null?null:ie.get(b)??null,G=()=>{e.invalidateQueries({queryKey:De})},K=()=>_(new Set);function se(e){_(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})}let q=[...h],J=j.isPending||M.isPending,ce=A.isPending||M.isPending;function le(){q.length!==0&&j.mutate({plateIds:q},{onSettled:()=>{G(),K()}})}function ue(){q.length!==0&&Promise.allSettled(q.map(e=>M.mutateAsync({plateId:e}))).then(()=>{G(),K()})}function de(e){S(null),y([e])}function fe(e){A.mutate({plateId:e},{onSettled:G}),S(null)}function pe(e){M.mutate({plateId:e},{onSettled:G}),S(null)}let me=V.length!==P.length;return n(`div`,{className:`relative space-y-3`,children:[n(`div`,{className:`flex flex-wrap items-center gap-1.5`,children:[s(`div`,{className:`flex items-center gap-1`,children:je.map(e=>s(`button`,{type:`button`,onClick:()=>c(e.value),className:`rounded-md px-2.5 py-1 text-xs transition-colors ${t===e.value?`bg-primary/12 text-primary font-medium`:`text-foreground-subtle hover:bg-surface-hover hover:text-foreground`}`,children:e.label},e.value))}),s(U,{onChange:f}),s(te,{cameras:B,selected:p,onChange:m}),!T&&s(`span`,{className:`ml-auto text-[10px] text-foreground-subtle`,children:me?`${String(V.length)} of ${String(P.length)} plates`:`${String(V.length)} plate${V.length===1?``:`s`}`})]}),h.size>0&&n(`div`,{className:`flex flex-wrap items-center gap-2 rounded-md border border-primary/40 bg-primary/8 px-3 py-2`,children:[n(`span`,{className:`text-xs font-medium text-foreground`,children:[h.size,` selected`]}),n(`div`,{className:`ml-auto flex flex-wrap items-center gap-1.5`,children:[n(g,{variant:`primary`,onClick:()=>y(q),disabled:J,children:[s(I,{className:`h-3.5 w-3.5`}),` Assign`]}),n(g,{variant:`secondary`,onClick:le,disabled:J,children:[j.isPending?s(Y,{className:`h-3.5 w-3.5 animate-spin`}):s(F,{className:`h-3.5 w-3.5`}),` `,`Detach`]}),n(g,{variant:`secondary`,onClick:ue,disabled:J,children:[s(Z,{className:`h-3.5 w-3.5`}),` Delete`]}),s(g,{variant:`ghost`,onClick:K,disabled:J,children:s(X,{className:`h-3.5 w-3.5`})})]})]}),T&&n(`div`,{className:`flex items-center gap-2 py-4 text-xs text-foreground-subtle`,children:[s(Y,{className:`h-4 w-4 animate-spin`}),` Loading plates…`]}),!T&&V.length===0&&s(`p`,{className:`py-4 text-xs text-foreground-subtle`,children:P.length>0?`No plates match the current filters.`:`No plates recognized yet.`}),!T&&V.length>0&&n(i,{children:[s(`div`,{className:`grid grid-cols-[repeat(auto-fill,minmax(9rem,1fr))] gap-2`,children:H.pageItems.map(e=>s(Ae,{plate:e,cameraName:L(e.deviceId),nowMs:N,selected:h.has(e.plateId),onToggleSelect:se,onAssign:e=>y([e]),onOpenDetail:S},e.plateId))}),s(R,{currentPage:H.page,totalItems:H.totalItems,pageSize:H.pageSize,onPageChange:H.setPage,itemNoun:`plates`})]}),s(we,{plate:W,cameraName:W?L(W.deviceId):``,onClose:()=>S(null),onAssign:de,onUnassign:fe,onDelete:pe,actionsPending:ce}),s(Ee,{plateIds:v,vehicles:E,onDone:()=>{y(null),K()}})]})}t();var Pe=[[`plateGallery`]],Fe=2e3;function Ie(){let t=a(),n=e(t);n.current=t;let r=e(void 0);r.current||=W({delayMs:Fe,invalidate:()=>{n.current.invalidateQueries({queryKey:Pe})}}),c(()=>()=>r.current?.cancel(),[]),m(N.PipelineAnalyticsPlateGalleryChanged,()=>{r.current?.trigger()})}function Le(){return Ie(),s(fe,{icon:J,title:`Plates`,subtitle:`Manage enrolled vehicles and assign recognized license plates to them.`,children:n(`section`,{className:`space-y-3`,children:[n(`div`,{children:[s(`h2`,{className:`text-sm font-semibold text-foreground mb-1`,children:`Vehicles`}),s(`p`,{className:`text-xs text-foreground-subtle mb-3`,children:`Enrolled vehicle identities used for plate recognition. Expand a row to view or remove plate samples.`}),s(ye,{})]}),n(`div`,{className:`pt-4 border-t border-border`,children:[s(`h2`,{className:`text-sm font-semibold text-foreground mb-1`,children:`Recent recognized plates`}),s(`p`,{className:`text-xs text-foreground-subtle mb-3`,children:`License plates read by the detection pipeline. Assign them to a vehicle, correct the OCR text, or delete.`}),s(Ne,{})]})]})})}export{Le as PlatesPage};
@@ -1 +0,0 @@
1
- import{K as e}from"./index-CEBJ8eMc.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{K as e}from"./index-CEBJ8eMc.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};