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 =
- )}
+ {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.