@xenon-device-management/xenon 2.14.0 → 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.
- package/README.md +7 -4
- package/lib/package.json +5 -5
- package/lib/public/assets/{AnnotationOverlay-B_VNtKBH.js → AnnotationOverlay-Btq3dZRI.js} +1 -1
- package/lib/public/assets/{ApiKeyGate-BwuaMjkX.js → ApiKeyGate-C9OoAgg_.js} +1 -1
- package/lib/public/assets/DeviceMosaicView-DBC_xczB.js +2 -0
- package/lib/public/assets/{EmptyState-BSjhk_IV.js → EmptyState-DqWU2-vM.js} +1 -1
- package/lib/public/assets/{FieldGroup-Cb5QZsE1.js → FieldGroup-CveQ3xrA.js} +1 -1
- package/lib/public/assets/{FilterMenu-BAaSlWbW.js → FilterMenu-BfKDSfHz.js} +1 -1
- package/lib/public/assets/{Menu-JGGYrSQQ.js → Menu-CtdCybzA.js} +1 -1
- package/lib/public/assets/{Modal-CFCp3n9d.js → Modal-Bsvj1tm2.js} +1 -1
- package/lib/public/assets/{RecordingPage-CbJj_EBT.js → RecordingPage-CRofOiyx.js} +1 -1
- package/lib/public/assets/{RecordingsPage-BJeYnygR.js → RecordingsPage-jNQHb2IR.js} +1 -1
- package/lib/public/assets/{SegmentedControl-Bg42Atjy.js → SegmentedControl-C8HtTha-.js} +1 -1
- package/lib/public/assets/{SettingCard-Njz1pUIJ.js → SettingCard-D8K1LZNo.js} +1 -1
- package/lib/public/assets/{Table-BcTm5xV2.js → Table-zNTX92Pn.js} +1 -1
- package/lib/public/assets/{activity-DOVdsfMQ.js → activity-CJ8LwZq9.js} +1 -1
- package/lib/public/assets/ai-settings-CgxQZqrc.js +16 -0
- package/lib/public/assets/{api-keys-BKnNSTw9.js → api-keys-ECpo-zTo.js} +1 -1
- package/lib/public/assets/{apps-D0SC6uw6.js → apps-BjGymyf3.js} +1 -1
- package/lib/public/assets/{arrow-left-MMbTmgoE.js → arrow-left-BWfCbeHP.js} +1 -1
- package/lib/public/assets/{arrow-right-BMfnGmxW.js → arrow-right-DC7UGf_n.js} +1 -1
- package/lib/public/assets/{arrow-up-right-DuAftMWB.js → arrow-up-right-BOjwybDk.js} +1 -1
- package/lib/public/assets/{auth-shell-nZC2JNDO.js → auth-shell-CxMTo9aH.js} +2 -2
- package/lib/public/assets/{builds-page-hDCgTwkS.js → builds-page-DOCm4HkA.js} +1 -1
- package/lib/public/assets/{button-Dda4irn_.js → button-Cg08-EMT.js} +1 -1
- package/lib/public/assets/{calendar-BMr0Q62v.js → calendar-CA1ikLJs.js} +1 -1
- package/lib/public/assets/{check-CZ9iw9-e.js → check-BMTaH72W.js} +1 -1
- package/lib/public/assets/{chevron-right-BRYJJVC9.js → chevron-right-B2QOv9Nx.js} +1 -1
- package/lib/public/assets/{circle-check-CqAJjQ5O.js → circle-check-CYXBoUqT.js} +1 -1
- package/lib/public/assets/{circle-x-DlDJtnVz.js → circle-x-DTwnSAnl.js} +1 -1
- package/lib/public/assets/{clock-CpuDKysU.js → clock-C8_HViQP.js} +1 -1
- package/lib/public/assets/{copy-CAQydNFe.js → copy-Be7LNMXV.js} +1 -1
- package/lib/public/assets/derive-UnLRp4r3.js +1 -0
- package/lib/public/assets/device-explorer-BOqtfGXz.js +282 -0
- package/lib/public/assets/{download-C9XG6lLv.js → download-B56lwxWP.js} +1 -1
- package/lib/public/assets/forgot-password-CCU6bzLn.js +1 -0
- package/lib/public/assets/{h264Stream-VQBphYhg.js → h264Stream-C-OtmIuk.js} +6 -6
- package/lib/public/assets/index-B9KQ6LsY.js +15 -0
- package/lib/public/assets/{index-BbKEXUFH.js → index-BOxe43p1.js} +2 -2
- package/lib/public/assets/{index-DJGc1M2f.js → index-CfxsUslp.js} +1 -1
- package/lib/public/assets/{input-Cm0tmSoc.js → input-CZHFjbSg.js} +1 -1
- package/lib/public/assets/{line-chart-D2DyJCml.js → line-chart-Gl_Dz3X_.js} +1 -1
- package/lib/public/assets/{list-checks-UWf1GY99.js → list-checks-CCgjeyGY.js} +1 -1
- package/lib/public/assets/{lock-CCJv9m_I.js → lock-CkOwgDcx.js} +1 -1
- package/lib/public/assets/{login-f8vOVW-U.js → login-D5cc4w7M.js} +1 -1
- package/lib/public/assets/{maintenance-settings-C1PrkuAH.js → maintenance-settings-t7qr3fvX.js} +1 -1
- package/lib/public/assets/{monitor-B2jDgwm7.js → monitor-DEJixKQO.js} +1 -1
- package/lib/public/assets/{mouse-pointer-2-DLI1RtzU.js → mouse-pointer-2-CtOrk4M8.js} +1 -1
- package/lib/public/assets/{network-ebT86qoi.js → network-Dii9qdvk.js} +1 -1
- package/lib/public/assets/{overview-C0aykVrd.js → overview-rolAACrO.js} +1 -1
- package/lib/public/assets/{page-header-BjzgWz-T.js → page-header-COQZxJfR.js} +1 -1
- package/lib/public/assets/{play-DLG9t8FU.js → play-DrN1Se_R.js} +1 -1
- package/lib/public/assets/{plus-nBFSMu_X.js → plus-5aq-9uRx.js} +1 -1
- package/lib/public/assets/{profile-page-CSl0UYlv.js → profile-page-6i5kY6kF.js} +1 -1
- package/lib/public/assets/{reset-password-LeOuHqmB.js → reset-password-sp2IBrc7.js} +1 -1
- package/lib/public/assets/runbook-page-DJDjeopU.js +253 -0
- package/lib/public/assets/{select-88jHcl-Z.js → select-Bpyn7rWO.js} +1 -1
- package/lib/public/assets/{selector-detail-redirect-BbXKJjZM.js → selector-detail-redirect-BH74vmKv.js} +1 -1
- package/lib/public/assets/{selector-health-page-B4rA1Xkv.js → selector-health-page-Cw_g218H.js} +1 -1
- package/lib/public/assets/session-detail-page-AZJE6XXE.js +4 -0
- package/lib/public/assets/{settings-GF6ZMSQ6.js → settings-C3uyGhyc.js} +1 -1
- package/lib/public/assets/{settings-Dep_3kbA.css → settings-K8UHWMdI.css} +1 -1
- package/lib/public/assets/{stat-tile-BV98e_Sv.js → stat-tile-xVqAKIlI.js} +1 -1
- package/lib/public/assets/{tablet-BiAsnFDj.js → tablet-BxUScAeO.js} +1 -1
- package/lib/public/assets/{teams-B4-jrr-1.js → teams-B5ljGkY2.js} +1 -1
- package/lib/public/assets/{trash-2-C5RSuX0e.js → trash-2-B701i8sy.js} +1 -1
- package/lib/public/assets/{upload-BG7_rMXK.js → upload-C2gr44RS.js} +1 -1
- package/lib/public/assets/{use-builds-data-J-riQYyC.js → use-builds-data-NeQOFEoy.js} +1 -1
- package/lib/public/assets/{use-password-reset-mode-C8-eH-UG.js → use-password-reset-mode-DEzJq5ef.js} +1 -1
- package/lib/public/assets/{users-CFba5TSy.js → users-D_vv_yz4.js} +1 -1
- package/lib/public/assets/{users-Cp0beJm3.js → users-MY6eNe6s.js} +1 -1
- package/lib/public/assets/{video-off-DDsEISjV.js → video-off-OK1lNZQn.js} +1 -1
- package/lib/public/assets/{webhook-settings-BGu32vSB.js → webhook-settings-BU-C9lBf.js} +1 -1
- package/lib/public/assets/{zap-l4VaXzq8.js → zap-DO9ry1iz.js} +1 -1
- package/lib/public/index.html +1 -1
- package/lib/schema.json +5 -5
- package/lib/src/app/dashboardPluginLink.js +117 -0
- package/lib/src/app/index.js +13 -34
- package/lib/src/app/openapi/control.yaml +6 -4
- package/lib/src/app/openapi/grid.yaml +8 -2
- package/lib/src/app/openapi/identity.yaml +103 -31
- package/lib/src/app/openapi/platform.yaml +33 -15
- package/lib/src/app/openapi/sessions.yaml +10 -3
- package/lib/src/app/routers/apikeys.js +14 -2
- package/lib/src/app/routers/auth.js +29 -5
- package/lib/src/app/routers/control.js +13 -5
- package/lib/src/app/routers/dashboard.js +42 -27
- package/lib/src/app/routers/grid.js +5 -3
- package/lib/src/app/routers/profile.js +21 -0
- package/lib/src/app/routers/users.js +10 -5
- package/lib/src/app/swagger.js +2 -0
- package/lib/src/app/ws/h264StreamWs.js +10 -1
- package/lib/src/config.js +1 -0
- package/lib/src/dashboard/commands.js +5 -5
- package/lib/src/dashboard/event-manager.js +49 -61
- package/lib/src/dashboard/services/failure-analysis-service.js +136 -45
- package/lib/src/dashboard/sessionCommandSummary.js +39 -0
- package/lib/src/data-service/device-store.js +14 -1
- package/lib/src/data-service/prisma-store.js +19 -7
- package/lib/src/data-service/web-config-service.js +7 -0
- package/lib/src/device-managers/android/AndroidH264StreamService.js +69 -20
- package/lib/src/device-managers/android/H264Multiplexer.js +38 -4
- package/lib/src/device-utils.js +20 -2
- package/lib/src/gateway/defaultGateway.js +1 -1
- package/lib/src/gateway/forwardToNode.js +2 -0
- package/lib/src/gateway/healReport.js +87 -0
- package/lib/src/gateway/sessionGateway.js +12 -2
- package/lib/src/generated/client/edge.js +4 -3
- package/lib/src/generated/client/index-browser.js +1 -0
- package/lib/src/generated/client/index.d.ts +32 -0
- package/lib/src/generated/client/index.js +4 -3
- package/lib/src/generated/client/package.json +1 -1
- package/lib/src/generated/client/schema.prisma +3 -0
- package/lib/src/generated/client/wasm.js +1 -0
- package/lib/src/interceptors/CommandInterceptor.js +243 -181
- package/lib/src/middleware/authMiddleware.js +15 -3
- package/lib/src/middleware/commandCaller.js +3 -3
- package/lib/src/middleware/verifyCredential.js +58 -1
- package/lib/src/plugin.js +8 -3
- package/lib/src/services/AICommandService.js +9 -2
- package/lib/src/services/AIService.js +192 -42
- package/lib/src/services/EmailService.js +29 -0
- package/lib/src/services/OrphanSweeper.js +2 -0
- package/lib/src/services/SelectorVerificationJob.js +15 -4
- package/lib/src/services/ServerManager.js +11 -1
- package/lib/src/services/SessionLifecycleService.js +86 -26
- package/lib/src/services/SocketServer.js +19 -3
- package/lib/src/services/bug-report/video-slice.js +4 -1
- package/lib/src/services/device-access/leaseOverride.js +7 -5
- package/lib/src/services/healing/FuzzyXmlHealingProvider.js +51 -0
- package/lib/src/services/healing/HealEtalonService.js +3 -2
- package/lib/src/services/healing/HealingOrchestrator.js +55 -72
- package/lib/src/services/healing/OcrHealingProvider.js +41 -64
- package/lib/src/services/healing/ResilioTreeHealingProvider.js +41 -50
- package/lib/src/services/healing/VisualAiHealingProvider.js +1 -1
- package/lib/src/services/healing/fingerprintIdentity.js +126 -0
- package/lib/src/services/healing/resilioPath.js +274 -0
- package/lib/src/services/logcat/SessionDeviceLogs.js +271 -0
- package/lib/src/services/logcat/deviceLogBook.js +163 -0
- package/lib/src/services/ocr/ocrData.js +118 -0
- package/lib/src/services/ocr/vendor/LICENSE-tessdata.txt +202 -0
- package/lib/src/services/ocr/vendor/eng.traineddata.gz +0 -0
- package/lib/src/services/omni-vision/OmniVisionService.js +83 -56
- package/lib/src/services/passwordResetLink.js +50 -9
- package/lib/src/services/passwordResetMode.js +3 -1
- package/lib/src/services/publicUrl.js +45 -0
- package/lib/src/services/session/sessionIdentity.js +5 -3
- package/lib/src/services/session/shutdownReason.js +26 -0
- package/lib/src/services/settings/aiEngineSettings.js +219 -0
- package/lib/src/services/token/mintedLifetime.js +51 -0
- package/lib/src/sessions/SessionManager.js +8 -2
- package/lib/src/sessions/sessionMemory.js +25 -0
- package/lib/test/helpers/fake-ai-provider.js +188 -0
- package/lib/test/helpers/loki-stores.js +33 -0
- package/lib/test/helpers/page-sources.js +164 -0
- package/lib/test/helpers/scratch-database.js +57 -13
- package/lib/test/integration/audit-ingest.spec.js +10 -10
- package/lib/test/integration/auth-flow.spec.js +9 -14
- package/lib/test/integration/auth-rate-limit.spec.js +6 -3
- package/lib/test/integration/bug-report-route.spec.js +22 -2
- package/lib/test/integration/forgot-password-rate-limit.spec.js +6 -3
- package/lib/test/integration/forgot-password.spec.js +17 -18
- package/lib/test/integration/legacy-deprecation-headers.spec.js +5 -2
- package/lib/test/integration/migration.spec.js +6 -1
- package/lib/test/integration/node-pair-auth-rest.spec.js +5 -9
- package/lib/test/integration/ports-router.spec.js +4 -4
- package/lib/test/integration/prisma-device-store-add-devices.spec.js +2 -3
- package/lib/test/integration/prisma-device-store-team-filter.spec.js +2 -5
- package/lib/test/integration/profile-tokens.spec.js +10 -16
- package/lib/test/integration/recordings-router.spec.js +16 -16
- package/lib/test/integration/reset-revokes-sessions.spec.js +4 -9
- package/lib/test/integration/role-matrix.spec.js +4 -9
- package/lib/test/integration/sdk-leases-router.spec.js +9 -9
- package/lib/test/integration/sdk-version.spec.js +2 -2
- package/lib/test/integration/selector-health-endpoint.spec.js +5 -5
- package/lib/test/integration/team-membership-migration.spec.js +73 -12
- package/lib/test/integration/team-visibility-apps.spec.js +15 -22
- package/lib/test/integration/team-visibility-control.spec.js +96 -69
- package/lib/test/integration/team-visibility-dashboard.spec.js +7 -23
- package/lib/test/integration/team-visibility-grid.spec.js +16 -15
- package/lib/test/integration/team-visibility-leases.spec.js +8 -11
- package/lib/test/integration/team-visibility-recordings.spec.js +6 -19
- package/lib/test/integration/team-visibility-sessions.spec.js +6 -19
- package/lib/test/integration/users-flow.spec.js +7 -12
- package/lib/test/integration/users-lockout.spec.js +5 -3
- package/lib/test/unit/EmailService.test.js +66 -0
- package/lib/test/unit/ResilioTreeHealingProvider.test.js +46 -19
- package/lib/test/unit/ai-call-time-limit.spec.js +130 -0
- package/lib/test/unit/ai-engine-settings.spec.js +338 -0
- package/lib/test/unit/ai-provider-switch.spec.js +130 -0
- package/lib/test/unit/ai-rate-limit.spec.js +126 -0
- package/lib/test/unit/android-h264-viewers.spec.js +272 -0
- package/lib/test/unit/android-preview-hold.spec.js +3 -2
- package/lib/test/unit/apikeys-router.spec.js +84 -0
- package/lib/test/unit/authMiddleware.bearer.spec.js +9 -0
- package/lib/test/unit/authMiddleware.credentialLifetime.spec.js +149 -0
- package/lib/test/unit/bug-report/video-slice.spec.js +19 -0
- package/lib/test/unit/dashboard-events-device-logs.spec.js +207 -0
- package/lib/test/unit/dashboard-plugin-link.spec.js +213 -0
- package/lib/test/unit/device-log-book.spec.js +180 -0
- package/lib/test/unit/enable-dashboard-option.spec.js +57 -0
- package/lib/test/unit/event-log-session-data.spec.js +244 -0
- package/lib/test/unit/failure-analysis.spec.js +182 -0
- package/lib/test/unit/failure-categories.spec.js +128 -0
- package/lib/test/unit/fingerprint-identity.spec.js +433 -0
- package/lib/test/unit/h264-multiplexer.spec.js +46 -0
- package/lib/test/unit/heal-report.spec.js +71 -0
- package/lib/test/unit/healing-instrumentation.spec.js +6 -1
- package/lib/test/unit/healing-tier-gate.spec.js +73 -29
- package/lib/test/unit/healing-tiers-every-session.spec.js +219 -0
- package/lib/test/unit/hub-node-gateway-appium-server.spec.js +171 -0
- package/lib/test/unit/interceptor-visual-elements.spec.js +192 -0
- package/lib/test/unit/lease/lease-override.spec.js +23 -6
- package/lib/test/unit/lease/session-lease-proof.spec.js +16 -4
- package/lib/test/unit/ocr-healing-tier-real-ocr.spec.js +113 -0
- package/lib/test/unit/ocr-healing-tier.spec.js +122 -0
- package/lib/test/unit/ocr-offline.spec.js +213 -0
- package/lib/test/unit/omni-virtual-element-store.spec.js +301 -0
- package/lib/test/unit/omni-vision-ios-points.spec.js +0 -2
- package/lib/test/unit/omni-vision.spec.js +5 -7
- package/lib/test/unit/package-engines.spec.js +27 -0
- package/lib/test/unit/passwordResetMode.test.js +10 -2
- package/lib/test/unit/profile-router.test.js +122 -1
- package/lib/test/unit/queue-requester.spec.js +1 -1
- package/lib/test/unit/reset-link-address.spec.js +266 -0
- package/lib/test/unit/reset-link.test.js +10 -4
- package/lib/test/unit/resilio-path-healing.spec.js +270 -0
- package/lib/test/unit/selector-learning-every-session.spec.js +179 -0
- package/lib/test/unit/selector-verification-clean-build.spec.js +130 -0
- package/lib/test/unit/selector-verification-job.spec.js +13 -13
- package/lib/test/unit/self-healing-boot.spec.js +10 -5
- package/lib/test/unit/self-healing-setting.spec.js +7 -6
- package/lib/test/unit/session-app-resolution.spec.js +5 -1
- package/lib/test/unit/session-attribution-wiring.spec.js +41 -13
- package/lib/test/unit/session-create-credential-owner.spec.js +242 -0
- package/lib/test/unit/session-credential-strip.spec.js +1 -1
- package/lib/test/unit/session-device-logs.spec.js +347 -0
- package/lib/test/unit/session-end-failure-analysis.spec.js +133 -0
- package/lib/test/unit/session-log-indexes.spec.js +64 -3
- package/lib/test/unit/socketServer.sessionCookie.spec.js +2 -1
- package/lib/test/unit/stream-start-pipelines.spec.js +72 -18
- package/lib/test/unit/token-mint-limits.spec.js +165 -0
- package/lib/test/unit/unexpected-shutdown-reason.spec.js +163 -0
- package/lib/test/unit/verify-credential.spec.js +33 -0
- package/lib/test/unit/vision-assertion.spec.js +3 -2
- package/lib/test/unit/web-config-service.spec.js +19 -0
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -5
- package/prisma/migrations/20261004174413_locator_etalon_path/migration.sql +2 -0
- package/prisma/schema.prisma +3 -0
- package/schema.json +5 -5
- package/lib/public/assets/BugReportButton-BAt0_pzq.js +0 -15
- package/lib/public/assets/DeviceMosaicView-BYaQHhTf.js +0 -2
- package/lib/public/assets/ai-settings-CsuJroRf.js +0 -21
- package/lib/public/assets/device-explorer-CdO6_nrn.js +0 -282
- package/lib/public/assets/forgot-password-CGnkRgE9.js +0 -1
- package/lib/public/assets/runbook-page-CMMeQml9.js +0 -124
- package/lib/public/assets/session-detail-page-COL_RZxw.js +0 -4
- /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-BbKEXUFH.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-BjzgWz-T.js";import{B as I}from"./button-Dda4irn_.js";import{E as F}from"./EmptyState-BSjhk_IV.js";import{M as ue}from"./Modal-CFCp3n9d.js";import{P as de,M as fe,a as me}from"./Menu-JGGYrSQQ.js";import{A as ge}from"./AnnotationOverlay-B_VNtKBH.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-MMbTmgoE.js";import{T as Re}from"./trash-2-C5RSuX0e.js";import{P as Se,a as Ne}from"./play-DLG9t8FU.js";import{D as Ee}from"./download-C9XG6lLv.js";import"./utils-CDN07tui.js";import"./index-DJGc1M2f.js";import"./check-CZ9iw9-e.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
|
+
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,H as Y,r as l,j as n,$ as z,A as G,e as q}from"./index-
|
|
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
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-
|
|
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-
|
|
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-
|
|
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};
|
|
@@ -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 $,Z as g,y as oe}from"./index-BbKEXUFH.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-BcTm5xV2.js";import{F as m}from"./FieldGroup-Cb5QZsE1.js";import{P as O}from"./page-header-BjzgWz-T.js";import{M as B}from"./Modal-CFCp3n9d.js";import{B as u}from"./button-Dda4irn_.js";import{I as H}from"./input-Cm0tmSoc.js";import{S as M}from"./select-88jHcl-Z.js";import{P as v}from"./plus-nBFSMu_X.js";import{T as pe}from"./trash-2-C5RSuX0e.js";import{C as he}from"./check-CZ9iw9-e.js";import{C as xe}from"./copy-CAQydNFe.js";import"./index-DJGc1M2f.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,N]=a.useState(!0),[G,k]=a.useState(!1),[Z,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),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()=>{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 V=()=>{A(""),I({read:!0,sessions:!0,devices:!1,admin:!1}),P(300),D(""),F("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=>{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: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=>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:U.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(Y(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(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:[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 K,t as ve,b as je,X as p,O as fe,q as V,z as ye,v as ge}from"./index-
|
|
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.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import{c as i,j as e,n,S as o}from"./index-
|
|
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.
|
|
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-
|
|
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-
|
|
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};
|
|
@@ -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};
|