@xenon-device-management/xenon 2.9.2 → 2.10.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 (143) hide show
  1. package/lib/package.json +1 -1
  2. package/lib/public/assets/{AnnotationOverlay-B87n4pUu.js → AnnotationOverlay-LzfXiiZJ.js} +1 -1
  3. package/lib/public/assets/{ApiKeyGate-CNZJH6Cs.js → ApiKeyGate-BzFDp4mK.js} +1 -1
  4. package/lib/public/assets/{BugReportButton-DQ-R87ZV.js → BugReportButton-BpgWvmZo.js} +1 -1
  5. package/lib/public/assets/{DeviceMosaicView-dX3e7O-w.js → DeviceMosaicView-CCB-egSH.js} +2 -2
  6. package/lib/public/assets/{EmptyState-D3fG2GHY.js → EmptyState-DkUVmANo.js} +1 -1
  7. package/lib/public/assets/{FieldGroup-CUmbJZxI.js → FieldGroup-mbfnfTql.js} +1 -1
  8. package/lib/public/assets/{FilterMenu-Dm2c-UCk.js → FilterMenu-BH5usz4Y.js} +1 -1
  9. package/lib/public/assets/{Menu-Dl4uXMkH.js → Menu-Cbo9mdTk.js} +1 -1
  10. package/lib/public/assets/{Modal-DNmn2RDs.js → Modal-D6XfQHPr.js} +1 -1
  11. package/lib/public/assets/{RecordingPage-Dn3By34o.js → RecordingPage-CmFPkWqH.js} +1 -1
  12. package/lib/public/assets/{RecordingsPage-lCUIM4pm.js → RecordingsPage-CSlKk2qC.js} +1 -1
  13. package/lib/public/assets/{SegmentedControl-BdA_mHiZ.js → SegmentedControl-BFW9Dlqd.js} +1 -1
  14. package/lib/public/assets/{SettingCard-Dx3WhK7w.js → SettingCard-C4DioTTi.js} +1 -1
  15. package/lib/public/assets/{Table-D_2lhvRM.js → Table-DrKjlL00.js} +1 -1
  16. package/lib/public/assets/{activity-cNHHOKx5.js → activity-C9bE7Jm8.js} +1 -1
  17. package/lib/public/assets/{ai-settings-t6RMrDkg.js → ai-settings-DRYic4oO.js} +1 -1
  18. package/lib/public/assets/{api-keys-CK_qyQvW.js → api-keys-CaQU0g7c.js} +1 -1
  19. package/lib/public/assets/{apps-DCiI3UOb.js → apps-c1gUFmmK.js} +1 -1
  20. package/lib/public/assets/{arrow-left-CnYs8HVw.js → arrow-left-DMvAWA8r.js} +1 -1
  21. package/lib/public/assets/{arrow-right-Cc9qm6UG.js → arrow-right-BEQgxmKT.js} +1 -1
  22. package/lib/public/assets/{arrow-up-right-e7yBOb-c.js → arrow-up-right-Ba0e2GeU.js} +1 -1
  23. package/lib/public/assets/{auth-shell-DKrtcIjG.js → auth-shell-COODQnc7.js} +2 -2
  24. package/lib/public/assets/{builds-page-CRd5oEz6.js → builds-page-DZQgWBUs.js} +4 -4
  25. package/lib/public/assets/{button-C0caCjJB.js → button-WW9j43wR.js} +1 -1
  26. package/lib/public/assets/{calendar-BqOOkln_.js → calendar-COUs9VxF.js} +1 -1
  27. package/lib/public/assets/{check-DYSXRG79.js → check-D8ifHIJR.js} +1 -1
  28. package/lib/public/assets/{chevron-right-hCNu0CA-.js → chevron-right-BjKVUlB_.js} +1 -1
  29. package/lib/public/assets/{circle-check-DnQ263fa.js → circle-check-CfP79QE2.js} +1 -1
  30. package/lib/public/assets/{circle-x-BaRKZyz9.js → circle-x-BZbFCixZ.js} +1 -1
  31. package/lib/public/assets/{clock-XP3iBAhg.js → clock-BuTm35Qg.js} +1 -1
  32. package/lib/public/assets/{copy-D8d9UzWE.js → copy-W00zUBwN.js} +1 -1
  33. package/lib/public/assets/{device-explorer-pdM3L9TC.js → device-explorer-BEpS-Y-_.js} +5 -5
  34. package/lib/public/assets/{download-SaN9-umX.js → download-CGz-MS3y.js} +1 -1
  35. package/lib/public/assets/{forgot-password-DfUhEZW5.js → forgot-password-DG7SqVgU.js} +1 -1
  36. package/lib/public/assets/{index-C8pvxG1f.css → index-DQa193-A.css} +1 -1
  37. package/lib/public/assets/{index-IefGCFQQ.js → index-DWHTp1YP.js} +1 -1
  38. package/lib/public/assets/{index-CzaIyL9t.js → index-EkaQM1DK.js} +2 -2
  39. package/lib/public/assets/{input-BqFzAQT3.js → input-ChaTXeCq.js} +1 -1
  40. package/lib/public/assets/{keycodes-DDV2OlpQ.js → keycodes-BhbgeW_r.js} +10 -5
  41. package/lib/public/assets/line-chart-9P3RxScy.js +1 -0
  42. package/lib/public/assets/list-checks-_23IIEEL.js +11 -0
  43. package/lib/public/assets/{lock-Eye1CG8p.js → lock-B2JaqqRI.js} +1 -1
  44. package/lib/public/assets/{login-Co1IXuen.js → login-BEWIfLfC.js} +1 -1
  45. package/lib/public/assets/{maintenance-settings-D1fw6iqm.js → maintenance-settings-BGJIJQ-k.js} +1 -1
  46. package/lib/public/assets/{monitor-U5Y-PxW5.js → monitor-BrwMY4G0.js} +1 -1
  47. package/lib/public/assets/{mouse-pointer-2-CDAwphUm.js → mouse-pointer-2-DsWDMyrY.js} +1 -1
  48. package/lib/public/assets/{network-BP_U4iDZ.js → network-DfIhNVJv.js} +1 -1
  49. package/lib/public/assets/overview-B1mePY2_.js +6 -0
  50. package/lib/public/assets/{page-header-ZdzNEJp9.js → page-header-DoD3TOzZ.js} +1 -1
  51. package/lib/public/assets/{plus-1k0sxXyU.js → plus-BGvWvpBB.js} +1 -1
  52. package/lib/public/assets/{profile-page-B_GWKRy3.js → profile-page-CvV5aWvl.js} +1 -1
  53. package/lib/public/assets/{reset-password-DizCTkdw.js → reset-password-CGVd31LR.js} +1 -1
  54. package/lib/public/assets/{runbook-page-DWzRiOLZ.js → runbook-page-Bq2cvwb5.js} +1 -1
  55. package/lib/public/assets/{select-CiRW6v17.js → select-CTcD4jWR.js} +1 -1
  56. package/lib/public/assets/selector-detail-redirect-19odlD4B.js +1 -0
  57. package/lib/public/assets/selector-health-page-LqIsLrjW.js +11 -0
  58. package/lib/public/assets/session-detail-page-DQzb8_fq.js +4 -0
  59. package/lib/public/assets/{settings-DhwZoWv7.js → settings-C-EnGIqs.js} +1 -1
  60. package/lib/public/assets/stat-tile-BY0RDTRm.js +1 -0
  61. package/lib/public/assets/{tablet-CPJV3dBq.js → tablet-B4cFM-5B.js} +1 -1
  62. package/lib/public/assets/{teams-D0IBa2Ov.js → teams-BFe-RpYd.js} +1 -1
  63. package/lib/public/assets/time-D-gjmE1o.js +1 -0
  64. package/lib/public/assets/{trash-2-u8MlXUBD.js → trash-2-CJCKBOP9.js} +1 -1
  65. package/lib/public/assets/{upload-Cq8L3kpw.js → upload-DidWkbld.js} +1 -1
  66. package/lib/public/assets/use-builds-data-fnfxatOd.js +8 -0
  67. package/lib/public/assets/{use-password-reset-mode-Dbr2HEfw.js → use-password-reset-mode-iPen3tmC.js} +1 -1
  68. package/lib/public/assets/{users-CZqCE511.js → users-CrcjmRdf.js} +1 -1
  69. package/lib/public/assets/{users-DxLHYmFm.js → users-DBUv0CJx.js} +1 -1
  70. package/lib/public/assets/{video-off-mh1EEzP9.js → video-off-eh69-FKB.js} +1 -1
  71. package/lib/public/assets/view-state-CP9dE1UI.js +1 -0
  72. package/lib/public/assets/{webhook-settings-BYuOib-Q.js → webhook-settings-CQoSshBn.js} +1 -1
  73. package/lib/public/assets/{zap-BOpUur0M.js → zap-CICtWiLn.js} +1 -1
  74. package/lib/public/index.html +2 -2
  75. package/lib/schema.json +5 -0
  76. package/lib/src/app/routers/dashboard.js +86 -40
  77. package/lib/src/app/routers/selector-health.js +75 -0
  78. package/lib/src/app/swagger-docs.js +77 -8
  79. package/lib/src/dashboard/event-manager.js +15 -99
  80. package/lib/src/generated/client/edge.js +27 -3
  81. package/lib/src/generated/client/index-browser.js +24 -0
  82. package/lib/src/generated/client/index.d.ts +8207 -5283
  83. package/lib/src/generated/client/index.js +27 -3
  84. package/lib/src/generated/client/package.json +1 -1
  85. package/lib/src/generated/client/schema.prisma +43 -9
  86. package/lib/src/generated/client/wasm.js +24 -0
  87. package/lib/src/prisma.js +2 -0
  88. package/lib/src/services/CleanupService.js +1 -0
  89. package/lib/src/services/NotificationService.js +3 -4
  90. package/lib/src/services/SelectorStateService.js +151 -113
  91. package/lib/src/services/SelectorVerificationJob.js +14 -9
  92. package/lib/src/services/metrics/AndroidMetricsSampler.js +94 -0
  93. package/lib/src/services/metrics/IOSMetricsSampler.js +120 -0
  94. package/lib/src/services/metrics/SessionMetricsService.js +238 -0
  95. package/lib/src/services/metrics/androidMetrics.js +94 -0
  96. package/lib/src/services/metrics/iosMetrics.js +26 -0
  97. package/lib/src/services/metrics/metricsBody.js +37 -0
  98. package/lib/src/services/metrics/types.js +19 -0
  99. package/lib/src/services/selector-health/access.js +66 -0
  100. package/lib/src/services/selector-health/healingTrend.js +49 -0
  101. package/lib/src/services/selector-health/people.js +27 -0
  102. package/lib/src/services/selector-health/selectorDetail.js +198 -0
  103. package/lib/src/services/selector-health/selectorKeys.js +36 -0
  104. package/lib/src/services/selector-health/selectorList.js +333 -0
  105. package/lib/src/services/selector-health/stateView.js +67 -0
  106. package/lib/test/helpers/scratch-database.js +2 -0
  107. package/lib/test/helpers/selector-health-fixture.js +216 -0
  108. package/lib/test/integration/team-visibility-sessions.spec.js +1 -0
  109. package/lib/test/unit/CleanupService.spec.js +28 -2
  110. package/lib/test/unit/dashboard-events-metrics.spec.js +146 -0
  111. package/lib/test/unit/healing-no-cost.spec.js +134 -0
  112. package/lib/test/unit/healing-state-endpoints.spec.js +70 -0
  113. package/lib/test/unit/healing-trend.spec.js +118 -0
  114. package/lib/test/unit/selector-event-model.spec.js +47 -0
  115. package/lib/test/unit/selector-health-actions.spec.js +106 -0
  116. package/lib/test/unit/selector-health-detail.spec.js +131 -0
  117. package/lib/test/unit/selector-health-list.spec.js +185 -0
  118. package/lib/test/unit/selector-state-service.spec.js +74 -1
  119. package/lib/test/unit/selector-verification-job.spec.js +38 -0
  120. package/lib/test/unit/session-metrics-parse.spec.js +138 -0
  121. package/lib/test/unit/session-metrics-route.spec.js +140 -0
  122. package/lib/test/unit/session-metrics-samplers.spec.js +248 -0
  123. package/lib/test/unit/session-metrics-service.spec.js +215 -0
  124. package/lib/tsconfig.tsbuildinfo +1 -1
  125. package/package.json +1 -1
  126. package/prisma/migrations/20261002120000_session_metric/migration.sql +17 -0
  127. package/prisma/migrations/20261002130000_selector_event/migration.sql +13 -0
  128. package/prisma/schema.prisma +43 -9
  129. package/schema.json +5 -0
  130. package/lib/public/assets/chevron-left-BSG6mcpo.js +0 -6
  131. package/lib/public/assets/funnel-OefHE-54.js +0 -6
  132. package/lib/public/assets/layers-a3GNz2DA.js +0 -6
  133. package/lib/public/assets/list-checks-DMrMAFDt.js +0 -6
  134. package/lib/public/assets/overview-CsPyPv10.js +0 -1
  135. package/lib/public/assets/selector-detail-page-pA913STP.js +0 -1
  136. package/lib/public/assets/selector-health-BlICzZlk.css +0 -1
  137. package/lib/public/assets/selector-health-CHLX8KqY.js +0 -16
  138. package/lib/public/assets/selector-health-page-vVkg8Mii.js +0 -16
  139. package/lib/public/assets/session-detail-page-BCD49zDi.js +0 -4
  140. package/lib/public/assets/stat-tile-BaE76cnK.js +0 -8
  141. package/lib/public/assets/time-B8FIgwPE.js +0 -1
  142. package/lib/src/profiling/AndroidAppProfiler.js +0 -213
  143. /package/lib/public/assets/{session-detail-page-Bzzc3bMl.css → line-chart-Bzzc3bMl.css} +0 -0
