Feat: Add Hermes brain change buttons and skills.sh guide source
This commit is contained in:
@@ -2,6 +2,8 @@ import { useEffect, useState, useRef } from "react"
|
||||
import { X, RefreshCw, Terminal, Cpu, Server, Shield, Power, Eye, EyeOff, Key, Download, AlertTriangle } from "lucide-react"
|
||||
import { api, type Job, type UpdatesResp } from "@/lib/api"
|
||||
import { cn } from "@/lib/utils"
|
||||
import { CustomDialog } from "./CustomDialog"
|
||||
|
||||
|
||||
interface SystemDrawerProps {
|
||||
open: boolean
|
||||
@@ -34,6 +36,51 @@ export function SystemDrawer({ open, onClose, defaultTab = "maintenance" }: Syst
|
||||
const [activeTab, setActiveTab] = useState<"maintenance" | "logs" | "settings">("maintenance")
|
||||
const [checkingUpdates, setCheckingUpdates] = useState(false)
|
||||
|
||||
// Custom Dialog State
|
||||
const [dialog, setDialog] = useState<{
|
||||
type: "alert" | "confirm"
|
||||
title: string
|
||||
message: string
|
||||
onConfirm: () => void
|
||||
onCancel?: () => void
|
||||
} | null>(null)
|
||||
|
||||
function showAlert(title: string, message: string, onConfirm?: () => void) {
|
||||
setDialog({
|
||||
type: "alert",
|
||||
title,
|
||||
message,
|
||||
onConfirm: () => {
|
||||
setDialog(null)
|
||||
if (onConfirm) onConfirm()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function showConfirm(title: string, message: string, onConfirm: () => void) {
|
||||
setDialog({
|
||||
type: "confirm",
|
||||
title,
|
||||
message,
|
||||
onConfirm: () => {
|
||||
setDialog(null)
|
||||
onConfirm()
|
||||
},
|
||||
onCancel: () => setDialog(null)
|
||||
})
|
||||
}
|
||||
|
||||
function formatLastCheck(ts?: number | null) {
|
||||
if (!ts) return "Nie"
|
||||
return new Date(ts * 1000).toLocaleString("de-DE", {
|
||||
day: "2-digit",
|
||||
month: "2-digit",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
second: "2-digit"
|
||||
})
|
||||
}
|
||||
|
||||
// Credentials State
|
||||
const [sudoPasswordInput, setSudoPasswordInput] = useState("")
|
||||
const [hfTokenInput, setHfTokenInput] = useState("")
|
||||
@@ -117,7 +164,7 @@ export function SystemDrawer({ open, onClose, defaultTab = "maintenance" }: Syst
|
||||
loadJobs()
|
||||
setActiveTab("maintenance")
|
||||
} catch (e: any) {
|
||||
alert(`Fehler beim Starten des OS-Updates: ${e.message}`)
|
||||
showAlert("Fehler", `Fehler beim Starten des OS-Updates: ${e.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,7 +174,7 @@ export function SystemDrawer({ open, onClose, defaultTab = "maintenance" }: Syst
|
||||
loadJobs()
|
||||
setActiveTab("maintenance")
|
||||
} catch (e: any) {
|
||||
alert(`Fehler: ${e.message}`)
|
||||
showAlert("Fehler", `Fehler beim Engine-Update: ${e.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,7 +185,7 @@ export function SystemDrawer({ open, onClose, defaultTab = "maintenance" }: Syst
|
||||
loadJobs()
|
||||
setActiveTab("maintenance")
|
||||
} catch (e: any) {
|
||||
alert(`Fehler bei der Update-Suche: ${e.message}`)
|
||||
showAlert("Fehler", `Fehler bei der Update-Suche: ${e.message}`)
|
||||
} finally {
|
||||
setCheckingUpdates(false)
|
||||
}
|
||||
@@ -150,23 +197,29 @@ export function SystemDrawer({ open, onClose, defaultTab = "maintenance" }: Syst
|
||||
method: "POST",
|
||||
body: JSON.stringify({ repo, role })
|
||||
})
|
||||
alert(`Modell-Upgrade für '${role}' (${repo}) gestartet.`)
|
||||
showAlert("Gestartet", `Modell-Upgrade für '${role}' (${repo}) gestartet.`)
|
||||
loadJobs()
|
||||
setActiveTab("maintenance")
|
||||
} catch (e: any) {
|
||||
alert(`Fehler beim Starten des Modell-Upgrades: ${e.message}`)
|
||||
showAlert("Fehler", `Fehler beim Starten des Modell-Upgrades: ${e.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
async function triggerReboot() {
|
||||
if (!confirm("Bist du sicher, dass du das gesamte Host-System neu starten willst?")) return
|
||||
try {
|
||||
await api("/api/maintenance/reboot", { method: "POST" })
|
||||
alert("Reboot ausgelöst. System startet neu...")
|
||||
onClose()
|
||||
} catch (e: any) {
|
||||
alert(`Fehler: ${e.message}`)
|
||||
}
|
||||
showConfirm(
|
||||
"Reboot bestätigen",
|
||||
"Bist du sicher, dass du das gesamte Host-System neu starten willst?",
|
||||
async () => {
|
||||
try {
|
||||
await api("/api/maintenance/reboot", { method: "POST" })
|
||||
showAlert("Reboot", "Reboot ausgelöst. System startet neu...", () => {
|
||||
onClose()
|
||||
})
|
||||
} catch (e: any) {
|
||||
showAlert("Fehler", `Fehler beim Reboot: ${e.message}`)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
async function restartService(serviceId: string) {
|
||||
@@ -177,15 +230,16 @@ export function SystemDrawer({ open, onClose, defaultTab = "maintenance" }: Syst
|
||||
body: JSON.stringify({ service: serviceId })
|
||||
})
|
||||
if (res.ok) {
|
||||
alert(`Dienst ${serviceId} wurde erfolgreich neu gestartet.`)
|
||||
if (activeTab === "logs" && selectedService === serviceId) {
|
||||
loadServiceLogs(serviceId)
|
||||
}
|
||||
showAlert("Dienst neu gestartet", `Dienst ${serviceId} wurde erfolgreich neu gestartet.`, () => {
|
||||
if (activeTab === "logs" && selectedService === serviceId) {
|
||||
loadServiceLogs(serviceId)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
alert(`Fehler beim Neustart: ${res.err || "Unbekannter Fehler"}`)
|
||||
showAlert("Fehler", `Fehler beim Neustart: ${res.err || "Unbekannter Fehler"}`)
|
||||
}
|
||||
} catch (e: any) {
|
||||
alert(`Fehler: ${e.message}`)
|
||||
showAlert("Fehler", `Fehler beim Neustart: ${e.message}`)
|
||||
} finally {
|
||||
setRestartingServices(prev => ({ ...prev, [serviceId]: false }))
|
||||
}
|
||||
@@ -196,7 +250,7 @@ export function SystemDrawer({ open, onClose, defaultTab = "maintenance" }: Syst
|
||||
await api(`/api/jobs/${jobId}/cancel`, { method: "POST" })
|
||||
loadJobs()
|
||||
} catch (e: any) {
|
||||
alert(`Fehler beim Abbrechen: ${e.message}`)
|
||||
showAlert("Fehler", `Fehler beim Abbrechen: ${e.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,14 +331,21 @@ export function SystemDrawer({ open, onClose, defaultTab = "maintenance" }: Syst
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<h3 className="text-xs font-bold uppercase tracking-wider text-muted-foreground">Wartungsaktionen</h3>
|
||||
<button
|
||||
onClick={triggerCheckUpdates}
|
||||
disabled={checkingUpdates}
|
||||
className="flex items-center gap-1 text-[10px] font-semibold text-primary hover:text-primary/80 transition-colors disabled:opacity-50"
|
||||
>
|
||||
<RefreshCw className={cn("h-3 w-3", checkingUpdates && "animate-spin")} />
|
||||
Nach Updates suchen
|
||||
</button>
|
||||
<div className="flex items-center gap-2">
|
||||
{updates?.last_check && (
|
||||
<span className="text-[9px] text-muted-foreground">
|
||||
Zuletzt gesucht: {formatLastCheck(updates.last_check)}
|
||||
</span>
|
||||
)}
|
||||
<button
|
||||
onClick={triggerCheckUpdates}
|
||||
disabled={checkingUpdates}
|
||||
className="flex items-center gap-1 text-[10px] font-semibold text-primary hover:text-primary/80 transition-colors disabled:opacity-50"
|
||||
>
|
||||
<RefreshCw className={cn("h-3 w-3", checkingUpdates && "animate-spin")} />
|
||||
Nach Updates suchen
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
@@ -326,7 +387,14 @@ export function SystemDrawer({ open, onClose, defaultTab = "maintenance" }: Syst
|
||||
{/* Modell Upgrades */}
|
||||
{updates?.model_list && updates.model_list.length > 0 && (
|
||||
<div className="space-y-3">
|
||||
<h3 className="text-xs font-bold uppercase tracking-wider text-muted-foreground">Verfügbare Modell-Upgrades</h3>
|
||||
<div className="flex items-center justify-between">
|
||||
<h3 className="text-xs font-bold uppercase tracking-wider text-muted-foreground">Verfügbare Modell-Upgrades</h3>
|
||||
{updates?.last_check && (
|
||||
<span className="text-[9px] text-muted-foreground">
|
||||
Gesucht: {formatLastCheck(updates.last_check)}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
{updates.model_list.map((m) => (
|
||||
<div key={m.role} className="p-3 rounded-xl border border-border/60 bg-background/20 flex flex-col gap-2">
|
||||
@@ -588,9 +656,9 @@ export function SystemDrawer({ open, onClose, defaultTab = "maintenance" }: Syst
|
||||
onClick={() => {
|
||||
localStorage.setItem("mc_sudo_password", sudoPasswordInput);
|
||||
localStorage.setItem("mc_hf_token", hfTokenInput);
|
||||
alert("Einstellungen erfolgreich lokal gespeichert.");
|
||||
showAlert("Erfolgreich", "Einstellungen erfolgreich lokal gespeichert.");
|
||||
}}
|
||||
className="flex-1 h-9 flex items-center justify-center text-xs font-semibold text-primary-foreground bg-primary hover:bg-primary/90 rounded-lg transition-colors"
|
||||
className="flex-1 h-9 flex items-center justify-center text-xs font-semibold text-primary-foreground bg-primary hover:bg-primary/90 rounded-lg transition-colors shadow shadow-primary/10 cursor-pointer"
|
||||
>
|
||||
Speichern
|
||||
</button>
|
||||
@@ -600,9 +668,9 @@ export function SystemDrawer({ open, onClose, defaultTab = "maintenance" }: Syst
|
||||
setHfTokenInput("");
|
||||
localStorage.removeItem("mc_sudo_password");
|
||||
localStorage.removeItem("mc_hf_token");
|
||||
alert("Zugangsdaten gelöscht.");
|
||||
showAlert("Gelöscht", "Zugangsdaten gelöscht.");
|
||||
}}
|
||||
className="h-9 px-4 flex items-center justify-center text-xs font-semibold text-muted-foreground border border-border/60 bg-background/20 hover:bg-accent rounded-lg transition-colors"
|
||||
className="h-9 px-4 flex items-center justify-center text-xs font-semibold text-muted-foreground border border-border/60 bg-background/20 hover:bg-accent rounded-lg transition-colors cursor-pointer"
|
||||
>
|
||||
Zurücksetzen
|
||||
</button>
|
||||
@@ -611,6 +679,16 @@ export function SystemDrawer({ open, onClose, defaultTab = "maintenance" }: Syst
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{dialog && (
|
||||
<CustomDialog
|
||||
type={dialog.type}
|
||||
title={dialog.title}
|
||||
message={dialog.message}
|
||||
onConfirm={dialog.onConfirm}
|
||||
onCancel={dialog.onCancel}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user