@piwitests/server 0.17.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.output/nitro.json +1 -1
- package/.output/public/_nuxt/{BcLXUmKT.js → 36cXPVrY.js} +1 -1
- package/.output/public/_nuxt/{CMB-NkFa.js → 87SGk1nu.js} +1 -1
- package/.output/public/_nuxt/{CWmQcueG.js → AjuKBlzz.js} +1 -1
- package/.output/public/_nuxt/{DAeYmPfX.js → B1CB30tg.js} +1 -1
- package/.output/public/_nuxt/{BU6xjw05.js → B6IHiVa1.js} +1 -1
- package/.output/public/_nuxt/{z7PmsnBG.js → B6rt3IcG.js} +1 -1
- package/.output/public/_nuxt/{BDcIWTTq.js → BAaSmp8J.js} +1 -1
- package/.output/public/_nuxt/{rw7Hdll3.js → BAkJhSAW.js} +1 -1
- package/.output/public/_nuxt/{L6HlmmEa.js → BCArQk0c.js} +1 -1
- package/.output/public/_nuxt/{D811X8KM.js → BEB2Mv6B.js} +1 -1
- package/.output/public/_nuxt/BFjmLXYo.js +8 -0
- package/.output/public/_nuxt/{CbuWynGG.js → BJltXwHg.js} +1 -1
- package/.output/public/_nuxt/{Dn6cGVYB.js → BKaU95es.js} +1 -1
- package/.output/public/_nuxt/{CHHqhAsw.js → BReNbog6.js} +1 -1
- package/.output/public/_nuxt/{yZ4LuI9d.js → BTYiG93l.js} +1 -1
- package/.output/public/_nuxt/{D7P0ML0H.js → BUMZHDRC.js} +1 -1
- package/.output/public/_nuxt/{US3YSX4T.js → BVDBIVAQ.js} +1 -1
- package/.output/public/_nuxt/{BgDEjrcz.js → B_aSGB8S.js} +1 -1
- package/.output/public/_nuxt/{Ce3tBrN7.js → BaDv5D7A.js} +1 -1
- package/.output/public/_nuxt/{BWFY2RuU.js → BdHdHyop.js} +1 -1
- package/.output/public/_nuxt/{jlBi8Byu.js → BfoG8R5a.js} +1 -1
- package/.output/public/_nuxt/{3QTvYrZp.js → Bi3i470l.js} +1 -1
- package/.output/public/_nuxt/Bi9DO8jm.js +1 -0
- package/.output/public/_nuxt/{PxPbRVF-.js → BiX7c2qU.js} +1 -1
- package/.output/public/_nuxt/{DwZiG9xH.js → BoC6qaRF.js} +4 -4
- package/.output/public/_nuxt/{C7nwFokE.js → BsDB_eCd.js} +1 -1
- package/.output/public/_nuxt/{cBj9fai9.js → BuuvTH9e.js} +1 -1
- package/.output/public/_nuxt/{DvC5Adg1.js → C11lmBd4.js} +1 -1
- package/.output/public/_nuxt/{Dx1oCMgy.js → C4AfzZER.js} +1 -1
- package/.output/public/_nuxt/{CYuWAvXE.js → C7ZVzS0K.js} +1 -1
- package/.output/public/_nuxt/{B6hPf4UR.js → C8cz5feG.js} +1 -1
- package/.output/public/_nuxt/{DjRhouSr.js → C9EpbPNU.js} +1 -1
- package/.output/public/_nuxt/{HCK35QD8.js → C9ahP7km.js} +1 -1
- package/.output/public/_nuxt/{8jZmK2De.js → CBEM3L1q.js} +1 -1
- package/.output/public/_nuxt/{sMFaPAAR.js → CCsl9MOZ.js} +1 -1
- package/.output/public/_nuxt/{DTH2lteW.js → CCw3Tx4S.js} +1 -1
- package/.output/public/_nuxt/{99tAfVF5.js → CGq9qR-0.js} +1 -1
- package/.output/public/_nuxt/{Dym66h3p.js → CLdGRzLL.js} +1 -1
- package/.output/public/_nuxt/{BRdhP5lm.js → CP0vUzbd.js} +1 -1
- package/.output/public/_nuxt/{D_TbJDHY.js → CPZ5wygb.js} +1 -1
- package/.output/public/_nuxt/{Bua_L6p4.js → CRcjGmf7.js} +1 -1
- package/.output/public/_nuxt/{DS9yGVFL.js → CRpbGS75.js} +1 -1
- package/.output/public/_nuxt/{DDPptydi.js → CTgM5Fke.js} +1 -1
- package/.output/public/_nuxt/{D_A6axXa.js → CU3W9YrI.js} +1 -1
- package/.output/public/_nuxt/{BwKwWgQe.js → CUDeMcEK.js} +1 -1
- package/.output/public/_nuxt/{DFM2jv9I.js → CYIR2GbL.js} +1 -1
- package/.output/public/_nuxt/{B1CUXGbl.js → Ccit_CX1.js} +1 -1
- package/.output/public/_nuxt/CiPH-swI.js +1 -0
- package/.output/public/_nuxt/{DRTxhZBV.js → ClIKZ4qY.js} +1 -1
- package/.output/public/_nuxt/{DvXvJzFP.js → ClVRQpP_.js} +1 -1
- package/.output/public/_nuxt/{CvtYJHkY.js → CmbjAoQu.js} +1 -1
- package/.output/public/_nuxt/Cx65B3c3.js +1 -0
- package/.output/public/_nuxt/{Cz2HhsB6.js → D1ttGJfs.js} +1 -1
- package/.output/public/_nuxt/{DtXREpk_.js → D3MWm6JP.js} +1 -1
- package/.output/public/_nuxt/{BrT_Sys2.js → D3SYPlEB.js} +28 -28
- package/.output/public/_nuxt/{Cf4h8qty.js → D4SFgXAf.js} +1 -1
- package/.output/public/_nuxt/{DCffDvxl.js → D51_cB9D.js} +1 -1
- package/.output/public/_nuxt/{QFMx1VKs.js → D8YZvjas.js} +1 -1
- package/.output/public/_nuxt/{BE8ykmwr.js → DB3ljns7.js} +1 -1
- package/.output/public/_nuxt/{CSAmL8XJ.js → DC51KKt4.js} +1 -1
- package/.output/public/_nuxt/{3QTorEhJ.js → DCMFuzDI.js} +1 -1
- package/.output/public/_nuxt/{CNULGfLp.js → DIA_NAIv.js} +1 -1
- package/.output/public/_nuxt/{COVRAesU.js → DM_YaJgJ.js} +1 -1
- package/.output/public/_nuxt/{DJHNEqb7.js → DOr_4nln.js} +2 -2
- package/.output/public/_nuxt/{BGZQONfm.js → DRE6Aqqp.js} +1 -1
- package/.output/public/_nuxt/{DPSOtRoz.js → DVgMaBxD.js} +1 -1
- package/.output/public/_nuxt/{Sgf5OLhm.js → DaewB_zT.js} +1 -1
- package/.output/public/_nuxt/{ClJkng9p.js → Db_-yjYg.js} +1 -1
- package/.output/public/_nuxt/{DxQq_L07.js → Dbg8z684.js} +1 -1
- package/.output/public/_nuxt/{qYFZH4Z8.js → DcfRfTaA.js} +1 -1
- package/.output/public/_nuxt/{csqspBeX.js → Dm1_3W9g.js} +1 -1
- package/.output/public/_nuxt/{Dz3Wbekz.js → DnThe2U0.js} +1 -1
- package/.output/public/_nuxt/{D0-HTQTD.js → Do6zIWQf.js} +1 -1
- package/.output/public/_nuxt/{CoKEjZX7.js → DoFSKAvY.js} +1 -1
- package/.output/public/_nuxt/{Bpha13F_.js → DoYgYLOd.js} +1 -1
- package/.output/public/_nuxt/{Dvc1aWpA.js → Doul3p1_.js} +1 -1
- package/.output/public/_nuxt/{Ba4_ydKG.js → DraETso1.js} +1 -1
- package/.output/public/_nuxt/{CxLN5Tmq.js → Dwp3GkV-.js} +1 -1
- package/.output/public/_nuxt/{-9tk1FrT.js → Dy4TloG3.js} +1 -1
- package/.output/public/_nuxt/{DT5rhzhJ.js → EltzgiyS.js} +1 -1
- package/.output/public/_nuxt/{D13ybpY3.js → HTQtMbWb.js} +1 -1
- package/.output/public/_nuxt/{Wfk1m0ni.js → KYucVFu7.js} +1 -1
- package/.output/public/_nuxt/TBDx0s9p.js +3 -0
- package/.output/public/_nuxt/{Bq0PQfQY.js → Tt5LX5Y-.js} +1 -1
- package/.output/public/_nuxt/{BxRsAYRS.js → Vnfkr1pJ.js} +1 -1
- package/.output/public/_nuxt/{Df3QtbpW.js → WAaPPk0g.js} +2 -2
- package/.output/public/_nuxt/builds/latest.json +1 -1
- package/.output/public/_nuxt/builds/meta/ed1db2e5-9865-4231-9605-4edd5272e164.json +1 -0
- package/.output/public/_nuxt/{CHIbdzqp.js → empGC_x-.js} +1 -1
- package/.output/public/_nuxt/entry.ChQMshd4.css +1 -0
- package/.output/public/_nuxt/{BciovqwK.js → l0QnzFNM.js} +1 -1
- package/.output/public/_nuxt/{73aPL7Ir.js → lowCGL2S.js} +1 -1
- package/.output/public/_nuxt/{B6w76fJT.js → mlAADjK3.js} +1 -1
- package/.output/public/_nuxt/{Ds2Y3oms.js → n-QWmQgc.js} +1 -1
- package/.output/public/_nuxt/{DpJrGwCr.js → oFIS9u6t.js} +1 -1
- package/.output/public/_nuxt/{BEsJE07U.js → oWY3I9uX.js} +1 -1
- package/.output/public/_nuxt/{lCkcEykv.js → q0DPzLKN.js} +1 -1
- package/.output/public/_nuxt/{r9WApUfF.js → quV6tp4n.js} +1 -1
- package/.output/public/_nuxt/{8xyZSRSO.js → riEUDnED.js} +1 -1
- package/.output/public/_nuxt/{ByoIgYX_.js → rm7OkgDG.js} +1 -1
- package/.output/public/_nuxt/uaqMzXqE.js +5 -0
- package/.output/public/_nuxt/{vzXhOO8R.js → va1mwSm9.js} +1 -1
- package/.output/public/_nuxt/{BoRJdCd4.js → wGpfdK6o.js} +1 -1
- package/.output/public/_nuxt/{za5M7BGh.js → wQZj69OY.js} +1 -1
- package/.output/public/_nuxt/wgcgHmRR.js +1 -0
- package/.output/public/sw.js +1 -1
- package/.output/server/chunks/build/{about-TuEZ9n1Q.mjs → about-CoJjvUwM.mjs} +119 -11
- package/.output/server/chunks/build/about-CoJjvUwM.mjs.map +1 -0
- package/.output/server/chunks/build/client.precomputed.mjs +1 -1
- package/.output/server/chunks/build/{docs-EXhN3sqC.mjs → docs-BN_x1OW3.mjs} +50 -6
- package/.output/server/chunks/build/{docs-EXhN3sqC.mjs.map → docs-BN_x1OW3.mjs.map} +1 -1
- package/.output/server/chunks/build/{mcp-CQ-21rwc.mjs → mcp-_o6cMS6m.mjs} +307 -225
- package/.output/server/chunks/build/mcp-_o6cMS6m.mjs.map +1 -0
- package/.output/server/chunks/build/server.mjs +3 -3
- package/.output/server/chunks/build/useTauri-lRT8zkLv.mjs +7 -0
- package/.output/server/chunks/build/useTauri-lRT8zkLv.mjs.map +1 -0
- package/.output/server/chunks/nitro/nitro.mjs +688 -695
- package/.output/server/package.json +1 -1
- package/package.json +1 -1
- package/.output/public/_nuxt/26ll_vBr.js +0 -1
- package/.output/public/_nuxt/B_QIrc7l.js +0 -1
- package/.output/public/_nuxt/CEuVRSr0.js +0 -3
- package/.output/public/_nuxt/Cl96oI21.js +0 -5
- package/.output/public/_nuxt/DATh_1DQ.js +0 -1
- package/.output/public/_nuxt/DUe6xuKQ.js +0 -1
- package/.output/public/_nuxt/DqsMiUoW.js +0 -2
- package/.output/public/_nuxt/Ds4Lb1vi.js +0 -7
- package/.output/public/_nuxt/builds/meta/05a2dd95-d1c1-4e3a-8625-ac6bfea83837.json +0 -1
- package/.output/public/_nuxt/entry.BaIGwMjT.css +0 -1
- package/.output/server/chunks/build/DesktopMcpCard-B4JuUTKj.mjs +0 -122
- package/.output/server/chunks/build/DesktopMcpCard-B4JuUTKj.mjs.map +0 -1
- package/.output/server/chunks/build/about-TuEZ9n1Q.mjs.map +0 -1
- package/.output/server/chunks/build/mcp-CQ-21rwc.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{_ as js}from"./BDcIWTTq.js";import{_ as ws}from"./B1CUXGbl.js";import{b as Re,K as $t,d as ue,L as Nt,w as ye,B as ge,k as e,o as s,f as k,g as t,j as l,_ as Te,c as i,i as a,m as d,t as c,q as S,F as Q,y as ie,v as Le,x as Oe,l as G,M as Vt,N as Bt,p as re,h as B,r as w,E as Ds,O as Kt,n as Ct,s as Ae,P as Tt,D as Lt,I as Rs,u as As,a as Us,e as zs,H as Pt,Q as Ms,R as Fs}from"./BrT_Sys2.js";import{_ as Is}from"./BE8ykmwr.js";import{_ as qe,a as Es}from"./B6hPf4UR.js";import{_ as Ue}from"./sMFaPAAR.js";import{_ as Ot}from"./ClJkng9p.js";import{u as Vs}from"./C7nwFokE.js";import{u as he}from"./Dvc1aWpA.js";import{_ as Bs}from"./BwKwWgQe.js";import{_ as Ps,a as Ns}from"./CMB-NkFa.js";import{_ as qt}from"./DvXvJzFP.js";import{_ as Ht}from"./Bua_L6p4.js";import{_ as Se}from"./Wfk1m0ni.js";import{C as kt,w as Xt,O as at,a as Gt,_ as Jt,u as Qt}from"./D811X8KM.js";import{N as Ks}from"./CNULGfLp.js";import{_ as Ls}from"./CHHqhAsw.js";import{_ as Os}from"./Ds2Y3oms.js";import{_ as qs}from"./D13ybpY3.js";import{_ as Hs}from"./DTH2lteW.js";import{_ as Xs}from"./D_A6axXa.js";import{_ as Gs}from"./DjRhouSr.js";import{_ as Js}from"./Dym66h3p.js";import{_ as ze}from"./DJHNEqb7.js";import{_ as He}from"./CoKEjZX7.js";import{_ as Yt}from"./CHIbdzqp.js";import{_ as lt}from"./CYuWAvXE.js";import{f as St,a as Qs,c as Ys,g as I,e as Wt,p as ot,h as Ce,i as tt}from"./D7P0ML0H.js";import{_ as jt}from"./Bq0PQfQY.js";import{_ as wt}from"./3QTvYrZp.js";import{_ as Ws}from"./Sgf5OLhm.js";import{_ as Zs}from"./DT5rhzhJ.js";import{_ as en}from"./Cf4h8qty.js";import{_ as tn}from"./BGZQONfm.js";import{_ as sn}from"./Dz3Wbekz.js";import{_ as Dt}from"./BciovqwK.js";import{M as nn,D as bt,g as xt}from"./D7W_4Sqc.js";import{_ as an}from"./CxLN5Tmq.js";import{u as on}from"./r9WApUfF.js";import{u as ln}from"./Bpha13F_.js";import"./z7PmsnBG.js";import"./r3SBLxtE.js";import"./DtXREpk_.js";import"./26ll_vBr.js";import"./rw7Hdll3.js";import"./DATh_1DQ.js";import"./ByoIgYX_.js";import"./BxRsAYRS.js";import"./za5M7BGh.js";import"./DxQq_L07.js";import"./QFMx1VKs.js";import"./COVRAesU.js";import"./BU6xjw05.js";import"./yZ4LuI9d.js";import"./vzXhOO8R.js";import"./D0-HTQTD.js";const rn=["run.finished","run.failed","run.failed.default_branch","cluster.new","flakiness.spike","perf.regression","diagnosis.completed"],st=new Map,nt=new Map;function cn(A,T){const x=[{event:"run.failed",scenario:{title:`Test run failed — ${A}`,description:"3 of 12 tests failed on main — checkout › applies discount code +2 more",icon:"i-lucide-circle-x",color:"error"}},{event:"run.failed.default_branch",scenario:{title:`Test run failed on main — ${A}`,description:"2 of 12 tests failed · main — auth › logs in with valid credentials +1 more",icon:"i-lucide-circle-x",color:"error"}},{event:"cluster.new",scenario:{title:`New failure cluster — ${A}`,description:"TimeoutError: locator.click: Timeout 30000ms exceeded",icon:"i-lucide-layers",color:"warning"}},{event:"flakiness.spike",scenario:{title:`Flakiness spike — ${A}`,description:"3 tests became flaky (8.3% rate)",icon:"i-lucide-shuffle",color:"warning"}},{event:"perf.regression",scenario:{title:`Performance regression — ${A}`,description:"p90 duration increased by 42% vs last week",icon:"i-lucide-trending-down",color:"warning"}},{event:"run.finished",scenario:{title:`Test run recovered — ${A}`,description:"All 12 tests passed on main",icon:"i-lucide-circle-check",color:"success"}},{event:"diagnosis.completed",scenario:{title:`Diagnosis complete — ${A}`,description:"Root cause: test bug — confidence: high",icon:"i-lucide-sparkles",color:"info"}}],D=x.filter(b=>T.length===0||T.includes(b.event)).map(b=>b.scenario);return D.length===0?[x[0].scenario,x[x.length-1].scenario]:D}function un(){if(!$t().public.demoMode)return null;const T=Re();function x(b,f,u){D(b);const E=cn(f,u);nt.set(b,0);function U(){const R=(nt.get(b)??0)%E.length;nt.set(b,R+1);const C=E[R];T.add({title:C.title,description:C.description,icon:C.icon,color:C.color,duration:7e3});const _=25e3+Math.random()*1e4;st.set(b,setTimeout(U,_))}st.set(b,setTimeout(U,8e3))}function D(b){const f=st.get(b);f!==void 0&&(clearTimeout(f),st.delete(b)),nt.delete(b)}return{scheduleFor:x,cancelFor:D}}const dn={key:0,class:"p-3 space-y-3"},mn={key:0,class:"text-xs text-gray-500"},pn={key:1,class:"text-xs text-gray-500"},gn={key:2,class:"text-xs text-gray-500"},fn={class:"space-y-1"},vn=["checked","onChange"],_n={key:1,class:"p-3 space-y-3"},yn={class:"flex items-center justify-between"},hn={class:"font-medium text-sm inline-flex items-center gap-1"},bn={key:0,class:"text-xs text-muted bg-primary/5 rounded px-2 py-1.5"},xn={key:1,class:"text-xs text-muted text-center py-2"},kn={key:2,class:"space-y-1.5"},$n={key:0,class:"space-y-2 rounded border border-primary/30 bg-primary/5 px-2 py-2"},Cn={class:"space-y-1"},Tn=["value"],Sn={class:"flex gap-1.5 justify-end"},jn={class:"flex-1 font-medium truncate"},wn={key:3,class:"text-xs text-muted text-center py-1"},Dn={key:4,class:"space-y-2 border-t border-default pt-2"},Rn={class:"space-y-1"},An=["value"],Un={class:"flex gap-1.5 justify-end"},zn=ue({__name:"SubscribeBell",props:{projectId:{},projectLabel:{}},async setup(A){let T,x;const D=A,b=$t(),f=b.public.demoMode,u=B(()=>b.public.authEnabled),{authState:E}=Nt(),U=B(()=>E.value.authenticated),R=Re(),C=w(!1),_=f?un():null,y=!u.value&&!f?Vs():null,z=w("default"),h=B(()=>"Notification"in window);"Notification"in window&&(z.value=Notification.permission);const v=B(()=>y?.getProject(D.projectId).events??[]),M=B(()=>y?.isSubscribed(D.projectId)??!1);async function K(){!h.value||z.value!=="default"||(z.value=await Notification.requestPermission())}function $(V){return v.value.includes(V)}function g(V){y?.toggleEvent(D.projectId,V)}const m=f||u.value&&U.value,q=f?{server:!1}:{},{data:Z,refresh:O}=([T,x]=ye(()=>he(`/api/subscriptions?projectId=${D.projectId}`,{immediate:m,...q},"$5zp4moJ-7_")),T=await T,x(),T),P=B(()=>Z.value?.subscriptions??[]),be=B(()=>P.value.length>0),{data:xe}=([T,x]=ye(()=>he("/api/channels",{immediate:m,...q},"$vFApQ6eA2X")),T=await T,x(),T),p=B(()=>xe.value?.channels??[]),L=w(!1),oe=w(void 0),de=w(["run.failed"]),ke=w(!1),fe=w(null),ce=w(void 0),ve=w([]),Y=w(!1);function rt(V){fe.value=V,ce.value=V.channel.id,ve.value=[...V.events]}function it(){fe.value=null}async function Me(){if(!(!fe.value||!ce.value||ve.value.length===0)){Y.value=!0;try{await $fetch(`/api/subscriptions/${fe.value.id}`,{method:"PATCH",body:{channelId:ce.value,events:ve.value}}),await O(),fe.value=null}catch(V){R.add({title:"Update failed",description:String(V?.message??V),color:"error"})}finally{Y.value=!1}}}const Xe=B(()=>p.value.map(V=>({label:V.type==="personal_email"?`${V.name} (${V.config.address})`:V.name,value:V.id}))),W=rn.map(V=>({label:V.replace(/\./g," › "),value:V}));ge(C,V=>{V?(m&&O(),p.value.length>0&&!oe.value&&(oe.value=p.value[0].id)):(L.value=!1,fe.value=null)});async function _e(){if(!(!oe.value||de.value.length===0)){ke.value=!0;try{await $fetch("/api/subscriptions",{method:"POST",body:{channelId:oe.value,projectId:D.projectId,events:de.value,mode:"realtime"}}),await O(),L.value=!1,R.add({title:"Subscribed",color:"success"}),f&&_?.scheduleFor(D.projectId,D.projectLabel||"this project",de.value)}catch(V){R.add({title:"Subscribe failed",description:String(V?.message??V),color:"error"})}finally{ke.value=!1}}}async function Fe(V){try{await $fetch(`/api/subscriptions/${V}`,{method:"DELETE"}),await O(),R.add({title:"Unsubscribed",color:"success"}),f&&P.value.length===0&&_?.cancelFor(D.projectId)}catch(j){R.add({title:"Failed",description:String(j?.message??j),color:"error"})}}async function ct(V){const j=V.mutedUntil&&new Date(V.mutedUntil)>new Date;try{await $fetch(`/api/subscriptions/${V.id}`,{method:"PATCH",body:{mutedUntil:j?null:new Date(Date.now()+10080*60*1e3).toISOString()}}),await O()}catch(ee){R.add({title:"Failed",description:String(ee?.message??ee),color:"error"})}}function Ie(V){return V.mutedUntil&&new Date(V.mutedUntil)>new Date}function Ee(V){return V==="personal_email"?"i-lucide-user-round":V==="email"?"i-lucide-mail":V==="slack"?"i-lucide-slack":"i-lucide-webhook"}const ut=B(()=>f||u.value&&U.value||y!=null),Ve=B(()=>f||u.value?be.value:M.value);return(V,j)=>{const ee=Te,Ge=Is,Be=qe,Pe=Le,dt=Oe,Je=Ue,je=Ot,Ne=Ds;return e(ut)?(s(),k(Ne,{key:0,open:e(C),"onUpdate:open":j[6]||(j[6]=N=>G(C)?C.value=N:null),ui:{content:"w-72"}},{content:t(()=>[e(y)?(s(),i("div",dn,[j[9]||(j[9]=a("div",{class:"flex items-center justify-between"},[a("span",{class:"font-medium text-sm"},"Browser notifications")],-1)),e(h)&&e(z)==="default"?(s(),i("p",mn,[l(ee,{variant:"link",size:"xs",class:"p-0",onClick:K},{default:t(()=>[...j[7]||(j[7]=[d(" Allow notifications ",-1)])]),_:1}),j[8]||(j[8]=d(" "+c(" ")+"in your browser to get alerts for this project. ",-1))])):e(h)&&e(z)==="denied"?(s(),i("p",pn," Notifications are blocked. Check your browser settings to allow them. ")):e(h)?S("",!0):(s(),i("p",gn,"Notifications are not supported in this browser.")),e(h)&&e(z)==="granted"?(s(),i(Q,{key:3},[l(Ge),a("div",fn,[(s(!0),i(Q,null,ie(e(W),N=>(s(),i("label",{key:N.value,class:"flex items-center gap-1.5 text-xs cursor-pointer"},[a("input",{type:"checkbox",checked:$(N.value),class:"accent-primary size-3",onChange:X=>g(N.value)},null,40,vn),d(" "+c(N.label),1)]))),128))])],64)):S("",!0)])):(s(),i("div",_n,[a("div",yn,[a("span",hn,[j[10]||(j[10]=d(" Notifications ",-1)),l(Be,{topic:"notifications.subscribe"})]),e(L)?S("",!0):(s(),k(ee,{key:0,size:"xs",icon:"i-lucide-plus",variant:"ghost",color:"neutral",disabled:e(p).length===0,onClick:j[0]||(j[0]=N=>L.value=!0)},{default:t(()=>[...j[11]||(j[11]=[d(" Add ",-1)])]),_:1},8,["disabled"]))]),e(f)?(s(),i("div",bn,[l(Pe,{name:"i-lucide-sparkles",class:"size-3 inline-block mr-1 text-primary"}),j[12]||(j[12]=d(" Demo — notifications will appear as toasts in ~8 s. ",-1))])):e(p).length===0?(s(),i("div",xn,[j[14]||(j[14]=d(" No channels configured.",-1)),j[15]||(j[15]=a("br",null,null,-1)),l(dt,{to:"/settings/notifications",class:"text-primary underline"},{default:t(()=>[...j[13]||(j[13]=[d("Add one in Settings",-1)])]),_:1})])):S("",!0),e(P).length>0?(s(),i("div",kn,[(s(!0),i(Q,null,ie(e(P),N=>(s(),i(Q,{key:N.id},[e(fe)?.id===N.id?(s(),i("div",$n,[l(je,{label:"Channel",size:"xs"},{default:t(()=>[l(Je,{modelValue:e(ce),"onUpdate:modelValue":j[1]||(j[1]=X=>G(ce)?ce.value=X:null),items:e(Xe),"value-key":"value",class:"w-full text-xs",size:"xs"},null,8,["modelValue","items"])]),_:1}),l(je,{label:"Events",size:"xs"},{default:t(()=>[a("div",Cn,[(s(!0),i(Q,null,ie(e(W),X=>(s(),i("label",{key:X.value,class:"flex items-center gap-1.5 text-xs cursor-pointer"},[Vt(a("input",{type:"checkbox",value:X.value,"onUpdate:modelValue":j[2]||(j[2]=mt=>G(ve)?ve.value=mt:null),class:"accent-primary size-3"},null,8,Tn),[[Bt,e(ve)]]),d(" "+c(X.label),1)]))),128))])]),_:1}),a("div",Sn,[l(ee,{size:"xs",color:"neutral",variant:"ghost",onClick:it},{default:t(()=>[...j[16]||(j[16]=[d("Cancel",-1)])]),_:1}),l(ee,{size:"xs",color:"primary",loading:e(Y),disabled:!e(ce)||e(ve).length===0,onClick:Me},{default:t(()=>[...j[17]||(j[17]=[d(" Save ",-1)])]),_:1},8,["loading","disabled"])])])):(s(),i("div",{key:1,class:re(["flex items-center gap-2 rounded px-2 py-1.5 text-xs",Ie(N)?"opacity-60":""])},[l(Pe,{name:Ee(N.channel.type),class:"size-3.5 text-muted shrink-0"},null,8,["name"]),a("span",jn,c(N.channel.name),1),l(ee,{icon:"i-lucide-pencil",color:"neutral",variant:"ghost",size:"xs",title:"Edit subscription",onClick:X=>rt(N)},null,8,["onClick"]),l(ee,{icon:Ie(N)?"i-lucide-bell":"i-lucide-bell-off",color:"neutral",variant:"ghost",size:"xs",title:Ie(N)?"Unmute":"Mute 7 days",onClick:X=>ct(N)},null,8,["icon","title","onClick"]),l(ee,{icon:"i-lucide-x",color:"error",variant:"ghost",size:"xs",title:"Unsubscribe",onClick:X=>Fe(N.id)},null,8,["onClick"])],2))],64))),128))])):!e(L)&&e(p).length>0?(s(),i("div",wn," Not subscribed to this project. ")):S("",!0),e(L)?(s(),i("div",Dn,[l(je,{label:"Channel",size:"xs"},{default:t(()=>[l(Je,{modelValue:e(oe),"onUpdate:modelValue":j[3]||(j[3]=N=>G(oe)?oe.value=N:null),items:e(Xe),"value-key":"value",class:"w-full text-xs",size:"xs"},null,8,["modelValue","items"])]),_:1}),l(je,{label:"Events",size:"xs"},{default:t(()=>[a("div",Rn,[(s(!0),i(Q,null,ie(e(W),N=>(s(),i("label",{key:N.value,class:"flex items-center gap-1.5 text-xs cursor-pointer"},[Vt(a("input",{type:"checkbox",value:N.value,"onUpdate:modelValue":j[4]||(j[4]=X=>G(de)?de.value=X:null),class:"accent-primary size-3"},null,8,An),[[Bt,e(de)]]),d(" "+c(N.label),1)]))),128))])]),_:1}),a("div",Un,[l(ee,{size:"xs",color:"neutral",variant:"ghost",onClick:j[5]||(j[5]=N=>L.value=!1)},{default:t(()=>[...j[18]||(j[18]=[d("Cancel",-1)])]),_:1}),l(ee,{size:"xs",color:"primary",loading:e(ke),disabled:!e(oe)||e(de).length===0,onClick:_e},{default:t(()=>[...j[19]||(j[19]=[d(" Subscribe ",-1)])]),_:1},8,["loading","disabled"])])])):S("",!0)]))]),default:t(()=>[l(ee,{icon:e(Ve)?"i-lucide-bell-ring":"i-lucide-bell",size:"sm",color:e(Ve)?"primary":"neutral",variant:e(Ve)?"soft":"outline",title:"Notification subscriptions for this project"},null,8,["icon","color","variant"])]),_:1},8,["open"])):S("",!0)}}}),Mn=Object.assign(zn,{__name:"SubscribeBell"}),Fn={class:"w-full relative"},In={key:0},En={class:"p-2 text-sm text-gray-900 dark:text-gray-100"},Vn={class:"font-semibold mb-1"},Bn={class:"capitalize mb-1"},Pn={class:"space-y-0.5"},Nn={class:"font-medium mt-1"},Kn=ue({__name:"TestRunsChart",props:{testRuns:{},height:{default:300},markers:{default:()=>[]}},emits:["marker-click"],setup(A,{emit:T}){const x=A,D=T,b=B(()=>x.markers),f=B(()=>!x.testRuns||x.testRuns.length===0?[]:[...x.testRuns].sort((m,q)=>new Date(m.startTime).getTime()-new Date(q.startTime).getTime()).slice(-30).map(m=>({id:m.id,date:new Date(m.startTime),passed:m.passedTests||0,failed:m.failedTests||0,skipped:m.skippedTests||0,flaky:m.flakyTests||0,total:m.totalTests||0,status:m.status}))),u=g=>g.date,E=g=>g.passed,U=g=>g.failed,R=g=>g.skipped,C=g=>g.flaky,_=["rgb(34, 197, 94)","rgb(239, 68, 68)","rgb(245, 158, 11)","rgb(147, 51, 234)"],y=w(null),{tooltipData:z,tooltipPos:h,markerTooltip:v,markerTooltipPos:M,onRenderComplete:K}=Qt(y,f,{x:g=>g.date,series:[{y:g=>g.passed,color:_[0]},{y:g=>g.failed,color:_[1]},{y:g=>g.skipped,color:_[2]},{y:g=>g.flaky,color:_[3]}],onClick:g=>Ct(`/test-runs/${g.id}`),markers:b,onMarkerClick:g=>D("marker-click",g.id)}),$=[{color:_[0],label:"Passed"},{color:_[1],label:"Failed"},{color:_[2],label:"Skipped"},{color:_[3],label:"Flaky"}];return(g,m)=>{const q=Ht,Z=Se,O=Jt;return s(),i("div",Fn,[e(f).length>0?(s(),i("div",In,[l(e(Gt),{ref_key:"xyContainerRef",ref:y,data:e(f),height:A.height,padding:{top:10,right:10,bottom:0,left:0},"on-render-complete":e(K)},{default:t(()=>[l(e(Ks),{x:u,y:[E,U,R,C],color:_,"curve-type":e(kt).MonotoneX},null,8,["y","curve-type"]),l(e(Xt),{x:u,y:[E,U,R,C],color:_,"curve-type":e(kt).MonotoneX,"line-width":2},null,8,["y","curve-type"]),l(e(at),{type:"x","tick-format":P=>new Date(P).toLocaleDateString("en-US",{month:"short",day:"numeric"})},null,8,["tick-format"]),l(e(at),{type:"y",label:"Tests","tick-format":P=>P.toString()},null,8,["tick-format"])]),_:1},8,["data","height","on-render-complete"]),e(z)?(s(),i("div",{key:0,class:"fixed z-50 pointer-events-none bg-white dark:bg-gray-800 rounded-lg shadow-lg border border-gray-200 dark:border-gray-700 max-w-[260px]",style:Kt({left:`${e(h).x}px`,top:`${e(h).y}px`})},[a("div",En,[a("div",Vn,c(new Date(e(z).date).toLocaleDateString("en-US",{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})),1),a("div",Bn,"Status: "+c(e(z).status),1),a("div",Pn,[a("div",null,[m[0]||(m[0]=a("span",{class:"text-green-500 dark:text-green-400"},"●",-1)),d(" Passed: "+c(e(z).passed),1)]),a("div",null,[m[1]||(m[1]=a("span",{class:"text-red-500 dark:text-red-400"},"●",-1)),d(" Failed: "+c(e(z).failed),1)]),a("div",null,[m[2]||(m[2]=a("span",{class:"text-orange-500 dark:text-orange-400"},"●",-1)),d(" Skipped: "+c(e(z).skipped),1)]),a("div",null,[m[3]||(m[3]=a("span",{class:"text-purple-500 dark:text-purple-400"},"●",-1)),d(" Flaky: "+c(e(z).flaky),1)]),a("div",Nn,"Total: "+c(e(z).total),1)]),m[4]||(m[4]=a("div",{class:"text-gray-400 dark:text-gray-500 text-xs mt-1"},"Click to view run details",-1))])],4)):S("",!0),l(q,{marker:e(v),pos:e(M)},null,8,["marker","pos"])])):(s(),k(Z,{key:1,text:"No test run data available to display chart"})),l(O,{items:$})])}}}),Ln=Object.assign(Kn,{__name:"TestRunsChart"}),On={class:"space-y-3"},qn={class:"min-w-0 space-y-1"},Hn={class:"flex items-center gap-2 flex-wrap text-sm"},Xn={key:0,class:"text-gray-500"},Gn=["title"],Jn=["title"],Qn={key:0,class:"text-xs text-gray-500 italic"},Yn={class:"flex items-center gap-2 shrink-0"},Wn=ue({__name:"ClusterMergeSuggestions",props:{projectId:{}},emits:["merged"],setup(A,{emit:T}){const x=A,D=T,b=Re(),f=w([]),u=w(null);async function E(){try{f.value=await $fetch(`/api/projects/${x.projectId}/cluster-merge-suggestions`)}catch{f.value=[]}}ge(()=>x.projectId,E,{immediate:!0});async function U(C,_){u.value=C;try{await $fetch(`/api/cluster-merge-suggestions/${C}/${_}`,{method:"POST"}),b.add({title:_==="approve"?"Clusters merged":"Suggestion dismissed",color:"success"}),await E(),_==="approve"&&D("merged")}catch(y){b.add({title:"Action failed",description:String(y?.message??y),color:"error"})}finally{u.value=null}}const R=C=>C==null?"":`${Math.round(C*100)}% similar`;return(C,_)=>{const y=Ae,z=Te,h=Yt;return e(f).length?(s(),k(h,{key:0,icon:"i-lucide-git-merge",title:"Suggested merges",count:e(f).length,class:"mb-4"},{subtitle:t(()=>[..._[0]||(_[0]=[d(" Likely-duplicate clusters found by semantic analysis. Approving merges them into the older cluster. ",-1)])]),default:t(()=>[a("div",On,[(s(!0),i(Q,null,ie(e(f),v=>(s(),i("div",{key:v.id,class:"rounded-lg border border-default p-3 flex items-start justify-between gap-4"},[a("div",qn,[a("div",Hn,[l(y,{color:v.method==="llm"?"primary":"neutral",variant:"subtle",size:"sm"},{default:t(()=>[d(c(v.method==="llm"?`AI · ${v.llmConfidence??""}`:"similarity"),1)]),_:2},1032,["color"]),R(v.score)?(s(),i("span",Xn,c(R(v.score)),1)):S("",!0)]),a("p",{class:"text-sm truncate",title:v.clusterA?.signature||""},[_[1]||(_[1]=a("span",{class:"text-gray-400"},"A:",-1)),d(" "+c(v.clusterA?.signature||`#${v.id}`),1)],8,Gn),a("p",{class:"text-sm truncate",title:v.clusterB?.signature||""},[_[2]||(_[2]=a("span",{class:"text-gray-400"},"B:",-1)),d(" "+c(v.clusterB?.signature||""),1)],8,Jn),v.llmReason?(s(),i("p",Qn,c(v.llmReason),1)):S("",!0)]),a("div",Yn,[l(z,{size:"sm",color:"primary",icon:"i-lucide-git-merge",loading:e(u)===v.id,onClick:M=>U(v.id,"approve")},{default:t(()=>[..._[3]||(_[3]=[d(" Merge ",-1)])]),_:1},8,["loading","onClick"]),l(z,{size:"sm",color:"neutral",variant:"ghost",icon:"i-lucide-x",disabled:e(u)===v.id,onClick:M=>U(v.id,"reject")},{default:t(()=>[..._[4]||(_[4]=[d(" Dismiss ",-1)])]),_:1},8,["disabled","onClick"])])]))),128))])]),_:1},8,["count"])):S("",!0)}}}),Zn=Object.assign(Wn,{__name:"ClusterMergeSuggestions"}),ea={class:"flex items-center justify-between"},ta={class:"text-sm text-gray-500 inline-flex items-center gap-1"},sa={class:"min-w-0 space-y-0.5"},na={key:0,class:"text-xs text-gray-500 italic truncate"},aa={key:1,class:"text-gray-400 text-xs"},oa={class:"text-sm tabular-nums"},la={class:"text-sm tabular-nums"},ra={key:1,class:"text-gray-400 text-xs"},ia={class:"text-sm text-gray-500 whitespace-nowrap"},ca={key:0,class:"ml-1 text-xs text-gray-400"},ua={class:"flex justify-end"},da=ue({__name:"FailureClustersList",props:{projectId:{}},async setup(A){let T,x;const D=A,b=w(void 0),{data:f,pending:u}=([T,x]=ye(()=>he(()=>{const U=new URLSearchParams;b.value&&U.set("status",b.value);const R=U.toString();return`/api/projects/${D.projectId}/failure-clusters${R?`?${R}`:""}`},{lazy:!0,server:!1,watch:[b]},"$f7pDU1t-lL")),T=await T,x(),T),E=[{accessorKey:"signature",header:I("Signature")},{accessorKey:"errorType",header:I("Type")},{accessorKey:"status",header:I("Status")},{accessorKey:"affectedTests",header:I("Tests")},{accessorKey:"occurrences",header:I("Occurrences")},{accessorKey:"diagnosis",header:"AI"},{accessorKey:"lastSeenAt",header:I("Last seen")},{id:"actions",header:"Actions"}];return(U,R)=>{const C=qe,_=Ue,y=Oe,z=Ae,h=Le,v=Te,M=ze,K=lt,$=Se,g=He;return s(),k(g,null,{header:t(()=>[a("div",ea,[a("p",ta,[R[1]||(R[1]=d(" Ongoing failure signatures grouped by normalized error. ",-1)),l(C,{topic:"cluster.concept"})]),l(_,{modelValue:e(b),"onUpdate:modelValue":R[0]||(R[0]=m=>G(b)?b.value=m:null),items:[{label:"All",value:void 0},{label:"Open",value:"open"},{label:"Resolved",value:"resolved"},{label:"Ignored",value:"ignored"}],size:"xs",class:"w-32"},null,8,["modelValue"])])]),default:t(()=>[l(K,{"min-width":"48rem",bleed:!1},{default:t(()=>[l(M,{data:e(f)??[],columns:E,loading:e(u)},{"actions-header":t(()=>[...R[2]||(R[2]=[a("div",{class:"text-right"},"Actions",-1)])]),"signature-cell":t(({row:m})=>[a("div",sa,[l(y,{to:`/failure-clusters/${m.original.id}`,class:re(["text-sm text-primary hover:underline truncate block",m.original.title?"":"font-mono"]),title:m.original.signature},{default:t(()=>[d(c(m.original.title||m.original.signature),1)]),_:2},1032,["to","class","title"]),m.original.triageNote?(s(),i("p",na,c(m.original.triageNote),1)):S("",!0)])]),"errorType-cell":t(({row:m})=>[m.original.errorType?(s(),k(z,{key:0,color:("clusterErrorTypeColor"in U?U.clusterErrorTypeColor:e(Ys))(m.original.errorType),variant:"subtle",size:"sm"},{default:t(()=>[d(c(m.original.errorType),1)]),_:2},1032,["color"])):(s(),i("span",aa,"—"))]),"status-cell":t(({row:m})=>[l(z,{color:("clusterStatusColor"in U?U.clusterStatusColor:e(Qs))(m.original.status),variant:"subtle",size:"sm"},{default:t(()=>[d(c(m.original.status),1)]),_:2},1032,["color"])]),"affectedTests-cell":t(({row:m})=>[a("span",oa,c(m.original.affectedTests),1)]),"occurrences-cell":t(({row:m})=>[a("span",la,c(m.original.occurrences),1)]),"diagnosis-cell":t(({row:m})=>[m.original.diagnosis?.status==="completed"&&m.original.diagnosis.category?(s(),k(z,{key:0,color:"neutral",variant:"subtle",size:"sm",class:"gap-1"},{default:t(()=>[l(h,{name:"i-lucide-sparkles",class:"size-3"}),d(" "+c(m.original.diagnosis.category),1)]),_:2},1024)):(s(),i("span",ra,"—"))]),"lastSeenAt-cell":t(({row:m})=>[a("div",ia,[l(y,{to:`/test-runs/${m.original.lastSeenRunId}`,class:"text-primary hover:underline"},{default:t(()=>[d(" run #"+c(m.original.lastSeenRunId),1)]),_:2},1032,["to"]),m.original.lastSeenAt?(s(),i("span",ca," ("+c(("formatRelativeTime"in U?U.formatRelativeTime:e(St))(m.original.lastSeenAt))+") ",1)):S("",!0)])]),"actions-cell":t(({row:m})=>[a("div",ua,[l(v,{to:`/failure-clusters/${m.original.id}`,size:"sm",variant:"outline","trailing-icon":"i-lucide-arrow-right"},{default:t(()=>[...R[3]||(R[3]=[d(" View ",-1)])]),_:1},8,["to"])])]),_:1},8,["data","loading"])]),_:1}),!e(u)&&e(f)&&e(f).length===0?(s(),k($,{key:0,text:"No failure clusters recorded for this project.",padded:!1,class:"py-4"})):S("",!0)]),_:1})}}}),ma=Object.assign(da,{__name:"FailureClustersList"}),pa={class:"flex items-center justify-between"},ga={class:"flex items-center gap-3"},fa={class:"text-sm text-gray-500 inline-flex items-center gap-1"},va={class:"flex items-center gap-1.5"},_a={class:"min-w-0 space-y-0.5"},ya={class:"flex items-center gap-2"},ha={class:"text-sm tabular-nums"},ba={class:"text-sm tabular-nums"},xa={key:1,class:"text-gray-400 text-xs"},ka={key:1,class:"text-gray-400 text-xs"},$a={key:1,class:"text-gray-400 text-xs"},Ca={key:0,class:"text-sm text-gray-500"},Ta={key:1,class:"text-gray-400 text-xs"},Sa={class:"flex justify-end"},ja={key:0,class:"text-sm text-gray-500 py-4 text-center"},wa=ue({__name:"FlakyTestsList",props:{projectId:{},environment:{},projectName:{}},async setup(A){let T,x;const D=A,b=w(50),f=w([]),{data:u,pending:E}=([T,x]=ye(()=>he(()=>{const h=new URLSearchParams({runs:String(b.value)});return D.environment&&h.set("environment",D.environment),`/api/projects/${D.projectId}/flaky-tests?${h.toString()}`},{lazy:!0,server:!1,watch:[b,()=>D.environment]},"$qKoEnbecbI")),T=await T,x(),T),U=B(()=>f.value.length===0?u.value??[]:(u.value??[]).filter(h=>f.value.includes(h.rootCause??"")));function R(h){return h>=60?"error":h>=30?"warning":"neutral"}function C(h){switch(h){case"timing":return"amber";case"network":return"red";case"assertion":return"blue";case"environment":return"purple";default:return"gray"}}function _(h){f.value.indexOf(h)>=0?f.value=f.value.filter(M=>M!==h):f.value=[...f.value,h]}const y=[{label:"Timing",value:"timing"},{label:"Network",value:"network"},{label:"Assertion",value:"assertion"},{label:"Environment",value:"environment"},{label:"Other",value:"other"}],z=[{accessorKey:"title",header:I("Test")},{accessorKey:"impact",header:I("Impact")},{accessorKey:"score",header:I("Score")},{accessorKey:"failureRate",header:I("Failure rate")},{accessorKey:"retryPassRuns",header:I("Retry passes")},{accessorKey:"alternations",header:I("Flips")},{accessorKey:"rootCause",header:"Root cause"},{accessorKey:"lastFlakeAt",header:I("Last flake")},{id:"actions",header:"Actions"}];return(h,v)=>{const M=qe,K=Le,$=Ae,g=Te,m=Ue,q=Oe,Z=jt,O=qt,P=ze,be=lt,xe=He;return s(),k(xe,null,{header:t(()=>[a("div",pa,[a("div",ga,[a("p",fa,[v[1]||(v[1]=d(" Tests that fail intermittently — detected by retry passes and status alternations ",-1)),l(M,{topic:"project.flaky-tests"})]),A.environment?(s(),k($,{key:0,color:"neutral",variant:"subtle",size:"sm",class:"gap-1"},{default:t(()=>[l(K,{name:"i-lucide-layers",class:"size-3"}),d(" "+c(A.environment),1)]),_:1})):S("",!0),a("div",va,[(s(),i(Q,null,ie(y,p=>l(g,{key:p.value,size:"xs",variant:e(f).includes(p.value)?"solid":"outline",color:(e(f).includes(p.value),"neutral"),onClick:L=>_(p.value)},{default:t(()=>[d(c(p.label),1)]),_:2},1032,["variant","color","onClick"])),64))])]),l(m,{modelValue:e(b),"onUpdate:modelValue":v[0]||(v[0]=p=>G(b)?b.value=p:null),items:[{label:"Last 20 runs",value:20},{label:"Last 50 runs",value:50},{label:"Last 100 runs",value:100}],size:"xs",class:"w-36"},null,8,["modelValue"])])]),default:t(()=>[l(be,{"min-width":"52rem",bleed:!1},{default:t(()=>[l(P,{data:e(U),columns:z,loading:e(E),sticky:"",class:"max-h-[32rem]"},{"actions-header":t(()=>[...v[2]||(v[2]=[a("div",{class:"text-right"},"Actions",-1)])]),"title-cell":t(({row:p})=>[a("div",_a,[l(q,{to:`/test-run-cases/${p.original.latestRunsCaseId}`,class:"text-sm font-medium text-primary hover:underline truncate block",title:p.original.title},{default:t(()=>[d(c(p.original.title),1)]),_:2},1032,["to","title"]),l(Z,{"file-path":p.original.filePath,"project-key":A.projectId,"project-name":A.projectName,class:"text-xs text-gray-400"},null,8,["file-path","project-key","project-name"])])]),"impact-cell":t(({row:p})=>[a("div",ya,[a("span",{class:re(["inline-block w-2 h-2 rounded-full shrink-0",{"bg-red-500":p.original.wastedCiMinutes>=30,"bg-amber-500":p.original.wastedCiMinutes>=5&&p.original.wastedCiMinutes<30,"bg-green-500":p.original.wastedCiMinutes>=0&&p.original.wastedCiMinutes<5}])},null,2),a("span",ha,c(Math.round(p.original.wastedCiMinutes))+" min wasted",1)])]),"score-cell":t(({row:p})=>[l($,{color:R(p.original.score),variant:"subtle",size:"sm"},{default:t(()=>[d(c(p.original.score),1)]),_:2},1032,["color"])]),"failureRate-cell":t(({row:p})=>[a("span",ba,c(Math.round(p.original.failureRate*100))+"%",1)]),"retryPassRuns-cell":t(({row:p})=>[p.original.retryPassRuns?(s(),k($,{key:0,color:"warning",variant:"outline",size:"sm"},{default:t(()=>[d(c(p.original.retryPassRuns)+" run"+c(p.original.retryPassRuns===1?"":"s"),1)]),_:2},1024)):(s(),i("span",xa,"—"))]),"alternations-cell":t(({row:p})=>[p.original.alternations>=2?(s(),k($,{key:0,color:"neutral",variant:"outline",size:"sm"},{default:t(()=>[d(c(p.original.alternations),1)]),_:2},1024)):(s(),i("span",ka,"—"))]),"rootCause-cell":t(({row:p})=>[p.original.rootCause?(s(),k(O,{key:0,text:p.original.rootCause,color:C(p.original.rootCause)},null,8,["text","color"])):(s(),i("span",$a,"—"))]),"lastFlakeAt-cell":t(({row:p})=>[p.original.lastFlakeAt?(s(),i("span",Ca,c(("formatRelativeTime"in h?h.formatRelativeTime:e(St))(p.original.lastFlakeAt)),1)):(s(),i("span",Ta,"—"))]),"actions-cell":t(({row:p})=>[a("div",Sa,[l(g,{to:`/test-run-cases/${p.original.latestRunsCaseId}`,size:"sm",variant:"outline","trailing-icon":"i-lucide-arrow-right"},{default:t(()=>[...v[3]||(v[3]=[d(" View ",-1)])]),_:1},8,["to"])])]),_:1},8,["data","loading"])]),_:1}),!e(E)&&e(U).length===0?(s(),i("p",ja," No flaky tests detected in the last "+c(e(b))+" runs. ",1)):S("",!0)]),_:1})}}}),Da=Object.assign(wa,{__name:"FlakyTestsList"}),Ra={class:"w-full relative"},Aa={key:0},Ua={class:"p-2 text-sm text-gray-900 dark:text-gray-100"},za={class:"font-semibold mb-1"},Ma={class:"capitalize mb-1"},Fa={class:"space-y-0.5"},Ia={class:"mt-1"},Ea={key:0,class:"text-gray-400 dark:text-gray-500 text-xs"},Va=ue({__name:"PerformanceTrendChart",props:{data:{},height:{default:300},markers:{default:()=>[]}},emits:["marker-click"],setup(A,{emit:T}){const x=A,D=T,b=B(()=>x.markers),f=B(()=>!x.data||x.data.length===0?[]:x.data.map($=>({id:$.id,date:new Date($.startTime),duration:$.duration?Math.round($.duration/1e3):null,avgTestDuration:$.avgTestDuration?Math.round($.avgTestDuration/1e3):null,p90TestDuration:$.p90TestDuration?Math.round($.p90TestDuration/1e3):null,commit:$.commit?$.commit.substring(0,7):null,status:$.status,totalTests:$.totalTests}))),u=$=>$.date,E=$=>$.duration??void 0,U=$=>$.avgTestDuration??void 0,R=$=>$.p90TestDuration??void 0,C=["rgb(59, 130, 246)","rgb(34, 197, 94)","rgb(249, 115, 22)"],_=w(null),{tooltipData:y,tooltipPos:z,markerTooltip:h,markerTooltipPos:v,onRenderComplete:M}=Qt(_,f,{x:$=>$.date,series:[{y:$=>$.duration,color:C[0]},{y:$=>$.avgTestDuration,color:C[1]},{y:$=>$.p90TestDuration,color:C[2]}],onClick:$=>Ct(`/test-runs/${$.id}`),markers:b,onMarkerClick:$=>D("marker-click",$.id)}),K=[{color:C[0],label:"Total Duration"},{color:C[1],label:"Avg Test Duration"},{color:C[2],label:"P90 Test Duration"}];return($,g)=>{const m=Ht,q=Se,Z=Jt;return s(),i("div",Ra,[e(f).length>0?(s(),i("div",Aa,[l(e(Gt),{ref_key:"xyContainerRef",ref:_,data:e(f),height:A.height,padding:{top:10,right:10,bottom:0,left:0},"on-render-complete":e(M)},{default:t(()=>[l(e(Xt),{x:u,y:[E,U,R],color:C,"curve-type":e(kt).MonotoneX,"line-width":2},null,8,["y","curve-type"]),l(e(at),{type:"x","tick-format":O=>new Date(O).toLocaleDateString("en-US",{month:"short",day:"numeric"}),label:"Date"},null,8,["tick-format"]),l(e(at),{type:"y",label:"Duration (s)","tick-format":O=>`${O}s`},null,8,["tick-format"])]),_:1},8,["data","height","on-render-complete"]),e(y)?(s(),i("div",{key:0,class:"fixed z-50 pointer-events-none bg-white dark:bg-gray-800 rounded-lg shadow-lg border border-gray-200 dark:border-gray-700 max-w-[260px]",style:Kt({left:`${e(z).x}px`,top:`${e(z).y}px`})},[a("div",Ua,[a("div",za,c(new Date(e(y).date).toLocaleDateString("en-US",{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})),1),a("div",Ma,"Status: "+c(e(y).status),1),a("div",Fa,[a("div",null,[g[0]||(g[0]=a("span",{class:"text-blue-500 dark:text-blue-400"},"●",-1)),d(" Total: "+c(e(y).duration??"-")+"s ",1)]),a("div",null,[g[1]||(g[1]=a("span",{class:"text-green-500 dark:text-green-400"},"●",-1)),d(" Avg: "+c(e(y).avgTestDuration??"-")+"s ",1)]),a("div",null,[g[2]||(g[2]=a("span",{class:"text-orange-500 dark:text-orange-400"},"●",-1)),d(" P90: "+c(e(y).p90TestDuration??"-")+"s ",1)]),a("div",Ia,"Tests: "+c(e(y).totalTests),1),e(y).commit?(s(),i("div",Ea," Commit: "+c(e(y).commit),1)):S("",!0)]),g[3]||(g[3]=a("div",{class:"text-gray-400 dark:text-gray-500 text-xs mt-1"},"Click to view run details",-1))])],4)):S("",!0),l(m,{marker:e(h),pos:e(v)},null,8,["marker","pos"])])):(s(),k(q,{key:1,text:"No performance data available to display chart"})),l(Z,{items:K})])}}}),Ba=Object.assign(Va,{__name:"PerformanceTrendChart"}),Pa={class:"min-w-0"},Na={class:"mt-1"},Ka={class:"tabular-nums"},La={key:0,class:"ml-1 text-xs text-gray-500",title:"timeout ÷ p95"},Oa={class:"tabular-nums text-gray-500"},qa={key:0,class:"text-sm"},Ha={key:1,class:"tabular-nums"},Xa={class:"tabular-nums font-medium text-green-600 dark:text-green-400"},Ga={class:"tabular-nums text-gray-500"},Ja=ue({__name:"TimeoutOpportunitiesTable",props:{projectId:{},projectName:{}},async setup(A){let T,x;const D=A,{data:b,pending:f}=([T,x]=ye(()=>he(()=>`/api/projects/${D.projectId}/timeout-opportunities`,{lazy:!0,server:!1},"$tMBJjTyDol")),T=await T,x(),T),u=B(()=>b.value??[]);function E(R){return R==null?"—":R<1e3?`${R}ms`:`${(R/1e3).toFixed(1)}s`}const U=[{accessorKey:"title",header:I("Test case")},{accessorKey:"kind",header:"Type"},{accessorKey:"timeout",header:I("Timeout")},{accessorKey:"p95",header:I("p95")},{accessorKey:"recommendedTimeout",header:"Recommendation"},{accessorKey:"estimatedSavingMs",header:I("Est. saving / failure")},{accessorKey:"runCount",header:I("Runs")}];return(R,C)=>{const _=wt,y=Se,z=Oe,h=jt,v=Ae,M=ze,K=lt,$=He;return s(),k($,null,{header:t(()=>[...C[0]||(C[0]=[a("h2",{class:"text-xl font-semibold"},"Timeout opportunities",-1),a("p",{class:"text-sm text-gray-600 mt-1"},[d(" Tests whose configured timeout far exceeds their real duration, or that still carry a stale "),a("code",{class:"text-xs"},"test.slow()"),d(" mark — tightening these makes failures surface sooner. ")],-1)])]),default:t(()=>[e(f)?(s(),k(_,{key:0})):e(u).length===0?(s(),k(y,{key:1,text:"No timeout opportunities",description:"No oversized timeouts or stale test.slow() marks were found for this project."})):(s(),k(K,{key:2,"min-width":"52rem",bleed:!1},{default:t(()=>[l(M,{data:e(u),columns:U,sticky:"",class:"max-h-[32rem]"},{"title-cell":t(({row:g})=>[a("div",Pa,[l(z,{to:`/test-cases/${g.original.testCaseId}`,class:"font-medium truncate block hover:text-primary hover:underline"},{default:t(()=>[d(c(g.original.title),1)]),_:2},1032,["to"]),a("div",Na,[l(h,{"file-path":g.original.filePath,"project-key":A.projectId,"project-name":A.projectName,class:"text-xs"},null,8,["file-path","project-key","project-name"])])])]),"kind-cell":t(({row:g})=>[l(v,{color:g.original.kind==="oversized-timeout"?"warning":"info",variant:"subtle",size:"sm"},{default:t(()=>[d(c(g.original.kind==="oversized-timeout"?"Oversized timeout":"Stale test.slow()"),1)]),_:2},1032,["color"])]),"timeout-cell":t(({row:g})=>[a("span",Ka,c(E(g.original.timeout)),1),g.original.headroomRatio!=null?(s(),i("span",La," ("+c(g.original.headroomRatio)+"×) ",1)):S("",!0)]),"p95-cell":t(({row:g})=>[a("span",Oa,c(E(g.original.p95)),1)]),"recommendedTimeout-cell":t(({row:g})=>[g.original.kind==="stale-slow"?(s(),i("span",qa,[...C[1]||(C[1]=[d("Remove ",-1),a("code",{class:"text-xs"},"test.slow()",-1)])])):(s(),i("span",Ha,"Lower to ~"+c(E(g.original.recommendedTimeout)),1))]),"estimatedSavingMs-cell":t(({row:g})=>[a("span",Xa,c(E(g.original.estimatedSavingMs)),1)]),"runCount-cell":t(({row:g})=>[a("span",Ga,c(g.original.runCount),1)]),_:1},8,["data"])]),_:1}))]),_:1})}}}),Qa=Object.assign(Ja,{__name:"TimeoutOpportunitiesTable"}),Ya={class:"flex items-center justify-between"},Wa={class:"text-sm text-gray-500 inline-flex items-center gap-1"},Za={class:"truncate font-mono text-xs"},eo={class:"tabular-nums"},to={class:"tabular-nums text-gray-500"},so={class:"tabular-nums text-gray-500"},no=ue({__name:"SpecHealthTable",props:{projectId:{}},async setup(A){let T,x;const D=A,b=w(30),{data:f,pending:u}=([T,x]=ye(()=>he(()=>`/api/projects/${D.projectId}/spec-health?days=${b.value}`,{lazy:!0,server:!1,watch:[b]},"$QL0nEFEG1b")),T=await T,x(),T),E=B(()=>f.value?.specs??[]);function U(h){return h>=.9?"bg-green-500":h>=.7?"bg-amber-500":h>0?"bg-red-500":"bg-gray-300 dark:bg-gray-600"}function R(h){return h>=.9?"text-green-600 dark:text-green-400":h>=.7?"text-amber-600 dark:text-amber-400":h>0?"text-red-600 dark:text-red-400":"text-gray-500"}function C(h){return`${Math.round(h*100)}%`}function _(h){return h<1e3?`${h}ms`:`${(h/1e3).toFixed(1)}s`}const y=[{label:"Last 7 days",value:7},{label:"Last 30 days",value:30},{label:"Last 90 days",value:90}],z=[{accessorKey:"prefix",header:I("Spec prefix")},{accessorKey:"passRate",header:I("Pass rate")},{accessorKey:"flakyRate",header:I("Flaky")},{accessorKey:"failureCount",header:I("Failures")},{accessorKey:"testCount",header:I("Tests")},{accessorKey:"avgDuration",header:I("Avg time")}];return(h,v)=>{const M=qe,K=Ue,$=wt,g=Se,m=Oe,q=ze,Z=lt,O=He;return s(),k(O,null,{header:t(()=>[a("div",Ya,[a("p",Wa,[v[1]||(v[1]=d(" Spec-file health overview — pass rate, flaky rate, and failure count per spec prefix ",-1)),l(M,{topic:"project.spec-health"})]),l(K,{modelValue:e(b),"onUpdate:modelValue":v[0]||(v[0]=P=>G(b)?b.value=P:null),items:y,size:"xs",class:"w-32"},null,8,["modelValue"])])]),default:t(()=>[e(u)?(s(),k($,{key:0})):e(E).length===0?(s(),k(g,{key:1,text:"No data",description:"No spec health data available for the selected period."})):(s(),k(Z,{key:2,"min-width":"46rem",bleed:!1},{default:t(()=>[l(q,{data:e(E),columns:z,sticky:"",class:"max-h-[32rem]"},{"prefix-cell":t(({row:P})=>[l(m,{to:`/projects/${A.projectId}/test-cases?file=${encodeURIComponent(P.original.prefix)}`,class:"flex items-center gap-2 min-w-0 text-primary hover:underline",title:P.original.prefix},{default:t(()=>[a("span",{class:re(["inline-block size-3 rounded shrink-0",U(P.original.passRate)])},null,2),a("span",Za,c(P.original.prefix),1)]),_:2},1032,["to","title"])]),"passRate-cell":t(({row:P})=>[a("span",{class:re(["font-medium tabular-nums",R(P.original.passRate)])},c(C(P.original.passRate)),3)]),"flakyRate-cell":t(({row:P})=>[a("span",eo,c(Math.round(P.original.flakyRate*100))+"%",1)]),"failureCount-cell":t(({row:P})=>[a("span",{class:re(["tabular-nums",P.original.failureCount>0?"text-red-600 dark:text-red-400":""])},c(P.original.failureCount),3)]),"testCount-cell":t(({row:P})=>[a("span",to,c(P.original.testCount),1)]),"avgDuration-cell":t(({row:P})=>[a("span",so,c(_(P.original.avgDuration)),1)]),_:1},8,["data"])]),_:1}))]),_:1})}}}),ao=Object.assign(no,{__name:"SpecHealthTable"}),oo={class:"space-y-4"},lo={class:"grid grid-cols-1 sm:grid-cols-2 gap-4"},ro={id:"marker-environments"},io=["value"],co=ue({__name:"MarkerFormModal",props:{open:{type:Boolean},projectId:{},marker:{},environments:{}},emits:["update:open","saved"],setup(A,{emit:T}){const x=A,D=T,b=Re(),f=nn.map(_=>({label:_.label,value:_.id,icon:_.icon})),u=Rs({label:"",occurredAt:"",category:bt,environment:"",description:""}),E=B(()=>!!x.marker),U=w(!1);function R(_){const y=new Date(_),z=h=>String(h).padStart(2,"0");return`${y.getFullYear()}-${z(y.getMonth()+1)}-${z(y.getDate())}T${z(y.getHours())}:${z(y.getMinutes())}`}ge(()=>x.open,_=>{_&&(x.marker?(u.label=x.marker.label,u.occurredAt=R(x.marker.occurredAt),u.category=x.marker.category||bt,u.environment=x.marker.environment??"",u.description=x.marker.description??""):(u.label="",u.occurredAt=R(new Date),u.category=bt,u.environment="",u.description=""))});async function C(){if(!u.label.trim()){b.add({title:"Label is required",color:"error"});return}if(!u.occurredAt){b.add({title:"Date is required",color:"error"});return}U.value=!0;const _={label:u.label.trim(),occurredAt:new Date(u.occurredAt).toISOString(),category:u.category,environment:u.environment.trim()||null,description:u.description.trim()||null};try{x.marker?(await $fetch(`/api/markers/${x.marker.id}`,{method:"PUT",body:_}),b.add({title:"Marker updated",color:"success"})):(await $fetch(`/api/projects/${x.projectId}/markers`,{method:"POST",body:_}),b.add({title:"Marker created",color:"success"})),D("update:open",!1),D("saved")}catch(y){b.add({title:E.value?"Failed to update marker":"Failed to create marker",description:Wt(y),color:"error"})}finally{U.value=!1}}return(_,y)=>{const z=Lt,h=Ot,v=Ue,M=sn,K=Te,$=Dt,g=Tt;return s(),k(g,null,{default:t(()=>[l($,{open:A.open,title:e(E)?"Edit marker":"Add marker","onUpdate:open":y[6]||(y[6]=m=>D("update:open",m))},{body:t(()=>[a("div",oo,[l(h,{label:"Label",name:"label",required:""},{default:t(()=>[l(z,{modelValue:e(u).label,"onUpdate:modelValue":y[0]||(y[0]=m=>e(u).label=m),placeholder:"e.g. Migrated CI to new runners",class:"w-full"},null,8,["modelValue"])]),_:1}),a("div",lo,[l(h,{label:"Date & time",name:"occurredAt",required:""},{default:t(()=>[l(z,{modelValue:e(u).occurredAt,"onUpdate:modelValue":y[1]||(y[1]=m=>e(u).occurredAt=m),type:"datetime-local",class:"w-full"},null,8,["modelValue"])]),_:1}),l(h,{label:"Category",name:"category"},{default:t(()=>[l(v,{modelValue:e(u).category,"onUpdate:modelValue":y[2]||(y[2]=m=>e(u).category=m),items:e(f),class:"w-full"},null,8,["modelValue","items"])]),_:1})]),l(h,{label:"Environment",name:"environment",help:"Optional. Leave empty to apply to all environments."},{default:t(()=>[l(z,{modelValue:e(u).environment,"onUpdate:modelValue":y[3]||(y[3]=m=>e(u).environment=m),list:"marker-environments",placeholder:"e.g. production",class:"w-full"},null,8,["modelValue"]),a("datalist",ro,[(s(!0),i(Q,null,ie(A.environments||[],m=>(s(),i("option",{key:m,value:m},null,8,io))),128))])]),_:1}),l(h,{label:"Description",name:"description"},{default:t(()=>[l(M,{modelValue:e(u).description,"onUpdate:modelValue":y[4]||(y[4]=m=>e(u).description=m),rows:3,placeholder:"Optional details",class:"w-full"},null,8,["modelValue"])]),_:1})])]),footer:t(()=>[l(K,{color:"neutral",variant:"ghost",label:"Cancel",onClick:y[5]||(y[5]=m=>D("update:open",!1))}),l(K,{label:e(E)?"Save changes":"Add marker",icon:e(E)?"i-lucide-check":"i-lucide-plus",loading:e(U),onClick:C},null,8,["label","icon","loading"])]),_:1},8,["open","title"])]),_:1})}}}),uo=Object.assign(co,{__name:"MarkerFormModal"}),mo={class:"md:hidden space-y-3"},po={class:"flex items-start justify-between gap-2"},go={key:0,class:"flex gap-1 shrink-0"},fo={class:"text-sm text-muted"},vo={key:0,class:"text-xs"},_o={key:1,class:"text-sm text-muted"},yo={class:"whitespace-nowrap"},ho={class:"text-sm"},bo={class:"text-xs text-muted"},xo={class:"font-medium flex items-center gap-1"},ko={key:0,class:"text-xs text-muted line-clamp-1"},$o={key:1,class:"text-xs text-muted"},Co={key:0,class:"flex gap-1 justify-end"},To=ue({__name:"ProjectTimeline",props:{projectId:{},markers:{},environments:{},canEdit:{type:Boolean},focusMarkerId:{}},emits:["changed","clear-focus"],setup(A,{emit:T}){const x=A,D=T,b=Re(),f=B(()=>[...x.markers].sort((v,M)=>+new Date(M.occurredAt)-+new Date(v.occurredAt))),u=[{accessorKey:"occurredAt",header:"When"},{accessorKey:"category",header:"Category"},{accessorKey:"label",header:"Label"},{accessorKey:"environment",header:"Environment"},{accessorKey:"actions",header:""}],E=w(!1),U=w(null);function R(){U.value=null,E.value=!0}function C(v){U.value=v,E.value=!0}ge(()=>x.focusMarkerId,v=>{if(v==null)return;const M=x.markers.find(K=>K.id===v);M&&C(M),D("clear-focus")},{immediate:!0});const _=w(!1),y=w(null);function z(v){y.value=v,_.value=!0}async function h(){const v=y.value;if(_.value=!1,y.value=null,!!v)try{await $fetch(`/api/markers/${v.id}`,{method:"DELETE"}),b.add({title:"Marker deleted",color:"success"}),D("changed")}catch(M){b.add({title:"Failed to delete marker",description:Wt(M),color:"error"})}}return(v,M)=>{const K=Te,$=Se,g=tn,m=Ae,q=Le,Z=ze,O=uo,P=Dt,be=Tt,xe=Yt;return s(),k(xe,{title:"Timeline markers",count:A.markers.length,icon:"i-lucide-milestone",help:"project.timeline",subtitle:"Dated events overlaid on the analytics charts"},{actions:t(()=>[A.canEdit?(s(),k(K,{key:0,label:"Add marker",icon:"i-lucide-plus",size:"sm",onClick:R})):S("",!0)]),default:t(()=>[A.markers.length===0?(s(),k($,{key:0,icon:"i-lucide-milestone",text:"No markers yet. Add a deploy, config change, or incident to see it on the charts."})):(s(),i(Q,{key:1},[a("div",mo,[(s(!0),i(Q,null,ie(e(f),p=>(s(),i("div",{key:p.id,class:"rounded-lg border border-default p-3 space-y-2"},[a("div",po,[l(g,{marker:p},null,8,["marker"]),A.canEdit?(s(),i("div",go,[l(K,{icon:"i-lucide-pencil",color:"neutral",variant:"ghost",size:"xs",onClick:L=>C(p)},null,8,["onClick"]),l(K,{icon:"i-lucide-trash-2",color:"error",variant:"ghost",size:"xs",onClick:L=>z(p)},null,8,["onClick"])])):S("",!0)]),a("div",fo,c(("prettyDateFormat"in v?v.prettyDateFormat:e(ot))(p.occurredAt)),1),p.environment?(s(),i("div",vo,[l(m,{color:"neutral",variant:"subtle",size:"xs"},{default:t(()=>[d(c(p.environment),1)]),_:2},1024)])):S("",!0),p.description?(s(),i("p",_o,c(p.description),1)):S("",!0)]))),128))]),l(Z,{data:e(f),columns:u,class:"hidden md:block"},{"occurredAt-cell":t(({row:p})=>[a("div",yo,[a("div",ho,c(("prettyDateFormat"in v?v.prettyDateFormat:e(ot))(p.original.occurredAt)),1),a("div",bo,c(("formatRelativeTime"in v?v.formatRelativeTime:e(St))(p.original.occurredAt)),1)])]),"category-cell":t(({row:p})=>[l(m,{color:e(xt)(p.original.category).color,variant:"subtle",size:"sm",class:"gap-1"},{default:t(()=>[l(q,{name:e(xt)(p.original.category).icon,class:"size-3"},null,8,["name"]),d(" "+c(e(xt)(p.original.category).label),1)]),_:2},1032,["color"])]),"label-cell":t(({row:p})=>[a("div",null,[a("div",xo,[d(c(p.original.label)+" ",1),p.original.source==="auto"?(s(),k(q,{key:0,name:"i-lucide-sparkles",class:"size-3 text-muted",title:"Automatically detected"})):S("",!0)]),p.original.description?(s(),i("div",ko,c(p.original.description),1)):S("",!0)])]),"environment-cell":t(({row:p})=>[p.original.environment?(s(),k(m,{key:0,color:"neutral",variant:"subtle",size:"xs"},{default:t(()=>[d(c(p.original.environment),1)]),_:2},1024)):(s(),i("span",$o,"All"))]),"actions-cell":t(({row:p})=>[A.canEdit?(s(),i("div",Co,[l(K,{icon:"i-lucide-pencil",color:"neutral",variant:"ghost",size:"sm",onClick:L=>C(p.original)},null,8,["onClick"]),l(K,{icon:"i-lucide-trash-2",color:"error",variant:"ghost",size:"sm",onClick:L=>z(p.original)},null,8,["onClick"])])):S("",!0)]),_:1},8,["data"])],64)),l(O,{open:e(E),"onUpdate:open":M[0]||(M[0]=p=>G(E)?E.value=p:null),"project-id":A.projectId,marker:e(U),environments:A.environments,onSaved:M[1]||(M[1]=p=>D("changed"))},null,8,["open","project-id","marker","environments"]),l(be,null,{default:t(()=>[l(P,{open:e(_),title:"Delete marker","onUpdate:open":M[3]||(M[3]=p=>_.value=p)},{body:t(()=>[a("p",null,[M[4]||(M[4]=d(" Delete marker ",-1)),e(y)?(s(),k(g,{key:0,marker:e(y),class:"inline-flex align-middle"},null,8,["marker"])):S("",!0),M[5]||(M[5]=d("? This can't be undone. ",-1))])]),footer:t(()=>[l(K,{color:"neutral",variant:"ghost",label:"Cancel",onClick:M[2]||(M[2]=p=>_.value=!1)}),l(K,{color:"error",label:"Delete",icon:"i-lucide-trash-2",onClick:h})]),_:1},8,["open"])]),_:1})]),_:1},8,["count"])}}}),So=Object.assign(To,{__name:"ProjectTimeline"}),jo={class:"flex flex-col h-full overflow-y-auto gap-4"},wo={key:0,class:"pb-0 space-y-4"},Do={key:0,class:"text-gray-600"},Ro={key:1,class:"flex flex-wrap gap-1 mt-2"},Ao={class:"flex flex-wrap items-center gap-3 mb-4"},Uo={class:"inline-flex items-center gap-1"},zo=["onClick"],Mo={key:0,class:"flex items-center gap-3 px-3 py-2 mb-3 rounded-lg bg-primary-50 dark:bg-primary-900/20 border border-primary-200 dark:border-primary-800"},Fo={class:"text-sm text-primary-700 dark:text-primary-300"},Io={key:1,class:"text-xs text-primary-500"},Eo=["checked","onClick"],Vo={class:"flex items-center gap-2"},Bo=["href","onClick"],Po={key:0,class:"text-xs text-gray-500 dark:text-gray-400 truncate max-w-32"},No={class:"inline-flex items-center gap-1"},Ko={key:0,class:"flex items-center gap-1"},Lo={class:"text-xs text-gray-600"},Oo={key:0,class:"text-xs font-medium bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200 px-1.5 py-0.5 rounded"},qo={key:0,class:"flex items-center gap-1 flex-wrap"},Ho={key:0,class:"text-xs font-medium bg-gray-100 dark:bg-gray-800 px-1.5 py-0.5 rounded"},Xo={key:1,class:"text-xs text-gray-500"},Go={class:"space-y-1"},Jo={class:"text-xs text-gray-500"},Qo={class:"flex justify-end gap-2"},Yo={key:2,class:"text-center py-8 text-gray-500"},Wo={class:"text-xs text-gray-400 max-w-sm"},Zo={class:"bg-gray-100 dark:bg-gray-800 px-1 rounded"},el={class:"flex flex-wrap items-center gap-3"},tl={class:"text-xl font-semibold inline-flex items-center gap-1"},sl={class:"font-medium"},nl={class:"mt-1"},al={key:0,class:"text-red-600 font-medium"},ol={key:1,class:"text-green-600 font-medium"},ll={key:2,class:"text-gray-500"},rl={key:2,class:"text-center py-8 text-red-500"},il={key:3,class:"text-center py-8 text-gray-500"},cl={class:"flex items-center justify-between"},ul={class:"text-xl font-semibold inline-flex items-center gap-1"},dl={class:"space-y-4"},ml={class:"grid grid-cols-1 md:grid-cols-2 gap-4"},pl={key:0,class:"text-center py-4 text-gray-500"},gl={key:1,class:"space-y-4"},fl={class:"flex gap-4 text-sm"},vl={key:0,class:"text-gray-400"},_l={key:0,class:"text-gray-400"},yl={key:0},hl={key:1,class:"text-gray-400"},bl={key:0},xl={key:1,class:"text-gray-400"},kl={key:0,class:"text-gray-400"},$l={key:0,class:"text-gray-400"},Cl={key:2,class:"text-center py-8 text-gray-500"},Tl={key:3,class:"text-center py-8 text-gray-500"},Sl={class:"flex items-center justify-between"},jl={class:"text-sm text-gray-600 inline-flex items-center gap-1"},wl={class:"space-y-4"},Dl={class:"grid grid-cols-1 md:grid-cols-2 gap-4"},Rl={key:0,class:"text-center py-8 text-gray-500"},Al={key:1,class:"space-y-4"},Ul={class:"space-y-2"},zl={class:"flex flex-wrap gap-4 text-sm"},Ml={key:3,class:"text-sm text-gray-500"},Fl={class:"flex flex-wrap gap-4 text-sm"},Il={key:0,class:"text-gray-400"},El={key:0,class:"text-gray-400"},Vl={key:0},Bl={key:1,class:"text-gray-400"},Pl={key:0},Nl={key:1,class:"text-gray-400"},Kl={key:0,class:"text-gray-400"},Ll={key:0,class:"text-gray-400"},Ol={key:2,class:"text-center py-8 text-gray-500"},ql={key:3,class:"text-center py-8 text-gray-500"},Hl={class:"flex items-center justify-between"},Xl={class:"text-sm text-gray-600 inline-flex items-center gap-1"},Gl={key:0,class:"space-y-2"},Jl={class:"font-medium text-sm"},Ql={class:"text-xs text-muted flex items-center gap-2"},Yl={key:0,class:"italic"},Wl={key:1,class:"text-xs text-muted italic"},Zl={key:1,class:"text-center py-8 text-muted text-sm"},er={class:"space-y-4"},tr={class:"text-sm text-gray-600 dark:text-gray-400"},sr={class:"block text-sm font-medium mb-1"},nr={class:"bg-gray-100 dark:bg-gray-800 px-1 rounded"},li=ue({__name:"index",async setup(A){let T,x;const D=As(),b=Us(),f=D.params.id,{data:u,refresh:E}=([T,x]=ye(()=>he(`/api/projects/${f}`,"$NX9Zy2qnH1")),T=await T,x(),T);zs(B(()=>({title:`${u.value?.label||u.value?.name||"Project"} — Piwi Dashboard`})));const U=Re(),R=w(null),C=w(null),{isAdmin:_,isReporter:y}=Nt(),z=$t(),h=B(()=>!z.public.authEnabled||_.value),v=w(!1),M=w(""),K=w(!1),$=B(()=>M.value===u.value?.name);async function g(){if($.value){K.value=!0;try{await $fetch(`/api/projects/${f}`,{method:"DELETE"}),U.add({title:"Project deleted",color:"success"}),await Fs(),await b.push("/")}catch(r){const n=r&&typeof r=="object"&&"data"in r?r.data?.message:void 0;U.add({title:"Delete failed",description:n||"An error occurred",color:"error"}),K.value=!1}}}ln(E);async function m(r){C.value=null,R.value=r;try{await $fetch(`/api/test-runs/${r}`,{method:"DELETE"}),U.add({title:"Test run deleted",color:"success"}),await E()}catch(n){const F=n&&typeof n=="object"&&"data"in n?n.data?.message:void 0;U.add({title:"Delete failed",description:F||"An error occurred",color:"error"})}finally{R.value=null}}const q=w([]),Z=w([]),O=w([]),P=B(()=>{const r=new Map(q.value.map(F=>[F.id,F])),n=[];for(const F of Z.value){if(F.role==="administrator")continue;const H=r.get(F.id);n.push({id:F.id,username:F.username,name:F.name??null,role:F.role,global:H?.global??!1,hasAccess:!!H})}for(const F of q.value)F.role==="administrator"&&n.push({...F,hasAccess:!0});return n}),be=B(()=>{const r=q.value.filter(F=>F.role!=="administrator"&&!F.global).map(F=>F.id).sort(),n=[...O.value].sort();return JSON.stringify(r)!==JSON.stringify(n)});ge(()=>u.value?.id,async r=>{if(!(!r||!_.value))try{const[n,F]=await Promise.all([$fetch(`/api/projects/${f}/members`),$fetch("/api/users")]);q.value=n.users,Z.value=F.users,O.value=n.users.filter(H=>H.role!=="administrator"&&!H.global).map(H=>H.id)}catch{q.value=[],Z.value=[],O.value=[]}},{immediate:!0});function xe(r){const n=O.value.indexOf(r);n>=0?O.value.splice(n,1):O.value.push(r)}async function p(){try{await $fetch(`/api/projects/${f}/members`,{method:"PUT",body:{userIds:O.value}}),U.add({title:"Members updated",color:"success"});const r=await $fetch(`/api/projects/${f}/members`);q.value=r.users}catch(r){const n=r&&typeof r=="object"&&"data"in r?r.data?.message:void 0;U.add({title:"Update failed",description:n||"An error occurred",color:"error"})}}const L=w("test-runs"),oe=w(0),de=["test-runs","failure-clusters","flaky-tests","performance","test-cases","compare","spec-health","timeline","members"],ke=D.query.tab;typeof ke=="string"&&de.includes(ke)&&(L.value=ke),ge(L,r=>{D.query.tab!==r&&de.includes(r)&&b.replace({query:{...D.query,tab:r}})});const fe=B(()=>u.value?.testRuns?.some(r=>r.failedTests>0)??!1),ce=B(()=>[{label:`Test runs (${Ee.value.length})`,icon:"i-lucide-play-circle",value:"test-runs",slot:"test-runs"},...fe.value?[{label:"Failure clusters",icon:"i-lucide-layers",value:"failure-clusters",slot:"failure-clusters"}]:[],{label:"Flaky tests",icon:"i-lucide-shuffle",value:"flaky-tests",slot:"flaky-tests"},{label:"Performance",icon:"i-lucide-trending-up",value:"performance",slot:"performance"},{label:`Test cases${Ne.value!=null?` (${Ne.value})`:""}`,icon:"i-lucide-list-checks",value:"test-cases",slot:"test-cases"},{label:"Compare",icon:"i-lucide-git-compare-arrows",value:"compare",slot:"compare"},{label:"Spec health",icon:"i-lucide-table-2",value:"spec-health",slot:"spec-health"},{label:`Timeline${j.value.length?` (${j.value.length})`:""}`,icon:"i-lucide-milestone",value:"timeline",slot:"timeline"},..._.value?[{label:"Members",icon:"i-lucide-users",value:"members",slot:"members"}]:[]]),ve=B(()=>ce.value.find(r=>r.value===L.value)?.icon),Y=w([]),rt=r=>Y.value.includes(r);function it(r){const n=Y.value.indexOf(r);if(n>=0)Y.value.splice(n,1);else{if(Y.value.length>=2){U.add({title:"Maximum 2 runs",description:"Select at most 2 runs to compare. Deselect one first.",color:"warning"});return}Y.value.push(r)}}const Me=w(null);function Xe(){Y.value.length===2&&(Me.value=[Y.value[0],Y.value[1]],L.value="compare")}const W=w([]),_e=w(!0),Fe=B(()=>{const r=new Set;for(const n of u.value?.testRuns||[])n.environment&&r.add(n.environment);return[...r].sort()});function ct(r){const n=W.value.indexOf(r);n===-1?W.value.push(r):W.value.splice(n,1)}function Ie(r){return W.value.includes(r)}const Ee=B(()=>{let r=u.value?.testRuns||[];return _e.value&&(r=r.filter(n=>n.isFullRun!==!1)),W.value.length===0?r:r.filter(n=>n.environment&&W.value.includes(n.environment))}),ut=B(()=>W.value.length===1?W.value[0]:void 0),{data:Ve,refresh:V}=([T,x]=ye(()=>he(`/api/projects/${f}/markers`,{default:()=>({markers:[]})},"$3gm0grYTFL")),T=await T,x(),T),j=B(()=>Ve.value?.markers??[]),ee=B(()=>!z.public.authEnabled||_.value||y.value),Ge=B(()=>W.value.length===0?j.value:j.value.filter(r=>r.environment==null||W.value.includes(r.environment))),Be=w(null);function Pe(r){Be.value=r,L.value="timeline"}const dt=B(()=>{const r=u.value?.testRuns||[];return _e.value?r.filter(n=>n.isFullRun!==!1):r});function Je(r){if(r.isFullRun!==!1)return"Full run — the complete test suite ran";const n=[],F=r.filterDetails?.grep?.trim(),H=r.filterDetails?.grepInvert?.trim(),me=r.filterDetails?.files;return F&&F!==".*"&&n.push(`grep: ${F}`),H&&n.push(`grep-invert: ${H}`),me?.length&&n.push(`files: ${me.join(", ")}`),n.length?`Partial run — ${n.join(" · ")}`:"Partial run — only a filtered subset of tests ran (grep, file, or line filter)"}const je=[{accessorKey:"select",header:""},{accessorKey:"id",header:I("Run")},{accessorKey:"status",header:I("Status")},{accessorKey:"isFullRun",header:"Scope"},{id:"browsers",accessorFn:r=>r.browsers,header:""},{accessorKey:"startTime",header:I("Started")},{accessorKey:"environment",header:I("Environment")},{accessorKey:"metadata",header:"Branch / Commit"},{accessorKey:"duration",header:I("Test status / Dur.")},{accessorKey:"reports",header:"Reports"},{id:"actions",header:"Actions"}],Ne=w(null),N=w(""),X=w(""),mt=B(()=>{const r={};return N.value&&(r.from=N.value),X.value&&(r.to=X.value),r}),pt=w(null),gt=w(!1),we=w(null),ft=w(!1),Qe=w(!1),Zt=B(()=>gt.value&&pt.value===null);ge([L,mt,_e],async([r,n])=>{if(r!=="performance")return;gt.value=!0,we.value||(Qe.value=!0);const F=new URLSearchParams(n).toString(),H=_e.value?`${F?"&":""}fullRunsOnly=true`:"",me=F||H?`?${F}${H}`:"";pt.value=await $fetch(`/api/projects/${f}/performance${me}`).catch(pe=>(console.warn("[PerformanceTab] Failed to fetch performance trend:",pe),null)),gt.value=!1,Qe.value&&(ft.value=!1,we.value=await $fetch(`/api/projects/${f}/slow-tests`).catch(pe=>(ft.value=!0,console.warn("[PerformanceTab] Failed to fetch slow tests:",pe),null)),Qe.value=!1)},{immediate:!0});const es=[{accessorKey:"title",header:I("Test case")},{accessorKey:"avgDuration",header:I("Avg duration")},{accessorKey:"maxDuration",header:I("Max")},{accessorKey:"minDuration",header:I("Min")},{accessorKey:"latestDuration",header:I("Latest")},{accessorKey:"trend",header:I("Trend")},{accessorKey:"runCount",header:I("Runs")}];function ts(r){const n=ot(r.startTime,{dateOnly:!0}),F=r.metadata?.scm?.commit?` (${r.metadata.scm.commit.substring(0,7)})`:"";return`Run #${r.id} — ${n}${F}`}const le=B(()=>u.value?.testRuns?[...u.value.testRuns].reverse().map(r=>({label:ts(r),value:r.id})):[]),te=w(void 0),se=w(void 0),Rt=B(()=>D.query.runA?Number(D.query.runA):null),At=B(()=>D.query.runB?Number(D.query.runB):null);ge(le,r=>{if(Rt.value){const n=r.find(F=>F.value===Rt.value);n&&(te.value=n)}if(At.value){const n=r.find(F=>F.value===At.value);n&&(se.value=n)}},{immediate:!0}),ge(Me,r=>{if(r){const n=le.value.find(H=>H.value===r[0]),F=le.value.find(H=>H.value===r[1]);n&&(te.value=n),F&&(se.value=F),Me.value=null}});function Ut(){le.value.length>=2&&(te.value=le.value[1],se.value=le.value[0])}const vt=w(null),_t=w(null),Ye=w(!1);async function ss(){const r=te.value,n=se.value;if(!(!r?.value&&!n?.value)){Ye.value=!0;try{const F=[];r?.value&&F.push(r.value),n?.value&&F.push(n.value);const H=await Promise.all(F.map(pe=>$fetch(`/api/test-runs/${pe}/summary`))),me=new Map;for(const pe of H)me.set(pe.id,pe);vt.value=r?.value?me.get(r.value)??null:null,_t.value=n?.value?me.get(n.value)??null:null}catch{vt.value=null,_t.value=null}finally{Ye.value=!1}}}ge([te,se],()=>{ss()});const{comparisonData:We,comparisonSummary:J}=on(vt,_t),zt=[{accessorKey:"title",header:I("Test case")},{accessorKey:"statusA",header:I("Status A")},{accessorKey:"statusB",header:I("Status B")},{accessorKey:"durationA",header:I("Duration A")},{accessorKey:"durationB",header:I("Duration B")},{accessorKey:"delta",header:I("Delta")},{accessorKey:"percentChange",header:I("Change")}];return(r,n)=>{const F=js,H=ws,me=Mn,pe=Bs,ns=Ns,as=qt,os=Ue,ls=Ln,Mt=Ls,rs=Os,De=qe,ae=Te,is=qs,yt=Le,cs=Hs,us=Xs,ds=Gs,ms=Js,Ze=ze,ps=Es,gs=Se,Ke=He,fs=Zn,vs=ma,_s=Da,ht=Lt,Ft=wt,ys=Ba,hs=jt,bs=Qa,et=Ws,ne=Ae,xs=Zs,ks=ao,$s=en,Cs=So,Ts=an,Ss=Ps,It=Dt,Et=Tt;return s(),i(Q,null,[l(Ss,{id:"project-detail"},{header:t(()=>[l(ns,null,{leading:t(()=>[l(F),l(H,{items:[{label:"Home",icon:"i-lucide-house",to:"/"},{label:"Projects",to:"/projects"},{label:e(u)?.label||e(u)?.name||"Project"}]},null,8,["items"])]),right:t(()=>[l(pe,{size:"sm",actions:[...e(h)?[{label:"Delete",icon:"i-lucide-trash-2",color:"error",variant:"ghost",onClick:()=>{M.value="",v.value=!0}}]:[],{label:"Edit",icon:"i-lucide-pencil",variant:"outline",to:`/projects/${e(f)}/edit`},{label:"Refresh",icon:"i-lucide-refresh-cw",variant:"outline",onClick:()=>e(E)()}]},{leading:t(()=>[l(me,{"project-id":parseInt(e(f)),"project-label":e(u)?.label||e(u)?.name},null,8,["project-id","project-label"])]),_:1},8,["actions"])]),_:1})]),body:t(()=>[a("div",jo,[e(u)?.description||e(u)?.tags&&e(u).tags.length>0?(s(),i("div",wo,[e(u)?.description?(s(),i("p",Do,c(e(u).description),1)):S("",!0),e(u)?.tags&&e(u).tags.length>0?(s(),i("div",Ro,[(s(!0),i(Q,null,ie(e(u).tags,o=>(s(),k(as,{key:o.id,text:o.text,color:o.color},null,8,["text","color"]))),128))])):S("",!0)])):S("",!0),l(os,{modelValue:e(L),"onUpdate:modelValue":n[0]||(n[0]=o=>G(L)?L.value=o:null),items:e(ce),icon:e(ve),size:"md",class:"w-full mx-1 mb-1 sm:hidden"},null,8,["modelValue","items","icon"]),l(Ts,{modelValue:e(L),"onUpdate:modelValue":n[14]||(n[14]=o=>G(L)?L.value=o:null),items:e(ce),size:"sm",class:"p-1",ui:{list:"max-sm:hidden overflow-x-auto",trigger:"shrink-0"}},{"test-runs":t(()=>[e(u)?.testRuns&&e(u).testRuns.length>0?(s(),k(Mt,{key:0,title:"Run trend",subtitle:`Test run statistics over time for ${e(u)?.label||e(u)?.name}`,help:"project.runs-trend"},{default:t(()=>[l(ls,{"test-runs":e(dt),height:200,markers:e(Ge),onMarkerClick:Pe},null,8,["test-runs","markers"])]),_:1},8,["subtitle"])):S("",!0),l(Ke,{class:"mt-4"},{default:t(()=>[a("div",Ao,[a("div",Uo,[l(rs,{modelValue:e(_e),"onUpdate:modelValue":n[1]||(n[1]=o=>G(_e)?_e.value=o:null),label:"Full runs only",ui:{label:"text-sm"}},null,8,["modelValue"]),l(De,{topic:"project.run-scope"})]),e(Fe).length>0?(s(),i(Q,{key:0},[n[21]||(n[21]=a("span",{class:"text-sm text-muted shrink-0"},"Environment:",-1)),(s(!0),i(Q,null,ie(e(Fe),o=>(s(),i("button",{key:o,type:"button",class:re(["text-xs font-medium px-2 py-1 rounded border cursor-pointer focus:outline-none transition-colors",Ie(o)?"bg-blue-600 text-white border-blue-600":"bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200 border-blue-300 dark:border-blue-700 hover:bg-blue-200 dark:hover:bg-blue-800"]),onClick:$e=>ct(o)},c(o),11,zo))),128)),e(W).length>0?(s(),k(ae,{key:0,size:"xs",variant:"ghost",color:"neutral",icon:"i-lucide-x",label:"Clear filter",onClick:n[2]||(n[2]=o=>W.value=[])})):S("",!0)],64)):S("",!0)]),e(Y).length>0?(s(),i("div",Mo,[a("span",Fo,c(e(Y).length)+" run"+c(e(Y).length>1?"s":"")+" selected ",1),e(Y).length===2?(s(),k(ae,{key:0,icon:"i-lucide-git-compare-arrows",size:"sm",color:"primary",label:"Compare selected runs",onClick:Xe})):(s(),i("span",Io," Select another run to compare ")),l(ae,{size:"xs",variant:"ghost",color:"neutral",icon:"i-lucide-x",label:"Clear",onClick:n[3]||(n[3]=o=>Y.value=[])})])):S("",!0),e(Ee).length>0?(s(),k(Ze,{key:1,data:e(Ee),columns:je,ui:{base:"table-fixed border-separate border-spacing-0",thead:"[&>tr]:bg-elevated/50 [&>tr]:after:content-none",tbody:"[&>tr]:last:[&>td]:border-b-0",th:"first:rounded-l-lg last:rounded-r-lg border-y border-default first:border-l last:border-r",td:"border-b border-default"}},{"select-cell":t(({row:o})=>[a("input",{type:"checkbox",checked:rt(o.original.id),class:"cursor-pointer size-4 accent-primary",onClick:Pt($e=>it(o.original.id),["stop"])},null,8,Eo)]),"id-cell":t(({row:o})=>[a("div",Vo,[a("a",{href:`/test-runs/${o.original.id}`,class:"text-primary hover:underline font-medium",onClick:Pt($e=>("navigateTo"in r?r.navigateTo:e(Ct))(`/test-runs/${o.original.id}`),["prevent"])}," Run #"+c(o.original.id),9,Bo),o.original.label?(s(),i("span",Po,c(o.original.label),1)):S("",!0)])]),"status-cell":t(({row:o})=>[l(is,{status:o.original.status},null,8,["status"])]),"isFullRun-header":t(()=>[a("span",No,[n[22]||(n[22]=d("Scope ",-1)),l(De,{topic:"run.partial"})])]),"isFullRun-cell":t(({row:o})=>[l(cs,{text:Je(o.original)},{default:t(()=>[l(yt,{name:o.original.isFullRun===!1?"i-lucide-list-filter":"i-lucide-list-checks",class:re(["size-4 shrink-0 cursor-help",o.original.isFullRun===!1?"text-amber-500":"text-green-500"])},null,8,["name","class"])]),_:2},1032,["text"])]),"browsers-cell":t(({row:o})=>[o.original.browsers?.length?(s(),i("div",Ko,[(s(!0),i(Q,null,ie(o.original.browsers,$e=>(s(),k(us,{key:$e,browser:{projectName:$e},size:"sm"},null,8,["browser"]))),128))])):S("",!0)]),"startTime-cell":t(({row:o})=>[a("span",Lo,c(("prettyDateFormat"in r?r.prettyDateFormat:e(ot))(o.original.startTime)),1)]),"environment-cell":t(({row:o})=>[o.original.environment?(s(),i("span",Oo,c(o.original.environment),1)):S("",!0)]),"metadata-cell":t(({row:o})=>[o.original.metadata?.scm?(s(),i("div",qo,[o.original.metadata.scm.branch?(s(),i("span",Ho,c(o.original.metadata.scm.branch),1)):S("",!0),o.original.metadata.scm.commit?(s(),i("code",Xo,c(o.original.metadata.scm.commit.substring(0,7)),1)):S("",!0)])):S("",!0)]),"duration-cell":t(({row:o})=>[a("div",Go,[l(ds,{passed:o.original.passedTests,failed:o.original.failedTests,skipped:o.original.skippedTests,flaky:o.original.flakyTests,"did-not-run":o.original.didNotRunTests??0,total:o.original.totalTests},null,8,["passed","failed","skipped","flaky","did-not-run","total"]),a("span",Jo,c(("formatDuration"in r?r.formatDuration:e(Ce))(o.original.duration)),1)])]),"reports-cell":t(({row:o})=>[l(ms,{reports:o.original.reports},null,8,["reports"])]),"actions-header":t(()=>[...n[23]||(n[23]=[a("div",{class:"text-right"},"Actions",-1)])]),"actions-cell":t(({row:o})=>[a("div",Qo,[l(ae,{to:`/test-runs/${o.original.id}`,size:"sm",variant:"outline"},{default:t(()=>[...n[24]||(n[24]=[d(" View ",-1)])]),_:1},8,["to"]),l(ae,{size:"sm",color:"error",variant:"soft",icon:"i-lucide-trash-2",loading:e(R)===o.original.id,onClick:$e=>C.value=o.original.id},{default:t(()=>[...n[25]||(n[25]=[d(" Delete ",-1)])]),_:1},8,["loading","onClick"])])]),_:1},8,["data"])):e(u)?.testRuns&&e(u).testRuns.length>0?(s(),i("div",Yo," No test runs match the selected environment filter. ")):(s(),k(gs,{key:3,icon:"i-lucide-rocket",text:"No test runs yet for this project."},{default:t(()=>[a("p",Wo,[n[27]||(n[27]=d(" Point the reporter's ",-1)),n[28]||(n[28]=a("code",{class:"bg-gray-100 dark:bg-gray-800 px-1 rounded"},"projectName",-1)),n[29]||(n[29]=d(" at ",-1)),a("code",Zo,c(e(u)?.name),1),n[30]||(n[30]=d(" to send results here — see the ",-1)),l(ps,{to:"reporter","no-icon":"",class:"text-primary hover:underline"},{default:t(()=>[...n[26]||(n[26]=[d("reporter docs",-1)])]),_:1}),n[31]||(n[31]=d(" for setup instructions. ",-1))])]),_:1}))]),_:1})]),"failure-clusters":t(()=>[e(L)==="failure-clusters"?(s(),i(Q,{key:0},[(s(),k(fs,{key:`sug-${e(oe)}`,"project-id":String(e(f)),onMerged:n[4]||(n[4]=o=>oe.value++)},null,8,["project-id"])),(s(),k(vs,{key:e(oe),"project-id":String(e(f))},null,8,["project-id"]))],64)):S("",!0)]),"flaky-tests":t(()=>[e(L)==="flaky-tests"?(s(),k(_s,{key:0,"project-id":String(e(f)),environment:e(ut),"project-name":e(u)?.name},null,8,["project-id","environment","project-name"])):S("",!0)]),performance:t(()=>[a("div",el,[n[32]||(n[32]=a("span",{class:"text-sm text-muted shrink-0"},"Date range:",-1)),l(ht,{modelValue:e(N),"onUpdate:modelValue":n[5]||(n[5]=o=>G(N)?N.value=o:null),type:"date",size:"sm",placeholder:"From",class:"w-40"},null,8,["modelValue"]),n[33]||(n[33]=a("span",{class:"text-sm text-muted"},"to",-1)),l(ht,{modelValue:e(X),"onUpdate:modelValue":n[6]||(n[6]=o=>G(X)?X.value=o:null),type:"date",size:"sm",placeholder:"To",class:"w-40"},null,8,["modelValue"]),e(N)||e(X)?(s(),k(ae,{key:0,size:"xs",variant:"ghost",color:"neutral",icon:"i-lucide-x",label:"Clear",onClick:n[7]||(n[7]=o=>{N.value="",X.value=""})})):S("",!0)]),l(Mt,{title:"Performance trend",subtitle:"Duration metrics over time",help:"project.performance"},{default:t(()=>[e(Zt)?(s(),k(Ft,{key:0,text:"Loading chart…"})):(s(),k(ys,{key:1,data:e(pt)||[],height:350,markers:e(Ge),onMarkerClick:Pe},null,8,["data","markers"]))]),_:1}),l(Ke,null,{header:t(()=>[a("h2",tl,[n[34]||(n[34]=d(" Slowest tests ",-1)),l(De,{topic:"project.slowest-tests"})]),n[35]||(n[35]=a("p",{class:"text-sm text-gray-600 mt-1"},"Top 20 slowest test cases across recent runs",-1))]),default:t(()=>[e(Qe)&&e(we)===null?(s(),k(Ft,{key:0,text:"Loading…"})):e(we)&&e(we).length>0?(s(),k(Ze,{key:1,data:e(we),columns:es,ui:{base:"table-fixed border-separate border-spacing-0",thead:"[&>tr]:bg-elevated/50 [&>tr]:after:content-none",tbody:"[&>tr]:last:[&>td]:border-b-0",th:"first:rounded-l-lg last:rounded-r-lg border-y border-default first:border-l last:border-r",td:"border-b border-default"}},{"title-cell":t(({row:o})=>[a("div",null,[a("div",sl,c(o.original.title),1),a("div",nl,[l(hs,{"file-path":o.original.filePath,"project-key":e(f),"project-name":e(u)?.name,class:"text-xs"},null,8,["file-path","project-key","project-name"])])])]),"trend-cell":t(({row:o})=>[o.original.trend==="slower"?(s(),i("span",al,"▲ Slower")):o.original.trend==="faster"?(s(),i("span",ol,"▼ Faster")):(s(),i("span",ll,"— Stable"))]),_:1},8,["data"])):e(ft)?(s(),i("div",rl," Couldn't load the slowest tests — try refreshing. ")):(s(),i("div",il,"No slow test data available yet."))]),_:1}),l(bs,{"project-id":String(e(f)),"project-name":e(u)?.name},null,8,["project-id","project-name"]),l(Ke,null,{header:t(()=>[a("div",cl,[a("div",null,[a("h2",ul,[n[36]||(n[36]=d(" Run comparison ",-1)),l(De,{topic:"project.run-compare"})]),n[37]||(n[37]=a("p",{class:"text-sm text-gray-600 mt-1"},"Compare duration changes between two runs",-1))]),e(le).length>=2?(s(),k(ae,{key:0,icon:"i-lucide-git-compare-arrows",size:"sm",variant:"outline",label:"Compare latest vs previous",onClick:Ut})):S("",!0)])]),default:t(()=>[a("div",dl,[a("div",ml,[a("div",null,[n[38]||(n[38]=a("label",{class:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"},"Run A (baseline)",-1)),l(et,{modelValue:e(te),"onUpdate:modelValue":n[8]||(n[8]=o=>G(te)?te.value=o:null),items:e(le),placeholder:"Select run A..."},null,8,["modelValue","items"])]),a("div",null,[n[39]||(n[39]=a("label",{class:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"},"Run B (comparison)",-1)),l(et,{modelValue:e(se),"onUpdate:modelValue":n[9]||(n[9]=o=>G(se)?se.value=o:null),items:e(le),placeholder:"Select run B..."},null,8,["modelValue","items"])])]),e(Ye)?(s(),i("div",pl,[l(yt,{name:"i-lucide-loader-2",class:"animate-spin mr-2"}),n[40]||(n[40]=d(" Loading run data… ",-1))])):e(te)&&e(se)&&e(We).length>0?(s(),i("div",gl,[a("div",fl,[l(ne,{color:"success",variant:"soft",size:"lg"},{default:t(()=>[d(c(e(J).improved)+" improved",1)]),_:1}),l(ne,{color:"error",variant:"soft",size:"lg"},{default:t(()=>[d(c(e(J).regressed)+" regressed",1)]),_:1}),l(ne,{color:"neutral",variant:"soft",size:"lg"},{default:t(()=>[d(c(e(J).unchanged)+" unchanged",1)]),_:1})]),l(Ze,{data:e(We),columns:zt,ui:{base:"table-fixed border-separate border-spacing-0",thead:"[&>tr]:bg-elevated/50 [&>tr]:after:content-none",tbody:"[&>tr]:last:[&>td]:border-b-0",th:"first:rounded-l-lg last:rounded-r-lg border-y border-default first:border-l last:border-r",td:"border-b border-default"}},{"statusA-cell":t(({row:o})=>[o.original.statusA?(s(),k(ne,{key:1,color:("getStatusColor"in r?r.getStatusColor:e(tt))(o.original.statusA),class:"capitalize"},{default:t(()=>[d(c(o.original.statusA),1)]),_:2},1032,["color"])):(s(),i("span",vl,"—"))]),"statusB-cell":t(({row:o})=>[o.original.statusB?(s(),k(ne,{key:1,color:("getStatusColor"in r?r.getStatusColor:e(tt))(o.original.statusB),class:"capitalize"},{default:t(()=>[d(c(o.original.statusB),1)]),_:2},1032,["color"])):(s(),i("span",_l,"—"))]),"durationA-cell":t(({row:o})=>[o.original.durationA!==null?(s(),i("span",yl,c(("formatDuration"in r?r.formatDuration:e(Ce))(o.original.durationA)),1)):(s(),i("span",hl,"—"))]),"durationB-cell":t(({row:o})=>[o.original.durationB!==null?(s(),i("span",bl,c(("formatDuration"in r?r.formatDuration:e(Ce))(o.original.durationB)),1)):(s(),i("span",xl,"—"))]),"delta-cell":t(({row:o})=>[o.original.delta===null?(s(),i("span",kl,"—")):(s(),i("span",{key:1,class:re(o.original.delta>0?"text-red-600":o.original.delta<0?"text-green-600":"text-gray-500")},c(o.original.delta>0?"+":"")+c(("formatDuration"in r?r.formatDuration:e(Ce))(o.original.delta)),3))]),"percentChange-cell":t(({row:o})=>[o.original.percentChange===null?(s(),i("span",$l,"—")):(s(),i("span",{key:1,class:re(o.original.percentChange>10?"text-red-600 font-medium":o.original.percentChange<-10?"text-green-600 font-medium":"text-gray-500")},c(o.original.percentChange>0?"+":"")+c(o.original.percentChange)+"% ",3))]),_:1},8,["data"])])):!e(te)||!e(se)?(s(),i("div",Cl," Select two runs to compare their performance. ")):(s(),i("div",Tl," No overlapping test cases found between the selected runs. "))])]),_:1})]),"test-cases":t(()=>[l(xs,{"project-id":e(f),"project-name":e(u)?.name,"sync-query":"",onTotal:n[10]||(n[10]=o=>Ne.value=o)},null,8,["project-id","project-name"])]),compare:t(()=>[l(Ke,null,{header:t(()=>[a("div",Sl,[a("p",jl,[n[41]||(n[41]=d(" Compare two test runs side-by-side — status changes and duration deltas ",-1)),l(De,{topic:"project.compare"})]),e(le).length>=2?(s(),k(ae,{key:0,icon:"i-lucide-git-compare-arrows",size:"sm",variant:"outline",label:"Latest vs previous",onClick:Ut})):S("",!0)])]),default:t(()=>[a("div",wl,[a("div",Dl,[a("div",null,[n[42]||(n[42]=a("label",{class:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"},"Run A (baseline)",-1)),l(et,{modelValue:e(te),"onUpdate:modelValue":n[11]||(n[11]=o=>G(te)?te.value=o:null),items:e(le),placeholder:"Select run A..."},null,8,["modelValue","items"])]),a("div",null,[n[43]||(n[43]=a("label",{class:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"},"Run B (comparison)",-1)),l(et,{modelValue:e(se),"onUpdate:modelValue":n[12]||(n[12]=o=>G(se)?se.value=o:null),items:e(le),placeholder:"Select run B..."},null,8,["modelValue","items"])])]),e(Ye)?(s(),i("div",Rl,[l(yt,{name:"i-lucide-loader-2",class:"animate-spin mr-2"}),n[44]||(n[44]=d(" Loading run data… ",-1))])):e(te)&&e(se)&&e(We).length>0?(s(),i("div",Al,[a("div",Ul,[a("div",zl,[n[45]||(n[45]=a("span",{class:"text-xs font-semibold text-gray-500 uppercase tracking-wider mr-1"},"Status changes",-1)),e(J).newFailures>0?(s(),k(ne,{key:0,color:"error",variant:"soft",size:"lg"},{default:t(()=>[d(c(e(J).newFailures)+" new failure"+c(e(J).newFailures>1?"s":""),1)]),_:1})):S("",!0),e(J).recovered>0?(s(),k(ne,{key:1,color:"success",variant:"soft",size:"lg"},{default:t(()=>[d(c(e(J).recovered)+" recovered ",1)]),_:1})):S("",!0),e(J).stillFailing>0?(s(),k(ne,{key:2,color:"warning",variant:"soft",size:"lg"},{default:t(()=>[d(c(e(J).stillFailing)+" still failing ",1)]),_:1})):S("",!0),e(J).newFailures===0&&e(J).recovered===0&&e(J).stillFailing===0?(s(),i("span",Ml,"No status changes")):S("",!0)]),a("div",Fl,[n[46]||(n[46]=a("span",{class:"text-xs font-semibold text-gray-500 uppercase tracking-wider mr-1"},"Duration changes",-1)),e(J).regressed>0?(s(),k(ne,{key:0,color:"error",variant:"soft",size:"lg"},{default:t(()=>[d(c(e(J).regressed)+" regressed ",1)]),_:1})):S("",!0),e(J).improved>0?(s(),k(ne,{key:1,color:"success",variant:"soft",size:"lg"},{default:t(()=>[d(c(e(J).improved)+" improved ",1)]),_:1})):S("",!0),l(ne,{color:"neutral",variant:"soft",size:"lg"},{default:t(()=>[d(c(e(J).unchanged)+" unchanged ",1)]),_:1})])]),l(Ze,{data:e(We),columns:zt,ui:{base:"table-fixed border-separate border-spacing-0",thead:"[&>tr]:bg-elevated/50 [&>tr]:after:content-none",tbody:"[&>tr]:last:[&>td]:border-b-0",th:"first:rounded-l-lg last:rounded-r-lg border-y border-default first:border-l last:border-r",td:"border-b border-default"}},{"statusA-cell":t(({row:o})=>[o.original.statusA?(s(),k(ne,{key:1,color:("getStatusColor"in r?r.getStatusColor:e(tt))(o.original.statusA),class:"capitalize"},{default:t(()=>[d(c(o.original.statusA),1)]),_:2},1032,["color"])):(s(),i("span",Il,"—"))]),"statusB-cell":t(({row:o})=>[o.original.statusB?(s(),k(ne,{key:1,color:("getStatusColor"in r?r.getStatusColor:e(tt))(o.original.statusB),class:"capitalize"},{default:t(()=>[d(c(o.original.statusB),1)]),_:2},1032,["color"])):(s(),i("span",El,"—"))]),"durationA-cell":t(({row:o})=>[o.original.durationA!==null?(s(),i("span",Vl,c(("formatDuration"in r?r.formatDuration:e(Ce))(o.original.durationA)),1)):(s(),i("span",Bl,"—"))]),"durationB-cell":t(({row:o})=>[o.original.durationB!==null?(s(),i("span",Pl,c(("formatDuration"in r?r.formatDuration:e(Ce))(o.original.durationB)),1)):(s(),i("span",Nl,"—"))]),"delta-cell":t(({row:o})=>[o.original.delta===null?(s(),i("span",Kl,"—")):(s(),i("span",{key:1,class:re(o.original.delta>0?"text-red-600":o.original.delta<0?"text-green-600":"text-gray-500")},c(o.original.delta>0?"+":"")+c(("formatDuration"in r?r.formatDuration:e(Ce))(o.original.delta)),3))]),"percentChange-cell":t(({row:o})=>[o.original.percentChange===null?(s(),i("span",Ll,"—")):(s(),i("span",{key:1,class:re(o.original.percentChange>10?"text-red-600 font-medium":o.original.percentChange<-10?"text-green-600 font-medium":"text-gray-500")},c(o.original.percentChange>0?"+":"")+c(o.original.percentChange)+"% ",3))]),_:1},8,["data"])])):!e(te)||!e(se)?(s(),i("div",Ol," Select two runs to compare test results. ")):(s(),i("div",ql," No overlapping test cases found between the selected runs. "))])]),_:1})]),"spec-health":t(()=>[l(ks,{"project-id":String(e(f))},null,8,["project-id"])]),members:t(()=>[l(Ke,null,{header:t(()=>[a("div",Hl,[a("p",Xl,[n[47]||(n[47]=d(" Users with access to this project ",-1)),l(De,{topic:"project.members"})]),l(ae,{label:"Save changes",icon:"i-lucide-check",size:"sm",disabled:!e(be),onClick:p},null,8,["disabled"])])]),default:t(()=>[e(P).length>0?(s(),i("div",Gl,[(s(!0),i(Q,null,ie(e(P),o=>(s(),i("div",{key:o.id,class:"flex items-center justify-between rounded-lg border border-default px-4 py-3"},[a("div",null,[a("div",Jl,c(o.name||o.username),1),a("div",Ql,[a("span",null,"@"+c(o.username),1),l(ne,{color:o.role==="administrator"?"primary":o.role==="reporter"?"info":"neutral",variant:"subtle",size:"xs"},{default:t(()=>[d(c(o.role),1)]),_:2},1032,["color"]),o.global?(s(),i("span",Yl,"Global access")):S("",!0)])]),o.role!=="administrator"?(s(),k($s,{key:0,"model-value":e(O).includes(o.id),disabled:o.global,title:o.global?"Has global access — remove global assignment first":"",onChange:$e=>xe(o.id)},null,8,["model-value","disabled","title","onChange"])):(s(),i("span",Wl,"Admin"))]))),128))])):(s(),i("div",Zl,"Loading members…"))]),_:1})]),timeline:t(()=>[l(Cs,{"project-id":Number(e(f)),markers:e(j),environments:e(Fe),"can-edit":e(ee),"focus-marker-id":e(Be),onChanged:e(V),onClearFocus:n[13]||(n[13]=o=>Be.value=null)},null,8,["project-id","markers","environments","can-edit","focus-marker-id","onChanged"])]),_:1},8,["modelValue","items"])])]),_:1}),l(Et,null,{default:t(()=>[l(It,{open:e(v),title:"Delete project","onUpdate:open":n[17]||(n[17]=o=>{o||(v.value=!1)})},{body:t(()=>[a("div",er,[a("p",tr,[n[48]||(n[48]=d(" This will permanently delete ",-1)),a("strong",null,c(e(u)?.label||e(u)?.name),1),n[49]||(n[49]=d(" and all its test runs, reports, traces, and failure clusters. This action cannot be undone. ",-1))]),a("div",null,[a("label",sr,[n[50]||(n[50]=d(" Type the project key ",-1)),a("code",nr,c(e(u)?.name),1),n[51]||(n[51]=d(" to confirm: ",-1))]),l(ht,{modelValue:e(M),"onUpdate:modelValue":n[15]||(n[15]=o=>G(M)?M.value=o:null),placeholder:e(u)?.name,autofocus:"",onKeydown:Ms(g,["enter"])},null,8,["modelValue","placeholder"])])])]),footer:t(()=>[l(ae,{color:"neutral",variant:"ghost",label:"Cancel",onClick:n[16]||(n[16]=o=>v.value=!1)}),l(ae,{color:"error",label:"Delete project",icon:"i-lucide-trash-2",disabled:!e($),loading:e(K),onClick:g},null,8,["disabled","loading"])]),_:1},8,["open"])]),_:1}),l(Et,null,{default:t(()=>[l(It,{open:e(C)!==null,title:"Delete test run","onUpdate:open":n[20]||(n[20]=o=>{o||(C.value=null)})},{body:t(()=>[a("p",null,[n[52]||(n[52]=d(" Are you sure you want to delete ",-1)),a("strong",null,"Run #"+c(e(C)),1),n[53]||(n[53]=d("? This will also remove all associated test results, reports, and traces. This action cannot be undone. ",-1))])]),footer:t(()=>[l(ae,{color:"neutral",variant:"ghost",label:"Cancel",onClick:n[18]||(n[18]=o=>C.value=null)}),l(ae,{color:"error",label:"Delete",icon:"i-lucide-trash-2",loading:e(R)===e(C),onClick:n[19]||(n[19]=o=>m(e(C)))},null,8,["loading"])]),_:1},8,["open"])]),_:1})],64)}}});export{li as default};
|
|
1
|
+
import{_ as js}from"./BAaSmp8J.js";import{_ as ws}from"./Ccit_CX1.js";import{b as Re,K as $t,d as ue,L as Nt,w as ye,B as ge,k as e,o as s,f as k,g as t,j as l,_ as Te,c as i,i as a,m as d,t as c,q as S,F as Q,y as ie,v as Le,x as Oe,l as G,M as Vt,N as Bt,p as re,h as B,r as w,E as Ds,O as Kt,n as Ct,s as Ae,P as Tt,D as Lt,I as Rs,u as As,a as Us,e as zs,H as Pt,Q as Ms,R as Fs}from"./D3SYPlEB.js";import{_ as Is}from"./DB3ljns7.js";import{_ as qe,a as Es}from"./C8cz5feG.js";import{_ as Ue}from"./CCsl9MOZ.js";import{_ as Ot}from"./Db_-yjYg.js";import{u as Vs}from"./BsDB_eCd.js";import{u as he}from"./Doul3p1_.js";import{_ as Bs}from"./CUDeMcEK.js";import{_ as Ps,a as Ns}from"./87SGk1nu.js";import{_ as qt}from"./ClVRQpP_.js";import{_ as Ht}from"./CRcjGmf7.js";import{_ as Se}from"./KYucVFu7.js";import{C as kt,w as Xt,O as at,a as Gt,_ as Jt,u as Qt}from"./BEB2Mv6B.js";import{N as Ks}from"./DIA_NAIv.js";import{_ as Ls}from"./BReNbog6.js";import{_ as Os}from"./n-QWmQgc.js";import{_ as qs}from"./HTQtMbWb.js";import{_ as Hs}from"./CCw3Tx4S.js";import{_ as Xs}from"./CU3W9YrI.js";import{_ as Gs}from"./C9EpbPNU.js";import{_ as Js}from"./CLdGRzLL.js";import{_ as ze}from"./DOr_4nln.js";import{_ as He}from"./DoFSKAvY.js";import{_ as Yt}from"./empGC_x-.js";import{_ as lt}from"./C7ZVzS0K.js";import{f as St,a as Qs,c as Ys,g as I,e as Wt,p as ot,h as Ce,i as tt}from"./BUMZHDRC.js";import{_ as jt}from"./Tt5LX5Y-.js";import{_ as wt}from"./Bi3i470l.js";import{_ as Ws}from"./DaewB_zT.js";import{_ as Zs}from"./EltzgiyS.js";import{_ as en}from"./D4SFgXAf.js";import{_ as tn}from"./DRE6Aqqp.js";import{_ as sn}from"./DnThe2U0.js";import{_ as Dt}from"./l0QnzFNM.js";import{M as nn,D as bt,g as xt}from"./D7W_4Sqc.js";import{_ as an}from"./Dwp3GkV-.js";import{u as on}from"./quV6tp4n.js";import{u as ln}from"./DoYgYLOd.js";import"./B6rt3IcG.js";import"./r3SBLxtE.js";import"./D3MWm6JP.js";import"./Cx65B3c3.js";import"./BAkJhSAW.js";import"./wgcgHmRR.js";import"./rm7OkgDG.js";import"./Vnfkr1pJ.js";import"./wQZj69OY.js";import"./Dbg8z684.js";import"./D8YZvjas.js";import"./DM_YaJgJ.js";import"./B6IHiVa1.js";import"./BTYiG93l.js";import"./va1mwSm9.js";import"./Do6zIWQf.js";const rn=["run.finished","run.failed","run.failed.default_branch","cluster.new","flakiness.spike","perf.regression","diagnosis.completed"],st=new Map,nt=new Map;function cn(A,T){const x=[{event:"run.failed",scenario:{title:`Test run failed — ${A}`,description:"3 of 12 tests failed on main — checkout › applies discount code +2 more",icon:"i-lucide-circle-x",color:"error"}},{event:"run.failed.default_branch",scenario:{title:`Test run failed on main — ${A}`,description:"2 of 12 tests failed · main — auth › logs in with valid credentials +1 more",icon:"i-lucide-circle-x",color:"error"}},{event:"cluster.new",scenario:{title:`New failure cluster — ${A}`,description:"TimeoutError: locator.click: Timeout 30000ms exceeded",icon:"i-lucide-layers",color:"warning"}},{event:"flakiness.spike",scenario:{title:`Flakiness spike — ${A}`,description:"3 tests became flaky (8.3% rate)",icon:"i-lucide-shuffle",color:"warning"}},{event:"perf.regression",scenario:{title:`Performance regression — ${A}`,description:"p90 duration increased by 42% vs last week",icon:"i-lucide-trending-down",color:"warning"}},{event:"run.finished",scenario:{title:`Test run recovered — ${A}`,description:"All 12 tests passed on main",icon:"i-lucide-circle-check",color:"success"}},{event:"diagnosis.completed",scenario:{title:`Diagnosis complete — ${A}`,description:"Root cause: test bug — confidence: high",icon:"i-lucide-sparkles",color:"info"}}],D=x.filter(b=>T.length===0||T.includes(b.event)).map(b=>b.scenario);return D.length===0?[x[0].scenario,x[x.length-1].scenario]:D}function un(){if(!$t().public.demoMode)return null;const T=Re();function x(b,f,u){D(b);const E=cn(f,u);nt.set(b,0);function U(){const R=(nt.get(b)??0)%E.length;nt.set(b,R+1);const C=E[R];T.add({title:C.title,description:C.description,icon:C.icon,color:C.color,duration:7e3});const _=25e3+Math.random()*1e4;st.set(b,setTimeout(U,_))}st.set(b,setTimeout(U,8e3))}function D(b){const f=st.get(b);f!==void 0&&(clearTimeout(f),st.delete(b)),nt.delete(b)}return{scheduleFor:x,cancelFor:D}}const dn={key:0,class:"p-3 space-y-3"},mn={key:0,class:"text-xs text-gray-500"},pn={key:1,class:"text-xs text-gray-500"},gn={key:2,class:"text-xs text-gray-500"},fn={class:"space-y-1"},vn=["checked","onChange"],_n={key:1,class:"p-3 space-y-3"},yn={class:"flex items-center justify-between"},hn={class:"font-medium text-sm inline-flex items-center gap-1"},bn={key:0,class:"text-xs text-muted bg-primary/5 rounded px-2 py-1.5"},xn={key:1,class:"text-xs text-muted text-center py-2"},kn={key:2,class:"space-y-1.5"},$n={key:0,class:"space-y-2 rounded border border-primary/30 bg-primary/5 px-2 py-2"},Cn={class:"space-y-1"},Tn=["value"],Sn={class:"flex gap-1.5 justify-end"},jn={class:"flex-1 font-medium truncate"},wn={key:3,class:"text-xs text-muted text-center py-1"},Dn={key:4,class:"space-y-2 border-t border-default pt-2"},Rn={class:"space-y-1"},An=["value"],Un={class:"flex gap-1.5 justify-end"},zn=ue({__name:"SubscribeBell",props:{projectId:{},projectLabel:{}},async setup(A){let T,x;const D=A,b=$t(),f=b.public.demoMode,u=B(()=>b.public.authEnabled),{authState:E}=Nt(),U=B(()=>E.value.authenticated),R=Re(),C=w(!1),_=f?un():null,y=!u.value&&!f?Vs():null,z=w("default"),h=B(()=>"Notification"in window);"Notification"in window&&(z.value=Notification.permission);const v=B(()=>y?.getProject(D.projectId).events??[]),M=B(()=>y?.isSubscribed(D.projectId)??!1);async function K(){!h.value||z.value!=="default"||(z.value=await Notification.requestPermission())}function $(V){return v.value.includes(V)}function g(V){y?.toggleEvent(D.projectId,V)}const m=f||u.value&&U.value,q=f?{server:!1}:{},{data:Z,refresh:O}=([T,x]=ye(()=>he(`/api/subscriptions?projectId=${D.projectId}`,{immediate:m,...q},"$5zp4moJ-7_")),T=await T,x(),T),P=B(()=>Z.value?.subscriptions??[]),be=B(()=>P.value.length>0),{data:xe}=([T,x]=ye(()=>he("/api/channels",{immediate:m,...q},"$vFApQ6eA2X")),T=await T,x(),T),p=B(()=>xe.value?.channels??[]),L=w(!1),oe=w(void 0),de=w(["run.failed"]),ke=w(!1),fe=w(null),ce=w(void 0),ve=w([]),Y=w(!1);function rt(V){fe.value=V,ce.value=V.channel.id,ve.value=[...V.events]}function it(){fe.value=null}async function Me(){if(!(!fe.value||!ce.value||ve.value.length===0)){Y.value=!0;try{await $fetch(`/api/subscriptions/${fe.value.id}`,{method:"PATCH",body:{channelId:ce.value,events:ve.value}}),await O(),fe.value=null}catch(V){R.add({title:"Update failed",description:String(V?.message??V),color:"error"})}finally{Y.value=!1}}}const Xe=B(()=>p.value.map(V=>({label:V.type==="personal_email"?`${V.name} (${V.config.address})`:V.name,value:V.id}))),W=rn.map(V=>({label:V.replace(/\./g," › "),value:V}));ge(C,V=>{V?(m&&O(),p.value.length>0&&!oe.value&&(oe.value=p.value[0].id)):(L.value=!1,fe.value=null)});async function _e(){if(!(!oe.value||de.value.length===0)){ke.value=!0;try{await $fetch("/api/subscriptions",{method:"POST",body:{channelId:oe.value,projectId:D.projectId,events:de.value,mode:"realtime"}}),await O(),L.value=!1,R.add({title:"Subscribed",color:"success"}),f&&_?.scheduleFor(D.projectId,D.projectLabel||"this project",de.value)}catch(V){R.add({title:"Subscribe failed",description:String(V?.message??V),color:"error"})}finally{ke.value=!1}}}async function Fe(V){try{await $fetch(`/api/subscriptions/${V}`,{method:"DELETE"}),await O(),R.add({title:"Unsubscribed",color:"success"}),f&&P.value.length===0&&_?.cancelFor(D.projectId)}catch(j){R.add({title:"Failed",description:String(j?.message??j),color:"error"})}}async function ct(V){const j=V.mutedUntil&&new Date(V.mutedUntil)>new Date;try{await $fetch(`/api/subscriptions/${V.id}`,{method:"PATCH",body:{mutedUntil:j?null:new Date(Date.now()+10080*60*1e3).toISOString()}}),await O()}catch(ee){R.add({title:"Failed",description:String(ee?.message??ee),color:"error"})}}function Ie(V){return V.mutedUntil&&new Date(V.mutedUntil)>new Date}function Ee(V){return V==="personal_email"?"i-lucide-user-round":V==="email"?"i-lucide-mail":V==="slack"?"i-lucide-slack":"i-lucide-webhook"}const ut=B(()=>f||u.value&&U.value||y!=null),Ve=B(()=>f||u.value?be.value:M.value);return(V,j)=>{const ee=Te,Ge=Is,Be=qe,Pe=Le,dt=Oe,Je=Ue,je=Ot,Ne=Ds;return e(ut)?(s(),k(Ne,{key:0,open:e(C),"onUpdate:open":j[6]||(j[6]=N=>G(C)?C.value=N:null),ui:{content:"w-72"}},{content:t(()=>[e(y)?(s(),i("div",dn,[j[9]||(j[9]=a("div",{class:"flex items-center justify-between"},[a("span",{class:"font-medium text-sm"},"Browser notifications")],-1)),e(h)&&e(z)==="default"?(s(),i("p",mn,[l(ee,{variant:"link",size:"xs",class:"p-0",onClick:K},{default:t(()=>[...j[7]||(j[7]=[d(" Allow notifications ",-1)])]),_:1}),j[8]||(j[8]=d(" "+c(" ")+"in your browser to get alerts for this project. ",-1))])):e(h)&&e(z)==="denied"?(s(),i("p",pn," Notifications are blocked. Check your browser settings to allow them. ")):e(h)?S("",!0):(s(),i("p",gn,"Notifications are not supported in this browser.")),e(h)&&e(z)==="granted"?(s(),i(Q,{key:3},[l(Ge),a("div",fn,[(s(!0),i(Q,null,ie(e(W),N=>(s(),i("label",{key:N.value,class:"flex items-center gap-1.5 text-xs cursor-pointer"},[a("input",{type:"checkbox",checked:$(N.value),class:"accent-primary size-3",onChange:X=>g(N.value)},null,40,vn),d(" "+c(N.label),1)]))),128))])],64)):S("",!0)])):(s(),i("div",_n,[a("div",yn,[a("span",hn,[j[10]||(j[10]=d(" Notifications ",-1)),l(Be,{topic:"notifications.subscribe"})]),e(L)?S("",!0):(s(),k(ee,{key:0,size:"xs",icon:"i-lucide-plus",variant:"ghost",color:"neutral",disabled:e(p).length===0,onClick:j[0]||(j[0]=N=>L.value=!0)},{default:t(()=>[...j[11]||(j[11]=[d(" Add ",-1)])]),_:1},8,["disabled"]))]),e(f)?(s(),i("div",bn,[l(Pe,{name:"i-lucide-sparkles",class:"size-3 inline-block mr-1 text-primary"}),j[12]||(j[12]=d(" Demo — notifications will appear as toasts in ~8 s. ",-1))])):e(p).length===0?(s(),i("div",xn,[j[14]||(j[14]=d(" No channels configured.",-1)),j[15]||(j[15]=a("br",null,null,-1)),l(dt,{to:"/settings/notifications",class:"text-primary underline"},{default:t(()=>[...j[13]||(j[13]=[d("Add one in Settings",-1)])]),_:1})])):S("",!0),e(P).length>0?(s(),i("div",kn,[(s(!0),i(Q,null,ie(e(P),N=>(s(),i(Q,{key:N.id},[e(fe)?.id===N.id?(s(),i("div",$n,[l(je,{label:"Channel",size:"xs"},{default:t(()=>[l(Je,{modelValue:e(ce),"onUpdate:modelValue":j[1]||(j[1]=X=>G(ce)?ce.value=X:null),items:e(Xe),"value-key":"value",class:"w-full text-xs",size:"xs"},null,8,["modelValue","items"])]),_:1}),l(je,{label:"Events",size:"xs"},{default:t(()=>[a("div",Cn,[(s(!0),i(Q,null,ie(e(W),X=>(s(),i("label",{key:X.value,class:"flex items-center gap-1.5 text-xs cursor-pointer"},[Vt(a("input",{type:"checkbox",value:X.value,"onUpdate:modelValue":j[2]||(j[2]=mt=>G(ve)?ve.value=mt:null),class:"accent-primary size-3"},null,8,Tn),[[Bt,e(ve)]]),d(" "+c(X.label),1)]))),128))])]),_:1}),a("div",Sn,[l(ee,{size:"xs",color:"neutral",variant:"ghost",onClick:it},{default:t(()=>[...j[16]||(j[16]=[d("Cancel",-1)])]),_:1}),l(ee,{size:"xs",color:"primary",loading:e(Y),disabled:!e(ce)||e(ve).length===0,onClick:Me},{default:t(()=>[...j[17]||(j[17]=[d(" Save ",-1)])]),_:1},8,["loading","disabled"])])])):(s(),i("div",{key:1,class:re(["flex items-center gap-2 rounded px-2 py-1.5 text-xs",Ie(N)?"opacity-60":""])},[l(Pe,{name:Ee(N.channel.type),class:"size-3.5 text-muted shrink-0"},null,8,["name"]),a("span",jn,c(N.channel.name),1),l(ee,{icon:"i-lucide-pencil",color:"neutral",variant:"ghost",size:"xs",title:"Edit subscription",onClick:X=>rt(N)},null,8,["onClick"]),l(ee,{icon:Ie(N)?"i-lucide-bell":"i-lucide-bell-off",color:"neutral",variant:"ghost",size:"xs",title:Ie(N)?"Unmute":"Mute 7 days",onClick:X=>ct(N)},null,8,["icon","title","onClick"]),l(ee,{icon:"i-lucide-x",color:"error",variant:"ghost",size:"xs",title:"Unsubscribe",onClick:X=>Fe(N.id)},null,8,["onClick"])],2))],64))),128))])):!e(L)&&e(p).length>0?(s(),i("div",wn," Not subscribed to this project. ")):S("",!0),e(L)?(s(),i("div",Dn,[l(je,{label:"Channel",size:"xs"},{default:t(()=>[l(Je,{modelValue:e(oe),"onUpdate:modelValue":j[3]||(j[3]=N=>G(oe)?oe.value=N:null),items:e(Xe),"value-key":"value",class:"w-full text-xs",size:"xs"},null,8,["modelValue","items"])]),_:1}),l(je,{label:"Events",size:"xs"},{default:t(()=>[a("div",Rn,[(s(!0),i(Q,null,ie(e(W),N=>(s(),i("label",{key:N.value,class:"flex items-center gap-1.5 text-xs cursor-pointer"},[Vt(a("input",{type:"checkbox",value:N.value,"onUpdate:modelValue":j[4]||(j[4]=X=>G(de)?de.value=X:null),class:"accent-primary size-3"},null,8,An),[[Bt,e(de)]]),d(" "+c(N.label),1)]))),128))])]),_:1}),a("div",Un,[l(ee,{size:"xs",color:"neutral",variant:"ghost",onClick:j[5]||(j[5]=N=>L.value=!1)},{default:t(()=>[...j[18]||(j[18]=[d("Cancel",-1)])]),_:1}),l(ee,{size:"xs",color:"primary",loading:e(ke),disabled:!e(oe)||e(de).length===0,onClick:_e},{default:t(()=>[...j[19]||(j[19]=[d(" Subscribe ",-1)])]),_:1},8,["loading","disabled"])])])):S("",!0)]))]),default:t(()=>[l(ee,{icon:e(Ve)?"i-lucide-bell-ring":"i-lucide-bell",size:"sm",color:e(Ve)?"primary":"neutral",variant:e(Ve)?"soft":"outline",title:"Notification subscriptions for this project"},null,8,["icon","color","variant"])]),_:1},8,["open"])):S("",!0)}}}),Mn=Object.assign(zn,{__name:"SubscribeBell"}),Fn={class:"w-full relative"},In={key:0},En={class:"p-2 text-sm text-gray-900 dark:text-gray-100"},Vn={class:"font-semibold mb-1"},Bn={class:"capitalize mb-1"},Pn={class:"space-y-0.5"},Nn={class:"font-medium mt-1"},Kn=ue({__name:"TestRunsChart",props:{testRuns:{},height:{default:300},markers:{default:()=>[]}},emits:["marker-click"],setup(A,{emit:T}){const x=A,D=T,b=B(()=>x.markers),f=B(()=>!x.testRuns||x.testRuns.length===0?[]:[...x.testRuns].sort((m,q)=>new Date(m.startTime).getTime()-new Date(q.startTime).getTime()).slice(-30).map(m=>({id:m.id,date:new Date(m.startTime),passed:m.passedTests||0,failed:m.failedTests||0,skipped:m.skippedTests||0,flaky:m.flakyTests||0,total:m.totalTests||0,status:m.status}))),u=g=>g.date,E=g=>g.passed,U=g=>g.failed,R=g=>g.skipped,C=g=>g.flaky,_=["rgb(34, 197, 94)","rgb(239, 68, 68)","rgb(245, 158, 11)","rgb(147, 51, 234)"],y=w(null),{tooltipData:z,tooltipPos:h,markerTooltip:v,markerTooltipPos:M,onRenderComplete:K}=Qt(y,f,{x:g=>g.date,series:[{y:g=>g.passed,color:_[0]},{y:g=>g.failed,color:_[1]},{y:g=>g.skipped,color:_[2]},{y:g=>g.flaky,color:_[3]}],onClick:g=>Ct(`/test-runs/${g.id}`),markers:b,onMarkerClick:g=>D("marker-click",g.id)}),$=[{color:_[0],label:"Passed"},{color:_[1],label:"Failed"},{color:_[2],label:"Skipped"},{color:_[3],label:"Flaky"}];return(g,m)=>{const q=Ht,Z=Se,O=Jt;return s(),i("div",Fn,[e(f).length>0?(s(),i("div",In,[l(e(Gt),{ref_key:"xyContainerRef",ref:y,data:e(f),height:A.height,padding:{top:10,right:10,bottom:0,left:0},"on-render-complete":e(K)},{default:t(()=>[l(e(Ks),{x:u,y:[E,U,R,C],color:_,"curve-type":e(kt).MonotoneX},null,8,["y","curve-type"]),l(e(Xt),{x:u,y:[E,U,R,C],color:_,"curve-type":e(kt).MonotoneX,"line-width":2},null,8,["y","curve-type"]),l(e(at),{type:"x","tick-format":P=>new Date(P).toLocaleDateString("en-US",{month:"short",day:"numeric"})},null,8,["tick-format"]),l(e(at),{type:"y",label:"Tests","tick-format":P=>P.toString()},null,8,["tick-format"])]),_:1},8,["data","height","on-render-complete"]),e(z)?(s(),i("div",{key:0,class:"fixed z-50 pointer-events-none bg-white dark:bg-gray-800 rounded-lg shadow-lg border border-gray-200 dark:border-gray-700 max-w-[260px]",style:Kt({left:`${e(h).x}px`,top:`${e(h).y}px`})},[a("div",En,[a("div",Vn,c(new Date(e(z).date).toLocaleDateString("en-US",{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})),1),a("div",Bn,"Status: "+c(e(z).status),1),a("div",Pn,[a("div",null,[m[0]||(m[0]=a("span",{class:"text-green-500 dark:text-green-400"},"●",-1)),d(" Passed: "+c(e(z).passed),1)]),a("div",null,[m[1]||(m[1]=a("span",{class:"text-red-500 dark:text-red-400"},"●",-1)),d(" Failed: "+c(e(z).failed),1)]),a("div",null,[m[2]||(m[2]=a("span",{class:"text-orange-500 dark:text-orange-400"},"●",-1)),d(" Skipped: "+c(e(z).skipped),1)]),a("div",null,[m[3]||(m[3]=a("span",{class:"text-purple-500 dark:text-purple-400"},"●",-1)),d(" Flaky: "+c(e(z).flaky),1)]),a("div",Nn,"Total: "+c(e(z).total),1)]),m[4]||(m[4]=a("div",{class:"text-gray-400 dark:text-gray-500 text-xs mt-1"},"Click to view run details",-1))])],4)):S("",!0),l(q,{marker:e(v),pos:e(M)},null,8,["marker","pos"])])):(s(),k(Z,{key:1,text:"No test run data available to display chart"})),l(O,{items:$})])}}}),Ln=Object.assign(Kn,{__name:"TestRunsChart"}),On={class:"space-y-3"},qn={class:"min-w-0 space-y-1"},Hn={class:"flex items-center gap-2 flex-wrap text-sm"},Xn={key:0,class:"text-gray-500"},Gn=["title"],Jn=["title"],Qn={key:0,class:"text-xs text-gray-500 italic"},Yn={class:"flex items-center gap-2 shrink-0"},Wn=ue({__name:"ClusterMergeSuggestions",props:{projectId:{}},emits:["merged"],setup(A,{emit:T}){const x=A,D=T,b=Re(),f=w([]),u=w(null);async function E(){try{f.value=await $fetch(`/api/projects/${x.projectId}/cluster-merge-suggestions`)}catch{f.value=[]}}ge(()=>x.projectId,E,{immediate:!0});async function U(C,_){u.value=C;try{await $fetch(`/api/cluster-merge-suggestions/${C}/${_}`,{method:"POST"}),b.add({title:_==="approve"?"Clusters merged":"Suggestion dismissed",color:"success"}),await E(),_==="approve"&&D("merged")}catch(y){b.add({title:"Action failed",description:String(y?.message??y),color:"error"})}finally{u.value=null}}const R=C=>C==null?"":`${Math.round(C*100)}% similar`;return(C,_)=>{const y=Ae,z=Te,h=Yt;return e(f).length?(s(),k(h,{key:0,icon:"i-lucide-git-merge",title:"Suggested merges",count:e(f).length,class:"mb-4"},{subtitle:t(()=>[..._[0]||(_[0]=[d(" Likely-duplicate clusters found by semantic analysis. Approving merges them into the older cluster. ",-1)])]),default:t(()=>[a("div",On,[(s(!0),i(Q,null,ie(e(f),v=>(s(),i("div",{key:v.id,class:"rounded-lg border border-default p-3 flex items-start justify-between gap-4"},[a("div",qn,[a("div",Hn,[l(y,{color:v.method==="llm"?"primary":"neutral",variant:"subtle",size:"sm"},{default:t(()=>[d(c(v.method==="llm"?`AI · ${v.llmConfidence??""}`:"similarity"),1)]),_:2},1032,["color"]),R(v.score)?(s(),i("span",Xn,c(R(v.score)),1)):S("",!0)]),a("p",{class:"text-sm truncate",title:v.clusterA?.signature||""},[_[1]||(_[1]=a("span",{class:"text-gray-400"},"A:",-1)),d(" "+c(v.clusterA?.signature||`#${v.id}`),1)],8,Gn),a("p",{class:"text-sm truncate",title:v.clusterB?.signature||""},[_[2]||(_[2]=a("span",{class:"text-gray-400"},"B:",-1)),d(" "+c(v.clusterB?.signature||""),1)],8,Jn),v.llmReason?(s(),i("p",Qn,c(v.llmReason),1)):S("",!0)]),a("div",Yn,[l(z,{size:"sm",color:"primary",icon:"i-lucide-git-merge",loading:e(u)===v.id,onClick:M=>U(v.id,"approve")},{default:t(()=>[..._[3]||(_[3]=[d(" Merge ",-1)])]),_:1},8,["loading","onClick"]),l(z,{size:"sm",color:"neutral",variant:"ghost",icon:"i-lucide-x",disabled:e(u)===v.id,onClick:M=>U(v.id,"reject")},{default:t(()=>[..._[4]||(_[4]=[d(" Dismiss ",-1)])]),_:1},8,["disabled","onClick"])])]))),128))])]),_:1},8,["count"])):S("",!0)}}}),Zn=Object.assign(Wn,{__name:"ClusterMergeSuggestions"}),ea={class:"flex items-center justify-between"},ta={class:"text-sm text-gray-500 inline-flex items-center gap-1"},sa={class:"min-w-0 space-y-0.5"},na={key:0,class:"text-xs text-gray-500 italic truncate"},aa={key:1,class:"text-gray-400 text-xs"},oa={class:"text-sm tabular-nums"},la={class:"text-sm tabular-nums"},ra={key:1,class:"text-gray-400 text-xs"},ia={class:"text-sm text-gray-500 whitespace-nowrap"},ca={key:0,class:"ml-1 text-xs text-gray-400"},ua={class:"flex justify-end"},da=ue({__name:"FailureClustersList",props:{projectId:{}},async setup(A){let T,x;const D=A,b=w(void 0),{data:f,pending:u}=([T,x]=ye(()=>he(()=>{const U=new URLSearchParams;b.value&&U.set("status",b.value);const R=U.toString();return`/api/projects/${D.projectId}/failure-clusters${R?`?${R}`:""}`},{lazy:!0,server:!1,watch:[b]},"$f7pDU1t-lL")),T=await T,x(),T),E=[{accessorKey:"signature",header:I("Signature")},{accessorKey:"errorType",header:I("Type")},{accessorKey:"status",header:I("Status")},{accessorKey:"affectedTests",header:I("Tests")},{accessorKey:"occurrences",header:I("Occurrences")},{accessorKey:"diagnosis",header:"AI"},{accessorKey:"lastSeenAt",header:I("Last seen")},{id:"actions",header:"Actions"}];return(U,R)=>{const C=qe,_=Ue,y=Oe,z=Ae,h=Le,v=Te,M=ze,K=lt,$=Se,g=He;return s(),k(g,null,{header:t(()=>[a("div",ea,[a("p",ta,[R[1]||(R[1]=d(" Ongoing failure signatures grouped by normalized error. ",-1)),l(C,{topic:"cluster.concept"})]),l(_,{modelValue:e(b),"onUpdate:modelValue":R[0]||(R[0]=m=>G(b)?b.value=m:null),items:[{label:"All",value:void 0},{label:"Open",value:"open"},{label:"Resolved",value:"resolved"},{label:"Ignored",value:"ignored"}],size:"xs",class:"w-32"},null,8,["modelValue"])])]),default:t(()=>[l(K,{"min-width":"48rem",bleed:!1},{default:t(()=>[l(M,{data:e(f)??[],columns:E,loading:e(u)},{"actions-header":t(()=>[...R[2]||(R[2]=[a("div",{class:"text-right"},"Actions",-1)])]),"signature-cell":t(({row:m})=>[a("div",sa,[l(y,{to:`/failure-clusters/${m.original.id}`,class:re(["text-sm text-primary hover:underline truncate block",m.original.title?"":"font-mono"]),title:m.original.signature},{default:t(()=>[d(c(m.original.title||m.original.signature),1)]),_:2},1032,["to","class","title"]),m.original.triageNote?(s(),i("p",na,c(m.original.triageNote),1)):S("",!0)])]),"errorType-cell":t(({row:m})=>[m.original.errorType?(s(),k(z,{key:0,color:("clusterErrorTypeColor"in U?U.clusterErrorTypeColor:e(Ys))(m.original.errorType),variant:"subtle",size:"sm"},{default:t(()=>[d(c(m.original.errorType),1)]),_:2},1032,["color"])):(s(),i("span",aa,"—"))]),"status-cell":t(({row:m})=>[l(z,{color:("clusterStatusColor"in U?U.clusterStatusColor:e(Qs))(m.original.status),variant:"subtle",size:"sm"},{default:t(()=>[d(c(m.original.status),1)]),_:2},1032,["color"])]),"affectedTests-cell":t(({row:m})=>[a("span",oa,c(m.original.affectedTests),1)]),"occurrences-cell":t(({row:m})=>[a("span",la,c(m.original.occurrences),1)]),"diagnosis-cell":t(({row:m})=>[m.original.diagnosis?.status==="completed"&&m.original.diagnosis.category?(s(),k(z,{key:0,color:"neutral",variant:"subtle",size:"sm",class:"gap-1"},{default:t(()=>[l(h,{name:"i-lucide-sparkles",class:"size-3"}),d(" "+c(m.original.diagnosis.category),1)]),_:2},1024)):(s(),i("span",ra,"—"))]),"lastSeenAt-cell":t(({row:m})=>[a("div",ia,[l(y,{to:`/test-runs/${m.original.lastSeenRunId}`,class:"text-primary hover:underline"},{default:t(()=>[d(" run #"+c(m.original.lastSeenRunId),1)]),_:2},1032,["to"]),m.original.lastSeenAt?(s(),i("span",ca," ("+c(("formatRelativeTime"in U?U.formatRelativeTime:e(St))(m.original.lastSeenAt))+") ",1)):S("",!0)])]),"actions-cell":t(({row:m})=>[a("div",ua,[l(v,{to:`/failure-clusters/${m.original.id}`,size:"sm",variant:"outline","trailing-icon":"i-lucide-arrow-right"},{default:t(()=>[...R[3]||(R[3]=[d(" View ",-1)])]),_:1},8,["to"])])]),_:1},8,["data","loading"])]),_:1}),!e(u)&&e(f)&&e(f).length===0?(s(),k($,{key:0,text:"No failure clusters recorded for this project.",padded:!1,class:"py-4"})):S("",!0)]),_:1})}}}),ma=Object.assign(da,{__name:"FailureClustersList"}),pa={class:"flex items-center justify-between"},ga={class:"flex items-center gap-3"},fa={class:"text-sm text-gray-500 inline-flex items-center gap-1"},va={class:"flex items-center gap-1.5"},_a={class:"min-w-0 space-y-0.5"},ya={class:"flex items-center gap-2"},ha={class:"text-sm tabular-nums"},ba={class:"text-sm tabular-nums"},xa={key:1,class:"text-gray-400 text-xs"},ka={key:1,class:"text-gray-400 text-xs"},$a={key:1,class:"text-gray-400 text-xs"},Ca={key:0,class:"text-sm text-gray-500"},Ta={key:1,class:"text-gray-400 text-xs"},Sa={class:"flex justify-end"},ja={key:0,class:"text-sm text-gray-500 py-4 text-center"},wa=ue({__name:"FlakyTestsList",props:{projectId:{},environment:{},projectName:{}},async setup(A){let T,x;const D=A,b=w(50),f=w([]),{data:u,pending:E}=([T,x]=ye(()=>he(()=>{const h=new URLSearchParams({runs:String(b.value)});return D.environment&&h.set("environment",D.environment),`/api/projects/${D.projectId}/flaky-tests?${h.toString()}`},{lazy:!0,server:!1,watch:[b,()=>D.environment]},"$qKoEnbecbI")),T=await T,x(),T),U=B(()=>f.value.length===0?u.value??[]:(u.value??[]).filter(h=>f.value.includes(h.rootCause??"")));function R(h){return h>=60?"error":h>=30?"warning":"neutral"}function C(h){switch(h){case"timing":return"amber";case"network":return"red";case"assertion":return"blue";case"environment":return"purple";default:return"gray"}}function _(h){f.value.indexOf(h)>=0?f.value=f.value.filter(M=>M!==h):f.value=[...f.value,h]}const y=[{label:"Timing",value:"timing"},{label:"Network",value:"network"},{label:"Assertion",value:"assertion"},{label:"Environment",value:"environment"},{label:"Other",value:"other"}],z=[{accessorKey:"title",header:I("Test")},{accessorKey:"impact",header:I("Impact")},{accessorKey:"score",header:I("Score")},{accessorKey:"failureRate",header:I("Failure rate")},{accessorKey:"retryPassRuns",header:I("Retry passes")},{accessorKey:"alternations",header:I("Flips")},{accessorKey:"rootCause",header:"Root cause"},{accessorKey:"lastFlakeAt",header:I("Last flake")},{id:"actions",header:"Actions"}];return(h,v)=>{const M=qe,K=Le,$=Ae,g=Te,m=Ue,q=Oe,Z=jt,O=qt,P=ze,be=lt,xe=He;return s(),k(xe,null,{header:t(()=>[a("div",pa,[a("div",ga,[a("p",fa,[v[1]||(v[1]=d(" Tests that fail intermittently — detected by retry passes and status alternations ",-1)),l(M,{topic:"project.flaky-tests"})]),A.environment?(s(),k($,{key:0,color:"neutral",variant:"subtle",size:"sm",class:"gap-1"},{default:t(()=>[l(K,{name:"i-lucide-layers",class:"size-3"}),d(" "+c(A.environment),1)]),_:1})):S("",!0),a("div",va,[(s(),i(Q,null,ie(y,p=>l(g,{key:p.value,size:"xs",variant:e(f).includes(p.value)?"solid":"outline",color:(e(f).includes(p.value),"neutral"),onClick:L=>_(p.value)},{default:t(()=>[d(c(p.label),1)]),_:2},1032,["variant","color","onClick"])),64))])]),l(m,{modelValue:e(b),"onUpdate:modelValue":v[0]||(v[0]=p=>G(b)?b.value=p:null),items:[{label:"Last 20 runs",value:20},{label:"Last 50 runs",value:50},{label:"Last 100 runs",value:100}],size:"xs",class:"w-36"},null,8,["modelValue"])])]),default:t(()=>[l(be,{"min-width":"52rem",bleed:!1},{default:t(()=>[l(P,{data:e(U),columns:z,loading:e(E),sticky:"",class:"max-h-[32rem]"},{"actions-header":t(()=>[...v[2]||(v[2]=[a("div",{class:"text-right"},"Actions",-1)])]),"title-cell":t(({row:p})=>[a("div",_a,[l(q,{to:`/test-run-cases/${p.original.latestRunsCaseId}`,class:"text-sm font-medium text-primary hover:underline truncate block",title:p.original.title},{default:t(()=>[d(c(p.original.title),1)]),_:2},1032,["to","title"]),l(Z,{"file-path":p.original.filePath,"project-key":A.projectId,"project-name":A.projectName,class:"text-xs text-gray-400"},null,8,["file-path","project-key","project-name"])])]),"impact-cell":t(({row:p})=>[a("div",ya,[a("span",{class:re(["inline-block w-2 h-2 rounded-full shrink-0",{"bg-red-500":p.original.wastedCiMinutes>=30,"bg-amber-500":p.original.wastedCiMinutes>=5&&p.original.wastedCiMinutes<30,"bg-green-500":p.original.wastedCiMinutes>=0&&p.original.wastedCiMinutes<5}])},null,2),a("span",ha,c(Math.round(p.original.wastedCiMinutes))+" min wasted",1)])]),"score-cell":t(({row:p})=>[l($,{color:R(p.original.score),variant:"subtle",size:"sm"},{default:t(()=>[d(c(p.original.score),1)]),_:2},1032,["color"])]),"failureRate-cell":t(({row:p})=>[a("span",ba,c(Math.round(p.original.failureRate*100))+"%",1)]),"retryPassRuns-cell":t(({row:p})=>[p.original.retryPassRuns?(s(),k($,{key:0,color:"warning",variant:"outline",size:"sm"},{default:t(()=>[d(c(p.original.retryPassRuns)+" run"+c(p.original.retryPassRuns===1?"":"s"),1)]),_:2},1024)):(s(),i("span",xa,"—"))]),"alternations-cell":t(({row:p})=>[p.original.alternations>=2?(s(),k($,{key:0,color:"neutral",variant:"outline",size:"sm"},{default:t(()=>[d(c(p.original.alternations),1)]),_:2},1024)):(s(),i("span",ka,"—"))]),"rootCause-cell":t(({row:p})=>[p.original.rootCause?(s(),k(O,{key:0,text:p.original.rootCause,color:C(p.original.rootCause)},null,8,["text","color"])):(s(),i("span",$a,"—"))]),"lastFlakeAt-cell":t(({row:p})=>[p.original.lastFlakeAt?(s(),i("span",Ca,c(("formatRelativeTime"in h?h.formatRelativeTime:e(St))(p.original.lastFlakeAt)),1)):(s(),i("span",Ta,"—"))]),"actions-cell":t(({row:p})=>[a("div",Sa,[l(g,{to:`/test-run-cases/${p.original.latestRunsCaseId}`,size:"sm",variant:"outline","trailing-icon":"i-lucide-arrow-right"},{default:t(()=>[...v[3]||(v[3]=[d(" View ",-1)])]),_:1},8,["to"])])]),_:1},8,["data","loading"])]),_:1}),!e(E)&&e(U).length===0?(s(),i("p",ja," No flaky tests detected in the last "+c(e(b))+" runs. ",1)):S("",!0)]),_:1})}}}),Da=Object.assign(wa,{__name:"FlakyTestsList"}),Ra={class:"w-full relative"},Aa={key:0},Ua={class:"p-2 text-sm text-gray-900 dark:text-gray-100"},za={class:"font-semibold mb-1"},Ma={class:"capitalize mb-1"},Fa={class:"space-y-0.5"},Ia={class:"mt-1"},Ea={key:0,class:"text-gray-400 dark:text-gray-500 text-xs"},Va=ue({__name:"PerformanceTrendChart",props:{data:{},height:{default:300},markers:{default:()=>[]}},emits:["marker-click"],setup(A,{emit:T}){const x=A,D=T,b=B(()=>x.markers),f=B(()=>!x.data||x.data.length===0?[]:x.data.map($=>({id:$.id,date:new Date($.startTime),duration:$.duration?Math.round($.duration/1e3):null,avgTestDuration:$.avgTestDuration?Math.round($.avgTestDuration/1e3):null,p90TestDuration:$.p90TestDuration?Math.round($.p90TestDuration/1e3):null,commit:$.commit?$.commit.substring(0,7):null,status:$.status,totalTests:$.totalTests}))),u=$=>$.date,E=$=>$.duration??void 0,U=$=>$.avgTestDuration??void 0,R=$=>$.p90TestDuration??void 0,C=["rgb(59, 130, 246)","rgb(34, 197, 94)","rgb(249, 115, 22)"],_=w(null),{tooltipData:y,tooltipPos:z,markerTooltip:h,markerTooltipPos:v,onRenderComplete:M}=Qt(_,f,{x:$=>$.date,series:[{y:$=>$.duration,color:C[0]},{y:$=>$.avgTestDuration,color:C[1]},{y:$=>$.p90TestDuration,color:C[2]}],onClick:$=>Ct(`/test-runs/${$.id}`),markers:b,onMarkerClick:$=>D("marker-click",$.id)}),K=[{color:C[0],label:"Total Duration"},{color:C[1],label:"Avg Test Duration"},{color:C[2],label:"P90 Test Duration"}];return($,g)=>{const m=Ht,q=Se,Z=Jt;return s(),i("div",Ra,[e(f).length>0?(s(),i("div",Aa,[l(e(Gt),{ref_key:"xyContainerRef",ref:_,data:e(f),height:A.height,padding:{top:10,right:10,bottom:0,left:0},"on-render-complete":e(M)},{default:t(()=>[l(e(Xt),{x:u,y:[E,U,R],color:C,"curve-type":e(kt).MonotoneX,"line-width":2},null,8,["y","curve-type"]),l(e(at),{type:"x","tick-format":O=>new Date(O).toLocaleDateString("en-US",{month:"short",day:"numeric"}),label:"Date"},null,8,["tick-format"]),l(e(at),{type:"y",label:"Duration (s)","tick-format":O=>`${O}s`},null,8,["tick-format"])]),_:1},8,["data","height","on-render-complete"]),e(y)?(s(),i("div",{key:0,class:"fixed z-50 pointer-events-none bg-white dark:bg-gray-800 rounded-lg shadow-lg border border-gray-200 dark:border-gray-700 max-w-[260px]",style:Kt({left:`${e(z).x}px`,top:`${e(z).y}px`})},[a("div",Ua,[a("div",za,c(new Date(e(y).date).toLocaleDateString("en-US",{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})),1),a("div",Ma,"Status: "+c(e(y).status),1),a("div",Fa,[a("div",null,[g[0]||(g[0]=a("span",{class:"text-blue-500 dark:text-blue-400"},"●",-1)),d(" Total: "+c(e(y).duration??"-")+"s ",1)]),a("div",null,[g[1]||(g[1]=a("span",{class:"text-green-500 dark:text-green-400"},"●",-1)),d(" Avg: "+c(e(y).avgTestDuration??"-")+"s ",1)]),a("div",null,[g[2]||(g[2]=a("span",{class:"text-orange-500 dark:text-orange-400"},"●",-1)),d(" P90: "+c(e(y).p90TestDuration??"-")+"s ",1)]),a("div",Ia,"Tests: "+c(e(y).totalTests),1),e(y).commit?(s(),i("div",Ea," Commit: "+c(e(y).commit),1)):S("",!0)]),g[3]||(g[3]=a("div",{class:"text-gray-400 dark:text-gray-500 text-xs mt-1"},"Click to view run details",-1))])],4)):S("",!0),l(m,{marker:e(h),pos:e(v)},null,8,["marker","pos"])])):(s(),k(q,{key:1,text:"No performance data available to display chart"})),l(Z,{items:K})])}}}),Ba=Object.assign(Va,{__name:"PerformanceTrendChart"}),Pa={class:"min-w-0"},Na={class:"mt-1"},Ka={class:"tabular-nums"},La={key:0,class:"ml-1 text-xs text-gray-500",title:"timeout ÷ p95"},Oa={class:"tabular-nums text-gray-500"},qa={key:0,class:"text-sm"},Ha={key:1,class:"tabular-nums"},Xa={class:"tabular-nums font-medium text-green-600 dark:text-green-400"},Ga={class:"tabular-nums text-gray-500"},Ja=ue({__name:"TimeoutOpportunitiesTable",props:{projectId:{},projectName:{}},async setup(A){let T,x;const D=A,{data:b,pending:f}=([T,x]=ye(()=>he(()=>`/api/projects/${D.projectId}/timeout-opportunities`,{lazy:!0,server:!1},"$tMBJjTyDol")),T=await T,x(),T),u=B(()=>b.value??[]);function E(R){return R==null?"—":R<1e3?`${R}ms`:`${(R/1e3).toFixed(1)}s`}const U=[{accessorKey:"title",header:I("Test case")},{accessorKey:"kind",header:"Type"},{accessorKey:"timeout",header:I("Timeout")},{accessorKey:"p95",header:I("p95")},{accessorKey:"recommendedTimeout",header:"Recommendation"},{accessorKey:"estimatedSavingMs",header:I("Est. saving / failure")},{accessorKey:"runCount",header:I("Runs")}];return(R,C)=>{const _=wt,y=Se,z=Oe,h=jt,v=Ae,M=ze,K=lt,$=He;return s(),k($,null,{header:t(()=>[...C[0]||(C[0]=[a("h2",{class:"text-xl font-semibold"},"Timeout opportunities",-1),a("p",{class:"text-sm text-gray-600 mt-1"},[d(" Tests whose configured timeout far exceeds their real duration, or that still carry a stale "),a("code",{class:"text-xs"},"test.slow()"),d(" mark — tightening these makes failures surface sooner. ")],-1)])]),default:t(()=>[e(f)?(s(),k(_,{key:0})):e(u).length===0?(s(),k(y,{key:1,text:"No timeout opportunities",description:"No oversized timeouts or stale test.slow() marks were found for this project."})):(s(),k(K,{key:2,"min-width":"52rem",bleed:!1},{default:t(()=>[l(M,{data:e(u),columns:U,sticky:"",class:"max-h-[32rem]"},{"title-cell":t(({row:g})=>[a("div",Pa,[l(z,{to:`/test-cases/${g.original.testCaseId}`,class:"font-medium truncate block hover:text-primary hover:underline"},{default:t(()=>[d(c(g.original.title),1)]),_:2},1032,["to"]),a("div",Na,[l(h,{"file-path":g.original.filePath,"project-key":A.projectId,"project-name":A.projectName,class:"text-xs"},null,8,["file-path","project-key","project-name"])])])]),"kind-cell":t(({row:g})=>[l(v,{color:g.original.kind==="oversized-timeout"?"warning":"info",variant:"subtle",size:"sm"},{default:t(()=>[d(c(g.original.kind==="oversized-timeout"?"Oversized timeout":"Stale test.slow()"),1)]),_:2},1032,["color"])]),"timeout-cell":t(({row:g})=>[a("span",Ka,c(E(g.original.timeout)),1),g.original.headroomRatio!=null?(s(),i("span",La," ("+c(g.original.headroomRatio)+"×) ",1)):S("",!0)]),"p95-cell":t(({row:g})=>[a("span",Oa,c(E(g.original.p95)),1)]),"recommendedTimeout-cell":t(({row:g})=>[g.original.kind==="stale-slow"?(s(),i("span",qa,[...C[1]||(C[1]=[d("Remove ",-1),a("code",{class:"text-xs"},"test.slow()",-1)])])):(s(),i("span",Ha,"Lower to ~"+c(E(g.original.recommendedTimeout)),1))]),"estimatedSavingMs-cell":t(({row:g})=>[a("span",Xa,c(E(g.original.estimatedSavingMs)),1)]),"runCount-cell":t(({row:g})=>[a("span",Ga,c(g.original.runCount),1)]),_:1},8,["data"])]),_:1}))]),_:1})}}}),Qa=Object.assign(Ja,{__name:"TimeoutOpportunitiesTable"}),Ya={class:"flex items-center justify-between"},Wa={class:"text-sm text-gray-500 inline-flex items-center gap-1"},Za={class:"truncate font-mono text-xs"},eo={class:"tabular-nums"},to={class:"tabular-nums text-gray-500"},so={class:"tabular-nums text-gray-500"},no=ue({__name:"SpecHealthTable",props:{projectId:{}},async setup(A){let T,x;const D=A,b=w(30),{data:f,pending:u}=([T,x]=ye(()=>he(()=>`/api/projects/${D.projectId}/spec-health?days=${b.value}`,{lazy:!0,server:!1,watch:[b]},"$QL0nEFEG1b")),T=await T,x(),T),E=B(()=>f.value?.specs??[]);function U(h){return h>=.9?"bg-green-500":h>=.7?"bg-amber-500":h>0?"bg-red-500":"bg-gray-300 dark:bg-gray-600"}function R(h){return h>=.9?"text-green-600 dark:text-green-400":h>=.7?"text-amber-600 dark:text-amber-400":h>0?"text-red-600 dark:text-red-400":"text-gray-500"}function C(h){return`${Math.round(h*100)}%`}function _(h){return h<1e3?`${h}ms`:`${(h/1e3).toFixed(1)}s`}const y=[{label:"Last 7 days",value:7},{label:"Last 30 days",value:30},{label:"Last 90 days",value:90}],z=[{accessorKey:"prefix",header:I("Spec prefix")},{accessorKey:"passRate",header:I("Pass rate")},{accessorKey:"flakyRate",header:I("Flaky")},{accessorKey:"failureCount",header:I("Failures")},{accessorKey:"testCount",header:I("Tests")},{accessorKey:"avgDuration",header:I("Avg time")}];return(h,v)=>{const M=qe,K=Ue,$=wt,g=Se,m=Oe,q=ze,Z=lt,O=He;return s(),k(O,null,{header:t(()=>[a("div",Ya,[a("p",Wa,[v[1]||(v[1]=d(" Spec-file health overview — pass rate, flaky rate, and failure count per spec prefix ",-1)),l(M,{topic:"project.spec-health"})]),l(K,{modelValue:e(b),"onUpdate:modelValue":v[0]||(v[0]=P=>G(b)?b.value=P:null),items:y,size:"xs",class:"w-32"},null,8,["modelValue"])])]),default:t(()=>[e(u)?(s(),k($,{key:0})):e(E).length===0?(s(),k(g,{key:1,text:"No data",description:"No spec health data available for the selected period."})):(s(),k(Z,{key:2,"min-width":"46rem",bleed:!1},{default:t(()=>[l(q,{data:e(E),columns:z,sticky:"",class:"max-h-[32rem]"},{"prefix-cell":t(({row:P})=>[l(m,{to:`/projects/${A.projectId}/test-cases?file=${encodeURIComponent(P.original.prefix)}`,class:"flex items-center gap-2 min-w-0 text-primary hover:underline",title:P.original.prefix},{default:t(()=>[a("span",{class:re(["inline-block size-3 rounded shrink-0",U(P.original.passRate)])},null,2),a("span",Za,c(P.original.prefix),1)]),_:2},1032,["to","title"])]),"passRate-cell":t(({row:P})=>[a("span",{class:re(["font-medium tabular-nums",R(P.original.passRate)])},c(C(P.original.passRate)),3)]),"flakyRate-cell":t(({row:P})=>[a("span",eo,c(Math.round(P.original.flakyRate*100))+"%",1)]),"failureCount-cell":t(({row:P})=>[a("span",{class:re(["tabular-nums",P.original.failureCount>0?"text-red-600 dark:text-red-400":""])},c(P.original.failureCount),3)]),"testCount-cell":t(({row:P})=>[a("span",to,c(P.original.testCount),1)]),"avgDuration-cell":t(({row:P})=>[a("span",so,c(_(P.original.avgDuration)),1)]),_:1},8,["data"])]),_:1}))]),_:1})}}}),ao=Object.assign(no,{__name:"SpecHealthTable"}),oo={class:"space-y-4"},lo={class:"grid grid-cols-1 sm:grid-cols-2 gap-4"},ro={id:"marker-environments"},io=["value"],co=ue({__name:"MarkerFormModal",props:{open:{type:Boolean},projectId:{},marker:{},environments:{}},emits:["update:open","saved"],setup(A,{emit:T}){const x=A,D=T,b=Re(),f=nn.map(_=>({label:_.label,value:_.id,icon:_.icon})),u=Rs({label:"",occurredAt:"",category:bt,environment:"",description:""}),E=B(()=>!!x.marker),U=w(!1);function R(_){const y=new Date(_),z=h=>String(h).padStart(2,"0");return`${y.getFullYear()}-${z(y.getMonth()+1)}-${z(y.getDate())}T${z(y.getHours())}:${z(y.getMinutes())}`}ge(()=>x.open,_=>{_&&(x.marker?(u.label=x.marker.label,u.occurredAt=R(x.marker.occurredAt),u.category=x.marker.category||bt,u.environment=x.marker.environment??"",u.description=x.marker.description??""):(u.label="",u.occurredAt=R(new Date),u.category=bt,u.environment="",u.description=""))});async function C(){if(!u.label.trim()){b.add({title:"Label is required",color:"error"});return}if(!u.occurredAt){b.add({title:"Date is required",color:"error"});return}U.value=!0;const _={label:u.label.trim(),occurredAt:new Date(u.occurredAt).toISOString(),category:u.category,environment:u.environment.trim()||null,description:u.description.trim()||null};try{x.marker?(await $fetch(`/api/markers/${x.marker.id}`,{method:"PUT",body:_}),b.add({title:"Marker updated",color:"success"})):(await $fetch(`/api/projects/${x.projectId}/markers`,{method:"POST",body:_}),b.add({title:"Marker created",color:"success"})),D("update:open",!1),D("saved")}catch(y){b.add({title:E.value?"Failed to update marker":"Failed to create marker",description:Wt(y),color:"error"})}finally{U.value=!1}}return(_,y)=>{const z=Lt,h=Ot,v=Ue,M=sn,K=Te,$=Dt,g=Tt;return s(),k(g,null,{default:t(()=>[l($,{open:A.open,title:e(E)?"Edit marker":"Add marker","onUpdate:open":y[6]||(y[6]=m=>D("update:open",m))},{body:t(()=>[a("div",oo,[l(h,{label:"Label",name:"label",required:""},{default:t(()=>[l(z,{modelValue:e(u).label,"onUpdate:modelValue":y[0]||(y[0]=m=>e(u).label=m),placeholder:"e.g. Migrated CI to new runners",class:"w-full"},null,8,["modelValue"])]),_:1}),a("div",lo,[l(h,{label:"Date & time",name:"occurredAt",required:""},{default:t(()=>[l(z,{modelValue:e(u).occurredAt,"onUpdate:modelValue":y[1]||(y[1]=m=>e(u).occurredAt=m),type:"datetime-local",class:"w-full"},null,8,["modelValue"])]),_:1}),l(h,{label:"Category",name:"category"},{default:t(()=>[l(v,{modelValue:e(u).category,"onUpdate:modelValue":y[2]||(y[2]=m=>e(u).category=m),items:e(f),class:"w-full"},null,8,["modelValue","items"])]),_:1})]),l(h,{label:"Environment",name:"environment",help:"Optional. Leave empty to apply to all environments."},{default:t(()=>[l(z,{modelValue:e(u).environment,"onUpdate:modelValue":y[3]||(y[3]=m=>e(u).environment=m),list:"marker-environments",placeholder:"e.g. production",class:"w-full"},null,8,["modelValue"]),a("datalist",ro,[(s(!0),i(Q,null,ie(A.environments||[],m=>(s(),i("option",{key:m,value:m},null,8,io))),128))])]),_:1}),l(h,{label:"Description",name:"description"},{default:t(()=>[l(M,{modelValue:e(u).description,"onUpdate:modelValue":y[4]||(y[4]=m=>e(u).description=m),rows:3,placeholder:"Optional details",class:"w-full"},null,8,["modelValue"])]),_:1})])]),footer:t(()=>[l(K,{color:"neutral",variant:"ghost",label:"Cancel",onClick:y[5]||(y[5]=m=>D("update:open",!1))}),l(K,{label:e(E)?"Save changes":"Add marker",icon:e(E)?"i-lucide-check":"i-lucide-plus",loading:e(U),onClick:C},null,8,["label","icon","loading"])]),_:1},8,["open","title"])]),_:1})}}}),uo=Object.assign(co,{__name:"MarkerFormModal"}),mo={class:"md:hidden space-y-3"},po={class:"flex items-start justify-between gap-2"},go={key:0,class:"flex gap-1 shrink-0"},fo={class:"text-sm text-muted"},vo={key:0,class:"text-xs"},_o={key:1,class:"text-sm text-muted"},yo={class:"whitespace-nowrap"},ho={class:"text-sm"},bo={class:"text-xs text-muted"},xo={class:"font-medium flex items-center gap-1"},ko={key:0,class:"text-xs text-muted line-clamp-1"},$o={key:1,class:"text-xs text-muted"},Co={key:0,class:"flex gap-1 justify-end"},To=ue({__name:"ProjectTimeline",props:{projectId:{},markers:{},environments:{},canEdit:{type:Boolean},focusMarkerId:{}},emits:["changed","clear-focus"],setup(A,{emit:T}){const x=A,D=T,b=Re(),f=B(()=>[...x.markers].sort((v,M)=>+new Date(M.occurredAt)-+new Date(v.occurredAt))),u=[{accessorKey:"occurredAt",header:"When"},{accessorKey:"category",header:"Category"},{accessorKey:"label",header:"Label"},{accessorKey:"environment",header:"Environment"},{accessorKey:"actions",header:""}],E=w(!1),U=w(null);function R(){U.value=null,E.value=!0}function C(v){U.value=v,E.value=!0}ge(()=>x.focusMarkerId,v=>{if(v==null)return;const M=x.markers.find(K=>K.id===v);M&&C(M),D("clear-focus")},{immediate:!0});const _=w(!1),y=w(null);function z(v){y.value=v,_.value=!0}async function h(){const v=y.value;if(_.value=!1,y.value=null,!!v)try{await $fetch(`/api/markers/${v.id}`,{method:"DELETE"}),b.add({title:"Marker deleted",color:"success"}),D("changed")}catch(M){b.add({title:"Failed to delete marker",description:Wt(M),color:"error"})}}return(v,M)=>{const K=Te,$=Se,g=tn,m=Ae,q=Le,Z=ze,O=uo,P=Dt,be=Tt,xe=Yt;return s(),k(xe,{title:"Timeline markers",count:A.markers.length,icon:"i-lucide-milestone",help:"project.timeline",subtitle:"Dated events overlaid on the analytics charts"},{actions:t(()=>[A.canEdit?(s(),k(K,{key:0,label:"Add marker",icon:"i-lucide-plus",size:"sm",onClick:R})):S("",!0)]),default:t(()=>[A.markers.length===0?(s(),k($,{key:0,icon:"i-lucide-milestone",text:"No markers yet. Add a deploy, config change, or incident to see it on the charts."})):(s(),i(Q,{key:1},[a("div",mo,[(s(!0),i(Q,null,ie(e(f),p=>(s(),i("div",{key:p.id,class:"rounded-lg border border-default p-3 space-y-2"},[a("div",po,[l(g,{marker:p},null,8,["marker"]),A.canEdit?(s(),i("div",go,[l(K,{icon:"i-lucide-pencil",color:"neutral",variant:"ghost",size:"xs",onClick:L=>C(p)},null,8,["onClick"]),l(K,{icon:"i-lucide-trash-2",color:"error",variant:"ghost",size:"xs",onClick:L=>z(p)},null,8,["onClick"])])):S("",!0)]),a("div",fo,c(("prettyDateFormat"in v?v.prettyDateFormat:e(ot))(p.occurredAt)),1),p.environment?(s(),i("div",vo,[l(m,{color:"neutral",variant:"subtle",size:"xs"},{default:t(()=>[d(c(p.environment),1)]),_:2},1024)])):S("",!0),p.description?(s(),i("p",_o,c(p.description),1)):S("",!0)]))),128))]),l(Z,{data:e(f),columns:u,class:"hidden md:block"},{"occurredAt-cell":t(({row:p})=>[a("div",yo,[a("div",ho,c(("prettyDateFormat"in v?v.prettyDateFormat:e(ot))(p.original.occurredAt)),1),a("div",bo,c(("formatRelativeTime"in v?v.formatRelativeTime:e(St))(p.original.occurredAt)),1)])]),"category-cell":t(({row:p})=>[l(m,{color:e(xt)(p.original.category).color,variant:"subtle",size:"sm",class:"gap-1"},{default:t(()=>[l(q,{name:e(xt)(p.original.category).icon,class:"size-3"},null,8,["name"]),d(" "+c(e(xt)(p.original.category).label),1)]),_:2},1032,["color"])]),"label-cell":t(({row:p})=>[a("div",null,[a("div",xo,[d(c(p.original.label)+" ",1),p.original.source==="auto"?(s(),k(q,{key:0,name:"i-lucide-sparkles",class:"size-3 text-muted",title:"Automatically detected"})):S("",!0)]),p.original.description?(s(),i("div",ko,c(p.original.description),1)):S("",!0)])]),"environment-cell":t(({row:p})=>[p.original.environment?(s(),k(m,{key:0,color:"neutral",variant:"subtle",size:"xs"},{default:t(()=>[d(c(p.original.environment),1)]),_:2},1024)):(s(),i("span",$o,"All"))]),"actions-cell":t(({row:p})=>[A.canEdit?(s(),i("div",Co,[l(K,{icon:"i-lucide-pencil",color:"neutral",variant:"ghost",size:"sm",onClick:L=>C(p.original)},null,8,["onClick"]),l(K,{icon:"i-lucide-trash-2",color:"error",variant:"ghost",size:"sm",onClick:L=>z(p.original)},null,8,["onClick"])])):S("",!0)]),_:1},8,["data"])],64)),l(O,{open:e(E),"onUpdate:open":M[0]||(M[0]=p=>G(E)?E.value=p:null),"project-id":A.projectId,marker:e(U),environments:A.environments,onSaved:M[1]||(M[1]=p=>D("changed"))},null,8,["open","project-id","marker","environments"]),l(be,null,{default:t(()=>[l(P,{open:e(_),title:"Delete marker","onUpdate:open":M[3]||(M[3]=p=>_.value=p)},{body:t(()=>[a("p",null,[M[4]||(M[4]=d(" Delete marker ",-1)),e(y)?(s(),k(g,{key:0,marker:e(y),class:"inline-flex align-middle"},null,8,["marker"])):S("",!0),M[5]||(M[5]=d("? This can't be undone. ",-1))])]),footer:t(()=>[l(K,{color:"neutral",variant:"ghost",label:"Cancel",onClick:M[2]||(M[2]=p=>_.value=!1)}),l(K,{color:"error",label:"Delete",icon:"i-lucide-trash-2",onClick:h})]),_:1},8,["open"])]),_:1})]),_:1},8,["count"])}}}),So=Object.assign(To,{__name:"ProjectTimeline"}),jo={class:"flex flex-col h-full overflow-y-auto gap-4"},wo={key:0,class:"pb-0 space-y-4"},Do={key:0,class:"text-gray-600"},Ro={key:1,class:"flex flex-wrap gap-1 mt-2"},Ao={class:"flex flex-wrap items-center gap-3 mb-4"},Uo={class:"inline-flex items-center gap-1"},zo=["onClick"],Mo={key:0,class:"flex items-center gap-3 px-3 py-2 mb-3 rounded-lg bg-primary-50 dark:bg-primary-900/20 border border-primary-200 dark:border-primary-800"},Fo={class:"text-sm text-primary-700 dark:text-primary-300"},Io={key:1,class:"text-xs text-primary-500"},Eo=["checked","onClick"],Vo={class:"flex items-center gap-2"},Bo=["href","onClick"],Po={key:0,class:"text-xs text-gray-500 dark:text-gray-400 truncate max-w-32"},No={class:"inline-flex items-center gap-1"},Ko={key:0,class:"flex items-center gap-1"},Lo={class:"text-xs text-gray-600"},Oo={key:0,class:"text-xs font-medium bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200 px-1.5 py-0.5 rounded"},qo={key:0,class:"flex items-center gap-1 flex-wrap"},Ho={key:0,class:"text-xs font-medium bg-gray-100 dark:bg-gray-800 px-1.5 py-0.5 rounded"},Xo={key:1,class:"text-xs text-gray-500"},Go={class:"space-y-1"},Jo={class:"text-xs text-gray-500"},Qo={class:"flex justify-end gap-2"},Yo={key:2,class:"text-center py-8 text-gray-500"},Wo={class:"text-xs text-gray-400 max-w-sm"},Zo={class:"bg-gray-100 dark:bg-gray-800 px-1 rounded"},el={class:"flex flex-wrap items-center gap-3"},tl={class:"text-xl font-semibold inline-flex items-center gap-1"},sl={class:"font-medium"},nl={class:"mt-1"},al={key:0,class:"text-red-600 font-medium"},ol={key:1,class:"text-green-600 font-medium"},ll={key:2,class:"text-gray-500"},rl={key:2,class:"text-center py-8 text-red-500"},il={key:3,class:"text-center py-8 text-gray-500"},cl={class:"flex items-center justify-between"},ul={class:"text-xl font-semibold inline-flex items-center gap-1"},dl={class:"space-y-4"},ml={class:"grid grid-cols-1 md:grid-cols-2 gap-4"},pl={key:0,class:"text-center py-4 text-gray-500"},gl={key:1,class:"space-y-4"},fl={class:"flex gap-4 text-sm"},vl={key:0,class:"text-gray-400"},_l={key:0,class:"text-gray-400"},yl={key:0},hl={key:1,class:"text-gray-400"},bl={key:0},xl={key:1,class:"text-gray-400"},kl={key:0,class:"text-gray-400"},$l={key:0,class:"text-gray-400"},Cl={key:2,class:"text-center py-8 text-gray-500"},Tl={key:3,class:"text-center py-8 text-gray-500"},Sl={class:"flex items-center justify-between"},jl={class:"text-sm text-gray-600 inline-flex items-center gap-1"},wl={class:"space-y-4"},Dl={class:"grid grid-cols-1 md:grid-cols-2 gap-4"},Rl={key:0,class:"text-center py-8 text-gray-500"},Al={key:1,class:"space-y-4"},Ul={class:"space-y-2"},zl={class:"flex flex-wrap gap-4 text-sm"},Ml={key:3,class:"text-sm text-gray-500"},Fl={class:"flex flex-wrap gap-4 text-sm"},Il={key:0,class:"text-gray-400"},El={key:0,class:"text-gray-400"},Vl={key:0},Bl={key:1,class:"text-gray-400"},Pl={key:0},Nl={key:1,class:"text-gray-400"},Kl={key:0,class:"text-gray-400"},Ll={key:0,class:"text-gray-400"},Ol={key:2,class:"text-center py-8 text-gray-500"},ql={key:3,class:"text-center py-8 text-gray-500"},Hl={class:"flex items-center justify-between"},Xl={class:"text-sm text-gray-600 inline-flex items-center gap-1"},Gl={key:0,class:"space-y-2"},Jl={class:"font-medium text-sm"},Ql={class:"text-xs text-muted flex items-center gap-2"},Yl={key:0,class:"italic"},Wl={key:1,class:"text-xs text-muted italic"},Zl={key:1,class:"text-center py-8 text-muted text-sm"},er={class:"space-y-4"},tr={class:"text-sm text-gray-600 dark:text-gray-400"},sr={class:"block text-sm font-medium mb-1"},nr={class:"bg-gray-100 dark:bg-gray-800 px-1 rounded"},li=ue({__name:"index",async setup(A){let T,x;const D=As(),b=Us(),f=D.params.id,{data:u,refresh:E}=([T,x]=ye(()=>he(`/api/projects/${f}`,"$NX9Zy2qnH1")),T=await T,x(),T);zs(B(()=>({title:`${u.value?.label||u.value?.name||"Project"} — Piwi Dashboard`})));const U=Re(),R=w(null),C=w(null),{isAdmin:_,isReporter:y}=Nt(),z=$t(),h=B(()=>!z.public.authEnabled||_.value),v=w(!1),M=w(""),K=w(!1),$=B(()=>M.value===u.value?.name);async function g(){if($.value){K.value=!0;try{await $fetch(`/api/projects/${f}`,{method:"DELETE"}),U.add({title:"Project deleted",color:"success"}),await Fs(),await b.push("/")}catch(r){const n=r&&typeof r=="object"&&"data"in r?r.data?.message:void 0;U.add({title:"Delete failed",description:n||"An error occurred",color:"error"}),K.value=!1}}}ln(E);async function m(r){C.value=null,R.value=r;try{await $fetch(`/api/test-runs/${r}`,{method:"DELETE"}),U.add({title:"Test run deleted",color:"success"}),await E()}catch(n){const F=n&&typeof n=="object"&&"data"in n?n.data?.message:void 0;U.add({title:"Delete failed",description:F||"An error occurred",color:"error"})}finally{R.value=null}}const q=w([]),Z=w([]),O=w([]),P=B(()=>{const r=new Map(q.value.map(F=>[F.id,F])),n=[];for(const F of Z.value){if(F.role==="administrator")continue;const H=r.get(F.id);n.push({id:F.id,username:F.username,name:F.name??null,role:F.role,global:H?.global??!1,hasAccess:!!H})}for(const F of q.value)F.role==="administrator"&&n.push({...F,hasAccess:!0});return n}),be=B(()=>{const r=q.value.filter(F=>F.role!=="administrator"&&!F.global).map(F=>F.id).sort(),n=[...O.value].sort();return JSON.stringify(r)!==JSON.stringify(n)});ge(()=>u.value?.id,async r=>{if(!(!r||!_.value))try{const[n,F]=await Promise.all([$fetch(`/api/projects/${f}/members`),$fetch("/api/users")]);q.value=n.users,Z.value=F.users,O.value=n.users.filter(H=>H.role!=="administrator"&&!H.global).map(H=>H.id)}catch{q.value=[],Z.value=[],O.value=[]}},{immediate:!0});function xe(r){const n=O.value.indexOf(r);n>=0?O.value.splice(n,1):O.value.push(r)}async function p(){try{await $fetch(`/api/projects/${f}/members`,{method:"PUT",body:{userIds:O.value}}),U.add({title:"Members updated",color:"success"});const r=await $fetch(`/api/projects/${f}/members`);q.value=r.users}catch(r){const n=r&&typeof r=="object"&&"data"in r?r.data?.message:void 0;U.add({title:"Update failed",description:n||"An error occurred",color:"error"})}}const L=w("test-runs"),oe=w(0),de=["test-runs","failure-clusters","flaky-tests","performance","test-cases","compare","spec-health","timeline","members"],ke=D.query.tab;typeof ke=="string"&&de.includes(ke)&&(L.value=ke),ge(L,r=>{D.query.tab!==r&&de.includes(r)&&b.replace({query:{...D.query,tab:r}})});const fe=B(()=>u.value?.testRuns?.some(r=>r.failedTests>0)??!1),ce=B(()=>[{label:`Test runs (${Ee.value.length})`,icon:"i-lucide-play-circle",value:"test-runs",slot:"test-runs"},...fe.value?[{label:"Failure clusters",icon:"i-lucide-layers",value:"failure-clusters",slot:"failure-clusters"}]:[],{label:"Flaky tests",icon:"i-lucide-shuffle",value:"flaky-tests",slot:"flaky-tests"},{label:"Performance",icon:"i-lucide-trending-up",value:"performance",slot:"performance"},{label:`Test cases${Ne.value!=null?` (${Ne.value})`:""}`,icon:"i-lucide-list-checks",value:"test-cases",slot:"test-cases"},{label:"Compare",icon:"i-lucide-git-compare-arrows",value:"compare",slot:"compare"},{label:"Spec health",icon:"i-lucide-table-2",value:"spec-health",slot:"spec-health"},{label:`Timeline${j.value.length?` (${j.value.length})`:""}`,icon:"i-lucide-milestone",value:"timeline",slot:"timeline"},..._.value?[{label:"Members",icon:"i-lucide-users",value:"members",slot:"members"}]:[]]),ve=B(()=>ce.value.find(r=>r.value===L.value)?.icon),Y=w([]),rt=r=>Y.value.includes(r);function it(r){const n=Y.value.indexOf(r);if(n>=0)Y.value.splice(n,1);else{if(Y.value.length>=2){U.add({title:"Maximum 2 runs",description:"Select at most 2 runs to compare. Deselect one first.",color:"warning"});return}Y.value.push(r)}}const Me=w(null);function Xe(){Y.value.length===2&&(Me.value=[Y.value[0],Y.value[1]],L.value="compare")}const W=w([]),_e=w(!0),Fe=B(()=>{const r=new Set;for(const n of u.value?.testRuns||[])n.environment&&r.add(n.environment);return[...r].sort()});function ct(r){const n=W.value.indexOf(r);n===-1?W.value.push(r):W.value.splice(n,1)}function Ie(r){return W.value.includes(r)}const Ee=B(()=>{let r=u.value?.testRuns||[];return _e.value&&(r=r.filter(n=>n.isFullRun!==!1)),W.value.length===0?r:r.filter(n=>n.environment&&W.value.includes(n.environment))}),ut=B(()=>W.value.length===1?W.value[0]:void 0),{data:Ve,refresh:V}=([T,x]=ye(()=>he(`/api/projects/${f}/markers`,{default:()=>({markers:[]})},"$3gm0grYTFL")),T=await T,x(),T),j=B(()=>Ve.value?.markers??[]),ee=B(()=>!z.public.authEnabled||_.value||y.value),Ge=B(()=>W.value.length===0?j.value:j.value.filter(r=>r.environment==null||W.value.includes(r.environment))),Be=w(null);function Pe(r){Be.value=r,L.value="timeline"}const dt=B(()=>{const r=u.value?.testRuns||[];return _e.value?r.filter(n=>n.isFullRun!==!1):r});function Je(r){if(r.isFullRun!==!1)return"Full run — the complete test suite ran";const n=[],F=r.filterDetails?.grep?.trim(),H=r.filterDetails?.grepInvert?.trim(),me=r.filterDetails?.files;return F&&F!==".*"&&n.push(`grep: ${F}`),H&&n.push(`grep-invert: ${H}`),me?.length&&n.push(`files: ${me.join(", ")}`),n.length?`Partial run — ${n.join(" · ")}`:"Partial run — only a filtered subset of tests ran (grep, file, or line filter)"}const je=[{accessorKey:"select",header:""},{accessorKey:"id",header:I("Run")},{accessorKey:"status",header:I("Status")},{accessorKey:"isFullRun",header:"Scope"},{id:"browsers",accessorFn:r=>r.browsers,header:""},{accessorKey:"startTime",header:I("Started")},{accessorKey:"environment",header:I("Environment")},{accessorKey:"metadata",header:"Branch / Commit"},{accessorKey:"duration",header:I("Test status / Dur.")},{accessorKey:"reports",header:"Reports"},{id:"actions",header:"Actions"}],Ne=w(null),N=w(""),X=w(""),mt=B(()=>{const r={};return N.value&&(r.from=N.value),X.value&&(r.to=X.value),r}),pt=w(null),gt=w(!1),we=w(null),ft=w(!1),Qe=w(!1),Zt=B(()=>gt.value&&pt.value===null);ge([L,mt,_e],async([r,n])=>{if(r!=="performance")return;gt.value=!0,we.value||(Qe.value=!0);const F=new URLSearchParams(n).toString(),H=_e.value?`${F?"&":""}fullRunsOnly=true`:"",me=F||H?`?${F}${H}`:"";pt.value=await $fetch(`/api/projects/${f}/performance${me}`).catch(pe=>(console.warn("[PerformanceTab] Failed to fetch performance trend:",pe),null)),gt.value=!1,Qe.value&&(ft.value=!1,we.value=await $fetch(`/api/projects/${f}/slow-tests`).catch(pe=>(ft.value=!0,console.warn("[PerformanceTab] Failed to fetch slow tests:",pe),null)),Qe.value=!1)},{immediate:!0});const es=[{accessorKey:"title",header:I("Test case")},{accessorKey:"avgDuration",header:I("Avg duration")},{accessorKey:"maxDuration",header:I("Max")},{accessorKey:"minDuration",header:I("Min")},{accessorKey:"latestDuration",header:I("Latest")},{accessorKey:"trend",header:I("Trend")},{accessorKey:"runCount",header:I("Runs")}];function ts(r){const n=ot(r.startTime,{dateOnly:!0}),F=r.metadata?.scm?.commit?` (${r.metadata.scm.commit.substring(0,7)})`:"";return`Run #${r.id} — ${n}${F}`}const le=B(()=>u.value?.testRuns?[...u.value.testRuns].reverse().map(r=>({label:ts(r),value:r.id})):[]),te=w(void 0),se=w(void 0),Rt=B(()=>D.query.runA?Number(D.query.runA):null),At=B(()=>D.query.runB?Number(D.query.runB):null);ge(le,r=>{if(Rt.value){const n=r.find(F=>F.value===Rt.value);n&&(te.value=n)}if(At.value){const n=r.find(F=>F.value===At.value);n&&(se.value=n)}},{immediate:!0}),ge(Me,r=>{if(r){const n=le.value.find(H=>H.value===r[0]),F=le.value.find(H=>H.value===r[1]);n&&(te.value=n),F&&(se.value=F),Me.value=null}});function Ut(){le.value.length>=2&&(te.value=le.value[1],se.value=le.value[0])}const vt=w(null),_t=w(null),Ye=w(!1);async function ss(){const r=te.value,n=se.value;if(!(!r?.value&&!n?.value)){Ye.value=!0;try{const F=[];r?.value&&F.push(r.value),n?.value&&F.push(n.value);const H=await Promise.all(F.map(pe=>$fetch(`/api/test-runs/${pe}/summary`))),me=new Map;for(const pe of H)me.set(pe.id,pe);vt.value=r?.value?me.get(r.value)??null:null,_t.value=n?.value?me.get(n.value)??null:null}catch{vt.value=null,_t.value=null}finally{Ye.value=!1}}}ge([te,se],()=>{ss()});const{comparisonData:We,comparisonSummary:J}=on(vt,_t),zt=[{accessorKey:"title",header:I("Test case")},{accessorKey:"statusA",header:I("Status A")},{accessorKey:"statusB",header:I("Status B")},{accessorKey:"durationA",header:I("Duration A")},{accessorKey:"durationB",header:I("Duration B")},{accessorKey:"delta",header:I("Delta")},{accessorKey:"percentChange",header:I("Change")}];return(r,n)=>{const F=js,H=ws,me=Mn,pe=Bs,ns=Ns,as=qt,os=Ue,ls=Ln,Mt=Ls,rs=Os,De=qe,ae=Te,is=qs,yt=Le,cs=Hs,us=Xs,ds=Gs,ms=Js,Ze=ze,ps=Es,gs=Se,Ke=He,fs=Zn,vs=ma,_s=Da,ht=Lt,Ft=wt,ys=Ba,hs=jt,bs=Qa,et=Ws,ne=Ae,xs=Zs,ks=ao,$s=en,Cs=So,Ts=an,Ss=Ps,It=Dt,Et=Tt;return s(),i(Q,null,[l(Ss,{id:"project-detail"},{header:t(()=>[l(ns,null,{leading:t(()=>[l(F),l(H,{items:[{label:"Home",icon:"i-lucide-house",to:"/"},{label:"Projects",to:"/projects"},{label:e(u)?.label||e(u)?.name||"Project"}]},null,8,["items"])]),right:t(()=>[l(pe,{size:"sm",actions:[...e(h)?[{label:"Delete",icon:"i-lucide-trash-2",color:"error",variant:"ghost",onClick:()=>{M.value="",v.value=!0}}]:[],{label:"Edit",icon:"i-lucide-pencil",variant:"outline",to:`/projects/${e(f)}/edit`},{label:"Refresh",icon:"i-lucide-refresh-cw",variant:"outline",onClick:()=>e(E)()}]},{leading:t(()=>[l(me,{"project-id":parseInt(e(f)),"project-label":e(u)?.label||e(u)?.name},null,8,["project-id","project-label"])]),_:1},8,["actions"])]),_:1})]),body:t(()=>[a("div",jo,[e(u)?.description||e(u)?.tags&&e(u).tags.length>0?(s(),i("div",wo,[e(u)?.description?(s(),i("p",Do,c(e(u).description),1)):S("",!0),e(u)?.tags&&e(u).tags.length>0?(s(),i("div",Ro,[(s(!0),i(Q,null,ie(e(u).tags,o=>(s(),k(as,{key:o.id,text:o.text,color:o.color},null,8,["text","color"]))),128))])):S("",!0)])):S("",!0),l(os,{modelValue:e(L),"onUpdate:modelValue":n[0]||(n[0]=o=>G(L)?L.value=o:null),items:e(ce),icon:e(ve),size:"md",class:"w-full mx-1 mb-1 sm:hidden"},null,8,["modelValue","items","icon"]),l(Ts,{modelValue:e(L),"onUpdate:modelValue":n[14]||(n[14]=o=>G(L)?L.value=o:null),items:e(ce),size:"sm",class:"p-1",ui:{list:"max-sm:hidden overflow-x-auto",trigger:"shrink-0"}},{"test-runs":t(()=>[e(u)?.testRuns&&e(u).testRuns.length>0?(s(),k(Mt,{key:0,title:"Run trend",subtitle:`Test run statistics over time for ${e(u)?.label||e(u)?.name}`,help:"project.runs-trend"},{default:t(()=>[l(ls,{"test-runs":e(dt),height:200,markers:e(Ge),onMarkerClick:Pe},null,8,["test-runs","markers"])]),_:1},8,["subtitle"])):S("",!0),l(Ke,{class:"mt-4"},{default:t(()=>[a("div",Ao,[a("div",Uo,[l(rs,{modelValue:e(_e),"onUpdate:modelValue":n[1]||(n[1]=o=>G(_e)?_e.value=o:null),label:"Full runs only",ui:{label:"text-sm"}},null,8,["modelValue"]),l(De,{topic:"project.run-scope"})]),e(Fe).length>0?(s(),i(Q,{key:0},[n[21]||(n[21]=a("span",{class:"text-sm text-muted shrink-0"},"Environment:",-1)),(s(!0),i(Q,null,ie(e(Fe),o=>(s(),i("button",{key:o,type:"button",class:re(["text-xs font-medium px-2 py-1 rounded border cursor-pointer focus:outline-none transition-colors",Ie(o)?"bg-blue-600 text-white border-blue-600":"bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200 border-blue-300 dark:border-blue-700 hover:bg-blue-200 dark:hover:bg-blue-800"]),onClick:$e=>ct(o)},c(o),11,zo))),128)),e(W).length>0?(s(),k(ae,{key:0,size:"xs",variant:"ghost",color:"neutral",icon:"i-lucide-x",label:"Clear filter",onClick:n[2]||(n[2]=o=>W.value=[])})):S("",!0)],64)):S("",!0)]),e(Y).length>0?(s(),i("div",Mo,[a("span",Fo,c(e(Y).length)+" run"+c(e(Y).length>1?"s":"")+" selected ",1),e(Y).length===2?(s(),k(ae,{key:0,icon:"i-lucide-git-compare-arrows",size:"sm",color:"primary",label:"Compare selected runs",onClick:Xe})):(s(),i("span",Io," Select another run to compare ")),l(ae,{size:"xs",variant:"ghost",color:"neutral",icon:"i-lucide-x",label:"Clear",onClick:n[3]||(n[3]=o=>Y.value=[])})])):S("",!0),e(Ee).length>0?(s(),k(Ze,{key:1,data:e(Ee),columns:je,ui:{base:"table-fixed border-separate border-spacing-0",thead:"[&>tr]:bg-elevated/50 [&>tr]:after:content-none",tbody:"[&>tr]:last:[&>td]:border-b-0",th:"first:rounded-l-lg last:rounded-r-lg border-y border-default first:border-l last:border-r",td:"border-b border-default"}},{"select-cell":t(({row:o})=>[a("input",{type:"checkbox",checked:rt(o.original.id),class:"cursor-pointer size-4 accent-primary",onClick:Pt($e=>it(o.original.id),["stop"])},null,8,Eo)]),"id-cell":t(({row:o})=>[a("div",Vo,[a("a",{href:`/test-runs/${o.original.id}`,class:"text-primary hover:underline font-medium",onClick:Pt($e=>("navigateTo"in r?r.navigateTo:e(Ct))(`/test-runs/${o.original.id}`),["prevent"])}," Run #"+c(o.original.id),9,Bo),o.original.label?(s(),i("span",Po,c(o.original.label),1)):S("",!0)])]),"status-cell":t(({row:o})=>[l(is,{status:o.original.status},null,8,["status"])]),"isFullRun-header":t(()=>[a("span",No,[n[22]||(n[22]=d("Scope ",-1)),l(De,{topic:"run.partial"})])]),"isFullRun-cell":t(({row:o})=>[l(cs,{text:Je(o.original)},{default:t(()=>[l(yt,{name:o.original.isFullRun===!1?"i-lucide-list-filter":"i-lucide-list-checks",class:re(["size-4 shrink-0 cursor-help",o.original.isFullRun===!1?"text-amber-500":"text-green-500"])},null,8,["name","class"])]),_:2},1032,["text"])]),"browsers-cell":t(({row:o})=>[o.original.browsers?.length?(s(),i("div",Ko,[(s(!0),i(Q,null,ie(o.original.browsers,$e=>(s(),k(us,{key:$e,browser:{projectName:$e},size:"sm"},null,8,["browser"]))),128))])):S("",!0)]),"startTime-cell":t(({row:o})=>[a("span",Lo,c(("prettyDateFormat"in r?r.prettyDateFormat:e(ot))(o.original.startTime)),1)]),"environment-cell":t(({row:o})=>[o.original.environment?(s(),i("span",Oo,c(o.original.environment),1)):S("",!0)]),"metadata-cell":t(({row:o})=>[o.original.metadata?.scm?(s(),i("div",qo,[o.original.metadata.scm.branch?(s(),i("span",Ho,c(o.original.metadata.scm.branch),1)):S("",!0),o.original.metadata.scm.commit?(s(),i("code",Xo,c(o.original.metadata.scm.commit.substring(0,7)),1)):S("",!0)])):S("",!0)]),"duration-cell":t(({row:o})=>[a("div",Go,[l(ds,{passed:o.original.passedTests,failed:o.original.failedTests,skipped:o.original.skippedTests,flaky:o.original.flakyTests,"did-not-run":o.original.didNotRunTests??0,total:o.original.totalTests},null,8,["passed","failed","skipped","flaky","did-not-run","total"]),a("span",Jo,c(("formatDuration"in r?r.formatDuration:e(Ce))(o.original.duration)),1)])]),"reports-cell":t(({row:o})=>[l(ms,{reports:o.original.reports},null,8,["reports"])]),"actions-header":t(()=>[...n[23]||(n[23]=[a("div",{class:"text-right"},"Actions",-1)])]),"actions-cell":t(({row:o})=>[a("div",Qo,[l(ae,{to:`/test-runs/${o.original.id}`,size:"sm",variant:"outline"},{default:t(()=>[...n[24]||(n[24]=[d(" View ",-1)])]),_:1},8,["to"]),l(ae,{size:"sm",color:"error",variant:"soft",icon:"i-lucide-trash-2",loading:e(R)===o.original.id,onClick:$e=>C.value=o.original.id},{default:t(()=>[...n[25]||(n[25]=[d(" Delete ",-1)])]),_:1},8,["loading","onClick"])])]),_:1},8,["data"])):e(u)?.testRuns&&e(u).testRuns.length>0?(s(),i("div",Yo," No test runs match the selected environment filter. ")):(s(),k(gs,{key:3,icon:"i-lucide-rocket",text:"No test runs yet for this project."},{default:t(()=>[a("p",Wo,[n[27]||(n[27]=d(" Point the reporter's ",-1)),n[28]||(n[28]=a("code",{class:"bg-gray-100 dark:bg-gray-800 px-1 rounded"},"projectName",-1)),n[29]||(n[29]=d(" at ",-1)),a("code",Zo,c(e(u)?.name),1),n[30]||(n[30]=d(" to send results here — see the ",-1)),l(ps,{to:"reporter","no-icon":"",class:"text-primary hover:underline"},{default:t(()=>[...n[26]||(n[26]=[d("reporter docs",-1)])]),_:1}),n[31]||(n[31]=d(" for setup instructions. ",-1))])]),_:1}))]),_:1})]),"failure-clusters":t(()=>[e(L)==="failure-clusters"?(s(),i(Q,{key:0},[(s(),k(fs,{key:`sug-${e(oe)}`,"project-id":String(e(f)),onMerged:n[4]||(n[4]=o=>oe.value++)},null,8,["project-id"])),(s(),k(vs,{key:e(oe),"project-id":String(e(f))},null,8,["project-id"]))],64)):S("",!0)]),"flaky-tests":t(()=>[e(L)==="flaky-tests"?(s(),k(_s,{key:0,"project-id":String(e(f)),environment:e(ut),"project-name":e(u)?.name},null,8,["project-id","environment","project-name"])):S("",!0)]),performance:t(()=>[a("div",el,[n[32]||(n[32]=a("span",{class:"text-sm text-muted shrink-0"},"Date range:",-1)),l(ht,{modelValue:e(N),"onUpdate:modelValue":n[5]||(n[5]=o=>G(N)?N.value=o:null),type:"date",size:"sm",placeholder:"From",class:"w-40"},null,8,["modelValue"]),n[33]||(n[33]=a("span",{class:"text-sm text-muted"},"to",-1)),l(ht,{modelValue:e(X),"onUpdate:modelValue":n[6]||(n[6]=o=>G(X)?X.value=o:null),type:"date",size:"sm",placeholder:"To",class:"w-40"},null,8,["modelValue"]),e(N)||e(X)?(s(),k(ae,{key:0,size:"xs",variant:"ghost",color:"neutral",icon:"i-lucide-x",label:"Clear",onClick:n[7]||(n[7]=o=>{N.value="",X.value=""})})):S("",!0)]),l(Mt,{title:"Performance trend",subtitle:"Duration metrics over time",help:"project.performance"},{default:t(()=>[e(Zt)?(s(),k(Ft,{key:0,text:"Loading chart…"})):(s(),k(ys,{key:1,data:e(pt)||[],height:350,markers:e(Ge),onMarkerClick:Pe},null,8,["data","markers"]))]),_:1}),l(Ke,null,{header:t(()=>[a("h2",tl,[n[34]||(n[34]=d(" Slowest tests ",-1)),l(De,{topic:"project.slowest-tests"})]),n[35]||(n[35]=a("p",{class:"text-sm text-gray-600 mt-1"},"Top 20 slowest test cases across recent runs",-1))]),default:t(()=>[e(Qe)&&e(we)===null?(s(),k(Ft,{key:0,text:"Loading…"})):e(we)&&e(we).length>0?(s(),k(Ze,{key:1,data:e(we),columns:es,ui:{base:"table-fixed border-separate border-spacing-0",thead:"[&>tr]:bg-elevated/50 [&>tr]:after:content-none",tbody:"[&>tr]:last:[&>td]:border-b-0",th:"first:rounded-l-lg last:rounded-r-lg border-y border-default first:border-l last:border-r",td:"border-b border-default"}},{"title-cell":t(({row:o})=>[a("div",null,[a("div",sl,c(o.original.title),1),a("div",nl,[l(hs,{"file-path":o.original.filePath,"project-key":e(f),"project-name":e(u)?.name,class:"text-xs"},null,8,["file-path","project-key","project-name"])])])]),"trend-cell":t(({row:o})=>[o.original.trend==="slower"?(s(),i("span",al,"▲ Slower")):o.original.trend==="faster"?(s(),i("span",ol,"▼ Faster")):(s(),i("span",ll,"— Stable"))]),_:1},8,["data"])):e(ft)?(s(),i("div",rl," Couldn't load the slowest tests — try refreshing. ")):(s(),i("div",il,"No slow test data available yet."))]),_:1}),l(bs,{"project-id":String(e(f)),"project-name":e(u)?.name},null,8,["project-id","project-name"]),l(Ke,null,{header:t(()=>[a("div",cl,[a("div",null,[a("h2",ul,[n[36]||(n[36]=d(" Run comparison ",-1)),l(De,{topic:"project.run-compare"})]),n[37]||(n[37]=a("p",{class:"text-sm text-gray-600 mt-1"},"Compare duration changes between two runs",-1))]),e(le).length>=2?(s(),k(ae,{key:0,icon:"i-lucide-git-compare-arrows",size:"sm",variant:"outline",label:"Compare latest vs previous",onClick:Ut})):S("",!0)])]),default:t(()=>[a("div",dl,[a("div",ml,[a("div",null,[n[38]||(n[38]=a("label",{class:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"},"Run A (baseline)",-1)),l(et,{modelValue:e(te),"onUpdate:modelValue":n[8]||(n[8]=o=>G(te)?te.value=o:null),items:e(le),placeholder:"Select run A..."},null,8,["modelValue","items"])]),a("div",null,[n[39]||(n[39]=a("label",{class:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"},"Run B (comparison)",-1)),l(et,{modelValue:e(se),"onUpdate:modelValue":n[9]||(n[9]=o=>G(se)?se.value=o:null),items:e(le),placeholder:"Select run B..."},null,8,["modelValue","items"])])]),e(Ye)?(s(),i("div",pl,[l(yt,{name:"i-lucide-loader-2",class:"animate-spin mr-2"}),n[40]||(n[40]=d(" Loading run data… ",-1))])):e(te)&&e(se)&&e(We).length>0?(s(),i("div",gl,[a("div",fl,[l(ne,{color:"success",variant:"soft",size:"lg"},{default:t(()=>[d(c(e(J).improved)+" improved",1)]),_:1}),l(ne,{color:"error",variant:"soft",size:"lg"},{default:t(()=>[d(c(e(J).regressed)+" regressed",1)]),_:1}),l(ne,{color:"neutral",variant:"soft",size:"lg"},{default:t(()=>[d(c(e(J).unchanged)+" unchanged",1)]),_:1})]),l(Ze,{data:e(We),columns:zt,ui:{base:"table-fixed border-separate border-spacing-0",thead:"[&>tr]:bg-elevated/50 [&>tr]:after:content-none",tbody:"[&>tr]:last:[&>td]:border-b-0",th:"first:rounded-l-lg last:rounded-r-lg border-y border-default first:border-l last:border-r",td:"border-b border-default"}},{"statusA-cell":t(({row:o})=>[o.original.statusA?(s(),k(ne,{key:1,color:("getStatusColor"in r?r.getStatusColor:e(tt))(o.original.statusA),class:"capitalize"},{default:t(()=>[d(c(o.original.statusA),1)]),_:2},1032,["color"])):(s(),i("span",vl,"—"))]),"statusB-cell":t(({row:o})=>[o.original.statusB?(s(),k(ne,{key:1,color:("getStatusColor"in r?r.getStatusColor:e(tt))(o.original.statusB),class:"capitalize"},{default:t(()=>[d(c(o.original.statusB),1)]),_:2},1032,["color"])):(s(),i("span",_l,"—"))]),"durationA-cell":t(({row:o})=>[o.original.durationA!==null?(s(),i("span",yl,c(("formatDuration"in r?r.formatDuration:e(Ce))(o.original.durationA)),1)):(s(),i("span",hl,"—"))]),"durationB-cell":t(({row:o})=>[o.original.durationB!==null?(s(),i("span",bl,c(("formatDuration"in r?r.formatDuration:e(Ce))(o.original.durationB)),1)):(s(),i("span",xl,"—"))]),"delta-cell":t(({row:o})=>[o.original.delta===null?(s(),i("span",kl,"—")):(s(),i("span",{key:1,class:re(o.original.delta>0?"text-red-600":o.original.delta<0?"text-green-600":"text-gray-500")},c(o.original.delta>0?"+":"")+c(("formatDuration"in r?r.formatDuration:e(Ce))(o.original.delta)),3))]),"percentChange-cell":t(({row:o})=>[o.original.percentChange===null?(s(),i("span",$l,"—")):(s(),i("span",{key:1,class:re(o.original.percentChange>10?"text-red-600 font-medium":o.original.percentChange<-10?"text-green-600 font-medium":"text-gray-500")},c(o.original.percentChange>0?"+":"")+c(o.original.percentChange)+"% ",3))]),_:1},8,["data"])])):!e(te)||!e(se)?(s(),i("div",Cl," Select two runs to compare their performance. ")):(s(),i("div",Tl," No overlapping test cases found between the selected runs. "))])]),_:1})]),"test-cases":t(()=>[l(xs,{"project-id":e(f),"project-name":e(u)?.name,"sync-query":"",onTotal:n[10]||(n[10]=o=>Ne.value=o)},null,8,["project-id","project-name"])]),compare:t(()=>[l(Ke,null,{header:t(()=>[a("div",Sl,[a("p",jl,[n[41]||(n[41]=d(" Compare two test runs side-by-side — status changes and duration deltas ",-1)),l(De,{topic:"project.compare"})]),e(le).length>=2?(s(),k(ae,{key:0,icon:"i-lucide-git-compare-arrows",size:"sm",variant:"outline",label:"Latest vs previous",onClick:Ut})):S("",!0)])]),default:t(()=>[a("div",wl,[a("div",Dl,[a("div",null,[n[42]||(n[42]=a("label",{class:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"},"Run A (baseline)",-1)),l(et,{modelValue:e(te),"onUpdate:modelValue":n[11]||(n[11]=o=>G(te)?te.value=o:null),items:e(le),placeholder:"Select run A..."},null,8,["modelValue","items"])]),a("div",null,[n[43]||(n[43]=a("label",{class:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"},"Run B (comparison)",-1)),l(et,{modelValue:e(se),"onUpdate:modelValue":n[12]||(n[12]=o=>G(se)?se.value=o:null),items:e(le),placeholder:"Select run B..."},null,8,["modelValue","items"])])]),e(Ye)?(s(),i("div",Rl,[l(yt,{name:"i-lucide-loader-2",class:"animate-spin mr-2"}),n[44]||(n[44]=d(" Loading run data… ",-1))])):e(te)&&e(se)&&e(We).length>0?(s(),i("div",Al,[a("div",Ul,[a("div",zl,[n[45]||(n[45]=a("span",{class:"text-xs font-semibold text-gray-500 uppercase tracking-wider mr-1"},"Status changes",-1)),e(J).newFailures>0?(s(),k(ne,{key:0,color:"error",variant:"soft",size:"lg"},{default:t(()=>[d(c(e(J).newFailures)+" new failure"+c(e(J).newFailures>1?"s":""),1)]),_:1})):S("",!0),e(J).recovered>0?(s(),k(ne,{key:1,color:"success",variant:"soft",size:"lg"},{default:t(()=>[d(c(e(J).recovered)+" recovered ",1)]),_:1})):S("",!0),e(J).stillFailing>0?(s(),k(ne,{key:2,color:"warning",variant:"soft",size:"lg"},{default:t(()=>[d(c(e(J).stillFailing)+" still failing ",1)]),_:1})):S("",!0),e(J).newFailures===0&&e(J).recovered===0&&e(J).stillFailing===0?(s(),i("span",Ml,"No status changes")):S("",!0)]),a("div",Fl,[n[46]||(n[46]=a("span",{class:"text-xs font-semibold text-gray-500 uppercase tracking-wider mr-1"},"Duration changes",-1)),e(J).regressed>0?(s(),k(ne,{key:0,color:"error",variant:"soft",size:"lg"},{default:t(()=>[d(c(e(J).regressed)+" regressed ",1)]),_:1})):S("",!0),e(J).improved>0?(s(),k(ne,{key:1,color:"success",variant:"soft",size:"lg"},{default:t(()=>[d(c(e(J).improved)+" improved ",1)]),_:1})):S("",!0),l(ne,{color:"neutral",variant:"soft",size:"lg"},{default:t(()=>[d(c(e(J).unchanged)+" unchanged ",1)]),_:1})])]),l(Ze,{data:e(We),columns:zt,ui:{base:"table-fixed border-separate border-spacing-0",thead:"[&>tr]:bg-elevated/50 [&>tr]:after:content-none",tbody:"[&>tr]:last:[&>td]:border-b-0",th:"first:rounded-l-lg last:rounded-r-lg border-y border-default first:border-l last:border-r",td:"border-b border-default"}},{"statusA-cell":t(({row:o})=>[o.original.statusA?(s(),k(ne,{key:1,color:("getStatusColor"in r?r.getStatusColor:e(tt))(o.original.statusA),class:"capitalize"},{default:t(()=>[d(c(o.original.statusA),1)]),_:2},1032,["color"])):(s(),i("span",Il,"—"))]),"statusB-cell":t(({row:o})=>[o.original.statusB?(s(),k(ne,{key:1,color:("getStatusColor"in r?r.getStatusColor:e(tt))(o.original.statusB),class:"capitalize"},{default:t(()=>[d(c(o.original.statusB),1)]),_:2},1032,["color"])):(s(),i("span",El,"—"))]),"durationA-cell":t(({row:o})=>[o.original.durationA!==null?(s(),i("span",Vl,c(("formatDuration"in r?r.formatDuration:e(Ce))(o.original.durationA)),1)):(s(),i("span",Bl,"—"))]),"durationB-cell":t(({row:o})=>[o.original.durationB!==null?(s(),i("span",Pl,c(("formatDuration"in r?r.formatDuration:e(Ce))(o.original.durationB)),1)):(s(),i("span",Nl,"—"))]),"delta-cell":t(({row:o})=>[o.original.delta===null?(s(),i("span",Kl,"—")):(s(),i("span",{key:1,class:re(o.original.delta>0?"text-red-600":o.original.delta<0?"text-green-600":"text-gray-500")},c(o.original.delta>0?"+":"")+c(("formatDuration"in r?r.formatDuration:e(Ce))(o.original.delta)),3))]),"percentChange-cell":t(({row:o})=>[o.original.percentChange===null?(s(),i("span",Ll,"—")):(s(),i("span",{key:1,class:re(o.original.percentChange>10?"text-red-600 font-medium":o.original.percentChange<-10?"text-green-600 font-medium":"text-gray-500")},c(o.original.percentChange>0?"+":"")+c(o.original.percentChange)+"% ",3))]),_:1},8,["data"])])):!e(te)||!e(se)?(s(),i("div",Ol," Select two runs to compare test results. ")):(s(),i("div",ql," No overlapping test cases found between the selected runs. "))])]),_:1})]),"spec-health":t(()=>[l(ks,{"project-id":String(e(f))},null,8,["project-id"])]),members:t(()=>[l(Ke,null,{header:t(()=>[a("div",Hl,[a("p",Xl,[n[47]||(n[47]=d(" Users with access to this project ",-1)),l(De,{topic:"project.members"})]),l(ae,{label:"Save changes",icon:"i-lucide-check",size:"sm",disabled:!e(be),onClick:p},null,8,["disabled"])])]),default:t(()=>[e(P).length>0?(s(),i("div",Gl,[(s(!0),i(Q,null,ie(e(P),o=>(s(),i("div",{key:o.id,class:"flex items-center justify-between rounded-lg border border-default px-4 py-3"},[a("div",null,[a("div",Jl,c(o.name||o.username),1),a("div",Ql,[a("span",null,"@"+c(o.username),1),l(ne,{color:o.role==="administrator"?"primary":o.role==="reporter"?"info":"neutral",variant:"subtle",size:"xs"},{default:t(()=>[d(c(o.role),1)]),_:2},1032,["color"]),o.global?(s(),i("span",Yl,"Global access")):S("",!0)])]),o.role!=="administrator"?(s(),k($s,{key:0,"model-value":e(O).includes(o.id),disabled:o.global,title:o.global?"Has global access — remove global assignment first":"",onChange:$e=>xe(o.id)},null,8,["model-value","disabled","title","onChange"])):(s(),i("span",Wl,"Admin"))]))),128))])):(s(),i("div",Zl,"Loading members…"))]),_:1})]),timeline:t(()=>[l(Cs,{"project-id":Number(e(f)),markers:e(j),environments:e(Fe),"can-edit":e(ee),"focus-marker-id":e(Be),onChanged:e(V),onClearFocus:n[13]||(n[13]=o=>Be.value=null)},null,8,["project-id","markers","environments","can-edit","focus-marker-id","onChanged"])]),_:1},8,["modelValue","items"])])]),_:1}),l(Et,null,{default:t(()=>[l(It,{open:e(v),title:"Delete project","onUpdate:open":n[17]||(n[17]=o=>{o||(v.value=!1)})},{body:t(()=>[a("div",er,[a("p",tr,[n[48]||(n[48]=d(" This will permanently delete ",-1)),a("strong",null,c(e(u)?.label||e(u)?.name),1),n[49]||(n[49]=d(" and all its test runs, reports, traces, and failure clusters. This action cannot be undone. ",-1))]),a("div",null,[a("label",sr,[n[50]||(n[50]=d(" Type the project key ",-1)),a("code",nr,c(e(u)?.name),1),n[51]||(n[51]=d(" to confirm: ",-1))]),l(ht,{modelValue:e(M),"onUpdate:modelValue":n[15]||(n[15]=o=>G(M)?M.value=o:null),placeholder:e(u)?.name,autofocus:"",onKeydown:Ms(g,["enter"])},null,8,["modelValue","placeholder"])])])]),footer:t(()=>[l(ae,{color:"neutral",variant:"ghost",label:"Cancel",onClick:n[16]||(n[16]=o=>v.value=!1)}),l(ae,{color:"error",label:"Delete project",icon:"i-lucide-trash-2",disabled:!e($),loading:e(K),onClick:g},null,8,["disabled","loading"])]),_:1},8,["open"])]),_:1}),l(Et,null,{default:t(()=>[l(It,{open:e(C)!==null,title:"Delete test run","onUpdate:open":n[20]||(n[20]=o=>{o||(C.value=null)})},{body:t(()=>[a("p",null,[n[52]||(n[52]=d(" Are you sure you want to delete ",-1)),a("strong",null,"Run #"+c(e(C)),1),n[53]||(n[53]=d("? This will also remove all associated test results, reports, and traces. This action cannot be undone. ",-1))])]),footer:t(()=>[l(ae,{color:"neutral",variant:"ghost",label:"Cancel",onClick:n[18]||(n[18]=o=>C.value=null)}),l(ae,{color:"error",label:"Delete",icon:"i-lucide-trash-2",loading:e(R)===e(C),onClick:n[19]||(n[19]=o=>m(e(C)))},null,8,["loading"])]),_:1},8,["open"])]),_:1})],64)}}});export{li as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{d as m,B as h,o as n,f as o,U as p,
|
|
1
|
+
import{d as m,B as h,o as n,f as o,U as p,bH as g,bb as B,h as d,c as f,q as E,F as y,y as V}from"./D3SYPlEB.js";var k=m({inheritAttrs:!1,__name:"VisuallyHiddenInputBubble",props:{name:{type:String,required:!0},value:{type:null,required:!0},checked:{type:Boolean,required:!1,default:void 0},required:{type:Boolean,required:!1},disabled:{type:Boolean,required:!1},feature:{type:String,required:!1,default:"fully-hidden"}},setup(i){const e=i,{primitiveElement:s,currentElement:l}=B(),t=d(()=>e.checked??e.value);return h(t,(r,a)=>{if(!l.value)return;const u=l.value,b=window.HTMLInputElement.prototype,v=Object.getOwnPropertyDescriptor(b,"value").set;if(v&&r!==a){const _=new Event("input",{bubbles:!0}),q=new Event("change",{bubbles:!0});v.call(u,r),u.dispatchEvent(_),u.dispatchEvent(q)}}),(r,a)=>(n(),o(g,p({ref_key:"primitiveElement",ref:s},{...e,...r.$attrs},{as:"input"}),null,16))}}),c=k,A=m({inheritAttrs:!1,__name:"VisuallyHiddenInput",props:{name:{type:String,required:!0},value:{type:null,required:!0},checked:{type:Boolean,required:!1,default:void 0},required:{type:Boolean,required:!1},disabled:{type:Boolean,required:!1},feature:{type:String,required:!1,default:"fully-hidden"}},setup(i){const e=i,s=d(()=>typeof e.value=="object"&&Array.isArray(e.value)&&e.value.length===0&&e.required),l=d(()=>typeof e.value=="string"||typeof e.value=="number"||typeof e.value=="boolean"||e.value===null||e.value===void 0?[{name:e.name,value:e.value}]:typeof e.value=="object"&&Array.isArray(e.value)?e.value.flatMap((t,r)=>typeof t=="object"?Object.entries(t).map(([a,u])=>({name:`${e.name}[${r}][${a}]`,value:u})):{name:`${e.name}[${r}]`,value:t}):e.value!==null&&typeof e.value=="object"&&!Array.isArray(e.value)?Object.entries(e.value).map(([t,r])=>({name:`${e.name}[${t}]`,value:r})):[]);return(t,r)=>(n(),f(y,null,[E(" We render single input if it's required "),s.value?(n(),o(c,p({key:t.name},{...e,...t.$attrs},{name:t.name,value:t.value}),null,16,["name","value"])):(n(!0),f(y,{key:1},V(l.value,a=>(n(),o(c,p({key:a.name},{ref_for:!0},{...e,...t.$attrs},{name:a.name,value:a.value}),null,16,["name","value"]))),128))],2112))}}),I=A;export{I as V};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import{_ as me,a as pe}from"./BAaSmp8J.js";import{_ as fe,a as he}from"./87SGk1nu.js";import{_ as _e}from"./Bi3i470l.js";import{d as H,o as n,c as r,F as B,y as T,i,t as u,k as s,q as b,m as R,f as U,h as g,av as xe,I as se,r as D,j as $,_ as Y,D as oe,l as X,s as ee,g as P,p as Q,K as ae,v as ye,b as ge,aw as be,e as ve}from"./D3SYPlEB.js";import{_ as ke}from"./DM_YaJgJ.js";import{_ as $e}from"./B6IHiVa1.js";import{_ as we}from"./CCsl9MOZ.js";import{_ as Ae}from"./DnThe2U0.js";import{_ as je}from"./oFIS9u6t.js";import{e as re}from"./BUMZHDRC.js";import{_ as Ue}from"./KYucVFu7.js";import{u as Ce}from"./D3MWm6JP.js";import{u as Se}from"./CiPH-swI.js";import{u as Oe}from"./Doul3p1_.js";import"./B6rt3IcG.js";import"./Cx65B3c3.js";const qe=["get","post","put","patch","delete","head","options","trace"];function Be(e){switch(e.toLowerCase()){case"get":return"success";case"post":return"info";case"put":case"patch":return"warning";case"delete":return"error";default:return"neutral"}}function Re(e,t){return`op-${e}-${t}`.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/(^-|-$)/g,"")}function Te(e){const t=new Map;for(const[a,o]of Object.entries(e?.paths??{})){if(!o)continue;const c=o.parameters??[];for(const m of qe){const f=o[m];if(!f)continue;const p=f.tags?.[0]??"Other",_={path:a,method:m,operation:f,parameters:[...c,...f.parameters??[]],tag:p,anchor:Re(m,a)},A=t.get(p);A?A.push(_):t.set(p,[_])}}return[...t.entries()].map(([a,o])=>({tag:a,operations:o})).sort((a,o)=>a.tag.localeCompare(o.tag))}function ie(e,t){return Array.isArray(e.security)?e.security.length>0:Array.isArray(t?.security)&&t.security.length>0}function Pe(e){return Array.isArray(e.security)&&e.security.length===0}function N(e,t){if(!e?.$ref)return e;const a=/^#\/components\/schemas\/(.+)$/.exec(e.$ref);return a?.[1]?t?.components?.schemas?.[a[1]]??e:e}const Ve=["administrator","reporter","user"];function ne(e){return e.charAt(0).toUpperCase()+e.slice(1)}function Le(e){const t=e["x-required-roles"];if(!t||t.length===0)return null;const a=Ve.every(o=>t.includes(o));return{roles:t,label:a?"Any signed-in user":t.map(ne).join(" or "),shortLabel:a?"Any user":t.map(o=>o==="administrator"?"Admin":ne(o)).join(" / "),elevated:!a&&!t.includes("user")}}function te(e){if(!e)return"any";if(e.$ref)return e.$ref.split("/").pop()??"object";const t=Array.isArray(e.type)?e.type.join(" | "):e.type;if(t==="array"){const a=e.items;return`array<${a?te(a):"any"}>`}return!t&&e.properties||!t&&(e.oneOf||e.anyOf||e.allOf)?"object":t??"any"}const ze={class:"space-y-2"},Ie={class:"flex flex-wrap items-baseline gap-x-2 gap-y-0.5"},De={class:"font-mono text-primary"},Ne={class:"text-xs text-muted font-mono"},Ee={key:0,class:"text-xs text-dimmed font-mono"},Je={key:1,class:"text-xs font-medium text-error"},Me={key:0,class:"text-muted mt-0.5"},He={key:1,class:"text-xs text-dimmed mt-0.5"},We={class:"font-mono"},Fe=H({__name:"ApiSchema",props:{schema:{},spec:{default:null},depth:{default:0}},setup(e){const t=e,a=g(()=>N(t.schema,t.spec)??t.schema),o=g(()=>{const p=a.value.type==="array"?N(a.value.items,t.spec):a.value,_=p?.properties;if(!_)return[];const A=new Set(p?.required??[]);return Object.entries(_).map(([x,j])=>({name:x,required:A.has(x),schema:N(j,t.spec)??j}))}),c=g(()=>(t.depth??0)<6);function m(p){const _=p.type==="array"?N(p.items,t.spec):p;return!!(_?.properties&&Object.keys(_.properties).length>0)}function f(p){return(p.enum??[]).map(_=>JSON.stringify(_)).join(", ")}return(p,_)=>{const A=le;return n(),r("div",ze,[(n(!0),r(B,null,T(s(o),x=>(n(),r("div",{key:x.name,class:"text-sm"},[i("div",Ie,[i("code",De,u(x.name),1),i("span",Ne,u(("schemaTypeLabel"in p?p.schemaTypeLabel:s(te))(x.schema)),1),x.schema.format?(n(),r("span",Ee,"("+u(x.schema.format)+")",1)):b("",!0),x.required?(n(),r("span",Je,"required")):b("",!0)]),x.schema.description?(n(),r("p",Me,u(x.schema.description),1)):b("",!0),x.schema.enum?.length?(n(),r("p",He,[_[0]||(_[0]=R(" Allowed values: ",-1)),i("span",We,u(f(x.schema)),1)])):b("",!0),s(c)&&m(x.schema)?(n(),U(A,{key:2,schema:x.schema,spec:e.spec,depth:(e.depth??0)+1,class:"mt-1.5 border-l border-default pl-3"},null,8,["schema","spec","depth"])):b("",!0)]))),128))])}}}),le=Object.assign(Fe,{__name:"ApiSchema"});function Qe(){return{token:xe("piwi-api-token","")}}function Ge(e,t){return e.replace(/\{([^}]+)\}/g,(a,o)=>{const c=t[o];return c?encodeURIComponent(c):a})}function Ke(e){const t=new URLSearchParams;for(const[o,c]of Object.entries(e))c!==void 0&&c!==""&&t.append(o,c);const a=t.toString();return a?`?${a}`:""}function Z(e,t,a=0){const o=N(e,t);if(!o||a>6)return null;if(o.example!==void 0)return o.example;if(o.default!==void 0)return o.default;if(o.enum?.length)return o.enum[0];const c=Array.isArray(o.type)?o.type.find(m=>m!=="null"):o.type;if(c==="object"||!c&&o.properties){const m={};for(const[f,p]of Object.entries(o.properties??{}))m[f]=Z(p,t,a+1);return m}if(c==="array")return[Z(o.items,t,a+1)];switch(c){case"string":return o.format==="date-time"?"2024-01-01T00:00:00Z":o.format==="date"?"2024-01-01":o.format==="uuid"?"00000000-0000-0000-0000-000000000000":"string";case"integer":case"number":return 0;case"boolean":return!1;default:return null}}function Xe(e,t){const a=e.requestBody?.content?.["application/json"]?.schema;return a?JSON.stringify(Z(a,t),null,2):null}function Ze(e){return!!e.requestBody?.content?.["application/json"]}function K(e){return`'${e.replace(/'/g,"'\\''")}'`}function Ye({method:e,url:t,headers:a,body:o}){const c=["curl"];e.toUpperCase()!=="GET"&&c.push("-X",e.toUpperCase());for(const[m,f]of Object.entries(a))c.push("-H",K(`${m}: ${f}`));return o&&c.push("-d",K(o)),c.push(K(t)),c.join(" ")}function et({method:e,url:t,headers:a,body:o}){const c=[` method: ${JSON.stringify(e.toUpperCase())},`];return Object.keys(a).length&&c.push(` headers: ${JSON.stringify(a)},`),o&&c.push(` body: ${JSON.stringify(o)},`),`const res = await fetch(${JSON.stringify(t)}, {
|
|
2
|
+
${c.join(`
|
|
3
|
+
`)}
|
|
4
|
+
});
|
|
5
|
+
const data = await res.json();`}const tt={class:"rounded-lg border border-default bg-default/50 p-3 space-y-3"},st={class:"flex items-center justify-between gap-2"},nt={key:0,class:"space-y-1"},ot={key:1,class:"space-y-1.5"},at=["title"],rt={key:2,class:"space-y-1.5"},it=["title"],lt={key:3,class:"space-y-1"},ct={key:4,class:"text-xs text-dimmed"},ut={key:5,class:"space-y-1.5"},dt={class:"flex items-center gap-2 text-xs"},mt={class:"text-dimmed"},pt={class:"max-h-80 overflow-auto"},ft={key:6,class:"text-xs text-error"},ht={class:"space-y-1.5"},_t={class:"flex gap-1"},xt=H({__name:"ApiTryIt",props:{item:{},spec:{}},setup(e){const t=e,a=ae(),o=a.public.demoMode,c=(a.app?.baseURL??"/").replace(/\/$/,""),{token:m}=Qe(),f=g(()=>ie(t.item.operation,t.spec)),p=g(()=>t.item.parameters.filter(O=>O.in==="path")),_=g(()=>t.item.parameters.filter(O=>O.in==="query")),A=se(Object.fromEntries(p.value.map(O=>[O.name,""]))),x=se(Object.fromEntries(_.value.map(O=>[O.name,""]))),j=g(()=>Ze(t.item.operation)),C=g(()=>!!t.item.operation.requestBody?.content?.["multipart/form-data"]&&!j.value),w=D(Xe(t.item.operation,t.spec)??""),l=g(()=>j.value&&w.value.trim()?w.value:void 0),h=g(()=>c+Ge(t.item.path,A)+Ke(x)),S=g(()=>{const O={};return l.value&&(O["Content-Type"]="application/json"),f.value&&m.value&&(O.Authorization=`Bearer ${m.value}`),O}),q=g(()=>window.location.origin+h.value),L=g(()=>Ye({method:t.item.method,url:q.value,headers:S.value,body:l.value})),I=g(()=>et({method:t.item.method,url:q.value,headers:S.value,body:l.value})),y=D("curl"),d=D(!1),V=D(null),z=D(null);async function ue(){d.value=!0,V.value=null,z.value=null;const O=performance.now();try{const v={...S.value};o&&(v["x-demo-user-id"]=localStorage.getItem("piwi-demo-user-id")||"1");const E=await fetch(h.value,{method:t.item.method.toUpperCase(),headers:v,body:l.value,credentials:"same-origin"}),J=Math.round(performance.now()-O),W=await E.text();let F=W;try{F=JSON.stringify(JSON.parse(W),null,2)}catch{}z.value={status:E.status,statusText:E.statusText,ok:E.ok,timeMs:J,body:F}}catch(v){V.value=re(v)}finally{d.value=!1}}return(O,v)=>{const E=Y,J=oe,W=we,F=Ae,de=ee,G=je;return n(),r("div",tt,[i("div",st,[v[4]||(v[4]=i("h4",{class:"text-xs font-semibold uppercase tracking-wide text-dimmed"},"Try it out",-1)),$(E,{size:"xs",color:"primary",icon:"i-lucide-play",loading:s(d),label:"Send",onClick:ue},null,8,["loading"])]),s(f)?(n(),r("div",nt,[v[5]||(v[5]=i("label",{class:"text-xs text-dimmed"},"Authorization — Bearer token",-1)),$(J,{modelValue:s(m),"onUpdate:modelValue":v[0]||(v[0]=k=>X(m)?m.value=k:null),type:"password",placeholder:"pd_…",size:"sm",class:"w-full",ui:{base:"font-mono"}},null,8,["modelValue"])])):b("",!0),s(p).length?(n(),r("div",ot,[v[6]||(v[6]=i("label",{class:"text-xs text-dimmed"},"Path parameters",-1)),(n(!0),r(B,null,T(s(p),k=>(n(),r("div",{key:k.name,class:"flex items-center gap-2"},[i("code",{class:"text-xs font-mono text-primary w-28 shrink-0 truncate",title:k.name},u(k.name),9,at),$(J,{modelValue:s(A)[k.name],"onUpdate:modelValue":M=>s(A)[k.name]=M,placeholder:k.name,size:"sm",class:"flex-1",ui:{base:"font-mono"}},null,8,["modelValue","onUpdate:modelValue","placeholder"])]))),128))])):b("",!0),s(_).length?(n(),r("div",rt,[v[7]||(v[7]=i("label",{class:"text-xs text-dimmed"},"Query parameters",-1)),(n(!0),r(B,null,T(s(_),k=>(n(),r("div",{key:k.name,class:"flex items-center gap-2"},[i("code",{class:"text-xs font-mono text-primary w-28 shrink-0 truncate",title:k.name},u(k.name),9,it),k.schema?.enum?.length?(n(),U(W,{key:0,modelValue:s(x)[k.name],"onUpdate:modelValue":M=>s(x)[k.name]=M,items:["",...k.schema.enum.map(String)],size:"sm",class:"flex-1"},null,8,["modelValue","onUpdate:modelValue","items"])):(n(),U(J,{key:1,modelValue:s(x)[k.name],"onUpdate:modelValue":M=>s(x)[k.name]=M,placeholder:k.name,size:"sm",class:"flex-1",ui:{base:"font-mono"}},null,8,["modelValue","onUpdate:modelValue","placeholder"]))]))),128))])):b("",!0),s(j)?(n(),r("div",lt,[v[8]||(v[8]=i("label",{class:"text-xs text-dimmed"},"Request body — application/json",-1)),$(F,{modelValue:s(w),"onUpdate:modelValue":v[1]||(v[1]=k=>X(w)?w.value=k:null),rows:6,class:"w-full",ui:{base:"font-mono text-xs"}},null,8,["modelValue"])])):s(C)?(n(),r("p",ct,[...v[9]||(v[9]=[R(" This endpoint expects ",-1),i("code",{class:"font-mono"},"multipart/form-data",-1),R(" (file upload) — use the cURL sample below as a starting point. ",-1)])])):b("",!0),s(z)?(n(),r("div",ut,[i("div",dt,[$(de,{color:s(z).ok?"success":"error",variant:"subtle",class:"font-mono"},{default:P(()=>[R(u(s(z).status)+" "+u(s(z).statusText),1)]),_:1},8,["color"]),i("span",mt,u(s(z).timeMs)+" ms",1)]),i("div",pt,[$(G,{code:s(z).body,lang:"json"},null,8,["code"])])])):s(V)?(n(),r("p",ft,"Request failed: "+u(s(V)),1)):b("",!0),i("div",ht,[i("div",_t,[i("button",{type:"button",class:Q(["text-xs px-2 py-0.5 rounded-md transition-colors",s(y)==="curl"?"bg-elevated text-highlighted":"text-muted hover:text-highlighted"]),onClick:v[2]||(v[2]=k=>y.value="curl")}," cURL ",2),i("button",{type:"button",class:Q(["text-xs px-2 py-0.5 rounded-md transition-colors",s(y)==="fetch"?"bg-elevated text-highlighted":"text-muted hover:text-highlighted"]),onClick:v[3]||(v[3]=k=>y.value="fetch")}," JavaScript ",2)]),s(y)==="curl"?(n(),U(G,{key:0,code:s(L),lang:"bash"},null,8,["code"])):(n(),U(G,{key:1,code:s(I),lang:"javascript"},null,8,["code"]))])])}}}),yt=Object.assign(xt,{__name:"ApiTryIt"}),gt=["id"],bt=["aria-expanded"],vt={class:"font-mono text-sm text-highlighted break-all"},kt={class:"text-sm text-muted truncate hidden sm:inline flex-1"},$t={key:0,class:"px-3 pb-3 pt-1 space-y-4 border-t border-default"},wt={key:0,class:"text-sm font-medium text-highlighted sm:hidden"},At={key:1,class:"text-sm text-muted"},jt={key:2,class:"flex items-center gap-1.5 text-xs"},Ut={class:"text-muted font-medium"},Ct={key:0,class:"space-y-1.5"},St={class:"text-xs font-semibold uppercase tracking-wide text-dimmed"},Ot={class:"space-y-2"},qt={class:"flex flex-wrap items-baseline gap-x-2 gap-y-0.5"},Bt={class:"font-mono text-primary"},Rt={class:"text-xs text-muted font-mono"},Tt={key:0,class:"text-xs font-medium text-error"},Pt={key:0,class:"text-muted mt-0.5"},Vt={key:1,class:"text-xs text-dimmed mt-0.5"},Lt={class:"font-mono"},zt={key:3,class:"space-y-1.5"},It={class:"text-xs text-dimmed font-mono"},Dt={key:4,class:"space-y-1.5"},Nt={class:"flex items-baseline gap-2"},Et={class:"text-muted"},Jt={class:"text-xs text-dimmed font-mono"},Mt=H({__name:"ApiOperation",props:{item:{},spec:{}},setup(e){const t=e,a=D(!1),o=g(()=>ie(t.item.operation,t.spec)),c=g(()=>Pe(t.item.operation)),m=g(()=>Le(t.item.operation)),f=g(()=>c.value?"Public — no authentication required":m.value?m.value.label:o.value?"Requires authentication":null),p=g(()=>t.item.parameters.filter(l=>l.in==="path")),_=g(()=>t.item.parameters.filter(l=>l.in==="query")),A=g(()=>t.item.parameters.filter(l=>l.in==="header")),x=g(()=>Object.entries(t.item.operation.requestBody?.content??{}).map(([l,h])=>({contentType:l,schema:N(h.schema,t.spec)}))),j=g(()=>Object.entries(t.item.operation.responses??{}).map(([l,h])=>({status:l,description:h.description,entries:Object.entries(h.content??{}).map(([S,q])=>({contentType:S,schema:N(q.schema,t.spec)}))}))),C=g(()=>t.item.path.split(/(\{[^}]+\})/g).map(l=>({text:l,isParam:l.startsWith("{")})));function w(l){return l.startsWith("2")?"text-success":l.startsWith("3")?"text-info":l.startsWith("4")?"text-warning":l.startsWith("5")?"text-error":"text-muted"}return(l,h)=>{const S=ee,q=ye,L=le,I=yt;return n(),r("div",{id:e.item.anchor,class:"border border-default rounded-lg bg-elevated/20 scroll-mt-20"},[i("button",{type:"button",class:"w-full flex items-center gap-3 px-3 py-2.5 text-left cursor-pointer","aria-expanded":s(a),onClick:h[0]||(h[0]=y=>a.value=!s(a))},[$(S,{color:("methodBadgeColor"in l?l.methodBadgeColor:s(Be))(e.item.method),variant:"subtle",class:"font-mono uppercase shrink-0 w-16 justify-center"},{default:P(()=>[R(u(e.item.method),1)]),_:1},8,["color"]),i("code",vt,[(n(!0),r(B,null,T(s(C),(y,d)=>(n(),r("span",{key:d,class:Q(y.isParam?"text-warning":"")},u(y.text),3))),128))]),i("span",kt,u(e.item.operation.summary),1),s(m)?.elevated?(n(),U(S,{key:0,color:"warning",variant:"subtle",size:"sm",icon:"i-lucide-shield",class:"shrink-0 ml-auto sm:ml-0",title:`Requires role: ${s(m).label}`},{default:P(()=>[R(u(s(m).shortLabel),1)]),_:1},8,["title"])):s(c)?(n(),U(S,{key:1,color:"neutral",variant:"subtle",size:"sm",class:"shrink-0 ml-auto sm:ml-0"},{default:P(()=>[...h[1]||(h[1]=[R(" Public ",-1)])]),_:1})):s(o)?(n(),U(q,{key:2,name:"i-lucide-lock",class:"size-3.5 text-dimmed shrink-0 ml-auto sm:ml-0",title:"Requires authentication"})):b("",!0),$(q,{name:s(a)?"i-lucide-chevron-down":"i-lucide-chevron-right",class:"size-4 text-dimmed shrink-0"},null,8,["name"])],8,bt),s(a)?(n(),r("div",$t,[e.item.operation.summary?(n(),r("p",wt,u(e.item.operation.summary),1)):b("",!0),e.item.operation.description?(n(),r("p",At,u(e.item.operation.description),1)):b("",!0),s(f)?(n(),r("div",jt,[$(q,{name:s(m)?.elevated?"i-lucide-shield":"i-lucide-users",class:"size-3.5 text-dimmed shrink-0"},null,8,["name"]),h[2]||(h[2]=i("span",{class:"text-dimmed"},"Access",-1)),i("span",Ut,u(s(f)),1)])):b("",!0),(n(!0),r(B,null,T([{label:"Path parameters",params:s(p)},{label:"Query parameters",params:s(_)},{label:"Header parameters",params:s(A)}],y=>(n(),r(B,{key:y.label},[y.params.length?(n(),r("div",Ct,[i("h4",St,u(y.label),1),i("div",Ot,[(n(!0),r(B,null,T(y.params,d=>(n(),r("div",{key:d.name,class:"text-sm"},[i("div",qt,[i("code",Bt,u(d.name),1),i("span",Rt,u(("schemaTypeLabel"in l?l.schemaTypeLabel:s(te))(d.schema)),1),d.required?(n(),r("span",Tt,"required")):b("",!0)]),d.description?(n(),r("p",Pt,u(d.description),1)):b("",!0),d.schema?.enum?.length?(n(),r("p",Vt,[h[3]||(h[3]=R(" Allowed values: ",-1)),i("span",Lt,u(d.schema.enum.map(V=>JSON.stringify(V)).join(", ")),1)])):b("",!0)]))),128))])])):b("",!0)],64))),128)),s(x).length?(n(),r("div",zt,[h[4]||(h[4]=i("h4",{class:"text-xs font-semibold uppercase tracking-wide text-dimmed"},"Request body",-1)),(n(!0),r(B,null,T(s(x),y=>(n(),r("div",{key:y.contentType,class:"space-y-1.5"},[i("code",It,u(y.contentType),1),y.schema?(n(),U(L,{key:0,schema:y.schema,spec:e.spec},null,8,["schema","spec"])):b("",!0)]))),128))])):b("",!0),s(j).length?(n(),r("div",Dt,[h[5]||(h[5]=i("h4",{class:"text-xs font-semibold uppercase tracking-wide text-dimmed"},"Responses",-1)),(n(!0),r(B,null,T(s(j),y=>(n(),r("div",{key:y.status,class:"text-sm"},[i("div",Nt,[i("code",{class:Q(["font-mono font-semibold",w(y.status)])},u(y.status),3),i("span",Et,u(y.description),1)]),(n(!0),r(B,null,T(y.entries,d=>(n(),r("div",{key:d.contentType,class:"mt-1 pl-3 border-l border-default"},[i("code",Jt,u(d.contentType),1),d.schema?(n(),U(L,{key:0,schema:d.schema,spec:e.spec,class:"mt-1"},null,8,["schema","spec"])):b("",!0)]))),128))]))),128))])):b("",!0),$(I,{item:e.item,spec:e.spec},null,8,["item","spec"])])):b("",!0)],8,gt)}}}),Ht=Object.assign(Mt,{__name:"ApiOperation"});function ce(){const e=Se(),t=ge();async function a(o,c){const m=be();if(!m){window.open(o,"_blank");return}try{const f=await fetch(o,{credentials:"include"});if(!f.ok)throw new Error(`Request failed (${f.status})`);const p=await f.text(),_=await m.invoke("desktop_save_download",{filename:c,contents:p});t.add({title:"Saved to Downloads",description:_,color:"success",icon:"i-lucide-download"})}catch(f){t.add({title:"Download failed",description:re(f),color:"error"})}}return{isDesktop:e,download:a}}const Wt={class:"max-w-4xl mx-auto px-4 sm:px-6 py-6 space-y-6"},Ft={class:"space-y-3"},Qt={class:"flex flex-wrap items-center gap-2"},Gt={class:"text-xl font-semibold text-highlighted"},Kt={key:0,class:"text-sm text-muted"},Xt={key:1,class:"flex items-center gap-2 text-sm"},Zt={class:"flex flex-wrap items-center gap-2"},Yt={class:"text-xs text-dimmed"},es={key:0,class:"flex flex-wrap gap-1.5"},ts=["href"],ss={class:"text-dimmed"},ns={key:1,class:"space-y-8"},os=["id"],as={class:"text-sm font-semibold uppercase tracking-wide text-dimmed"},rs={class:"text-dimmed/60"},is=H({__name:"ApiReference",props:{spec:{},specUrl:{}},setup(e){const t=e,{copy:a,copied:o}=Ce(),{isDesktop:c,download:m}=ce(),f=D("");function p(w){c&&(w.preventDefault(),m(t.specUrl,"piwi-openapi.json"))}const _=g(()=>Te(t.spec)),A=g(()=>_.value.reduce((w,l)=>w+l.operations.length,0)),x=g(()=>{const w=f.value.trim().toLowerCase();return w?_.value.map(l=>({tag:l.tag,operations:l.operations.filter(h=>`${h.method} ${h.path} ${h.operation.summary??""} ${h.operation.description??""} ${h.tag}`.toLowerCase().includes(w))})).filter(l=>l.operations.length>0):_.value}),j=g(()=>t.spec.servers?.[0]?.url??"");function C(w){return`tag-${w.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/(^-|-$)/g,"")}`}return(w,l)=>{const h=ee,S=Y,q=$e,L=oe,I=Ht,y=Ue;return n(),r("div",Wt,[i("header",Ft,[i("div",Qt,[i("h1",Gt,u(e.spec.info?.title??"API Reference"),1),e.spec.info?.version?(n(),U(h,{key:0,color:"neutral",variant:"subtle",class:"font-mono"},{default:P(()=>[R(" v"+u(e.spec.info.version),1)]),_:1})):b("",!0)]),e.spec.info?.description?(n(),r("p",Kt,u(e.spec.info.description),1)):b("",!0),s(j)?(n(),r("div",Xt,[l[2]||(l[2]=i("span",{class:"text-dimmed"},"Base URL",-1)),$(S,{label:s(j),color:"neutral",variant:"subtle",size:"xs",icon:s(o)?"i-lucide-check":"i-lucide-copy",class:"font-mono",onClick:l[0]||(l[0]=d=>s(a)(s(j),{toast:!0}))},null,8,["label","icon"])])):b("",!0),i("div",Zt,[$(S,{to:e.specUrl,target:"_blank",external:"",color:"neutral",variant:"outline",size:"xs",icon:"i-lucide-file-json",label:"Raw OpenAPI spec",onClick:p},null,8,["to"]),i("span",Yt,u(s(A))+" endpoints",1)]),$(q,{color:"info",variant:"subtle",icon:"i-lucide-terminal",title:"Windows users",description:"curl examples below use Unix syntax — run them in Git Bash / WSL, or use PowerShell's Invoke-RestMethod instead."})]),$(L,{modelValue:s(f),"onUpdate:modelValue":l[1]||(l[1]=d=>X(f)?f.value=d:null),icon:"i-lucide-search",placeholder:"Filter endpoints by path, method, or description…",size:"md",class:"w-full",ui:{root:"sticky top-0 z-10"}},null,8,["modelValue"]),!s(f)&&s(_).length>1?(n(),r("div",es,[(n(!0),r(B,null,T(s(_),d=>(n(),r("a",{key:d.tag,href:`#${C(d.tag)}`,class:"text-xs px-2 py-1 rounded-md bg-elevated text-muted hover:text-highlighted hover:bg-accented transition-colors"},[R(u(d.tag)+" ",1),i("span",ss,u(d.operations.length),1)],8,ts))),128))])):b("",!0),s(x).length?(n(),r("div",ns,[(n(!0),r(B,null,T(s(x),d=>(n(),r("section",{key:d.tag,id:C(d.tag),class:"space-y-2 scroll-mt-4"},[i("h2",as,[R(u(d.tag)+" ",1),i("span",rs,"("+u(d.operations.length)+")",1)]),(n(!0),r(B,null,T(d.operations,V=>(n(),U(I,{key:V.anchor,item:V,spec:e.spec},null,8,["item","spec"]))),128))],8,os))),128))])):(n(),U(y,{key:2,icon:"i-lucide-search-x",text:"No endpoints match your filter."}))])}}}),ls=Object.assign(is,{__name:"ApiReference"}),cs={key:1,class:"p-6"},us={class:"flex flex-wrap justify-center gap-2 mt-1"},Us=H({__name:"docs",setup(e){const a=ae().public.demoMode,o=a?"/demo/_openapi.json":"/_openapi.json",{isDesktop:c,download:m}=ce();function f(j){c&&(j.preventDefault(),m(o,"piwi-openapi.json"))}ve({title:"API Reference — Piwi Dashboard"});const{data:p,status:_,error:A,refresh:x}=Oe(o,{key:"openapi-spec",lazy:!0,server:!a},"$jVU__ibpQM");return(j,C)=>{const w=me,l=pe,h=he,S=_e,q=Y,L=ke,I=ls,y=fe;return n(),U(y,{id:"docs"},{header:P(()=>[$(h,null,{leading:P(()=>[$(w),$(l,{items:[{label:"API Reference",icon:"i-lucide-book-open"}]})]),_:1})]),body:P(()=>[s(_)==="pending"||!s(p)&&!s(A)?(n(),U(S,{key:0,text:"Loading API reference…"})):s(A)||!s(p)?(n(),r("div",cs,[$(L,{text:"Couldn't load the API reference UI."},{action:P(()=>[C[3]||(C[3]=i("p",{class:"text-sm text-muted max-w-sm"},"The raw OpenAPI spec is still available directly.",-1)),i("div",us,[$(q,{size:"sm",color:"neutral",variant:"outline",icon:"i-lucide-refresh-cw",onClick:C[0]||(C[0]=()=>s(x)())},{default:P(()=>[...C[1]||(C[1]=[R(" Retry ",-1)])]),_:1}),$(q,{to:s(o),target:"_blank",external:"",size:"sm",variant:"outline",icon:"i-lucide-file-json",onClick:f},{default:P(()=>[...C[2]||(C[2]=[R(" Raw OpenAPI spec ",-1)])]),_:1},8,["to"])])]),_:1})])):(n(),U(I,{key:2,spec:s(p),"spec-url":s(o)},null,8,["spec","spec-url"]))]),_:1})}}});export{Us as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{a$ as l,aM as s}from"./D3SYPlEB.js";function t(r,i){return l(r)?!1:Array.isArray(r)?r.some(a=>s(a,i)):s(r,i)}export{t as i};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{d as o,u as s,w as c,n as u,o as p,c as i}from"./
|
|
1
|
+
import{d as o,u as s,w as c,n as u,o as p,c as i}from"./D3SYPlEB.js";const d=o({__name:"compare",async setup(_){let t,n;const e=s(),a=e.params.id;{const r=new URLSearchParams;r.set("tab","compare"),e.query.runA&&r.set("runA",String(e.query.runA)),e.query.runB&&r.set("runB",String(e.query.runB)),[t,n]=c(()=>u(`/projects/${a}?${r.toString()}`,{replace:!0})),await t,n()}return(r,m)=>(p(),i("div"))}});export{d as default};
|