@hot-updater/console 1.0.0-rc.8 → 1.0.0

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 (342) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/ConsoleFeatureUnavailable-jB4Loglh.js +1 -0
  3. package/.output/public/assets/EventDetails-B6yUsyNA.js +1 -0
  4. package/.output/public/assets/HashValueDisplay-BFX_kY3-.js +1 -0
  5. package/.output/public/assets/InsightsInfo-BNO0WznZ.js +1 -0
  6. package/.output/public/assets/InsightsPageHeader-B892oVml.js +1 -0
  7. package/.output/public/assets/NotFoundPage-DIqCpWa3.js +1 -0
  8. package/.output/public/assets/alert-dialog-Bbk_4-WJ.js +1 -0
  9. package/.output/public/assets/api-DCM0wr6O.js +1 -0
  10. package/.output/public/assets/api-keys-CIO9L_wu.js +1 -0
  11. package/.output/public/assets/api-keys-DVTL_--f.js +1 -0
  12. package/.output/public/assets/arrow-left-CnMYpqB7.js +1 -0
  13. package/.output/public/assets/arrow-up-right-BtffZA6e.js +1 -0
  14. package/.output/public/assets/chevron-right-BqD5wtFb.js +1 -0
  15. package/.output/public/assets/clipboard-DS9ucUQL.js +1 -0
  16. package/.output/public/assets/console-features-api-BH5m_PtQ.js +1 -0
  17. package/.output/public/assets/dialog-Bqbb7B0N.js +1 -0
  18. package/.output/public/assets/dist-LxKJB-Vu.js +1 -0
  19. package/.output/public/assets/empty-CuT2UhFp.js +1 -0
  20. package/.output/public/assets/field-BBDpjIqu.js +1 -0
  21. package/.output/public/assets/index-6o51GkFe.js +11 -0
  22. package/.output/public/assets/input-group-ja_30qaF.js +1 -0
  23. package/.output/public/assets/insights-CmraDzQh.js +1 -0
  24. package/.output/public/assets/insights-CxZ2GCYV.js +2 -0
  25. package/.output/public/assets/insights-api-BigAU9sZ.js +1 -0
  26. package/.output/public/assets/insights-usage-rpc-DYEhsCKT.js +1 -0
  27. package/.output/public/assets/insights-vNRCrfnS.js +42 -0
  28. package/.output/public/assets/insights_.distribution-ChOerfJt.js +1 -0
  29. package/.output/public/assets/insights_.distribution-D-e4iga8.js +1 -0
  30. package/.output/public/assets/insights_.distribution-DZtkibX1.js +2 -0
  31. package/.output/public/assets/installations-BazSJXE0.js +2 -0
  32. package/.output/public/assets/installations-ClHTqdAO.js +1 -0
  33. package/.output/public/assets/installations-DpKsBuHi.js +1 -0
  34. package/.output/public/assets/key-round-wS_SIZ6b.js +1 -0
  35. package/.output/public/assets/list-CgrYiadM.js +1 -0
  36. package/.output/public/assets/refresh-cw-BYgoNCco.js +1 -0
  37. package/.output/public/assets/remote-config-BWwHOkCK.js +1 -0
  38. package/.output/public/assets/remote-config-Br56BODb.js +6 -0
  39. package/.output/public/assets/remote-config-CXOi0LRu.js +1 -0
  40. package/.output/public/assets/routes-B88Erkpk.js +2 -0
  41. package/.output/public/assets/routes-CfzsAleC.js +1 -0
  42. package/.output/public/assets/search-DaTDPW25.js +1 -0
  43. package/.output/public/assets/select-BZZBXMkr.js +1 -0
  44. package/.output/public/assets/sidebar-DNVyJPfX.js +3 -0
  45. package/.output/public/assets/smartphone-DpTFgtKf.js +1 -0
  46. package/.output/public/assets/styles-DTGEAJFv.css +2 -0
  47. package/.output/public/assets/switch-DZ1TPwx-.js +1 -0
  48. package/.output/public/assets/table-Gm4qRWwE.js +1 -0
  49. package/.output/public/assets/tabs-C7FOEjFC.js +1 -0
  50. package/.output/public/assets/undo-2-CmrHjwFc.js +1 -0
  51. package/.output/public/assets/useCompositeListItem-9E4pj_CH.js +1 -0
  52. package/.output/public/assets/valueToPercent-CH8GCHaL.js +1 -0
  53. package/.output/server/__23tanstack-start-server-fn-resolver-BpRlos5Q.mjs +170 -0
  54. package/.output/server/_libs/@base-ui/react+[...].mjs +4389 -4207
  55. package/.output/server/_libs/@tanstack/react-router+[...].mjs +3802 -4022
  56. package/.output/server/_libs/@tanstack/react-router-ssr-query+[...].mjs +140 -97
  57. package/.output/server/_libs/lucide-react.mjs +221 -9
  58. package/.output/server/_libs/next-themes.mjs +1 -1
  59. package/.output/server/_libs/react-redux+[...].mjs +1 -1
  60. package/.output/server/_libs/recharts+[...].mjs +483 -901
  61. package/.output/server/_libs/sonner.mjs +1 -1
  62. package/.output/server/_libs/tanstack__history.mjs +68 -41
  63. package/.output/server/_libs/tanstack__query-core.mjs +2010 -309
  64. package/.output/server/_libs/tanstack__react-query.mjs +448 -21
  65. package/.output/server/_libs/verkit.mjs +102 -1
  66. package/.output/server/_ssr/BundleIdDisplay-x94o9rlU.mjs +13 -0
  67. package/.output/server/_ssr/ConsoleFeatureUnavailable-ldW8v8-q.mjs +58 -0
  68. package/.output/server/_ssr/EventDetails-Q8kfj9Nr.mjs +344 -0
  69. package/.output/server/_ssr/{HashValueDisplay-C5tS4oGo.mjs → HashValueDisplay-n1GholGS.mjs} +3 -3
  70. package/.output/server/_ssr/InsightsInfo-DuJFatQO.mjs +75 -0
  71. package/.output/server/_ssr/InsightsPageHeader-BSUX3Ye9.mjs +145 -0
  72. package/.output/server/_ssr/NotFoundPage-DZzOOzS3.mjs +37 -0
  73. package/.output/server/_ssr/{dialog-WiIAKl4L.mjs → alert-dialog-C43Doa0I.mjs} +6 -83
  74. package/.output/server/_ssr/{api-keys-aXriWrv7.mjs → api-keys-B4sYm8dM.mjs} +48 -9
  75. package/.output/server/_ssr/api-keys-CEnM9fqG.mjs +5 -0
  76. package/.output/server/_ssr/api-keys-rpc-BIFuUgMt.mjs +52 -0
  77. package/.output/server/_ssr/api-oZjRn9tP.mjs +186 -0
  78. package/.output/server/_ssr/api-rpc-BNiFRRK8.mjs +240 -0
  79. package/.output/server/_ssr/{auth-BF8mbAgF.mjs → auth-UP0wXs4i.mjs} +1 -1
  80. package/.output/server/_ssr/{auth-rpc-B7w3AdRr.mjs → auth-rpc-DnZqYxyq.mjs} +6 -6
  81. package/.output/server/_ssr/auth.server-DFpyxRDd.mjs +5374 -0
  82. package/.output/server/_ssr/bundleActivity-M5gzBFNg.mjs +18 -0
  83. package/.output/server/_ssr/config-WVX4IxSR.mjs +15 -0
  84. package/.output/server/_ssr/config.server-DskXCAyI.mjs +35 -0
  85. package/.output/server/_ssr/console-access-BJfAXknd.mjs +17 -0
  86. package/.output/server/_ssr/console-features-Oz0q20jJ.mjs +61 -0
  87. package/.output/server/_ssr/console-features-api-C9kiKvaV.mjs +43 -0
  88. package/.output/server/_ssr/console-features-rpc-P0GL7Z-R.mjs +19 -0
  89. package/.output/server/_ssr/{createServerFn-B2hcXoPM.mjs → createMiddleware-Cm6Tn0_Y.mjs} +67 -56
  90. package/.output/server/_ssr/{createServerRpc-DB29C_5p.mjs → createServerRpc-RLR4H-Fn.mjs} +2 -2
  91. package/.output/server/_ssr/databaseConfig-C5SkAyUy.mjs +5 -0
  92. package/.output/server/_ssr/{databaseJsonValue-d6I3nAS4.mjs → databaseJsonValue-Csbuzc9Q.mjs} +28 -5
  93. package/.output/server/_ssr/databaseRows-CPphvbag.mjs +73 -0
  94. package/.output/server/_ssr/dialog-BbYDMjdC.mjs +84 -0
  95. package/.output/server/_ssr/{dist-CyzPaI5v.mjs → dist-CbQbBIw-.mjs} +140 -7
  96. package/.output/server/_ssr/{downloadBundle-CI7JUKvC.mjs → downloadBundle-CZysjmNW.mjs} +10 -10
  97. package/.output/server/_ssr/empty-CVLGfxuu.mjs +60 -0
  98. package/.output/server/_ssr/{empty-plugin-adapters-B5QvGpEl.mjs → empty-plugin-adapters-CPtwX8a7.mjs} +1 -1
  99. package/.output/server/_ssr/failureReports-DKDhVsXA.mjs +33 -0
  100. package/.output/server/_ssr/field-asw83X0v.mjs +189 -0
  101. package/.output/server/_ssr/getBundleChildren-Cv9iz1As.mjs +22 -0
  102. package/.output/server/_ssr/{input-group-Coj6SwVP.mjs → input-group-CuYJHosb.mjs} +2 -2
  103. package/.output/server/_ssr/insights-B55FG5fm.mjs +14 -0
  104. package/.output/server/_ssr/insights-CWnHIFUV.mjs +5 -0
  105. package/.output/server/_ssr/insights-CpLpedFZ.mjs +2315 -0
  106. package/.output/server/_ssr/insights-api-sjws23WF.mjs +122 -0
  107. package/.output/server/_ssr/insights-errors-BjnFUyZj.mjs +34 -0
  108. package/.output/server/_ssr/insights-failures-rpc-BvbWvqNf.mjs +36 -0
  109. package/.output/server/_ssr/insights-failures-xaa41Buf.mjs +46 -0
  110. package/.output/server/_ssr/insights-recovery-BWQhiZaF.mjs +28 -0
  111. package/.output/server/_ssr/insights-recovery-rpc-GiYXdkaY.mjs +32 -0
  112. package/.output/server/_ssr/{insights-rpc-l2-oBYth.mjs → insights-rpc-DP_8Rmz4.mjs} +22 -14
  113. package/.output/server/_ssr/insights-usage-BpBM0U0c.mjs +29 -0
  114. package/.output/server/_ssr/insights-usage-rpc-BiolgB8e.mjs +29 -0
  115. package/.output/server/_ssr/insights-usage-rpc-KStL0zOx.mjs +41 -0
  116. package/.output/server/_ssr/insightsUsage-CzhVjsc8.mjs +56 -0
  117. package/.output/server/_ssr/insights_.distribution-CVrnbP3R.mjs +7 -0
  118. package/.output/server/_ssr/insights_.distribution-D2HaNTAA.mjs +16 -0
  119. package/.output/server/_ssr/{insights_.distribution-INw6QxbU.mjs → insights_.distribution-DN9pR422.mjs} +50 -22
  120. package/.output/server/_ssr/installations-BHmbbnH8.mjs +5 -0
  121. package/.output/server/_ssr/{installations-DH-tQuRo.mjs → installations-BSCmFq8Q.mjs} +279 -367
  122. package/.output/server/_ssr/installations-DD1g__Nc.mjs +69 -0
  123. package/.output/server/_ssr/listReleases-BfUBlCHo.mjs +79 -0
  124. package/.output/server/_ssr/plugins-BaD1slHx.mjs +2086 -0
  125. package/.output/server/_ssr/release-adoption-005tQRpo.mjs +55 -0
  126. package/.output/server/_ssr/release-adoption-rpc-BsstqxUp.mjs +41 -0
  127. package/.output/server/_ssr/releaseAdoption-CtOFkwli.mjs +114 -0
  128. package/.output/server/_ssr/releaseManagement-DFMUnDF5.mjs +11 -0
  129. package/.output/server/_ssr/remote-config-C2Ee8lXO.mjs +5 -0
  130. package/.output/server/_ssr/remote-config-Dv1ccMo-.mjs +17 -0
  131. package/.output/server/_ssr/remote-config-of0lGQH8.mjs +2648 -0
  132. package/.output/server/_ssr/remote-config-rpc-BzX31mUS.mjs +115 -0
  133. package/.output/server/_ssr/rolldown-runtime-rSIU-vHC.mjs +13 -0
  134. package/.output/server/_ssr/{router-DfFyAp5p.mjs → router-D8NuoJ_I.mjs} +117 -136
  135. package/.output/server/_ssr/{routes-BtsfVx-p.mjs → routes-DgvnFqDy.mjs} +195 -429
  136. package/.output/server/_ssr/routes-V8sDybGf.mjs +409 -0
  137. package/.output/server/_ssr/runtime.server-De0QVWc9.mjs +104 -0
  138. package/.output/server/_ssr/schema-BiAVyEj2.mjs +361 -0
  139. package/.output/server/_ssr/{select-CyvLaMza.mjs → select-t3iXRwc9.mjs} +3 -3
  140. package/.output/server/_ssr/server-h4VxnExB.mjs +8325 -0
  141. package/.output/server/_ssr/{createSsrRpc-C-dLcQuy.mjs → sidebar-DJcErBMo.mjs} +107 -47
  142. package/.output/server/_ssr/ssr.mjs +1 -1
  143. package/.output/server/_ssr/start-BfFbHKMK.mjs +4 -0
  144. package/.output/server/_ssr/switch-E-btwMGt.mjs +43 -0
  145. package/.output/server/_ssr/{table-CkVhsNpe.mjs → table-37Dd23TN.mjs} +2 -2
  146. package/.output/server/_ssr/tabs-DEFnTm95.mjs +45 -0
  147. package/.output/server/_ssr/updateFailures-H6pnnYK4.mjs +40 -0
  148. package/.output/server/_ssr/{uuidv7-D0QFkPL_.mjs → uuidv7-C88s9jWF.mjs} +2 -2
  149. package/.output/server/_tanstack-start-manifest_v-55AGsehh.mjs +139 -0
  150. package/.output/server/index.mjs +303 -205
  151. package/LICENSE +13 -14
  152. package/README.md +80 -71
  153. package/lib/index.d.mts +23 -11
  154. package/lib/vite-internal.mjs +13 -3
  155. package/lib/vite.d.mts +2 -0
  156. package/package.json +14 -14
  157. package/src/components/AppSidebar.tsx +74 -75
  158. package/src/components/ConsoleAccessPage.tsx +5 -1
  159. package/src/components/ConsoleFeatureUnavailable.tsx +80 -0
  160. package/src/components/NotFoundPage.tsx +7 -7
  161. package/src/components/features/FeatureSlots.tsx +103 -0
  162. package/src/components/features/api-keys/apiKeysFeatureUi.tsx +15 -0
  163. package/src/components/features/bundles/BundleMetadata.tsx +8 -5
  164. package/src/components/features/bundles/RolloutCohortsDialog.tsx +1 -1
  165. package/src/components/features/channels/ChannelManagementDialog.tsx +8 -6
  166. package/src/components/features/insights/AppUsage.tsx +41 -14
  167. package/src/components/features/insights/BuiltinBundle.tsx +36 -0
  168. package/src/components/features/insights/ComparedBundlesChart.tsx +310 -0
  169. package/src/components/features/insights/EstimatedCount.tsx +18 -0
  170. package/src/components/features/insights/EventDetails.tsx +390 -26
  171. package/src/components/features/insights/EventHistoryCard.tsx +111 -25
  172. package/src/components/features/insights/EventHistoryList.tsx +1 -1
  173. package/src/components/features/insights/FailureReports.tsx +407 -0
  174. package/src/components/features/insights/InsightsControls.tsx +240 -142
  175. package/src/components/features/insights/InsightsErrorAlert.tsx +14 -1
  176. package/src/components/features/insights/InsightsOverview.tsx +601 -403
  177. package/src/components/features/insights/InsightsPageHeader.tsx +19 -14
  178. package/src/components/features/insights/InsightsPeriodSelector.tsx +67 -12
  179. package/src/components/features/insights/InstallationHistoryCard.tsx +65 -10
  180. package/src/components/features/insights/InstallationMatchesCard.tsx +1 -1
  181. package/src/components/features/insights/ReleaseActivity.tsx +308 -0
  182. package/src/components/features/insights/ReportingDevicesSummary.tsx +13 -13
  183. package/src/components/features/insights/RollbackButton.tsx +118 -0
  184. package/src/components/features/insights/UpdateFailures.tsx +382 -0
  185. package/src/components/features/insights/insightsFeatureUi.tsx +35 -0
  186. package/src/components/features/releases/ReleaseEditorSheet.tsx +27 -13
  187. package/src/components/features/remote-config/ConditionDialog.tsx +592 -0
  188. package/src/components/features/remote-config/ConditionsCard.tsx +247 -0
  189. package/src/components/features/remote-config/ParameterDialog.tsx +426 -0
  190. package/src/components/features/remote-config/ParametersCard.tsx +254 -0
  191. package/src/components/features/remote-config/PreviewCard.tsx +284 -0
  192. package/src/components/features/remote-config/PublishDialog.tsx +325 -0
  193. package/src/components/features/remote-config/RemoteConfigPage.tsx +353 -0
  194. package/src/components/features/remote-config/RuleSummary.tsx +21 -0
  195. package/src/components/features/remote-config/ValueInput.tsx +151 -0
  196. package/src/components/features/remote-config/VersionsCard.tsx +384 -0
  197. package/src/components/features/remote-config/remoteConfigFeatureUi.tsx +15 -0
  198. package/src/components/features/remote-config/useDateTimeText.ts +16 -0
  199. package/src/components/ui/sidebar.tsx +22 -29
  200. package/src/index.ts +26 -19
  201. package/src/lib/api-keys-api.ts +0 -28
  202. package/src/lib/api-keys-rpc.ts +27 -38
  203. package/src/lib/api-rpc.ts +125 -288
  204. package/src/lib/api.ts +15 -134
  205. package/src/lib/bundle-activity.ts +24 -4
  206. package/src/lib/console-access.ts +20 -0
  207. package/src/lib/console-features-api.ts +68 -0
  208. package/src/lib/console-features-rpc.ts +13 -0
  209. package/src/lib/console-features.ts +98 -0
  210. package/src/lib/insights-api.ts +56 -2
  211. package/src/lib/insights-errors.ts +64 -0
  212. package/src/lib/insights-failures-rpc.ts +36 -0
  213. package/src/lib/insights-failures.ts +130 -0
  214. package/src/lib/insights-recovery-rpc.ts +13 -17
  215. package/src/lib/insights-recovery.ts +12 -36
  216. package/src/lib/insights-retention.ts +21 -0
  217. package/src/lib/insights-rpc.ts +30 -12
  218. package/src/lib/insights-search.ts +50 -4
  219. package/src/lib/insights-usage-rpc.ts +15 -9
  220. package/src/lib/insights-usage.ts +41 -3
  221. package/src/lib/insights-view.ts +34 -5
  222. package/src/lib/release-adoption-api.ts +214 -0
  223. package/src/lib/release-adoption-rpc.ts +49 -0
  224. package/src/lib/release-adoption.ts +164 -0
  225. package/src/lib/remote-config-api.ts +119 -0
  226. package/src/lib/remote-config-draft.ts +666 -0
  227. package/src/lib/remote-config-rpc.ts +196 -0
  228. package/src/lib/scroll-restoration.ts +21 -0
  229. package/src/lib/server/auth.server.ts +13 -5
  230. package/src/lib/server/bundleActivity.ts +27 -28
  231. package/src/lib/server/config.server.ts +21 -76
  232. package/src/lib/server/console-feature-apis.ts +70 -0
  233. package/src/lib/server/console-runtime.server.ts +82 -38
  234. package/src/lib/server/downloadBundle.ts +14 -15
  235. package/src/lib/server/failureReports.ts +50 -0
  236. package/src/lib/server/getBundleChildren.ts +31 -122
  237. package/src/lib/server/insightsUsage.ts +52 -113
  238. package/src/lib/server/listReleases.ts +109 -44
  239. package/src/lib/server/releaseAdoption.ts +151 -0
  240. package/src/lib/server/releaseReachability.ts +8 -8
  241. package/src/lib/server/remoteConfig.ts +75 -0
  242. package/src/lib/server/runtime.server.ts +120 -31
  243. package/src/lib/server/updateFailures.ts +66 -0
  244. package/src/lib/use-dialog-target.ts +27 -0
  245. package/src/routeTree.gen.ts +44 -44
  246. package/src/router.tsx +3 -2
  247. package/src/routes/-installations-search.ts +32 -8
  248. package/src/routes/-releases-search.ts +76 -29
  249. package/src/routes/__root.tsx +7 -1
  250. package/src/routes/api/bundles/$bundleId/download.ts +2 -5
  251. package/src/routes/api-keys.tsx +5 -2
  252. package/src/routes/index.tsx +210 -152
  253. package/src/routes/insights.tsx +91 -23
  254. package/src/routes/insights_.distribution.tsx +50 -9
  255. package/src/routes/installations.tsx +97 -40
  256. package/src/routes/remote-config.tsx +42 -0
  257. package/src/styles.css +9 -0
  258. package/src/vite-internal.ts +15 -3
  259. package/src/vite.ts +2 -0
  260. package/.output/public/assets/HashValueDisplay-BpTc3Oyg.js +0 -1
  261. package/.output/public/assets/InsightsPageHeader-DC2eEst8.js +0 -1
  262. package/.output/public/assets/api-CdUyUqzR.js +0 -42
  263. package/.output/public/assets/api-keys-64PM9PwW.js +0 -1
  264. package/.output/public/assets/api-keys-api-BeaJnvY5.js +0 -1
  265. package/.output/public/assets/arrow-left-04Rh8Zgp.js +0 -1
  266. package/.output/public/assets/card-CYHs5FZv.js +0 -1
  267. package/.output/public/assets/chart-no-axes-combined-DwyMsVFW.js +0 -1
  268. package/.output/public/assets/createServerFn-DU71xucx.js +0 -3
  269. package/.output/public/assets/dialog-IVMkBRCq.js +0 -1
  270. package/.output/public/assets/dist-BR4GzeEu.js +0 -1
  271. package/.output/public/assets/field-B3CYDpjg.js +0 -1
  272. package/.output/public/assets/index-C39o7rJH.js +0 -10
  273. package/.output/public/assets/info-C3y9HNoU.js +0 -1
  274. package/.output/public/assets/input-group-nLZylhWF.js +0 -1
  275. package/.output/public/assets/insights-Bm9v8uO3.js +0 -2
  276. package/.output/public/assets/insights-DS3iO7Up.js +0 -1
  277. package/.output/public/assets/insights-search-Byj3g3Mp.js +0 -1
  278. package/.output/public/assets/insights-usage-rpc-BaGR3lgq.js +0 -1
  279. package/.output/public/assets/insights_.distribution-B1i6cjlQ.js +0 -1
  280. package/.output/public/assets/insights_.distribution-C1Wf27eB.js +0 -2
  281. package/.output/public/assets/installations-CkFW4fV9.js +0 -2
  282. package/.output/public/assets/installations-DxTaIcHD.js +0 -1
  283. package/.output/public/assets/lazyRouteComponent-BapzjYnb.js +0 -1
  284. package/.output/public/assets/list-Dqt53fWZ.js +0 -1
  285. package/.output/public/assets/loader-circle-CUKfUqow.js +0 -1
  286. package/.output/public/assets/preload-helper-ClBMtM1g.js +0 -1
  287. package/.output/public/assets/refresh-cw-CNE_2PnD.js +0 -1
  288. package/.output/public/assets/routes-Cgtvspjg.js +0 -2
  289. package/.output/public/assets/routes-O2r2UUN8.js +0 -1
  290. package/.output/public/assets/shield-check-BFcJ46kz.js +0 -1
  291. package/.output/public/assets/signing-BgspC-xP.js +0 -1
  292. package/.output/public/assets/styles-DnrWuBwd.css +0 -2
  293. package/.output/public/assets/table-BuWQgxJJ.js +0 -1
  294. package/.output/public/assets/useMutation-CSV9NCUl.js +0 -1
  295. package/.output/public/assets/useOpenInteractionType-D5kduCTD.js +0 -1
  296. package/.output/public/assets/valueToPercent-BAtcbSLk.js +0 -1
  297. package/.output/server/__23tanstack-start-server-fn-resolver-CmYkol9D.mjs +0 -150
  298. package/.output/server/_ssr/InsightsPageHeader-Dma3dVj1.mjs +0 -64
  299. package/.output/server/_ssr/api-C3bGmgY0.mjs +0 -332
  300. package/.output/server/_ssr/api-keys-api-BRF6rbRC.mjs +0 -60
  301. package/.output/server/_ssr/api-keys-rpc-BMa1ZM6N.mjs +0 -136
  302. package/.output/server/_ssr/api-rpc-BYQ2e0z6.mjs +0 -1399
  303. package/.output/server/_ssr/auth.server-CmicHh0J.mjs +0 -47
  304. package/.output/server/_ssr/bundle-signing-rpc-DbQ4pFAX.mjs +0 -16
  305. package/.output/server/_ssr/bundle-signing.server-Uqt1OF49.mjs +0 -12
  306. package/.output/server/_ssr/bundleActivity-pBrPSG01.mjs +0 -28
  307. package/.output/server/_ssr/card-B7KSO_25.mjs +0 -108
  308. package/.output/server/_ssr/config-Dv8qLDZ0.mjs +0 -13
  309. package/.output/server/_ssr/config.server-C-d1QaBU.mjs +0 -368
  310. package/.output/server/_ssr/databaseRows-5bCRTxm-.mjs +0 -126
  311. package/.output/server/_ssr/deleteBundle-8X-jq7Z7.mjs +0 -66
  312. package/.output/server/_ssr/field-BDwuU8RE.mjs +0 -74
  313. package/.output/server/_ssr/getBundleChildren-DoL8l_AS.mjs +0 -50
  314. package/.output/server/_ssr/insights-BDJjaDLp.mjs +0 -938
  315. package/.output/server/_ssr/insights-D0FWpfOS.mjs +0 -10
  316. package/.output/server/_ssr/insights-recovery-Cv6RSyeR.mjs +0 -21
  317. package/.output/server/_ssr/insights-recovery-rpc-BE9YsK_T.mjs +0 -37
  318. package/.output/server/_ssr/insights-search-1czJMZgk.mjs +0 -21
  319. package/.output/server/_ssr/insights-usage-rpc-BE_aCnea.mjs +0 -184
  320. package/.output/server/_ssr/insights-usage-rpc-CtAolz-t.mjs +0 -24
  321. package/.output/server/_ssr/insightsContract-B09K_Px1.mjs +0 -303
  322. package/.output/server/_ssr/insightsHistory-Ci4rYAgl.mjs +0 -41
  323. package/.output/server/_ssr/insightsRecovery-CaghWL2t.mjs +0 -113
  324. package/.output/server/_ssr/insightsUsage-DNIj6jxF.mjs +0 -71
  325. package/.output/server/_ssr/insights_.distribution-Cp0kf1vW.mjs +0 -10
  326. package/.output/server/_ssr/installations-Bhyiwx8G.mjs +0 -29
  327. package/.output/server/_ssr/routes-xBkI2Fmt.mjs +0 -37
  328. package/.output/server/_ssr/runtime.server-CsiKFp_Z.mjs +0 -436
  329. package/.output/server/_ssr/server-BdkuOWe8.mjs +0 -7468
  330. package/.output/server/_ssr/signing-CQ70saFm.mjs +0 -133
  331. package/.output/server/_ssr/start-DpViQGnt.mjs +0 -4
  332. package/.output/server/_tanstack-start-manifest_v-CrBsoKQQ.mjs +0 -125
  333. package/src/components/features/bundles/BundleActivityChart.tsx +0 -97
  334. package/src/components/features/bundles/BundleInsightsSummary.tsx +0 -126
  335. package/src/components/features/signing/BundleSigningPage.tsx +0 -139
  336. package/src/lib/bundle-signing-api.ts +0 -14
  337. package/src/lib/bundle-signing-rpc.ts +0 -16
  338. package/src/lib/server/bundle-signing.server.ts +0 -23
  339. package/src/lib/server/deleteBundle.ts +0 -145
  340. package/src/lib/server/insightsHistory.ts +0 -52
  341. package/src/lib/server/insightsRecovery.ts +0 -187
  342. package/src/routes/signing.tsx +0 -37
