import { useState } from "react" import { cn } from "cn" import { Bestaetigen } from "@/components/cockpit/Bestaetigen" import { Chip, type ChipArt, Zustandsfeld } from "@/components/cockpit/Chip" import { Panel } from "@/components/cockpit/Panel" import { Button } from "@/components/ui/button" import { type UpdateLauf, useFreigeben, useJetztSichern, useJobs, useSicherungen, useStart, useUpdateDetails, useUpdateStarten, useUpdateVerlauf, useZurueckspielen, } from "@/lib/abfragen" import { versionen } from "@/lib/anzeige" import type { Festgehalten, Job, Sicherung } from "@/lib/typen" import { flugplanZeit } from "@/lib/zeit" const BAUSTEINE = [ { id: "os", name: "Betriebssystem" }, { id: "engine", name: "Motor (llama.cpp)" }, { id: "swap", name: "llama-swap" }, { id: "hermes", name: "Hermes" }, ] as const function BausteinZeile({ id, name, hatUpdate, fest, onStart, onFreigeben, laeuftGerade }: { id: string name: string hatUpdate: boolean fest: Festgehalten | undefined onStart: () => void onFreigeben: () => void laeuftGerade: boolean }) { const { data, isPending } = useUpdateDetails(id) const v = versionen(id, data) const neu = hatUpdate ? v.neu ?? "neu" : null const was = !hatUpdate ? "Aktuell." : data?.summary?.trim() || (id === "os" && data?.count ? "Paketliste unten in den Details." : isPending ? "Wird gelesen …" : "") return ( {name} {v.laeuft} {neu ? {neu} : } {fest && ( Festgehalten seit {fest.seit} auf {fest.version}: {fest.grund}. Der Sonntags-Lauf überspringt {name}. )} {was} {fest && ( )} {hatUpdate && ( )} ) } const LAUF_ART: Record = { rot: "rot", gelb: "bernstein", gruen: "gruen", info: "cyan", grau: "grau", } const PUNKT: Record = { rot: "bg-rot", gelb: "bg-bernstein", gruen: "bg-gruen", info: "bg-cyan", grau: "bg-text-3", } /** Ein Update-Lauf mit dem Ergebnis je Baustein — so, wie autoupdate.sh es gemeldet hat. */ function LaufEintrag({ lauf }: { lauf: UpdateLauf }) { return (
  • {flugplanZeit(lauf.start)} {lauf.anlass} {lauf.titel}
    {lauf.stufe !== "grau" && lauf.zeilen.length > 0 && (
      {lauf.zeilen.map((z) => (
    • {z.baustein} · {z.text}
    • ))}
    )}
  • ) } function JobKasten({ job }: { job: Job & { group?: string; log?: string[] } }) { const art = job.state === "done" ? "gruen" : job.state === "failed" ? "rot" : "cyan" const text = job.state === "done" ? "Fertig" : job.state === "failed" ? "Fehler" : job.state === "queued" ? "Wartet" : "Läuft" return (
    {job.label} {text}
    {job.log && job.log.length > 0 && (
              {job.log.slice(-8).join("\n")}
            
    )}
    ) } function sicherungsZeit(s: Sicherung) { return s.mtime ? flugplanZeit(new Date(s.mtime * 1000).toISOString()) : s.snapshot } export function UpdatesSeite() { const start = useStart() const jobs = useJobs() const verlauf = useUpdateVerlauf() const sicherungen = useSicherungen() const updateStarten = useUpdateStarten() const freigeben = useFreigeben() const sichern = useJetztSichern() const zurueck = useZurueckspielen() const [frage, setFrage] = useState(null) const mitUpdate = new Set(start.data?.updates.bausteine.map((b) => b.id) ?? []) const festgehalten = new Map((start.data?.updates.festgehalten ?? []).map((f) => [f.baustein, f])) const wartungsJobs = (jobs.data?.jobs ?? []).filter((j) => (j as { group?: string }).group === "maintenance") const laeuft = wartungsJobs.some((j) => j.state === "running" || j.state === "queued") return ( <> } >

    Jeden Sonntag um 04:30 automatisch. Vorher wird gesichert, danach geprüft.

    {start.isPending ? ( ) : (
    {BAUSTEINE.map((b) => ( updateStarten.mutate(b.id)} onFreigeben={() => freigeben.mutate(b.id)} /> ))}
    Baustein Läuft Neu Was sich ändert Aktion
    )} {wartungsJobs.length > 0 && (

    Laufende und letzte Aufträge

    {wartungsJobs.slice(-3).reverse().map((j) => )}
    )}
    {verlauf.data?.laeufe.length ? (
      {verlauf.data.laeufe.map((l) => )}
    ) : (

    {verlauf.isPending ? "Wird gelesen …" : "Noch keine Update-Läufe aufgezeichnet."}

    )}
    sichern.mutate(undefined)} disabled={sichern.isPending}> Jetzt sichern } >

    Täglich um 03:35, mit Kopie auf einem zweiten Gerät.

      {(sicherungen.data?.backups ?? []).slice(0, 5).map((s) => (
    • {sicherungsZeit(s)} {s.size_mb.toLocaleString("de-DE")} MB
    • ))}
    setFrage(null)} onJa={() => { updateStarten.mutate("alle") setFrage(null) }} /> setFrage(null)} onJa={() => { if (frage?.art === "zurueck") zurueck.mutate(frage.datei) setFrage(null) }} /> ) }