@hot-updater/console 1.0.0-rc.2 → 1.0.0-rc.21

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 (285) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/ConsoleFeatureUnavailable-D0LPL1Gy.js +1 -0
  3. package/.output/public/assets/HashValueDisplay-BmuB4FW-.js +1 -0
  4. package/.output/public/assets/InsightsInfo--v4SC07c.js +1 -0
  5. package/.output/public/assets/InsightsPageHeader-dU83CAQY.js +1 -0
  6. package/.output/public/assets/NotFoundPage-B5mhGG2a.js +1 -0
  7. package/.output/public/assets/api-D-vOVlQ4.js +1 -0
  8. package/.output/public/assets/api-keys-Csh8ARKU.js +1 -0
  9. package/.output/public/assets/api-keys-OMPUoA_A.js +1 -0
  10. package/.output/public/assets/arrow-left-Bwq9X1eS.js +1 -0
  11. package/.output/public/assets/arrow-up-right-BkOVn4if.js +1 -0
  12. package/.output/public/assets/card-C_7d6O9a.js +1 -0
  13. package/.output/public/assets/console-features-api-C1jRZTGw.js +1 -0
  14. package/.output/public/assets/dialog-DE8wFN_P.js +1 -0
  15. package/.output/public/assets/dist-C7ENGzpS.js +1 -0
  16. package/.output/public/assets/empty-CVd5NlQD.js +1 -0
  17. package/.output/public/assets/field-C06q1iC9.js +1 -0
  18. package/.output/public/assets/index-BeWlQtO6.js +11 -0
  19. package/.output/public/assets/input-group-Bi61biIA.js +1 -0
  20. package/.output/public/assets/insights-BjnAtC0f.js +2 -0
  21. package/.output/public/assets/insights-D86m11yH.js +42 -0
  22. package/.output/public/assets/insights-DpYstMoY.js +1 -0
  23. package/.output/public/assets/insights-recovery-rpc-BIm5_ALc.js +1 -0
  24. package/.output/public/assets/insights-search-KIF7mRtB.js +1 -0
  25. package/.output/public/assets/insights-usage-rpc-VHj8vyBt.js +1 -0
  26. package/.output/public/assets/insights_.distribution-ADcrX48c.js +2 -0
  27. package/.output/public/assets/insights_.distribution-CuuJUN6Y.js +1 -0
  28. package/.output/public/assets/insights_.distribution-DJRjuXsO.js +1 -0
  29. package/.output/public/assets/installations-BSBBzqWs.js +2 -0
  30. package/.output/public/assets/installations-DqIE6WcO.js +1 -0
  31. package/.output/public/assets/installations-UsELbDvw.js +1 -0
  32. package/.output/public/assets/loader-circle-CnCBxzHp.js +1 -0
  33. package/.output/public/assets/mutation-Csp7xUNh.js +1 -0
  34. package/.output/public/assets/preload-helper-B-cOmpLH.js +1 -0
  35. package/.output/public/assets/refresh-cw-FF1NtzlQ.js +1 -0
  36. package/.output/public/assets/routes-CoN9XHP_.js +2 -0
  37. package/.output/public/assets/routes-DT1jB0Zi.js +1 -0
  38. package/.output/public/assets/sidebar-D8mJRF15.js +3 -0
  39. package/.output/public/assets/styles-Bwt7v6U5.css +2 -0
  40. package/.output/public/assets/table-WBgfvgXg.js +1 -0
  41. package/.output/public/assets/useCompositeListItem-CloBmDwn.js +1 -0
  42. package/.output/public/assets/useMutation-DO8cvsTx.js +1 -0
  43. package/.output/public/assets/useOpenInteractionType-ReGr9GzJ.js +1 -0
  44. package/.output/public/assets/valueToPercent-BvPAi4bP.js +1 -0
  45. package/.output/server/{__23tanstack-start-server-fn-resolver-B7ioJhtE.mjs → __23tanstack-start-server-fn-resolver-DMRD4e4f.mjs} +51 -47
  46. package/.output/server/_libs/@base-ui/react+[...].mjs +7044 -3622
  47. package/.output/server/_libs/@reduxjs/toolkit+[...].mjs +1554 -0
  48. package/.output/server/_libs/@tanstack/react-router+[...].mjs +3803 -4023
  49. package/.output/server/_libs/@tanstack/react-router-ssr-query+[...].mjs +141 -98
  50. package/.output/server/_libs/d3-array.mjs +231 -0
  51. package/.output/server/_libs/d3-color.mjs +330 -0
  52. package/.output/server/_libs/d3-format.mjs +252 -0
  53. package/.output/server/_libs/d3-interpolate.mjs +207 -0
  54. package/.output/server/_libs/d3-path.mjs +77 -0
  55. package/.output/server/_libs/d3-scale+[...].mjs +1907 -0
  56. package/.output/server/_libs/d3-shape.mjs +818 -0
  57. package/.output/server/_libs/decimal.js-light.mjs +884 -0
  58. package/.output/server/_libs/es-toolkit.mjs +1159 -0
  59. package/.output/server/_libs/eventemitter3.mjs +236 -0
  60. package/.output/server/_libs/immer.mjs +532 -0
  61. package/.output/server/_libs/lucide-react.mjs +46 -32
  62. package/.output/server/_libs/next-themes.mjs +2 -2
  63. package/.output/server/_libs/react-redux+[...].mjs +205 -0
  64. package/.output/server/_libs/recharts+[...].mjs +14350 -0
  65. package/.output/server/_libs/sonner.mjs +2 -2
  66. package/.output/server/_libs/tanstack__history.mjs +68 -41
  67. package/.output/server/_libs/tanstack__query-core.mjs +1618 -309
  68. package/.output/server/_libs/tanstack__react-query.mjs +262 -22
  69. package/.output/server/_libs/verkit.mjs +99 -1
  70. package/.output/server/_runtime.mjs +10 -1
  71. package/.output/server/_ssr/ConsoleFeatureUnavailable-Du7jNPNS.mjs +58 -0
  72. package/.output/server/_ssr/{HashValueDisplay-DwpGLfrl.mjs → HashValueDisplay-GQvFkXoi.mjs} +3 -3
  73. package/.output/server/_ssr/InsightsInfo-Do7QSaFR.mjs +37 -0
  74. package/.output/server/_ssr/InsightsPageHeader-DSUWUWRc.mjs +154 -0
  75. package/.output/server/_ssr/NotFoundPage-DsF4Vrhg.mjs +37 -0
  76. package/.output/server/_ssr/api-BEiVs0H7.mjs +203 -0
  77. package/.output/server/_ssr/api-keys-BrvBWGRf.mjs +5 -0
  78. package/.output/server/_ssr/{api-keys-CZeTPQys.mjs → api-keys-K5v32nf7.mjs} +49 -9
  79. package/.output/server/_ssr/api-keys-rpc-B96bBllm.mjs +52 -0
  80. package/.output/server/_ssr/api-rpc-DcUe280B.mjs +296 -0
  81. package/.output/server/_ssr/{auth-rpc-DUaeOWKK.mjs → auth-rpc-C68W56DP.mjs} +6 -6
  82. package/.output/server/_ssr/auth.server-DM1J6NwR.mjs +5712 -0
  83. package/.output/server/_ssr/bundleActivity-CpuY9CTP.mjs +19 -0
  84. package/.output/server/_ssr/card-CPAEKx0w.mjs +49 -0
  85. package/.output/server/_ssr/config-nsIcsHh8.mjs +15 -0
  86. package/.output/server/_ssr/config.server-DDCZk3Sq.mjs +36 -0
  87. package/.output/server/_ssr/console-access-Da-2Qd7q.mjs +17 -0
  88. package/.output/server/_ssr/console-features-Dzu2iUGD.mjs +55 -0
  89. package/.output/server/_ssr/console-features-api-xAsSgFa_.mjs +43 -0
  90. package/.output/server/_ssr/console-features-rpc-qARGpB24.mjs +19 -0
  91. package/.output/server/_ssr/{createServerFn-B2hcXoPM.mjs → createMiddleware-BdBf_ezN.mjs} +67 -56
  92. package/.output/server/_ssr/{createServerRpc-DB29C_5p.mjs → createServerRpc-B_y2lrwA.mjs} +2 -2
  93. package/.output/server/_ssr/{databaseJsonValue-d6I3nAS4.mjs → databaseJsonValue-Bhxciy7Z.mjs} +28 -5
  94. package/.output/server/_ssr/databaseRows-DwMAjaF8.mjs +74 -0
  95. package/.output/server/_ssr/{dialog-DS-nw-pA.mjs → dialog-q__BJ7mQ.mjs} +2 -2
  96. package/.output/server/_ssr/{dist-CyzPaI5v.mjs → dist-Cxo9ghYv.mjs} +140 -6
  97. package/.output/server/_ssr/{downloadBundle-CNnYxYO2.mjs → downloadBundle-BW9I-pMQ.mjs} +10 -10
  98. package/.output/server/_ssr/empty-DcBTAooP.mjs +49 -0
  99. package/.output/server/_ssr/{empty-plugin-adapters-B5QvGpEl.mjs → empty-plugin-adapters-CYdinE-i.mjs} +1 -1
  100. package/.output/server/_ssr/{table-CnZmon_Z.mjs → field-QCDBVpXA.mjs} +63 -51
  101. package/.output/server/_ssr/getBundleChildren-DIAGCF4a.mjs +22 -0
  102. package/.output/server/_ssr/{input-group-BpsnmvZw.mjs → input-group-hCk2nUoU.mjs} +2 -2
  103. package/.output/server/_ssr/insights-BfBO0RFr.mjs +1238 -0
  104. package/.output/server/_ssr/insights-DsAU3-TB.mjs +14 -0
  105. package/.output/server/_ssr/insights-RIfg447W.mjs +5 -0
  106. package/.output/server/_ssr/insights-api-CDn-QQHU.mjs +105 -0
  107. package/.output/server/_ssr/insights-failures-BBGMhuUr.mjs +44 -0
  108. package/.output/server/_ssr/insights-failures-rpc-rA2dctK2.mjs +21 -0
  109. package/.output/server/_ssr/insights-recovery-Dpk6Mfb9.mjs +28 -0
  110. package/.output/server/_ssr/insights-recovery-rpc-BCaF-xSd.mjs +46 -0
  111. package/.output/server/_ssr/insights-recovery-rpc-CcgYyUHk.mjs +20 -0
  112. package/.output/server/_ssr/{insights-rpc-38DujK0G.mjs → insights-rpc-keycmwzw.mjs} +22 -14
  113. package/.output/server/_ssr/insights-search-BRg5VsNe.mjs +25 -0
  114. package/.output/server/_ssr/insights-usage-cbw9n2Fq.mjs +29 -0
  115. package/.output/server/_ssr/insights-usage-rpc-BKgV1QDf.mjs +29 -0
  116. package/.output/server/_ssr/insights-usage-rpc-D-JYachy.mjs +41 -0
  117. package/.output/server/_ssr/insightsRecovery-B7oMc8d8.mjs +45 -0
  118. package/.output/server/_ssr/insightsUsage-Oa7kk5ek.mjs +56 -0
  119. package/.output/server/_ssr/insights_.distribution-BIqOqRW0.mjs +335 -0
  120. package/.output/server/_ssr/insights_.distribution-CuUrDa7P.mjs +5 -0
  121. package/.output/server/_ssr/insights_.distribution-RT_6x_ud.mjs +14 -0
  122. package/.output/server/_ssr/{installations-DiVKEF5T.mjs → installations-BO5CjX2z.mjs} +517 -54
  123. package/.output/server/_ssr/installations-BjaHiIfh.mjs +5 -0
  124. package/.output/server/_ssr/installations-Dt5luA-N.mjs +69 -0
  125. package/.output/server/_ssr/listReleases-BitHzOYB.mjs +79 -0
  126. package/.output/server/_ssr/releaseManagement-B3e7I8J9.mjs +11 -0
  127. package/.output/server/_ssr/{router-B9wG_9f8.mjs → router-DfVAixxe.mjs} +135 -139
  128. package/.output/server/_ssr/{routes-D7Yh_jfj.mjs → routes-C6LstNp8.mjs} +176 -455
  129. package/.output/server/_ssr/routes-Q3Uhmwwz.mjs +292 -0
  130. package/.output/server/_ssr/runtime.server-fL0o6I2b.mjs +1459 -0
  131. package/.output/server/_ssr/schema-BKY9SqaY.mjs +25 -0
  132. package/.output/server/_ssr/select-CUlInmjk.mjs +107 -0
  133. package/.output/server/_ssr/server-C43wq9ft.mjs +8330 -0
  134. package/.output/server/_ssr/{createSsrRpc-DjWNJ0uc.mjs → sidebar-DKbx2ach.mjs} +117 -63
  135. package/.output/server/_ssr/ssr.mjs +1 -1
  136. package/.output/server/_ssr/start-BXUOv_n8.mjs +4 -0
  137. package/.output/server/_ssr/table-NGWV8B-S.mjs +53 -0
  138. package/.output/server/_ssr/updateFailures-Jwe2Baab.mjs +24 -0
  139. package/.output/server/_ssr/{uuidv7-D0QFkPL_.mjs → uuidv7-C8bwiZr8.mjs} +2 -2
  140. package/.output/server/_tanstack-start-manifest_v-WQ5qGn8n.mjs +124 -0
  141. package/.output/server/index.mjs +267 -162
  142. package/LICENSE +13 -14
  143. package/README.md +82 -72
  144. package/lib/index.d.mts +23 -11
  145. package/lib/vite-internal.mjs +13 -3
  146. package/lib/vite.d.mts +2 -0
  147. package/package.json +14 -14
  148. package/src/components/AppSidebar.tsx +100 -71
  149. package/src/components/ConsoleAccessPage.tsx +5 -1
  150. package/src/components/ConsoleFeatureUnavailable.tsx +80 -0
  151. package/src/components/NotFoundPage.tsx +7 -7
  152. package/src/components/features/FeatureSlots.tsx +99 -0
  153. package/src/components/features/api-keys/apiKeysFeatureUi.tsx +15 -0
  154. package/src/components/features/bundles/BundleMetadata.tsx +8 -5
  155. package/src/components/features/bundles/RolloutCohortsDialog.tsx +1 -1
  156. package/src/components/features/channels/ChannelManagementDialog.tsx +2 -5
  157. package/src/components/features/insights/AppUsage.tsx +370 -0
  158. package/src/components/features/insights/EstimatedCount.tsx +18 -0
  159. package/src/components/features/insights/EventDetails.tsx +117 -37
  160. package/src/components/features/insights/EventHistoryCard.tsx +112 -26
  161. package/src/components/features/insights/EventHistoryList.tsx +2 -2
  162. package/src/components/features/insights/InsightsControls.tsx +265 -102
  163. package/src/components/features/insights/InsightsErrorAlert.tsx +14 -1
  164. package/src/components/features/insights/InsightsInfo.tsx +48 -0
  165. package/src/components/features/insights/InsightsOverview.tsx +176 -173
  166. package/src/components/features/insights/InsightsPageHeader.tsx +35 -20
  167. package/src/components/features/insights/InsightsPeriodSelector.tsx +89 -0
  168. package/src/components/features/insights/InstallationHistoryCard.tsx +52 -10
  169. package/src/components/features/insights/InstallationMatchesCard.tsx +1 -1
  170. package/src/components/features/insights/ReleaseActivity.tsx +188 -0
  171. package/src/components/features/insights/ReportingDevicesSummary.tsx +65 -0
  172. package/src/components/features/insights/UpdateFailures.tsx +319 -0
  173. package/src/components/features/insights/insightsFeatureUi.tsx +35 -0
  174. package/src/components/features/releases/ReleaseEditorSheet.tsx +30 -7
  175. package/src/components/ui/card.tsx +1 -1
  176. package/src/components/ui/empty.tsx +101 -0
  177. package/src/components/ui/scroll-area.tsx +52 -0
  178. package/src/components/ui/sidebar.tsx +22 -29
  179. package/src/components/ui/tabs.tsx +81 -0
  180. package/src/index.ts +26 -19
  181. package/src/lib/api-keys-api.ts +0 -28
  182. package/src/lib/api-keys-rpc.ts +27 -38
  183. package/src/lib/api-rpc.ts +189 -266
  184. package/src/lib/api.ts +19 -102
  185. package/src/lib/bundle-activity.ts +31 -0
  186. package/src/lib/console-access.ts +20 -0
  187. package/src/lib/console-features-api.ts +68 -0
  188. package/src/lib/console-features-rpc.ts +13 -0
  189. package/src/lib/console-features.ts +91 -0
  190. package/src/lib/insights-api.ts +37 -1
  191. package/src/lib/insights-failures-rpc.ts +21 -0
  192. package/src/lib/insights-failures.ts +129 -0
  193. package/src/lib/insights-recovery-rpc.ts +51 -0
  194. package/src/lib/insights-recovery.ts +68 -0
  195. package/src/lib/insights-retention.ts +21 -0
  196. package/src/lib/insights-rpc.ts +30 -12
  197. package/src/lib/insights-search.ts +58 -0
  198. package/src/lib/insights-usage-rpc.ts +29 -0
  199. package/src/lib/insights-usage.ts +74 -0
  200. package/src/lib/insights-view.ts +38 -2
  201. package/src/lib/scroll-restoration.ts +21 -0
  202. package/src/lib/server/adminInsights.ts +124 -0
  203. package/src/lib/server/auth.server.ts +13 -5
  204. package/src/lib/server/bundleActivity.ts +37 -0
  205. package/src/lib/server/config.server.ts +21 -74
  206. package/src/lib/server/console-feature-apis.ts +59 -0
  207. package/src/lib/server/console-runtime.server.ts +82 -38
  208. package/src/lib/server/downloadBundle.ts +16 -15
  209. package/src/lib/server/getBundleChildren.ts +31 -122
  210. package/src/lib/server/insightsRecovery.ts +55 -0
  211. package/src/lib/server/insightsUsage.ts +63 -0
  212. package/src/lib/server/listReleases.ts +109 -44
  213. package/src/lib/server/releaseReachability.ts +8 -7
  214. package/src/lib/server/runtime.server.ts +120 -31
  215. package/src/lib/server/updateFailures.ts +31 -0
  216. package/src/routeTree.gen.ts +44 -44
  217. package/src/router.tsx +3 -2
  218. package/src/routes/-installations-search.ts +32 -8
  219. package/src/routes/-releases-search.ts +76 -29
  220. package/src/routes/__root.tsx +10 -4
  221. package/src/routes/api/bundles/$bundleId/download.ts +2 -5
  222. package/src/routes/api-keys.tsx +5 -2
  223. package/src/routes/index.tsx +167 -104
  224. package/src/routes/insights.tsx +100 -59
  225. package/src/routes/insights_.distribution.tsx +398 -0
  226. package/src/routes/installations.tsx +98 -41
  227. package/src/vite-internal.ts +15 -3
  228. package/src/vite.ts +2 -0
  229. package/.output/public/assets/HashValueDisplay-CB0Eskit.js +0 -1
  230. package/.output/public/assets/InsightsPageHeader-Car5LNiZ.js +0 -1
  231. package/.output/public/assets/api-keys-BzKocqRy.js +0 -1
  232. package/.output/public/assets/api-keys-api-BHcODB7q.js +0 -1
  233. package/.output/public/assets/card-Dhr_eFYj.js +0 -1
  234. package/.output/public/assets/chart-no-axes-combined-Dy4WJv2U.js +0 -1
  235. package/.output/public/assets/composite-Bp98A0Ld.js +0 -1
  236. package/.output/public/assets/createServerFn-CA8fs7QD.js +0 -3
  237. package/.output/public/assets/dialog-CUTrcPlB.js +0 -1
  238. package/.output/public/assets/dist-C_NydL0e.js +0 -1
  239. package/.output/public/assets/index-DdAz-CXv.js +0 -10
  240. package/.output/public/assets/input-group-cSOG4wh_.js +0 -1
  241. package/.output/public/assets/insights-C0PBSZ-n.js +0 -1
  242. package/.output/public/assets/installations-CE33wgbY.js +0 -2
  243. package/.output/public/assets/installations-CStZja8x.js +0 -1
  244. package/.output/public/assets/lazyRouteComponent-Ccp3bwBY.js +0 -1
  245. package/.output/public/assets/link-CI8idAUi.js +0 -1
  246. package/.output/public/assets/loader-circle-BoxLrsOu.js +0 -1
  247. package/.output/public/assets/preload-helper-CQ36nxok.js +0 -1
  248. package/.output/public/assets/refresh-cw-Bqc72UZG.js +0 -1
  249. package/.output/public/assets/routes-DGVXdzpw.js +0 -2
  250. package/.output/public/assets/routes-DTlwOr8I.js +0 -1
  251. package/.output/public/assets/shield-check-uK3MHWJZ.js +0 -1
  252. package/.output/public/assets/signing-CMf4aqDO.js +0 -1
  253. package/.output/public/assets/styles-BCvbtKsm.css +0 -2
  254. package/.output/public/assets/table-2vcV89QB.js +0 -1
  255. package/.output/public/assets/useCompositeListItem-CHLITE_4.js +0 -1
  256. package/.output/public/assets/x-DCd0j8c6.js +0 -1
  257. package/.output/server/_ssr/InsightsPageHeader-Df4Brj8u.mjs +0 -484
  258. package/.output/server/_ssr/api-keys-api-BUPQVSpk.mjs +0 -60
  259. package/.output/server/_ssr/api-keys-rpc-Cs7tS5_j.mjs +0 -136
  260. package/.output/server/_ssr/api-rpc-tAupfGQm.mjs +0 -1399
  261. package/.output/server/_ssr/auth.server-DW71WzsD.mjs +0 -47
  262. package/.output/server/_ssr/bundle-signing-rpc-BhnBw0-d.mjs +0 -16
  263. package/.output/server/_ssr/bundle-signing.server-C4NW5mWx.mjs +0 -12
  264. package/.output/server/_ssr/card-BRiPmi0C.mjs +0 -108
  265. package/.output/server/_ssr/config-Dv8qLDZ0.mjs +0 -13
  266. package/.output/server/_ssr/config.server-afDuAwaG.mjs +0 -368
  267. package/.output/server/_ssr/databaseRows-5bCRTxm-.mjs +0 -126
  268. package/.output/server/_ssr/deleteBundle-BTGwBgzx.mjs +0 -66
  269. package/.output/server/_ssr/getBundleChildren-C0vh4ZvE.mjs +0 -50
  270. package/.output/server/_ssr/insights-BdS364Xu.mjs +0 -460
  271. package/.output/server/_ssr/insightsContract-fjJDBeEE.mjs +0 -303
  272. package/.output/server/_ssr/installations-CtA59MQG.mjs +0 -29
  273. package/.output/server/_ssr/routes-CKrrS2q2.mjs +0 -37
  274. package/.output/server/_ssr/runtime.server-DacU1TBV.mjs +0 -438
  275. package/.output/server/_ssr/server-D_C2rMzf.mjs +0 -7468
  276. package/.output/server/_ssr/signing-Dz1WkZOf.mjs +0 -133
  277. package/.output/server/_ssr/start-DpViQGnt.mjs +0 -4
  278. package/.output/server/_tanstack-start-manifest_v-2MjTyxil.mjs +0 -97
  279. package/src/components/features/insights/InsightsBundleReports.tsx +0 -51
  280. package/src/components/features/signing/BundleSigningPage.tsx +0 -139
  281. package/src/lib/bundle-signing-api.ts +0 -14
  282. package/src/lib/bundle-signing-rpc.ts +0 -16
  283. package/src/lib/server/bundle-signing.server.ts +0 -23
  284. package/src/lib/server/deleteBundle.ts +0 -145
  285. package/src/routes/signing.tsx +0 -37
