@xenon-device-management/xenon 2.13.2 → 2.15.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 (350) hide show
  1. package/README.md +17 -8
  2. package/lib/package.json +5 -5
  3. package/lib/public/assets/{AnnotationOverlay-BXruClDk.js → AnnotationOverlay-Btq3dZRI.js} +1 -1
  4. package/lib/public/assets/{ApiKeyGate-qTS4LPLC.js → ApiKeyGate-C9OoAgg_.js} +1 -1
  5. package/lib/public/assets/DeviceMosaicView-DBC_xczB.js +2 -0
  6. package/lib/public/assets/{EmptyState-Cr17PdDv.js → EmptyState-DqWU2-vM.js} +1 -1
  7. package/lib/public/assets/{FieldGroup-Bvn08svv.js → FieldGroup-CveQ3xrA.js} +1 -1
  8. package/lib/public/assets/{FilterMenu-DDSO8aDf.js → FilterMenu-BfKDSfHz.js} +1 -1
  9. package/lib/public/assets/{Menu-B-Qn2X3T.js → Menu-CtdCybzA.js} +1 -1
  10. package/lib/public/assets/{Modal-Cg9V5JYU.js → Modal-Bsvj1tm2.js} +1 -1
  11. package/lib/public/assets/{RecordingPage-BTUs9VTW.js → RecordingPage-CRofOiyx.js} +1 -1
  12. package/lib/public/assets/{RecordingsPage-DYcfxITK.js → RecordingsPage-jNQHb2IR.js} +2 -2
  13. package/lib/public/assets/{SegmentedControl-Zy7suhT5.js → SegmentedControl-C8HtTha-.js} +1 -1
  14. package/lib/public/assets/{SettingCard-CWYmycoe.js → SettingCard-D8K1LZNo.js} +1 -1
  15. package/lib/public/assets/{Table-io9fwa98.js → Table-zNTX92Pn.js} +1 -1
  16. package/lib/public/assets/{activity-Bdf_uIWl.js → activity-CJ8LwZq9.js} +1 -1
  17. package/lib/public/assets/ai-settings-CgxQZqrc.js +16 -0
  18. package/lib/public/assets/{api-keys-CPqtVpm3.js → api-keys-ECpo-zTo.js} +1 -1
  19. package/lib/public/assets/{apps-BgZan0H9.js → apps-BjGymyf3.js} +2 -2
  20. package/lib/public/assets/{arrow-left-B27ckB31.js → arrow-left-BWfCbeHP.js} +1 -1
  21. package/lib/public/assets/{arrow-right-DOF8ITCz.js → arrow-right-DC7UGf_n.js} +1 -1
  22. package/lib/public/assets/{arrow-up-right-eFG5KTFS.js → arrow-up-right-BOjwybDk.js} +1 -1
  23. package/lib/public/assets/{auth-shell-DlC3_27j.js → auth-shell-CxMTo9aH.js} +2 -2
  24. package/lib/public/assets/{builds-page-BuXpPfKo.js → builds-page-DOCm4HkA.js} +1 -1
  25. package/lib/public/assets/{button-fIW8owMI.js → button-Cg08-EMT.js} +1 -1
  26. package/lib/public/assets/{calendar-WNjmrF-a.js → calendar-CA1ikLJs.js} +1 -1
  27. package/lib/public/assets/{check-BdTh1Sq7.js → check-BMTaH72W.js} +1 -1
  28. package/lib/public/assets/{chevron-right-B4BKlsqk.js → chevron-right-B2QOv9Nx.js} +1 -1
  29. package/lib/public/assets/{circle-check-zJU80_EF.js → circle-check-CYXBoUqT.js} +1 -1
  30. package/lib/public/assets/{circle-x-5Uwquo0h.js → circle-x-DTwnSAnl.js} +1 -1
  31. package/lib/public/assets/{clock-BtUprDsZ.js → clock-C8_HViQP.js} +1 -1
  32. package/lib/public/assets/{copy-DGSbZI3u.js → copy-Be7LNMXV.js} +1 -1
  33. package/lib/public/assets/derive-UnLRp4r3.js +1 -0
  34. package/lib/public/assets/device-explorer-BOqtfGXz.js +282 -0
  35. package/lib/public/assets/{download-WG6l7BgD.js → download-B56lwxWP.js} +1 -1
  36. package/lib/public/assets/forgot-password-CCU6bzLn.js +1 -0
  37. package/lib/public/assets/h264Stream-C-OtmIuk.js +26 -0
  38. package/lib/public/assets/index-B9KQ6LsY.js +15 -0
  39. package/lib/public/assets/{index-DI1fGIyj.js → index-BOxe43p1.js} +5 -5
  40. package/lib/public/assets/{index-HDQVe1gi.js → index-CfxsUslp.js} +1 -1
  41. package/lib/public/assets/{input-BjDRKCea.js → input-CZHFjbSg.js} +1 -1
  42. package/lib/public/assets/{line-chart-C0zdgd0v.js → line-chart-Gl_Dz3X_.js} +1 -1
  43. package/lib/public/assets/{list-checks-BdW5CjM8.js → list-checks-CCgjeyGY.js} +1 -1
  44. package/lib/public/assets/{lock-Dy3L4I8E.js → lock-CkOwgDcx.js} +1 -1
  45. package/lib/public/assets/{login-BHbY9CLG.js → login-D5cc4w7M.js} +1 -1
  46. package/lib/public/assets/maintenance-settings-t7qr3fvX.js +6 -0
  47. package/lib/public/assets/{monitor-8xjkeHHi.js → monitor-DEJixKQO.js} +1 -1
  48. package/lib/public/assets/{mouse-pointer-2-CXdKMXQ8.js → mouse-pointer-2-CtOrk4M8.js} +1 -1
  49. package/lib/public/assets/{network-Cj8JOKON.js → network-Dii9qdvk.js} +1 -1
  50. package/lib/public/assets/{overview-CTg7F0im.js → overview-rolAACrO.js} +1 -1
  51. package/lib/public/assets/{page-header--aTyJXq6.js → page-header-COQZxJfR.js} +1 -1
  52. package/lib/public/assets/{play-B-FodgHV.js → play-DrN1Se_R.js} +1 -1
  53. package/lib/public/assets/{plus-CsIk10Cq.js → plus-5aq-9uRx.js} +1 -1
  54. package/lib/public/assets/{profile-page-DkFKkMfl.js → profile-page-6i5kY6kF.js} +1 -1
  55. package/lib/public/assets/{reset-password-I2-zqLlI.js → reset-password-sp2IBrc7.js} +1 -1
  56. package/lib/public/assets/runbook-page-DJDjeopU.js +253 -0
  57. package/lib/public/assets/{select-DvCSv25z.js → select-Bpyn7rWO.js} +1 -1
  58. package/lib/public/assets/{selector-detail-redirect-BLVfMJs_.js → selector-detail-redirect-BH74vmKv.js} +1 -1
  59. package/lib/public/assets/{selector-health-page-oqadRokn.js → selector-health-page-Cw_g218H.js} +2 -2
  60. package/lib/public/assets/session-detail-page-AZJE6XXE.js +4 -0
  61. package/lib/public/assets/settings-C3uyGhyc.js +6 -0
  62. package/lib/public/assets/{settings-Dep_3kbA.css → settings-K8UHWMdI.css} +1 -1
  63. package/lib/public/assets/{stat-tile-DV9Ix-4O.js → stat-tile-xVqAKIlI.js} +1 -1
  64. package/lib/public/assets/{tablet-6b_SEN2X.js → tablet-BxUScAeO.js} +1 -1
  65. package/lib/public/assets/{teams-BjZyfuHh.js → teams-B5ljGkY2.js} +1 -1
  66. package/lib/public/assets/{trash-2-CTZpPSdd.js → trash-2-B701i8sy.js} +1 -1
  67. package/lib/public/assets/{upload-P3XzwQUb.js → upload-C2gr44RS.js} +1 -1
  68. package/lib/public/assets/{use-builds-data-1cOCMf-z.js → use-builds-data-NeQOFEoy.js} +1 -1
  69. package/lib/public/assets/{use-password-reset-mode-DgF9w088.js → use-password-reset-mode-DEzJq5ef.js} +1 -1
  70. package/lib/public/assets/{users-DMF9Mk5H.js → users-D_vv_yz4.js} +1 -1
  71. package/lib/public/assets/{users-CiNTKUiz.js → users-MY6eNe6s.js} +1 -1
  72. package/lib/public/assets/{video-off-CHp1KU_T.js → video-off-OK1lNZQn.js} +1 -1
  73. package/lib/public/assets/webhook-settings-BU-C9lBf.js +1 -0
  74. package/lib/public/assets/{zap-DRz0tDq5.js → zap-DO9ry1iz.js} +1 -1
  75. package/lib/public/index.html +1 -1
  76. package/lib/schema.json +23 -25
  77. package/lib/src/XenonCapabilityManager.js +22 -5
  78. package/lib/src/app/dashboardPluginLink.js +117 -0
  79. package/lib/src/app/index.js +13 -34
  80. package/lib/src/app/openapi/control.yaml +73 -20
  81. package/lib/src/app/openapi/grid.yaml +31 -7
  82. package/lib/src/app/openapi/identity.yaml +103 -31
  83. package/lib/src/app/openapi/platform.yaml +165 -39
  84. package/lib/src/app/openapi/sessions.yaml +10 -3
  85. package/lib/src/app/routers/apikeys.js +14 -2
  86. package/lib/src/app/routers/auth.js +29 -5
  87. package/lib/src/app/routers/control.js +20 -2
  88. package/lib/src/app/routers/dashboard.js +69 -26
  89. package/lib/src/app/routers/grid.js +37 -13
  90. package/lib/src/app/routers/profile.js +21 -0
  91. package/lib/src/app/routers/streamType.js +7 -2
  92. package/lib/src/app/routers/users.js +10 -5
  93. package/lib/src/app/routers/webhook.js +8 -4
  94. package/lib/src/app/swagger.js +2 -0
  95. package/lib/src/app/ws/h264StreamWs.js +10 -1
  96. package/lib/src/config.js +51 -5
  97. package/lib/src/dashboard/commands.js +185 -141
  98. package/lib/src/dashboard/event-manager.js +88 -67
  99. package/lib/src/dashboard/services/failure-analysis-service.js +136 -45
  100. package/lib/src/dashboard/sessionCommandSummary.js +39 -0
  101. package/lib/src/data-service/appleFamily.js +43 -0
  102. package/lib/src/data-service/db.js +11 -0
  103. package/lib/src/data-service/device-service.js +6 -1
  104. package/lib/src/data-service/device-store.js +76 -3
  105. package/lib/src/data-service/deviceClaims.js +37 -0
  106. package/lib/src/data-service/deviceFieldOwners.js +25 -11
  107. package/lib/src/data-service/deviceSettings.js +79 -0
  108. package/lib/src/data-service/prisma-store.js +169 -15
  109. package/lib/src/data-service/web-config-service.js +50 -92
  110. package/lib/src/device-managers/AndroidDeviceManager.js +9 -31
  111. package/lib/src/device-managers/android/AndroidH264StreamService.js +69 -20
  112. package/lib/src/device-managers/android/H264Multiplexer.js +38 -4
  113. package/lib/src/device-managers/ios/WDAClient.js +44 -43
  114. package/lib/src/device-managers/shellCommands.js +96 -0
  115. package/lib/src/device-utils.js +114 -40
  116. package/lib/src/gateway/defaultGateway.js +1 -1
  117. package/lib/src/gateway/forwardToNode.js +2 -0
  118. package/lib/src/gateway/healReport.js +87 -0
  119. package/lib/src/gateway/sessionGateway.js +12 -2
  120. package/lib/src/generated/client/edge.js +18 -3
  121. package/lib/src/generated/client/index-browser.js +15 -0
  122. package/lib/src/generated/client/index.d.ts +2086 -379
  123. package/lib/src/generated/client/index.js +18 -3
  124. package/lib/src/generated/client/package.json +1 -1
  125. package/lib/src/generated/client/schema.prisma +38 -7
  126. package/lib/src/generated/client/wasm.js +15 -0
  127. package/lib/src/interceptors/CommandInterceptor.js +271 -188
  128. package/lib/src/interceptors/xenonScripts.js +55 -0
  129. package/lib/src/interfaces/IPluginArgs.js +1 -2
  130. package/lib/src/middleware/authMiddleware.js +15 -3
  131. package/lib/src/middleware/commandCaller.js +3 -3
  132. package/lib/src/middleware/verifyCredential.js +58 -1
  133. package/lib/src/plugin.js +23 -4
  134. package/lib/src/prisma.js +1 -1
  135. package/lib/src/scripts/database-check.js +124 -0
  136. package/lib/src/services/AICommandService.js +9 -2
  137. package/lib/src/services/AIService.js +281 -32
  138. package/lib/src/services/CleanupService.js +6 -1
  139. package/lib/src/services/EmailService.js +29 -0
  140. package/lib/src/services/InterceptorService.js +70 -13
  141. package/lib/src/services/NetworkConditioningService.js +85 -88
  142. package/lib/src/services/NotificationService.js +36 -29
  143. package/lib/src/services/OrphanSweeper.js +7 -0
  144. package/lib/src/services/PortAllocator.js +5 -0
  145. package/lib/src/services/SelectorVerificationJob.js +15 -4
  146. package/lib/src/services/ServerManager.js +105 -9
  147. package/lib/src/services/SessionLifecycleService.js +133 -75
  148. package/lib/src/services/ShutdownCoordinator.js +33 -0
  149. package/lib/src/services/SocketServer.js +19 -3
  150. package/lib/src/services/TeamService.js +20 -3
  151. package/lib/src/services/bug-report/video-slice.js +4 -1
  152. package/lib/src/services/device-access/leaseOverride.js +7 -5
  153. package/lib/src/services/healing/FuzzyXmlHealingProvider.js +51 -0
  154. package/lib/src/services/healing/HealEtalonService.js +3 -2
  155. package/lib/src/services/healing/HealingOrchestrator.js +85 -71
  156. package/lib/src/services/healing/OcrHealingProvider.js +41 -64
  157. package/lib/src/services/healing/ResilioTreeHealingProvider.js +41 -50
  158. package/lib/src/services/healing/VisualAiHealingProvider.js +1 -1
  159. package/lib/src/services/healing/fingerprintIdentity.js +126 -0
  160. package/lib/src/services/healing/resilioPath.js +274 -0
  161. package/lib/src/services/interceptor/AndroidProxyAdapter.js +18 -0
  162. package/lib/src/services/interceptor/interceptorOptions.js +44 -0
  163. package/lib/src/services/logcat/SessionDeviceLogs.js +271 -0
  164. package/lib/src/services/logcat/deviceLogBook.js +163 -0
  165. package/lib/src/services/network/AndroidRadios.js +71 -0
  166. package/lib/src/services/network/PhoneNetworkLedger.js +184 -0
  167. package/lib/src/services/network/PhoneNetworkRestore.js +330 -0
  168. package/lib/src/services/network/adbForPhone.js +60 -0
  169. package/lib/src/services/network/phoneNetworkLock.js +20 -0
  170. package/lib/src/services/network/xenonProxy.js +107 -0
  171. package/lib/src/services/ocr/ocrData.js +118 -0
  172. package/lib/src/services/ocr/vendor/LICENSE-tessdata.txt +202 -0
  173. package/lib/src/services/ocr/vendor/eng.traineddata.gz +0 -0
  174. package/lib/src/services/omni-vision/OmniVisionService.js +132 -95
  175. package/lib/src/services/omni-vision/VisionAssertionService.js +28 -25
  176. package/lib/src/services/omni-vision/ocrTextMatch.js +105 -0
  177. package/lib/src/services/omni-vision/screenScale.js +68 -0
  178. package/lib/src/services/passwordResetLink.js +50 -9
  179. package/lib/src/services/passwordResetMode.js +3 -1
  180. package/lib/src/services/publicUrl.js +45 -0
  181. package/lib/src/services/recording/concurrency-gate.js +12 -3
  182. package/lib/src/services/session/sessionIdentity.js +5 -3
  183. package/lib/src/services/session/shutdownReason.js +26 -0
  184. package/lib/src/services/settings/SelfHealingSwitch.js +70 -0
  185. package/lib/src/services/settings/aiEngineSettings.js +219 -0
  186. package/lib/src/services/settings/labSettings.js +149 -0
  187. package/lib/src/services/token/mintedLifetime.js +51 -0
  188. package/lib/src/services/webhookEvents.js +173 -0
  189. package/lib/src/sessions/SessionManager.js +8 -2
  190. package/lib/src/sessions/sessionMemory.js +25 -0
  191. package/lib/test/helpers/fake-adb.js +58 -0
  192. package/lib/test/helpers/fake-ai-provider.js +188 -0
  193. package/lib/test/helpers/fake-device-table.js +63 -24
  194. package/lib/test/helpers/loki-stores.js +33 -0
  195. package/lib/test/helpers/page-sources.js +164 -0
  196. package/lib/test/helpers/scratch-database.js +58 -13
  197. package/lib/test/integration/audit-ingest.spec.js +10 -10
  198. package/lib/test/integration/auth-flow.spec.js +9 -14
  199. package/lib/test/integration/auth-rate-limit.spec.js +6 -3
  200. package/lib/test/integration/bug-report-route.spec.js +22 -2
  201. package/lib/test/integration/forgot-password-rate-limit.spec.js +6 -3
  202. package/lib/test/integration/forgot-password.spec.js +17 -18
  203. package/lib/test/integration/legacy-deprecation-headers.spec.js +5 -2
  204. package/lib/test/integration/migration.spec.js +6 -1
  205. package/lib/test/integration/node-pair-auth-rest.spec.js +5 -9
  206. package/lib/test/integration/ports-router.spec.js +4 -4
  207. package/lib/test/integration/prisma-device-store-add-devices.spec.js +2 -3
  208. package/lib/test/integration/prisma-device-store-team-filter.spec.js +2 -5
  209. package/lib/test/integration/profile-tokens.spec.js +10 -16
  210. package/lib/test/integration/recordings-router.spec.js +16 -16
  211. package/lib/test/integration/reset-revokes-sessions.spec.js +4 -9
  212. package/lib/test/integration/role-matrix.spec.js +4 -9
  213. package/lib/test/integration/sdk-leases-router.spec.js +9 -9
  214. package/lib/test/integration/sdk-version.spec.js +2 -2
  215. package/lib/test/integration/selector-health-endpoint.spec.js +5 -5
  216. package/lib/test/integration/team-membership-migration.spec.js +73 -12
  217. package/lib/test/integration/team-visibility-apps.spec.js +15 -22
  218. package/lib/test/integration/team-visibility-control.spec.js +96 -69
  219. package/lib/test/integration/team-visibility-dashboard.spec.js +7 -23
  220. package/lib/test/integration/team-visibility-grid.spec.js +16 -15
  221. package/lib/test/integration/team-visibility-leases.spec.js +8 -11
  222. package/lib/test/integration/team-visibility-recordings.spec.js +6 -19
  223. package/lib/test/integration/team-visibility-sessions.spec.js +6 -19
  224. package/lib/test/integration/users-flow.spec.js +7 -12
  225. package/lib/test/integration/users-lockout.spec.js +5 -3
  226. package/lib/test/unit/EmailService.test.js +66 -0
  227. package/lib/test/unit/ResilioTreeHealingProvider.test.js +46 -19
  228. package/lib/test/unit/TeamService.test.js +3 -0
  229. package/lib/test/unit/XenonCapabilityManager.spec.js +4 -2
  230. package/lib/test/unit/ai-call-time-limit.spec.js +130 -0
  231. package/lib/test/unit/ai-engine-settings.spec.js +338 -0
  232. package/lib/test/unit/ai-provider-switch.spec.js +130 -0
  233. package/lib/test/unit/ai-rate-limit.spec.js +126 -0
  234. package/lib/test/unit/android-h264-viewers.spec.js +272 -0
  235. package/lib/test/unit/android-preview-hold.spec.js +3 -2
  236. package/lib/test/unit/apikeys-router.spec.js +84 -0
  237. package/lib/test/unit/apple-family.spec.js +36 -0
  238. package/lib/test/unit/authMiddleware.bearer.spec.js +9 -0
  239. package/lib/test/unit/authMiddleware.credentialLifetime.spec.js +149 -0
  240. package/lib/test/unit/bug-report/video-slice.spec.js +19 -0
  241. package/lib/test/unit/cleanup-settings-db.spec.js +103 -0
  242. package/lib/test/unit/cleanup-settings.spec.js +244 -0
  243. package/lib/test/unit/dashboard-api-paths.spec.js +101 -0
  244. package/lib/test/unit/dashboard-commands.spec.js +249 -0
  245. package/lib/test/unit/dashboard-events-device-logs.spec.js +207 -0
  246. package/lib/test/unit/dashboard-events-team-scope.spec.js +9 -6
  247. package/lib/test/unit/dashboard-plugin-link.spec.js +213 -0
  248. package/lib/test/unit/database-check.spec.js +108 -0
  249. package/lib/test/unit/default-plugin-args.spec.js +33 -0
  250. package/lib/test/unit/device-log-book.spec.js +180 -0
  251. package/lib/test/unit/device-offline-webhook.spec.js +81 -0
  252. package/lib/test/unit/device-setting-columns.spec.js +66 -0
  253. package/lib/test/unit/device-settings-loki.spec.js +87 -0
  254. package/lib/test/unit/device-settings-survive.spec.js +555 -0
  255. package/lib/test/unit/device-sync-lost-update.spec.js +5 -0
  256. package/lib/test/unit/emulator-boot.spec.js +91 -0
  257. package/lib/test/unit/enable-dashboard-option.spec.js +57 -0
  258. package/lib/test/unit/event-log-session-data.spec.js +244 -0
  259. package/lib/test/unit/failure-analysis.spec.js +182 -0
  260. package/lib/test/unit/failure-categories.spec.js +128 -0
  261. package/lib/test/unit/fingerprint-identity.spec.js +433 -0
  262. package/lib/test/unit/h264-multiplexer.spec.js +46 -0
  263. package/lib/test/unit/heal-report.spec.js +71 -0
  264. package/lib/test/unit/healing-instrumentation.spec.js +6 -1
  265. package/lib/test/unit/healing-tier-gate.spec.js +73 -29
  266. package/lib/test/unit/healing-tiers-every-session.spec.js +219 -0
  267. package/lib/test/unit/hub-node-gateway-appium-server.spec.js +219 -0
  268. package/lib/test/unit/hub-node-same-host.spec.js +5 -0
  269. package/lib/test/unit/interceptor-visual-elements.spec.js +192 -0
  270. package/lib/test/unit/iphone-ipad-only.spec.js +132 -0
  271. package/lib/test/unit/json-logging-option.spec.js +74 -0
  272. package/lib/test/unit/lab-settings.spec.js +218 -0
  273. package/lib/test/unit/lease/lease-override.spec.js +23 -6
  274. package/lib/test/unit/lease/session-lease-proof.spec.js +16 -4
  275. package/lib/test/unit/max-sessions.spec.js +240 -0
  276. package/lib/test/unit/ocr-healing-tier-real-ocr.spec.js +113 -0
  277. package/lib/test/unit/ocr-healing-tier.spec.js +122 -0
  278. package/lib/test/unit/ocr-offline.spec.js +213 -0
  279. package/lib/test/unit/ocr-text-match.spec.js +44 -0
  280. package/lib/test/unit/omni-virtual-element-store.spec.js +301 -0
  281. package/lib/test/unit/omni-vision-analyze-screen.spec.js +72 -0
  282. package/lib/test/unit/omni-vision-ios-points.spec.js +159 -0
  283. package/lib/test/unit/omni-vision-tap-text.spec.js +129 -0
  284. package/lib/test/unit/omni-vision.spec.js +6 -8
  285. package/lib/test/unit/package-engines.spec.js +27 -0
  286. package/lib/test/unit/partial-config-file.spec.js +14 -0
  287. package/lib/test/unit/passwordResetMode.test.js +10 -2
  288. package/lib/test/unit/phone-network/boot-clean-up.spec.js +64 -0
  289. package/lib/test/unit/phone-network/interceptor-options.spec.js +77 -0
  290. package/lib/test/unit/phone-network/interceptor-proxy-restore.spec.js +145 -0
  291. package/lib/test/unit/phone-network/network-conditioning.spec.js +145 -0
  292. package/lib/test/unit/phone-network/phone-network-restore.spec.js +246 -0
  293. package/lib/test/unit/phone-network/session-end-paths.spec.js +182 -0
  294. package/lib/test/unit/phone-network/session-start.spec.js +110 -0
  295. package/lib/test/unit/phone-network/xenon-proxy.spec.js +69 -0
  296. package/lib/test/unit/plugin.spec.js +3 -3
  297. package/lib/test/unit/profile-router.test.js +122 -1
  298. package/lib/test/unit/queue-requester.spec.js +1 -1
  299. package/lib/test/unit/recording-options.spec.js +181 -0
  300. package/lib/test/unit/reset-link-address.spec.js +266 -0
  301. package/lib/test/unit/reset-link.test.js +10 -4
  302. package/lib/test/unit/resilio-path-healing.spec.js +270 -0
  303. package/lib/test/unit/selector-learning-every-session.spec.js +179 -0
  304. package/lib/test/unit/selector-verification-clean-build.spec.js +130 -0
  305. package/lib/test/unit/selector-verification-job.spec.js +13 -13
  306. package/lib/test/unit/self-healing-boot.spec.js +80 -0
  307. package/lib/test/unit/self-healing-setting.spec.js +273 -0
  308. package/lib/test/unit/session-app-resolution.spec.js +5 -1
  309. package/lib/test/unit/session-attribution-wiring.spec.js +41 -13
  310. package/lib/test/unit/session-create-credential-owner.spec.js +242 -0
  311. package/lib/test/unit/session-credential-strip.spec.js +1 -1
  312. package/lib/test/unit/session-device-logs.spec.js +347 -0
  313. package/lib/test/unit/session-end-failure-analysis.spec.js +133 -0
  314. package/lib/test/unit/session-failed-webhook.spec.js +170 -0
  315. package/lib/test/unit/session-log-indexes.spec.js +64 -3
  316. package/lib/test/unit/shell-commands.spec.js +133 -0
  317. package/lib/test/unit/socketServer.scopedEmit.spec.js +2 -0
  318. package/lib/test/unit/socketServer.sessionCookie.spec.js +2 -1
  319. package/lib/test/unit/stream-start-pipelines.spec.js +264 -0
  320. package/lib/test/unit/stream-status-type.spec.js +4 -0
  321. package/lib/test/unit/token-mint-limits.spec.js +165 -0
  322. package/lib/test/unit/unexpected-shutdown-reason.spec.js +163 -0
  323. package/lib/test/unit/verify-credential.spec.js +33 -0
  324. package/lib/test/unit/vision-assertion.spec.js +119 -0
  325. package/lib/test/unit/wda-client-shell.spec.js +133 -0
  326. package/lib/test/unit/web-config-service.spec.js +98 -0
  327. package/lib/test/unit/webhook-delivery.spec.js +24 -0
  328. package/lib/test/unit/webhook-payloads.spec.js +273 -0
  329. package/lib/test/unit/xenon-execute-scripts.spec.js +138 -0
  330. package/lib/tsconfig.tsbuildinfo +1 -1
  331. package/lib/web/src/components/webhook-settings/webhookEventVariables.json +30 -0
  332. package/package.json +5 -5
  333. package/prisma/migrations/20261004140000_keep_device_settings/migration.sql +19 -0
  334. package/prisma/migrations/20261004174413_locator_etalon_path/migration.sql +2 -0
  335. package/prisma/schema.prisma +38 -7
  336. package/schema.json +23 -25
  337. package/scripts/generate-types-from-schema.js +1 -2
  338. package/scripts/lib/always-present-plugin-args.js +4 -1
  339. package/lib/public/assets/BugReportButton-BoGhlI7F.js +0 -15
  340. package/lib/public/assets/DeviceMosaicView-8J0oYqMM.js +0 -2
  341. package/lib/public/assets/ai-settings-Bce5SJob.js +0 -21
  342. package/lib/public/assets/device-explorer-C-KnhMHI.js +0 -279
  343. package/lib/public/assets/forgot-password-DnudqFFo.js +0 -1
  344. package/lib/public/assets/maintenance-settings-zDVlOMVK.js +0 -6
  345. package/lib/public/assets/recording-group-store-WVM3hoXn.js +0 -26
  346. package/lib/public/assets/runbook-page-DJTVCJX7.js +0 -124
  347. package/lib/public/assets/session-detail-page-CGn55Pvl.js +0 -4
  348. package/lib/public/assets/settings-MsVU2ukE.js +0 -6
  349. package/lib/public/assets/webhook-settings-DiS8geIm.js +0 -1
  350. /package/lib/public/assets/{BugReportButton-CPBjfiv4.css → index-CPBjfiv4.css} +0 -0
