diff --git a/frontend/src/views/Dienste.tsx b/frontend/src/views/Dienste.tsx index af39fb3..378c8de 100644 --- a/frontend/src/views/Dienste.tsx +++ b/frontend/src/views/Dienste.tsx @@ -1,11 +1,28 @@ import { useState } from "react" import { useQueryClient } from "@tanstack/react-query" +import { cn } from "cn" import { Button } from "@/components/ui/button" import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from "@/components/ui/sheet" -import { useDienste, useProtokoll } from "@/lib/abfragen" +import { type Dienst, useDienste, useProtokoll } from "@/lib/abfragen" +import { fehlerText } from "@/lib/anzeige" import { post } from "@/lib/api" import { melden } from "@/lib/meldungen" -import { cn } from "cn" +import type { AktionsErgebnis } from "@/lib/typen" + +/** Das Protokoll eines Dienstes, direkt unter seiner Zeile — am Handy sonst weit unten außer Sicht. */ +function Protokoll({ unit }: { unit: string }) { + const protokoll = useProtokoll(unit) + let text: string + if (protokoll.isPending) text = "Wird gelesen …" + else if (protokoll.isError) text = `Das Protokoll lässt sich gerade nicht lesen: ${protokoll.error.message}` + else if (protokoll.data.ok === false) text = protokoll.data.err || protokoll.data.text || "Das Protokoll lässt sich nicht lesen." + else text = protokoll.data.text?.trim() || "Noch keine Einträge." + return ( +
+      {text}
+    
+ ) +} /** Dienste der Box mit Protokoll und Neustart — die „Log-Ansicht der Dienste“. */ export function Dienste({ offen, onSchliessen }: { offen: boolean; onSchliessen: () => void }) { @@ -13,20 +30,79 @@ export function Dienste({ offen, onSchliessen }: { offen: boolean; onSchliessen: const dienste = useDienste() const [gewaehlt, setGewaehlt] = useState(null) const [bestaetigen, setBestaetigen] = useState(null) - const protokoll = useProtokoll(gewaehlt) + const [startet, setStartet] = useState(null) - async function neustarten(unit: string) { + async function neustarten(d: Dienst) { + if (startet) return setBestaetigen(null) + setStartet(d.unit) try { - const e = await post<{ ok: boolean; err?: string }>("/api/maintenance/restart", { service: unit }) - if (e.ok) melden("erfolg", `${unit} startet neu.`) - else melden("fehler", e.err || `${unit} ließ sich nicht neu starten.`) + const e = await post("/api/maintenance/restart", { service: d.unit }) + if (e.ok) melden("erfolg", `${d.name} ${d.schlaeft ? "wird geweckt" : "startet neu"}.`) + else melden("fehler", `${d.name} ließ sich nicht starten: ${fehlerText(e)}`) qc.invalidateQueries({ queryKey: ["dienste"] }) } catch (f) { melden("fehler", (f as Error).message) + } finally { + setStartet(null) } } + let inhalt + if (dienste.isPending) { + inhalt =

Dienste werden gelesen …

+ } else if (dienste.isError && !dienste.data) { + inhalt =

Die Dienste lassen sich gerade nicht lesen: {dienste.error.message}

+ } else if (!dienste.data?.services.length) { + inhalt =

Keine Dienste gefunden.

+ } else { + inhalt = ( +
    + {dienste.data.services.map((d) => ( +
  • + + + + {d.name} + + {d.unit} · {d.ok ? "läuft" : d.schlaeft ? "schläft (abgeschaltet)" : "antwortet nicht"} + + + + + + {bestaetigen === d.unit ? ( + <> + + + + ) : ( + + )} + + {gewaehlt === d.unit && } +
  • + ))} +
+ ) + } + return ( !o && onSchliessen()}> @@ -34,43 +110,7 @@ export function Dienste({ offen, onSchliessen }: { offen: boolean; onSchliessen: Dienste und Protokolle Welcher Dienst läuft, was er zuletzt geschrieben hat. -
    - {(dienste.data?.services ?? []).map((d) => ( -
  • - - - - {d.name} - - {d.unit} · {d.ok ? "läuft" : d.schlaeft ? "schläft (abgeschaltet)" : "antwortet nicht"} - - - - - - {bestaetigen === d.unit ? ( - - ) : ( - - )} - -
  • - ))} -
- {gewaehlt && ( -
-            {protokoll.isFetching ? "Wird gelesen …" : protokoll.data?.text || protokoll.data?.err || "Kein Protokoll."}
-          
- )} + {inhalt}
) diff --git a/frontend/src/views/Einstellungen.tsx b/frontend/src/views/Einstellungen.tsx index 8986ef9..6ceeb5d 100644 --- a/frontend/src/views/Einstellungen.tsx +++ b/frontend/src/views/Einstellungen.tsx @@ -20,8 +20,13 @@ export function Einstellungen({ offen, onSchliessen }: { offen: boolean; onSchli enabled: offen, }) const [token, setToken] = useState("") + const [speichert, setSpeichert] = useState(false) + const [loeschFrage, setLoeschFrage] = useState(false) async function speichern(wert: string | null) { + if (speichert) return + setSpeichert(true) + setLoeschFrage(false) try { await post("/api/maintenance/geheimnisse", { schluessel: "hf_token", wert }) melden("erfolg", wert ? "Hugging-Face-Zugang gespeichert." : "Hugging-Face-Zugang gelöscht.") @@ -29,10 +34,17 @@ export function Einstellungen({ offen, onSchliessen }: { offen: boolean; onSchli qc.invalidateQueries({ queryKey: ["geheimnisse"] }) } catch (f) { melden("fehler", (f as Error).message) + } finally { + setSpeichert(false) } } const s = stand.data + // Solange der Stand lädt, weiß die Oberfläche nicht, ob ein Zugang hinterlegt ist — also nicht „Fehlt.“ sagen. + let standText: string + if (stand.isPending) standText = "Wird gelesen …" + else if (!s) standText = `Lässt sich gerade nicht lesen${stand.error ? `: ${stand.error.message}` : "."}` + else standText = s.hf_token_gesetzt ? "Ist hinterlegt." : "Fehlt." return ( !o && onSchliessen()}> @@ -42,10 +54,14 @@ export function Einstellungen({ offen, onSchliessen }: { offen: boolean; onSchli

Hugging-Face-Zugang

-

- {s?.hf_token_gesetzt ? "Ist hinterlegt." : "Fehlt."} Nötig für gesperrte Modelle und schnellere Downloads. +

+ {standText} Nötig für gesperrte Modelle und + schnellere Downloads. {s?.hf_token_aus_env ? " Er kommt aus der Dienst-Einstellung und lässt sich hier nicht löschen." : ""}

+ {s?.schreibbar === false && ( +

Die Box kann den Zugang gerade nicht speichern: Ihre Ablage ist nicht beschreibbar.

+ )}
{ @@ -63,10 +79,21 @@ export function Einstellungen({ offen, onSchliessen }: { offen: boolean; onSchli placeholder="hf_…" className="h-11 min-w-0 flex-1 rounded-lg border border-linie-stark bg-erhaben px-3 text-[15px] outline-none focus:border-cyan" /> - +
{s?.hf_token_gesetzt && !s.hf_token_aus_env && ( - + loeschFrage ? ( + + + + + ) : ( + + ) )}