@@ -1,34 +1,473 @@
1
- import { r as __toESM } from "../_runtime.mjs";
2
- import { J as require_react, q as require_jsx_runtime } from "../_libs/@base-ui/react+[...].mjs";
3
- import { N as ChevronDown, P as Check, R as ArrowLeft, d as RefreshCw, l as Search, t as X } from "../_libs/lucide-react.mjs";
4
- import { C as cn, S as buttonVariants, _ as Skeleton, r as Separator$1, t as Button$1 } from "./createSsrRpc-DjWNJ0uc.mjs";
5
- import { s as useElementScrollRestoration } from "../_libs/@tanstack/react-router+[...].mjs";
6
- import { d as CardTitle, o as Card, s as CardContent, u as CardHeader } from "./card-BRiPmi0C.mjs";
7
- import { a as FieldLabel, c as TableBody, d as TableHeader, f as TableRow, l as TableCell, s as Table, t as Field, u as TableHead } from "./table-CnZmon_Z.mjs";
8
- import { n as shortenIdentifier, t as HashValueDisplay } from "./HashValueDisplay-DwpGLfrl.mjs";
9
- import { a as EventTypeBadge, c as InsightsPagination, d as useInsightsInstallationQuery, f as useInsightsInstallationsQuery, i as EventTimestamp, l as useInsightsEventsQuery, n as EventHistoryCard, o as InsightsErrorAlert, p as useInsightsTimeFormat, r as EventHistoryList, s as InsightsPageHeader, t as EventBundleTransition, u as useInsightsInstallationEventsQuery } from "./InsightsPageHeader-Df4Brj8u.mjs";
10
- import { n as getInsightsScrollRestorationKey, t as Route } from "./installations-CtA59MQG.mjs";
11
- import { i as InputGroupInput, n as InputGroupAddon, r as InputGroupButton, t as InputGroup } from "./input-group-BpsnmvZw.mjs";
12
- //#region node_modules/.nitro/vite/services/ssr/assets/installations-DiVKEF5T.js
1
+ import { i as __toESM } from "../_runtime.mjs";
2
+ import { mt as require_react, pt as require_jsx_runtime } from "../_libs/@base-ui/react+[...].mjs";
3
+ import { A as CircleAlert, B as Activity, E as Download, F as Check, L as ArrowUpRight, P as ChevronDown, c as Search, d as RefreshCw, t as X, u as RotateCcw, z as ArrowLeft } from "../_libs/lucide-react.mjs";
4
+ import { D as buttonVariants, O as cn, S as Skeleton, r as Separator$1, t as Button$1 } from "./sidebar-DKbx2ach.mjs";
5
+ import { c as useElementScrollRestoration, h as Link, o as useLocation } from "../_libs/@tanstack/react-router+[...].mjs";
6
+ import { a as CardHeader, n as CardContent, o as CardTitle, r as CardDescription, t as Card } from "./card-CPAEKx0w.mjs";
7
+ import { a as Badge, o as Field, u as FieldLabel } from "./field-QCDBVpXA.mjs";
8
+ import { a as TableHeader, i as TableHead, n as TableBody, o as TableRow, r as TableCell, t as Table } from "./table-NGWV8B-S.mjs";
9
+ import { n as describeFailure } from "./insights-failures-BBGMhuUr.mjs";
10
+ import { a as useInsightsInstallationEventsQuery, c as useInsightsRetention, i as useInsightsEventsQuery, n as formatDays, o as useInsightsInstallationQuery, s as useInsightsInstallationsQuery, t as DEFAULT_INSIGHTS_RETENTION } from "./insights-api-CDn-QQHU.mjs";
11
+ import { i as InputGroupInput, n as InputGroupAddon, r as InputGroupButton, t as InputGroup } from "./input-group-hCk2nUoU.mjs";
12
+ import { i as PeriodSelector, n as InsightsPageHeader, t as InsightsErrorAlert } from "./InsightsPageHeader-DSUWUWRc.mjs";
13
+ import { a as installationsScrollRestorationKey, i as eventRanges, n as Route, o as widerEventRange, r as eventRangeBounds, t as EVENT_RANGES } from "./installations-Dt5luA-N.mjs";
14
+ import { n as shortenIdentifier, t as HashValueDisplay } from "./HashValueDisplay-GQvFkXoi.mjs";
15
+ //#region node_modules/.nitro/vite/services/ssr/assets/installations-BO5CjX2z.js
13
16
  var import_react = /* @__PURE__ */ __toESM(require_react());
