diff --git a/apps/fabro-web/app/routes/run-files/states.test.tsx b/apps/fabro-web/app/routes/run-files/states.test.tsx index dd4c0a6d5..5a222e522 100644 --- a/apps/fabro-web/app/routes/run-files/states.test.tsx +++ b/apps/fabro-web/app/routes/run-files/states.test.tsx @@ -1,6 +1,7 @@ import { describe, expect, test } from "bun:test"; import TestRenderer from "react-test-renderer"; +import { RunStatus } from "@qltysh/fabro-api-client"; import { deriveEmptyKind, emptyStateCopy, @@ -59,7 +60,7 @@ describe("deriveEmptyKind", () => { // Terminal-success + teardown states → R4(b) or R4(c2) depending on // whether files were ever changed - test.each(["succeeded", "removing"])( + test.each(["succeeded", "removing", "archived"])( "%s with changes but no data is R4(c2) 'diff_lost'", (status) => { expect( @@ -72,7 +73,7 @@ describe("deriveEmptyKind", () => { }, ); - test.each(["succeeded", "removing"])( + test.each(["succeeded", "removing", "archived"])( "%s with no changes is R4(b)", (status) => { expect( @@ -105,24 +106,13 @@ describe("deriveEmptyKind", () => { ).toBe("unknown"); }); - test("every documented RunStatus gets a non-unknown empty kind when applicable", () => { - // Regression guard: if a new RunStatus appears in - // `apps/fabro-web/app/data/runs.ts` without a matching branch here, - // the decision table silently returns "unknown" ("not available right - // now") — misleading copy for a cancelled or paused run. - const knownRunStatuses = [ - "submitted", - "queued", - "starting", - "running", - "blocked", - "paused", - "removing", - "succeeded", - "failed", - "dead", - ]; - for (const status of knownRunStatuses) { + test("every documented RunStatus gets a non-unknown empty kind", () => { + // Regression guard sourced from the generated API client enum so any + // new RunStatus added to the OpenAPI spec fails this test until the + // decision table grows a branch. Without this guard, unhandled + // statuses silently render as "unknown" ("not available right now") — + // misleading copy for e.g. a paused or archived run. + for (const status of Object.values(RunStatus)) { const result = deriveEmptyKind({ runStatus: status, totalChanged: 0, diff --git a/apps/fabro-web/app/routes/run-files/states.tsx b/apps/fabro-web/app/routes/run-files/states.tsx index 39faa950b..a44f2ac7b 100644 --- a/apps/fabro-web/app/routes/run-files/states.tsx +++ b/apps/fabro-web/app/routes/run-files/states.tsx @@ -49,7 +49,7 @@ export function emptyStateCopy(kind: EmptyKind): string { /// /// The full RunStatus enum (per fabro-types/src/status.rs) is: /// submitted, queued, starting, running, blocked, paused, removing, -/// succeeded, failed, dead +/// succeeded, failed, dead, archived /// partial_success is a stage status, not a run status. export function deriveEmptyKind(args: { runStatus: string | undefined; @@ -81,10 +81,10 @@ export function deriveEmptyKind(args: { return degraded ? "unknown" : "failed_before_checkpoint"; } - // Terminal-success + teardown states: the run ran to completion or is - // shutting down. Distinguish "succeeded with no changes" (R4b) from - // "succeeded but diff lost" (R4c2) via total_changed. - if (s === "succeeded" || s === "removing") { + // Terminal-success, teardown, and archive states: the run ran to + // completion (possibly long ago). Distinguish "had no changes" (R4b) + // from "diff captured then lost" (R4c2) via total_changed. + if (s === "succeeded" || s === "removing" || s === "archived") { if (degraded) { // We have a patch; the component renders PatchDiff instead of an // empty state. Shouldn't reach here in practice. diff --git a/lib/crates/fabro-spa/assets/assets/entry-fqcfxfyb.js b/lib/crates/fabro-spa/assets/assets/entry-pmqz8d3n.js similarity index 98% rename from lib/crates/fabro-spa/assets/assets/entry-fqcfxfyb.js rename to lib/crates/fabro-spa/assets/assets/entry-pmqz8d3n.js index 6acfee3df..eabbad3af 100644 --- a/lib/crates/fabro-spa/assets/assets/entry-fqcfxfyb.js +++ b/lib/crates/fabro-spa/assets/assets/entry-pmqz8d3n.js @@ -2366,7 +2366,7 @@ Please report this to https://github.com/markedjs/marked.`,Z){let q="
An error review -> apply [label="Accept"] review -> propose [label="Revise", style=dashed] apply -> exit -}`}function N90(Z){let Y=Z.querySelector(".graph > title");if(!Y)return;let J=Y.nextElementSibling;while(J&&J.tagName==="text"){let q=J.nextElementSibling;J.remove(),J=q}Y.remove()}function im({loaderData:Z}){let{id:Y}=q7(),{stages:J,graphSvg:q}=Z,z=w7.useRef(null),B=w7.useRef(null),W=w7.useRef(null),[U,G]=w7.useState(null),[w,N]=w7.useState(LH),[O,A]=w7.useState("LR"),[_,P]=w7.useState({x:0,y:0}),L=w7.useRef(null),R=a3[w],{theme:C}=Z6(),T=gq(C);w7.useEffect(()=>{let E=!1;async function h(){try{let i;if(q){let k=await fetch(`/api/v1/runs/${Y}/graph?direction=${O}`,{credentials:"include"});if(E)return;if(!k.ok){G("Failed to load graph");return}let r=await k.text(),e=new DOMParser().parseFromString(r,"image/svg+xml").documentElement;if(!(e instanceof SVGSVGElement)){G("Invalid SVG from server");return}i=e}else{let{instance:k}=await import("./chunk-a51kkeyv.js"),r=await k();if(E)return;i=r.renderSVGElement(H90(O,T))}if(N90(i),W.current=i,B.current)B.current.replaceChildren(i)}catch(i){G(i instanceof Error?i.message:"Failed to render diagram")}}return P({x:0,y:0}),h(),()=>{E=!0}},[O,T,q,Y]);let v=w7.useCallback((E)=>{if(E.target.closest("button"))return;E.currentTarget.setPointerCapture(E.pointerId),L.current={startX:E.clientX,startY:E.clientY,startPanX:_.x,startPanY:_.y}},[_]),D=w7.useCallback((E)=>{let h=L.current;if(!h)return;P({x:h.startPanX+E.clientX-h.startX,y:h.startPanY+E.clientY-h.startY})},[]),S=w7.useCallback(()=>{L.current=null},[]),j=w7.useCallback(()=>{let E=W.current,h=z.current;if(!E||!h)return;let i=E.viewBox.baseVal.width||E.getBoundingClientRect().width,k=E.viewBox.baseVal.height||E.getBoundingClientRect().height,r=48,X0=h.clientWidth-r,B0=h.clientHeight-r,e=Math.min(X0/i,B0/k)*100,m=0;for(let q0=a3.length-1;q0>=0;q0--)if(a3[q0]<=e){m=q0;break}N(m),P({x:0,y:0})},[]);if(U)return i3.jsxDEV("p",{className:"text-sm text-coral",children:U},void 0,!1,void 0,this);return i3.jsxDEV("div",{className:"flex gap-6",children:[i3.jsxDEV(EZ,{stages:J,runId:Y,activeLink:"graph"},void 0,!1,void 0,this),i3.jsxDEV("div",{className:"min-w-0 flex-1",children:i3.jsxDEV("div",{className:"graph-svg relative rounded-md border border-line bg-panel-alt",children:[i3.jsxDEV(RH,{direction:O,setDirection:A,fitToWindow:j,zoomIndex:w,setZoomIndex:N},void 0,!1,void 0,this),i3.jsxDEV("div",{ref:z,className:"overflow-hidden p-6",style:{cursor:L.current?"grabbing":"grab"},onPointerDown:v,onPointerMove:D,onPointerUp:S,onPointerCancel:S,children:i3.jsxDEV("div",{ref:B,className:"flex items-center justify-center",style:{transform:`translate(${_.x}px, ${_.y}px) scale(${R/100})`,transformOrigin:"center center"},children:i3.jsxDEV("p",{className:"text-sm text-fg-muted",children:"Loading diagram..."},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var VR={};a5(VR,{loader:()=>T90,handle:()=>v90,extractRequestId:()=>Kp,default:()=>Wp,ErrorBoundary:()=>D90});var u5=g(Y0(),1);var j2=g(j0(),1);function O90({name:Z}){return j2.jsxDEV("div",{className:"flex items-center justify-between rounded-md border border-line bg-panel/60 px-4 py-3 text-sm text-fg-muted",children:[j2.jsxDEV("span",{className:"font-mono text-fg-2",children:Z},void 0,!1,void 0,this),j2.jsxDEV("span",{className:"rounded bg-rose-950/40 px-2 py-0.5 text-xs text-rose-200",children:"sensitive — contents omitted"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function A90({name:Z}){return j2.jsxDEV("div",{className:"flex items-center justify-between rounded-md border border-line bg-panel/60 px-4 py-3 text-sm text-fg-muted",children:[j2.jsxDEV("span",{className:"font-mono text-fg-2",children:Z},void 0,!1,void 0,this),j2.jsxDEV("span",{className:"rounded bg-panel-alt/80 px-2 py-0.5 text-xs text-fg-3",children:"binary — not shown inline"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function _90({name:Z,reason:Y}){return j2.jsxDEV("div",{className:"flex items-center justify-between rounded-md border border-line bg-panel/60 px-4 py-3 text-sm text-fg-muted",children:[j2.jsxDEV("span",{className:"font-mono text-fg-2",children:Z},void 0,!1,void 0,this),j2.jsxDEV("span",{className:"rounded bg-panel-alt/80 px-2 py-0.5 text-xs text-fg-3",children:Y==="budget_exhausted"?"omitted — too many files changed":"too large to render inline"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function tm({name:Z,kind:Y}){return j2.jsxDEV("div",{className:"flex items-center justify-between rounded-md border border-line bg-panel/60 px-4 py-3 text-sm text-fg-muted",children:[j2.jsxDEV("span",{className:"font-mono text-fg-2",children:Z},void 0,!1,void 0,this),j2.jsxDEV("span",{className:"rounded bg-panel-alt/80 px-2 py-0.5 text-xs text-fg-3",children:Y},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function nm(Z){let Y=Z.new_file.name||Z.old_file.name;if(Z.sensitive)return j2.jsxDEV(O90,{name:Y},void 0,!1,void 0,this);if(Z.binary)return j2.jsxDEV(A90,{name:Y},void 0,!1,void 0,this);if(Z.change_kind==="symlink")return j2.jsxDEV(tm,{name:Y,kind:"symlink"},void 0,!1,void 0,this);if(Z.change_kind==="submodule")return j2.jsxDEV(tm,{name:Y,kind:"submodule"},void 0,!1,void 0,this);if(Z.truncated)return j2.jsxDEV(_90,{name:Y,reason:Z.truncation_reason},void 0,!1,void 0,this);return null}function em({reason:Z}){return j2.jsxDEV("div",{className:"rounded-md border border-amber-500/30 bg-amber-950/20 px-4 py-3 text-sm text-amber-100",children:F90(Z)},void 0,!1,void 0,this)}function F90(Z){switch(Z){case"sandbox_gone":return"Showing final patch only. This run's sandbox has been cleaned up, so individual file contents are no longer available.";case"provider_unsupported":return"Live diff isn't supported for this sandbox provider. Showing the patch captured at the last checkpoint.";case"sandbox_unreachable":default:return"Couldn't reach this run's sandbox. Showing the patch captured at the last checkpoint — refresh to try again."}}var i7=g(j0(),1);function AR({kind:Z}){return i7.jsxDEV("div",{role:"status",className:"rounded-md border border-dashed border-line bg-panel/40 px-6 py-10 text-center text-sm text-fg-muted",children:P90(Z)},void 0,!1,void 0,this)}function P90(Z){switch(Z){case"starting":return"Run is still starting. Files will appear once it begins.";case"no_changes":return"This run didn't change any files.";case"failed_before_checkpoint":return"This run failed before capturing any changes.";case"diff_lost":return"The diff for this run is no longer available. If you expect files here, please report it.";case"unknown":default:return"The diff for this run is not available right now."}}function _R(Z){let{runStatus:Y,totalChanged:J,degraded:q}=Z;if(!Y)return"unknown";let z=Y.toLowerCase();if(z==="submitted"||z==="queued"||z==="starting")return"starting";if(z==="running"||z==="blocked"||z==="paused")return"no_changes";if(z==="failed"||z==="dead")return q?"unknown":"failed_before_checkpoint";if(z==="succeeded"||z==="removing"){if(q)return"unknown";return J>0?"diff_lost":"no_changes"}return"unknown"}function Zp(){return i7.jsxDEV("div",{className:"flex flex-col gap-3","aria-label":"Loading files",children:[i7.jsxDEV("div",{className:"h-8 rounded-md bg-panel/60 motion-safe:animate-pulse"},void 0,!1,void 0,this),i7.jsxDEV("div",{className:"h-32 rounded-md bg-panel/60 motion-safe:animate-pulse"},void 0,!1,void 0,this),i7.jsxDEV("div",{className:"h-32 rounded-md bg-panel/60 motion-safe:animate-pulse"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function VW({message:Z,onRetry:Y}){return i7.jsxDEV("div",{className:"flex items-center justify-between gap-3 rounded-md border border-rose-500/30 bg-rose-950/20 px-4 py-3 text-sm text-rose-100",children:[i7.jsxDEV("span",{children:Z},void 0,!1,void 0,this),i7.jsxDEV("button",{type:"button",onClick:Y,className:"min-h-[32px] rounded-md border border-rose-500/40 bg-rose-950/40 px-3 py-1 text-xs font-medium text-rose-50 transition-colors hover:bg-rose-950/60",children:"Retry"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function TQ({children:Z}){return i7.jsxDEV("div",{role:"status","aria-live":"polite",className:"pointer-events-none fixed bottom-6 right-6 z-50 rounded-md border border-line bg-panel/95 px-3 py-2 text-xs text-fg-2 shadow-lg",children:Z},void 0,!1,void 0,this)}function FR(Z){let{status:Y,requestId:J,onRetry:q}=Z;if(Y===401||Y===403)return i7.jsxDEV("div",{role:"status",className:"rounded-md border border-dashed border-line bg-panel/40 px-6 py-10 text-center text-sm text-fg-muted",children:"You don't have access to this run's files."},void 0,!1,void 0,this);if(Y===429||Y===503)return i7.jsxDEV(VW,{message:"The diff service is temporarily unavailable.",onRetry:q},void 0,!1,void 0,this);if(Y>=500){let z=J?` Request ID: ${J}.`:"";return i7.jsxDEV("div",{role:"status",className:"rounded-md border border-dashed border-line bg-panel/40 px-6 py-10 text-center text-sm text-fg-muted",children:["Something went wrong.",z," Please contact support if this persists."]},void 0,!0,void 0,this)}return i7.jsxDEV(VW,{message:`Couldn't load files (${Y}).`,onRetry:q},void 0,!1,void 0,this)}function Yp(){let Z=iU();if(V3(Z))return FR({status:Z.status,requestId:V90(Z.data),onRetry:()=>window.location.reload()});return i7.jsxDEV("div",{role:"status",className:"rounded-md border border-dashed border-line bg-panel/40 px-6 py-10 text-center text-sm text-fg-muted",children:"Something went wrong loading this run's files."},void 0,!1,void 0,this)}function V90(Z){if(!Z||typeof Z!=="object")return null;let Y=Z;if(typeof Y.request_id==="string")return Y.request_id;let J=Y.errors;if(Array.isArray(J)&&J.length>0){let q=J[0];if(q&&typeof q==="object"){let z=q;if(typeof z.request_id==="string")return z.request_id;if(typeof z.detail==="string"){let B=z.detail.match(/request[_ ]id[=:]?\s*([a-zA-Z0-9-_]+)/i);if(B)return B[1]}}}return null}var Qp=g(Y0(),1);function L90(Z){if(!Z)return!1;let Y=Z.tagName.toLowerCase();if(Y==="input"||Y==="textarea"||Y==="select")return!0;return Z.isContentEditable===!0}function Jp(Z,Y){Qp.useEffect(()=>{if(!Z.current)return;let J=(q)=>{if(q.key!=="j"&&q.key!=="k")return;if(q.metaKey||q.ctrlKey||q.altKey)return;if(L90(document.activeElement))return;let z=Z.current;if(!z)return;let B=Array.from(z.querySelectorAll('[data-run-file-row="true"]'));if(B.length===0)return;let W=document.activeElement,U=B.findIndex((N)=>N.contains(W)),G;if(U<0)G=0;else G=q.key==="j"?U+1:U-1;if(G<0||G>=B.length)return;q.preventDefault();let w=B[G];w.focus({preventScroll:!1}),w.scrollIntoView({block:"nearest",behavior:"smooth"})};return document.addEventListener("keydown",J),()=>document.removeEventListener("keydown",J)},[Z,Y])}var t3=g(j0(),1);function Xp({onRefresh:Z,refreshing:Y,refreshDisabled:J,freshness:q,refreshButtonRef:z,diffStyle:B,onDiffStyleChange:W,diffStyleForced:U}){return t3.jsxDEV("div",{className:"flex items-center justify-between gap-3 rounded-md border border-line bg-panel/40 px-3 py-2 text-xs text-fg-muted",children:[t3.jsxDEV("div",{className:"flex items-center gap-3",children:t3.jsxDEV("span",{"aria-live":"polite",className:"min-w-0 truncate",children:q??" "},void 0,!1,void 0,this)},void 0,!1,void 0,this),t3.jsxDEV("div",{className:"flex items-center gap-2",children:[t3.jsxDEV(R90,{value:B,onChange:W,forced:U},void 0,!1,void 0,this),t3.jsxDEV("button",{ref:z,type:"button",onClick:Z,disabled:Y||J,"aria-label":Y?"Refreshing files":"Refresh files",className:"min-h-[44px] min-w-[44px] rounded-md border border-line bg-panel px-3 py-1 text-xs font-medium text-fg-2 transition-colors hover:bg-overlay disabled:opacity-60",children:Y?"Refreshing…":"Refresh"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}function R90({value:Z,onChange:Y,forced:J}){return t3.jsxDEV("div",{className:"flex items-center gap-1",role:"group","aria-label":"Diff layout",children:[t3.jsxDEV("button",{type:"button",onClick:()=>Y("split"),disabled:J,"aria-pressed":Z==="split",className:`min-h-[44px] rounded-md border border-line px-3 py-1 text-xs font-medium transition-colors disabled:opacity-60 ${Z==="split"?"bg-overlay text-fg-1":"bg-panel text-fg-2 hover:bg-overlay"}`,children:"Split"},void 0,!1,void 0,this),t3.jsxDEV("button",{type:"button",onClick:()=>Y("unified"),disabled:J,"aria-pressed":Z==="unified",className:`min-h-[44px] rounded-md border border-line px-3 py-1 text-xs font-medium transition-colors disabled:opacity-60 ${Z==="unified"?"bg-overlay text-fg-1":"bg-panel text-fg-2 hover:bg-overlay"}`,children:"Unified"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var I5=g(j0(),1),v90={wide:!0};async function T90({request:Z,params:Y}){let J=await fetch(`/api/v1/runs/${Y.id}/files`,{credentials:"include",...Z?.signal?{signal:Z.signal}:{}});if(J.status===404||J.status===501)return{data:null,error:null};if(J.ok)return{data:await J.json(),error:null};let q="";try{q=await J.text()}catch{}let z=null;if(q)try{z=JSON.parse(q)}catch{}return{data:null,error:{status:J.status,message:J.statusText||`HTTP ${J.status}`,requestId:Kp(z)}}}function Kp(Z){if(!Z||typeof Z!=="object")return null;let Y=Z;if(typeof Y.request_id==="string")return Y.request_id;let J=Y.errors;if(Array.isArray(J)&&J.length>0){let q=J[0];if(q&&typeof q==="object"){let z=q;if(typeof z.request_id==="string")return z.request_id;if(typeof z.detail==="string"){let B=z.detail.match(/request[_ ]id[=:]?\s*([a-zA-Z0-9-_]+)/i);if(B)return B[1]}}}return null}var C90=new Set(["checkpoint.completed","run.completed","run.failed"]),b90=768,Bp="fabro.run-files.diff-style",D90=Yp;function E90(){let[Z,Y]=u5.useState(!1);return u5.useEffect(()=>{if(typeof window>"u")return;let J=window.matchMedia(`(max-width: ${b90-1}px)`),q=()=>Y(J.matches);return q(),J.addEventListener("change",q),()=>J.removeEventListener("change",q)},[]),Z}function y90(Z){let Y=R3();u5.useEffect(()=>{if(!Z)return;let J=new EventSource(`/api/v1/runs/${Z}/attach?since_seq=1`),q;return J.onmessage=(z)=>{try{let B=JSON.parse(z.data);if(C90.has(B.event))clearTimeout(q),q=setTimeout(()=>Y.revalidate(),500)}catch{}},()=>{clearTimeout(q),J.close()}},[Z])}function I90(Z,Y){let J=!!Z&&(!!Z.to_sha_committed_at||Y!==null),[,q]=u5.useState(0);if(u5.useEffect(()=>{if(!J)return;let U=setInterval(()=>q((G)=>G+1),1e4);return()=>clearInterval(U)},[J]),!Z)return null;let z=Date.now(),B=Z.to_sha_committed_at?`Captured ${qp(Z.to_sha_committed_at,z)}`:null,W=Y?`Fetched ${qp(new Date(Y).toISOString(),z)}`:null;if(Z.degraded&&B&&W)return`${B} · ${W}`;return B??W??null}function qp(Z,Y){if(!Z)return"";let J=Date.parse(Z);if(Number.isNaN(J))return"";let q=Math.max(0,Math.floor((Y-J)/1000));if(q<5)return"just now";if(q<60)return`${q}s ago`;let z=Math.floor(q/60);if(z<60)return`${z}m ago`;let B=Math.floor(z/60);if(B<24)return`${B}h ago`;return`${Math.floor(B/24)}d ago`}function j90(){if(typeof window>"u")return"split";try{let Z=window.localStorage.getItem(Bp);if(Z==="split"||Z==="unified")return Z}catch{}return"split"}function S90(Z){if(typeof window>"u")return;try{window.localStorage.setItem(Bp,Z)}catch{}}function PR(Z){return`run-file:${Z}`}function zp(Z){if(!Z)return null;let Y=Z.startsWith("#")?Z.slice(1):Z,J="file=";if(!Y.startsWith(J))return null;try{return decodeURIComponent(Y.slice(J.length))}catch{return null}}function k90(Z){for(let Y of Z){let J=Y.data;if(!J)continue;if(typeof J?.run?.lifecycleStatus==="string")return J.run.lifecycleStatus;if(typeof J?.lifecycleStatus==="string")return J.lifecycleStatus}return}function Wp({loaderData:Z}){let Y=Z6(),J=q7(),q=oU(),z=R3(),B=PY(),W=Z,U=E90(),G=k90(B),w=u5.useRef(null),N=u5.useRef(null),[O,A]=u5.useState(null),[_,P]=u5.useState(null);u5.useEffect(()=>{if(!W?.data)return;let R0=w.current;if(R0&&R0.data.length>0&&W.data.data.length===0){A("No changes in this run.");let k0=setTimeout(()=>A(null),3500);return w.current=W.data,N.current=Date.now(),()=>clearTimeout(k0)}w.current=W.data,N.current=Date.now();return},[W?.data]);let L=W?.data??w.current;y90(J.id);let R=q.state==="loading"&&!Z,C=z.state==="loading",T=W?.error&&w.current?`Couldn't refresh (${W.error.status}).`:null,v=W?.error&&!w.current?W.error:null,D=I90(L?.meta??null,N.current),[S,j]=u5.useState(j90),E=U?"unified":S,h=U,i=u5.useCallback((R0)=>{if(h)return;j(R0),S90(R0)},[h]),k=Y.theme==="dark"?"pierre-dark":"pierre-light",r=u5.useRef(null),X0=u5.useRef(null),B0=u5.useRef(!1);u5.useEffect(()=>{if(B0.current&&!C)r.current?.focus({preventScroll:!0});B0.current=C},[C]);let e=L?.data.length??0;Jp(X0,e);let[m,q0]=u5.useState(()=>{if(typeof window>"u")return null;return zp(window.location.hash)});u5.useEffect(()=>{if(typeof window>"u")return;let R0=()=>q0(zp(window.location.hash));return window.addEventListener("hashchange",R0),()=>window.removeEventListener("hashchange",R0)},[]),u5.useEffect(()=>{if(!m||!L)return;if(L.meta.degraded&&L.meta.patch){P("File-level navigation isn't available in the patch-only view.");let M0=setTimeout(()=>P(null),5000);return()=>clearTimeout(M0)}if(!L.data.some((M0)=>M0.new_file.name===m||M0.old_file.name===m)){P(`File ${m} is not in this run.`);let M0=setTimeout(()=>P(null),5000);return()=>clearTimeout(M0)}let k0=document.getElementById(PR(m));if(k0)k0.scrollIntoView({block:"start",behavior:"smooth"}),k0.focus({preventScroll:!0})},[m,L]);let Q0=u5.useCallback((R0)=>R0.map((k0,M0)=>{let p0=k0.new_file.name||k0.old_file.name,r0=nm(k0);if(r0)return I5.jsxDEV("div",{id:PR(p0),tabIndex:-1,"data-run-file-row":"true",role:"region","aria-label":`${k0.change_kind??"changed"}: ${p0}`,className:"focus:outline-2 focus:outline-focus focus:outline-offset-2 rounded-md",children:r0},`${p0}-${M0}`,!1,void 0,this);let O1=!!m&&(k0.new_file.name===m||k0.old_file.name===m);return I5.jsxDEV("div",{id:PR(p0),tabIndex:-1,"data-run-file-row":"true",role:"region","aria-label":`${k0.change_kind??"modified"}: ${k0.new_file.name}`,className:"focus:outline-2 focus:outline-focus focus:outline-offset-2 rounded-md",children:I5.jsxDEV(kL,{oldFile:k0.old_file,newFile:k0.new_file,options:{diffStyle:E,theme:k,expandUnchanged:O1?!0:void 0}},void 0,!1,void 0,this)},`${k0.new_file.name}-${M0}`,!1,void 0,this)}),[E,k,m]);if(R)return I5.jsxDEV(Zp,{},void 0,!1,void 0,this);if(v)return FR({status:v.status,requestId:v.requestId,onRetry:()=>z.revalidate()});if(!L)return I5.jsxDEV(AR,{kind:_R({runStatus:G,totalChanged:0,degraded:!1})},void 0,!1,void 0,this);let{data:t,meta:W0}=L,x=w.current?.meta?.to_sha??null,U0=!!W0.to_sha&&x!==null&&x===W0.to_sha,H0=I5.jsxDEV(Xp,{onRefresh:()=>z.revalidate(),refreshing:C,refreshDisabled:U0,freshness:D,refreshButtonRef:r,diffStyle:E,onDiffStyleChange:i,diffStyleForced:h},void 0,!1,void 0,this);if(W0.degraded&&W0.patch)return I5.jsxDEV("div",{ref:X0,className:"flex flex-col gap-4",children:[H0,T?I5.jsxDEV(VW,{message:T,onRetry:()=>z.revalidate()},void 0,!1,void 0,this):null,I5.jsxDEV(em,{reason:W0.degraded_reason},void 0,!1,void 0,this),I5.jsxDEV(xL,{patch:W0.patch,options:{diffStyle:E,theme:k}},void 0,!1,void 0,this),O&&I5.jsxDEV(TQ,{children:O},void 0,!1,void 0,this),_&&I5.jsxDEV(TQ,{children:_},void 0,!1,void 0,this)]},void 0,!0,void 0,this);if(t.length===0)return I5.jsxDEV("div",{ref:X0,className:"flex flex-col gap-4",children:[H0,I5.jsxDEV(AR,{kind:_R({runStatus:G,totalChanged:W0.total_changed,degraded:W0.degraded??!1})},void 0,!1,void 0,this),O&&I5.jsxDEV(TQ,{children:O},void 0,!1,void 0,this),_&&I5.jsxDEV(TQ,{children:_},void 0,!1,void 0,this)]},void 0,!0,void 0,this);let w0=t.length>20?I5.jsxDEV(WL,{children:Q0(t)},void 0,!1,void 0,this):I5.jsxDEV(I5.Fragment,{children:Q0(t)},void 0,!1,void 0,this);return I5.jsxDEV("div",{ref:X0,className:"flex flex-col gap-4",children:[H0,T?I5.jsxDEV(VW,{message:T,onRetry:()=>z.revalidate()},void 0,!1,void 0,this):null,w0,O&&I5.jsxDEV(TQ,{children:O},void 0,!1,void 0,this),_&&I5.jsxDEV(TQ,{children:_},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var LR={};a5(LR,{loader:()=>x90,default:()=>$p});var n0=g(j0(),1);function jZ(Z){return`${(Z/1000).toFixed(1)}k`}function jH(Z){return Z==null?"-":`$${(Z/1e6).toFixed(2)}`}async function x90({request:Z,params:Y}){let J=await y4(`/runs/${Y.id}/billing`,{request:Z}),q=J.stages.map((w)=>({stage:w.stage.name,model:w.model.id,inputTokens:w.billing.input_tokens,outputTokens:w.billing.output_tokens+(w.billing.reasoning_tokens??0),runtime:L7(w.runtime_secs),totalUsdMicros:w.billing.total_usd_micros})),z=L7(J.totals.runtime_secs),B=J.totals.input_tokens,W=J.totals.output_tokens+(J.totals.reasoning_tokens??0),U=J.totals.total_usd_micros,G=J.by_model.map((w)=>({model:w.model.id,stages:w.stages,inputTokens:w.billing.input_tokens,outputTokens:w.billing.output_tokens+(w.billing.reasoning_tokens??0),totalUsdMicros:w.billing.total_usd_micros})).sort((w,N)=>(N.totalUsdMicros??-1)-(w.totalUsdMicros??-1));return{stages:q,totalRuntime:z,totalUsdMicros:U,totalInput:B,totalOutput:W,modelBreakdown:G}}function $p({loaderData:Z}){let{stages:Y,totalRuntime:J,totalUsdMicros:q,totalInput:z,totalOutput:B,modelBreakdown:W}=Z;if(!Y.length)return n0.jsxDEV("div",{className:"py-12",children:n0.jsxDEV(C8,{title:"No billing yet",description:"Token usage and cost will appear here once stages complete."},void 0,!1,void 0,this)},void 0,!1,void 0,this);return n0.jsxDEV("div",{className:"space-y-6",children:[n0.jsxDEV("div",{className:"overflow-hidden rounded-md border border-line",children:n0.jsxDEV("table",{className:"w-full text-sm",children:[n0.jsxDEV("thead",{children:n0.jsxDEV("tr",{className:"border-b border-line bg-panel/60 text-left text-xs font-medium text-fg-3",children:[n0.jsxDEV("th",{className:"px-4 py-2.5 font-medium",children:"Stage"},void 0,!1,void 0,this),n0.jsxDEV("th",{className:"px-4 py-2.5 font-medium",children:"Model"},void 0,!1,void 0,this),n0.jsxDEV("th",{className:"px-4 py-2.5 font-medium text-right",children:"Tokens"},void 0,!1,void 0,this),n0.jsxDEV("th",{className:"px-4 py-2.5 font-medium text-right",children:"Run time"},void 0,!1,void 0,this),n0.jsxDEV("th",{className:"px-4 py-2.5 font-medium text-right",children:"Billing"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),n0.jsxDEV("tbody",{children:Y.map((U)=>n0.jsxDEV("tr",{className:"border-b border-line last:border-b-0",children:[n0.jsxDEV("td",{className:"px-4 py-3 text-fg-2",children:U.stage},void 0,!1,void 0,this),n0.jsxDEV("td",{className:"px-4 py-3 font-mono text-xs text-fg-3",children:U.model},void 0,!1,void 0,this),n0.jsxDEV("td",{className:"px-4 py-3 text-right font-mono text-xs tabular-nums text-fg-3",children:[jZ(U.inputTokens)," ",n0.jsxDEV("span",{className:"text-fg-muted",children:"/"},void 0,!1,void 0,this)," ",jZ(U.outputTokens)]},void 0,!0,void 0,this),n0.jsxDEV("td",{className:"px-4 py-3 text-right font-mono text-xs text-fg-3",children:U.runtime},void 0,!1,void 0,this),n0.jsxDEV("td",{className:"px-4 py-3 text-right font-mono text-xs text-fg-3",children:jH(U.totalUsdMicros)},void 0,!1,void 0,this)]},U.stage,!0,void 0,this))},void 0,!1,void 0,this),n0.jsxDEV("tfoot",{children:n0.jsxDEV("tr",{className:"border-t border-line-strong bg-overlay",children:[n0.jsxDEV("td",{className:"px-4 py-3 font-medium text-fg",children:"Total"},void 0,!1,void 0,this),n0.jsxDEV("td",{},void 0,!1,void 0,this),n0.jsxDEV("td",{className:"px-4 py-3 text-right font-mono text-xs tabular-nums font-medium text-fg",children:[jZ(z)," ",n0.jsxDEV("span",{className:"text-fg-muted",children:"/"},void 0,!1,void 0,this)," ",jZ(B)]},void 0,!0,void 0,this),n0.jsxDEV("td",{className:"px-4 py-3 text-right font-mono text-xs font-medium text-fg",children:J},void 0,!1,void 0,this),n0.jsxDEV("td",{className:"px-4 py-3 text-right font-mono text-xs font-medium text-fg",children:jH(q)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),n0.jsxDEV("div",{children:[n0.jsxDEV("h3",{className:"mb-3 text-sm font-semibold text-fg",children:"By model"},void 0,!1,void 0,this),n0.jsxDEV("div",{className:"overflow-hidden rounded-md border border-line",children:n0.jsxDEV("table",{className:"w-full text-sm",children:[n0.jsxDEV("thead",{children:n0.jsxDEV("tr",{className:"border-b border-line bg-panel/60 text-left text-xs font-medium text-fg-3",children:[n0.jsxDEV("th",{className:"px-4 py-2.5 font-medium",children:"Model"},void 0,!1,void 0,this),n0.jsxDEV("th",{className:"px-4 py-2.5 font-medium text-right",children:"Stages"},void 0,!1,void 0,this),n0.jsxDEV("th",{className:"px-4 py-2.5 font-medium text-right",children:"Tokens"},void 0,!1,void 0,this),n0.jsxDEV("th",{className:"px-4 py-2.5 font-medium text-right",children:"Billing"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),n0.jsxDEV("tbody",{children:W.map((U)=>n0.jsxDEV("tr",{className:"border-b border-line last:border-b-0",children:[n0.jsxDEV("td",{className:"px-4 py-3 font-mono text-xs text-fg-2",children:U.model},void 0,!1,void 0,this),n0.jsxDEV("td",{className:"px-4 py-3 text-right font-mono text-xs tabular-nums text-fg-3",children:U.stages},void 0,!1,void 0,this),n0.jsxDEV("td",{className:"px-4 py-3 text-right font-mono text-xs tabular-nums text-fg-3",children:[jZ(U.inputTokens)," ",n0.jsxDEV("span",{className:"text-fg-muted",children:"/"},void 0,!1,void 0,this)," ",jZ(U.outputTokens)]},void 0,!0,void 0,this),n0.jsxDEV("td",{className:"px-4 py-3 text-right font-mono text-xs text-fg-3",children:jH(U.totalUsdMicros)},void 0,!1,void 0,this)]},U.model,!0,void 0,this))},void 0,!1,void 0,this),n0.jsxDEV("tfoot",{children:n0.jsxDEV("tr",{className:"border-t border-line-strong bg-overlay",children:[n0.jsxDEV("td",{className:"px-4 py-3 font-medium text-fg",children:"Total"},void 0,!1,void 0,this),n0.jsxDEV("td",{className:"px-4 py-3 text-right font-mono text-xs tabular-nums font-medium text-fg",children:Y.length},void 0,!1,void 0,this),n0.jsxDEV("td",{className:"px-4 py-3 text-right font-mono text-xs tabular-nums font-medium text-fg",children:[jZ(z)," ",n0.jsxDEV("span",{className:"text-fg-muted",children:"/"},void 0,!1,void 0,this)," ",jZ(B)]},void 0,!0,void 0,this),n0.jsxDEV("td",{className:"px-4 py-3 text-right font-mono text-xs font-medium text-fg",children:jH(q)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}var RR={};a5(RR,{meta:()=>f90,loader:()=>h90,handle:()=>g90,default:()=>Up});var P2=g(j0(),1);function f90({}){return[{title:"Insights — Fabro"}]}var g90={wide:!0};async function h90({request:Z}){let[{data:Y},{data:J}]=await Promise.all([y4("/insights/queries",{request:Z}),y4("/insights/history",{request:Z})]),q=Y.map((B)=>({id:B.id,name:B.name,sql:B.sql})),z=J.map((B)=>({id:B.id,sql:B.sql,timestamp:B.timestamp,elapsed:B.elapsed,rowsReturned:B.row_count}));return{savedQueries:q,historyEntries:z}}function Up({loaderData:Z}){let{savedQueries:Y,historyEntries:J}=Z,q=E4();return P2.jsxDEV("div",{className:"flex gap-6",children:[P2.jsxDEV("div",{className:"w-56 shrink-0",children:P2.jsxDEV("div",{className:"sticky top-6 space-y-4",children:[P2.jsxDEV(d1,{to:"/insights/new",className:"inline-flex w-full items-center justify-center gap-1.5 rounded-md border border-line bg-panel/80 px-3 py-2 text-sm font-medium text-fg-3 transition-colors hover:border-line-strong hover:bg-panel hover:text-fg",children:[P2.jsxDEV(sP,{className:"size-3.5"},void 0,!1,void 0,this),"New Query"]},void 0,!0,void 0,this),P2.jsxDEV("div",{children:[P2.jsxDEV("h3",{className:"mb-2 text-[11px] font-semibold uppercase tracking-wider text-fg-muted",children:"Saved Queries"},void 0,!1,void 0,this),P2.jsxDEV("div",{className:"space-y-0.5",children:Y.map((z)=>P2.jsxDEV("button",{type:"button",onClick:()=>{q("/insights",{state:{sql:z.sql,name:z.name}})},className:"flex w-full flex-col gap-0.5 rounded-md px-2.5 py-2 text-left transition-colors hover:bg-overlay",children:[P2.jsxDEV("span",{className:"text-sm font-medium text-fg-2",children:z.name},void 0,!1,void 0,this),P2.jsxDEV("span",{className:"truncate font-mono text-[10px] text-fg-muted",children:z.sql.split(` +}`}function N90(Z){let Y=Z.querySelector(".graph > title");if(!Y)return;let J=Y.nextElementSibling;while(J&&J.tagName==="text"){let q=J.nextElementSibling;J.remove(),J=q}Y.remove()}function im({loaderData:Z}){let{id:Y}=q7(),{stages:J,graphSvg:q}=Z,z=w7.useRef(null),B=w7.useRef(null),W=w7.useRef(null),[U,G]=w7.useState(null),[w,N]=w7.useState(LH),[O,A]=w7.useState("LR"),[_,P]=w7.useState({x:0,y:0}),L=w7.useRef(null),R=a3[w],{theme:C}=Z6(),T=gq(C);w7.useEffect(()=>{let E=!1;async function h(){try{let i;if(q){let k=await fetch(`/api/v1/runs/${Y}/graph?direction=${O}`,{credentials:"include"});if(E)return;if(!k.ok){G("Failed to load graph");return}let r=await k.text(),e=new DOMParser().parseFromString(r,"image/svg+xml").documentElement;if(!(e instanceof SVGSVGElement)){G("Invalid SVG from server");return}i=e}else{let{instance:k}=await import("./chunk-a51kkeyv.js"),r=await k();if(E)return;i=r.renderSVGElement(H90(O,T))}if(N90(i),W.current=i,B.current)B.current.replaceChildren(i)}catch(i){G(i instanceof Error?i.message:"Failed to render diagram")}}return P({x:0,y:0}),h(),()=>{E=!0}},[O,T,q,Y]);let v=w7.useCallback((E)=>{if(E.target.closest("button"))return;E.currentTarget.setPointerCapture(E.pointerId),L.current={startX:E.clientX,startY:E.clientY,startPanX:_.x,startPanY:_.y}},[_]),D=w7.useCallback((E)=>{let h=L.current;if(!h)return;P({x:h.startPanX+E.clientX-h.startX,y:h.startPanY+E.clientY-h.startY})},[]),S=w7.useCallback(()=>{L.current=null},[]),j=w7.useCallback(()=>{let E=W.current,h=z.current;if(!E||!h)return;let i=E.viewBox.baseVal.width||E.getBoundingClientRect().width,k=E.viewBox.baseVal.height||E.getBoundingClientRect().height,r=48,X0=h.clientWidth-r,B0=h.clientHeight-r,e=Math.min(X0/i,B0/k)*100,m=0;for(let q0=a3.length-1;q0>=0;q0--)if(a3[q0]<=e){m=q0;break}N(m),P({x:0,y:0})},[]);if(U)return i3.jsxDEV("p",{className:"text-sm text-coral",children:U},void 0,!1,void 0,this);return i3.jsxDEV("div",{className:"flex gap-6",children:[i3.jsxDEV(EZ,{stages:J,runId:Y,activeLink:"graph"},void 0,!1,void 0,this),i3.jsxDEV("div",{className:"min-w-0 flex-1",children:i3.jsxDEV("div",{className:"graph-svg relative rounded-md border border-line bg-panel-alt",children:[i3.jsxDEV(RH,{direction:O,setDirection:A,fitToWindow:j,zoomIndex:w,setZoomIndex:N},void 0,!1,void 0,this),i3.jsxDEV("div",{ref:z,className:"overflow-hidden p-6",style:{cursor:L.current?"grabbing":"grab"},onPointerDown:v,onPointerMove:D,onPointerUp:S,onPointerCancel:S,children:i3.jsxDEV("div",{ref:B,className:"flex items-center justify-center",style:{transform:`translate(${_.x}px, ${_.y}px) scale(${R/100})`,transformOrigin:"center center"},children:i3.jsxDEV("p",{className:"text-sm text-fg-muted",children:"Loading diagram..."},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var VR={};a5(VR,{loader:()=>T90,handle:()=>v90,extractRequestId:()=>Kp,default:()=>Wp,ErrorBoundary:()=>D90});var u5=g(Y0(),1);var j2=g(j0(),1);function O90({name:Z}){return j2.jsxDEV("div",{className:"flex items-center justify-between rounded-md border border-line bg-panel/60 px-4 py-3 text-sm text-fg-muted",children:[j2.jsxDEV("span",{className:"font-mono text-fg-2",children:Z},void 0,!1,void 0,this),j2.jsxDEV("span",{className:"rounded bg-rose-950/40 px-2 py-0.5 text-xs text-rose-200",children:"sensitive — contents omitted"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function A90({name:Z}){return j2.jsxDEV("div",{className:"flex items-center justify-between rounded-md border border-line bg-panel/60 px-4 py-3 text-sm text-fg-muted",children:[j2.jsxDEV("span",{className:"font-mono text-fg-2",children:Z},void 0,!1,void 0,this),j2.jsxDEV("span",{className:"rounded bg-panel-alt/80 px-2 py-0.5 text-xs text-fg-3",children:"binary — not shown inline"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function _90({name:Z,reason:Y}){return j2.jsxDEV("div",{className:"flex items-center justify-between rounded-md border border-line bg-panel/60 px-4 py-3 text-sm text-fg-muted",children:[j2.jsxDEV("span",{className:"font-mono text-fg-2",children:Z},void 0,!1,void 0,this),j2.jsxDEV("span",{className:"rounded bg-panel-alt/80 px-2 py-0.5 text-xs text-fg-3",children:Y==="budget_exhausted"?"omitted — too many files changed":"too large to render inline"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function tm({name:Z,kind:Y}){return j2.jsxDEV("div",{className:"flex items-center justify-between rounded-md border border-line bg-panel/60 px-4 py-3 text-sm text-fg-muted",children:[j2.jsxDEV("span",{className:"font-mono text-fg-2",children:Z},void 0,!1,void 0,this),j2.jsxDEV("span",{className:"rounded bg-panel-alt/80 px-2 py-0.5 text-xs text-fg-3",children:Y},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function nm(Z){let Y=Z.new_file.name||Z.old_file.name;if(Z.sensitive)return j2.jsxDEV(O90,{name:Y},void 0,!1,void 0,this);if(Z.binary)return j2.jsxDEV(A90,{name:Y},void 0,!1,void 0,this);if(Z.change_kind==="symlink")return j2.jsxDEV(tm,{name:Y,kind:"symlink"},void 0,!1,void 0,this);if(Z.change_kind==="submodule")return j2.jsxDEV(tm,{name:Y,kind:"submodule"},void 0,!1,void 0,this);if(Z.truncated)return j2.jsxDEV(_90,{name:Y,reason:Z.truncation_reason},void 0,!1,void 0,this);return null}function em({reason:Z}){return j2.jsxDEV("div",{className:"rounded-md border border-amber-500/30 bg-amber-950/20 px-4 py-3 text-sm text-amber-100",children:F90(Z)},void 0,!1,void 0,this)}function F90(Z){switch(Z){case"sandbox_gone":return"Showing final patch only. This run's sandbox has been cleaned up, so individual file contents are no longer available.";case"provider_unsupported":return"Live diff isn't supported for this sandbox provider. Showing the patch captured at the last checkpoint.";case"sandbox_unreachable":default:return"Couldn't reach this run's sandbox. Showing the patch captured at the last checkpoint — refresh to try again."}}var i7=g(j0(),1);function AR({kind:Z}){return i7.jsxDEV("div",{role:"status",className:"rounded-md border border-dashed border-line bg-panel/40 px-6 py-10 text-center text-sm text-fg-muted",children:P90(Z)},void 0,!1,void 0,this)}function P90(Z){switch(Z){case"starting":return"Run is still starting. Files will appear once it begins.";case"no_changes":return"This run didn't change any files.";case"failed_before_checkpoint":return"This run failed before capturing any changes.";case"diff_lost":return"The diff for this run is no longer available. If you expect files here, please report it.";case"unknown":default:return"The diff for this run is not available right now."}}function _R(Z){let{runStatus:Y,totalChanged:J,degraded:q}=Z;if(!Y)return"unknown";let z=Y.toLowerCase();if(z==="submitted"||z==="queued"||z==="starting")return"starting";if(z==="running"||z==="blocked"||z==="paused")return"no_changes";if(z==="failed"||z==="dead")return q?"unknown":"failed_before_checkpoint";if(z==="succeeded"||z==="removing"||z==="archived"){if(q)return"unknown";return J>0?"diff_lost":"no_changes"}return"unknown"}function Zp(){return i7.jsxDEV("div",{className:"flex flex-col gap-3","aria-label":"Loading files",children:[i7.jsxDEV("div",{className:"h-8 rounded-md bg-panel/60 motion-safe:animate-pulse"},void 0,!1,void 0,this),i7.jsxDEV("div",{className:"h-32 rounded-md bg-panel/60 motion-safe:animate-pulse"},void 0,!1,void 0,this),i7.jsxDEV("div",{className:"h-32 rounded-md bg-panel/60 motion-safe:animate-pulse"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function VW({message:Z,onRetry:Y}){return i7.jsxDEV("div",{className:"flex items-center justify-between gap-3 rounded-md border border-rose-500/30 bg-rose-950/20 px-4 py-3 text-sm text-rose-100",children:[i7.jsxDEV("span",{children:Z},void 0,!1,void 0,this),i7.jsxDEV("button",{type:"button",onClick:Y,className:"min-h-[32px] rounded-md border border-rose-500/40 bg-rose-950/40 px-3 py-1 text-xs font-medium text-rose-50 transition-colors hover:bg-rose-950/60",children:"Retry"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function TQ({children:Z}){return i7.jsxDEV("div",{role:"status","aria-live":"polite",className:"pointer-events-none fixed bottom-6 right-6 z-50 rounded-md border border-line bg-panel/95 px-3 py-2 text-xs text-fg-2 shadow-lg",children:Z},void 0,!1,void 0,this)}function FR(Z){let{status:Y,requestId:J,onRetry:q}=Z;if(Y===401||Y===403)return i7.jsxDEV("div",{role:"status",className:"rounded-md border border-dashed border-line bg-panel/40 px-6 py-10 text-center text-sm text-fg-muted",children:"You don't have access to this run's files."},void 0,!1,void 0,this);if(Y===429||Y===503)return i7.jsxDEV(VW,{message:"The diff service is temporarily unavailable.",onRetry:q},void 0,!1,void 0,this);if(Y>=500){let z=J?` Request ID: ${J}.`:"";return i7.jsxDEV("div",{role:"status",className:"rounded-md border border-dashed border-line bg-panel/40 px-6 py-10 text-center text-sm text-fg-muted",children:["Something went wrong.",z," Please contact support if this persists."]},void 0,!0,void 0,this)}return i7.jsxDEV(VW,{message:`Couldn't load files (${Y}).`,onRetry:q},void 0,!1,void 0,this)}function Yp(){let Z=iU();if(V3(Z))return FR({status:Z.status,requestId:V90(Z.data),onRetry:()=>window.location.reload()});return i7.jsxDEV("div",{role:"status",className:"rounded-md border border-dashed border-line bg-panel/40 px-6 py-10 text-center text-sm text-fg-muted",children:"Something went wrong loading this run's files."},void 0,!1,void 0,this)}function V90(Z){if(!Z||typeof Z!=="object")return null;let Y=Z;if(typeof Y.request_id==="string")return Y.request_id;let J=Y.errors;if(Array.isArray(J)&&J.length>0){let q=J[0];if(q&&typeof q==="object"){let z=q;if(typeof z.request_id==="string")return z.request_id;if(typeof z.detail==="string"){let B=z.detail.match(/request[_ ]id[=:]?\s*([a-zA-Z0-9-_]+)/i);if(B)return B[1]}}}return null}var Qp=g(Y0(),1);function L90(Z){if(!Z)return!1;let Y=Z.tagName.toLowerCase();if(Y==="input"||Y==="textarea"||Y==="select")return!0;return Z.isContentEditable===!0}function Jp(Z,Y){Qp.useEffect(()=>{if(!Z.current)return;let J=(q)=>{if(q.key!=="j"&&q.key!=="k")return;if(q.metaKey||q.ctrlKey||q.altKey)return;if(L90(document.activeElement))return;let z=Z.current;if(!z)return;let B=Array.from(z.querySelectorAll('[data-run-file-row="true"]'));if(B.length===0)return;let W=document.activeElement,U=B.findIndex((N)=>N.contains(W)),G;if(U<0)G=0;else G=q.key==="j"?U+1:U-1;if(G<0||G>=B.length)return;q.preventDefault();let w=B[G];w.focus({preventScroll:!1}),w.scrollIntoView({block:"nearest",behavior:"smooth"})};return document.addEventListener("keydown",J),()=>document.removeEventListener("keydown",J)},[Z,Y])}var t3=g(j0(),1);function Xp({onRefresh:Z,refreshing:Y,refreshDisabled:J,freshness:q,refreshButtonRef:z,diffStyle:B,onDiffStyleChange:W,diffStyleForced:U}){return t3.jsxDEV("div",{className:"flex items-center justify-between gap-3 rounded-md border border-line bg-panel/40 px-3 py-2 text-xs text-fg-muted",children:[t3.jsxDEV("div",{className:"flex items-center gap-3",children:t3.jsxDEV("span",{"aria-live":"polite",className:"min-w-0 truncate",children:q??" "},void 0,!1,void 0,this)},void 0,!1,void 0,this),t3.jsxDEV("div",{className:"flex items-center gap-2",children:[t3.jsxDEV(R90,{value:B,onChange:W,forced:U},void 0,!1,void 0,this),t3.jsxDEV("button",{ref:z,type:"button",onClick:Z,disabled:Y||J,"aria-label":Y?"Refreshing files":"Refresh files",className:"min-h-[44px] min-w-[44px] rounded-md border border-line bg-panel px-3 py-1 text-xs font-medium text-fg-2 transition-colors hover:bg-overlay disabled:opacity-60",children:Y?"Refreshing…":"Refresh"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}function R90({value:Z,onChange:Y,forced:J}){return t3.jsxDEV("div",{className:"flex items-center gap-1",role:"group","aria-label":"Diff layout",children:[t3.jsxDEV("button",{type:"button",onClick:()=>Y("split"),disabled:J,"aria-pressed":Z==="split",className:`min-h-[44px] rounded-md border border-line px-3 py-1 text-xs font-medium transition-colors disabled:opacity-60 ${Z==="split"?"bg-overlay text-fg-1":"bg-panel text-fg-2 hover:bg-overlay"}`,children:"Split"},void 0,!1,void 0,this),t3.jsxDEV("button",{type:"button",onClick:()=>Y("unified"),disabled:J,"aria-pressed":Z==="unified",className:`min-h-[44px] rounded-md border border-line px-3 py-1 text-xs font-medium transition-colors disabled:opacity-60 ${Z==="unified"?"bg-overlay text-fg-1":"bg-panel text-fg-2 hover:bg-overlay"}`,children:"Unified"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var I5=g(j0(),1),v90={wide:!0};async function T90({request:Z,params:Y}){let J=await fetch(`/api/v1/runs/${Y.id}/files`,{credentials:"include",...Z?.signal?{signal:Z.signal}:{}});if(J.status===404||J.status===501)return{data:null,error:null};if(J.ok)return{data:await J.json(),error:null};let q="";try{q=await J.text()}catch{}let z=null;if(q)try{z=JSON.parse(q)}catch{}return{data:null,error:{status:J.status,message:J.statusText||`HTTP ${J.status}`,requestId:Kp(z)}}}function Kp(Z){if(!Z||typeof Z!=="object")return null;let Y=Z;if(typeof Y.request_id==="string")return Y.request_id;let J=Y.errors;if(Array.isArray(J)&&J.length>0){let q=J[0];if(q&&typeof q==="object"){let z=q;if(typeof z.request_id==="string")return z.request_id;if(typeof z.detail==="string"){let B=z.detail.match(/request[_ ]id[=:]?\s*([a-zA-Z0-9-_]+)/i);if(B)return B[1]}}}return null}var C90=new Set(["checkpoint.completed","run.completed","run.failed"]),b90=768,Bp="fabro.run-files.diff-style",D90=Yp;function E90(){let[Z,Y]=u5.useState(!1);return u5.useEffect(()=>{if(typeof window>"u")return;let J=window.matchMedia(`(max-width: ${b90-1}px)`),q=()=>Y(J.matches);return q(),J.addEventListener("change",q),()=>J.removeEventListener("change",q)},[]),Z}function y90(Z){let Y=R3();u5.useEffect(()=>{if(!Z)return;let J=new EventSource(`/api/v1/runs/${Z}/attach?since_seq=1`),q;return J.onmessage=(z)=>{try{let B=JSON.parse(z.data);if(C90.has(B.event))clearTimeout(q),q=setTimeout(()=>Y.revalidate(),500)}catch{}},()=>{clearTimeout(q),J.close()}},[Z])}function I90(Z,Y){let J=!!Z&&(!!Z.to_sha_committed_at||Y!==null),[,q]=u5.useState(0);if(u5.useEffect(()=>{if(!J)return;let U=setInterval(()=>q((G)=>G+1),1e4);return()=>clearInterval(U)},[J]),!Z)return null;let z=Date.now(),B=Z.to_sha_committed_at?`Captured ${qp(Z.to_sha_committed_at,z)}`:null,W=Y?`Fetched ${qp(new Date(Y).toISOString(),z)}`:null;if(Z.degraded&&B&&W)return`${B} · ${W}`;return B??W??null}function qp(Z,Y){if(!Z)return"";let J=Date.parse(Z);if(Number.isNaN(J))return"";let q=Math.max(0,Math.floor((Y-J)/1000));if(q<5)return"just now";if(q<60)return`${q}s ago`;let z=Math.floor(q/60);if(z<60)return`${z}m ago`;let B=Math.floor(z/60);if(B<24)return`${B}h ago`;return`${Math.floor(B/24)}d ago`}function j90(){if(typeof window>"u")return"split";try{let Z=window.localStorage.getItem(Bp);if(Z==="split"||Z==="unified")return Z}catch{}return"split"}function S90(Z){if(typeof window>"u")return;try{window.localStorage.setItem(Bp,Z)}catch{}}function PR(Z){return`run-file:${Z}`}function zp(Z){if(!Z)return null;let Y=Z.startsWith("#")?Z.slice(1):Z,J="file=";if(!Y.startsWith(J))return null;try{return decodeURIComponent(Y.slice(J.length))}catch{return null}}function k90(Z){for(let Y of Z){let J=Y.data;if(!J)continue;if(typeof J?.run?.lifecycleStatus==="string")return J.run.lifecycleStatus;if(typeof J?.lifecycleStatus==="string")return J.lifecycleStatus}return}function Wp({loaderData:Z}){let Y=Z6(),J=q7(),q=oU(),z=R3(),B=PY(),W=Z,U=E90(),G=k90(B),w=u5.useRef(null),N=u5.useRef(null),[O,A]=u5.useState(null),[_,P]=u5.useState(null);u5.useEffect(()=>{if(!W?.data)return;let R0=w.current;if(R0&&R0.data.length>0&&W.data.data.length===0){A("No changes in this run.");let k0=setTimeout(()=>A(null),3500);return w.current=W.data,N.current=Date.now(),()=>clearTimeout(k0)}w.current=W.data,N.current=Date.now();return},[W?.data]);let L=W?.data??w.current;y90(J.id);let R=q.state==="loading"&&!Z,C=z.state==="loading",T=W?.error&&w.current?`Couldn't refresh (${W.error.status}).`:null,v=W?.error&&!w.current?W.error:null,D=I90(L?.meta??null,N.current),[S,j]=u5.useState(j90),E=U?"unified":S,h=U,i=u5.useCallback((R0)=>{if(h)return;j(R0),S90(R0)},[h]),k=Y.theme==="dark"?"pierre-dark":"pierre-light",r=u5.useRef(null),X0=u5.useRef(null),B0=u5.useRef(!1);u5.useEffect(()=>{if(B0.current&&!C)r.current?.focus({preventScroll:!0});B0.current=C},[C]);let e=L?.data.length??0;Jp(X0,e);let[m,q0]=u5.useState(()=>{if(typeof window>"u")return null;return zp(window.location.hash)});u5.useEffect(()=>{if(typeof window>"u")return;let R0=()=>q0(zp(window.location.hash));return window.addEventListener("hashchange",R0),()=>window.removeEventListener("hashchange",R0)},[]),u5.useEffect(()=>{if(!m||!L)return;if(L.meta.degraded&&L.meta.patch){P("File-level navigation isn't available in the patch-only view.");let M0=setTimeout(()=>P(null),5000);return()=>clearTimeout(M0)}if(!L.data.some((M0)=>M0.new_file.name===m||M0.old_file.name===m)){P(`File ${m} is not in this run.`);let M0=setTimeout(()=>P(null),5000);return()=>clearTimeout(M0)}let k0=document.getElementById(PR(m));if(k0)k0.scrollIntoView({block:"start",behavior:"smooth"}),k0.focus({preventScroll:!0})},[m,L]);let Q0=u5.useCallback((R0)=>R0.map((k0,M0)=>{let p0=k0.new_file.name||k0.old_file.name,r0=nm(k0);if(r0)return I5.jsxDEV("div",{id:PR(p0),tabIndex:-1,"data-run-file-row":"true",role:"region","aria-label":`${k0.change_kind??"changed"}: ${p0}`,className:"focus:outline-2 focus:outline-focus focus:outline-offset-2 rounded-md",children:r0},`${p0}-${M0}`,!1,void 0,this);let O1=!!m&&(k0.new_file.name===m||k0.old_file.name===m);return I5.jsxDEV("div",{id:PR(p0),tabIndex:-1,"data-run-file-row":"true",role:"region","aria-label":`${k0.change_kind??"modified"}: ${k0.new_file.name}`,className:"focus:outline-2 focus:outline-focus focus:outline-offset-2 rounded-md",children:I5.jsxDEV(kL,{oldFile:k0.old_file,newFile:k0.new_file,options:{diffStyle:E,theme:k,expandUnchanged:O1?!0:void 0}},void 0,!1,void 0,this)},`${k0.new_file.name}-${M0}`,!1,void 0,this)}),[E,k,m]);if(R)return I5.jsxDEV(Zp,{},void 0,!1,void 0,this);if(v)return FR({status:v.status,requestId:v.requestId,onRetry:()=>z.revalidate()});if(!L)return I5.jsxDEV(AR,{kind:_R({runStatus:G,totalChanged:0,degraded:!1})},void 0,!1,void 0,this);let{data:t,meta:W0}=L,x=w.current?.meta?.to_sha??null,U0=!!W0.to_sha&&x!==null&&x===W0.to_sha,H0=I5.jsxDEV(Xp,{onRefresh:()=>z.revalidate(),refreshing:C,refreshDisabled:U0,freshness:D,refreshButtonRef:r,diffStyle:E,onDiffStyleChange:i,diffStyleForced:h},void 0,!1,void 0,this);if(W0.degraded&&W0.patch)return I5.jsxDEV("div",{ref:X0,className:"flex flex-col gap-4",children:[H0,T?I5.jsxDEV(VW,{message:T,onRetry:()=>z.revalidate()},void 0,!1,void 0,this):null,I5.jsxDEV(em,{reason:W0.degraded_reason},void 0,!1,void 0,this),I5.jsxDEV(xL,{patch:W0.patch,options:{diffStyle:E,theme:k}},void 0,!1,void 0,this),O&&I5.jsxDEV(TQ,{children:O},void 0,!1,void 0,this),_&&I5.jsxDEV(TQ,{children:_},void 0,!1,void 0,this)]},void 0,!0,void 0,this);if(t.length===0)return I5.jsxDEV("div",{ref:X0,className:"flex flex-col gap-4",children:[H0,I5.jsxDEV(AR,{kind:_R({runStatus:G,totalChanged:W0.total_changed,degraded:W0.degraded??!1})},void 0,!1,void 0,this),O&&I5.jsxDEV(TQ,{children:O},void 0,!1,void 0,this),_&&I5.jsxDEV(TQ,{children:_},void 0,!1,void 0,this)]},void 0,!0,void 0,this);let w0=t.length>20?I5.jsxDEV(WL,{children:Q0(t)},void 0,!1,void 0,this):I5.jsxDEV(I5.Fragment,{children:Q0(t)},void 0,!1,void 0,this);return I5.jsxDEV("div",{ref:X0,className:"flex flex-col gap-4",children:[H0,T?I5.jsxDEV(VW,{message:T,onRetry:()=>z.revalidate()},void 0,!1,void 0,this):null,w0,O&&I5.jsxDEV(TQ,{children:O},void 0,!1,void 0,this),_&&I5.jsxDEV(TQ,{children:_},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var LR={};a5(LR,{loader:()=>x90,default:()=>$p});var n0=g(j0(),1);function jZ(Z){return`${(Z/1000).toFixed(1)}k`}function jH(Z){return Z==null?"-":`$${(Z/1e6).toFixed(2)}`}async function x90({request:Z,params:Y}){let J=await y4(`/runs/${Y.id}/billing`,{request:Z}),q=J.stages.map((w)=>({stage:w.stage.name,model:w.model.id,inputTokens:w.billing.input_tokens,outputTokens:w.billing.output_tokens+(w.billing.reasoning_tokens??0),runtime:L7(w.runtime_secs),totalUsdMicros:w.billing.total_usd_micros})),z=L7(J.totals.runtime_secs),B=J.totals.input_tokens,W=J.totals.output_tokens+(J.totals.reasoning_tokens??0),U=J.totals.total_usd_micros,G=J.by_model.map((w)=>({model:w.model.id,stages:w.stages,inputTokens:w.billing.input_tokens,outputTokens:w.billing.output_tokens+(w.billing.reasoning_tokens??0),totalUsdMicros:w.billing.total_usd_micros})).sort((w,N)=>(N.totalUsdMicros??-1)-(w.totalUsdMicros??-1));return{stages:q,totalRuntime:z,totalUsdMicros:U,totalInput:B,totalOutput:W,modelBreakdown:G}}function $p({loaderData:Z}){let{stages:Y,totalRuntime:J,totalUsdMicros:q,totalInput:z,totalOutput:B,modelBreakdown:W}=Z;if(!Y.length)return n0.jsxDEV("div",{className:"py-12",children:n0.jsxDEV(C8,{title:"No billing yet",description:"Token usage and cost will appear here once stages complete."},void 0,!1,void 0,this)},void 0,!1,void 0,this);return n0.jsxDEV("div",{className:"space-y-6",children:[n0.jsxDEV("div",{className:"overflow-hidden rounded-md border border-line",children:n0.jsxDEV("table",{className:"w-full text-sm",children:[n0.jsxDEV("thead",{children:n0.jsxDEV("tr",{className:"border-b border-line bg-panel/60 text-left text-xs font-medium text-fg-3",children:[n0.jsxDEV("th",{className:"px-4 py-2.5 font-medium",children:"Stage"},void 0,!1,void 0,this),n0.jsxDEV("th",{className:"px-4 py-2.5 font-medium",children:"Model"},void 0,!1,void 0,this),n0.jsxDEV("th",{className:"px-4 py-2.5 font-medium text-right",children:"Tokens"},void 0,!1,void 0,this),n0.jsxDEV("th",{className:"px-4 py-2.5 font-medium text-right",children:"Run time"},void 0,!1,void 0,this),n0.jsxDEV("th",{className:"px-4 py-2.5 font-medium text-right",children:"Billing"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),n0.jsxDEV("tbody",{children:Y.map((U)=>n0.jsxDEV("tr",{className:"border-b border-line last:border-b-0",children:[n0.jsxDEV("td",{className:"px-4 py-3 text-fg-2",children:U.stage},void 0,!1,void 0,this),n0.jsxDEV("td",{className:"px-4 py-3 font-mono text-xs text-fg-3",children:U.model},void 0,!1,void 0,this),n0.jsxDEV("td",{className:"px-4 py-3 text-right font-mono text-xs tabular-nums text-fg-3",children:[jZ(U.inputTokens)," ",n0.jsxDEV("span",{className:"text-fg-muted",children:"/"},void 0,!1,void 0,this)," ",jZ(U.outputTokens)]},void 0,!0,void 0,this),n0.jsxDEV("td",{className:"px-4 py-3 text-right font-mono text-xs text-fg-3",children:U.runtime},void 0,!1,void 0,this),n0.jsxDEV("td",{className:"px-4 py-3 text-right font-mono text-xs text-fg-3",children:jH(U.totalUsdMicros)},void 0,!1,void 0,this)]},U.stage,!0,void 0,this))},void 0,!1,void 0,this),n0.jsxDEV("tfoot",{children:n0.jsxDEV("tr",{className:"border-t border-line-strong bg-overlay",children:[n0.jsxDEV("td",{className:"px-4 py-3 font-medium text-fg",children:"Total"},void 0,!1,void 0,this),n0.jsxDEV("td",{},void 0,!1,void 0,this),n0.jsxDEV("td",{className:"px-4 py-3 text-right font-mono text-xs tabular-nums font-medium text-fg",children:[jZ(z)," ",n0.jsxDEV("span",{className:"text-fg-muted",children:"/"},void 0,!1,void 0,this)," ",jZ(B)]},void 0,!0,void 0,this),n0.jsxDEV("td",{className:"px-4 py-3 text-right font-mono text-xs font-medium text-fg",children:J},void 0,!1,void 0,this),n0.jsxDEV("td",{className:"px-4 py-3 text-right font-mono text-xs font-medium text-fg",children:jH(q)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),n0.jsxDEV("div",{children:[n0.jsxDEV("h3",{className:"mb-3 text-sm font-semibold text-fg",children:"By model"},void 0,!1,void 0,this),n0.jsxDEV("div",{className:"overflow-hidden rounded-md border border-line",children:n0.jsxDEV("table",{className:"w-full text-sm",children:[n0.jsxDEV("thead",{children:n0.jsxDEV("tr",{className:"border-b border-line bg-panel/60 text-left text-xs font-medium text-fg-3",children:[n0.jsxDEV("th",{className:"px-4 py-2.5 font-medium",children:"Model"},void 0,!1,void 0,this),n0.jsxDEV("th",{className:"px-4 py-2.5 font-medium text-right",children:"Stages"},void 0,!1,void 0,this),n0.jsxDEV("th",{className:"px-4 py-2.5 font-medium text-right",children:"Tokens"},void 0,!1,void 0,this),n0.jsxDEV("th",{className:"px-4 py-2.5 font-medium text-right",children:"Billing"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),n0.jsxDEV("tbody",{children:W.map((U)=>n0.jsxDEV("tr",{className:"border-b border-line last:border-b-0",children:[n0.jsxDEV("td",{className:"px-4 py-3 font-mono text-xs text-fg-2",children:U.model},void 0,!1,void 0,this),n0.jsxDEV("td",{className:"px-4 py-3 text-right font-mono text-xs tabular-nums text-fg-3",children:U.stages},void 0,!1,void 0,this),n0.jsxDEV("td",{className:"px-4 py-3 text-right font-mono text-xs tabular-nums text-fg-3",children:[jZ(U.inputTokens)," ",n0.jsxDEV("span",{className:"text-fg-muted",children:"/"},void 0,!1,void 0,this)," ",jZ(U.outputTokens)]},void 0,!0,void 0,this),n0.jsxDEV("td",{className:"px-4 py-3 text-right font-mono text-xs text-fg-3",children:jH(U.totalUsdMicros)},void 0,!1,void 0,this)]},U.model,!0,void 0,this))},void 0,!1,void 0,this),n0.jsxDEV("tfoot",{children:n0.jsxDEV("tr",{className:"border-t border-line-strong bg-overlay",children:[n0.jsxDEV("td",{className:"px-4 py-3 font-medium text-fg",children:"Total"},void 0,!1,void 0,this),n0.jsxDEV("td",{className:"px-4 py-3 text-right font-mono text-xs tabular-nums font-medium text-fg",children:Y.length},void 0,!1,void 0,this),n0.jsxDEV("td",{className:"px-4 py-3 text-right font-mono text-xs tabular-nums font-medium text-fg",children:[jZ(z)," ",n0.jsxDEV("span",{className:"text-fg-muted",children:"/"},void 0,!1,void 0,this)," ",jZ(B)]},void 0,!0,void 0,this),n0.jsxDEV("td",{className:"px-4 py-3 text-right font-mono text-xs font-medium text-fg",children:jH(q)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}var RR={};a5(RR,{meta:()=>f90,loader:()=>h90,handle:()=>g90,default:()=>Up});var P2=g(j0(),1);function f90({}){return[{title:"Insights — Fabro"}]}var g90={wide:!0};async function h90({request:Z}){let[{data:Y},{data:J}]=await Promise.all([y4("/insights/queries",{request:Z}),y4("/insights/history",{request:Z})]),q=Y.map((B)=>({id:B.id,name:B.name,sql:B.sql})),z=J.map((B)=>({id:B.id,sql:B.sql,timestamp:B.timestamp,elapsed:B.elapsed,rowsReturned:B.row_count}));return{savedQueries:q,historyEntries:z}}function Up({loaderData:Z}){let{savedQueries:Y,historyEntries:J}=Z,q=E4();return P2.jsxDEV("div",{className:"flex gap-6",children:[P2.jsxDEV("div",{className:"w-56 shrink-0",children:P2.jsxDEV("div",{className:"sticky top-6 space-y-4",children:[P2.jsxDEV(d1,{to:"/insights/new",className:"inline-flex w-full items-center justify-center gap-1.5 rounded-md border border-line bg-panel/80 px-3 py-2 text-sm font-medium text-fg-3 transition-colors hover:border-line-strong hover:bg-panel hover:text-fg",children:[P2.jsxDEV(sP,{className:"size-3.5"},void 0,!1,void 0,this),"New Query"]},void 0,!0,void 0,this),P2.jsxDEV("div",{children:[P2.jsxDEV("h3",{className:"mb-2 text-[11px] font-semibold uppercase tracking-wider text-fg-muted",children:"Saved Queries"},void 0,!1,void 0,this),P2.jsxDEV("div",{className:"space-y-0.5",children:Y.map((z)=>P2.jsxDEV("button",{type:"button",onClick:()=>{q("/insights",{state:{sql:z.sql,name:z.name}})},className:"flex w-full flex-col gap-0.5 rounded-md px-2.5 py-2 text-left transition-colors hover:bg-overlay",children:[P2.jsxDEV("span",{className:"text-sm font-medium text-fg-2",children:z.name},void 0,!1,void 0,this),P2.jsxDEV("span",{className:"truncate font-mono text-[10px] text-fg-muted",children:z.sql.split(` `)[0]},void 0,!1,void 0,this)]},z.id,!0,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),P2.jsxDEV("div",{children:[P2.jsxDEV("h3",{className:"mb-2 text-[11px] font-semibold uppercase tracking-wider text-fg-muted",children:"History"},void 0,!1,void 0,this),P2.jsxDEV("div",{className:"space-y-0.5",children:J.map((z)=>P2.jsxDEV("button",{type:"button",onClick:()=>{q("/insights",{state:{sql:z.sql}})},className:"flex w-full flex-col gap-0.5 rounded-md px-2.5 py-2 text-left transition-colors hover:bg-overlay",children:[P2.jsxDEV("span",{className:"truncate font-mono text-[10px] text-fg-3",children:z.sql},void 0,!1,void 0,this),P2.jsxDEV("span",{className:"font-mono text-[10px] text-fg-muted",children:[LM(z.timestamp)," · ",z.rowsReturned," rows"]},void 0,!0,void 0,this)]},z.id,!0,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),P2.jsxDEV("div",{className:"min-w-0 flex-1",children:P2.jsxDEV(I6,{},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var vR={};a5(vR,{default:()=>Mp});var d5=g(Y0(),1);var b0=g(j0(),1);function u90(Z){let Y=Z.toLowerCase();if(Y.includes("workflow_name")&&Y.includes("avg"))return{columns:["workflow_name","avg_duration","run_count"],rows:[{workflow_name:"Expand Product",avg_duration:342.5,run_count:48},{workflow_name:"Implement Feature",avg_duration:287.3,run_count:156},{workflow_name:"Security Scan",avg_duration:198.1,run_count:312},{workflow_name:"Fix Build",avg_duration:145.7,run_count:482},{workflow_name:"Sync Drift",avg_duration:89.2,run_count:94},{workflow_name:"Dependency Audit",avg_duration:67.4,run_count:201}],elapsed:0.531,rowsRead:5182366,bytesRead:357780000,rowsReturned:6};if(Y.includes("failure_rate")||Y.includes("failed"))return{columns:["day","failures","total","failure_rate"],rows:Array.from({length:14},(J,q)=>{let z=new Date;z.setDate(z.getDate()-q);let B=80+Math.floor(Math.random()*60),W=Math.floor(Math.random()*15);return{day:z.toISOString().slice(0,10),failures:W,total:B,failure_rate:Math.round(1000*W/B)/10}}),elapsed:0.287,rowsRead:2841092,bytesRead:198400000,rowsReturned:14};return{columns:["repo","runs","total_additions","total_deletions"],rows:[{repo:"fabro-engine",runs:482,total_additions:28450,total_deletions:12300},{repo:"fabro-web",runs:356,total_additions:19200,total_deletions:8900},{repo:"fabro-cli",runs:198,total_additions:8700,total_deletions:4200},{repo:"fabro-docs",runs:145,total_additions:12100,total_deletions:3400},{repo:"fabro-sdk",runs:89,total_additions:5600,total_deletions:2100},{repo:"fabro-infra",runs:67,total_additions:3200,total_deletions:1800},{repo:"fabro-actions",runs:42,total_additions:2100,total_deletions:980},{repo:"fabro-proto",runs:28,total_additions:1400,total_deletions:650}],elapsed:0.148,rowsRead:1204588,bytesRead:89200000,rowsReturned:8}}function m90(Z){if(Z>=1e9)return`${(Z/1e9).toFixed(2)} GB`;if(Z>=1e6)return`${(Z/1e6).toFixed(2)} MB`;if(Z>=1000)return`${(Z/1000).toFixed(2)} KB`;return`${Z} B`}function SH(Z){return Z.toLocaleString()}var Gp=["rgba(90, 200, 168, 0.85)","rgba(103, 178, 215, 0.85)","rgba(181, 221, 239, 0.65)","rgba(240, 164, 91, 0.75)"];function p90({result:Z}){let Y=d5.useRef(null),[J,q]=d5.useState(0);d5.useEffect(()=>{let T=Y.current;if(!T)return;let v=new ResizeObserver((D)=>{let S=D[0];if(S)q(S.contentRect.width)});return v.observe(T),()=>v.disconnect()},[]);let z=Z.columns[0],B=Z.columns.slice(1).filter((T)=>{return typeof Z.rows[0]?.[T]==="number"});if(B.length===0||Z.rows.length===0)return b0.jsxDEV("div",{className:"flex h-64 items-center justify-center text-sm text-fg-muted",children:"No numeric columns to chart"},void 0,!1,void 0,this);let W=B[0],U=Math.max(...Z.rows.map((T)=>{let v=T[W];return typeof v==="number"?v:0})),G=260,w=52,N={top:12,bottom:48,right:16},O=G-N.top-N.bottom,A=J-w-N.right,_=Z.rows.length,P=Math.max(8,Math.min(16,A/_*0.3)),L=Math.max(12,(A-P*(_+1))/_),R=5,C=Array.from({length:R},(T,v)=>Math.round(U*(R-1-v)/(R-1)));return b0.jsxDEV("div",{ref:Y,children:[J>0&&b0.jsxDEV("svg",{width:J,height:G,className:"select-none",children:[C.map((T,v)=>{let D=N.top+O*v/(R-1);return b0.jsxDEV("g",{children:[b0.jsxDEV("line",{x1:w,y1:D,x2:J-N.right,y2:D,stroke:"var(--chart-gridline)",strokeDasharray:"4,4"},void 0,!1,void 0,this),b0.jsxDEV("text",{x:w-8,y:D+4,textAnchor:"end",fill:"var(--chart-axis-label)",fontSize:"11",fontFamily:"JetBrains Mono, monospace",children:T>=1000?`${(T/1000).toFixed(T>=1e4?0:1)}k`:T},void 0,!1,void 0,this)]},T,!0,void 0,this)}),Z.rows.map((T,v)=>{let D=T[W],S=typeof D==="number"?D:0,j=U>0?S/U*O:0,E=w+P+v*(L+P),h=N.top+O-j,i=String(T[z]),k=v%Gp.length,r=Math.floor(L/6);return b0.jsxDEV("g",{children:[b0.jsxDEV("rect",{x:E,y:h,width:L,height:j,rx:3,fill:Gp[k],className:"transition-opacity hover:opacity-100",opacity:0.85},void 0,!1,void 0,this),b0.jsxDEV("title",{children:[i,": ",SH(S)]},void 0,!0,void 0,this),b0.jsxDEV("text",{x:E+L/2,y:G-N.bottom+16,textAnchor:"middle",fill:"var(--chart-axis-label)",fontSize:"10",fontFamily:"JetBrains Mono, monospace",children:i.length>r?i.slice(0,Math.max(3,r-1))+"…":i},void 0,!1,void 0,this)]},i+v,!0,void 0,this)})]},void 0,!0,void 0,this),b0.jsxDEV("div",{className:"mt-1 flex items-center gap-4 px-2",children:b0.jsxDEV("span",{className:"font-mono text-[10px] uppercase tracking-wider text-fg-muted",children:W.replace(/_/g," ")},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function c90({result:Z}){return b0.jsxDEV("div",{className:"overflow-x-auto",children:b0.jsxDEV("table",{className:"w-full text-left",children:[b0.jsxDEV("thead",{children:b0.jsxDEV("tr",{className:"border-b border-line",children:Z.columns.map((Y)=>b0.jsxDEV("th",{className:"whitespace-nowrap px-3 py-2.5 font-mono text-[11px] font-semibold uppercase tracking-wider text-fg-muted",children:Y},Y,!1,void 0,this))},void 0,!1,void 0,this)},void 0,!1,void 0,this),b0.jsxDEV("tbody",{children:Z.rows.map((Y)=>b0.jsxDEV("tr",{className:"border-b border-line transition-colors hover:bg-overlay",children:Z.columns.map((J)=>{let q=Y[J],z=typeof q==="number";return b0.jsxDEV("td",{className:`whitespace-nowrap px-3 py-2 font-mono text-xs ${z?"tabular-nums text-fg-2":"text-fg-3"}`,children:z?SH(q):String(q)},J,!1,void 0,this)})},String(Y[Z.columns[0]]),!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}function d90({value:Z,onChange:Y,onRun:J}){let q=d5.useRef(null),z=d5.useRef(null),B=Z.split(` `).length,W=d5.useCallback(()=>{if(q.current&&z.current)z.current.scrollTop=q.current.scrollTop},[]),U=(G)=>{if(G.key==="Enter"&&(G.metaKey||G.ctrlKey)){G.preventDefault(),J();return}if(G.key==="Tab"){G.preventDefault();let w=G.currentTarget,N=w.selectionStart,O=w.selectionEnd,A=Z.slice(0,N)+" "+Z.slice(O);Y(A),requestAnimationFrame(()=>{w.selectionStart=N+2,w.selectionEnd=N+2})}};return b0.jsxDEV("div",{className:"relative flex overflow-hidden rounded-md border border-line bg-page/80 font-mono text-sm",children:[b0.jsxDEV("div",{ref:z,className:"pointer-events-none flex shrink-0 flex-col overflow-hidden border-r border-line bg-page/60 px-3 py-3 text-right leading-[1.625rem] text-fg-muted select-none","aria-hidden":"true",children:Array.from({length:B},(G,w)=>b0.jsxDEV("span",{className:"text-[11px]",children:w+1},w+1,!1,void 0,this))},void 0,!1,void 0,this),b0.jsxDEV("textarea",{ref:q,value:Z,onChange:(G)=>Y(G.target.value),onScroll:W,onKeyDown:U,spellCheck:!1,autoCapitalize:"off",autoCorrect:"off",className:"min-h-[7lh] w-full resize-y bg-transparent px-4 py-3 leading-[1.625rem] text-fg-2 placeholder-fg-muted outline-none",placeholder:"SELECT * FROM runs LIMIT 10"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var l90=`SELECT workflow_name, AVG(duration_seconds) as avg_duration, COUNT(*) as run_count diff --git a/lib/crates/fabro-spa/assets/index.html b/lib/crates/fabro-spa/assets/index.html index 26ece3edd..a2dc2e28e 100644 --- a/lib/crates/fabro-spa/assets/index.html +++ b/lib/crates/fabro-spa/assets/index.html @@ -61,7 +61,7 @@ - +