@@ -0,0 +1,118 @@
1
+ import { useQueryClient } from "@tanstack/react-query";
2
+ import { Undo2 } from "lucide-react";
3
+ import { useState } from "react";
4
+ import { toast } from "sonner";
5
+
6
+ import { BundleIdDisplay } from "@/components/BundleIdDisplay";
7
+ import {
8
+ AlertDialog,
9
+ AlertDialogAction,
10
+ AlertDialogCancel,
11
+ AlertDialogContent,
12
+ AlertDialogDescription,
13
+ AlertDialogFooter,
14
+ AlertDialogHeader,
15
+ AlertDialogTitle,
16
+ } from "@/components/ui/alert-dialog";
17
+ import { Button } from "@/components/ui/button";
18
+ import {
19
+ usePreflightReleaseMutation,
20
+ useUpdateReleaseMutation,
21
+ } from "@/lib/api";
22
+ import type { AdoptionRelease } from "@/lib/release-adoption";
23
+
24
+ const percent = (rate: number) => `${(rate * 100).toFixed(1)}%`;
25
+
26
+ /**
27
+ * Rolls a crashing bundle back the way its editor does: disabling its
28
+ * release sends installations running it back to the previous enabled
29
+ * release on their next update check.
30
+ */
31
+ export function RollbackButton({
32
+ release,
33
+ rate,
34
+ crashes,
35
+ attempts,
36
+ }: {
37
+ readonly release: AdoptionRelease;
38
+ readonly rate: number;
39
+ readonly crashes: number;
40
+ readonly attempts: number;
41
+ }) {
42
+ const [open, setOpen] = useState(false);
43
+ const [error, setError] = useState("");
44
+ const queryClient = useQueryClient();
45
+ const preflight = usePreflightReleaseMutation();
46
+ const update = useUpdateReleaseMutation();
47
+ const busy = preflight.isPending || update.isPending;
48
+ const id = release.releaseId;
49
+ const rollBack = async () => {
50
+ const input = {
51
+ expectedRevision: release.revision,
52
+ patch: { enabled: false },
53
+ releaseId: release.releaseId,
54
+ };
55
+ setError("");
56
+ try {
57
+ await preflight.mutateAsync(input);
58
+ await update.mutateAsync(input);
59
+ await queryClient.invalidateQueries({
60
+ queryKey: ["insights", "adoption-releases"],
61
+ });
62
+ toast.success(`${id} rolled back`, {
63
+ description:
64
+ "Installations running it return to the previous enabled bundle on their next update check.",
65
+ });
66
+ setOpen(false);
67
+ } catch (caught) {
68
+ setError(
69
+ caught instanceof Error
70
+ ? caught.message
71
+ : "The bundle could not be rolled back.",
72
+ );
73
+ }
74
+ };
75
+ return (
76
+ <AlertDialog
77
+ open={open}
78
+ onOpenChange={(next) => {
79
+ if (busy) return;
80
+ setOpen(next);
81
+ if (!next) setError("");
82
+ }}
83
+ >
84
+ <Button variant="destructive" size="sm" onClick={() => setOpen(true)}>
85
+ <Undo2 aria-hidden="true" data-icon="inline-start" />
86
+ Roll back
87
+ </Button>
88
+ <AlertDialogContent>
89
+ <AlertDialogHeader>
90
+ <AlertDialogTitle>Roll back this bundle?</AlertDialogTitle>
91
+ <BundleIdDisplay bundleId={id} />
92
+ <AlertDialogDescription>
93
+ It crashed for {percent(rate)} of the installations that tried it (
94
+ {crashes.toLocaleString()} of {attempts.toLocaleString()}). Rolling
95
+ back disables it, so installations running it return to the previous
96
+ enabled bundle on their next update check. You can enable it again
97
+ in its bundle details.
98
+ </AlertDialogDescription>
99
+ </AlertDialogHeader>
100
+ {error ? (
101
+ <p role="alert" className="text-sm text-destructive">
102
+ {error}
103
+ </p>
104
+ ) : null}
105
+ <AlertDialogFooter>
106
+ <AlertDialogCancel disabled={busy}>Cancel</AlertDialogCancel>
107
+ <AlertDialogAction
108
+ variant="destructive"
109
+ disabled={busy}
110
+ onClick={() => void rollBack()}
111
+ >
112
+ {busy ? "Rolling back…" : "Roll back"}
113
+ </AlertDialogAction>
114
+ </AlertDialogFooter>
115
+ </AlertDialogContent>
116
+ </AlertDialog>
117
+ );
118
+ }
@@ -0,0 +1,382 @@
1
+ import { ChevronRight, RotateCw } from "lucide-react";
2
+ import type { ReactNode } from "react";
3
+
4
+ import { Button } from "@/components/ui/button";
5
+ import {
6
+ Card,
7
+ CardContent,
8
+ CardDescription,
9
+ CardFooter,
10
+ CardHeader,
11
+ CardTitle,
12
+ } from "@/components/ui/card";
13
+ import { Separator } from "@/components/ui/separator";
14
+ import { Skeleton } from "@/components/ui/skeleton";
15
+ import {
16
+ Table,
17
+ TableBody,
18
+ TableCell,
19
+ TableHead,
20
+ TableHeader,
21
+ TableRow,
22
+ } from "@/components/ui/table";
23
+ import {
24
+ checkFailureRate,
25
+ failureDetailParts,
26
+ failureRate,
27
+ failureReasonLabel,
28
+ failureStageLabel,
29
+ formatRate,
30
+ type InsightsFailureBreakdown,
31
+ type UpdateFailuresReport,
32
+ } from "@/lib/insights-failures";
33
+ import { cn } from "@/lib/utils";
34
+
35
+ import { EstimatedCount } from "./EstimatedCount";
36
+ import { InsightsErrorAlert } from "./InsightsErrorAlert";
37
+ import { InsightsInfo } from "./InsightsInfo";
38
+
39
+ const share = (events: number, total: number) =>
40
+ total === 0 ? "—" : `${((events / total) * 100).toFixed(1)}%`;
41
+
42
+ /**
43
+ * One kind of failure: its rate as the headline, then how many failures and
44
+ * installations it holds.
45
+ */
46
+ function FailureSummary({
47
+ id,
48
+ title,
49
+ info,
50
+ rate,
51
+ of,
52
+ failures,
53
+ installations,
54
+ previous,
55
+ children,
56
+ }: {
57
+ readonly id: string;
58
+ readonly title: string;
59
+ readonly info: string;
60
+ readonly rate: number | null;
61
+ /** What the rate is a share of. */
62
+ readonly of: string;
63
+ readonly failures: number;
64
+ readonly installations: number;
65
+ readonly previous?: {
66
+ readonly rate: number | null;
67
+ readonly complete: boolean;
68
+ };
69
+ readonly children?: ReactNode;
70
+ }) {
71
+ return (
72
+ <section aria-labelledby={id} className="flex min-w-0 flex-col gap-1">
73
+ <h3
74
+ id={id}
75
+ className="flex min-h-11 items-center gap-1 text-sm font-medium sm:min-h-7"
76
+ >
77
+ {title}
78
+ <InsightsInfo label={`About ${title.toLowerCase()}`}>
79
+ {info}
80
+ </InsightsInfo>
81
+ </h3>
82
+ <p className="text-3xl font-semibold tracking-tight tabular-nums">
83
+ <Rate value={rate} />
84
+ </p>
85
+ <p className="text-xs text-muted-foreground">{of}</p>
86
+ {previous ? (
87
+ <RateChange
88
+ value={rate}
89
+ previous={previous.rate}
90
+ complete={previous.complete}
91
+ />
92
+ ) : null}
93
+ <p className="mt-2 text-sm text-muted-foreground tabular-nums">
94
+ {failures.toLocaleString()} {failures === 1 ? "failure" : "failures"}
95
+ {" · "}
96
+ <EstimatedCount value={installations} />{" "}
97
+ {installations === 1 ? "installation" : "installations"}
98
+ </p>
99
+ {children}
100
+ </section>
101
+ );
102
+ }
103
+
104
+ function Rate({ value }: { readonly value: number | null }) {
105
+ const formatted = formatRate(value);
106
+ return value === null ? (
107
+ formatted
108
+ ) : (
109
+ <>
110
+ {formatted.slice(0, -1)}
111
+ <span className="ml-0.5 text-sm font-normal text-muted-foreground">
112
+ %
113
+ </span>
114
+ </>
115
+ );
116
+ }
117
+
118
+ function RateChange({
119
+ value,
120
+ previous,
121
+ complete,
122
+ }: {
123
+ readonly value: number | null;
124
+ readonly previous: number | null;
125
+ readonly complete: boolean;
126
+ }) {
127
+ // No change to show before a whole previous period was recorded.
128
+ if (!complete || value === null || previous === null) return null;
129
+ const difference = (value - previous) * 100;
130
+ const rounded = Number(difference.toFixed(2));
131
+ return (
132
+ <span
133
+ className={cn(
134
+ "mt-1 block text-xs font-normal",
135
+ rounded > 0 ? "text-warning" : "text-muted-foreground",
136
+ )}
137
+ >
138
+ {rounded === 0
139
+ ? "Unchanged"
140
+ : `${rounded > 0 ? "↑ +" : "↓ "}${rounded.toFixed(2)} pp`}{" "}
141
+ vs previous period
142
+ </span>
143
+ );
144
+ }
145
+
146
+ /** One stage and reason, and what else its clients knew, most first. */
147
+ function FailureRow({
148
+ failure,
149
+ total,
150
+ }: {
151
+ readonly failure: InsightsFailureBreakdown;
152
+ readonly total: number;
153
+ }) {
154
+ const label = `${failureStageLabel(failure.stage)} · ${failureReasonLabel(failure.reason)}`;
155
+ return (
156
+ <TableRow className="[&>td]:px-2 [&>td]:py-3 [&>td]:align-top sm:[&>td]:px-4">
157
+ <TableCell className="whitespace-normal">
158
+ <details className="group/failure">
159
+ <summary
160
+ aria-label={label}
161
+ className="flex min-h-11 w-fit max-w-full cursor-pointer list-none items-center gap-3 rounded-md outline-none focus-visible:ring-2 focus-visible:ring-ring [&::-webkit-details-marker]:hidden"
162
+ >
163
+ <ChevronRight
164
+ aria-hidden="true"
165
+ className="size-4 shrink-0 text-muted-foreground group-open/failure:rotate-90"
166
+ />
167
+ <span className="flex min-w-0 flex-col gap-1">
168
+ <span className="text-xs text-muted-foreground">
169
+ {failureStageLabel(failure.stage)}
170
+ </span>
171
+ <span className="text-sm font-medium wrap-anywhere">
172
+ {failureReasonLabel(failure.reason)}
173
+ </span>
174
+ </span>
175
+ </summary>
176
+ <ul
177
+ aria-label={`${label} details`}
178
+ className="mt-3 flex flex-col gap-3 rounded-md border bg-muted/20 p-3 text-sm"
179
+ >
180
+ {failure.details.map((detail) => {
181
+ const parts = failureDetailParts(detail);
182
+ return (
183
+ <li
184
+ key={JSON.stringify(detail)}
185
+ className="flex justify-between gap-4"
186
+ >
187
+ <span className="wrap-anywhere">
188
+ {parts.length === 0
189
+ ? "No details reported"
190
+ : parts.join(" · ")}
191
+ </span>
192
+ <span className="shrink-0 font-medium tabular-nums">
193
+ {detail.events.toLocaleString()}
194
+ </span>
195
+ </li>
196
+ );
197
+ })}
198
+ </ul>
199
+ </details>
200
+ </TableCell>
201
+ <TableCell className="text-right tabular-nums">
202
+ <span className="inline-flex min-h-11 items-center text-sm font-medium">
203
+ {failure.events.toLocaleString()}
204
+ </span>
205
+ </TableCell>
206
+ <TableCell className="text-right tabular-nums text-muted-foreground">
207
+ <span className="inline-flex min-h-11 items-center text-sm">
208
+ {share(failure.events, total)}
209
+ </span>
210
+ </TableCell>
211
+ </TableRow>
212
+ );
213
+ }
214
+
215
+ function FailuresReport({
216
+ report,
217
+ errors,
218
+ }: {
219
+ readonly report: UpdateFailuresReport;
220
+ readonly errors?: ReactNode;
221
+ }) {
222
+ const breakdown = report.breakdown ?? [];
223
+ const total = breakdown.reduce((sum, { events }) => sum + events, 0);
224
+ const unreasoned = breakdown
225
+ .filter(({ reason }) => reason === "unknown")
226
+ .reduce((sum, { events }) => sum + events, 0);
227
+ const patchAttempts = report.patchDownloads + report.patchFallbacks;
228
+ return (
229
+ <div className="flex flex-col gap-8">
230
+ <div className={cn("grid gap-6", report.checks && "sm:grid-cols-2")}>
231
+ <FailureSummary
232
+ id="download-install-failures"
233
+ title="Downloads & installs"
234
+ info="Failed downloads and installs ÷ those plus successful downloads."
235
+ rate={failureRate(report)}
236
+ of="of update attempts failed"
237
+ failures={report.failedUpdates}
238
+ installations={report.failedInstallations}
239
+ previous={
240
+ report.previous && {
241
+ rate: report.previous.attemptRate,
242
+ complete: report.previous.complete,
243
+ }
244
+ }
245
+ >
246
+ {patchAttempts > 0 ? (
247
+ <p className="text-sm text-muted-foreground tabular-nums">
248
+ {report.patchFallbacks.toLocaleString()} of{" "}
249
+ {patchAttempts.toLocaleString()} patch downloads fell back to the
250
+ full archive
251
+ </p>
252
+ ) : null}
253
+ </FailureSummary>
254
+ {report.checks ? (
255
+ <FailureSummary
256
+ id="update-check-failures"
257
+ title="Update checks"
258
+ info="Installations whose update check failed ÷ active installations. A check that fails offline isn't reported."
259
+ rate={checkFailureRate(report.checks)}
260
+ of="of active installations had a check fail"
261
+ failures={report.checks.failures}
262
+ installations={report.checks.failedInstallations}
263
+ previous={
264
+ report.previous && {
265
+ rate: report.previous.checkRate,
266
+ complete: report.previous.complete,
267
+ }
268
+ }
269
+ />
270
+ ) : null}
271
+ </div>
272
+ <Separator />
273
+ {errors ? (
274
+ <>
275
+ {errors}
276
+ <Separator />
277
+ </>
278
+ ) : null}
279
+ <section
280
+ aria-labelledby="failures-by-stage"
281
+ className="flex flex-col gap-3"
282
+ >
283
+ <h3 className="text-sm font-medium" id="failures-by-stage">
284
+ Failures by stage and reason
285
+ </h3>
286
+ {unreasoned * 2 > total ? (
287
+ <p className="text-sm text-muted-foreground">
288
+ Most report no reason: an SDK that doesn&apos;t classify failures
289
+ reports every failed check, offline ones included.
290
+ </p>
291
+ ) : null}
292
+ {breakdown.length === 0 ? (
293
+ <p className="text-sm text-muted-foreground">
294
+ No update failures in this period.
295
+ </p>
296
+ ) : (
297
+ <Table aria-label="Failures by stage and reason">
298
+ <TableHeader>
299
+ <TableRow className="[&>th]:px-2 sm:[&>th]:px-4">
300
+ <TableHead>Stage / reason</TableHead>
301
+ <TableHead className="w-16 text-right sm:w-24">
302
+ Reports
303
+ </TableHead>
304
+ <TableHead className="w-16 text-right sm:w-24">Share</TableHead>
305
+ </TableRow>
306
+ </TableHeader>
307
+ <TableBody>
308
+ {breakdown.map((failure) => (
309
+ <FailureRow
310
+ key={`${failure.stage} ${failure.reason}`}
311
+ failure={failure}
312
+ total={total}
313
+ />
314
+ ))}
315
+ </TableBody>
316
+ </Table>
317
+ )}
318
+ </section>
319
+ </div>
320
+ );
321
+ }
322
+
323
+ /**
324
+ * Update failures for Release health's scope and period: counts, rates, and
325
+ * the stage and reason breakdown with what else the clients knew.
326
+ */
327
+ export function UpdateFailures({
328
+ errors,
329
+ query,
330
+ onRefresh,
331
+ }: {
332
+ readonly errors?: ReactNode;
333
+ readonly query: {
334
+ readonly data: UpdateFailuresReport | undefined;
335
+ readonly error: Error | null;
336
+ readonly isPending: boolean;
337
+ readonly isFetching: boolean;
338
+ };
339
+ readonly onRefresh: () => void;
340
+ }) {
341
+ return (
342
+ <section aria-label="Update failures">
343
+ <Card className="min-w-0 overflow-hidden shadow-sm">
344
+ <CardHeader className="flex flex-col gap-1.5 p-4 sm:p-6">
345
+ <div className="flex flex-wrap items-center justify-between gap-4">
346
+ <CardTitle>Update failures</CardTitle>
347
+ <Button
348
+ aria-label="Refresh update failures"
349
+ variant="ghost"
350
+ size="icon-lg"
351
+ disabled={query.isFetching}
352
+ onClick={onRefresh}
353
+ >
354
+ <RotateCw aria-hidden="true" />
355
+ </Button>
356
+ </div>
357
+ <CardDescription>
358
+ Track failure rates, inspect original errors, and open individual
359
+ reports in the selected Release health scope and period.
360
+ </CardDescription>
361
+ </CardHeader>
362
+ <CardContent className="px-4 pb-4 sm:px-6 sm:pb-6">
363
+ {query.isPending ? (
364
+ <Skeleton aria-label="Loading update failures" className="h-64" />
365
+ ) : query.error ? (
366
+ <InsightsErrorAlert
367
+ error={query.error}
368
+ fallbackTitle="Update failures unavailable"
369
+ />
370
+ ) : query.data ? (
371
+ <FailuresReport report={query.data} errors={errors} />
372
+ ) : null}
373
+ </CardContent>
374
+ {query.data?.coverage.kind === "partial" ? (
375
+ <CardFooter className="border-t px-6 py-5">
376
+ <span className="text-xs text-muted-foreground">Partial</span>
377
+ </CardFooter>
378
+ ) : null}
379
+ </Card>
380
+ </section>
381
+ );
382
+ }
@@ -0,0 +1,35 @@
1
+ import { Link } from "@tanstack/react-router";
2
+ import { ChartNoAxesCombined } from "lucide-react";
3
+
4
+ import type { ConsoleFeatureUiRegistry } from "../FeatureSlots";
5
+ import {
6
+ BundleInsightsSummary,
7
+ ReleaseFailuresSection,
8
+ releaseActivityColumn,
9
+ } from "./ReleaseActivity";
10
+
11
+ /**
12
+ * What the Insights features add: their navigation item, release activity on
13
+ * the Bundles page and in the release editor, and a release's download
14
+ * failures in the release editor, which a self-hosted server serves too.
15
+ */
16
+ export const insightsFeatureUi = {
17
+ insights: {
18
+ navigation: {
19
+ icon: <ChartNoAxesCombined />,
20
+ paths: ["/insights", "/insights/distribution", "/installations"],
21
+ // A self-hosted server's admin API serves events, not the overview.
22
+ link: ({ features, onClick }) =>
23
+ features.insightsAnalytics ? (
24
+ <Link to="/insights" onClick={onClick} />
25
+ ) : (
26
+ <Link to="/installations" onClick={onClick} />
27
+ ),
28
+ },
29
+ releaseSection: ({ release }) => <ReleaseFailuresSection input={release} />,
30
+ },
31
+ insightsAnalytics: {
32
+ releaseColumn: releaseActivityColumn,
33
+ releaseSection: ({ release }) => <BundleInsightsSummary input={release} />,
34
+ },
35
+ } satisfies ConsoleFeatureUiRegistry;
@@ -1,23 +1,23 @@
1
- import {
2
- getPatchBaseBundleId,
3
- INVALID_COHORT_ERROR_MESSAGE,
4
- isValidCohort,
5
- normalizeCohortValue,
6
- } from "@hot-updater/core";
7
1
  import type {
8
2
  ChannelRow,
9
3
  ReleasePolicyPatch,
10
4
  ReleaseRow,
11
5
  } from "@hot-updater/plugin-core";