14
17
  var import_jsx_runtime = require_jsx_runtime();
15
- var getUserLabel$1 = (event) => event.userId ?? event.username ?? "—";
16
- var getLastKnownBundleId$1 = (event) => "lastKnownBundleId" in event ? event.lastKnownBundleId : event.toBundleId ?? event.fromBundleId;
17
- function InstallationHistoryCard({ error, history, isLoading, onNext, onPrevious, onRefresh, pageNumber, selectedEvent, selectedInstallId }) {
18
+ var eventTypes = {
19
+ UPDATE_DOWNLOADED: {
20
+ label: "Downloaded",
21
+ description: "Download complete. Waiting for the app to restart and apply it.",
22
+ variant: "default",
23
+ icon: Download
24
+ },
25
+ UPDATE_APPLIED: {
26
+ label: "Update applied",
27
+ description: "The app started using the downloaded update.",
28
+ variant: "success",
29
+ icon: Check
30
+ },
31
+ RECOVERED: {
32
+ label: "Recovered",
33
+ description: "Recovered from a crashed bundle.",
34
+ variant: "warning",
35
+ icon: RotateCcw
36
+ },
37
+ UPDATE_FAILED: {
38
+ label: "Update failed",
39
+ description: "An update check, download, or install failed.",
40
+ variant: "destructive",
41
+ icon: CircleAlert
42
+ },
43
+ UNCHANGED: {
44
+ label: "No change",
45
+ description: "No download or apply was reported at this point.",
46
+ variant: "secondary",
47
+ icon: Activity
48
+ }
49
+ };
50
+ function useInsightsTimeFormat() {
51
+ const [timeZone, setTimeZone] = (0, import_react.useState)("UTC");
52
+ (0, import_react.useEffect)(() => {
53
+ setTimeZone(Intl.DateTimeFormat().resolvedOptions().timeZone);
54
+ }, []);
55
+ return new Intl.DateTimeFormat("en", {
56
+ timeZone,
57
+ timeZoneName: "shortOffset",
58
+ year: "numeric",
59
+ month: "2-digit",
60
+ day: "2-digit",
61
+ hour: "2-digit",
62
+ minute: "2-digit",
63
+ second: "2-digit",
64
+ hourCycle: "h23"
65
+ });
66
+ }
67
+ function formatInsightsTimestamp(value, formatter) {
68
+ const parts = Object.fromEntries(formatter.formatToParts(new Date(value)).map(({ type, value }) => [type, value]));
69
+ const offset = parts.timeZoneName === "GMT" ? "GMT+0" : parts.timeZoneName;
70
+ return `${parts.year}/${parts.month}/${parts.day} ${parts.hour}:${parts.minute}:${parts.second} ${offset}`;
71
+ }
72
+ function EventTimestamp({ value, formatter, touch = false }) {
73
+ const date = new Date(value);
74
+ const localTime = formatInsightsTimestamp(value, formatter);
75
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("details", {
76
+ className: "group/time",
77
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("summary", {
78
+ className: `cursor-pointer list-none rounded-md outline-none focus-visible:ring-2 focus-visible:ring-ring/30 [&::-webkit-details-marker]:hidden ${touch ? "flex min-h-11 items-center" : ""}`,
79
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
80
+ className: "flex items-center gap-1",
81
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("time", {
82
+ dateTime: date.toISOString(),
83
+ className: "whitespace-nowrap",
84
+ children: localTime
85
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronDown, {
86
+ "aria-hidden": "true",
87
+ className: "size-3 text-muted-foreground group-open/time:rotate-180"
88
+ })]
89
+ })
90
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
91
+ className: "mt-2 text-muted-foreground",
92
+ children: date.toISOString().replace("T", " ").replace("Z", " UTC")
93
+ })]
94
+ });
95
+ }
96
+ var deliveries = {
97
+ patch: "A patch delivered it.",
98
+ manifest: "Only the changed files were downloaded.",
99
+ archive: "The full archive was downloaded."
100
+ };
101
+ /** What the event's report added: where an update failed, how a bundle arrived, why a process exited. */
102
+ var eventNote = (event) => {
103
+ if (event.type === "UPDATE_FAILED" && event.failure) return describeFailure(event.failure);
104
+ if (event.type === "UPDATE_DOWNLOADED" && event.delivery) {
105
+ const delivered = deliveries[event.delivery] ?? null;
106
+ return event.patchFallback ? `The patch failed. ${delivered ?? ""}`.trim() : delivered;
107
+ }
108
+ if (event.type === "RECOVERED" && event.previousProcessExit) return `The crashed process exited with ${event.previousProcessExit}.`;
109
+ return null;
110
+ };
111
+ function EventTypeDetails({ event }) {
112
+ const eventType = eventTypes[event.type];
113
+ const Icon = eventType.icon;
114
+ const note = eventNote(event);
115
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
116
+ className: "flex min-w-0 flex-col items-start gap-2",
117
+ children: [
118
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Badge, {
119
+ variant: eventType.variant,
120
+ className: "gap-1 whitespace-nowrap [&_svg]:size-3",
121
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { "aria-hidden": "true" }), eventType.label]
122
+ }),
123
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
124
+ className: "max-w-56 whitespace-normal text-xs text-muted-foreground",
125
+ children: event.type === "UPDATE_FAILED" && note ? note : eventType.description
126
+ }),
127
+ event.type !== "UPDATE_FAILED" && note ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
128
+ className: "max-w-56 whitespace-normal text-xs text-muted-foreground",
129
+ children: note
130
+ }) : null
131
+ ]
132
+ });
133
+ }
134
+ function EventBundleTransition({ event, touch = false }) {
135
+ const downloaded = event.type === "UPDATE_DOWNLOADED";
136
+ const failed = event.type === "UPDATE_FAILED";
137
+ const targeted = !failed || event.failure?.stage !== "check";
138
+ const changed = downloaded || failed || event.type === "UPDATE_APPLIED" || event.type === "RECOVERED";
139
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("dl", {
140
+ className: "grid grid-cols-[auto_minmax(0,1fr)] items-center gap-x-2 gap-y-2",
141
+ children: [event.fromBundleId && changed ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("dt", {
142
+ className: "text-muted-foreground",
143
+ children: downloaded || failed ? "Running" : "From"
144
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("dd", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(HashValueDisplay, {
145
+ value: event.fromBundleId,
146
+ buttonClassName: touch ? "min-h-11 px-3" : void 0
147
+ }) })] }) : null, targeted ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("dt", {
148
+ className: "text-muted-foreground",
149
+ children: downloaded ? "Pending" : failed ? "Target" : changed ? "To" : "Current"
150
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("dd", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(HashValueDisplay, {
151
+ value: event.toBundleId,
152
+ buttonClassName: touch ? "min-h-11 px-3" : void 0
153
+ }) })] }) : null]
154
+ });
155
+ }
156
+ function EventHistoryList({ events, formatter, renderIdentity }) {
157
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
158
+ className: "px-4 pb-2 text-xs text-muted-foreground sm:px-6",
159
+ children: "Time in your browser zone"
160
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ol", {
161
+ "aria-label": "Events",
162
+ className: "divide-y border-y",
163
+ children: events.map((event) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", {
164
+ className: "flex min-w-0 flex-col gap-3 px-4 py-4 sm:px-6",
165
+ children: [
166
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
167
+ className: "flex flex-wrap items-center justify-between gap-x-4 gap-y-1",
168
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(EventTypeDetails, { event }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
169
+ className: "text-xs tabular-nums",
170
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EventTimestamp, {
171
+ value: event.receivedAtMs,
172
+ formatter,
173
+ touch: true
174
+ })
175
+ })]
176
+ }),
177
+ renderIdentity?.(event),
178
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("dl", {
179
+ className: "flex flex-wrap gap-x-2 gap-y-1 text-sm",
180
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("dt", {
181
+ className: "sr-only",
182
+ children: "App"
183
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("dd", { children: [
184
+ event.platform === "ios" ? "iOS" : "Android",
185
+ " ",
186
+ event.appVersion
187
+ ] })] }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
188
+ className: "min-w-0 text-muted-foreground",
189
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("dt", {
190
+ className: "sr-only",
191
+ children: "Channel"
192
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("dd", {
193
+ className: "wrap-anywhere",
194
+ children: event.channel
195
+ })]
196
+ })]
197
+ }),
198
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
199
+ className: "text-xs",
200
+ "aria-label": "Bundle",
201
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EventBundleTransition, {
202
+ event,
203
+ touch: true
204
+ })
205
+ })
206
+ ]
207
+ }, event.id))
208
+ })] });
209
+ }
210
+ function InsightsPagination({ hasPrevious, label, nextCursor, onNext, onPrevious, pageLength, pageNumber }) {
211
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("nav", {
212
+ "aria-label": `${label} pagination`,
213
+ className: "flex flex-wrap items-center justify-between gap-3 border-t px-4 py-3 sm:px-6",
214
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
215
+ className: "text-xs text-muted-foreground tabular-nums",
216
+ children: [
217
+ "Page ",
218
+ pageNumber,
219
+ " · ",
220
+ pageLength.toLocaleString(),
221
+ " rows"
222
+ ]
223
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
224
+ className: "flex gap-2",
225
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
226
+ className: "h-11 min-w-11 px-3 lg:h-8 lg:min-w-0 lg:px-2",
227
+ disabled: !hasPrevious,
228
+ onClick: onPrevious,
229
+ size: "sm",
230
+ type: "button",
231
+ variant: "outline",
232
+ children: "Previous"
233
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
234
+ className: "h-11 min-w-11 px-3 lg:h-8 lg:min-w-0 lg:px-2",
235
+ disabled: nextCursor === null,
236
+ onClick: onNext,
237
+ size: "sm",
238
+ type: "button",
239
+ variant: "outline",
240
+ children: "Next"
241
+ })]
242
+ })]
243
+ });
244
+ }
245
+ /** The ranges within the days raw events are kept, the shortest always. */
246
+ var rangesWithin = (days) => EVENT_RANGES.filter((value, position) => position === 0 || eventRanges[value].durationMs <= days * 864e5);
247
+ function EventIdentity({ event, eventsLocation, touch = false }) {
248
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
249
+ className: touch ? "flex min-w-0 flex-wrap items-center justify-between gap-2" : "flex min-w-0 flex-col items-start gap-2",
250
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Link, {
251
+ className: buttonVariants({
252
+ className: touch ? "-ml-2 h-auto min-h-11 min-w-0 flex-1 justify-start gap-2 whitespace-normal text-sm" : "-ml-2 max-w-full justify-start",
253
+ size: "sm",
254
+ variant: "ghost"
255
+ }),
256
+ to: "/installations",
257
+ search: {
258
+ ...eventsLocation,
259
+ query: event.installId || void 0,
260
+ installId: event.installId
261
+ },
262
+ state: (previous) => ({ insightsPagination: { eventsBack: previous.insightsPagination?.eventsBack } }),
263
+ "aria-label": `View history for ${event.userId ?? "anonymous installation"} (${event.installId})`,
264
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
265
+ className: touch ? "min-w-0 text-left wrap-anywhere" : "truncate",
266
+ children: event.userId ?? "Anonymous installation"
267
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ArrowUpRight, {
268
+ "aria-hidden": "true",
269
+ "data-icon": "inline-end"
270
+ })]
271
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(HashValueDisplay, {
272
+ value: event.installId,
273
+ maxLength: 13,
274
+ buttonClassName: touch ? "min-h-11 px-3" : void 0
275
+ })]
276
+ });
277
+ }
278
+ function EventHistoryCard({ children, description, error, eventsLocation, history, isFetching, isLoading, onNext, onPrevious, onRangeChange, onRefresh, pageNumber, range, rawDays = 90, title = "All events" }) {
279
+ const dateTimeFormat = useInsightsTimeFormat();
280
+ const hasPrevious = pageNumber > 1;
281
+ const ranges = rangesWithin(rawDays);
282
+ const next = range === void 0 ? void 0 : widerEventRange(range);
283
+ const wider = next !== void 0 && ranges.includes(next) ? next : void 0;
284
+ const widen = wider !== void 0 && onRangeChange ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
285
+ className: "h-11 px-3 lg:h-8",
286
+ onClick: () => onRangeChange(wider),
287
+ type: "button",
288
+ variant: "outline",
289
+ children: `Show the last ${eventRanges[wider].period}`
290
+ }) : null;
291
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Card, {
292
+ className: "@container min-w-0 shadow-sm",
293
+ "aria-busy": isFetching,
294
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(CardHeader, {
295
+ className: "gap-4 p-4 sm:p-6",
296
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
297
+ className: "flex flex-col gap-1.5",
298
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
299
+ className: "flex flex-wrap items-center justify-between gap-3",
300
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardTitle, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { children: title }) }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
301
+ className: "flex flex-wrap items-center gap-2",
302
+ children: [range !== void 0 && onRangeChange ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PeriodSelector, {
303
+ label: "Time range",
304
+ onPeriodChange: onRangeChange,
305
+ period: range,
306
+ periods: ranges.map((value) => ({
307
+ value,
308
+ name: `Last ${eventRanges[value].period}`
309
+ }))
310
+ }) : null, /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button$1, {
311
+ className: "h-11 lg:h-8",
312
+ disabled: isFetching,
313
+ onClick: onRefresh,
314
+ size: "lg",
315
+ variant: "outline",
316
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(RefreshCw, {
317
+ "aria-hidden": "true",
318
+ "data-icon": "inline-start"
319
+ }), "Refresh"]
320
+ })]
321
+ })]
322
+ }), description ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardDescription, { children: description }) : null]
323
+ }), children]
324
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardContent, {
325
+ className: "min-w-0 p-0",
326
+ children: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
327
+ className: "flex flex-col gap-4 p-6",
328
+ role: "status",
329
+ "aria-label": "Loading events",
330
+ children: [
331
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Skeleton, { className: "h-12 w-full" }),
332
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Skeleton, { className: "h-12 w-full" }),
333
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Skeleton, { className: "h-12 w-full" })
334
+ ]
335
+ }) : error ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
336
+ className: "px-6 pb-6",
337
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(InsightsErrorAlert, {
338
+ error,
339
+ fallbackTitle: "Event history unavailable"
340
+ })
341
+ }) : history ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
342
+ history.data.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
343
+ className: "@[58rem]:hidden",
344
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EventHistoryList, {
345
+ events: history.data,
346
+ formatter: dateTimeFormat,
347
+ renderIdentity: (event) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EventIdentity, {
348
+ event,
349
+ eventsLocation,
350
+ touch: true
351
+ })
352
+ })
353
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
354
+ className: "hidden @[58rem]:block",
355
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Table, {
356
+ className: "min-w-4xl table-fixed",
357
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(TableRow, {
358
+ className: "[&>th]:px-4 sm:[&>th]:px-6",
359
+ children: [
360
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableHead, {
361
+ className: "w-64",
362
+ children: "Time"
363
+ }),
364
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableHead, {
365
+ className: "w-48",
366
+ children: "Event"
367
+ }),
368
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableHead, {
369
+ className: "w-48",
370
+ children: "User / installation"
371
+ }),
372
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableHead, {
373
+ className: "w-32",
374
+ children: "App"
375
+ }),
376
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableHead, {
377
+ className: "w-52",
378
+ children: "Bundle"
379
+ })
380
+ ]
381
+ }) }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableBody, { children: history.data.map((event) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(TableRow, {
382
+ className: "[&>td]:px-4 [&>td]:py-4 [&>td]:align-top sm:[&>td]:px-6",
383
+ children: [
384
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableCell, {
385
+ className: "whitespace-normal text-xs tabular-nums",
386
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EventTimestamp, {
387
+ value: event.receivedAtMs,
388
+ formatter: dateTimeFormat
389
+ })
390
+ }),
391
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableCell, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EventTypeDetails, { event }) }),
392
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableCell, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EventIdentity, {
393
+ event,
394
+ eventsLocation
395
+ }) }),
396
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableCell, {
397
+ className: "whitespace-normal text-xs",
398
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
399
+ className: "flex flex-col gap-2",
400
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
401
+ event.platform === "ios" ? "iOS" : "Android",
402
+ " ",
403
+ event.appVersion
404
+ ] }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
405
+ className: "text-muted-foreground",
406
+ children: event.channel
407
+ })]
408
+ })
409
+ }),
410
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableCell, {
411
+ className: "whitespace-normal text-xs",
412
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EventBundleTransition, { event })
413
+ })
414
+ ]
415
+ }, event.id)) })]
416
+ })
417
+ })] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
418
+ className: "flex flex-wrap items-center justify-between gap-3 px-4 pb-4 sm:px-6 sm:pb-6",
419
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
420
+ className: "text-sm text-muted-foreground",
421
+ children: hasPrevious ? "No older events in this range." : range !== void 0 ? `No events in the last ${eventRanges[range].period}.` : title === "All events" ? "No events recorded yet" : "No matching reports in this period"
422
+ }), hasPrevious ? null : widen]
423
+ }),
424
+ range !== void 0 && history.nextCursor === null && (history.data.length > 0 || hasPrevious) ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
425
+ className: "flex flex-wrap items-center justify-between gap-3 border-t px-4 py-3 sm:px-6",
426
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
427
+ className: "text-sm text-muted-foreground",
428
+ children: "Start of range reached"
429
+ }), widen]
430
+ }) : null,
431
+ history.data.length > 0 || hasPrevious || history.nextCursor ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(InsightsPagination, {
432
+ hasPrevious,
433
+ label: title,
434
+ nextCursor: history.nextCursor,
435
+ onNext,
436
+ onPrevious,
437
+ pageLength: history.data.length,
438
+ pageNumber
439
+ }) : null
440
+ ] }) : null
441
+ })]
442
+ });
443
+ }
444
+ var getUserLabel$1 = (event) => event.userId ?? "—";
445
+ /** A download or a failed update leaves the installation on the bundle it ran. */
446
+ var getLastKnownBundleId$1 = (event) => "lastKnownBundleId" in event ? event.lastKnownBundleId : event.type === "UPDATE_DOWNLOADED" || event.type === "UPDATE_FAILED" ? event.fromBundleId : event.toBundleId;
447
+ function InstallationHistoryCard({ error, history, isLoading, onNext, onPrevious, onRefresh, pageNumber, retention = DEFAULT_INSIGHTS_RETENTION, selectedEvent, selectedInstallId }) {
18
448
  const dateTimeFormat = useInsightsTimeFormat();
19
449
  const lastKnownBundleId = selectedEvent ? getLastKnownBundleId$1(selectedEvent) : void 0;
450
+ const pendingBundleId = selectedEvent && "pendingBundleId" in selectedEvent ? selectedEvent.pendingBundleId : selectedEvent && "type" in selectedEvent && selectedEvent.type === "UPDATE_DOWNLOADED" ? selectedEvent.toBundleId : null;
20
451
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Card, {
21
452
  className: "@container min-h-0 min-w-0 shadow-sm",
22
453
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardHeader, {
23
454
  className: "p-4 sm:p-6",
24
455
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
25
456
  className: "flex flex-wrap items-center justify-between gap-3",
26
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
457
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
27
458
  className: "flex min-w-0 flex-col gap-1.5",
28
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardTitle, {
459
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardTitle, {
29
460
  className: "text-sm font-medium",
30
461
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { children: selectedInstallId !== void 0 ? "Installation history" : "Select an installation" })
31
- })
462
+ }), selectedInstallId !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(CardDescription, { children: [
463
+ "Bundle changes and update failures are kept for",
464
+ " ",
465
+ formatDays(retention.rawDays),
466
+ "; the latest report, for",
467
+ " ",
468
+ formatDays(retention.dailyDays),
469
+ " after the installation last reports."
470
+ ] }) : null]
32
471
  }), onRefresh && selectedInstallId !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button$1, {
33
472
  className: "h-11 lg:h-8",
34
473
  size: "lg",
@@ -88,7 +527,17 @@ function InstallationHistoryCard({ error, history, isLoading, onNext, onPrevious
88
527
  buttonClassName: "min-h-11 px-3 lg:min-h-0 lg:px-1.5"
89
528
  }) : "—"
90
529
  })]
