import { Fragment, useEffect, useState } from "react"; const EVERY = 60 * 1000; const LINE = /^(\S+)\s+(DEBUG|INFO|WARNING|ERROR|CRITICAL)\s+(.*)$/; export const when = (seconds) => (seconds ? new Date(seconds * 1000).toISOString().replace("T", " ").slice(0, 19) + " UTC" : "never"); export const ago = (seconds) => { if (!seconds) return "never"; const gap = Math.max(0, Math.floor(Date.now() / 1000 - seconds)); if (gap < 90) return `${gap} s ago`; if (gap < 5400) return `${Math.round(gap / 60)} min ago`; if (gap < 172800) return `${(gap / 3600).toFixed(1)} h ago`; return `${Math.round(gap / 86400)} d ago`; }; export const bytes = (n) => (n == null ? "" : n < 1e6 ? `${(n / 1e3).toFixed(0)} kB` : n < 1e9 ? `${(n / 1e6).toFixed(1)} MB` : `${(n / 1e9).toFixed(2)} GB`); async function grab(path) { try { const reply = await fetch(path, { cache: "no-store" }); return reply.ok ? await reply.json() : null; } catch { return null; } } export function useMirror(path) { const [seen, setSeen] = useState(null); useEffect(() => { let live = true; let timer = 0; const refresh = async () => { const data = await grab(path); if (live) setSeen({ data }); }; const run = () => { clearInterval(timer); if (document.hidden) return; void refresh(); timer = setInterval(refresh, EVERY); }; document.addEventListener("visibilitychange", run); run(); return () => { live = false; clearInterval(timer); document.removeEventListener("visibilitychange", run); }; }, [path]); return seen; } export function Waiting({ seen }) { return

{seen ? "No data yet." : "Loading"}

; } export function Rows({ list }) { return ( {list.map(([name, value]) => ( ))}
{name} {String(value ?? "")}
); } export function Code({ lines }) { return (
      
        {lines.map((line, i) => {
          const hit = LINE.exec(line);
          return (
            
              {hit ? (
                
                  {hit[1]} {hit[2].padEnd(7)} {hit[3]}
                
              ) : (
                {line}
              )}
              {i < lines.length - 1 ? "\n" : null}
            
          );
        })}
      
    
); }