@xenon-device-management/xenon 2.5.0 → 2.6.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 (81) hide show
  1. package/lib/package.json +1 -1
  2. package/lib/public/assets/{AnnotationOverlay-BeypNvFL.js → AnnotationOverlay-PMj0TMCJ.js} +1 -1
  3. package/lib/public/assets/{ApiKeyGate-CQg51mzi.js → ApiKeyGate-DXo-ecxe.js} +1 -1
  4. package/lib/public/assets/BugReportButton-DY9ltq27.js +15 -0
  5. package/lib/public/assets/{DeviceMosaicView-BnEKlOi9.js → DeviceMosaicView-CT7nA_re.js} +1 -1
  6. package/lib/public/assets/{EmptyState-CVk_39sG.js → EmptyState-DX4jwZ9l.js} +1 -1
  7. package/lib/public/assets/{FieldGroup-DC4jWFOr.js → FieldGroup-Czk8gPhv.js} +1 -1
  8. package/lib/public/assets/{FilterMenu-Df4ApWT_.js → FilterMenu-DTblXm4v.js} +1 -1
  9. package/lib/public/assets/{Menu-BZcyp6Df.js → Menu-CdGgXICe.js} +1 -1
  10. package/lib/public/assets/{Modal-D27eM9ja.js → Modal-CtzTciQY.js} +1 -1
  11. package/lib/public/assets/{RecordingPage-ScK_NxUR.js → RecordingPage-BjJH7AyA.js} +1 -1
  12. package/lib/public/assets/{RecordingsPage-DO6KsDwr.js → RecordingsPage-BkgX2xkA.js} +1 -1
  13. package/lib/public/assets/{SegmentedControl-P0_wzUSa.js → SegmentedControl-DEXgl8Qw.js} +1 -1
  14. package/lib/public/assets/{SettingCard-CnbZajUY.js → SettingCard-BnwAoJhk.js} +1 -1
  15. package/lib/public/assets/{Table-DCLEpILV.js → Table-hmNY-ICS.js} +1 -1
  16. package/lib/public/assets/{activity-c-lgQI29.js → activity-Bmuu2fcZ.js} +1 -1
  17. package/lib/public/assets/{ai-settings-S4Qb0zMX.js → ai-settings-uAzHwRK_.js} +1 -1
  18. package/lib/public/assets/{api-keys-B8OZRdWq.js → api-keys-CFZeXLs7.js} +1 -1
  19. package/lib/public/assets/{apps-BUdm1f-6.js → apps-DgwQRGg6.js} +1 -1
  20. package/lib/public/assets/{arrow-left-DuWnjija.js → arrow-left-D5x8OLs-.js} +1 -1
  21. package/lib/public/assets/{arrow-right-9qDEU3uD.js → arrow-right-DRYGEjl5.js} +1 -1
  22. package/lib/public/assets/{arrow-up-right-b6Of0lQ3.js → arrow-up-right-DLtHJsd6.js} +1 -1
  23. package/lib/public/assets/{auth-shell-DM7UlvlL.js → auth-shell-D_TLCi0Y.js} +2 -2
  24. package/lib/public/assets/builds-page-CwKR7w5o.js +11 -0
  25. package/lib/public/assets/{button-D2poE4AT.js → button-CbVMa9PL.js} +1 -1
  26. package/lib/public/assets/{calendar-BwZZxp7_.js → calendar-DgmwU-Oq.js} +1 -1
  27. package/lib/public/assets/{check-bpRVp-8m.js → check-Du5vvLoJ.js} +1 -1
  28. package/lib/public/assets/{chevron-left-o5fCPIVE.js → chevron-left-CiRlzB7w.js} +1 -1
  29. package/lib/public/assets/{chevron-right-Bp0cGaHf.js → chevron-right-i93nTPHX.js} +1 -1
  30. package/lib/public/assets/{circle-check-C7h_YWkh.js → circle-check-DxYO7yp5.js} +1 -1
  31. package/lib/public/assets/{circle-x-BevILQ_g.js → circle-x-Dw1DFg0I.js} +1 -1
  32. package/lib/public/assets/{clock-BEKymxJ4.js → clock-0q-GqRU0.js} +1 -1
  33. package/lib/public/assets/{copy-R5Kb2Sya.js → copy-Ds-F075f.js} +1 -1
  34. package/lib/public/assets/{device-explorer-DuD_PXL0.js → device-explorer-Dsldlx2g.js} +54 -59
  35. package/lib/public/assets/{download-CUlaFpHe.js → download-BdJEWL8b.js} +1 -1
  36. package/lib/public/assets/{forgot-password-CHO8yPDz.js → forgot-password-D7eNuw-V.js} +1 -1
  37. package/lib/public/assets/{funnel-uB2CBRiY.js → funnel-CY3Ovebz.js} +1 -1
  38. package/lib/public/assets/{index-KgmoUqNo.js → index-BpJwb7cQ.js} +1 -1
  39. package/lib/public/assets/{index-DSFSk-0t.css → index-C8pvxG1f.css} +1 -1
  40. package/lib/public/assets/{index-yibbsLFD.js → index-tW_VASh2.js} +2 -2
  41. package/lib/public/assets/{input-BR-cDtqC.js → input-DvCYrL_q.js} +1 -1
  42. package/lib/public/assets/{keycodes-dLBaFcVi.js → keycodes-CyOBCkU6.js} +1 -1
  43. package/lib/public/assets/{layers-BESinxSO.js → layers-ChEcsAc2.js} +1 -1
  44. package/lib/public/assets/{list-checks-DpKchgZl.js → list-checks-EWcywAEC.js} +1 -1
  45. package/lib/public/assets/{lock--sC5e3s6.js → lock-DmkRlmQB.js} +1 -1
  46. package/lib/public/assets/{login-Cc-IivWH.js → login-BXeYWAn-.js} +1 -1
  47. package/lib/public/assets/{maintenance-settings-CO1mxmXj.js → maintenance-settings-Cd37WZ5e.js} +1 -1
  48. package/lib/public/assets/{monitor-Cf5xQDkm.js → monitor-BTqiDmvk.js} +1 -1
  49. package/lib/public/assets/{mouse-pointer-2-D0FTHFsu.js → mouse-pointer-2-BrwX4M5d.js} +1 -1
  50. package/lib/public/assets/{network-BDR_XEsw.js → network-8uySyPSM.js} +1 -1
  51. package/lib/public/assets/{overview-Bgr23HrL.js → overview-CdBGYC95.js} +1 -1
  52. package/lib/public/assets/{page-header-mkEQJJPW.js → page-header-BYzd5kfp.js} +1 -1
  53. package/lib/public/assets/{plus-BGTOA7GD.js → plus-BIekJsya.js} +1 -1
  54. package/lib/public/assets/{profile-page-hogPzCrJ.js → profile-page-a-nQ7xFX.js} +1 -1
  55. package/lib/public/assets/{reset-password-BobaiMBQ.js → reset-password-7Gbj29w1.js} +1 -1
  56. package/lib/public/assets/{runbook-page-qw6u9fmW.js → runbook-page-Bgd9u7W6.js} +1 -1
  57. package/lib/public/assets/{select-skq1Kjsx.js → select-DEpRzm_3.js} +1 -1
  58. package/lib/public/assets/{selector-detail-page-BJl3YxfV.js → selector-detail-page-CvqjXfvp.js} +1 -1
  59. package/lib/public/assets/{selector-health-CMmIKYip.js → selector-health-BEzkwE_K.js} +1 -1
  60. package/lib/public/assets/{selector-health-page-DR8zYoS9.js → selector-health-page-Dl_IE1Je.js} +1 -1
  61. package/lib/public/assets/session-detail-page-CuF_EwRE.js +4 -0
  62. package/lib/public/assets/{settings-rZ0cTErR.js → settings-CxLw5tlF.js} +1 -1
  63. package/lib/public/assets/stat-tile-DFuoxV5Y.js +6 -0
  64. package/lib/public/assets/{tablet-C08V4-n2.js → tablet-DJBOerD6.js} +1 -1
  65. package/lib/public/assets/{teams-9lNK5Hv4.js → teams-CDQQdVRl.js} +1 -1
  66. package/lib/public/assets/{trash-2-Uko_-EoJ.js → trash-2-B_zQvjI3.js} +1 -1
  67. package/lib/public/assets/{upload-CyTBX5YJ.js → upload-9FV8q3NB.js} +1 -1
  68. package/lib/public/assets/{use-password-reset-mode-BQkqB45G.js → use-password-reset-mode-Cx5GHMnk.js} +1 -1
  69. package/lib/public/assets/{users-CQKCMBqe.js → users-DC0IoOuZ.js} +1 -1
  70. package/lib/public/assets/{users-D7RusV-M.js → users-ep-SOGaV.js} +1 -1
  71. package/lib/public/assets/{video-off-CWBbZnqz.js → video-off-BmUg-gKW.js} +1 -1
  72. package/lib/public/assets/{webhook-settings-Q3AJC_pt.js → webhook-settings-CwUBzLGC.js} +1 -1
  73. package/lib/public/assets/{zap-CN2fMC_t.js → zap-CBld_5xf.js} +1 -1
  74. package/lib/public/index.html +2 -2
  75. package/lib/src/app/routers/dashboard.js +3 -1
  76. package/lib/test/unit/session-list-insights.spec.js +25 -0
  77. package/package.json +1 -1
  78. package/lib/public/assets/BugReportButton-JVduDicX.js +0 -10
  79. package/lib/public/assets/builds-page-AOQqU3g3.js +0 -16
  80. package/lib/public/assets/session-detail-page-Cpbl4HPh.js +0 -3
  81. package/lib/public/assets/use-builds-data-TVBd_s-l.js +0 -1
@@ -189,6 +189,31 @@ describe('Sessions page data', () => {
189
189
  (0, chai_1.expect)(res.body[0].ranOn).to.equal(null);
190
190
  }));
191
191
  });