91
- })
530
+ }),
531
+ pendingBundleId ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
532
+ className: "col-span-2 min-w-0",
533
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("dt", {
534
+ className: "text-xs text-muted-foreground",
535
+ children: "Downloaded · Pending apply"
536
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("dd", {
537
+ className: "mt-1 text-xs",
538
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(HashValueDisplay, { value: pendingBundleId })
539
+ })]
540
+ }) : null
92
541
  ]
93
542
  })]
94
543
  }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Separator$1, {})] }) : null, selectedInstallId !== void 0 ? isLoading ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
@@ -148,7 +597,7 @@ function InstallationHistoryCard({ error, history, isLoading, onNext, onPrevious
148
597
  formatter: dateTimeFormat
149
598
  })
150
599
  }),
151
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableCell, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EventTypeBadge, { type: event.type }) }),
600
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableCell, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EventTypeDetails, { event }) }),
152
601
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableCell, {
153
602
  className: "whitespace-normal text-xs",
154
603
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
@@ -182,7 +631,7 @@ function InstallationHistoryCard({ error, history, isLoading, onNext, onPrevious
182
631
  })
183
632
  ] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
184
633
  className: "p-6 text-sm text-muted-foreground",
185
- children: pageNumber > 1 || history?.nextCursor ? "No bundle changes on this page." : "No bundle changes recorded yet."
634
+ children: pageNumber > 1 ? "No older bundle changes." : "No bundle changes recorded yet."
186
635
  }), history && (pageNumber > 1 || history.nextCursor) ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(InsightsPagination, {
187
636
  hasPrevious: pageNumber > 1,
188
637
  label: "Installation history",
@@ -196,7 +645,7 @@ function InstallationHistoryCard({ error, history, isLoading, onNext, onPrevious
196
645
  });
197
646
  }
198
647
  var getLastKnownBundleId = (event) => event.lastKnownBundleId;
199
- var getUserLabel = (event) => event.userId ?? event.username ?? "—";
648
+ var getUserLabel = (event) => event.userId ?? "—";
200
649
  function InstallationMatchesCard({ error, onNext, onPrevious, onSelect, pageNumber, results, selectedInstallId }) {
201
650
  const [expanded, setExpanded] = (0, import_react.useState)(false);
202
651
  const contentId = (0, import_react.useId)();
@@ -397,25 +846,35 @@ var popCursor = (stack) => ({
397
846
  function InstallationsPage() {
398
847
  const search = Route.useSearch();
399
848
  const navigate = Route.useNavigate();
849
+ const retention = useInsightsRetention();
400
850
  const [draftQuery, setDraftQuery] = (0, import_react.useState)(search.query ?? "");
401
851
  const [initialEventsBefore] = (0, import_react.useState)(freshBefore);
402
852
  const [initialHistoryBefore] = (0, import_react.useState)(freshBefore);
403
- const [eventsBack, setEventsBack] = (0, import_react.useState)([]);
404
- const [searchBack, setSearchBack] = (0, import_react.useState)([]);
405
- const [historyBack, setHistoryBack] = (0, import_react.useState)([]);
853
+ const pagination = useLocation({ select: (location) => location.state.insightsPagination });
854
+ const eventsBack = pagination?.eventsBack ?? [];
855
+ const searchBack = pagination?.searchBack ?? [];
856
+ const historyBack = pagination?.historyBack ?? [];
406
857
  const query = search.query?.trim() ?? "";
407
858
  const hasSearchQuery = query.length > 0;
408
859
  const hasSelection = search.installId !== void 0;
409
860
  const hasLookup = hasSearchQuery || hasSelection;
410
861
  const eventsBefore = search.eventsBefore ?? initialEventsBefore;
862
+ const eventsRange = search.eventsRange ?? "7d";
411
863
  const historyBefore = search.historyBefore ?? initialHistoryBefore;
412
- const updateSearch = (next, replace = false) => {
864
+ const updateSearch = (next, replace = false, nextPagination = {}) => {
413
865
  navigate({
414
866
  to: "/installations",
415
867
  search: {
416
868
  ...search,
417
869
  ...next
418
870
  },
871
+ state: (previous) => ({
872
+ ...previous,
873
+ insightsPagination: {
874
+ ...previous.insightsPagination,
875
+ ...nextPagination
876
+ }
877
+ }),
419
878
  replace
420
879
  });
421
880
  };
@@ -433,9 +892,9 @@ function InstallationsPage() {
433
892
  search.historyBefore
434
893
  ]);
435
894
  const events = useInsightsEventsQuery({
436
- beforeReceivedAtMs: eventsBefore,
895
+ ...eventRangeBounds(eventsRange, eventsBefore),
437
896
  cursor: search.eventsCursor,
438
- limit: EVENT_LIMIT
897
+ limit: 20
439
898
  }, !hasLookup);
440
899
  const matches = useInsightsInstallationsQuery({
441
900
  cursor: search.searchCursor,
@@ -445,12 +904,11 @@ function InstallationsPage() {
445
904
  (0, import_react.useEffect)(() => {
446
905
  const firstInstallId = matches.data?.data[0]?.installId;
447
906
  if (!hasSearchQuery || hasSelection || firstInstallId === void 0) return;
448
- setHistoryBack([]);
449
907
  updateSearch({
450
908
  historyBefore: freshBefore(),
451
909
  historyCursor: void 0,
452
910
  installId: firstInstallId
453
- }, true);
911
+ }, true, { historyBack: [] });
454
912
  }, [
455
913
  hasSearchQuery,
456
914
  hasSelection,
@@ -468,7 +926,7 @@ function InstallationsPage() {
468
926
  const scrollRef = (0, import_react.useRef)(null);
469
927
  const scrollEntry = useElementScrollRestoration({
470
928
  id: scrollRestorationId,
471
- getKey: getInsightsScrollRestorationKey
929
+ getKey: installationsScrollRestorationKey
472
930
  });
473
931
  (0, import_react.useLayoutEffect)(() => {
474
932
  if (!hasLookup && !events.isLoading && scrollRef.current) scrollRef.current.scrollTop = scrollEntry?.scrollY ?? 0;
@@ -480,14 +938,15 @@ function InstallationsPage() {
480
938
  ]);
481
939
  const clearLookup = () => {
482
940
  setDraftQuery("");
483
- setHistoryBack([]);
484
- setSearchBack([]);
485
941
  updateSearch({
486
942
  historyBefore: void 0,
487
943
  historyCursor: void 0,
488
944
  installId: void 0,
489
945
  query: void 0,
490
946
  searchCursor: void 0
947
+ }, false, {
948
+ historyBack: [],
949
+ searchBack: []
491
950
  });
492
951
  };
493
952
  const installationLookup = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(InstallationSearchPanel, {
@@ -500,14 +959,15 @@ function InstallationsPage() {
500
959
  clearLookup();
501
960
  return;
502
961
  }
503
- setHistoryBack([]);
504
- setSearchBack([]);
505
962
  updateSearch({
506
963
  historyBefore: void 0,
507
964
  historyCursor: void 0,
508
965
  installId: void 0,
509
966
  query: nextQuery,
510
967
  searchCursor: void 0
968
+ }, false, {
969
+ historyBack: [],
970
+ searchBack: []
511
971
  });
512
972
  }
513
973
  });
@@ -535,32 +995,40 @@ function InstallationsPage() {
535
995
  }), installationLookup]
536
996
  })
537
997
  }) : null, !hasLookup ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EventHistoryCard, {
998
+ description: `Downloads, applies, recoveries, and update failures, newest first, kept for ${formatDays(retention.rawDays)}. A launch without an update counts in App usage and in its installation's latest report.`,
538
999
  error: events.error,
539
1000
  eventsLocation: {
540
1001
  eventsBefore,
541
- eventsCursor: search.eventsCursor
1002
+ eventsCursor: search.eventsCursor,
1003
+ eventsRange: search.eventsRange
542
1004
  },
543
1005
  history: events.data,
544
1006
  isFetching: events.isFetching,
545
1007
  isLoading: events.isLoading,
546
1008
  onNext: () => {
547
1009
  if (!events.data?.nextCursor) return;
548
- setEventsBack(pushCursor(eventsBack, search.eventsCursor));
549
- updateSearch({ eventsCursor: events.data.nextCursor }, true);
1010
+ updateSearch({ eventsCursor: events.data.nextCursor }, true, { eventsBack: pushCursor(eventsBack, search.eventsCursor) });
550
1011
  },
551
1012
  onPrevious: () => {
552
1013
  const previous = popCursor(eventsBack);
553
- setEventsBack(previous.stack);
554
- updateSearch({ eventsCursor: previous.cursor }, true);
1014
+ updateSearch({ eventsCursor: previous.cursor }, true, { eventsBack: previous.stack });
1015
+ },
1016
+ onRangeChange: (range) => {
1017
+ updateSearch({
1018
+ eventsBefore: freshBefore(),
1019
+ eventsCursor: void 0,
1020
+ eventsRange: range
1021
+ }, false, { eventsBack: [] });
555
1022
  },
556
1023
  onRefresh: () => {
557
- setEventsBack([]);
558
1024
  updateSearch({
559
1025
  eventsBefore: freshBefore(),
560
1026
  eventsCursor: void 0
561
- }, true);
1027
+ }, true, { eventsBack: [] });
562
1028
  },
563
1029
  pageNumber: eventsBack.length + 1,
1030
+ range: eventsRange,
1031
+ rawDays: retention.rawDays,
564
1032
  children: installationLookup
565
1033
  }) : matches.isLoading && hasSearchQuery ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(InstallationResultsSkeleton, {}) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