6
+ import {
7
+ getPatchBaseBundleId,
8
+ INVALID_COHORT_ERROR_MESSAGE,
9
+ isValidCohort,
10
+ normalizeCohortValue,
11
+ } from "@hot-updater/protocol";
12
12
  import { AlertTriangle, Download, Plus, X } from "lucide-react";
13
13
  import { useEffect, useState } from "react";
14
14
  import { toast } from "sonner";
15
15
  import { normalizeRange } from "verkit";
16
16
 
17
17
  import { BundleIdDisplay } from "@/components/BundleIdDisplay";
18
- import { BundleInsightsSummary } from "@/components/features/bundles/BundleInsightsSummary";
19
18
  import { BundleMetadata } from "@/components/features/bundles/BundleMetadata";
20
19
  import { RolloutCohortsDialog } from "@/components/features/bundles/RolloutCohortsDialog";
20
+ import { ReleaseSections } from "@/components/features/FeatureSlots";
21
21
  import { PlatformIcon } from "@/components/PlatformIcon";
22
22
  import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
23
23
  import {
@@ -204,11 +204,14 @@ function RolloutPercentageInput({
204
204
  export function ReleaseEditorSheet({
205
205
  channels,
206
206
  onOpenChange,
207
+ onShowScope,
207
208
  open,
208
209
  releaseId,
209
210
  }: {
210
211
  channels: readonly ChannelRow[];
211
212
  onOpenChange: (open: boolean) => void;
213
+ /** Lists the bundles of this release's catalog scope: its channel, platform, and target kind. */
214
+ onShowScope?: (scopeKey: string) => void;
212
215
  open: boolean;
213
216
  releaseId: string;
214
217
  }) {
@@ -369,7 +372,7 @@ export function ReleaseEditorSheet({
369
372
  />
370
373
  {!release.bundle_id ? (
371
374
  <span className="text-xs text-foreground">
372
- Built-in app
375
+ Built-in bundle
373
376
  </span>
374
377
  ) : null}
375
378
  </span>
@@ -410,11 +413,12 @@ export function ReleaseEditorSheet({
410
413
  {release && draft ? (
411
414
  <div className="flex flex-col gap-6 px-4 pb-4 sm:px-6 sm:pb-6">
412
415
  {channelName ? (
413
- <BundleInsightsSummary
414
- input={{
416
+ <ReleaseSections
417
+ release={{
415
418
  platform: release.platform,
416
419
  channel: channelName,
417
420
  releaseId: release.id,
421
+ builtIn: !release.bundle_id,
418
422
  }}
419
423
  />
420
424
  ) : null}
@@ -601,7 +605,7 @@ export function ReleaseEditorSheet({
601
605
  <h3 className="text-sm font-medium">Actions</h3>
602
606
  <Button
603
607
  className="w-full"
604
- disabled={release.kind !== "BUNDLE" || busy}
608
+ disabled={!release.bundle_id || busy}
605
609
  onClick={() => setShowPromote(true)}
606
610
  size="sm"
607
611
  variant="outline"
@@ -624,7 +628,7 @@ export function ReleaseEditorSheet({
624
628
  variant="outline"
625
629
  >
626
630
  <Download data-icon="inline-start" />
627
- Download bundle
631
+ Download manifest
628
632
  </Button>
629
633
  ) : null}
630
634
  <Button
@@ -662,7 +666,7 @@ export function ReleaseEditorSheet({
662
666
  <div className="sm:col-span-2">
663
667
  <dt>Artifact ID</dt>
664
668
  <dd className="mt-1 break-all font-mono text-foreground">
665
- {release.bundle_id ?? "Built-in app"}
669
+ {release.bundle_id ?? "Built-in bundle"}
666
670
  </dd>
667
671
  </div>
668
672
  <div>
@@ -698,6 +702,16 @@ export function ReleaseEditorSheet({
698
702
  <dd className="mt-1 break-all font-mono text-foreground">
699
703
  {release.scope_key}
700
704
  </dd>
705
+ {onShowScope ? (
706
+ <Button
707
+ className="mt-1 h-auto px-0 text-xs"
708
+ onClick={() => onShowScope(release.scope_key)}
709
+ size="sm"
710
+ variant="link"
711
+ >
712
+ Show bundles for this target
713
+ </Button>
714
+ ) : null}
701
715
  </div>
702
716
  </dl>
703
717
  {diagnostics.isError ? (