PageSourceSearch

https://prirodni.teacher.bg/assets/AuditCorrections-B61jnaSr.js

js teacher.bg collected 2026-10-02 08:11:10 UTC 58,023 bytes, 2 lines download raw bytes

1import{j as e}from"./vendor-query-CTD2tXPx.js";import{r as u}from"./vendor-charts-Debegyj1.js";import{L as ze,a as xt}from"./vendor-router-BVlBSwqy.js";import{D as Ee,a as qe,b as Le,c as Oe,e as Be,d as Te}from"./dialog-DDAk0TRZ.js";import{s as G,c as D,B as z,b as pt}from"./index-DOCSA3X_.js";import{B as v}from"./badge-sO-2LWky.js";import{P as ft}from"./progress-DMqP3qiz.js";import{l as gt}from"./allResourcesLoader-B0DBPRQ9.js";import{S as Ie,z as st,aA as jt,a0 as vt,a4 as _t,b8 as bt,V as rt,g as yt,X as Nt,E as at,b9 as wt,r as We,A as St,R as Ke,aN as Ue,ba as kt,bb as Xe,bc as He,l as Ct,bd as $t,a2 as At}from"./vendor-icons-B3WZHYud.js";import{I as Qe}from"./input-DsvowBq8.js";import{C as xe,a as pe,b as Re,c as Fe}from"./card-CvTQ_2Cx.js";import{S as ne,a as ie,b as le,c as oe,d as L}from"./select-D-4cxA7Q.js";import{T as Pe}from"./textarea-DufuBWnv.js";import{l as nt,i as Rt}from"./resourceLoader-BV6bDOvK.js";import{p as Ft}from"./normalizeCorrection-BdmUye0-.js";import"./vendor-radix-khLywtIJ.js";import"./vendor-supabase-CQ9eTX7v.js";let ce=null;async function zt(){if(ce)return ce;const t=await fetch("/sim-snapshots.json",{cache:"force-cache"});return t.ok?(ce=await t.json(),ce):(ce={byResource:{},sims:{}},ce)}async function It(t){const{data:l,error:r}=await G.from("content_audit_runs").insert({ai_model:t.ai_model,scope:`enrichment:${t.scopeLabel}`,total_resources:0,status:"running"}).select("id").single();if(r||!l)throw new Error((r==null?void 0:r.message)??"Cannot start run");return l.id}async function Pt(t,l,r){await G.from("content_audit_runs").update({processed_resources:l,total_findings:r,status:"completed",finished_at:new Date().toISOString()}).eq("id",t)}async function Et(t){if(t.length===0)return{};const{data:l,error:r}=await G.from("content_audit_findings").select("resource_id, claim, correction").in("resource_id",t).neq("category","enrichment").limit(500);if(r||!l)return{};const d={};for(const i of l)d[i.resource_id]||(d[i.resource_id]=[]),d[i.resource_id].push({claim:i.claim,correction:i.correction});return d}function qt(t,l){const r=l.byResource[t.id],d=r?l.sims[r]:null;return{id:t.id,title:t.title,subject:t.subject,grade:t.grade,concept:t.concept,goals:t.goals,materials:t.materials,steps:t.steps,quiz:t.quiz,sim_snapshot:d?{componentName:r,...d}:null}}async function Ye(t){var _,c,R,w;const l=Math.min(t.batchSize??5,5),r=await zt(),d=t.resources.length;let i=0,a=0,o=null;for(let p=0;p<d;p+=l){if((_=t.shouldAbort)!=null&&_.call(t))return{totalProcessed:i,totalFindings:a,aborted:!0,criticalStop:o};const f=t.resources.slice(p,p+l),b=f.map(I=>I.id),g=await Et(b),N=f.map(I=>qt(I,r));(c=t.onProgress)==null||c.call(t,{processed:i,total:d,findingsCreated:a,currentBatch:b,lastFailures:[]});const{data:h,error:C}=await G.functions.invoke("audit-content-enrich",{body:{audit_run_id:t.audit_run_id,resources:N,existing_findings:g,model:t.model??"google/gemini-2.5-flash"}});if(C){(R=t.onProgress)==null||R.call(t,{processed:i,total:d,findingsCreated:a,currentBatch:b,lastFailures:[{id:b.join(","),phase:"invoke_error",reason:String(C.message??C)}]});break}const y=h;i+=(y==null?void 0:y.processed)??0,a+=(y==null?void 0:y.findings_created)??0;const F=((y==null?void 0:y.failures)??[]).find(I=>I.status===429||I.status===402);if(F&&(o=F.status===429?"rate_limited":"credits_exhausted"),(w=t.onProgress)==null||w.call(t,{processed:i,total:d,findingsCreated:a,currentBatch:b,lastFailures:(y==null?void 0:y.failures)??[]}),o)break}return{totalProcessed:i,totalFindings:a,aborted:!1,criticalStop:o}}const be="openai/gpt-5.2",Ze=80;function Lt({open:t,onOpenChange:l,resourceIdFilter:r,onCompleted:d}){const[i,a]=u.useState(!1),[o,_]=u.useState([]),[c,R]=u.useState([]),[w,p]=u.useState(!1),[f,b]=u.useState(null),[g,N]=u.useState(null),[h,C]=u.useState(new Set),[y,F]=u.useState(0),I=u.useRef(null),K=u.useRef(!1);u.useEffect(()=>{t&&(N(null),b(null),C(new Set),F(0),I.current=null,K.current=!1,(async()=>{a(!0);try{let S=G.from("content_audit_findings").select("resource_id").neq("category","enrichment").limit(2e3);r!=null&&r.trim()&&(S=S.ilike("resource_id",`%${r.trim()}%`));const{data:E,error:T}=await S;if(T)throw T;const O=Array.from(new Set((E??[]).map(q=>q.resource_id))).sort();if(_(O),c.length===0){const q=await gt();R(q)}}catch(S){D.error("Грешка при зареждане: "+((S==null?void 0:S.message)??String(S)))}finally{a(!1)}})())},[t,r]);const P=u.useMemo(()=>
1{if(c.length===0)return[];const S=new Map(c.map(E=>[E.id,E]));return o.map(E=>S.get(E)).filter(E=>!!E)},[o,c]),Z=o.length-P.length,Q=Math.max(1,Math.round(P.length*Ze/60)),W=S=>{const E=new Set;for(const T of S)for(const O of String(T.id).split(",")){const q=O.trim();q&&E.add(q)}return Array.from(E)},se=async(S,E={})=>{if(S.length===0){D.error("Няма ресурси за обработка");return}p(!0),K.current=!1;const T=new Set;b({processed:0,total:S.length,findingsCreated:0,currentBatch:[],lastFailures:[]});try{let O=E.reuseRunId??null;O||(O=await It({scopeLabel:E.label??`${S.length}-resources`,ai_model:be}),I.current=O);const q=await Ye({resources:S,audit_run_id:O,model:be,batchSize:5,onProgress:U=>{for(const H of W(U.lastFailures))T.add(H);b(U)},shouldAbort:()=>K.current});let de=0;const ee=Array.from(T).filter(U=>S.some(H=>H.id===U));if(!q.criticalStop&&ee.length>0){D.message(`Авто-повтаряне на ${ee.length} non-2xx ресурса…`);const U=S.filter(te=>ee.includes(te.id));T.clear(),b({processed:0,total:U.length,findingsCreated:0,currentBatch:[],lastFailures:[]});const H=await Ye({resources:U,audit_run_id:O,model:be,batchSize:5,onProgress:te=>{for(const ge of W(te.lastFailures))T.add(ge);b(te)},shouldAbort:()=>K.current});q.totalProcessed+=H.totalProcessed,q.totalFindings+=H.totalFindings,H.criticalStop&&(q.critical
1Stop=H.criticalStop),de=U.length-T.size}await Pt(O,q.totalProcessed,q.totalFindings),C(new Set(T)),N({findings:q.totalFindings,processed:q.totalProcessed,criticalStop:q.criticalStop,autoRetried:de}),q.criticalStop==="rate_limited"?D.error("Спряно: rate-limit от AI gateway. Опитай по-късно."):q.criticalStop==="credits_exhausted"?D.error("Спряно: изчерпани credits на Lovable AI workspace."):T.size>0?D.warning(`Готово с ${T.size} неуспешни — натисни „Повтори" за нов опит.`):D.success(`Готово: ${q.totalFindings} нови предложения за ${q.totalProcessed} ресурса.`),d==null||d()}catch(O){D.error("Грешка: "+((O==null?void 0:O.message)??String(O)))}finally{p(!1)}},re=()=>se(P),ae=()=>{const S=Array.from(h),E=P.filter(T=>S.includes(T.id));if(E.length===0){D.info("Няма неуспешни за повтаряне.");return}F(T=>T+1),N(null),se(E,{reuseRunId:I.current,label:`retry-${y+1}`})},fe=()=>{K.current=!0,D.info("Спира след текущата партида…")},X=f&&f.total>0?Math.round(f.processed/f.total*100):0;return e.jsx(Ee,{open:t,onOpenChange:S=>{w||l(S)},children:e.jsxs(qe,{className:"max-w-2xl",children:[e.jsxs(Le,{children:[e.jsxs(Oe,{className:"flex items-center gap-2",children:[e.jsx(Ie,{className:"h-5 w-5 text-primary"})," Обогатяване (втори AI pass)"]}),e.jsxs(Be,{children:["Над вече анализираните ресурси пуска ",e.jsx("code",{className:"font-mono text-xs",children:be})," с фокус върху добавки (примери, референции, по-добри обяснения, допълнителни quiz въпроси). Резултатите се записват като нови корекции с ",e.jsx("code",{className:"font-mono text-xs",children:"category=enrichment"}),", готови за one-by-one преглед в текущата страница."]})]}),!w&&!g&&e.jsx("div",{className:"space-y-3",children:i?e.jsxs("div",{className:"flex items-center gap-2 text-muted-foreground py-6 justify-center",children:[e.jsx(st,{className:"h-5 w-5 animate-spin"})," Зареждам анализирани ресурси…"]}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2 text-sm",children:[e.jsxs(v,{variant:"secondary",className:"gap-1",children:[e.jsx(jt,{className:"h-3.5 w-3.5"})," ",P.length," ресурса"]}),Z>0&&e.jsxs(v,{variant:"outline",className:"text-amber-600 border-amber-500",children:[Z," липсват в библиотеката"]}),e.jsxs(v,{variant:"outline",children:["≈ ",Q," мин"]}),(r==null?void 0:r.trim())&&e.jsxs(v,{variant:"outline",children:["filter: ",r.trim()]})]}),e.jsxs("div",{className:"rounded-md border border-border bg-muted/30 p-3 max-h-56 overflow-auto text-xs font-mono",children:[P.map(S=>e.jsxs("div",{className:"flex justify-between gap-2 py-0.5",children:[e.jsx("span",{children:S.id}),e.jsx("span",{className:"text-muted-foreground truncate max-w-[60%]",children:S.title})]},S.id)),P.length===0&&e.jsx("div",{className:"text-muted-foreground py-2 text-center",children:"Няма анализирани ресурси по текущия филтър."})]}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:["Партиди по 5 ресурса последователно (~",Ze,"s/ресурс). Можеш да спреш по всяко време след текущата партида."]})]})}),w&&f&&e.jsxs("div",{className:"space-y-3",children:[e.jsx(ft,{value:X}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2 text-sm",children:[e.jsxs(v,{children:[f.processed," / ",f.total]}),e.jsxs(v,{variant:"secondary",children:[f.findingsCreated," нови корекции"]}),f.currentBatch.length>0&&e.jsxs(v,{variant:"outline",className:"font-mono text-xs",children:["партида: ",f.currentBatch.join(", ")]})]}),f.lastFailures.length>0&&e.jsx("div",{className:"rounded-md border border-destructive/40 bg-destructive/5 p-2 text-xs space-y-1",children:f.lastFailures.slice(0,5).map((S,E)=>e.jsxs("div",{className:"font-mono",children:[e.jsx("span",{className:"text-destructive",children:S.id})," · ",S.phase,": ",S.reason]},E))})]}),g&&e.jsxs("div",{className:"space-y-2 text-sm",children:[e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsxs(v,{children:["Обработени: ",g.processed]}),e.jsxs(v,{variant:"secondary",children:["Нови корекции: ",g.findings]}),g.autoRetried?e.jsxs(v,{variant:"outline",children:["Авто-повторени: ",g.autoRetried]}):null,h.size>0&&e.jsxs(v,{variant:"destructive",children:["Неуспешни: ",h.size]}
1),g.criticalStop&&e.jsx(v,{variant:"destructive",children:g.criticalStop})]}),h.size>0&&e.jsxs("div",{className:"rounded-md border border-destructive/40 bg-destructive/5 p-2 text-xs font-mono max-h-32 overflow-auto",children:[Array.from(h).slice(0,30).join(", "),h.size>30&&` …+${h.size-30}`]}),e.jsx("p",{className:"text-muted-foreground",children:"Новите предложения вече са в списъка. Премини през тях с обичайния workflow approve/reject."})]}),e.jsxs(Te,{children:[!w&&!g&&e.jsxs(e.Fragment,{children:[e.jsx(z,{variant:"outline",onClick:()=>l(!1),children:"Отказ"}),e.jsxs(z,{onClick:re,disabled:i||P.length===0,children:[e.jsx(Ie,{className:"h-4 w-4 mr-1"})," Стартирай (",P.length,")"]})]}),w&&e.jsx(z,{variant:"outline",onClick:fe,children:"Спри след партидата"}),g&&e.jsxs(e.Fragment,{children:[h.size>0&&!g.criticalStop&&e.jsxs(z,{variant:"secondary",onClick:ae,children:[e.jsx(vt,{className:"h-4 w-4 mr-1"})," Повтори (",h.size,")"]}),e.jsx(z,{onClick:()=>l(!1),children:"Затвори"})]})]})]})})}function et(t){return t.split(/(\s+|[.,;:!?()«»„""\-—])/g).filter(l=>l.length>0)}function Ot(t,l){const r=t.length,d=l.length,i=Array.from({length:r+1},()=>new Array(d+1).fill(0));for(let a=1;a<=r;a++)for(let o=1;o<=d;o++)i[a][o]=t[a-1]===l[o-1]?i[a-1][o-1]+1:Math.max(i[a-1][o],i[a][o-1]);return i}function it(t,l){const r=et(t??""),d=et(l??""),i=Ot(r,d),a=[];let o=r.length,_=d.length;const c=[];for(;o>0&&_>0;)r[o-1]===d[_-1]?(c.push({type:"equal",value:r[o-1]}),o--,_--):i[o-1][_]>=i[o][_-1]?(c.push({type:"removed",value:r[o-1]}),o--):(c.push({type:"added",value:d[_-1]}),_--);for(;o>0;)c.push({type:"removed",value:r[--o]});for(;_>0;)c.push({type:"added",value:d[--_]});for(let R=c.length-1;R>=0;R--){const w=c[R],p=a[a.length-1];p&&p.type===w.type?p.value+=w.value:a.push({...w})}return a}function Bt(t){return(t.match(/\S+/g)??[]).length}function Tt(t,l=8,r=6){if(t.length===0)return[];if(!t.some(_=>_.type!=="equal"))return[{type:"context",segments:t}];const i=[];let a=[];const o=()=>{a.length&&(i.push({type:"context",segments:a}),a=[])};for(let _=0;_<t.length;_++){const c=t[_];if(c.type!=="equal"){a.push(c);continue}const R=a.length===0,p=t.findIndex((h,C)=>C>_&&h.type!=="equal")===-1,f=c.value.split(/(\s+)/).filter(h=>h.length>0),b=Bt(c.value),g=h=>{const C=[];let y=0;for(const F of f)if(C.push(F),/\S/.test(F)&&(y++,y>=h))break;return C.join("")},N=h=>{const C=[];let y=0;for(let F=f.length-1;F>=0&&(C.unshift(f[F]),!(/\S/.test(f[F])&&(y++,y>=h)));F--);return C.join("")};if(R){if(b>l+r){const h=b-l;i.push({type:"gap",hiddenWords:h,full:c.value.slice(0,c.value.length-N(l).length)}),a.push({type:"equal",value:N(l)})}else a.push(c);continue}if(p){if(b>l+r){const h=g(l);a.push({type:"equal",value:h}),o(),i.push({type:"gap",hiddenWords:b-l,full:c.value.slice(h.length)})}else a.push(c),o();continue}if(b>2*l+r){const h=g(l),C=N(l),y=b-2*l;a.push({type:"equal",value:h}),o(),i.push({type:"gap",hiddenWords:y,full:c.value.slice(h.length,c.value.length-C.length)}),a.push({type:"equal",value:C})}else a.push(c)}return o(),i}const Dt=t=>t==="high"?"bg-emerald-500/15 text-emerald-700 dark:text-emerald-300 border-emerald-500/40":t==="medium"?"bg-amber-500/15 text-amber-700 dark:text-amber-300 border-amber-500/40":"bg-muted text-muted-foreground",Mt=({s:t})=>t.type==="equal"?e.jsx("span",{className:"text-muted-foreground",children:t.value}):t.type==="removed"?e.jsx("span",{className:"bg-destructive/15 text-destructive line-through decoration-destructive/60 rounded px-0.5",children:t.value}):e.jsx("span",{className:"bg-emerald-500/15 text-emerald-700 dark:text-emerald-300 rounded px-0.5",children:t.value}),Vt=({chunks:t})=>{const[l,r]=u.useState(new Set),d=i=>r(a=>{const o=new Set(a);return o.has(i)?o.delete(i):o.add(i),o});return e.jsx("div",{className:"font-mono text-[12.5px] leading-relaxed whitespace-pre-wrap break-words",children:t.map((i,a)=>{if(i.type==="context")return e.jsx("span",{children:i.segments.map((_,c)=>e.jsx(Mt,{s:_},c))},a);const o=l.has(a);return e.jsx("span",{children:o?e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"text-muted-foreground",children:i.full}),e.jsxs("button",{type:"button",onClick:()=>d(a),className:"mx-1 inline-flex items-center gap-0.5 rounded border border-border bg-muted px-1.5 py-0.5 text-[10px] font-sans text-muted-foreground hover:bg-muted/70",title:"Скрий контекста",children:[e.jsx(wt,{className:"h-3 w-3"})," скрий"]})]}):e.jsxs("button",{type:"button",onClick:()=>d(a),className:"mx-1 inline-flex items-center gap-0.5 rounded border border-dashed border-border bg-muted/40 px-1.5 py-0.5 text-[10px] font-sans text-muted-foreground hover:bg-muted",title:"Покажи скрития контекст",children:["… +",i.hiddenWords," думи"]})},a)})})},Jt=({row:t,selected:l,onToggleSelect:r,onApprove:d,onReject:i,onPreview:a,busy:o=!1})=>{const[_,c]=u.useState(t.reviewer_note??""),[R,w]=u.useState(!1),p=t.patch.kind==="code",f=u.useMemo(()=>it(t.patch.old_value,t.patch.new_value),[t.patch.old_value,t.patch.new_value]),[b,g]=u.useState(!1),N=u.useMemo(()=>b?[{type:"context",segments:f}]:Tt(f,8,6),[f,b]),h=N.some(C=>C.type==="gap");return e.jsx(xe,{className:"border-l-4",style:{borderLeftColor:t.patch.confidence==="high"?"hsl(var(--primary))":void 0},children:e.jsxs(pe,{className:"p-4 space-y-3",children:[e.jsxs("div",{className:"flex flex-wrap items-start gap-3",children:[e.jsx("input",{type:"checkbox",className:"mt-1 h-4 w-4 roun
1ded border-border accent-primary",checked:l,onChange:r,disabled:p,title:p?"Code patches изискват индивидуален преглед":"Маркирай за bulk одобрение"}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2 mb-1",children:[e.jsxs(ze,{to:`/resource/${t.resource_id}`,target:"_blank",rel:"noopener noreferrer",className:"font-bold text-foreground hover:underline inline-flex items-center gap-1",children:[t.resource_title??t.resource_id,e.jsx(_t,{className:"h-3 w-3"})]}),e.jsx(v,{variant:"outline",className:"font-mono text-[10px]",children:t.resource_id}),t.subject&&e.jsx(v,{variant:"secondary",children:t.subject}),t.grade!==null&&e.jsxs(v,{variant:"secondary",children:[t.grade," клас"]})]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2 text-xs text-muted-foreground",children:[e.jsxs("span",{className:"inline-flex items-center gap-1",children:[p?e.jsx(bt,{className:"h-3.5 w-3.5"}):e.jsx(rt,{className:"h-3.5 w-3.5"}),e.jsx("span",{className:"font-mono",children:t.patch.patch_target})]}),e.jsxs(v,{className:Dt(t.patch.confidence),variant:"outline",children:["conf: ",t.patch.confidence]}),e.jsx(v,{variant:"outline",children:t.patch.kind}),e.jsx(v,{variant:"outline",children:t.severity})]})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"rounded-md border border-destructive/30 bg-destructive/5 p-2.5",children:[e.jsx("p",{className:"mb-1 text-[10px] font-bold uppercase tracking-wide text-destructive",children:"- Старо"}),e.jsx("pre",{className:"whitespace-pre-wrap break-words font-mono text-[12.5px] text-foreground",children:t.patch.old_value})]}),e.jsxs("div",{className:"rounded-md border border-emerald-500/30 bg-emerald-500/5 p-2.5",children:[e.jsx("p",{className:"mb-1 text-[10px] font-bold uppercase tracking-wide text-emerald-700 dark:text-emerald-300",children:"+ Ново"}),e.jsx("pre",{className:"whitespace-pre-wrap break-words font-mono text-[12.5px] text-foreground",children:t.patch.new_value})]}),!p&&e.jsxs("div",{className:"rounded-md border border-border bg-muted/30 p-2.5",children:[e.jsxs("div",{className:"mb-1 flex items-center justify-between gap-2",children:[e.jsxs("p",{className:"text-[10px] font-bold uppercase tracking-wide text-muted-foreground",children:["Inline diff ",h&&!b&&"· контекст 8 думи около всяка промяна"]}),(h||b)&&e.jsx("button",{type:"button",onClick:()=>g(C=>!C),className:"text-[10px] font-sans text-muted-foreground hover:text-foreground underline",children:b?"Скрий пълния текст":"Покажи пълния текст"})]}),e.jsx(Vt,{chunks:N})]})]}),t.patch.rationale&&e.jsxs("p",{className:"text-xs text-muted-foreground italic",children:[e.jsx("span",{className:"font-semibold not-italic",children:"Обосновка:"})," ",t.patch.rationale]}),R?e.jsxs("div",{className:"space-y-2",children:[e.jsx(Pe,{placeholder:"Защо отхвърляш тази корекция? (задължително)",value:_,onChange:C=>
1c(C.target.value),className:"min-h-[60px]"}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(z,{variant:"destructive",size:"sm",disabled:o||_.trim().length===0,onClick:()=>i(_.trim()),children:"Потвърди отхвърляне"}),e.jsx(z,{variant:"outline",size:"sm",onClick:()=>w(!1),disabled:o,children:"Отказ"})]})]}):e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsxs(z,{size:"sm",disabled:o,onClick:()=>d(_.trim()||void 0),children:[e.jsx(yt,{className:"h-4 w-4 mr-1"})," Одобри"]}),e.jsxs(z,{size:"sm",variant:"outline",disabled:o,onClick:()=>w(!0),children:[e.jsx(Nt,{className:"h-4 w-4 mr-1"})," Отхвърли"]}),a&&e.jsxs(z,{size:"sm",variant:"ghost",onClick:a,title:"Сравни с текущите стойности на ресурса",children:[e.jsx(at,{className:"h-4 w-4 mr-1"})," Преглед на промените"]})]}),t.status!=="open"&&e.jsxs("p",{className:"text-[11px] text-muted-foreground",children:["Статус: ",e.jsx("span",{className:"font-mono",children:t.status}),t.reviewer_note?` · бел.: ${t.reviewer_note}`:""]})]})})},Gt=new Set(["concept"]),Wt=new Set(["goals","materials","steps"]);function tt(t,l){let r=t;for(const d of l){if(r==null)return;r=r[d]}return r}function De(t,l){const r=[],d=Ft(t.patch_target);d.length===t.field_path.length&&d.every((c,R)=>c===t.field_path[R])||r.push({severity:"error",code:"target_path_mismatch",message:`field_path ${JSON.stringify(t.field_path)} не съвпада с parse(${t.patch_target}) = ${JSON.stringify(d)}`});const a=t.field_path[0];if(typeof a!="string")return r.push({severity:"error",code:"unknown_root",message:`field_path започва с не-стринг сегмент: ${JSON.stringify(a)}`}),{ok:!1,issues:r};const o=Gt.has(a),_=Wt.has(a);if(!o&&!_)return t.new_value.trim()||r.push({severity:"warning",code:"empty_new_value",message:"new_value е празно"}),{ok:!r.some(c=>c.severity==="error"),issues:r};if(t.kind!=="text"&&r.push({severity:"error",code:"invalid_kind_for_field",message:`${a} изисква kind="text", получено "${t.kind}"`}),t.new_value.trim()||r.push({severity:"error",code:"empty_new_value",message:"new_value е празно — би изтрило съдържание"}),o){if(t.field_path.length>1&&r.push({severity:"error",code:"extra_path_segments",message:`concept приема само ["concept"], получено ${JSON.stringify(t.field_path)}`}),l!==void 0){const c=tt(l,t.field_path);c===void 0?r.push({severity:"warning",code:"field_missing_in_resource",message:"concept липсва в ресурса"}):typeof c!="string"?r.push({severity:"error",code:"concept_must_be_string",message:`concept в ресурса не е string (${typeof c})`}):t.old_value&&c.trim()!==t.old_value.trim()&&c.trim()!==t.new_value.trim()&&r.push({severity:"warning",code:"old_value_mismatch",message:"Текущото concept не съвпада с patch.old_value (ресурсът може да е променен)"})}}else{t.field_path.length===1?r.push({severity:"error",code:"array_field_needs_index",message:`${a} е масив — patch_target трябва да е напр. "${a}[0]", не "${a}"`}):t.field_path.length>2&&r.push({severity:"error",code:"extra_path_segments",message:`${a}[i] е string — допълнителни сегменти не се поддържат: ${JSON.stringify(t.field_path.slice(2))}`});const c=t.field_path[1];if(t.field_path.length>=2&&(typeof c!="number"||!Number.isInteger(c)?r.push({severity:"error",code:"array_field_needs_index",message:`${a}[i] изисква целочислен индекс, получено ${JSON.stringify(c)}`}):c<0&&r.push({severity:"error",code:"array_index_negative",message:`${a}[${c}] — индексът е отрицателен`})),/\r|\n/.test(t.new_value)&&r.push({severity:"warning",code:"newline_in_array_item",message:`${a}[i] не трябва да съдържа нов ред — това би объркало структурата на масива`}),l!==void 0){const R=tt(l,[a]);if(R===void 0)r.push({severity:"warning",code:"field_missing_in_resource",message:`${a} липсва в ресурса`});else if(!Array.isArray(R))r.push({severity:"error",code:"array_item_must_be_string",message:`${a} в ресурса не е масив (${typeof R})`});else{const w=typeof c=="number"?c:-1;if(w>=0)if(w>=R.length)r.push({severity:"error",code:"array_index_out_of_range",message:`${a}[${w}] е извън диапазона (масивът има ${R.length} елемента)`});else{const p=R[w];typeof p!="string"?r.push({severity:"error",code:"array_item_must_be_string",message:`${a}[${w}] не е string (${typeof p})`}):t.old_value&&p.trim()!==t.old_value.trim()&&p.trim()!==t.new_value.trim()&&r.push({severity:"warning",code:"old_value_mismatch",message:`Текущото ${a}[${w}] не съвпада с patch.old_value (ресурсът може да е променен)`})}}}}return{ok:!r.some(c=>
1c.severity==="error"),issues:r}}function Kt(t,l){const r=t.map(a=>De(a,l));let d=0,i=0;for(const a of r)for(const o of a.issues)o.severity==="error"?d++:i++;return{ok:d===0,results:r,errorCount:d,warningCount:i}}const Ut=new Set(["concept","goals","materials","steps"]);function Xt(t,l){let r=t;for(const d of l){if(r==null)return;r=r[d]}return r}function Ht(t){if(t===void 0)return"(няма стойност)";if(t===null)return"(null)";if(typeof t=="string")return t;if(Array.isArray(t))return t.map((l,r)=>`${r+1}. ${String(l)}`).join(`
2`);try{return JSON.stringify(t,null,2)}catch{return String(t)}}const Qt=({oldStr:t,newStr:l})=>{const r=u.useMemo(()=>it(t,l),[t,l]);return e.jsx("div",{className:"font-mono text-[12.5px] leading-relaxed whitespace-pre-wrap break-words",children:r.map((d,i)=>d.type==="equal"?e.jsx("span",{className:"text-muted-foreground",children:d.value},i):d.type==="removed"?e.jsx("span",{className:"bg-destructive/15 text-destructive line-through decoration-destructive/60 rounded px-0.5",children:d.value},i):e.jsx("span",{className:"bg-emerald-500/15 text-emerald-700 dark:text-emerald-300 rounded px-0.5",children:d.value},i))})},Yt=({open:t,onOpenChange:l,resourceId:r,resourceTitle:d,patches:i})=>{const[a,o]=u.useState(null),[_,c]=u.useState(!1),[R,w]=u.useState(null);u.useEffect(()=>{if(!t||!r)return;let g=!0;return c(!0),w(null),o(null),nt(r).then(N=>{g&&o(N)}).catch(N=>{g&&w((N==null?void 0:N.message)??String(N))}).finally(()=>{g&&c(!1)}),()=>{g=!1}},[t,r]);const p=u.useMemo(()=>i.filter(g=>{const N=g.field_path[0];return typeof N=="string"&&Ut.has(N)}),[i]),f=i.length-p.length,b=u.useMemo(()=>Kt(p,a??void 0),[p,a]);return e.jsx(Ee,{open:t,onOpenChange:l,children:e.jsxs(qe,{className:"max-w-4xl max-h-[88vh] overflow-hidden flex flex-col",children:[e.jsxs(Le,{children:[e.jsxs(Oe,{className:"flex items-center gap-2 flex-wrap",children:[e.jsx(rt,{className:"h-4 w-4"})," Преглед на промените",r&&e.jsx(v,{variant:"outline",className:"font-mono text-[10px]",children:r}),p.length>0&&(b.ok?e.jsxs(v,{className:"bg-emerald-500/15 text-emerald-700 dark:text-emerald-300 border-emerald-500/40",variant:"outline",children:["✓ готово за прилагане (",p.length,")"]}):e.jsxs(v,{variant:"destructive",children:["✗ ",b.errorCount," ",b.errorCount===1?"грешка":"грешки"," — НЕ е готово"]})),b.warningCount>0&&e.jsxs(v,{className:"bg-amber-500/15 text-amber-700 dark:text-amber-300 border-amber-500/40",variant:"outline",children:["⚠ ",b.warningCount," предупр."]})]}),e.jsxs(Be,{children:[d??r," · сравнение между текущи и предложени стойности (concept, goals, materials, steps).",f>0&&e.jsxs("span",{className:"ml-1 text-amber-600",children:[f," ",f===1?"patch":"patches"," извън тези полета са скрити."]})]})]}),e.jsx("div",{className:"flex-1 min-h-0 overflow-auto space-y-4 pr-1",children:_?e.jsxs("div",{className:"flex items-center justify-center py-12 text-muted-foreground",children:[e.jsx(st,{className:"h-5 w-5 animate-spin mr-2"})," Зареждане на ресурса…"]}):R?e.jsxs("div",{className:"flex items-center gap-2 p-4 rounded border border-destructive/40 bg-destructive/5 text-destructive text-sm",children:[e.jsx(We,{className:"h-4 w-4"})," Грешка: ",R]}):a?p.length===0?e.jsxs("div",{className:"p-4 rounded border border-border bg-muted/30 text-sm text-muted-foreground",children:["Няма patches към ",e.jsx("code",{className:"font-mono",children:"concept / goals / materials / steps"})," за този ресурс."]}):p.map((g,N)=>{const h=Xt(a,g.field_path),C=Ht(h),y=g.new_value||"(празно)",F=g.old_value,I=typeof h=="string"&&h.trim()===g.new_value.trim(),K=h===void 0,P=De(g,a),Z=P.issues.filter(W=>W.severity==="error"),Q=P.issues.filter(W=>W.severity==="warning");return e.jsxs("div",{className:"rounded-lg border border-border bg-card p-3 space-y-2",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx(v,{variant:"secondary",className:"font-mono text-[10px]",children:g.patch_target}),e.jsx(v,{variant:"outline",children:g.kind}),e.jsxs(v,{variant:"outline",children:["conf: ",g.confidence]}),P.ok?e.jsx(v,{className:"bg-emerald-500/15 text-emerald-700 dark:text-emerald-300 border-emerald-500/40",variant:"outline",children:"✓ структурно валиден"}):e.jsxs(v,{variant:"destructive",children:["✗ ",Z.length," ",Z.length===1?"грешка":"грешки"]}),Q.length>0&&e.jsxs(v,{className:"bg-amber-500/15 text-amber-700 dark:text-amber-300 border-amber-500/40",variant:"outline",children:["⚠ ",Q.length," предупр."]}),I&&e.jsx(v,{className:"bg-emerald-500/15 text-emerald-700 dark:text-emerald-300 border-emerald-500/40",variant:"outline",children:"вече приложен"}),K&&e.jsx(v,{className:"bg-amber-500/15 text-amber-700 dark:text-amber-300 border-amber-500/40",variant:"outline",children:"полето липсва в ресурса"})]}),P.issues.length>0&&e.jsx("ul",{className:"rounded border border-border bg-muted/30 p-2 text-[12px] space-y-1",children:P.issues.map((W,se)=>e.jsxs("li",{className:W.severity==="error"?"text-destructive":"text-amber-700 dark:text-amber-300",children:[e.jsxs("span",{className:"font-mono uppercase text-[10px] mr-1",children:["[",W.severity,"]"]}),e.jsx("span",{className:"font-mono text-[10px] mr-1",children:W.code}),W.message]},se))}),e.jsxs("div",{className:"grid md:grid-cols-2 gap-2",children:[e.jsxs("div",{className:"rounded border border-destructive/30 bg-destructive/5 p-2",children:[e.jsx("p",{className:"mb-1 text-[10px] font-bold uppercase tracking-wide text-destructive",children:"- Текущо в ресурса"}),e.jsx("pre",{className:"whitespace-pre-wrap break-words font-mono text-[12.5px] text-foreground",children:C})]}),e.jsxs("div",{className:"rounded border border-emerald-500/30 bg-emerald-500/5 p-2",children:[e.jsx("p",{className:"mb-1 text-[10px] font-bold uppercase tracking-wide text-emerald-700 dark:text-emerald-300",children:"+ Предложено"}),e.jsx("pre",{className:"whitespace-pre-wrap break-words font-mono text-[12.5px] text-foreground",children:y})]})]}),typeof h=="string"&&e.jsxs("div",{className:"rounded border border-border bg-muted/30 p-2",children:[e.jsx("p",{className:"mb-1 text-[10px] font-bold uppercase tracking-wide text-muted-foreground",children:"Inline diff (текущо → предложено)"}),e.jsx(Qt,{oldStr:C,newStr:y})]}
2),F&&typeof h=="string"&&h.trim()!==F.trim()&&!I&&e.jsxs("div",{className:"flex items-start gap-2 p-2 rounded border border-amber-500/40 bg-amber-500/5 text-[12px] text-amber-800 dark:text-amber-300",children:[e.jsx(We,{className:"h-3.5 w-3.5 mt-0.5 shrink-0"}),e.jsx("div",{children:'Patch-ът очаква друго „старо" съдържание — възможно е ресурсът да е променен след одита. Прегледай внимателно преди прилагане.'})]}),g.rationale&&e.jsxs("p",{className:"text-xs text-muted-foreground italic",children:[e.jsx("span",{className:"font-semibold not-italic",children:"Обосновка:"})," ",g.rationale]})]},N)}):e.jsx("div",{className:"p-4 rounded border border-amber-500/40 bg-amber-500/5 text-sm",children:"Ресурсът не е намерен в библиотеката."})}),e.jsx(Te,{children:e.jsx(z,{variant:"outline",onClick:()=>l(!1),children:"Затвори"})})]})})},Zt=new Set(["concept","goals","materials","steps"]);async function es(t,l,r){var w,p;const d=[];let i=0,a=0,o=0,_=0;const c=new Map;for(const f of t){const b=c.get(f.resource_id)??[];b.push(f),c.set(f.resource_id,b)}let R=0;for(const[f,b]of c.entries()){R++,r==null||r(`Ресурс ${R}/${c.size}: ${f} (${b.length} findings)`);const g=await nt(f);if(!g){for(const N of b){for(const h of((w=N.patch_json)==null?void 0:w.patches)??[])o++,d.push({finding_id:N.id,resource_id:f,patch_target:h.patch_target,status:"skipped",reason:"resource_not_found"});a++}continue}for(const N of b){const h=((p=N.patch_json)==null?void 0:p.patches)??[];let C=0;const y=[];for(const F of h){o++;const I=F.field_path[0];if(typeof I!="string"||!Zt.has(I)){d.push({finding_id:N.id,resource_id:f,patch_target:F.patch_target,status:"skipped",reason:"untracked_field"});continue}const K=De(F,g);if(!K.ok){d.push({finding_id:N.id,resource_id:f,patch_target:F.patch_target,status:"skipped",reason:"validation_failed:"+K.issues.filter(P=>P.severity==="error").map(P=>P.code).join(",")});continue}y.push({resource_id:f,field_path:F.field_path,new_value:F.new_value,applied_from_finding_id:N.id,applied_by:l,note:F.rationale??""})}if(y.length>0){const{error:F}=await G.from("resource_field_overrides").upsert(y,{onConflict:"resource_id,field_path_key"});if(F)for(const I of y)d.push({finding_id:N.id,resource_id:f,patch_target:JSON.stringify(I.field_path),status:"skipped",reason:"upsert_error:"+F.message});else{C=y.length,_+=y.length;for(const I of y)d.push({finding_id:N.id,resource_id:f,patch_target:JSON.stringify(I.field_path),status:"applied"})}}C>0?(i++,await G.from("content_audit_findings").update({status:"applied",applied_at:new Date().toISOString(),applied_commit:`db-overlay:${C}`}).eq("id",N.id)):a++}}return _>0&&Rt(),{outcomes:d,appliedFindings:i,skippedFindings:a,totalPatches:o,appliedPatches:_}}const ye=50,js=()=>{const{user:t}=pt(),[l]=xt(),[r,d]=u.useState(!1),[i,a]=u.useState([]),[o,_]=u.useState(new Set),[c,R]=u.useState(new Set),[w,p]=u.useState(0),[f,b]=u.useState(0),[g,N]=u.useState(()=>l.get("status")??"open"),[h,C]=u.useState("all"),[y,F]=u.useState("all"),[I,K]=u.useState("all"),[P,Z]=u.useState("all"),[Q,W]=u.useState(()=>l.get("resource_id")??""),[se,re]=u.useState(!1),[ae,fe]=u.useState(!1),[X,S]=u.useState(null),[E,T]=u.useState([]),[O,q]=u.useState(""),de=u.useRef(null),[ee,U]=u.useState([]),[H,te]=u.useState(!1),[ge,lt]=u.useState(null),[je,ot]=u.useState(!1),[Ne,ct]=u.useState(30),B=(s,n)=>{const m=new Date().toLocaleTimeString("bg-BG",{hour12:!1});T(x=>[...x,{ts:m,level:s,msg:n}]),console.log(`[auto-approve ${s}] ${n}`)},dt=s=>{q(s??""),requestAnimationFrame(()=>{var n;(n=de.current)==null||n.scrollIntoView({behavior:"smooth",block:"start"})})},we=(s,n)=>`${s}::${n}`,Y=async()=>{var s;d(!0),_(new Set);try{let n=G.from("content_audit_findings").select("id, resource_id, resource_title, subject, grade, severity, status, reviewer_note, patch_json",{count:"exact"}).not("patch_json","is",null);g!=="all"&&(n=n.eq("status",g)),h!=="all"&&(n=n.eq("subject",h)),y!=="all"&&(n=n.eq("grade",Number(y))),Q.trim()&&(n=n.ilike("resource_id",`%${Q.trim()}%`)),n=n.order("severity",{ascending:!1}).order("resource_id",{ascending:!0}).range(w*ye,w*ye+ye-1);const{data:m,error:x,count:$}=await n;if(x)throw x;const A=[];for(const j of m??[])(((s=j.patch_json)==null?void 0:s.patches)??[]).forEac
2h((M,V)=>{I!=="all"&&M.confidence!==I||P!=="all"&&M.kind!==P||A.push({id:j.id,resource_id:j.resource_id,resource_title:j.resource_title,subject:j.subject,grade:j.grade,severity:j.severity,status:j.status,reviewer_note:j.reviewer_note,patch:M,patch_index:V})});a(A),b($??0)}catch(n){D.error("Грешка при зареждане: "+((n==null?void 0:n.message)??String(n)))}finally{d(!1)}};u.useEffect(()=>{Y()},[w,g,h,y,I,P]);const Se=u.useCallback(async s=>{var n;if(s.length===0){U([]);return}te(!0);try{const[m,x]=await Promise.all([G.from("content_audit_findings").select("resource_id, resource_title, status").in("resource_id",s),G.from("resource_field_overrides").select("resource_id").in("resource_id",s)]);if(m.error)throw m.error;if(x.error)throw x.error;const $=new Map;for(const A of s)$.set(A,{resource_id:A,resource_title:((n=i.find(j=>j.resource_id===A))==null?void 0:n.resource_title)??null,open:0,approved:0,rejected:0,applied:0,overrides:0,total:0});for(const A of m.data??[]){const j=$.get(A.resource_id);j&&(!j.resource_title&&A.resource_title&&(j.resource_title=A.resource_title),j.total++,A.status==="open"?j.open++:A.status==="approved"?j.approved++:A.status==="rejected"?j.rejected++:A.status==="applied"&&j.applied++)}for(const A of x.data??[]){const j=$.get(A.resource_id);j&&j.overrides++}U(Array.from($.values()).sort((A,j)=>A.resource_id.localeCompare(j.resource_id))),lt(new Date)}catch(m){console.warn("resource status fetch failed",m),U([])}finally{te(!1)}},[i]);u.useEffect(()=>{const s=Array.from(new Set(i.map(n=>n.resource_id)));Se(s)},[i]),u.useEffect(()=>{if(!je)return;const s=setInterval(()=>{const n=Array.from(new Set(i.map(m=>m.resource_id)));Se(n)},Ne*1e3);return()=>clearInterval(s)},[je,Ne,i,Se]);const ke=async(s,n,m)=>{if(!t){D.error("Не си логнат");return}const x=Array.from(new Set(s));R($=>new Set([...$,...x]));try{const $=new Date().toISOString(),A={status:n,reviewed_at:$,reviewed_by:t.id,...n==="approved"?{approved_by:t.id,approved_at:$}:{},...m!==void 0?{reviewer_note:m}:{}},{error:j}=await G.from("content_audit_findings").update(A).in("id",x);if(j)throw j;D.success(`${n==="approved"?"Одобрени":"Отхвърлени"}: ${x.length} ${x.length===1?"корекция":"корекции"}`),_(new Set),await Y()}catch($){D.error("Грешка: "+(($==null?void 0:$.message)??String($)))}finally{R($=>{const A=new Set($);return x.forEach(j=>A.delete(j)),A})}},ve=u.useMemo(()=>i.filter(s=>s.patch.kind!=="code").map(s=>we(s.id,s.patch_index)),[i]),Me=ve.length>0&&ve.every(s=>o.has(s)),ut=()=>{_(Me?new Set:new Set(ve))},[k,_e]=u.useState(null),[ue,Ce]=u.useState(""),Ve=s=>{const n=i.filter(m=>o.has(we(m.id,m.patch_index)));if(n.length===0){D.error("Няма избрани text patches");return}Ce(""),_e({decision:s,rows:n,findingIds:Array.from(new Set(n.map(m=>m.id)))})},mt=async()=>{if(!k)return;if(k.decision==="rejected"&&!ue.trim()){D.error("Бележката е задължителна при отхвърляне");return}const{decision:s,findingIds:n}=k;_e(null),await ke(n,s,ue.trim()||void 0)},$e=Math.max(1,Math.ceil(f/ye)),ht=async()=>{if(!t){D.error("Не си логнат");return}if(confirm("Ще одобри всички отворени корекции с confidence high+medium (text patches), след което ще пусне обогатяване. Продължаваме?")){fe(!0),T([]),B("info","Старт: тегля open находки с patch_json…");try{const s=[];let m=0;for(let M=0;;M+=1e3){m++;const{data:V,error:J}=await G.from("content_audit_findings").select("id, patch_json").eq("status","open").not("patch_json","is",null).range(M,M+1e3-1);if(J)throw B("err",`Fetch page ${m} грешка: ${J.message}`),J;const he=V??[];if(s.push(...he),B("info",`Fetch page ${m}: +${he.length} находки (общо ${s.length})`),he.length<1e3)break}B("ok",`Заредени общо ${s.length} open находки.`);const x=s.filter(M=>{var V;return(((V=M.patch_json)==null?void 0:V.patches)??[]).some(J=>J.kind==="text"&&(J.confidence==="high"||J.confidence==="medium"))}).map(M=>M.id),$=s.length-x.length;if(B("info",`Филтър: ${x.length} подходящи (text + high/medium); пропуснати ${$} (low / code).`),x.length===0){B("warn","Няма подходящи находки. Отварям обогатяване директно."),D.info("Няма подходящи open корекции за авто-одобрение."),re(!0);return}const A=new Date().toISOString();let j=0;const me=Math.ceil(x.length/500);for(let M=0,V=0;M<x.length;M+=500,V++){const J=x.slice(M,M+500),he=performance.now(),{error:Ae}=await G.from("content_audit_findings").update({status:"approved",reviewed_at:A,reviewed_by:t.id,approved_by:t.id,approved_at:A,reviewer_note:"auto-approved (high+medium confidence)"}).in("id",J),Ge=Math.round(performance.now()-he);if(Ae)throw B("err",`Партида ${V+1}/${me} (${J.length} ids) грешка след ${Ge}ms: ${Ae.message}`),Ae;j+=J.length,B("ok",`Партида ${V+1}/${me}: одобрени ${J.length} (общо ${j}/${x.length}) за ${Ge}ms.`)}B("ok",`Готово: ${j} находки одобрени.`),D.success(`Авто-одобрени: ${j} находки.`),B("info","Phase C: прилагам overrides към ресурсите…"),await Je(x),B("info","Отварям обогатяване…"),await Y(),re(!0)}catch(s){B("err",`Прекъснато: ${(s==null?void 0:s.message)??String(s)}`),D.error("Грешка при авто-одобрение: "+((s==null?void 0:s.message)??String(s)))}finally{fe(!1)}}},Je=async s=>{if(t)try{let n=G.from("content_audit_findings").select("id, resource_id, patch_json").not("patch_json","is",null);s&&s.length>0?n=n.in("id",s):n=n.eq("status","approved").is("applied_at",null);const{data:m,error:x}=await n.limit(5e3);if(x){B("err",`Phase C fetch грешка: ${x.message}`);return}const $=m??[];if(B("info",`Phase C: ${$.length} findings за прилагане.`),$.length===0)return;const A=performance.now(),j=await es($,t.id,V=>B("info",V)),me=Math.round(performance.now()-A);B("ok",`Phase C готово за ${me}ms: приложени ${j.appliedPatches}/${j.totalPatches} patches; findings applied=${j.appliedFindings}, skipped=${j.skippedFindings}.`);const M=new Map;for(const V of j.outcomes)if(V.status==="skipped"){const J=V.reason??"unknown";M.set(J,(M.get(J)??0)+1)}for(const[V,J]of M.entries())B("warn",`Phase C skipped ${J}× — ${V}`);j.appliedPatches>0&&D.success(`Приложени ${j.appliedPatches} корекции директно към ресурсите.`)}catch(n){B("err",`Phase C прекъснато: ${(n==null?void 0:n.message)??String(n)}`)}};return e.jsxs("div",{className:"container mx-auto p-6 space-y-6",children:[e.jsxs("div",{className:"flex items-center justify-between gap-4 flex-wrap",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-3xl font-bold",children:"Преглед на корекции"}),e.jsxs("p",{className:"text-sm text-muted-foreground",children:["Phase B · одобри / отхвърли корекциите от ",e.jsx("code",{className:"font-mono",children:"content_audit_findings"}),". Code patches (sim_source) изискват индивидуален преглед."]})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(z,{variant:"outline",asChild:!0,children:e.jsxs(ze,{to:"/admin/quality-audit",children:[e.jsx(St,{className:"h-4 w-4 mr-1"})," Quality Audit"]})}),e.jsxs(z,{variant:"outline",onClick:Y,disabled:r,children:[e.jsx(Ke,{className:`h-4 w-4 mr-1 ${r?"animate-spin":""}`})," Презареди"]}),e.jsxs(z,{variant:"secondary",onClick:ht,disabled:ae||r,children:[e.jsx(Ue,{className:`h-4 w-4 mr-1 ${ae?"animate-spin":""}`})," Авто-одобри + Обогати"]}),e.jsxs(z,{onClick:()=>re(!0),children:[e.jsx(Ie,{className:"h-4 w-4 mr-1"})," Обогати анализираните…"]})]})]}),e.jsx(Lt,{open:se,onOpenChange:re,resourceIdFilter:Q,onCompleted:async()=>{B("info","Обогатяване готово — авто-одобрявам новите open находки…");try{const{data:s,error:n}=await G.from("content_audit_findings").select("id, patch_json").eq("status","open").not("patch_json","is",null).limit(5e3);if(n)throw n;const m=(s??[]).filter(x=>{var $;return((($=x.patch_json)==null?void 0:$.patches)??[]).some(A=>A.kind==="text"&&(A.confidence==="high"||A.confidence==="medium"))}).map(x=>x.id);if(m.length>0&&t){const x=new Date().toISOString(),{error:$}=await G.from("content_audit_findings").update({status:"approved",reviewed_at:x,reviewed_by:t.id,approved_by:t.id,approved_at:x,reviewer_note:"auto-approved (post-enrichment)"}).in("id",m);if($)throw $;B("ok",`Авто-одобрени след обогатяване: ${m.length} находки.`),await Je(m)}else B("info","Няма нови high/medium open находки след обогатяване.")}
2catch(s){B("err",`Post-enrich грешка: ${(s==null?void 0:s.message)??String(s)}`)}await Y()}}),E.length>0&&e.jsxs(xe,{ref:de,children:[e.jsxs(Re,{className:"pb-2 flex flex-row items-center justify-between gap-2",children:[e.jsxs(Fe,{className:"text-sm flex items-center gap-2",children:[e.jsx(Ue,{className:"h-4 w-4"})," Лог на авто-одобрение",ae&&e.jsx("span",{className:"text-xs text-muted-foreground",children:"(работи…)"}),O&&e.jsxs(v,{variant:"secondary",className:"font-mono text-[10px]",children:["филтър: ",O]})]}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(Qe,{value:O,onChange:s=>q(s.target.value),placeholder:"филтър по текст / resource_id",className:"h-7 w-56 text-xs"}),O&&e.jsx(z,{variant:"ghost",size:"icon",className:"h-7 w-7",onClick:()=>q(""),title:"Изчисти филтъра",children:e.jsx(kt,{className:"h-3.5 w-3.5"})}),e.jsx(z,{variant:"ghost",size:"sm",onClick:()=>T([]),disabled:ae,children:"Изчисти лог"})]})]}),e.jsx(pe,{children:e.jsx("div",{className:"max-h-64 overflow-auto rounded border bg-muted/30 p-2 font-mono text-xs space-y-0.5",children:(()=>{const s=O.trim().toLowerCase(),n=s?E.filter(m=>m.msg.toLowerCase().includes(s)):E;return n.length===0?e.jsxs("div",{className:"text-muted-foreground italic",children:["Няма съвпадения за „",O,'".']}):n.map((m,x)=>e.jsxs("div",{className:m.level==="err"?"text-destructive":m.level==="warn"?"text-amber-600":m.level==="ok"?"text-emerald-700":"text-foreground/80",children:[e.jsxs("span",{className:"text-muted-foreground",children:["[",m.ts,"]"]})," ",e.jsx("span",{className:"uppercase",children:m.level})," · ",m.msg]},x))})()})})]}),e.jsxs(xe,{children:[e.jsx(Re,{className:"pb-3",children:e.jsxs(Fe,{className:"flex items-center gap-2 text-base",children:[e.jsx(Xe,{className:"h-4 w-4"})," Филтри"]})}),e.jsxs(pe,{className:"grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-3",children:[e.jsxs("div",{children:[e.jsx("label",{className:"text-xs text-muted-foreground",children:"Статус"}),e.jsxs(ne,{value:g,onValueChange:s=>{p(0),N(s)},children:[e.jsx(ie,{children:e.jsx(le,{})}),e.jsxs(oe,{children:[e.jsx(L,{value:"open",children:"Open"}),e.jsx(L,{value:"approved",children:"Approved"}),e.jsx(L,{value:"rejected",children:"Rejected"}),e.jsx(L,{value:"applied",children:"Applied"}),e.jsx(L,{value:"all",children:"Всички"})]})]})]}),e.jsxs("div",{children:[e.jsx("label",{className:"text-xs text-muted-foreground",children:"Предмет"}),e.jsxs(ne,{value:h,onValueChange:s=>{p(0),C(s)},children:[e.jsx(ie,{children:e.jsx(le,{})}),e.jsxs(oe,{children:[e.jsx(L,{value:"all",children:"Всички"}),e.jsx(L,{value:"biology",children:"Биология"}),e.jsx(L,{value:"chemistry",children:"Химия"}),e.jsx(L,{value:"physics",children:"Физика"}),e.jsx(L,{value:"nature",children:"Природа"}),e.jsx(L,{value:"tech",children:"Технологии"})]})]})]}),e.jsxs("div",{children:[e.jsx("label",{className:"text-xs text-muted-foreground",children:"Клас"}),e.jsxs(ne,{value:y,onValueChange:s=>{p(0),F(s)},children:[e.jsx(ie,{children:e.jsx(le,{})}),e.jsxs(oe,{children:[e.jsx(L,{value:"all",children:"Всички"}),[4,5,6,7,8,9,10,11].map(s=>e.jsx(L,{value:String(s),children:s},s))]})]})]}),e.jsxs("div",{children:[e.jsx("label",{className:"text-xs text-muted-foreground",children:"Confidence"}),e.jsxs(ne,{value:I,onValueChange:s=>{p(0),K(s)},children:[e.jsx(ie,{children:e.jsx(le,{})}),e.jsxs(oe,{children:[e.jsx(L,{value:"all",children:"Всички"}),e.jsx(L,{value:"high",children:"High"}),e.jsx(L,{value:"medium",children:"Medium"}),e.jsx(L,{value:"low",children:"Low"})]})]})]}),e.jsxs("div",{children:[e.jsx("label",{className:"text-xs text-muted-foreground",children:"Тип"}),e.jsxs(ne,{value:P,onValueChange:s=>{p(0),Z(s)},children:[e.jsx(ie,{children:e.jsx(le,{})}),e.jsxs(oe,{children:[e.jsx(L,{value:"all",children:"Всички"}),e.jsx(L,{value:"text",children:"Text"}),e.jsx(L,{value:"code",children:"Code (sim)"})]})]})]}),e.jsxs("div",{children:[e.jsx("label",{className:"text-xs text-muted-foreground",children:"Resource ID"}),e.jsxs("div",{className:"flex gap-1",children:[e.jsx(Qe,{value:Q,onChange:s=>W(s.target.value),onKeyDown:s=>{s.key==="Enter"&&(p(0),Y())},placeholder:"напр. bio7-12"}),e.jsx(z,{size:"sm",variant:"outline",onClick:()=>{p(0),Y()},children:"OK"})]})]})]})]}),ee.length>0&&e.jsxs(xe,{children:[e.jsxs(Re,{className:"pb-2 flex flex-row items-center justify-between gap-2 flex-wrap",children:[e.jsxs(Fe,{className:"text-sm flex items-center gap-2",children:[e.jsx(He,{className:"h-4 w-4"}),"Статус по ресурс (",ee.length,")",H&&e.jsx("span",{className:"text-xs text-muted-foreground",children:"(обновяване…)"}),ge&&e.jsxs("span",{className:"text-[10px] text-muted-foreground flex items-center gap-1",title:"Последно обновяване",children:[e.jsx(Ct,{className:"h-3 w-3"}),ge.toLocaleTimeString("bg-BG",{hour12:!1})]})]}),e.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[e.jsxs("label",{className:"flex items-center gap-1.5 text-xs text-muted-foreground cursor-pointer select-none",children:[e.jsx("input",{type:"checkbox",className:"h-3.5 w-3.5 rounded border-border accent-primary",checked:je,onChange:s=>ot(s.target.checked)}),"Авто-обновяване"]}),e.jsxs(ne,{value:String(Ne),onValueChange:s=>ct(Number(s)),disabled:!je,children:[e.jsx(ie,{className:"h-7 w-24 text-xs",children:e.jsx(le,{})}),e.jsxs(oe,{children:[e.jsx(L,{value:"10",children:"10 сек"}),e.jsx(L,{value:"30",children:"30 сек"}),e.jsx(L,{value:"60",children:"1 мин"}),e.jsx(L,{value:"120",children:"2 мин"})]})]}),e.jsx("span",{className:"text-xs text-muted-foreground",children:"броячи покриват ВСИЧКИ findings за ресурса (не само текущите филтри)"})]})]}),e.jsx(pe,{className:"p-0",children:e.jsx("div",{className:"max-h-80 overflow-auto divide-y divide-border",children:ee.map(s=>{const n=s.applied>0||s.overrides>0,m=n?s.open>0||s.approved>0?"частично приложен":"приложен":s.approved>0?"одобрен (чака прилагане)":s.open>0?"отворен":s.rejected>0?"отхвърлен":"—",x=n&&s.open===0&&s.approved===0?"bg-emerald-500/15 text-emerald-700 border-emerald-500/40":n?"bg-sky-500/15 text-sky-700 border-sky-500/40":s.approved>0?"bg-amber-500/15 text-amber-700 border-amber-500/40":s.open>
20?"bg-muted text-foreground/80":"bg-muted text-muted-foreground";return e.jsxs("div",{className:"flex items-start gap-3 px-3 py-2 hover:bg-muted/40",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[e.jsx(v,{variant:"outline",className:"font-mono text-[10px]",children:s.resource_id}),e.jsx(v,{variant:"outline",className:`text-[10px] ${x}`,children:m}),s.overrides>0&&e.jsxs(v,{variant:"outline",className:"text-[10px] bg-emerald-500/10 text-emerald-700 border-emerald-500/40",children:["overrides: ",s.overrides]})]}),e.jsx("div",{className:"mt-0.5 truncate text-sm",children:s.resource_title??s.resource_id}),e.jsxs("div",{className:"mt-1 flex flex-wrap gap-1",children:[e.jsxs(v,{variant:"secondary",className:"text-[10px]",children:["open: ",s.open]}),e.jsxs(v,{variant:"secondary",className:"text-[10px] bg-amber-500/15 text-amber-700",children:["approved: ",s.approved]}),e.jsxs(v,{variant:"secondary",className:"text-[10px] bg-emerald-500/15 text-emerald-700",children:["applied: ",s.applied]}),e.jsxs(v,{variant:"secondary",className:"text-[10px] bg-destructive/10 text-destructive",children:["rejected: ",s.rejected]}),e.jsxs(v,{variant:"outline",className:"text-[10px]",children:["общо: ",s.total]})]})]}),e.jsxs("div",{className:"flex flex-col sm:flex-row gap-1 shrink-0",children:[e.jsxs(z,{size:"sm",variant:"outline",className:"h-7 text-xs",onClick:()=>{W(s.resource_id),p(0),Y()},title:"Филтрирай списъка по този ресурс",children:[e.jsx(Xe,{className:"h-3 w-3 mr-1"})," Филтрирай"]}),e.jsxs(z,{size:"sm",variant:"outline",className:"h-7 text-xs",onClick:()=>S({resourceId:s.resource_id,resourceTitle:s.resource_title}),title:"Преглед на патчовете спрямо текущото състояние",children:[e.jsx(at,{className:"h-3 w-3 mr-1"})," Преглед"]}),e.jsxs(z,{size:"sm",variant:"ghost",className:"h-7 text-xs",disabled:E.length===0,onClick:()=>dt(s.resource_id),title:"Скрол към лога с филтър по resource_id",children:[e.jsx(He,{className:"h-3 w-3 mr-1"})," Логове"]})]})]},s.resource_id)})})})]}),e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-2 rounded-md border border-border bg-muted/30 px-3 py-2",children:[e.jsxs("div",{className:"flex items-center gap-3 text-sm",children:[e.jsxs("label",{className:"inline-flex items-center gap-2",children:[e.jsx("input",{type:"checkbox",className:"h-4 w-4 rounded border-border accent-primary",checked:Me,onChange:ut,disabled:ve.length===0}),e.jsx("span",{children:"Маркирай всички text patches на страницата"})]}),e.jsxs(v,{variant:"secondary",children:[o.size," избрани"]}),e.jsxs(v,{variant:"outline",children:["общо ",f]})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsxs(z,{size:"sm",disabled:o.size===0,onClick:()=>Ve("approved"),children:[e.jsx($t,{className:"h-4 w-4 mr-1"})," Bulk одобри…"]}),e.jsxs(z,{size:"sm",variant:"outline",disabled:o.size===0,onClick:()=>Ve("rejected"),children:[e.jsx(At,{className:"h-4 w-4 mr-1"})," Bulk отхвърли…"]})]})]}),r?e.jsxs("div",{className:"flex items-center justify-center py-12 text-muted-foreground",children:[e.jsx(Ke,{className:"h-5 w-5 animate-spin mr-2"})," Зареждане…"]}):i.length===0?e.jsx(xe,{children:e.jsxs(pe,{className:"py-10 text-center text-muted-foreground",children:["Няма корекции по тези филтри. Стартирай Phase A в ",e.jsx(ze,{to:"/admin/quality-audit",className:"underline",children:"Quality Audit"})," за да генерираш патчове."]})}):e.jsx("div",{className:"space-y-3",children:i.map(s=>{const n=we(s.id,s.patch_index);return e.jsx(Jt,{row:s,selected:o.has(n),onToggleSelect:()=>_(m=>{const x=new Set(m);return x.has(n)?x.delete(n):x.add(n),x}),onApprove:m=>ke([s.id],"approved",m),onReject:m=>ke([s.id],"rejected",m),onPreview:()=>S({resourceId:s.resource_id,resourceTitle:s.resource_title}),busy:c.has(s.id)},n)})}),$e>1&&e.jsxs("div",{className:"flex items-center justify-center gap-2",children:[e.jsx(z,{size:"sm",variant:"outline",disabled:w===0,onClick:()=>p(s=>Math.max(0,s-1)),children:"← Предишна"}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:["Стр. ",w+1," / ",$e]}),e.jsx(z,{size:"sm",variant:"outline",disabled:w+1>=$e,onClick:()=>p(s=>s+1),children:"Следваща →"})]}),e.jsx(Ee,{open:!!k,onOpenChange:s=>!s&&_e(null),children:e.jsxs(qe,{className:"max-w-2xl max-h-[85vh] overflow-hidden flex flex-col",children:[e.jsxs(Le,{children:[e.jsxs(Oe,{children:[(k==null?void 0:k.decision)==="approved"?"Одобри":"Отхвърли"," ",k==null?void 0:k.findingIds.length," ",(k==null?void 0:k.findingIds.length)===1?"находка":"находки",k&&k.rows.length!==k.findingIds.length&&e.jsxs("span",{className:"ml-1 text-sm font-normal text-muted-foreground",children:["(",k.rows.length," patches)"]})]}),e.jsx(Be,{children:"Преглед по текущите филтри и избор. Code patches са изключени от bulk операцията."})]}),e.jsx("div",{className:"flex-1 min-h-0 overflow-auto rounded-md border border-border bg-muted/20 p-2",children:k&&(()=>{const s=new Map;for(const n of k.rows){const m=s.get(n.resource_id)??[];m.push(n),s.set(n.resource_id,m)}return e.jsx("ul",{className:"text-sm space-y-1.5",children:Array.from(s.entries()).map(([n,m])=>e.jsxs("li",{className:"flex items-start gap-2 py-1 border-b border-border/40 last:border-0",children:[e.jsx(v,{variant:"outline",className:"font-mono text-[10px] shrink-0",children:n}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("div",{className:"truncate font-medium",children:m[0].resource_title??n}),e.jsx("div",{className:"flex flex-wrap gap-1 mt-0.5",children:m.map((x,$)=>e.jsxs(v,{variant:"secondary",className:"text-[10px] font-mono",title:`${x.patch.patch_target} · ${x.patch.confidence}`,children:[x.patch.patch_target.split(".").pop()," · ",x.patch.confidence]},$))})]})]},n))})})()}),(k==null?void 0:k.decision)==="rejected"&&e.jsxs("div",{className:"space-y-1",children:[e.jsx("label",{className:"text-xs text-muted-foreground",children:"БелеÐ
2¶ÐºÐ° (задължителна)"}),e.jsx(Pe,{value:ue,onChange:s=>Ce(s.target.value),placeholder:"Защо отхвърляш тези корекции?",className:"min-h-[60px]"})]}),(k==null?void 0:k.decision)==="approved"&&e.jsxs("div",{className:"space-y-1",children:[e.jsx("label",{className:"text-xs text-muted-foreground",children:"Бележка (по желание)"}),e.jsx(Pe,{value:ue,onChange:s=>Ce(s.target.value),placeholder:"Опционална бележка",className:"min-h-[40px]"})]}),e.jsxs(Te,{children:[e.jsx(z,{variant:"outline",onClick:()=>_e(null),children:"Отказ"}),e.jsxs(z,{variant:(k==null?void 0:k.decision)==="rejected"?"destructive":"default",onClick:mt,disabled:(k==null?void 0:k.decision)==="rejected"&&!ue.trim(),children:["Потвърди ",(k==null?void 0:k.decision)==="approved"?"одобрение":"отхвърляне"]})]})]})}),e.jsx(Yt,{open:!!X,onOpenChange:s=>{s||S(null)},resourceId:(X==null?void 0:X.resourceId)??null,resourceTitle:(X==null?void 0:X.resourceTitle)??null,patches:X?i.filter(s=>s.resource_id===X.resourceId).map(s=>s.patch):[]})]})};export{js 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.