192
+ describe('GET /session/:id', () => {
193
+ // The detail page's header names who ran the session and where, as its row does.
194
+ it('says who ran the session and where, as the list does', () => __awaiter(void 0, void 0, void 0, function* () {
195
+ yield user('u-priya', 'Priya Shah', 'priya@example.com');
196
+ yield scratch.db.device.create({
197
+ data: {
198
+ udid: 'node-phone',
199
+ host: 'http://10.0.0.9:4725',
200
+ nodeId: 'node-2',
201
+ platform: 'ios',
202
+ },
203
+ });
204
+ yield session({
205
+ id: 'one',
206
+ user_id: 'u-priya',
207
+ node_id: 'node-2',
208
+ device_udid: 'node-phone',
209
+ });
210
+ const res = yield (0, loopbackRequest_1.default)(app()).get('/session/one');
211
+ (0, chai_1.expect)(res.status).to.equal(200);
212
+ (0, chai_1.expect)(res.body.id).to.equal('one');
213
+ (0, chai_1.expect)(res.body.owner).to.deep.equal({ name: 'Priya Shah', email: 'priya@example.com' });
214
+ (0, chai_1.expect)(res.body.ranOn).to.equal('10.0.0.9:4725');
215
+ }));
216
+ });
192
217
  describe('GET /session-summary', () => {
193
218
  it('summarizes the period and the one before it, of the same length', () => __awaiter(void 0, void 0, void 0, function* () {
194
219
  const build = yield scratch.db.build.create({ data: { name: 'nightly' } });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xenon-device-management/xenon",
3
- "version": "2.5.0",
3
+ "version": "2.6.0",
4
4
  "description": "Xenon - Intelligent Mobile Infrastructure. A self-healing device orchestration platform for Appium.",
5
5
  "main": "./lib/src/index.js",
6
6
  "exports": {
@@ -1,10 +0,0 @@
1
- import{c as m,j as o,r as f,t as g,f as b}from"./index-yibbsLFD.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 x=[["path",{d:"M12 20v-9",key:"1qisl0"}],["path",{d:"M14 7a4 4 0 0 1 4 4v3a6 6 0 0 1-12 0v-3a4 4 0 0 1 4-4z",key:"uouzyp"}],["path",{d:"M14.12 3.88 16 2",key:"qol33r"}],["path",{d:"M21 21a4 4 0 0 0-3.81-4",key:"1b0z45"}],["path",{d:"M21 5a4 4 0 0 1-3.55 3.97",key:"5cxbf6"}],["path",{d:"M22 13h-4",key:"1jl80f"}],["path",{d:"M3 21a4 4 0 0 1 3.81-4",key:"1fjd4g"}],["path",{d:"M3 5a4 4 0 0 0 3.55 3.97",key:"1d7oge"}],["path",{d:"M6 13H2",key:"82j7cp"}],["path",{d:"m8 2 1.88 1.88",key:"fmnt4t"}],["path",{d:"M9 7.13V6a3 3 0 1 1 6 0v1.13",key:"1vgav8"}]],h=m("bug",x),v=({tone:e="neutral",children:r,title:s,className:t})=>o.jsx("span",{className:`pill pill-${e}${t?` ${t}`:""}`,title:s,children:r});async function y(e){const r=new URLSearchParams({mode:e.mode});e.mode==="slice"&&e.windowSec&&r.set("windowSec",String(e.windowSec));const s=`/xenon/api/sessions/${encodeURIComponent(e.sessionId)}/bug-report?${r.toString()}`,t=await fetch(s,{method:"POST"});if(!t.ok){let u=`HTTP ${t.status}`;try{const p=await t.json();p&&p.error&&(u=p.error)}catch{}throw new Error(u)}const a=t.headers.get("content-disposition")||"",n=/filename="([^"]+)"/.exec(a),d=n?n[1]:`bugreport-${e.sessionId}.zip`,c=await t.blob(),l=URL.createObjectURL(c),i=document.createElement("a");i.href=l,i.download=d,document.body.appendChild(i),i.click(),document.body.removeChild(i),URL.revokeObjectURL(l)}const j=({sessionId:e,mode:r,windowSec:s,variant:t})=>{const[a,n]=f.useState(!1),{toast:d}=g();async function c(){if(!a){n(!0);try{await y({sessionId:e,mode:r,windowSec:s}),d("Bug report downloaded","success")}catch(l){d(`Bug report failed: ${l.message}`,"error")}finally{n(!1)}}}return t==="floating"?o.jsxs("button",{type:"button",onClick:c,disabled:a,title:`Capture last ${s??60}s as bug report`,"aria-label":"Generate bug report",className:`fixed bottom-4 right-4 z-30 inline-flex items-center gap-2 px-3 py-2 rounded-full
7
- bg-[var(--surface-2)] border border-[var(--border)] text-xs text-[var(--text)]
8
- shadow-lg hover:bg-[var(--surface-raised)] disabled:opacity-50`,children:[a?o.jsx(b,{className:"h-3.5 w-3.5 animate-spin"}):o.jsx(h,{className:"h-3.5 w-3.5"}),"Bug report"]}):o.jsxs("button",{type:"button",onClick:c,disabled:a,title:"Download a zip of this session for ticketing",className:`inline-flex items-center gap-1.5 px-3 py-1.5 rounded text-xs
9
- bg-[var(--surface-2)] hover:bg-[var(--surface-raised)] border border-[var(--border)]
10
- text-[var(--text)] disabled:opacity-50`,children:[a?o.jsx(b,{className:"h-3.5 w-3.5 animate-spin"}):o.jsx(h,{className:"h-3.5 w-3.5"}),"Download bug report"]})};export{j as B,v as P};
@@ -1,16 +0,0 @@
1
- import{c as G,r as h,p as se,X as H,j as e,z as X,R as B,f as ae,T as re,q as ne,u as le,i as oe,t as ie,M as ce}from"./index-yibbsLFD.js";import{s as de,b as I,P as xe,T,i as ue,f as V,a as W,c as me,d as pe,p as he,e as ve,r as fe,g as be,h as ge,j as D,k as je,l as J,m as Ne,n as ye,u as we,S as Se}from"./use-builds-data-TVBd_s-l.js";import{I as K}from"./input-BR-cDtqC.js";import{L as $e}from"./layers-BESinxSO.js";import{B as P}from"./button-D2poE4AT.js";import{D as ke}from"./download-CUlaFpHe.js";import{s as Ce}from"./labels-C21SA4JG.js";import{C as Me}from"./circle-x-BevILQ_g.js";import{C as Re}from"./circle-check-C7h_YWkh.js";import{C as Te}from"./chevron-right-Bp0cGaHf.js";import{T as Ee}from"./tablet-C08V4-n2.js";import{M as Be}from"./monitor-Cf5xQDkm.js";import{P as Ie}from"./page-header-mkEQJJPW.js";import{S as _e}from"./select-skq1Kjsx.js";import{E as F}from"./EmptyState-CVk_39sG.js";import{L as Le}from"./list-checks-DpKchgZl.js";import"./time-B8FIgwPE.js";import"./utils-CDN07tui.js";/**
2
- * @license lucide-react v0.555.0 - ISC
3
- *
4
- * This source code is licensed under the ISC license.
5
- * See the LICENSE file in the root directory of this source tree.
6
- */const De=[["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"}]],Oe=G("circle-dashed",De);/**
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 Ae=[["path",{d:"M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",key:"14sxne"}],["path",{d:"M3 3v5h5",key:"1xhq8a"}],["path",{d:"M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16",key:"1hlbsb"}],["path",{d:"M16 16h5v5",key:"ccwih5"}]],Pe=G("refresh-ccw",Ae),Fe=15e3;function Ue(t,a){const[s,r]=h.useState(null),c=h.useRef(!0),d=h.useRef(0),{on:u}=se(),o=h.useCallback(async()=>{const x=++d.current;try{const m=await H.getSessionSummary(a?{buildId:a}:{since:de(t,Date.now())});c.current&&x===d.current&&m&&m.current&&r(m)}catch{}},[t,a]);return h.useEffect(()=>{c.current=!0,r(null),o();const x=setInterval(o,Fe);return()=>{c.current=!1,clearInterval(x)}},[o]),h.useEffect(()=>{const x=[u("session_started",o),u("session_stopped",o)];return()=>{for(const m of x)m()}},[u,o]),s}const U=(t,a)=>`${t} ${a}${t===1?"":"s"}`,ze=({build:t})=>{const{passedCount:a,failedCount:s,runningCount:r,sessionCount:c}=t,d=Math.max(0,c-a-s-r);if(c===0)return null;const u=[a>0&&`${a} passed`,s>0&&`${s} failed`,r>0&&`${r} running`,d>0&&`${d} without a verdict`].filter(Boolean);return e.jsxs("div",{role:"img","aria-label":u.join(", "),title:u.join(", "),className:"mt-2 flex h-1 w-full gap-px overflow-hidden rounded-full bg-[rgb(var(--rgb-fg)/0.08)]",children:[a>0&&e.jsx("span",{className:"bg-[var(--color-success)]",style:{flexGrow:a}}),s>0&&e.jsx("span",{className:"bg-[var(--color-danger)]",style:{flexGrow:s}}),r>0&&e.jsx("span",{className:"bg-[var(--color-warning)]",style:{flexGrow:r}}),d>0&&e.jsx("span",{style:{flexGrow:d}})]})},z=({active:t,onClick:a,children:s})=>e.jsxs("button",{type:"button",onClick:a,"aria-current":t?"true":void 0,className:`w-full text-left relative px-4 py-2.5 transition-colors ${t?"bg-[var(--surface-2)]":"hover:bg-[rgb(var(--rgb-fg)/0.04)]"}`,children:[t&&e.jsx("span",{className:"absolute left-0 top-2 bottom-2 w-[3px] rounded-r bg-[var(--color-accent)]"}),s]}),qe=({builds:t,selectedBuildId:a,onSelect:s,timeFilter:r})=>{const[c,d]=h.useState(""),u=c.trim().toLowerCase(),o=Date.now(),x=t.filter(n=>{if(u&&!`${I(n)} ${n.name??""} ${n.id}`.toLowerCase().includes(u))return!1;if(r!=="all"){const l=Date.parse(String(n.createdAt));if(!Number.isFinite(l)||o-l>xe[r])return!1}return!0}),m=u?"No builds match.":r!=="all"?`No builds in the ${T[r].toLowerCase()}.`:"No builds yet. They appear here after your first test run.";return e.jsxs("aside",{className:"w-[280px] shrink-0 border-r border-[var(--border)] bg-[var(--surface)] flex flex-col min-h-0",children:[e.jsx("div",{className:"p-3 border-b border-[var(--border)]",children:e.jsxs("div",{className:"relative",children:[e.jsx(X,{className:"absolute left-2.5 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-[var(--text-dim)]"}),e.jsx(K,{type:"text",value:c,onChange:n=>d(n.target.value),placeholder:"Find builds…","aria-label":"Find builds",className:"w-full h-8 pl-8 pr-2 text-xs"})]})}),e.jsxs("div",{role:"group","aria-label":"Builds",className:"flex-1 overflow-y-auto py-1",children:[e.jsxs(z,{active:a===null,onClick:()=>s(null),children:[e.jsxs("div",{className:"flex items-center gap-2 text-[13px] font-medium text-[var(--text)]",children:[e.jsx($e,{className:"h-3.5 w-3.5 text-[var(--text-dim)]","aria-hidden":"true"}),"All sessions"]}),e.jsxs("div",{className:"mt-0.5 text-[11px] text-[var(--text-muted)]",children:[T[r],", every build"]})]}),e.jsx("div",{className:"px-4 pt-3 pb-1 text-[11px] font-medium text-[var(--text-dim)]",children:"Builds"}),x.length===0&&e.jsx("div",{className:"px-4 py-6 text-xs text-[var(--text-dim)]",children:m}),x.map(n=>{const l=ue(n),j=l?U(n.sessionCount,"session"):`${V(n.createdAt)} · ${U(n.sessionCount,"session")}`;return e.jsxs(z,{active:n.id===a,onClick:()=>s(n.id),children:[e.jsx("div",{className:`text-[13px] font-medium truncate ${l?"text-[var(--text-muted)]":"text-[var(--text)]"}`,title:n.name||void 0,children:I(n)}),e.jsx("div",{className:"mt-0.5 text-[11px] text-[var(--text-muted)] tabular-nums",children:j}),e.jsx(ze,{build:n})]},n.id)})]})]})},Ge={neutral:"bg-[var(--text-dim)]",green:"bg-[var(--color-success)]",red:"bg-[var(--red)]",amber:"bg-[var(--amber)]",blue:"bg-[var(--blue)]"},E=({label:t,count:a,active:s,onClick:r,tone:c="neutral",bullet:d=!0})=>e.jsxs("button",{type:"button",onClick:r,"aria-pressed":s,className:`inline-flex items-center gap-2 h-8 px-3 rounded-md border text-[11px] font-semibold transition-colors cursor-pointer ${s?"bg-[var(--surface-2)] border-[var(--border-strong)] text-[var(--text)]":"bg-transparent border-transparent text-[var(--text-muted)] hover:text-[var(--text)] hover:bg-[var(--surface-2)]/50"}`,children:[d&&c!=="neutral"&&e.jsx("span",{className:`h-1.5 w-1.5 rounded-full ${Ge[c]}`}),e.jsx("span",{children:t}),typeof a=="number"&&e.jsx("span",{className:"font-mono text-[10px] text-[var(--text-dim)]",children:a})]}),He=({sessions:t,active:a,onChange:s,search:r,onSearchChange:c,totalMatching:d,totalUnfiltered:u,capped:o=!1})=>{const x=W(t);return e.jsxs("div",{className:"flex items-center gap-3 px-4 py-2.5 border-b border-[var(--border)] bg-[var(--surface)]",children:[e.jsxs("div",{role:"group","aria-label":"Status",className:"flex items-center gap-1.5",children:[e.jsx(E,{label:"All",count:x.all,active:a==="all",onClick:()=>s("all"),tone:"neutral",bullet:!1}),e.jsx(E,{label:"Passed",count:x.passed,active:a==="passed",onClick:()=>s("passed"),tone:"green"}),e.jsx(E,{label:"Failed",count:x.failed,active:a==="failed",onClick:()=>s("failed"),tone:"red"}),e.jsx(E,{label:"Running",count:x.running,active:a==="running",onClick:()=>s("running"),tone:"amber"})]}),e.jsxs("span",{className:"ml-auto text-[11px] text-[var(--text-dim)] tabular-nums whitespace-nowrap",children:[d," of ",u," sessions",o?" (the newest)":""]}),e.jsxs("div",{className:"relative w-64 shrink-0",children:[e.jsx(X,{className:"absolute left-2.5 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-[var(--text-dim)]"}),e.jsx(K,{type:"text",value:r,onChange:m=>c(m.target.value),placeholder:"Search tests, devices, people…","aria-label":"Search sessions",className:"w-full h-8 pl-8 pr-2 text-xs"})]})]})};function Xe(t){return(t.split("-")[0]||t).slice(0,8).toUpperCase()}const Ve=({build:t,failedCount:a,selectedCount:s,onRetryFailed:r,onExport:c})=>{const d=a>0||s>0,[u,o]=B.useState(!1),x=B.useRef(null);B.useEffect(()=>{const n=l=>{x.current&&!x.current.contains(l.target)&&o(!1)};return document.addEventListener("mousedown",n),()=>document.removeEventListener("mousedown",n)},[]);const m=d?`Retry ${s||a} session${(s||a)===1?"":"s"}`:"No failed sessions to retry";return e.jsxs("header",{className:"flex items-start justify-between gap-4 px-4 py-3 border-b border-[var(--border)] bg-[var(--surface)]",children:[e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center gap-2 text-[11px] text-[var(--text-dim)]",children:[e.jsx("span",{children:"Build"}),e.jsxs("span",{className:"font-mono text-[var(--color-accent)]",title:t.id,children:["#",Xe(t.id)]}),e.jsx("span",{"aria-hidden":"true",children:"·"}),e.jsxs("span",{className:"tabular-nums",children:["Started ",V(t.createdAt)]})]}),e.jsx("h2",{className:"mt-0.5 text-sm font-semibold text-[var(--text)]",children:I(t)})]}),e.jsxs("div",{className:"flex items-center gap-2",ref:x,children:[e.jsxs(P,{type:"button",variant:"secondary",size:"sm",onClick:r,disabled:!d,title:m,className:"gap-1.5",children:[e.jsx(Pe,{className:"h-3.5 w-3.5"}),"Retry failed"]}),e.jsxs("div",{className:"relative",children:[e.jsxs(P,{type:"button",variant:"secondary",size:"sm",onClick:()=>o(n=>!n),className:"gap-1.5",children:[e.jsx(ke,{className:"h-3.5 w-3.5"}),"Export"]}),u&&e.jsxs("div",{className:"absolute top-full right-0 mt-1 w-40 rounded-md border border-[var(--border)] bg-[var(--surface)] shadow-lg overflow-hidden z-20",children:[e.jsx("button",{type:"button",onClick:()=>{o(!1),c("json")},className:"w-full text-left px-3 py-2 text-xs text-[var(--text)] hover:bg-[var(--surface-2)]",children:"Export as JSON"}),e.jsx("button",{type:"button",onClick:()=>{o(!1),c("csv")},className:"w-full text-left px-3 py-2 text-xs text-[var(--text)] hover:bg-[var(--surface-2)]",children:"Export as CSV"})]})]})]})]})};function We({platform:t}){const a=(t||"").toLowerCase(),s="h-3.5 w-3.5 shrink-0 text-[var(--text-dim)]";return a.includes("tv")?e.jsx(re,{className:s}):a.includes("pad")||a.includes("tablet")?e.jsx(Ee,{className:s}):a.includes("android")||a.includes("ios")?e.jsx(ne,{className:s}):e.jsx(Be,{className:s})}const Je={passed:{label:"Passed",Icon:Re,cls:"text-[var(--color-success)]"},failed:{label:"Failed",Icon:Me,cls:"text-[var(--color-danger)]"},running:{label:"Running",Icon:ae,cls:"text-[var(--color-warning)]"},other:{Icon:Oe,cls:"text-[var(--text-dim)]"}},Ke="Unnamed session. Set xe:options.name in its capabilities to name it.",Qe=({session:t,buildName:a,showBuild:s,showSelection:r,selected:c,onToggleSelect:d,onOpen:u})=>{var N,$,k;const o=me(t.status),x=Je[o],m=o==="failed",n=pe(t),l=m?(N=t.failure_reason)==null?void 0:N.trim():"",j=[he(t),t.device_version].filter(v=>v&&v!=="—").join(" "),S=[ve(t),j].filter(Boolean).join(" · "),f=[fe(t.ranOn),($=t.owner)==null?void 0:$.name].filter(Boolean).join(" · "),p=m?"shadow-[inset_3px_0_0_var(--color-danger)]":"";return e.jsxs("tr",{onClick:u,tabIndex:0,onKeyDown:v=>{v.target!==v.currentTarget||v.key!=="Enter"&&v.key!==" "||(v.preventDefault(),u())},"data-outcome":o,className:`group border-b border-[var(--border)] cursor-pointer transition-colors focus-visible:outline focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-[var(--color-focus-ring)] ${m?"bg-[rgb(var(--rgb-red)/0.04)] hover:bg-[rgb(var(--rgb-red)/0.08)]":"hover:bg-[var(--surface-2)]"}`,children:[r&&e.jsx("td",{className:`pl-4 pr-2 py-3 align-top ${p}`,onClick:v=>v.stopPropagation(),children:e.jsx("input",{type:"checkbox",checked:c,onChange:d,"aria-label":`Select session ${n.text}`})}),e.jsx("td",{className:`px-4 py-3 align-top ${r?"":p}`,children:e.jsxs("span",{className:`inline-flex items-center gap-1.5 text-xs font-medium ${x.cls}`,children:[e.jsx(x.Icon,{className:`h-3.5 w-3.5 shrink-0 ${o==="running"?"animate-spin":""}`,"aria-hidden":"true"}),x.label??Ce(t.status||"unknown")]})}),e.jsxs("td",{className:"px-3 py-3 align-top min-w-0",children:[e.jsx("div",{className:`text-[13px] font-medium truncate ${n.source==="name"?"text-[var(--text)]":"text-[var(--text-muted)]"}`,title:n.source==="name"?n.text:`${n.text}
12
- ${Ke}`,children:n.text}),l?e.jsx("div",{className:"mt-0.5 text-[11px] text-[var(--color-danger)] truncate",title:l,children:l}):s&&a&&e.jsx("div",{className:"mt-0.5 text-[11px] text-[var(--text-muted)] truncate",title:a,children:a})]}),e.jsxs("td",{className:"px-3 py-3 align-top min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-1.5 text-[13px] text-[var(--text)] min-w-0",children:[e.jsx(We,{platform:t.device_platform}),e.jsx("span",{className:"truncate",title:t.device_udid,children:S})]}),f&&e.jsx("div",{className:"mt-0.5 text-[11px] text-[var(--text-muted)] truncate",title:[t.ranOn==="here"?null:`Node ${t.node_id}`,(k=t.owner)==null?void 0:k.email].filter(Boolean).join(`
13
- `),children:f})]}),e.jsx("td",{className:"px-3 py-3 align-top text-xs text-[var(--text-muted)] tabular-nums whitespace-nowrap",title:ge(t.startTime),children:be(t.startTime)}),e.jsx("td",{className:"px-3 py-3 align-top text-xs text-[var(--text)] tabular-nums whitespace-nowrap text-right",children:D(je(t))}),e.jsx("td",{className:"pr-4 pl-1 py-3 align-top text-right",children:e.jsx(Te,{className:"inline h-4 w-4 text-[var(--text-dim)] group-hover:text-[var(--text)]","aria-hidden":"true"})})]})},R="px-3 py-2 text-[11px] font-medium text-[var(--text-dim)]",q=({sessions:t,statusFilter:a,searchQuery:s,buildNames:r,showBuild:c,showSelection:d,selectedIds:u,onToggleSelect:o,onToggleSelectAll:x,onOpenRow:m,empty:n})=>{const l=h.useMemo(()=>J(t,a,s),[t,a,s]);if(t.length===0)return e.jsx(e.Fragment,{children:n});if(l.length===0)return e.jsx("div",{className:"px-6 py-12 text-center text-xs text-[var(--text-dim)]",children:"No sessions match the current filters."});const j=l.every(p=>u.has(p.id)),S=l.some(p=>u.has(p.id)),f=l.some(p=>{var N;return!((N=p.name)!=null&&N.trim())});return e.jsxs("div",{className:"flex-1 overflow-y-auto",children:[e.jsxs("table",{className:"w-full text-left table-fixed",children:[e.jsx("thead",{className:"sticky top-0 bg-[var(--surface)] border-b border-[var(--border)] z-10",children:e.jsxs("tr",{children:[d&&e.jsx("th",{className:"pl-4 pr-2 py-2 w-[44px]",children:e.jsx("input",{type:"checkbox","aria-label":"Select all shown",checked:j,ref:p=>{p&&(p.indeterminate=S&&!j)},onChange:()=>x(l.map(p=>p.id))})}),e.jsx("th",{className:`${R} pl-4 w-[112px]`,children:"Status"}),e.jsx("th",{className:R,children:"Test"}),e.jsx("th",{className:`${R} w-[240px]`,children:"Device"}),e.jsx("th",{className:`${R} w-[124px]`,children:"Started"}),e.jsx("th",{className:`${R} w-[84px] text-right`,children:"Duration"}),e.jsx("th",{className:"w-[40px]",children:e.jsx("span",{className:"sr-only",children:"Open"})})]})}),e.jsx("tbody",{children:l.map(p=>e.jsx(Qe,{session:p,buildName:p.build_id?r.get(p.build_id):null,showBuild:c,showSelection:d,selected:u.has(p.id),onToggleSelect:()=>o(p.id),onOpen:()=>m(p)},p.id))})]}),f&&e.jsxs("p",{className:"px-4 py-3 text-[11px] text-[var(--text-dim)]",children:["Unnamed sessions show their app. Name a test with"," ",e.jsx("code",{className:"font-mono text-[var(--text-muted)]",children:"xe:options.name"})," and a run with"," ",e.jsx("code",{className:"font-mono text-[var(--text-muted)]",children:"xe:options.build"})," in its capabilities."]})]})},Ye={neutral:"text-[var(--text-muted)]",good:"text-[var(--color-success)]",bad:"text-[var(--color-danger)]"},w=({label:t,value:a,valueCls:s="text-[var(--text)]",note:r,noteTone:c="neutral"})=>e.jsxs("div",{className:"min-w-0 rounded-lg border border-[var(--border)] bg-[var(--surface)] px-4 py-3",children:[e.jsx("div",{className:"text-xs text-[var(--text-muted)]",children:t}),e.jsx("div",{className:`mt-1 text-2xl font-semibold tabular-nums leading-tight ${s}`,children:a}),e.jsx("div",{className:`mt-0.5 text-[11px] truncate ${Ye[c]}`,children:r??" "})]});function Ze(t,a){const s=Math.round(t);return s===0?{text:`No change vs prior ${a}`,tone:"neutral"}:s>0?{text:`+${s} pts vs prior ${a}`,tone:"good"}:{text:`−${-s} pts vs prior ${a}`,tone:"bad"}}const et=({summary:t,periodLabel:a})=>{if(!t)return e.jsxs("div",{className:"grid grid-cols-4 gap-3 px-6 py-3 border-b border-[var(--border)]",children:[e.jsx(w,{label:"Pass rate",value:"—"}),e.jsx(w,{label:"Failed",value:"—"}),e.jsx(w,{label:"Running now",value:"—"}),e.jsx(w,{label:"Median duration",value:"—"})]});const{current:s,previous:r,runningNow:c}=t,d=Ne(s),u=s.passed+s.failed,o=a?ye(s,r):null,x=o!==null?Ze(o,a):u>0?{text:`${s.passed} of ${u} passed`,tone:"neutral"}:{text:"No finished sessions",tone:"neutral"};return e.jsxs("div",{className:"grid grid-cols-4 gap-3 px-6 py-3 border-b border-[var(--border)]",children:[e.jsx(w,{label:"Pass rate",value:d===null?"—":`${Math.round(d)}%`,note:x.text,noteTone:x.tone}),e.jsx(w,{label:"Failed",value:s.failed,valueCls:s.failed>0?"text-[var(--color-danger)]":"text-[var(--text)]",note:`of ${s.total} session${s.total===1?"":"s"}`}),e.jsx(w,{label:"Running now",value:c.sessions,note:c.sessions>0?`on ${c.devices} device${c.devices===1?"":"s"}`:"Nothing running"}),e.jsx(w,{label:"Median duration",value:D(s.medianMs),note:s.p90Ms===null?"No finished sessions":`p90 ${D(s.p90Ms)}`})]})},tt={"24h":"24 hours","7d":"7 days","30d":"30 days"},st=`"xe:options": {
14
- "name": "Checkout happy path",
15
- "build": "Nightly smoke"
16
- }`,at=()=>e.jsxs("div",{className:"text-xs text-[var(--text-muted)]",children:[e.jsx("p",{children:"Name each test, and group a run, in its capabilities:"}),e.jsx("pre",{className:"mt-2 inline-block rounded-md border border-[var(--border)] bg-[var(--surface-2)] px-3 py-2 text-left font-mono text-[11px] text-[var(--text)]",children:st})]}),yt=()=>{const t=le(),{buildId:a}=oe(),{toast:s}=ie(),[r,c]=h.useState("7d"),[d,u]=h.useState("all"),[o,x]=h.useState(""),[m,n]=h.useState(new Set),l=we({withSessions:!0,timeFilter:r}),j=Ue(r,l.selectedBuildId),{selectBuild:S,selectedBuildId:f}=l;B.useEffect(()=>{const i=a??null;i!==f&&(S(i),n(new Set))},[a,f,S]);const p=i=>t(i?`/builds/${i}`:"/builds"),N=i=>t(`/builds/${encodeURIComponent(i.build_id||"none")}/sessions/${i.id}`),$=h.useCallback(i=>{n(b=>{const g=new Set(b);return g.has(i)?g.delete(i):g.add(i),g})},[]),k=h.useCallback(i=>{n(b=>{const g=i.length>0&&i.every(y=>b.has(y)),C=new Set(b);return g?i.forEach(y=>C.delete(y)):i.forEach(y=>C.add(y)),C})},[]),v=h.useMemo(()=>new Map(l.builds.map(i=>[i.id,I(i)])),[l.builds]),_=l.builds.find(i=>i.id===f)||null,Q=W(l.sessions),Y=()=>{s("Bulk retry lands in a future release.","info")},Z=async i=>{if(f)try{const b=m.size>0?Array.from(m):void 0,{blob:g,filename:C}=await H.exportBuild(f,i,b),y=URL.createObjectURL(g),M=document.createElement("a");M.href=y,M.download=C,document.body.appendChild(M),M.click(),document.body.removeChild(M),URL.revokeObjectURL(y);const A=b?b.length:"all";s(`Exported ${A} session${A===1?"":"s"} as ${i.toUpperCase()}.`,"success")}catch(b){const g=b instanceof Error?b.message:String(b);s(`Export failed: ${g}`,"error")}},L=f===null,ee=L&&r!=="all"?tt[r]:null,te=!L&&!_&&!l.loading,O=e.jsx(He,{sessions:l.sessions,active:d,onChange:u,search:o,onSearchChange:x,totalMatching:J(l.sessions,d,o).length,totalUnfiltered:l.sessions.length,capped:l.sessions.length>=Se});return e.jsxs("div",{className:"flex flex-col h-full",children:[e.jsx(Ie,{icon:ce,title:"Sessions",subtitle:"Every test session, newest first, with its build, device and outcome.",action:e.jsx(_e,{value:r,onChange:i=>c(i.target.value),selectSize:"sm","aria-label":"Period",className:"w-40 text-xs",children:Object.keys(T).map(i=>e.jsx("option",{value:i,children:T[i]},i))})}),e.jsx(et,{summary:j,periodLabel:ee}),e.jsxs("div",{className:"flex flex-1 min-h-0",children:[e.jsx(qe,{builds:l.builds,selectedBuildId:f,onSelect:p,timeFilter:r}),e.jsx("section",{className:"flex-1 flex flex-col min-w-0",children:te?e.jsx(F,{title:"This build isn’t available",description:"It may have been removed, or belong to a team you’re not on."}):L?e.jsxs(e.Fragment,{children:[e.jsx("h2",{className:"sr-only",children:"All sessions"}),O,e.jsx(q,{sessions:l.sessions,statusFilter:d,searchQuery:o,buildNames:v,showBuild:!0,showSelection:!1,selectedIds:m,onToggleSelect:$,onToggleSelectAll:k,onOpenRow:N,empty:l.loading?null:e.jsx("div",{className:"px-6 py-6",children:e.jsx(F,{icon:e.jsx(Le,{className:"h-5 w-5"}),title:r==="all"?"No sessions yet":`No sessions in the ${T[r].toLowerCase()}`,description:"Sessions appear here as your tests run.",action:e.jsx(at,{})})})})]}):_?e.jsxs(e.Fragment,{children:[e.jsx(Ve,{build:_,failedCount:Q.failed,selectedCount:m.size,onRetryFailed:Y,onExport:Z}),O,e.jsx(q,{sessions:l.sessions,statusFilter:d,searchQuery:o,buildNames:v,showBuild:!1,showSelection:!0,selectedIds:m,onToggleSelect:$,onToggleSelectAll:k,onOpenRow:N,empty:e.jsx("div",{className:"px-6 py-12 text-center text-xs text-[var(--text-dim)]",children:"No sessions in this build yet. Trigger one from your test runner."})})]}):null})]})]})};export{yt as BuildsPage,yt as default};
@@ -1,3 +0,0 @@
1
- import{r as x,X as C,t as $,j as e,e as B,y as Y,p as G,i as Q,u as q}from"./index-yibbsLFD.js";import{u as Z,b as ee,o as te,k as se,e as re,p as ae,q as ne,h as ie,c as oe}from"./use-builds-data-TVBd_s-l.js";import{B as le,P as g}from"./BugReportButton-JVduDicX.js";import{A as ce}from"./arrow-left-DuWnjija.js";import{C as A}from"./chevron-right-Bp0cGaHf.js";import{C as D}from"./copy-R5Kb2Sya.js";import{A as de}from"./arrow-up-right-b6Of0lQ3.js";import{V as xe}from"./video-off-CWBbZnqz.js";import{E}from"./EmptyState-CVk_39sG.js";import{T as me,a as ue,b as M,c as R,d as fe,e as _}from"./Table-DCLEpILV.js";import{M as he}from"./Modal-D27eM9ja.js";import{D as pe}from"./download-CUlaFpHe.js";import{N as ve}from"./network-BDR_XEsw.js";import{s as be}from"./labels-C21SA4JG.js";import"./time-B8FIgwPE.js";import"./index-KgmoUqNo.js";function ge(t){const[s,r]=x.useState(null),[n,a]=x.useState([]),[l,c]=x.useState([]),[o,d]=x.useState([]),[f,m]=x.useState([]),[h,v]=x.useState(!0),[N,w]=x.useState(null),[y,j]=x.useState(!1),[k,L]=x.useState(0);return x.useEffect(()=>{if(!t){r(null),a([]),c([]),d([]),m([]),j(!1),v(!1);return}let p=!0;return v(!0),Promise.all([C.getSession(t),C.getSessionLogs(t),C.getDeviceLogs(t),C.getDebugLogs(t),C.getProfilingData(t).catch(()=>[])]).then(([i,b,S,u,T])=>{if(!p)return;const H=i&&typeof i=="object"&&typeof i.id=="string"&&typeof i.status=="string";r(H?i:null),H?(j(!1),w(null)):(j(!!i&&typeof i=="object"&&(i.error===!0||typeof i.message=="string")),w(typeof(i==null?void 0:i.message)=="string"?i.message:"Session not found")),a(Array.isArray(b)?b:[]),c(Array.isArray(S)?S:[]),d(Array.isArray(u)?u:[]),m(Array.isArray(T)?T:[])}).catch(i=>{p&&w(i instanceof Error?i.message:String(i))}).finally(()=>{p&&v(!1)}),()=>{p=!1}},[t,k]),{session:s,sessionLogs:n,deviceLogs:l,debugLogs:o,profiling:f,loading:h,error:N,notFound:y,refresh:()=>L(p=>p+1)}}const J=({buildId:t,buildName:s,sessionId:r})=>{const{toast:n}=$(),a=async()=>{try{await navigator.clipboard.writeText(r),n("Session ID copied","success")}catch{n("Failed to copy (clipboard unavailable)","error")}};return e.jsxs("header",{className:"flex items-center gap-2 px-4 py-3 border-b border-[var(--border)] bg-[var(--surface)]",children:[e.jsxs(B,{to:"/builds",className:"inline-flex items-center gap-1.5 text-xs text-[var(--text-muted)] hover:text-[var(--text)] transition-colors",children:[e.jsx(ce,{className:"h-3.5 w-3.5"}),"Sessions"]}),e.jsx(A,{className:"h-3 w-3 text-[var(--text-dim)]"}),s&&e.jsxs(e.Fragment,{children:[e.jsx(B,{to:`/builds/${t}`,className:"text-[11px] text-[var(--color-accent)] hover:underline",children:s}),e.jsx(A,{className:"h-3 w-3 text-[var(--text-dim)]"})]}),e.jsxs("span",{className:"font-mono text-xs text-[var(--text)]",title:r,children:["#",r]}),e.jsx("button",{type:"button",onClick:a,"aria-label":"Copy session ID",className:"p-1 rounded text-[var(--text-dim)] hover:text-[var(--text)] hover:bg-[var(--surface-2)] transition-colors",children:e.jsx(D,{className:"h-3 w-3"})}),e.jsx("div",{className:"ml-auto",children:e.jsx(le,{sessionId:r,mode:"full",variant:"inline"})})]})},je={default:"text-[var(--text)]",red:"text-[var(--red)]",green:"text-[var(--color-success)]",amber:"text-[var(--amber)]"},O=({label:t,rows:s})=>e.jsxs("div",{className:"flex-1 min-w-0 p-4",children:[e.jsx("div",{className:"text-[11px] font-semibold text-[var(--text-dim)] mb-3",children:t}),e.jsx("dl",{className:"space-y-2",children:s.map((r,n)=>e.jsxs("div",{className:"flex items-baseline justify-between gap-3",children:[e.jsx("dt",{className:"text-[11px] text-[var(--text-dim)] shrink-0",children:r.label}),e.jsx("dd",{className:`text-xs text-right truncate min-w-0 ${r.mono?"font-mono":""} ${je[r.tone??"default"]}`,children:r.value})]},`${r.label}-${n}`))})]}),Ne=({identity:t,run:s,result:r})=>e.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-3 rounded-lg border border-[var(--border)] bg-[var(--surface)] divide-y md:divide-y-0 md:divide-x divide-[var(--border)]",children:[e.jsx(O,{label:"Identity",rows:t}),e.jsx(O,{label:"Run",rows:s}),e.jsx(O,{label:"Result",rows:r})]});function ye(t){if(!t||t.length===0)return null;const s=t.find(r=>r.is_success===!1);return s||(t[t.length-1]??null)}function we(t,s=8){if(!t)return[];const r=t.split(/\r?\n/),n=[];for(const a of r){const l=a.trim();if(/^at\s+/.test(l)&&(n.push(l),n.length>=s))break}return n}function F(t){return t?t.split(/[_\s]+/).filter(Boolean).map(s=>s.charAt(0).toUpperCase()+s.slice(1).toLowerCase()).join(" "):""}function U(t){if(!t)return{};try{const s=JSON.parse(t);return s&&typeof s=="object"&&!Array.isArray(s)?s:{}}catch{return{}}}function I(t,s=200){if(t==null)return"";if(typeof t=="string")return t;if(typeof t=="number"||typeof t=="boolean")return String(t);try{const r=JSON.stringify(t);return r.length>s?r.slice(0,s)+"…":r}catch{return String(t)}}function ke(t,s,r,n,a){var f;const l=F(t.failure_category),c=((f=t.device_name)==null?void 0:f.trim())||"Unknown Device",o=t.device_version?` ${t.device_version}`:"",d=(a==null?void 0:a.message)||(a?JSON.stringify(a).slice(0,200):"(no logs captured)");return[`**Session:** ${t.id}`,`**Build:** ${s} (#${r})`,`**Device:** ${c} (${t.node_id||"unknown-node"}) · ${t.device_platform||"unknown"}${o}`,`**Duration:** ${n}`,`**Failure category:** ${l||"(uncategorized)"}`,`**Failure reason:** ${t.failure_reason||"(not set)"}`,`**First error:** ${d}`].join(`
2
- `)}const Se=({session:t,buildName:s,buildId:r,allLogs:n,durationText:a})=>{const{toast:l}=$(),c=F(t.failure_category),o=ye(n),d=we(t.failure_reason),f=d.length>0,m=async()=>{const v=ke(t,s,r,a,o);try{await navigator.clipboard.writeText(v),l("Failure report copied","success")}catch{l("Clipboard unavailable","error")}},h=t.failure_category?`/xenon/runbooks/${encodeURIComponent(t.failure_category.toLowerCase())}`:void 0;return e.jsxs("section",{className:"rounded-lg border border-[var(--red)]/30 bg-[var(--surface)] overflow-hidden",children:[e.jsxs("header",{className:"flex items-center justify-between gap-4 px-4 py-3 border-b border-[var(--border)] bg-[var(--red)]/5",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(Y,{className:"h-4 w-4 text-[var(--red)]"}),e.jsx("span",{className:"text-sm font-semibold text-[var(--red)]",children:"Failure summary"}),c&&e.jsx("span",{className:"text-[11px] text-[var(--text-dim)] ml-2",children:c})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("button",{type:"button",onClick:m,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:[e.jsx(D,{className:"h-3 w-3"}),"Copy"]}),e.jsxs("a",{...h?{href:h,target:"_blank",rel:"noreferrer"}:{"aria-disabled":!0,onClick:v=>v.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 ${h?"":"opacity-50 cursor-not-allowed"}`,title:h?"Open runbook in new tab":"No runbook — failure category not set",children:[e.jsx(de,{className:"h-3 w-3"}),"Open runbook"]})]})]}),e.jsxs("div",{className:"px-4 py-4 space-y-4",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-[11px] font-semibold text-[var(--text-dim)] mb-1",children:"Reason"}),e.jsx("div",{className:"text-sm text-[var(--text)]",children:t.failure_reason||e.jsx("span",{className:"text-[var(--text-dim)]",children:"(not set)"})})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-[11px] font-semibold text-[var(--text-dim)] mb-1",children:"First error"}),e.jsx("div",{className:"text-sm text-[var(--text-muted)] min-w-0",children:o!=null&&o.message?e.jsx("span",{className:"break-words",children:o.message}):o?e.jsxs("dl",{className:"space-y-1 text-xs",children:[e.jsxs("div",{className:"flex gap-2 min-w-0",children:[e.jsx("dt",{className:"text-[var(--text-dim)] shrink-0 text-[11px]",children:"Command"}),e.jsx("dd",{className:"font-mono break-all",children:o.command_name||o.title||"—"})]}),o.subtitle&&e.jsxs("div",{className:"flex gap-2 min-w-0",children:[e.jsx("dt",{className:"text-[var(--text-dim)] shrink-0 text-[11px]",children:"Target"}),e.jsx("dd",{className:"font-mono break-all",children:o.subtitle})]}),o.response&&e.jsxs("div",{className:"flex gap-2 min-w-0",children:[e.jsx("dt",{className:"text-[var(--text-dim)] shrink-0 text-[11px]",children:"Response"}),e.jsx("dd",{className:"font-mono break-all",children:String(o.response).slice(0,400)})]})]}):e.jsx("span",{className:"text-[var(--text-dim)]",children:"(no logs captured before failure)"})})]}),f&&e.jsxs("div",{children:[e.jsx("div",{className:"text-[11px] font-semibold text-[var(--text-dim)] mb-1",children:"Stack trace"}),e.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:d.join(`
3
- `)})]})]})]})},Re=({session:t})=>{const s=t.status==="running",r=!!t.video_recording;return e.jsxs("section",{className:"rounded-lg border border-[var(--border)] bg-[var(--surface)] overflow-hidden",children:[e.jsxs("header",{className:"px-3 py-2 border-b border-[var(--border)] flex items-center justify-between",children:[e.jsx("span",{className:"text-[11px] font-semibold text-[var(--text-dim)]",children:"Recording"}),s&&e.jsxs("span",{className:"inline-flex items-center gap-1.5 text-[11px] text-[var(--red)]",children:[e.jsx("span",{className:"h-1.5 w-1.5 rounded-full bg-[var(--red)] pulse-dot"}),"Live"]})]}),e.jsx("div",{className:"aspect-video bg-[var(--bg)] flex items-center justify-center",children:s&&t.has_live_video?e.jsx("img",{src:C.getSessionLiveVideoUrl(t.id),alt:`Live view of session ${t.id}`,className:"w-full h-full object-contain"}):r?e.jsx("video",{controls:!0,src:C.getAssetUrl(t.video_recording),className:"w-full h-full object-contain"}):e.jsxs("div",{className:"flex flex-col items-center text-center px-6 py-8 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(xe,{className:"h-5 w-5 text-[var(--text-dim)]"})}),e.jsx("div",{className:"text-sm text-[var(--text)] font-medium",children:"No video available"}),e.jsx("div",{className:"text-xs text-[var(--text-dim)] max-w-xs",children:t.status==="failed"?"Session failed before recording started.":t.video_recording_enabled===!1?"Recording was disabled for this session.":"No recording was captured."})]})})]})},_e=({session:t})=>{const[s,r]=x.useState("desired"),n=U(t.desired_capabilities),a=U(t.session_capabilities),c=Object.entries(s==="desired"?n:a);return e.jsxs("section",{className:"rounded-lg border border-[var(--border)] bg-[var(--surface)] overflow-hidden",children:[e.jsx("header",{className:"flex items-center border-b border-[var(--border)]",children:["desired","session"].map(o=>e.jsx("button",{type:"button",onClick:()=>r(o),"aria-pressed":s===o,className:`flex-1 h-9 text-[11px] font-semibold transition-colors border-b-2 ${s===o?"border-[var(--color-accent)] text-[var(--text)]":"border-transparent text-[var(--text-muted)] hover:text-[var(--text)]"}`,children:o},o))}),c.length===0?e.jsxs("div",{className:"px-3 py-6 text-center text-xs text-[var(--text-dim)]",children:["No ",s," capabilities reported for this session."]}):e.jsx("dl",{className:"divide-y divide-[var(--border)]",children:c.map(([o,d])=>e.jsxs("div",{className:"flex items-baseline justify-between gap-3 px-3 py-2",children:[e.jsx("dt",{className:"text-xs text-[var(--text-muted)] truncate shrink-0 max-w-[45%]",children:o}),e.jsx("dd",{className:"font-mono text-xs text-[var(--text)] truncate text-right min-w-0",title:I(d,500),children:I(d)})]},o))})]})},Ce=({tabs:t,active:s,onChange:r,errorsOnly:n,onErrorsOnlyChange:a})=>{const l=t.filter(c=>!(c.hideWhenEmpty&&c.count===0));return e.jsxs("div",{className:"flex items-center justify-between gap-4 px-3 border-b border-[var(--border)] bg-[var(--surface)]",children:[e.jsx("div",{className:"flex items-center gap-1 overflow-x-auto",children:l.map(c=>{const o=c.key===s;return e.jsxs("button",{type:"button",onClick:()=>r(c.key),"aria-pressed":o,className:`relative inline-flex items-center gap-1.5 h-9 px-3 text-xs whitespace-nowrap transition-colors ${o?"text-[var(--text)]":"text-[var(--text-muted)] hover:text-[var(--text)]"}`,children:[e.jsx("span",{children:c.label}),e.jsx("span",{className:`font-mono text-[10px] ${o?"text-[var(--text-muted)]":"text-[var(--text-dim)]"}`,children:c.count}),o&&e.jsx("span",{className:"absolute left-2 right-2 bottom-0 h-[2px] bg-[var(--color-accent)] rounded-t"})]},c.key)})}),e.jsxs("label",{className:"inline-flex items-center gap-2 text-[11px] text-[var(--text-muted)] cursor-pointer select-none whitespace-nowrap",children:[e.jsx("input",{type:"checkbox",checked:n,onChange:c=>a(c.target.checked),"aria-label":"Show only error rows"}),"Errors only"]})]})};function W(t){const s=t.timestamp;if(!s){const c=t.createdAt;return c?W({timestamp:c}):"--:--:--"}const r=typeof s=="number"?new Date(s):new Date(String(s));if(Number.isNaN(r.getTime()))return"--:--:--";const n=String(r.getHours()).padStart(2,"0"),a=String(r.getMinutes()).padStart(2,"0"),l=String(r.getSeconds()).padStart(2,"0");return`${n}:${a}:${l}`}function Te(t){if(t.healed===!0)return{label:String(t.command_name||"healed"),tone:"amber"};if(t.is_success===!1)return{label:String(t.command_name||t.title||"error"),tone:"red"};if(t.is_success===!0)return{label:String(t.command_name||t.title||"ok"),tone:"green"};const s=t.title||t.event||t.command_name;return typeof s=="string"?/stop|fail|error/i.test(s)?{label:s,tone:"red"}:/start|begin|init/i.test(s)?{label:s,tone:"green"}:{label:s,tone:"blue"}:{label:"log",tone:"neutral"}}function $e(t){if(t==null)return"";if(typeof t=="string")try{return JSON.stringify(JSON.parse(t),null,2)}catch{return t}try{return JSON.stringify(t,null,2)}catch{return String(t)}}function De(t){if(!t||typeof t!="string")return[{text:String(t??""),kind:"plain"}];const s=[],r=/("(?:\\.|[^"\\])*")(\s*:)|("(?:\\.|[^"\\])*")|(-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?)|\b(true|false)\b|\b(null)\b|([{}[\],])/g;let n=0,a;for(;(a=r.exec(t))!==null;)a.index>n&&s.push({text:t.slice(n,a.index),kind:"plain"}),a[1]&&a[2]!==void 0?(s.push({text:a[1],kind:"key"}),s.push({text:a[2],kind:"punct"})):a[3]?s.push({text:a[3],kind:"string"}):a[4]?s.push({text:a[4],kind:"number"}):a[5]?s.push({text:a[5],kind:"boolean"}):a[6]?s.push({text:a[6],kind:"null"}):a[7]&&s.push({text:a[7],kind:"punct"}),n=r.lastIndex;return n<t.length&&s.push({text:t.slice(n),kind:"plain"}),s}function Le(t){const s=t,r=typeof s.title=="string"&&s.title.trim()?s.title.trim():null,n=typeof s.command_name=="string"&&s.command_name.trim()?s.command_name.trim():null;return r??n??"Command"}function V(t){const s=t.subtitle;return typeof s=="string"&&s.trim()?s.trim():null}function Ee(t,s){return s?t.filter(r=>r.is_success===!1):t}const Oe={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)]"},Ae=({value:t,maxHeightPx:s})=>{const r=$e(t);if(!r)return e.jsx("span",{className:"text-[var(--text-dim)] text-xs",children:"(empty)"});let n;try{n=De(r)}catch{n=[{text:r,kind:"plain"}]}return e.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:s?{maxHeight:s,overflowY:"auto"}:void 0,children:n.map((a,l)=>e.jsx("span",{className:Oe[a.kind],children:a.text},l))})},Fe={green:"bg-[var(--color-success)]",red:"bg-[var(--red)]",amber:"bg-[var(--amber)]",blue:"bg-[var(--blue)]",neutral:"bg-[var(--text-dim)]"},Pe={green:"text-[var(--color-success)]",red:"text-[var(--red)]",amber:"text-[var(--amber)]",blue:"text-[var(--blue)]",neutral:"text-[var(--text-muted)]"},He=({log:t})=>{const[s,r]=x.useState(!1),{toast:n}=$(),a=W(t),l=Te(t),c=async o=>{o.stopPropagation();try{const d=t.body??t,f=typeof d=="string"?d:JSON.stringify(d,null,2);await navigator.clipboard.writeText(f),n("Log entry copied","success")}catch{n("Clipboard unavailable","error")}};return e.jsxs("div",{className:"border-b border-[var(--border)] last:border-b-0",children:[e.jsxs("button",{type:"button",onClick:()=>r(o=>!o),"aria-expanded":s,className:"group w-full flex items-center gap-2 px-3 py-2 text-left hover:bg-[var(--surface-2)]/60 transition-colors",children:[e.jsx(A,{className:`h-3 w-3 text-[var(--text-dim)] transition-transform shrink-0 ${s?"rotate-90":""}`}),e.jsx("span",{className:"font-mono text-[11px] text-[var(--text-muted)] w-[64px] shrink-0",children:a}),e.jsx("span",{className:`h-1.5 w-1.5 rounded-full shrink-0 ${Fe[l.tone]}`}),e.jsx("span",{className:`font-mono text-[11px] font-medium shrink-0 ${Pe[l.tone]}`,children:l.label}),e.jsxs("span",{className:"min-w-0 flex-1 flex items-baseline gap-2 truncate",children:[e.jsx("span",{className:"text-[12px] text-[var(--text)] shrink-0",children:Le(t)}),V(t)&&e.jsx("span",{className:"font-mono text-[11px] text-[var(--text-dim)] truncate min-w-0",children:V(t)})]}),e.jsx("span",{role:"button",tabIndex:0,onClick:c,onKeyDown:o=>{(o.key==="Enter"||o.key===" ")&&c(o)},"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:e.jsx(D,{className:"h-3 w-3"})})]}),s&&e.jsx("div",{className:"px-3 pb-3 pl-9",children:e.jsx(Ae,{value:t.body??t,maxHeightPx:400})})]})},Be=({sessionLogs:t,deviceLogs:s,debugLogs:r,profiling:n})=>{const[a,l]=x.useState("text"),[c,o]=x.useState(!1),d=x.useMemo(()=>[{key:"text",label:"Text logs",count:t.length},{key:"performance",label:"Performance trace",count:0},{key:"evidence",label:"Evidence",count:0},{key:"device",label:"Device logs",count:s.length},{key:"debug",label:"Debug logs",count:r.length},{key:"profiling",label:"System profiling",count:n.length,hideWhenEmpty:!0}],[t.length,s.length,r.length,n.length]),f=x.useMemo(()=>{let m=[];return a==="text"?m=t:a==="device"?m=s:a==="debug"?m=r:a==="profiling"&&(m=n),Ee(m,c)},[a,t,s,r,n,c]);return e.jsxs("section",{className:"rounded-lg border border-[var(--border)] bg-[var(--surface)] flex flex-col min-h-[280px]",children:[e.jsx(Ce,{tabs:d,active:a,onChange:l,errorsOnly:c,onErrorsOnlyChange:o}),e.jsxs("div",{className:"flex-1 overflow-y-auto",children:[a==="performance"&&e.jsx("div",{className:"px-4 py-10 text-center text-xs text-[var(--text-dim)]",children:"Performance Trace will be wired up once a session emits trace data."}),a==="evidence"&&e.jsx("div",{className:"px-4 py-10 text-center text-xs text-[var(--text-dim)]",children:"Evidence (screenshots) will be wired up alongside the screenshot service."}),(a==="text"||a==="device"||a==="debug"||a==="profiling")&&(f.length===0?e.jsx("div",{className:"px-4 py-10 text-center text-xs text-[var(--text-dim)]",children:c?"No error rows in this tab.":"No log entries in this tab."}):f.map((m,h)=>e.jsx(He,{log:m},m.id??h)))]})]})},Me=({header:t,footer:s,action:r,padded:n=!0,className:a,children:l})=>e.jsxs("div",{className:`card${a?" "+a:""}`,children:[(t||r)&&e.jsxs("div",{className:"card-header",children:[e.jsx("div",{className:"card-header-title",children:t}),r&&e.jsx("div",{className:"card-header-action",children:r})]}),e.jsx("div",{className:n?"card-body":"card-body-flush",children:l}),s&&e.jsx("div",{className:"card-footer",children:s})]});function X(t){if(!t)return"failed";switch(t){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 P="/xenon/api/interceptor";async function Je(t){const s=await fetch(`${P}/sessions/${encodeURIComponent(t)}/requests`);if(s.status===404){const n=await s.json().catch(()=>({}));return{active:!1,error:n==null?void 0:n.error}}return s.ok?{active:!0,requests:(await s.json()).requests||[]}:{active:!1,error:`request failed (${s.status})`}}async function Ue(t,s){const r=await fetch(`${P}/sessions/${encodeURIComponent(t)}/requests/${encodeURIComponent(s)}`);return r.ok?r.json():null}function Ie(t){return`${P}/sessions/${encodeURIComponent(t)}/har`}function Ve(t){return t>=200&&t<300?"ready":t>=300&&t<400?"neutral":t>=400&&t<500?"busy":t>=500?"error":"neutral"}const K=({headers:t})=>{const s=Object.entries(t||{});return s.length===0?e.jsx("div",{className:"text-xs text-[var(--text-dim)]",children:"No headers"}):e.jsx("div",{className:"space-y-0.5 font-mono text-xs",children:s.map(([r,n])=>e.jsxs("div",{className:"flex gap-2",children:[e.jsxs("span",{className:"text-[var(--text-dim)] shrink-0",children:[r,":"]}),e.jsx("span",{className:"break-all",children:n})]},r))})},z=({body:t})=>{if(t==null||t==="")return e.jsx("div",{className:"text-xs text-[var(--text-dim)]",children:"No body"});let s=t;try{s=JSON.stringify(JSON.parse(t),null,2)}catch{}return e.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:s})},Ke=({request:t,onClose:s})=>{if(!t)return null;const r=e.jsxs("div",{className:"flex items-center gap-2 text-sm",children:[e.jsx(g,{tone:"accent",children:t.method}),t.failed?e.jsx(g,{tone:"error",children:X(t.failureKind)}):e.jsx(g,{tone:Ve(t.resStatus),children:t.resStatus||"—"}),e.jsx("span",{className:"font-mono text-xs truncate",title:t.url,children:t.url})]});return e.jsx(he,{open:!!t,title:r,onClose:s,width:720,children:e.jsxs("div",{className:"space-y-4 text-xs",children:[t.failed&&e.jsxs("div",{className:"border border-[var(--red)] rounded p-2 bg-[rgb(var(--rgb-red-600)/0.08)]",children:[e.jsx("div",{className:"text-[var(--red)] text-[11px] mb-1",children:"Failure"}),e.jsx("div",{className:"text-xs",children:t.failureReason||"Request failed"}),t.failureKind&&e.jsx("div",{className:"font-mono text-[10px] text-[var(--text-dim)] mt-1",children:t.failureKind})]}),!t.failed&&e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-[var(--text-dim)] text-[11px] mb-1",children:"Duration"}),e.jsxs("div",{className:"font-mono",children:[t.durationMs," ms"]})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-[var(--text-dim)] text-[11px] mb-1",children:"Flags"}),e.jsxs("div",{className:"flex gap-1",children:[t.mocked&&e.jsx(g,{tone:"accent",children:"mocked"}),t.modified&&e.jsx(g,{tone:"busy",children:"modified"}),!t.mocked&&!t.modified&&e.jsx("span",{className:"text-[var(--text-dim)]",children:"passthrough"})]})]})]}),t.commandHint&&e.jsxs("div",{children:[e.jsx("div",{className:"text-[var(--text-dim)] text-[11px] mb-1",children:"Triggered by"}),e.jsx("div",{className:"font-mono",children:t.commandHint.commandName})]}),!t.failed&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-[var(--text-dim)] text-[11px] mb-1",children:"Request Headers"}),e.jsx(K,{headers:t.reqHeaders})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-[var(--text-dim)] text-[11px] mb-1",children:"Request Body"}),e.jsx(z,{body:t.reqBody})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-[var(--text-dim)] text-[11px] mb-1",children:"Response Headers"}),e.jsx(K,{headers:t.resHeaders})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-[var(--text-dim)] text-[11px] mb-1",children:"Response Body"}),e.jsx(z,{body:t.resBody})]})]})]})})};function ze(t){return t?new Date(t).toLocaleTimeString(void 0,{hour12:!1}):"—"}function We(t){return t>=200&&t<300?"ready":t>=300&&t<400?"neutral":t>=400&&t<500?"busy":t>=500?"error":"neutral"}const Xe=({sessionId:t,sessionEnded:s})=>{const[r,n]=x.useState(null),[a,l]=x.useState(null),[c,o]=x.useState([]),[d,f]=x.useState(!0),[m,h]=x.useState(null),v=x.useRef(new Set),{on:N,isConnected:w}=G();x.useEffect(()=>{let i=!0;return f(!0),Je(t).then(b=>{if(!i)return;n(b.active),l(b.error||null);const S=b.requests||[];o(S),v.current=new Set(S.map(u=>u.id))}).finally(()=>{i&&f(!1)}),()=>{i=!1}},[t]),x.useEffect(()=>{if(s)return;const i=N("interceptor_request",u=>{!u||u.sessionId!==t||v.current.has(u.id)||(v.current.add(u.id),o(T=>[u,...T]),n(!0))}),b=N("interceptor_session_started",u=>{(u==null?void 0:u.sessionId)===t&&n(!0)}),S=N("interceptor_session_stopped",u=>{(u==null?void 0:u.sessionId)===t&&n(!1)});return()=>{i(),b(),S()}},[N,t,s,w]);const y=x.useMemo(()=>[...c].sort((i,b)=>b.ts-i.ts),[c]),j=async i=>{if(h(i),r){const b=await Ue(t,i.id);b&&h(b)}},k=r&&c.length>0?e.jsxs("a",{href:Ie(t),className:"inline-flex items-center gap-1 text-xs text-[var(--text-dim)] hover:text-[var(--text)]",title:"Download HAR",children:[e.jsx(pe,{className:"h-3 w-3"}),"HAR"]}):null,L=e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(ve,{className:"h-3.5 w-3.5 text-[var(--text-dim)]"}),e.jsx("span",{children:"Network"}),r&&c.length>0&&e.jsxs("span",{className:"text-xs text-[var(--text-dim)]",children:["(",c.length,")"]})]});let p;return d?p=e.jsx("div",{className:"p-4 text-xs text-[var(--text-dim)]",children:"Loading…"}):r===!1&&s?p=e.jsx(E,{title:"No network capture",description:"Network interception was not enabled for this session."}):r===!1?p=e.jsx(E,{title:"Network interception disabled",description:"Enable interceptor.enabled in plugin config to capture requests for Android sessions."}):a?p=e.jsxs("div",{className:"p-4 text-xs text-[var(--red)]",children:["Failed to load requests: ",a]}):y.length===0?p=e.jsx(E,{title:"Waiting for requests",description:s?"No HTTP traffic was captured during this session.":"Captured requests will appear here as the device makes calls."}):p=e.jsx("div",{className:"overflow-auto max-h-96",children:e.jsxs(me,{children:[e.jsx(ue,{children:e.jsxs(M,{children:[e.jsx(R,{style:{width:80},children:"Time"}),e.jsx(R,{style:{width:70},children:"Method"}),e.jsx(R,{style:{width:70},children:"Status"}),e.jsx(R,{children:"Host"}),e.jsx(R,{children:"Path"}),e.jsx(R,{style:{width:80},children:"Duration"}),e.jsx(R,{style:{width:90},children:"Flags"})]})}),e.jsx(fe,{children:y.map(i=>e.jsxs(M,{onClick:()=>j(i),style:{cursor:"pointer"},title:i.failed?i.failureReason:void 0,children:[e.jsx(_,{className:"font-mono text-[11px]",children:ze(i.ts)}),e.jsx(_,{children:e.jsx(g,{tone:"accent",children:i.method})}),e.jsx(_,{children:i.failed?e.jsx(g,{tone:"error",children:X(i.failureKind)}):e.jsx(g,{tone:We(i.resStatus),children:i.resStatus||"—"})}),e.jsx(_,{className:"font-mono text-[11px] truncate",title:i.host,children:i.host}),e.jsx(_,{className:"font-mono text-[11px] truncate",title:i.path,children:i.failed?"—":i.path}),e.jsx(_,{className:"font-mono text-[11px]",children:i.failed?"—":`${i.durationMs}ms`}),e.jsx(_,{children:e.jsxs("div",{className:"flex gap-1",children:[i.mocked&&e.jsx(g,{tone:"accent",children:"mock"}),i.modified&&e.jsx(g,{tone:"busy",children:"mod"})]})})]},i.id))})]})}),e.jsxs(e.Fragment,{children:[e.jsx(Me,{header:L,action:k,padded:!1,children:p}),e.jsx(Ke,{request:m,onClose:()=>h(null)})]})},Ye={ready:"border-[var(--color-success)]/40 text-[var(--color-success)]",passed:"border-[var(--color-success)]/40 text-[var(--color-success)]",running:"border-[var(--amber)]/40 text-[var(--amber)]",failed:"border-[var(--red)]/40 text-[var(--red)]",offline:"border-[var(--text-dim)]/40 text-[var(--text-dim)]"},Ge=({label:t,tone:s})=>e.jsx("span",{className:`inline-flex items-center justify-center h-6 px-2.5 rounded border text-[10px] font-mono font-semibold tracking-wider ${Ye[s]}`,children:t});function Qe(t){switch(oe(t)){case"running":return{label:"Running",tone:"running"};case"failed":return{label:"Failed",tone:"failed"};case"passed":return{label:"Passed",tone:"passed"};default:return{label:be((typeof t=="string"?t:"")||"unknown"),tone:"offline"}}}const ft=()=>{const{buildId:t="",sessionId:s=""}=Q(),{toast:r}=$(),n=q(),a=Z(),l=ge(s||null),c=x.useMemo(()=>a.builds.find(k=>k.id===t)??null,[a.builds,t]),o=c?ee(c):"Build";if(x.useEffect(()=>{!l.loading&&l.notFound&&(r("Session not available — it may belong to a team you are not on.","info"),n("/builds",{replace:!0}))},[l.loading,l.notFound,n,r]),l.loading)return e.jsx("div",{className:"p-6 text-xs text-[var(--text-dim)]",children:"Loading session…"});if(l.error||!l.session)return e.jsxs("div",{className:"p-6 space-y-2",children:[e.jsx(J,{buildId:t,buildName:c?o:null,sessionId:s}),e.jsx("div",{className:"mt-6 rounded-md border border-[var(--red)]/30 bg-[var(--surface)] p-4 text-xs text-[var(--red)]",children:l.error||"Session not found."})]});const d=l.session,f=Qe(d.status),m=te(se(d)),h=[...l.sessionLogs,...l.deviceLogs,...l.debugLogs],v=async()=>{try{await navigator.clipboard.writeText(d.id),r("Session ID copied","success")}catch{r("Clipboard unavailable","error")}},N=[{label:"Device",value:re(d)},{label:"Node ID",value:d.node_id||"—",mono:!0},{label:"Platform",value:ae(d)},{label:"OS version",value:d.device_version?ne(d):"—",mono:!0}],w=[{label:"Session ID",value:e.jsxs("span",{className:"inline-flex items-center gap-1",children:[e.jsx("span",{className:"truncate",title:d.id,children:d.id}),e.jsx("button",{type:"button",onClick:v,"aria-label":"Copy session ID",className:"p-0.5 rounded text-[var(--text-dim)] hover:text-[var(--text)]",children:e.jsx(D,{className:"h-3 w-3"})})]}),mono:!0},{label:"Start time",value:ie(d.startTime),mono:!0},{label:"Duration",value:m,mono:!0}],y=d.status==="failed",j=[{label:"Status",value:e.jsx(Ge,{label:f.label,tone:f.tone})}];if(y&&d.failure_category){const k=F(d.failure_category);j.push({label:"Category",value:e.jsx("a",{href:`/xenon/runbooks/${encodeURIComponent(d.failure_category.toLowerCase())}`,target:"_blank",rel:"noreferrer",className:"text-[var(--red)] hover:underline",children:k})})}return y&&d.failure_reason&&j.push({label:"Failure reason",value:d.failure_reason,tone:"red"}),e.jsxs("div",{className:"flex flex-col h-full min-h-0",children:[e.jsx(J,{buildId:t,buildName:c?o:null,sessionId:d.id}),e.jsx("div",{className:"flex-1 overflow-y-auto overflow-x-hidden",children:e.jsxs("div",{className:"px-4 py-4 space-y-4",children:[e.jsx(Ne,{identity:N,run:w,result:j}),y&&e.jsx(Se,{session:d,buildName:o,buildId:t,allLogs:h,durationText:m}),e.jsxs("div",{className:"grid grid-cols-1 lg:grid-cols-[1fr_340px] gap-4",children:[e.jsx("div",{className:"min-w-0",children:e.jsx(Be,{sessionLogs:l.sessionLogs,deviceLogs:l.deviceLogs,debugLogs:l.debugLogs,profiling:l.profiling})}),e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsx(Re,{session:d}),e.jsx(_e,{session:d})]})]}),e.jsx(Xe,{sessionId:d.id,sessionEnded:d.status!=="running"})]})})]})};export{ft as SessionDetailPage,ft as default};
@@ -1 +0,0 @@
1
- import{r as i,p as A,X as S}from"./index-yibbsLFD.js";import{f as F}from"./time-B8FIgwPE.js";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 H(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 I(e,t){return t==="all"?!0:$(e.status)===t}function J(e,t,n){const r=n.trim().toLowerCase();return e.filter(s=>{var o,d;return!(!I(s,t)||r&&![s.id,B(s).text,s.name,s.failure_reason,s.device_name,s.device_platform,s.device_version,s.node_id,s.ranOn,(o=s.owner)==null?void 0:o.name,(d=s.owner)==null?void 0:d.email].filter(Boolean).join(" ").toLowerCase().includes(r))})}function j(e){var n;const t=(n=e.device_name)==null?void 0:n.trim();return t&&t.length>0?t:"Unknown Device"}function U(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 Y(e){return e.device_version?`v${e.device_version}`:""}function q(e){return F(e)}function V(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 X(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),o=(t-n*3600-r*60).toFixed(1);return n>0?`${n}h ${r}m ${o}s`:r>0?`${r}m ${o}s`:`${o}s`}const y=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],h=e=>String(e).padStart(2,"0");function p(e,t){const n=e[`appium:${t}`]??e[t];return typeof n=="string"&&n.trim()?n.trim():null}function E(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 D(e){const t=E(e);if(!t)return null;const n=p(t,"appPackage")??p(t,"bundleId");if(n)return n;const r=p(t,"app");if(r){const s=r.split(/[?#]/)[0].split(/[\\/]/).pop()??"";if(s&&s!=="download")return s}return p(t,"browserName")}function B(e){var r;const t=(r=e.name)==null?void 0:r.trim();if(t)return{text:t,source:"name"};const n=D(e.session_capabilities)??D(e.desired_capabilities);return n?{text:n,source:"app"}:{text:`Session ${e.id.slice(0,8)}`,source:"id"}}function g(e){return`${y[e.getMonth()]} ${e.getDate()}, ${h(e.getHours())}:${h(e.getMinutes())}`}function z(e){const t=e?new Date(e):null;return t&&!Number.isNaN(t.getTime())?g(t):"—"}function O(e){var n;const t=(n=e.name)==null?void 0:n.trim();return!t||t==="Default Build"}function G(e){if(!O(e))return e.name.trim();const t=new Date(e.createdAt);return Number.isNaN(t.getTime())?"Build":`Build · ${g(t)}`}const K={all:"All time","24h":"Last 24 hours","7d":"Last 7 days","30d":"Last 30 days"},C={"24h":864e5,"7d":7*864e5,"30d":30*864e5};function k(e,t){return e==="all"?null:new Date(t-C[e]).toISOString()}function Q(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 W(e,t=new Date){if(!e)return"—";const n=new Date(e);if(Number.isNaN(n.getTime()))return"—";const r=`${h(n.getHours())}:${h(n.getMinutes())}`;return n.getFullYear()!==t.getFullYear()?`${y[n.getMonth()]} ${n.getDate()}, ${n.getFullYear()} ${r}`:n.getMonth()===t.getMonth()&&n.getDate()===t.getDate()?r:g(n)}function M(e){const t=e.passed+e.failed;return t>0?e.passed/t*100:null}function Z(e,t){const n=M(e),r=t?M(t):null;return n===null||r===null?null:n-r}function ee(e){return e?e==="here"?"This server":e:null}const x=3e3,te=500;function ne(e={}){const{withSessions:t=!1,timeFilter:n="all"}=e,[r,s]=i.useState([]),[o,d]=i.useState([]),[c,N]=i.useState(null),[_,w]=i.useState(!0),[T,b]=i.useState(null),l=i.useRef(!0),{on:f}=A(),v=i.useCallback(()=>{if(!t)return Promise.resolve([]);if(c)return S.getSessions({buildId:c});const a=k(n,Date.now())??void 0;return S.getSessions({since:a})},[t,c,n]),u=i.useCallback(async()=>{try{const[a,m]=await Promise.all([S.getBuilds(),v()]);if(!l.current)return;s(Array.isArray(a)?a:[]),d(Array.isArray(m)?m:[]),b(null)}catch(a){if(!l.current)return;b(a instanceof Error?a.message:String(a))}finally{l.current&&w(!1)}},[v]);return i.useEffect(()=>{l.current=!0,u();const a=setInterval(u,x);return()=>{l.current=!1,clearInterval(a)}},[u]),i.useEffect(()=>{const a=()=>u(),m=[f("session_started",a),f("session_stopped",a),f("device_added",a),f("device_removed",a)];return()=>{for(const L of m)L()}},[f,u]),{builds:r,selectedBuildId:c,sessions:o,loading:_,error:T,selectBuild:N,refresh:u}}export{C as P,te as S,K as T,H as a,G as b,$ as c,B as d,j as e,z as f,W as g,q as h,O as i,Q as j,V as k,J as l,M as m,Z as n,X as o,U as p,Y as q,ee as r,k as s,ne as u};