566
1034
  className: `grid min-h-0 min-w-0 items-stretch gap-4 sm:gap-6 ${hasSearchQuery ? "lg:min-h-96 lg:grid-cols-[minmax(18rem,20rem)_minmax(0,1fr)]" : "lg:grid-cols-1"}`,
@@ -568,27 +1036,24 @@ function InstallationsPage() {
568
1036
  error: matches.error,
569
1037
  onNext: () => {
570
1038
  if (!matches.data?.nextCursor) return;
571
- setSearchBack(pushCursor(searchBack, search.searchCursor));
572
1039
  updateSearch({
573
1040
  installId: void 0,
574
1041
  searchCursor: matches.data.nextCursor
575
- }, true);
1042
+ }, true, { searchBack: pushCursor(searchBack, search.searchCursor) });
576
1043
  },
577
1044
  onPrevious: () => {
578
1045
  const previous = popCursor(searchBack);
579
- setSearchBack(previous.stack);
580
1046
  updateSearch({
581
1047
  installId: void 0,
582
1048
  searchCursor: previous.cursor
583
- }, true);
1049
+ }, true, { searchBack: previous.stack });
584
1050
  },
585
1051
  onSelect: (installId) => {
586
- setHistoryBack([]);
587
1052
  updateSearch({
588
1053
  historyBefore: freshBefore(),
589
1054
  historyCursor: void 0,
590
1055
  installId
591
- });
1056
+ }, false, { historyBack: [] });
592
1057
  },
