@piwitests/server 0.20.0 → 0.21.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/{CXEH9OPk.js → 9ti9eNH9.js} +1 -1
- package/.output/public/_nuxt/{oAClCn_h.js → B-zdP-D4.js} +1 -1
- package/.output/public/_nuxt/{DsesNydr.js → B1RmmOsM.js} +1 -1
- package/.output/public/_nuxt/{C0_yH0N7.js → B3Fsod9X.js} +1 -1
- package/.output/public/_nuxt/{Cnsmicv2.js → B3rirOqU.js} +34 -34
- package/.output/public/_nuxt/B3zmIJYb.js +1 -0
- package/.output/public/_nuxt/{DuwtTfO8.js → BAKUqW95.js} +2 -2
- package/.output/public/_nuxt/BG0KKQiT.js +7 -0
- package/.output/public/_nuxt/BGL_V7Y4.js +1 -0
- package/.output/public/_nuxt/{Dpd16JVI.js → BGusFAvZ.js} +1 -1
- package/.output/public/_nuxt/{l5WKbU4h.js → BNurUTla.js} +3 -3
- package/.output/public/_nuxt/BR5cR2Ot.js +1 -0
- package/.output/public/_nuxt/BTCh_0zN.js +1 -0
- package/.output/public/_nuxt/{C8e1EbJI.js → BTVqMsA3.js} +1 -1
- package/.output/public/_nuxt/{DabzhQB1.js → B_13C0GF.js} +1 -1
- package/.output/public/_nuxt/BeDIjhoR.js +44 -0
- package/.output/public/_nuxt/{D5tke0B5.js → BerCW7Ug.js} +1 -1
- package/.output/public/_nuxt/{BicAJ6U8.js → BfTNbVc_.js} +1 -1
- package/.output/public/_nuxt/BnbSEpXX.js +1 -0
- package/.output/public/_nuxt/Bo_dxehb.js +1 -0
- package/.output/public/_nuxt/{C2hkrSey.js → BpBHls4-.js} +1 -1
- package/.output/public/_nuxt/{Bm62iDV5.js → BpM6ZPIG.js} +1 -1
- package/.output/public/_nuxt/{GPNI1ffD.js → BqGumsDo.js} +2 -2
- package/.output/public/_nuxt/{A1pj0VnG.js → BrxtP_cN.js} +1 -1
- package/.output/public/_nuxt/{KyA_4Ks-.js → C2hNxjjz.js} +1 -1
- package/.output/public/_nuxt/C5PSqfKi.js +2 -0
- package/.output/public/_nuxt/C5vsaU4G.js +1 -0
- package/.output/public/_nuxt/C9sdHaXd.js +1 -0
- package/.output/public/_nuxt/{Und3xXFc.js → CAxgBYIt.js} +2 -2
- package/.output/public/_nuxt/{BmUfSNMV.js → CES2i5Pl.js} +1 -1
- package/.output/public/_nuxt/{CNyV9YpI.js → CFEdRqaj.js} +1 -1
- package/.output/public/_nuxt/{Dy-TJ0Mt.js → CFTZwazK.js} +1 -1
- package/.output/public/_nuxt/CIBS7ye6.js +1 -0
- package/.output/public/_nuxt/CIEceDOw.js +1 -0
- package/.output/public/_nuxt/{bLcjFslv.js → CJBhojV6.js} +1 -1
- package/.output/public/_nuxt/{b-GYfcrQ.js → CKYddHa6.js} +1 -1
- package/.output/public/_nuxt/{BKkF4pPD.js → CLVWiCds.js} +1 -1
- package/.output/public/_nuxt/{CwGWJbiy.js → CMYAryzi.js} +1 -1
- package/.output/public/_nuxt/{CjPfj7ya.js → COhdybDy.js} +1 -1
- package/.output/public/_nuxt/{B7FTvFWq.js → CRBXM2d6.js} +2 -2
- package/.output/public/_nuxt/CTD_pJ_v.js +1 -0
- package/.output/public/_nuxt/{Cus22Ud3.js → CTP8Pw0-.js} +2 -2
- package/.output/public/_nuxt/{CeW8v31b.js → CV8iF2kG.js} +1 -1
- package/.output/public/_nuxt/{H94BMf3L.js → CWKmbYlT.js} +1 -1
- package/.output/public/_nuxt/C_NfGMTd.js +9 -0
- package/.output/public/_nuxt/Cejoebel.js +6 -0
- package/.output/public/_nuxt/{FaFoMVKo.js → Chpah_7l.js} +1 -1
- package/.output/public/_nuxt/Ci9d8YVV.js +1 -0
- package/.output/public/_nuxt/{CIrFl3MW.js → CifRHVaR.js} +1 -1
- package/.output/public/_nuxt/{DrfE8IY0.js → Ckgsh9AT.js} +1 -1
- package/.output/public/_nuxt/{-f7BAm1H.js → Cpsq-kYE.js} +1 -1
- package/.output/public/_nuxt/Cqc-DSTF.js +1 -0
- package/.output/public/_nuxt/{CAAwCT7H.js → CsHulb12.js} +1 -1
- package/.output/public/_nuxt/Ctb2CqUf.js +5 -0
- package/.output/public/_nuxt/CtstIQSh.js +1 -0
- package/.output/public/_nuxt/{DJxlKFGb.js → CvMzDKvu.js} +1 -1
- package/.output/public/_nuxt/{CTU1mrhq.js → D2pBhsH8.js} +1 -1
- package/.output/public/_nuxt/{B3obW6cw.js → D8gX1Jde.js} +2 -2
- package/.output/public/_nuxt/D9knOn6D.js +1 -0
- package/.output/public/_nuxt/DAPTVdvA.js +1 -0
- package/.output/public/_nuxt/{Du2W7Jne.js → DCFbQvIN.js} +42 -42
- package/.output/public/_nuxt/DCoJlz_q.js +1 -0
- package/.output/public/_nuxt/DGnQ69wW.js +64 -0
- package/.output/public/_nuxt/{hNh4CIL0.js → DHzij16p.js} +1 -1
- package/.output/public/_nuxt/DJMCXRuW.js +5 -0
- package/.output/public/_nuxt/DJXcGkJP.js +2 -0
- package/.output/public/_nuxt/{DPCxhHri.js → DKFXZdWZ.js} +1 -1
- package/.output/public/_nuxt/{Bnxf8nbZ.js → DL24AjfW.js} +1 -1
- package/.output/public/_nuxt/DON74Yh6.js +1 -0
- package/.output/public/_nuxt/{5A6ITZXj.js → DQM62mxB.js} +1 -1
- package/.output/public/_nuxt/DSe8DxMl.js +1 -0
- package/.output/public/_nuxt/DWwiVTZX.js +24 -0
- package/.output/public/_nuxt/DX4tAP78.js +1 -0
- package/.output/public/_nuxt/{C1gTN4Q8.js → D_eDAIsT.js} +1 -1
- package/.output/public/_nuxt/Da8A92cF.js +1 -0
- package/.output/public/_nuxt/{CzAPFPpL.js → DdH3op4b.js} +1 -1
- package/.output/public/_nuxt/DepFDZO3.js +1 -0
- package/.output/public/_nuxt/{BzRRzmwm.js → DfSBKzrC.js} +1 -1
- package/.output/public/_nuxt/{BdfhYr-u.js → DfnKh3dZ.js} +1 -1
- package/.output/public/_nuxt/{Bow4tTR0.js → DhpTfeip.js} +1 -1
- package/.output/public/_nuxt/{CAvY22RE.js → Dk9nD32g.js} +1 -1
- package/.output/public/_nuxt/{BrQEE053.js → DkT2nCqn.js} +1 -1
- package/.output/public/_nuxt/DlW85lQq.js +4 -0
- package/.output/public/_nuxt/DnNio-ut.js +1 -0
- package/.output/public/_nuxt/{DdwHkKfV.js → DnQv_hst.js} +1 -1
- package/.output/public/_nuxt/{B99fbi73.js → DqEOMteW.js} +1 -1
- package/.output/public/_nuxt/{4gYNA-d4.js → Dsvu7YJT.js} +1 -1
- package/.output/public/_nuxt/DvhCDBrR.js +2 -0
- package/.output/public/_nuxt/DwQaVMZR.js +1 -0
- package/.output/public/_nuxt/E-_n_6vi.js +1 -0
- package/.output/public/_nuxt/{BT3wGCTI.js → Ebw5l7n8.js} +1 -1
- package/.output/public/_nuxt/{CA9B2HE5.js → IPePdbzl.js} +1 -1
- package/.output/public/_nuxt/{DJmoLeVt.js → LHoUGrfi.js} +1 -1
- package/.output/public/_nuxt/{L3kAWB2a.js → NERLHpOL.js} +1 -1
- package/.output/public/_nuxt/{CeG9pBAD.js → RAdNGxcF.js} +1 -1
- package/.output/public/_nuxt/Vxyo_mU9.js +1 -0
- package/.output/public/_nuxt/{pQqGiNch.js → YE1kAkU9.js} +1 -1
- package/.output/public/_nuxt/{CsLojMwR.js → YmT5WiN5.js} +1 -1
- package/.output/public/_nuxt/ZcAfCxWE.js +17 -0
- package/.output/public/_nuxt/{CxyAzHr3.js → _rglcvXN.js} +1 -1
- package/.output/public/_nuxt/bFU9Y1Vw.js +10 -0
- package/.output/public/_nuxt/bfecIH89.js +1 -0
- package/.output/public/_nuxt/builds/latest.json +1 -1
- package/.output/public/_nuxt/builds/meta/31ca2be4-a949-4df6-9818-773fc085557a.json +1 -0
- package/.output/public/_nuxt/entry.BAvBQY-h.css +1 -0
- package/.output/public/_nuxt/four-S1Y.js +1 -0
- package/.output/public/_nuxt/{CJFtzlQ4.js → gV2U_Gqd.js} +1 -1
- package/.output/public/_nuxt/{DeY2JkR2.js → lGC893pn.js} +1 -1
- package/.output/public/_nuxt/nOfj-ar8.js +1 -0
- package/.output/public/_nuxt/oKrbs1XK.js +1 -0
- package/.output/public/_nuxt/oSJFAC38.js +1 -0
- package/.output/public/_nuxt/rL4C0HV5.js +1 -0
- package/.output/public/_nuxt/{Dyeqn3aG.js → tQoyVPCE.js} +1 -1
- package/.output/public/_nuxt/{DfgOx_ou.js → uSPCvASp.js} +1 -1
- package/.output/public/_nuxt/{hC_z4G8p.js → wkz5-1SO.js} +1 -1
- package/.output/public/_nuxt/yYlVYKCz.js +34 -0
- package/.output/public/_nuxt/{AbmKWFQQ.js → zv8WdMx0.js} +1 -1
- package/.output/server/chunks/_/scope.mjs +43 -27
- package/.output/server/chunks/_/scope.mjs.map +1 -1
- package/.output/server/chunks/_/users.mjs +1 -1
- package/.output/server/chunks/build/{Breadcrumb-Ak2Lg3oM.mjs → Breadcrumb-3itRZ1uz.mjs} +2 -2
- package/.output/server/chunks/build/Breadcrumb-3itRZ1uz.mjs.map +1 -0
- package/.output/server/chunks/build/{BreadcrumbNav-DO7I_z-n.mjs → BreadcrumbNav-GnjBvXuT.mjs} +2 -2
- package/.output/server/chunks/build/BreadcrumbNav-GnjBvXuT.mjs.map +1 -0
- package/.output/server/chunks/build/{BrowserBadge-MFvBwxmD.mjs → BrowserBadge-DQqJS9CV.mjs} +2 -2
- package/.output/server/chunks/build/BrowserBadge-DQqJS9CV.mjs.map +1 -0
- package/.output/server/chunks/build/{ChartCard-Y1UKwMsf.mjs → ChartCard-D0rzMf-N.mjs} +2 -2
- package/.output/server/chunks/build/ChartCard-D0rzMf-N.mjs.map +1 -0
- package/.output/server/chunks/build/{Checkbox-4Q5d0fa0.mjs → Checkbox-DmRKG-0s.mjs} +3 -3
- package/.output/server/chunks/build/Checkbox-DmRKG-0s.mjs.map +1 -0
- package/.output/server/chunks/build/{CodeBlock-BgE-NSmE.mjs → CodeBlock-DGhKVFad.mjs} +4 -4
- package/.output/server/chunks/build/CodeBlock-DGhKVFad.mjs.map +1 -0
- package/.output/server/chunks/build/{DashboardNavbar-BHmMSPX7.mjs → DashboardNavbar-DCr10nxL.mjs} +2 -2
- package/.output/server/chunks/build/DashboardNavbar-DCr10nxL.mjs.map +1 -0
- package/.output/server/chunks/build/{DashboardSidebarToggle-DCTnHiIv.mjs → DashboardSidebarToggle-8EpBhX0R.mjs} +3 -3
- package/.output/server/chunks/build/DashboardSidebarToggle-8EpBhX0R.mjs.map +1 -0
- package/.output/server/chunks/build/{DataLocationCard-B_YHdzSz.mjs → DataLocationCard-rzS-pgCP.mjs} +5 -5
- package/.output/server/chunks/build/DataLocationCard-rzS-pgCP.mjs.map +1 -0
- package/.output/server/chunks/build/{DiagnosisPanel-CALyEmcJ.mjs → DiagnosisPanel-BWTpoCKy.mjs} +8 -7
- package/.output/server/chunks/build/DiagnosisPanel-BWTpoCKy.mjs.map +1 -0
- package/.output/server/chunks/build/{useAiStatus-CxjMmDDY.mjs → DiagnosisResult-Br3qBLXe.mjs} +10 -32
- package/.output/server/chunks/build/DiagnosisResult-Br3qBLXe.mjs.map +1 -0
- package/.output/server/chunks/build/{DurationValue-D20oGbnc.mjs → DurationValue-CWKfjIF2.mjs} +2 -2
- package/.output/server/chunks/build/DurationValue-CWKfjIF2.mjs.map +1 -0
- package/.output/server/chunks/build/{EntityLinks-BBHWssHH.mjs → EntityLinks-CF0xG3Y8.mjs} +6 -6
- package/.output/server/chunks/build/EntityLinks-CF0xG3Y8.mjs.map +1 -0
- package/.output/server/chunks/build/EnvManagedBadge-UwD2b9v2.mjs +1 -1
- package/.output/server/chunks/build/FeatureUnavailable-CwPms6X_.mjs +83 -0
- package/.output/server/chunks/build/FeatureUnavailable-CwPms6X_.mjs.map +1 -0
- package/.output/server/chunks/build/{FormField-B0HKsdMd.mjs → FormField-e7OnSKPM.mjs} +2 -2
- package/.output/server/chunks/build/FormField-e7OnSKPM.mjs.map +1 -0
- package/.output/server/chunks/build/GetStartedWizard-CB5v1Xzu.mjs +510 -0
- package/.output/server/chunks/build/GetStartedWizard-CB5v1Xzu.mjs.map +1 -0
- package/.output/server/chunks/build/{HelpHint-DrcIv-Oj.mjs → HelpHint-DjGrGFA7.mjs} +3 -3
- package/.output/server/chunks/build/HelpHint-DjGrGFA7.mjs.map +1 -0
- package/.output/server/chunks/build/{LoadingState-C3pBSuOO.mjs → LoadingState-B8v1nWJt.mjs} +3 -3
- package/.output/server/chunks/build/LoadingState-B8v1nWJt.mjs.map +1 -0
- package/.output/server/chunks/build/{CiEnvCard-DB5DvBh1.mjs → MetaStripGroup-dXXa_MzF.mjs} +242 -529
- package/.output/server/chunks/build/MetaStripGroup-dXXa_MzF.mjs.map +1 -0
- package/.output/server/chunks/build/{MiniRunBars-CZMugDrh.mjs → MiniRunBars-fgLMgRUp.mjs} +2 -2
- package/.output/server/chunks/build/MiniRunBars-fgLMgRUp.mjs.map +1 -0
- package/.output/server/chunks/build/{useSettingsNav-DnQKacz8.mjs → NavigationMenu-cqpt11Ce.mjs} +5 -28
- package/.output/server/chunks/build/NavigationMenu-cqpt11Ce.mjs.map +1 -0
- package/.output/server/chunks/build/{OpenInIdeLink-CQWKKChd.mjs → OpenInIdeLink-B9wvQkhy.mjs} +5 -5
- package/.output/server/chunks/build/{OpenInIdeLink-CQWKKChd.mjs.map → OpenInIdeLink-B9wvQkhy.mjs.map} +1 -1
- package/.output/server/chunks/build/{ProjectTestCasesTable-Bo61P5K1.mjs → ProjectTestCasesTable-BwHEtZTz.mjs} +15 -15
- package/.output/server/chunks/build/ProjectTestCasesTable-BwHEtZTz.mjs.map +1 -0
- package/.output/server/chunks/build/{RunReports-DFLv51TX.mjs → RunReports-BDRIWn3o.mjs} +2 -2
- package/.output/server/chunks/build/RunReports-BDRIWn3o.mjs.map +1 -0
- package/.output/server/chunks/build/{RunStatusBadge-FfGb6bkW.mjs → RunStatusBadge-CuTDknRJ.mjs} +2 -2
- package/.output/server/chunks/build/RunStatusBadge-CuTDknRJ.mjs.map +1 -0
- package/.output/server/chunks/build/{SectionCard-CN-v0FZ_.mjs → SectionCard-BW5Lynrr.mjs} +2 -2
- package/.output/server/chunks/build/SectionCard-BW5Lynrr.mjs.map +1 -0
- package/.output/server/chunks/build/{Select-5DK9frQ7.mjs → Select-CVctwpib.mjs} +3 -3
- package/.output/server/chunks/build/Select-CVctwpib.mjs.map +1 -0
- package/.output/server/chunks/build/{SelectMenu-D-2FSqBU.mjs → SelectMenu-XLVBEa11.mjs} +3 -3
- package/.output/server/chunks/build/{SelectMenu-D-2FSqBU.mjs.map → SelectMenu-XLVBEa11.mjs.map} +1 -1
- package/.output/server/chunks/build/{SettingsField-BZfx4ma1.mjs → SettingsField-DvtRvI6O.mjs} +3 -3
- package/.output/server/chunks/build/SettingsField-DvtRvI6O.mjs.map +1 -0
- package/.output/server/chunks/build/{StatTile-D61Vzo6e.mjs → StatTile-DpcVQFVI.mjs} +2 -26
- package/.output/server/chunks/build/StatTile-DpcVQFVI.mjs.map +1 -0
- package/.output/server/chunks/build/StatTileGrid-7zOFUQ6j.mjs +30 -0
- package/.output/server/chunks/build/StatTileGrid-7zOFUQ6j.mjs.map +1 -0
- package/.output/server/chunks/build/{Switch-B5Fp8ULt.mjs → Switch-8zWfwI5B.mjs} +2 -2
- package/.output/server/chunks/build/Switch-8zWfwI5B.mjs.map +1 -0
- package/.output/server/chunks/build/Table-BRk04Hd2.mjs +1 -1
- package/.output/server/chunks/build/{TestCaseHistoryChart-CSi64vVA.mjs → TestCaseHistoryChart-C6t5RrCG.mjs} +2 -2
- package/.output/server/chunks/build/TestCaseHistoryChart-C6t5RrCG.mjs.map +1 -0
- package/.output/server/chunks/build/{TestMetaBadges-D5_yUtIP.mjs → TestMetaBadges-BlyKmfeP.mjs} +1 -1
- package/.output/server/chunks/build/TestMetaBadges-BlyKmfeP.mjs.map +1 -0
- package/.output/server/chunks/build/{TestStatusBar-DX3EhlyP.mjs → TestStatusBar-DhbrM_rQ.mjs} +3 -3
- package/.output/server/chunks/build/TestStatusBar-DhbrM_rQ.mjs.map +1 -0
- package/.output/server/chunks/build/{Textarea-Dv2-lOvW.mjs → Textarea-vkMKVQTJ.mjs} +2 -2
- package/.output/server/chunks/build/Textarea-vkMKVQTJ.mjs.map +1 -0
- package/.output/server/chunks/build/Tooltip-Dv4htNP6.mjs +1 -1
- package/.output/server/chunks/build/{_id_-BdG37K7s.mjs → _id_-2PMH6rl8.mjs} +20 -19
- package/.output/server/chunks/build/_id_-2PMH6rl8.mjs.map +1 -0
- package/.output/server/chunks/build/{_id_-BdJs7BJZ.mjs → _id_-8cGIgeg6.mjs} +1903 -1113
- package/.output/server/chunks/build/_id_-8cGIgeg6.mjs.map +1 -0
- package/.output/server/chunks/build/{_id_-C_uSBiyU.mjs → _id_-CUZ5S6y5.mjs} +29 -29
- package/.output/server/chunks/build/_id_-CUZ5S6y5.mjs.map +1 -0
- package/.output/server/chunks/build/{_id_-BxA6IgWr.mjs → _id_-DMkgWSLZ.mjs} +885 -381
- package/.output/server/chunks/build/_id_-DMkgWSLZ.mjs.map +1 -0
- package/.output/server/chunks/build/{about-BE0UV-8-.mjs → about-D3WXTDro.mjs} +21 -453
- package/.output/server/chunks/build/about-D3WXTDro.mjs.map +1 -0
- package/.output/server/chunks/build/{account-DAfvaD-F.mjs → account-BslDNCoo.mjs} +6 -6
- package/.output/server/chunks/build/account-BslDNCoo.mjs.map +1 -0
- package/.output/server/chunks/build/{ai-Cn05ch0u.mjs → ai-C23R9l94.mjs} +14 -14
- package/.output/server/chunks/build/{ai-Cn05ch0u.mjs.map → ai-C23R9l94.mjs.map} +1 -1
- package/.output/server/chunks/build/{analytics-Bo_B_jko.mjs → analytics-DQHeToK0.mjs} +104 -77
- package/.output/server/chunks/build/analytics-DQHeToK0.mjs.map +1 -0
- package/.output/server/chunks/build/client.precomputed.mjs +1 -1
- package/.output/server/chunks/build/compare-RxHSOdsO.mjs +1 -0
- package/.output/server/chunks/build/{db.client-CQoVTYB9.mjs → db.client-D74DghqX.mjs} +38 -2
- package/.output/server/chunks/build/db.client-D74DghqX.mjs.map +1 -0
- package/.output/server/chunks/build/{default-CbNHaFsy.mjs → default-CeyePZ5I.mjs} +32 -19
- package/.output/server/chunks/build/{default-CbNHaFsy.mjs.map → default-CeyePZ5I.mjs.map} +1 -1
- package/.output/server/chunks/build/{docs-B_llWMxx.mjs → docs-f_bnC75q.mjs} +14 -14
- package/.output/server/chunks/build/{docs-B_llWMxx.mjs.map → docs-f_bnC75q.mjs.map} +1 -1
- package/.output/server/chunks/build/{edit-J0asTFg8.mjs → edit-BOC4zWuH.mjs} +11 -12
- package/.output/server/chunks/build/edit-BOC4zWuH.mjs.map +1 -0
- package/.output/server/chunks/build/{fetch-B4FwBOzu.mjs → fetch-BQg_fhX0.mjs} +32 -4
- package/.output/server/chunks/build/fetch-BQg_fhX0.mjs.map +1 -0
- package/.output/server/chunks/build/{forgot-password-CC__1OnV.mjs → forgot-password-CxuVbGWy.mjs} +4 -3
- package/.output/server/chunks/build/forgot-password-CxuVbGWy.mjs.map +1 -0
- package/.output/server/chunks/build/{import-CS9oylTN.mjs → import-CC27wEIu.mjs} +12 -12
- package/.output/server/chunks/build/import-CC27wEIu.mjs.map +1 -0
- package/.output/server/chunks/build/{index-e9skCi-V.mjs → index-B6PjfyTY.mjs} +39 -537
- package/.output/server/chunks/build/index-B6PjfyTY.mjs.map +1 -0
- package/.output/server/chunks/build/{index-CU2nZhAa.mjs → index-BOK1aJk9.mjs} +2 -1
- package/.output/server/chunks/build/index-BOK1aJk9.mjs.map +1 -0
- package/.output/server/chunks/build/{index-hGHlmyxj.mjs → index-BhS1DuCr.mjs} +117 -76
- package/.output/server/chunks/build/index-BhS1DuCr.mjs.map +1 -0
- package/.output/server/chunks/build/{index-DE45ycdZ.mjs → index-DUmjP3Gr.mjs} +12 -13
- package/.output/server/chunks/build/index-DUmjP3Gr.mjs.map +1 -0
- package/.output/server/chunks/build/index-jvF53f7_.mjs +91 -0
- package/.output/server/chunks/build/index-jvF53f7_.mjs.map +1 -0
- package/.output/server/chunks/build/isValueEqualOrExist-D2qw9YEr.mjs +1 -1
- package/.output/server/chunks/build/{login-Da4u1IlW.mjs → login-CdpOhiP8.mjs} +8 -7
- package/.output/server/chunks/build/login-CdpOhiP8.mjs.map +1 -0
- package/.output/server/chunks/build/{mcp-uhVCCwQM.mjs → mcp-WTeO5WRo.mjs} +193 -10
- package/.output/server/chunks/build/mcp-WTeO5WRo.mjs.map +1 -0
- package/.output/server/chunks/build/{notifications-fx_qnKGA.mjs → notifications-yY6ik-fi.mjs} +9 -9
- package/.output/server/chunks/build/notifications-yY6ik-fi.mjs.map +1 -0
- package/.output/server/chunks/build/{pr-feedback-X6-70iF0.mjs → pr-feedback-Hv2Ydh_6.mjs} +7 -7
- package/.output/server/chunks/build/pr-feedback-Hv2Ydh_6.mjs.map +1 -0
- package/.output/server/chunks/build/{reset-password-BmrUS4ZD.mjs → reset-password-CFtO8A6n.mjs} +4 -3
- package/.output/server/chunks/build/reset-password-CFtO8A6n.mjs.map +1 -0
- package/.output/server/chunks/build/server.mjs +51 -34
- package/.output/server/chunks/build/{settings-CCYe7rsc.mjs → settings-DIpvnY8_.mjs} +10 -8
- package/.output/server/chunks/build/settings-DIpvnY8_.mjs.map +1 -0
- package/.output/server/chunks/build/{settings-metadata-DrEqWcW-.mjs → settings-metadata-DRv9VveS.mjs} +32 -2
- package/.output/server/chunks/build/settings-metadata-DRv9VveS.mjs.map +1 -0
- package/.output/server/chunks/build/setup-Di0UMyWx.mjs +1116 -0
- package/.output/server/chunks/build/setup-Di0UMyWx.mjs.map +1 -0
- package/.output/server/chunks/build/{storage-CJEmviCD.mjs → storage-gAbY1KbQ.mjs} +10 -10
- package/.output/server/chunks/build/storage-gAbY1KbQ.mjs.map +1 -0
- package/.output/server/chunks/build/{tags-DauTe_F-.mjs → tags-DJ80wCqt.mjs} +6 -7
- package/.output/server/chunks/build/tags-DJ80wCqt.mjs.map +1 -0
- package/.output/server/chunks/build/{test-cases-thBbAykw.mjs → test-cases-YP83YlnL.mjs} +18 -18
- package/.output/server/chunks/build/test-cases-YP83YlnL.mjs.map +1 -0
- package/.output/server/chunks/build/test-functions-BwLTxGmM.mjs +550 -0
- package/.output/server/chunks/build/test-functions-BwLTxGmM.mjs.map +1 -0
- package/.output/server/chunks/build/{timeout-hygiene-CbnSaVbK.mjs → timeout-hygiene-RpXDjXTX.mjs} +6 -6
- package/.output/server/chunks/build/timeout-hygiene-RpXDjXTX.mjs.map +1 -0
- package/.output/server/chunks/build/useAiStatus-UR8x-feE.mjs +9 -0
- package/.output/server/chunks/build/useAiStatus-UR8x-feE.mjs.map +1 -0
- package/.output/server/chunks/build/{useCopyRich-RJKhWoyj.mjs → useCopyRich-Cd5Yj_Wy.mjs} +694 -242
- package/.output/server/chunks/build/useCopyRich-Cd5Yj_Wy.mjs.map +1 -0
- package/.output/server/chunks/build/{useDesktopDownload-BepjqxOt.mjs → useDesktopDownload-BmR6ouz2.mjs} +2 -2
- package/.output/server/chunks/build/useDesktopDownload-BmR6ouz2.mjs.map +1 -0
- package/.output/server/chunks/build/{useOpenInIde-BbTnPhFA.mjs → useOpenInIde-DolN3bZ5.mjs} +1 -1
- package/.output/server/chunks/build/useOpenInIde-DolN3bZ5.mjs.map +1 -0
- package/.output/server/chunks/build/useSettingsNav-DfnOFlR_.mjs +19 -0
- package/.output/server/chunks/build/useSettingsNav-DfnOFlR_.mjs.map +1 -0
- package/.output/server/chunks/build/{users-CTUqXyGh.mjs → users-I2K7HXS2.mjs} +6 -7
- package/.output/server/chunks/build/users-I2K7HXS2.mjs.map +1 -0
- package/.output/server/chunks/build/{wasted-time-BNTPIyrC.mjs → wasted-time-DyIk0olc.mjs} +9 -9
- package/.output/server/chunks/build/wasted-time-DyIk0olc.mjs.map +1 -0
- package/.output/server/chunks/nitro/nitro.mjs +1348 -675
- package/.output/server/chunks/nitro/nitro.mjs.map +1 -1
- package/.output/server/chunks/routes/__piwi/session.get.mjs +2 -1
- package/.output/server/chunks/routes/__piwi/session.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/admin/cleanup.delete.mjs +1 -0
- package/.output/server/chunks/routes/api/admin/cleanup.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/admin/stats.get.mjs +1 -0
- package/.output/server/chunks/routes/api/admin/stats.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/ai/status.get.mjs +1 -0
- package/.output/server/chunks/routes/api/ai/status.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/analytics/_widget_.get.mjs +1 -0
- package/.output/server/chunks/routes/api/analytics/_widget_.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/auth/logout.post.mjs +1 -0
- package/.output/server/chunks/routes/api/auth/logout.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/auth/me.get.mjs +1 -0
- package/.output/server/chunks/routes/api/auth/me.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/auth/oauth/_provider/callback.get.mjs +1 -0
- package/.output/server/chunks/routes/api/auth/oauth/_provider/callback.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/auth/oauth/_provider/login.get.mjs +1 -0
- package/.output/server/chunks/routes/api/auth/oauth/_provider/login.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/auth/oauth/_provider/unlink.post.mjs +1 -0
- package/.output/server/chunks/routes/api/auth/oauth/_provider/unlink.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/auth/send-verify-email.post.mjs +1 -0
- package/.output/server/chunks/routes/api/auth/send-verify-email.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/auth/setup.get.mjs +1 -0
- package/.output/server/chunks/routes/api/auth/setup.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/auth/verify-email.get.mjs +1 -0
- package/.output/server/chunks/routes/api/auth/verify-email.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/channels/_id/test.post.mjs +1 -0
- package/.output/server/chunks/routes/api/channels/_id/test.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/channels/_id_.delete.mjs +1 -0
- package/.output/server/chunks/routes/api/channels/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/cluster-merge-suggestions/_id/approve.post.mjs +1 -0
- package/.output/server/chunks/routes/api/cluster-merge-suggestions/_id/approve.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/cluster-merge-suggestions/_id/reject.post.mjs +1 -0
- package/.output/server/chunks/routes/api/cluster-merge-suggestions/_id/reject.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/desktop/import-local.post.mjs +1 -0
- package/.output/server/chunks/routes/api/desktop/import-local.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/desktop/reporter-config.get.mjs +1 -0
- package/.output/server/chunks/routes/api/desktop/reporter-config.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/failure-clusters/_id/base-commit.patch.mjs +1 -0
- package/.output/server/chunks/routes/api/failure-clusters/_id/base-commit.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/failure-clusters/_id/branches.get.mjs +1 -0
- package/.output/server/chunks/routes/api/failure-clusters/_id/branches.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/failure-clusters/_id/commit-diff.get.mjs +1 -0
- package/.output/server/chunks/routes/api/failure-clusters/_id/commit-diff.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/failure-clusters/_id/commits.get.mjs +1 -0
- package/.output/server/chunks/routes/api/failure-clusters/_id/commits.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/failure-clusters/_id/context.get.mjs +1 -0
- package/.output/server/chunks/routes/api/failure-clusters/_id/context.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/failure-clusters/_id/diagnose/stream.post.mjs +1 -0
- package/.output/server/chunks/routes/api/failure-clusters/_id/diagnose/stream.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/failure-clusters/_id/diagnose.post.mjs +1 -0
- package/.output/server/chunks/routes/api/failure-clusters/_id/diagnose.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/failure-clusters/_id/diagnoses.get.mjs +1 -0
- package/.output/server/chunks/routes/api/failure-clusters/_id/diagnoses.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/failure-clusters/_id/diagnosis.get.mjs +1 -0
- package/.output/server/chunks/routes/api/failure-clusters/_id/diagnosis.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/failure-clusters/_id/export.get.mjs +1 -0
- package/.output/server/chunks/routes/api/failure-clusters/_id/export.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/failure-clusters/_id/extract-cases.post.mjs +1 -0
- package/.output/server/chunks/routes/api/failure-clusters/_id/extract-cases.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/failure-clusters/_id/fix-plan.get.mjs +1 -0
- package/.output/server/chunks/routes/api/failure-clusters/_id/fix-plan.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/failure-clusters/_id/status.patch.mjs +1 -0
- package/.output/server/chunks/routes/api/failure-clusters/_id/status.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/failure-clusters/_id_.get.mjs +1 -0
- package/.output/server/chunks/routes/api/failure-clusters/_id_.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/failure-diagnoses/_id/feedback.patch.mjs +1 -0
- package/.output/server/chunks/routes/api/failure-diagnoses/_id/feedback.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/files/_...path_.get.mjs +1 -0
- package/.output/server/chunks/routes/api/files/_...path_.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/health.get.mjs +1 -0
- package/.output/server/chunks/routes/api/health.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/index.get.mjs +1 -0
- package/.output/server/chunks/routes/api/index.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/index.get2.mjs +1 -0
- package/.output/server/chunks/routes/api/index.get2.mjs.map +1 -1
- package/.output/server/chunks/routes/api/index.get3.mjs +1 -0
- package/.output/server/chunks/routes/api/index.get3.mjs.map +1 -1
- package/.output/server/chunks/routes/api/index.get4.mjs +2 -1
- package/.output/server/chunks/routes/api/index.get4.mjs.map +1 -1
- package/.output/server/chunks/routes/api/index.get5.mjs +1 -0
- package/.output/server/chunks/routes/api/index.get5.mjs.map +1 -1
- package/.output/server/chunks/routes/api/index.post3.mjs +1 -1
- package/.output/server/chunks/routes/api/index.post4.mjs +1 -1
- package/.output/server/chunks/routes/api/index.post5.mjs +1 -1
- package/.output/server/chunks/routes/api/links/_id/refresh.post.mjs +1 -0
- package/.output/server/chunks/routes/api/links/_id/refresh.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/links/_id_.delete.mjs +1 -0
- package/.output/server/chunks/routes/api/links/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/markers/_id_.delete.mjs +1 -0
- package/.output/server/chunks/routes/api/markers/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/notifications/stream.get.mjs +1 -0
- package/.output/server/chunks/routes/api/notifications/stream.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/projects/_id/cluster-merge-suggestions.get.mjs +1 -0
- package/.output/server/chunks/routes/api/projects/_id/cluster-merge-suggestions.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/projects/_id/failure-clusters.get.mjs +1 -0
- package/.output/server/chunks/routes/api/projects/_id/failure-clusters.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/projects/_id/flaky-classify.post.mjs +1 -0
- package/.output/server/chunks/routes/api/projects/_id/flaky-classify.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/projects/_id/flaky-tests.get.mjs +1 -0
- package/.output/server/chunks/routes/api/projects/_id/flaky-tests.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/projects/_id/latest-run.get.mjs +1 -0
- package/.output/server/chunks/routes/api/projects/_id/latest-run.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/projects/_id/markers.get.mjs +1 -0
- package/.output/server/chunks/routes/api/projects/_id/markers.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/projects/_id/members.get.mjs +1 -0
- package/.output/server/chunks/routes/api/projects/_id/members.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/projects/_id/performance.get.mjs +1 -0
- package/.output/server/chunks/routes/api/projects/_id/performance.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/projects/_id/quarantine/_testCaseId_.delete.mjs +1 -0
- package/.output/server/chunks/routes/api/projects/_id/quarantine/_testCaseId_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/projects/_id/quarantine.get.mjs +1 -0
- package/.output/server/chunks/routes/api/projects/_id/quarantine.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/projects/_id/quarantine.post.mjs +1 -0
- package/.output/server/chunks/routes/api/projects/_id/quarantine.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/projects/_id/slow-tests.get.mjs +1 -0
- package/.output/server/chunks/routes/api/projects/_id/slow-tests.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/projects/_id/spec-health.get.mjs +1 -0
- package/.output/server/chunks/routes/api/projects/_id/spec-health.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/projects/_id/test-cases.get.mjs +1 -0
- package/.output/server/chunks/routes/api/projects/_id/test-cases.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/projects/_id/test-functions/extract.post.mjs +76 -0
- package/.output/server/chunks/routes/api/projects/_id/test-functions/extract.post.mjs.map +1 -0
- package/.output/server/chunks/routes/api/projects/_id/test-functions/validate-proposal.post.mjs +66 -0
- package/.output/server/chunks/routes/api/projects/_id/test-functions/validate-proposal.post.mjs.map +1 -0
- package/.output/server/chunks/routes/api/projects/_id/test-functions.get.mjs +53 -0
- package/.output/server/chunks/routes/api/projects/_id/test-functions.get.mjs.map +1 -0
- package/.output/server/chunks/routes/api/projects/_id/test-functions.post.mjs +67 -0
- package/.output/server/chunks/routes/api/projects/_id/test-functions.post.mjs.map +1 -0
- package/.output/server/chunks/routes/api/projects/_id/timeout-opportunities.get.mjs +2 -1
- package/.output/server/chunks/routes/api/projects/_id/timeout-opportunities.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/projects/_id_.delete.mjs +1 -0
- package/.output/server/chunks/routes/api/projects/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/projects/_id_.get.mjs +1 -0
- package/.output/server/chunks/routes/api/projects/_id_.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/projects/menu.get.mjs +2 -1
- package/.output/server/chunks/routes/api/projects/menu.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/projects/overview.get.mjs +2 -1
- package/.output/server/chunks/routes/api/projects/overview.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/projects.get.mjs +1 -0
- package/.output/server/chunks/routes/api/projects.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/search.get.mjs +2 -1
- package/.output/server/chunks/routes/api/search.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/settings/ai/limits.get.mjs +2 -1
- package/.output/server/chunks/routes/api/settings/ai/limits.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/settings/ai/limits.put.mjs +2 -1
- package/.output/server/chunks/routes/api/settings/ai/limits.put.mjs.map +1 -1
- package/.output/server/chunks/routes/api/settings/ai/models.post.mjs +1 -0
- package/.output/server/chunks/routes/api/settings/ai/models.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/settings/ai/test.post.mjs +2 -1
- package/.output/server/chunks/routes/api/settings/ai/test.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/settings/ai/usage.get.mjs +1 -0
- package/.output/server/chunks/routes/api/settings/ai/usage.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/settings/ai.get.mjs +2 -1
- package/.output/server/chunks/routes/api/settings/ai.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/settings/ai.put.mjs +2 -1
- package/.output/server/chunks/routes/api/settings/ai.put.mjs.map +1 -1
- package/.output/server/chunks/routes/api/settings/pr-feedback.get.mjs +2 -1
- package/.output/server/chunks/routes/api/settings/pr-feedback.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/settings/pr-feedback.put.mjs +2 -1
- package/.output/server/chunks/routes/api/settings/pr-feedback.put.mjs.map +1 -1
- package/.output/server/chunks/routes/api/settings/smtp.get.mjs +2 -1
- package/.output/server/chunks/routes/api/settings/smtp.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/settings/timeout-hygiene.get.mjs +2 -1
- package/.output/server/chunks/routes/api/settings/timeout-hygiene.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/settings/timeout-hygiene.put.mjs +2 -1
- package/.output/server/chunks/routes/api/settings/timeout-hygiene.put.mjs.map +1 -1
- package/.output/server/chunks/routes/api/settings/wasted-waits.get.mjs +2 -1
- package/.output/server/chunks/routes/api/settings/wasted-waits.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/settings/wasted-waits.put.mjs +2 -1
- package/.output/server/chunks/routes/api/settings/wasted-waits.put.mjs.map +1 -1
- package/.output/server/chunks/routes/api/setup-status.get.mjs +99 -0
- package/.output/server/chunks/routes/api/setup-status.get.mjs.map +1 -0
- package/.output/server/chunks/routes/api/stream.get.mjs +1 -0
- package/.output/server/chunks/routes/api/stream.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/subscriptions/_id_.delete.mjs +1 -0
- package/.output/server/chunks/routes/api/subscriptions/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/subscriptions/_id_.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/tags/_id_.delete.mjs +2 -1
- package/.output/server/chunks/routes/api/tags/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/tags/_id_.put.mjs +1 -1
- package/.output/server/chunks/routes/api/test-cases/_id/history.get.mjs +2 -1
- package/.output/server/chunks/routes/api/test-cases/_id/history.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/test-cases/_id/stability-trend.get.mjs +2 -1
- package/.output/server/chunks/routes/api/test-cases/_id/stability-trend.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/test-cases/_id_.get.mjs +2 -1
- package/.output/server/chunks/routes/api/test-cases/_id_.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/test-functions/_id_.delete.mjs +60 -0
- package/.output/server/chunks/routes/api/test-functions/_id_.delete.mjs.map +1 -0
- package/.output/server/chunks/routes/api/test-functions/_id_.put.mjs +69 -0
- package/.output/server/chunks/routes/api/test-functions/_id_.put.mjs.map +1 -0
- package/.output/server/chunks/routes/api/test-run-cases/_id/diagnose.post.mjs +2 -1
- package/.output/server/chunks/routes/api/test-run-cases/_id/diagnose.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/test-run-cases/_id/diagnosis-context.get.mjs +2 -1
- package/.output/server/chunks/routes/api/test-run-cases/_id/diagnosis-context.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/test-run-cases/_id/diagnosis.get.mjs +2 -1
- package/.output/server/chunks/routes/api/test-run-cases/_id/diagnosis.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/test-run-cases/_id/export.get.mjs +2 -1
- package/.output/server/chunks/routes/api/test-run-cases/_id/export.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/test-run-cases/_id/traces.get.mjs +2 -1
- package/.output/server/chunks/routes/api/test-run-cases/_id/traces.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/test-run-cases/_id_.get.mjs +2 -1
- package/.output/server/chunks/routes/api/test-run-cases/_id_.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/test-runs/_id/begin.post.mjs +2 -1
- package/.output/server/chunks/routes/api/test-runs/_id/begin.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/test-runs/_id/case-files.post.mjs +2 -1
- package/.output/server/chunks/routes/api/test-runs/_id/case-files.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/test-runs/_id/cases/_caseId/dom-snapshot.get.mjs +2 -1
- package/.output/server/chunks/routes/api/test-runs/_id/cases/_caseId/dom-snapshot.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/test-runs/_id/cases/_caseId/environment-diff.get.mjs +2 -1
- package/.output/server/chunks/routes/api/test-runs/_id/cases/_caseId/environment-diff.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/test-runs/_id/cases/_caseId/locator-healing.get.mjs +2 -1
- package/.output/server/chunks/routes/api/test-runs/_id/cases/_caseId/locator-healing.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/test-runs/_id/cases/_caseId/locator-pick.post.mjs +2 -1
- package/.output/server/chunks/routes/api/test-runs/_id/cases/_caseId/locator-pick.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/test-runs/_id/cases/_caseId/trace-network-body.get.mjs +2 -1
- package/.output/server/chunks/routes/api/test-runs/_id/cases/_caseId/trace-network-body.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/test-runs/_id/cases/_caseId/trace-network.get.mjs +2 -1
- package/.output/server/chunks/routes/api/test-runs/_id/cases/_caseId/trace-network.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/test-runs/_id/cases/_caseId/trace-stacks.get.mjs +2 -1
- package/.output/server/chunks/routes/api/test-runs/_id/cases/_caseId/trace-stacks.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/test-runs/_id/cases/_caseId/visual-diff.get.mjs +2 -1
- package/.output/server/chunks/routes/api/test-runs/_id/cases/_caseId/visual-diff.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/test-runs/_id/events.post.mjs +2 -1
- package/.output/server/chunks/routes/api/test-runs/_id/events.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/test-runs/_id/failure-groups.get.mjs +2 -1
- package/.output/server/chunks/routes/api/test-runs/_id/failure-groups.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/test-runs/_id/finish.post.mjs +2 -1
- package/.output/server/chunks/routes/api/test-runs/_id/finish.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/test-runs/_id/gate.post.mjs +2 -1
- package/.output/server/chunks/routes/api/test-runs/_id/gate.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/test-runs/_id/heartbeat.post.mjs +2 -1
- package/.output/server/chunks/routes/api/test-runs/_id/heartbeat.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/test-runs/_id/insights.get.mjs +2 -1
- package/.output/server/chunks/routes/api/test-runs/_id/insights.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/test-runs/_id/network-requests.get.mjs +2 -1
- package/.output/server/chunks/routes/api/test-runs/_id/network-requests.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/test-runs/_id/regression-context.get.mjs +2 -1
- package/.output/server/chunks/routes/api/test-runs/_id/regression-context.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/test-runs/_id/stream.get.mjs +2 -1
- package/.output/server/chunks/routes/api/test-runs/_id/stream.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/test-runs/_id/summary.get.mjs +2 -1
- package/.output/server/chunks/routes/api/test-runs/_id/summary.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/test-runs/_id_.delete.mjs +2 -1
- package/.output/server/chunks/routes/api/test-runs/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/test-runs/_id_.get.mjs +2 -1
- package/.output/server/chunks/routes/api/test-runs/_id_.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/test-runs/_id_.patch.mjs +2 -1
- package/.output/server/chunks/routes/api/test-runs/_id_.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/test-runs/import/check.post.mjs +2 -1
- package/.output/server/chunks/routes/api/test-runs/import/check.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/test-runs/import.post.mjs +2 -1
- package/.output/server/chunks/routes/api/test-runs/import.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/test-runs/recent.get.mjs +2 -1
- package/.output/server/chunks/routes/api/test-runs/recent.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/test-runs/setup.post.mjs +2 -1
- package/.output/server/chunks/routes/api/test-runs/setup.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/test-runs/start.post.mjs +2 -1
- package/.output/server/chunks/routes/api/test-runs/start.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/test-runs/submit.post.mjs +2 -1
- package/.output/server/chunks/routes/api/test-runs/submit.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/test-runs/upload.post.mjs +2 -1
- package/.output/server/chunks/routes/api/test-runs/upload.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/tests/cleanup.delete.mjs +1 -0
- package/.output/server/chunks/routes/api/tests/cleanup.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/traces/check.post.mjs +2 -1
- package/.output/server/chunks/routes/api/traces/check.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/users/_id/api-keys/_keyId_.delete.mjs +1 -0
- package/.output/server/chunks/routes/api/users/_id/api-keys/_keyId_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/users/_id/index.get.mjs +1 -0
- package/.output/server/chunks/routes/api/users/_id/index.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/users/_id/index.post.mjs +1 -1
- package/.output/server/chunks/routes/api/users/_id/invite.post.mjs +2 -1
- package/.output/server/chunks/routes/api/users/_id/invite.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/users/_id/projects.get.mjs +2 -1
- package/.output/server/chunks/routes/api/users/_id/projects.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/users/_id/projects.put.mjs +1 -1
- package/.output/server/chunks/routes/api/users/_id_.delete.mjs +1 -0
- package/.output/server/chunks/routes/api/users/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/version.get.mjs +2 -1
- package/.output/server/chunks/routes/api/version.get.mjs.map +1 -1
- package/.output/server/chunks/routes/mcp.post.mjs +41 -11
- package/.output/server/chunks/routes/mcp.post.mjs.map +1 -1
- package/.output/server/chunks/routes/renderer.mjs +1 -1
- package/.output/server/chunks/tasks/sweep.mjs +1 -0
- package/.output/server/chunks/tasks/sweep.mjs.map +1 -1
- package/.output/server/chunks/tasks/sweep2.mjs +1 -0
- package/.output/server/chunks/tasks/sweep2.mjs.map +1 -1
- package/.output/server/database/migrations/0043_watery_dragon_lord.sql +22 -0
- package/.output/server/database/migrations/meta/0043_snapshot.json +3764 -0
- package/.output/server/database/migrations/meta/_journal.json +7 -0
- package/.output/server/database/migrations-pg/0044_dark_triathlon.sql +22 -0
- package/.output/server/database/migrations-pg/meta/0044_snapshot.json +4473 -0
- package/.output/server/database/migrations-pg/meta/_journal.json +7 -0
- package/.output/server/index.mjs +2 -1
- package/.output/server/index.mjs.map +1 -1
- package/.output/server/package.json +1 -1
- package/package.json +1 -1
- package/.output/public/_nuxt/8PUUncmO.js +0 -44
- package/.output/public/_nuxt/B8zkOmwo.js +0 -1
- package/.output/public/_nuxt/B96M2gdj.js +0 -1
- package/.output/public/_nuxt/B9OLmp0f.js +0 -1
- package/.output/public/_nuxt/BUa0V0Ly.js +0 -1
- package/.output/public/_nuxt/BUkim3TM.js +0 -1
- package/.output/public/_nuxt/BVc14Ncz.js +0 -4
- package/.output/public/_nuxt/BY0HxR3t.js +0 -17
- package/.output/public/_nuxt/B_xAMWQS.js +0 -2
- package/.output/public/_nuxt/BdQoBaOv.js +0 -1
- package/.output/public/_nuxt/BgRu_3tT.js +0 -1
- package/.output/public/_nuxt/BiO7RBWb.js +0 -6
- package/.output/public/_nuxt/CEfS4-oS.js +0 -64
- package/.output/public/_nuxt/CIoSMkpp.js +0 -1
- package/.output/public/_nuxt/CSJ-eOQM.js +0 -1
- package/.output/public/_nuxt/CahpB9Z2.js +0 -5
- package/.output/public/_nuxt/Cbh--1MW.js +0 -1
- package/.output/public/_nuxt/Cx6gc2VW.js +0 -1
- package/.output/public/_nuxt/D--H4jLI.js +0 -1
- package/.output/public/_nuxt/D1POo6S4.js +0 -10
- package/.output/public/_nuxt/D8nkF-OO.js +0 -3
- package/.output/public/_nuxt/DA25RkyK.js +0 -1
- package/.output/public/_nuxt/DIB-5fUJ.js +0 -1
- package/.output/public/_nuxt/DMec-OLo.js +0 -1
- package/.output/public/_nuxt/DSqHUrvO.js +0 -1
- package/.output/public/_nuxt/DmkUdSS4.js +0 -1
- package/.output/public/_nuxt/DoIREDVb.js +0 -1
- package/.output/public/_nuxt/DpZ1r1HA.js +0 -1
- package/.output/public/_nuxt/DqcKngf3.js +0 -1
- package/.output/public/_nuxt/DtHJgCS8.js +0 -1
- package/.output/public/_nuxt/Dtd4rC58.js +0 -9
- package/.output/public/_nuxt/Dy86h-7P.js +0 -1
- package/.output/public/_nuxt/HPNQD6v3.js +0 -1
- package/.output/public/_nuxt/HXadJrHu.js +0 -2
- package/.output/public/_nuxt/McL25vkx.js +0 -34
- package/.output/public/_nuxt/Nn93e_Mz.js +0 -1
- package/.output/public/_nuxt/UdR3DBPS.js +0 -1
- package/.output/public/_nuxt/_mj6CfPa.js +0 -1
- package/.output/public/_nuxt/builds/meta/e659b3e1-0e61-4971-940e-10063f9f4763.json +0 -1
- package/.output/public/_nuxt/entry.DmptwB51.css +0 -1
- package/.output/public/_nuxt/ryMzSDUj.js +0 -2
- package/.output/server/chunks/build/Breadcrumb-Ak2Lg3oM.mjs.map +0 -1
- package/.output/server/chunks/build/BreadcrumbNav-DO7I_z-n.mjs.map +0 -1
- package/.output/server/chunks/build/BrowserBadge-MFvBwxmD.mjs.map +0 -1
- package/.output/server/chunks/build/ChartCard-Y1UKwMsf.mjs.map +0 -1
- package/.output/server/chunks/build/Checkbox-4Q5d0fa0.mjs.map +0 -1
- package/.output/server/chunks/build/CiEnvCard-DB5DvBh1.mjs.map +0 -1
- package/.output/server/chunks/build/CodeBlock-BgE-NSmE.mjs.map +0 -1
- package/.output/server/chunks/build/DashboardNavbar-BHmMSPX7.mjs.map +0 -1
- package/.output/server/chunks/build/DashboardSidebarToggle-DCTnHiIv.mjs.map +0 -1
- package/.output/server/chunks/build/DataLocationCard-B_YHdzSz.mjs.map +0 -1
- package/.output/server/chunks/build/DiagnosisPanel-CALyEmcJ.mjs.map +0 -1
- package/.output/server/chunks/build/DurationValue-D20oGbnc.mjs.map +0 -1
- package/.output/server/chunks/build/EntityLinks-BBHWssHH.mjs.map +0 -1
- package/.output/server/chunks/build/FormField-B0HKsdMd.mjs.map +0 -1
- package/.output/server/chunks/build/HelpHint-DrcIv-Oj.mjs.map +0 -1
- package/.output/server/chunks/build/LoadingState-C3pBSuOO.mjs.map +0 -1
- package/.output/server/chunks/build/MiniRunBars-CZMugDrh.mjs.map +0 -1
- package/.output/server/chunks/build/ProjectTestCasesTable-Bo61P5K1.mjs.map +0 -1
- package/.output/server/chunks/build/RunReports-DFLv51TX.mjs.map +0 -1
- package/.output/server/chunks/build/RunStatusBadge-FfGb6bkW.mjs.map +0 -1
- package/.output/server/chunks/build/SectionCard-CN-v0FZ_.mjs.map +0 -1
- package/.output/server/chunks/build/Select-5DK9frQ7.mjs.map +0 -1
- package/.output/server/chunks/build/SettingsField-BZfx4ma1.mjs.map +0 -1
- package/.output/server/chunks/build/StatTile-D61Vzo6e.mjs.map +0 -1
- package/.output/server/chunks/build/Switch-B5Fp8ULt.mjs.map +0 -1
- package/.output/server/chunks/build/TestCaseHistoryChart-CSi64vVA.mjs.map +0 -1
- package/.output/server/chunks/build/TestMetaBadges-D5_yUtIP.mjs.map +0 -1
- package/.output/server/chunks/build/TestStatusBar-DX3EhlyP.mjs.map +0 -1
- package/.output/server/chunks/build/Textarea-Dv2-lOvW.mjs.map +0 -1
- package/.output/server/chunks/build/_id_-BdG37K7s.mjs.map +0 -1
- package/.output/server/chunks/build/_id_-BdJs7BJZ.mjs.map +0 -1
- package/.output/server/chunks/build/_id_-BxA6IgWr.mjs.map +0 -1
- package/.output/server/chunks/build/_id_-C_uSBiyU.mjs.map +0 -1
- package/.output/server/chunks/build/about-BE0UV-8-.mjs.map +0 -1
- package/.output/server/chunks/build/account-DAfvaD-F.mjs.map +0 -1
- package/.output/server/chunks/build/analytics-Bo_B_jko.mjs.map +0 -1
- package/.output/server/chunks/build/db.client-CQoVTYB9.mjs.map +0 -1
- package/.output/server/chunks/build/edit-J0asTFg8.mjs.map +0 -1
- package/.output/server/chunks/build/fetch-B4FwBOzu.mjs.map +0 -1
- package/.output/server/chunks/build/forgot-password-CC__1OnV.mjs.map +0 -1
- package/.output/server/chunks/build/import-CS9oylTN.mjs.map +0 -1
- package/.output/server/chunks/build/index-CU2nZhAa.mjs.map +0 -1
- package/.output/server/chunks/build/index-DE45ycdZ.mjs.map +0 -1
- package/.output/server/chunks/build/index-e9skCi-V.mjs.map +0 -1
- package/.output/server/chunks/build/index-hGHlmyxj.mjs.map +0 -1
- package/.output/server/chunks/build/index-tR6owKzj.mjs +0 -167
- package/.output/server/chunks/build/index-tR6owKzj.mjs.map +0 -1
- package/.output/server/chunks/build/login-Da4u1IlW.mjs.map +0 -1
- package/.output/server/chunks/build/mcp-uhVCCwQM.mjs.map +0 -1
- package/.output/server/chunks/build/notifications-fx_qnKGA.mjs.map +0 -1
- package/.output/server/chunks/build/pr-feedback-X6-70iF0.mjs.map +0 -1
- package/.output/server/chunks/build/reset-password-BmrUS4ZD.mjs.map +0 -1
- package/.output/server/chunks/build/settings-CCYe7rsc.mjs.map +0 -1
- package/.output/server/chunks/build/settings-metadata-DrEqWcW-.mjs.map +0 -1
- package/.output/server/chunks/build/storage-CJEmviCD.mjs.map +0 -1
- package/.output/server/chunks/build/tags-DauTe_F-.mjs.map +0 -1
- package/.output/server/chunks/build/test-cases-thBbAykw.mjs.map +0 -1
- package/.output/server/chunks/build/timeout-hygiene-CbnSaVbK.mjs.map +0 -1
- package/.output/server/chunks/build/useAiStatus-CxjMmDDY.mjs.map +0 -1
- package/.output/server/chunks/build/useCopy-CeKWgHyT.mjs +0 -33
- package/.output/server/chunks/build/useCopy-CeKWgHyT.mjs.map +0 -1
- package/.output/server/chunks/build/useCopyRich-RJKhWoyj.mjs.map +0 -1
- package/.output/server/chunks/build/useDesktopDownload-BepjqxOt.mjs.map +0 -1
- package/.output/server/chunks/build/useOpenInIde-BbTnPhFA.mjs.map +0 -1
- package/.output/server/chunks/build/useSettingsNav-DnQKacz8.mjs.map +0 -1
- package/.output/server/chunks/build/users-CTUqXyGh.mjs.map +0 -1
- package/.output/server/chunks/build/wasted-time-BNTPIyrC.mjs.map +0 -1
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import{d as te,b as Je,o as n,f as P,g as C,j as k,_ as Ae,m as z,i as u,k as t,l as ze,r as U,J as gt,h as S,A as Re,c,O as ht,V as Oe,ae as vt,S as pe,C as ge,p as ve,q as ae,v as $,t as v,F as H,K as yt,y as se,s as Be,E as st,H as Ee,af as Le,B as at,I as xt,Q as Xe,G as We,ac as Ie,D as bt,W as je,ag as Se,T as kt,ad as _t,ah as $t,ai as wt,aj as Ct,a0 as St,a1 as Tt}from"./Du2W7Jne.js";import{_ as rt,a as Lt}from"./Bm62iDV5.js";import{_ as zt}from"./Dy-TJ0Mt.js";import{u as It}from"./BgRu_3tT.js";import{u as He}from"./DSqHUrvO.js";import{g as it,u as At,v as Rt,f as Ge,w as lt,n as Ue,x as Bt}from"./DuwtTfO8.js";import{_ as Ye}from"./BrQEE053.js";import{_ as Ne}from"./C0_yH0N7.js";import{_ as Pt}from"./BUkim3TM.js";import{u as Me}from"./B8zkOmwo.js";import{_ as Et}from"./CxyAzHr3.js";import{_ as Ot}from"./BT3wGCTI.js";import{_ as Ut}from"./B3obW6cw.js";import{k as jt,i as Mt,b as Nt}from"./Cnsmicv2.js";import{f as Kt}from"./D-c8ZSws.js";import{_ as ct}from"./DJmoLeVt.js";import{_ as Dt}from"./-f7BAm1H.js";const Vt={class:"w-64 p-1 space-y-0.5"},Ht={class:"flex items-center justify-between px-2 pt-1 pb-1"},Ft=te({__name:"ExportMenu",props:{endpoint:{},baseName:{}},setup(e){const r=e,{download:i}=It(),{copy:d}=He(),s=Je(),a=U(!1),o=U(""),p=S(()=>(Re().app?.baseURL??"/").replace(/\/$/,""));function l(L){return`${p.value}${L}`}async function g(L){a.value=!1,await i(l(`${r.endpoint}?format=${L}`),`${r.baseName}.${L}`,{binary:L==="zip"})}function T(){a.value=!1,window.open(l(`${r.endpoint}?format=html&print=1`),"_blank")}async function I(L,x,A){o.value=x;try{const j=await fetch(l(L));if(!j.ok)throw new Error(`Request failed (${j.status})`);const D=await j.text();d(A?A(D):D,{toast:`${x} copied`}),a.value=!1}catch(j){s.add({title:`Could not copy ${x.toLowerCase()}`,description:it(j),color:"error"})}finally{o.value=""}}function b(){return I(`${r.endpoint}?format=md`,"Report")}return(L,x)=>{const A=Ae,j=rt,D=zt,E=gt;return n(),P(E,{open:t(a),"onUpdate:open":x[4]||(x[4]=B=>ze(a)?a.value=B:null)},{content:C(()=>[u("div",Vt,[u("div",Ht,[x[6]||(x[6]=u("p",{class:"text-xs font-medium text-gray-500"},"Download",-1)),k(j,{topic:"export.offline"})]),k(A,{block:"",size:"sm",color:"neutral",variant:"ghost",class:"justify-start",icon:"i-lucide-file-code",title:"One self-contained HTML file with screenshots and video embedded",onClick:x[0]||(x[0]=B=>g("html"))},{default:C(()=>[...x[7]||(x[7]=[z(" HTML — single file ",-1)])]),_:1}),k(A,{block:"",size:"sm",color:"neutral",variant:"ghost",class:"justify-start",icon:"i-lucide-file-archive",title:"Report plus the raw artifacts, including trace archives and data.json",onClick:x[1]||(x[1]=B=>g("zip"))},{default:C(()=>[...x[8]||(x[8]=[z(" ZIP — with all evidence ",-1)])]),_:1}),k(A,{block:"",size:"sm",color:"neutral",variant:"ghost",class:"justify-start",icon:"i-lucide-printer",title:"Opens the report with your browser's print dialog, for Save as PDF",onClick:T},{default:C(()=>[...x[9]||(x[9]=[z(" PDF — via print ",-1)])]),_:1}),k(A,{block:"",size:"sm",color:"neutral",variant:"ghost",class:"justify-start",icon:"i-lucide-file-text",title:"The Markdown report as a file",onClick:x[2]||(x[2]=B=>g("md"))},{default:C(()=>[...x[10]||(x[10]=[z(" Markdown ",-1)])]),_:1}),k(A,{block:"",size:"sm",color:"neutral",variant:"ghost",class:"justify-start",icon:"i-lucide-file-json",title:"Everything the report contains, machine-readable",onClick:x[3]||(x[3]=B=>g("json"))},{default:C(()=>[...x[11]||(x[11]=[z(" JSON ",-1)])]),_:1}),k(D,{class:"my-1"}),x[13]||(x[13]=u("p",{class:"text-xs font-medium text-gray-500 px-2 pt-1 pb-1"},"Copy to clipboard",-1)),k(A,{block:"",size:"sm",color:"neutral",variant:"ghost",class:"justify-start",icon:"i-lucide-clipboard-list",loading:t(o)==="Report",title:"The whole investigation as Markdown, for an issue or a chat",onClick:b},{default:C(()=>[...x[12]||(x[12]=[z(" Report (Markdown) ",-1)])]),_:1},8,["loading"])])]),default:C(()=>[k(A,{icon:"i-lucide-share",size:"xs",color:"neutral",variant:"outline",title:"Take this investigation away"},{default:C(()=>[...x[5]||(x[5]=[z(" Export ",-1)])]),_:1})]),_:1},8,["open"])}}}),Ba=Object.assign(Ft,{__name:"ExportMenu"}),qt={class:"flex items-center justify-between gap-2"},Zt=["aria-expanded","title"],Wt={class:"text-lg font-medium inline-flex items-center gap-1 shrink-0"},Jt={key:2,class:"min-w-0 flex-1 truncate text-sm text-gray-500 dark:text-gray-400"},Gt={key:0,class:"flex items-center gap-1 shrink-0"},Yt={key:0,class:"text-sm text-gray-500 mt-1 ml-11"},Qt=te({__name:"CollapsibleSectionCard",props:{title:{},icon:{},subtitle:{},count:{},iconClass:{default:"text-primary"},help:{},storageKey:{},defaultFolded:{type:Boolean,default:!0}},setup(e,{expose:r}){const i=e,{folded:d,toggle:s,setFolded:a}=jt(`piwi-section-fold-${i.storageKey}`,i.defaultFolded),o=U(null);function p(){a(!1),yt(()=>o.value?.scrollIntoView({behavior:"smooth",block:"start"}))}return r({setFolded:a,reveal:p}),(l,g)=>{const T=ve,I=rt,b=Dt;return n(),c("div",{ref_key:"rootEl",ref:o,class:"scroll-mt-4"},[k(b,{ui:{header:"p-3 sm:px-4 sm:py-3",body:t(d)?"p-0 sm:p-0":""},class:ae(t(d)&&"divide-y-0")},{header:C(()=>[u("div",qt,[u("div",{class:"flex items-center gap-2 min-w-0 flex-1 cursor-pointer select-none rounded-sm outline-none focus-visible:outline-2 focus-visible:outline-primary",role:"button",tabindex:"0","aria-expanded":!t(d),title:t(d)?"Expand section":"Collapse section",onClick:g[1]||(g[1]=(...L)=>t(s)&&t(s)(...L)),onKeydown:[g[2]||(g[2]=pe((...L)=>t(s)&&t(s)(...L),["enter"])),g[3]||(g[3]=pe(ge((...L)=>t(s)&&t(s)(...L),["prevent"]),["space"]))]},[k(T,{name:t(d)?"i-lucide-chevron-right":"i-lucide-chevron-down",class:"size-4 shrink-0 text-gray-400"},null,8,["name"]),e.icon?(n(),P(T,{key:0,name:e.icon,class:ae(["size-5 shrink-0",e.iconClass])},null,8,["name","class"])):$("",!0),u("h3",Wt,[z(v(e.title),1),e.count!=null?(n(),c(H,{key:0},[z(" ("+v(e.count)+")",1)],64)):$("",!0)]),e.help?(n(),c("span",{key:1,onClick:g[0]||(g[0]=ge(()=>{},["stop"]))},[k(I,{topic:e.help},null,8,["topic"])])):$("",!0),t(d)&&l.$slots.folded?(n(),c("span",Jt,[Oe(l.$slots,"folded")])):$("",!0)],40,Zt),l.$slots.actions?(n(),c("div",Gt,[Oe(l.$slots,"actions")])):$("",!0)]),!t(d)&&(e.subtitle||l.$slots.subtitle)?(n(),c("p",Yt,[Oe(l.$slots,"subtitle",{},()=>[z(v(e.subtitle),1)])])):$("",!0)]),default:C(()=>[ht(u("div",null,[Oe(l.$slots,"default")],512),[[vt,!t(d)]])]),_:3},8,["ui","class"])],512)}}}),Ke=Object.assign(Qt,{__name:"CollapsibleSectionCard"}),Xt={class:"overflow-x-auto text-xs font-mono"},en=te({__name:"DiffPatch",props:{patch:{}},setup(e){return(r,i)=>(n(),c("div",Xt,[(n(!0),c(H,null,se(("parsePatchLines"in r?r.parsePatchLines:t(Rt))(e.patch),(d,s)=>(n(),c("div",{key:s,class:ae(["px-3 py-px whitespace-pre leading-5 min-w-0",("patchLineClass"in r?r.patchLineClass:t(At))[d.type]])},v(d.text||" "),3))),128))]))}}),tn=Object.assign(en,{__name:"DiffPatch"}),nn=["role","aria-checked","tabindex"],on={class:"flex-1 min-w-0"},sn=["title"],an={key:0,class:"text-[11px] leading-4 text-gray-500 truncate"},rn=te({__name:"LocatorAlternativeRow",props:{alt:{},note:{default:void 0},copied:{type:Boolean,default:!1},dense:{type:Boolean,default:!1},selectable:{type:Boolean,default:!1},selected:{type:Boolean,default:!1}},emits:["copy","select"],setup(e){const r=e;function i(a){return a>=80?"success":a>=50?"warning":"error"}function d(a){const{method:o,score:p,args:l}=a;return l&&(l.anchorTestId||l.anchorSelector||l.anchorRole)?"scoped to a stable ancestor — survives renames":p>=100?"most stable — purpose-built for testing":o==="getByRole"&&l&&!("name"in l)?"name-free role — survives renames":o==="getByRole"?"browser ARIA tree — semantic and stable":o==="getByLabel"?"associated <label> element":o==="getByPlaceholder"?"input placeholder":o==="getByText"?"visible text":o==="getByAltText"?"image alt text":o==="getByTitle"?"title attribute":o==="locator"&&p>=50?"stable selector":o==="locator"?"CSS class — may be fragile":""}const s=S(()=>r.note??d(r.alt));return(a,o)=>{const p=Be,l=ve,g=Ae;return n(),c("div",{class:ae(["flex items-center gap-2 rounded border",[e.dense?"py-1 px-2":"py-1.5 px-2.5",e.selectable?"cursor-pointer hover:bg-elevated transition-colors focus-visible:outline-2 focus-visible:outline-primary":"",e.selectable&&e.selected?"border-primary/60 ring-1 ring-primary/50":"border-default/50"]]),role:e.selectable?"radio":void 0,"aria-checked":e.selectable?e.selected:void 0,tabindex:e.selectable?0:void 0,onClick:o[1]||(o[1]=T=>e.selectable&&a.$emit("select")),onKeydown:[o[2]||(o[2]=pe(ge(T=>e.selectable&&a.$emit("select"),["prevent"]),["enter"])),o[3]||(o[3]=pe(ge(T=>e.selectable&&a.$emit("select"),["prevent"]),["space"]))]},[k(p,{size:"xs",color:i(e.alt.score),variant:"subtle",class:ae(["shrink-0 font-mono tabular-nums cursor-default text-center",e.dense?"min-w-[2.25rem]":"min-w-[2.5rem]"]),title:`Stability score: ${e.alt.score}/100`},{default:C(()=>[z(v(e.alt.score),1)]),_:1},8,["color","class","title"]),u("div",on,[u("code",{class:"text-xs font-mono block truncate",title:e.alt.locator},v(e.alt.locator),9,sn),t(s)?(n(),c("p",an,v(t(s)),1)):$("",!0)]),e.alt.pickedByUser&&e.dense?(n(),P(l,{key:0,name:"i-lucide-user-check",class:"size-3.5 text-primary shrink-0",title:"Confirmed with the locator picker"})):e.alt.pickedByUser?(n(),P(p,{key:1,size:"xs",color:"primary",variant:"subtle",icon:"i-lucide-user-check",class:"shrink-0",title:"Confirmed with the locator picker on the failing page"})):$("",!0),k(g,{size:"xs",variant:"ghost",color:"neutral",icon:e.copied?"i-lucide-check":"i-lucide-copy",title:e.copied?"Copied!":"Copy",class:"shrink-0",onClick:o[0]||(o[0]=ge(T=>a.$emit("copy"),["stop"]))},null,8,["icon","title"])],42,nn)}}}),ut=Object.assign(rn,{__name:"LocatorAlternativeRow"}),et={getByTestId:"testid",getByRole:"semantic",getByLabel:"label",getByPlaceholder:"label",getByText:"text",getByAltText:"text",getByTitle:"text",locator:"css","page.locator":"css"},ln=50;function dt(e,r,i=ln){const d=r[0]??null;if(!d)return{recommended:null,durable:null,preservesConvention:!1,hasDurableAlternative:!1,suggestAddTestId:!1};const s=e?et[e]:void 0,a=(e?r.find(l=>l.method===e&&l.score>=i):void 0)??(s?r.find(l=>et[l.method]===s&&l.score>=i):void 0),p=r.find(l=>l.pickedByUser)??a??d;return{recommended:p,durable:d,preservesConvention:!!a&&p===a,hasDurableAlternative:p.locator!==d.locator,suggestAddTestId:d.score<i}}const ft={a:"link",button:"button",nav:"navigation",main:"main",article:"article",section:"region",form:"form",img:"img",figure:"figure",figcaption:"caption",blockquote:"blockquote",table:"table",ul:"list",ol:"list",li:"listitem",dialog:"dialog",output:"status",progress:"progressbar",meter:"meter",textarea:"textbox",h1:"heading",h2:"heading",h3:"heading",h4:"heading",h5:"heading",h6:"heading",details:"group",summary:"button",search:"search"},cn={button:"button",submit:"button",reset:"button",image:"button",checkbox:"checkbox",radio:"radio",range:"slider",search:"searchbox",number:"spinbutton",text:"textbox",email:"textbox",tel:"textbox",url:"textbox",password:"textbox"},un=["id","class","name","data-testid","placeholder","alt","title","aria-label","aria-level","role","type","href","multiple"];function dn(e){const r=e.attributes.role;if(r)return r;const i=e.tagName;if(!i)return null;if(i==="input"){const d=(e.attributes.type??"text").toLowerCase();return cn[d]??"textbox"}return i==="select"?e.attributes.multiple!=null?"listbox":"combobox":i==="a"?e.attributes.href!=null?"link":null:ft[i]??null}function fn(e,r){if(r!=="heading")return null;const i=e.tagName.match(/^h([1-6])$/);if(i)return Number(i[1]);const d=e.attributes["aria-level"];return d&&/^\d+$/.test(d)?Number(d):null}const $e=(e,r)=>e.attributes[r]||null,me=e=>e.replace(/\\/g,"\\\\").replace(/'/g,"\\'"),qe=e=>e.replace(/\\/g,"\\\\").replace(/"/g,'\\"'),tt=e=>/^[A-Za-z][A-Za-z0-9_-]*$/.test(e);function mn(e){return/[a-f0-9]{8,}/i.test(e)?10:/^(?:css|sc|emotion|styled)-/i.test(e)?15:/^(bg|text|border|shadow|opacity|font|w-|h-|m[tblrxy]?-|p[tblrxy]?-|flex|grid|gap|rounded|absolute|relative|fixed|sticky|block|inline|hidden|overflow|z-|top-|right-|bottom-|left-|inset-|justify-|items-|self-|content-|order-|col-|row-)/.test(e)?25:/__/.test(e)||/--/.test(e)?35:/^[a-z]+(-[a-z]+)+$/.test(e)||/^[a-z]+[A-Z][a-zA-Z]+$/.test(e)?40:(e.includes("_")||/^[a-z]+-[a-z0-9]{5,}$/.test(e)&&/[0-9]/.test(e),15)}function nt(e){return!!(/^[a-f0-9]{8}-([a-f0-9]{4}-){3}[a-f0-9]{12}$/i.test(e)||/^[a-f0-9]{8,}$/i.test(e)||/^[a-z]+-\d+$/.test(e)||/^(emotion-|styled-|css-|sc-)/.test(e)||e.startsWith("ng-")||/^(radix-|headlessui-|mui-|mantine-|chakra-)/i.test(e)||/^:r[0-9a-z]+:$/i.test(e)||/^«r[0-9a-z]+»$/i.test(e))}function pn(e){const r=[],i=new Set,d=y=>{i.has(y.locator)||(i.add(y.locator),r.push(y))},{accessibleName:s}=e,a=e.tagName,o=dn(e),p=e.selectorCounts,l=y=>y==null||y<=1,g=e.textContent?e.textContent.replace(/\s+/g," ").trim():null,T=$e(e,"data-testid");T&&l(p?.testId)&&d({locator:`getByTestId('${me(T)}')`,method:"getByTestId",args:{testId:T},score:100});const I=fn(e,o),b=I!=null?`, level: ${I}`:"",L=y=>I!=null?{...y,level:I}:y;o&&s&&d({locator:`getByRole('${o}', { name: '${me(s)}'${b} })`,method:"getByRole",args:L({role:o,name:s}),score:90});const x=$e(e,"aria-label");if(o&&x&&x!==s&&d({locator:`getByRole('${o}', { name: '${me(x)}'${b} })`,method:"getByRole",args:L({role:o,name:x}),score:85}),s&&["input","select","textarea"].includes(a)){const y=$e(e,"aria-label");(e.hasLabel===void 0||e.hasLabel===!0||y===s)&&d({locator:`getByLabel('${me(s)}')`,method:"getByLabel",args:{label:s},score:85})}const A=$e(e,"placeholder");A&&d({locator:`getByPlaceholder('${me(A)}')`,method:"getByPlaceholder",args:{placeholder:A},score:80}),g&&g.length<80&&d({locator:`getByText('${me(g)}')`,method:"getByText",args:{text:g},score:75});const j=$e(e,"id");if(j&&!nt(j)&&l(p?.id)){const y=tt(j)?`#${j}`:`[id="${qe(j)}"]`;d({locator:`locator('${me(y)}')`,method:"locator",args:{selector:y},score:65})}const D=$e(e,"name");if(D&&l(p?.name)){const y=`[name="${qe(D)}"]`;d({locator:`locator('${me(y)}')`,method:"locator",args:{selector:y},score:60})}const E=$e(e,"alt");E&&d({locator:`getByAltText('${me(E)}')`,method:"getByAltText",args:{text:E},score:60});const B=$e(e,"title");B&&d({locator:`getByTitle('${me(B)}')`,method:"getByTitle",args:{title:B},score:50});const le=!!(T&&l(p?.testId));if(o&&!le){const y=I!=null?`'${o}', { level: ${I} }`:`'${o}'`,q=L({role:o});let M=!1,V=!1,G=!1;for(const Y of e.ancestors??[]){if(Y.scopedRoleCount!==1)continue;if(!M&&Y.testId&&Y.testIdCount===1&&(M=!0,d({locator:`getByTestId('${me(Y.testId)}').getByRole(${y})`,method:"getByRole",args:{...q,anchorTestId:Y.testId},score:72})),!V&&Y.id&&!nt(Y.id)&&Y.idCount===1){V=!0;const ye=tt(Y.id)?`#${Y.id}`:`[id="${qe(Y.id)}"]`;d({locator:`locator('${me(ye)}').getByRole(${y})`,method:"getByRole",args:{...q,anchorSelector:ye},score:64})}const he=Y.role||ft[Y.tag]||null;!G&&he&&he!==o&&Y.roleCount===1&&(G=!0,d({locator:`getByRole('${me(he)}').getByRole(${y})`,method:"getByRole",args:{...q,anchorRole:he},score:55}))}const Z=e.rolePosition;Z&&Z.role===o&&(Z.count===1||I!=null&&Z.levelCount===1)&&d({locator:`getByRole(${y})`,method:"getByRole",args:q,score:58})}const ee=$e(e,"class");if(ee){const y=p?.classes,q=ee.split(/\s+/).filter(M=>M.length>1&&/^[A-Za-z_-][A-Za-z0-9_-]*$/.test(M)&&l(y?.[M])).map(M=>({cls:M,score:mn(M)})).sort((M,V)=>V.score-M.score).slice(0,3);for(const{cls:M,score:V}of q)d({locator:`locator('.${me(M)}')`,method:"locator",args:{selector:`.${M}`},score:V})}return r.sort((y,q)=>q.score-y.score)}function gn(e){const r=e.attributes,i=r["aria-label"];if(i)return i;if(e.textContent)return e.textContent;const d=r.title;if(d)return d;const s=r.placeholder;return s||null}function hn(e){if(window.__piwiPickerInstalled)return;window.__piwiPickerInstalled=!0;var r=document,i=window,d=2147483600,s=e.probedAttrs,a=r.createElement("div");a.id="__piwi_picker_highlight",a.style.cssText="position:fixed;pointer-events:none;z-index:"+d+";display:none;box-sizing:border-box;border:2px solid #7c3aed;background:rgba(124,58,237,.12);border-radius:3px;",r.body.appendChild(a);var o=r.createElement("div");o.id="__piwi_picker_banner",o.style.cssText="position:fixed;top:12px;left:50%;transform:translateX(-50%);z-index:"+(d+2)+";background:#111827;color:#f9fafb;font:13px/1.5 system-ui,sans-serif;padding:10px 16px;border-radius:8px;box-shadow:0 4px 24px rgba(0,0,0,.4);max-width:80vw;",o.innerHTML='<div>Click an element to generate locators</div><div style="color:#9ca3af;margin-top:3px;font-size:11px">↑ parent · ↓ child · Esc skip</div>',r.body.appendChild(o),i.parent.postMessage({type:"pickerReady"},"*");function p(f){var w=(f.tagName||"?").toLowerCase(),R=f.getAttribute&&f.getAttribute("data-testid");if(R)return"getByTestId('"+R+"')";if(f.labels&&f.labels.length>0){var N=(f.labels[0].textContent||"").replace(/\s+/g," ").trim().slice(0,80);if(N)return"getByLabel('"+N+"')"}var X=f.getAttribute&&f.getAttribute("aria-label");if(X)return"getByLabel('"+X+"')";var W=f.getAttribute&&f.getAttribute("placeholder");if(W)return"getByPlaceholder('"+W+"')";var J=f.getAttribute&&f.getAttribute("alt");if(J)return"getByAltText('"+J+"')";var fe=f.getAttribute&&f.getAttribute("title");if(fe)return"getByTitle('"+fe+"')";if(f.id)return"locator('#"+f.id+"')";var _=(f.getAttribute&&f.getAttribute("class")||"").split(/\s+/).find(function(h){return h.length>1});return _?"locator('."+_+"')":w}function l(f){for(var w=[],R=f;R&&w.length<15;){var N=(R.tagName||"").toLowerCase();if(N==="body"||N==="html")break;w.push(R),R=R.parentElement}return w.length?w:[f]}var g=["button","a","input","select","textarea","summary","option"];function T(f){for(var w=0;w<Math.min(f.length,4);w++){var R=f[w],N=(R.tagName||"").toLowerCase();if(g.indexOf(N)!==-1||R.getAttribute&&(R.getAttribute("role")||R.getAttribute("data-testid")))return w}return 0}var I=[],b=0,L=null;function x(){return I[b]||null}function A(){var f=x();if(!f){a.style.display="none";return}var w=f.getBoundingClientRect();a.style.display="block",a.style.left=w.left+"px",a.style.top=w.top+"px",a.style.width=w.width+"px",a.style.height=w.height+"px";var R=r.getElementById("__piwi_picker_foot");R&&(R.textContent=p(f)+" — click to pick · ↑ parent · ↓ child · Esc skip")}var j=o.querySelector("[style*=margin]");j&&(j.id="__piwi_picker_foot");function D(f){for(var w={},R=0;R<s.length;R++){var N=s[R],X=f.getAttribute(N)||f[N];w[N]=typeof X=="string"?X.slice(0,200):X?String(X).slice(0,200):null}var W=f.getBoundingClientRect(),J={};try{var fe=function(we){return i.CSS.escape(we)},_=function(we){try{return r.querySelectorAll(we).length}catch{return}};w["data-testid"]&&(J.testId=_("[data-testid="+JSON.stringify(w["data-testid"])+"]")),w.id&&(J.id=_("#"+fe(w.id))),w.name&&(J.name=_("[name="+JSON.stringify(w.name)+"]"));var h=(w.class||"").split(/\s+/).filter(function(we){return we.length>1}).slice(0,10);if(h.length>0){for(var Q={},oe=0;oe<h.length;oe++){var De=_("."+fe(h[oe]));De!==void 0&&(Q[h[oe]]=De)}J.classes=Q}}catch{}var Ve=null;return f.labels&&f.labels.length>0&&(Ve=(f.labels[0].textContent||"").replace(/\s+/g," ").trim().slice(0,120)||null),{tagName:(f.tagName||"").toLowerCase(),attributes:w,textContent:(f.textContent||"").replace(/\s+/g," ").trim().slice(0,80)||null,center:{x:Math.round(W.x+W.width/2),y:Math.round(W.y+W.height/2)},hasLabel:!!(f.labels&&f.labels.length>0),labelText:Ve,selectorCounts:J}}function E(f){f.preventDefault(),f.stopImmediatePropagation()}function B(f){return f===o||f===a||o.contains&&o.contains(f)||f&&f.__piwiHint}var le="top";function ee(f){le!==f&&(le=f,f==="bottom"?(o.style.top="auto",o.style.bottom="12px"):(o.style.top="12px",o.style.bottom="auto"))}function y(f){var w=f.target;if(!w||B(w)){a.style.display="none";return}w!==L&&(L=w,I=l(w),b=T(I)),A();var R=x();if(R){var N=R.getBoundingClientRect(),X=o.getBoundingClientRect(),W=8;N.left<X.right+W&&N.right>X.left-W&&N.top<X.bottom+W&&N.bottom>X.top-W&&ee(le==="top"?"bottom":"top")}}function q(f){if(f==="Escape"){F();return}f==="ArrowUp"&&(b=Math.min(b+1,I.length-1),A()),f==="ArrowDown"&&(b=Math.max(b-1,0),A())}function M(f){E(f),q(f.key)}var V=[];function G(){for(var f=0;f<V.length;f++)V[f].parentNode&&V[f].parentNode.removeChild(V[f]);V=[]}function Z(f){return(f||"").replace(/\s+/g," ").trim().toLowerCase()}function Y(f){var w=Z(f);if(w.length<2)return[];for(var R=r.querySelectorAll("button,a,[role],h1,h2,h3,h4,h5,h6,label,summary,input,textarea,select,option,span,li,td,th,p"),N=[],X=[],W=0;W<R.length;W++){var J=R[W],fe=Z(J.textContent);if(!fe){var _=Z(J.getAttribute&&(J.getAttribute("placeholder")||J.getAttribute("aria-label"))||"");_&&(_===w||_.indexOf(w)!==-1)&&N.push(J);continue}fe.length>120||(fe===w?N.push(J):fe.indexOf(w)!==-1&&fe.length<w.length+30&&X.push(J))}return N.concat(X)}function he(f,w){var R=f.getBoundingClientRect();if(R.width===0&&R.height===0)return null;var N=r.createElement("div");return N.__piwiHint=!0,N.style.cssText="position:fixed;pointer-events:none;z-index:"+(d+1)+";box-sizing:border-box;border-radius:3px;transition:opacity .3s;border:2px solid "+w+";box-shadow:0 0 0 3px "+w+"55;left:"+R.left+"px;top:"+R.top+"px;width:"+R.width+"px;height:"+R.height+"px;",r.body.appendChild(N),V.push(N),N}function ye(f){var w=f.getBoundingClientRect();i.parent.postMessage({type:"piwiScrollTo",y:w.top},"*")}function Pe(f){if(G(),!(!f||!f.length)){for(var w=null,R=0;R<f.length;R++)for(var N=f[R],X=Y(N&&N.text),W=0;W<Math.min(X.length,3);W++)he(X[W],"#f59e0b"),w||(w=X[W]);w&&ye(w),setTimeout(function(){for(var J=0;J<V.length;J++)V[J].style.opacity="0"},2600),setTimeout(G,3e3)}}var ne=[],ke=0;function O(){i.parent.postMessage({type:"piwiSearchResult",count:ne.length,index:ne.length?ke:-1},"*")}function m(){G();var f=ne[ke];f&&(he(f,"#7c3aed"),ye(f),O())}function K(f){if(ne=Y(f),ke=0,!ne.length){G(),O();return}m()}function xe(){ne.length&&(ke=(ke+1)%ne.length,m())}function de(f){var w=f.data;if(!(!w||typeof w.type!="string")){if(w.type==="piwiPickerKey"&&typeof w.key=="string")q(w.key);else if(w.type==="piwiHighlight")try{Pe(w.hints)}catch{}else if(w.type==="piwiSearch")try{K(w.q)}catch{}else if(w.type==="piwiSearchNext")try{xe()}catch{}else if(w.type==="piwiClearHints")try{G()}catch{}}}function ce(f){E(f);var w=x();if(!(!w||B(f.target))){var R=D(w);a.style.display="none",G(),o.innerHTML='<div style="text-align:center;color:#9ca3af;">Analyzing element…</div>',ue(),i.parent.postMessage({type:"elementPicked",attrs:R},"*")}}var _e=["mousedown","mouseup","pointerdown","pointerup","auxclick","dblclick","contextmenu","submit","beforeinput","input","change","paste","cut","drop","dragstart","keypress","keyup","touchstart","touchend"];function Te(){for(var f=0;f<_e.length;f++)r.addEventListener(_e[f],E,!0)}function Ce(){r.removeEventListener("mousemove",y,!0),r.removeEventListener("click",ce,!0),r.removeEventListener("keydown",M,!0),i.removeEventListener("message",de,!1)}function ue(){Ce(),r.addEventListener("click",E,!0),r.addEventListener("keydown",E,!0)}function F(){Ce();for(var f=0;f<_e.length;f++)r.removeEventListener(_e[f],E,!0);r.removeEventListener("click",E,!0),r.removeEventListener("keydown",E,!0),G(),a.remove(),o.remove(),i.parent.postMessage({type:"pickerClosed"},"*")}r.addEventListener("mousemove",y,!0),r.addEventListener("click",ce,!0),r.addEventListener("keydown",M,!0),i.addEventListener("message",de,!1),Te();function re(){var f=Math.max(r.documentElement?r.documentElement.scrollHeight:0,r.body?r.body.scrollHeight:0);f>0&&i.parent.postMessage({type:"piwiContentHeight",height:f},"*")}re();try{if(i.ResizeObserver){var be=new i.ResizeObserver(re);r.documentElement&&be.observe(r.documentElement),r.body&&be.observe(r.body)}}catch{}}function vn(e){const r=[],i=new Set,d=a=>{if(typeof a!="string")return;const o=a.trim();if(o.length<2||o.length>80)return;const p=o.toLowerCase();i.has(p)||(i.add(p),r.push({text:o}))},s=a=>a&&(a.name??a.text??a.label??a.placeholder??a.alt??a.title);d(s(e.failingLocator?.args));for(const a of e.fromElementMatch??[])d(s(a.args));for(const a of e.fromAriaSnapshot??[])d(s(a.args));return r.slice(0,6)}function yn(e){return`<script>(${String(hn).replace(/<\/(script)/gi,"<\\/$1")})(${JSON.stringify(e)})<\/script>`}function xn(e){return e.replace(/<base\b[^>]*>/gi,"")}function bn(e,r){return xn(e)+yn(r)}const kn={key:0,class:"flex items-center justify-center py-20"},_n={key:1,class:"py-8 text-center"},$n={class:"text-xs text-gray-400 mt-1"},wn={key:2,class:"py-8 text-center"},Cn={class:"mb-2 flex items-center gap-2 flex-wrap"},Sn={key:1,class:"ml-auto inline-flex rounded-md border border-default overflow-hidden text-xs"},Tn={key:0,class:"flex items-center gap-1 mb-1.5 text-xs text-gray-500"},Ln={class:"tabular-nums w-11 text-center select-none"},zn={class:"ml-auto text-gray-400 tabular-nums"},In={key:1,class:"flex items-center gap-2 mb-1.5"},An={key:0,class:"text-xs text-gray-500 tabular-nums"},Rn={key:1,class:"text-xs text-gray-400"},Bn={key:0,class:"absolute inset-0 flex items-center justify-center bg-white dark:bg-gray-900 z-10"},Pn=["src"],En={key:2,class:"mt-4 space-y-3"},On={class:"flex items-center gap-3 bg-elevated rounded-lg p-3"},Un={class:"flex-1 min-w-0"},jn={class:"text-sm font-medium"},Mn={class:"text-xs"},Nn={key:0,class:"text-xs text-gray-400 ml-1"},Kn={key:0,class:"text-xs text-gray-500 mt-0.5 truncate"},Dn={class:"space-y-1",role:"radiogroup","aria-label":"Alternative locators"},Vn={class:"flex-1 min-w-0"},Hn={class:"text-xs font-medium text-primary"},Fn={class:"text-sm font-mono block truncate mt-0.5"},qn={class:"flex justify-between w-full"},Zn={key:1},Wn={class:"flex gap-2"},Jn=te({__name:"SnapshotLocatorPicker",props:We({runId:{},testRunsCaseId:{},failingLocator:{},healing:{}},{open:{type:Boolean,required:!0},openModifiers:{}}),emits:We(["close","confirmed"],["update:open"]),setup(e,{emit:r}){const i=e,d=r,s=st(e,"open"),a=U(!1),o=U(null),p=U(null),l=U(void 0);async function g(){a.value=!0,p.value=null;try{const _=new URLSearchParams({inlineStyles:"1"});l.value&&_.set("source",l.value);const h=`?${_.toString()}`;o.value=await $fetch(`/api/test-runs/${i.runId}/cases/${i.testRunsCaseId}/dom-snapshot${h}`),o.value?.source&&(l.value=o.value.source)}catch(_){p.value=_ instanceof Error?_.message:"Unknown error"}finally{a.value=!1}}const T=S(()=>o.value?.availableSources??[]);function I(_){_===l.value||a.value||(l.value=_,x.value=!1,b.value="pick-element",ee.value=0,q.value=!1,A.value=null,j.value=[],ue.value=null,K.value="",xe.value=0,de.value=-1,g())}Ee(s,_=>{_&&(o.value=null,x.value=!1,b.value="pick-element",ee.value=0,q.value=!1,l.value=void 0,A.value=null,j.value=[],ue.value=null,K.value="",xe.value=0,de.value=-1,g())});const b=U("pick-element"),L=U(null),x=U(!1),A=U(null),j=U([]),D=U(void 0);function E(_){return URL.createObjectURL(new Blob([bn(_,{probedAttrs:un})],{type:"text/html"}))}Ee(()=>o.value?.html,_=>{D.value&&(URL.revokeObjectURL(D.value),D.value=void 0),_&&(D.value=E(_))},{immediate:!0});const B=U(null),le=U(0),ee=U(0),y=U(1),q=U(!1),M=S(()=>o.value?.viewport??null),V=S(()=>{const _=M.value;return!_?.width||!le.value?1:Math.min(le.value/_.width,1)}),G=S(()=>{const _=M.value;if(!_)return{width:"100%",height:ee.value?`${ee.value}px`:"100%"};const h=ee.value||_.height;return{width:`${Math.round(_.width*y.value)}px`,height:`${Math.round(h*y.value)}px`}}),Z=S(()=>{const _=M.value;if(!_)return{width:"100%",height:ee.value?`${ee.value}px`:"100%",border:"0"};const h=ee.value||_.height;return{width:`${_.width}px`,height:`${h}px`,transform:`scale(${y.value})`,transformOrigin:"top left",border:"0"}}),Y=S(()=>Math.round(y.value*100)),he=_=>Math.min(4,Math.max(.1,_));function ye(_){q.value=!0,y.value=he(y.value*_)}function Pe(){q.value=!1,y.value=V.value}Ee([V,M],()=>{q.value||(y.value=V.value)});let ne=null;Ee(B,_=>{ne?.disconnect(),_&&(le.value=_.clientWidth,ne=new ResizeObserver(h=>{for(const Q of h)le.value=Q.contentRect.width}),ne.observe(_))}),Le(()=>{ne?.disconnect()}),Le(()=>{D.value&&URL.revokeObjectURL(D.value)});function ke(_){if(!L.value||_.source!==L.value.contentWindow)return;const h=_.data;if(h?.type==="pickerReady"){x.value=!0,m();return}if(h?.type==="piwiContentHeight"&&typeof h.height=="number"){ee.value=Math.max(h.height,M.value?.height??0);return}if(h?.type==="piwiScrollTo"&&typeof h.y=="number"){const Q=B.value;Q&&Q.scrollTo({top:Math.max(0,h.y*y.value-80),behavior:"smooth"});return}if(h?.type==="piwiSearchResult"){xe.value=typeof h.count=="number"?h.count:0,de.value=typeof h.index=="number"?h.index:-1;return}if(h?.type==="elementPicked"&&h.attrs){const{labelText:Q,...oe}=h.attrs;A.value={...oe,accessibleName:Q??gn(oe)},j.value=pn(A.value),ue.value=null,b.value="review"}h?.type==="pickerClosed"&&R()}function O(_){L.value?.contentWindow?.postMessage(_,"*")}function m(){const _=vn({failingLocator:i.failingLocator,fromElementMatch:i.healing?.fromElementMatch??null,fromAriaSnapshot:i.healing?.fromAriaSnapshot??null});_.length&&O({type:"piwiHighlight",hints:_})}const K=U(""),xe=U(0),de=U(-1);let ce=null;Ee(K,_=>{ce&&clearTimeout(ce),ce=setTimeout(()=>O({type:"piwiSearch",q:_}),180)});function _e(){O({type:"piwiSearchNext"})}Le(()=>{ce&&clearTimeout(ce)});function Te(_){if(!s.value||b.value!=="pick-element"||!x.value||_.key!=="ArrowUp"&&_.key!=="ArrowDown")return;const h=(document.activeElement?.tagName??"").toLowerCase();if(h==="input"||h==="textarea")return;const Q=L.value?.contentWindow;Q&&(_.preventDefault(),Q.postMessage({type:"piwiPickerKey",key:_.key},"*"))}function Ce(){L.value&&(L.value.src="about:blank")}at(()=>{window.addEventListener("message",ke),window.addEventListener("keydown",Te,!0)}),Le(()=>{window.removeEventListener("message",ke),window.removeEventListener("keydown",Te,!0)});const ue=U(null),F=U(!1);function re(_){ue.value=_}const be=S(()=>dt(i.failingLocator.method,j.value)),f=Je();async function w(){if(ue.value){F.value=!0;try{(await $fetch(`/api/test-runs/${i.runId}/cases/${i.testRunsCaseId}/locator-pick`,{method:"POST",body:{failingLocator:i.failingLocator,pickedLocator:ue.value,element:A.value}})).status==="ok"?d("confirmed",ue.value):f.add({title:"Pick not saved",description:"This failure has no call-site or locator signature to attach the pick to.",color:"warning",icon:"i-lucide-alert-triangle"}),s.value=!1}catch(_){f.add({title:"Could not save the pick",description:it(_),color:"error",icon:"i-lucide-alert-triangle"})}finally{F.value=!1}}}function R(){Ce(),s.value=!1}function N(){A.value=null,j.value=[],ue.value=null,b.value="pick-element",x.value=!1,K.value="",xe.value=0,de.value=-1;const _=o.value?.html;_&&(D.value&&URL.revokeObjectURL(D.value),D.value=E(_))}const{copy:X}=He(),W=U(null);let J=null;function fe(_,h){X(_,{toast:"Locator copied"}),W.value=h,J&&clearTimeout(J),J=setTimeout(()=>{W.value=null},2e3)}return Le(()=>{J&&clearTimeout(J)}),(_,h)=>{const Q=ve,oe=Ae,De=xt,Ve=Be,we=Pt;return n(),P(we,{open:s.value,"onUpdate:open":h[8]||(h[8]=ie=>s.value=ie),ui:{content:"max-w-6xl w-[95vw]"},onAfterLeave:R},{header:C(()=>[...h[9]||(h[9]=[u("div",null,[u("h3",{class:"text-lg font-medium"},"Pick a locator from the DOM snapshot"),u("p",{class:"text-sm text-gray-500 mt-0.5"}," Click the element the failing locator should target. Use ↑↓ to walk the DOM tree. ")],-1)])]),body:C(()=>[t(a)?(n(),c("div",kn,[k(Q,{name:"i-lucide-loader",class:"size-6 animate-spin text-gray-400"}),h[10]||(h[10]=u("span",{class:"ml-2 text-sm text-gray-500"},"Loading DOM snapshot...",-1))])):t(p)?(n(),c("div",_n,[k(Q,{name:"i-lucide-alert-triangle",class:"size-8 text-red-300 mx-auto mb-2"}),h[12]||(h[12]=u("p",{class:"text-sm text-red-500"},"Failed to load snapshot",-1)),u("p",$n,v(t(p)),1),k(oe,{size:"xs",variant:"outline",color:"neutral",class:"mt-3",onClick:g},{default:C(()=>[...h[11]||(h[11]=[z("Retry",-1)])]),_:1})])):t(o)?.status!=="ok"||!t(o).html?(n(),c("div",wn,[k(Q,{name:"i-lucide-file-x",class:"size-8 text-gray-300 mx-auto mb-2"}),h[13]||(h[13]=u("p",{class:"text-sm text-gray-500"},"No DOM snapshot or ARIA data available for this execution",-1)),h[14]||(h[14]=u("p",{class:"text-xs text-gray-400 mt-1"},"This test run has no stored trace or ARIA snapshot to pick from.",-1))])):(n(),c(H,{key:3},[u("div",Cn,[t(o).source?(n(),c("div",{key:0,class:ae(["text-xs flex items-center gap-1",t(o).source==="aria"?"text-amber-600 dark:text-amber-400":"text-green-600 dark:text-green-400"])},[k(Q,{name:t(o).source==="aria"?"i-lucide-accessibility":"i-lucide-check",class:"size-3.5 shrink-0"},null,8,["name"]),t(o).source==="aria"?(n(),c(H,{key:0},[z(" Accessibility tree from the failure-time ARIA snapshot — element styles are approximate ")],64)):(n(),c(H,{key:1},[z(" Rendered from the failure-time DOM snapshot ")],64))],2)):$("",!0),t(T).length>1?(n(),c("div",Sn,[u("button",{type:"button",class:ae(["px-2 py-1 flex items-center gap-1 transition-colors",t(l)==="dom"?"bg-primary/10 text-primary font-medium":"text-gray-500 hover:bg-elevated"]),title:"Rendered page from the trace",onClick:h[0]||(h[0]=ie=>I("dom"))},[k(Q,{name:"i-lucide-layout-panel-top",class:"size-3.5"}),h[15]||(h[15]=z(" DOM ",-1))],2),u("button",{type:"button",class:ae(["px-2 py-1 flex items-center gap-1 border-l border-default transition-colors",t(l)==="aria"?"bg-primary/10 text-primary font-medium":"text-gray-500 hover:bg-elevated"]),title:"Accessibility tree from the ARIA snapshot",onClick:h[1]||(h[1]=ie=>I("aria"))},[k(Q,{name:"i-lucide-accessibility",class:"size-3.5"}),h[16]||(h[16]=z(" Tree ",-1))],2)])):$("",!0)]),t(M)?(n(),c("div",Tn,[k(oe,{size:"xs",variant:"ghost",color:"neutral",icon:"i-lucide-zoom-out",title:"Zoom out",onClick:h[2]||(h[2]=ie=>ye(1/1.25))}),u("span",Ln,v(t(Y))+"%",1),k(oe,{size:"xs",variant:"ghost",color:"neutral",icon:"i-lucide-zoom-in",title:"Zoom in",onClick:h[3]||(h[3]=ie=>ye(1.25))}),k(oe,{size:"xs",variant:"outline",color:"neutral",class:"ml-1",onClick:Pe},{default:C(()=>[...h[17]||(h[17]=[z("Fit",-1)])]),_:1}),u("span",zn,v(t(M).width)+"×"+v(t(M).height),1)])):$("",!0),t(b)==="pick-element"?(n(),c("div",In,[k(De,{modelValue:t(K),"onUpdate:modelValue":h[4]||(h[4]=ie=>ze(K)?K.value=ie:null),size:"xs",icon:"i-lucide-search",placeholder:"Find an element by its text…",class:"max-w-xs",onKeydown:pe(ge(_e,["prevent"]),["enter"])},null,8,["modelValue","onKeydown"]),t(K)&&t(xe)>0?(n(),c("span",An,v(t(de)+1)+"/"+v(t(xe)),1)):t(K)?(n(),c("span",Rn,"no matches")):$("",!0),t(xe)>1?(n(),P(oe,{key:2,size:"xs",variant:"ghost",color:"neutral",icon:"i-lucide-chevron-down",title:"Next match (Enter)",onClick:_e})):$("",!0)])):$("",!0),u("div",{ref_key:"stageRef",ref:B,class:ae(["relative border border-default rounded-lg overflow-auto",[t(b)==="pick-element"?"h-[75vh]":"h-80",t(M)?"bg-gray-100 dark:bg-gray-800":""]])},[t(x)?$("",!0):(n(),c("div",Bn,[k(Q,{name:"i-lucide-loader",class:"size-5 animate-spin text-gray-400"}),h[18]||(h[18]=u("span",{class:"ml-2 text-sm text-gray-500"},"Initializing picker...",-1))])),u("div",{style:Xe(t(G))},[u("iframe",{ref_key:"iframeRef",ref:L,src:t(D),style:Xe(t(Z)),class:"bg-white",sandbox:"allow-scripts",title:"DOM snapshot"},null,12,Pn)],4)],2),t(b)==="review"&&t(A)?(n(),c("div",En,[u("div",On,[k(Q,{name:"i-lucide-crosshair",class:"size-5 text-primary shrink-0"}),u("div",Un,[u("p",jn,[h[19]||(h[19]=z(" Picked: ",-1)),u("code",Mn,v(t(A).tagName),1),t(A).attributes.id?(n(),c("code",Nn,"#"+v(t(A).attributes.id),1)):$("",!0),t(A).attributes["data-testid"]?(n(),P(Ve,{key:1,size:"xs",color:"primary",variant:"subtle",class:"ml-1"},{default:C(()=>[z(v(t(A).attributes["data-testid"]),1)]),_:1})):$("",!0)]),t(A).textContent?(n(),c("p",Kn,' "'+v(t(A).textContent)+'" ',1)):$("",!0)]),k(oe,{size:"xs",variant:"ghost",color:"neutral",icon:"i-lucide-rotate-ccw",title:"Pick a different element",onClick:N})]),u("div",Dn,[(n(!0),c(H,null,se(t(j),(ie,Fe)=>(n(),P(ut,{key:Fe,alt:ie,copied:t(W)===`picked-${Fe}`,dense:!0,selectable:!0,selected:t(ue)?.locator===ie.locator,onCopy:pt=>fe(ie.locator,`picked-${Fe}`),onSelect:pt=>re(ie)},null,8,["alt","copied","selected","onCopy","onSelect"]))),128))]),t(be).recommended?(n(),c("div",{key:0,class:"rounded-lg border border-primary/40 bg-primary/5 p-3 flex items-center gap-3 cursor-pointer",role:"button",tabindex:"0",title:"Select this locator for Confirm",onClick:h[6]||(h[6]=ie=>re(t(be).recommended)),onKeydown:h[7]||(h[7]=pe(ge(ie=>re(t(be).recommended),["prevent"]),["enter"]))},[k(Q,{name:"i-lucide-star",class:"size-5 text-primary shrink-0"}),u("div",Vn,[u("p",Hn," Recommended (score: "+v(t(be).recommended.score)+") ",1),u("code",Fn,v(t(be).recommended.locator),1)]),k(oe,{size:"sm",color:"primary",variant:"solid","trailing-icon":t(W)==="rec"?"i-lucide-check":"i-lucide-copy",onClick:h[5]||(h[5]=ge(ie=>fe(t(be).recommended.locator,"rec"),["stop"]))},{default:C(()=>[...h[20]||(h[20]=[z(" Copy ",-1)])]),_:1},8,["trailing-icon"])],32)):$("",!0)])):$("",!0)],64))]),footer:C(()=>[u("div",qn,[t(b)==="review"?(n(),P(oe,{key:0,size:"sm",variant:"outline",color:"neutral",icon:"i-lucide-rotate-ccw",onClick:N},{default:C(()=>[...h[21]||(h[21]=[z(" Pick a different element ",-1)])]),_:1})):(n(),c("div",Zn)),u("div",Wn,[k(oe,{size:"sm",variant:"outline",color:"neutral",onClick:R},{default:C(()=>[...h[22]||(h[22]=[z("Cancel",-1)])]),_:1}),t(b)==="review"?(n(),P(oe,{key:0,size:"sm",color:"primary",loading:t(F),disabled:!t(ue),onClick:w},{default:C(()=>[...h[23]||(h[23]=[z(" Confirm pick ",-1)])]),_:1},8,["loading","disabled"])):$("",!0)])])]),_:1},8,["open"])}}}),Gn=Object.assign(Jn,{__name:"SnapshotLocatorPicker"});function Yn(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function Qn(e,r){let i=0,d=null;for(let s=r;s<e.length;s++){const a=e[s];if(d){if(a==="\\"){s++;continue}a===d&&(d=null);continue}if(a==="'"||a==='"'||a==="`"){d=a;continue}if(a==="(")i++;else if(a===")"&&(i--,i===0))return s}return-1}function Xn(e,r,i){if(!e||!r||!i)return null;const d=new RegExp(`${Yn(r)}\\s*\\(`,"g");let s;for(;(s=d.exec(e))!==null;){const a=s.index,o=a>0?e[a-1]:"";if(o&&/[A-Za-z0-9_$]/.test(o))continue;const p=a+s[0].lastIndexOf("("),l=Qn(e,p);if(l===-1)return null;const g=e.slice(0,a)+i+e.slice(l+1);return g===e?null:{old:e,new:g}}return null}function eo(e,r){return`${r?`@@ ${r} @@
|
|
2
|
-
`:""}-${e.old.trimEnd()}
|
|
3
|
-
+${e.new.trimEnd()}`}function to(e,r){const i=e??{},d=r??{},s=o=>o==null?null:typeof o=="string"?o:JSON.stringify(o),a=[];for(const o of new Set([...Object.keys(i),...Object.keys(d)])){const p=s(i[o]),l=s(d[o]);p!==l&&a.push({key:o,from:p,to:l})}return a}function no(e){const i=[`In ${e.location??(e.sourceLine?`line ${e.sourceLine.line}`:"the failing test")}, the Playwright locator \`${e.failing}\` no longer matches its element.`,`Replace it with \`${e.recommended}\`.`];return e.sourceLine&&i.push("","Current line:",e.sourceLine.text.trim()),i.join(`
|
|
4
|
-
`)}const oo={key:0,class:"text-xs font-mono"},so={key:1},ao={class:"flex items-center gap-1"},ro={key:1,class:"rounded-lg border border-primary/50 bg-primary/10 p-3 mb-3 flex items-center gap-3"},io={class:"flex-1 min-w-0"},lo={class:"text-xs font-medium text-primary flex items-center gap-1.5"},co={class:"text-sm font-mono block truncate mt-0.5"},uo={key:2,class:"flex items-center gap-2 bg-elevated rounded p-2 mb-3 border border-red-200 dark:border-red-800"},fo={class:"text-xs font-mono text-red-600 dark:text-red-400 flex-1 truncate"},mo={key:4,class:"rounded-lg border border-primary/40 bg-primary/5 p-3 mb-3 space-y-2"},po={class:"flex items-center gap-2 min-w-0"},go={key:0,class:"text-[11px] text-gray-500 truncate min-w-0"},ho={key:0,class:"rounded border border-default overflow-hidden bg-default"},vo={class:"text-sm font-mono block truncate"},yo={key:0,class:"text-xs flex flex-wrap items-center gap-x-1.5 gap-y-0.5"},xo={class:"font-mono text-gray-500"},bo={key:0,class:"font-mono text-red-500 line-through"},ko={key:1,class:"text-gray-400"},_o={key:2,class:"font-mono text-green-600 dark:text-green-400"},$o={key:3,class:"text-gray-400"},wo={key:2,class:"text-xs text-gray-500"},Co={key:3,class:"text-xs text-primary/90 flex items-center gap-1"},So={class:"flex items-center gap-2"},To={key:5,class:"rounded-lg border border-default bg-elevated p-3 mb-3 flex items-center gap-3"},Lo={class:"flex-1 min-w-0"},zo={class:"text-xs font-medium text-success-600 dark:text-success-400"},Io={class:"text-sm font-mono block truncate mt-0.5"},Ao={class:"space-y-2"},Ro={key:6,class:"mt-3"},Bo={class:"space-y-2"},Po={class:"flex items-center gap-1"},ot=3,Eo=te({__name:"LocatorHealingPanel",props:{runId:{},testRunsCaseId:{},storageKey:{},affectedCount:{}},setup(e){const r=e,i=S(()=>r.storageKey?Ke:Ne),d=S(()=>r.storageKey?{storageKey:r.storageKey}:{}),{data:s,pending:a,error:o}=Me(()=>`/api/test-runs/${r.runId}/cases/${r.testRunsCaseId}/locator-healing`,{lazy:!0},"$z1C7vU2CXe"),p=S(()=>!!s.value&&s.value.source!=="none"&&!!(s.value.fromElementMatch?.length||s.value.fromPriorSuccess?.length||s.value.fromAriaSnapshot?.length)),l=S(()=>s.value?s.value.fromElementMatch??s.value.fromPriorSuccess??s.value.fromAriaSnapshot??[]:[]),g=S(()=>l.value.find(O=>O.pickedByUser)??null),T=S(()=>s.value?.recommendation?s.value.recommendation:s.value?.priorNameMayBeStale||!l.value.length?null:dt(s.value?.failingLocator?.method,l.value)),I=S(()=>s.value?.priorNameMayBeStale&&s.value.fromPriorSuccess?.length?s.value.fromAriaSnapshot??[]:[]),b=S(()=>{const O=T.value;return O?.recommended?O.recommended.pickedByUser?"Confirmed with the locator picker on the failing page":O.preservesConvention?"Keeps your original locator style — minimal, idiomatic edit":O.suggestAddTestId?"Most stable available, but still fragile":"Most stable available — a sturdier style than the original":""}),L=S(()=>{const O=s.value?.priorNameMayBeStale,m=(()=>{switch(s.value?.source){case"prior-run":return O?"Pre-captured from the last passing run — the element looks changed since":"Pre-captured from the last passing run — highest confidence";case"element-match":return"The element looks renamed or moved — these are fresh locators for its current identity on the failing page";case"fingerprint":return"Matched by locator signature (line numbers shifted)";case"cross-test":return"Captured by another test in this project that uses the same locator";case"aria-snapshot":return"Generated from the failure-time ARIA snapshot — limited, no HTML attributes";default:return""}})(),K=s.value?.capturedAt;return K?`${m} · captured ${Ge(K)}`:m}),x=S(()=>{if(s.value?.priorNameMayBeStale)return"text-warning-600 dark:text-warning-400";switch(s.value?.source){case"prior-run":case"fingerprint":case"cross-test":return"text-success-600 dark:text-success-400";case"element-match":return"text-primary-600 dark:text-primary-400";default:return"text-warning-600 dark:text-warning-400"}}),A=S(()=>{const O=s.value?.failingLocator;return O?`${O.method}(${JSON.stringify(O.args)})`:""}),j=Re(),{data:D}=Me(()=>`/api/test-run-cases/${r.testRunsCaseId}/traces`,{lazy:!0},"$vsBboELop9"),E=S(()=>{const O=D.value?.[0];if(!O)return null;const m=!!j.public.demoMode&&O.filePath.startsWith("demo/");return lt(O.filePath,j.app?.baseURL,m)}),B=U(!1);async function le(){await kt(`/api/test-runs/${r.runId}/cases/${r.testRunsCaseId}/locator-healing`)}const{copy:ee}=He(),y=U(null);let q=null;function M(O,m,K){ee(O,{toast:K}),y.value=m,q&&clearTimeout(q),q=setTimeout(()=>{y.value=null},2e3)}function V(O,m){M(O,m,"Locator copied")}Le(()=>{q&&clearTimeout(q)});const G=S(()=>T.value?.recommended??null),Z=S(()=>r.affectedCount&&r.affectedCount>1&&G.value?`Same break affects ${r.affectedCount} tests in this cluster — one fix`:""),Y=S(()=>{if(G.value?.pickedByUser)return"your confirmed pick";switch(s.value?.source){case"prior-run":return"from the last passing run";case"fingerprint":return"from a prior run (line shifted)";case"cross-test":return"from another test in this project";case"element-match":return"from the current failing page";case"aria-snapshot":return"from the ARIA snapshot";default:return""}}),he=S(()=>{const O=s.value?.sourceLine,m=G.value;if(!O||!m)return null;const K=Xn(O.text,s.value?.failingLocator?.method,m.locator);return K?{edit:K,patch:eo(K,s.value?.location??null)}:null}),ye=S(()=>{if(he.value)return[];const O=s.value?.failingLocator,m=G.value;return!O||!m||m.method!==O.method?[]:to(O.args,m.args)});function Pe(){const O=G.value;!O||!s.value||M(no({location:s.value.location??null,sourceLine:s.value.sourceLine??null,failing:A.value,recommended:O.locator}),"fix-prompt","Fix prompt copied")}const ne=U(!1),ke=S(()=>ne.value?l.value:l.value.slice(0,ot));return(O,m)=>{const K=Ae,xe=bt,de=Ye,ce=ve,_e=Be,Te=tn,Ce=ut,ue=Lt;return n(),c(H,null,[!t(a)&&!t(o)&&t(p)?(n(),P(Se(t(i)),je({key:0},t(d),{icon:"i-lucide-bandage",title:"Alternative locators",count:t(l).length,help:"locator-healing"}),Ie({subtitle:C(()=>[u("span",{class:ae(t(x))},v(t(L)),3)]),default:C(()=>[t(s)?.healedInRunId?(n(),P(de,{key:0,class:"mb-3",color:"success",icon:"i-lucide-circle-check",variant:"subtle",title:"Locator healed"},{description:C(()=>[m[11]||(m[11]=z(" The recommended locator now passes at this call site — ",-1)),k(xe,{to:`/test-runs/${t(s).healedInRunId}`,class:"underline font-medium"},{default:C(()=>[z(" see run #"+v(t(s).healedInRunId),1)]),_:1},8,["to"]),m[12]||(m[12]=z(". ",-1))]),_:1})):$("",!0),t(g)?(n(),c("div",ro,[k(ce,{name:"i-lucide-user-check",class:"size-5 text-primary shrink-0"}),u("div",io,[u("p",lo,[m[14]||(m[14]=z(" Your pick ",-1)),k(_e,{size:"sm",color:"primary",variant:"subtle"},{default:C(()=>[...m[13]||(m[13]=[z("confirmed on the failing page",-1)])]),_:1})]),u("code",co,v(t(g).locator),1)]),k(K,{size:"sm",color:"primary",variant:"solid","trailing-icon":t(y)==="user-pick"?"i-lucide-check":"i-lucide-copy",onClick:m[1]||(m[1]=F=>V(t(g).locator,"user-pick"))},{default:C(()=>[...m[15]||(m[15]=[z(" Copy ",-1)])]),_:1},8,["trailing-icon"])])):$("",!0),t(s)?.failingLocator?(n(),c("div",uo,[k(ce,{name:"i-lucide-x-circle",class:"size-4 text-red-500 shrink-0"}),u("code",fo,v(t(A)),1),k(K,{size:"xs",variant:"ghost",color:"neutral",icon:t(y)==="failing"?"i-lucide-check":"i-lucide-copy",title:t(y)==="failing"?"Copied!":"Copy",onClick:m[2]||(m[2]=F=>V(t(A),"failing"))},null,8,["icon","title"])])):$("",!0),t(s)?.priorNameMayBeStale?(n(),P(de,{key:3,class:"mb-3",color:"warning",icon:"i-lucide-alert-triangle",variant:"subtle",title:"The element's name looks changed",description:"The captured accessible name no longer appears on the failing page, so name-based alternatives (and the failing locator itself) probably no longer match. Prefer the structural options, or the failing-page candidates below."})):$("",!0),t(G)?(n(),c("div",mo,[u("div",po,[k(ce,{name:"i-lucide-star",class:"size-4 text-primary shrink-0"}),m[16]||(m[16]=u("p",{class:"text-xs font-medium text-primary shrink-0"},"Recommended fix",-1)),t(Y)?(n(),c("span",go," · "+v(t(Y)),1)):$("",!0),m[17]||(m[17]=u("span",{class:"flex-1"},null,-1)),k(_e,{size:"xs",color:"primary",variant:"subtle",class:"font-mono tabular-nums shrink-0"},{default:C(()=>[z(v(t(G).score),1)]),_:1})]),t(he)?(n(),c("div",ho,[k(Te,{patch:t(he).patch},null,8,["patch"])])):(n(),c(H,{key:1},[u("code",vo,v(t(G).locator),1),t(ye).length?(n(),c("p",yo,[(n(!0),c(H,null,se(t(ye),(F,re)=>(n(),c(H,{key:re},[u("span",xo,v(F.key)+":",1),F.from?(n(),c("span",bo,v(F.from),1)):(n(),c("span",ko,"—")),k(ce,{name:"i-lucide-arrow-right",class:"size-3 text-gray-400"}),F.to?(n(),c("span",_o,v(F.to),1)):(n(),c("span",$o,"removed"))],64))),128))])):$("",!0)],64)),t(b)?(n(),c("p",wo,v(t(b)),1)):$("",!0),t(Z)?(n(),c("p",Co,[k(ce,{name:"i-lucide-layers",class:"size-3 shrink-0"}),z(v(t(Z)),1)])):$("",!0),u("div",So,[k(K,{size:"xs",color:"primary",variant:"solid","trailing-icon":t(y)==="top"?"i-lucide-check":"i-lucide-copy",onClick:m[3]||(m[3]=F=>V(t(G).locator,"top"))},{default:C(()=>[...m[18]||(m[18]=[z(" Copy locator ",-1)])]),_:1},8,["trailing-icon"]),k(K,{size:"xs",color:"neutral",variant:"outline",icon:t(y)==="fix-prompt"?"i-lucide-check":"i-lucide-sparkles",title:"Copy an instruction an AI coding agent can apply directly to the test",onClick:Pe},{default:C(()=>[...m[19]||(m[19]=[z(" Copy fix prompt ",-1)])]),_:1},8,["icon"])])])):$("",!0),t(T)?.hasDurableAlternative&&t(T).durable?(n(),c("div",To,[k(ce,{name:"i-lucide-shield-check",class:"size-5 text-success shrink-0"}),u("div",Lo,[u("p",zo," Most stable option (score: "+v(t(T).durable.score)+") ",1),u("code",Io,v(t(T).durable.locator),1),m[20]||(m[20]=u("p",{class:"text-xs text-gray-500 mt-0.5"},"Sturdier, but changes the locator style",-1))]),k(K,{size:"sm",color:"neutral",variant:"outline","trailing-icon":t(y)==="durable"?"i-lucide-check":"i-lucide-copy",onClick:m[4]||(m[4]=F=>V(t(T).durable.locator,"durable"))},{default:C(()=>[...m[21]||(m[21]=[z(" Copy ",-1)])]),_:1},8,["trailing-icon"])])):$("",!0),u("div",Ao,[m[22]||(m[22]=u("p",{class:"text-xs font-medium text-gray-500"},"All alternatives",-1)),(n(!0),c(H,null,se(t(ke),(F,re)=>(n(),P(Ce,{key:re,alt:F,copied:t(y)===`alt-${re}`,onCopy:be=>V(F.locator,`alt-${re}`)},null,8,["alt","copied","onCopy"]))),128)),t(l).length>ot?(n(),P(K,{key:0,size:"xs",variant:"ghost",color:"neutral",block:"",icon:t(ne)?"i-lucide-chevron-up":"i-lucide-chevron-down",onClick:m[5]||(m[5]=F=>ne.value=!t(ne))},{default:C(()=>[z(v(t(ne)?"Show fewer":`Show all ${t(l).length} alternatives`),1)]),_:1},8,["icon"])):$("",!0)]),t(I).length?(n(),c("div",Ro,[m[23]||(m[23]=u("p",{class:"text-xs font-medium text-gray-500 mb-2"},"From the failing page",-1)),u("div",Bo,[(n(!0),c(H,null,se(t(I),(F,re)=>(n(),P(Ce,{key:re,alt:F,note:"candidate from the failure-time ARIA snapshot",copied:t(y)===`supp-${re}`,onCopy:be=>V(F.locator,`supp-${re}`)},null,8,["alt","copied","onCopy"]))),128))])])):$("",!0),t(T)?.suggestAddTestId?(n(),P(de,{key:7,class:"mt-3",color:"warning",icon:"i-lucide-info",variant:"subtle",title:"All alternatives are fragile",description:"Every captured locator scores below 50. Add a stable data-testid attribute to this element in the app for a durable fix."})):$("",!0),t(s)?.source==="aria-snapshot"?(n(),P(de,{key:8,class:"mt-3",color:"info",icon:"i-lucide-info",variant:"subtle"},{description:C(()=>[m[25]||(m[25]=z(" No HTML attributes were available. ",-1)),k(ue,{to:"capture-fixtures","no-icon":"",class:"text-primary hover:underline"},{default:C(()=>[...m[24]||(m[24]=[z("Enable Piwi fixture capture",-1)])]),_:1}),m[26]||(m[26]=z(" for full alternatives including data-testid and CSS selectors. ",-1))]),_:1})):$("",!0)]),_:2},[e.storageKey?{name:"folded",fn:C(()=>[t(T)?.recommended?(n(),c("code",oo,v(t(T).recommended.locator),1)):(n(),c("span",so,v(t(l).length)+" alternative"+v(t(l).length===1?"":"s"),1))]),key:"0"}:void 0,t(E)||t(s)?.failingLocator?{name:"actions",fn:C(()=>[u("div",ao,[t(s)?.failingLocator?(n(),P(K,{key:0,size:"xs",color:"neutral",variant:"outline",icon:"i-lucide-mouse-pointer",title:"Open the failure-time DOM snapshot and click the element to pick a locator",onClick:m[0]||(m[0]=F=>B.value=!0)},{default:C(()=>[...m[9]||(m[9]=[z(" Pick from snapshot ",-1)])]),_:1})):$("",!0),t(E)?(n(),P(K,{key:1,to:t(E),target:"_blank",size:"xs",color:"neutral",variant:"outline",icon:"i-lucide-crosshair",title:"Open the failure trace in the trace viewer — its Pick locator tool works on the recorded page snapshots"},{default:C(()=>[...m[10]||(m[10]=[z(" Pick from trace ",-1)])]),_:1},8,["to"])):$("",!0)])]),key:"1"}:void 0]),1040,["count"])):!t(a)&&!t(o)&&!t(p)?(n(),P(Se(t(i)),je({key:1},t(d),{icon:"i-lucide-bandage",title:"Alternative locators",subtitle:"No alternatives available",help:"locator-healing"}),Ie({default:C(()=>[k(de,{color:"neutral",icon:"i-lucide-info",variant:"subtle"},{description:C(()=>[m[31]||(m[31]=z(" No pre-captured alternatives — this locator has never passed in a previous run. ",-1)),k(ue,{to:"capture-fixtures","no-icon":"",class:"text-primary hover:underline"},{default:C(()=>[...m[30]||(m[30]=[z("Enable Piwi dashboard fixtures",-1)])]),_:1}),m[32]||(m[32]=z(" to capture element attributes at test time, or use “Pick from snapshot” above to choose a locator by hand on the failure-time page. ",-1))]),_:1})]),_:2},[e.storageKey?{name:"folded",fn:C(()=>[m[27]||(m[27]=u("span",null,"No alternatives available",-1))]),key:"0"}:void 0,t(E)||t(s)?.failingLocator?{name:"actions",fn:C(()=>[u("div",Po,[t(s)?.failingLocator?(n(),P(K,{key:0,size:"xs",color:"neutral",variant:"outline",icon:"i-lucide-mouse-pointer",title:"Open the failure-time DOM snapshot and click the element to pick a locator",onClick:m[6]||(m[6]=F=>B.value=!0)},{default:C(()=>[...m[28]||(m[28]=[z(" Pick from snapshot ",-1)])]),_:1})):$("",!0),t(E)?(n(),P(K,{key:1,to:t(E),target:"_blank",size:"xs",color:"neutral",variant:"outline",icon:"i-lucide-crosshair",title:"Open the failure trace in the trace viewer — its Pick locator tool works on the recorded page snapshots"},{default:C(()=>[...m[29]||(m[29]=[z(" Pick from trace ",-1)])]),_:1},8,["to"])):$("",!0)])]),key:"1"}:void 0]),1040)):$("",!0),t(s)?.failingLocator?(n(),P(Gn,{key:2,open:t(B),"onUpdate:open":m[7]||(m[7]=F=>ze(B)?B.value=F:null),"run-id":e.runId,"test-runs-case-id":e.testRunsCaseId,"failing-locator":t(s).failingLocator,healing:t(s),onConfirmed:le,onClose:m[8]||(m[8]=F=>B.value=!1)},null,8,["open","run-id","test-runs-case-id","failing-locator","healing"])):$("",!0)],64)}}}),Pa=Object.assign(Eo,{__name:"LocatorHealingPanel"}),Oo={key:1,class:"space-y-2"},Uo={class:"text-xs font-medium text-gray-500 dark:text-gray-400 sm:w-40 shrink-0"},jo={class:"flex flex-wrap items-center gap-1.5 min-w-0 text-xs font-mono"},Mo={class:"rounded bg-red-50 px-1.5 py-0.5 text-red-700 dark:bg-red-950/30 dark:text-red-400 break-all"},No={class:"rounded bg-green-50 px-1.5 py-0.5 text-green-700 dark:bg-green-950/30 dark:text-green-400 break-all"},Ko={key:0,class:"text-xs text-gray-400 dark:text-gray-500"},Do={key:0},Vo=te({__name:"EnvironmentDiffCard",props:{runId:{},testRunsCaseId:{},storageKey:{}},setup(e,{expose:r}){const i=e,d=S(()=>i.storageKey?Ke:Ne),s=S(()=>i.storageKey?{storageKey:i.storageKey}:{}),{data:a,pending:o,error:p}=Me(()=>`/api/test-runs/${i.runId}/cases/${i.testRunsCaseId}/environment-diff`,{lazy:!0},"$yASgALxNz3"),l=S(()=>a.value?.entries??[]),g=S(()=>l.value.filter(x=>!x.informational)),T=S(()=>l.value.filter(x=>x.informational)),I=S(()=>{const x=a.value?.baseline;if(!x)return"";const A=x.startTime?` · ${Ge(new Date(x.startTime))}`:"";return`vs last pass in run #${x.runId}${A}`}),b=S(()=>{if(a.value?.status!=="ok")return"No passing baseline to compare against";const x=g.value.length;return x===0?"Identical to last pass — no environment drift":`${x} change${x===1?"":"s"}: ${g.value.map(A=>A.label).join(", ")}`}),L=U(null);return r({reveal:()=>L.value?.reveal?.()}),(x,A)=>{const j=Ye,D=ve;return!t(o)&&!t(p)&&t(a)?.status==="ok"?(n(),P(Se(t(d)),je({key:0,ref_key:"card",ref:L},t(s),{icon:"i-lucide-git-compare-arrows",title:"Environment diff",count:t(g).length||void 0,help:"environment-diff",subtitle:t(I)}),Ie({default:C(()=>[t(l).length===0?(n(),P(j,{key:0,color:"success",icon:"i-lucide-check-circle",variant:"subtle",description:"The environment is identical to the last passing run — environment drift is unlikely to explain this failure."})):(n(),c("div",Oo,[(n(!0),c(H,null,se(t(g),E=>(n(),c("div",{key:E.key,class:"rounded-lg border border-default p-3 flex flex-col gap-1 sm:flex-row sm:items-center sm:gap-3"},[u("span",Uo,v(E.label),1),u("div",jo,[u("code",Mo,v(E.failing??"(unset)"),1),k(D,{name:"i-lucide-arrow-left",class:"size-3 shrink-0 text-gray-400"}),u("code",No,v(E.baseline??"(unset)"),1)])]))),128)),t(T).length>0?(n(),c("p",Ko,[A[0]||(A[0]=z(" Also changed (varies naturally between runs): ",-1)),(n(!0),c(H,null,se(t(T),(E,B)=>(n(),c("span",{key:E.key},[z(v(E.label.toLowerCase())+" "+v(E.baseline??"—")+" → "+v(E.failing??"—"),1),B<t(T).length-1?(n(),c("span",Do,", ")):$("",!0)]))),128))])):$("",!0)]))]),_:2},[e.storageKey?{name:"folded",fn:C(()=>[u("span",null,v(t(b)),1)]),key:"0"}:void 0]),1040,["count","subtitle"])):$("",!0)}}}),Ea=Object.assign(Vo,{__name:"EnvironmentDiffCard"}),Ho={class:"absolute top-4 left-4 text-white/70 text-sm font-medium"},Fo=["src","alt"],qo=te({__name:"ScreenshotLightbox",props:{images:{},modelValue:{}},emits:["update:modelValue"],setup(e,{emit:r}){const i=e,d=r,s=S(()=>i.modelValue!==null);function a(){d("update:modelValue",null)}function o(){i.modelValue!==null&&i.modelValue>0&&d("update:modelValue",i.modelValue-1)}function p(){i.modelValue!==null&&i.modelValue<i.images.length-1&&d("update:modelValue",i.modelValue+1)}const l=S(()=>i.modelValue===null?null:i.images[i.modelValue]??null);function g(T){s.value&&(T.key==="Escape"&&a(),T.key==="ArrowLeft"&&o(),T.key==="ArrowRight"&&p())}return at(()=>window.addEventListener("keydown",g)),_t(()=>window.removeEventListener("keydown",g)),(T,I)=>{const b=ve;return n(),P($t,{to:"body"},[k(wt,{name:"lightbox"},{default:C(()=>[s.value?(n(),c("div",{key:0,class:"fixed inset-0 z-50 flex items-center justify-center bg-black/90",onClick:ge(a,["self"])},[u("button",{class:"absolute top-4 right-4 size-10 flex items-center justify-center rounded-full bg-white/10 text-white hover:bg-white/20 transition-colors",onClick:a},[k(b,{name:"i-lucide-x",class:"size-6"})]),u("div",Ho,v((e.modelValue??0)+1)+" / "+v(e.images.length),1),e.images.length>1&&(e.modelValue??0)>0?(n(),c("button",{key:0,class:"absolute left-4 size-10 flex items-center justify-center rounded-full bg-white/10 text-white hover:bg-white/20 transition-colors",onClick:o},[k(b,{name:"i-lucide-chevron-left",class:"size-6"})])):$("",!0),l.value?(n(),c("img",{key:1,src:l.value.src,alt:l.value.name,class:"max-h-[90vh] max-w-[90vw] object-contain rounded-lg",onClick:I[0]||(I[0]=ge(()=>{},["stop"]))},null,8,Fo)):$("",!0),e.images.length>1&&(e.modelValue??0)<e.images.length-1?(n(),c("button",{key:2,class:"absolute right-4 size-10 flex items-center justify-center rounded-full bg-white/10 text-white hover:bg-white/20 transition-colors",onClick:p},[k(b,{name:"i-lucide-chevron-right",class:"size-6"})])):$("",!0)])):$("",!0)]),_:1})])}}}),mt=Object.assign(Ct(qo,[["__scopeId","data-v-c02b1e9b"]]),{__name:"ScreenshotLightbox"}),Zo={class:"flex justify-end mb-2"},Wo={key:1,class:"rounded overflow-hidden border border-default bg-gray-50 dark:bg-gray-900"},Jo=["src"],Go={key:2,class:"grid grid-cols-1 sm:grid-cols-2 gap-2"},Yo={class:"rounded overflow-hidden border border-red-200 dark:border-red-900 bg-gray-50 dark:bg-gray-900"},Qo=["src"],Xo={class:"rounded overflow-hidden border border-green-200 dark:border-green-900 bg-gray-50 dark:bg-gray-900"},es={class:"px-2 py-1 text-[10px] font-medium text-green-600 dark:text-green-400"},ts=["src"],ns=te({__name:"VisualDiffCard",props:{runId:{},testRunsCaseId:{},storageKey:{}},setup(e,{expose:r}){const i=e,d=S(()=>i.storageKey?Ke:Ne),s=S(()=>i.storageKey?{storageKey:i.storageKey}:{}),a=Re(),{data:o,pending:p,error:l}=Me(()=>`/api/test-runs/${i.runId}/cases/${i.testRunsCaseId}/visual-diff`,{lazy:!0},"$nTbSHl3faK"),g=S(()=>o.value?.status==="ok"?o.value.diff??null:null),T=U("overlay"),I=[{label:"Overlay",value:"overlay"},{label:"Side by side",value:"side-by-side"}],b=S(()=>g.value?Ue(g.value.path,"image/png",a.app?.baseURL):""),L=S(()=>g.value?Ue(g.value.failingPath,null,a.app?.baseURL):""),x=S(()=>g.value?Ue(g.value.baselinePath,null,a.app?.baseURL):""),A=S(()=>g.value?(g.value.changedPixelRatio*100).toFixed(2):"0"),j=S(()=>{const ee=g.value?.changedPixelRatio??0;return ee>.1?"error":ee>.01?"warning":"success"}),D=S(()=>g.value?g.value.dimensionMismatch?`${A.value}% changed — dimensions differ, unreliable`:`${A.value}% of pixels changed vs last pass`:"No comparable screenshots"),E=S(()=>g.value?[{src:L.value,name:"Failing screenshot"},{src:x.value,name:"Last passing screenshot"},{src:b.value,name:"Diff overlay"}]:[]),B=U(null),le=U(null);return r({reveal:()=>le.value?.reveal?.()}),(ee,y)=>{const q=Be,M=Ye,V=Et,G=mt;return!t(p)&&!t(l)&&t(g)?(n(),P(Se(t(d)),je({key:0,ref_key:"card",ref:le},t(s),{icon:"i-lucide-images",title:"Visual diff",help:"visual-diff"}),Ie({subtitle:C(()=>[u("span",null,"vs last pass in run #"+v(t(g).baselineRunId),1)]),actions:C(()=>[k(q,{color:t(j),variant:"subtle",size:"sm",class:"font-mono tabular-nums"},{default:C(()=>[z(v(t(A))+"% changed ",1)]),_:1},8,["color"])]),default:C(()=>[t(g).dimensionMismatch?(n(),P(M,{key:0,class:"mb-3",color:"warning",icon:"i-lucide-alert-triangle",variant:"subtle",title:"Screenshot dimensions differ",description:"The failing and passing screenshots have different sizes (viewport change?). They are compared on a padded canvas, so the changed-pixel ratio is inflated and unreliable."})):$("",!0),u("div",Zo,[k(V,{modelValue:t(T),"onUpdate:modelValue":y[0]||(y[0]=Z=>ze(T)?T.value=Z:null),items:I,size:"xs",content:!1,ui:{list:"overflow-x-auto",trigger:"shrink-0"}},null,8,["modelValue"])]),t(T)==="overlay"?(n(),c("div",Wo,[u("img",{src:t(b),alt:"Diff overlay (red = changed pixels)",class:"w-full max-h-96 object-contain cursor-zoom-in outline-none focus-visible:outline-2 focus-visible:outline-primary",loading:"lazy",role:"button",tabindex:"0","aria-label":"Open diff overlay in lightbox",onClick:y[1]||(y[1]=Z=>B.value=2),onKeydown:[y[2]||(y[2]=pe(Z=>B.value=2,["enter"])),y[3]||(y[3]=pe(ge(Z=>B.value=2,["prevent"]),["space"]))]},null,40,Jo),y[11]||(y[11]=u("p",{class:"px-2 py-1 text-[10px] text-gray-500"},"Red pixels mark differences against the last passing run",-1))])):(n(),c("div",Go,[u("div",Yo,[y[12]||(y[12]=u("p",{class:"px-2 py-1 text-[10px] font-medium text-red-600 dark:text-red-400"},"Failing",-1)),u("img",{src:t(L),alt:"Failing screenshot",class:"w-full max-h-80 object-contain cursor-zoom-in outline-none focus-visible:outline-2 focus-visible:outline-primary",loading:"lazy",role:"button",tabindex:"0","aria-label":"Open failing screenshot in lightbox",onClick:y[4]||(y[4]=Z=>B.value=0),onKeydown:[y[5]||(y[5]=pe(Z=>B.value=0,["enter"])),y[6]||(y[6]=pe(ge(Z=>B.value=0,["prevent"]),["space"]))]},null,40,Qo)]),u("div",Xo,[u("p",es," Last pass (run #"+v(t(g).baselineRunId)+") ",1),u("img",{src:t(x),alt:"Last passing screenshot",class:"w-full max-h-80 object-contain cursor-zoom-in outline-none focus-visible:outline-2 focus-visible:outline-primary",loading:"lazy",role:"button",tabindex:"0","aria-label":"Open last passing screenshot in lightbox",onClick:y[7]||(y[7]=Z=>B.value=1),onKeydown:[y[8]||(y[8]=pe(Z=>B.value=1,["enter"])),y[9]||(y[9]=pe(ge(Z=>B.value=1,["prevent"]),["space"]))]},null,40,ts)])])),k(G,{modelValue:t(B),"onUpdate:modelValue":y[10]||(y[10]=Z=>ze(B)?B.value=Z:null),images:t(E)},null,8,["modelValue","images"])]),_:2},[e.storageKey?{name:"folded",fn:C(()=>[u("span",null,v(t(D)),1)]),key:"0"}:void 0]),1040)):$("",!0)}}}),Oa=Object.assign(ns,{__name:"VisualDiffCard"}),os={class:"max-h-96 overflow-y-auto"},ss={key:0,class:"mt-2 text-xs text-gray-400 dark:text-gray-500"},Ze=2e4,as=te({__name:"DomSnapshotCard",props:{runId:{},testRunsCaseId:{},storageKey:{}},setup(e,{expose:r}){const i=e,d=S(()=>i.storageKey?Ke:Ne),s=S(()=>i.storageKey?{storageKey:i.storageKey}:{}),{data:a,pending:o,error:p}=Me(()=>`/api/test-runs/${i.runId}/cases/${i.testRunsCaseId}/dom-snapshot`,{lazy:!0},"$AxHFpokm2o"),l=S(()=>(a.value?.html??"").slice(0,Ze)),g=S(()=>(a.value?.html?.length??0)>Ze),T=S(()=>{const x=a.value;return!x||x.status!=="ok"?"":`${Math.round((x.html?.length??0)/1024)} KB · rendered from the uploaded trace${x.snapshotName?` (${x.snapshotName})`:""}`}),{copy:I,copied:b}=He(),L=U(null);return r({reveal:()=>L.value?.reveal?.()}),(x,A)=>{const j=Ae,D=Ot,E=Ut;return!t(o)&&!t(p)&&t(a)?.status==="ok"&&t(a).html?(n(),P(Se(t(d)),je({key:0,ref_key:"card",ref:L},t(s),{icon:"i-lucide-file-code",title:"DOM snapshot",help:"dom-snapshot",subtitle:t(T)}),Ie({actions:C(()=>[k(D,{text:t(b)?"Copied!":"Copy full HTML"},{default:C(()=>[k(j,{size:"xs",variant:"ghost",color:"neutral",icon:t(b)?"i-lucide-check":"i-lucide-clipboard",onClick:A[0]||(A[0]=B=>t(I)(t(a).html))},null,8,["icon"])]),_:1},8,["text"])]),default:C(()=>[u("div",os,[k(E,{code:t(l),lang:"xml"},null,8,["code"])]),t(g)||t(a).truncated?(n(),c("p",ss,[t(g)?(n(),c(H,{key:0},[z("Showing the first "+v(Math.round(Ze/1e3))+"k characters — use Copy for the full document.",1)],64)):(n(),c(H,{key:1},[z("The snapshot was truncated to its size cap.")],64))])):$("",!0)]),_:2},[e.storageKey?{name:"folded",fn:C(()=>[u("span",null,"Failure-time HTML extracted from the trace — "+v(Math.round((t(a).html.length??0)/1024))+" KB",1)]),key:"0"}:void 0]),1040,["subtitle"])):$("",!0)}}}),Ua=Object.assign(as,{__name:"DomSnapshotCard"}),rs={class:"rounded-md border border-default overflow-hidden"},is={class:"text-xs font-semibold text-gray-600 dark:text-gray-300 flex-1"},ls={key:0,class:"text-gray-400 font-normal ml-1"},cs={key:0},us=te({__name:"TestEvidenceSection",props:We({icon:{},label:{},count:{},collapsible:{type:Boolean}},{open:{type:Boolean,default:!1},openModifiers:{}}),emits:["update:open"],setup(e){const r=e,i=st(e,"open"),d=S(()=>r.collapsible===!1||i.value);return(s,a)=>{const o=ve;return n(),c("div",rs,[(n(),P(Se(e.collapsible===!1?"div":"button"),{class:ae(["w-full flex items-center gap-1.5 px-3 py-2 bg-elevated border-b border-default text-left",e.collapsible!==!1&&"hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors cursor-pointer"]),onClick:a[0]||(a[0]=p=>e.collapsible!==!1&&(i.value=!i.value))},{default:C(()=>[k(o,{name:e.icon,class:"size-3.5 shrink-0 text-primary/70"},null,8,["name"]),u("span",is,[z(v(e.label),1),e.count!=null?(n(),c("span",ls,"("+v(e.count)+")",1)):$("",!0)]),e.collapsible!==!1?(n(),P(o,{key:0,name:i.value?"i-lucide-chevron-up":"i-lucide-chevron-down",class:"size-3.5 text-gray-400"},null,8,["name"])):$("",!0)]),_:1},8,["class"])),t(d)?(n(),c("div",cs,[Oe(s.$slots,"default")])):$("",!0)])}}}),Qe=Object.assign(us,{__name:"TestEvidenceSection"}),ds={class:"grid grid-cols-2 gap-2 p-2 bg-gray-50 dark:bg-gray-900"},fs=["aria-label","onClick","onKeydown"],ms=["src","alt"],ps={class:"absolute inset-0 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity bg-black/30"},gs={class:"absolute bottom-0 inset-x-0 px-1.5 py-0.5 text-[10px] text-white bg-black/50 truncate"},hs=te({__name:"TestEvidenceScreenshots",props:{attachments:{}},setup(e){const r=e,i=Re();function d(o){return o.split("/").pop()||o}const s=S(()=>r.attachments.filter(o=>Mt(o.path,o.contentType)).map(o=>({src:Ue(o.path,o.contentType,i.app?.baseURL),name:o.name||d(o.path)}))),a=U(null);return(o,p)=>{const l=ve,g=mt,T=Qe;return t(s).length>0?(n(),P(T,{key:0,icon:"i-lucide-image",label:"Screenshots",count:t(s).length,collapsible:!1},{default:C(()=>[u("div",ds,[(n(!0),c(H,null,se(t(s),(I,b)=>(n(),c("div",{key:I.src,class:"relative group cursor-pointer rounded overflow-hidden border border-default outline-none focus-visible:outline-2 focus-visible:outline-primary",role:"button",tabindex:"0","aria-label":`View screenshot ${I.name}`,onClick:L=>a.value=b,onKeydown:[pe(L=>a.value=b,["enter"]),pe(ge(L=>a.value=b,["prevent"]),["space"])]},[u("img",{src:I.src,alt:I.name,class:"w-full h-28 object-cover object-top transition-opacity group-hover:opacity-80",loading:"lazy"},null,8,ms),u("div",ps,[k(l,{name:"i-lucide-zoom-in",class:"size-5 text-white"})]),u("p",gs,v(I.name),1)],40,fs))),128))]),k(g,{modelValue:t(a),"onUpdate:modelValue":p[0]||(p[0]=I=>ze(a)?a.value=I:null),images:t(s)},null,8,["modelValue","images"])]),_:1},8,["count"])):$("",!0)}}}),ja=Object.assign(hs,{__name:"TestEvidenceScreenshots"}),vs={class:"m-0"},ys={class:"bg-black rounded overflow-hidden"},xs=["src"],bs=["title"],ks=te({__name:"VideoPlayer",props:{src:{},label:{}},setup(e){return(r,i)=>(n(),c("figure",vs,[u("div",ys,[u("video",{src:e.src,controls:"",preload:"metadata",class:"w-full max-h-96"}," Your browser does not support the video tag. ",8,xs)]),e.label?(n(),c("figcaption",{key:0,class:"mt-1 text-xs text-gray-400 truncate",title:e.label},v(e.label),9,bs)):$("",!0)]))}}),_s=Object.assign(ks,{__name:"VideoPlayer"}),$s={class:"space-y-2 p-2 bg-gray-50 dark:bg-gray-900"},ws=te({__name:"TestEvidenceVideos",props:{attachments:{}},setup(e){const r=e,i=Re();function d(a){return a.split("/").pop()||a}const s=S(()=>r.attachments.filter(a=>Nt(a.path,a.contentType)).map(a=>({src:Ue(a.path,a.contentType,i.app?.baseURL),name:a.name||d(a.path)})));return(a,o)=>{const p=_s,l=Qe;return t(s).length>0?(n(),P(l,{key:0,icon:"i-lucide-video",label:"Videos",count:t(s).length,collapsible:!1},{default:C(()=>[u("div",$s,[(n(!0),c(H,null,se(t(s),g=>(n(),P(p,{key:g.src,src:g.src,label:g.name},null,8,["src","label"]))),128))])]),_:1},8,["count"])):$("",!0)}}}),Ma=Object.assign(ws,{__name:"TestEvidenceVideos"}),Cs={class:"flex items-center justify-between gap-2"},Ss={class:"flex items-center gap-2 min-w-0"},Ts={class:"text-sm truncate"},Ls={key:0,class:"text-xs text-gray-400 shrink-0"},zs={key:1,class:"text-xs text-gray-400 shrink-0"},Is={class:"flex items-center gap-1.5 shrink-0"},As=te({__name:"TraceListItem",props:{trace:{},showTime:{type:Boolean,default:!0}},setup(e){const r=e,i=Re(),d=S(()=>(i.app?.baseURL??"/").replace(/\/$/,"")),s=S(()=>!!i.public.demoMode&&r.trace.filePath.startsWith("demo/")),a=S(()=>r.trace.filePath.split("/").pop()||r.trace.filePath),o=S(()=>lt(r.trace.filePath,i.app?.baseURL,s.value)),p=S(()=>s.value?`${d.value}/${r.trace.filePath}`:`${d.value}/api/files/${Bt(r.trace.filePath)}`);return(l,g)=>{const T=ve,I=Ae;return n(),c("div",Cs,[u("div",Ss,[k(T,{name:"i-lucide-file-archive",class:"size-4 text-gray-400 shrink-0"}),u("span",Ts,v(t(a)),1),e.trace.size?(n(),c("span",Ls,v(("formatBytes"in l?l.formatBytes:t(Kt))(e.trace.size)),1)):$("",!0),e.showTime?(n(),c("span",zs,v(("formatRelativeTime"in l?l.formatRelativeTime:t(Ge))(e.trace.createdAt)),1)):$("",!0)]),u("div",Is,[k(I,{to:t(o),target:"_blank",icon:"i-lucide-bug-play",size:"xs",label:"View trace"},null,8,["to"]),k(I,{to:t(p),target:"_blank",icon:"i-lucide-download",size:"xs",color:"neutral",variant:"soft",label:"Download"},null,8,["to"])])])}}}),Rs=Object.assign(As,{__name:"TraceListItem"}),Bs={key:0,class:"flex items-center justify-center py-4"},Ps={key:1,class:"divide-y divide-default"},Es=te({__name:"TestEvidenceTraces",props:{traces:{},loading:{type:Boolean}},setup(e){return(r,i)=>{const d=ve,s=Rs,a=Qe;return e.loading||e.traces.length>0?(n(),P(a,{key:0,icon:"i-lucide-bug-play",label:"Traces",count:e.traces.length||null,collapsible:!1},{default:C(()=>[e.loading&&!e.traces.length?(n(),c("div",Bs,[k(d,{name:"i-lucide-loader-circle",class:"size-4 animate-spin text-gray-400"})])):(n(),c("div",Ps,[(n(!0),c(H,null,se(e.traces,o=>(n(),P(s,{key:o.id,trace:o,class:"px-3 py-2"},null,8,["trace"]))),128))]))]),_:1},8,["count"])):$("",!0)}}}),Na=Object.assign(Es,{__name:"TestEvidenceTraces"}),Os={class:"space-y-2"},Us={key:0,class:"rounded-lg border border-default overflow-hidden"},js=["title"],Ms={key:2,class:"truncate text-gray-400 dark:text-gray-500"},Ns={class:"font-mono"},Ks={key:0,class:"overflow-x-auto text-xs font-mono leading-relaxed py-1"},Ds={class:"min-w-max"},Vs={key:1,class:"rounded-lg border border-dashed border-default"},Hs=["onClick"],Fs={key:0,class:"px-3 pb-2 space-y-1"},qs=["title"],Zs={key:0,class:"truncate font-mono shrink-0"},Ws=te({__name:"TraceCallStack",props:{frames:{},projectKey:{},projectName:{}},setup(e){const r=e,i=S(()=>{if(!r.frames.some(I=>I.inProject))return r.frames.map((I,b)=>({kind:"frame",frame:I,frameIndex:b}));const l=[];let g=[];const T=()=>{g.length!==0&&(l.push({kind:"group",frames:g,key:`group-${l.length}`}),g=[])};return r.frames.forEach((I,b)=>{I.inProject?(T(),l.push({kind:"frame",frame:I,frameIndex:b})):g.push(I)}),T(),l}),d=S(()=>{const p=r.frames.findIndex(l=>l.inProject);return p>=0?p:0}),s=U(new Set);function a(p){const l=new Set(s.value);l.has(p)?l.delete(p):l.add(p),s.value=l}function o(p){return p.source?p.source.lines.map((l,g)=>{const T=p.source.startLine+g;return{lineNo:T,text:l,failing:T===p.line}}):[]}return(p,l)=>{const g=ve,T=ct,I=Be;return n(),c("div",Os,[(n(!0),c(H,null,se(t(i),b=>(n(),c(H,{key:b.kind==="frame"?`f-${b.frameIndex}`:b.key},[b.kind==="frame"?(n(),c("div",Us,[u("div",{class:ae(["flex items-center gap-2 px-3 py-1.5 bg-elevated/40 text-xs",b.frame.source?"border-b border-default":""])},[k(g,{name:b.frameIndex===t(d)?"i-lucide-circle-x":"i-lucide-corner-left-up",class:ae([b.frameIndex===t(d)?"text-red-500":"text-gray-400","size-3.5 shrink-0"])},null,8,["name","class"]),b.frame.inProject?(n(),P(T,{key:0,"file-path":b.frame.file,line:b.frame.line,column:b.frame.column,"project-key":e.projectKey,"project-name":e.projectName,class:"min-w-0"},null,8,["file-path","line","column","project-key","project-name"])):(n(),c("code",{key:1,class:"truncate text-gray-500 dark:text-gray-400",title:b.frame.absFile||b.frame.file},v(b.frame.file)+":"+v(b.frame.line),9,js)),b.frame.functionName?(n(),c("span",Ms,[l[0]||(l[0]=z(" in ",-1)),u("span",Ns,v(b.frame.functionName),1)])):$("",!0),k(I,{color:b.frameIndex===t(d)?"error":"neutral",variant:"subtle",size:"xs",class:"ml-auto shrink-0"},{default:C(()=>[z(v(b.frameIndex===t(d)?"Failed here":"Caller"),1)]),_:2},1032,["color"])],2),b.frame.source?(n(),c("div",Ks,[u("div",Ds,[(n(!0),c(H,null,se(o(b.frame),L=>(n(),c("div",{key:L.lineNo,class:ae(["px-3 whitespace-pre flex",L.failing?"bg-red-50 dark:bg-red-950/30 text-red-700 dark:text-red-300 font-medium":"text-gray-600 dark:text-gray-400"])},[u("span",{class:ae(["w-10 shrink-0 text-right pr-3 tabular-nums select-none",L.failing?"text-red-400 dark:text-red-500":"text-gray-300 dark:text-gray-600"])},v(L.lineNo),3),u("span",null,v(L.text),1)],2))),128))])])):$("",!0)])):(n(),c("div",Vs,[u("button",{type:"button",class:"w-full flex items-center gap-2 px-3 py-1.5 text-xs text-gray-400 dark:text-gray-500 hover:text-gray-600 dark:hover:text-gray-300",onClick:L=>a(b.key)},[k(g,{name:t(s).has(b.key)?"i-lucide-chevron-down":"i-lucide-chevron-right",class:"size-3.5 shrink-0"},null,8,["name"]),z(" "+v(b.frames.length)+" frame"+v(b.frames.length===1?"":"s")+" in dependencies ",1)],8,Hs),t(s).has(b.key)?(n(),c("div",Fs,[(n(!0),c(H,null,se(b.frames,(L,x)=>(n(),c("div",{key:x,class:"flex items-center gap-2 text-xs text-gray-400 dark:text-gray-500 min-w-0"},[k(g,{name:"i-lucide-corner-left-up",class:"size-3 shrink-0"}),u("code",{class:"truncate",title:L.absFile||L.file},v(L.file)+":"+v(L.line),9,qs),L.functionName?(n(),c("span",Zs,v(L.functionName),1)):$("",!0)]))),128))])):$("",!0)]))],64))),128))])}}}),Ka=Object.assign(Ws,{__name:"TraceCallStack"}),Js={class:"space-y-2"},Gs={class:"flex items-center gap-2 px-3 py-1.5 bg-elevated/40 border-b border-default text-xs"},Ys={class:"overflow-x-auto text-xs font-mono leading-relaxed py-1"},Qs={class:"min-w-max"},Xs=te({__name:"TestSourceStack",props:{frames:{},projectKey:{},projectName:{}},setup(e){function r(i){return i.split(`
|
|
5
|
-
`).map(d=>({text:d,failing:d.startsWith(">")}))}return(i,d)=>{const s=ve,a=ct,o=Be;return n(),c("div",Js,[(n(!0),c(H,null,se(e.frames,(p,l)=>(n(),c("div",{key:`${p.file}:${p.line}:${l}`,class:"rounded-lg border border-default overflow-hidden"},[u("div",Gs,[k(s,{name:l===0?"i-lucide-circle-x":"i-lucide-corner-left-up",class:ae([l===0?"text-red-500":"text-gray-400","size-3.5 shrink-0"])},null,8,["name","class"]),k(a,{"file-path":p.file,line:p.line,"project-key":e.projectKey,"project-name":e.projectName,class:"min-w-0"},null,8,["file-path","line","project-key","project-name"]),k(o,{color:l===0?"error":"neutral",variant:"subtle",size:"xs",class:"ml-auto shrink-0"},{default:C(()=>[z(v(l===0?"Failed here":"Caller"),1)]),_:2},1032,["color"])]),u("div",Ys,[u("div",Qs,[(n(!0),c(H,null,se(r(p.snippet),(g,T)=>(n(),c("div",{key:T,class:ae(["px-3 whitespace-pre",g.failing?"bg-red-50 dark:bg-red-950/30 text-red-700 dark:text-red-300 font-medium":"text-gray-600 dark:text-gray-400"])},v(g.text),3))),128))])])]))),128))])}}}),Da=Object.assign(Xs,{__name:"TestSourceStack"}),ea={class:"space-y-3 text-sm"},ta={key:0,class:"flex flex-col gap-0.5"},na={class:"text-xs font-mono break-all"},oa={key:1,class:"flex flex-col gap-0.5"},sa={class:"text-xs font-mono break-all"},aa={class:"grid grid-cols-1 gap-3 sm:grid-cols-2"},ra={class:"text-xs font-medium text-gray-500 dark:text-gray-400"},ia={key:0,class:"text-xs text-gray-400"},la={key:1,class:"mt-1 space-y-0.5"},ca={class:"text-gray-400"},ua={class:"text-xs font-medium text-gray-500 dark:text-gray-400"},da={key:0,class:"text-xs text-gray-400"},fa={key:1,class:"mt-1 space-y-0.5"},ma={key:0,class:"text-gray-400"},pa={class:"text-gray-400"},ga=te({__name:"PageStateCard",props:{pageState:{},storageKey:{},plain:{type:Boolean}},setup(e){const r=e,i=S(()=>r.plain?"div":r.storageKey?Ke:Ne),d=S(()=>r.plain?{}:{icon:"i-lucide-database",title:"App state at test end",help:"page-state",...r.storageKey?{storageKey:r.storageKey}:{}}),s=o=>[o.httpOnly?"HttpOnly":null,o.secure?"Secure":null,o.sameSite??null].filter(Boolean).join(", "),a=S(()=>{const o=r.pageState;return[`${o.localStorage.length} localStorage`,`${o.sessionStorage.length} sessionStorage`,`${o.cookies.length} cookie${o.cookies.length===1?"":"s"}`].join(" · ")});return(o,p)=>(n(),P(Se(t(i)),St(Tt(t(d))),Ie({default:C(()=>[u("div",ea,[e.pageState.url?(n(),c("div",ta,[p[0]||(p[0]=u("span",{class:"text-xs font-medium text-gray-500 dark:text-gray-400"},"URL",-1)),u("code",na,v(e.pageState.url)+v(e.pageState.hash??""),1)])):$("",!0),e.pageState.historyState?(n(),c("div",oa,[p[1]||(p[1]=u("span",{class:"text-xs font-medium text-gray-500 dark:text-gray-400"},"History state",-1)),u("code",sa,v(e.pageState.historyState),1)])):$("",!0),u("div",aa,[(n(!0),c(H,null,se({localStorage:e.pageState.localStorage,sessionStorage:e.pageState.sessionStorage},(l,g)=>(n(),c("div",{key:g},[u("span",ra,v(g)+" ("+v(l.length)+")",1),l.length===0?(n(),c("p",ia,"empty")):(n(),c("ul",la,[(n(!0),c(H,null,se(l,T=>(n(),c("li",{key:T.key,class:"text-xs font-mono truncate"},[z(v(T.key)+" ",1),u("span",ca,"("+v(T.length)+" ch)",1)]))),128))]))]))),128))]),u("div",null,[u("span",ua,"Cookies ("+v(e.pageState.cookies.length)+")",1),e.pageState.cookies.length===0?(n(),c("p",da,"none")):(n(),c("ul",fa,[(n(!0),c(H,null,se(e.pageState.cookies,l=>(n(),c("li",{key:l.name+l.domain,class:"text-xs font-mono truncate"},[z(v(l.name)+" ",1),s(l)?(n(),c("span",ma,"["+v(s(l))+"]",1)):$("",!0),u("span",pa,"· "+v(l.domain),1)]))),128))]))]),p[2]||(p[2]=u("p",{class:"text-[11px] text-gray-400 dark:text-gray-500"}," Storage values and cookie values are never captured — key names, lengths and flags only. ",-1))])]),_:2},[e.storageKey&&!e.plain?{name:"folded",fn:C(()=>[u("span",null,v(t(a)),1)]),key:"0"}:void 0]),1040))}}),Va=Object.assign(ga,{__name:"PageStateCard"});function Ha(e={}){const r=U(!1),i=Je();let d=null;async function s(a,o,p={}){try{typeof ClipboardItem<"u"?await navigator.clipboard.write([new ClipboardItem({"text/plain":new Blob([a],{type:"text/plain"}),"text/html":new Blob([o],{type:"text/html"})})]):await navigator.clipboard.writeText(a),r.value=!0,d&&clearTimeout(d),d=setTimeout(()=>{r.value=!1,d=null},e.duration??2e3),p.toast&&i.add({title:typeof p.toast=="string"?p.toast:"Copied to clipboard",icon:"i-lucide-check",color:"success",duration:2e3})}catch{}}return{copyRich:s,copied:r}}export{Qe as _,ja as a,Ma as b,Na as c,Ka as d,Da as e,Va as f,tn as g,Ke as h,Pa as i,Ea as j,Oa as k,Ua as l,Ba as m,Rs as n,_s as o,mt as p,Ha as u};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{bW as e}from"./Du2W7Jne.js";import{h as a}from"./BjaRappk.js";const n=[{id:"account",label:"Account",icon:"i-lucide-user-round",to:"/settings/account",authOnly:!0,fields:[{id:"account.display-name",label:"Display name",help:"account.display-name"},{id:"account.email",label:"Email address",help:"account.email"},{id:"account.connected-accounts",label:"Connected accounts",help:"account.connected-accounts"},{id:"account.password",label:"Password",help:"account.password"},{id:"account.auth-toggle",label:"Authentication",help:"settings.auth-toggle",envOnly:!0}]},{id:"users",label:"Users",icon:"i-lucide-users",to:"/settings/users",roles:[e.ADMINISTRATOR],authOnly:!0,introHelp:"settings.users",fields:[{id:"users.list",label:"Users & roles",help:"settings.users"},{id:"users.api-keys",label:"API keys",help:"settings.api-keys"}]},{id:"notifications",label:"Notifications",icon:"i-lucide-bell",to:"/settings/notifications",fields:[{id:"notifications.smtp",label:"SMTP email delivery",help:"settings.smtp",envOnly:!0},{id:"notifications.test-email",label:"Send test email",help:"notifications.test-email"},{id:"notifications.channels",label:"Notification channels",help:"notifications.channels"},{id:"notifications.subscriptions",label:"My subscriptions",help:"notifications.subscriptions"}]},{id:"tags",label:"Tags",icon:"i-lucide-tags",to:"/settings/tags",roles:[e.ADMINISTRATOR],introHelp:"settings.tags",fields:[{id:"tags.list",label:"Tags",help:"settings.tags"}]},{id:"storage",label:"Storage",icon:"i-lucide-hard-drive",to:"/settings/storage",roles:[e.ADMINISTRATOR],fields:[{id:"storage.backend",label:"Storage backend",help:"settings.storage-backend",envOnly:!0},{id:"storage.stats",label:"Storage statistics",help:"settings.storage-stats"},{id:"storage.cleanup",label:"Cleanup old test runs",help:"settings.cleanup"}]},{id:"wasted-time",label:"Wasted time",icon:"i-lucide-hourglass",to:"/settings/wasted-time",roles:[e.ADMINISTRATOR],introHelp:"settings.wasted-time",fields:[{id:"wasted-time.patterns",label:"Wasted-time patterns",help:"settings.wasted-time"}]},{id:"timeout-hygiene",label:"Timeout hygiene",icon:"i-lucide-scissors",to:"/settings/timeout-hygiene",roles:[e.ADMINISTRATOR],introHelp:"settings.timeout-hygiene",fields:[{id:"timeout-hygiene.thresholds",label:"Detection thresholds",help:"settings.timeout-hygiene"}]},{id:"pr-feedback",label:"Pull requests",icon:"i-lucide-git-pull-request",to:"/settings/pr-feedback",roles:[e.ADMINISTRATOR],introHelp:"settings.pr-feedback",fields:[{id:"pr-feedback.settings",label:"Pull-request feedback",help:"settings.pr-feedback"}]},{id:"ai",label:"AI diagnosis",icon:"i-lucide-sparkles",to:"/settings/ai",roles:[e.ADMINISTRATOR],fields:[{id:"ai.diagnosis",label:"Diagnosis model",help:"settings.ai-provider"},{id:"ai.research",label:"Research model",help:"settings.ai-research"},{id:"ai.embedding",label:"Embedding model",help:"settings.embedding-model"},{id:"ai.auto-diagnose",label:"Auto-diagnose",help:"settings.auto-diagnose"},{id:"ai.context-limits",label:"Diagnosis context limits",help:"settings.ai-limits"},{id:"ai.instructions",label:"Global analysis instructions",help:"settings.ai-instructions"},{id:"ai.scm-token",label:"Repository access token",help:"project.scm-token"},{id:"ai.privacy",label:"Privacy notice",help:"settings.privacy"}]},{id:"about",label:"About",icon:"i-lucide-info",to:"/settings/about",fields:[]}];function o(t){return a(t.help)}function r(t){const i=new Set;for(const s of t.fields)for(const l of o(s))i.add(l);return[...i]}function g(t){const i=n.find(s=>s.id===t);if(!i)throw new Error(`Unknown settings page: ${t}`);return i}export{n as S,g,r as p};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{_ as Ee,a as Re}from"./CsLojMwR.js";import{d as H,E as le,H as se,o as l,f as T,g as c,i as s,j as r,I as G,l as W,k as a,c as m,p as ne,F as C,y as F,q as ie,m as I,t as w,v as x,G as X,r as R,h as D,K as $e,_ as re,w as oe,b as Oe,ac as Le,L as z}from"./Du2W7Jne.js";import{_ as Be}from"./Bm62iDV5.js";import{_ as pe}from"./Dpd16JVI.js";import{_ as fe}from"./A1pj0VnG.js";import{_ as ve}from"./AbmKWFQQ.js";import{_ as ge}from"./BmUfSNMV.js";import{_ as Fe}from"./BUkim3TM.js";import{h as We}from"./BjaRappk.js";import{_ as ye}from"./C0_yH0N7.js";import{_ as Ne}from"./BzRRzmwm.js";import{u as ae}from"./B8zkOmwo.js";import{_ as De}from"./DsesNydr.js";import{p as Xe,g as qe}from"./Cbh--1MW.js";import"./BrQEE053.js";import"./DSqHUrvO.js";import"./L3kAWB2a.js";import"./UdR3DBPS.js";import"./Nn93e_Mz.js";import"./DmkUdSS4.js";import"./BT3wGCTI.js";import"./-f7BAm1H.js";import"./DuwtTfO8.js";const Ke={class:"space-y-3"},je={key:0,class:"flex items-center justify-center gap-2 py-8 text-gray-400"},ze={key:1,class:"py-8 text-center text-sm text-gray-400"},He={key:2,class:"max-h-96 overflow-y-auto space-y-px"},Ge=["onClick"],Qe={class:"flex-1 min-w-0"},Ye={class:"text-sm font-medium leading-snug truncate"},Ze={key:0,class:"text-gray-500 font-normal"},Je={class:"text-xs text-gray-400 leading-snug mt-0.5"},et={key:3,class:"italic text-gray-500"},tt={key:0,class:"flex items-center gap-1 shrink-0 pt-0.5"},st=["title"],ot=["title"],at={key:0,class:"py-8 text-center text-sm text-gray-400"},lt=H({__name:"ModelPickerModal",props:X({models:{},selected:{},loading:{type:Boolean}},{open:{type:Boolean,required:!0},openModifiers:{}}),emits:X(["select"],["update:open"]),setup(o,{emit:M}){function U(y){return y?y>=1e6?`${(y/1e6).toFixed(1)}M`:y>=1e3?`${Math.round(y/1e3)}K`:String(y):""}const v=o,i=M,A=le(o,"open"),_=R(null),d=R("");se(A,y=>{y&&$e(()=>_.value?.focus())});const n=D(()=>{const y=d.value.toLowerCase();return y?v.models.filter(h=>h.id.toLowerCase().includes(y)||(h.label?.toLowerCase()??"").includes(y)):v.models}),k={image:{icon:"i-lucide-image",label:"Image input"},pdf:{icon:"i-lucide-file-text",label:"PDF input"},code:{icon:"i-lucide-code",label:"Code execution"},thinking:{icon:"i-lucide-brain",label:"Extended thinking"},json:{icon:"i-lucide-braces",label:"Structured output"},text:{icon:"i-lucide-type",label:"Text"},audio:{icon:"i-lucide-music",label:"Audio"}};function V(y){return y.map(h=>{const g=h.indexOf("→");if(g!==-1){const E=h.slice(0,g),O=h.slice(g+1);return{inputs:E.split("+").filter(Boolean),outputs:O.split("+").filter(Boolean)}}return{inputs:[h],outputs:[]}})}function $(y){i("select",y),A.value=!1,d.value=""}return(y,h)=>{const g=G,E=ne,O=Fe;return l(),T(O,{open:A.value,"onUpdate:open":h[1]||(h[1]=f=>A.value=f),title:"Select a model",ui:{content:"max-w-2xl"}},{body:c(()=>[s("div",Ke,[r(g,{ref_key:"searchInput",ref:_,modelValue:a(d),"onUpdate:modelValue":h[0]||(h[0]=f=>W(d)?d.value=f:null),placeholder:"Search models…",icon:"i-lucide-search",size:"sm"},null,8,["modelValue"]),o.models.length===0&&o.loading?(l(),m("div",je,[r(E,{name:"i-lucide-loader-2",class:"size-4 animate-spin"}),h[2]||(h[2]=s("span",{class:"text-sm"},"Loading models…",-1))])):o.models.length===0?(l(),m("div",ze," No models available — check your provider configuration ")):(l(),m("div",He,[(l(!0),m(C,null,F(a(n),f=>(l(),m("button",{key:f.id,class:ie(["w-full text-left px-4 py-3 rounded-lg hover:bg-elevated transition-colors border border-transparent hover:border-default flex items-start gap-4",o.selected===f.id?"bg-primary/10 ring-1 ring-inset ring-primary/30 border-primary/30":""]),onClick:b=>$(f.id)},[s("div",Qe,[s("p",Ye,[I(w(f.id)+" ",1),f.label&&f.label!==f.id?(l(),m("span",Ze," — "+w(f.label),1)):x("",!0)]),s("p",Je,[f.contextLength?(l(),m(C,{key:0},[I(w(U(f.contextLength))+" ctx",1)],64)):x("",!0),f.maxTokens?(l(),m(C,{key:1},[I(" · up to "+w(U(f.maxTokens))+" out",1)],64)):x("",!0),f.pricing?.prompt?(l(),m(C,{key:2},[I(" · $"+w(f.pricing.prompt)+" / $"+w(f.pricing.completion??"?")+" per 1M",1)],64)):x("",!0),!f.contextLength&&!f.maxTokens&&!f.pricing?.prompt?(l(),m("span",et,"No additional info")):x("",!0)])]),f.modalities?.length?(l(),m("div",tt,[(l(!0),m(C,null,F(V(f.modalities),b=>(l(),m(C,{key:b.inputs.join()+"→"+b.outputs.join()},[(l(!0),m(C,null,F(b.inputs,P=>(l(),m("span",{key:"in-"+P,title:k[P]?.label??P,class:"inline-flex items-center justify-center size-6 rounded-md bg-gray-100 dark:bg-gray-800 text-gray-500 hover:text-primary transition-colors"},[r(E,{name:k[P]?.icon??"i-lucide-cpu",class:"size-3.5"},null,8,["name"])],8,st))),128)),b.outputs.length?(l(),T(E,{key:0,name:"i-lucide-arrow-right",class:"size-3 text-gray-400 shrink-0"})):x("",!0),(l(!0),m(C,null,F(b.outputs,P=>(l(),m("span",{key:"out-"+P,title:k[P]?.label??P,class:"inline-flex items-center justify-center size-6 rounded-md bg-gray-100 dark:bg-gray-800 text-gray-500 hover:text-primary transition-colors"},[r(E,{name:k[P]?.icon??"i-lucide-cpu",class:"size-3.5"},null,8,["name"])],8,ot))),128))],64))),128))])):x("",!0)],10,Ge))),128)),a(n).length===0?(l(),m("div",at,' No models match "'+w(a(d))+'" ',1)):x("",!0)]))])]),_:1},8,["open"])}}}),nt=Object.assign(lt,{__name:"ModelPickerModal"}),it={class:"flex gap-2"},rt=H({__name:"ModelFieldInput",props:X({provider:{},providerResolved:{},reuse:{type:Boolean},models:{},loadingModels:{type:Boolean},placeholderAnthropic:{},placeholderOpenai:{}},{modelValue:{required:!0},modelModifiers:{}}),emits:X(["loadModels"],["update:modelValue"]),setup(o,{emit:M}){const U=M,v=le(o,"modelValue"),i=R(!1);return(A,_)=>{const d=G,n=re,k=nt;return l(),m(C,null,[s("div",it,[r(d,{modelValue:v.value,"onUpdate:modelValue":_[0]||(_[0]=V=>v.value=V),placeholder:o.providerResolved==="anthropic"?o.placeholderAnthropic:o.placeholderOpenai,class:"flex-1"},null,8,["modelValue","placeholder"]),o.providerResolved?(l(),T(n,{key:0,size:"sm",variant:"soft",onClick:_[1]||(_[1]=V=>{U("loadModels"),i.value=!0})},{default:c(()=>[..._[4]||(_[4]=[I(" Choose model… ",-1)])]),_:1})):x("",!0)]),r(k,{open:a(i),"onUpdate:open":_[2]||(_[2]=V=>W(i)?i.value=V:null),models:o.models,selected:v.value,loading:o.loadingModels,onSelect:_[3]||(_[3]=V=>v.value=V)},null,8,["open","models","selected","loading"])],64)}}}),dt=Object.assign(rt,{__name:"ModelFieldInput"}),ct={class:"flex items-start justify-between gap-3"},ut={class:"flex items-start gap-2"},mt={class:"font-medium inline-flex items-center gap-1"},pt={class:"text-sm text-gray-500"},ft={class:"inline-flex items-center gap-1"},vt={class:"inline-flex items-center gap-1"},gt={class:"inline-flex items-center gap-1"},yt={key:3,class:"flex justify-end"},ht=H({__name:"AiRoleConfigForm",props:X({meta:{},hasApiKey:{type:Boolean},reuseOptions:{},providerOptions:{},presetOptions:{},disabled:{type:Boolean},envManaged:{type:Boolean},models:{},loadingModels:{type:Boolean},providerResolved:{},testing:{type:Boolean}},{modelValue:{required:!0},modelModifiers:{}}),emits:X(["applyPreset","loadModels","test"],["update:modelValue"]),setup(o,{emit:M}){const U=o,v=M,i=le(o,"modelValue"),A=D({get:()=>i.value.reuse??"own",set:d=>i.value.reuse=d==="own"?null:d}),_=D(()=>We(U.meta.help));return(d,n)=>{const k=ne,V=Be,$=pe,y=fe,h=ve,g=ge,E=G,O=dt,f=re;return l(),m("div",{class:ie(["rounded-lg border border-default p-4 space-y-4",o.meta.optional&&!i.value.enabled?"opacity-80":""])},[s("div",ct,[s("div",ut,[r(k,{name:o.meta.icon,class:"size-5 mt-0.5 text-primary"},null,8,["name"]),s("div",null,[s("p",mt,[I(w(o.meta.title)+" ",1),r(V,{topic:o.meta.help},null,8,["topic"])]),s("p",pt,w(o.meta.blurb),1)])]),o.meta.optional?(l(),T($,{key:0,modelValue:i.value.enabled,"onUpdate:modelValue":n[0]||(n[0]=b=>i.value.enabled=b),disabled:o.disabled&&!o.envManaged,"aria-label":o.meta.enableLabel},null,8,["modelValue","disabled","aria-label"])):x("",!0)]),!o.meta.optional||i.value.enabled?(l(),m(C,{key:0},[o.meta.reuseTargets.length?(l(),T(h,{key:0,label:"Provider source"},{default:c(()=>[r(y,{modelValue:a(A),"onUpdate:modelValue":n[1]||(n[1]=b=>W(A)?A.value=b:null),items:o.reuseOptions,disabled:o.disabled&&!o.envManaged,class:"w-full"},null,8,["modelValue","items","disabled"])]),_:1})):x("",!0),i.value.reuse?x("",!0):(l(),m(C,{key:1},[r(h,{label:"Provider"},{label:c(()=>[s("span",ft,[n[9]||(n[9]=I(" Provider ",-1)),o.disabled?(l(),T(g,{key:0,"env-vars":a(_)},null,8,["env-vars"])):x("",!0)])]),default:c(()=>[r(y,{modelValue:i.value.provider,"onUpdate:modelValue":n[2]||(n[2]=b=>i.value.provider=b),items:o.providerOptions,disabled:o.disabled,placeholder:"Choose a provider…",class:"w-full"},null,8,["modelValue","items","disabled"])]),_:1}),i.value.provider==="openai"?(l(),T(h,{key:0,label:"Preset",description:"Pick a known provider to auto-fill the URL and model, then adjust as needed"},{default:c(()=>[r(y,{items:o.presetOptions,placeholder:"Choose a preset…",disabled:o.disabled,class:"w-full","onUpdate:modelValue":n[3]||(n[3]=b=>v("applyPreset",b))},null,8,["items","disabled"])]),_:1})):x("",!0),i.value.provider?(l(),T(h,{key:1,label:"API key",description:o.hasApiKey?"Leave empty to keep the stored key, clear and save to remove it":"Required for Anthropic; optional for local OpenAI-compatible servers"},{label:c(()=>[s("span",vt,[n[10]||(n[10]=I(" API key ",-1)),o.disabled?(l(),T(g,{key:0,"env-vars":a(_)},null,8,["env-vars"])):x("",!0)])]),default:c(()=>[r(E,{modelValue:i.value.apiKey,"onUpdate:modelValue":n[4]||(n[4]=b=>i.value.apiKey=b),type:"password",placeholder:o.hasApiKey?"•••••••• (unchanged)":"sk-…",disabled:o.disabled,class:"w-full font-mono"},null,8,["modelValue","placeholder","disabled"])]),_:1},8,["description"])):x("",!0),i.value.provider==="openai"?(l(),T(h,{key:2,label:"Base URL",description:"Required, e.g. http://localhost:11434/v1"},{label:c(()=>[s("span",gt,[n[11]||(n[11]=I(" Base URL ",-1)),o.disabled?(l(),T(g,{key:0,"env-vars":a(_)},null,8,["env-vars"])):x("",!0)])]),default:c(()=>[r(E,{modelValue:i.value.baseUrl,"onUpdate:modelValue":n[5]||(n[5]=b=>i.value.baseUrl=b),placeholder:"http://localhost:11434/v1",disabled:o.disabled,class:"w-full"},null,8,["modelValue","disabled"])]),_:1})):x("",!0)],64)),i.value.reuse||i.value.provider?(l(),T(h,{key:2,label:"Model",description:i.value.reuse?"Leave empty to use the reused role's model":void 0},{default:c(()=>[r(O,{modelValue:i.value.model,"onUpdate:modelValue":n[6]||(n[6]=b=>i.value.model=b),provider:i.value.provider,"provider-resolved":o.providerResolved,reuse:!!i.value.reuse,models:o.models,"loading-models":o.loadingModels,"placeholder-anthropic":o.meta.modelPlaceholderAnthropic,"placeholder-openai":o.meta.modelPlaceholderOpenai,onLoadModels:n[7]||(n[7]=b=>v("loadModels"))},null,8,["modelValue","provider","provider-resolved","reuse","models","loading-models","placeholder-anthropic","placeholder-openai"])]),_:1},8,["description"])):x("",!0),o.providerResolved?(l(),m("div",yt,[r(f,{size:"xs",color:"neutral",variant:"soft",icon:"i-lucide-plug",loading:o.testing,onClick:n[8]||(n[8]=b=>v("test"))},{default:c(()=>[...n[12]||(n[12]=[I(" Test connection ",-1)])]),_:1},8,["loading"])])):x("",!0)],64)):x("",!0)],2)}}}),bt=Object.assign(ht,{__name:"AiRoleConfigForm"}),_t={key:0,class:"space-y-3"},xt={class:"text-sm text-gray-500"},kt={key:0,class:"text-sm text-gray-500"},At={key:1,class:"overflow-x-auto"},It={class:"w-full text-sm"},Mt={class:"px-2 py-2"},St={class:"font-mono text-xs"},Vt={class:"text-xs text-gray-400"},wt={class:"text-right px-2 py-2"},Pt=["title"],Tt=["title"],Ut={class:"text-right px-2 py-2"},Ct={key:1,class:"flex items-center gap-2 py-4 text-muted"},Et=H({__name:"AiUsagePanel",async setup(o){let M,U;const v=R(30),i=[{label:"Last 7 days",value:7},{label:"Last 30 days",value:30},{label:"Last 90 days",value:90}],{data:A,pending:_}=([M,U]=oe(()=>ae("/api/settings/ai/usage",{query:{days:v}},"$1ij5UlwVIK")),M=await M,U(),M);function d(n){return n>=1e6?`${(n/1e6).toFixed(1)}M`:n>=1e3?`${(n/1e3).toFixed(1)}k`:String(n)}return(n,k)=>{const V=fe,$=Ne,y=ne,h=ye;return l(),T(h,{icon:"i-lucide-activity",title:"AI usage"},{actions:c(()=>[r(V,{modelValue:a(v),"onUpdate:modelValue":k[0]||(k[0]=g=>W(v)?v.value=g:null),items:i,size:"sm",class:"w-36"},null,8,["modelValue"])]),default:c(()=>[a(A)?(l(),m("div",_t,[s("p",xt,w(d(a(A).totals.diagnoses))+" diagnoses · "+w(d(a(A).totals.inputTokens))+" input tokens · "+w(d(a(A).totals.outputTokens))+" output tokens ",1),a(A).byModel.length===0?(l(),m("p",kt,"No AI calls recorded in this period.")):(l(),m("div",At,[s("table",It,[k[1]||(k[1]=s("thead",null,[s("tr",{class:"text-xs text-gray-500 uppercase tracking-wider border-b border-default"},[s("th",{class:"text-left px-2 py-2 font-medium"},"Model"),s("th",{class:"text-right px-2 py-2 font-medium"},"Diagnoses"),s("th",{class:"text-right px-2 py-2 font-medium"},"Failed"),s("th",{class:"text-right px-2 py-2 font-medium"},"Input tokens"),s("th",{class:"text-right px-2 py-2 font-medium"},"Output tokens"),s("th",{class:"text-right px-2 py-2 font-medium"},"Avg duration")])],-1)),s("tbody",null,[(l(!0),m(C,null,F(a(A).byModel,g=>(l(),m("tr",{key:`${g.provider??"unknown"}/${g.model}`,class:"border-b last:border-b-0 border-default"},[s("td",Mt,[s("span",St,w(g.model),1),s("span",Vt," · "+w(g.provider??"unknown"),1)]),s("td",wt,w(g.diagnoses),1),s("td",{class:ie(["text-right px-2 py-2",g.failed>0?"text-red-600 dark:text-red-400":""])},w(g.failed),3),s("td",{class:"text-right px-2 py-2",title:g.inputTokens.toLocaleString()},w(d(g.inputTokens)),9,Pt),s("td",{class:"text-right px-2 py-2",title:g.outputTokens.toLocaleString()},w(d(g.outputTokens)),9,Tt),s("td",Ut,[r($,{ms:g.avgDurationMs},null,8,["ms"])])]))),128))])])]))])):a(_)?(l(),m("div",Ct,[r(y,{name:"i-lucide-loader-circle",class:"size-4 animate-spin"}),k[2]||(k[2]=s("span",{class:"text-sm"},"Loading usage…",-1))])):x("",!0)]),_:1})}}}),Rt=Object.assign(Et,{__name:"AiUsagePanel"}),$t=[{key:"sampleErrorChars",label:"Error text characters",envVar:"PIWI_AI_MAX_SAMPLE_ERROR_CHARS",description:"Max characters of raw error text (per error block).",min:200,max:5e4},{key:"scmPatchBudget",label:"SCM patch budget",envVar:"PIWI_AI_MAX_SCM_PATCH_BUDGET",description:"Total characters of diff patches across changed files.",min:0,max:5e4},{key:"affectedTests",label:"Affected tests",envVar:"PIWI_AI_MAX_AFFECTED_TESTS",description:"Max affected tests listed.",min:1,max:200},{key:"steps",label:"Test steps",envVar:"PIWI_AI_MAX_STEPS",description:"Max recent test steps included.",min:1,max:200},{key:"consoleEntries",label:"Console entries",envVar:"PIWI_AI_MAX_CONSOLE_ENTRIES",description:"Max console error/warning entries included.",min:0,max:200},{key:"consoleEntryChars",label:"Console entry characters",envVar:"PIWI_AI_MAX_CONSOLE_ENTRY_CHARS",description:"Max characters per console entry.",min:50,max:5e3},{key:"networkRequests",label:"Network requests",envVar:"PIWI_AI_MAX_NETWORK_REQUESTS",description:"Max failed network requests included.",min:0,max:200},{key:"ariaSnapshotChars",label:"ARIA snapshot characters",envVar:"PIWI_AI_MAX_ARIA_SNAPSHOT_CHARS",description:"Max characters of the page ARIA snapshot.",min:0,max:5e4},{key:"testSourceChars",label:"Test source characters",envVar:"PIWI_AI_MAX_TEST_SOURCE_CHARS",description:"Max characters of the test source snippet.",min:0,max:5e4},{key:"maxSourceFiles",label:"Full source files",envVar:"PIWI_AI_MAX_SOURCE_FILES",description:"Max full source files fetched from SCM to ground patches (0 disables).",min:0,max:20},{key:"sourceFileChars",label:"Source file characters",envVar:"PIWI_AI_MAX_SOURCE_FILE_CHARS",description:"Max characters per fetched full source file.",min:0,max:5e4},{key:"serverLogEntries",label:"Server log entries",envVar:"PIWI_AI_MAX_SERVER_LOG_ENTRIES",description:"Max backend server log entries (from X-Piwi-Logs header) included.",min:0,max:200},{key:"serverLogEntryChars",label:"Server log entry characters",envVar:"PIWI_AI_MAX_SERVER_LOG_ENTRY_CHARS",description:"Max characters per backend server log entry.",min:50,max:5e3},{key:"serverTraceSpans",label:"Server trace spans",envVar:"PIWI_AI_MAX_SERVER_TRACE_SPANS",description:"Max backend server spans (from X-Piwi-Trace header) included (0 disables).",min:0,max:500},{key:"maxImages",label:"Max screenshots",envVar:"PIWI_AI_MAX_IMAGES",description:"Max screenshots auto-included in the diagnosis context.",min:0,max:20},{key:"maxPassedPeers",label:"Max passed peers",envVar:"PIWI_AI_MAX_PASSED_PEERS",description:"Max peer tests in the same file listed when they passed.",min:0,max:100},{key:"maxConsoleWindow",label:"Console window entries",envVar:"PIWI_AI_MAX_CONSOLE_WINDOW",description:"Max console entries of any type in the window before failure.",min:0,max:200},{key:"slowRequestMs",label:"Slow request threshold (ms)",envVar:"PIWI_AI_SLOW_REQUEST_MS",description:"Network request duration threshold for flagging as slow.",min:100,max:3e4},{key:"maxTraceActions",label:"Trace actions",envVar:"PIWI_AI_MAX_TRACE_ACTIONS",description:"Max actions extracted from trace ZIP for failing-action context (0 disables).",min:0,max:50},{key:"traceDomChars",label:"Trace DOM excerpt characters",envVar:"PIWI_AI_TRACE_DOM_CHARS",description:"Max characters for the trace-derived DOM/ARIA excerpt in failing-action context.",min:0,max:2e4},{key:"traceStackFrames",label:"Trace stack frames",envVar:"PIWI_AI_MAX_TRACE_STACK_FRAMES",description:"Max call-stack frames (with source windows) from the trace (0 disables).",min:0,max:50},{key:"traceNetworkRequests",label:"Trace network requests",envVar:"PIWI_AI_MAX_TRACE_NETWORK_REQUESTS",description:"Max requests from the trace network stream (0 disables).",min:0,max:200},{key:"domSnapshotChars",label:"DOM snapshot characters",envVar:"PIWI_AI_MAX_DOM_SNAPSHOT_CHARS",description:"Max characters of the failure-time DOM snapshot rendered from the trace (0 disables).",min:0,max:5e4},{key:"imageMaxEdge",label:"Screenshot max edge (px)",envVar:"PIWI_AI_IMAGE_MAX_EDGE",description:"Screenshots are downscaled to at most this many pixels on the long edge before being sent.",min:512,max:8192}],Ot={class:"space-y-6"},Lt={class:"space-y-5"},Bt={class:"flex items-center gap-3"},Ft={class:"flex items-center gap-2 justify-end"},Wt={class:"flex justify-end"},Nt={class:"flex justify-end"},Dt={class:"grid grid-cols-1 sm:grid-cols-2 gap-x-4 gap-y-3"},Xt={class:"flex justify-end gap-2"},ps=H({__name:"ai",async setup(o){let M,U;const v=Oe(),{data:i,refresh:A}=([M,U]=oe(()=>ae("/api/settings/ai","$nV9xx-QVRl")),M=await M,U(),M);function _(){return{enabled:!1,reuse:null,provider:"",model:"",baseUrl:"",apiKey:""}}const d=z({diagnosis:_(),research:_(),embedding:_()}),n=R(!1),k=R(""),V=R(""),$=R(!1),y=R(!1),h=R(!1),g=z({diagnosis:!1,research:!1,embedding:!1}),E=z({diagnosis:[],research:[],embedding:[]}),O=z({diagnosis:!1,research:!1,embedding:!1});function f(t){const e=d[t];return e.reuse?d[e.reuse]?.provider||"":e.provider}async function b(t){const e=d[t],p=f(t),S=e.reuse?d[e.reuse]:e,ee=S.apiKey||void 0;O[t]=!0;try{const te=await $fetch("/api/settings/ai/models",{method:"POST",body:{role:t,provider:p,baseUrl:S.baseUrl||void 0,apiKey:ee}});E[t]=te.models}catch{E[t]=[]}finally{O[t]=!1}}const P=[{key:"diagnosis",title:"Diagnosis model",icon:"i-lucide-stethoscope",help:"settings.ai-provider",optional:!1,enableLabel:"",blurb:"The main model that writes the final diagnosis. Required to enable AI features.",reuseTargets:[],modelPlaceholderAnthropic:"claude-opus-4-8",modelPlaceholderOpenai:"e.g. gpt-4o, llama3.1"},{key:"research",title:"Research model",icon:"i-lucide-search",help:"settings.ai-research",optional:!0,enableLabel:"Two-stage diagnosis",blurb:"A cheaper/faster model that pre-analyzes the failure before the diagnosis model writes the final answer. Also used for cluster naming and merge adjudication.",reuseTargets:["diagnosis"],modelPlaceholderAnthropic:"e.g. claude-haiku-4-5",modelPlaceholderOpenai:"e.g. llama-3.1-8b-instant"},{key:"embedding",title:"Embedding model",icon:"i-lucide-vector-square",help:"settings.embedding-model",optional:!0,enableLabel:"Semantic clustering",blurb:"Embeds failures so semantically-similar errors group together (used by failure clustering).",reuseTargets:["diagnosis","research"],modelPlaceholderAnthropic:"— Anthropic has no embeddings API —",modelPlaceholderOpenai:"e.g. text-embedding-3-small"}],de=[{label:"Anthropic API",value:"anthropic"},{label:"OpenAI-compatible",value:"openai"}],he=de.filter(t=>t.value!=="anthropic"),be=D(()=>{const t={};for(const e of P)t[e.key]=[{label:"Configure its own provider",value:"own"},...e.reuseTargets.filter(p=>d[p].enabled||p==="diagnosis").filter(p=>e.key!=="embedding"||d[p].provider==="openai").map(p=>({label:`Reuse ${P.find(S=>S.key===p).title.toLowerCase()}`,value:p}))];return t}),N=D(()=>!!i.value?.envManaged),_e=Xe(qe("ai"));se(i,t=>{if(t){for(const e of P){const p=t.roles[e.key],S=d[e.key];S.enabled=!!p,S.reuse=p?.reuse??null,S.provider=p?.provider??"",S.model=p?.model??"",S.baseUrl=p?.baseUrl??"",S.apiKey=""}n.value=t.autoDiagnose,k.value=t.customInstructions||""}},{immediate:!0});function xe(t){return!!i.value?.roles[t]?.hasApiKey}const ce=[{label:"ollama (local)",baseUrl:"http://localhost:11434/v1",model:"llama3.1"},{label:"LM Studio (local)",baseUrl:"http://localhost:1234/v1",model:""},{label:"OpenRouter",baseUrl:"https://openrouter.ai/api/v1",model:"meta-llama/llama-3.1-8b-instruct"},{label:"Groq",baseUrl:"https://api.groq.com/openai/v1",model:"llama-3.1-8b-instant"},{label:"OpenAI",baseUrl:"https://api.openai.com/v1",model:"gpt-4o"},{label:"Mistral AI",baseUrl:"https://api.mistral.ai/v1",model:"mistral-small-latest"},{label:"Custom",baseUrl:"",model:""}],ke=ce.map(t=>({label:t.label,value:t.label}));function Ae(t,e){const p=ce.find(S=>S.label===e);!p||p.label==="Custom"||(d[t].baseUrl=p.baseUrl,d[t].model=p.model)}function Q(t){const e=d[t];if(!e.enabled)return null;if(e.reuse)return{reuse:e.reuse,model:e.model||void 0};const p={provider:e.provider,model:e.model||void 0,baseUrl:e.baseUrl||void 0};return e.apiKey!==""&&(p.apiKey=e.apiKey),p}async function Ie(){$.value=!0;try{!N&&(!d.diagnosis.enabled||!d.diagnosis.provider)?await $fetch("/api/settings/ai",{method:"PUT",body:{roles:null,autoDiagnose:n.value}}):await $fetch("/api/settings/ai",{method:"PUT",body:{roles:{diagnosis:Q("diagnosis"),research:Q("research"),embedding:Q("embedding")},autoDiagnose:n.value}}),await A();for(const t of P)d[t.key].apiKey="";v.add({title:"Settings saved",color:"success"})}catch(t){v.add({title:"Save failed",description:String(t?.message??t),color:"error"})}finally{$.value=!1}}async function Me(){h.value=!0;try{await $fetch("/api/settings/ai",{method:"PUT",body:{scmToken:V.value||null}}),await A(),V.value="",v.add({title:"SCM token saved",color:"success"})}catch(t){v.add({title:"Save failed",description:String(t?.message??t),color:"error"})}finally{h.value=!1}}async function Se(){y.value=!0;try{await $fetch("/api/settings/ai",{method:"PUT",body:{customInstructions:k.value||null}}),await A(),v.add({title:"Instructions saved",color:"success"})}catch(t){v.add({title:"Save failed",description:String(t?.message??t),color:"error"})}finally{y.value=!1}}async function Ve(t){g[t]=!0;try{const e=d[t],p=e.reuse?d[e.reuse]:e,S=await $fetch("/api/settings/ai/test",{method:"POST",body:{role:t,provider:p.provider||void 0,apiKey:p.apiKey||void 0,model:e.model||(e.reuse?p.model:"")||void 0,baseUrl:p.baseUrl||void 0}});S.success?v.add({title:"Connection successful",description:`Model: ${S.model}`,color:"success"}):v.add({title:"Connection failed",description:S.error||"Unknown error",color:"error"})}catch(e){v.add({title:"Connection failed",description:String(e?.message??e),color:"error"})}finally{g[t]=!1}}const{data:L}=([M,U]=oe(()=>ae("/api/settings/ai/limits","$cSpsteApgW")),M=await M,U(),M),Y=$t,q=z({}),Z=R(!1),J=D(()=>new Set(L.value?.envManaged??[]));se(L,t=>{if(t)for(const e of Y)q[e.key]=t.limits[e.key]},{immediate:!0});async function we(){Z.value=!0;try{L.value=await $fetch("/api/settings/ai/limits",{method:"PUT",body:{limits:q}}),v.add({title:"Context limits saved",color:"success"})}catch(t){v.add({title:"Failed to save context limits",description:String(t?.message??t),color:"error"})}finally{Z.value=!1}}function Pe(){if(L.value)for(const t of Y)J.value.has(t.key)||(q[t.key]=L.value.defaults[t.key])}return(t,e)=>{const p=Ee,S=bt,ee=pe,te=Re,K=re,j=ye,Te=Rt,ue=G,me=ve,Ue=De,Ce=ge;return l(),m("div",Ot,[a(N)?(l(),T(p,{key:0,"env-vars":a(_e)},null,8,["env-vars"])):x("",!0),r(j,{icon:"i-lucide-sparkles",title:"Model providers",help:"settings.ai-provider"},{subtitle:c(()=>[...e[3]||(e[3]=[I(" Configure a complete provider for each model role. Optional roles can reuse another role's provider so you don't re-enter credentials. ",-1)])]),footer:c(()=>[s("div",Ft,[r(K,{color:"primary",loading:a($),icon:"i-lucide-save",onClick:Ie},{default:c(()=>[...e[5]||(e[5]=[I(" Save ",-1)])]),_:1},8,["loading"])])]),default:c(()=>[s("div",Lt,[(l(),m(C,null,F(P,u=>r(S,{key:u.key,modelValue:a(d)[u.key],"onUpdate:modelValue":B=>a(d)[u.key]=B,meta:u,"has-api-key":xe(u.key),"reuse-options":a(be)[u.key],"provider-options":u.key==="embedding"?a(he):de,"preset-options":a(ke),disabled:a(N),"env-managed":a(N),"provider-resolved":f(u.key),models:a(E)[u.key],"loading-models":a(O)[u.key],testing:a(g)[u.key],onApplyPreset:B=>Ae(u.key,B),onLoadModels:B=>b(u.key),onTest:B=>Ve(u.key)},null,8,["modelValue","onUpdate:modelValue","meta","has-api-key","reuse-options","provider-options","preset-options","disabled","env-managed","provider-resolved","models","loading-models","testing","onApplyPreset","onLoadModels","onTest"])),64)),r(te,{label:"Auto-diagnose",help:"settings.auto-diagnose","env-managed":a(N)},{default:c(()=>[s("div",Bt,[r(ee,{modelValue:a(n),"onUpdate:modelValue":e[0]||(e[0]=u=>W(n)?n.value=u:null),disabled:a(N)||!a(d).diagnosis.enabled},null,8,["modelValue","disabled"]),e[4]||(e[4]=s("span",{class:"text-sm text-gray-500"}," Automatically diagnose new failure clusters when a run finishes — up to 3 clusters per run (research + diagnosis call each), plus one batched call to title new clusters ",-1))])]),_:1},8,["env-managed"])])]),_:1}),r(Te),r(j,{title:"Repository access",help:"project.scm-token"},{subtitle:c(()=>[...e[6]||(e[6]=[I(" Optional — required for private repositories. Per-project tokens override this. ",-1)])]),footer:c(()=>[s("div",Wt,[r(K,{color:"primary",loading:a(h),icon:"i-lucide-save",onClick:Me},{default:c(()=>[...e[7]||(e[7]=[I(" Save token ",-1)])]),_:1},8,["loading"])])]),default:c(()=>[r(me,{label:"SCM token",description:a(i)?.hasScmToken?"Leave empty to keep the stored token, enter a new value to replace it, or save empty to remove it":"Personal access token with read access to repository contents. Supports GitHub (ghp_), GitLab (glpat-), and Bitbucket tokens."},{default:c(()=>[r(ue,{modelValue:a(V),"onUpdate:modelValue":e[1]||(e[1]=u=>W(V)?V.value=u:null),type:"password",placeholder:a(i)?.hasScmToken?"•••••••• (unchanged)":"ghp_..., glpat-..., or Bitbucket token",class:"w-full font-mono"},null,8,["modelValue","placeholder"])]),_:1},8,["description"])]),_:1}),r(j,{title:"Global analysis instructions",help:"settings.ai-instructions"},{footer:c(()=>[s("div",Nt,[r(K,{color:"primary",loading:a(y),icon:"i-lucide-save",onClick:Se},{default:c(()=>[...e[8]||(e[8]=[I(" Save instructions ",-1)])]),_:1},8,["loading"])])]),default:c(()=>[r(Ue,{modelValue:a(k),"onUpdate:modelValue":e[2]||(e[2]=u=>W(k)?k.value=u:null),rows:6,placeholder:"e.g. Always suggest running failing tests with --repeat-each 5 to confirm flakiness. Prefer network-level evidence over ARIA snapshots. Recommend git bisect when a commit range is available.",class:"w-full font-mono text-sm"},null,8,["modelValue"]),e[9]||(e[9]=s("p",{class:"text-xs text-gray-400 mt-2"}," These instructions are appended to the base system prompt. They shape how the AI analyzes failures but cannot override the response schema or confidence requirement. ",-1))]),_:1}),r(j,{title:"Diagnosis context limits",help:"settings.ai-limits"},{subtitle:c(()=>[...e[10]||(e[10]=[I(" Leave a field empty to use its default; env-managed fields are read-only. ",-1)])]),footer:c(()=>[s("div",Xt,[r(K,{color:"neutral",variant:"ghost",size:"sm",onClick:Pe},{default:c(()=>[...e[11]||(e[11]=[I("Reset to defaults",-1)])]),_:1}),r(K,{color:"primary",loading:a(Z),icon:"i-lucide-save",size:"sm",onClick:we},{default:c(()=>[...e[12]||(e[12]=[I(" Save limits ",-1)])]),_:1},8,["loading"])])]),default:c(()=>[s("div",Dt,[(l(!0),m(C,null,F(a(Y),u=>(l(),T(me,{key:u.key,label:u.label,description:u.description,hint:`default ${a(L)?.defaults[u.key]??""}`},{default:c(()=>[r(ue,{modelValue:a(q)[u.key],"onUpdate:modelValue":B=>a(q)[u.key]=B,modelModifiers:{number:!0},type:"number",min:u.min,max:u.max,disabled:a(J).has(u.key),placeholder:`default ${a(L)?.defaults[u.key]??""}`,class:"w-full"},Le({_:2},[a(J).has(u.key)?{name:"trailing",fn:c(()=>[r(Ce,{"env-vars":[u.envVar]},null,8,["env-vars"])]),key:"0"}:void 0]),1032,["modelValue","onUpdate:modelValue","min","max","disabled","placeholder"])]),_:2},1032,["label","description","hint"]))),128))])]),_:1}),r(j,{icon:"i-lucide-shield-check",title:"Privacy notice",help:"settings.privacy"},{default:c(()=>[...e[13]||(e[13]=[s("div",{class:"space-y-2 text-sm text-gray-600 dark:text-gray-400"},[s("p",null,"When diagnosing a failure cluster, the following data is sent to the configured LLM provider:"),s("ul",{class:"list-disc list-inside space-y-1 ml-2"},[s("li",null,"Normalized error signature and sample raw error text"),s("li",null,"Test titles and file paths for affected tests"),s("li",null,"Browser info, test steps, console error/warning entries (excerpts)"),s("li",null,"Failed network request URLs and status codes"),s("li",null,"ARIA page snapshot (if collected)"),s("li",null," Commit SHA range since last passing run, plus changed file names and diff patches fetched from GitHub/GitLab/Bitbucket (if a repository token is configured or the repo is public) ")]),s("p",{class:"mt-2"},[I(" API keys are stored encrypted in the application database (admin-only access). For stricter setups, use the "),s("code",{class:"font-mono text-xs"},"PIWI_AI_*"),I(" environment variables instead of the UI. ")])],-1)])]),_:1})])}}});export{ps as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{_ as q}from"./BrQEE053.js";import{_ as S}from"./Dpd16JVI.js";import{_ as $}from"./AbmKWFQQ.js";import{d as T,b as j,w as F,aw as N,c as y,j as n,g as r,o as m,k as e,f as O,v as P,i as c,q as B,F as I,y as R,I as E,_ as L,m as k,r as M,L as W}from"./Du2W7Jne.js";import{_ as A}from"./C0_yH0N7.js";import{u as z}from"./B8zkOmwo.js";import"./L3kAWB2a.js";import"./UdR3DBPS.js";import"./Nn93e_Mz.js";import"./DmkUdSS4.js";import"./Bm62iDV5.js";import"./BjaRappk.js";import"./DSqHUrvO.js";import"./-f7BAm1H.js";const D={class:"space-y-6"},K={class:"space-y-4"},G={class:"flex items-center justify-between gap-2"},H={class:"flex items-center gap-2 shrink-0"},ue=T({__name:"pr-feedback",async setup(J){let u,p;const d=j(),{data:o,refresh:f}=([u,p]=F(()=>z("/api/settings/pr-feedback","$My52-nCqWi")),u=await u,p(),u),l=M(!1),t=W({enabled:!1,comment:!0,status:!0,onlyOnFailure:!1,statusContext:"piwi/tests"});N(()=>{o.value&&Object.assign(t,o.value.settings)});const v=[{key:"comment",label:"Post a summary comment",description:"Creates one comment on the pull request and edits it on every later run, so a busy branch gets one comment rather than one per push."},{key:"status",label:"Set a commit status",description:"Marks the run’s commit passed or failed, so the pull request shows the result in its checks list. Still set on a green run when the comment is suppressed."},{key:"onlyOnFailure",label:"Only comment on failures",description:"Keeps green runs from adding a comment. The commit status is still set either way."}];async function g(){l.value=!0;try{const i=await $fetch("/api/settings/pr-feedback",{method:"PUT",body:{settings:{...t}}});o.value=i,Object.assign(t,i.settings),d.add({title:"Saved",color:"success"}),await f()}catch{d.add({title:"Save failed",color:"error"})}finally{l.value=!1}}async function w(){l.value=!0;try{const i=await $fetch("/api/settings/pr-feedback",{method:"PUT",body:{settings:null}});o.value=i,Object.assign(t,i.settings),d.add({title:"Reset to defaults",color:"success"}),await f()}catch{d.add({title:"Reset failed",color:"error"})}finally{l.value=!1}}return(i,s)=>{const x=q,h=S,_=$,C=E,b=L,V=A;return m(),y("div",D,[n(V,{icon:"i-lucide-git-pull-request",title:"Pull-request feedback",help:"settings.pr-feedback"},{subtitle:r(()=>[...s[2]||(s[2]=[k(" When a run finishes on a branch with an open pull request, post the result back to it — new failures separated from pre-existing ones, the failure clusters behind them, and the locator to use instead of the one that broke. ",-1)])]),footer:r(()=>[c("div",G,[s[4]||(s[4]=c("p",{class:"text-xs text-muted"}," Needs an SCM token with write access to the repository — set it globally, or per project in the project’s edit page. ",-1)),c("div",H,[n(b,{variant:"ghost",color:"neutral",disabled:e(l),label:"Reset to defaults",onClick:w},null,8,["disabled"]),n(b,{color:"primary",loading:e(l),icon:"i-lucide-save",onClick:g},{default:r(()=>[...s[3]||(s[3]=[k("Save",-1)])]),_:1},8,["loading"])])])]),default:r(()=>[e(o)&&!e(o).siteUrlConfigured?(m(),O(x,{key:0,color:"warning",variant:"soft",icon:"i-lucide-triangle-alert",title:"PIWI_SITE_URL is not set",description:"Nothing is posted until it is — every link in the comment is built from it, and a comment full of unreachable links is worse than no comment.",class:"mb-4"})):P("",!0),c("div",K,[n(h,{modelValue:e(t).enabled,"onUpdate:modelValue":s[0]||(s[0]=a=>e(t).enabled=a),label:"Post feedback to pull requests"},null,8,["modelValue"]),c("div",{class:B(["space-y-4 pl-1",!e(t).enabled&&"opacity-50 pointer-events-none"])},[(m(),y(I,null,R(v,a=>n(_,{key:a.key,label:a.label,description:a.description},{default:r(()=>[n(h,{modelValue:e(t)[a.key],"onUpdate:modelValue":U=>e(t)[a.key]=U},null,8,["modelValue","onUpdate:modelValue"])]),_:2},1032,["label","description"])),64)),n(_,{label:"Commit status context",description:"The name shown next to the status in the pull request’s checks list.",hint:`default ${e(o)?.defaults.statusContext??""}`},{default:r(()=>[n(C,{modelValue:e(t).statusContext,"onUpdate:modelValue":s[1]||(s[1]=a=>e(t).statusContext=a),placeholder:e(o)?.defaults.statusContext,class:"w-full max-w-sm"},null,8,["modelValue","placeholder"])]),_:1},8,["hint"])],2)])]),_:1})])}}});export{ue as default};
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import{_ as tt,a as et}from"./DoIREDVb.js";import{_ as j}from"./C0_yH0N7.js";import{d as L,b as N,B as O,ao as U,k as t,f as x,g as m,v as C,r as b,o as c,i as e,c as w,j as s,m as o,t as D,_ as z,z as nt,F as G,ap as st,h as R,x as W,am as ot,p as A,w as V,A as at}from"./Du2W7Jne.js";import{g as E,f as it}from"./DuwtTfO8.js";import{_ as lt}from"./BdfhYr-u.js";import{_ as F}from"./B3obW6cw.js";import{_ as rt}from"./Dy-TJ0Mt.js";import{u as K}from"./DSqHUrvO.js";import{_ as ct}from"./Dpd16JVI.js";import{a as ut}from"./Bm62iDV5.js";import{u as dt}from"./_mj6CfPa.js";import{u as T}from"./B8zkOmwo.js";import"./-f7BAm1H.js";import"./L3kAWB2a.js";import"./UdR3DBPS.js";import"./Nn93e_Mz.js";import"./DmkUdSS4.js";import"./BjaRappk.js";const pt={class:"space-y-3"},mt={key:0,class:"flex items-center justify-between gap-3"},_t={key:1,class:"text-sm text-muted"},ft={key:2,class:"flex items-center justify-between gap-3"},vt={class:"text-sm flex items-center gap-2"},kt={class:"flex items-start justify-between gap-3"},yt={class:"space-y-1 min-w-0"},gt={class:"text-sm font-medium"},ht={key:0,class:"text-xs text-muted whitespace-pre-wrap line-clamp-6"},xt={key:1,class:"text-xs text-muted"},bt=L({__name:"DesktopUpdateCard",props:{currentVersion:{}},setup(y){const l=N(),_=b(!1),u=b(!1),d=b(!1),a=b(!1),n=b(null),f=b(null);let g=null;O(()=>{_.value=!!U()}),ot(()=>{g?.()});async function h(){const p=U();if(!(!p||u.value)){u.value=!0;try{n.value=await p.invoke("desktop_check_update")}catch(i){l.add({title:"Update check failed",description:E(i),color:"error"})}finally{u.value=!1}}}async function v(){const p=U(),i=st();if(!(!p||d.value)){d.value=!0,f.value={downloaded:0,total:null};try{i&&!g&&(g=await i.listen("piwi:update-progress",({payload:k})=>{f.value=k})),await p.invoke("desktop_install_update"),a.value=!0}catch(k){l.add({title:"Update failed",description:E(k),color:"error"}),f.value=null}finally{d.value=!1}}}async function r(){const p=U();if(p)try{await p.invoke("desktop_restart_app")}catch{}}const B=R(()=>{const p=f.value;return p?.total?Math.min(100,Math.round(p.downloaded/p.total*100)):null});return(p,i)=>{const k=z,$=W,S=A,P=nt,I=j;return t(_)?(c(),x(I,{key:0,icon:"i-lucide-arrow-up-circle",title:"Updates"},{subtitle:m(()=>[o(" Updates install from GitHub releases and apply on restart"+D(y.currentVersion?` — you are on v${y.currentVersion}`:"")+". ",1)]),default:m(()=>[e("div",pt,[t(n)?t(n).state==="unsupported"?(c(),w("p",_t,[i[3]||(i[3]=o(" This build has no update channel — dev builds and releases made without the update signing key cannot self-update. Grab new versions from the ",-1)),s($,{to:"https://github.com/piwitests/platform/releases/latest",target:"_blank",rel:"noopener noreferrer",class:"text-primary hover:underline"},{default:m(()=>[...i[2]||(i[2]=[o("latest release",-1)])]),_:1}),i[4]||(i[4]=o(". ",-1))])):t(n).state==="uptodate"?(c(),w("div",ft,[e("p",vt,[s(S,{name:"i-lucide-check-circle",class:"size-4 text-success"}),i[5]||(i[5]=o(" You're on the latest version. ",-1))]),s(k,{size:"xs",color:"neutral",variant:"soft",icon:"i-lucide-refresh-cw",loading:t(u),onClick:h},{default:m(()=>[...i[6]||(i[6]=[o(" Check again ",-1)])]),_:1},8,["loading"])])):(c(),w(G,{key:3},[e("div",kt,[e("div",yt,[e("p",gt,"Version "+D(t(n).version)+" is available",1),t(n).notes?(c(),w("p",ht,D(t(n).notes),1)):C("",!0)]),t(a)?(c(),x(k,{key:1,size:"xs",color:"success",icon:"i-lucide-rotate-cw",class:"shrink-0",onClick:r},{default:m(()=>[...i[7]||(i[7]=[o(" Restart now ",-1)])]),_:1})):(c(),x(k,{key:0,size:"xs",icon:"i-lucide-download",loading:t(d),class:"shrink-0",onClick:v},{default:m(()=>[o(D(t(d)?"Installing…":"Install update"),1)]),_:1},8,["loading"]))]),t(d)&&t(B)!==null?(c(),x(P,{key:0,"model-value":t(B),size:"sm"},null,8,["model-value"])):C("",!0),t(a)?(c(),w("p",xt," The update is installed — it applies the next time the app starts. ")):C("",!0)],64)):(c(),w("div",mt,[i[1]||(i[1]=e("p",{class:"text-sm text-muted"},"Check GitHub for a newer version of the desktop app.",-1)),s(k,{size:"xs",icon:"i-lucide-refresh-cw",loading:t(u),onClick:h},{default:m(()=>[...i[0]||(i[0]=[o("Check for updates",-1)])]),_:1},8,["loading"])]))])]),_:1})):C("",!0)}}}),wt=Object.assign(bt,{__name:"DesktopUpdateCard"}),Ct={class:"space-y-4 text-sm"},$t={class:"space-y-1"},St={class:"space-y-3"},Ut={class:"space-y-1"},Dt={class:"flex items-start gap-2"},Bt={class:"text-xs break-all flex-1"},Rt={class:"space-y-1"},jt=`reporter: [
|
|
2
|
-
['@piwitests/reporter', { projectName: 'my-project' }],
|
|
3
|
-
],`,Lt=L({__name:"DesktopReporterCard",props:{url:{},token:{}},setup(y){const l=y,{copy:_}=K(),u=R(()=>`reporter: [
|
|
4
|
-
['@piwitests/reporter', {
|
|
5
|
-
serverUrl: '${l.url}',
|
|
6
|
-
projectName: 'my-project',
|
|
7
|
-
apiKey: '${l.token}',
|
|
8
|
-
}],
|
|
9
|
-
],`);return(d,a)=>{const n=F,f=rt,g=z,h=j;return c(),x(h,{icon:"i-lucide-upload",title:"Send results to this app"},{subtitle:m(()=>[...a[1]||(a[1]=[o(" While this app is running, the Playwright reporter finds it on its own — no URL and no token in your config. ",-1)])]),default:m(()=>[e("div",Ct,[e("div",$t,[a[2]||(a[2]=e("div",{class:"text-muted"},"playwright.config.ts",-1)),s(n,{code:jt,lang:"typescript"}),a[3]||(a[3]=e("p",{class:"text-muted text-xs"},[o(" The app publishes its address and token to "),e("code",null,"~/.piwi/desktop.json"),o(" while it runs. The reporter reads that file only when your config and environment set no "),e("code",null,"serverUrl"),o(" and no "),e("code",null,"apiKey"),o(", so a project already pointed at another dashboard is never redirected here. ")],-1))]),s(f),e("div",St,[a[6]||(a[6]=e("p",{class:"text-muted"},[o(" Configure it by hand when discovery cannot apply — tests running as another user, in a container, or with a config that already sets "),e("code",null,"serverUrl"),o(". The token is a local secret: prefer the "),e("code",null,"PIWI_API_KEY"),o(" env var over committing it. ")],-1)),e("div",Ut,[a[4]||(a[4]=e("div",{class:"text-muted"},"Access token",-1)),e("div",Dt,[e("code",Bt,D(y.token),1),s(g,{icon:"i-lucide-copy",color:"neutral",variant:"ghost",size:"xs","aria-label":"Copy access token",onClick:a[0]||(a[0]=v=>t(_)(y.token,{toast:!0}))})])]),e("div",Rt,[a[5]||(a[5]=e("div",{class:"text-muted"},"playwright.config.ts",-1)),s(n,{code:t(u),lang:"typescript"},null,8,["code"])])])])]),_:1})}}}),It=Object.assign(Lt,{__name:"DesktopReporterCard"}),Pt={class:"space-y-3 text-sm"},Vt={class:"space-y-1"},Tt={class:"flex items-start gap-2"},zt={class:"text-xs break-all flex-1"},At={class:"space-y-1"},Mt={class:"flex items-start gap-2"},Et={class:"text-xs break-all flex-1"},Nt={class:"space-y-1"},Ot=L({__name:"DesktopMcpCard",props:{url:{},token:{}},setup(y){const l=y,{copy:_}=K(),u=R(()=>`${l.url}/mcp`),d=R(()=>`claude mcp add --transport http piwi ${u.value} \\
|
|
10
|
-
--header "Authorization: Bearer ${l.token}"`);return(a,n)=>{const f=z,g=F,h=j;return c(),x(h,{icon:"i-lucide-plug",title:"Connect an AI assistant (MCP)"},{subtitle:m(()=>[...n[2]||(n[2]=[o(" This app exposes a local MCP endpoint. Point your client at the URL below and authenticate with the access token — it is the Bearer token, even though sign-in is off. ",-1)])]),default:m(()=>[e("div",Pt,[e("div",Vt,[n[3]||(n[3]=e("div",{class:"text-muted"},"MCP URL",-1)),e("div",Tt,[e("code",zt,D(t(u)),1),s(f,{icon:"i-lucide-copy",color:"neutral",variant:"ghost",size:"xs","aria-label":"Copy MCP URL",onClick:n[0]||(n[0]=v=>t(_)(t(u),{toast:!0}))})])]),e("div",At,[n[4]||(n[4]=e("div",{class:"text-muted"},"Access token",-1)),e("div",Mt,[e("code",Et,D(y.token),1),s(f,{icon:"i-lucide-copy",color:"neutral",variant:"ghost",size:"xs","aria-label":"Copy access token",onClick:n[1]||(n[1]=v=>t(_)(y.token,{toast:!0}))})])]),e("div",Nt,[n[5]||(n[5]=e("div",{class:"text-muted"},"Claude Code",-1)),s(g,{code:t(d),lang:"sh"},null,8,["code"])])])]),_:1})}}}),Gt=Object.assign(Ot,{__name:"DesktopMcpCard"}),Wt={key:0,class:"flex items-center gap-2 text-sm text-muted"},Ft={key:1,class:"space-y-4"},Kt={class:"flex items-start justify-between gap-4"},qt={class:"flex items-start justify-between gap-4"},Ht={key:2,class:"space-y-1 text-sm text-muted"},Yt=L({__name:"DesktopServiceCard",setup(y){const l=N(),_=b(!0),u=b(!1),d=b(!1),a=b(!1),n=b(!1);async function f(){const v=U();if(!v){u.value=!1,_.value=!1;return}try{const r=await v.invoke("desktop_get_service_settings");a.value=!!r.run_in_background,n.value=!!r.start_on_login,u.value=!0}catch{u.value=!1}finally{_.value=!1}}O(f);async function g(v){const r=U();if(r){d.value=!0;try{await r.invoke("desktop_set_run_in_background",{enabled:v}),a.value=v}catch{l.add({title:'Could not update "Run in background"',color:"error"})}finally{d.value=!1}}}async function h(v){const r=U();if(r){d.value=!0;try{await r.invoke("desktop_set_start_on_login",{enabled:v}),n.value=v}catch{l.add({title:'Could not update "Start on login"',color:"error"})}finally{d.value=!1}}}return(v,r)=>{const B=A,p=ct,i=j;return c(),x(i,{icon:"i-lucide-monitor-cog",title:"Desktop app"},{subtitle:m(()=>[...r[0]||(r[0]=[o(" Keep Piwi running in the background and start it automatically when you log in. ",-1)])]),default:m(()=>[t(_)?(c(),w("div",Wt,[s(B,{name:"i-lucide-loader-2",class:"size-4 animate-spin"}),r[1]||(r[1]=o(" Checking… ",-1))])):t(u)?(c(),w("div",Ft,[e("div",Kt,[r[2]||(r[2]=e("div",{class:"space-y-0.5"},[e("p",{class:"text-sm font-medium"},"Run in background"),e("p",{class:"text-xs text-muted"},"Closing the window keeps the server running in the tray instead of quitting.")],-1)),s(p,{"model-value":t(a),disabled:t(d),"onUpdate:modelValue":g},null,8,["model-value","disabled"])]),e("div",qt,[r[3]||(r[3]=e("div",{class:"space-y-0.5"},[e("p",{class:"text-sm font-medium"},"Start on login"),e("p",{class:"text-xs text-muted"}," Launch Piwi automatically (hidden in the tray) when you sign in to your computer. ")],-1)),s(p,{"model-value":t(n),disabled:t(d),"onUpdate:modelValue":h},null,8,["model-value","disabled"])])])):(c(),w("div",Ht,[...r[4]||(r[4]=[e("p",null,"Manage these from the Piwi tray icon:",-1),e("p",{class:"text-xs"},[o(" Right-click the Piwi icon in your system tray for "),e("strong",null,"Run in background"),o(" and "),e("strong",null,"Start on login"),o(". On Windows the icon may be hidden under the “show hidden icons” arrow (▲) next to the clock — drag it onto the taskbar to keep it in view. ")],-1)])]))]),_:1})}}}),Qt=Object.assign(Yt,{__name:"DesktopServiceCard"}),Jt={class:"space-y-6"},Xt={class:"flex flex-wrap items-center gap-x-6 gap-y-3 text-sm"},ke=L({__name:"about",async setup(y){let l,_;const u=at(),d=dt(),{data:a}=([l,_]=V(()=>T("/api/version","$mIoGdvWYhF")),l=await l,_(),l),{data:n}=([l,_]=V(()=>T("/api/admin/stats",{immediate:d,default:()=>null},"$IuuLVEbWlE")),l=await l,_(),l),{data:f}=([l,_]=V(()=>T("/api/desktop/reporter-config",{immediate:d,default:()=>null},"$A4rSe7BAN_")),l=await l,_(),l),g=u.public.appVersion,h=u.public.buildSha,v=u.public.buildTime,r=u.public.nodeVersion,B=u.public.authEnabled,p=R(()=>h?h.slice(0,7):null),i=R(()=>{const k=a.value?.dbBackend;return k==="postgresql"?"PostgreSQL":k==="sqlite"?"SQLite":k??null});return(k,$)=>{const S=et,P=tt,I=j,q=wt,H=lt,Y=It,Q=Gt,J=Qt,X=ut,M=W,Z=A;return c(),w("div",Jt,[s(I,{icon:"i-lucide-info",title:"Application"},{default:m(()=>[s(P,null,{default:m(()=>[s(S,{label:"Version",value:`v${t(g)}`},null,8,["value"]),t(p)?(c(),x(S,{key:0,label:"Build",value:t(p),hint:t(h)},null,8,["value","hint"])):C("",!0),t(v)?(c(),x(S,{key:1,label:"Built",value:("formatRelativeTime"in k?k.formatRelativeTime:t(it))(t(v)),hint:t(v)},null,8,["value","hint"])):C("",!0),s(S,{label:"Node.js",value:t(r)},null,8,["value"]),s(S,{label:"Database",value:t(i)},null,8,["value"]),s(S,{label:"Authentication",value:t(B)?"Enabled":"Disabled"},null,8,["value"])]),_:1})]),_:1}),s(q,{"current-version":t(g)},null,8,["current-version"]),t(d)?(c(),w(G,{key:0},[t(n)?(c(),x(H,{key:0,database:t(n).databaseLocation,storage:t(n).storageLocation},null,8,["database","storage"])):C("",!0),t(f)?(c(),x(Y,{key:1,url:t(f).url,token:t(f).token},null,8,["url","token"])):C("",!0),t(f)?(c(),x(Q,{key:2,url:t(f).url,token:t(f).token},null,8,["url","token"])):C("",!0),s(J)],64)):C("",!0),s(I,{icon:"i-lucide-book-open",title:"Resources"},{default:m(()=>[e("div",Xt,[s(X,{to:""},{default:m(()=>[...$[0]||($[0]=[o("Documentation",-1)])]),_:1}),s(M,{to:"/docs",class:"inline-flex items-center gap-1 text-primary hover:underline"},{default:m(()=>[...$[1]||($[1]=[o(" API reference ",-1)])]),_:1}),s(M,{to:"https://github.com/piwitests/platform",target:"_blank",rel:"noopener noreferrer",class:"inline-flex items-center gap-1 text-primary hover:underline"},{default:m(()=>[$[2]||($[2]=o(" GitHub ",-1)),s(Z,{name:"i-lucide-external-link",class:"w-3.5 h-3.5 shrink-0"})]),_:1})])]),_:1})])}}});export{ke as default};
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import{_ as Q,a as X}from"./5A6ITZXj.js";import{_ as Z}from"./BrQEE053.js";import{d as M,b as ee,B as te,ao as P,k as r,o,f as v,g as p,c as d,j as c,p as L,m as s,F as j,y as B,q as se,i as e,t as y,s as re,v as f,_ as N,r as T,w as ie,e as oe,A as ne,h as x}from"./Du2W7Jne.js";import{_ as E}from"./C0_yH0N7.js";import{g as O}from"./DuwtTfO8.js";import{_ as ae}from"./B3obW6cw.js";import{_ as ce}from"./CxyAzHr3.js";import{u as pe}from"./_mj6CfPa.js";import{u as de}from"./DSqHUrvO.js";import{u as le}from"./B8zkOmwo.js";import"./KyA_4Ks-.js";import"./Bm62iDV5.js";import"./BjaRappk.js";import"./-f7BAm1H.js";import"./pQqGiNch.js";const ue={key:0,class:"flex items-center gap-2 text-sm text-muted"},me={key:1,class:"space-y-2"},ge=["data-testid"],fe={class:"min-w-0 flex-1"},ye={class:"flex items-center gap-2"},he={class:"text-sm font-medium"},be={key:0,class:"text-xs text-muted truncate"},_e={key:1,class:"text-xs text-warning"},xe={class:"flex items-center gap-1.5 shrink-0"},ve=M({__name:"DesktopMcpClientsCard",setup($){const h=ee(),w=T(!1),I=T(!0),k=T([]),l=T(null);async function A(){const n=P();if(n)try{k.value=await n.invoke("desktop_mcp_clients"),w.value=!0}catch{w.value=!1}finally{I.value=!1}}te(()=>{P()?A():I.value=!1});async function b(n,a){const m=P();if(m){l.value=n.id;try{const _=await m.invoke(a?"desktop_mcp_connect":"desktop_mcp_disconnect",{clientId:n.id});k.value=k.value.map(g=>g.id===_.id?_:g),h.add({title:a?`${n.label} connected`:`${n.label} disconnected`,description:a?`Restart ${n.label} to pick up the new server.`:void 0,color:"success",icon:"i-lucide-plug"})}catch(_){h.add({title:`Could not update ${n.label}`,description:O(_),color:"error"})}finally{l.value=null}}}async function u(n){const a=P();if(a)try{await a.invoke("desktop_mcp_reveal",{clientId:n.id})}catch(m){h.add({title:"Could not open the file",description:O(m),color:"error"})}}function S(n){switch(n.status){case"connected":return{label:"Connected",color:"success"};case"stale":return{label:"Needs update",color:"warning"};case"manual":return{label:"Manual setup",color:"warning"};case"not_installed":return{label:"Not detected",color:"neutral"};default:return null}}return(n,a)=>{const m=L,_=re,g=N,U=E;return r(w)?(o(),v(U,{key:0,icon:"i-lucide-plug-zap",title:"Connect a client on this machine"},{subtitle:p(()=>[...a[0]||(a[0]=[s(" One click writes the ",-1),e("code",null,"piwi",-1),s(" entry into the client's own config file (a backup is kept next to it), and entries are kept current when this app's address changes. Restart the client after connecting. ",-1)])]),default:p(()=>[r(I)?(o(),d("div",ue,[c(m,{name:"i-lucide-loader-2",class:"size-4 animate-spin"}),a[1]||(a[1]=s(" Detecting clients… ",-1))])):(o(),d("div",me,[(o(!0),d(j,null,B(r(k),i=>(o(),d("div",{key:i.id,"data-testid":`mcp-client-${i.id}`,class:se(["flex items-center gap-3 rounded-md border border-default p-2.5",i.status==="not_installed"?"opacity-60":""])},[c(m,{name:"i-lucide-bot",class:"size-4 text-gray-400 shrink-0"}),e("div",fe,[e("div",ye,[e("p",he,y(i.label),1),S(i)?(o(),v(_,{key:0,color:S(i).color,variant:"subtle",size:"sm"},{default:p(()=>[s(y(S(i).label),1)]),_:2},1032,["color"])):f("",!0)]),i.config_path?(o(),d("p",be,y(i.config_path),1)):f("",!0),i.detail?(o(),d("p",_e,y(i.detail),1)):f("",!0)]),e("div",xe,[i.status==="not_connected"?(o(),v(g,{key:0,size:"xs",icon:"i-lucide-plug",loading:r(l)===i.id,onClick:q=>b(i,!0)},{default:p(()=>[...a[2]||(a[2]=[s(" Connect ",-1)])]),_:1},8,["loading","onClick"])):i.status==="stale"?(o(),v(g,{key:1,size:"xs",color:"warning",icon:"i-lucide-refresh-cw",loading:r(l)===i.id,onClick:q=>b(i,!0)},{default:p(()=>[...a[3]||(a[3]=[s(" Update ",-1)])]),_:1},8,["loading","onClick"])):f("",!0),i.status==="connected"||i.status==="stale"?(o(),v(g,{key:2,size:"xs",color:"neutral",variant:"ghost",icon:"i-lucide-unplug",loading:r(l)===i.id,onClick:q=>b(i,!1)},{default:p(()=>[...a[4]||(a[4]=[s(" Disconnect ",-1)])]),_:1},8,["loading","onClick"])):f("",!0),i.status!=="not_installed"&&i.config_path?(o(),v(g,{key:3,size:"xs",color:"neutral",variant:"ghost",icon:"i-lucide-folder-open","aria-label":"Reveal config file",title:"Reveal config file",onClick:q=>u(i)},null,8,["onClick"])):f("",!0)])],10,ge))),128)),a[5]||(a[5]=e("p",{class:"text-xs text-muted"}," A client that is not listed — or marked manual — can always be connected with the snippets below. ",-1))]))]),_:1})):f("",!0)}}}),ke=Object.assign(ve,{__name:"DesktopMcpClientsCard"}),we=[{name:"list_projects",description:"List all projects with stats: total runs, test cases, latest run status and branch. Use this first to discover available projects and their IDs.",inputSchema:{type:"object",properties:{}}},{name:"get_project",description:"Get project details and its recent test runs with pass/fail counts. Results are paginated — use pageSize and cursor for the runs list.",inputSchema:{type:"object",properties:{id:{type:"number",description:"Project ID from list_projects"},pageSize:{type:"number",description:"Runs per page (default 10, max 50)"},cursor:{type:"string",description:"Opaque cursor from a previous response to get the next page of runs"}},required:["id"]}},{name:"list_runs",description:"List test runs for a project with filters.",inputSchema:{type:"object",properties:{projectId:{type:"number",description:"Project ID"},status:{type:"string",enum:["passed","failed","running","initialising","aborted"],description:"Filter by status"},branch:{type:"string",description:"Filter by branch name (exact match against SCM metadata)"},pageSize:{type:"number",description:"Results per page (default 10, max 50)"},cursor:{type:"string",description:"Opaque cursor from a previous response to get the next page"}},required:["projectId"]}},{name:"get_run",description:"Get a test run summary plus its test cases (paginated), with status, truncated error text, and failure cluster IDs. Filter by status and page with pageSize/cursor.",inputSchema:{type:"object",properties:{id:{type:"number",description:"Test run ID"},status_filter:{type:"string",enum:["failed","flaky","all"],description:'Which test cases to include (default: "failed" — only failed+timedOut; "flaky" — only flaky; "all" — every case)'},pageSize:{type:"number",description:"Cases per page (default 10, max 50)"},cursor:{type:"string",description:"Opaque cursor from a previous response for the next page of cases"}},required:["id"]}},{name:"list_failed_cases",description:"List failed and timed-out test cases across recent runs for a project.",inputSchema:{type:"object",properties:{projectId:{type:"number",description:"Project ID"},pageSize:{type:"number",description:"Results per page (default 10, max 50)"},cursor:{type:"string",description:"Opaque cursor from a previous response to get the next page"},runId:{type:"number",description:"Optional: restrict to a specific run"}},required:["projectId"]}},{name:"list_flaky_tests",description:"List flaky tests for a project with flakiness scores.",inputSchema:{type:"object",properties:{projectId:{type:"number",description:"Project ID"},runs:{type:"number",description:"Number of recent runs to analyze (default 50, max 200)"},pageSize:{type:"number",description:"Results per page (default 10, max 50)"},cursor:{type:"string",description:"Opaque cursor from a previous response. Cursor is the flakyScore value (descending)."}},required:["projectId"]}},{name:"get_test_case",description:"Get test case details including aggregated pass/fail stats, flakiness metrics, and recent executions (paginated). Use testCaseId (stable identity), not the per-run caseId.",inputSchema:{type:"object",properties:{id:{type:"number",description:"Test case ID (testCaseId from list_failed_cases or list_flaky_tests)"},pageSize:{type:"number",description:"Executions per page (default 10, max 50)"},cursor:{type:"string",description:"Opaque cursor from a previous response to get the next page of executions"}},required:["id"]}},{name:"list_clusters",description:"List failure clusters for a project. Each cluster groups similar failures by error fingerprint.",inputSchema:{type:"object",properties:{projectId:{type:"number",description:"Project ID"},status:{type:"string",enum:["open","resolved","ignored"],description:"Filter by triage status (default: all statuses)"},pageSize:{type:"number",description:"Results per page (default 10, max 50)"},cursor:{type:"string",description:"Opaque cursor from a previous response to get the next page"}},required:["projectId"]}},{name:"get_cluster",description:"Get full details for a failure cluster including all affected test cases, a compact diagnosis summary, and locator healing suggestions for up to 5 affected cases. Each healing entry includes the failing locator, the recommended fix, and the number of alternatives available. Use get_cluster_diagnosis for the full diagnosis text, or get_cluster_context for the raw AI evidence.",inputSchema:{type:"object",properties:{id:{type:"number",description:"Cluster ID from list_clusters"}},required:["id"]}},{name:"get_fix_plan",description:"Everything needed to fix one failure cluster, in a single answer: the diagnosis and its validated patch, ranked locator replacements with the exact file and line to edit, the failing tests, the owning team, and the command that verifies the work. `verify.expectation` states what the dashboard records once those tests pass, so you can confirm the fix landed rather than guessing. Prefer this over assembling get_cluster + get_cluster_diagnosis + get_locator_healing yourself.",inputSchema:{type:"object",properties:{clusterId:{type:"number",description:"Cluster ID from list_clusters or list_open_clusters"}},required:["clusterId"]}},{name:"get_cluster_diagnosis",description:"Get the stored AI diagnosis for a failure cluster. Returns category, confidence, root cause, evidence, and suggested fix. Returns null if no diagnosis has been run yet.",inputSchema:{type:"object",properties:{id:{type:"number",description:"Cluster ID"}},required:["id"]}},{name:"get_test_case_context",description:"Get the AI evidence context for a specific test-run-case (execution scope). Use this when debugging a single test failure — it provides the execution-scoped evidence including steps, console, network, and SCM diff.",inputSchema:{type:"object",properties:{id:{type:"number",description:"Test run case ID"}},required:["id"]}},{name:"get_case_screenshots",description:"Get screenshots for a test-run-case. By default returns metadata only (name, type, size). Set content=true to include base64-encoded image data (max 3, capped at ~100 KB each). Call metadata-only first to discover what exists, then request content for the ones you need.",inputSchema:{type:"object",properties:{testRunsCaseId:{type:"number",description:"Test run case ID"},content:{type:"boolean",description:"Include base64 image data (default false — metadata only)"}},required:["testRunsCaseId"]}},{name:"get_cluster_context",description:"Get the full AI evidence context for a failure cluster — the same data sent to the diagnosis AI. Includes error samples, stack traces, test steps, console logs, network failures, ARIA snapshots, SCM diff (changed files since last green run), and a per-section breakdown with char counts and truncation flags. This is the richest available evidence for debugging a failure.",inputSchema:{type:"object",properties:{id:{type:"number",description:"Cluster ID"},baseCommit:{type:"string",description:"Optional: override the baseline commit SHA for SCM diff comparison"},selectedCommitShas:{type:"array",items:{type:"string"},description:"Optional: specific commit SHAs to include in the diff context (max 10)"}},required:["id"]}},{name:"search_test_cases",description:"Search test cases by title or file path within a project. Accepts a free-text query and returns matching test cases with basic stats. Use this to find a test case when you don't know its ID.",inputSchema:{type:"object",properties:{projectId:{type:"number",description:"Project ID"},q:{type:"string",description:"Search query — matched against title and file path (case-insensitive)"},pageSize:{type:"number",description:"Results per page (default 10, max 50)"},cursor:{type:"string",description:"Opaque cursor from a previous response to get the next page"}},required:["projectId","q"]}},{name:"get_test_run_case",description:"Get a single test-run-case execution record with full (untruncated) error text plus steps, console logs, web vitals, and ARIA snapshot. Use include to fetch only the blobs you need. The ID is the executionId from get_run.cases or testRunsCaseId from get_cluster.affectedTestCases.",inputSchema:{type:"object",properties:{id:{type:"number",description:"Test run case ID (executionId from get_run.cases or testRunsCaseId from get_cluster.affectedTestCases)"},include:{type:"array",items:{type:"string",enum:["steps","console","webVitals","aria","source"]},description:"Optional: which heavy blobs to include (default: all). The error, status, and summary are always returned."}},required:["id"]}},{name:"list_recent_activity",description:"List the most recent test runs across all projects. No projectId required — returns a cross-project view of recent CI activity. Paginated by startTime descending.",inputSchema:{type:"object",properties:{pageSize:{type:"number",description:"Results per page (default 10, max 50)"},cursor:{type:"string",description:"Opaque cursor from a previous response to get the next page"}}}},{name:"get_repo_commits",description:"List recent commits for a project's repository. Requires SCM token configuration (per-project or global). Returns commit details (SHA, message, author, date).",inputSchema:{type:"object",properties:{projectId:{type:"number",description:"Project ID"},branch:{type:"string",description:"Branch name (default: repository default branch)"},limit:{type:"number",description:"Max commits (default 20, max 100)"}},required:["projectId"]}},{name:"get_repo_diff",description:"Get the diff (changed files with patches) for a single commit in a project's repository. Requires SCM token configuration (per-project or global). Useful for inspecting what code changed in a specific commit suspected of causing a failure.",inputSchema:{type:"object",properties:{projectId:{type:"number",description:"Project ID"},sha:{type:"string",description:"Full commit SHA"}},required:["projectId","sha"]}},{name:"get_run_insights",description:'Compare a run to its last green baseline: pass-rate delta, new regressions, recurrences, recovered tests, new flaky tests, biggest perf improvements/regressions, worker imbalance, and newly opened clusters. Use this to answer "what changed?" and "did my fix work?".',inputSchema:{type:"object",properties:{id:{type:"number",description:"Test run ID"}},required:["id"]}},{name:"get_spec_health",description:"Per-spec-file health for a project: pass rate, flaky rate, failure count, test count, and average duration grouped by spec-file prefix over the last N days. Use to find which areas of the suite are unhealthy.",inputSchema:{type:"object",properties:{projectId:{type:"number",description:"Project ID"},days:{type:"number",description:"Lookback window in days (default 30, max 90)"}},required:["projectId"]}},{name:"get_slow_tests",description:"Slowest test cases in a project by average duration, with max/min and trend direction across recent runs. Use to target performance work.",inputSchema:{type:"object",properties:{projectId:{type:"number",description:"Project ID"},runs:{type:"number",description:"Recent runs to analyze (default 50, max 100)"}},required:["projectId"]}},{name:"get_performance_trend",description:'Time series of run duration, average test duration, and p90 test duration for a project. Use to answer "is the suite getting slower?".',inputSchema:{type:"object",properties:{projectId:{type:"number",description:"Project ID"},limit:{type:"number",description:"Number of recent runs (default 30, max 100)"}},required:["projectId"]}},{name:"get_test_stability_trend",description:'Time-series stability for a single test case: flaky rate, pass rate, and average duration bucketed over its recent execution history. Use to answer "is this test getting flakier?".',inputSchema:{type:"object",properties:{id:{type:"number",description:"Test case ID (stable testCaseId)"},buckets:{type:"number",description:"Number of time buckets (default 20, 5–50)"}},required:["id"]}},{name:"get_network_requests",description:"A run's network requests aggregated by method + normalized route, sorted by average duration, with status codes and captured backend server logs. Use to pin a UI failure on a slow or failing endpoint.",inputSchema:{type:"object",properties:{id:{type:"number",description:"Test run ID"}},required:["id"]}},{name:"get_failure_groups",description:"One run's failures grouped by failure cluster, with per-group affected cases and worker correlation. Run-scoped counterpart to list_clusters.",inputSchema:{type:"object",properties:{id:{type:"number",description:"Test run ID"}},required:["id"]}},{name:"get_locator_healing",description:"Ranked alternative locators for a failing test-run-case: the failing locator, the recommended durable fix, and the full alternative lists (from prior success, element match, and ARIA snapshot). Use when fixing a broken selector.",inputSchema:{type:"object",properties:{testRunsCaseId:{type:"number",description:"Test run case ID (executionId)"}},required:["testRunsCaseId"]}},{name:"search",description:"Global search across all in-scope projects, runs (by label or numeric id), and test cases (by title). Use to find a run by its label or locate an entity across projects.",inputSchema:{type:"object",properties:{q:{type:"string",description:"Search query (min 2 chars)"}},required:["q"]}},{name:"list_case_traces",description:"List Playwright trace files for a test-run-case, with a download path for each. Fetch the bytes via GET /api/files/<path>.",inputSchema:{type:"object",properties:{testRunsCaseId:{type:"number",description:"Test run case ID (executionId)"}},required:["testRunsCaseId"]}},{name:"list_links",description:"List external entity links (Jira, GitHub PR/issue, etc.) attached to a run, test-run-case, or test case, with provider and unfurled status.",inputSchema:{type:"object",properties:{entityType:{type:"string",enum:["test_run","test_runs_case","test_case"],description:"Which entity the links are attached to"},id:{type:"number",description:"The entity ID matching entityType"}},required:["entityType","id"]}},{name:"list_tags",description:"List the project tag catalog (id, text, color).",inputSchema:{type:"object",properties:{}}},{name:"get_project_test_catalog",description:"The full test-case catalog for a project with aggregated pass/fail/flaky counts, average duration, and last status per test. Offset-paginated bulk companion to get_test_case.",inputSchema:{type:"object",properties:{projectId:{type:"number",description:"Project ID"},pageSize:{type:"number",description:"Results per page (default 10, max 50)"},offset:{type:"number",description:"Row offset for paging (default 0)"},query:{type:"string",description:"Optional case-insensitive substring filter on title or file path"},tags:{type:"string",description:"Comma-separated tags; a test must carry every one of them. A leading @ is optional."},owner:{type:"string",description:"Exact owner declared via the piwi:owner annotation"},priority:{type:"string",enum:["critical","high","medium","low"],description:"Priority declared via the piwi:priority annotation"}},required:["projectId"]}},{name:"list_open_clusters",description:"Open failure clusters across all in-scope projects, ranked by occurrences — a cross-project triage queue. Filter by status; paginate with pageSize/cursor.",inputSchema:{type:"object",properties:{status:{type:"string",enum:["open","resolved","ignored"],description:"Triage status (default: open)"},pageSize:{type:"number",description:"Results per page (default 10, max 50)"},cursor:{type:"string",description:"Opaque cursor from a previous response to get the next page"}}}},{name:"get_instance_stats",description:"Instance-wide counts (projects, runs, test cases, executions, files) and total storage size. Admin only.",inputSchema:{type:"object",properties:{}}},{name:"explain_failure",description:"One-call evidence bundle for a single failing execution: error, steps, console, ARIA snapshot, the recommended locator fix, a screenshot count, and the AI diagnosis context. Prefer this over chaining get_test_run_case + get_locator_healing + get_test_case_context.",inputSchema:{type:"object",properties:{testRunsCaseId:{type:"number",description:"Test run case ID (executionId)"}},required:["testRunsCaseId"]}},{name:"set_cluster_status",description:"Triage a failure cluster: set its status to open, resolved, or ignored with an optional note. Requires reporter or admin access. Use after fixing the underlying issue.",inputSchema:{type:"object",properties:{id:{type:"number",description:"Cluster ID"},status:{type:"string",enum:["open","resolved","ignored"],description:"New triage status"},triageNote:{type:"string",description:"Optional note explaining the status change"}},required:["id","status"]}},{name:"set_cluster_base_commit",description:'Pin the baseline commit SHA a cluster uses for its SCM-diff diagnosis context, so "what changed since green" is accurate. Requires reporter or admin access.',inputSchema:{type:"object",properties:{id:{type:"number",description:"Cluster ID"},commit:{type:"string",description:"Baseline commit SHA (empty to clear)"}},required:["id","commit"]}},{name:"submit_diagnosis_feedback",description:"Record thumbs up/down feedback on a stored diagnosis, with an optional note. Requires reporter or admin access.",inputSchema:{type:"object",properties:{id:{type:"number",description:"Diagnosis ID"},feedback:{type:"string",enum:["up","down"],description:"Rating (omit to clear)"},feedbackNote:{type:"string",description:"Optional note"}},required:["id"]}},{name:"run_cluster_diagnosis",description:"Trigger an AI diagnosis for a failure cluster and return the result (category, confidence, root cause, suggested fix). Returns the existing completed diagnosis unless force is set. Requires reporter or admin access and a configured AI provider.",inputSchema:{type:"object",properties:{id:{type:"number",description:"Cluster ID"},force:{type:"boolean",description:"Re-run even if a completed diagnosis exists (default false)"},baseCommit:{type:"string",description:"Optional baseline commit SHA for SCM-diff context"}},required:["id"]}}];function Ie($){return new URL(globalThis.location.href)}const Ce={class:"max-w-3xl mx-auto p-6 space-y-6"},je={key:0,class:"mb-4 space-y-3 rounded-md border border-default bg-elevated/50 p-3"},Se={class:"space-y-1"},qe={class:"flex items-start gap-2"},Re={class:"text-xs break-all flex-1"},Ae={class:"space-y-1"},De={class:"flex items-start gap-2"},Pe={class:"text-xs break-all flex-1"},Te={class:"text-sm text-gray-500 dark:text-gray-400 mb-4"},Ue={class:"space-y-3"},ze={class:"space-y-3"},$e={class:"space-y-3"},Oe={class:"space-y-3"},Me={class:"space-y-3"},Le={class:"space-y-3"},Be={class:"flex flex-col gap-1.5"},Ne={class:"min-w-0"},Ee={class:"text-sm font-mono font-semibold text-foreground"},Ge={class:"text-xs text-gray-500 dark:text-gray-400 mt-0.5"},Fe={class:"space-y-3 text-sm text-gray-600 dark:text-gray-400"},He={key:0},We={key:1},Ve={key:2,class:"text-xs text-gray-400"},Ye={key:3,class:"text-xs text-gray-400"},Je={class:"space-y-2"},Ke={class:"flex items-center gap-2"},Qe={class:"flex-1 px-3 py-2 bg-muted rounded-md text-sm font-mono break-all"},Xe={class:"text-xs text-gray-400"},Ze="pd_YOUR_API_KEY",ft=M({__name:"mcp",async setup($){let h,w;const I=ne(),k=I.public.demoMode,l=pe(),{copy:A}=de(),{data:b}=([h,w]=ie(()=>le("/api/desktop/reporter-config",{immediate:l,default:()=>null},"$fdl6kilREP")),h=await h,w(),h),u=x(()=>b.value?.token??Ze),S=Ie(),n=x(()=>`${b.value?.url??I.public.siteUrl??S.origin}/mcp`);oe({title:"MCP server — Piwi Dashboard"});const a=we,m=[{label:"Claude Code",slot:"claude-code"},{label:"Cursor",slot:"cursor"},{label:"VS Code",slot:"vscode"},{label:"Claude Desktop",slot:"claude-desktop"},{label:"Gemini CLI",slot:"gemini"},{label:"Windsurf / Continue",slot:"windsurf"}],_=x(()=>`claude mcp add --transport http piwi ${n.value} \\
|
|
2
|
-
--header "Authorization: Bearer ${u.value}"`),g=x(()=>JSON.stringify({mcpServers:{piwi:{url:n.value,headers:{Authorization:`Bearer ${u.value}`}}}},null,2)),U=x(()=>JSON.stringify({servers:{piwi:{type:"http",url:n.value,headers:{Authorization:`Bearer ${u.value}`}}}},null,2)),i=x(()=>JSON.stringify({mcpServers:{piwi:{type:"http",url:n.value,headers:{Authorization:`Bearer ${u.value}`}}}},null,2)),q=x(()=>`gemini mcp add --transport http piwi ${n.value} \\
|
|
3
|
-
--header "Authorization: Bearer ${u.value}"`),G=x(()=>JSON.stringify({mcpServers:{piwi:{serverUrl:n.value,headers:{Authorization:`Bearer ${u.value}`}}}},null,2));return(F,t)=>{const H=X,W=Z,V=ke,z=N,C=ae,Y=ce,D=E,J=L,K=Q;return o(),v(K,null,{header:p(()=>[c(H,{title:"MCP server"})]),body:p(()=>[e("div",Ce,[r(k)?(o(),v(W,{key:0,color:"info",icon:"i-lucide-bot",title:"Feature preview",description:"The MCP endpoint is not active in this demo — it requires a real Piwi backend. The tools and client setup shown below reflect what your own deployment exposes."})):f("",!0),c(V),c(D,{icon:"i-lucide-settings-2",title:"Client setup",help:"mcp.client-setup"},{default:p(()=>[r(b)?(o(),d("div",je,[e("div",Se,[t[2]||(t[2]=e("div",{class:"text-xs text-muted"},"MCP URL",-1)),e("div",qe,[e("code",Re,y(r(n)),1),c(z,{icon:"i-lucide-copy",color:"neutral",variant:"ghost",size:"xs","aria-label":"Copy MCP URL",onClick:t[0]||(t[0]=R=>r(A)(r(n),{toast:!0}))})])]),e("div",Ae,[t[3]||(t[3]=e("div",{class:"text-xs text-muted"},"Access token",-1)),e("div",De,[e("code",Pe,y(r(u)),1),c(z,{icon:"i-lucide-copy",color:"neutral",variant:"ghost",size:"xs","aria-label":"Copy access token",onClick:t[1]||(t[1]=R=>r(A)(r(u),{toast:!0}))})])]),t[4]||(t[4]=e("p",{class:"text-xs text-muted"},[s(" This app authenticates with a local access token even though sign-in is off — it is the "),e("code",{class:"font-mono"},"Bearer"),s(" value, already filled into the snippets below. ")],-1))])):f("",!0),e("p",Te,[r(b)?(o(),d(j,{key:0},[s("Pick your client below — the URL and access token above are already baked into each snippet.")],64)):(o(),d(j,{key:1},[t[5]||(t[5]=s("Replace ",-1)),t[6]||(t[6]=e("code",{class:"px-1 py-0.5 bg-muted rounded text-xs font-mono"},"pd_YOUR_API_KEY",-1)),t[7]||(t[7]=s(" with your actual API key. The MCP URL shown in the snippets is auto-detected from your current browser origin.",-1))],64))]),c(Y,{items:m,ui:{list:"mb-4"}},{"claude-code":p(()=>[e("div",Ue,[t[8]||(t[8]=e("p",{class:"text-sm text-gray-600 dark:text-gray-400"}," Run once in any terminal. Claude Code stores the server in your global MCP config. ",-1)),c(C,{code:r(_),lang:"sh"},null,8,["code"]),t[9]||(t[9]=e("p",{class:"text-xs text-gray-400"},[s(" After adding, restart Claude Code and use "),e("code",{class:"font-mono"},"/mcp"),s(" to verify "),e("strong",null,"piwi"),s(" is connected. Claude will call the tools automatically when you ask about test results or failures. ")],-1))])]),cursor:p(()=>[e("div",ze,[t[10]||(t[10]=e("p",{class:"text-sm text-gray-600 dark:text-gray-400"},[s(" Add to "),e("code",{class:"font-mono text-xs"},"~/.cursor/mcp.json"),s(" (global) or "),e("code",{class:"font-mono text-xs"},".cursor/mcp.json"),s(" in your project root: ")],-1)),c(C,{code:r(g),lang:"json"},null,8,["code"]),t[11]||(t[11]=e("p",{class:"text-xs text-gray-400"}," Restart Cursor, then enable the MCP server in Cursor Settings → MCP. ",-1))])]),vscode:p(()=>[e("div",$e,[t[12]||(t[12]=e("p",{class:"text-sm text-gray-600 dark:text-gray-400"},[s(" Add to "),e("code",{class:"font-mono text-xs"},".vscode/mcp.json"),s(" in your workspace (VS Code Copilot agent mode, version 1.99+): ")],-1)),c(C,{code:r(U),lang:"json"},null,8,["code"]),t[13]||(t[13]=e("p",{class:"text-xs text-gray-400"}," The server appears in the Copilot chat agent drop-down once the file is saved. ",-1))])]),"claude-desktop":p(()=>[e("div",Oe,[t[14]||(t[14]=e("p",{class:"text-sm text-gray-600 dark:text-gray-400"},"Add to your Claude Desktop config file:",-1)),t[15]||(t[15]=e("ul",{class:"text-xs text-gray-400 space-y-0.5 mb-2"},[e("li",null,[e("strong",null,"macOS:"),e("code",{class:"font-mono"},"~/Library/Application Support/Claude/claude_desktop_config.json")]),e("li",null,[e("strong",null,"Windows:"),e("code",{class:"font-mono"},"%APPDATA%\\Claude\\claude_desktop_config.json")])],-1)),c(C,{code:r(i),lang:"json"},null,8,["code"]),t[16]||(t[16]=e("p",{class:"text-xs text-gray-400"}," Requires Claude Desktop with remote MCP support (released early 2025). Restart the app after saving. ",-1))])]),gemini:p(()=>[e("div",Me,[t[17]||(t[17]=e("p",{class:"text-sm text-gray-600 dark:text-gray-400"},"Run once to register the server with Gemini CLI:",-1)),c(C,{code:r(q),lang:"sh"},null,8,["code"]),t[18]||(t[18]=e("p",{class:"text-xs text-gray-400"}," Gemini CLI fetches the tool list on startup and makes them available in agent mode. ",-1))])]),windsurf:p(()=>[e("div",Le,[t[19]||(t[19]=e("p",{class:"text-sm text-gray-600 dark:text-gray-400"},[s(" Add to your Windsurf or Continue MCP config. For Windsurf: "),e("code",{class:"font-mono text-xs"},"~/.codeium/windsurf/mcp_config.json"),s(". For Continue: "),e("code",{class:"font-mono text-xs"},"~/.continue/config.json"),s(" under "),e("code",{class:"font-mono text-xs"},"mcpServers"),s(". ")],-1)),c(C,{code:r(G),lang:"json"},null,8,["code"])])]),_:1})]),_:1}),c(D,{icon:"i-lucide-bot",title:"What it provides",help:"mcp.tools"},{default:p(()=>[e("div",Be,[(o(!0),d(j,null,B(r(a),R=>(o(),d("div",{key:R.name,class:"flex items-start gap-3 px-3 py-2.5 rounded-md bg-elevated/50 border border-default hover:bg-elevated transition-colors"},[c(J,{name:"i-lucide-wrench",class:"size-4 mt-0.5 shrink-0 text-primary"}),e("div",Ne,[e("p",Ee,y(R.name),1),e("p",Ge,y(R.description),1)])]))),128))])]),_:1}),c(D,{icon:"i-lucide-key",title:"Authentication",help:"mcp.auth"},{default:p(()=>[e("div",Fe,[t[24]||(t[24]=e("p",null,[s(" MCP requests are authenticated with the same API keys used by the REST API. API keys start with "),e("code",{class:"px-1 py-0.5 bg-muted rounded text-xs font-mono"},"pd_"),s(". ")],-1)),r(l)?(o(),d("p",We,[...t[21]||(t[21]=[s(" This app provides a local access token automatically — shown in ",-1),e("strong",null,"Client setup",-1),s(" above and already filled into every snippet, so there is nothing to replace. ",-1)])])):(o(),d("p",He,[...t[20]||(t[20]=[s(" Generate a key in ",-1),e("strong",null,"Settings → Users → [your account] → API keys",-1),s(", then replace ",-1),e("code",{class:"px-1 py-0.5 bg-muted rounded text-xs font-mono"},"pd_YOUR_API_KEY",-1),s(" in the snippets above. ",-1)])])),r(l)?(o(),d("p",Ye,[...t[23]||(t[23]=[s(" This desktop app keeps sign-in off but still requires its own local access token on every request — it is the ",-1),e("code",{class:"font-mono"},"Bearer",-1),s(" value. The endpoint is not open. ",-1)])])):(o(),d("p",Ve,[...t[22]||(t[22]=[s(" When authentication is disabled (",-1),e("code",{class:"font-mono"},"PIWI_AUTH_ENABLED",-1),s(" not set), any request is accepted without a key. ",-1)])]))])]),_:1}),c(D,{icon:"i-lucide-link",title:"Server URL"},{default:p(()=>[e("div",Je,[e("div",Ke,[e("code",Qe,y(r(n)),1),c(z,{icon:"i-lucide-external-link",size:"sm",color:"neutral",variant:"outline",title:"Open API docs",to:"/docs",external:!r(k)},{default:p(()=>[...t[25]||(t[25]=[s(" REST API docs ",-1)])]),_:1},8,["external"])]),e("p",Xe,[t[32]||(t[32]=s(" This is your Piwi instance's MCP endpoint. It is also the server URL to paste into client configs above. ",-1)),r(l)?(o(),d(j,{key:0},[t[26]||(t[26]=s("This desktop app requires its local access token as the ",-1)),t[27]||(t[27]=e("code",{class:"font-mono"},"Bearer",-1)),t[28]||(t[28]=s(" value on every request.",-1))],64)):(o(),d(j,{key:1},[t[29]||(t[29]=s("The server requires a valid Bearer token (or no auth if ",-1)),t[30]||(t[30]=e("code",{class:"font-mono"},"PIWI_AUTH_ENABLED",-1)),t[31]||(t[31]=s(" is not set).",-1))],64))])])]),_:1})])]),_:1})}}});export{ft as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{_ as $,a as k}from"./CXEH9OPk.js";import{_ as y,a as B}from"./5A6ITZXj.js";import{u as C,_ as D}from"./CIoSMkpp.js";import{a3 as M,a5 as S,o as m,f as d,g as i,V as c,i as p,q as u,k as s,X as U,h as _,a8 as N,B as P,r as q,d as T,e as j,j as o,aK as V}from"./Du2W7Jne.js";import"./KyA_4Ks-.js";import"./DfgOx_ou.js";import"./BT3wGCTI.js";import"./Cbh--1MW.js";import"./BjaRappk.js";import"./_mj6CfPa.js";const H={slots:{root:"shrink-0 flex items-center justify-between border-b border-default px-4 sm:px-6 gap-1.5 overflow-x-auto min-h-[49px]",left:"flex items-center gap-1.5",right:"flex items-center gap-1.5"}},z={__name:"UDashboardToolbar",props:{as:{type:null,required:!1},class:{type:null,required:!1},ui:{type:Object,required:!1}},setup(t){const e=M("dashboardToolbar",t),a=S(),l=_(()=>N({extend:H,...a.ui?.dashboardToolbar||{}})());return(r,f)=>(m(),d(s(U),{as:s(e).as,"data-slot":"root",class:u(l.value.root({class:[s(e).ui?.root,s(e).class]}))},{default:i(()=>[c(r.$slots,"default",{},()=>[p("div",{"data-slot":"left",class:u(l.value.left({class:[s(e).ui?.left]}))},[c(r.$slots,"left")],2),p("div",{"data-slot":"right",class:u(l.value.right({class:[s(e).ui?.right]}))},[c(r.$slots,"right")],2)])]),_:3},8,["as","class"]))}};function A(){const t=q({account:!1,users:!1,notifications:!1,tags:!1,storage:!1,"wasted-time":!1,"timeout-hygiene":!1,"pr-feedback":!1,ai:!1,about:!1});async function n(){const e=[];e.push($fetch("/api/settings/ai").then(a=>{t.value.ai=!!a.envManaged}).catch(()=>{})),e.push($fetch("/api/settings/wasted-waits").then(a=>{t.value["wasted-time"]=!!a.envManaged}).catch(()=>{})),e.push($fetch("/api/settings/smtp").then(a=>{t.value.notifications=!!(a.envManaged&&a.configured)}).catch(()=>{})),await Promise.all(e)}return P(()=>{n()}),{envManaged:t,refresh:n}}const E={class:"flex flex-col gap-4 sm:gap-6 lg:gap-12 w-full lg:max-w-4xl mx-auto"},W=T({__name:"settings",setup(t){j({title:"Settings — Piwi Dashboard"});const{envManaged:n}=A(),e=C(n),a=_(()=>[e.value,[{label:"Documentation",icon:"i-lucide-book-open",to:"https://github.com/piwitests/platform",target:"_blank"}]]);return(l,r)=>{const f=$,g=k,h=B,b=D,v=z,x=V,w=y;return m(),d(w,{id:"settings",ui:{body:"lg:py-12"}},{header:i(()=>[o(h,null,{leading:i(()=>[o(f),o(g,{items:[{label:"Home",icon:"i-lucide-house",to:"/"},{label:"Settings"}]})]),_:1}),o(v,null,{default:i(()=>[o(b,{items:s(a),highlight:"",class:"-mx-1 flex-1",ui:{list:"overflow-x-auto",root:"min-w-0"}},null,8,["items"])]),_:1})]),body:i(()=>[p("div",E,[o(x)])]),_:1})}}});export{W as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{d as j,b as F,w as R,aw as T,c as y,j as l,g as r,o as _,i as m,F as $,y as S,k as i,I as U,_ as V,m as u,r as C,L as O}from"./Du2W7Jne.js";import{_ as P}from"./AbmKWFQQ.js";import{_ as A}from"./C0_yH0N7.js";import{u as B}from"./B8zkOmwo.js";import"./L3kAWB2a.js";import"./Bm62iDV5.js";import"./BjaRappk.js";import"./DSqHUrvO.js";import"./-f7BAm1H.js";const N={class:"space-y-6"},E={class:"grid grid-cols-1 gap-x-4 gap-y-3 sm:grid-cols-2"},L={class:"flex items-center justify-end gap-2"},X=j({__name:"timeout-hygiene",async setup(z){let d,p;const c=F(),{data:s,refresh:f}=([d,p]=R(()=>B("/api/settings/timeout-hygiene","$8Luq-s6QSj")),d=await d,p(),d),o=C(!1),n=O({minRuns:0,factor:0,floorMs:0,safety:0,recommendedFloorMs:0,slowStaleP95Ms:0});T(()=>{s.value&&Object.assign(n,s.value.thresholds)});const g=[{key:"minRuns",label:"Minimum runs",description:"Executions with a duration needed before a test is judged.",min:1,step:1},{key:"factor",label:"Oversize factor (×)",description:"Flag a timeout when it is at least this many times the test’s p95 duration.",min:1,step:.5},{key:"floorMs",label:"Minimum headroom (ms)",description:"Only flag when the timeout − p95 gap is at least this many ms.",min:0,step:1e3},{key:"safety",label:"Recommendation safety (×)",description:"Recommended timeout = p95 × this.",min:1,step:.5},{key:"recommendedFloorMs",label:"Recommendation floor (ms)",description:"Never recommend a timeout below this many ms.",min:0,step:1e3},{key:"slowStaleP95Ms",label:"Stale slow() p95 (ms)",description:"A test.slow() test is stale when its p95 duration stays under this.",min:0,step:1e3}];async function v(){o.value=!0;try{const e=await $fetch("/api/settings/timeout-hygiene",{method:"PUT",body:{thresholds:{...n}}});s.value=e,c.add({title:"Timeout-hygiene thresholds saved",color:"success"}),await f()}catch(e){const a=e&&typeof e=="object"&&"data"in e?e.data?.message:void 0;c.add({title:"Save failed",description:a||"An error occurred",color:"error"})}finally{o.value=!1}}async function b(){o.value=!0;try{const e=await $fetch("/api/settings/timeout-hygiene",{method:"PUT",body:{thresholds:null}});s.value=e,Object.assign(n,e.thresholds),c.add({title:"Reset to defaults",color:"success"}),await f()}catch{c.add({title:"Reset failed",color:"error"})}finally{o.value=!1}}return(e,a)=>{const w=U,k=P,h=V,x=A;return _(),y("div",N,[l(x,{icon:"i-lucide-scissors",title:"Timeout hygiene",help:"settings.timeout-hygiene"},{subtitle:r(()=>[...a[0]||(a[0]=[u(" Tune how timeout opportunities are detected — oversized per-test timeouts and stale ",-1),m("code",null,"test.slow()",-1),u(" marks — surfaced per project (Performance tab) and in Analytics. Opportunities are recomputed when viewed, so changes apply to existing runs immediately. ",-1)])]),footer:r(()=>[m("div",L,[l(h,{variant:"ghost",color:"neutral",disabled:i(o),label:"Reset to defaults",onClick:b},null,8,["disabled"]),l(h,{color:"primary",loading:i(o),icon:"i-lucide-save",onClick:v},{default:r(()=>[...a[1]||(a[1]=[u("Save",-1)])]),_:1},8,["loading"])])]),default:r(()=>[m("div",E,[(_(),y($,null,S(g,t=>l(k,{key:t.key,label:t.label,description:t.description,hint:`default ${i(s)?.defaults[t.key]??""}`},{default:r(()=>[l(w,{modelValue:i(n)[t.key],"onUpdate:modelValue":M=>i(n)[t.key]=M,modelModifiers:{number:!0},type:"number",min:t.min,step:t.step,placeholder:`default ${i(s)?.defaults[t.key]??""}`,class:"w-full"},null,8,["modelValue","onUpdate:modelValue","min","step","placeholder"])]),_:2},1032,["label","description","hint"])),64))])]),_:1})])}}});export{X as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{_ as pe}from"./CXEH9OPk.js";import{_ as me}from"./DabzhQB1.js";import{_ as he,a as fe}from"./5A6ITZXj.js";import{_ as ye}from"./B3obW6cw.js";import{_ as Y}from"./BrQEE053.js";import{_ as ge}from"./C0_yH0N7.js";import{d as G,o as v,c as C,i as b,t as I,k as e,j as E,g as S,p as J,q,m as R,s as ve,f as A,v as z,x as _e,F as W,y as Q,h as U,_ as Z,z as be,A as ee,r as F,u as xe,w as we,e as ke,B as $e,C as H}from"./Du2W7Jne.js";import{_ as Te}from"./C1gTN4Q8.js";import{f as V}from"./D-c8ZSws.js";import{u as Ce}from"./B8zkOmwo.js";import"./KyA_4Ks-.js";import"./DuwtTfO8.js";import"./DSqHUrvO.js";import"./Bm62iDV5.js";import"./BjaRappk.js";import"./-f7BAm1H.js";const Ie={class:"p-3 sm:p-4 space-y-2"},ze={class:"flex items-start justify-between gap-3"},Be={class:"min-w-0 space-y-1"},Ee={class:"font-medium text-sm break-all"},Ue={class:"text-xs text-gray-500"},Re={class:"flex items-center gap-2 shrink-0"},Ae={key:2,class:"text-xs"},je={key:0,class:"text-xs text-gray-500"},Pe={class:"text-default"},Le={key:1,class:"flex flex-wrap gap-x-4 gap-y-1 text-xs text-gray-500"},Se={key:0},De={key:1},Fe={key:2},Ne={key:3},Me={key:3,class:"text-xs text-gray-500"},Ve={class:"space-y-0.5"},Oe={class:"text-[11px]"},He=G({__name:"ImportFileRow",props:{entry:{},removable:{type:Boolean}},emits:["remove"],setup(p){const c=p,a={hashing:{label:"Reading",color:"neutral",icon:"i-lucide-loader-circle"},checking:{label:"Checking",color:"neutral",icon:"i-lucide-loader-circle"},ready:{label:"Ready",color:"primary",icon:"i-lucide-circle-check"},uploading:{label:"Importing",color:"primary",icon:"i-lucide-loader-circle"},imported:{label:"Imported",color:"success",icon:"i-lucide-check"},duplicate:{label:"Already imported",color:"neutral",icon:"i-lucide-copy-check"},"too-large":{label:"Too large",color:"warning",icon:"i-lucide-weight"},invalid:{label:"Not importable",color:"warning",icon:"i-lucide-file-x"},failed:{label:"Failed",color:"error",icon:"i-lucide-circle-alert"}},d=U(()=>a[c.entry.state]),m=U(()=>["hashing","checking","uploading"].includes(c.entry.state)),o=U(()=>c.entry.result),t=U(()=>c.entry.state==="imported"?o.value:null),h=U(()=>t.value?.kind==="trace");function n(l,i){return`${l} ${i}${l===1?"":"s"}`}return(l,i)=>{const f=J,y=ve,k=Z,$=be,x=_e,T=Y;return v(),C("div",Ie,[b("div",ze,[b("div",Be,[b("p",Ee,I(p.entry.name),1),b("p",Ue,I(("formatBytes"in l?l.formatBytes:e(V))(p.entry.size)),1)]),b("div",Re,[E(y,{color:e(d).color,variant:"subtle",size:"sm"},{default:S(()=>[E(f,{name:e(d).icon,class:q(["size-3.5 mr-1",e(m)&&"animate-spin"])},null,8,["name","class"]),R(" "+I(e(d).label),1)]),_:1},8,["color"]),p.removable?(v(),A(k,{key:0,icon:"i-lucide-x",color:"neutral",variant:"ghost",size:"xs",title:"Remove from the list",onClick:i[0]||(i[0]=s=>l.$emit("remove",p.entry.id))})):z("",!0)])]),p.entry.state==="uploading"||p.entry.state==="hashing"?(v(),A($,{key:0,"model-value":Math.round(p.entry.progress*100),size:"sm"},null,8,["model-value"])):z("",!0),p.entry.message?(v(),C("p",{key:1,class:q(["text-xs",p.entry.state==="failed"?"text-error":"text-gray-500"])},I(p.entry.message),3)):z("",!0),e(o)?.testRunId?(v(),C("div",Ae,[E(x,{to:`/test-runs/${e(o).testRunId}`,class:"text-primary hover:underline"},{default:S(()=>[R(" View run #"+I(e(o).testRunId),1)]),_:1},8,["to"])])):z("",!0),e(t)?(v(),C(W,{key:3},[e(h)?(v(),C("p",je,[i[1]||(i[1]=R(" Added ",-1)),b("span",Pe,I(e(t).caseTitle),1),i[2]||(i[2]=R(" to this run. ",-1))])):(v(),C("div",Le,[b("span",null,I(n(e(t).totalTests,"execution")),1),b("span",null,I(e(t).passedTests)+" passed",1),b("span",null,I(e(t).failedTests)+" failed",1),e(t).skippedTests?(v(),C("span",Se,I(e(t).skippedTests)+" skipped",1)):z("",!0),e(t).flakyTests?(v(),C("span",De,I(e(t).flakyTests)+" flaky",1)):z("",!0),e(t).traceCount?(v(),C("span",Fe,I(n(e(t).traceCount,"trace")),1)):z("",!0),e(t).attachmentCount?(v(),C("span",Ne,I(n(e(t).attachmentCount,"attachment")),1)):z("",!0)])),e(t).shard?(v(),A(T,{key:2,color:"warning",variant:"subtle",icon:"i-lucide-split",description:`This archive is shard ${e(t).shard.current} of ${e(t).shard.total}. Each shard imports as its own run — they are not merged.`,ui:{description:"text-xs"}},null,8,["description"])):z("",!0),e(t).filePaths.length&&!e(h)?(v(),C("div",Me,[i[3]||(i[3]=b("p",{class:"mb-1"},[R(" Spec files recorded as "),b("span",{class:"text-gray-400"},"(these must match the paths your live runs report for history to line up)"),R(": ")],-1)),b("ul",Ve,[(v(!0),C(W,null,Q(e(t).filePaths,s=>(v(),C("li",{key:s},[b("code",Oe,I(s),1)]))),128))])])):z("",!0)],64)):z("",!0)])}}}),qe=Object.assign(He,{__name:"ImportFileRow"}),L=new Uint32Array([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),We=new Uint32Array([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),Ke=Array.from({length:256},(p,c)=>c.toString(16).padStart(2,"0"));class te{#r=new Uint32Array(We);#t=new Uint8Array(64);#e=0;#n=0;#i=new Uint32Array(64);#o=!1;update(c){if(this.#o)throw new Error("Sha256: update() after digest()");this.#n+=c.length;let a=0;if(this.#e>0){const d=Math.min(64-this.#e,c.length);if(this.#t.set(c.subarray(0,d),this.#e),this.#e+=d,a=d,this.#e<64)return this;this.#s(this.#t,0),this.#e=0}for(;a+64<=c.length;a+=64)this.#s(c,a);return a<c.length&&(this.#t.set(c.subarray(a),0),this.#e=c.length-a),this}digest(){if(this.#o)throw new Error("Sha256: digest() called twice");this.#o=!0;const c=this.#n*8;this.#t[this.#e++]=128,this.#e>56&&(this.#t.fill(0,this.#e),this.#s(this.#t,0),this.#e=0),this.#t.fill(0,this.#e,56);const a=new DataView(this.#t.buffer,this.#t.byteOffset,64);a.setUint32(56,Math.floor(c/4294967296),!1),a.setUint32(60,c>>>0,!1),this.#s(this.#t,0);const d=new Uint8Array(32),m=new DataView(d.buffer);for(let o=0;o<8;o++)m.setUint32(o*4,this.#r[o],!1);return d}hex(){const c=this.digest();let a="";for(let d=0;d<32;d++)a+=Ke[c[d]];return a}#s(c,a){const d=this.#i,m=this.#r;for(let r=0;r<16;r++){const _=a+r*4;d[r]=c[_]<<24|c[_+1]<<16|c[_+2]<<8|c[_+3]}for(let r=16;r<64;r++){const _=d[r-15],B=d[r-2],g=(_>>>7|_<<25)^(_>>>18|_<<14)^_>>>3,D=(B>>>17|B<<15)^(B>>>19|B<<13)^B>>>10;d[r]=d[r-16]+g+d[r-7]+D|0}let o=m[0],t=m[1],h=m[2],n=m[3],l=m[4],i=m[5],f=m[6],y=m[7],k=0,$=0,x=0,T=0,s=0,u=0;for(let r=0;r<64;r+=8)$=(l>>>6|l<<26)^(l>>>11|l<<21)^(l>>>25|l<<7),x=l&i^~l&f,s=y+$+x+L[r]+d[r]|0,k=(o>>>2|o<<30)^(o>>>13|o<<19)^(o>>>22|o<<10),T=o&t^o&h^t&h,u=k+T|0,n=n+s|0,y=s+u|0,$=(n>>>6|n<<26)^(n>>>11|n<<21)^(n>>>25|n<<7),x=n&l^~n&i,s=f+$+x+L[r+1]+d[r+1]|0,k=(y>>>2|y<<30)^(y>>>13|y<<19)^(y>>>22|y<<10),T=y&o^y&t^o&t,u=k+T|0,h=h+s|0,f=s+u|0,$=(h>>>6|h<<26)^(h>>>11|h<<21)^(h>>>25|h<<7),x=h&n^~h&l,s=i+$+x+L[r+2]+d[r+2]|0,k=(f>>>2|f<<30)^(f>>>13|f<<19)^(f>>>22|f<<10),T=f&y^f&o^y&o,u=k+T|0,t=t+s|0,i=s+u|0,$=(t>>>6|t<<26)^(t>>>11|t<<21)^(t>>>25|t<<7),x=t&h^~t&n,s=l+$+x+L[r+3]+d[r+3]|0,k=(i>>>2|i<<30)^(i>>>13|i<<19)^(i>>>22|i<<10),T=i&f^i&y^f&y,u=k+T|0,o=o+s|0,l=s+u|0,$=(o>>>6|o<<26)^(o>>>11|o<<21)^(o>>>25|o<<7),x=o&t^~o&h,s=n+$+x+L[r+4]+d[r+4]|0,k=(l>>>2|l<<30)^(l>>>13|l<<19)^(l>>>22|l<<10),T=l&i^l&f^i&f,u=k+T|0,y=y+s|0,n=s+u|0,$=(y>>>6|y<<26)^(y>>>11|y<<21)^(y>>>25|y<<7),x=y&o^~y&t,s=h+$+x+L[r+5]+d[r+5]|0,k=(n>>>2|n<<30)^(n>>>13|n<<19)^(n>>>22|n<<10),T=n&l^n&i^l&i,u=k+T|0,f=f+s|0,h=s+u|0,$=(f>>>6|f<<26)^(f>>>11|f<<21)^(f>>>25|f<<7),x=f&y^~f&o,s=t+$+x+L[r+6]+d[r+6]|0,k=(h>>>2|h<<30)^(h>>>13|h<<19)^(h>>>22|h<<10),T=h&n^h&l^n&l,u=k+T|0,i=i+s|0,t=s+u|0,$=(i>>>6|i<<26)^(i>>>11|i<<21)^(i>>>25|i<<7),x=i&f^~i&y,s=o+$+x+L[r+7]+d[r+7]|0,k=(t>>>2|t<<30)^(t>>>13|t<<19)^(t>>>22|t<<10),T=t&h^t&n^h&n,u=k+T|0,l=l+s|0,o=s+u|0;m[0]=m[0]+o|0,m[1]=m[1]+t|0,m[2]=m[2]+h|0,m[3]=m[3]+n|0,m[4]=m[4]+l|0,m[5]=m[5]+i|0,m[6]=m[6]+f|0,m[7]=m[7]+y|0}}async function Xe(p,c){const a=new te,d=p.stream().getReader();let m=0;for(;;){const{done:o,value:t}=await d.read();if(o)break;a.update(t),m+=t.length,c&&c(p.size?m/p.size:1)}return c&&c(1),a.hex()}const X=["ready","failed"],Ye={ok:"ready",duplicate:"duplicate","too-large":"too-large",invalid:"invalid"};function Ge(p){const c=Je("/api/test-runs/import"),a=F([]),d=F(null),m=F(null),o=F(!1);let t=1;const h=U(()=>a.value.filter(s=>X.includes(s.state)).length),n=U(()=>a.value.filter(s=>s.state==="imported").length),l=U(()=>a.value.some(s=>s.state==="hashing"||s.state==="checking")),i=F({done:0,total:0});async function f(){if(p.value)try{const s=await $fetch("/api/test-runs/import/check",{method:"POST",body:{projectName:p.value,files:[]}});d.value=s.maxBytes,m.value=null}catch(s){m.value=M(s,"Could not reach the server to read its upload limit.")}}async function y(s){const u=s.map(g=>({id:t++,file:g,name:g.name,size:g.size,state:"hashing",progress:0}));a.value=[...a.value,...u];const r=a.value.slice(-u.length),_=[];for(const g of r)d.value!=null&&g.size>d.value?(g.state="too-large",g.message=`${V(g.size)} exceeds the ${V(d.value)} limit.`):g.size===0?(g.state="invalid",g.message="The file is empty."):g.name.toLowerCase().endsWith(".zip")?_.push(g):(g.state="invalid",g.message="Expected a .zip blob report (blob-report/report-*.zip).");if(_.length===0)return;for(const g of _)try{g.progress=0,g.hash=await Xe(g.file,D=>{g.progress=D}),g.state="checking"}catch(D){g.state="failed",g.message=M(D,"Could not read the file.")}finally{g.progress=0}const B=await Qe(_);for(const g of _)g.group=B??void 0;await k(_.filter(g=>g.state==="checking"))}async function k(s){if(!(s.length===0||!p.value))try{const u=await $fetch("/api/test-runs/import/check",{method:"POST",body:{projectName:p.value,files:s.map(r=>({name:r.name,size:r.size,hash:r.hash}))}});d.value=u.maxBytes,u.results.forEach((r,_)=>{const B=s[_];B&&(B.state=Ye[r.status]??"ready",B.message=r.message,r.testRunId&&(B.result={testRunId:r.testRunId}))})}catch(u){const r=M(u,"Pre-flight check failed.");for(const _ of s)_.state="ready",_.message=`${r} Importing will still verify it.`}}async function $(){if(o.value||!p.value)return;o.value=!0;const s=a.value.filter(u=>X.includes(u.state));i.value={done:0,total:s.length};try{for(const u of s){u.state="uploading",u.message=void 0,u.progress=0;try{const r=await Ze(c,p.value,u,u.group??null,_=>{u.progress=_});u.result=r,u.state=r.status==="duplicate"?"duplicate":"imported",u.message=r.status==="duplicate"?"Already imported into this project.":void 0}catch(r){u.state="failed",u.message=M(r,"The import failed.")}finally{u.progress=0,i.value={...i.value,done:i.value.done+1}}}}finally{o.value=!1}}function x(s){a.value=a.value.filter(u=>u.id!==s)}function T(){a.value=a.value.filter(s=>!["imported","duplicate"].includes(s.state))}return{entries:a,maxBytes:d,limitError:m,importing:o,readyCount:h,importedCount:n,busy:l,batch:i,loadLimit:f,addFiles:y,startImport:$,remove:x,clearFinished:T}}function Je(p){return`${(ee().app.baseURL||"/").replace(/\/$/,"")}${p}`}async function Qe(p){const c=p.map(a=>a.hash).filter(a=>!!a);return c.length===0?null:new te().update(new TextEncoder().encode([...c].sort().join(""))).hex()}function Ze(p,c,a,d,m){return new Promise((o,t)=>{const h=new FormData;h.append("projectName",c),d&&h.append("importGroup",d),h.append("archive",a.file,a.name);const n=new XMLHttpRequest;n.open("POST",p),n.responseType="json",n.upload.addEventListener("progress",l=>{l.lengthComputable&&m(l.loaded/l.total)}),n.addEventListener("load",()=>{const l=n.response;if(n.status>=200&&n.status<300){o(l);return}const i=typeof l?.message=="string"?l.message:null;t(new Error(i??et(n.status)))}),n.addEventListener("error",()=>t(new Error("The connection dropped during the upload."))),n.addEventListener("abort",()=>t(new Error("The upload was cancelled."))),n.addEventListener("timeout",()=>t(new Error("The upload timed out."))),n.send(h)})}function et(p){return p===413?"The server (or a proxy in front of it) rejected the archive as too large.":p===401||p===403?"You do not have permission to import into this project.":p===0?"The connection dropped during the upload.":p>=500?`The server failed while importing (HTTP ${p}).`:`The import was rejected (HTTP ${p}).`}function M(p,c){const a=p?.data;return typeof a?.message=="string"&&a.message?a.message:p?.message||c}const tt={class:"p-4 space-y-4"},st={class:"space-y-4"},ot={class:"text-sm text-gray-600 dark:text-gray-400 space-y-2"},rt={class:"flex items-center gap-2"},nt={key:0,class:"text-xs text-gray-500 tabular-nums"},it={class:"space-y-4"},at={key:0,class:"text-xs text-gray-500 mt-3"},lt={key:1,class:"divide-y divide-gray-100 dark:divide-gray-800 border rounded-lg border-gray-200 dark:border-gray-800"},ct={key:2,class:"flex justify-end"},Ct=G({__name:"import",async setup(p){let c,a;const m=xe().params.id,{data:o}=([c,a]=we(()=>Ce(`/api/projects/${m}`,"$w9ISz8uFNz")),c=await c,a(),c);ke(U(()=>({title:`Import runs — ${o.value?.label||o.value?.name||"Project"} — Piwi Dashboard`})));const t=ee().public.demoMode,h=U(()=>o.value?.name),{entries:n,maxBytes:l,limitError:i,importing:f,readyCount:y,importedCount:k,busy:$,batch:x,loadLimit:T,addFiles:s,startImport:u,remove:r,clearFinished:_}=Ge(h);$e(T);const B=F(null),g=F(!1);function D(j){const w=j.target;w.files?.length&&s([...w.files]),w.value=""}function se(j){g.value=!1;const w=[...j.dataTransfer?.files??[]];w.length&&s(w)}const oe=U(()=>n.value.filter(j=>["imported","duplicate"].includes(j.state)).length);return(j,w)=>{const re=pe,ne=me,ie=fe,ae=ye,O=Y,K=ge,N=Z,le=J,ce=Te,de=qe,ue=he;return v(),A(ue,{id:"project-import"},{header:S(()=>[E(ie,null,{leading:S(()=>[E(re),E(ne,{items:[{label:"Home",icon:"i-lucide-house",to:"/"},{label:"Projects",to:"/projects"},{label:e(o)?.label||e(o)?.name||"Project",to:`/projects/${e(m)}`},{label:"Import runs"}]},null,8,["items"])]),_:1})]),body:S(()=>[b("div",tt,[E(K,{title:"Import past runs",icon:"i-lucide-import",help:"project.import",subtitle:"Backfill runs recorded before you started using Piwi, from Playwright's own blob reports."},{default:S(()=>[b("div",st,[b("div",ot,[w[5]||(w[5]=b("p",null,[R(" Run your suite with the blob reporter and upload the archives it writes to "),b("code",null,"blob-report/"),R(": ")],-1)),E(ae,{code:"npx playwright test --reporter=blob",language:"bash"}),w[6]||(w[6]=b("p",null," Each archive imports as one completed run, with its traces, screenshots and videos. Importing the same archive twice does nothing, so an interrupted batch is safe to repeat. ",-1))]),e(t)?(v(),A(O,{key:0,color:"primary",variant:"subtle",icon:"i-lucide-monitor-smartphone",title:"Nothing leaves your browser",description:"This is the demo: the archive is read by a service worker and stored in your browser, not uploaded. It is cleared when the demo's sample data is refreshed, or when you reset the demo.",ui:{description:"text-xs"}})):z("",!0),E(O,{color:"neutral",variant:"subtle",icon:"i-lucide-info",title:"What imported runs carry",description:"Failures still cluster, and traces, screenshots and videos open exactly as they do for reported runs. Web vitals, page state and locator healing come from Piwi's own capture fixtures, so historical runs have none — they start once the reporter is in place.",ui:{description:"text-xs"}}),e(i)?(v(),A(O,{key:1,color:"error",variant:"subtle",icon:"i-lucide-circle-alert",description:e(i)},null,8,["description"])):z("",!0)])]),_:1}),E(K,{title:"Archives",icon:"i-lucide-files",count:e(n).length||null},{actions:S(()=>[b("div",rt,[e(f)?(v(),C("span",nt,I(e(x).done)+" of "+I(e(x).total)+" done ",1)):z("",!0),e(oe)>0&&!e(f)?(v(),A(N,{key:1,label:"Clear finished",icon:"i-lucide-eraser",color:"neutral",variant:"ghost",size:"sm",disabled:e(f),onClick:w[0]||(w[0]=P=>e(_)())},null,8,["disabled"])):z("",!0),E(N,{label:e(y)>0?`Import ${e(y)} archive${e(y)===1?"":"s"}`:"Import",icon:"i-lucide-upload",size:"sm",loading:e(f),disabled:e(y)===0||e($),onClick:w[1]||(w[1]=P=>e(u)())},null,8,["label","loading","disabled"])])]),default:S(()=>[b("div",it,[b("div",{class:q(["rounded-lg border-2 border-dashed p-6 text-center transition-colors",e(g)?"border-primary bg-primary/5":"border-gray-200 dark:border-gray-700"]),onDragover:w[3]||(w[3]=H(P=>g.value=!0,["prevent"])),onDragleave:w[4]||(w[4]=H(P=>g.value=!1,["prevent"])),onDrop:H(se,["prevent"])},[E(le,{name:"i-lucide-file-archive",class:"size-7 text-gray-400 mb-2"}),w[7]||(w[7]=b("p",{class:"text-sm text-gray-600 dark:text-gray-400"},[R("Drop "),b("code",null,"report-*.zip"),R(" files here, or")],-1)),E(N,{label:"Choose files",icon:"i-lucide-folder-open",variant:"outline",size:"sm",class:"mt-2",disabled:e(f),onClick:w[2]||(w[2]=P=>e(B)?.click())},null,8,["disabled"]),e(l)?(v(),C("p",at," Up to "+I(("formatBytes"in j?j.formatBytes:e(V))(e(l)))+" per archive. Larger ones are rejected here, before uploading. ",1)):z("",!0),b("input",{ref_key:"fileInput",ref:B,type:"file",accept:".zip",multiple:"",class:"hidden",onChange:D},null,544)],34),e(n).length===0?(v(),A(ce,{key:0,icon:"i-lucide-inbox",text:"No archives selected yet."})):(v(),C("div",lt,[(v(!0),C(W,null,Q(e(n),P=>(v(),A(de,{key:P.id,entry:P,removable:!e(f)&&P.state!=="uploading",onRemove:e(r)},null,8,["entry","removable","onRemove"]))),128))])),e(k)>0?(v(),C("div",ct,[E(N,{label:`Open ${e(o)?.label||e(o)?.name||"project"}`,icon:"i-lucide-arrow-right",trailing:"",variant:"ghost",size:"sm",to:`/projects/${e(m)}`},null,8,["label","to"])])):z("",!0)])]),_:1},8,["count"])])]),_:1})}}});export{Ct as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{ck as u,b as n}from"./Du2W7Jne.js";function d(c={}){const{copy:i,copied:r,isSupported:a}=u({copiedDuring:c.duration??2e3,legacy:!0}),e=n();async function s(t,o={}){if(t){try{await i(t)}catch{return}o.toast&&e.add({title:typeof o.toast=="string"?o.toast:"Copied to clipboard",icon:"i-lucide-check",color:"success",duration:2e3})}}return{copy:s,copied:r,isSupported:a}}export{d as u};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{d as m,H as h,o as l,f as o,W as p,bl as g,c2 as E,h as d,c,v as B,F as f,y as V}from"./Du2W7Jne.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:n}=E(),t=d(()=>e.checked??e.value);return h(t,(r,a)=>{if(!n.value)return;const u=n.value,_=window.HTMLInputElement.prototype,v=Object.getOwnPropertyDescriptor(_,"value").set;if(v&&r!==a){const b=new Event("input",{bubbles:!0}),q=new Event("change",{bubbles:!0});v.call(u,r),u.dispatchEvent(b),u.dispatchEvent(q)}}),(r,a)=>(l(),o(g,p({ref_key:"primitiveElement",ref:s},{...e,...r.$attrs},{as:"input"}),null,16))}}),y=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),n=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)=>(l(),c(f,null,[B(" We render single input if it's required "),s.value?(l(),o(y,p({key:t.name},{...e,...t.$attrs},{name:t.name,value:t.value}),null,16,["name","value"])):(l(!0),c(f,{key:1},V(n.value,a=>(l(),o(y,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};
|