@@ -1 +1 @@
1
- import{r as c,i as J,u as Q,b as X,t as ee,j as e,e as B,A as te,_ as ne}from"./index-DI1fGIyj.js";import{f as q,a as re,c as se,h as ae,i as Z,j as ie,k as oe,m as ce}from"./recordings-BWe1ydXm.js";import{P as le}from"./page-header--aTyJXq6.js";import{B as I}from"./button-fIW8owMI.js";import{E as L}from"./EmptyState-Cr17PdDv.js";import{M as ue}from"./Modal-Cg9V5JYU.js";import{P as de,M as fe,a as me}from"./Menu-B-Qn2X3T.js";import{A as ge}from"./AnnotationOverlay-BXruClDk.js";import{t as O,v as pe,R as he,P as be,n as ye,c as U,o as ve,a as R,f as ke,p as xe,S as V,b as je,d as Me}from"./recordings-n-GTW3aT.js";import{A as we}from"./arrow-left-B27ckB31.js";import{T as Re}from"./trash-2-CTZpPSdd.js";import{P as Se,a as Ne}from"./play-B-FodgHV.js";import{D as Ee}from"./download-WG6l7BgD.js";import"./utils-CDN07tui.js";import"./index-HDQVe1gi.js";import"./check-BdTh1Sq7.js";function Ce(n){const t=[{key:"zip",label:"All videos (zip)",url:re(n.groupId)}];return n.hasComposite&&t.push({key:"composite",label:"Side-by-side video",url:se(n.groupId)}),t.push({key:"bundle",label:"Proof bundle",url:ae(n.groupId)}),n.phones.filter(l=>l.status!=="FAILED"&&l.status!=="DISCARDED").forEach(l=>{t.push({key:`video-${l.recordingId}`,label:`${l.name}: video`,url:Z(n.groupId,l.recordingId,!0)}),l.annotationCount>0&&t.push({key:`annotated-${l.recordingId}`,label:`${l.name}: video with annotations`,url:ie(n.groupId,l.recordingId)})}),t}function Ie(n,t){return t?t.role==="ADMIN"||t.role==="SUPER_ADMIN"?!0:!!n.startedBy&&!!t.userId&&n.startedBy.id===t.userId:!1}function De(n){if(n instanceof q){if(n.code==="not_owner")return"Only the person who recorded it, or an admin, can delete it.";if(n.code==="recording_in_progress")return"It’s still recording. Stop it on Live devices first.";if(n.status===404)return"It was already deleted, or it’s on phones you can’t see."}return`Couldn’t delete the recording: ${n instanceof Error?n.message:String(n)}`}function Ae(n){const t=document.createElement("a");t.href=n,t.download="",document.body.appendChild(t),t.click(),document.body.removeChild(t)}const Te={now:()=>performance.now(),schedule:n=>window.requestAnimationFrame(()=>n()),cancel:n=>window.cancelAnimationFrame(n)},Pe=100,_e=3,Fe=.05;function W(n){return n.ended||Number.isFinite(n.duration)&&n.currentTime>=n.duration-Fe}function Le(n,t=Te){const l=c.useRef(new Map),v=c.useRef(new Map),u=c.useRef(new Map),d=c.useRef({baseMs:0,since:null,running:!1,waiting:!1}),p=c.useRef(null),S=c.useRef(-1/0),k=c.useRef(n);k.current=n;const[D,w]=c.useState({timeMs:0,playing:!1,waiting:!1}),x=()=>d.current.since===null?d.current.baseMs:d.current.baseMs+(t.now()-d.current.since),h=(s,a)=>{l.current.forEach((i,M)=>{var _;const m=v.current.get(M);if(!m||i.error)return;const T=O(s,m.offsetMs,m.durationMs);let C=T==="before"?0:T==="after"?m.durationMs:pe(s,m.offsetMs);Number.isFinite(i.duration)&&(C=Math.min(C,i.duration*1e3));const $=d.current.running?he:be;ye(i.currentTime*1e3,C,$)&&(i.currentTime=C/1e3),a&&T==="playing"?i.paused&&!W(i)&&((_=i.play())==null||_.catch(()=>{})):i.paused||i.pause()})},j=s=>Array.from(l.current.entries()).some(([a,i])=>{const M=v.current.get(a);return!!M&&!i.error&&!W(i)&&O(s,M.offsetMs,M.durationMs)==="playing"&&i.readyState<_e}),g=s=>{const a=t.now();!s&&a-S.current<Pe||(S.current=a,w({timeMs:x(),playing:d.current.running,waiting:d.current.waiting}))},b=()=>{p.current!==null&&t.cancel(p.current),p.current=null},A=()=>{p.current=null;const s=d.current;if(!s.running)return;const a=x();if(a>=k.current){Object.assign(s,{baseMs:k.current,since:null,running:!1,waiting:!1}),h(k.current,!1),g(!0);return}const i=j(a);i!==s.waiting?(s.baseMs=a,s.since=i?null:t.now(),s.waiting=i,h(a,!i),g(!0)):(h(a,!i),g(!1)),p.current=t.schedule(A)},N=()=>{const s=d.current;x()>=k.current?s.baseMs=0:s.baseMs=x(),Object.assign(s,{since:t.now(),running:!0,waiting:!1}),h(s.baseMs,!0),g(!0),b(),p.current=t.schedule(A)},y=()=>{const s=d.current;Object.assign(s,{baseMs:x(),since:null,running:!1,waiting:!1}),b(),h(s.baseMs,!1),g(!0)},f=s=>{const a=d.current,i=U(s,k.current);a.baseMs=i,a.since=a.running&&!a.waiting?t.now():null,h(i,a.running&&!a.waiting),g(!0)},P=c.useCallback((s,a)=>{v.current.set(s,a);let i=u.current.get(s);return i||(i=M=>{if(M){l.current.set(s,M);const m=d.current;h(x(),m.running&&!m.waiting)}else l.current.delete(s)},u.current.set(s,i)),i},[]);return c.useEffect(()=>b,[]),{...D,play:N,pause:y,toggle:()=>d.current.running?y():N(),seek:f,bind:P}}const $e=()=>{},Y="Stop the recording on Live devices first.",Be=1e3;function Oe(n){const t=n;return!t||!t.closest?!1:!!t.closest('input:not([type="range"]):not([type="checkbox"]), select, textarea, [contenteditable="true"], [role="dialog"], [role="menu"]')}function Ue({groupId:n,phone:t,timeMs:l,marks:v,showMarks:u,bind:d}){const[p,S]=c.useState(!1),[k,D]=c.useState(void 0),w=t.status==="FAILED"||t.status==="DISCARDED",x=O(l,t.offsetMs,t.durationMs),h=je(v,l).map(Me).filter(g=>g!==null);let j=null;return w?j=`Recording failed: ${t.failReason??"unknown reason"}`:p?j="Video no longer available":x==="before"&&t.offsetMs>=Be&&(j=`Starts at ${R(t.offsetMs)}`),e.jsxs("figure",{className:"rec-tile theme-dark","aria-label":t.name,children:[e.jsx("figcaption",{className:"rec-tile-name",title:t.name,children:t.name}),e.jsxs("div",{className:"rec-tile-screen",children:[!w&&e.jsx("video",{className:"rec-tile-video",muted:!0,playsInline:!0,preload:"auto",src:Z(n,t.recordingId),ref:d(t.recordingId,{offsetMs:t.offsetMs,durationMs:t.durationMs}),onError:()=>S(!0),onLoadedMetadata:g=>{const b=g.currentTarget;b.videoWidth>0&&b.videoHeight>0&&D(b.videoWidth/b.videoHeight)}}),!w&&u&&e.jsx(ge,{enabled:!1,shape:"RECT",color:"currentColor",onCommit:$e,committed:h,mediaAspect:k}),j&&e.jsx("div",{className:"rec-tile-note",children:j})]})]})}function ze({detail:n}){const[t,l]=c.useState(!1),v=c.useRef(null);return e.jsxs(e.Fragment,{children:[e.jsxs(I,{ref:v,variant:"secondary","aria-haspopup":"menu","aria-expanded":t,onClick:()=>l(u=>!u),children:[e.jsx(Ee,{size:14,"aria-hidden":"true"}),"Download"]}),e.jsx(de,{open:t,onClose:()=>l(!1),anchorRef:v,children:e.jsx(fe,{children:Ce(n.summary).map(u=>e.jsx(me,{onClick:()=>{l(!1),Ae(u.url)},children:u.label},u.key))})})]})}function at(){var K;const{groupId:n=""}=J(),t=Q(),{me:l}=X(),{toast:v}=ee(),[u,d]=c.useState(null),[p,S]=c.useState(null),[k,D]=c.useState(0),[w,x]=c.useState(!0),[h,j]=c.useState(!1),[g,b]=c.useState(!1),[A,N]=c.useState(null);c.useEffect(()=>{let r=!0;return S(null),d(null),oe(n).then(o=>r&&d(ve(o))).catch(o=>{r&&S({missing:o instanceof q&&o.status===404,message:o instanceof Error?o.message:String(o)})}),()=>{r=!1}},[n,k]);const y=(u==null?void 0:u.summary.durationMs)??0,f=Le(y),P=c.useRef(f);P.current=f;const s=c.useRef(!0);if(c.useEffect(()=>(s.current=!0,()=>{s.current=!1}),[]),c.useEffect(()=>{if(!u||u.summary.status==="recording")return;const r=o=>{var F,H;if(o.metaKey||o.ctrlKey||o.altKey||Oe(o.target)||o.key===" "&&((H=(F=o.target)==null?void 0:F.closest)!=null&&H.call(F,"button, a, label")))return;if(o.key===" "&&o.repeat){o.preventDefault();return}const E=P.current;o.key===" "?(o.preventDefault(),E.toggle()):o.key==="ArrowRight"?(o.preventDefault(),E.seek(U(E.timeMs+V,y))):o.key==="ArrowLeft"&&(o.preventDefault(),E.seek(U(E.timeMs-V,y)))};return document.addEventListener("keydown",r),()=>document.removeEventListener("keydown",r)},[u,y]),p)return p.missing?e.jsx(L,{title:"This recording isn't available",description:"It may have been deleted, or it's on phones you can't see.",action:e.jsx(B,{className:"rec-link",to:"/recordings",children:"Back to Recordings"})}):e.jsx(L,{title:"Couldn't load this recording",description:p.message,action:e.jsxs(I,{variant:"secondary",onClick:()=>D(r=>r+1),children:[e.jsx(te,{size:14,"aria-hidden":"true"}),"Retry"]})});if(!u)return e.jsx(L,{title:"Loading recording…"});const{summary:a,bookmarks:i,annotations:M}=u,m=a.status==="recording",T=a.phones.map(r=>r.name).join(", "),C=r=>{var o;return((o=a.phones.find(E=>E.recordingId===r))==null?void 0:o.name)??""},$=[T,a.durationMs===null?null:`Length ${R(a.durationMs)}`,`Recorded by ${((K=a.startedBy)==null?void 0:K.name)??"Unknown"}`].filter(Boolean).join(" · "),_=Ie(a,l),z=()=>{j(!1),N(null)},G=async()=>{b(!0),N(null);try{await ce(n)}catch(r){s.current&&(b(!1),N(De(r)));return}v("Recording deleted","success"),s.current&&t("/recordings")};return e.jsxs("div",{className:"rec-page",children:[e.jsx("nav",{className:"rec-backbar",children:e.jsxs(B,{className:"rec-link",to:"/recordings",children:[e.jsx(we,{size:14,"aria-hidden":"true"})," Recordings"]})}),e.jsx(le,{icon:ne,title:ke(a.startedAt),subtitle:$,action:e.jsxs(e.Fragment,{children:[!m&&a.status!=="failed"&&e.jsx(ze,{detail:u}),_&&e.jsxs(e.Fragment,{children:[e.jsxs(I,{variant:"danger",disabled:m,"aria-describedby":m?"rec-delete-reason":void 0,title:m?Y:void 0,onClick:()=>{N(null),j(!0)},children:[e.jsx(Re,{size:14,"aria-hidden":"true"}),"Delete"]}),m&&e.jsx("span",{id:"rec-delete-reason",className:"sr-only",children:Y})]})]})}),m?e.jsx(L,{title:"Still recording",description:"Stop it on Live devices to play it here.",action:e.jsx(B,{className:"rec-link",to:"/devices/live",children:"Open Live devices"})}):e.jsxs("div",{className:`rec-body${i.length>0?" rec-body--with-list":""}`,children:[e.jsxs("div",{className:"rec-player",children:[e.jsx("div",{className:"rec-grid",children:a.phones.map(r=>e.jsx(Ue,{groupId:n,phone:r,timeMs:f.timeMs,marks:M.filter(o=>o.recordingId===r.recordingId),showMarks:w,bind:f.bind},r.recordingId))}),e.jsxs("div",{className:"rec-transport",children:[e.jsx(I,{variant:"secondary",size:"icon","aria-label":f.playing?"Pause":"Play",onClick:f.toggle,children:f.playing?e.jsx(Se,{size:14,"aria-hidden":"true"}):e.jsx(Ne,{size:14,"aria-hidden":"true"})}),e.jsxs("span",{className:"rec-num rec-clock",children:[R(f.timeMs)," / ",R(y)]}),e.jsxs("div",{className:"rec-timeline",children:[e.jsx("input",{type:"range",className:"rec-range","aria-label":"Timeline","aria-valuetext":`${R(f.timeMs)} of ${R(y)}`,min:0,max:y,step:100,value:f.timeMs,onChange:r=>f.seek(Number(r.target.value))}),i.map(r=>e.jsx("button",{type:"button",className:"rec-mark",style:{left:`${xe(r.timecodeMs,y)}%`},title:r.label,"aria-label":`Bookmark: ${r.label}, ${R(r.timecodeMs)}`,onClick:()=>f.seek(r.timecodeMs)},r.id))]}),e.jsx("span",{role:"status",className:"rec-waiting",children:f.waiting?"Buffering…":""}),a.annotationCount>0&&e.jsxs("label",{className:"rec-toggle",children:[e.jsx("input",{type:"checkbox",checked:w,onChange:r=>x(r.target.checked)}),"Annotations"]})]})]}),i.length>0&&e.jsxs("section",{className:"rec-bookmarks","aria-labelledby":"rec-bookmarks-title",children:[e.jsx("h2",{id:"rec-bookmarks-title",className:"rec-bookmarks-title",children:"Bookmarks"}),e.jsx("ol",{className:"rec-bookmark-list",children:i.map(r=>e.jsx("li",{children:e.jsxs("button",{type:"button",className:"rec-bookmark",onClick:()=>f.seek(r.timecodeMs),children:[e.jsx("span",{className:"rec-bookmark-label",children:r.label}),e.jsxs("span",{className:"rec-num rec-bookmark-meta",children:[R(r.timecodeMs)," · ",C(r.recordingId)]})]})},r.id))})]})]}),e.jsxs(ue,{open:h,title:"Delete this recording?",onClose:()=>{g||z()},footer:e.jsxs(e.Fragment,{children:[e.jsx(I,{variant:"secondary",onClick:z,disabled:g,children:"Cancel"}),e.jsx(I,{variant:"danger",onClick:G,disabled:g,children:"Delete"})]}),children:[e.jsx("p",{children:"Its videos, bookmarks and annotations are removed for everyone."}),A&&e.jsx("p",{role:"alert",className:"rec-error",children:A})]})]})}export{at as default};
1
+ import{r as c,i as J,u as Q,b as X,t as ee,j as e,e as B,A as te,$ as ne}from"./index-BOxe43p1.js";import{f as q,a as re,c as se,h as ae,i as Z,j as ie,k as oe,m as ce}from"./recordings-BWe1ydXm.js";import{P as le}from"./page-header-COQZxJfR.js";import{B as I}from"./button-Cg08-EMT.js";import{E as F}from"./EmptyState-DqWU2-vM.js";import{M as ue}from"./Modal-Bsvj1tm2.js";import{P as de,M as fe,a as me}from"./Menu-CtdCybzA.js";import{A as ge}from"./AnnotationOverlay-Btq3dZRI.js";import{t as O,v as pe,R as he,P as be,n as ye,c as U,o as ve,a as R,f as ke,p as xe,S as V,b as je,d as Me}from"./recordings-n-GTW3aT.js";import{A as we}from"./arrow-left-BWfCbeHP.js";import{T as Re}from"./trash-2-B701i8sy.js";import{P as Se,a as Ne}from"./play-DrN1Se_R.js";import{D as Ee}from"./download-B56lwxWP.js";import"./utils-CDN07tui.js";import"./index-CfxsUslp.js";import"./check-BMTaH72W.js";function Ce(n){const t=[{key:"zip",label:"All videos (zip)",url:re(n.groupId)}];return n.hasComposite&&t.push({key:"composite",label:"Side-by-side video",url:se(n.groupId)}),t.push({key:"bundle",label:"Proof bundle",url:ae(n.groupId)}),n.phones.filter(l=>l.status!=="FAILED"&&l.status!=="DISCARDED").forEach(l=>{t.push({key:`video-${l.recordingId}`,label:`${l.name}: video`,url:Z(n.groupId,l.recordingId,!0)}),l.annotationCount>0&&t.push({key:`annotated-${l.recordingId}`,label:`${l.name}: video with annotations`,url:ie(n.groupId,l.recordingId)})}),t}function Ie(n,t){return t?t.role==="ADMIN"||t.role==="SUPER_ADMIN"?!0:!!n.startedBy&&!!t.userId&&n.startedBy.id===t.userId:!1}function De(n){if(n instanceof q){if(n.code==="not_owner")return"Only the person who recorded it, or an admin, can delete it.";if(n.code==="recording_in_progress")return"It’s still recording. Stop it on Live devices first.";if(n.status===404)return"It was already deleted, or it’s on phones you can’t see."}return`Couldn’t delete the recording: ${n instanceof Error?n.message:String(n)}`}function Ae(n){const t=document.createElement("a");t.href=n,t.download="",document.body.appendChild(t),t.click(),document.body.removeChild(t)}const Te={now:()=>performance.now(),schedule:n=>window.requestAnimationFrame(()=>n()),cancel:n=>window.cancelAnimationFrame(n)},Pe=100,_e=3,$e=.05;function W(n){return n.ended||Number.isFinite(n.duration)&&n.currentTime>=n.duration-$e}function Fe(n,t=Te){const l=c.useRef(new Map),v=c.useRef(new Map),u=c.useRef(new Map),d=c.useRef({baseMs:0,since:null,running:!1,waiting:!1}),p=c.useRef(null),S=c.useRef(-1/0),k=c.useRef(n);k.current=n;const[D,w]=c.useState({timeMs:0,playing:!1,waiting:!1}),x=()=>d.current.since===null?d.current.baseMs:d.current.baseMs+(t.now()-d.current.since),h=(s,a)=>{l.current.forEach((i,M)=>{var _;const m=v.current.get(M);if(!m||i.error)return;const T=O(s,m.offsetMs,m.durationMs);let C=T==="before"?0:T==="after"?m.durationMs:pe(s,m.offsetMs);Number.isFinite(i.duration)&&(C=Math.min(C,i.duration*1e3));const L=d.current.running?he:be;ye(i.currentTime*1e3,C,L)&&(i.currentTime=C/1e3),a&&T==="playing"?i.paused&&!W(i)&&((_=i.play())==null||_.catch(()=>{})):i.paused||i.pause()})},j=s=>Array.from(l.current.entries()).some(([a,i])=>{const M=v.current.get(a);return!!M&&!i.error&&!W(i)&&O(s,M.offsetMs,M.durationMs)==="playing"&&i.readyState<_e}),g=s=>{const a=t.now();!s&&a-S.current<Pe||(S.current=a,w({timeMs:x(),playing:d.current.running,waiting:d.current.waiting}))},b=()=>{p.current!==null&&t.cancel(p.current),p.current=null},A=()=>{p.current=null;const s=d.current;if(!s.running)return;const a=x();if(a>=k.current){Object.assign(s,{baseMs:k.current,since:null,running:!1,waiting:!1}),h(k.current,!1),g(!0);return}const i=j(a);i!==s.waiting?(s.baseMs=a,s.since=i?null:t.now(),s.waiting=i,h(a,!i),g(!0)):(h(a,!i),g(!1)),p.current=t.schedule(A)},N=()=>{const s=d.current;x()>=k.current?s.baseMs=0:s.baseMs=x(),Object.assign(s,{since:t.now(),running:!0,waiting:!1}),h(s.baseMs,!0),g(!0),b(),p.current=t.schedule(A)},y=()=>{const s=d.current;Object.assign(s,{baseMs:x(),since:null,running:!1,waiting:!1}),b(),h(s.baseMs,!1),g(!0)},f=s=>{const a=d.current,i=U(s,k.current);a.baseMs=i,a.since=a.running&&!a.waiting?t.now():null,h(i,a.running&&!a.waiting),g(!0)},P=c.useCallback((s,a)=>{v.current.set(s,a);let i=u.current.get(s);return i||(i=M=>{if(M){l.current.set(s,M);const m=d.current;h(x(),m.running&&!m.waiting)}else l.current.delete(s)},u.current.set(s,i)),i},[]);return c.useEffect(()=>b,[]),{...D,play:N,pause:y,toggle:()=>d.current.running?y():N(),seek:f,bind:P}}const Le=()=>{},Y="Stop the recording on Live devices first.",Be=1e3;function Oe(n){const t=n;return!t||!t.closest?!1:!!t.closest('input:not([type="range"]):not([type="checkbox"]), select, textarea, [contenteditable="true"], [role="dialog"], [role="menu"]')}function Ue({groupId:n,phone:t,timeMs:l,marks:v,showMarks:u,bind:d}){const[p,S]=c.useState(!1),[k,D]=c.useState(void 0),w=t.status==="FAILED"||t.status==="DISCARDED",x=O(l,t.offsetMs,t.durationMs),h=je(v,l).map(Me).filter(g=>g!==null);let j=null;return w?j=`Recording failed: ${t.failReason??"unknown reason"}`:p?j="Video no longer available":x==="before"&&t.offsetMs>=Be&&(j=`Starts at ${R(t.offsetMs)}`),e.jsxs("figure",{className:"rec-tile theme-dark","aria-label":t.name,children:[e.jsx("figcaption",{className:"rec-tile-name",title:t.name,children:t.name}),e.jsxs("div",{className:"rec-tile-screen",children:[!w&&e.jsx("video",{className:"rec-tile-video",muted:!0,playsInline:!0,preload:"auto",src:Z(n,t.recordingId),ref:d(t.recordingId,{offsetMs:t.offsetMs,durationMs:t.durationMs}),onError:()=>S(!0),onLoadedMetadata:g=>{const b=g.currentTarget;b.videoWidth>0&&b.videoHeight>0&&D(b.videoWidth/b.videoHeight)}}),!w&&u&&e.jsx(ge,{enabled:!1,shape:"RECT",color:"currentColor",onCommit:Le,committed:h,mediaAspect:k}),j&&e.jsx("div",{className:"rec-tile-note",children:j})]})]})}function ze({detail:n}){const[t,l]=c.useState(!1),v=c.useRef(null);return e.jsxs(e.Fragment,{children:[e.jsxs(I,{ref:v,variant:"secondary","aria-haspopup":"menu","aria-expanded":t,onClick:()=>l(u=>!u),children:[e.jsx(Ee,{size:14,"aria-hidden":"true"}),"Download"]}),e.jsx(de,{open:t,onClose:()=>l(!1),anchorRef:v,children:e.jsx(fe,{children:Ce(n.summary).map(u=>e.jsx(me,{onClick:()=>{l(!1),Ae(u.url)},children:u.label},u.key))})})]})}function at(){var K;const{groupId:n=""}=J(),t=Q(),{me:l}=X(),{toast:v}=ee(),[u,d]=c.useState(null),[p,S]=c.useState(null),[k,D]=c.useState(0),[w,x]=c.useState(!0),[h,j]=c.useState(!1),[g,b]=c.useState(!1),[A,N]=c.useState(null);c.useEffect(()=>{let r=!0;return S(null),d(null),oe(n).then(o=>r&&d(ve(o))).catch(o=>{r&&S({missing:o instanceof q&&o.status===404,message:o instanceof Error?o.message:String(o)})}),()=>{r=!1}},[n,k]);const y=(u==null?void 0:u.summary.durationMs)??0,f=Fe(y),P=c.useRef(f);P.current=f;const s=c.useRef(!0);if(c.useEffect(()=>(s.current=!0,()=>{s.current=!1}),[]),c.useEffect(()=>{if(!u||u.summary.status==="recording")return;const r=o=>{var $,H;if(o.metaKey||o.ctrlKey||o.altKey||Oe(o.target)||o.key===" "&&((H=($=o.target)==null?void 0:$.closest)!=null&&H.call($,"button, a, label")))return;if(o.key===" "&&o.repeat){o.preventDefault();return}const E=P.current;o.key===" "?(o.preventDefault(),E.toggle()):o.key==="ArrowRight"?(o.preventDefault(),E.seek(U(E.timeMs+V,y))):o.key==="ArrowLeft"&&(o.preventDefault(),E.seek(U(E.timeMs-V,y)))};return document.addEventListener("keydown",r),()=>document.removeEventListener("keydown",r)},[u,y]),p)return p.missing?e.jsx(F,{title:"This recording isn't available",description:"It may have been deleted, or it's on phones you can't see.",action:e.jsx(B,{className:"rec-link",to:"/recordings",children:"Back to Recordings"})}):e.jsx(F,{title:"Couldn't load this recording",description:p.message,action:e.jsxs(I,{variant:"secondary",onClick:()=>D(r=>r+1),children:[e.jsx(te,{size:14,"aria-hidden":"true"}),"Retry"]})});if(!u)return e.jsx(F,{title:"Loading recording…"});const{summary:a,bookmarks:i,annotations:M}=u,m=a.status==="recording",T=a.phones.map(r=>r.name).join(", "),C=r=>{var o;return((o=a.phones.find(E=>E.recordingId===r))==null?void 0:o.name)??""},L=[T,a.durationMs===null?null:`Length ${R(a.durationMs)}`,`Recorded by ${((K=a.startedBy)==null?void 0:K.name)??"Unknown"}`].filter(Boolean).join(" · "),_=Ie(a,l),z=()=>{j(!1),N(null)},G=async()=>{b(!0),N(null);try{await ce(n)}catch(r){s.current&&(b(!1),N(De(r)));return}v("Recording deleted","success"),s.current&&t("/recordings")};return e.jsxs("div",{className:"rec-page",children:[e.jsx("nav",{className:"rec-backbar",children:e.jsxs(B,{className:"rec-link",to:"/recordings",children:[e.jsx(we,{size:14,"aria-hidden":"true"})," Recordings"]})}),e.jsx(le,{icon:ne,title:ke(a.startedAt),subtitle:L,action:e.jsxs(e.Fragment,{children:[!m&&a.status!=="failed"&&e.jsx(ze,{detail:u}),_&&e.jsxs(e.Fragment,{children:[e.jsxs(I,{variant:"danger",disabled:m,"aria-describedby":m?"rec-delete-reason":void 0,title:m?Y:void 0,onClick:()=>{N(null),j(!0)},children:[e.jsx(Re,{size:14,"aria-hidden":"true"}),"Delete"]}),m&&e.jsx("span",{id:"rec-delete-reason",className:"sr-only",children:Y})]})]})}),m?e.jsx(F,{title:"Still recording",description:"Stop it on Live devices to play it here.",action:e.jsx(B,{className:"rec-link",to:"/devices/live",children:"Open Live devices"})}):e.jsxs("div",{className:`rec-body${i.length>0?" rec-body--with-list":""}`,children:[e.jsxs("div",{className:"rec-player",children:[e.jsx("div",{className:"rec-grid",children:a.phones.map(r=>e.jsx(Ue,{groupId:n,phone:r,timeMs:f.timeMs,marks:M.filter(o=>o.recordingId===r.recordingId),showMarks:w,bind:f.bind},r.recordingId))}),e.jsxs("div",{className:"rec-transport",children:[e.jsx(I,{variant:"secondary",size:"icon","aria-label":f.playing?"Pause":"Play",onClick:f.toggle,children:f.playing?e.jsx(Se,{size:14,"aria-hidden":"true"}):e.jsx(Ne,{size:14,"aria-hidden":"true"})}),e.jsxs("span",{className:"rec-num rec-clock",children:[R(f.timeMs)," / ",R(y)]}),e.jsxs("div",{className:"rec-timeline",children:[e.jsx("input",{type:"range",className:"rec-range","aria-label":"Timeline","aria-valuetext":`${R(f.timeMs)} of ${R(y)}`,min:0,max:y,step:100,value:f.timeMs,onChange:r=>f.seek(Number(r.target.value))}),i.map(r=>e.jsx("button",{type:"button",className:"rec-mark",style:{left:`${xe(r.timecodeMs,y)}%`},title:r.label,"aria-label":`Bookmark: ${r.label}, ${R(r.timecodeMs)}`,onClick:()=>f.seek(r.timecodeMs)},r.id))]}),e.jsx("span",{role:"status",className:"rec-waiting",children:f.waiting?"Buffering…":""}),a.annotationCount>0&&e.jsxs("label",{className:"rec-toggle",children:[e.jsx("input",{type:"checkbox",checked:w,onChange:r=>x(r.target.checked)}),"Annotations"]})]})]}),i.length>0&&e.jsxs("section",{className:"rec-bookmarks","aria-labelledby":"rec-bookmarks-title",children:[e.jsx("h2",{id:"rec-bookmarks-title",className:"rec-bookmarks-title",children:"Bookmarks"}),e.jsx("ol",{className:"rec-bookmark-list",children:i.map(r=>e.jsx("li",{children:e.jsxs("button",{type:"button",className:"rec-bookmark",onClick:()=>f.seek(r.timecodeMs),children:[e.jsx("span",{className:"rec-bookmark-label",children:r.label}),e.jsxs("span",{className:"rec-num rec-bookmark-meta",children:[R(r.timecodeMs)," · ",C(r.recordingId)]})]})},r.id))})]})]}),e.jsxs(ue,{open:h,title:"Delete this recording?",onClose:()=>{g||z()},footer:e.jsxs(e.Fragment,{children:[e.jsx(I,{variant:"secondary",onClick:z,disabled:g,children:"Cancel"}),e.jsx(I,{variant:"danger",onClick:G,disabled:g,children:"Delete"})]}),children:[e.jsx("p",{children:"Its videos, bookmarks and annotations are removed for everyone."}),A&&e.jsx("p",{role:"alert",className:"rec-error",children:A})]})]})}export{at as default};
@@ -1,2 +1,2 @@
1
- import{u as V,G,r as l,j as n,_ as Y,A as z,e as q}from"./index-DI1fGIyj.js";import{P as Q}from"./page-header--aTyJXq6.js";import{T as Z,a as J,b as T,c as h,d as X,e as m}from"./Table-io9fwa98.js";import{B as v}from"./button-fIW8owMI.js";import{E as y}from"./EmptyState-Cr17PdDv.js";import{I as ee}from"./input-BjDRKCea.js";import{F as f}from"./FilterMenu-DDSO8aDf.js";import{l as A}from"./recordings-BWe1ydXm.js";import{f as ne,a as te}from"./recordings-n-GTW3aT.js";import"./utils-CDN07tui.js";import"./Menu-B-Qn2X3T.js";import"./index-HDQVe1gi.js";import"./check-BdTh1Sq7.js";import"./plus-CsIk10Cq.js";const re={phone:"",by:"",when:"any",q:""},oe=["any","24h","7d","30d"],R=864e5,se={"24h":R,"7d":7*R,"30d":30*R},ae={any:"Any time","24h":"Last 24 hours","7d":"Last 7 days","30d":"Last 30 days"};function ce(t){const r=t.get("when");return{phone:t.get("phone")??"",by:t.get("by")??"",when:r&&oe.includes(r)?r:"any",q:t.get("q")??""}}function F(t){const r=new URLSearchParams;return t.phone&&r.set("phone",t.phone),t.by&&r.set("by",t.by),t.when!=="any"&&r.set("when",t.when),t.q.trim()&&r.set("q",t.q),r}function ie(t){return!!(t.phone||t.by||t.when!=="any"||t.q.trim())}function P(t,r){return{udid:t.phone||void 0,startedBy:t.by||void 0,since:t.when==="any"?void 0:new Date(r-se[t.when]).toISOString(),q:t.q.trim()||void 0}}const B=50,le=250;function de(t){const r=t.phones.map(g=>g.name);return{text:r.length>2?`${r.slice(0,2).join(", ")} +${r.length-2}`:r.join(", "),title:r.join(`
2
- `)}}const ue=t=>t.status==="recording"?"/devices/live":`/recordings/${encodeURIComponent(t.groupId)}`;function Ne(){const t=V(),[r,g]=G(),a=ce(r),x=F(a).toString(),[s,S]=l.useState(null),[I,D]=l.useState(null),[j,C]=l.useState([]),[N,w]=l.useState(null),[M,k]=l.useState(!1),[_,H]=l.useState(0),u=l.useRef(0),d=l.useRef(!0),p=e=>g(F(e),{replace:!0});l.useEffect(()=>{d.current=!0;const e=++u.current,c=window.setTimeout(()=>{A({...P(a,Date.now()),limit:B}).then(i=>{!d.current||e!==u.current||(S(i),C(i.recordings),w(null),D(x))}).catch(i=>{!d.current||e!==u.current||w(i instanceof Error?i.message:String(i))})},le);return()=>{window.clearTimeout(c),d.current=!1}},[x,_]);const b=I===x?(s==null?void 0:s.nextCursor)??null:null,O=async()=>{if(!b)return;const e=u.current;k(!0);try{const c=await A({...P(a,Date.now()),limit:B,cursor:b});if(!d.current||e!==u.current)return;S(c),C(i=>i.concat(c.recordings))}catch(c){if(!d.current||e!==u.current)return;w(c instanceof Error?c.message:String(c))}finally{d.current&&k(!1)}},o=s==null?void 0:s.facets,W=[{value:"",label:"Any phone",count:(o==null?void 0:o.when.any)??0},...((o==null?void 0:o.phones)??[]).map(e=>({value:e.udid,label:e.name,count:e.count}))],K=[{value:"",label:"Anyone",count:(o==null?void 0:o.when.any)??0},...((o==null?void 0:o.people)??[]).map(e=>({value:e.id,label:e.name,count:e.count})),...o&&o.unknownCount>0?[{value:"unknown",label:"Unknown",count:o.unknownCount}]:[]],U=["any","24h","7d","30d"].map(e=>({value:e,label:ae[e],count:(o==null?void 0:o.when[e])??0})),E=(s==null?void 0:s.total)??0;return n.jsxs("div",{className:"rec-page",children:[n.jsx(Q,{icon:Y,title:"Recordings",subtitle:s?`${E} recording${E===1?"":"s"}`:void 0}),n.jsxs("div",{className:"rec-toolbar",children:[n.jsx(ee,{type:"text",className:"rec-search","aria-label":"Search recordings",placeholder:"Search phones and bookmarks",value:a.q,onChange:e=>p({...a,q:e.target.value})}),n.jsx(f,{name:"Phone",value:a.phone,anyValue:"",options:W,onChange:e=>p({...a,phone:e})}),n.jsx(f,{name:"Recorded by",value:a.by,anyValue:"",options:K,onChange:e=>p({...a,by:e})}),n.jsx(f,{name:"When",value:a.when,anyValue:"any",options:U,onChange:e=>p({...a,when:e})})]}),N?n.jsx(y,{title:"Couldn't load recordings",description:N,action:n.jsxs(v,{variant:"secondary",onClick:()=>H(e=>e+1),children:[n.jsx(z,{size:14,"aria-hidden":"true"}),"Retry"]})}):s?j.length===0?ie(a)?n.jsx(y,{title:"No recordings match",action:n.jsx(v,{variant:"secondary",onClick:()=>p(re),children:"Clear filters"})}):n.jsx(y,{title:"No recordings yet",description:"Record phones from Live devices.",action:n.jsx(q,{className:"rec-link",to:"/devices/live",children:"Open Live devices"})}):n.jsxs(n.Fragment,{children:[n.jsxs(Z,{className:"rec-table",children:[n.jsxs("caption",{className:"sr-only",children:["Recordings, ",j.length," shown"]}),n.jsx(J,{children:n.jsxs(T,{children:[n.jsx(h,{scope:"col",children:"When"}),n.jsx(h,{scope:"col",children:"Phones"}),n.jsx(h,{scope:"col",children:"Length"}),n.jsx(h,{scope:"col",children:"Recorded by"}),n.jsx(h,{scope:"col",children:"Bookmarks"}),n.jsx(h,{scope:"col",children:"Status"})]})}),n.jsx(X,{children:j.map(e=>{var L;const c=de(e),i=ue(e);return n.jsxs(T,{className:"rec-row",onClick:$=>{$.target.closest("a")||t(i)},children:[n.jsx(m,{children:n.jsx(q,{to:i,className:"rec-link",children:ne(e.startedAt)})}),n.jsx(m,{title:c.title,children:c.text}),n.jsx(m,{className:"rec-num",children:e.durationMs===null?"—":te(e.durationMs)}),n.jsx(m,{children:((L=e.startedBy)==null?void 0:L.name)??"Unknown"}),n.jsx(m,{className:"rec-num",children:e.bookmarkCount}),n.jsx(m,{children:e.status==="recording"?"Recording…":e.status==="failed"?"Failed":""})]},e.groupId)})})]}),b&&n.jsx("div",{className:"rec-more",children:n.jsx(v,{variant:"secondary",onClick:O,disabled:M,children:"Load more"})})]}):n.jsx(y,{title:"Loading recordings…"}),s&&n.jsxs("p",{className:"rec-footnote",children:["Recordings are kept for ",s.retention.days," days, up to the newest"," ",s.retention.maxCount,"."]})]})}export{Ne as default,de as phoneNames};
1
+ import{u as V,H as Y,r as l,j as n,$ as z,A as G,e as q}from"./index-BOxe43p1.js";import{P as Q}from"./page-header-COQZxJfR.js";import{T as Z,a as J,b as T,c as h,d as X,e as m}from"./Table-zNTX92Pn.js";import{B as v}from"./button-Cg08-EMT.js";import{E as y}from"./EmptyState-DqWU2-vM.js";import{I as ee}from"./input-CZHFjbSg.js";import{F as f}from"./FilterMenu-BfKDSfHz.js";import{l as A}from"./recordings-BWe1ydXm.js";import{f as ne,a as te}from"./recordings-n-GTW3aT.js";import"./utils-CDN07tui.js";import"./Menu-CtdCybzA.js";import"./index-CfxsUslp.js";import"./check-BMTaH72W.js";import"./plus-5aq-9uRx.js";const re={phone:"",by:"",when:"any",q:""},oe=["any","24h","7d","30d"],R=864e5,se={"24h":R,"7d":7*R,"30d":30*R},ae={any:"Any time","24h":"Last 24 hours","7d":"Last 7 days","30d":"Last 30 days"};function ce(t){const r=t.get("when");return{phone:t.get("phone")??"",by:t.get("by")??"",when:r&&oe.includes(r)?r:"any",q:t.get("q")??""}}function F(t){const r=new URLSearchParams;return t.phone&&r.set("phone",t.phone),t.by&&r.set("by",t.by),t.when!=="any"&&r.set("when",t.when),t.q.trim()&&r.set("q",t.q),r}function ie(t){return!!(t.phone||t.by||t.when!=="any"||t.q.trim())}function P(t,r){return{udid:t.phone||void 0,startedBy:t.by||void 0,since:t.when==="any"?void 0:new Date(r-se[t.when]).toISOString(),q:t.q.trim()||void 0}}const B=50,le=250;function de(t){const r=t.phones.map(g=>g.name);return{text:r.length>2?`${r.slice(0,2).join(", ")} +${r.length-2}`:r.join(", "),title:r.join(`
2
+ `)}}const ue=t=>t.status==="recording"?"/devices/live":`/recordings/${encodeURIComponent(t.groupId)}`;function Ne(){const t=V(),[r,g]=Y(),a=ce(r),x=F(a).toString(),[s,S]=l.useState(null),[I,D]=l.useState(null),[j,C]=l.useState([]),[N,w]=l.useState(null),[H,k]=l.useState(!1),[M,O]=l.useState(0),u=l.useRef(0),d=l.useRef(!0),p=e=>g(F(e),{replace:!0});l.useEffect(()=>{d.current=!0;const e=++u.current,c=window.setTimeout(()=>{A({...P(a,Date.now()),limit:B}).then(i=>{!d.current||e!==u.current||(S(i),C(i.recordings),w(null),D(x))}).catch(i=>{!d.current||e!==u.current||w(i instanceof Error?i.message:String(i))})},le);return()=>{window.clearTimeout(c),d.current=!1}},[x,M]);const b=I===x?(s==null?void 0:s.nextCursor)??null:null,_=async()=>{if(!b)return;const e=u.current;k(!0);try{const c=await A({...P(a,Date.now()),limit:B,cursor:b});if(!d.current||e!==u.current)return;S(c),C(i=>i.concat(c.recordings))}catch(c){if(!d.current||e!==u.current)return;w(c instanceof Error?c.message:String(c))}finally{d.current&&k(!1)}},o=s==null?void 0:s.facets,W=[{value:"",label:"Any phone",count:(o==null?void 0:o.when.any)??0},...((o==null?void 0:o.phones)??[]).map(e=>({value:e.udid,label:e.name,count:e.count}))],$=[{value:"",label:"Anyone",count:(o==null?void 0:o.when.any)??0},...((o==null?void 0:o.people)??[]).map(e=>({value:e.id,label:e.name,count:e.count})),...o&&o.unknownCount>0?[{value:"unknown",label:"Unknown",count:o.unknownCount}]:[]],K=["any","24h","7d","30d"].map(e=>({value:e,label:ae[e],count:(o==null?void 0:o.when[e])??0})),E=(s==null?void 0:s.total)??0;return n.jsxs("div",{className:"rec-page",children:[n.jsx(Q,{icon:z,title:"Recordings",subtitle:s?`${E} recording${E===1?"":"s"}`:void 0}),n.jsxs("div",{className:"rec-toolbar",children:[n.jsx(ee,{type:"text",className:"rec-search","aria-label":"Search recordings",placeholder:"Search phones and bookmarks",value:a.q,onChange:e=>p({...a,q:e.target.value})}),n.jsx(f,{name:"Phone",value:a.phone,anyValue:"",options:W,onChange:e=>p({...a,phone:e})}),n.jsx(f,{name:"Recorded by",value:a.by,anyValue:"",options:$,onChange:e=>p({...a,by:e})}),n.jsx(f,{name:"When",value:a.when,anyValue:"any",options:K,onChange:e=>p({...a,when:e})})]}),N?n.jsx(y,{title:"Couldn't load recordings",description:N,action:n.jsxs(v,{variant:"secondary",onClick:()=>O(e=>e+1),children:[n.jsx(G,{size:14,"aria-hidden":"true"}),"Retry"]})}):s?j.length===0?ie(a)?n.jsx(y,{title:"No recordings match",action:n.jsx(v,{variant:"secondary",onClick:()=>p(re),children:"Clear filters"})}):n.jsx(y,{title:"No recordings yet",description:"Record phones from Live devices.",action:n.jsx(q,{className:"rec-link",to:"/devices/live",children:"Open Live devices"})}):n.jsxs(n.Fragment,{children:[n.jsxs(Z,{className:"rec-table",children:[n.jsxs("caption",{className:"sr-only",children:["Recordings, ",j.length," shown"]}),n.jsx(J,{children:n.jsxs(T,{children:[n.jsx(h,{scope:"col",children:"When"}),n.jsx(h,{scope:"col",children:"Phones"}),n.jsx(h,{scope:"col",children:"Length"}),n.jsx(h,{scope:"col",children:"Recorded by"}),n.jsx(h,{scope:"col",children:"Bookmarks"}),n.jsx(h,{scope:"col",children:"Status"})]})}),n.jsx(X,{children:j.map(e=>{var L;const c=de(e),i=ue(e);return n.jsxs(T,{className:"rec-row",onClick:U=>{U.target.closest("a")||t(i)},children:[n.jsx(m,{children:n.jsx(q,{to:i,className:"rec-link",children:ne(e.startedAt)})}),n.jsx(m,{title:c.title,children:c.text}),n.jsx(m,{className:"rec-num",children:e.durationMs===null?"—":te(e.durationMs)}),n.jsx(m,{children:((L=e.startedBy)==null?void 0:L.name)??"Unknown"}),n.jsx(m,{className:"rec-num",children:e.bookmarkCount}),n.jsx(m,{children:e.status==="recording"?"Recording…":e.status==="failed"?"Failed":""})]},e.groupId)})})]}),b&&n.jsx("div",{className:"rec-more",children:n.jsx(v,{variant:"secondary",onClick:_,disabled:H,children:"Load more"})})]}):n.jsx(y,{title:"Loading recordings…"}),s&&n.jsxs("p",{className:"rec-footnote",children:["Recordings are kept for ",s.retention.days," days, up to the newest"," ",s.retention.maxCount,"."]})]})}export{Ne as default,de as phoneNames};
@@ -1 +1 @@
1
- import{j as e}from"./index-DI1fGIyj.js";const s=({kind:n,size:a=6,className:l})=>e.jsx("span",{className:`status-dot status-dot-${n}${l?" "+l:""}`,style:{width:a,height:a},"aria-hidden":!0});function d({segments:n,value:a,onChange:l,size:o="md",label:i}){return e.jsx("div",{className:`seg seg-${o}`,role:"tablist","aria-label":i,children:n.map(t=>e.jsxs("button",{role:"tab","aria-selected":t.value===a,"aria-label":t.title&&typeof t.label=="string"?t.label:void 0,"aria-keyshortcuts":t.keyShortcuts,title:t.title,disabled:t.disabled,className:`seg-btn${t.value===a?" seg-btn-active":""}`,onClick:()=>{t.disabled||l(t.value)},type:"button",children:[t.tone&&e.jsx(s,{kind:t.tone}),e.jsx("span",{children:t.label}),typeof t.count=="number"&&e.jsx("span",{className:`seg-count${t.count===0?" seg-count-zero":""}`,children:t.count})]},t.value))})}export{s as S,d as a};
1
+ import{j as e}from"./index-BOxe43p1.js";const s=({kind:n,size:a=6,className:l})=>e.jsx("span",{className:`status-dot status-dot-${n}${l?" "+l:""}`,style:{width:a,height:a},"aria-hidden":!0});function d({segments:n,value:a,onChange:l,size:o="md",label:i}){return e.jsx("div",{className:`seg seg-${o}`,role:"tablist","aria-label":i,children:n.map(t=>e.jsxs("button",{role:"tab","aria-selected":t.value===a,"aria-label":t.title&&typeof t.label=="string"?t.label:void 0,"aria-keyshortcuts":t.keyShortcuts,title:t.title,disabled:t.disabled,className:`seg-btn${t.value===a?" seg-btn-active":""}`,onClick:()=>{t.disabled||l(t.value)},type:"button",children:[t.tone&&e.jsx(s,{kind:t.tone}),e.jsx("span",{children:t.label}),typeof t.count=="number"&&e.jsx("span",{className:`seg-count${t.count===0?" seg-count-zero":""}`,children:t.count})]},t.value))})}export{s as S,d as a};
@@ -1,4 +1,4 @@
1
- import{c as n,j as s,A as h}from"./index-DI1fGIyj.js";import{B as r}from"./button-fIW8owMI.js";/**
1
+ import{c as n,j as s,A as h}from"./index-BOxe43p1.js";import{B as r}from"./button-Cg08-EMT.js";/**
2
2
  * @license lucide-react v0.555.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1 +1 @@
1
- import{j as t}from"./index-DI1fGIyj.js";const x=({className:s,...a})=>t.jsx("table",{className:`tbl${s?" "+s:""}`,...a}),j=s=>t.jsx("thead",{...s}),c=s=>t.jsx("tbody",{...s}),e=s=>t.jsx("tr",{...s}),n=s=>t.jsx("th",{...s}),T=s=>t.jsx("td",{...s});export{x as T,j as a,e as b,n as c,c as d,T as e};
1
+ import{j as t}from"./index-BOxe43p1.js";const x=({className:s,...a})=>t.jsx("table",{className:`tbl${s?" "+s:""}`,...a}),j=s=>t.jsx("thead",{...s}),c=s=>t.jsx("tbody",{...s}),e=s=>t.jsx("tr",{...s}),n=s=>t.jsx("th",{...s}),T=s=>t.jsx("td",{...s});export{x as T,j as a,e as b,n as c,c as d,T as e};
@@ -1,4 +1,4 @@
1
- import{c as t}from"./index-DI1fGIyj.js";/**
1
+ import{c as t}from"./index-BOxe43p1.js";/**
2
2
  * @license lucide-react v0.555.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -0,0 +1,16 @@
1
+ import{c as p,t as z,r,X as h,j as e,S as M,A,W as O,Y as B}from"./index-BOxe43p1.js";/* empty css */import{S as k,A as L}from"./SettingCard-D8K1LZNo.js";import{P as U}from"./page-header-COQZxJfR.js";import{L as _}from"./lock-CkOwgDcx.js";import{C as w}from"./circle-check-CYXBoUqT.js";import{A as $}from"./activity-CJ8LwZq9.js";import"./button-Cg08-EMT.js";import"./utils-CDN07tui.js";/**
2
+ * @license lucide-react v0.555.0 - ISC
3
+ *
4
+ * This source code is licensed under the ISC license.
5
+ * See the LICENSE file in the root directory of this source tree.
6
+ */const D=[["path",{d:"M12 20v2",key:"1lh1kg"}],["path",{d:"M12 2v2",key:"tus03m"}],["path",{d:"M17 20v2",key:"1rnc9c"}],["path",{d:"M17 2v2",key:"11trls"}],["path",{d:"M2 12h2",key:"1t8f8n"}],["path",{d:"M2 17h2",key:"7oei6x"}],["path",{d:"M2 7h2",key:"asdhe0"}],["path",{d:"M20 12h2",key:"1q8mjw"}],["path",{d:"M20 17h2",key:"1fpfkl"}],["path",{d:"M20 7h2",key:"1o8tra"}],["path",{d:"M7 20v2",key:"4gnj0m"}],["path",{d:"M7 2v2",key:"1i4yhu"}],["rect",{x:"4",y:"4",width:"16",height:"16",rx:"2",key:"1vbyd7"}],["rect",{x:"8",y:"8",width:"8",height:"8",rx:"1",key:"z9xiuo"}]],G=p("cpu",D);/**
7
+ * @license lucide-react v0.555.0 - ISC
8
+ *
9
+ * This source code is licensed under the ISC license.
10
+ * See the LICENSE file in the root directory of this source tree.
11
+ */const R=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20",key:"13o1zl"}],["path",{d:"M2 12h20",key:"9i4pu4"}]],T=p("globe",R);/**
12
+ * @license lucide-react v0.555.0 - ISC
13
+ *
14
+ * This source code is licensed under the ISC license.
15
+ * See the LICENSE file in the root directory of this source tree.
16
+ */const H=[["rect",{width:"20",height:"8",x:"2",y:"2",rx:"2",ry:"2",key:"ngkwjq"}],["rect",{width:"20",height:"8",x:"2",y:"14",rx:"2",ry:"2",key:"iecqi9"}],["line",{x1:"6",x2:"6.01",y1:"6",y2:"6",key:"16zg32"}],["line",{x1:"6",x2:"6.01",y1:"18",y2:"18",key:"nzw8ys"}]],X=p("server",H),C={aiProvider:"gemini",aiModel:"",aiBaseUrl:"",geminiModel:"",openaiModel:"",anthropicModel:"",ollamaModel:"",geminiSet:!1,openaiSet:!1,anthropicSet:!1},q=(a,i)=>a.aiProvider===i.aiProvider,F=(a,i)=>({gemini:a.geminiModel,openai:a.openaiModel,anthropic:a.anthropicModel,ollama:a.ollamaModel})[i]||a.aiModel,Y=["openai","ollama"],d=a=>{switch(a){case"gemini":return"gemini-3-flash-preview";case"openai":return"gpt-4o";case"anthropic":return"claude-sonnet-4-6";case"ollama":return"llama3";default:return"—"}},K=a=>{switch(a){case"ollama":return"http://localhost:11434";default:return"Provider default"}},ne=()=>{const{toast:a}=z(),[i,l]=r.useState(C),[m,u]=r.useState(C),[b,g]=r.useState(!0),[v,f]=r.useState(!1),[x,y]=r.useState(!1);r.useEffect(()=>{E()},[]);const E=async()=>{g(!0);try{const s=await h.getGlobalConfig(),n={aiProvider:s.aiProvider||"gemini",aiModel:s.aiModel||"",aiBaseUrl:s.aiBaseUrl||"",geminiModel:s.geminiModel||"",openaiModel:s.openaiModel||"",anthropicModel:s.anthropicModel||"",ollamaModel:s.ollamaModel||"",geminiSet:!!s.geminiSet,openaiSet:!!s.openaiSet,anthropicSet:!!s.anthropicSet};l(n),u(n)}catch(s){console.error("Failed to load AISettings",s),a("Failed to access AI configuration.","error")}finally{g(!1)}},P=async()=>{f(!0);try{await h.updateGlobalConfig({aiProvider:i.aiProvider}),u(i),a("AI engine configuration saved.","success")}catch(s){console.error("Failed to save AISettings",s),B(a,s)}finally{f(!1)}},I=async()=>{y(!0);const s=Date.now();try{const n=await h.testAIConfig({aiProvider:i.aiProvider}),o=Date.now()-s;n.success?a(`${n.message} (${o}ms)`,"success"):a(n.message,"error")}catch(n){a(`Connection failed: ${(n==null?void 0:n.message)||"unknown error"}`,"error")}finally{y(!1)}},c=[{id:"gemini",name:"Google Gemini",description:`${d("gemini")} — Multimodal reasoning`,icon:e.jsx("span",{className:"ai-provider-glyph",children:"G"}),isConfigured:!!i.geminiSet,setupHint:"Set XENON_GEMINI_API_KEY on the server to use Google Gemini"},{id:"openai",name:"OpenAI",description:`${d("openai")} — OpenAI v1 compatible`,icon:e.jsx(G,{size:18}),isConfigured:!!i.openaiSet,setupHint:"Set XENON_OPENAI_API_KEY on the server to use OpenAI"},{id:"anthropic",name:"Anthropic",description:`${d("anthropic")} — Advanced analysis`,icon:e.jsx(M,{size:18}),isConfigured:!!i.anthropicSet,setupHint:"Set XENON_ANTHROPIC_API_KEY on the server to use Anthropic"},{id:"ollama",name:"Ollama",description:"Local / self-hosted — no API key required",icon:e.jsx(X,{size:18}),isConfigured:!!i.ollamaModel||!!i.aiModel||!!i.aiBaseUrl,setupHint:"Set XENON_OLLAMA_MODEL or XENON_AI_BASE_URL on the server to use Ollama"}],t=c.find(s=>s.id===i.aiProvider),j=F(i,i.aiProvider),N=c.filter(s=>s.isConfigured).length,S=!q(i,m);return b?e.jsxs("div",{className:"settings-loading",children:[e.jsx(A,{className:"animate-spin",size:32}),e.jsx("span",{children:"Synchronizing Global State..."})]}):e.jsxs("div",{className:"settings-container",children:[e.jsx(U,{icon:O,title:"AI engine",subtitle:e.jsxs(e.Fragment,{children:["All credentials and endpoints are managed via environment variables.",e.jsxs("span",{className:"page-header-subnote",children:[e.jsx(_,{size:12}),"Select the active provider from configured options below."]})]})}),e.jsx("div",{className:"settings-content",children:e.jsxs("div",{className:"settings-grid settings-grid--two-equal",children:[e.jsx(k,{icon:e.jsx(M,{size:16}),title:"Provider registry",titleExtra:e.jsxs("span",{className:`provider-count-pill ${N>0?"is-ok":"is-empty"}`,children:[N," / ",c.length," configured"]}),description:"Providers are set up on the server. The one you save here replaces the server's own choice, and stays after a restart.",children:e.jsx("div",{className:"provider-list",children:c.map(s=>{const n=i.aiProvider===s.id,o=s.isConfigured;return e.jsxs("button",{type:"button",className:`provider-row ${n?"is-active":""} ${o?"":"is-disabled"}`,onClick:()=>o&&l({...i,aiProvider:s.id}),disabled:!o,title:o?`Activate ${s.name}`:s.setupHint,children:[e.jsx("div",{className:"provider-row__icon",children:s.icon}),e.jsxs("div",{className:"provider-row__body",children:[e.jsx("div",{className:"provider-row__name",children:s.name}),e.jsx("div",{className:"provider-row__desc",children:s.description}),e.jsx("div",{className:"provider-row__status",children:n?e.jsxs("span",{className:"provider-status provider-status--active",children:[e.jsx(w,{size:11}),s.isConfigured?"Active":"Active — no key"]}):s.isConfigured?e.jsxs("span",{className:"provider-status provider-status--ready",children:[e.jsx(w,{size:11}),"READY"]}):e.jsxs("span",{className:"provider-status provider-status--off",children:[e.jsx(_,{size:10}),"Not set"]})})]})]},s.id)})})}),e.jsxs(k,{icon:e.jsx(T,{size:16}),title:"Runtime configuration",description:"The model and address the active provider uses, from the server's settings.",children:[e.jsxs("div",{className:"ai-config-display",children:[e.jsxs("div",{className:"ai-config-row",children:[e.jsx("span",{className:"ai-config-label",children:"Active provider"}),e.jsxs("span",{className:"ai-config-value",children:[t==null?void 0:t.icon,(t==null?void 0:t.name)||"—"]})]}),e.jsxs("div",{className:"ai-config-row",children:[e.jsx("span",{className:"ai-config-label",children:"Model"}),e.jsxs("span",{className:"ai-config-value mono",children:[e.jsx("span",{children:j||d(i.aiProvider)}),!j&&e.jsx("span",{className:"ai-config-default",children:"Default"})]})]}),Y.includes(i.aiProvider)&&e.jsxs("div",{className:"ai-config-row",children:[e.jsx("span",{className:"ai-config-label",children:"Base URL"}),e.jsxs("span",{className:"ai-config-value mono",children:[e.jsx("span",{children:i.aiBaseUrl||K(i.aiProvider)}),!i.aiBaseUrl&&e.jsx("span",{className:"ai-config-default",children:"Default"})]})]})]}),e.jsxs("button",{type:"button",className:"test-connection-btn",onClick:I,disabled:x||!(t!=null&&t.isConfigured),children:[x?e.jsx(A,{size:14,className:"animate-spin"}):e.jsx($,{size:14}),e.jsx("span",{children:"Test Connection"})]})]})]})}),(S||v)&&e.jsx(L,{onSave:P,onDiscard:()=>l(m),isSaving:v,isDirty:S,saveLabel:"Save configuration"})]})};export{ne as AISettings};
@@ -1 +1 @@
1
- import{t as le,r as a,j as e,A as $,Y as g,y as oe}from"./index-DI1fGIyj.js";/* empty css */import{a as L}from"./time-D-gjmE1o.js";import{T as ce,a as de,b as z,c as l,d as me,e as o}from"./Table-io9fwa98.js";import{F as m}from"./FieldGroup-Bvn08svv.js";import{P as O}from"./page-header--aTyJXq6.js";import{M as B}from"./Modal-Cg9V5JYU.js";import{B as u}from"./button-fIW8owMI.js";import{I as H}from"./input-BjDRKCea.js";import{S as M}from"./select-DvCSv25z.js";import{P as v}from"./plus-CsIk10Cq.js";import{T as pe}from"./trash-2-CTZpPSdd.js";import{C as he}from"./check-BdTh1Sq7.js";import{C as xe}from"./copy-DGSbZI3u.js";import"./index-HDQVe1gi.js";import"./utils-CDN07tui.js";const Y=["read","sessions","devices","admin"],U={"7d":"7 days","30d":"30 days","90d":"90 days","1y":"1 year",never:"No expiry"},ue={"7d":7,"30d":30,"90d":90,"1y":365};function W(i){return i==="never"?null:new Date(Date.now()+ue[i]*864e5).toISOString()}function q(i){if(!i)return"Never";const n=Date.now()-new Date(i).getTime();return n<6e4?"Just now":n<36e5?`${Math.floor(n/6e4)}m ago`:n<864e5?`${Math.floor(n/36e5)}h ago`:`${Math.floor(n/864e5)}d ago`}const Ee=()=>{const{toast:i}=le(),[n,w]=a.useState([]),[b,J]=a.useState([]),[X,N]=a.useState(!0),[G,k]=a.useState(!1),[Q,d]=a.useState(!1),[r,y]=a.useState(null),[C,S]=a.useState(null),[T,_]=a.useState(!1),[p,A]=a.useState(""),[j,I]=a.useState({read:!0,sessions:!0,devices:!1,admin:!1}),[R,P]=a.useState(300),[E,D]=a.useState(""),[h,F]=a.useState("30d"),[x,K]=a.useState(!1),V=s=>{var t;return s?((t=b.find(c=>c.id===s))==null?void 0:t.name)||s.slice(0,8):"Shared"},f=async()=>{N(!0);try{const[s,t]=await Promise.all([fetch("/xenon/api/apikeys",{credentials:"include"}),fetch("/xenon/api/teams",{credentials:"include"})]);if(s.status===403){k(!0),w([]);return}if(!s.ok)throw new Error(`HTTP ${s.status}`);w(await s.json()),t.ok&&J(await t.json()),k(!1)}catch(s){i(`Failed to load API keys: ${s.message}`,"error")}finally{N(!1)}};a.useEffect(()=>{f()},[]);const Z=()=>{A(""),I({read:!0,sessions:!0,devices:!1,admin:!1}),P(300),D(""),F("30d")},ee=async()=>{const s=Y.filter(t=>j[t]);if(!p.trim()){i("Key name is required","error");return}if(s.length===0){i("Select at least one scope","error");return}K(!0);try{const t=await fetch("/xenon/api/apikeys",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:p.trim(),scopes:s,rateLimit:R,teamId:E||null,expiresAt:W(h)})});if(!t.ok)throw new Error(`HTTP ${t.status}`);const c=await t.json();d(!1),Z(),y({name:p.trim(),raw:c.key}),await f()}catch(t){i(`Create failed: ${t.message}`,"error")}finally{K(!1)}},se=async s=>{S(s);try{const t=await fetch(`/xenon/api/apikeys/${s}`,{method:"DELETE",credentials:"include"});if(!t.ok)throw new Error(`HTTP ${t.status}`);i("Key revoked","success"),await f()}catch(t){i(`Revoke failed: ${t.message}`,"error")}finally{S(null)}},te=async s=>{try{await navigator.clipboard.writeText(s),_(!0),setTimeout(()=>_(!1),1500)}catch{i("Copy failed — select the text manually","error")}};if(X)return e.jsxs("div",{className:"settings-loading",children:[e.jsx($,{className:"animate-spin",size:32}),e.jsx("span",{children:"Loading API keys…"})]});if(G)return e.jsx("div",{className:"settings-container",children:e.jsx(O,{icon:g,title:"API keys",subtitle:e.jsxs(e.Fragment,{children:["Your key lacks the ",e.jsx("code",{children:"admin"})," scope. Ask an administrator to issue an admin key so you can manage access for other users."]})})});const ae=n.length,ie=n.filter(s=>s.scopes.includes("admin")).length,ne=n.filter(s=>s.lastUsedAt&&Date.now()-new Date(s.lastUsedAt).getTime()<864e5).length;return e.jsxs("div",{className:"settings-container",children:[e.jsx(O,{icon:g,title:"API keys",subtitle:e.jsxs(e.Fragment,{children:["Issue scoped credentials for humans (dashboard login) and machines (CI, WebDriver clients via ",e.jsx("code",{children:"xe:options.accessKey"})," + ",e.jsx("code",{children:"xe:options.token"}),"). Keys are shown only once at creation — copy the value before closing the dialog."]}),action:e.jsxs("button",{type:"button",className:"page-header-action",onClick:()=>d(!0),children:[e.jsx(v,{size:16}),e.jsx("span",{children:"Create new key"})]})}),e.jsxs("div",{className:"settings-content",children:[n.length>0&&e.jsxs("div",{className:"stat-strip",children:[e.jsxs("div",{className:"stat-strip__cell",children:[e.jsx("div",{className:"stat-strip__value",children:ae}),e.jsx("div",{className:"stat-strip__label",children:"Total keys"})]}),e.jsxs("div",{className:"stat-strip__cell",children:[e.jsx("div",{className:"stat-strip__value stat-strip__value--accent",children:ie}),e.jsx("div",{className:"stat-strip__label",children:"Admin scope"})]}),e.jsxs("div",{className:"stat-strip__cell",children:[e.jsx("div",{className:"stat-strip__value",children:ne}),e.jsx("div",{className:"stat-strip__label",children:"Active in last 24h"})]})]}),n.length===0?e.jsxs("div",{className:"empty-state",children:[e.jsx("div",{className:"empty-state__icon",children:e.jsx(g,{size:28})}),e.jsx("h3",{className:"empty-state__title",children:"No API keys yet"}),e.jsx("p",{className:"empty-state__copy",children:"Issue your first key to authenticate WebDriver clients or CI pipelines. Keys are shown only once at creation — copy the value before closing the dialog."}),e.jsxs("button",{type:"button",className:"page-header-action empty-state__action",onClick:()=>d(!0),children:[e.jsx(v,{size:16}),e.jsx("span",{children:"Create your first key"})]})]}):e.jsx("div",{className:"data-card",children:e.jsxs(ce,{children:[e.jsx(de,{children:e.jsxs(z,{children:[e.jsx(l,{children:"Name"}),e.jsx(l,{children:"Team"}),e.jsx(l,{children:"Scopes"}),e.jsx(l,{children:"Rate limit"}),e.jsx(l,{children:"Last used"}),e.jsx(l,{children:"Created"}),e.jsx(l,{children:"Expires"}),e.jsx(l,{style:{textAlign:"right"},children:"Actions"})]})}),e.jsx(me,{children:n.map(s=>e.jsxs(z,{children:[e.jsxs(o,{children:[e.jsx("strong",{children:s.name}),e.jsx("div",{className:"row-meta-mono",children:s.id.slice(0,8)})]}),e.jsx(o,{children:e.jsx("span",{className:`pill-chip ${s.teamId?"pill-chip--team":"pill-chip--shared"}`,children:V(s.teamId)})}),e.jsx(o,{children:e.jsx("div",{className:"scope-chips",children:s.scopes.split(",").map(t=>{const c=t.trim(),re=c==="admin";return e.jsx("span",{className:`pill-chip ${re?"pill-chip--admin":"pill-chip--scope"}`,children:c},t)})})}),e.jsxs(o,{className:"row-mono",children:[s.rateLimit,"/min"]}),e.jsx(o,{className:"row-mono",children:q(s.lastUsedAt)}),e.jsx(o,{className:"row-mono",children:q(s.createdAt)}),e.jsx(o,{className:"row-mono",children:s.expiresAt?new Date(s.expiresAt).getTime()<=Date.now()?e.jsx("span",{style:{color:"var(--red)"},children:"expired"}):L(s.expiresAt):"Never"}),e.jsx(o,{style:{textAlign:"right"},children:e.jsxs("button",{type:"button",className:"row-action row-action--danger",disabled:C===s.id,onClick:()=>{window.confirm(`Revoke "${s.name}"? Any client using this key will immediately fail.`)&&se(s.id)},children:[e.jsx(pe,{size:13}),C===s.id?"Revoking…":"Revoke"]})})]},s.id))})]})})]}),e.jsx(B,{open:Q,title:"Create API key",width:520,onClose:()=>d(!1),footer:e.jsxs(e.Fragment,{children:[e.jsx(u,{variant:"secondary",onClick:()=>d(!1),disabled:x,children:"Cancel"}),e.jsxs(u,{variant:"primary",onClick:ee,disabled:x,children:[x?e.jsx($,{className:"animate-spin",size:18}):e.jsx(v,{size:18}),x?"Creating…":"Create key"]})]}),children:e.jsxs("div",{style:{display:"flex",flexDirection:"column"},children:[e.jsx(m,{label:"Name",htmlFor:"apikey-name",children:e.jsx(H,{id:"apikey-name",type:"text",value:p,onChange:s=>A(s.target.value),placeholder:"alice-laptop, ci-main, etc.",className:"w-full",autoFocus:!0})}),e.jsx(m,{label:"Scopes",description:e.jsxs(e.Fragment,{children:[e.jsx("code",{children:"admin"})," grants full access including API-key management."," ",e.jsx("code",{children:"sessions"})," is required for WebDriver sessions (",e.jsx("code",{children:"xe:options.accessKey"})," + ",e.jsx("code",{children:"xe:options.token"}),")."]}),children:e.jsx("div",{style:{display:"flex",flexWrap:"wrap",gap:8},children:Y.map(s=>e.jsxs("label",{style:ye,children:[e.jsx("input",{type:"checkbox",checked:j[s],onChange:t=>I({...j,[s]:t.target.checked})}),e.jsx("span",{children:s})]},s))})}),e.jsx(m,{label:"Rate limit (requests/min)",htmlFor:"apikey-ratelimit",children:e.jsx(H,{id:"apikey-ratelimit",type:"number",min:10,step:10,value:R,onChange:s=>P(parseInt(s.target.value)||300),className:"w-full"})}),e.jsx(m,{label:"Default team",description:e.jsxs(e.Fragment,{children:["Keys without a team can only reach shared-pool devices. Admins can override at session time via ",e.jsx("code",{children:"xe:options.team"}),"."]}),htmlFor:"apikey-team",children:e.jsxs(M,{id:"apikey-team",value:E,onChange:s=>D(s.target.value),className:"w-full",children:[e.jsx("option",{value:"",children:"No team (shared pool only)"}),b.map(s=>e.jsx("option",{value:s.id,children:s.name},s.id))]})}),e.jsx(m,{label:"Expires after",description:h==="never"?"Key never expires. Rotate manually when needed.":`Key will stop working on ${L(W(h))}.`,htmlFor:"apikey-expiry",children:e.jsx(M,{id:"apikey-expiry",value:h,onChange:s=>F(s.target.value),className:"w-full",children:Object.keys(U).map(s=>e.jsx("option",{value:s,children:U[s]},s))})})]})}),e.jsx(B,{open:!!r,title:r?`Key created: ${r.name}`:"",width:560,onClose:()=>y(null),closeOnOverlayClick:!1,footer:e.jsxs(e.Fragment,{children:[e.jsxs(u,{variant:"primary",onClick:()=>r&&te(r.raw),disabled:!r,children:[T?e.jsx(he,{size:18}):e.jsx(xe,{size:18}),T?"Copied":"Copy to clipboard"]}),e.jsx(u,{variant:"secondary",onClick:()=>y(null),children:"I've saved it"})]}),children:r&&e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:16},children:[e.jsxs("div",{style:{background:"var(--status-busy-bg)",border:"1px solid var(--status-busy-border)",borderRadius:6,padding:12,display:"flex",gap:8,alignItems:"flex-start"},children:[e.jsx(oe,{size:18,style:{flexShrink:0,marginTop:2}}),e.jsxs("div",{children:[e.jsx("strong",{children:"This key will not be shown again."})," Copy it now and store it in your password manager, CI secret store, or client config."]})]}),e.jsx("div",{style:{fontFamily:"monospace",padding:12,background:"rgb(var(--rgb-black) / 0.3)",borderRadius:6,wordBreak:"break-all",fontSize:"0.9em"},children:r.raw})]})})]})},ye={display:"flex",alignItems:"center",gap:6,padding:"6px 12px",background:"rgb(var(--rgb-white) / 0.04)",borderRadius:6,cursor:"pointer",fontFamily:"monospace",fontSize:"0.9em"};export{Ee as ApiKeys};
1
+ import{t as le,r as a,j as e,A as $,Z as g,y as oe}from"./index-BOxe43p1.js";/* empty css */import{a as L}from"./time-D-gjmE1o.js";import{T as ce,a as de,b as z,c as l,d as me,e as o}from"./Table-zNTX92Pn.js";import{F as m}from"./FieldGroup-CveQ3xrA.js";import{P as O}from"./page-header-COQZxJfR.js";import{M as B}from"./Modal-Bsvj1tm2.js";import{B as u}from"./button-Cg08-EMT.js";import{I as H}from"./input-CZHFjbSg.js";import{S as M}from"./select-Bpyn7rWO.js";import{P as v}from"./plus-5aq-9uRx.js";import{T as pe}from"./trash-2-B701i8sy.js";import{C as he}from"./check-BMTaH72W.js";import{C as xe}from"./copy-Be7LNMXV.js";import"./index-CfxsUslp.js";import"./utils-CDN07tui.js";const U=["read","sessions","devices","admin"],W={"7d":"7 days","30d":"30 days","90d":"90 days","1y":"1 year",never:"No expiry"},ue={"7d":7,"30d":30,"90d":90,"1y":365};function Y(i){return i==="never"?null:new Date(Date.now()+ue[i]*864e5).toISOString()}function q(i){if(!i)return"Never";const n=Date.now()-new Date(i).getTime();return n<6e4?"Just now":n<36e5?`${Math.floor(n/6e4)}m ago`:n<864e5?`${Math.floor(n/36e5)}h ago`:`${Math.floor(n/864e5)}d ago`}const Ee=()=>{const{toast:i}=le(),[n,w]=a.useState([]),[b,J]=a.useState([]),[X,k]=a.useState(!0),[G,N]=a.useState(!1),[Z,d]=a.useState(!1),[r,y]=a.useState(null),[C,T]=a.useState(null),[S,_]=a.useState(!1),[p,I]=a.useState(""),[j,A]=a.useState({read:!0,sessions:!0,devices:!1,admin:!1}),[R,P]=a.useState(300),[E,F]=a.useState(""),[h,D]=a.useState("30d"),[x,K]=a.useState(!1),Q=s=>{var t;return s?((t=b.find(c=>c.id===s))==null?void 0:t.name)||s.slice(0,8):"Shared"},f=async()=>{k(!0);try{const[s,t]=await Promise.all([fetch("/xenon/api/apikeys",{credentials:"include"}),fetch("/xenon/api/teams",{credentials:"include"})]);if(s.status===403){N(!0),w([]);return}if(!s.ok)throw new Error(`HTTP ${s.status}`);w(await s.json()),t.ok&&J(await t.json()),N(!1)}catch(s){i(`Failed to load API keys: ${s.message}`,"error")}finally{k(!1)}};a.useEffect(()=>{f()},[]);const V=()=>{I(""),A({read:!0,sessions:!0,devices:!1,admin:!1}),P(300),F(""),D("30d")},ee=async()=>{const s=U.filter(t=>j[t]);if(!p.trim()){i("Key name is required","error");return}if(s.length===0){i("Select at least one scope","error");return}K(!0);try{const t=await fetch("/xenon/api/apikeys",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:p.trim(),scopes:s,rateLimit:R,teamId:E||null,expiresAt:Y(h)})});if(!t.ok)throw new Error(`HTTP ${t.status}`);const c=await t.json();d(!1),V(),y({name:p.trim(),raw:c.key}),await f()}catch(t){i(`Create failed: ${t.message}`,"error")}finally{K(!1)}},se=async s=>{T(s);try{const t=await fetch(`/xenon/api/apikeys/${s}`,{method:"DELETE",credentials:"include"});if(!t.ok)throw new Error(`HTTP ${t.status}`);i("Key revoked","success"),await f()}catch(t){i(`Revoke failed: ${t.message}`,"error")}finally{T(null)}},te=async s=>{try{await navigator.clipboard.writeText(s),_(!0),setTimeout(()=>_(!1),1500)}catch{i("Copy failed — select the text manually","error")}};if(X)return e.jsxs("div",{className:"settings-loading",children:[e.jsx($,{className:"animate-spin",size:32}),e.jsx("span",{children:"Loading API keys…"})]});if(G)return e.jsx("div",{className:"settings-container",children:e.jsx(O,{icon:g,title:"API keys",subtitle:e.jsxs(e.Fragment,{children:["Your key lacks the ",e.jsx("code",{children:"admin"})," scope. Ask an administrator to issue an admin key so you can manage access for other users."]})})});const ae=n.length,ie=n.filter(s=>s.scopes.includes("admin")).length,ne=n.filter(s=>s.lastUsedAt&&Date.now()-new Date(s.lastUsedAt).getTime()<864e5).length;return e.jsxs("div",{className:"settings-container",children:[e.jsx(O,{icon:g,title:"API keys",subtitle:e.jsxs(e.Fragment,{children:["Issue scoped credentials for humans (dashboard login) and machines (CI, WebDriver clients via ",e.jsx("code",{children:"xe:options.accessKey"})," + ",e.jsx("code",{children:"xe:options.token"}),"). Keys are shown only once at creation — copy the value before closing the dialog."]}),action:e.jsxs("button",{type:"button",className:"page-header-action",onClick:()=>d(!0),children:[e.jsx(v,{size:16}),e.jsx("span",{children:"Create new key"})]})}),e.jsxs("div",{className:"settings-content",children:[n.length>0&&e.jsxs("div",{className:"stat-strip",children:[e.jsxs("div",{className:"stat-strip__cell",children:[e.jsx("div",{className:"stat-strip__value",children:ae}),e.jsx("div",{className:"stat-strip__label",children:"Total keys"})]}),e.jsxs("div",{className:"stat-strip__cell",children:[e.jsx("div",{className:"stat-strip__value stat-strip__value--accent",children:ie}),e.jsx("div",{className:"stat-strip__label",children:"Admin scope"})]}),e.jsxs("div",{className:"stat-strip__cell",children:[e.jsx("div",{className:"stat-strip__value",children:ne}),e.jsx("div",{className:"stat-strip__label",children:"Active in last 24h"})]})]}),n.length===0?e.jsxs("div",{className:"empty-state",children:[e.jsx("div",{className:"empty-state__icon",children:e.jsx(g,{size:28})}),e.jsx("h3",{className:"empty-state__title",children:"No API keys yet"}),e.jsx("p",{className:"empty-state__copy",children:"Issue your first key to authenticate WebDriver clients or CI pipelines. Keys are shown only once at creation — copy the value before closing the dialog."}),e.jsxs("button",{type:"button",className:"page-header-action empty-state__action",onClick:()=>d(!0),children:[e.jsx(v,{size:16}),e.jsx("span",{children:"Create your first key"})]})]}):e.jsx("div",{className:"data-card",children:e.jsxs(ce,{children:[e.jsx(de,{children:e.jsxs(z,{children:[e.jsx(l,{children:"Name"}),e.jsx(l,{children:"Team"}),e.jsx(l,{children:"Scopes"}),e.jsx(l,{children:"Rate limit"}),e.jsx(l,{children:"Last used"}),e.jsx(l,{children:"Created"}),e.jsx(l,{children:"Expires"}),e.jsx(l,{style:{textAlign:"right"},children:"Actions"})]})}),e.jsx(me,{children:n.map(s=>e.jsxs(z,{children:[e.jsxs(o,{children:[e.jsx("strong",{children:s.name}),e.jsx("div",{className:"row-meta-mono",children:s.id.slice(0,8)})]}),e.jsx(o,{children:e.jsx("span",{className:`pill-chip ${s.teamId?"pill-chip--team":"pill-chip--shared"}`,children:Q(s.teamId)})}),e.jsx(o,{children:e.jsx("div",{className:"scope-chips",children:s.scopes.split(",").map(t=>{const c=t.trim(),re=c==="admin";return e.jsx("span",{className:`pill-chip ${re?"pill-chip--admin":"pill-chip--scope"}`,children:c},t)})})}),e.jsxs(o,{className:"row-mono",children:[s.rateLimit,"/min"]}),e.jsx(o,{className:"row-mono",children:q(s.lastUsedAt)}),e.jsx(o,{className:"row-mono",children:q(s.createdAt)}),e.jsx(o,{className:"row-mono",children:s.expiresAt?new Date(s.expiresAt).getTime()<=Date.now()?e.jsx("span",{style:{color:"var(--red)"},children:"expired"}):L(s.expiresAt):"Never"}),e.jsx(o,{style:{textAlign:"right"},children:e.jsxs("button",{type:"button",className:"row-action row-action--danger",disabled:C===s.id,onClick:()=>{window.confirm(`Revoke "${s.name}"? Any client using this key will immediately fail.`)&&se(s.id)},children:[e.jsx(pe,{size:13}),C===s.id?"Revoking…":"Revoke"]})})]},s.id))})]})})]}),e.jsx(B,{open:Z,title:"Create API key",width:520,onClose:()=>d(!1),footer:e.jsxs(e.Fragment,{children:[e.jsx(u,{variant:"secondary",onClick:()=>d(!1),disabled:x,children:"Cancel"}),e.jsxs(u,{variant:"primary",onClick:ee,disabled:x,children:[x?e.jsx($,{className:"animate-spin",size:18}):e.jsx(v,{size:18}),x?"Creating…":"Create key"]})]}),children:e.jsxs("div",{style:{display:"flex",flexDirection:"column"},children:[e.jsx(m,{label:"Name",htmlFor:"apikey-name",children:e.jsx(H,{id:"apikey-name",type:"text",value:p,onChange:s=>I(s.target.value),placeholder:"alice-laptop, ci-main, etc.",className:"w-full",autoFocus:!0})}),e.jsx(m,{label:"Scopes",description:e.jsxs(e.Fragment,{children:[e.jsx("code",{children:"admin"})," grants full access including API-key management."," ",e.jsx("code",{children:"sessions"})," is required for WebDriver sessions (",e.jsx("code",{children:"xe:options.accessKey"})," + ",e.jsx("code",{children:"xe:options.token"}),")."]}),children:e.jsx("div",{style:{display:"flex",flexWrap:"wrap",gap:8},children:U.map(s=>e.jsxs("label",{style:ye,children:[e.jsx("input",{type:"checkbox",checked:j[s],onChange:t=>A({...j,[s]:t.target.checked})}),e.jsx("span",{children:s})]},s))})}),e.jsx(m,{label:"Rate limit (requests/min)",htmlFor:"apikey-ratelimit",children:e.jsx(H,{id:"apikey-ratelimit",type:"number",min:10,step:10,value:R,onChange:s=>P(parseInt(s.target.value)||300),className:"w-full"})}),e.jsx(m,{label:"Team",description:e.jsxs(e.Fragment,{children:["The key is yours, so like you it can use every team's devices, whichever team you pick. The team is recorded on the leases it takes, and limits the key only if you are made a member. To keep a test session to one team, set"," ",e.jsx("code",{children:"xe:options.team"}),"."]}),htmlFor:"apikey-team",children:e.jsxs(M,{id:"apikey-team",value:E,onChange:s=>F(s.target.value),className:"w-full",children:[e.jsx("option",{value:"",children:"No team"}),b.map(s=>e.jsx("option",{value:s.id,children:s.name},s.id))]})}),e.jsx(m,{label:"Expires after",description:h==="never"?"Key never expires. Rotate manually when needed.":`Key will stop working on ${L(Y(h))}.`,htmlFor:"apikey-expiry",children:e.jsx(M,{id:"apikey-expiry",value:h,onChange:s=>D(s.target.value),className:"w-full",children:Object.keys(W).map(s=>e.jsx("option",{value:s,children:W[s]},s))})})]})}),e.jsx(B,{open:!!r,title:r?`Key created: ${r.name}`:"",width:560,onClose:()=>y(null),closeOnOverlayClick:!1,footer:e.jsxs(e.Fragment,{children:[e.jsxs(u,{variant:"primary",onClick:()=>r&&te(r.raw),disabled:!r,children:[S?e.jsx(he,{size:18}):e.jsx(xe,{size:18}),S?"Copied":"Copy to clipboard"]}),e.jsx(u,{variant:"secondary",onClick:()=>y(null),children:"I've saved it"})]}),children:r&&e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:16},children:[e.jsxs("div",{style:{background:"var(--status-busy-bg)",border:"1px solid var(--status-busy-border)",borderRadius:6,padding:12,display:"flex",gap:8,alignItems:"flex-start"},children:[e.jsx(oe,{size:18,style:{flexShrink:0,marginTop:2}}),e.jsxs("div",{children:[e.jsx("strong",{children:"This key will not be shown again."})," Copy it now and store it in your password manager, CI secret store, or client config."]})]}),e.jsx("div",{style:{fontFamily:"monospace",padding:12,background:"rgb(var(--rgb-black) / 0.3)",borderRadius:6,wordBreak:"break-all",fontSize:"0.9em"},children:r.raw})]})})]})},ye={display:"flex",alignItems:"center",gap:6,padding:"6px 12px",background:"rgb(var(--rgb-white) / 0.04)",borderRadius:6,cursor:"pointer",fontFamily:"monospace",fontSize:"0.9em"};export{Ee as ApiKeys};
@@ -1,4 +1,4 @@
1
- import{c as k,j as e,r as i,A as X,t as ve,b as je,X as p,K as fe,q as V,z as ye,v as ge}from"./index-DI1fGIyj.js";import{f as Ne}from"./time-D-gjmE1o.js";import{c as be,B as x}from"./button-fIW8owMI.js";import{c as ke}from"./utils-CDN07tui.js";import{P as we}from"./page-header--aTyJXq6.js";import{S as Z}from"./select-DvCSv25z.js";import{M as J}from"./Modal-Cg9V5JYU.js";import{F as Q}from"./FieldGroup-Bvn08svv.js";import{U as ee,T as q}from"./upload-P3XzwQUb.js";import{C as Ce}from"./check-BdTh1Sq7.js";import{C as Ae}from"./copy-DGSbZI3u.js";import{Z as Se}from"./zap-DRz0tDq5.js";import{D as ze}from"./download-WG6l7BgD.js";import{T as Me}from"./trash-2-CTZpPSdd.js";import"./index-HDQVe1gi.js";/**
1
+ import{c as k,j as e,r as i,A as K,t as ve,b as je,X as p,O as fe,q as V,z as ye,v as ge}from"./index-BOxe43p1.js";import{f as Ne}from"./time-D-gjmE1o.js";import{c as be,B as x}from"./button-Cg08-EMT.js";import{c as ke}from"./utils-CDN07tui.js";import{P as we}from"./page-header-COQZxJfR.js";import{S as Z}from"./select-Bpyn7rWO.js";import{M as J}from"./Modal-Bsvj1tm2.js";import{F as Q}from"./FieldGroup-CveQ3xrA.js";import{U as ee,T as q}from"./upload-C2gr44RS.js";import{C as Ce}from"./check-BMTaH72W.js";import{C as Ae}from"./copy-Be7LNMXV.js";import{Z as Se}from"./zap-DO9ry1iz.js";import{D as ze}from"./download-B56lwxWP.js";import{T as Me}from"./trash-2-B701i8sy.js";import"./index-CfxsUslp.js";/**
2
2
  * @license lucide-react v0.555.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -23,4 +23,4 @@ import{c as k,j as e,r as i,A as X,t as ve,b as je,X as p,K as fe,q as V,z as ye
23
23
  *
24
24
  * This source code is licensed under the ISC license.
25
25
  * See the LICENSE file in the root directory of this source tree.
26
- */const Ue=[["path",{d:"M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09z",key:"m3kijz"}],["path",{d:"m12 15-3-3a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.35 22.35 0 0 1-4 2z",key:"1fmvmk"}],["path",{d:"M9 12H4s.55-3.03 2-4c1.62-1.08 5 0 5 0",key:"1f8sc4"}],["path",{d:"M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5",key:"qeys4"}]],W=k("rocket",Ue),Re=be("badge-base",{variants:{variant:{default:"badge-variant-default",success:"badge-variant-success",warning:"badge-variant-warning",error:"badge-variant-error",outline:"badge-variant-outline",secondary:"badge-variant-secondary"}},defaultVariants:{variant:"default"}});function Y({className:r,variant:c,...n}){return e.jsx("div",{className:ke(Re({variant:c}),r),...n})}const ae=({id:r,value:c,teams:n,onChange:m,disabled:h})=>e.jsxs(Z,{id:r,value:c,disabled:h,className:"w-full",onChange:l=>m(l.target.value),children:[e.jsx("option",{value:"",children:"Shared"}),n.map(l=>e.jsx("option",{value:l.id,children:l.name},l.id))]}),te="Members of the team can see and run it. Shared apps are open to everyone.",_e=({open:r,teams:c,teamId:n,onTeamChange:m,onChooseFile:h,onClose:l})=>e.jsx(J,{open:r,onClose:l,title:"Upload app",footer:e.jsxs(e.Fragment,{children:[e.jsx(x,{variant:"secondary",onClick:l,children:"Cancel"}),e.jsxs(x,{variant:"primary",onClick:h,children:[e.jsx(ee,{size:14,className:"mr-1"}),"Choose file…"]})]}),children:e.jsx(Q,{label:"Team",htmlFor:"upload-app-team",description:te,children:e.jsx(ae,{id:"upload-app-team",value:n,teams:c,onChange:m})})}),Le=({app:r,teams:c,onMove:n,onClose:m})=>{const[h,l]=i.useState(""),[d,f]=i.useState(!1),[y,u]=i.useState(null);i.useEffect(()=>{l((r==null?void 0:r.teamId)??""),u(null)},[r]);const g=async()=>{f(!0),u(null);try{await n(h||null)}catch(v){u((v==null?void 0:v.message)||"Could not move the app")}finally{f(!1)}};return e.jsxs(J,{open:!!r,onClose:m,title:"Move to team",footer:e.jsxs(e.Fragment,{children:[e.jsx(x,{variant:"secondary",onClick:m,disabled:d,children:"Cancel"}),e.jsxs(x,{variant:"primary",onClick:g,disabled:d,children:[d?e.jsx(X,{size:14,className:"mr-1 animate-spin"}):e.jsx(se,{size:14,className:"mr-1"}),"Move"]})]}),children:[e.jsx("p",{className:"app-move-name",children:r==null?void 0:r.name}),e.jsx(Q,{label:"Team",htmlFor:"move-app-team",description:te,error:y??void 0,children:e.jsx(ae,{id:"move-app-team",value:h,teams:c,onChange:l,disabled:d})})]})},K=r=>{var c;return((c=r.team)==null?void 0:c.name)??(r.teamId?String(r.teamId).slice(0,8):"Shared")},ss=()=>{const{toast:r,removeToast:c}=ve(),[n,m]=i.useState([]),[h,l]=i.useState([]),[d,f]=i.useState(!1),[y,u]=i.useState(""),[g,v]=i.useState(!1),[re,R]=i.useState(null),[w,_]=i.useState({android:!0,ios:!0}),[S,ie]=i.useState("desc"),[C,z]=i.useState(null),[M,T]=i.useState(""),D=i.useRef(null),{me:j}=je(),N=(j==null?void 0:j.role)==="ADMIN"||(j==null?void 0:j.role)==="SUPER_ADMIN",[L,B]=i.useState([]),[ne,I]=i.useState(!1),[E,G]=i.useState(""),[F,$]=i.useState(null),b=i.useCallback(async()=>{f(!0);try{const s=await p.getApps();m(Array.isArray(s)?s:[])}catch(s){console.error("Failed to fetch apps",s)}finally{f(!1)}},[]),U=i.useCallback(async()=>{try{const s=await p.getDevices();l(Array.isArray(s)?s:[])}catch(s){console.error("Failed to fetch devices",s)}},[]);i.useEffect(()=>{b(),U();const s=setInterval(U,1e4);return()=>clearInterval(s)},[b,U]),i.useEffect(()=>{N&&p.listTeams().then(B).catch(()=>B([]))},[N]);const O=()=>{var s;N?(G(""),I(!0)):(s=D.current)==null||s.click()},le=async s=>{F&&(await p.setAppTeam(F.id,s),r(s?"App moved to team":"App shared with everyone","success"),$(null),await b())},ce=async s=>{var o;const a=(o=s.target.files)==null?void 0:o[0];if(!a)return;const t=N&&E?E:null;I(!1),v(!0);try{await p.uploadApp(a,t),await b()}catch(ue){console.error("Upload failed",ue)}finally{v(!1),s.target&&(s.target.value="")}},oe=async(s,a)=>{if(window.confirm(`Permanently remove artifact "${a}"?`))try{await p.deleteApp(s),m(t=>t.filter(o=>o.id!==s))}catch(t){console.error("Delete failed",t)}},de=(s,a)=>{navigator.clipboard.writeText(s),R(`${a}-${s}`),setTimeout(()=>R(null),2e3)},me=async(s,a)=>{const t=r(`Deploying app to ${a}...`,"loading",0);try{const o=await p.installRepositoryApp(a,s);o.success?(r("App deployed successfully","success"),z(null),T("")):r(`Deployment failed: ${o.error}`,"error")}catch(o){r(`Execution Error: ${o.message}`,"error")}finally{c(t)}},A=n.filter(s=>{const a=s.name.toLowerCase().includes(y.toLowerCase())||s.packageName&&s.packageName.toLowerCase().includes(y.toLowerCase()),t=w.android&&s.platform==="android"||w.ios&&s.platform==="ios";return a&&t}).sort((s,a)=>{const t=new Date(s.createdAt).getTime(),o=new Date(a.createdAt).getTime();return S==="desc"?o-t:t-o}),he=s=>{if(!s)return"0 B";const a=1024,t=Math.floor(Math.log(s)/Math.log(a));return parseFloat((s/Math.pow(a,t)).toFixed(1))+" "+["B","KB","MB","GB"][t]},pe=s=>Ne(s),P=s=>{_(a=>({...a,[s]:!a[s]}))},xe=s=>{const a=s.toLowerCase();return a.includes("wda-signed")||a.includes("wda-resign")||a.includes("webdriveragent")};return e.jsxs("div",{className:"apps-container device-explorer-container",children:[e.jsx("div",{className:"scanline",style:{position:"absolute",inset:0,pointerEvents:"none",opacity:.05,zIndex:1001}}),e.jsx(we,{icon:fe,title:"Apps",subtitle:"Signed builds available for installation across your device fleet."}),e.jsxs("div",{className:"device-explorer-header-container",children:[e.jsxs("div",{className:"device-explorer-header-left-container",children:[e.jsx("div",{className:"device-explorer-header-entry",children:e.jsxs("div",{className:"device-explorer-header-value",children:[e.jsxs("button",{className:`device-explorer-header__platform-btn ${w.android&&"selected"}`,onClick:()=>P("android"),children:[e.jsx(V,{size:18,color:"currentColor"})," Android"]}),e.jsxs("button",{className:`device-explorer-header__platform-btn ${w.ios&&"selected"}`,onClick:()=>P("ios"),children:[e.jsx(H,{size:18,color:"currentColor"})," iOS"]})]})}),e.jsx("div",{className:"device-explorer-header-entry",children:e.jsx("div",{className:"device-explorer-header-value",children:e.jsxs("div",{className:"device-explorer-search-wrapper",children:[e.jsx(ye,{size:16,color:"#94a3b8",className:"device-explorer-search-icon"}),e.jsx("input",{type:"text",className:"device-explorer-header-text-filter",placeholder:"Filter by bundle or name...",value:y,onChange:s=>u(s.target.value)})]})})}),e.jsx("div",{className:"device-explorer-header-filter-count",children:e.jsxs(Y,{variant:"secondary",children:[e.jsx("span",{className:"font-bold",children:A.length})," of"," ",e.jsx("span",{className:"font-bold",children:n.length})," ",n.length===1?"artifact":"artifacts"]})})]}),e.jsxs("div",{className:"device-explorer-header-right-container",children:[e.jsx("button",{className:"icon-btn-secondary sort-btn",onClick:()=>ie(s=>s==="desc"?"asc":"desc"),title:S==="desc"?"Newest First":"Oldest First",children:S==="desc"?e.jsx(Ie,{size:18}):e.jsx($e,{size:18})}),e.jsxs(x,{size:"sm",variant:"secondary",onClick:()=>b(),disabled:d,children:[e.jsx(X,{size:14,className:`mr-1 ${d&&"animate-spin"}`}),"Refresh"]}),e.jsx("input",{ref:D,type:"file",accept:".apk,.ipa",onChange:ce,hidden:!0}),e.jsxs(x,{size:"sm",variant:"primary",onClick:O,disabled:g,children:[e.jsx(ee,{size:14,className:"mr-1"}),"Upload app"]})]})]}),e.jsx("main",{className:"apps-registry-content",children:d&&n.length===0?e.jsxs("div",{className:"empty-data-vignette",children:[e.jsx("div",{className:"processing-loader"}),e.jsx("p",{className:"text-muted text-xs font-bold tracking-widest",children:"SYNCING REGISTRY..."})]}):e.jsxs(e.Fragment,{children:[A.length>0&&e.jsxs("div",{className:"registry-table-header",children:[e.jsx("div",{children:"Artifact bundle"}),e.jsx("div",{children:"Version"}),e.jsx("div",{children:"Size"}),e.jsx("div",{children:"Team"}),e.jsx("div",{children:"Registry date"}),e.jsx("div",{style:{textAlign:"right"},children:"Management"})]}),e.jsx("div",{className:"registry-list",children:A.map(s=>{const a=h.filter(t=>t.platform===s.platform&&!t.busy&&!t.offline);return e.jsxs("div",{className:`artifact-row ${s.platform}`,children:[e.jsxs("div",{className:"col-app-info",children:[e.jsx("div",{className:"app-platform-badge",children:s.platform==="android"?e.jsx(V,{size:18}):e.jsx(H,{size:18})}),e.jsxs("div",{className:"app-text-block",children:[e.jsxs("div",{className:"app-display-name",title:s.name,children:[s.name,xe(s.name)&&e.jsx(Y,{variant:"outline",className:"ml-2 text-[10px] h-4 py-0 border-primary text-primary",children:"WDA"})]}),e.jsxs("div",{className:"app-package-id",children:[e.jsx("code",{children:s.packageName||"internal.bundle"}),s.packageName&&e.jsx("div",{className:"copy-hint",title:`Copy ${s.packageName}`,onClick:()=>de(s.packageName,"pkg"),children:re===`pkg-${s.packageName}`?e.jsx(Ce,{size:10,className:"text-primary"}):e.jsx(Ae,{size:10})})]})]})]}),e.jsx("div",{className:"col-version",children:s.version||"v1.0.0"}),e.jsx("div",{className:"col-size",children:he(s.size)}),e.jsx("div",{className:"col-team",title:K(s),children:K(s)}),e.jsx("div",{className:"col-timestamp",children:pe(s.createdAt)}),e.jsxs("div",{className:"col-actions",children:[e.jsxs("div",{className:"deploy-anchor",children:[e.jsx("button",{className:`instant-deploy-trigger ${C===s.id&&"active"}`,onClick:()=>{C===s.id?(z(null),T("")):z(s.id)},children:C===s.id?e.jsxs(e.Fragment,{children:[e.jsx(ge,{size:12})," CANCEL"]}):e.jsxs(e.Fragment,{children:[e.jsx(Se,{size:12})," Deploy"]})}),C===s.id&&e.jsx("div",{className:"deployment-flyout",children:a.length>0?e.jsxs("div",{className:"deploy-actions-group",children:[e.jsxs(Z,{selectSize:"sm",className:"min-w-[280px]",autoFocus:!0,value:M,onChange:t=>T(t.target.value),children:[e.jsx("option",{value:"",children:"SELECT TARGET..."}),a.map(t=>e.jsxs("option",{value:t.udid,children:[t.name," (",t.udid,")"]},t.udid))]}),e.jsx("button",{className:"confirm-deploy-btn",disabled:!M,onClick:()=>me(s.id,M),title:"Confirm deployment",children:e.jsx(W,{size:14})})]}):e.jsx("div",{className:"target-device-select empty",children:"NO TARGETS"})})]}),e.jsx("button",{className:"utility-icon-btn",onClick:()=>window.open(`/xenon/api/apps/${s.id}/download`,"_blank"),children:e.jsx(ze,{size:14})}),N&&e.jsx("button",{className:"utility-icon-btn","aria-label":`Move ${s.name} to team`,title:"Move to team",onClick:()=>$(s),children:e.jsx(se,{size:14})}),e.jsx("button",{className:"utility-icon-btn danger",onClick:()=>oe(s.id,s.name),children:e.jsx(Me,{size:14})})]})]},s.id)})}),A.length===0&&n.length>0&&!d&&e.jsxs("div",{className:"empty-registry-technical",children:[e.jsx("div",{className:"empty-icon-container",children:e.jsx(q,{size:48,className:"text-primary opacity-40"})}),e.jsx("h2",{className:"empty-title brand-font",children:"No matching artifacts"}),e.jsxs("p",{className:"empty-description",children:[n.length," ",n.length===1?"artifact is":"artifacts are"," registered, but none match the current filter."]}),e.jsx("div",{className:"empty-actions",children:e.jsx(x,{size:"sm",variant:"default",onClick:()=>{u(""),_({android:!0,ios:!0})},children:"Clear filters"})})]}),n.length===0&&!d&&e.jsxs("div",{className:"empty-registry-technical",children:[e.jsx("div",{className:"empty-icon-container",children:e.jsx(q,{size:48,className:"text-primary opacity-40 animate-pulse"})}),e.jsx("h2",{className:"empty-title brand-font",children:"No apps yet"}),e.jsxs("p",{className:"empty-description",children:["Upload ",e.jsx("code",{className:"text-primary",children:".apk"})," or"," ",e.jsx("code",{className:"text-primary",children:".ipa"})," artifacts to enable versioned installs across your device fleet."]}),e.jsx("div",{className:"empty-actions",children:e.jsx("button",{type:"button",className:"upload-trigger-massive",onClick:O,disabled:g,children:e.jsxs("span",{className:"massive-upload-content",children:[e.jsx(W,{size:24,className:"mb-2"}),e.jsx("span",{children:"Upload your first app"})]})})})]})]})}),e.jsx(_e,{open:ne,teams:L,teamId:E,onTeamChange:G,onChooseFile:()=>{var s;return(s=D.current)==null?void 0:s.click()},onClose:()=>I(!1)}),e.jsx(Le,{app:F,teams:L,onMove:le,onClose:()=>$(null)}),g&&e.jsx("div",{className:"upload-overlay-technical",children:e.jsxs("div",{className:"upload-card-technical",children:[e.jsx("div",{className:"processing-loader"}),e.jsx("h2",{className:"brand-font",style:{fontSize:"20px",marginBottom:"8px"},children:"Artifact ingestion"}),e.jsx("p",{className:"text-muted text-xs",children:"VERIFYING CHECKSUM & DEPLOYING TO REGISTRY..."})]})})]})};export{ss as default};
26
+ */const Ue=[["path",{d:"M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09z",key:"m3kijz"}],["path",{d:"m12 15-3-3a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.35 22.35 0 0 1-4 2z",key:"1fmvmk"}],["path",{d:"M9 12H4s.55-3.03 2-4c1.62-1.08 5 0 5 0",key:"1f8sc4"}],["path",{d:"M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5",key:"qeys4"}]],W=k("rocket",Ue),Re=be("badge-base",{variants:{variant:{default:"badge-variant-default",success:"badge-variant-success",warning:"badge-variant-warning",error:"badge-variant-error",outline:"badge-variant-outline",secondary:"badge-variant-secondary"}},defaultVariants:{variant:"default"}});function Y({className:r,variant:c,...n}){return e.jsx("div",{className:ke(Re({variant:c}),r),...n})}const ae=({id:r,value:c,teams:n,onChange:m,disabled:h})=>e.jsxs(Z,{id:r,value:c,disabled:h,className:"w-full",onChange:l=>m(l.target.value),children:[e.jsx("option",{value:"",children:"Shared"}),n.map(l=>e.jsx("option",{value:l.id,children:l.name},l.id))]}),te="Members of the team can see and run it. Shared apps are open to everyone.",_e=({open:r,teams:c,teamId:n,onTeamChange:m,onChooseFile:h,onClose:l})=>e.jsx(J,{open:r,onClose:l,title:"Upload app",footer:e.jsxs(e.Fragment,{children:[e.jsx(x,{variant:"secondary",onClick:l,children:"Cancel"}),e.jsxs(x,{variant:"primary",onClick:h,children:[e.jsx(ee,{size:14,className:"mr-1"}),"Choose file…"]})]}),children:e.jsx(Q,{label:"Team",htmlFor:"upload-app-team",description:te,children:e.jsx(ae,{id:"upload-app-team",value:n,teams:c,onChange:m})})}),Le=({app:r,teams:c,onMove:n,onClose:m})=>{const[h,l]=i.useState(""),[d,f]=i.useState(!1),[y,u]=i.useState(null);i.useEffect(()=>{l((r==null?void 0:r.teamId)??""),u(null)},[r]);const g=async()=>{f(!0),u(null);try{await n(h||null)}catch(v){u((v==null?void 0:v.message)||"Could not move the app")}finally{f(!1)}};return e.jsxs(J,{open:!!r,onClose:m,title:"Move to team",footer:e.jsxs(e.Fragment,{children:[e.jsx(x,{variant:"secondary",onClick:m,disabled:d,children:"Cancel"}),e.jsxs(x,{variant:"primary",onClick:g,disabled:d,children:[d?e.jsx(K,{size:14,className:"mr-1 animate-spin"}):e.jsx(se,{size:14,className:"mr-1"}),"Move"]})]}),children:[e.jsx("p",{className:"app-move-name",children:r==null?void 0:r.name}),e.jsx(Q,{label:"Team",htmlFor:"move-app-team",description:te,error:y??void 0,children:e.jsx(ae,{id:"move-app-team",value:h,teams:c,onChange:l,disabled:d})})]})},X=r=>{var c;return((c=r.team)==null?void 0:c.name)??(r.teamId?String(r.teamId).slice(0,8):"Shared")},ss=()=>{const{toast:r,removeToast:c}=ve(),[n,m]=i.useState([]),[h,l]=i.useState([]),[d,f]=i.useState(!1),[y,u]=i.useState(""),[g,v]=i.useState(!1),[re,R]=i.useState(null),[w,_]=i.useState({android:!0,ios:!0}),[S,ie]=i.useState("desc"),[C,z]=i.useState(null),[M,T]=i.useState(""),D=i.useRef(null),{me:j}=je(),N=(j==null?void 0:j.role)==="ADMIN"||(j==null?void 0:j.role)==="SUPER_ADMIN",[L,B]=i.useState([]),[ne,I]=i.useState(!1),[E,O]=i.useState(""),[F,$]=i.useState(null),b=i.useCallback(async()=>{f(!0);try{const s=await p.getApps();m(Array.isArray(s)?s:[])}catch(s){console.error("Failed to fetch apps",s)}finally{f(!1)}},[]),U=i.useCallback(async()=>{try{const s=await p.getDevices();l(Array.isArray(s)?s:[])}catch(s){console.error("Failed to fetch devices",s)}},[]);i.useEffect(()=>{b(),U();const s=setInterval(U,1e4);return()=>clearInterval(s)},[b,U]),i.useEffect(()=>{N&&p.listTeams().then(B).catch(()=>B([]))},[N]);const G=()=>{var s;N?(O(""),I(!0)):(s=D.current)==null||s.click()},le=async s=>{F&&(await p.setAppTeam(F.id,s),r(s?"App moved to team":"App shared with everyone","success"),$(null),await b())},ce=async s=>{var o;const a=(o=s.target.files)==null?void 0:o[0];if(!a)return;const t=N&&E?E:null;I(!1),v(!0);try{await p.uploadApp(a,t),await b()}catch(ue){console.error("Upload failed",ue)}finally{v(!1),s.target&&(s.target.value="")}},oe=async(s,a)=>{if(window.confirm(`Permanently remove artifact "${a}"?`))try{await p.deleteApp(s),m(t=>t.filter(o=>o.id!==s))}catch(t){console.error("Delete failed",t)}},de=(s,a)=>{navigator.clipboard.writeText(s),R(`${a}-${s}`),setTimeout(()=>R(null),2e3)},me=async(s,a)=>{const t=r(`Deploying app to ${a}...`,"loading",0);try{const o=await p.installRepositoryApp(a,s);o.success?(r("App deployed successfully","success"),z(null),T("")):r(`Deployment failed: ${o.error}`,"error")}catch(o){r(`Execution Error: ${o.message}`,"error")}finally{c(t)}},A=n.filter(s=>{const a=s.name.toLowerCase().includes(y.toLowerCase())||s.packageName&&s.packageName.toLowerCase().includes(y.toLowerCase()),t=w.android&&s.platform==="android"||w.ios&&s.platform==="ios";return a&&t}).sort((s,a)=>{const t=new Date(s.createdAt).getTime(),o=new Date(a.createdAt).getTime();return S==="desc"?o-t:t-o}),he=s=>{if(!s)return"0 B";const a=1024,t=Math.floor(Math.log(s)/Math.log(a));return parseFloat((s/Math.pow(a,t)).toFixed(1))+" "+["B","KB","MB","GB"][t]},pe=s=>Ne(s),P=s=>{_(a=>({...a,[s]:!a[s]}))},xe=s=>{const a=s.toLowerCase();return a.includes("wda-signed")||a.includes("wda-resign")||a.includes("webdriveragent")};return e.jsxs("div",{className:"apps-container device-explorer-container",children:[e.jsx("div",{className:"scanline",style:{position:"absolute",inset:0,pointerEvents:"none",opacity:.05,zIndex:1001}}),e.jsx(we,{icon:fe,title:"Apps",subtitle:"Signed builds available for installation across your device fleet."}),e.jsxs("div",{className:"device-explorer-header-container",children:[e.jsxs("div",{className:"device-explorer-header-left-container",children:[e.jsx("div",{className:"device-explorer-header-entry",children:e.jsxs("div",{className:"device-explorer-header-value",children:[e.jsxs("button",{className:`device-explorer-header__platform-btn ${w.android&&"selected"}`,onClick:()=>P("android"),children:[e.jsx(V,{size:18,color:"currentColor"})," Android"]}),e.jsxs("button",{className:`device-explorer-header__platform-btn ${w.ios&&"selected"}`,onClick:()=>P("ios"),children:[e.jsx(H,{size:18,color:"currentColor"})," iOS"]})]})}),e.jsx("div",{className:"device-explorer-header-entry",children:e.jsx("div",{className:"device-explorer-header-value",children:e.jsxs("div",{className:"device-explorer-search-wrapper",children:[e.jsx(ye,{size:16,color:"#94a3b8",className:"device-explorer-search-icon"}),e.jsx("input",{type:"text",className:"device-explorer-header-text-filter",placeholder:"Filter by bundle or name...",value:y,onChange:s=>u(s.target.value)})]})})}),e.jsx("div",{className:"device-explorer-header-filter-count",children:e.jsxs(Y,{variant:"secondary",children:[e.jsx("span",{className:"font-bold",children:A.length})," of"," ",e.jsx("span",{className:"font-bold",children:n.length})," ",n.length===1?"artifact":"artifacts"]})})]}),e.jsxs("div",{className:"device-explorer-header-right-container",children:[e.jsx("button",{className:"icon-btn-secondary sort-btn",onClick:()=>ie(s=>s==="desc"?"asc":"desc"),title:S==="desc"?"Newest First":"Oldest First",children:S==="desc"?e.jsx(Ie,{size:18}):e.jsx($e,{size:18})}),e.jsxs(x,{size:"sm",variant:"secondary",onClick:()=>b(),disabled:d,children:[e.jsx(K,{size:14,className:`mr-1 ${d&&"animate-spin"}`}),"Refresh"]}),e.jsx("input",{ref:D,type:"file",accept:".apk,.ipa",onChange:ce,hidden:!0}),e.jsxs(x,{size:"sm",variant:"primary",onClick:G,disabled:g,children:[e.jsx(ee,{size:14,className:"mr-1"}),"Upload app"]})]})]}),e.jsx("main",{className:"apps-registry-content",children:d&&n.length===0?e.jsxs("div",{className:"empty-data-vignette",children:[e.jsx("div",{className:"processing-loader"}),e.jsx("p",{className:"text-muted text-xs font-bold tracking-widest",children:"SYNCING REGISTRY..."})]}):e.jsxs(e.Fragment,{children:[A.length>0&&e.jsxs("div",{className:"registry-table-header",children:[e.jsx("div",{children:"Artifact bundle"}),e.jsx("div",{children:"Version"}),e.jsx("div",{children:"Size"}),e.jsx("div",{children:"Team"}),e.jsx("div",{children:"Registry date"}),e.jsx("div",{style:{textAlign:"right"},children:"Management"})]}),e.jsx("div",{className:"registry-list",children:A.map(s=>{const a=h.filter(t=>t.platform===s.platform&&!t.busy&&!t.offline);return e.jsxs("div",{className:`artifact-row ${s.platform}`,children:[e.jsxs("div",{className:"col-app-info",children:[e.jsx("div",{className:"app-platform-badge",children:s.platform==="android"?e.jsx(V,{size:18}):e.jsx(H,{size:18})}),e.jsxs("div",{className:"app-text-block",children:[e.jsxs("div",{className:"app-display-name",title:s.name,children:[s.name,xe(s.name)&&e.jsx(Y,{variant:"outline",className:"ml-2 text-[10px] h-4 py-0 border-primary text-primary",children:"WDA"})]}),e.jsxs("div",{className:"app-package-id",children:[e.jsx("code",{children:s.packageName||"internal.bundle"}),s.packageName&&e.jsx("div",{className:"copy-hint",title:`Copy ${s.packageName}`,onClick:()=>de(s.packageName,"pkg"),children:re===`pkg-${s.packageName}`?e.jsx(Ce,{size:10,className:"text-primary"}):e.jsx(Ae,{size:10})})]})]})]}),e.jsx("div",{className:"col-version",children:s.version||"v1.0.0"}),e.jsx("div",{className:"col-size",children:he(s.size)}),e.jsx("div",{className:"col-team",title:X(s),children:X(s)}),e.jsx("div",{className:"col-timestamp",children:pe(s.createdAt)}),e.jsxs("div",{className:"col-actions",children:[e.jsxs("div",{className:"deploy-anchor",children:[e.jsx("button",{className:`instant-deploy-trigger ${C===s.id&&"active"}`,onClick:()=>{C===s.id?(z(null),T("")):z(s.id)},children:C===s.id?e.jsxs(e.Fragment,{children:[e.jsx(ge,{size:12})," CANCEL"]}):e.jsxs(e.Fragment,{children:[e.jsx(Se,{size:12})," Deploy"]})}),C===s.id&&e.jsx("div",{className:"deployment-flyout",children:a.length>0?e.jsxs("div",{className:"deploy-actions-group",children:[e.jsxs(Z,{selectSize:"sm",className:"min-w-[280px]",autoFocus:!0,value:M,onChange:t=>T(t.target.value),children:[e.jsx("option",{value:"",children:"SELECT TARGET..."}),a.map(t=>e.jsxs("option",{value:t.udid,children:[t.name," (",t.udid,")"]},t.udid))]}),e.jsx("button",{className:"confirm-deploy-btn",disabled:!M,onClick:()=>me(s.id,M),title:"Confirm deployment",children:e.jsx(W,{size:14})})]}):e.jsx("div",{className:"target-device-select empty",children:"NO TARGETS"})})]}),e.jsx("button",{className:"utility-icon-btn",onClick:()=>window.open(`/xenon/api/apps/${s.id}/download`,"_blank"),children:e.jsx(ze,{size:14})}),N&&e.jsx("button",{className:"utility-icon-btn","aria-label":`Move ${s.name} to team`,title:"Move to team",onClick:()=>$(s),children:e.jsx(se,{size:14})}),e.jsx("button",{className:"utility-icon-btn danger",onClick:()=>oe(s.id,s.name),children:e.jsx(Me,{size:14})})]})]},s.id)})}),A.length===0&&n.length>0&&!d&&e.jsxs("div",{className:"empty-registry-technical",children:[e.jsx("div",{className:"empty-icon-container",children:e.jsx(q,{size:48,className:"text-primary opacity-40"})}),e.jsx("h2",{className:"empty-title brand-font",children:"No matching artifacts"}),e.jsxs("p",{className:"empty-description",children:[n.length," ",n.length===1?"artifact is":"artifacts are"," registered, but none match the current filter."]}),e.jsx("div",{className:"empty-actions",children:e.jsx(x,{size:"sm",variant:"default",onClick:()=>{u(""),_({android:!0,ios:!0})},children:"Clear filters"})})]}),n.length===0&&!d&&e.jsxs("div",{className:"empty-registry-technical",children:[e.jsx("div",{className:"empty-icon-container",children:e.jsx(q,{size:48,className:"text-primary opacity-40 animate-pulse"})}),e.jsx("h2",{className:"empty-title brand-font",children:"No apps yet"}),e.jsxs("p",{className:"empty-description",children:["Upload ",e.jsx("code",{className:"text-primary",children:".apk"})," or"," ",e.jsx("code",{className:"text-primary",children:".ipa"})," artifacts to enable versioned installs across your device fleet."]}),e.jsx("div",{className:"empty-actions",children:e.jsx("button",{type:"button",className:"upload-trigger-massive",onClick:G,disabled:g,children:e.jsxs("span",{className:"massive-upload-content",children:[e.jsx(W,{size:24,className:"mb-2"}),e.jsx("span",{children:"Upload your first app"})]})})})]})]})}),e.jsx(_e,{open:ne,teams:L,teamId:E,onTeamChange:O,onChooseFile:()=>{var s;return(s=D.current)==null?void 0:s.click()},onClose:()=>I(!1)}),e.jsx(Le,{app:F,teams:L,onMove:le,onClose:()=>$(null)}),g&&e.jsx("div",{className:"upload-overlay-technical",children:e.jsxs("div",{className:"upload-card-technical",children:[e.jsx("div",{className:"processing-loader"}),e.jsx("h2",{className:"brand-font",style:{fontSize:"20px",marginBottom:"8px"},children:"Artifact ingestion"}),e.jsx("p",{className:"text-muted text-xs",children:"VERIFYING CHECKSUM & DEPLOYING TO REGISTRY..."})]})})]})};export{ss as default};
@@ -1,4 +1,4 @@
1
- import{c as o}from"./index-DI1fGIyj.js";/**
1
+ import{c as o}from"./index-BOxe43p1.js";/**
2
2
  * @license lucide-react v0.555.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{c as o}from"./index-DI1fGIyj.js";/**
1
+ import{c as o}from"./index-BOxe43p1.js";/**
2
2
  * @license lucide-react v0.555.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{c as o}from"./index-DI1fGIyj.js";/**
1
+ import{c as o}from"./index-BOxe43p1.js";/**
2
2
  * @license lucide-react v0.555.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,6 +1,6 @@
1
- import{c as i,j as e,n,S as o}from"./index-DI1fGIyj.js";import{N as l}from"./network-Cj8JOKON.js";/**
1
+ import{c as i,j as e,n,S as o}from"./index-BOxe43p1.js";import{N as l}from"./network-Dii9qdvk.js";/**
2
2
  * @license lucide-react v0.555.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
5
5
  * See the LICENSE file in the root directory of this source tree.
6
- */const d=[["path",{d:"M18 8V6a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h8",key:"10dyio"}],["path",{d:"M10 19v-3.96 3.15",key:"1irgej"}],["path",{d:"M7 19h5",key:"qswx4l"}],["rect",{width:"6",height:"10",x:"16",y:"12",rx:"2",key:"1egngj"}]],c=i("monitor-smartphone",d),x=[{icon:o,title:"Self-healing selectors",body:"Broken locators recover through six escalating tiers before a test fails."},{icon:c,title:"Live Android & iOS devices",body:"Watch, drive and record real devices from the browser."},{icon:l,title:"Hub–node scaling",body:"One hub orchestrates device labs across machines."}];function b({children:t}){return e.jsxs("div",{className:"grid min-h-screen w-full grid-cols-1 bg-[var(--bg)] text-[var(--text)] md:grid-cols-[minmax(0,5fr)_minmax(0,7fr)]",children:[e.jsxs("aside",{className:"relative hidden overflow-hidden border-r border-[rgb(var(--rgb-fg)/0.06)] bg-[var(--surface-sunken)] md:flex md:flex-col",children:[e.jsx("div",{"aria-hidden":"true",className:"pointer-events-none absolute inset-0 bg-[radial-gradient(ellipse_90%_60%_at_0%_0%,rgb(var(--rgb-accent)/0.14),transparent_60%)]"}),e.jsx("div",{"aria-hidden":"true",className:"pointer-events-none absolute inset-0 bg-[linear-gradient(to_right,rgb(var(--rgb-white)/0.03)_1px,transparent_1px),linear-gradient(to_bottom,rgb(var(--rgb-white)/0.03)_1px,transparent_1px)] bg-[size:48px_48px] [mask-image:linear-gradient(to_bottom,black,transparent_85%)]"}),e.jsxs("div",{className:"relative flex flex-1 flex-col justify-between px-12 py-10",children:[e.jsx(n,{className:"h-8 w-auto self-start object-contain"}),e.jsxs("div",{className:"max-w-md",children:[e.jsxs("h2",{className:"text-4xl font-semibold leading-tight tracking-tight",children:["Your device lab,",e.jsx("br",{}),e.jsx("span",{className:"text-[var(--color-accent)]",children:"under control."})]}),e.jsx("p",{className:"mt-4 text-sm leading-relaxed text-[var(--text-muted)]",children:"Appium orchestration for the devices you own — with self-healing tests, live streaming and recordable proof of what ran."}),e.jsx("ul",{className:"mt-10 space-y-6",children:x.map(({icon:a,title:r,body:s})=>e.jsxs("li",{className:"flex gap-4",children:[e.jsx("span",{className:"grid h-9 w-9 shrink-0 place-items-center rounded-lg border border-[var(--accent-border)] bg-[var(--accent-subtle)]",children:e.jsx(a,{className:"h-4 w-4 text-[var(--color-accent)]","aria-hidden":"true"})}),e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-medium text-[var(--text)]",children:r}),e.jsx("div",{className:"mt-0.5 text-sm text-[var(--text-muted)]",children:s})]})]},r))})]}),e.jsxs("footer",{className:"flex items-center justify-between border-t border-[rgb(var(--rgb-fg)/0.06)] pt-5 text-xs text-[var(--text-muted)]",children:[e.jsxs("span",{children:["Xenon v","2.13.2"," · Self-hosted device lab"]}),e.jsx("a",{href:"/xenon/api-docs",target:"_blank",rel:"noreferrer",className:"text-[var(--text-muted)] underline-offset-4 hover:text-[var(--text)] hover:underline",children:"API docs"})]})]})]}),e.jsx("main",{className:"flex items-center justify-center px-6 py-10",children:e.jsx("div",{className:"w-full max-w-[400px] rounded-xl border border-[var(--border)] bg-[var(--surface)] px-8 py-9 shadow-[var(--shadow-lg)]",children:t})})]})}export{b as A};
6
+ */const d=[["path",{d:"M18 8V6a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h8",key:"10dyio"}],["path",{d:"M10 19v-3.96 3.15",key:"1irgej"}],["path",{d:"M7 19h5",key:"qswx4l"}],["rect",{width:"6",height:"10",x:"16",y:"12",rx:"2",key:"1egngj"}]],c=i("monitor-smartphone",d),x=[{icon:o,title:"Self-healing selectors",body:"Broken locators recover through six escalating tiers before a test fails."},{icon:c,title:"Live Android & iOS devices",body:"Watch, drive and record real devices from the browser."},{icon:l,title:"Hub–node scaling",body:"One hub orchestrates device labs across machines."}];function b({children:t}){return e.jsxs("div",{className:"grid min-h-screen w-full grid-cols-1 bg-[var(--bg)] text-[var(--text)] md:grid-cols-[minmax(0,5fr)_minmax(0,7fr)]",children:[e.jsxs("aside",{className:"relative hidden overflow-hidden border-r border-[rgb(var(--rgb-fg)/0.06)] bg-[var(--surface-sunken)] md:flex md:flex-col",children:[e.jsx("div",{"aria-hidden":"true",className:"pointer-events-none absolute inset-0 bg-[radial-gradient(ellipse_90%_60%_at_0%_0%,rgb(var(--rgb-accent)/0.14),transparent_60%)]"}),e.jsx("div",{"aria-hidden":"true",className:"pointer-events-none absolute inset-0 bg-[linear-gradient(to_right,rgb(var(--rgb-white)/0.03)_1px,transparent_1px),linear-gradient(to_bottom,rgb(var(--rgb-white)/0.03)_1px,transparent_1px)] bg-[size:48px_48px] [mask-image:linear-gradient(to_bottom,black,transparent_85%)]"}),e.jsxs("div",{className:"relative flex flex-1 flex-col justify-between px-12 py-10",children:[e.jsx(n,{className:"h-8 w-auto self-start object-contain"}),e.jsxs("div",{className:"max-w-md",children:[e.jsxs("h2",{className:"text-4xl font-semibold leading-tight tracking-tight",children:["Your device lab,",e.jsx("br",{}),e.jsx("span",{className:"text-[var(--color-accent)]",children:"under control."})]}),e.jsx("p",{className:"mt-4 text-sm leading-relaxed text-[var(--text-muted)]",children:"Appium orchestration for the devices you own — with self-healing tests, live streaming and recordable proof of what ran."}),e.jsx("ul",{className:"mt-10 space-y-6",children:x.map(({icon:a,title:r,body:s})=>e.jsxs("li",{className:"flex gap-4",children:[e.jsx("span",{className:"grid h-9 w-9 shrink-0 place-items-center rounded-lg border border-[var(--accent-border)] bg-[var(--accent-subtle)]",children:e.jsx(a,{className:"h-4 w-4 text-[var(--color-accent)]","aria-hidden":"true"})}),e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-medium text-[var(--text)]",children:r}),e.jsx("div",{className:"mt-0.5 text-sm text-[var(--text-muted)]",children:s})]})]},r))})]}),e.jsxs("footer",{className:"flex items-center justify-between border-t border-[rgb(var(--rgb-fg)/0.06)] pt-5 text-xs text-[var(--text-muted)]",children:[e.jsxs("span",{children:["Xenon v","2.15.0"," · Self-hosted device lab"]}),e.jsx("a",{href:"/xenon/api-docs",target:"_blank",rel:"noreferrer",className:"text-[var(--text-muted)] underline-offset-4 hover:text-[var(--text)] hover:underline",children:"API docs"})]})]})]}),e.jsx("main",{className:"flex items-center justify-center px-6 py-10",children:e.jsx("div",{className:"w-full max-w-[400px] rounded-xl border border-[var(--border)] bg-[var(--surface)] px-8 py-9 shadow-[var(--shadow-lg)]",children:t})})]})}export{b as A};
@@ -1,4 +1,4 @@
1
- import{c as ee,r as h,p as te,X,j as e,z as V,R as _,f as se,T as ae,q as re,u as ne,i as le,t as oe,M as ie}from"./index-DI1fGIyj.js";import{s as ce,b as L,P as de,T as B,i as xe,f as q,a as ue,c as me,d as pe,p as he,e as fe,r as ve,C as be,g as ge,h as je,j as A,k as Ne,l as W,S as we,m as ye,n as Se,u as Ce,o as $e}from"./use-builds-data-1cOCMf-z.js";import{I as J}from"./input-BjDRKCea.js";import{L as ke,a as Me}from"./list-checks-BdW5CjM8.js";import{B as O}from"./button-fIW8owMI.js";import{D as Ee}from"./download-WG6l7BgD.js";import{s as Te}from"./labels-C21SA4JG.js";import{C as Re}from"./circle-x-5Uwquo0h.js";import{C as Be}from"./circle-check-zJU80_EF.js";import{C as Le}from"./chevron-right-B4BKlsqk.js";import{T as Ie}from"./tablet-6b_SEN2X.js";import{M as _e}from"./monitor-8xjkeHHi.js";import{S}from"./stat-tile-DV9Ix-4O.js";import{P as De}from"./page-header--aTyJXq6.js";import{S as Ae}from"./select-DvCSv25z.js";import{E as F}from"./EmptyState-Cr17PdDv.js";import"./time-D-gjmE1o.js";import"./utils-CDN07tui.js";/**
1
+ import{c as ee,r as h,p as te,X,j as e,z as V,R as _,f as se,T as ae,q as re,u as ne,i as le,t as oe,M as ie}from"./index-BOxe43p1.js";import{s as ce,b as L,P as de,T as B,i as xe,f as q,a as ue,c as me,d as pe,p as he,e as fe,r as ve,C as be,g as ge,h as je,j as A,k as Ne,l as W,S as we,m as ye,n as Se,u as Ce,o as $e}from"./use-builds-data-NeQOFEoy.js";import{I as J}from"./input-CZHFjbSg.js";import{L as ke,a as Me}from"./list-checks-CCgjeyGY.js";import{B as O}from"./button-Cg08-EMT.js";import{D as Ee}from"./download-B56lwxWP.js";import{s as Te}from"./labels-C21SA4JG.js";import{C as Re}from"./circle-x-DTwnSAnl.js";import{C as Be}from"./circle-check-CYXBoUqT.js";import{C as Le}from"./chevron-right-B2QOv9Nx.js";import{T as Ie}from"./tablet-BxUScAeO.js";import{M as _e}from"./monitor-DEJixKQO.js";import{S}from"./stat-tile-xVqAKIlI.js";import{P as De}from"./page-header-COQZxJfR.js";import{S as Ae}from"./select-Bpyn7rWO.js";import{E as F}from"./EmptyState-DqWU2-vM.js";import"./time-D-gjmE1o.js";import"./utils-CDN07tui.js";/**
2
2
  * @license lucide-react v0.555.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1 +1 @@
1
- import{r as x,j as z}from"./index-DI1fGIyj.js";import{a as j,c as g}from"./utils-CDN07tui.js";const v=a=>typeof a=="boolean"?`${a}`:a===0?"0":a,b=j,k=(a,e)=>t=>{var l;if((e==null?void 0:e.variants)==null)return b(a,t==null?void 0:t.class,t==null?void 0:t.className);const{variants:d,defaultVariants:r}=e,y=Object.keys(d).map(n=>{const s=t==null?void 0:t[n],o=r==null?void 0:r[n];if(s===null)return null;const i=v(s)||v(o);return d[n][i]}),c=t&&Object.entries(t).reduce((n,s)=>{let[o,i]=s;return i===void 0||(n[o]=i),n},{}),f=e==null||(l=e.compoundVariants)===null||l===void 0?void 0:l.reduce((n,s)=>{let{class:o,className:i,...V}=s;return Object.entries(V).every(N=>{let[m,u]=N;return Array.isArray(u)?u.includes({...r,...c}[m]):{...r,...c}[m]===u})?[...n,o,i]:n},[]);return b(a,y,f,t==null?void 0:t.class,t==null?void 0:t.className)},C=k("btn-base",{variants:{variant:{default:"btn-primary",primary:"btn-primary",secondary:"btn-secondary",outline:"btn-secondary",ghost:"btn-ghost",tonal:"btn-tonal",link:"btn-link",destructive:"btn-danger",danger:"btn-danger"},size:{default:"btn-size-md",md:"btn-size-md",sm:"btn-size-sm",lg:"btn-size-lg",icon:"btn-size-icon"}},defaultVariants:{variant:"primary",size:"md"}}),O=x.forwardRef(({className:a,variant:e,size:t,...l},d)=>z.jsx("button",{className:g(C({variant:e,size:t,className:a})),ref:d,...l}));O.displayName="Button";export{O as B,k as c};
1
+ import{r as x,j as z}from"./index-BOxe43p1.js";import{a as j,c as g}from"./utils-CDN07tui.js";const v=a=>typeof a=="boolean"?`${a}`:a===0?"0":a,b=j,k=(a,e)=>t=>{var l;if((e==null?void 0:e.variants)==null)return b(a,t==null?void 0:t.class,t==null?void 0:t.className);const{variants:d,defaultVariants:r}=e,y=Object.keys(d).map(n=>{const s=t==null?void 0:t[n],o=r==null?void 0:r[n];if(s===null)return null;const i=v(s)||v(o);return d[n][i]}),c=t&&Object.entries(t).reduce((n,s)=>{let[o,i]=s;return i===void 0||(n[o]=i),n},{}),f=e==null||(l=e.compoundVariants)===null||l===void 0?void 0:l.reduce((n,s)=>{let{class:o,className:i,...V}=s;return Object.entries(V).every(N=>{let[m,u]=N;return Array.isArray(u)?u.includes({...r,...c}[m]):{...r,...c}[m]===u})?[...n,o,i]:n},[]);return b(a,y,f,t==null?void 0:t.class,t==null?void 0:t.className)},C=k("btn-base",{variants:{variant:{default:"btn-primary",primary:"btn-primary",secondary:"btn-secondary",outline:"btn-secondary",ghost:"btn-ghost",tonal:"btn-tonal",link:"btn-link",destructive:"btn-danger",danger:"btn-danger"},size:{default:"btn-size-md",md:"btn-size-md",sm:"btn-size-sm",lg:"btn-size-lg",icon:"btn-size-icon"}},defaultVariants:{variant:"primary",size:"md"}}),O=x.forwardRef(({className:a,variant:e,size:t,...l},d)=>z.jsx("button",{className:g(C({variant:e,size:t,className:a})),ref:d,...l}));O.displayName="Button";export{O as B,k as c};
@@ -1,4 +1,4 @@
1
- import{c as e}from"./index-DI1fGIyj.js";/**
1
+ import{c as e}from"./index-BOxe43p1.js";/**
2
2
  * @license lucide-react v0.555.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{c}from"./index-DI1fGIyj.js";/**
1
+ import{c}from"./index-BOxe43p1.js";/**
2
2
  * @license lucide-react v0.555.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{c as o}from"./index-DI1fGIyj.js";/**
1
+ import{c as o}from"./index-BOxe43p1.js";/**
2
2
  * @license lucide-react v0.555.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{c}from"./index-DI1fGIyj.js";/**
1
+ import{c}from"./index-BOxe43p1.js";/**
2
2
  * @license lucide-react v0.555.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{c}from"./index-DI1fGIyj.js";/**
1
+ import{c}from"./index-BOxe43p1.js";/**
2
2
  * @license lucide-react v0.555.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{c}from"./index-DI1fGIyj.js";/**
1
+ import{c}from"./index-BOxe43p1.js";/**
2
2
  * @license lucide-react v0.555.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{c}from"./index-DI1fGIyj.js";/**
1
+ import{c}from"./index-BOxe43p1.js";/**
2
2
  * @license lucide-react v0.555.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -0,0 +1 @@
1
+ function o(r,t=8){if(!r)return[];const n=r.split(/\r?\n/),e=[];for(const s of n){const i=s.trim();if(/^at\s+/.test(i)&&(e.push(i),e.length>=t))break}return e}function a(r){return r?r.split(/[_\s]+/).filter(Boolean).map(t=>t.charAt(0).toUpperCase()+t.slice(1).toLowerCase()).join(" "):""}function f(r){if(!r)return{};try{const t=JSON.parse(r);return t&&typeof t=="object"&&!Array.isArray(t)?t:{}}catch{return{}}}function c(r,t=200){if(r==null)return"";if(typeof r=="string")return r;if(typeof r=="number"||typeof r=="boolean")return String(r);try{const n=JSON.stringify(r);return n.length>t?n.slice(0,t)+"…":n}catch{return String(r)}}export{f as a,c as b,a as h,o as p};