@xenon-device-management/xenon 1.22.2 → 1.22.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/package.json +1 -1
- package/lib/public/assets/{ApiKeyGate-Snh2iZH5.js → ApiKeyGate-bHtvfyNp.js} +1 -1
- package/lib/public/assets/{BugReportButton-Sk0KGufH.js → BugReportButton-DFK28wAC.js} +1 -1
- package/lib/public/assets/DeviceMosaicView-C4Yrz2PA.js +7 -0
- package/lib/public/assets/{EmptyState-CQun3BJE.js → EmptyState-aXHIYg04.js} +1 -1
- package/lib/public/assets/{FieldGroup-DmYZP2j7.js → FieldGroup-C_DwE2dP.js} +1 -1
- package/lib/public/assets/{Modal-C5W8lMJ6.js → Modal-BCbDzIzg.js} +1 -1
- package/lib/public/assets/{SegmentedControl-BIzlKyUd.js → SegmentedControl-BPjRPFXH.js} +1 -1
- package/lib/public/assets/{SettingCard-DAFqQw7S.js → SettingCard-BJ8-ywEG.js} +1 -1
- package/lib/public/assets/{Table-DRkkM4OR.js → Table-C7XQ4gI0.js} +1 -1
- package/lib/public/assets/{activity-B6x69oOy.js → activity-Bv16pTkN.js} +1 -1
- package/lib/public/assets/{ai-settings-CSZQis7F.js → ai-settings-BpXcUQm3.js} +1 -1
- package/lib/public/assets/{api-keys-4ddjSngL.js → api-keys-HzfbVxL2.js} +1 -1
- package/lib/public/assets/{apps-CePIfnu9.js → apps-CtyCtiVx.js} +1 -1
- package/lib/public/assets/{arrow-left-CaOe18yC.js → arrow-left-TEnyrpa4.js} +1 -1
- package/lib/public/assets/{arrow-right-FEQsqDvH.js → arrow-right-ILl07Dxb.js} +1 -1
- package/lib/public/assets/{arrow-up-right-Dnszb73S.js → arrow-up-right-BOGBb0NS.js} +1 -1
- package/lib/public/assets/{auth-shell-Vq1rYIVD.js → auth-shell-D3PWn3HG.js} +2 -2
- package/lib/public/assets/{builds-page-FfsUegKZ.js → builds-page-BsKfrrMf.js} +1 -1
- package/lib/public/assets/{button-DrqhMLZ0.js → button-Kv_nqg_I.js} +1 -1
- package/lib/public/assets/{calendar-BuRuUa7q.js → calendar-DnjXodK3.js} +1 -1
- package/lib/public/assets/{check-DYccNk73.js → check-DvGXlj1A.js} +1 -1
- package/lib/public/assets/chevron-left-CZDYD4H3.js +6 -0
- package/lib/public/assets/{chevron-right-C6ny35i3.js → chevron-right-CuPozn4T.js} +1 -1
- package/lib/public/assets/{circle-check-Cokzy9a2.js → circle-check-CBxV3geR.js} +1 -1
- package/lib/public/assets/{circle-x-BhUzyxKR.js → circle-x-X-nHBZnY.js} +1 -1
- package/lib/public/assets/{clock-BCG0drfS.js → clock-lLny_RuH.js} +1 -1
- package/lib/public/assets/{copy-BKOm9hko.js → copy-CYjhxjiV.js} +1 -1
- package/lib/public/assets/{device-explorer-CIjs3BXP.js → device-explorer-ClkV_k7q.js} +43 -63
- package/lib/public/assets/{download-R2k7Nd4P.js → download-2y5oRiK2.js} +1 -1
- package/lib/public/assets/{forgot-password-CiZcr-gB.js → forgot-password-BouiRKS-.js} +1 -1
- package/lib/public/assets/{funnel-SD4F5IdR.js → funnel-DozJGkC5.js} +1 -1
- package/lib/public/assets/{index-BHDlQcd6.js → index-4PUiCXoJ.js} +2 -2
- package/lib/public/assets/{index-C7S8Y7Fj.css → index-BYvkQIjW.css} +1 -1
- package/lib/public/assets/{input-Ilib6feD.js → input-Cg5C6lE3.js} +1 -1
- package/lib/public/assets/keycodes-paeodb9g.js +21 -0
- package/lib/public/assets/layers-CVD3KYnj.js +6 -0
- package/lib/public/assets/{lock-s9ZhGDFF.js → lock-DnyJ9riq.js} +1 -1
- package/lib/public/assets/{login-EkaxK7K5.js → login-BMa0mDmt.js} +1 -1
- package/lib/public/assets/{maintenance-settings-yYhZaU7n.js → maintenance-settings-EezUAUBC.js} +1 -1
- package/lib/public/assets/{mouse-pointer-2-C6yy1DTx.js → mouse-pointer-2-k4GDYFXz.js} +1 -1
- package/lib/public/assets/{network-B8fPwmW9.js → network-ULTYYDWq.js} +1 -1
- package/lib/public/assets/{overview-DrTe5eJi.js → overview-DM4y4MtE.js} +1 -1
- package/lib/public/assets/{page-header-DhD-Kua9.js → page-header-DgX21Ndv.js} +1 -1
- package/lib/public/assets/{plus-B75ovH3O.js → plus-DaUKFcvv.js} +1 -1
- package/lib/public/assets/{profile-page-C2p5rB3x.js → profile-page-dcPePTH5.js} +1 -1
- package/lib/public/assets/{reset-password-tCemYrqV.js → reset-password-Ct5IlHB3.js} +1 -1
- package/lib/public/assets/{runbook-page-Dq3wdSII.js → runbook-page-C5jLKOAy.js} +1 -1
- package/lib/public/assets/{select-Cfv-njLE.js → select-HMxRDgs7.js} +1 -1
- package/lib/public/assets/selector-detail-page-BhlyEw8l.js +1 -0
- package/lib/public/assets/{selector-health-BP45B44s.js → selector-health-DQlTiNJV.js} +1 -1
- package/lib/public/assets/{selector-health-page-D-8SdN_l.js → selector-health-page-Cd1Mm_DB.js} +1 -1
- package/lib/public/assets/{session-detail-page-Dm4tnoTT.js → session-detail-page-BU8Y3HnL.js} +3 -8
- package/lib/public/assets/{settings-ChfaAd8F.js → settings-k_Xaf5kj.js} +1 -1
- package/lib/public/assets/{status-pill-outline-CLa0C1Sg.js → status-pill-outline-C5m6HFzT.js} +1 -1
- package/lib/public/assets/{tablet-0sIFwy2Z.js → tablet-2ogUZZch.js} +1 -1
- package/lib/public/assets/{teams-BFhWbK5i.js → teams-C2AfSO30.js} +1 -1
- package/lib/public/assets/{trash-2-BcQxmJP-.js → trash-2-BDdM7yPO.js} +1 -1
- package/lib/public/assets/{upload-BucqEWub.js → upload-C1vqAOQK.js} +1 -1
- package/lib/public/assets/{use-password-reset-mode-XoxXVCzm.js → use-password-reset-mode-Cw6xu19K.js} +1 -1
- package/lib/public/assets/{users-DyB6E3FF.js → users-C5jlnASB.js} +1 -1
- package/lib/public/assets/{users-B7uveXL_.js → users-CsatJcoI.js} +1 -1
- package/lib/public/assets/video-off-CAdNNByI.js +6 -0
- package/lib/public/assets/{webhook-settings-qoHAETzC.js → webhook-settings-D9Yjj-J6.js} +1 -1
- package/lib/public/assets/{zap-CqGOjAjn.js → zap-CduRPXBS.js} +1 -1
- package/lib/public/index.html +2 -2
- package/package.json +1 -1
- package/lib/public/assets/DeviceMosaicView-O292tZkA.js +0 -2
- package/lib/public/assets/keycodes-bIEJfQzr.js +0 -1
- package/lib/public/assets/layers-CLuKN5Oy.js +0 -11
- package/lib/public/assets/selector-detail-page-8xf4CxH5.js +0 -1
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{r as d,j as n,X as $,T as Ie,Y as De}from"./index-BHDlQcd6.js";import{p as ke}from"./labels-C21SA4JG.js";import{A as q,I as Me}from"./keycodes-bIEJfQzr.js";import{a as _e}from"./page-header-DhD-Kua9.js";function $e(e,t){return e!=="auto"?e:t<=1?"1":t===2?"2x1":t<=4?"2x2":"3x2"}const Oe={selected:new Set,layout:"2x2",tiles:[],groupId:null,compositeEnabled:!1,downloadableVideoCount:0,recordingPhase:"idle",recording:!1,startedAt:null,annotateMode:!1,shape:"RECT",color:"#ff3333",overlayAnnotations:{},errorBanner:null,banner:null};function Pe(e,t){var r;switch(t.type){case"SET_LAYOUT":return{...e,layout:t.layout};case"TOGGLE_SELECTED":{const o=new Set(e.selected);return o.has(t.udid)?o.delete(t.udid):o.add(t.udid),{...e,selected:o}}case"CLEAR_SELECTED":return{...e,selected:new Set};case"SET_TILES":return{...e,tiles:t.tiles};case"ADD_TILE":return e.tiles.some(o=>o.udid===t.tile.udid)?e:{...e,tiles:[...e.tiles,t.tile]};case"PATCH_TILE_DIMS":{let o=!1;const s=e.tiles.map(f=>f.udid!==t.udid||f.screenWidth&&f.screenHeight?f:(o=!0,{...f,screenWidth:t.screenWidth,screenHeight:t.screenHeight,aspect:t.aspect??f.aspect}));return o?{...e,tiles:s}:e}case"REMOVE_TILE":return e.recordingPhase!=="idle"?e:{...e,tiles:e.tiles.filter(o=>o.udid!==t.udid)};case"BIND_RECORDING_IDS":{const o=e.tiles.map(s=>({...s,recordingId:t.map[s.udid]??s.recordingId}));return{...e,tiles:o}}case"SET_RECORDING_PHASE":{const o=t.phase;return{...e,recordingPhase:o,recording:o==="recording"||o==="stopping"}}case"START_RECORDING":{const o=e.tiles.map(s=>({...s,recordingId:t.tileIds[s.udid]??s.recordingId}));return{...e,groupId:t.groupId,compositeEnabled:t.compositeEnabled===!0,downloadableVideoCount:0,recordingPhase:"recording",recording:!0,annotateMode:!0,startedAt:t.startedAt,overlayAnnotations:{},tiles:o}}case"REHYDRATE_RECORDING":{const o=e.tiles.map(s=>({...s,recordingId:t.tileIds[s.udid]??s.recordingId}));return{...e,groupId:t.groupId,compositeEnabled:t.compositeEnabled,downloadableVideoCount:0,recordingPhase:"recording",recording:!0,annotateMode:!1,startedAt:t.startedAt,overlayAnnotations:t.overlayAnnotations,tiles:o}}case"STOP_RECORDING":{const o=e.tiles.map(s=>({...s,recordingId:void 0}));return{...e,recording:!1,recordingPhase:"idle",annotateMode:!1,overlayAnnotations:{},downloadableVideoCount:t.downloadableVideoCount??e.downloadableVideoCount,compositeEnabled:t.compositeEnabled!==void 0?t.compositeEnabled:e.compositeEnabled,tiles:o}}case"SET_ANNOTATE_MODE":return{...e,annotateMode:t.enabled};case"SET_SHAPE":return{...e,shape:t.shape};case"SET_COLOR":return{...e,color:t.color};case"SET_OVERLAY_ANNOTATIONS":return{...e,overlayAnnotations:{...e.overlayAnnotations,[t.recordingId]:t.annotations}};case"CLEAR_OVERLAY_ANNOTATIONS":return{...e,overlayAnnotations:{}};case"SET_ERROR_BANNER":return{...e,errorBanner:t.message,banner:t.message?{tone:"error",message:t.message}:null};case"SET_BANNER":return{...e,banner:t.banner,errorBanner:((r=t.banner)==null?void 0:r.tone)==="error"?t.banner.message:null};default:return e}}const pe=d.createContext(null);function Le(){const e=d.useContext(pe);if(!e)throw new Error("useMosaic must be used inside <MosaicContext.Provider>");return e}function Be(){return d.useReducer(Pe,Oe)}function Ye(e){const t=Math.max(0,Math.floor(e/1e3)),r=Math.floor(t/3600),o=Math.floor(t%3600/60),s=t%60;return r>0?`${r}:${String(o).padStart(2,"0")}:${String(s).padStart(2,"0")}`:`${o}:${String(s).padStart(2,"0")}`}function Ue(e){switch(e){case"automation":return"In automation";case"manual_other":return"Manual control by another user";case"manual_self":return"In your mosaic";case"recording_other_group":return"Recording in another group";default:return e?"Busy":null}}const ie=[{id:"ios",label:"iOS",match:e=>e==="ios"},{id:"android",label:"Android",match:e=>e==="android"},{id:"tvos",label:"tvOS",match:e=>e==="tvos"},{id:"androidtv",label:"Android TV",match:e=>e==="androidtv"||e==="android-tv"},{id:"other",label:"Other",match:()=>!0}];function Fe(e){return ke(e)}function Xe({devices:e,inMosaic:t,onToggle:r}){const[o,s]=d.useState(""),[f,l]=d.useState({}),x=d.useMemo(()=>{const a=o.trim().toLowerCase();return a?e.filter(g=>g.udid.toLowerCase().includes(a)||(g.name??"").toLowerCase().includes(a)||(g.platform??"").toLowerCase().includes(a)):e},[e,o]),w=d.useMemo(()=>{const a=ie.map(u=>({id:u.id,label:u.label,rows:[]})),g=u=>a.find((y,E)=>ie[E].match(u))??a[a.length-1];for(const u of x)g((u.platform??"").toLowerCase()).rows.push(u);return a.filter(u=>u.rows.length>0)},[x]);return e.length===0?n.jsx("div",{className:"text-xs text-[var(--text-dim)] p-3",children:"No devices online."}):n.jsxs("div",{className:"flex flex-col gap-2",children:[n.jsxs("div",{className:"relative",children:[n.jsx("span",{"aria-hidden":!0,className:"absolute left-2 top-1/2 -translate-y-1/2 text-[var(--text-dim)] text-xs",children:"⌕"}),n.jsx("input",{type:"text",value:o,placeholder:"Filter devices...",onChange:a=>s(a.target.value),className:"w-full pl-7 pr-2 py-1.5 text-xs rounded border border-[var(--border)] bg-transparent placeholder:text-[var(--text-dim)] focus:outline-none focus:border-[var(--color-info)]"})]}),w.map(a=>{const g=f[a.id];return n.jsxs("section",{className:"flex flex-col gap-1",children:[n.jsxs("button",{type:"button",onClick:()=>l(u=>({...u,[a.id]:!u[a.id]})),className:"flex items-center justify-between w-full text-[11px] text-[var(--text-dim)] hover:text-[rgb(var(--rgb-fg))] px-1 py-0.5",children:[n.jsxs("span",{className:"flex items-center gap-1.5",children:[n.jsx("span",{"aria-hidden":!0,className:`inline-block transition-transform ${g?"-rotate-90":"rotate-0"}`,children:"▾"}),a.label]}),n.jsx("span",{children:a.rows.length})]}),!g&&n.jsx("ul",{className:"flex flex-col gap-1 text-sm",children:a.rows.map(u=>{const y=u.busyReason==="manual_self",E=t.has(u.udid),p=!!u.busy&&!y&&!E||!!u.offline,b=u.offline?"Offline":Ue(u.busyReason),I=!p;return n.jsx("li",{children:n.jsxs("button",{type:"button",disabled:p,draggable:!p,onDragStart:D=>{D.dataTransfer.effectAllowed="copy",D.dataTransfer.setData("application/x-xenon-udid",u.udid),D.dataTransfer.setData("text/plain",u.udid)},onClick:()=>r(u.udid),className:`w-full flex items-center gap-2 px-2 py-1.5 rounded text-left border transition-colors ${p?"opacity-60 cursor-not-allowed border-transparent":E?"border-[rgb(var(--rgb-accent)/0.4)] bg-[rgb(var(--rgb-accent)/0.05)] hover:bg-[rgb(var(--rgb-accent)/0.1)]":"border-transparent hover:border-[var(--border)] hover:bg-[var(--surface-2)]"}`,title:p?`${b} — release first`:E?"Click to remove from mosaic (or drag to a cell)":"Click to add to mosaic (or drag to a cell)",children:[n.jsx("span",{"aria-hidden":!0,className:`inline-flex items-center justify-center w-4 h-4 text-xs ${E?"text-[var(--color-accent-soft)]":"text-[var(--text-dim)]"}`,children:E?"●":"○"}),n.jsx("span",{"aria-hidden":!0,className:`inline-block w-1.5 h-1.5 rounded-full ${u.offline?"bg-zinc-600":I?"bg-[var(--color-success)]":"bg-yellow-500"}`}),n.jsx("span",{className:"font-medium flex-1 truncate text-[13px]",children:u.name??u.udid}),u.platform&&n.jsx("span",{className:"text-[11px] px-1.5 py-0.5 rounded bg-[var(--surface-2)] text-[var(--text-dim)]",children:Fe(u.platform)})]})},u.udid)})})]},a.id)}),o&&w.length===0&&n.jsxs("div",{className:"text-xs text-[var(--text-dim)] px-1 py-2",children:['No devices match "',o,'".']}),n.jsxs("div",{className:"text-[10px] text-[var(--text-dim)] px-1 pt-2 flex items-center gap-3",children:[n.jsxs("span",{className:"inline-flex items-center gap-1",children:[n.jsx("span",{className:"w-1.5 h-1.5 rounded-full bg-[var(--color-success)] inline-block"})," available"]}),n.jsxs("span",{className:"inline-flex items-center gap-1",children:[n.jsx("span",{className:"w-1.5 h-1.5 rounded-full bg-yellow-500 inline-block"})," in use"]}),n.jsxs("span",{className:"inline-flex items-center gap-1",children:[n.jsx("span",{className:"w-1.5 h-1.5 rounded-full bg-zinc-600 inline-block"})," offline"]})]})]})}const Ve=[{id:"1",label:"1",icon:n.jsx(We,{})},{id:"2x1",label:"2×1",icon:n.jsx(ze,{})},{id:"2x2",label:"2×2",icon:n.jsx(He,{})},{id:"3x2",label:"3×2",icon:n.jsx(Ke,{})},{id:"auto",label:"Auto",icon:n.jsx(Je,{})}];function Ge({value:e,onChange:t}){return n.jsx("div",{role:"tablist",className:"inline-flex border border-[var(--border)] rounded-md overflow-hidden text-xs bg-[rgb(var(--rgb-white)/0.02)]",children:Ve.map(r=>{const o=e===r.id;return n.jsxs("button",{role:"tab","aria-selected":o,onClick:()=>t(r.id),className:`flex items-center gap-1.5 px-2.5 py-1.5 border-r border-[var(--border)] last:border-r-0 transition-colors ${o?"bg-[var(--surface-2)] text-[rgb(var(--rgb-fg))]":"text-[var(--text-dim)] hover:bg-[var(--surface-2)] hover:text-[rgb(var(--rgb-fg))]"}`,title:`Layout: ${r.label}`,children:[n.jsx("span",{className:"w-3.5 h-3.5 inline-flex items-center justify-center",children:r.icon}),n.jsx("span",{children:r.label})]},r.id)})})}function U(e){return n.jsx("rect",{rx:1.2,ry:1.2,fill:"currentColor",...e})}function We(){return n.jsx("svg",{viewBox:"0 0 14 14",className:"w-3.5 h-3.5",children:U({x:2,y:2,width:10,height:10})})}function ze(){return n.jsxs("svg",{viewBox:"0 0 14 14",className:"w-3.5 h-3.5",children:[U({x:1.5,y:3,width:5,height:8}),U({x:7.5,y:3,width:5,height:8})]})}function He(){return n.jsxs("svg",{viewBox:"0 0 14 14",className:"w-3.5 h-3.5",children:[U({x:1.5,y:1.5,width:5,height:5}),U({x:7.5,y:1.5,width:5,height:5}),U({x:1.5,y:7.5,width:5,height:5}),U({x:7.5,y:7.5,width:5,height:5})]})}function Ke(){return n.jsxs("svg",{viewBox:"0 0 14 14",className:"w-3.5 h-3.5",children:[U({x:1,y:1.5,width:3.3,height:5}),U({x:5.35,y:1.5,width:3.3,height:5}),U({x:9.7,y:1.5,width:3.3,height:5}),U({x:1,y:7.5,width:3.3,height:5}),U({x:5.35,y:7.5,width:3.3,height:5}),U({x:9.7,y:7.5,width:3.3,height:5})]})}function Je(){return n.jsxs("svg",{viewBox:"0 0 14 14",className:"w-3.5 h-3.5",fill:"none",stroke:"currentColor",strokeWidth:"1.4",children:[n.jsx("rect",{x:"2",y:"2",width:"10",height:"10",rx:"1.5"}),n.jsx("circle",{cx:"7",cy:"7",r:"1.5",fill:"currentColor",stroke:"none"})]})}const qe=1600;function Ze(e,t){const r=qe/Math.max(e,t);return{w:Math.round(e*r),h:Math.round(t*r)}}function Qe(e,t,r,o=document){if(t<=0||r<=0)return null;const{w:s,h:f}=Ze(t,r),l=o.createElement("canvas");l.width=s,l.height=f;const x=l.getContext("2d");if(!x)return null;x.scale(s/t,f/r),ne(x,t,r,e);try{return l.toDataURL("image/png")}catch{return null}}function me(e,t,r){const o={left:0,top:0,width:e,height:t};if(!r||!(r>0)||e<=0||t<=0)return o;const s=e/t;if(Math.abs(s-r)<1e-6)return o;if(r>s){const l=e/r;return{left:0,top:(t-l)/2,width:e,height:l}}const f=t*r;return{left:(e-f)/2,top:0,width:f,height:t}}const et=(e,t)=>e===t||!!e&&!!t&&e.left===t.left&&e.top===t.top&&e.width===t.width&&e.height===t.height,tt=2,rt=2e3;function ae(e,t,r){if(e.length>=rt)return e;const o=e[e.length-1];return o&&Math.hypot(t-o[0],r-o[1])<tt?e:[...e,[t,r]]}function ce(e,t){const r=(e||"#ff3333").trim();if(/^#[0-9a-fA-F]{6}$/.test(r)){const o=parseInt(r.slice(1,3),16),s=parseInt(r.slice(3,5),16),f=parseInt(r.slice(5,7),16);return`rgba(${o},${s},${f},${t})`}return r}function ne(e,t,r,o){var u;const s=o.geometry,f=o.color||"#ff3333",l=Math.max(4,Math.round(Math.min(t,r)*.008));if(e.lineCap="round",e.lineJoin="round",o.shape==="CIRCLE"){const y=(s.x??0)*t,E=(s.y??0)*r,p=Math.max(2,(s.w??0)*t),b=Math.max(2,(s.h??0)*r);e.beginPath(),e.ellipse(y,E,p,b,0,0,Math.PI*2),e.fillStyle=ce(f,.22),e.fill(),e.lineWidth=l+2,e.strokeStyle="rgba(0,0,0,0.55)",e.stroke(),e.beginPath(),e.ellipse(y,E,p,b,0,0,Math.PI*2),e.lineWidth=l,e.strokeStyle=f,e.stroke();return}if(o.shape==="ARROW"){const y=(s.x??0)*t,E=(s.y??0)*r,p=y+(s.w??0)*t,b=E+(s.h??0)*r;e.lineWidth=l+2,e.strokeStyle="rgba(0,0,0,0.55)",e.beginPath(),e.moveTo(y,E),e.lineTo(p,b),e.stroke(),e.lineWidth=l,e.strokeStyle=f,e.beginPath(),e.moveTo(y,E),e.lineTo(p,b),e.stroke();const I=Math.atan2(b-E,p-y),D=Math.max(14,l*3);e.fillStyle=f,e.beginPath(),e.moveTo(p,b),e.lineTo(p-D*Math.cos(I-.4),b-D*Math.sin(I-.4)),e.lineTo(p-D*Math.cos(I+.4),b-D*Math.sin(I+.4)),e.closePath(),e.fill();return}if(o.shape==="TEXT"&&o.text){const y=Math.max(16,Math.round(Math.min(t,r)*.035));e.font=`bold ${y}px sans-serif`,e.lineWidth=3,e.strokeStyle="rgba(0,0,0,0.65)",e.strokeText(o.text,(s.x??0)*t,(s.y??0)*r),e.fillStyle=f,e.fillText(o.text,(s.x??0)*t,(s.y??0)*r);return}if(o.shape==="FREEHAND"&&(((u=s.points)==null?void 0:u.length)??0)>=2){const y=s.points,E=()=>{e.beginPath(),e.moveTo(y[0][0]*t,y[0][1]*r);for(let p=1;p<y.length;p++)e.lineTo(y[p][0]*t,y[p][1]*r)};e.lineWidth=l+2,e.strokeStyle="rgba(0,0,0,0.55)",E(),e.stroke(),e.lineWidth=l,e.strokeStyle=f,E(),e.stroke();return}const x=(s.x??0)*t,w=(s.y??0)*r,a=Math.max(2,(s.w??0)*t),g=Math.max(2,(s.h??0)*r);e.fillStyle=ce(f,.22),e.fillRect(x,w,a,g),e.lineWidth=l+2,e.strokeStyle="rgba(0,0,0,0.55)",e.strokeRect(x,w,a,g),e.lineWidth=l,e.strokeStyle=f,e.strokeRect(x,w,a,g)}function le(e,t,r,o,s){if(o<=0||s<=0)return null;if(e==="CIRCLE"){const a=Math.hypot(r.curX-r.startX,r.curY-r.startY);return a<=4?null:{shape:e,color:t,geometry:{x:r.startX/o,y:r.startY/s,w:a/o,h:a/s}}}if(e==="ARROW"){const a=r.curX-r.startX,g=r.curY-r.startY;return Math.hypot(a,g)<=6?null:{shape:e,color:t,geometry:{x:r.startX/o,y:r.startY/s,w:a/o,h:g/s}}}if(e==="FREEHAND"){if(r.points.length<2)return null;const a=r.points.map(E=>E[0]),g=r.points.map(E=>E[1]),u=Math.min(...a),y=Math.min(...g);return{shape:e,color:t,geometry:{x:u/o,y:y/s,w:Math.max(.005,(Math.max(...a)-u)/o),h:Math.max(.005,(Math.max(...g)-y)/s),points:r.points.map(([E,p])=>[E/o,p/s])}}}const f=Math.min(r.startX,r.curX)/o,l=Math.min(r.startY,r.curY)/s,x=Math.abs(r.curX-r.startX)/o,w=Math.abs(r.curY-r.startY)/s;return x<=.005||w<=.005?null:{shape:e,color:t,geometry:{x:f,y:l,w:x,h:w}}}function nt({enabled:e,shape:t,color:r,onCommit:o,committed:s,onCommittedChange:f,mediaAspect:l}){const x=d.useRef(null),[w,a]=d.useState(null),[g,u]=d.useState([]),[y,E]=d.useState(null),p=s??g,b=d.useRef(p),I=d.useRef(w),D=d.useRef(t),M=d.useRef(r),i=d.useRef(e);b.current=p,I.current=w,D.current=t,M.current=r,i.current=e;const m=d.useCallback(h=>{const R=h(b.current);b.current=R,f?f(R):u(R)},[f]),N=d.useCallback(()=>{const h=x.current;if(!h)return;const R=h.getContext("2d");if(!R)return;R.clearRect(0,0,h.width,h.height);for(const j of b.current)ne(R,h.width,h.height,j);const C=I.current;if(C){const j=le(D.current,M.current,C,h.width,h.height);j&&ne(R,h.width,h.height,j)}},[]);d.useEffect(()=>{const h=x.current;if(!h)return;const R=()=>{const j=Math.max(1,Math.round(h.clientWidth)),O=Math.max(1,Math.round(h.clientHeight));(h.width!==j||h.height!==O)&&(h.width=j,h.height=O),N()};R();const C=new ResizeObserver(R);return C.observe(h),()=>C.disconnect()},[N]),d.useEffect(()=>{N()},[w,p,N]),d.useEffect(()=>{var j;const h=(j=x.current)==null?void 0:j.parentElement;if(!h)return;const R=()=>{const O=l?me(h.clientWidth,h.clientHeight,l):null;E(F=>et(F,O)?F:O)};R();const C=new ResizeObserver(R);return C.observe(h),()=>C.disconnect()},[l]),d.useEffect(()=>{var R;if(e)return;a(null);const h=x.current;if(h&&h.hasPointerCapture)try{for(let C=0;C<8;C++)(R=h.hasPointerCapture)!=null&&R.call(h,C)&&h.releasePointerCapture(C)}catch{}},[e]);const A=h=>{const C=x.current.getBoundingClientRect();return{px:h.clientX-C.left,py:h.clientY-C.top,w:C.width,h:C.height}},v=h=>{const R=I.current;if(!R||!i.current){a(null);return}const C=x.current;if(!C||C.width<=0){a(null);return}const j=A(h),O=le(D.current,M.current,{...R,curX:j.px,curY:j.py,points:ae(R.points,j.px,j.py)},j.w,j.h);O&&(m(F=>[...F,O]),o(O,Qe(O,j.w,j.h))),a(null)},T=h=>{if(!e||h.button!==0)return;h.preventDefault(),h.currentTarget.setPointerCapture(h.pointerId);const R=A(h);a({startX:R.px,startY:R.py,curX:R.px,curY:R.py,points:[[R.px,R.py]]})},_=h=>{if(!I.current)return;const R=A(h);a(C=>C&&{...C,curX:R.px,curY:R.py,points:ae(C.points,R.px,R.py)})},k=h=>{try{h.currentTarget.releasePointerCapture(h.pointerId)}catch{}v(h)};return n.jsx("canvas",{ref:x,style:{position:"absolute",...y?{left:`${y.left}px`,top:`${y.top}px`,width:`${y.width}px`,height:`${y.height}px`}:{inset:0,width:"100%",height:"100%"},pointerEvents:e?"auto":"none",cursor:e?"crosshair":"default",zIndex:e?40:25},onPointerDown:T,onPointerMove:_,onPointerUp:k,onPointerCancel:k})}function ot(e,t,r,o,s,f,l=!1){const x=me(r.width,r.height,f);let w=(e-r.left-x.left)/x.width,a=(t-r.top-x.top)/x.height;return!(w>=0&&w<=1&&a>=0&&a<=1)&&!l?null:(w=Math.min(1,Math.max(0,w)),a=Math.min(1,Math.max(0,a)),{x:Math.round(w*o),y:Math.round(a*s)})}const st=5e3;function it(e,t){if(e.httpStatus===404)return{ended:!0,startedAt:t};if(e.httpStatus!==200)return{ended:!1,startedAt:t};const r=e.body??{};return r.status!=="running"?{ended:!0,startedAt:t}:t&&r.startedAt&&r.startedAt!==t?{ended:!0,startedAt:t}:{ended:!1,startedAt:t??r.startedAt}}function at(e,t,r,o=st){const s=d.useRef(r);s.current=r,d.useEffect(()=>{if(!t)return;let f=!1,l=!1,x;const w=async()=>{if(!(l||f)){l=!0;try{const g=await fetch(`/xenon/api/control/${encodeURIComponent(e)}/stream/status`),u=g.ok?await g.json().catch(()=>{}):void 0;if(f)return;const y=it({httpStatus:g.status,body:u},x);x=y.startedAt,y.ended&&(f=!0,s.current())}catch{}finally{l=!1}}};w();const a=setInterval(w,o);return()=>{f=!0,clearInterval(a)}},[e,t,o])}const ct=3,lt=45e3,de=[2e3,5e3,1e4];function dt(e){const t=Math.max(0,Math.min(e,de.length-1));return de[t]}function ut(e){return e<ct}function ue(e){const t=(e.lastError||"").toLowerCase();return/did not find test app|not installed|webdriveragentrunner|applicationverification/.test(t)?"WebDriverAgent is not installed on this device. Install and trust WDA, then retry.":/unsupported ios version|manualpairingtunnelstart/.test(t)?"This device’s iOS version is not supported for live streaming on this host.":/econnrefused|econnreset|connection reset|tunnel/.test(t)?"Lost the connection to the device tunnel. Reconnect the device, then retry.":e.lastError&&e.lastError.trim()?e.lastError.trim():"We couldn’t start the live stream for this device."}function ht(e){for(let t=0;t+4<e.length;t++){const r=e[t]===0&&e[t+1]===0&&e[t+2]===0&&e[t+3]===1,o=e[t]===0&&e[t+1]===0&&e[t+2]===1;if(!r&&!o)continue;const s=t+(r?4:3);if((e[s]&31)===7){const f=l=>l.toString(16).padStart(2,"0");return`avc1.${f(e[s+1])}${f(e[s+2])}${f(e[s+3])}`}}return"avc1.42e01e"}const ft=({wsUrl:e,onFatal:t,onReady:r,onFrameSize:o,className:s})=>{const f=d.useRef(null),l=d.useRef(t);l.current=t;const x=d.useRef(r);x.current=r;const w=d.useRef(o);return w.current=o,d.useEffect(()=>{var M;const a=window,g=f.current;if(typeof a.VideoDecoder>"u"||!g){(M=l.current)==null||M.call(l);return}const u=g.getContext("2d");let y=!1,E=!1,p=!0,b=0;const I=new a.VideoDecoder({output:i=>{var m,N;if(y){i.close();return}(g.width!==i.displayWidth||g.height!==i.displayHeight)&&(g.width=i.displayWidth,g.height=i.displayHeight,(m=w.current)==null||m.call(w,i.displayWidth,i.displayHeight)),u==null||u.drawImage(i,0,0),i.close(),p&&(p=!1,(N=x.current)==null||N.call(x))},error:()=>{var i;return(i=l.current)==null?void 0:i.call(l)}}),D=new WebSocket(e);return D.binaryType="arraybuffer",D.onerror=()=>{var i;return(i=l.current)==null?void 0:i.call(l)},D.onclose=()=>{var i;y||(i=l.current)==null||i.call(l)},D.onmessage=i=>{var v;const m=i.data,N=new DataView(m).getUint8(0),A=new Uint8Array(m,1);if(N===0){if(E)return;try{I.configure({codec:ht(A),optimizeForLatency:!0}),E=!0}catch{(v=l.current)==null||v.call(l)}return}if(!(!E||I.state!=="configured"))try{I.decode(new a.EncodedVideoChunk({type:N===1?"key":"delta",timestamp:b,data:A})),b+=11111}catch{}},()=>{y=!0;try{D.close()}catch{}try{I.state!=="closed"&&I.close()}catch{}}},[e]),n.jsx("canvas",{ref:f,className:s,style:{width:"100%",height:"100%",objectFit:"contain",display:"block"}})};function pt(e,t,r){return(e==="android"||e==="androidtv"||e==="android-tv")&&t==="h264"&&r?"h264":"mjpeg"}const mt=10,gt=500;function xt({udid:e,name:t,recordingId:r,annotateMode:o,shape:s,color:f,aspect:l="9 / 16",screenWidth:x,screenHeight:w,platform:a,onAnnotation:g,overlayAnnotations:u,onOverlayAnnotationsChange:y,onRemove:E}){const[p,b]=d.useState("connecting"),[I,D]=d.useState(),M=d.useCallback((c,S)=>{if(!(c>0)||!(S>0))return;const L=c/S;D(B=>B!==void 0&&Math.abs(B-L)<.001?B:L)},[]),[i,m]=d.useState(0),[N,A]=d.useState(null),v=d.useRef(0),T=d.useRef(null),[_,k]=d.useState(""),[h,R]=d.useState([]),[C,j]=d.useState(!1),O=d.useRef(null),F=d.useRef(null),G=a==="android"||a==="androidtv"||a==="android-tv",be=a==="ios"||a==="tvos";d.useEffect(()=>{let c=!1;if(r){A(null),b("connecting"),m(Date.now()),$.startStream(e).catch(()=>{});return}const S=typeof window.VideoDecoder<"u";return(async()=>{try{const L=encodeURIComponent(e),B=await fetch(`/xenon/api/control/${L}/stream/status`);if(!B.ok)return;const P=await B.json();if(pt(a||"",P==null?void 0:P.type,S)!=="h264"||!(P!=null&&P.h264Path))return;const X=await fetch(`/xenon/api/control/${L}/stream/ticket`,{method:"POST"});if(!X.ok)return;const{ticket:Y}=await X.json();if(c||!Y)return;const K=`${window.location.protocol==="https:"?"wss":"ws"}://${window.location.host}${P.h264Path}?ticket=${encodeURIComponent(Y)}`;A(K)}catch{}})(),()=>{c=!0}},[e,a,r]);const H=!o&&!!x&&!!w,Q=(c,S,L,B=!1)=>ot(c,S,L,x,w,I,B),ye=(c,S,L)=>{const B=Date.now()+Math.random(),P=c-L.left,X=S-L.top;R(Y=>[...Y,{id:B,x:P,y:X}]),window.setTimeout(()=>{R(Y=>Y.filter(z=>z.id!==B))},500)},ve=c=>{if(!H||p==="unavailable"||c.button!==0)return;const S=c.currentTarget;S.focus(),Q(c.clientX,c.clientY,S.getBoundingClientRect())&&(S.setPointerCapture(c.pointerId),F.current={startX:c.clientX,startY:c.clientY,startTime:Date.now(),rect:S.getBoundingClientRect()},ye(c.clientX,c.clientY,F.current.rect))},we=async c=>{var K,se;const S=F.current;if(F.current=null,!S||!H)return;try{c.currentTarget.releasePointerCapture(c.pointerId)}catch{}const L=c.clientX-S.startX,B=c.clientY-S.startY,P=Math.hypot(L,B),X=Date.now()-S.startTime,Y=Q(S.startX,S.startY,S.rect,!0),z=P<mt;try{if(z&&X<gt)await $.tap(e,Y.x,Y.y);else if(z)await((se=(K=$).touchAndHold)==null?void 0:se.call(K,e,Y.x,Y.y,X));else{const J=Q(c.clientX,c.clientY,S.rect,!0);await $.swipe(e,Y.x,Y.y,J.x,J.y)}}catch(J){console.error(`[DeviceTile] gesture failed for ${e}`,J)}},Ee=()=>{F.current=null},Ne=async c=>{if(!H||p==="unavailable"||c.metaKey||c.ctrlKey||c.altKey)return;const S=c.key;try{if(S.length===1){c.preventDefault(),await $.typeText(e,S);return}if(S==="Backspace"){c.preventDefault(),G?await $.pressKey(e,67):await $.typeText(e,"\b");return}if(S==="Enter"){c.preventDefault(),G?await $.pressKey(e,66):await $.typeText(e,`
|
|
2
|
-
`);return}if(S==="Tab"){c.preventDefault(),await $.typeText(e," ");return}S==="Escape"&&G&&(c.preventDefault(),await $.pressKey(e,q.BACK))}catch(L){console.error(`[DeviceTile] keystroke "${S}" failed for ${e}`,L)}},Re=()=>$.pressKey(e,G?q.HOME:Me.HOME).catch(c=>console.error(`[DeviceTile] home failed for ${e}`,c)),Se=()=>$.pressKey(e,q.BACK).catch(c=>console.error(`[DeviceTile] back failed for ${e}`,c)),Te=()=>$.pressKey(e,q.APP_SWITCH).catch(c=>console.error(`[DeviceTile] app-switch failed for ${e}`,c)),je=async()=>{try{const c=await $.getScreenshot(e),S=(c==null?void 0:c.screenshot)??(c==null?void 0:c.value)??c;if(!S)return;const L=await fetch(`data:image/png;base64,${S}`).then(X=>X.blob()),B=URL.createObjectURL(L),P=document.createElement("a");P.href=B,P.download=`${t||e}-${Date.now()}.png`,document.body.appendChild(P),P.click(),P.remove(),setTimeout(()=>URL.revokeObjectURL(B),1e3)}catch(c){console.error(`[DeviceTile] screenshot failed for ${e}`,c)}};d.useEffect(()=>{console.log(`[DeviceTile] Rendering ${e} in state: ${p}`)},[e,p]);const Ce=`/xenon/api/control/${encodeURIComponent(e)}/stream?t=${i}`,oe=d.useCallback(async()=>{try{const c=await fetch(`/xenon/api/control/${encodeURIComponent(e)}/stream/status`);if(!c.ok)throw new Error(String(c.status));const S=await c.json();k(ue({lastError:S==null?void 0:S.lastError,status:S==null?void 0:S.status}))}catch{k(ue({}))}},[e]),ee=d.useCallback(()=>{const c=v.current;ut(c)?(v.current=c+1,T.current&&clearTimeout(T.current),T.current=setTimeout(()=>{b("connecting"),m(Date.now())},dt(c))):(b("unavailable"),oe())},[oe]);d.useEffect(()=>{if(p!=="connecting")return;const c=setTimeout(ee,lt);return()=>clearTimeout(c)},[p,i,ee]),at(e,p==="live"&&!N,()=>{console.warn(`[DeviceTile] MJPEG stream ended for ${e}; reconnecting`),b("connecting"),m(Date.now())}),d.useEffect(()=>()=>{T.current&&clearTimeout(T.current)},[]);const Ae=()=>{T.current&&clearTimeout(T.current),v.current=0,k(""),b("connecting"),m(Date.now())},W=!!r,te=t||e.slice(0,16)+"…";return n.jsxs("div",{className:"flex items-stretch justify-center w-full h-full min-h-0 min-w-0 gap-2",children:[n.jsxs("div",{className:"relative bg-[var(--black)] rounded-lg overflow-hidden border border-[var(--border)] group max-h-full max-w-full self-center",style:{aspectRatio:l,height:"100%"},children:[p==="connecting"&&n.jsxs("div",{className:"flex flex-col items-center justify-center bg-neutral-900/80 text-neutral-400 absolute inset-0 z-20 pointer-events-none",children:[n.jsx("div",{className:"relative flex items-center justify-center",children:n.jsx("div",{className:"w-12 h-12 border-4 border-neutral-800 border-t-neutral-400 rounded-full animate-spin"})}),n.jsx("div",{className:"mt-4 font-bold text-neutral-200",children:"Starting Stream…"}),n.jsx("div",{className:"text-[10px] mt-1 text-neutral-500 opacity-60 font-mono",children:e}),n.jsx("div",{className:"text-[10px] mt-4 text-neutral-400 bg-white/5 px-2 py-1 rounded",children:"Waiting for device connection..."})]}),p==="unavailable"&&n.jsx("div",{className:"flex items-center justify-center bg-black text-neutral-400 absolute inset-0 z-20",children:n.jsxs("div",{className:"text-center p-6",children:[n.jsx("div",{className:"text-5xl mb-4 opacity-20",children:"📵"}),n.jsx("div",{className:"font-bold text-white text-lg",children:"Connection Failed"}),n.jsx("p",{className:"text-xs mt-2 text-neutral-500 leading-relaxed max-w-[240px] mx-auto",children:_||"We couldn’t start the live stream for this device."}),n.jsx("button",{className:"mt-6 text-sm font-semibold px-6 py-2.5 rounded-full bg-red-600 hover:bg-red-500 text-white transition-all active:scale-95",onClick:Ae,children:"Retry connection"})]})}),N?n.jsx(ft,{wsUrl:N,className:"absolute inset-0 w-full h-full object-contain bg-black select-none pointer-events-none",onReady:()=>b("live"),onFrameSize:M,onFatal:()=>{console.warn(`[DeviceTile] H.264 fatal for ${e}; falling back to MJPEG`),A(null),b("connecting"),m(Date.now())}}):n.jsx("img",{src:Ce,alt:te,className:"absolute inset-0 w-full h-full object-contain bg-black select-none pointer-events-none",draggable:!1,style:{opacity:p==="live"?1:0,transition:"opacity 0.3s ease-in-out"},onLoad:c=>{console.log(`[DeviceTile] Image LOADED for ${e}`),M(c.currentTarget.naturalWidth,c.currentTarget.naturalHeight),v.current=0,T.current&&clearTimeout(T.current),b("live")},onError:c=>{console.error(`[DeviceTile] Image ERROR for ${e}`,c),ee()}},i),H&&p!=="unavailable"&&n.jsx("div",{ref:O,className:`absolute inset-0 z-[35] touch-none outline-none ${C?"ring-2 ring-[rgb(var(--rgb-accent)/0.6)] ring-inset rounded-lg":""}`,tabIndex:0,onPointerDown:ve,onPointerUp:we,onPointerCancel:Ee,onKeyDown:Ne,onFocus:()=>j(!0),onBlur:()=>j(!1)}),n.jsx("div",{className:"absolute inset-0 z-20 pointer-events-none overflow-hidden",children:h.map(c=>n.jsx("span",{className:"absolute block w-10 h-10 rounded-full border-2 border-[var(--color-accent-soft)] animate-ping",style:{left:c.x-20,top:c.y-20}},c.id))}),W&&n.jsx(nt,{enabled:o,shape:s,color:f,committed:u,mediaAspect:I,onCommittedChange:y,onCommit:(c,S)=>g(r,c,S)}),W&&o&&p==="live"&&n.jsx("div",{className:"absolute top-3 left-14 right-3 z-30 flex justify-end pointer-events-none",children:n.jsx("span",{className:"px-2 py-0.5 rounded-sm bg-[var(--color-info)] text-white text-[10px] font-semibold shadow-lg whitespace-nowrap overflow-hidden text-ellipsis",children:"Annotating · drag to mark"})}),W&&n.jsx("div",{className:"absolute top-3 left-3 z-30 pointer-events-none",children:n.jsx("span",{className:"px-2 py-0.5 rounded-sm bg-red-600 text-white text-[9px] font-black shadow-lg",children:"REC"})}),n.jsxs("div",{className:"absolute top-3 left-3 z-30 flex flex-col gap-1.5 pointer-events-none opacity-0 group-hover:opacity-100 transition-opacity duration-150",children:[p==="live"&&n.jsx("span",{className:"px-2 py-0.5 rounded-sm bg-[var(--color-success)] text-[var(--color-on-success)] text-[11px] font-semibold shadow-lg w-fit",children:"Live"}),n.jsx("span",{className:"px-2 py-1 rounded bg-black/80 text-white text-[11px] font-medium backdrop-blur-md border border-white/10 shadow-xl truncate max-w-[180px]",children:te})]})]}),n.jsx(bt,{streamState:p,recording:W,isIOS:be,isAndroid:G,platform:a,onClose:!W&&E?()=>E(e):void 0,sendHome:Re,sendBack:Se,sendAppSwitch:Te,captureScreenshot:je,displayName:te})]})}function bt({streamState:e,recording:t,isIOS:r,isAndroid:o,platform:s,onClose:f,sendHome:l,sendBack:x,sendAppSwitch:w,captureScreenshot:a,displayName:g}){const u=e==="live";return!f&&!u?null:n.jsxs("div",{className:"self-stretch w-9 flex flex-col items-center justify-between gap-1 py-2 rounded-lg bg-black/40 border border-white/10 backdrop-blur-md text-white",children:[n.jsx("div",{className:"flex flex-col items-center gap-1",children:f&&n.jsx("button",{type:"button","aria-label":`Remove ${g} from mosaic`,title:"Remove from mosaic",onClick:f,className:"w-7 h-7 flex items-center justify-center rounded-md hover:bg-red-600/70 transition-colors text-base leading-none",children:"×"})}),u&&n.jsxs("div",{className:"flex flex-col items-center gap-1.5 my-auto",children:[(o||r)&&n.jsx("button",{type:"button",title:`Home${s?` (${s})`:""}`,onClick:l,className:"w-7 h-7 flex items-center justify-center rounded-md hover:bg-white/15 transition-colors text-sm",children:"⌂"}),o&&n.jsx("button",{type:"button",title:"Back",onClick:x,className:"w-7 h-7 flex items-center justify-center rounded-md hover:bg-white/15 transition-colors text-sm",children:"‹"}),o&&n.jsx("button",{type:"button",title:"Recent apps",onClick:w,className:"w-7 h-7 flex items-center justify-center rounded-md hover:bg-white/15 transition-colors text-sm",children:"▢"})]}),u&&n.jsx("div",{className:"flex flex-col items-center gap-1",children:n.jsx("button",{type:"button",title:"Screenshot",onClick:a,className:"w-7 h-7 flex items-center justify-center rounded-md hover:bg-white/15 transition-colors text-sm",children:"⎙"})})]})}const yt={1:"1fr","2x1":"1fr 1fr","2x2":"1fr 1fr","3x2":"1fr 1fr 1fr"},vt={1:"1fr","2x1":"1fr","2x2":"1fr 1fr","3x2":"1fr 1fr"},wt={1:1,"2x1":2,"2x2":4,"3x2":6};function Et({layout:e,tiles:t,annotateMode:r,shape:o,color:s,onAnnotation:f,overlayAnnotationsByRecording:l,onOverlayAnnotationsChange:x,onRemove:w,onDropDevice:a}){const g=$e(e,t.length),u=wt[g];t.length;const y=t.length,E=e==="auto"?Math.max(y,1):u,p=Math.max(0,E-y);return n.jsxs("div",{style:{display:"grid",gap:8,gridTemplateColumns:yt[g],gridTemplateRows:vt[g]},className:"h-full",children:[t.map(b=>n.jsx(xt,{udid:b.udid,name:b.name,mjpegPort:b.mjpegPort,recordingId:b.recordingId,aspect:b.aspect,screenWidth:b.screenWidth,screenHeight:b.screenHeight,platform:b.platform,annotateMode:r,shape:o,color:s,overlayAnnotations:b.recordingId?l==null?void 0:l[b.recordingId]:void 0,onOverlayAnnotationsChange:b.recordingId&&x?I=>x(b.recordingId,I):void 0,onAnnotation:f,onRemove:w},b.udid)),Array.from({length:p},(b,I)=>n.jsx(Nt,{onDropDevice:a},`empty-${I}`))]})}function Nt({onDropDevice:e}){const[t,r]=d.useState(!1);return n.jsxs("div",{onDragOver:o=>{e&&(o.preventDefault(),o.dataTransfer.dropEffect="copy",t||r(!0))},onDragLeave:()=>r(!1),onDrop:o=>{if(r(!1),!e)return;o.preventDefault();const s=o.dataTransfer.getData("application/x-xenon-udid")||o.dataTransfer.getData("text/plain");s&&e(s)},className:`flex flex-col items-center justify-center gap-2 rounded-lg border border-dashed transition-colors ${t?"border-[rgb(var(--rgb-accent)/0.6)] bg-[rgb(var(--rgb-accent)/0.05)]":"border-[var(--border)] bg-[rgb(var(--rgb-white)/0.02)]"} text-[var(--text-dim)] min-h-[120px]`,children:[n.jsx("div",{"aria-hidden":"true",className:`w-8 h-8 rounded-full flex items-center justify-center text-xl ${t?"bg-[rgb(var(--rgb-accent)/0.15)] text-[var(--color-accent-soft)]":"bg-[rgb(var(--rgb-fg)/0.05)] text-[rgb(var(--rgb-fg)/0.6)]"}`,children:"+"}),n.jsx("div",{className:"text-xs font-medium",children:"Drag device here"}),n.jsx("div",{className:"text-[10px] opacity-70",children:"or click one in the panel"})]})}const V="/xenon/api/recordings";class ge extends Error{constructor(t){super(t.message??t.error),this.body=t}}async function Z(e,t){const r=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:t?JSON.stringify(t):void 0});if(r.status===409)throw new ge(await r.json());if(!r.ok)throw new Error(`HTTP ${r.status}`);return r.json()}function Rt(e,t){return Z(V,{udids:e,...t})}function St(e){return Z(`${V}/${encodeURIComponent(e)}/stop`)}function he(e,t){return Z(`${V}/${encodeURIComponent(e)}/annotation`,t)}function Tt(e,t){return Z(`${V}/${encodeURIComponent(e)}/annotations/clear`,{timecodeMs:t})}async function jt(){const e=await fetch(`${V}/active`);if(!e.ok)throw new Error(`HTTP ${e.status}`);return e.json()}function Ct(e){return`${V}/${encodeURIComponent(e)}/videos.zip`}function At(e,t){return`${V}/${encodeURIComponent(e)}/video.mp4`}function It(e){return`${V}/${encodeURIComponent(e)}/composite.mp4`}function Dt(e,t){return t==="starting"?"Starting…":e<=0?"Record":e===1?"● Record":`● Record ${e} devices`}function kt({selectedUdids:e,onClearMarks:t}){const{state:r,dispatch:o}=Le(),[s,f]=d.useState(()=>Date.now());d.useEffect(()=>{if(r.recordingPhase!=="recording"&&r.recordingPhase!=="stopping")return;f(Date.now());const v=window.setInterval(()=>f(Date.now()),250);return()=>window.clearInterval(v)},[r.recordingPhase]);const l=r.startedAt&&(r.recordingPhase==="recording"||r.recordingPhase==="stopping")?s-r.startedAt:0,x=r.recordingPhase==="starting"||r.recordingPhase==="stopping",w=r.recordingPhase==="idle"&&e.length>0&&!x,a=r.recordingPhase==="recording"||r.recording&&r.tiles.some(v=>!!v.recordingId),g=a&&!x,u=g,y=u&&r.annotateMode,E=!!r.groupId&&r.recordingPhase==="idle",p=e.length>1||r.downloadableVideoCount>1,b=E&&r.compositeEnabled,I=E&&!r.compositeEnabled&&(r.downloadableVideoCount===1||r.downloadableVideoCount===0&&e.length<=1),D=async()=>{var v;if(w){o({type:"SET_RECORDING_PHASE",phase:"starting"}),o({type:"SET_BANNER",banner:null});try{const T=await Rt(e);if(!((v=T.recordings)!=null&&v.length)){o({type:"SET_RECORDING_PHASE",phase:"idle"}),o({type:"SET_BANNER",banner:{tone:"error",message:"Recording did not start. Check that live preview is working, then try again."}});return}const _={};for(const h of T.recordings)_[h.udid]=h.id;const k=e.length-T.recordings.length;o({type:"START_RECORDING",groupId:T.groupId,startedAt:Date.now(),tileIds:_,compositeEnabled:T.compositeEnabled===!0}),k>0?o({type:"SET_BANNER",banner:{tone:"error",message:`Recording started on ${T.recordings.length} of ${e.length} devices (${k} failed).`}}):o({type:"SET_BANNER",banner:null})}catch(T){if(o({type:"SET_RECORDING_PHASE",phase:"idle"}),T instanceof ge)if(T.body.error==="device_busy"){const _=(T.body.busyDevices??[]).map(k=>`${k.udid} (${k.reason})`).join(", ");o({type:"SET_BANNER",banner:{tone:"error",message:`Cannot start — these devices are busy: ${_}`}})}else o({type:"SET_BANNER",banner:{tone:"error",message:`Server-wide recording cap reached (${T.body.active}/${T.body.limit}).`}});else o({type:"SET_BANNER",banner:{tone:"error",message:`Recording failed: ${T.message}`}})}}},M=async()=>{if(!(!r.groupId||r.recordingPhase!=="recording")){o({type:"SET_RECORDING_PHASE",phase:"stopping"});try{const v=await St(r.groupId),T=(v.recordings??[]).filter(k=>k.status==="STOPPED"&&(k.sizeBytes??0)>=1024),_=(v.recordings??[]).filter(k=>k.status!=="STOPPED");o({type:"STOP_RECORDING",downloadableVideoCount:T.length,compositeEnabled:r.compositeEnabled}),T.length===0?o({type:"SET_BANNER",banner:{tone:"error",message:_.length>0?`Recording failed on ${_.length} device(s). Nothing to download.`:"Recording stopped but no playable video was produced."}}):_.length>0?o({type:"SET_BANNER",banner:{tone:"info",message:`${T.length} video(s) ready · ${_.length} failed. Use Download below.`}}):o({type:"SET_BANNER",banner:{tone:"info",message:T.length===1?"Video ready — download below.":`${T.length} videos ready — download below.`}})}catch(v){o({type:"STOP_RECORDING"}),o({type:"SET_BANNER",banner:{tone:"error",message:`Stop failed: ${v.message}`}})}}},i=()=>{u&&o({type:"SET_ANNOTATE_MODE",enabled:!r.annotateMode})},m=()=>{u&&t()},N=Object.values(r.overlayAnnotations).some(v=>((v==null?void 0:v.length)??0)>0),A=[{id:"RECT",label:"Rect"},{id:"CIRCLE",label:"Circle"},{id:"ARROW",label:"Arrow"},{id:"FREEHAND",label:"Draw"}];return n.jsxs("div",{className:"flex items-center gap-2 flex-wrap justify-end",children:[(r.recordingPhase==="recording"||r.recordingPhase==="stopping")&&n.jsxs("span",{className:"inline-flex items-center gap-1.5 px-2 py-1 rounded text-xs font-mono tabular-nums bg-[rgb(var(--rgb-red-600)/0.2)] text-[var(--red-200)] border border-[rgb(var(--rgb-red)/0.4)]",title:"Recording elapsed time",children:[n.jsx("span",{className:"inline-block w-1.5 h-1.5 rounded-full bg-[var(--red)] animate-pulse"}),"REC ",Ye(l),r.recordingPhase==="stopping"?" · Stopping…":""]}),n.jsx("button",{type:"button",onClick:D,disabled:!w,title:e.length===0?"Add a device to the mosaic first":"Record every device currently in the mosaic",className:"px-3 py-1.5 text-sm rounded bg-[var(--red-600)] text-white disabled:opacity-40 disabled:cursor-not-allowed light:disabled:bg-transparent light:disabled:text-[var(--text)] light:disabled:ring-1 light:disabled:ring-inset light:disabled:ring-[color:var(--border)]",children:Dt(e.length,r.recordingPhase)}),n.jsx("button",{type:"button",onClick:M,disabled:!g,className:"px-3 py-1.5 text-sm rounded border border-[var(--border)] disabled:opacity-40 disabled:cursor-not-allowed",children:r.recordingPhase==="stopping"?"Stopping…":"⏹ Stop"}),n.jsx("button",{type:"button",onClick:i,disabled:!u,title:u?r.annotateMode?"Exit annotate mode (tap/swipe resumes)":"Draw on the live screen — saved with the recording":"Start recording to annotate",className:`px-3 py-1.5 text-sm rounded border ${r.annotateMode?"bg-[var(--color-info)] text-white border-transparent":"border-[var(--border)]"} disabled:opacity-40 disabled:cursor-not-allowed`,children:"✎ Annotate"}),a&&n.jsxs("div",{className:"flex items-center gap-1 ml-1 pl-2 border-l border-[var(--border)]",children:[A.map(v=>n.jsx("button",{type:"button",disabled:!y,"aria-pressed":r.shape===v.id,onClick:()=>o({type:"SET_SHAPE",shape:v.id}),className:`px-2 py-1 text-xs rounded border disabled:opacity-40 disabled:cursor-not-allowed ${r.shape===v.id?"bg-[var(--surface-2)] border-[var(--color-info)] text-[rgb(var(--rgb-fg))]":"border-[var(--border)] opacity-80 hover:opacity-100"}`,children:v.label},v.id)),n.jsx("input",{type:"color",value:r.color,disabled:!y,onChange:v=>o({type:"SET_COLOR",color:v.target.value}),title:"Annotation color","aria-label":"Annotation color",className:"w-7 h-7 rounded border border-[var(--border)] bg-transparent cursor-pointer disabled:opacity-40 disabled:cursor-not-allowed"}),n.jsx("button",{type:"button",onClick:m,disabled:!u||!N,title:"Clear marks from the preview and the recording",className:"px-2 py-1 text-xs rounded border border-[var(--border)] hover:bg-[var(--surface-2)] disabled:opacity-40 disabled:cursor-not-allowed",children:"Clear marks"})]}),E&&I&&n.jsx("a",{href:At(r.groupId),className:"ml-1 px-3 py-1.5 text-sm rounded border border-[var(--border)] hover:bg-[var(--surface-2)]",download:!0,children:"⤓ Download video"}),E&&!I&&n.jsxs("a",{href:Ct(r.groupId),className:"ml-1 px-3 py-1.5 text-sm rounded border border-[var(--border)] hover:bg-[var(--surface-2)]",download:`videos-${r.groupId}.zip`,title:"ZIP of mp4 files only (no JSON extras)",children:["⤓ Download ",p?"videos":"video"]}),b&&n.jsx("a",{href:It(r.groupId),className:"px-3 py-1.5 text-sm rounded border border-[var(--border)] hover:bg-[var(--surface-2)]",download:`side-by-side-${r.groupId}.mp4`,title:"All devices in one side-by-side video",children:"⤓ Side-by-side"})]})}function Mt({remainingSec:e,onContinue:t,onReleaseNow:r}){return n.jsx("div",{role:"dialog","aria-modal":"true","aria-labelledby":"idle-warning-title",className:"fixed inset-0 z-40 bg-black/60 flex items-center justify-center",children:n.jsxs("div",{className:"bg-[var(--bg)] border border-[var(--border)] rounded-lg w-full max-w-md p-6",children:[n.jsx("h3",{id:"idle-warning-title",className:"text-base font-semibold mb-2",children:"Are you still there?"}),n.jsxs("p",{className:"text-sm text-[var(--text-dim)] mb-4",children:["Your devices will be released in"," ",n.jsxs("span",{className:"text-[var(--text)] font-mono font-semibold",children:[e,"s"]})," due to inactivity. Click ",n.jsx("strong",{children:"Continue Session"})," to keep them locked."]}),n.jsxs("div",{className:"flex justify-end gap-2",children:[n.jsx("button",{type:"button",onClick:r,className:"h-9 px-3 rounded-md border border-[var(--border)] text-sm text-[var(--text-dim)] hover:text-[var(--text)]",children:"Release now"}),n.jsx("button",{type:"button",autoFocus:!0,onClick:t,className:"h-9 px-4 rounded-md bg-[var(--color-accent)] text-[var(--color-on-accent)] text-sm font-medium",children:"Continue session"})]})]})})}function xe(e,t,r){return!r||!e?!1:e===`manual_${r}_${t}`}function _t(e,t){return e.busy?xe(e.session_id,e.udid,t):!1}function $t(){let e=Promise.resolve();return{enqueue(t){const r=e.then(t,t);return e=r.then(()=>{},()=>{}),r}}}const fe=["mousemove","mousedown","keydown","touchstart","wheel"];function Ot({idleAfterMs:e,warningSec:t,onWarning:r,onTimeout:o,enabled:s}){const[f,l]=d.useState(!1),[x,w]=d.useState(null),a=d.useRef(null),g=d.useRef(null),u=d.useRef(!1),y=d.useRef(r),E=d.useRef(o);y.current=r,E.current=o;function p(){a.current&&(clearTimeout(a.current),a.current=null),g.current&&(clearInterval(g.current),g.current=null)}function b(){u.current=!0,l(!0),w(t),y.current(t);let M=t;g.current=setInterval(()=>{M-=1,M<=0?(p(),u.current=!1,l(!1),w(null),E.current()):w(M)},1e3)}function I(){p(),u.current=!1,l(!1),w(null);const M=e-t*1e3;a.current=setTimeout(b,Math.max(0,M))}function D(){s&&I()}return d.useEffect(()=>{if(!s){p(),u.current=!1,l(!1),w(null);return}function M(){u.current||I()}return fe.forEach(i=>window.addEventListener(i,M,{passive:!0})),I(),()=>{fe.forEach(i=>window.removeEventListener(i,M)),p()}},[s,e,t]),{warning:f,remainingSec:x,reset:D}}const Pt=5*60*1e3,Lt=30;function re(e){if(!e)return"9 / 16";const t=Number(e.screenWidth),r=Number(e.screenHeight);if(Number.isFinite(t)&&Number.isFinite(r)&&t>0&&r>0)return`${t} / ${r}`;const o=(e.platform||"").toLowerCase();return o==="tvos"||o==="androidtv"||o==="android-tv"?"16 / 9":"9 / 16"}function Bt(e,t){if(e.busy)return e.session_id?e.session_id.startsWith("manual_")?xe(e.session_id,e.udid,t)?"manual_self":"manual_other":"automation":"unknown"}function Yt(e,t){return{udid:e.udid,name:e.name,platform:e.platform,busy:e.busy,busyReason:Bt(e,t),mjpegServerPort:e.mjpegServerPort,offline:!!e.offline}}function Gt(){const[e,t]=Be(),[r,o]=d.useState([]),[s,f]=d.useState(0),[l,x]=d.useState(null),w=d.useRef(!1),a=d.useRef($t());d.useEffect(()=>{let i=!1;return fetch("/xenon/api/auth/me",{credentials:"include"}).then(m=>m.ok?m.json():null).then(m=>{!i&&(m!=null&&m.userId)&&x(m.userId)}).catch(()=>{}),()=>{i=!0}},[]),d.useEffect(()=>{let i=!1;const m=async()=>{try{const A=await $.getDevices();i||o(Array.isArray(A)?A:[])}catch{}};m();const N=window.setInterval(m,5e3);return()=>{i=!0,window.clearInterval(N)}},[s]),d.useEffect(()=>{let i=!1;if(!l||w.current)return;w.current=!0;const m=N=>{const A=Number(N.screenWidth),v=Number(N.screenHeight);return{udid:N.udid,name:N.name,mjpegPort:0,aspect:re(N),screenWidth:Number.isFinite(A)&&A>0?A:void 0,screenHeight:Number.isFinite(v)&&v>0?v:void 0,platform:N.platform}};return(async()=>{var v;let N=[],A=[];try{const T=await $.getDevices();N=Array.isArray(T)?T:[];const _=N.filter(h=>_t(h,l));if(A=(await Promise.all(_.map(async h=>{try{const R=await fetch(`/xenon/api/control/${encodeURIComponent(h.udid)}/stream/status`);if(!R.ok)return null;const C=await R.json();return(C==null?void 0:C.status)==="running"?h:null}catch{return null}}))).filter(h=>h!==null).map(m),i)return;A.length>0&&t({type:"SET_TILES",tiles:A})}catch{}try{const{serverNow:T,groups:_}=await jt(),k=_[0];if(i||!k)return;const h=new Set(A.map(j=>j.udid)),R=k.recordings.filter(j=>!h.has(j.udid)).map(j=>N.find(O=>O.udid===j.udid)).filter(j=>!!j).map(m);R.length>0&&t({type:"SET_TILES",tiles:[...A,...R]});const C={};for(const j of k.annotations){let O;try{O=JSON.parse(j.geometry)}catch{continue}(C[v=j.recordingId]??(C[v]=[])).push({shape:j.shape,color:j.color,geometry:O,text:j.text??void 0})}t({type:"REHYDRATE_RECORDING",groupId:k.groupId,startedAt:Date.now()-(T-Date.parse(k.startedAt)),tileIds:Object.fromEntries(k.recordings.map(j=>[j.udid,j.id])),compositeEnabled:k.compositeEnabled,overlayAnnotations:C})}catch{}})(),()=>{i=!0}},[l,t]),d.useEffect(()=>{for(const i of e.tiles){if(i.screenWidth&&i.screenHeight)continue;const m=r.find(v=>v.udid===i.udid);if(!m)continue;const N=Number(m.screenWidth),A=Number(m.screenHeight);Number.isFinite(N)&&N>0&&Number.isFinite(A)&&A>0&&t({type:"PATCH_TILE_DIMS",udid:i.udid,screenWidth:N,screenHeight:A,aspect:re(m)})}},[r,e.tiles,t]);const g=d.useMemo(()=>new Set(e.tiles.map(i=>i.udid)),[e.tiles]),u=d.useMemo(()=>r.map(i=>Yt(i,l)),[r,l]),y=i=>{const m=Number(i.screenWidth),N=Number(i.screenHeight);return{udid:i.udid,name:i.name,mjpegPort:0,aspect:re(i),screenWidth:Number.isFinite(m)&&m>0?m:void 0,screenHeight:Number.isFinite(N)&&N>0?N:void 0,platform:i.platform}},E=async i=>{if(e.tiles.some(v=>v.udid===i)){await p(i);return}if(e.recording){t({type:"SET_ERROR_BANNER",message:"Stop recording before changing the mosaic layout."});return}const N=r.find(v=>v.udid===i);if(!N)return;t({type:"ADD_TILE",tile:y(N)});const A=await $.startStream(i).catch(()=>null);De(A)&&t({type:"REMOVE_TILE",udid:i})},p=async i=>{t({type:"REMOVE_TILE",udid:i});try{await fetch(`/xenon/api/control/${encodeURIComponent(i)}/stream/stop`,{method:"POST"})}catch{}f(m=>m+1)},b=(i,m,N)=>{if(!e.groupId)return;const A=e.groupId,v=e.startedAt?Date.now()-e.startedAt:0,T={recordingId:i,timecodeMs:v,shape:m.shape,geometry:JSON.stringify(m.geometry),color:m.color,text:m.text};a.current.enqueue(async()=>{try{return await he(A,N?{...T,image:N}:T)}catch(_){if(!N)throw _;return he(A,T)}}).catch(_=>t({type:"SET_ERROR_BANNER",message:`Annotation failed: ${_.message}`}))},I=()=>{if(!e.groupId)return;const i=e.groupId,m=e.startedAt?Date.now()-e.startedAt:0;t({type:"CLEAR_OVERLAY_ANNOTATIONS"}),a.current.enqueue(()=>Tt(i,m)).catch(()=>t({type:"SET_ERROR_BANNER",message:"Couldn't clear marks from the recording. They will still appear in the video."}))},D=()=>{for(const i of e.tiles){const m=`/xenon/api/control/${encodeURIComponent(i.udid)}/stream/stop`;try{navigator.sendBeacon?navigator.sendBeacon(m):fetch(m,{method:"POST",keepalive:!0}).catch(()=>{})}catch{}}e.tiles.forEach(i=>t({type:"REMOVE_TILE",udid:i.udid}))},M=Ot({idleAfterMs:Pt,warningSec:Lt,enabled:e.tiles.length>0,onWarning:()=>{},onTimeout:()=>{D()}});return n.jsxs(pe.Provider,{value:{state:e,dispatch:t},children:[n.jsxs("div",{className:"flex flex-col h-full p-4 gap-3",children:[n.jsxs("header",{className:"flex items-center justify-between gap-3",children:[n.jsxs("div",{className:"flex items-center gap-3",children:[n.jsx(_e,{icon:Ie,children:"Live devices"}),n.jsx(Ge,{value:e.layout,onChange:i=>t({type:"SET_LAYOUT",layout:i})})]}),n.jsx(kt,{selectedUdids:e.tiles.map(i=>i.udid),onClearMarks:I})]}),e.banner&&n.jsxs("div",{role:"alert",className:`text-sm rounded border px-3 py-2 flex items-center gap-2 ${e.banner.tone==="error"?"border-[rgb(var(--rgb-red)/0.4)] bg-[rgb(var(--rgb-red)/0.1)] text-[var(--red-100)]":"border-[rgb(var(--rgb-success)/0.4)] bg-[rgb(var(--rgb-success)/0.1)] text-[var(--text)]"}`,children:[n.jsx("span",{className:"flex-1",children:e.banner.message}),n.jsx("button",{type:"button",className:"text-xs opacity-80 hover:opacity-100",onClick:()=>t({type:"SET_BANNER",banner:null}),children:"Dismiss"})]}),n.jsxs("div",{className:"grid grid-cols-[260px_1fr] gap-3 flex-1 min-h-0",children:[n.jsxs("aside",{className:"flex flex-col gap-2 border border-[var(--border)] rounded p-3 overflow-y-auto min-h-0",children:[n.jsxs("div",{className:"flex items-center justify-between",children:[n.jsx("span",{className:"text-xs text-[var(--text-dim)]",children:"Devices"}),n.jsx("button",{className:"text-xs underline opacity-70 hover:opacity-100",onClick:()=>f(i=>i+1),children:"Refresh"})]}),n.jsx(Xe,{devices:u,inMosaic:g,onToggle:E}),n.jsx("p",{className:"mt-2 text-[11px] text-[var(--text-dim)] leading-relaxed",children:"Click a device to add it to the mosaic. Record captures every device in the mosaic. After Stop, download the video (mp4) — not a proof bundle."})]}),n.jsx("main",{className:"border border-[var(--border)] rounded p-2 overflow-y-auto h-full min-h-0",children:n.jsx(Et,{layout:e.layout,tiles:e.tiles,annotateMode:e.annotateMode,shape:e.shape,color:e.color,overlayAnnotationsByRecording:e.overlayAnnotations,onOverlayAnnotationsChange:(i,m)=>t({type:"SET_OVERLAY_ANNOTATIONS",recordingId:i,annotations:m}),onAnnotation:b,onRemove:p,onDropDevice:E})})]})]}),M.warning&&M.remainingSec!==null&&n.jsx(Mt,{remainingSec:M.remainingSec,onContinue:M.reset,onReleaseNow:D})]})}export{Gt as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const O={HOME:3,BACK:4,APP_SWITCH:187,VOLUME_UP:24,VOLUME_DOWN:25},E={HOME:"home",VOLUME_UP:"volumeup",VOLUME_DOWN:"volumedown"};export{O as A,E as I};
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import{c as a}from"./index-BHDlQcd6.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 e=[["path",{d:"m15 18-6-6 6-6",key:"1wnfg3"}]],c=a("chevron-left",e);/**
|
|
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:"M12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83z",key:"zw3jo"}],["path",{d:"M2 12a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 12",key:"1wduqc"}],["path",{d:"M2 17a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 17",key:"kqbvx6"}]],n=a("layers",o);export{c as C,n as L};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{u as I,x as A,W as F,r,X as v,j as e,J as f,D as w,C as R,A as D}from"./index-BHDlQcd6.js";import{f as g}from"./time-B8FIgwPE.js";import{P as S}from"./page-header-DhD-Kua9.js";import{f as P,H as B,V as H,E as L}from"./selector-health-BP45B44s.js";import{C as M,L as E}from"./layers-CLuKN5Oy.js";import{C as U}from"./circle-check-Cokzy9a2.js";import{Z as O}from"./zap-CqGOjAjn.js";import{C as q}from"./check-DYccNk73.js";import{C as K}from"./copy-BKOm9hko.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 te=()=>{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(U,{size:16,style:{color:"var(--color-success)"}}),e.jsx("span",{children:"Resolved"})]}),a.status==="muted"&&e.jsxs(e.Fragment,{children:[e.jsx(H,{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(O,{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(E,{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(q,{size:11}):e.jsx(K,{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(L,{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{te as default};
|