@@ -1 +0,0 @@
1
- import{r as h,p as y,X as p,j as e,u as E,T as R,q as T,s as H}from"./index-CzaIyL9t.js";import{p as M}from"./labels-C21SA4JG.js";import{F as L}from"./funnel-OefHE-54.js";import{A as O}from"./arrow-right-Cc9qm6UG.js";import{T as B}from"./tablet-CPJV3dBq.js";import{M as P}from"./monitor-U5Y-PxW5.js";import{A as U}from"./activity-cNHHOKx5.js";import{P as X}from"./page-header-ZdzNEJp9.js";const k=20;function G(s){return s.deviceName||(s.deviceUdid?s.deviceUdid.slice(0,8):"device")}function C(s){const n=s.commandName||"selector",i=G(s);return s.tier?e.jsxs(e.Fragment,{children:[e.jsx("strong",{children:s.tier})," healed ",e.jsx("strong",{children:n})," on ",e.jsx("strong",{children:i})]}):e.jsxs(e.Fragment,{children:["Healed ",e.jsx("strong",{children:n})," on ",e.jsx("strong",{children:i})]})}function K(){const[s,n]=h.useState([]),[i,x]=h.useState([]),[u,g]=h.useState(0),[a,j]=h.useState([]),{on:m}=y(),F=h.useRef(0);h.useEffect(()=>{let o=!1;const f=()=>{p.getDevices().then(c=>{!o&&Array.isArray(c)&&n(c)}).catch(()=>{})};f();const w=setInterval(f,3e4);return p.getSessions().then(c=>{!o&&Array.isArray(c)&&x(c)}).catch(()=>{}),p.getPendingSessionsCount().then(c=>{if(o)return;const b=typeof c=="number"?c:typeof(c==null?void 0:c.count)=="number"?c.count:0;g(b)}).catch(()=>{}),p.getRecentHealingEvents().then(c=>{if(o||!c)return;const b=Array.isArray(c.events)?c.events:[];b.length!==0&&j(N=>{const S=new Set(N.map(r=>r.id));return[...b.filter(r=>!S.has(r.id)).map(r=>({id:r.id,ts:Date.parse(r.createdAt)||Date.now(),kind:"heal",message:C(r)})),...N].sort((r,l)=>l.ts-r.ts).slice(0,k)})}).catch(()=>{}),()=>{o=!0,clearInterval(w)}},[]),h.useEffect(()=>{const o=[],f=(t,r)=>{F.current+=1;const l={id:`${Date.now()}-${F.current}`,ts:Date.now(),kind:t,message:r};j(d=>[l,...d].slice(0,k))},w=t=>{var d;t&&t.session&&x(v=>v.find($=>$.id===t.session.id)?v:[t.session,...v]);const r=((d=t==null?void 0:t.session)==null?void 0:d.id)||(t==null?void 0:t.sessionId)||"",l=r?r.slice(0,6):"";f("session",e.jsxs(e.Fragment,{children:["Session ",e.jsx("strong",{children:l||"—"})," started"]}))},c=t=>{var v,A;const r=((v=t==null?void 0:t.session)==null?void 0:v.id)||(t==null?void 0:t.sessionId)||"",l=!!((A=t==null?void 0:t.session)!=null&&A.failure_reason||t!=null&&t.failure_reason);r&&x($=>$.map(D=>D.id===r?{...D,status:l?"failed":"finished"}:D));const d=r?r.slice(0,6):"";f(l?"session-failed":"session-end",l?e.jsxs(e.Fragment,{children:["Session ",e.jsx("strong",{children:d||"—"})," failed"]}):e.jsxs(e.Fragment,{children:["Session ",e.jsx("strong",{children:d||"—"})," ended"]}))},b=t=>{const r=(t==null?void 0:t.nodeId)||(t==null?void 0:t.id)||"node";f("node",e.jsxs(e.Fragment,{children:["Node ",e.jsx("strong",{children:String(r)})," connected"]}))},N=t=>{const r=(t==null?void 0:t.nodeId)||(t==null?void 0:t.id)||"node";f("node",e.jsxs(e.Fragment,{children:["Node ",e.jsx("strong",{children:String(r)})," disconnected"]}))},S=t=>{const r=t;if(!r||!r.id)return;const l={id:r.id,ts:Date.parse(r.createdAt)||Date.now(),kind:"heal",message:C(r)};j(d=>d.some(v=>v.id===l.id)?d:[l,...d].slice(0,k))};return o.push(m("session_started",w)),o.push(m("session_stopped",c)),o.push(m("node_connected",b)),o.push(m("node_disconnected",N)),o.push(m("healing_event",S)),()=>{o.forEach(t=>t&&t())}},[m]);const q=i.filter(o=>o.status==="running");return{devices:s,activeSessions:q,queuedSessions:u,activity:a}}const Q={healthy:"bg-[var(--color-success)]",neutral:"bg-[var(--border-strong)]",warn:"bg-[var(--amber)]",critical:"bg-[var(--red)]"},V={healthy:"bg-[var(--color-success)]",neutral:"bg-[var(--text-dim)]",warn:"bg-[var(--amber)]",critical:"bg-[var(--red)]"},Y={healthy:"text-[var(--color-success)]",neutral:"text-[var(--text-muted)]",warn:"text-[var(--amber)]",critical:"text-[var(--red)]"},I=({label:s,value:n,secondaryValue:i,subtitle:x,state:u="neutral"})=>e.jsxs("div",{className:"relative overflow-hidden rounded-lg border border-[var(--border)] bg-[var(--surface)] p-4 hover:border-[var(--border-strong)] transition-colors",children:[e.jsx("span",{className:`absolute left-0 top-0 bottom-0 w-[2px] ${Q[u]}`}),e.jsx("div",{className:"text-[11px] font-semibold text-[var(--text-muted)]",children:s}),e.jsxs("div",{className:"mt-3 flex items-baseline gap-2",children:[e.jsx("span",{className:"text-3xl font-semibold text-[var(--text)] tabular-nums",children:n}),i!=null&&e.jsxs("span",{className:"text-sm font-mono text-[var(--text-dim)]",children:["/ ",i]})]}),e.jsxs("div",{className:`mt-3 flex items-center gap-1.5 text-xs ${Y[u]}`,children:[e.jsx("span",{className:`h-1.5 w-1.5 rounded-full ${V[u]}`}),e.jsx("span",{children:x})]})]});function _(s){return s.offline?"offline":s.reservedBy?"reserved":s.busy?"busy":"ready"}function z(s){const n=(s.platform||"").toLowerCase();return n==="tvos"?R:/pad|tablet/i.test(s.name||"")?B:n==="ios"||n==="android"?T:P}const J={ready:{dot:"bg-[var(--color-success)]",text:"text-[var(--color-success)]",label:"Ready"},busy:{dot:"bg-[var(--amber)]",text:"text-[var(--amber)]",label:"Busy"},reserved:{dot:"bg-[var(--blue)]",text:"text-[var(--blue)]",label:"Reserved"},offline:{dot:"bg-[var(--text-dim)]",text:"text-[var(--text-dim)]",label:"Offline"}};function W(s){return s?s.length<=16?s:`${s.slice(0,8)}…${s.slice(-4)}`:""}const Z=({devices:s,maxRows:n=6})=>{const[i,x]=h.useState("all"),u=E(),g=(i==="all"?s:s.filter(a=>_(a)!=="ready")).slice(0,n);return e.jsxs("section",{className:"rounded-lg border border-[var(--border)] bg-[var(--surface)] flex flex-col",children:[e.jsxs("header",{className:"flex items-center justify-between px-4 py-3 border-b border-[var(--border)]",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("h2",{className:"text-sm font-semibold text-[var(--text)]",children:"Fleet status"}),e.jsxs("span",{className:"text-xs font-mono text-[var(--text-dim)]",children:[s.length," devices"]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("div",{role:"group","aria-label":"Filter devices",className:"flex items-center gap-0.5 bg-[var(--surface-2)] border border-[var(--border)] rounded-md p-0.5",children:[e.jsx("button",{type:"button",onClick:()=>x("all"),"aria-pressed":i==="all",className:`px-2 py-1 text-[11px] rounded transition-colors ${i==="all"?"bg-[var(--border-strong)] text-[var(--text)]":"text-[var(--text-dim)] hover:text-[var(--text)]"}`,children:"All"}),e.jsxs("button",{type:"button",onClick:()=>x("issues"),"aria-pressed":i==="issues",className:`px-2 py-1 text-[11px] rounded transition-colors flex items-center gap-1 ${i==="issues"?"bg-[var(--border-strong)] text-[var(--text)]":"text-[var(--text-dim)] hover:text-[var(--text)]"}`,children:[e.jsx(L,{className:"h-3 w-3"}),"Non-ready"]})]}),e.jsxs("button",{type:"button",onClick:()=>u("/devices"),className:"ml-1 inline-flex items-center gap-1 text-xs text-[var(--text-muted)] hover:text-[var(--text)] transition-colors",children:["View all ",e.jsx(O,{className:"h-3 w-3"})]})]})]}),e.jsx("div",{className:"divide-y divide-[var(--border)]",children:g.length===0?e.jsx("div",{className:"px-4 py-8 text-center text-xs text-[var(--text-dim)]",children:i==="issues"?"All devices are ready.":"No devices registered."}):g.map(a=>{const j=z(a),m=J[_(a)];return e.jsxs("button",{type:"button",onClick:()=>a.udid&&u(`/devices/${a.udid}/control/screen`),className:"w-full flex items-center gap-3 px-4 py-2.5 hover:bg-[var(--surface-2)] transition-colors text-left",children:[e.jsx("span",{className:`h-1.5 w-1.5 rounded-full shrink-0 ${m.dot}`}),e.jsx(j,{className:"h-4 w-4 text-[var(--text-dim)] shrink-0"}),e.jsxs("div",{className:"flex-1 min-w-0 flex items-center gap-3",children:[e.jsx("div",{className:"min-w-0 flex-1",children:e.jsx("div",{className:"text-xs text-[var(--text)] truncate",children:a.name||a.udid})}),e.jsxs("div",{className:"hidden md:block text-[11px] font-mono text-[var(--text-dim)] w-24 text-right",children:[M(a.platform)," ",a.sdk||""]}),e.jsx("div",{className:"hidden lg:block text-[11px] font-mono text-[var(--text-dim)] w-32 text-right",children:W(a.udid)})]}),e.jsx("span",{className:`font-mono text-[10px] font-semibold tracking-wider w-20 text-right ${m.text}`,children:m.label})]},a.udid||a.name)})})]})},ee={session:"bg-[var(--color-accent)]","session-end":"bg-[var(--text-dim)]","session-failed":"bg-[var(--red)]",node:"bg-[var(--blue)]",heal:"bg-[var(--amber)]"};function te(s){const n=new Date(s);return`${String(n.getHours()).padStart(2,"0")}:${String(n.getMinutes()).padStart(2,"0")}`}const se=({events:s,live:n=!0})=>e.jsxs("section",{className:"rounded-lg border border-[var(--border)] bg-[var(--surface)] flex flex-col",children:[e.jsx("header",{className:"flex items-center justify-between px-4 py-3 border-b border-[var(--border)]",children:e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("h2",{className:"text-sm font-semibold text-[var(--text)]",children:"Recent activity"}),e.jsxs("span",{className:"flex items-center gap-1 text-[11px] text-[var(--text-dim)]",children:[e.jsx("span",{className:`h-1.5 w-1.5 rounded-full ${n?"bg-[var(--color-success)] pulse-dot":"bg-[var(--text-dim)]"}`}),n?"Live":"Offline"]})]})}),s.length===0?e.jsxs("div",{className:"flex-1 flex flex-col items-center justify-center px-6 py-10 text-center gap-2",children:[e.jsx("div",{className:"h-10 w-10 rounded-full bg-[var(--surface-2)] border border-[var(--border)] flex items-center justify-center",children:e.jsx(U,{className:"h-5 w-5 text-[var(--text-dim)]"})}),e.jsx("div",{className:"text-sm font-medium text-[var(--text)]",children:"No activity yet"}),e.jsx("div",{className:"text-xs text-[var(--text-dim)] max-w-xs",children:"Session and heal events will appear here as they happen."})]}):e.jsx("div",{className:"flex-1 overflow-y-auto divide-y divide-[var(--border)]",children:s.map(i=>e.jsxs("div",{className:"flex items-center gap-3 px-4 py-2.5",children:[e.jsx("span",{className:"font-mono text-[10px] text-[var(--text-dim)] w-10 shrink-0",children:te(i.ts)}),e.jsx("span",{className:`h-1.5 w-1.5 rounded-full shrink-0 ${ee[i.kind]}`}),e.jsx("span",{className:"text-xs text-[var(--text-muted)] truncate",children:i.message})]},i.id))})]}),re="—",ue=()=>{const s=K(),n=s.devices.length,i=s.devices.filter(g=>!g.offline).length,x=n===0?"neutral":i===n?"healthy":"warn",u=s.activeSessions.length>0?"healthy":s.queuedSessions>0?"warn":"neutral";return e.jsxs("div",{className:"flex-1 min-w-0 overflow-y-auto",children:[e.jsx(X,{icon:H,title:"Overview",subtitle:"Devices, sessions and healing activity across your lab."}),e.jsxs("div",{className:"max-w-7xl mx-auto px-6 py-6",children:[e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-3 mb-6",children:[e.jsx(I,{label:"Devices online",value:n===0?re:i,secondaryValue:n===0?void 0:n,subtitle:n===0?"No devices registered":`${i} of ${n} online`,state:x}),e.jsx(I,{label:"Active sessions",value:s.activeSessions.length,subtitle:s.queuedSessions>0?`${s.queuedSessions} queued`:"No queue",state:u})]}),e.jsxs("div",{className:"grid grid-cols-1 lg:grid-cols-2 gap-3",children:[e.jsx(Z,{devices:s.devices}),e.jsx(se,{events:s.activity,live:!0})]})]})]})};export{ue as default};
@@ -1 +0,0 @@
1
- import{u as I,t as A,E as F,r,X as v,j as e,K as f,A as w,C as R,y as D}from"./index-CzaIyL9t.js";import{f as g}from"./time-B8FIgwPE.js";import{P as S}from"./page-header-ZdzNEJp9.js";import{f as P,H as B,V as E,E as H}from"./selector-health-CHLX8KqY.js";import{C as M}from"./chevron-left-BSG6mcpo.js";import{C as L}from"./circle-check-DnQ263fa.js";import{Z as U}from"./zap-BOpUur0M.js";import{L as O}from"./layers-a3GNz2DA.js";import{C as K}from"./check-DYSXRG79.js";import{C as q}from"./copy-D8d9UzWE.js";function V(d){const h=Date.parse(d);if(!Number.isFinite(h))return"";const x=Math.max(0,Date.now()-h),l=Math.floor(x/1e3);if(l<60)return`${l}s ago`;const i=Math.floor(l/60);if(i<60)return`${i}m ago`;const o=Math.floor(i/60);return o<24?`${o}h ago`:`${Math.floor(o/24)}d ago`}function X(d){return d===0?"$0":d<.01?"<$0.01":`$${d.toFixed(2)}`}const le=()=>{const d=I(),{toast:h}=A(),[x]=F(),l=x.get("value")??"",i=x.get("strategy")??"",o=parseInt(x.get("windowDays")??"30",10)||30,[t,y]=r.useState(null),[a,p]=r.useState(null),[_,C]=r.useState(!1),[$,T]=r.useState(!1),[N,k]=r.useState(null),b=r.useCallback(async()=>{if(l){C(!0);try{const s=await v.getHealingSelectorDetail(l,o);y(s??null)}catch{y(null)}finally{C(!1),T(!0)}}},[l,o]),j=r.useCallback(async()=>{if(!i||!l){p(null);return}try{const s=await v.getSelectorState(i,l);p((s==null?void 0:s.state)??null)}catch{p(null)}},[i,l]);r.useEffect(()=>{b()},[b]),r.useEffect(()=>{j()},[j]);const m=r.useCallback(async s=>{if(!i||!l)return;const n=(()=>{switch(s){case"mark_fixed":return"Mark this selector as fixed? Move to Pending Verification.";case"mute":return"Mute this selector? It will be hidden from Hotspots, the CI gate, and digests.";case"unmute":return"Unmute this selector?";case"cancel_verification":return"Cancel verification? The selector returns to Active and the clean-build counter resets."}})();if(window.confirm(n))try{await v.postSelectorStateAction({original_strategy:i,original_selector:l,action:s}),h("Done.","success"),j()}catch(c){const u=c!=null&&c.currentStatus?` (currently ${c.currentStatus})`:"";h(`${(c==null?void 0:c.message)??"Action failed"}${u}`,"error")}},[i,l,h,j]),z=(s,n)=>{navigator.clipboard.writeText(s).catch(()=>{}),k(n),setTimeout(()=>k(c=>c===n?null:c),1500)};return l?e.jsxs("div",{className:"selector-health-page",children:[e.jsx(S,{icon:f,eyebrow:"Test quality / Selector",title:e.jsx("span",{className:"sh-detail-title",children:e.jsx("code",{title:l,children:l})}),subtitle:`All heals for this selector over the last ${o} days.`,action:e.jsxs(e.Fragment,{children:[e.jsxs("button",{className:"sh-back-btn",onClick:()=>d("/selector-health"),children:[e.jsx(M,{size:12})," Back"]}),e.jsxs("button",{className:"sh-refresh-btn",onClick:b,disabled:_,title:"Refresh",children:[e.jsx(w,{size:12,className:_?"animate-spin":""}),"Refresh"]})]})}),e.jsxs("div",{className:"sh-content",children:[i&&e.jsxs("div",{className:"sh-detail-strategy-line",title:"Tuple identity for this drill-down",children:[e.jsx("span",{className:"sh-strategy-badge",children:P(i)}),e.jsx("code",{children:l})]}),!i&&e.jsxs("div",{className:"sh-detail-banner",children:["Showing every strategy that ever healed this selector value. To scope to a single tuple, append ",e.jsx("code",{children:"?strategy=<name>"})," ","to the URL or open this row from the Active tab on Selector Health."]}),a&&e.jsxs("div",{className:`sh-detail-state sh-detail-state--${a.status}`,children:[e.jsxs("div",{className:"sh-detail-state__head",children:[e.jsxs("span",{className:"sh-detail-state__badge",children:[a.status==="pending"&&e.jsxs(e.Fragment,{children:[e.jsx(B,{size:16,style:{color:"var(--color-highlight)"}}),e.jsx("span",{children:"Pending verification"})]}),a.status==="resolved"&&e.jsxs(e.Fragment,{children:[e.jsx(L,{size:16,style:{color:"var(--color-success)"}}),e.jsx("span",{children:"Resolved"})]}),a.status==="muted"&&e.jsxs(e.Fragment,{children:[e.jsx(E,{size:16,style:{color:"var(--text-muted)"}}),e.jsx("span",{children:"Muted"})]}),a.status==="active"&&(a.regression_count>0?e.jsxs(e.Fragment,{children:[e.jsx(R,{size:16,style:{color:"var(--amber)"}}),e.jsxs("span",{children:["Active — regressed ",a.regression_count,"×"]})]}):e.jsxs(e.Fragment,{children:[e.jsx(U,{size:16}),e.jsx("span",{children:"Active"})]}))]}),e.jsxs("div",{className:"sh-detail-state__actions",children:[a.status==="active"&&e.jsxs(e.Fragment,{children:[e.jsx("button",{type:"button",className:"sh-action-btn sh-action-btn--primary",onClick:()=>m("mark_fixed"),children:"Mark fixed"}),e.jsx("button",{type:"button",className:"sh-action-btn",onClick:()=>m("mute"),children:"Mute"})]}),a.status==="pending"&&e.jsxs(e.Fragment,{children:[e.jsx("button",{type:"button",className:"sh-action-btn",onClick:()=>m("cancel_verification"),children:"Cancel verification"}),e.jsx("button",{type:"button",className:"sh-action-btn",onClick:()=>m("mute"),children:"Mute"})]}),a.status==="resolved"&&e.jsx("button",{type:"button",className:"sh-action-btn",onClick:()=>m("mute"),children:"Mute"}),a.status==="muted"&&e.jsx("button",{type:"button",className:"sh-action-btn",onClick:()=>m("unmute"),children:"Unmute"})]})]}),e.jsxs("div",{className:"sh-detail-state__meta",children:[a.fixed_at&&e.jsxs("span",{children:["Marked fixed: ",g(a.fixed_at)]}),a.resolved_at&&e.jsxs("span",{children:["Resolved: ",g(a.resolved_at)]}),a.muted_at&&e.jsxs("span",{children:["Muted: ",g(a.muted_at)]}),a.status==="pending"&&e.jsxs("span",{children:["Clean builds: ",a.clean_builds_count,"/3"]}),a.regression_count>0&&e.jsxs("span",{children:["Regressions on record: ",a.regression_count]})]})]}),_&&!$?e.jsxs("div",{className:"sh-empty",children:[e.jsx(w,{size:18,className:"animate-spin"}),e.jsx("span",{children:"Loading detail…"})]}):!t||t.healCount===0?e.jsxs("div",{className:"sh-empty sh-empty--clean",children:[e.jsx(f,{size:28}),e.jsxs("div",{children:[e.jsx("div",{className:"sh-empty__title",children:"No heals recorded"}),e.jsxs("div",{className:"sh-empty__subtitle",children:["This selector has no healing events in the last ",o," days."]})]})]}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"sh-detail-stats",children:[e.jsxs("div",{className:"sh-detail-stat",children:[e.jsx("span",{className:"sh-detail-stat__label",children:"Heals"}),e.jsx("span",{className:"sh-detail-stat__value",children:t.healCount})]}),e.jsxs("div",{className:"sh-detail-stat",children:[e.jsx("span",{className:"sh-detail-stat__label",children:"Sessions"}),e.jsx("span",{className:"sh-detail-stat__value",children:t.sessionCount})]}),e.jsxs("div",{className:"sh-detail-stat",children:[e.jsx("span",{className:"sh-detail-stat__label",children:"Est. cost"}),e.jsx("span",{className:"sh-detail-stat__value",children:X(t.estCostUsd)})]}),e.jsxs("div",{className:"sh-detail-stat",children:[e.jsx("span",{className:"sh-detail-stat__label",children:"Tiers used"}),e.jsx("span",{className:"sh-detail-stat__value",children:Object.keys(t.byTier).length||"—"})]})]}),e.jsxs("div",{className:"sh-detail-grid",children:[e.jsxs("section",{className:"sh-card",children:[e.jsxs("header",{className:"sh-card__head",children:[e.jsx(O,{size:12}),e.jsx("span",{children:"Suggested rewrites"}),e.jsx("span",{className:"sh-card__hint",children:"every alternate the healer landed on, ranked by frequency"})]}),e.jsxs("ul",{className:"sh-alternates",children:[t.alternates.length===0&&e.jsx("li",{className:"sh-alternates__empty",children:"No healed selectors recorded — only the failure was captured."}),t.alternates.map((s,n)=>{const c=Math.round(s.share*100),u=`alt-${n}`;return e.jsxs("li",{className:"sh-alternate",children:[e.jsxs("div",{className:"sh-alternate__top",children:[e.jsxs("span",{className:"sh-alternate__share",children:[c,"%"]}),e.jsx("code",{className:"sh-alternate__value",title:s.healedSelector,children:s.healedSelector}),e.jsx("button",{type:"button",className:`sh-icon-btn ${N===u?"copied":""}`,onClick:()=>z(s.healedSelector,u),"aria-label":"Copy alternate",title:N===u?"Copied":"Copy",children:N===u?e.jsx(K,{size:11}):e.jsx(q,{size:11})})]}),e.jsxs("div",{className:"sh-alternate__meta",children:[e.jsxs("span",{children:[s.count," heal",s.count===1?"":"s"]}),s.averageConfidence!==null&&e.jsxs("span",{children:["· avg ",Math.round(s.averageConfidence*100),"% confidence"]}),s.tiers.length>0&&e.jsxs("span",{children:["· via ",s.tiers.join(", ")]})]})]},s.healedSelector)})]})]}),e.jsxs("section",{className:"sh-card",children:[e.jsxs("header",{className:"sh-card__head",children:[e.jsx(D,{size:12}),e.jsx("span",{children:"Breakdown"})]}),e.jsxs("div",{className:"sh-breakdown",children:[e.jsxs("div",{className:"sh-breakdown__group",children:[e.jsx("div",{className:"sh-breakdown__label",children:"By tier"}),Object.entries(t.byTier).sort((s,n)=>n[1]-s[1]).map(([s,n])=>e.jsxs("div",{className:"sh-breakdown__row",children:[e.jsx("span",{className:"sh-tier-pill",children:s}),e.jsx("span",{className:"sh-breakdown__count",children:n})]},s)),Object.keys(t.byTier).length===0&&e.jsx("div",{className:"sh-breakdown__empty",children:"none recorded"})]}),e.jsxs("div",{className:"sh-breakdown__group",children:[e.jsx("div",{className:"sh-breakdown__label",children:"By platform"}),Object.entries(t.byPlatform).sort((s,n)=>n[1]-s[1]).map(([s,n])=>e.jsxs("div",{className:"sh-breakdown__row",children:[e.jsx("span",{className:"sh-platform-pill",children:s}),e.jsx("span",{className:"sh-breakdown__count",children:n})]},s))]}),e.jsxs("div",{className:"sh-breakdown__group",children:[e.jsx("div",{className:"sh-breakdown__label",children:"By build"}),t.byBuild.slice(0,8).map(s=>e.jsxs("div",{className:"sh-breakdown__row",children:[e.jsx("span",{className:"sh-build-pill",title:s.buildId,children:s.buildId==="unattached"?"unattached":s.buildId.length>12?s.buildId.slice(0,8)+"…":s.buildId}),e.jsx("span",{className:"sh-breakdown__count",children:s.count})]},s.buildId)),t.byBuild.length===0&&e.jsx("div",{className:"sh-breakdown__empty",children:"none recorded"})]})]})]})]}),e.jsxs("section",{className:"sh-card",children:[e.jsxs("header",{className:"sh-card__head",children:[e.jsx("span",{children:"Timeline"}),e.jsxs("span",{className:"sh-card__hint",children:["most recent ",t.timeline.length," of ",t.healCount," heal",t.healCount===1?"":"s"]})]}),e.jsx("div",{className:"sh-timeline",children:t.timeline.map(s=>e.jsxs("div",{className:"sh-timeline__row",children:[e.jsx("span",{className:"sh-timeline__when",children:V(s.createdAt)}),s.tier&&e.jsx("span",{className:"sh-tier-pill",children:s.tier}),e.jsx("span",{className:"sh-timeline__cmd",children:s.commandName??"—"}),e.jsx("span",{className:"sh-timeline__device",children:s.deviceName??s.deviceUdid??"—"}),e.jsx("code",{className:"sh-timeline__healed",title:s.healedSelector??"",children:s.healedSelector??"—"}),s.confidence!==null&&e.jsxs("span",{className:"sh-timeline__conf",children:[Math.round(s.confidence*100),"%"]}),s.buildId&&s.sessionId&&e.jsx("a",{className:"sh-timeline__link",href:`/xenon/builds/${encodeURIComponent(s.buildId)}/sessions/${encodeURIComponent(s.sessionId)}`,title:"Open session detail",children:e.jsx(H,{size:11})})]},s.id))})]})]})]})]}):e.jsxs("div",{className:"selector-health-page",children:[e.jsx(S,{icon:f,eyebrow:"Test quality",title:"Selector detail",subtitle:"No selector specified."}),e.jsx("div",{className:"sh-content",children:e.jsxs("button",{className:"sh-back-btn",onClick:()=>d("/selector-health"),children:[e.jsx(M,{size:12})," Back to Selector health"]})})]})};export{le as default};
@@ -1 +0,0 @@
1
- .selector-health-page{display:flex;flex-direction:column;width:100%;min-height:100%;color:var(--text);background:var(--bg)}.sh-content{display:flex;flex-direction:column;gap:var(--space-5);padding:var(--space-5) var(--space-6);max-width:1440px;margin:0 auto;width:100%}.sh-kpi-strip{display:grid;grid-template-columns:1fr;gap:12px}@media (min-width: 768px){.sh-kpi-strip{grid-template-columns:repeat(2,minmax(0,1fr))}.sh-kpi--hero{grid-column:1 / -1}}@media (min-width: 1280px){.sh-kpi-strip{grid-template-columns:2fr repeat(5,minmax(0,1fr))}.sh-kpi--hero{grid-column:auto}}.sh-kpi{display:flex;flex-direction:column;gap:4px;padding:14px 16px;border-radius:var(--radius-md);background:var(--surface);border:1px solid var(--border-strong);transition:border-color .15s ease,background .15s ease}.sh-kpi:hover{border-color:var(--text-dim)}.sh-kpi--hero{background:var(--surface-2);border-color:var(--border-strong);padding:20px 22px;gap:6px}.sh-kpi--hero .sh-kpi__label{font-size:11px;color:var(--text)}.sh-kpi--hero .sh-kpi__value{font-size:2.75rem;line-height:1.05}.sh-kpi--hero .sh-kpi__foot{font-size:12px;margin-top:4px}.sh-kpi__info{display:inline-flex;align-items:center;margin-left:6px;color:var(--text-dim);cursor:help;vertical-align:middle}.sh-kpi__info:hover{color:var(--text)}.sh-kpi--warn{border-color:rgb(var(--rgb-amber) / .3)}.sh-kpi--critical{border-color:rgb(var(--rgb-red) / .35)}.sh-kpi__label{font-size:11px;font-weight:600;color:var(--text-dim)}.sh-kpi__value{font-size:1.75rem;font-weight:700;line-height:1.1;color:var(--text);font-family:Outfit,sans-serif}.sh-kpi__foot{display:flex;align-items:center;justify-content:space-between;gap:8px;font-size:11px;color:var(--text-muted);margin-top:2px}.sh-kpi__sub{color:var(--text-dim)}.sh-kpi__delta--with-icon{display:inline-flex;align-items:center;gap:4px}.sh-delta{display:inline-flex;align-items:center;gap:3px;padding:1px 6px;border-radius:4px;font-size:10px;font-weight:600;border:1px solid transparent}.sh-delta.good{background:rgb(var(--rgb-success) / .1);border-color:rgb(var(--rgb-success) / .3);color:var(--color-success)}.sh-delta.bad{background:rgb(var(--rgb-red) / .1);border-color:rgb(var(--rgb-red) / .3);color:var(--red, var(--red))}.sh-delta.neutral{background:rgb(var(--rgb-fg) / .04);border-color:var(--border);color:var(--text-dim)}.sh-filter-bar{display:flex;flex-wrap:wrap;align-items:center;gap:14px 18px;padding:10px 14px;border-radius:var(--radius-md);background:var(--surface);border:1px solid var(--border-strong);position:sticky;top:0;z-index:5;-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);background-color:color-mix(in srgb,var(--surface) 92%,transparent)}.sh-filter-bar__lead{font-size:11px;font-weight:700;color:var(--text-muted);margin-right:6px}.sh-filter-bar__group{display:flex;align-items:center;gap:8px}.sh-filter-bar__label{font-size:11px;font-weight:700;color:var(--text-dim)}.sh-select{background:var(--bg);border:1px solid var(--border);border-radius:var(--radius-sm);color:var(--text);font-family:JetBrains Mono,monospace;font-size:11.5px;padding:4px 26px 4px 10px;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 8px center;cursor:pointer;transition:border-color .15s ease}.sh-select:hover{border-color:var(--border-strong)}.sh-select:focus{outline:none;border-color:var(--color-accent)}.sh-filter-bar__clear{display:inline-flex;align-items:center;gap:4px;background:transparent;border:1px dashed var(--border-strong);color:var(--text-dim);font-size:11px;padding:4px 10px;border-radius:var(--radius-sm);cursor:pointer;transition:all .15s ease}.sh-filter-bar__clear:hover{color:var(--text);border-color:var(--text-dim)}.sh-refresh-btn,.sh-back-btn{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;border-radius:var(--radius-sm);font-size:12px;font-weight:500;background:var(--surface);border:1px solid var(--border-strong);color:var(--text);cursor:pointer;transition:all .15s ease}.sh-refresh-btn:hover,.sh-back-btn:hover{background:var(--surface-2);border-color:var(--color-accent);color:var(--color-accent)}.sh-refresh-btn:disabled{opacity:.6;cursor:not-allowed}.sh-ghost-btn{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;background:transparent;border:1px solid var(--border-strong);color:var(--text-muted);border-radius:var(--radius-sm);cursor:pointer;transition:color .15s ease,border-color .15s ease,background .15s ease}.sh-ghost-btn:hover:not(:disabled){color:var(--text);border-color:var(--text-dim);background:var(--surface-2)}.sh-ghost-btn:disabled{opacity:.5;cursor:not-allowed}.sh-empty{display:flex;align-items:center;justify-content:center;gap:10px;padding:32px 24px;color:var(--text-dim);font-size:12px;border-radius:var(--radius-md);background:var(--surface);border:1px dashed var(--border)}.sh-empty-actions{display:inline-flex;gap:8px;flex-wrap:wrap;justify-content:center}.sh-ghost-btn--inline{width:auto;height:auto;padding:6px 10px;gap:6px;font-size:12px;text-decoration:none}.sh-empty--clean{flex-direction:row;gap:14px;text-align:left;color:var(--text)}.sh-empty__title{font-size:13px;font-weight:600;color:var(--text)}.sh-empty__subtitle{font-size:11.5px;color:var(--text-muted);margin-top:2px}.sh-table{display:flex;flex-direction:column;border-radius:var(--radius-md);background:var(--surface);border:1px solid var(--border);overflow:hidden}.sh-table__head,.sh-table__row{display:grid;grid-template-columns:36px minmax(0,2fr) 70px 80px 100px 80px 90px minmax(0,2fr) max-content;gap:12px;align-items:center;padding:10px 14px}.sh-table__head{background:var(--surface-2);border-bottom:1px solid var(--border)}.sh-th{font-size:11px;font-weight:700;color:var(--text-dim)}.sh-th--rank,.sh-th--count{text-align:center}.sh-th--meta{text-align:left}.sh-table__row{border-bottom:1px solid var(--border);cursor:pointer;transition:background .15s ease}.sh-table__row:last-child{border-bottom:none}.sh-table__row:hover{background:var(--surface-2)}.sh-table__row:focus-visible{outline:2px solid var(--color-accent);outline-offset:-2px}.sh-td{font-size:12px;color:var(--text);min-width:0}.sh-td--rank{text-align:center;font-family:JetBrains Mono,monospace;color:var(--text-dim);font-weight:700}.sh-td--selector code,.sh-td--rewrite code{font-family:JetBrains Mono,monospace;font-size:11.5px;display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text)}.sh-td--count{text-align:center}.sh-td--meta{font-size:11.5px;color:var(--text-muted);font-family:JetBrains Mono,monospace}.sh-td--rewrite{display:flex;align-items:center;gap:6px;min-width:0}.sh-td--actions{display:flex;gap:4px;justify-content:flex-end}.sh-rewrite-share{font-size:9.5px;font-weight:700;color:var(--color-accent);background:rgb(var(--rgb-accent) / .12);padding:1px 5px;border-radius:3px;white-space:nowrap;flex-shrink:0}.sh-rewrite-value{flex:1;min-width:0}.sh-rewrite-empty{color:var(--text-dim);font-family:JetBrains Mono,monospace;font-size:11px}.sh-count-badge{display:inline-flex;align-items:center;gap:3px;padding:2px 8px;border-radius:10px;font-size:11px;font-weight:700;border:1px solid transparent}.sh-count-badge.severe{background:rgb(var(--rgb-red) / .12);border-color:rgb(var(--rgb-red) / .4);color:var(--red, var(--red))}.sh-count-badge.warn{background:rgb(var(--rgb-amber) / .12);border-color:rgb(var(--rgb-amber) / .4);color:var(--amber, var(--amber))}.sh-count-badge.mild{background:rgb(var(--rgb-fg) / .04);border-color:var(--border);color:var(--text-muted)}.sh-tier-pill{display:inline-block;padding:1px 8px;border-radius:10px;font-size:10px;font-weight:600;letter-spacing:.04em;background:rgb(var(--rgb-accent) / .06);border:1px solid rgb(var(--rgb-accent) / .25);color:var(--color-accent);white-space:nowrap}.sh-platform-pill,.sh-build-pill{display:inline-block;padding:1px 8px;border-radius:10px;font-size:10px;font-weight:600;background:var(--surface-2);border:1px solid var(--border);color:var(--text-muted);font-family:JetBrains Mono,monospace}.sh-icon-btn{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:4px;background:transparent;border:1px solid var(--border);color:var(--text-dim);cursor:pointer;transition:all .15s ease}.sh-icon-btn:hover{background:var(--surface-2);color:var(--text);border-color:var(--border-strong)}.sh-icon-btn.copied{background:var(--color-accent);border-color:var(--color-accent);color:var(--color-on-accent)}.sh-detail-title code{font-family:JetBrains Mono,monospace;font-size:.95rem;color:var(--text);display:inline-block;max-width:60ch;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom}.sh-detail-stats{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}@media (min-width: 768px){.sh-detail-stats{grid-template-columns:repeat(4,minmax(0,1fr))}}.sh-detail-stat{display:flex;flex-direction:column;gap:2px;padding:12px 14px;border-radius:var(--radius-md);background:var(--surface);border:1px solid var(--border)}.sh-detail-stat__label{font-size:11px;font-weight:600;color:var(--text-dim)}.sh-detail-stat__value{font-size:1.4rem;font-weight:700;color:var(--text);font-family:Outfit,sans-serif}.sh-detail-grid{display:grid;grid-template-columns:1fr;gap:14px}@media (min-width: 1024px){.sh-detail-grid{grid-template-columns:1.4fr 1fr}}.sh-card{border-radius:var(--radius-md);background:var(--surface);border:1px solid var(--border);overflow:hidden}.sh-card__head{display:flex;align-items:center;gap:6px;padding:10px 14px;border-bottom:1px solid var(--border);background:var(--surface-2);font-size:11px;font-weight:700;color:var(--text)}.sh-card__hint{margin-left:auto;font-weight:500;letter-spacing:.04em;text-transform:none;color:var(--text-dim);font-size:10.5px}.sh-alternates{list-style:none;margin:0;padding:8px;display:flex;flex-direction:column;gap:6px}.sh-alternates__empty{padding:12px;font-size:11.5px;color:var(--text-dim)}.sh-alternate{display:flex;flex-direction:column;gap:4px;padding:10px;border-radius:var(--radius-sm);background:rgb(var(--rgb-well) / calc(.25 * var(--well-k)));border:1px solid var(--border)}.sh-alternate__top{display:flex;align-items:center;gap:8px;min-width:0}.sh-alternate__share{font-family:JetBrains Mono,monospace;font-size:11px;font-weight:700;color:var(--color-accent);background:rgb(var(--rgb-accent) / .1);padding:1px 6px;border-radius:4px;flex-shrink:0}.sh-alternate__value{flex:1;min-width:0;font-family:JetBrains Mono,monospace;font-size:11.5px;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sh-alternate__meta{display:flex;flex-wrap:wrap;gap:4px 6px;font-size:10.5px;color:var(--text-dim);font-family:JetBrains Mono,monospace}.sh-breakdown{display:flex;flex-direction:column;gap:12px;padding:14px}.sh-breakdown__group{display:flex;flex-direction:column;gap:4px}.sh-breakdown__label{font-size:11px;font-weight:600;color:var(--text-dim);margin-bottom:4px}.sh-breakdown__row{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:4px 0}.sh-breakdown__count{font-family:JetBrains Mono,monospace;font-size:11.5px;color:var(--text-muted)}.sh-breakdown__empty{font-size:11px;color:var(--text-dim)}.sh-timeline{display:flex;flex-direction:column;padding:4px 8px}.sh-timeline__row{display:grid;grid-template-columns:70px auto 110px 130px minmax(180px,1fr) 50px 22px;gap:10px;align-items:center;padding:8px 6px;border-bottom:1px solid var(--border);font-size:11.5px}.sh-timeline__row:last-child{border-bottom:none}.sh-timeline__when{font-family:JetBrains Mono,monospace;font-size:10.5px;color:var(--text-dim)}.sh-timeline__cmd,.sh-timeline__device{font-family:JetBrains Mono,monospace;color:var(--text-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sh-timeline__healed{font-family:JetBrains Mono,monospace;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sh-timeline__conf{font-family:JetBrains Mono,monospace;color:var(--color-accent);font-size:11px;text-align:right}.sh-timeline__link{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:4px;background:transparent;border:1px solid var(--border);color:var(--text-dim);text-decoration:none;transition:all .15s ease}.sh-timeline__link:hover{color:var(--color-accent);border-color:var(--color-accent)}@media (max-width: 1024px){.sh-table__head,.sh-table__row{grid-template-columns:28px minmax(180px,1fr) 60px 60px 90px;grid-template-areas:"rank selector selector selector selector" "rank count sessions tier last" "rank rewrite rewrite rewrite actions"}.sh-th--meta:nth-of-type(4),.sh-th--actions{display:none}}.sh-tab-nav{display:flex;gap:var(--space-2);border-bottom:1px solid var(--border);margin:var(--space-4) 0 var(--space-5)}.sh-tab{background:transparent;border:0;padding:var(--space-3) var(--space-4);cursor:pointer;color:var(--text-muted);display:inline-flex;gap:var(--space-2);align-items:center;border-bottom:2px solid transparent;margin-bottom:-1px;font-size:.9rem;transition:color .15s ease,border-color .15s ease}.sh-tab:hover{color:var(--text)}.sh-tab--active{color:var(--text);border-bottom-color:var(--color-highlight);border-bottom-width:3px}.sh-tab__icon{font-size:.95rem;line-height:1}.sh-tab__count{background:var(--surface);border:1px solid var(--border);border-radius:999px;padding:0 .5rem;font-size:.75rem;min-width:1.5rem;text-align:center}.sh-strategy-badge{display:inline-flex;align-items:center;background:var(--surface);border:1px solid var(--border);color:var(--text-dim);border-radius:4px;padding:.05rem .4rem;font-size:.7rem;font-weight:500;text-transform:none;margin-right:.4rem;white-space:nowrap}.sh-strategy-badge--rewrite{color:var(--text)}.sh-action-btn{background:transparent;border:1px solid var(--border);color:var(--text-dim);border-radius:4px;padding:.25rem .55rem;font-size:.72rem;cursor:pointer;white-space:nowrap;transition:color .12s ease,border-color .12s ease,background .12s ease;margin-right:.3rem}.sh-action-btn:hover{color:var(--text);border-color:var(--text-dim)}.sh-action-btn--primary{color:var(--color-highlight);border-color:var(--color-highlight)}.sh-action-btn--primary:hover{background:var(--color-highlight);color:#fff}.sh-copy-group{display:inline-flex;align-items:stretch;margin-right:.3rem}.sh-copy-btn{display:inline-flex;align-items:center;gap:.25rem;border-top-right-radius:0;border-bottom-right-radius:0;margin-right:0;border-right-width:0}.sh-copy-btn__lang{font-size:.68rem;font-weight:500;letter-spacing:.02em}.sh-copy-btn--copied{color:var(--green, var(--color-accent-soft));border-color:var(--green, var(--color-accent-soft))}.sh-copy-chevron{border-top-left-radius:0;border-bottom-left-radius:0;padding:.25rem .35rem;margin-right:0}.sh-copy-modal__hint{color:var(--text-muted);margin:0 0 1rem;font-size:.85rem}.sh-copy-modal__lang-list{list-style:none;padding:0;margin:0 0 1rem}.sh-copy-modal__lang-row{display:flex;align-items:center;gap:.55rem;padding:.4rem 0;cursor:pointer;font-size:.9rem}.sh-copy-modal__preview-label{font-size:.72rem;color:var(--text-muted);margin-bottom:.3rem}.sh-copy-modal__preview{background:var(--bg, #0a0a0a);border:1px solid var(--border);padding:.6rem .8rem;border-radius:4px;font-size:.78rem;overflow-x:auto;margin:0 0 1rem;white-space:pre-wrap;word-break:break-all}.sh-copy-modal__remember{display:flex;gap:.45rem;align-items:center;font-size:.85rem;color:var(--text-dim);cursor:pointer}.sh-pending-list{display:flex;flex-direction:column;gap:var(--space-3)}.sh-table__row--pending{display:block;padding:var(--space-4);cursor:pointer}.sh-pending-row__head{display:flex;align-items:center;gap:var(--space-2)}.sh-pending-row__icon{color:var(--color-highlight)}.sh-pending-row__selector{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sh-pending-row__meta{font-size:.8rem;color:var(--text-muted);margin:.4rem 0 .6rem}.sh-pending-progress{background:var(--surface);border:1px solid var(--border);border-radius:4px;padding:var(--space-3);margin-bottom:var(--space-3)}.sh-pending-progress__dots{display:flex;gap:.6rem;margin-bottom:.4rem}.sh-pending-progress__dot{width:14px;height:14px;border-radius:999px;border:2px solid var(--color-highlight);background:transparent}.sh-pending-progress__dot--filled{background:var(--color-highlight)}.sh-pending-progress__legend{font-size:.85rem;color:var(--text)}.sh-pending-progress__hint{font-size:.75rem;color:var(--text-muted);margin-top:.3rem}.sh-pending-row__actions{display:flex;gap:var(--space-2)}.sh-table__row--resolved{display:block;padding:var(--space-4);cursor:pointer}.sh-resolved-row__head{display:flex;align-items:center;gap:var(--space-2);flex-wrap:wrap}.sh-resolved-row__icon{color:var(--green, var(--color-success-soft))}.sh-resolved-row__selector{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sh-resolved-row__regression{display:inline-flex;align-items:center;gap:.25rem;background:#f1c40f1f;color:#f1c40f;padding:.1rem .5rem;border-radius:999px;font-size:.72rem}.sh-resolved-row__meta{font-size:.85rem;color:var(--text);margin:.4rem 0 .2rem}.sh-resolved-row__history{font-size:.78rem;color:var(--text-muted);margin-bottom:var(--space-3)}.sh-resolved-row__actions{display:flex;gap:var(--space-2)}.sh-muted-list{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:var(--space-2)}.sh-muted-list__item{background:var(--surface);border:1px solid var(--border);border-radius:4px;padding:var(--space-3) var(--space-4)}.sh-muted-list__head{display:flex;align-items:center;gap:var(--space-2)}.sh-muted-list__icon{color:var(--text-muted)}.sh-muted-list__selector{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sh-muted-list__meta{font-size:.78rem;color:var(--text-muted);margin:.4rem 0 .6rem}.sh-muted-list__actions{display:flex;gap:var(--space-2)}.sh-regression-banner{display:flex;align-items:center;gap:var(--space-3);padding:var(--space-3) var(--space-4);background:#e74c3c14;border-left:4px solid var(--red-flat);border-radius:4px;margin-bottom:var(--space-4);font-size:.88rem;color:var(--text)}.sh-regression-banner__icon{color:var(--red-flat);flex-shrink:0}.sh-regression-banner__action{margin-left:auto;background:transparent;border:1px solid var(--red-flat);color:var(--red-flat);padding:.2rem .55rem;border-radius:4px;font-size:.76rem;cursor:pointer;white-space:nowrap}.sh-regression-banner__action:hover{background:#e74c3c26}.sh-regression-banner__close{background:transparent;border:0;color:var(--text-muted);cursor:pointer;padding:.15rem;display:inline-flex;align-items:center}.sh-regression-banner__close:hover{color:var(--text)}.sh-detail-strategy-line{display:flex;align-items:center;gap:var(--space-2);margin-bottom:var(--space-3);font-size:.9rem}.sh-detail-banner{background:rgb(var(--rgb-blue-400) / .06);border-left:3px solid var(--color-highlight);padding:var(--space-3) var(--space-4);border-radius:4px;margin-bottom:var(--space-3);font-size:.85rem;color:var(--text-dim)}.sh-detail-state{background:var(--surface);border:1px solid var(--border);border-radius:6px;padding:var(--space-4);margin-bottom:var(--space-4)}.sh-detail-state--pending{border-left:4px solid var(--color-highlight)}.sh-detail-state--resolved{border-left:4px solid var(--green, var(--color-success-soft))}.sh-detail-state--muted{border-left:4px solid var(--text-muted);opacity:.85}.sh-detail-state--active{border-left:4px solid var(--red-flat)}.sh-detail-state__head{display:flex;align-items:center;justify-content:space-between;gap:var(--space-3);flex-wrap:wrap}.sh-detail-state__badge{font-size:1rem;font-weight:500;display:inline-flex;align-items:center;gap:.5rem}.sh-detail-state__actions{display:flex;gap:var(--space-2)}.sh-detail-state__meta{margin-top:var(--space-3);display:flex;gap:var(--space-4);flex-wrap:wrap;font-size:.8rem;color:var(--text-muted)}:root[data-theme=light] .sh-resolved-row__regression{color:var(--amber)}
@@ -1,16 +0,0 @@
1
- import{c as e}from"./index-CzaIyL9t.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 t=[["path",{d:"M15 3h6v6",key:"1q9fwt"}],["path",{d:"M10 14 21 3",key:"gplh6r"}],["path",{d:"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6",key:"a6xqqp"}]],c=e("external-link",t);/**
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 o=[["path",{d:"M5 22h14",key:"ehvnwv"}],["path",{d:"M5 2h14",key:"pdyrp9"}],["path",{d:"M17 22v-4.172a2 2 0 0 0-.586-1.414L12 12l-4.414 4.414A2 2 0 0 0 7 17.828V22",key:"1d314k"}],["path",{d:"M7 2v4.172a2 2 0 0 0 .586 1.414L12 12l4.414-4.414A2 2 0 0 0 17 6.172V2",key:"1vvvr6"}]],r=e("hourglass",o);/**
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 i=[["path",{d:"M11 4.702a.705.705 0 0 0-1.203-.498L6.413 7.587A1.4 1.4 0 0 1 5.416 8H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2.416a1.4 1.4 0 0 1 .997.413l3.383 3.384A.705.705 0 0 0 11 19.298z",key:"uqj9uw"}],["line",{x1:"22",x2:"16",y1:"9",y2:"15",key:"1ewh16"}],["line",{x1:"16",x2:"22",y1:"9",y2:"15",key:"5ykzw1"}]],d=e("volume-x",i),n={"accessibility id":"Accessibility ID",xpath:"XPath",id:"ID",name:"Name","class name":"Class Name","-android uiautomator":"UiAutomator","-ios predicate string":"iOS Predicate","-ios class chain":"iOS Class Chain","xenon:visual":"Visual AI (coords)"};function h(a){return a?n[a]??a:"(unknown strategy)"}export{c as E,r as H,d as V,h as f};
@@ -1,16 +0,0 @@
1
- import{c as z,u as H,E as Y,j as e,r as h,w as le,v as P,C as re,X as k,A,p as Z,t as oe,K as W,y as ce,I as de}from"./index-CzaIyL9t.js";import{Z as he}from"./zap-BOpUur0M.js";import{H as B,V as R,f as w,E as ue}from"./selector-health-CHLX8KqY.js";import{C as Q}from"./circle-check-DnQ263fa.js";import{M as me}from"./Modal-DNmn2RDs.js";import{C as pe}from"./check-DYSXRG79.js";import{C as ge}from"./copy-D8d9UzWE.js";import{b as N}from"./time-B8FIgwPE.js";import{E as ve}from"./EmptyState-D3fG2GHY.js";import{P as be}from"./page-header-ZdzNEJp9.js";import{a as xe}from"./SegmentedControl-BdA_mHiZ.js";import{p as fe}from"./labels-C21SA4JG.js";import{F as G}from"./funnel-OefHE-54.js";import{C as _e}from"./chevron-right-hCNu0CA-.js";import{A as J}from"./arrow-up-right-e7yBOb-c.js";import"./index-IefGCFQQ.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 je=[["path",{d:"m7 7 10 10",key:"1fmybs"}],["path",{d:"M17 7v10H7",key:"6fjiku"}]],ye=z("arrow-down-right",je);/**
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 Ne=[["path",{d:"M5 12h14",key:"1ays0h"}]],q=z("minus",Ne);/**
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 we=[["path",{d:"M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11z",key:"1ffxy3"}],["path",{d:"m21.854 2.147-10.94 10.939",key:"12cjpa"}]],Se=z("send",we),Ce=[{id:"active",label:"Active",icon:he},{id:"pending",label:"Pending",icon:B,color:"var(--color-highlight)"},{id:"resolved",label:"Resolved",icon:Q,color:"var(--color-success)"},{id:"muted",label:"Muted",icon:R,color:"var(--text-muted)"}];function $e({current:s,counts:r={}}){const i=H(),[a]=Y(),n=l=>{const c=new URLSearchParams(a);c.set("tab",l),i({search:c.toString()})};return e.jsx("nav",{className:"sh-tab-nav",role:"tablist","aria-label":"Selector health tabs",children:Ce.map(l=>{const c=r[l.id],o=l.icon;return e.jsxs("button",{type:"button",role:"tab","aria-selected":s===l.id,onClick:()=>n(l.id),className:`sh-tab ${s===l.id?"sh-tab--active":""}`,children:[e.jsx("span",{className:"sh-tab__icon","aria-hidden":"true",style:l.color?{color:l.color}:void 0,children:e.jsx(o,{size:14})}),e.jsx("span",{className:"sh-tab__label",children:l.label}),typeof c=="number"&&e.jsx("span",{className:"sh-tab__count","aria-label":`${c} ${l.label}`,children:c})]},l.id)})})}const ke={javascript:{"accessibility id":s=>`await driver.findElement('accessibility id', '${s}')`,xpath:s=>`await driver.findElement('xpath', '${s}')`,id:s=>`await driver.findElement('id', '${s}')`,name:s=>`await driver.findElement('name', '${s}')`,"class name":s=>`await driver.findElement('class name', '${s}')`,"-android uiautomator":s=>`await driver.findElement('-android uiautomator', '${s}')`,"-ios predicate string":s=>`await driver.findElement('-ios predicate string', '${s}')`,"-ios class chain":s=>`await driver.findElement('-ios class chain', '${s}')`},java:{"accessibility id":s=>`driver.findElement(AppiumBy.accessibilityId("${s}"))`,xpath:s=>`driver.findElement(AppiumBy.xpath("${s}"))`,id:s=>`driver.findElement(AppiumBy.id("${s}"))`,name:s=>`driver.findElement(AppiumBy.name("${s}"))`,"class name":s=>`driver.findElement(AppiumBy.className("${s}"))`,"-android uiautomator":s=>`driver.findElement(AppiumBy.androidUIAutomator("${s}"))`,"-ios predicate string":s=>`driver.findElement(AppiumBy.iOSNsPredicateString("${s}"))`,"-ios class chain":s=>`driver.findElement(AppiumBy.iOSClassChain("${s}"))`},python:{"accessibility id":s=>`driver.find_element(AppiumBy.ACCESSIBILITY_ID, '${s}')`,xpath:s=>`driver.find_element(AppiumBy.XPATH, '${s}')`,id:s=>`driver.find_element(AppiumBy.ID, '${s}')`,name:s=>`driver.find_element(AppiumBy.NAME, '${s}')`,"class name":s=>`driver.find_element(AppiumBy.CLASS_NAME, '${s}')`,"-android uiautomator":s=>`driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, '${s}')`,"-ios predicate string":s=>`driver.find_element(AppiumBy.IOS_PREDICATE, '${s}')`,"-ios class chain":s=>`driver.find_element(AppiumBy.IOS_CLASS_CHAIN, '${s}')`},csharp:{"accessibility id":s=>`driver.FindElement(MobileBy.AccessibilityId("${s}"))`,xpath:s=>`driver.FindElement(By.XPath("${s}"))`,id:s=>`driver.FindElement(By.Id("${s}"))`,name:s=>`driver.FindElement(By.Name("${s}"))`,"class name":s=>`driver.FindElement(By.ClassName("${s}"))`},ruby:{"accessibility id":s=>`driver.find_element(:accessibility_id, '${s}')`,xpath:s=>`driver.find_element(:xpath, '${s}')`,id:s=>`driver.find_element(:id, '${s}')`,name:s=>`driver.find_element(:name, '${s}')`,"class name":s=>`driver.find_element(:class_name, '${s}')`}};function Ae(s,r){const i=s==="java"||s==="csharp",a=r.replace(/\\/g,"\\\\");return i?a.replace(/"/g,'\\"'):a.replace(/'/g,"\\'")}function ee(s,r,i){var n;if(r==="xenon:visual")return"/* Visual AI (coordinates) — no portable Appium snippet. Use snapshot view to find a stable native locator. */";const a=(n=ke[s])==null?void 0:n[r];return a?a(Ae(s,i)):`${(r??"").toString().toUpperCase()}: ${i}`}const O=[{value:"javascript",short:"JS",label:"JavaScript (WebdriverIO)"},{value:"java",short:"Java",label:"Java (Appium-Java)"},{value:"python",short:"Py",label:"Python (Appium-Python)"},{value:"csharp",short:"C#",label:"C# (.NET)"},{value:"ruby",short:"Rb",label:"Ruby"}],se="xenon.copyLang";function Me(){try{const s=localStorage.getItem(se);return s&&O.find(r=>r.value===s)?s:null}catch{return null}}function Ee(s){try{localStorage.setItem(se,s)}catch{}}function D(s){var r;return((r=O.find(i=>i.value===s))==null?void 0:r.short)??s}function Ie({open:s,initialLang:r,strategy:i,value:a,onCopy:n,onClose:l}){const[c,o]=h.useState(r??"javascript"),[d,g]=h.useState(!0),x=ee(c,i,a),m=async()=>{try{await navigator.clipboard.writeText(x)}catch{}d&&Ee(c),n(c,x),l()};return e.jsxs(me,{open:s,onClose:l,title:"Choose your default copy language",width:520,footer:e.jsxs(e.Fragment,{children:[e.jsx("button",{type:"button",className:"sh-action-btn",onClick:l,children:"Cancel"}),e.jsxs("button",{type:"button",className:"sh-action-btn sh-action-btn--primary",onClick:m,children:["Copy as ",D(c)]})]}),children:[e.jsx("p",{className:"sh-copy-modal__hint",children:"Snippets will be copied in this language until you change it."}),e.jsx("ul",{className:"sh-copy-modal__lang-list",children:O.map(f=>e.jsx("li",{children:e.jsxs("label",{className:"sh-copy-modal__lang-row",children:[e.jsx("input",{type:"radio",name:"copy-lang",value:f.value,checked:c===f.value,onChange:()=>o(f.value)}),f.label]})},f.value))}),e.jsx("div",{className:"sh-copy-modal__preview-label",children:"Preview"}),e.jsx("pre",{className:"sh-copy-modal__preview",children:e.jsx("code",{children:x})}),e.jsxs("label",{className:"sh-copy-modal__remember",children:[e.jsx("input",{type:"checkbox",checked:d,onChange:f=>g(f.target.checked)}),"Remember my choice"]})]})}function Te({hotspot:s,onCopied:r}){const[i,a]=h.useState(!1),[n,l]=h.useState(!1),c=Me(),o=s.suggestedStrategy??s.originalStrategy??"",d=s.suggestedRewrite??"",g=o==="xenon:visual",x=async()=>{if(!c){a(!0);return}const m=ee(c,o,d);try{await navigator.clipboard.writeText(m)}catch{}l(!0),r(c),setTimeout(()=>l(!1),1500)};return e.jsxs("span",{className:"sh-copy-group",children:[e.jsxs("button",{type:"button",className:`sh-action-btn sh-copy-btn ${n?"sh-copy-btn--copied":""}`,onClick:m=>{m.stopPropagation(),x()},disabled:g&&!d,title:g?"Visual AI heals are coordinate-based — no portable Appium snippet":c?`Copy as ${D(c)}`:"Pick a language and copy",children:[n?e.jsx(pe,{size:11}):e.jsx(ge,{size:11}),c&&!n&&e.jsx("span",{className:"sh-copy-btn__lang",children:D(c)})]}),e.jsx("button",{type:"button",className:"sh-action-btn sh-copy-chevron",onClick:m=>{m.stopPropagation(),a(!0)},title:"Choose copy language","aria-label":"Choose copy language",children:e.jsx(le,{size:11})}),e.jsx(Ie,{open:i,initialLang:c??void 0,strategy:o,value:d,onCopy:m=>{l(!0),r(m),setTimeout(()=>l(!1),1500)},onClose:()=>a(!1)})]})}function Le({hotspot:s,onCancel:r,onMute:i,onOpen:a}){const n=s.state??null,l=(n==null?void 0:n.clean_builds_count)??0,c=(n==null?void 0:n.fixed_at)??null,o=(n==null?void 0:n.fixed_by_api_key)??null;return e.jsx("div",{className:"sh-table__row sh-table__row--pending",role:"button",tabIndex:0,onClick:()=>a(s.originalSelector),onKeyDown:d=>{(d.key==="Enter"||d.key===" ")&&(d.preventDefault(),a(s.originalSelector))},children:e.jsxs("div",{className:"sh-pending-row",children:[e.jsxs("div",{className:"sh-pending-row__head",children:[e.jsx(B,{size:14,className:"sh-pending-row__icon"}),e.jsx("span",{className:"sh-strategy-badge",children:w(s.originalStrategy)}),e.jsx("code",{className:"sh-pending-row__selector",title:s.originalSelector,children:s.originalSelector})]}),e.jsxs("div",{className:"sh-pending-row__meta",children:["Marked fixed ",N(c),o?` by ${o}`:""," • verifying…"]}),e.jsxs("div",{className:"sh-pending-progress",children:[e.jsx("div",{className:"sh-pending-progress__dots","aria-label":`${l} of 3 clean builds`,children:[0,1,2].map(d=>e.jsx("span",{className:`sh-pending-progress__dot ${d<l?"sh-pending-progress__dot--filled":""}`},d))}),e.jsxs("div",{className:"sh-pending-progress__legend",children:[l," of 3 clean CI builds since fix"]}),e.jsx("div",{className:"sh-pending-progress__hint",children:"Only sessions with a build_id count toward verification — local runs do not."})]}),e.jsxs("div",{className:"sh-pending-row__actions",children:[e.jsxs("button",{type:"button",className:"sh-action-btn",onClick:d=>{d.stopPropagation(),r(s)},title:"Revert to Active without waiting for verification",children:[e.jsx(P,{size:11})," Cancel verification"]}),e.jsx("button",{type:"button",className:"sh-action-btn",onClick:d=>{d.stopPropagation(),i(s)},title:"Mute this selector instead of verifying it",children:"Mute"})]})]})})}function Pe({hotspot:s,onMute:r,onOpen:i}){const a=s.state??null,n=(a==null?void 0:a.fixed_at)??null,l=(a==null?void 0:a.resolved_at)??null,c=(a==null?void 0:a.clean_builds_count)??0,o=(a==null?void 0:a.regression_count)??0;return e.jsx("div",{className:"sh-table__row sh-table__row--resolved",role:"button",tabIndex:0,onClick:()=>i(s.originalSelector),onKeyDown:d=>{(d.key==="Enter"||d.key===" ")&&(d.preventDefault(),i(s.originalSelector))},children:e.jsxs("div",{className:"sh-resolved-row",children:[e.jsxs("div",{className:"sh-resolved-row__head",children:[e.jsx(Q,{size:14,className:"sh-resolved-row__icon"}),e.jsx("span",{className:"sh-strategy-badge",children:w(s.originalStrategy)}),e.jsx("code",{className:"sh-resolved-row__selector",title:s.originalSelector,children:s.originalSelector}),o>0&&e.jsxs("span",{className:"sh-resolved-row__regression",title:"This selector regressed at least once before being resolved again",children:[e.jsx(re,{size:11})," Previously regressed ",o,"×"]})]}),e.jsxs("div",{className:"sh-resolved-row__meta",children:["Resolved ",N(l)," • ",c," clean build",c===1?"":"s"," since fix"]}),e.jsxs("div",{className:"sh-resolved-row__history",children:["Marked fixed ",N(n)," • Verified ",N(l)]}),e.jsx("div",{className:"sh-resolved-row__actions",children:e.jsx("button",{type:"button",className:"sh-action-btn",onClick:d=>{d.stopPropagation(),r(s)},title:"Hide this selector entirely (e.g. if it regresses again later)",children:"Mute"})})]})})}function Re({onUnmute:s}){const[r,i]=h.useState(null),[a,n]=h.useState(!0),l=h.useCallback(async()=>{n(!0);try{const o=await k.getMutedSelectors({limit:200});i(o??null)}catch{i({muted:[],total:0,limit:200,offset:0})}finally{n(!1)}},[]);h.useEffect(()=>{l()},[l]);const c=async o=>{window.confirm(`Unmute "${o.original_selector}"?`)&&(await s(o.original_strategy,o.original_selector),l())};return a?e.jsxs("div",{className:"sh-empty",children:[e.jsx(A,{size:18,className:"animate-spin"}),e.jsx("span",{children:"Loading muted selectors…"})]}):!r||r.muted.length===0?e.jsxs("div",{className:"sh-empty sh-empty--clean",children:[e.jsx(R,{size:28}),e.jsxs("div",{children:[e.jsx("div",{className:"sh-empty__title",children:"Nothing muted"}),e.jsx("div",{className:"sh-empty__subtitle",children:"Selectors silenced from Hotspots, the CI gate, and digests will appear here."})]})]}):e.jsx("ul",{className:"sh-muted-list",children:r.muted.map(o=>e.jsxs("li",{className:"sh-muted-list__item",children:[e.jsxs("div",{className:"sh-muted-list__head",children:[e.jsx(R,{size:13,className:"sh-muted-list__icon"}),e.jsx("span",{className:"sh-strategy-badge",children:w(o.original_strategy)}),e.jsx("code",{className:"sh-muted-list__selector",title:o.original_selector,children:o.original_selector})]}),e.jsxs("div",{className:"sh-muted-list__meta",children:["Muted ",N(o.muted_at),o.muted_by_api_key?` by ${o.muted_by_api_key}`:"",o.last_healed_at?` • Last healed ${N(o.last_healed_at)}`:" • Never healed (pre-emptively muted)",o.regression_count>0?` • ${o.regression_count} regression${o.regression_count===1?"":"s"} on record`:""]}),e.jsx("div",{className:"sh-muted-list__actions",children:e.jsx("button",{type:"button",className:"sh-action-btn",onClick:()=>c(o),children:"Unmute"})})]},`${o.original_strategy}:${o.original_selector}`))})}const De=3e4,ze=5*6e4;function He(){const{on:s}=Z(),r=H(),[i,a]=h.useState([]);if(h.useEffect(()=>{const c=s("selector_regressed",o=>{a(d=>{const g=Date.now()-ze;return[...d.filter(m=>m.receivedAt>=g),{original_strategy:(o==null?void 0:o.original_strategy)??"",original_selector:(o==null?void 0:o.original_selector)??"",resolved_at:(o==null?void 0:o.resolved_at)??null,regression_count:o==null?void 0:o.regression_count,receivedAt:Date.now()}]})});return()=>{c&&c()}},[s]),h.useEffect(()=>{if(i.length===0)return;const c=setTimeout(()=>a([]),De);return()=>clearTimeout(c)},[i]),i.length===0)return null;const n=()=>a([]),l=()=>{r("/selector-health?tab=active"),a([])};if(i.length===1){const c=i[0];return e.jsxs("div",{className:"sh-regression-banner",role:"alert",children:[e.jsx(A,{size:14,className:"sh-regression-banner__icon"}),e.jsxs("span",{children:["A previously-fixed selector regressed:"," ",e.jsxs("strong",{children:[w(c.original_strategy),": ",c.original_selector]})," ","healed again."]}),e.jsx("button",{type:"button",className:"sh-regression-banner__action",onClick:l,children:"Show in Active →"}),e.jsx("button",{type:"button",className:"sh-regression-banner__close",onClick:n,"aria-label":"Dismiss",children:e.jsx(P,{size:13})})]})}return e.jsxs("div",{className:"sh-regression-banner",role:"alert",children:[e.jsx(A,{size:14,className:"sh-regression-banner__icon"}),e.jsxs("span",{children:[e.jsxs("strong",{children:[i.length," selectors"]})," have regressed in the last 5 minutes."]}),e.jsx("button",{type:"button",className:"sh-regression-banner__action",onClick:l,children:"Show all →"}),e.jsx("button",{type:"button",className:"sh-regression-banner__close",onClick:n,"aria-label":"Dismiss",children:e.jsx(P,{size:13})})]})}const Be=[{value:7,label:"7d"},{value:30,label:"30d"},{value:90,label:"90d"}],Oe=["","LLM","Visual AI","OCR","Fuzzy XML","Resilio","Native"],Fe=["","ios","android","tvos"];function Ue(s){const r=Date.parse(s);if(!Number.isFinite(r))return"";const i=Math.max(0,Date.now()-r),a=Math.floor(i/1e3);if(a<60)return`${a}s ago`;const n=Math.floor(a/60);if(n<60)return`${n}m ago`;const l=Math.floor(n/60);return l<24?`${l}h ago`:`${Math.floor(l/24)}d ago`}function Ke(s){return s===0?"$0":s<.01?"<$0.01":s<1?`$${s.toFixed(2)}`:s<100?`$${s.toFixed(2)}`:`$${Math.round(s)}`}function Ve(s){return s>=10?"severe":s>=5?"warn":"mild"}const E=({current:s,prior:r,invertColor:i=!1})=>{if(r===0&&s===0)return e.jsxs("span",{className:"sh-delta neutral",children:[e.jsx(q,{size:11}),"no change"]});if(r===0)return e.jsxs("span",{className:`sh-delta ${i?"good":"bad"}`,children:[e.jsx(J,{size:11}),"new"]});const a=Math.round((s-r)/r*100);if(a===0)return e.jsxs("span",{className:"sh-delta neutral",children:[e.jsx(q,{size:11}),"flat"]});const n=a>0,l=i?n:!n;return e.jsxs("span",{className:`sh-delta ${l?"good":"bad"}`,children:[n?e.jsx(J,{size:11}):e.jsx(ye,{size:11}),Math.abs(a),"%"]})},y=({label:s,value:r,sub:i,delta:a,tone:n="neutral",size:l="md",hint:c})=>e.jsxs("div",{className:`sh-kpi sh-kpi--${n} sh-kpi--${l}`,children:[e.jsxs("div",{className:"sh-kpi__label",children:[s,c&&e.jsx("span",{className:"sh-kpi__info",title:c,"aria-label":c,role:"img",children:e.jsx(de,{size:11})})]}),e.jsx("div",{className:"sh-kpi__value",children:r}),(i||a)&&e.jsxs("div",{className:"sh-kpi__foot",children:[i&&e.jsx("span",{className:"sh-kpi__sub",children:i}),a&&e.jsx("span",{className:"sh-kpi__delta",children:a})]})]}),I={brittle:"Distinct selectors that needed at least one heal in the window. Lower is better.",totalHeals:"Number of times Xenon's self-heal kicked in within the selected window.",llm:"Heals that escalated all the way to an LLM. The most expensive tier — keep this small.",cost:"Estimated dollar spend on LLM heals in the window."},Xe=({summary:s,loading:r})=>{var c;const i=(s==null?void 0:s.current)??{totalHeals:0,distinctSelectors:0,sessionsTouched:0,byTier:{},estCostUsd:0},a=(s==null?void 0:s.prior)??{totalHeals:0,distinctSelectors:0,sessionsTouched:0,estCostUsd:0},n=((c=i.byTier)==null?void 0:c.LLM)??0,l=i.totalHeals>0?Math.round(n/i.totalHeals*100):0;return e.jsxs("div",{className:"sh-kpi-strip",children:[e.jsx(y,{size:"hero",label:"Brittle selectors",hint:I.brittle,value:r?"—":i.distinctSelectors.toLocaleString(),sub:"distinct selectors needing attention",delta:!r&&e.jsx(E,{current:i.distinctSelectors,prior:a.distinctSelectors}),tone:i.distinctSelectors>50?"warn":"neutral"}),e.jsx(y,{label:"Total heals",hint:I.totalHeals,value:r?"—":i.totalHeals.toLocaleString(),sub:`${(s==null?void 0:s.windowDays)??30}d window`,delta:!r&&e.jsx(E,{current:i.totalHeals,prior:a.totalHeals}),tone:i.totalHeals>a.totalHeals&&a.totalHeals>0?"warn":"neutral"}),e.jsx(y,{label:"Sessions touched",value:r?"—":i.sessionsTouched.toLocaleString(),sub:"by self-heal",delta:!r&&e.jsx(E,{current:i.sessionsTouched,prior:a.sessionsTouched})}),e.jsx(y,{label:"LLM heals",hint:I.llm,value:r?"—":n.toLocaleString(),sub:`${l}% of total`,tone:l>30?"critical":l>10?"warn":"neutral"}),e.jsx(y,{label:"Est. cost",hint:I.cost,value:r?"—":Ke(i.estCostUsd),sub:"this window",delta:!r&&e.jsx(E,{current:Math.round(i.estCostUsd*100),prior:Math.round(a.estCostUsd*100)})}),e.jsx(y,{label:"Resolved",value:r?"—":((s==null?void 0:s.resolvedCount)??0).toLocaleString(),sub:`last ${(s==null?void 0:s.windowDays)??30}d`,delta:!r&&typeof(s==null?void 0:s.pendingCount)=="number"?e.jsxs("span",{className:"sh-kpi__delta sh-kpi__delta--with-icon",children:[e.jsx(B,{size:11,style:{color:"var(--color-highlight)"}}),s.pendingCount," pending"]}):void 0,tone:"neutral"})]})},ds=()=>{const s=H(),{on:r}=Z(),{toast:i}=oe(),[a]=Y(),n=a.get("tab")??"active",[l,c]=h.useState(30),[o,d]=h.useState(""),[g,x]=h.useState(""),[m,f]=h.useState(null),[S,te]=h.useState([]),[M,F]=h.useState(!1),[U,ie]=h.useState(!1),[We,K]=h.useState(null),[T,V]=h.useState(!1),_=h.useCallback(async()=>{F(!0);try{const[t,u]=await Promise.all([k.getHealingSummary(l),k.getHealingHotspots({windowDays:l,limit:50,tier:o||void 0,platform:g||void 0,status:n})]);f(t??null),te(Array.isArray(u==null?void 0:u.hotspots)?u.hotspots:[])}catch{}finally{F(!1),ie(!0)}},[l,o,g,n]);h.useEffect(()=>{_()},[_]),h.useEffect(()=>{const u=["healing_event","selector_fixed","selector_resolved","selector_regressed","selector_cancelled","selector_muted","selector_unmuted","selector_progress"].map(v=>r(v,()=>_()));return()=>{u.forEach(v=>v&&v())}},[r,_]);const C=t=>{s(`/selector-health/detail?value=${encodeURIComponent(t)}&windowDays=${l}`)},j=h.useCallback(async(t,u)=>{const v=(()=>{switch(t){case"mark_fixed":return"Mark this selector as fixed? Xenon will move it to Pending Verification and watch for 3 clean CI builds.";case"mute":return"Mute this selector? It will be hidden from Hotspots, the CI gate, and digests until you unmute.";case"unmute":return"Unmute this selector?";case"cancel_verification":return"Cancel verification? The selector returns to Active and the clean-build counter resets."}})();if(window.confirm(v))try{await k.postSelectorStateAction({original_strategy:u.originalStrategy??"",original_selector:u.originalSelector,action:t});const p=(()=>{switch(t){case"mark_fixed":return"Marked fixed. Watching for clean builds.";case"mute":return"Muted.";case"unmute":return"Unmuted.";case"cancel_verification":return"Verification cancelled."}})();i(p,"success"),_()}catch(p){const $=p!=null&&p.currentStatus?` (currently ${p.currentStatus})`:"";i(`${(p==null?void 0:p.message)??"Action failed"}${$}`,"error")}},[_,i]),ae=async()=>{V(!0);try{const t=await k.sendHealingDigest({windowDays:l,limit:5,minHealCount:2}),u=(t==null?void 0:t.sent)??0,v=(t==null?void 0:t.hotspotsIncluded)??0;u===0?i("No webhook is subscribed to selector_health_digest yet. Add one in Notifications.","error"):i(`Digest sent to ${u} webhook${u===1?"":"s"} (${v} hotspot${v===1?"":"s"} included).`,"success")}catch{i("Failed to send digest. Check the server logs.","error")}finally{V(!1)}},L=!!o||!!g,ne=h.useMemo(()=>"Surface the selectors your suite quietly relies on auto-heal for. Rewrite the worst offenders to keep tests fast, cheap, and portable.",[]);return e.jsxs("div",{className:"selector-health-page",children:[e.jsx(be,{icon:W,eyebrow:"Test quality",title:"Selector health",subtitle:ne,action:e.jsxs(e.Fragment,{children:[e.jsx("button",{type:"button",className:"sh-ghost-btn",onClick:ae,disabled:T,title:T?"Sending digest…":"Send digest to subscribed webhooks","aria-label":"Send digest",children:e.jsx(Se,{size:14,className:T?"animate-spin":""})}),e.jsx("button",{type:"button",className:"sh-ghost-btn",onClick:_,disabled:M,title:"Refresh hotspots","aria-label":"Refresh",children:e.jsx(A,{size:14,className:M?"animate-spin":""})})]})}),e.jsxs("div",{className:"sh-content",children:[e.jsx(He,{}),e.jsx(Xe,{summary:m,loading:M&&!U}),e.jsx($e,{current:n,counts:{[n]:S.length}}),n==="muted"?e.jsx(Re,{onUnmute:async(t,u)=>{await j("unmute",{originalStrategy:t,originalSelector:u})}}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"sh-filter-bar",children:[e.jsx("span",{className:"sh-filter-bar__lead",children:"Filter results"}),e.jsxs("div",{className:"sh-filter-bar__group",children:[e.jsx("span",{className:"sh-filter-bar__label",children:"Window"}),e.jsx(xe,{size:"sm",value:String(l),onChange:t=>c(parseInt(t,10)),segments:Be.map(t=>({value:String(t.value),label:t.label}))})]}),e.jsxs("div",{className:"sh-filter-bar__group",children:[e.jsx("span",{className:"sh-filter-bar__label",children:"Tier"}),e.jsx("select",{className:"sh-select",value:o,onChange:t=>d(t.target.value),children:Oe.map(t=>e.jsx("option",{value:t,children:t||"All tiers"},t||"all"))})]}),e.jsxs("div",{className:"sh-filter-bar__group",children:[e.jsx("span",{className:"sh-filter-bar__label",children:"Platform"}),e.jsx("select",{className:"sh-select",value:g,onChange:t=>x(t.target.value),children:Fe.map(t=>e.jsx("option",{value:t,children:t?fe(t):"All platforms"},t||"all"))})]}),L&&e.jsxs("button",{type:"button",className:"sh-filter-bar__clear",onClick:()=>{d(""),x("")},children:[e.jsx(G,{size:11})," Clear filters"]})]}),M&&!U?e.jsxs("div",{className:"sh-empty",children:[e.jsx(A,{size:18,className:"animate-spin"}),e.jsx("span",{children:"Loading hotspots…"})]}):S.length===0?e.jsx(ve,{icon:e.jsx(W,{size:32,color:n==="active"?"var(--color-accent)":"var(--text-dim)"}),title:n==="pending"?"Nothing pending":n==="resolved"?"Nothing resolved yet":"Locator hygiene is clean",description:n==="pending"?"When you mark a selector fixed, it shows here while we watch for 3 clean CI builds.":n==="resolved"?"Fix a hot selector and Xenon will track its verification here.":`No selectors required healing in the last ${l} days${L?" for the active filters":""}.`,action:e.jsxs("div",{className:"sh-empty-actions",children:[L&&n==="active"&&e.jsxs("button",{type:"button",className:"sh-ghost-btn sh-ghost-btn--inline",onClick:()=>{d(""),x("")},children:[e.jsx(G,{size:12})," Reset filters"]}),e.jsxs("a",{href:"/xenon/api-docs",target:"_blank",rel:"noreferrer",className:"sh-ghost-btn sh-ghost-btn--inline",children:[e.jsx(ue,{size:12})," View API docs"]})]})}):n==="pending"?e.jsx("div",{className:"sh-pending-list",children:S.map(t=>e.jsx(Le,{hotspot:t,onCancel:u=>j("cancel_verification",u),onMute:u=>j("mute",u),onOpen:C},`${t.originalStrategy??""} ${t.originalSelector}`))}):n==="resolved"?e.jsx("div",{className:"sh-pending-list",children:S.map(t=>e.jsx(Pe,{hotspot:t,onMute:u=>j("mute",u),onOpen:C},`${t.originalStrategy??""} ${t.originalSelector}`))}):e.jsxs("div",{className:"sh-table",children:[e.jsxs("div",{className:"sh-table__head",children:[e.jsx("div",{className:"sh-th sh-th--rank",children:"#"}),e.jsx("div",{className:"sh-th sh-th--selector",children:"Original selector"}),e.jsx("div",{className:"sh-th sh-th--count",children:"Heals"}),e.jsx("div",{className:"sh-th sh-th--meta",children:"Sessions"}),e.jsx("div",{className:"sh-th sh-th--meta",children:"Top tier"}),e.jsx("div",{className:"sh-th sh-th--meta",children:"Avg conf."}),e.jsx("div",{className:"sh-th sh-th--meta",children:"Last seen"}),e.jsx("div",{className:"sh-th sh-th--rewrite",children:"Suggested rewrite"}),e.jsx("div",{className:"sh-th sh-th--actions"})]}),S.map((t,u)=>{const v=Ve(t.healCount),p=t.suggestedRewriteShare!==null?Math.round(t.suggestedRewriteShare*100):null,$=`${u}-${t.originalSelector}`;return e.jsxs("div",{className:"sh-table__row",onClick:()=>C(t.originalSelector),role:"button",tabIndex:0,onKeyDown:b=>{(b.key==="Enter"||b.key===" ")&&(b.preventDefault(),C(t.originalSelector))},children:[e.jsx("div",{className:"sh-td sh-td--rank",children:u+1}),e.jsxs("div",{className:"sh-td sh-td--selector",children:[e.jsx("span",{className:"sh-strategy-badge",children:w(t.originalStrategy)}),e.jsx("code",{title:t.originalSelector,children:t.originalSelector})]}),e.jsx("div",{className:"sh-td sh-td--count",children:e.jsxs("span",{className:`sh-count-badge ${v}`,children:[e.jsx(ce,{size:10}),t.healCount]})}),e.jsx("div",{className:"sh-td sh-td--meta",children:t.sessionCount}),e.jsx("div",{className:"sh-td sh-td--meta",children:t.topTier?e.jsx("span",{className:"sh-tier-pill",children:t.topTier}):"—"}),e.jsx("div",{className:"sh-td sh-td--meta",children:t.averageConfidence!==null?`${Math.round(t.averageConfidence*100)}%`:"—"}),e.jsx("div",{className:"sh-td sh-td--meta",children:Ue(t.lastHealedAt)}),e.jsx("div",{className:"sh-td sh-td--rewrite",children:t.suggestedRewrite?e.jsxs(e.Fragment,{children:[p!==null&&e.jsxs("span",{className:"sh-rewrite-share",title:"Share of heals that landed on this selector",children:[p,"%"]}),t.suggestedStrategy&&e.jsx("span",{className:"sh-strategy-badge sh-strategy-badge--rewrite",title:"Strategy of the suggested rewrite",children:w(t.suggestedStrategy)}),e.jsx("code",{className:"sh-rewrite-value",title:t.suggestedRewrite,children:t.suggestedRewrite})]}):e.jsx("span",{className:"sh-rewrite-empty",children:"—"})}),e.jsxs("div",{className:"sh-td sh-td--actions",children:[t.suggestedRewrite&&e.jsx(Te,{hotspot:t,onCopied:b=>{K($),setTimeout(()=>K(X=>X===$?null:X),1500),i(`Copied as ${b}`,"success")}}),n==="active"&&e.jsxs(e.Fragment,{children:[e.jsx("button",{type:"button",className:"sh-action-btn sh-action-btn--primary",onClick:b=>{b.stopPropagation(),j("mark_fixed",t)},title:"Move to Pending Verification",children:"Mark fixed"}),e.jsx("button",{type:"button",className:"sh-action-btn sh-action-btn--ghost",onClick:b=>{b.stopPropagation(),j("mute",t)},title:"Hide from Hotspots, CI gate, and digests",children:"Mute"})]}),e.jsx("button",{type:"button",className:"sh-icon-btn",onClick:b=>{b.stopPropagation(),C(t.originalSelector)},"aria-label":"Open selector detail",title:"Drill in",children:e.jsx(_e,{size:12})})]})]},$)})]})]})]})]})};export{ds as default};
@@ -1,4 +0,0 @@
1
- import{r as x,X as j,j as t,e as Q,f as be,t as L,y as ve,R as ge,p as je,i as Ne,u as ye}from"./index-CzaIyL9t.js";import{C as we,d as ke,p as de,e as Se,r as xe,f as _e,j as me,k as J,c as Re,m as D,h as q,u as Ce,b as $e,t as Te}from"./stat-tile-BaE76cnK.js";import{A as Ae}from"./arrow-left-CnYs8HVw.js";import{C as U}from"./chevron-right-hCNu0CA-.js";import{s as De}from"./labels-C21SA4JG.js";import{B as Ee,S as ue,P as S}from"./BugReportButton-DQ-R87ZV.js";import{C as Oe}from"./circle-x-BaRKZyz9.js";import{C as Le}from"./circle-check-DnQ263fa.js";import{C as V}from"./copy-D8d9UzWE.js";import{A as Fe}from"./arrow-up-right-e7yBOb-c.js";import{A as Me}from"./arrow-right-Cc9qm6UG.js";import{V as Be}from"./video-off-mh1EEzP9.js";import{D as he}from"./download-SaN9-umX.js";import{E as P}from"./EmptyState-D3fG2GHY.js";import{T as He,a as Pe,b as Z,c as C,d as Ue,e as $}from"./Table-D_2lhvRM.js";import{M as Ie}from"./Modal-DNmn2RDs.js";import{N as Je}from"./network-BP_U4iDZ.js";import"./time-B8FIgwPE.js";import"./index-IefGCFQQ.js";const Ve=4e3,ee=e=>!!e&&typeof e=="object"&&typeof e.id=="string"&&typeof e.status=="string";function Ke(e){const[r,s]=x.useState(null),[a,n]=x.useState([]),[i,o]=x.useState([]),[l,c]=x.useState([]),[m,v]=x.useState([]),[b,p]=x.useState(!0),[N,y]=x.useState(null),[_,g]=x.useState(!1),[H,T]=x.useState(0),w=x.useRef(null);x.useEffect(()=>{if(!e){s(null),n([]),o([]),c([]),v([]),g(!1),p(!1);return}let f=!0;return w.current!==e&&p(!0),Promise.all([j.getSession(e),j.getSessionLogs(e),j.getDeviceLogs(e),j.getDebugLogs(e),j.getProfilingData(e).catch(()=>[])]).then(([h,u,R,A,Y])=>{if(!f)return;const G=ee(h);s(G?h:null),G?(w.current=e,g(!1),y(null)):(g(!!h&&typeof h=="object"&&(h.error===!0||typeof h.message=="string")),y(typeof(h==null?void 0:h.message)=="string"?h.message:"Session not found")),n(Array.isArray(u)?u:[]),o(Array.isArray(R)?R:[]),c(Array.isArray(A)?A:[]),v(Array.isArray(Y)?Y:[])}).catch(h=>{f&&y(h instanceof Error?h.message:String(h))}).finally(()=>{f&&p(!1)}),()=>{f=!1}},[e,H]);const d=(r==null?void 0:r.status)==="running";return x.useEffect(()=>{if(!e||!d)return;let f=!0;const h=setInterval(async()=>{try{const[u,R]=await Promise.all([j.getSession(e),j.getSessionLogs(e)]);if(!f||!ee(u))return;s(u),Array.isArray(R)&&n(R),u.status!=="running"&&T(A=>A+1)}catch{}},Ve);return()=>{f=!1,clearInterval(h)}},[e,d]),{session:r,sessionLogs:a,deviceLogs:i,debugLogs:l,profiling:m,loading:b,error:N,notFound:_,refresh:()=>T(f=>f+1)}}const te=({buildId:e,buildName:r,sessionId:s})=>t.jsxs("nav",{"aria-label":"Breadcrumb",className:"flex items-center gap-2 px-4 py-2 border-b border-[var(--border)] bg-[var(--surface)]",children:[t.jsxs(Q,{to:"/builds",className:"inline-flex items-center gap-1.5 text-xs text-[var(--text-muted)] hover:text-[var(--text)] transition-colors",children:[t.jsx(Ae,{className:"h-3.5 w-3.5"}),"Sessions"]}),t.jsx(U,{className:"h-3 w-3 text-[var(--text-dim)]"}),r&&t.jsxs(t.Fragment,{children:[t.jsx(Q,{to:`/builds/${e}`,className:"text-[11px] text-[var(--color-accent)] hover:underline",children:r}),t.jsx(U,{className:"h-3 w-3 text-[var(--text-dim)]"})]}),t.jsxs("span",{className:"font-mono text-[11px] text-[var(--text-muted)]",title:s,children:["#",s.slice(0,8)]})]}),ze={passed:{label:"Passed",Icon:Le,cls:"text-[var(--color-success)]"},failed:{label:"Failed",Icon:Oe,cls:"text-[var(--color-danger)]"},running:{label:"Running",Icon:be,cls:"text-[var(--color-warning)]"},other:{Icon:we,cls:"text-[var(--text-dim)]"}};function K(e){const r=Re(e),s=ze[r];return{bucket:r,...s,label:s.label??De(e||"unknown")}}const We=({session:e})=>{var i,o;const r=K(e.status),s=ke(e),a=[de(e),e.device_version].filter(l=>l&&l!=="—").join(" "),n=[[Se(e),a].filter(Boolean).join(" · "),xe(e.ranOn),(i=e.owner)==null?void 0:i.name,_e(e.startTime),me(J(e))].filter(l=>l&&l!=="—");return t.jsxs("header",{className:"flex items-start justify-between gap-4 px-4 py-4 border-b border-[var(--border)] bg-[var(--surface)]",children:[t.jsxs("div",{className:"min-w-0",children:[t.jsxs("div",{className:"flex items-center gap-2 min-w-0",children:[t.jsxs("span",{className:`inline-flex items-center gap-1.5 text-xs font-medium shrink-0 ${r.cls}`,children:[t.jsx(r.Icon,{className:`h-3.5 w-3.5 ${r.bucket==="running"?"animate-spin":""}`,"aria-hidden":"true"}),r.label]}),t.jsx("h1",{className:`text-lg font-semibold truncate ${s.source==="name"?"text-[var(--text)]":"text-[var(--text-muted)]"}`,title:s.source==="name"?s.text:`${s.text}
2
- Unnamed session. Set xe:options.name in its capabilities to name it.`,children:s.text})]}),t.jsx("p",{"data-testid":"outcome-meta",className:"mt-1 text-xs text-[var(--text-muted)] tabular-nums truncate",title:((o=e.owner)==null?void 0:o.email)??void 0,children:n.join(" · ")})]}),t.jsx("div",{className:"shrink-0",children:t.jsx(Ee,{sessionId:e.id,mode:"full",variant:"inline"})})]})};function Xe(e,r=8){if(!e)return[];const s=e.split(/\r?\n/),a=[];for(const n of s){const i=n.trim();if(/^at\s+/.test(i)&&(a.push(i),a.length>=r))break}return a}function z(e){return e?e.split(/[_\s]+/).filter(Boolean).map(r=>r.charAt(0).toUpperCase()+r.slice(1).toLowerCase()).join(" "):""}function re(e){if(!e)return{};try{const r=JSON.parse(e);return r&&typeof r=="object"&&!Array.isArray(r)?r:{}}catch{return{}}}function se(e,r=200){if(e==null)return"";if(typeof e=="string")return e;if(typeof e=="number"||typeof e=="boolean")return String(e);try{const s=JSON.stringify(e);return s.length>r?s.slice(0,r)+"…":s}catch{return String(e)}}const F=e=>e.command_name||e.title||"command",I=e=>{const r=e.createdAt?Date.parse(e.createdAt):NaN;return Number.isFinite(r)?r:0},W=e=>[...e].sort((r,s)=>I(r)-I(s));function M(e){return e.is_success===!1||e.is_error===!0}function fe(e){const r=[];let s=null;for(const a of W(e))a.is_healed&&a.healing_tier&&!r.includes(a.healing_tier)&&r.push(a.healing_tier),typeof a.duration=="number"&&(!s||a.duration>s.ms)&&(s={name:F(a),ms:a.duration});return{total:e.length,failed:e.filter(M).length,healed:e.filter(a=>a.is_healed).length,healedTiers:r,slowest:s,screenshots:e.filter(a=>a.screenshot).length}}const ae=(e,r)=>r?e?`${e}=${r}`:r:null;function Ye(e){return W(e.filter(r=>r.is_healed)).map(r=>({id:r.id,command:F(r),original:ae(r.original_strategy,r.original_selector),healed:ae(r.healed_strategy,r.healed_selector),tier:r.healing_tier??null,confidence:typeof r.healing_confidence=="number"?Math.round(r.healing_confidence*100):null,at:r.createdAt}))}function Ge(e){var r;if(!e.response)return null;try{const s=(r=JSON.parse(e.response))==null?void 0:r.value;if(!s||typeof s!="object")return null;const a=typeof s.message=="string"?s.message.trim():"";return a||(typeof s.error=="string"&&s.error?s.error:null)}catch{return null}}function Qe(e){if(e.length===0)return{spanMs:0,bars:[]};const r=e.map(n=>{const i=I(n),o=typeof n.duration=="number"&&n.duration>0?n.duration:0;return{l:n,start:i-o,end:i,durationMs:o}}),s=Math.min(...r.map(n=>n.start)),a=Math.max(...r.map(n=>n.end));return{spanMs:Math.max(1,a-s),bars:r.sort((n,i)=>n.start-i.start).map(({l:n,start:i,durationMs:o})=>({id:n.id,label:F(n),startMs:i-s,durationMs:o,failed:M(n),healed:!!n.is_healed}))}}function qe(e){return W(e.filter(r=>r.screenshot)).map(r=>({id:r.id,path:r.screenshot,command:F(r),at:r.createdAt,failed:M(r)}))}function O(e){if(e==null||!Number.isFinite(e)||e<0)return"—";if(e<1e3)return`${Math.round(e)}ms`;if(e<6e4)return`${(e/1e3).toFixed(1)}s`;const r=Math.round(e/1e3);return`${Math.floor(r/60)}m ${r%60}s`}const Ze=({session:e,commands:r})=>{var o,l;const s=K(e.status),a=fe(r),n=me(J(e)),i=s.bucket==="failed"?z(e.failure_category)||"No category recorded":s.bucket==="running"?`Running for ${n}`:`Ran ${n}`;return t.jsxs("div",{className:"grid grid-cols-4 gap-3",children:[t.jsx(D,{label:"Result",value:s.label,valueCls:s.cls,note:i,noteTone:s.bucket==="failed"?"bad":"neutral"}),t.jsx(D,{label:"Commands",value:a.total,note:a.failed>0?`${a.failed} failed`:"None failed",noteTone:a.failed>0?"bad":"neutral"}),t.jsx(D,{label:"Self-healing",value:a.healed>0?`${a.healed} healed`:"None",note:a.healed>0?a.healedTiers.join(", ")||"Tier not recorded":"No selector needed healing"}),t.jsx(D,{label:"Slowest command",value:O((o=a.slowest)==null?void 0:o.ms),note:((l=a.slowest)==null?void 0:l.name)??"No timings recorded"})]})};function et(e){const r=e.filter(M),s=r[r.length-1];return s?{command:s.command_name||s.title||"command",message:Ge(s)}:null}function tt(e,r,s,a,n){var m;const i=z(e.failure_category),o=((m=e.device_name)==null?void 0:m.trim())||"Unknown Device",l=e.device_version?` ${e.device_version}`:"",c=n?`${n.command}${n.message?`: ${n.message}`:""}`:"(no failed command recorded)";return[`**Session:** ${e.id}`,`**Build:** ${r} (#${s})`,`**Device:** ${o} (${e.node_id||"unknown-node"}) · ${e.device_platform||"unknown"}${l}`,`**Duration:** ${a}`,`**Failure category:** ${i||"(uncategorized)"}`,`**Failure reason:** ${e.failure_reason||"(not set)"}`,`**First failed command:** ${c}`,...e.ai_analysis?[`**AI analysis:** ${e.ai_analysis}`]:[]].join(`
3
- `)}function rt({text:e}){return t.jsx(t.Fragment,{children:e.split(/(\*\*[^*]+\*\*|`[^`]+`)/g).map((r,s)=>/^\*\*[^*]+\*\*$/.test(r)?t.jsx("strong",{children:r.slice(2,-2)},s):/^`[^`]+`$/.test(r)?t.jsx("code",{className:"font-mono text-[11px] px-1 rounded bg-[var(--surface-2)]",children:r.slice(1,-1)},s):t.jsx(ge.Fragment,{children:r},s))})}const E=({children:e})=>t.jsx("div",{className:"text-[11px] font-semibold text-[var(--text-dim)] mb-1",children:e}),st=({session:e,buildName:r,buildId:s,commands:a,durationText:n})=>{var _;const{toast:i}=L(),[o,l]=x.useState(!1),c=z(e.failure_category),m=et(a),v=Xe(e.failure_reason),b=(_=e.ai_analysis)==null?void 0:_.trim(),p=!!b&&b.length>480,N=async()=>{const g=tt(e,r,s,n,m);try{await navigator.clipboard.writeText(g),i("Failure report copied","success")}catch{i("Clipboard unavailable","error")}},y=e.failure_category?`/xenon/runbooks/${encodeURIComponent(e.failure_category.toLowerCase())}`:void 0;return t.jsxs("section",{className:"rounded-lg border border-[var(--red)]/30 bg-[var(--surface)] overflow-hidden",children:[t.jsxs("header",{className:"flex items-center justify-between gap-4 px-4 py-3 border-b border-[var(--border)] bg-[var(--red)]/5",children:[t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx(ve,{className:"h-4 w-4 text-[var(--red)]","aria-hidden":"true"}),t.jsx("h2",{className:"text-sm font-semibold text-[var(--red)]",children:"Why it failed"}),c&&t.jsx("span",{className:"text-[11px] text-[var(--text-dim)] ml-2",children:c})]}),t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsxs("button",{type:"button",onClick:N,className:"inline-flex items-center gap-1.5 h-7 px-2.5 rounded-md border border-[var(--border)] text-xs text-[var(--text)] hover:border-[var(--border-strong)] hover:bg-[var(--surface-2)] transition-colors",children:[t.jsx(V,{className:"h-3 w-3"}),"Copy"]}),t.jsxs("a",{...y?{href:y,target:"_blank",rel:"noreferrer"}:{"aria-disabled":!0,onClick:g=>g.preventDefault()},className:`inline-flex items-center gap-1.5 h-7 px-2.5 rounded-md border border-[var(--border)] text-xs text-[var(--text)] hover:border-[var(--border-strong)] hover:bg-[var(--surface-2)] transition-colors ${y?"":"opacity-50 cursor-not-allowed"}`,title:y?"Open runbook in new tab":"No runbook — failure category not set",children:[t.jsx(Fe,{className:"h-3 w-3"}),"Open runbook"]})]})]}),t.jsxs("div",{className:"px-4 py-4 space-y-4",children:[t.jsxs("div",{children:[t.jsx(E,{children:"Reason"}),t.jsx("div",{className:"text-sm text-[var(--text)] break-words",children:e.failure_reason||t.jsx("span",{className:"text-[var(--text-dim)]",children:"(not set)"})})]}),t.jsxs("div",{children:[t.jsx(E,{children:"First failed command"}),m?t.jsxs("div",{className:"flex items-baseline gap-2 min-w-0 text-sm",children:[t.jsx("span",{className:"font-mono text-xs text-[var(--color-danger)] shrink-0",children:m.command}),m.message&&t.jsx("span",{className:"text-[var(--text-muted)] break-words min-w-0",children:m.message})]}):t.jsx("span",{className:"text-sm text-[var(--text-dim)]",children:"No failed command recorded."})]}),b&&t.jsxs("div",{"data-testid":"ai-analysis",children:[t.jsx(E,{children:t.jsxs("span",{className:"inline-flex items-center gap-1.5",children:[t.jsx(ue,{className:"h-3 w-3","aria-hidden":"true"}),"AI analysis"]})}),t.jsx("div",{className:`text-sm text-[var(--text)] whitespace-pre-wrap break-words ${p&&!o?"line-clamp-6":""}`,children:t.jsx(rt,{text:b})}),p&&t.jsx("button",{type:"button",onClick:()=>l(g=>!g),"aria-expanded":o,className:"mt-1 text-xs text-[var(--color-accent)] hover:underline",children:o?"Show less":"Show all"})]}),v.length>0&&t.jsxs("div",{children:[t.jsx(E,{children:"Stack trace"}),t.jsx("pre",{className:"rounded-md border border-[var(--border)] bg-[var(--bg)] p-3 font-mono text-[11px] leading-relaxed text-[var(--color-accent)] overflow-x-auto",children:v.join(`
4
- `)})]})]})]})};function at(e){return e>=1e3?`${(e/1e3).toFixed(1).replace(/\.0$/,"")}k`:String(e)}function B(e){const r=e.timestamp;if(!r){const o=e.createdAt;return o?B({timestamp:o}):"--:--:--"}const s=typeof r=="number"?new Date(r):new Date(String(r));if(Number.isNaN(s.getTime()))return"--:--:--";const a=String(s.getHours()).padStart(2,"0"),n=String(s.getMinutes()).padStart(2,"0"),i=String(s.getSeconds()).padStart(2,"0");return`${a}:${n}:${i}`}function nt(e){if(e.is_healed===!0)return{label:String(e.command_name||"healed"),tone:"amber"};if(e.is_success===!1||e.is_error===!0)return{label:String(e.command_name||e.title||"error"),tone:"red"};if(e.is_success===!0)return{label:String(e.command_name||e.title||"ok"),tone:"green"};const r=e.title||e.event||e.command_name;return typeof r=="string"?/stop|fail|error/i.test(r)?{label:r,tone:"red"}:/start|begin|init/i.test(r)?{label:r,tone:"green"}:{label:r,tone:"blue"}:{label:"log",tone:"neutral"}}function it(e){if(e==null)return"";if(typeof e=="string")try{return JSON.stringify(JSON.parse(e),null,2)}catch{return e}try{return JSON.stringify(e,null,2)}catch{return String(e)}}function lt(e){if(!e||typeof e!="string")return[{text:String(e??""),kind:"plain"}];const r=[],s=/("(?:\\.|[^"\\])*")(\s*:)|("(?:\\.|[^"\\])*")|(-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?)|\b(true|false)\b|\b(null)\b|([{}[\],])/g;let a=0,n;for(;(n=s.exec(e))!==null;)n.index>a&&r.push({text:e.slice(a,n.index),kind:"plain"}),n[1]&&n[2]!==void 0?(r.push({text:n[1],kind:"key"}),r.push({text:n[2],kind:"punct"})):n[3]?r.push({text:n[3],kind:"string"}):n[4]?r.push({text:n[4],kind:"number"}):n[5]?r.push({text:n[5],kind:"boolean"}):n[6]?r.push({text:n[6],kind:"null"}):n[7]&&r.push({text:n[7],kind:"punct"}),a=s.lastIndex;return a<e.length&&r.push({text:e.slice(a),kind:"plain"}),r}function ot(e){const r=e,s=typeof r.title=="string"&&r.title.trim()?r.title.trim():null,a=typeof r.command_name=="string"&&r.command_name.trim()?r.command_name.trim():null;return s??a??"Command"}function ne(e){const r=e.subtitle;return typeof r=="string"&&r.trim()?r.trim():null}function ct(e,r){return r?e.filter(s=>s.is_success===!1||s.is_error===!0):e}const dt=({commands:e})=>{const r=Ye(e);return r.length===0?null:t.jsxs("section",{className:"rounded-lg border border-[var(--border)] bg-[var(--surface)] overflow-hidden",children:[t.jsxs("header",{className:"flex items-center gap-2 px-4 py-3 border-b border-[var(--border)]",children:[t.jsx(ue,{className:"h-4 w-4 text-[var(--color-warning)]","aria-hidden":"true"}),t.jsx("h2",{className:"text-sm font-semibold text-[var(--text)]",children:"Self-healing"}),t.jsxs("span",{className:"text-[11px] text-[var(--text-muted)]",children:[r.length," selector",r.length===1?"":"s"," healed. Update the test so the next run doesn't need to."]})]}),t.jsxs("table",{className:"w-full table-fixed text-left",children:[t.jsx("thead",{children:t.jsxs("tr",{className:"border-b border-[var(--border)] text-[11px] text-[var(--text-dim)]",children:[t.jsx("th",{className:"px-4 py-2 font-medium w-[88px]",children:"Time"}),t.jsx("th",{className:"px-3 py-2 font-medium w-[128px]",children:"Command"}),t.jsx("th",{className:"px-3 py-2 font-medium",children:"Asked for"}),t.jsx("th",{className:"w-[28px]",children:t.jsx("span",{className:"sr-only",children:"healed to"})}),t.jsx("th",{className:"px-3 py-2 font-medium",children:"Healed to"}),t.jsx("th",{className:"px-3 py-2 font-medium w-[112px]",children:"Tier"}),t.jsx("th",{className:"px-4 py-2 font-medium w-[96px] text-right",children:"Confidence"})]})}),t.jsx("tbody",{children:r.map((s,a)=>t.jsxs("tr",{className:"border-b border-[var(--border)] last:border-b-0 align-top",children:[t.jsx("td",{className:"px-4 py-2 text-xs text-[var(--text-muted)] tabular-nums",children:B({timestamp:s.at??null})}),t.jsx("td",{className:"px-3 py-2 text-xs text-[var(--text)] truncate",children:s.command}),t.jsx("td",{className:"px-3 py-2 font-mono text-[11px] text-[var(--text-muted)] break-all",children:s.original??"—"}),t.jsx("td",{className:"py-2 text-[var(--text-dim)]",children:t.jsx(Me,{className:"h-3.5 w-3.5","aria-hidden":"true"})}),t.jsx("td",{className:"px-3 py-2 font-mono text-[11px] text-[var(--text)] break-all",children:s.healed??"—"}),t.jsx("td",{className:"px-3 py-2 text-xs text-[var(--text)]",children:s.tier??"—"}),t.jsx("td",{className:"px-4 py-2 text-xs text-[var(--text)] tabular-nums text-right",children:s.confidence===null?"—":`${s.confidence}%`})]},s.id??a))})]})]})},xt=({session:e})=>{const r=e.status==="running",s=!!e.video_recording;return t.jsxs("section",{className:"rounded-lg border border-[var(--border)] bg-[var(--surface)] overflow-hidden",children:[t.jsxs("header",{className:"px-3 py-2 border-b border-[var(--border)] flex items-center justify-between",children:[t.jsx("span",{className:"text-[11px] font-semibold text-[var(--text-dim)]",children:"Recording"}),r&&t.jsxs("span",{className:"inline-flex items-center gap-1.5 text-[11px] text-[var(--red)]",children:[t.jsx("span",{className:"h-1.5 w-1.5 rounded-full bg-[var(--red)] pulse-dot"}),"Live"]})]}),t.jsx("div",{className:"aspect-video bg-[var(--bg)] flex items-center justify-center",children:r&&e.has_live_video?t.jsx("img",{src:j.getSessionLiveVideoUrl(e.id),alt:`Live view of session ${e.id}`,className:"w-full h-full object-contain"}):s?t.jsx("video",{controls:!0,src:j.getAssetUrl(e.video_recording),className:"w-full h-full object-contain"}):t.jsxs("div",{className:"flex flex-col items-center text-center px-6 py-8 gap-2",children:[t.jsx("div",{className:"h-10 w-10 rounded-full bg-[var(--surface-2)] border border-[var(--border)] flex items-center justify-center",children:t.jsx(Be,{className:"h-5 w-5 text-[var(--text-dim)]"})}),t.jsx("div",{className:"text-sm text-[var(--text)] font-medium",children:"No video available"}),t.jsx("div",{className:"text-xs text-[var(--text-dim)] max-w-xs",children:e.status==="failed"?"Session failed before recording started.":e.video_recording_enabled===!1?"Recording was disabled for this session.":"No recording was captured."})]})})]})},k=({label:e,children:r,title:s,mono:a})=>t.jsxs("div",{className:"flex items-baseline justify-between gap-3 px-3 py-2",children:[t.jsx("dt",{className:"text-xs text-[var(--text-muted)] shrink-0",children:e}),t.jsx("dd",{className:`text-xs text-[var(--text)] text-right min-w-0 break-all ${a?"font-mono text-[11px]":""}`,title:s,children:r})]}),mt=({session:e,buildName:r})=>{var o,l;const{toast:s}=L(),a=xe(e.ranOn),n=e.performance_trace?j.getAssetUrl(e.performance_trace):"",i=async()=>{try{await navigator.clipboard.writeText(e.id),s("Session ID copied","success")}catch{s("Clipboard unavailable","error")}};return t.jsxs("section",{className:"rounded-lg border border-[var(--border)] bg-[var(--surface)] overflow-hidden",children:[t.jsx("header",{className:"px-3 py-2 border-b border-[var(--border)]",children:t.jsx("h2",{className:"text-[11px] font-semibold text-[var(--text-dim)]",children:"Details"})}),t.jsxs("dl",{className:"divide-y divide-[var(--border)]",children:[t.jsx(k,{label:"Session ID",mono:!0,children:t.jsxs("span",{className:"inline-flex items-center gap-1",children:[t.jsx("span",{children:e.id}),t.jsx("button",{type:"button",onClick:i,"aria-label":"Copy session ID",className:"p-0.5 rounded text-[var(--text-dim)] hover:text-[var(--text)]",children:t.jsx(V,{className:"h-3 w-3"})})]})}),r&&t.jsx(k,{label:"Build",children:r}),t.jsx(k,{label:"Device UDID",mono:!0,children:e.device_udid||"—"}),t.jsx(k,{label:"Platform",children:[de(e),e.device_version].filter(c=>c&&c!=="—").join(" ")||"—"}),t.jsx(k,{label:"Ran on",title:e.node_id?`Node ${e.node_id}`:void 0,children:a??"Not known"}),t.jsx(k,{label:"Run by",title:(o=e.owner)==null?void 0:o.email,children:((l=e.owner)==null?void 0:l.name)??"Not recorded"}),t.jsx(k,{label:"Started",children:q(e.startTime)}),t.jsx(k,{label:"Ended",children:e.endTime?q(e.endTime):"—"}),e.tags&&t.jsx(k,{label:"Tags",children:e.tags}),n&&t.jsx(k,{label:"iOS trace",children:t.jsxs("a",{href:n,className:"inline-flex items-center gap-1 text-[var(--color-accent)] hover:underline",children:[t.jsx(he,{className:"h-3 w-3","aria-hidden":"true"}),"Performance trace"]})})]})]})},ie={desired:"Requested",session:"Actual"},ut=({session:e})=>{const[r,s]=x.useState("desired"),a=re(e.desired_capabilities),n=re(e.session_capabilities),o=Object.entries(r==="desired"?a:n);return t.jsxs("section",{className:"rounded-lg border border-[var(--border)] bg-[var(--surface)] overflow-hidden",children:[t.jsx("header",{className:"flex items-center border-b border-[var(--border)]",children:["desired","session"].map(l=>t.jsx("button",{type:"button",onClick:()=>s(l),"aria-pressed":r===l,className:`flex-1 h-9 text-[11px] font-semibold transition-colors border-b-2 ${r===l?"border-[var(--color-accent)] text-[var(--text)]":"border-transparent text-[var(--text-muted)] hover:text-[var(--text)]"}`,children:ie[l]},l))}),o.length===0?t.jsxs("div",{className:"px-3 py-6 text-center text-xs text-[var(--text-dim)]",children:["No ",ie[r].toLowerCase()," capabilities recorded for this session."]}):t.jsx("dl",{className:"divide-y divide-[var(--border)]",children:o.map(([l,c])=>t.jsxs("div",{className:"grid grid-cols-[minmax(0,1fr)_minmax(0,1fr)] items-baseline gap-3 px-3 py-2",children:[t.jsx("dt",{className:"text-xs text-[var(--text-muted)] break-all",children:l}),t.jsx("dd",{className:"font-mono text-xs text-[var(--text)] truncate text-right min-w-0",title:se(c,500),children:se(c)})]},l))})]})},ht=({tabs:e,active:r,onChange:s,errorsOnly:a,onErrorsOnlyChange:n,showErrorsOnly:i=!0})=>{const o=e.filter(l=>!(l.hideWhenEmpty&&l.count===0));return t.jsxs("div",{className:"flex items-center justify-between gap-4 px-3 border-b border-[var(--border)] bg-[var(--surface)]",children:[t.jsx("div",{className:"flex items-center gap-1 overflow-x-auto",children:o.map(l=>{const c=l.key===r;return t.jsxs("button",{type:"button",onClick:()=>s(l.key),"aria-pressed":c,"data-empty":l.count===0?"true":"false",className:`relative inline-flex items-center gap-1.5 h-9 px-3 text-xs whitespace-nowrap transition-colors ${c?"text-[var(--text)]":l.count===0?"text-[var(--text-dim)] hover:text-[var(--text-muted)]":"text-[var(--text-muted)] hover:text-[var(--text)]"}`,children:[t.jsx("span",{children:l.label}),l.count>0&&t.jsx("span",{className:`text-[10px] tabular-nums ${c?"text-[var(--text-muted)]":"text-[var(--text-dim)]"}`,children:at(l.count)}),c&&t.jsx("span",{className:"absolute left-2 right-2 bottom-0 h-[2px] bg-[var(--color-accent)] rounded-t"})]},l.key)})}),i&&t.jsxs("label",{className:"inline-flex items-center gap-2 text-[11px] text-[var(--text-muted)] cursor-pointer select-none whitespace-nowrap",children:[t.jsx("input",{type:"checkbox",checked:a,onChange:l=>n(l.target.checked),"aria-label":"Show only error rows"}),"Errors only"]})]})},ft={key:"text-[var(--blue)]",string:"text-[var(--color-accent)]",number:"text-[var(--amber)]",boolean:"text-[var(--amber)]",null:"text-[var(--text-dim)] italic",punct:"text-[var(--text-muted)]",plain:"text-[var(--text)]"},pt=({value:e,maxHeightPx:r})=>{const s=it(e);if(!s)return t.jsx("span",{className:"text-[var(--text-dim)] text-xs",children:"(empty)"});let a;try{a=lt(s)}catch{a=[{text:s,kind:"plain"}]}return t.jsx("pre",{className:"font-mono text-[11px] leading-relaxed bg-[var(--bg)] border border-[var(--border)] rounded-md p-3 overflow-x-auto whitespace-pre",style:r?{maxHeight:r,overflowY:"auto"}:void 0,children:a.map((n,i)=>t.jsx("span",{className:ft[n.kind],children:n.text},i))})},bt={green:"bg-[var(--color-success)]",red:"bg-[var(--red)]",amber:"bg-[var(--amber)]",blue:"bg-[var(--blue)]",neutral:"bg-[var(--text-dim)]"},vt={green:"text-[var(--color-success)]",red:"text-[var(--red)]",amber:"text-[var(--amber)]",blue:"text-[var(--blue)]",neutral:"text-[var(--text-muted)]"},gt=({log:e})=>{const[r,s]=x.useState(!1),{toast:a}=L(),n=B(e),i=nt(e),o=async l=>{l.stopPropagation();try{const c=e.body??e,m=typeof c=="string"?c:JSON.stringify(c,null,2);await navigator.clipboard.writeText(m),a("Log entry copied","success")}catch{a("Clipboard unavailable","error")}};return t.jsxs("div",{className:"border-b border-[var(--border)] last:border-b-0",children:[t.jsxs("button",{type:"button",onClick:()=>s(l=>!l),"aria-expanded":r,className:"group w-full flex items-center gap-2 px-3 py-2 text-left hover:bg-[var(--surface-2)]/60 transition-colors",children:[t.jsx(U,{className:`h-3 w-3 text-[var(--text-dim)] transition-transform shrink-0 ${r?"rotate-90":""}`}),t.jsx("span",{className:"font-mono text-[11px] text-[var(--text-muted)] w-[64px] shrink-0",children:n}),t.jsx("span",{className:`h-1.5 w-1.5 rounded-full shrink-0 ${bt[i.tone]}`}),t.jsx("span",{className:`font-mono text-[11px] font-medium shrink-0 ${vt[i.tone]}`,children:i.label}),t.jsxs("span",{className:"min-w-0 flex-1 flex items-baseline gap-2 truncate",children:[t.jsx("span",{className:"text-[12px] text-[var(--text)] shrink-0",children:ot(e)}),ne(e)&&t.jsx("span",{className:"font-mono text-[11px] text-[var(--text-dim)] truncate min-w-0",children:ne(e)})]}),typeof e.duration=="number"&&t.jsx("span",{className:"text-[11px] tabular-nums text-[var(--text-muted)] shrink-0",children:O(e.duration)}),t.jsx("span",{role:"button",tabIndex:0,onClick:o,onKeyDown:l=>{(l.key==="Enter"||l.key===" ")&&o(l)},"aria-label":"Copy log entry",className:"opacity-0 group-hover:opacity-100 p-1 rounded text-[var(--text-dim)] hover:text-[var(--text)] transition-opacity shrink-0",children:t.jsx(V,{className:"h-3 w-3"})})]}),r&&t.jsx("div",{className:"px-3 pb-3 pl-9",children:t.jsx(pt,{value:e.body??e,maxHeightPx:400})})]})},jt=(e,r)=>e?"bg-[var(--color-danger)]":r?"bg-[var(--color-warning)]":"bg-[var(--color-success)]",Nt=({commands:e})=>{const{spanMs:r,bars:s}=Qe(e);return s.length===0?t.jsx("div",{className:"px-4 py-10 text-center text-xs text-[var(--text-dim)]",children:"No commands recorded for this session."}):t.jsxs("div",{className:"px-3 py-3",children:[t.jsxs("div",{className:"flex items-center justify-between pb-2 text-[11px] text-[var(--text-dim)] tabular-nums",children:[t.jsxs("span",{children:[s.length," command",s.length===1?"":"s"," over ",O(r)]}),t.jsxs("span",{className:"inline-flex items-center gap-3",children:[t.jsxs("span",{className:"inline-flex items-center gap-1",children:[t.jsx("span",{className:"h-2 w-2 rounded-sm bg-[var(--color-danger)]"})," Failed"]}),t.jsxs("span",{className:"inline-flex items-center gap-1",children:[t.jsx("span",{className:"h-2 w-2 rounded-sm bg-[var(--color-warning)]"})," Healed"]})]})]}),t.jsx("ol",{className:"space-y-1",children:s.map((a,n)=>t.jsxs("li",{"data-testid":"timeline-bar","data-command":a.label,"data-failed":a.failed?"true":"false",className:"grid grid-cols-[128px_minmax(0,1fr)_64px] items-center gap-2",children:[t.jsx("span",{className:"truncate text-[11px] font-mono text-[var(--text-muted)]",title:a.label,children:a.label}),t.jsx("span",{className:"relative h-3 rounded-sm bg-[rgb(var(--rgb-fg)/0.05)]",children:t.jsx("span",{className:`absolute inset-y-0 rounded-sm ${jt(a.failed,a.healed)}`,style:{left:`${a.startMs/r*100}%`,width:`max(2px, ${a.durationMs/r*100}%)`}})}),t.jsx("span",{className:"text-right text-[11px] tabular-nums text-[var(--text-muted)]",children:a.durationMs>0?O(a.durationMs):"—"})]},a.id??n))})]})},yt=({commands:e})=>{const r=qe(e);return r.length===0?t.jsxs("div",{className:"px-4 py-10 text-center text-xs text-[var(--text-dim)]",children:["No screenshots were kept. A failed command keeps one unless"," ",t.jsx("code",{className:"font-mono",children:"xe:options.screenshotOnFailure"})," is false; set"," ",t.jsx("code",{className:"font-mono",children:"xe:options.screenshotOnEveryCommand"})," to keep one for every command."]}):t.jsx("ul",{className:"grid grid-cols-[repeat(auto-fill,minmax(140px,1fr))] gap-3 p-3",children:r.map((s,a)=>{const n=j.getAssetUrl(s.path),i=B({timestamp:s.at??null});return t.jsx("li",{children:t.jsxs("a",{href:n,target:"_blank",rel:"noreferrer",className:`block rounded-md border overflow-hidden hover:border-[var(--border-strong)] ${s.failed?"border-[var(--color-danger)]":"border-[var(--border)]"}`,children:[t.jsx("img",{src:n,alt:`${s.command} at ${i}`,loading:"lazy",className:"block w-full aspect-[9/16] object-contain bg-[rgb(var(--rgb-fg)/0.03)]"}),t.jsxs("span",{className:"flex items-center justify-between gap-2 px-2 py-1 text-[11px]",children:[t.jsx("span",{className:`truncate font-mono ${s.failed?"text-[var(--color-danger)]":"text-[var(--text)]"}`,children:s.command}),t.jsx("span",{className:"tabular-nums text-[var(--text-dim)] shrink-0",children:i})]})]})},s.id??a)})})},le=["commands","device","debug","profiling"],wt=({sessionLogs:e,deviceLogs:r,debugLogs:s,profiling:a})=>{const[n,i]=x.useState("commands"),[o,l]=x.useState(!1),c=e,m=x.useMemo(()=>fe(c).screenshots,[c]),v=x.useMemo(()=>[{key:"commands",label:"Commands",count:e.length},{key:"timeline",label:"Timeline",count:e.length},{key:"screenshots",label:"Screenshots",count:m},{key:"device",label:"Device logs",count:r.length},{key:"debug",label:"Debug logs",count:s.length},{key:"profiling",label:"System profiling",count:a.length,hideWhenEmpty:!0}],[e.length,m,r.length,s.length,a.length]),b=x.useMemo(()=>{let p=[];return n==="commands"?p=e:n==="device"?p=r:n==="debug"?p=s:n==="profiling"&&(p=a),ct(p,o)},[n,e,r,s,a,o]);return t.jsxs("section",{className:"rounded-lg border border-[var(--border)] bg-[var(--surface)] flex flex-col min-h-[280px] max-h-[640px]",children:[t.jsx(ht,{tabs:v,active:n,onChange:i,errorsOnly:o,onErrorsOnlyChange:l,showErrorsOnly:le.includes(n)}),t.jsxs("div",{className:"flex-1 overflow-y-auto",children:[n==="timeline"&&t.jsx(Nt,{commands:c}),n==="screenshots"&&t.jsx(yt,{commands:c}),le.includes(n)&&(b.length===0?t.jsx("div",{className:"px-4 py-10 text-center text-xs text-[var(--text-dim)]",children:o?"No error rows in this tab.":"No log entries in this tab."}):b.map((p,N)=>t.jsx(gt,{log:p},p.id??N)))]})]})},kt=({header:e,footer:r,action:s,padded:a=!0,className:n,children:i})=>t.jsxs("div",{className:`card${n?" "+n:""}`,children:[(e||s)&&t.jsxs("div",{className:"card-header",children:[t.jsx("div",{className:"card-header-title",children:e}),s&&t.jsx("div",{className:"card-header-action",children:s})]}),t.jsx("div",{className:a?"card-body":"card-body-flush",children:i}),r&&t.jsx("div",{className:"card-footer",children:r})]});function pe(e){if(!e)return"failed";switch(e){case"HTTPS_CLIENT_ERROR":case"HTTPS_SERVER_ERROR":case"OPEN_HTTPS_SERVER_ERROR":case"ON_CONNECT_ERROR":return"tls";case"PROXY_TO_SERVER_REQUEST_ERROR":return"net";default:return"failed"}}const X="/xenon/api/interceptor";async function St(e){const r=await fetch(`${X}/sessions/${encodeURIComponent(e)}/requests`);if(r.status===404){const a=await r.json().catch(()=>({}));return{active:!1,error:a==null?void 0:a.error}}return r.ok?{active:!0,requests:(await r.json()).requests||[]}:{active:!1,error:`request failed (${r.status})`}}async function _t(e,r){const s=await fetch(`${X}/sessions/${encodeURIComponent(e)}/requests/${encodeURIComponent(r)}`);return s.ok?s.json():null}function Rt(e){return`${X}/sessions/${encodeURIComponent(e)}/har`}function Ct(e){return e>=200&&e<300?"ready":e>=300&&e<400?"neutral":e>=400&&e<500?"busy":e>=500?"error":"neutral"}const oe=({headers:e})=>{const r=Object.entries(e||{});return r.length===0?t.jsx("div",{className:"text-xs text-[var(--text-dim)]",children:"No headers"}):t.jsx("div",{className:"space-y-0.5 font-mono text-xs",children:r.map(([s,a])=>t.jsxs("div",{className:"flex gap-2",children:[t.jsxs("span",{className:"text-[var(--text-dim)] shrink-0",children:[s,":"]}),t.jsx("span",{className:"break-all",children:a})]},s))})},ce=({body:e})=>{if(e==null||e==="")return t.jsx("div",{className:"text-xs text-[var(--text-dim)]",children:"No body"});let r=e;try{r=JSON.stringify(JSON.parse(e),null,2)}catch{}return t.jsx("pre",{className:"font-mono text-xs whitespace-pre-wrap break-all bg-[var(--surface-2,var(--surface))] rounded p-2 max-h-64 overflow-auto",children:r})},$t=({request:e,onClose:r})=>{if(!e)return null;const s=t.jsxs("div",{className:"flex items-center gap-2 text-sm",children:[t.jsx(S,{tone:"accent",children:e.method}),e.failed?t.jsx(S,{tone:"error",children:pe(e.failureKind)}):t.jsx(S,{tone:Ct(e.resStatus),children:e.resStatus||"—"}),t.jsx("span",{className:"font-mono text-xs truncate",title:e.url,children:e.url})]});return t.jsx(Ie,{open:!!e,title:s,onClose:r,width:720,children:t.jsxs("div",{className:"space-y-4 text-xs",children:[e.failed&&t.jsxs("div",{className:"border border-[var(--red)] rounded p-2 bg-[rgb(var(--rgb-red-600)/0.08)]",children:[t.jsx("div",{className:"text-[var(--red)] text-[11px] mb-1",children:"Failure"}),t.jsx("div",{className:"text-xs",children:e.failureReason||"Request failed"}),e.failureKind&&t.jsx("div",{className:"font-mono text-[10px] text-[var(--text-dim)] mt-1",children:e.failureKind})]}),!e.failed&&t.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[t.jsxs("div",{children:[t.jsx("div",{className:"text-[var(--text-dim)] text-[11px] mb-1",children:"Duration"}),t.jsxs("div",{className:"font-mono",children:[e.durationMs," ms"]})]}),t.jsxs("div",{children:[t.jsx("div",{className:"text-[var(--text-dim)] text-[11px] mb-1",children:"Flags"}),t.jsxs("div",{className:"flex gap-1",children:[e.mocked&&t.jsx(S,{tone:"accent",children:"mocked"}),e.modified&&t.jsx(S,{tone:"busy",children:"modified"}),!e.mocked&&!e.modified&&t.jsx("span",{className:"text-[var(--text-dim)]",children:"passthrough"})]})]})]}),e.commandHint&&t.jsxs("div",{children:[t.jsx("div",{className:"text-[var(--text-dim)] text-[11px] mb-1",children:"Triggered by"}),t.jsx("div",{className:"font-mono",children:e.commandHint.commandName})]}),!e.failed&&t.jsxs(t.Fragment,{children:[t.jsxs("div",{children:[t.jsx("div",{className:"text-[var(--text-dim)] text-[11px] mb-1",children:"Request Headers"}),t.jsx(oe,{headers:e.reqHeaders})]}),t.jsxs("div",{children:[t.jsx("div",{className:"text-[var(--text-dim)] text-[11px] mb-1",children:"Request Body"}),t.jsx(ce,{body:e.reqBody})]}),t.jsxs("div",{children:[t.jsx("div",{className:"text-[var(--text-dim)] text-[11px] mb-1",children:"Response Headers"}),t.jsx(oe,{headers:e.resHeaders})]}),t.jsxs("div",{children:[t.jsx("div",{className:"text-[var(--text-dim)] text-[11px] mb-1",children:"Response Body"}),t.jsx(ce,{body:e.resBody})]})]})]})})};function Tt(e){return e?new Date(e).toLocaleTimeString(void 0,{hour12:!1}):"—"}function At(e){return e>=200&&e<300?"ready":e>=300&&e<400?"neutral":e>=400&&e<500?"busy":e>=500?"error":"neutral"}const Dt=({sessionId:e,sessionEnded:r})=>{const[s,a]=x.useState(null),[n,i]=x.useState(null),[o,l]=x.useState([]),[c,m]=x.useState(!0),[v,b]=x.useState(null),p=x.useRef(new Set),{on:N,isConnected:y}=je();x.useEffect(()=>{let d=!0;return m(!0),St(e).then(f=>{if(!d)return;a(f.active),i(f.error||null);const h=f.requests||[];l(h),p.current=new Set(h.map(u=>u.id))}).finally(()=>{d&&m(!1)}),()=>{d=!1}},[e]),x.useEffect(()=>{if(r)return;const d=N("interceptor_request",u=>{!u||u.sessionId!==e||p.current.has(u.id)||(p.current.add(u.id),l(R=>[u,...R]),a(!0))}),f=N("interceptor_session_started",u=>{(u==null?void 0:u.sessionId)===e&&a(!0)}),h=N("interceptor_session_stopped",u=>{(u==null?void 0:u.sessionId)===e&&a(!1)});return()=>{d(),f(),h()}},[N,e,r,y]);const _=x.useMemo(()=>[...o].sort((d,f)=>f.ts-d.ts),[o]),g=async d=>{if(b(d),s){const f=await _t(e,d.id);f&&b(f)}},H=s&&o.length>0?t.jsxs("a",{href:Rt(e),className:"inline-flex items-center gap-1 text-xs text-[var(--text-dim)] hover:text-[var(--text)]",title:"Download HAR",children:[t.jsx(he,{className:"h-3 w-3"}),"HAR"]}):null,T=t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx(Je,{className:"h-3.5 w-3.5 text-[var(--text-dim)]"}),t.jsx("span",{children:"Network"}),s&&o.length>0&&t.jsxs("span",{className:"text-xs text-[var(--text-dim)]",children:["(",o.length,")"]})]});let w;return c?w=t.jsx("div",{className:"p-4 text-xs text-[var(--text-dim)]",children:"Loading…"}):s===!1&&r?w=t.jsx(P,{title:"No network capture",description:"Network interception was not enabled for this session."}):s===!1?w=t.jsx(P,{title:"Network interception disabled",description:"Enable interceptor.enabled in plugin config to capture requests for Android sessions."}):n?w=t.jsxs("div",{className:"p-4 text-xs text-[var(--red)]",children:["Failed to load requests: ",n]}):_.length===0?w=t.jsx(P,{title:"Waiting for requests",description:r?"No HTTP traffic was captured during this session.":"Captured requests will appear here as the device makes calls."}):w=t.jsx("div",{className:"overflow-auto max-h-96",children:t.jsxs(He,{children:[t.jsx(Pe,{children:t.jsxs(Z,{children:[t.jsx(C,{style:{width:80},children:"Time"}),t.jsx(C,{style:{width:70},children:"Method"}),t.jsx(C,{style:{width:70},children:"Status"}),t.jsx(C,{children:"Host"}),t.jsx(C,{children:"Path"}),t.jsx(C,{style:{width:80},children:"Duration"}),t.jsx(C,{style:{width:90},children:"Flags"})]})}),t.jsx(Ue,{children:_.map(d=>t.jsxs(Z,{onClick:()=>g(d),style:{cursor:"pointer"},title:d.failed?d.failureReason:void 0,children:[t.jsx($,{className:"font-mono text-[11px]",children:Tt(d.ts)}),t.jsx($,{children:t.jsx(S,{tone:"accent",children:d.method})}),t.jsx($,{children:d.failed?t.jsx(S,{tone:"error",children:pe(d.failureKind)}):t.jsx(S,{tone:At(d.resStatus),children:d.resStatus||"—"})}),t.jsx($,{className:"font-mono text-[11px] truncate",title:d.host,children:d.host}),t.jsx($,{className:"font-mono text-[11px] truncate",title:d.path,children:d.failed?"—":d.path}),t.jsx($,{className:"font-mono text-[11px]",children:d.failed?"—":`${d.durationMs}ms`}),t.jsx($,{children:t.jsxs("div",{className:"flex gap-1",children:[d.mocked&&t.jsx(S,{tone:"accent",children:"mock"}),d.modified&&t.jsx(S,{tone:"busy",children:"mod"})]})})]},d.id))})]})}),t.jsxs(t.Fragment,{children:[t.jsx(kt,{header:T,action:H,padded:!1,children:w}),t.jsx($t,{request:v,onClose:()=>b(null)})]})},qt=()=>{const{buildId:e="",sessionId:r=""}=Ne(),{toast:s}=L(),a=ye(),n=Ce(),i=Ke(r||null),o=x.useMemo(()=>n.builds.find(b=>b.id===e)??null,[n.builds,e]),l=o?$e(o):"Build";if(x.useEffect(()=>{!i.loading&&i.notFound&&(s("Session not available — it may belong to a team you are not on.","info"),a("/builds",{replace:!0}))},[i.loading,i.notFound,a,s]),i.loading)return t.jsx("div",{className:"p-6 text-xs text-[var(--text-dim)]",children:"Loading session…"});if(i.error||!i.session)return t.jsxs("div",{className:"p-6 space-y-2",children:[t.jsx(te,{buildId:e,buildName:o?l:null,sessionId:r}),t.jsx("div",{className:"mt-6 rounded-md border border-[var(--red)]/30 bg-[var(--surface)] p-4 text-xs text-[var(--red)]",children:i.error||"Session not found."})]});const c=i.session,m=i.sessionLogs,v=K(c.status).bucket==="failed";return t.jsxs("div",{className:"flex flex-col h-full min-h-0",children:[t.jsx(te,{buildId:e,buildName:o?l:null,sessionId:c.id}),t.jsx(We,{session:c}),t.jsx("div",{className:"flex-1 overflow-y-auto overflow-x-hidden",children:t.jsxs("div",{className:"px-4 py-4 space-y-4",children:[t.jsx(Ze,{session:c,commands:m}),v&&t.jsx(st,{session:c,buildName:l,buildId:e,commands:m,durationText:Te(J(c))}),t.jsx(dt,{commands:m}),t.jsxs("div",{className:"grid grid-cols-1 lg:grid-cols-[minmax(0,1fr)_340px] gap-4",children:[t.jsx("div",{className:"min-w-0",children:t.jsx(wt,{sessionLogs:i.sessionLogs,deviceLogs:i.deviceLogs,debugLogs:i.debugLogs,profiling:i.profiling})}),t.jsxs("div",{className:"flex flex-col gap-4 min-w-0",children:[t.jsx(xt,{session:c}),t.jsx(mt,{session:c,buildName:o?l:null}),t.jsx(ut,{session:c})]})]}),t.jsx(Dt,{sessionId:c.id,sessionEnded:c.status!=="running"})]})})]})};export{qt as SessionDetailPage,qt as default};
@@ -1,8 +0,0 @@
1
- import{c as V,r as o,p as Z,X as $,j as w}from"./index-CzaIyL9t.js";import{f as K}from"./time-B8FIgwPE.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 Q=[["path",{d:"M10.1 2.182a10 10 0 0 1 3.8 0",key:"5ilxe3"}],["path",{d:"M13.9 21.818a10 10 0 0 1-3.8 0",key:"11zvb9"}],["path",{d:"M17.609 3.721a10 10 0 0 1 2.69 2.7",key:"1iw5b2"}],["path",{d:"M2.182 13.9a10 10 0 0 1 0-3.8",key:"c0bmvh"}],["path",{d:"M20.279 17.609a10 10 0 0 1-2.7 2.69",key:"1ruxm7"}],["path",{d:"M21.818 10.1a10 10 0 0 1 0 3.8",key:"qkgqxc"}],["path",{d:"M3.721 6.391a10 10 0 0 1 2.7-2.69",key:"1mcia2"}],["path",{d:"M6.391 20.279a10 10 0 0 1-2.69-2.7",key:"1fvljs"}]],me=V("circle-dashed",Q);function _(e){switch(e){case"success":case"passed":case"ended":return"passed";case"failed":case"error":case"timeout":return"failed";case"running":return"running";default:return"other"}}function pe(e){const t={all:e.length,passed:0,failed:0,running:0};for(const n of e){const r=_(n.status);r!=="other"&&(t[r]+=1)}return t}function W(e,t){return t==="all"?!0:_(e.status)===t}function he(e,t,n){const r=n.trim().toLowerCase();return e.filter(s=>{var u,d;return!(!W(s,t)||r&&![s.id,q(s).text,s.name,s.failure_reason,s.device_name,s.device_platform,s.device_version,s.node_id,s.ranOn,(u=s.owner)==null?void 0:u.name,(d=s.owner)==null?void 0:d.email].filter(Boolean).join(" ").toLowerCase().includes(r))})}function ee(e){var n;const t=(n=e.device_name)==null?void 0:n.trim();return t&&t.length>0?t:"Unknown Device"}function te(e){const t=e.device_platform??"";if(!t)return"—";const n=t.toLowerCase();return n==="ios"?"iOS":n==="tvos"?"tvOS":n.charAt(0).toUpperCase()+n.slice(1)}function ge(e){return K(e)}function Se(e){if(!e.startTime)return null;const t=Date.parse(e.startTime);if(!Number.isFinite(t))return null;const n=e.endTime?Date.parse(e.endTime):Date.now();return Number.isFinite(n)?Math.max(0,n-t):null}function be(e){if(e==null||!Number.isFinite(e)||e<0)return"—";const t=e/1e3,n=Math.floor(t/3600),r=Math.floor(t%3600/60),u=(t-n*3600-r*60).toFixed(1);return n>0?`${n}h ${r}m ${u}s`:r>0?`${r}m ${u}s`:`${u}s`}const H=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],D=e=>String(e).padStart(2,"0");function A(e,t){const n=e[`appium:${t}`]??e[t];return typeof n=="string"&&n.trim()?n.trim():null}function ne(e){if(!e)return null;let t;try{t=JSON.parse(e)}catch{return null}if(!t||typeof t!="object")return null;let n=t;if(n.capabilities&&typeof n.capabilities=="object"&&(n=n.capabilities),n.alwaysMatch||n.firstMatch){const r=Array.isArray(n.firstMatch)?n.firstMatch[0]:void 0;return{...n.alwaysMatch||{},...r||{}}}return n}function O(e){const t=ne(e);if(!t)return null;const n=A(t,"appPackage")??A(t,"bundleId");if(n)return n;const r=A(t,"app");if(r){const s=r.split(/[?#]/)[0].split(/[\\/]/).pop()??"";if(s&&s!=="download")return s}return A(t,"browserName")}function q(e){var r;const t=(r=e.name)==null?void 0:r.trim();if(t)return{text:t,source:"name"};const n=O(e.session_capabilities)??O(e.desired_capabilities);return n?{text:n,source:"app"}:{text:`Session ${e.id.slice(0,8)}`,source:"id"}}function L(e){return`${H[e.getMonth()]} ${e.getDate()}, ${D(e.getHours())}:${D(e.getMinutes())}`}function ye(e){const t=e?new Date(e):null;return t&&!Number.isNaN(t.getTime())?L(t):"—"}function re(e){var n;const t=(n=e.name)==null?void 0:n.trim();return!t||t==="Default Build"}function Me(e){if(!re(e))return e.name.trim();const t=new Date(e.createdAt);return Number.isNaN(t.getTime())?"Build":`Build · ${L(t)}`}const ve={all:"All time","24h":"Last 24 hours","7d":"Last 7 days","30d":"Last 30 days"},se={"24h":864e5,"7d":7*864e5,"30d":30*864e5};function ae(e,t){return e==="all"?null:new Date(t-se[e]).toISOString()}function $e(e){if(e==null||!Number.isFinite(e)||e<0)return"—";if(e<1e3)return"<1s";const t=Math.floor(e/1e3),n=Math.floor(t/3600),r=Math.floor(t%3600/60),s=t%60;return n>0?`${n}h ${r}m`:r>0?`${r}m ${s}s`:`${s}s`}function xe(e,t=new Date){if(!e)return"—";const n=new Date(e);if(Number.isNaN(n.getTime()))return"—";const r=`${D(n.getHours())}:${D(n.getMinutes())}`;return n.getFullYear()!==t.getFullYear()?`${H[n.getMonth()]} ${n.getDate()}, ${n.getFullYear()} ${r}`:n.getMonth()===t.getMonth()&&n.getDate()===t.getDate()?r:L(n)}function R(e){const t=e.passed+e.failed;return t>0?e.passed/t*100:null}function we(e,t){const n=R(e),r=t?R(t):null;return n===null||r===null?null:n-r}function Ae(e){return e?e==="here"?"This server":e:null}function Ne(e,t,n){var m,p;const r=n&&n.size>0?t.filter(i=>n.has(i.id)):t,s=r.filter(i=>_(i.status)==="failed").reverse();if(s.length===0)return{count:0,text:""};const u=n&&n.size>0?`${r.length} selected session${r.length===1?"":"s"}`:`${r.length} session${r.length===1?"":"s"}`,d=[`Failed tests in ${e}: ${s.length} of ${u}`,""];for(const i of s){const E=((p=(m=i.failure_reason)==null?void 0:m.split(`
7
- `)[0])==null?void 0:p.trim())||"No reason recorded",S=[te(i),i.device_version].filter(h=>h&&h!=="—").join(" ");d.push(`- ${q(i).text}`,` ${E}`,` ${[ee(i),S,`session ${i.id}`].filter(Boolean).join(" · ")}`)}return{count:s.length,text:d.join(`
8
- `)}}const ie=3e3,N=200,oe=2e3,ce=200,ue=(e,t)=>e.createdAt===t.createdAt?e.id<t.id?1:-1:e.createdAt<t.createdAt?1:-1;function P(e,t){const n=new Map;for(const r of t)n.set(r.id,r);for(const r of e)n.set(r.id,r);return Array.from(n.values()).sort(ue)}function De(e={}){const{withSessions:t=!1,timeFilter:n="all"}=e,[r,s]=o.useState([]),[u,d]=o.useState([]),[m,p]=o.useState([]),i=o.useRef([]),[E,S]=o.useState(!1),[h,F]=o.useState(!1),[b,J]=o.useState(null),[X,z]=o.useState(!0),[U,T]=o.useState(null),l=o.useRef(!0),{on:y}=Z(),M=o.useCallback(()=>b?{buildId:b}:{since:ae(n,Date.now())??void 0},[b,n]);o.useEffect(()=>{i.current=[],p([]),S(!1)},[b,n]);const B=o.useCallback(async()=>{if(!t)return[];const a=i.current;if(a.length===0){const f=await $.getSessions({...M(),limit:N});return Array.isArray(f)&&S(f.length===N),f}const{since:c,...k}=M(),C=a[0].createdAt,j=a.filter(f=>_(f.status)==="running").slice(0,ce).map(f=>f.id),[G,I]=await Promise.all([$.getSessions({...k,since:c&&c>C?c:C,limit:oe}),j.length?$.getSessions({ids:j}):Promise.resolve([])]);if(l.current&&Array.isArray(I)&&I.length){const f=new Map(I.map(v=>[v.id,v]));i.current=i.current.map(v=>f.get(v.id)??v),p(i.current)}return G},[t,M]),g=o.useCallback(async()=>{try{const[a,c]=await Promise.all([$.getBuilds(),B()]);if(!l.current)return;s(Array.isArray(a)?a:[]),d(Array.isArray(c)?c:[]),T(null)}catch(a){if(!l.current)return;T(a instanceof Error?a.message:String(a))}finally{l.current&&z(!1)}},[B]);o.useEffect(()=>{l.current=!0,g();const a=setInterval(g,ie);return()=>{l.current=!1,clearInterval(a)}},[g]),o.useEffect(()=>{const a=()=>g(),c=[y("session_started",a),y("session_stopped",a),y("device_added",a),y("device_removed",a)];return()=>{for(const k of c)k()}},[y,g]);const x=o.useMemo(()=>P(u,m),[u,m]),Y=o.useCallback(async()=>{const a=x[x.length-1];if(!(!t||h||!a)){F(!0);try{const c=await $.getSessions({...M(),before:a.createdAt,beforeId:a.id,limit:N});if(!l.current||!Array.isArray(c))return;i.current=P([],[...i.current,...c]),p(i.current),S(c.length===N)}catch(c){l.current&&T(c instanceof Error?c.message:String(c))}finally{l.current&&F(!1)}}},[x,t,h,M]);return{builds:r,selectedBuildId:b,sessions:x,loading:X,error:U,selectBuild:J,refresh:g,hasMore:E,loadingMore:h,showMore:Y}}const le={neutral:"text-[var(--text-muted)]",good:"text-[var(--color-success)]",bad:"text-[var(--color-danger)]"},_e=({label:e,value:t,valueCls:n="text-[var(--text)]",note:r,noteTone:s="neutral"})=>w.jsxs("div",{className:"min-w-0 rounded-lg border border-[var(--border)] bg-[var(--surface)] px-4 py-3",children:[w.jsx("div",{className:"text-xs text-[var(--text-muted)]",children:e}),w.jsx("div",{className:`mt-1 text-2xl font-semibold tabular-nums leading-tight truncate ${n}`,children:t}),w.jsx("div",{className:`mt-0.5 text-[11px] truncate ${le[s]}`,children:r??" "})]});export{me as C,se as P,N as S,ve as T,pe as a,Me as b,_ as c,q as d,ee as e,ye as f,xe as g,ge as h,re as i,$e as j,Se as k,he as l,_e as m,R as n,we as o,te as p,Ne as q,Ae as r,ae as s,be as t,De as u};
@@ -1 +0,0 @@
1
- function c(t){if(!t)return"";const e=Date.parse(t);if(!Number.isFinite(e))return"";const n=Math.max(0,Date.now()-e),r=Math.floor(n/1e3);if(r<60)return`${r}s ago`;const a=Math.floor(r/60);if(a<60)return`${a}m ago`;const o=Math.floor(a/60);return o<24?`${o}h ago`:`${Math.floor(o/24)}d ago`}const u=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];function i(t){if(t==null||t==="")return"—";const e=t instanceof Date?t:new Date(t);if(Number.isNaN(e.getTime()))return"—";const n=r=>String(r).padStart(2,"0");return`${u[e.getMonth()]} ${e.getDate()}, ${n(e.getHours())}:${n(e.getMinutes())}:${n(e.getSeconds())}`}function g(t){if(t==null||t==="")return"—";const e=t instanceof Date?t:new Date(t);return Number.isNaN(e.getTime())?"—":`${u[e.getMonth()]} ${e.getDate()}, ${e.getFullYear()}`}export{g as a,c as b,i as f};
@@ -1,213 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- var __importDefault = (this && this.__importDefault) || function (mod) {
12
- return (mod && mod.__esModule) ? mod : { "default": mod };
13
- };
14
- Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.AndroidAppProfiler = void 0;
16
- const events_1 = __importDefault(require("events"));
17
- const bluebird_1 = __importDefault(require("bluebird"));
18
- const lodash_1 = __importDefault(require("lodash"));
19
- const teen_process_1 = require("teen_process");
20
- class AndroidAppProfiler extends events_1.default {
21
- constructor(opts) {
22
- super();
23
- this.adb = opts.adb;
24
- this.logs = [];
25
- this.deviceUDID = opts.deviceUDID;
26
- this.appPackage = opts.appPackage;
27
- this.proc = null;
28
- }
29
- startCapture() {
30
- return __awaiter(this, void 0, void 0, function* () {
31
- let started = false;
32
- return yield new bluebird_1.default((resolve_B, _reject_B) => __awaiter(this, void 0, void 0, function* () {
33
- var _a, _b;
34
- const resolve = function (...args) {
35
- started = true;
36
- resolve_B(...args);
37
- };
38
- const _reject = function (...args) {
39
- started = true;
40
- _reject_B(...args);
41
- };
42
- this.deviceInfo = yield this.getDeviceInfo();
43
- const defaultArgs = ((_a = this.adb.executable) === null || _a === void 0 ? void 0 : _a.defaultArgs) || [];
44
- const cmd = [
45
- ...defaultArgs,
46
- '-s',
47
- this.deviceUDID,
48
- 'shell',
49
- 'top',
50
- '-o',
51
- '%CPU,RSS,ARGS',
52
- '-s',
53
- '1',
54
- '-d',
55
- '2',
56
- ];
57
- /* -m argument is only supported after api level 28 */
58
- if (lodash_1.default.isNumber(this.deviceInfo.api_level) && this.deviceInfo.api_level >= 28) {
59
- cmd.push('-m', '20');
60
- }
61
- this.proc = new teen_process_1.SubProcess(((_b = this.adb.executable) === null || _b === void 0 ? void 0 : _b.path) || 'adb', cmd);
62
- this.proc.on('exit', (_code, _signal) => {
63
- this.proc = null;
64
- if (!started) {
65
- resolve();
66
- }
67
- });
68
- this.proc.on('lines-stdout', (lines) => {
69
- resolve();
70
- if (!lines[3]) {
71
- return;
72
- }
73
- const slicedLines = lines.slice(4);
74
- const sysInfo = {
75
- total_cpu_used: this.getSystemCpuUsage(lines[3]),
76
- total_memory_used: this.getSystemMemoryUsage(lines[1]),
77
- raw_cpu_log: lines[3],
78
- raw_memory_log: lines[1],
79
- };
80
- /* Logs received is not in proper format so ignore the entry */
81
- if (sysInfo.total_cpu_used == 0 && sysInfo.total_memory_used == 0) {
82
- return;
83
- }
84
- for (const line of slicedLines) {
85
- if (new RegExp(/\r/g).test(line)) {
86
- line
87
- .split(/\r/g)
88
- .filter((l) => !!l)
89
- .forEach((l) => this.outputHandler(sysInfo, lodash_1.default.trim(l)));
90
- }
91
- else {
92
- this.outputHandler(sysInfo, lodash_1.default.trim(line));
93
- }
94
- }
95
- });
96
- yield this.proc.start(0);
97
- }));
98
- });
99
- }
100
- outputHandler(generalCpuInfo, output) {
101
- //remove all ascii characters from the log line
102
- /* eslint-disable no-control-regex */
103
- output = output.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, '');
104
- // Use a regex to split by one or more spaces and filter out any empty strings
105
- const parts = output.trim().split(/\s+/);
106
- if (parts.length < 3) {
107
- return;
108
- }
109
- const [cpu, memory, pkg] = parts;
110
- // Filter out invalid samples or headers that cause graph 'drops to zero'
111
- if (!cpu || cpu === '0' || cpu === '%CPU' || isNaN(parseFloat(cpu))) {
112
- return;
113
- }
114
- const outputObj = Object.assign({ timestamp: new Date().toISOString(), cpu: cpu || '0', memory: memory || '0' }, generalCpuInfo);
115
- if (pkg === this.appPackage) {
116
- this.logs.push(outputObj);
117
- this.emit('output', outputObj);
118
- }
119
- }
120
- stopCapture() {
121
- return __awaiter(this, void 0, void 0, function* () {
122
- if (!this.proc || !this.proc.isRunning) {
123
- this.proc = null;
124
- return;
125
- }
126
- this.proc.removeAllListeners('exit');
127
- yield this.proc.stop();
128
- this.proc = null;
129
- });
130
- }
131
- getLogs() {
132
- return lodash_1.default.uniqBy(this.logs, 'timestamp');
133
- }
134
- getDeviceInfo() {
135
- return __awaiter(this, void 0, void 0, function* () {
136
- return {
137
- total_cpu: yield this.getTotalCpus(),
138
- total_memory: yield this.getTotalMemory(),
139
- api_level: yield this.getAndroidApiLevel(),
140
- };
141
- });
142
- }
143
- getAndroidApiLevel() {
144
- return __awaiter(this, void 0, void 0, function* () {
145
- var _a, _b, _c;
146
- if ((_a = this.deviceInfo) === null || _a === void 0 ? void 0 : _a.api_level)
147
- return this.deviceInfo.api_level;
148
- const defaultArgs = ((_b = this.adb.executable) === null || _b === void 0 ? void 0 : _b.defaultArgs) || [];
149
- const args = [
150
- ...defaultArgs,
151
- '-s',
152
- this.deviceUDID,
153
- 'shell',
154
- 'getprop',
155
- 'ro.build.version.sdk',
156
- ];
157
- const out = yield (0, teen_process_1.exec)(((_c = this.adb.executable) === null || _c === void 0 ? void 0 : _c.path) || 'adb', args);
158
- return Number(out.stdout.trim());
159
- });
160
- }
161
- getTotalCpus() {
162
- return __awaiter(this, void 0, void 0, function* () {
163
- var _a, _b, _c;
164
- const defaultArgs = ((_a = this.adb.executable) === null || _a === void 0 ? void 0 : _a.defaultArgs) || [];
165
- const args = [...defaultArgs, '-s', this.deviceUDID, 'shell', 'cat', '/proc/cpuinfo'];
166
- const out = yield (0, teen_process_1.exec)(((_b = this.adb.executable) === null || _b === void 0 ? void 0 : _b.path) || 'adb', args);
167
- return ((_c = out.stdout.match(/processor/g)) === null || _c === void 0 ? void 0 : _c.length) || 0;
168
- });
169
- }
170
- getTotalMemory() {
171
- return __awaiter(this, void 0, void 0, function* () {
172
- var _a, _b;
173
- const defaultArgs = ((_a = this.adb.executable) === null || _a === void 0 ? void 0 : _a.defaultArgs) || [];
174
- const args = [...defaultArgs, '-s', this.deviceUDID, 'shell', 'cat', '/proc/meminfo'];
175
- const out = yield (0, teen_process_1.exec)(((_b = this.adb.executable) === null || _b === void 0 ? void 0 : _b.path) || 'adb', args);
176
- const match = out.stdout.match(/MemTotal:.*[0-9]/g);
177
- if (match && match.length) {
178
- return match[0].replace(/[^0-9]/g, '');
179
- }
180
- return 0;
181
- });
182
- }
183
- getSystemCpuUsage(logLine) {
184
- if (!logLine) {
185
- return 0;
186
- }
187
- const data = {};
188
- ['cpu', 'idle'].forEach((type) => {
189
- const match = logLine.match(new RegExp(`([0-9]{0,})%${type}`));
190
- data[type] = match && match.length > 1 ? Number(match[1]) : 0;
191
- });
192
- let out = 0;
193
- ['user', 'nice', 'sys', 'iow', 'irq', 'sirq', 'host'].forEach((type) => {
194
- const match = logLine.match(new RegExp(`([0-9]{0,})%${type}`));
195
- out += match && match.length > 1 ? Number(match[1]) : 0;
196
- });
197
- return out > data['cpu'] ? data['cpu'] : out;
198
- }
199
- getSystemMemoryUsage(logLine) {
200
- if (!logLine) {
201
- return 0;
202
- }
203
- let match = logLine.match(new RegExp(/([0-9]{0,})k used/i));
204
- /* In some devices, memory will be shown in GB, so convert it back to KB */
205
- if (!match) {
206
- /* sample logLine "Mem: 5.5G total, 5.4G used, 71M free, 36M buffers" */
207
- match = logLine.match(new RegExp(/(([1-9]\d*)(\.\d+)?)G used/i));
208
- return match && match.length > 1 ? Math.ceil(parseFloat(match[1]) * 1024 * 1024) : 0;
209
- }
210
- return match && match.length > 1 ? Number(match[1]) : 0;
211
- }
212
- }
213
- exports.AndroidAppProfiler = AndroidAppProfiler;