593
1058
  pageNumber: searchBack.length + 1,
594
1059
  results: matches.data,
@@ -599,22 +1064,20 @@ function InstallationsPage() {
599
1064
  isLoading: history.isLoading || selectedInstallation.isLoading,
600
1065
  onNext: () => {
601
1066
  if (!history.data?.nextCursor) return;
602
- setHistoryBack(pushCursor(historyBack, search.historyCursor));
603
- updateSearch({ historyCursor: history.data.nextCursor }, true);
1067
+ updateSearch({ historyCursor: history.data.nextCursor }, true, { historyBack: pushCursor(historyBack, search.historyCursor) });
604
1068
  },
605
1069
  onPrevious: () => {
606
1070
  const previous = popCursor(historyBack);
607
- setHistoryBack(previous.stack);
608
- updateSearch({ historyCursor: previous.cursor }, true);
1071
+ updateSearch({ historyCursor: previous.cursor }, true, { historyBack: previous.stack });
609
1072
  },
610
1073
  onRefresh: () => {
611
- setHistoryBack([]);
612
1074
  updateSearch({
613
1075
  historyBefore: freshBefore(),
614
1076
  historyCursor: void 0
615
- }, true);
1077
+ }, true, { historyBack: [] });
616
1078
  },
617
1079
  pageNumber: historyBack.length + 1,
1080
+ retention,
618
1081
  selectedEvent,
619
1082
  selectedInstallId: search.installId
620
1083
  })]