1import{r as i,j as e}from"./react-vendor-CAvUCgBg.js";import{B as v,C as n,v as c,w as o,y as d,x as _,b as f,s as C,a as m}from"./index-BD5OT4An.js";import{S as L}from"./skeleton-C1MZj_BZ.js";import{ab as E,l as g,f as S,b2 as P}from"./icons-B1xxNXCI.js";import"./query-C7ekqVw8.js";import"./class-utils-B2rm_Apj.js";import"./supabase-L6Z3U_Fd.js";import"./radix-5feLYWdW.js";const h=a=>`${a.category_slug}${a.subcategory_slug?"/"+a.subcategory_slug:""}`;function q(){var k;i.useEffect(()=>{document.title="Posting Health · Admin"},[]);const[a,R]=i.useState([]),[p,N]=i.useState(!0),[A,y]=i.useState(!1),u=async()=>{N(!0);const{data:s,error:t}=await C.from("post_health_checks").select("*").order("checked_at",{ascending:!1}).limit(1e3);t&&m.error("Could not load posting health history"),R(s??[]),N(!1)};i.useEffect(()=>{u()},[]);const D=async s=>{y(!0);const{data:t,error:x}=await C.functions.invoke("post-health-monitor",{body:{deep:s}});if(y(!1),x){m.error("Health check could not run");return}const r=t;((r==null?void 0:r.broken)??0)===0?m.success(`All clear â ${(r==null?void 0:r.checked)??0} posting paths healthy`):m.warning(`${r==null?void 0:r.broken} posting path(s) still failing after auto-repair`),u()},l=i.useMemo(()=>{const s=new Map;for(const t of a)s.has(h(t))||s.set(h(t),t);return Array.from(s.values()).sort((t,x)=>Number(t.ok)-Number(x.ok)||h(t).localeCompare(h(x)))},[a]),b=l.filter(s=>!s.ok),j=a.filter(s=>s.auto_fixed&&Date.now()-new Date(s.checked_at).getTime()<7*864e5),w=(k=a[0])!=null&&k.checked_at?new Date(a[0].checked_at):null,H=l.length?Math.round(l.reduce((s,t)=>s+(t.duration_ms||0),0)/l.length):0;return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl font-bold",children:"Posting Health"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Fully automatic. Every 5 minutes the system runs a real (rolled-back) test post in each category â hourly it also tests every subcategory â repairs blockers itself with up to two escalating repair passes, re-tests, and notifies you after it recovers or if it can't."})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsxs(v,{variant:"outline",onClick:u,disabled:p,children:[e.jsx(E,{className:`mr-2 h-4 w-4 ${p?"animate-spin":""}`})," Refresh"]}),e.jsx(v,{variant:"ghost",size:"sm",onClick:()=>D(!0),disabled:A,children:"Deep check (optional)"})]})]}),e.jsx(n,{className:"border-green-600/40 bg-green-600/5",children:e.jsxs(c,{className:"flex items-center gap-3 py-4",children:[e.jsx(g,{className:"h-5 w-5 text-green-600"}),e.jsxs("div",{className:"text-sm",children:[e.jsx("span",{className:"font-semibold",children:"Auto self-repair is ON."})," ",e.jsx("span",{className:"text-muted-foreground",children:"No button needed â detection, repair, retry and alerting all run on a schedule 24/7."})]})]})}),e.jsxs("div",{className:"grid gap-4 sm:grid-cols-2 lg:grid-cols-4",children:[e.jsxs(n,{children:[e.jsx(o,{className:"pb-2",children:e.jsx(d,{children:"Status"})}),e.jsx(c,{children:b.length===0?e.jsxs("div",{className:"flex items-center gap-2 text-2xl font-bold text-green-600",children:[e.jsx(g,{className:"h-6 w-6"})," Healthy"]}):e.jsxs("div",{className:"flex items-center gap-2 text-2xl font-bold text-destructive",children:[e.jsx(S,{className:"h-6 w-6"})," ",b.length," blocked"]})})]}),e.jsxs(n,{children:[e.jsx(o,{className:"pb-2",children:e.jsx(d,{children:"Paths monitored"})}),e.jsx(c,{className:"text-2xl font-bold",children:l.length})]}),e.jsxs(n,{children:[e.jsx(o,{className:"pb-2",children:e.jsx(d,{children:"Self-repairs (7d)"})}),e.jsx(c,{className:"text-2xl font-bold",children:j.length})]}),e.jsxs(n,{children:[e.jsx(o,{className:"pb-2",children:e.jsx(d,{children:"Avg post time"})}),e.jsxs(c,{className:"text-2xl font-bold",children:[H," ms"]})]})]}),w&&e.jsxs("p",{className:"text-xs text-muted-foreground",children:["Last check: ",w.toLocaleString()]}),e.jsxs(n,{children:[e.jsxs(o,{children:[e.jsx(_,{children:"Current posting paths"}),e.jsx(d,{children:"Latest result per category. Failures are retried after auto-repair before being listed here."})]}),e.jsx(c,{children:p?e.jsx("div",{className:"space-y-2",children:Array.from({length:6}).map((s,t)=>e.jsx(L,{className:"h-10 w-full"},t))}):l.length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:"No checks recorded yet â hit âRun check nowâ."}):e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{className:"text-left text-muted-foreground",children:e.jsxs("tr",{children:[e.jsx("th",{className:"py-2 pr-4",children:"Path"}),e.jsx("th",{className:"py-2 pr-4",children:"Status"}),e.jsx("th",{className:"py-2 pr-4",children:"Time"}),e.jsx("th",{className:"py-2 pr-4",children:"Checked"}),e.jsx("th",{className:"py-2",children:"Detail"})]})}),e.jsx("tbody",{children:l.map(s=>e.jsxs("tr",{className:"border-t border-border/60",children:[e.jsx("td",{className:"py-2 pr-4 font-medium",children:h(s)}),e.jsxs("td",{className:"py-2 pr-4",children:[s.ok?e.jsxs(f,{variant:"secondary",className:"gap-1",children:[e.jsx(g,{className:"h-3 w-3"})," Can post"]}):e.jsxs(f,{variant:"destructive",className:"gap-1",children:[e.jsx(S,{className:"h-3 w-3"})," Blocked"]}),s.auto_fixed&&e.jsxs(f,{variant:"outline",className:"ml-2 gap-1",children:[e.jsx(P,{className:"h-3 w-3"})," self-repaired"]})]}),e.jsxs("td",{className:"py-2 pr-4",children:[s.duration_ms," ms"]}),e.jsx("td",{className:"py-2 pr-4 whitespace-nowrap",children:new Date(s.checked_at).toLocaleStr
1ing()}),e.jsx("td",{className:"py-2 text-muted-foreground",children:s.error_message??s.fix_note??"â"})]},s.id))})]})})})]}),e.jsxs(n,{children:[e.jsxs(o,{children:[e.jsx(_,{children:"Recent self-repairs"}),e.jsx(d,{children:"What the system fixed without you."})]}),e.jsx(c,{children:j.length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:"Nothing needed repair in the last 7 days."}):e.jsx("ul",{className:"space-y-2 text-sm",children:j.slice(0,20).map(s=>e.jsxs("li",{className:"flex flex-wrap gap-2",children:[e.jsx("span",{className:"text-muted-foreground",children:new Date(s.checked_at).toLocaleString()}),e.jsx("span",{className:"font-medium",children:h(s)}),e.jsxs("span",{className:"text-muted-foreground",children:["â ",s.fix_note]})]},s.id))})})]})]})}export{q as default};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.