1import{r as h,j as e}from"./vendor-react-EtBdcxzB.js";import{S as y}from"./SectionLabel-Bc9A66bh.js";import{c as g,O as E,Q as R,X as I,Y as M,Z as L,b as F,_ as z}from"./main-nkazyCpV.js";import{C as j}from"./CollapsibleCard-BlPI6jw9.js";import{D as O}from"./DataErrorState-D9g-1Bbk.js";import{D as _}from"./database-KKQsM2Ma.js";import{A as H}from"./activity-Bsv7zWa6.js";import"./minimize-2-BXJshPtz.js";/** 2 * @license lucide-react v0.469.0 - ISC 3 * 4 * This source code is licensed under the ISC license. 5 * See the LICENSE file in the root directory of this source tree. 6 */const P=g("CornerLeftUp",[["polyline",{points:"14 9 9 4 4 9",key:"m9oyvo"}],["path",{d:"M20 20h-7a4 4 0 0 1-4-4V4",key:"1blwi3"}]]);/** 7 * @license lucide-react v0.469.0 - ISC 8 * 9 * This source code is licensed under the ISC license. 10 * See the LICENSE file in the root directory of this source tree. 11 */const U=g("HardDrive",[["line",{x1:"22",x2:"2",y1:"12",y2:"12",key:"1y58io"}],["path",{d:"M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z",key:"oot6mr"}],["line",{x1:"6",x2:"6.01",y1:"16",y2:"16",key:"sgf278"}],["line",{x1:"10",x2:"10.01",y1:"16",y2:"16",key:"1l4acy"}]]);/** 12 * @license lucide-react v0.469.0 - ISC 13 * 14 * This source code is licensed under the ISC license. 15 * See the LICENSE file in the root directory of this source tree. 16 */const B=g("KeyRound",[["path",{d:"M2.586 17.414A2 2 0 0 0 2 18.828V21a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h1a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h.172a2 2 0 0 0 1.414-.586l.814-.814a6.5 6.5 0 1 0-4-4z",key:"1s6t7t"}],["circle",{cx:"16.5",cy:"7.5",r:".5",fill:"currentColor",key:"w0ekpg"}]]);/** 17 * @license lucide-react v0.469.0 - ISC 18 * 19 * This source code is licensed under the ISC license. 20 * See the LICENSE file in the root directory of this source tree. 21 */const V=g("RefreshCcw",[["path",{d:"M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",key:"14sxne"}],["path",{d:"M3 3v5h5",key:"1xhq8a"}],["path",{d:"M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16",key:"1hlbsb"}],["path",{d:"M16 16h5v5",key:"ccwih5"}]]),v="adminToken",k=new Set,S=()=>{try{return localStorage.getItem(v)||""}catch{return""}},w=s=>{try{s?localStorage.setItem(v,s):localStorage.removeItem(v)}catch{}k.forEach(l=>l())},q=s=>(k.add(s),()=>k.delete(s)),K=s=>!!s&&(s.code==="unauthorized"||/token inválido|admin no configurado/i.test(s.message||"")),Y=()=>"";function A(){return h.useSyncExternalStore(q,S,Y)}function J({children:s}){const l=A(),[a,d]=h.useState("");return l?s:e.jsxs("div",{className:"max-w-md mx-auto mt-12 rounded-xl border border-border bg-card p-6",children:[e.jsxs("h2",{className:"flex items-center gap-2 text-sm font-semibold mb-3",children:[e.jsx(B,{className:"h-4 w-4 text-primary"})," Panel de administración"]}),e.jsxs("p",{className:"text-sm text-muted-foreground mb-4",children:["Introduce el token de administración (",e.jsx("code",{children:"CACHE_SECRET"}),")."]}),e.jsxs("form",{onSubmit:n=>{n.preventDefault(),w(a.trim())},className:"flex gap-2",children:[e.jsx("input",{type:"password",value:a,onChange:n=>d(n.target.value),placeholder:"Token",autoFocus:!0,className:"flex-1 rounded-md border border-border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-primary"}),e.jsx("button",{type:"submit",disabled:!a.trim(),className:"rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground disabled:opacity-50",children:"Entrar"})]})]})}function W(){const s=A();return s?e.jsxs("div",{className:"flex items-center justify-end text-xs text-muted-foreground",children:["token ",s.length>8?`····${s.slice(-4)}`:"········",e.jsx("button",{className:"ml-2 underline",onClick:()=>w(""),children:"salir"})]}):null}const $=s=>({"X-Admin-Token":s??""}),D=(s,l={},a)=>E(R(s,l),{headers:$(a)});async function X(s,l={},a){const d=I("admin.php");d.searchParams.set("action",s),Object.entries(l).forEach(([n,o])=>d.searchParams.set(n,o));try{return await E(d.toString(),{headers:$(a),timeoutMessage:"La petición ha tardado demasiado (el refresh puede seguir corriendo en el servidor).",unwrapData:!1})}catch(n){throw n.status===401&&(n.code="unauthorized"),n}}const G=([s,{token:l,...a}])=>D(s,a,l);function p(s,l,a){const d=A(),n=M(d&&s?[s,{token:d,...l||{}}]:null,G,{revalidateOnFocus:!1,revalidateIfStale:!1,keepPreviousData:!0,...a});let o=null;return s&&(K(n.error)?o="auth":n.data||(o=n.error?"error":"loading")),{...n,blockingState:o}}const Q=()=>e.jsxs("div",{className:"rounded-xl border border-border bg-card/50 p-5 animate-pulse",children:[e.jsx("div",{className:"h-4 w-56 rounded bg-muted-foreground
21/15 mb-3"}),e.jsx("div",{className:"h-[120px] rounded bg-muted-foreground/8"})]}),Z=()=>e.jsxs("div",{className:"text-sm text-muted-foreground",children:["Token inválido."," ",e.jsx("button",{className:"underline text-primary",onClick:()=>w(""),children:"Introducir otro token"})]});function f({state:s,onRetry:l}){return s==="auth"?e.jsx(Z,{}):s==="error"?e.jsx(O,{onRetry:l}):e.jsx(Q,{})}const C=s=>String(Math.round(s*10)/10).replace(".",",");function b(s){return s==null?"â":s<90?`${Math.round(s)} s`:s<5400?`${Math.round(s/60)} min`:s<129600?`${C(s/3600)} h`:`${C(s/86400)} d`}function ee(){const{data:s,mutate:l,blockingState:a}=p("clear-cache"),[d,n]=h.useState(null),[o,c]=h.useState(null);if(a)return e.jsx(f,{state:a,onRetry:()=>l()});const i=async t=>{const x=t==="all"?"TODAS las cachés":`la caché "${t}"`,u=t==="all"?" El monitor de frescura queda silenciado ~90 min para que los crons horarios repueblen sin disparar una alerta.":"";if(window.confirm(`¿Borrar ${x}? Se regenerará en el siguiente fetch/cron.${u}`)){n(t),c(null);try{await D("clear-cache",{key:t},S()),c(`Borrada: ${t}`),t==="all"?l():l(m=>(m??[]).filter(T=>T.key!==t),{revalidate:!1})}catch(m){c(`Error: ${m.message}`)}finally{n(null)}}},r=s;return e.jsxs(j,{cardId:"admin-caches",className:"glass",title:e.jsxs(e.Fragment,{children:[e.jsx(_,{className:"h-4 w-4 text-primary"})," Cachés de providers · ",r.length]}),children:[o&&e.jsx("p",{className:"mb-2 text-xs text-muted-foreground",children:o}),e.jsx("div",{className:"overflow-x-auto max-h-96 overflow-y-auto",children:e.jsxs("table",{className:"w-full text-xs",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"text-left text-muted-foreground sticky top-0 bg-card",children:[e.jsx("th",{className:"py-1 pr-2",children:"Clave"}),e.jsx("th",{className:"py-1 pr-2",children:"Tamaño"}),e.jsx("th",{className:"py-1 pr-2",children:"Edad real"}),e.jsx("th",{className:"py-1"})]})}),e.jsx("tbody",{children:r.map(t=>e.jsxs("tr",{className:"border-t border-border/50",children:[e.jsx("td",{className:"py-1 pr-2 font-mono",children:t.key}),e.jsx("td",{className:"py-1 pr-2",children:t.size}),e.jsx("td",{className:"py-1 pr-2",title:t.age_source==="internal"?t.updated:t.modified?`~mtime ${t.modified} (sin timestamp interno; el deploy resetea mtimes)`:"sin ninguna marca de tiempo",children:t.age_min==null?"â":`${t.age_source==="mtime"?"~":""}${b(t.age_min*60)}`}),e.jsx("td",{className:"py-1 text-right",children:e.jsx("button",{className:"text-muted-foreground hover:text-red-500 disabled:opacity-40",disabled:d!==null,onClick:()=>i(t.key),title:`Borrar cache_${t.key}.json`,children:e.jsx(L,{className:"h-3.5 w-3.5"})})})]},t.key))})]})}),e.jsx("div",{className:"mt-3 text-right",children:e.jsx("button",{className:"text-xs text-red-400 underline disabled:opacity-40",disabled:d!==null,onClick:()=>i("all"),children:"Vaciar todas"})})]})}function se(){var x;const[s,l]=h.useState(null),{data:a,mutate:d,blockingState:n}=p("cron-status"),o=p(s?"cron-status":null,{log:s});if(n)return e.jsx(f,{state:n,onRetry:()=>d()});const c=Object.entries(a.logs??{}),i=s&&o.data?(x=o.data.logs)==null?void 0:x[s]:void 0,r=i==null?void 0:i.tail,t=s&&o.data!=null&&!o.isLoading;return e.jsxs(j,{cardId:"admin-crons",className:"glass",title:e.jsxs(e.Fragment,{children:[e.jsx(F,{className:"h-4 w-4 text-primary"})," Crons ·"," ",e.jsx("span",{className:a.cronRunning?"text-emerald-500":"text-red-500",children:a.cronRunning?`daemon vivo (pid ${a.cronPid})`:"daemon CAÃDO"})]}),children:[a.cronDefUnavailable&&e.jsx("p",{className:"mb-2 text-xs text-amber-500",children:"No se pudo leer /etc/cron.d/dashboard â la detección de logs esperados-pero-ausentes está ciega."}),e.jsxs("div",{className:"flex flex-wrap gap-1.5 mb-3",children:[c.map(([u,m])=>e.jsx("button",{onClick:()=>l(s===u?null:u),disabled:m.missing,title:m.missing?"Esperado por el crontab pero AUSENTE en disco":m.orphan?`Huérfano: existe pero ningún cron activo lo referencia · ${m.size} · ${m.modified}`:`${m.size} · ${m.modified}`,className:`rounded-full border px-2 py-0.5 text-xs ${m.missing?"border-red-500/50 text-red-400 cursor-not-allowed":s===u?"border-primary bg-primary/10 text-primary":m.orphan?"border-border border-dashed text-muted-foreground
21/70 hover:border-primary/50":"border-border text-muted-foreground hover:border-primary/50"}`,children:u.replace(/-cron$/,"")},u)),c.length===0&&e.jsx("p",{className:"text-sm text-muted-foreground",children:"Sin logs â entorno local sin flota de crons."})]}),s&&o.error&&e.jsxs("p",{className:"text-xs text-red-400",children:["Error cargando ",s,": ",o.error.message," ",e.jsx("button",{className:"underline",onClick:()=>o.mutate(),children:"reintentar"})]}),s&&!t&&!o.error&&e.jsxs("p",{className:"text-xs text-muted-foreground animate-pulse",children:["Cargando ",s,"â¦"]}),t&&!i&&e.jsxs("p",{className:"text-xs text-amber-500",children:["El log ",s," ya no existe en disco (¿rotado?)."]}),i&&e.jsx("pre",{className:"max-h-72 overflow-auto rounded-md border border-border bg-background/60 p-3 text-[11px] leading-relaxed whitespace-pre-wrap",children:r===""?"(log vacÃo â el cron aún no ha escrito nada)":r})]})}const te=[{action:"empleo-update",label:"Empleo + IPC (SEPE/SADEI/INE)"},{action:"demografia-update",label:"DemografÃa (INE)"},{action:"infraestructuras-update",label:"Infraestructuras (SETELECO)"}],ae=s=>X(s,{dataset:"all"},S());function re(){const{data:s,mutate:l,blockingState:a}=p("data-health"),[d,n]=h.useState(null),[o,c]=h.useState(null);if(a)return e.jsx(f,{state:a,onRetry:()=>l()});const i=Object.entries(s.datasets??{}).filter(([,t])=>t.anchor==="meta"),r=async(t,x)=>{if(window.confirm(`¿Refrescar ${x}? Descarga de las fuentes oficiales (puede tardar).`)){n(t),c(null);try{const u=await ae(t);c({label:x,json:u})}catch(u){c({label:x,json:{ok:!1,error:u.message}})}finally{n(null)}}};return e.jsxs(j,{cardId:"admin-datasets",className:"glass",title:e.jsxs(e.Fragment,{children:[e.jsx(V,{className:"h-4 w-4 text-primary"})," Datasets de refresh manual"]}),children:[e.jsx("ul",{className:"mb-3 space-y-1 text-sm",children:i.map(([t,x])=>e.jsxs("li",{className:"flex items-center justify-between gap-2",children:[e.jsx("span",{children:x.label}),e.jsx("span",{className:"text-xs text-muted-foreground",children:x.iso?x.iso.slice(0,10):"sin fecha"})]},t))}),e.jsx("div",{className:"flex flex-wrap gap-2",children:te.map(t=>e.jsx("button",{disabled:d!==null,onClick:()=>r(t.action,t.label),className:"rounded-md border border-border px-3 py-1.5 text-xs hover:border-primary/50 disabled:opacity-40",children:d===t.action?"Refrescandoâ¦":t.label},t.action))}),o&&e.jsxs("pre",{className:"mt-3 max-h-60 overflow-auto rounded-md border border-border bg-background/60 p-3 text-[11px] whitespace-pre-wrap",children:[o.label,": ",JSON.stringify(o.json,null,2)]})]})}function ne(){const[s,l]=h.useState(null),{data:a,error:d,isLoading:n,mutate:o,blockingState:c}=p("disk-usage",s?{dir:s}:void 0);if(c)return e.jsx(f,{state:c,onRetry:()=>o()});const i=n;return e.jsxs(j,{cardId:"admin-disco",className:"glass",title:e.jsxs(e.Fragment,{children:[e.jsx(U,{className:"h-4 w-4 text-primary"})," Volumen · ",a.totalSizeH," en ",a.totalFiles," ficheros"]}),children:[e.jsxs("p",{className:"mb-2 text-xs text-muted-foreground",children:[a.path," â libre ",a.diskFree," de ",a.diskTotal]}),s&&e.jsxs("button",{className:"mb-2 flex items-center gap-1 text-xs text-primary underline",onClick:()=>l(null),children:[e.jsx(P,{className:"h-3 w-3"})," Volver a la raÃz (",s,")"]}),d&&e.jsxs("p",{className:"mb-2 text-xs text-red-400",children:["Error al cargar «",s??"raÃz","»: ",d.message," â mostrando el último listado válido."]}),i&&e.jsxs("p",{className:"mb-2 text-xs text-muted-foreground animate-pulse",children:["Cargando ",s??"raÃz","â¦"]}),e.jsx("div",{className:"overflow-x-auto max-h-96 overflow-y-auto",children:e.jsxs("table",{className:"w-full text-xs",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"text-left text-muted-foreground sticky top-0 bg-card",children:[e.jsx("th",{className:"py-1 pr-2",children:"Entrada"}),e.jsx("th",{className:"py-1 pr-2",children:"Tamaño"}),e.jsx("th",{className:"py-1 pr-2",children:"Ficheros"}),e.jsx("th",{className:"py-1",children:"Más reciente"})]})}),e.jsx("tbody",{children:(a.entries??[]).map(r=>e.jsxs("tr",{className:"border-t border-border/50",children:[e.jsx("td",{className:"py-1 pr-2 font-mono",children:r.name.endsWith("/")?e.jsx("button",{className:"underline decoration-dotted disabled:opacity-40 disabled:no-underline",disabled:i,onClick:()=>{const t=r.name.replace(/\/$/,"");l(s?`${s}/${t}`:t)},children:r.name}):r.name}),e.jsx("td",{className:"py-1 pr-2",children:r.sizeH}),e.jsx("td",{className:"py-1 pr-2",children:r.files}),e.jsx("td",{className:"py-1 text-muted-foreground",children:r.newest??"â"})]},r.name))})]})})]})}function le(){const{data:s,mutate:l,blockingState:a}=p("newsletter-list");if(a)return e.jsx(f,{state:a,onRetry:()=>l()});const d=s.subscribers??[];return e.jsx(j,{cardId:"admin-newsletter",className:"glass",title:e.jsxs(e.Fragment,{children:[e.jsx(z,{className:"h-4 w-4 text-primary"})," Newsletter · ",s.active," activos de ",s.total]}),children:d.length>0?e.jsx("div",{className:"max-h-72 overflow-y-auto",children:e.jsxs("table",{className:"w-full text-xs",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"text-left text-muted-foreground sticky top-0 bg-card",children:[e.jsx("th",{className:"py-1 pr-2",children:"Email"}),e.jsx("th",{className:"py-1 pr-2",children:"Alta"}),e.jsx("th",{className:"py-1",children:"Estado"})]})}),e.jsx("tbody",{children:d.map(n=>e.jsxs("tr",{className:"border-t border-border/50",children:[e.jsx("td",{className:"py-1 pr-2",children:n.email}),e.jsx("td",{className:"py-1 pr-2 text-muted-foreground",children:(n.subscribedAt??"").slice(0,10)}),e.jsx("td",{className:"py-1",children:n.active?"activo":"baja"})]},n.email))})]})}):e.jsx("p",{className:"text-sm text-muted-foreground",children:"Sin suscriptores todavÃa."})})}const N={ok:{dot:"bg-emerald-500",label:"ok"}
21,info:{dot:"bg-sky-400",label:"info"},stale:{dot:"bg-amber-500",label:"rancio"},missing:{dot:"bg-red-500",label:"sin dato"}};function de(){var c;const{data:s,mutate:l,blockingState:a}=p("data-health");if(a)return e.jsx(f,{state:a,onRetry:()=>l()});const d=Object.entries(s.datasets??{}),n=d.filter(([,i])=>i.state==="stale"||i.state==="missing"),o=s.pct>=90?"text-emerald-500":s.pct>=60?"text-amber-500":"text-red-500";return e.jsxs(j,{cardId:"admin-salud",className:"glass",title:e.jsxs(e.Fragment,{children:[e.jsx(H,{className:"h-4 w-4 text-primary"})," Salud de datos (servidor) · ",e.jsxs("span",{className:o,children:[s.pct,"%"]})," (",s.score,")"]}),children:[((c=s.criticalStale)==null?void 0:c.length)>0&&e.jsxs("div",{className:"mb-3 rounded-md border border-red-500/30 bg-red-500/10 px-3 py-2 text-sm",children:[e.jsxs("strong",{children:[s.criticalStale.length," crÃticos rancios:"]})," ",s.criticalStale.map(i=>{var r;return((r=s.datasets[i])==null?void 0:r.label)??i}).join(", ")]}),n.length>0&&e.jsx("ul",{className:"mb-3 space-y-1 text-sm",children:n.map(([i,r])=>e.jsxs("li",{className:"flex items-center gap-2",children:[e.jsx("span",{className:`h-2 w-2 rounded-full shrink-0 ${N[r.state].dot}`}),e.jsx("span",{className:"font-medium",children:r.label}),e.jsxs("span",{className:"text-muted-foreground",children:[r.state==="missing"?"ancla ausente":`hace ${b(r.ageSeconds)} (máx ${b(r.maxAgeSeconds)})`,r.critical&&" · crÃtico"]})]},i))}),e.jsxs("details",{className:"text-sm",children:[e.jsxs("summary",{className:"cursor-pointer text-muted-foreground",children:["Los ",d.length," datasets"]}),e.jsx("div",{className:"mt-2 overflow-x-auto",children:e.jsxs("table",{className:"w-full text-xs",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"text-left text-muted-foreground",children:[e.jsx("th",{className:"py-1 pr-2",children:"Dataset"}),e.jsx("th",{className:"py-1 pr-2",children:"Estado"}),e.jsx("th",{className:"py-1 pr-2",children:"Edad"}),e.jsx("th",{className:"py-1 pr-2",children:"Máx"}),e.jsx("th",{className:"py-1",children:"Ancla"})]})}),e.jsx("tbody",{children:d.map(([i,r])=>e.jsxs("tr",{className:"border-t border-border/50",children:[e.jsxs("td",{className:"py-1 pr-2",children:[r.label,r.critical&&e.jsx("span",{className:"text-red-400",children:" *"})]}),e.jsx("td",{className:"py-1 pr-2",children:e.jsxs("span",{className:"inline-flex items-center gap-1.5",children:[e.jsx("span",{className:`h-1.5 w-1.5 rounded-full ${N[r.state].dot}`}),N[r.state].label]})}),e.jsx("td",{className:"py-1 pr-2",children:b(r.ageSeconds)}),e.jsx("td",{className:"py-1 pr-2",children:b(r.maxAgeSeconds)}),e.jsx("td",{className:"py-1 text-muted-foreground",children:r.anchor})]},i))})]})})]}),e.jsxs("div",{className:"mt-3 flex items-center justify-between text-xs text-muted-foreground",children:[e.jsxs("span",{children:["Evaluado: ",s.generatedAt]}),e.jsx("button",{className:"underline",onClick:()=>l(),children:"Reevaluar"})]})]})}function je(){return e.jsx(J,{children:e.jsxs("div",{className:"space-y-4",children:[e.jsx(W,{}),e.jsx(de,{}),e.jsx(y,{children:"Cachés y disco"}),e.jsx(ee,{}),e.jsx(ne,{}),e.jsx(y,{children:"Crons"}),e.jsx(se,{}),e.jsx(y,{children:"Datasets y newsletter"}),e.jsx(re,{}),e.jsx(le,{})]})})}export{je 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.