diff --git a/frontend/src/components/cockpit/Flugplan.tsx b/frontend/src/components/cockpit/Flugplan.tsx index 05fa8df..79decd6 100644 --- a/frontend/src/components/cockpit/Flugplan.tsx +++ b/frontend/src/components/cockpit/Flugplan.tsx @@ -8,18 +8,21 @@ const STATUS: Record geplant: { text: "Geplant", farbe: "text-text-3" }, } +// Die Liste richtet sich nach der Breite ihres Feldes, nicht des Bildschirms (@container): Schmal — +// am Handy und in der rechten Spalte bei 1024 px — stehen Zeit und Zustand oben, der Text darunter +// über die volle Breite. Vorher bekam der Text dort ~50 px und lief in den Zustand hinein. function Zeile({ e }: { e: FlugplanEintrag }) { const s = STATUS[e.status] ?? STATUS.geplant // Updates sind das Wichtigste im Plan — sie stehen in Cyan. const farbe = e.status === "geplant" && /update/i.test(e.titel) ? "text-cyan" : s.farbe return ( -
  • - {flugplanZeit(e.zeit)} - +
  • + {flugplanZeit(e.zeit)} + {e.titel} {e.text && , {e.text}} - {s.text} + {s.text}
  • ) } @@ -27,5 +30,5 @@ function Zeile({ e }: { e: FlugplanEintrag }) { export function Flugplan({ gelaufen, geplant }: { gelaufen: FlugplanEintrag[]; geplant: FlugplanEintrag[] }) { const alle = [...gelaufen, ...geplant.slice(0, 5)] if (alle.length === 0) return

    Heute ist noch nichts gelaufen, und nichts ist geplant.

    - return
      {alle.map((e) => )}
    + return
      {alle.map((e) => )}
    } diff --git a/frontend/src/components/cockpit/JobKarte.tsx b/frontend/src/components/cockpit/JobKarte.tsx index a785342..c404221 100644 --- a/frontend/src/components/cockpit/JobKarte.tsx +++ b/frontend/src/components/cockpit/JobKarte.tsx @@ -1,4 +1,5 @@ import { useState } from "react" +import { cn } from "cn" import { Button } from "@/components/ui/button" import { laeuftNoch } from "@/lib/anzeige" import { abbrechbar, fortschrittText, jobDownload, jobTitel, laufText, letzteMeldung } from "@/lib/wartung" @@ -15,6 +16,10 @@ const ZUSTAND: Record = { canceled: { text: "Abgebrochen", art: "grau" }, } +const BALKEN: Record = { + queued: "bg-cyan", running: "bg-cyan", done: "bg-gruen", failed: "bg-rot", canceled: "bg-text-3", +} + const zeitVon = (sekunden: number) => flugplanZeit(new Date(sekunden * 1000).toISOString()) /** @@ -53,7 +58,7 @@ export function JobKarte({ job, onAbbrechen, abbrechenGesperrt }: { className="h-2 overflow-hidden rounded-full bg-linie" >
    @@ -105,6 +110,7 @@ export function JobKarte({ job, onAbbrechen, abbrechenGesperrt }: { neinKnopf="Weiterlaufen lassen" onNein={() => setFrage(false)} onJa={() => { + if (!frage) return // zweiter Klick eines Doppelklicks setFrage(false) onAbbrechen?.(job) }} diff --git a/frontend/src/components/cockpit/Protokollfenster.tsx b/frontend/src/components/cockpit/Protokollfenster.tsx index cf83275..1a6019f 100644 --- a/frontend/src/components/cockpit/Protokollfenster.tsx +++ b/frontend/src/components/cockpit/Protokollfenster.tsx @@ -11,7 +11,7 @@ export function Protokollfenster({ offen, titel, text, onSchliessen }: { }) { return ( !o && onSchliessen()}> - + Protokoll {titel} diff --git a/frontend/src/components/cockpit/Zaehlwerk.tsx b/frontend/src/components/cockpit/Zaehlwerk.tsx index c5230bc..23c9903 100644 --- a/frontend/src/components/cockpit/Zaehlwerk.tsx +++ b/frontend/src/components/cockpit/Zaehlwerk.tsx @@ -1,8 +1,11 @@ import { laufzeit } from "@/lib/zeit" +// Alle Maße hängen an der Schriftgröße der Zeile (em), und die wächst mit der Breite des Feldes +// (cqw): So passt „TT T SS H“ auch in die schmale Hälfte eines 320-px-Handys, und am PC bleibt +// es bei den alten 38 × 56 px je Ziffer. function Ziffer({ z }: { z: string }) { return ( - + {z} ) @@ -15,14 +18,19 @@ export function Zaehlwerk({ sekunden }: { sekunden: number | null | undefined }) const std = String(lz?.[1] ?? 0).padStart(2, "0") const text = lz ? `Laufzeit ohne Neustart: ${lz[0]} Tage, ${lz[1]} Stunden` : "Laufzeit unbekannt" return ( -
    -
    +
    + {/* Höhe wie die Rundinstrumente daneben (200 × 150, also ¾ der Breite). */} +
    - T + T - H + H
    Ohne Neustart
    diff --git a/frontend/src/views/Dienste.tsx b/frontend/src/views/Dienste.tsx index a2b1037..af39fb3 100644 --- a/frontend/src/views/Dienste.tsx +++ b/frontend/src/views/Dienste.tsx @@ -29,7 +29,7 @@ export function Dienste({ offen, onSchliessen }: { offen: boolean; onSchliessen: return ( !o && onSchliessen()}> - + Dienste und Protokolle Welcher Dienst läuft, was er zuletzt geschrieben hat. diff --git a/frontend/src/views/Einstellungen.tsx b/frontend/src/views/Einstellungen.tsx index 111c6d7..8986ef9 100644 --- a/frontend/src/views/Einstellungen.tsx +++ b/frontend/src/views/Einstellungen.tsx @@ -35,7 +35,7 @@ export function Einstellungen({ offen, onSchliessen }: { offen: boolean; onSchli const s = stand.data return ( !o && onSchliessen()}> - + Einstellungen Was die Box sich merkt. diff --git a/frontend/src/views/ModellSuche.tsx b/frontend/src/views/ModellSuche.tsx index 807b908..b6e152a 100644 --- a/frontend/src/views/ModellSuche.tsx +++ b/frontend/src/views/ModellSuche.tsx @@ -1,4 +1,4 @@ -import { useState } from "react" +import { useRef, useState } from "react" import { useQuery } from "@tanstack/react-query" import { Bestaetigen } from "@/components/cockpit/Bestaetigen" import { Button } from "@/components/ui/button" @@ -30,6 +30,7 @@ export function ModellSuche({ offen, onSchliessen, rollenJetzt }: { const [repo, setRepo] = useState(null) const [rolle, setRolle] = useState("") const [auswahl, setAuswahl] = useState<{ quant: string; bytes?: number } | null>(null) + const unterwegs = useRef(false) const treffer = useQuery({ queryKey: ["hf-suche", begriff], @@ -47,8 +48,10 @@ export function ModellSuche({ offen, onSchliessen, rollenJetzt }: { const ersatz = rollenName && repo ? rollenErsatzText(repo, rollenName, rollenJetzt[rolle]) : null function starten() { - // Die Sperre gegen den Doppelklick: Solange ein Start unterwegs ist, geht kein zweiter los. - if (!repo || !auswahl || installieren.isPending) return + // Die Sperre gegen den Doppelklick: Solange ein Start unterwegs ist, geht kein zweiter los. Der + // Ref greift sofort — der Zustand von useMutation erst nach dem nächsten Rendern. + if (!repo || !auswahl || unterwegs.current) return + unterwegs.current = true installieren.mutate( { repo, quant: auswahl.quant, rolle: rolle || null }, { @@ -57,13 +60,16 @@ export function ModellSuche({ offen, onSchliessen, rollenJetzt }: { if (e.ok !== false) onSchliessen() }, onError: () => setAuswahl(null), + onSettled: () => { + unterwegs.current = false + }, }, ) } return ( !o && onSchliessen()}> - + Modelle selbst suchen Auf Hugging Face suchen, Quantisierung wählen, installieren. diff --git a/frontend/src/views/Updates.tsx b/frontend/src/views/Updates.tsx index 65b6d0f..8487c1d 100644 --- a/frontend/src/views/Updates.tsx +++ b/frontend/src/views/Updates.tsx @@ -130,7 +130,9 @@ function BausteinZeile({ id, name, neuLautStart, fest, gesperrt, onStart, onFrei const neu = hatUpdate ? v?.neu ?? neuLautStart ?? null : null const summary = zusammenfassung(d?.summary) - const laeuftZelle = laedt ? : <>{v?.laeuft ?? "–"} + // Scheitert die Prüfung, kennt das Backend oft nicht einmal die laufende Version (Hermes: git fetch). + const laeuftText = v && v.laeuft !== "–" ? v.laeuft : fehler ? "unbekannt" : "–" + const laeuftZelle = laedt ? : <>{laeuftText} const neuZelle = laedt ? ( ) : neu ? ( @@ -165,22 +167,22 @@ function BausteinZeile({ id, name, neuLautStart, fest, gesperrt, onStart, onFrei ) } - // Am PC eine Tabellenzeile, am Handy ein Block: Name und Versionen oben, darunter was sich - // ändert, darunter die Knöpfe — ohne seitliches Scrollen. + // Am PC eine Tabellenzeile, am Handy ein Block: Name, darunter die Versionen, darunter was sich + // ändert, darunter die Knöpfe — ohne seitliches Scrollen und ohne dass Name und Version aneinanderstoßen. return (
    {name} - + {laeuftZelle} {!laedt && (neu || fehler) && <> {neu ? "→" : "·"} {neuZelle}} {laeuftZelle} {neuZelle} -
    +
    {fest && ( Festgehalten seit {fest.seit} auf {fest.version}: {fest.grund}. Der Sonntags-Lauf überspringt {name}. @@ -189,7 +191,7 @@ function BausteinZeile({ id, name, neuLautStart, fest, gesperrt, onStart, onFrei {was}
    {(fest || hatUpdate) && ( - + {fest && (