Frontend-Erneuerung: Mobile, Diät, Tempo, UI-Politur (10-Punkte-Paket)
- Fix: 'Interaktives Terminal' im Cockpit führte ins Leere (#terminal) → Konsole - Mobile: Off-Canvas-Sidebar mit Hamburger unter md, Inhalt volle Breite (vorher: 240px starre Sidebar, 135px Rest mit Quer-Scroll auf dem Handy) - Dead Weight raus: src/mc3/ (verworfener Prototyp), DashboardView (alte Zentrale) + 6 nur dort genutzte Karten, 8 ungenutzte npm-Pakete (three, three-vrm, react-three fiber/drei, sigma, graphology ×2, @types/three) - Code-Splitting: alle Views außer Cockpit per React.lazy → Haupt-Bundle 983 → 739 KB, jede View ein eigenes Chunk - Fonts lokal (@fontsource) statt Google-CDN → UI offline identisch - Polling harmonisiert: EINE Takt-Tabelle in queries.ts (Graphen 3s, Rest 8-60s), keine Override-Intervalle mehr in Komponenten; Updates-Check (apt/git!) von 4s auf 60s - CSS-Hack-Layer aufgelöst: !important-Klassen-Sniffing → explizite .mc-card/.mc-card-sm/.nav-active-Klassen (Look identisch, ungeschichtete Regeln statt Utility-Raten); totes .light-Theme raus; Scrollbars 1× definiert - Aurora: animierte Fullscreen-Blur-Filter → statische radial-gradients (gleicher Look, keine Dauer-GPU-Last) - Sicherheit: Sudo-Passwort/HF-Token nur noch bei mutierenden Requests, nicht mehr auf jedem GET-Poll - Strg+K statt ⌘K auf Windows; dist neu gebaut Live gegen die Box verifiziert: alle 10 Views + Mobile-Flow, 0 Konsolen-Fehler. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -9,7 +9,7 @@ import { cn, resolveExternalUrl } from "@/lib/utils"
|
||||
const ALIASES = ["chat", "coding", "fast", "heavy"]
|
||||
|
||||
export function AgentView() {
|
||||
const { data: s, error: sErr } = useAgentStatus(5_000)
|
||||
const { data: s, error: sErr } = useAgentStatus()
|
||||
const { data: modelsData } = useModels()
|
||||
const { showAlert, dialogElement } = useDialog()
|
||||
const qc = useQueryClient()
|
||||
@@ -83,7 +83,7 @@ export function AgentView() {
|
||||
{s && (
|
||||
<div className="space-y-6">
|
||||
{/* Agent-Fluss: Terminal → Gateway → Hirn / Verdrahtung / PC (ruhig, statt SVG-Graph) */}
|
||||
<div className="rounded-2xl border border-border/60 bg-card/45 backdrop-blur-md p-5 shadow-lg shadow-black/10">
|
||||
<div className="mc-card p-5">
|
||||
<div className="mb-4 flex items-center gap-2">
|
||||
<Bot className="h-4.5 w-4.5 text-primary" />
|
||||
<span className="text-xs font-bold uppercase tracking-wider text-foreground">Agent-Fluss</span>
|
||||
@@ -168,7 +168,7 @@ export function AgentView() {
|
||||
</div>
|
||||
|
||||
{/* PC Executor Status Card */}
|
||||
<div className="rounded-2xl border border-border/60 bg-card/45 backdrop-blur-md p-6 space-y-4 shadow-lg shadow-black/10">
|
||||
<div className="mc-card p-6 space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<Monitor className="h-5 w-5 text-primary" />
|
||||
@@ -218,7 +218,7 @@ export function AgentView() {
|
||||
|
||||
{/* Diagnostic Details if Offline */}
|
||||
{!s.gateway_reachable && (
|
||||
<div className="rounded-2xl border border-border/60 bg-card/45 backdrop-blur-md p-6 space-y-4 shadow-lg shadow-black/10 text-left">
|
||||
<div className="mc-card p-6 space-y-4 text-left">
|
||||
<div className="flex items-center gap-2">
|
||||
<Shield className="h-5 w-5 text-amber-500" />
|
||||
<h3 className="text-sm font-bold uppercase tracking-wider text-foreground">Hermes-Agent Diagnostics</h3>
|
||||
|
||||
@@ -195,7 +195,7 @@ function IdeenSection() {
|
||||
<SectionLabel icon={Lightbulb}>
|
||||
Ideen-Queue{data ? ` — ${data.offen} offen` : ""}
|
||||
</SectionLabel>
|
||||
<div className="rounded-2xl border border-border/60 bg-card/45 p-4 shadow-lg shadow-black/15 backdrop-blur-md space-y-3">
|
||||
<div className="mc-card p-4 space-y-3">
|
||||
<div className="flex gap-2">
|
||||
<input
|
||||
value={text}
|
||||
@@ -311,7 +311,7 @@ function ProposalCard({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="rounded-2xl border border-border/60 bg-card/45 p-4 shadow-lg shadow-black/15 backdrop-blur-md space-y-3">
|
||||
<div className="mc-card p-4 space-y-3">
|
||||
<div className="flex flex-wrap items-start justify-between gap-3">
|
||||
<div className="min-w-0">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
|
||||
@@ -120,7 +120,7 @@ export function ConnectView() {
|
||||
</div>
|
||||
|
||||
{/* Hero: die zwei Leitungen */}
|
||||
<div className="p-5 rounded-2xl border border-border/60 bg-card/45 backdrop-blur-md shadow-lg shadow-black/10">
|
||||
<div className="p-5 mc-card">
|
||||
<div className="grid gap-4 md:grid-cols-[170px_1fr] items-center">
|
||||
{/* Lokaler Agent */}
|
||||
<div className="rounded-2xl border border-border/60 bg-background/40 p-4 text-center">
|
||||
@@ -186,7 +186,7 @@ export function ConnectView() {
|
||||
</div>
|
||||
|
||||
{/* Gemeinsame Variablen */}
|
||||
<div className="grid gap-4 md:grid-cols-2 p-5 rounded-2xl border border-border/60 bg-card/45 backdrop-blur-md shadow-lg shadow-black/10">
|
||||
<div className="grid gap-4 md:grid-cols-2 p-5 mc-card">
|
||||
<div className="space-y-1.5">
|
||||
<label className="text-[10px] font-bold uppercase tracking-wider text-muted-foreground flex items-center gap-1.5">
|
||||
<Globe className="h-3.5 w-3.5 text-primary" /> Box LAN IP-Adresse
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
import { SystemStatusCard } from "@/components/dashboard/SystemStatusCard"
|
||||
import { UpdatesCard } from "@/components/dashboard/UpdatesCard"
|
||||
import { AgentStatusCard } from "@/components/dashboard/AgentStatusCard"
|
||||
import { MemoryInputCard } from "@/components/dashboard/MemoryInputCard"
|
||||
import { TokenPerformanceCard } from "@/components/dashboard/TokenPerformanceCard"
|
||||
import { ServicesCard } from "@/components/dashboard/ServicesCard"
|
||||
import { LatencyCard } from "@/components/dashboard/LatencyCard"
|
||||
import { ModelsCard } from "@/components/dashboard/ModelsCard"
|
||||
import { LucyHealthCard } from "@/components/dashboard/LucyHealthCard"
|
||||
|
||||
function ZoneLabel({ children }: { children: React.ReactNode }) {
|
||||
return <p className="mb-2 ml-0.5 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground/60">{children}</p>
|
||||
}
|
||||
|
||||
export function DashboardView() {
|
||||
return (
|
||||
<div className="space-y-7">
|
||||
<div>
|
||||
<h1 className="text-2xl font-space font-bold tracking-tight bg-gradient-to-r from-foreground via-foreground to-primary bg-clip-text text-transparent">
|
||||
Zentrale
|
||||
</h1>
|
||||
<p className="text-sm text-muted-foreground">Aktueller Status von System, Modellen und Agent.</p>
|
||||
</div>
|
||||
|
||||
{/* „Geht's Lucy gut?" — Klartext-Ampel + 1-Klick-Reparatur, ganz oben. */}
|
||||
<LucyHealthCard />
|
||||
|
||||
{/* Hero-Banner — System, Durchsatz, Modelle (Rollen + warm + Inferenz in einer Karte) */}
|
||||
<div className="grid items-stretch gap-6 lg:grid-cols-3">
|
||||
<SystemStatusCard />
|
||||
<TokenPerformanceCard />
|
||||
<ModelsCard />
|
||||
</div>
|
||||
|
||||
{/* Stack & Telemetrie */}
|
||||
<section>
|
||||
<ZoneLabel>Stack & Telemetrie</ZoneLabel>
|
||||
<div className="grid gap-6 lg:grid-cols-2">
|
||||
<ServicesCard />
|
||||
<LatencyCard />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Betrieb & Wissen */}
|
||||
<section>
|
||||
<ZoneLabel>Betrieb & Wissen</ZoneLabel>
|
||||
<div className="grid gap-6 md:grid-cols-3">
|
||||
<UpdatesCard />
|
||||
<AgentStatusCard />
|
||||
<MemoryInputCard />
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -50,7 +50,7 @@ function Card({ id, icon: Icon, color, title, kicker, children, wide }: {
|
||||
<section
|
||||
id={id}
|
||||
className={cn(
|
||||
"scroll-mt-20 rounded-2xl border border-border/60 bg-card/45 backdrop-blur-md p-6 shadow-lg shadow-black/10 space-y-3",
|
||||
"scroll-mt-20 mc-card p-6 space-y-3",
|
||||
wide && "md:col-span-2"
|
||||
)}
|
||||
>
|
||||
@@ -109,7 +109,7 @@ export function GuideView() {
|
||||
return (
|
||||
<div className="space-y-7">
|
||||
{/* Hero */}
|
||||
<div className="rounded-2xl border border-border/60 bg-card/45 backdrop-blur-md p-6 shadow-lg shadow-black/10 flex items-start gap-4">
|
||||
<div className="mc-card p-6 flex items-start gap-4">
|
||||
<div className="h-11 w-11 rounded-xl bg-primary/15 flex items-center justify-center shrink-0">
|
||||
<BookOpen className="h-6 w-6 text-primary" />
|
||||
</div>
|
||||
@@ -419,7 +419,7 @@ description: Treibt Entwicklung mit strikter TDD-Praxis
|
||||
</Card>
|
||||
|
||||
{/* 13 — Ressourcen */}
|
||||
<section id="ressourcen" className="scroll-mt-20 md:col-span-2 rounded-2xl border border-border/60 bg-card/45 backdrop-blur-md p-6 shadow-lg shadow-black/10 space-y-4">
|
||||
<section id="ressourcen" className="scroll-mt-20 md:col-span-2 mc-card p-6 space-y-4">
|
||||
<div className="flex items-center gap-2.5 border-b border-border/20 pb-3">
|
||||
<Compass className="h-5 w-5 text-primary" />
|
||||
<div>
|
||||
|
||||
@@ -6,7 +6,7 @@ import { resolveExternalUrl, cn } from "@/lib/utils"
|
||||
// per iframe — Schwester der Hermes-Terminal-Seite. Login per Box-Passwort (su-Prompt im
|
||||
// Terminal selbst). Die Passwort-Verwaltung liegt in System-Wartung → Einstellungen.
|
||||
export function KonsoleView() {
|
||||
const { data: agent } = useAgentStatus(5_000)
|
||||
const { data: agent } = useAgentStatus()
|
||||
const url = agent?.box_console_url ? resolveExternalUrl(agent.box_console_url) : undefined
|
||||
const ok = agent?.box_console_reachable
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ export function ModelsView() {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex rounded-xl border border-border/60 bg-card/45 backdrop-blur-md p-1 self-start">
|
||||
<div className="flex mc-card-sm p-1 self-start">
|
||||
{(["cockpit", "discover"] as const).map((t) => (
|
||||
<button
|
||||
key={t}
|
||||
|
||||
@@ -134,7 +134,7 @@ export function WissenView() {
|
||||
</aside>
|
||||
|
||||
{/* Inhalt */}
|
||||
<div className="min-w-0 flex-1 rounded-2xl border border-border/60 bg-card/45 p-5 shadow-lg shadow-black/15 backdrop-blur-md">
|
||||
<div className="min-w-0 flex-1 mc-card p-5">
|
||||
{docLoading ? (
|
||||
<div className="flex items-center gap-2 text-xs text-muted-foreground"><Loader2 className="h-4 w-4 animate-spin" /> Notiz wird geladen …</div>
|
||||
) : doc ? (
|
||||
|
||||
@@ -42,7 +42,7 @@ export function CockpitTile({
|
||||
<button
|
||||
onClick={onClick}
|
||||
className={cn(
|
||||
"group relative flex flex-col items-start rounded-2xl border border-border/60 bg-card/45 p-5 text-left shadow-lg shadow-black/15 backdrop-blur-md transition-all duration-200 cursor-pointer hover:bg-card/70 hover:shadow-xl",
|
||||
"group relative flex flex-col items-start mc-card p-5 text-left cursor-pointer",
|
||||
RING[tone],
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -27,13 +27,13 @@ const openDrawer = (tab: "maintenance" | "logs") =>
|
||||
// dich"-Bereich für offene Aktionen, darunter die Bereichs-Kacheln (je EINE Live-Zahl).
|
||||
// Überblick außen, Tiefe hinter der Kachel — Daten/Aktionen aus den IST-Hooks.
|
||||
export function CockpitView({ onNavigate }: { onNavigate: (v: string) => void }) {
|
||||
const { data: models } = useModels(4_000)
|
||||
const { data: svc } = useServices(4_000)
|
||||
const { data: updates } = useUpdates(8_000)
|
||||
const { data: models } = useModels()
|
||||
const { data: svc } = useServices()
|
||||
const { data: updates } = useUpdates()
|
||||
const { data: memory } = useMemory()
|
||||
const { data: agent } = useAgentStatus()
|
||||
const { data: connect } = useConnectHealth()
|
||||
const { data: auftraege } = useAuftragsbuch(20_000)
|
||||
const { data: auftraege } = useAuftragsbuch()
|
||||
const health = useLucyHealth()
|
||||
|
||||
const { showAlert, dialogElement } = useDialog()
|
||||
@@ -369,7 +369,7 @@ function ToolListCard({ agent, svcErrors, onNavigate }: {
|
||||
label: "Interaktives Terminal",
|
||||
status: "Öffnen",
|
||||
tone: "muted",
|
||||
action: () => onNavigate("terminal"),
|
||||
action: () => onNavigate("konsole"),
|
||||
},
|
||||
{
|
||||
label: "Wissens-Vault",
|
||||
|
||||
@@ -48,7 +48,7 @@ export function ErinnerungenCard() {
|
||||
const sorted = [...items].sort((a, b) => a.next_ts - b.next_ts)
|
||||
|
||||
return (
|
||||
<div className="rounded-2xl border border-border/60 bg-card/45 p-4 shadow-lg shadow-black/15 backdrop-blur-md">
|
||||
<div className="mc-card p-4">
|
||||
<div className="mb-3 flex items-center justify-between">
|
||||
<span className="flex items-center gap-2 text-sm font-bold text-foreground">
|
||||
<span className="flex h-8 w-8 items-center justify-center rounded-lg border border-border/40 bg-background/30 text-amber-300">
|
||||
|
||||
@@ -15,8 +15,8 @@ import { useExpertMode } from "@/lib/useExpertMode"
|
||||
|
||||
export function Cockpit() {
|
||||
const qc = useQueryClient()
|
||||
const { data: modelsResp, isLoading: loading, error: loadErr } = useModels(4_000)
|
||||
const { data: updates } = useUpdates(4_000)
|
||||
const { data: modelsResp, isLoading: loading, error: loadErr } = useModels()
|
||||
const { data: updates } = useUpdates()
|
||||
const { data: brain } = useHermesBrain()
|
||||
const { data: sysStatus } = useSystemStatus()
|
||||
const { data: groupsResp } = useGroups()
|
||||
@@ -265,7 +265,7 @@ export function Cockpit() {
|
||||
`}</style>
|
||||
|
||||
{/* ZONE A: Widescreen VRAM HUD */}
|
||||
<div className="rounded-2xl border border-border/60 bg-card/45 backdrop-blur-md p-5 shadow-lg shadow-black/10 space-y-3.5">
|
||||
<div className="mc-card p-5 space-y-3.5">
|
||||
<div className="flex justify-between items-center">
|
||||
<div className="flex items-center gap-2">
|
||||
<HardDrive className="h-4.5 w-4.5 text-primary" />
|
||||
@@ -329,7 +329,7 @@ export function Cockpit() {
|
||||
{expert && <LaneEditor />}
|
||||
|
||||
{/* ZONE B.5: Slot-Belegung */}
|
||||
<div className="rounded-2xl border border-border/60 bg-card/45 backdrop-blur-md p-5 shadow-lg shadow-black/10 space-y-3.5">
|
||||
<div className="mc-card p-5 space-y-3.5">
|
||||
<div className="text-xs font-bold uppercase tracking-wider text-muted-foreground px-1">
|
||||
{expert ? "Gateway Steckplatz-Belegung (Slot-Zuweisung)" : "Wer macht was bei Lucy — zum Ändern antippen"}
|
||||
</div>
|
||||
@@ -515,7 +515,7 @@ export function Cockpit() {
|
||||
<div
|
||||
key={m.name}
|
||||
className={cn(
|
||||
"rounded-2xl border bg-card/45 backdrop-blur-md p-5 shadow-lg shadow-black/10 flex flex-col justify-between gap-4 transition-all duration-300 hover:border-primary/40 group relative overflow-hidden",
|
||||
"mc-card p-5 flex flex-col justify-between gap-4 group relative overflow-hidden",
|
||||
isRunning
|
||||
? "border-primary/45 shadow-primary/5"
|
||||
: m.role
|
||||
@@ -725,7 +725,7 @@ export function Cockpit() {
|
||||
<div
|
||||
key={m.name}
|
||||
className={cn(
|
||||
"rounded-xl border bg-card/45 backdrop-blur-md p-3.5 shadow-lg shadow-black/5 flex flex-col sm:flex-row sm:items-center justify-between gap-3 hover:border-primary/40 transition-all",
|
||||
"mc-card-sm p-3.5 flex flex-col sm:flex-row sm:items-center justify-between gap-3",
|
||||
isRunning
|
||||
? "border-primary/45"
|
||||
: m.role
|
||||
|
||||
@@ -77,7 +77,7 @@ export function Discover() {
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
{/* Modus-Umschalter: geführt (Empfohlen) vs. Stöbern & Suchen */}
|
||||
<div className="flex rounded-xl border border-border/60 bg-card/45 backdrop-blur-md p-1 w-fit">
|
||||
<div className="flex mc-card-sm p-1 w-fit">
|
||||
{([["recommended", "Empfohlen"], ["browse", "Stöbern & Suchen"]] as const).map(([m, label]) => (
|
||||
<button
|
||||
key={m}
|
||||
@@ -145,7 +145,7 @@ export function Discover() {
|
||||
<div
|
||||
key={cat.role}
|
||||
className={cn(
|
||||
"rounded-2xl border bg-card/45 backdrop-blur-md p-5 shadow-lg shadow-black/10 flex flex-col justify-between gap-5 transition-all duration-300 hover:border-primary/40",
|
||||
"mc-card p-5 flex flex-col justify-between gap-5",
|
||||
installedModel ? "border-border/60" : "border-primary/20 shadow-primary/5"
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -190,7 +190,7 @@ export function ModelBrowse() {
|
||||
<div
|
||||
key={r.repo}
|
||||
className={cn(
|
||||
"rounded-xl border bg-card/45 backdrop-blur-md transition-all",
|
||||
"mc-card-sm",
|
||||
isOpen ? "border-primary/40 shadow-lg shadow-primary/5" : "border-border/50 hover:border-primary/30",
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -26,7 +26,7 @@ export function MaschinenraumBar({
|
||||
const freePct = (freeBytes / capacity) * 100
|
||||
|
||||
return (
|
||||
<div className="rounded-2xl border border-border/60 bg-card/45 p-5 shadow-lg shadow-black/15 backdrop-blur-md">
|
||||
<div className="mc-card p-5">
|
||||
<div className="mb-3 flex flex-wrap items-end justify-between gap-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<HardDrive className="h-5 w-5 text-primary" />
|
||||
|
||||
@@ -24,7 +24,7 @@ const short = (name: string) => name.split("/").pop()?.replace(/\.gguf$/i, "") ?
|
||||
// Eingebettet als Haupt-Tab im Modell-Manager (Überschrift + Discover liefert ModelsView).
|
||||
export function ModelsWorkbench() {
|
||||
const qc = useQueryClient()
|
||||
const { data: modelsResp, isLoading, error } = useModels(4_000)
|
||||
const { data: modelsResp, isLoading, error } = useModels()
|
||||
const { data: sys } = useSystemStatus()
|
||||
const { data: groupsResp } = useGroups()
|
||||
const { showAlert, showConfirm, showPrompt, dialogElement } = useDialog()
|
||||
@@ -139,7 +139,7 @@ export function ModelsWorkbench() {
|
||||
|
||||
<div className="grid gap-5 lg:grid-cols-[minmax(0,1fr)_minmax(0,1.3fr)]">
|
||||
{/* Master — Liste */}
|
||||
<div className="rounded-2xl border border-border/60 bg-card/45 p-4 shadow-lg shadow-black/15 backdrop-blur-md">
|
||||
<div className="mc-card p-4">
|
||||
<div className="mb-3 flex items-center gap-2">
|
||||
<div className="relative flex-1">
|
||||
<Search className="pointer-events-none absolute left-2.5 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground/60" />
|
||||
@@ -194,7 +194,7 @@ export function ModelsWorkbench() {
|
||||
</div>
|
||||
|
||||
{/* Detail — verwalten */}
|
||||
<div className="rounded-2xl border border-border/60 bg-card/45 p-5 shadow-lg shadow-black/15 backdrop-blur-md">
|
||||
<div className="mc-card p-5">
|
||||
{!selected ? (
|
||||
<div className="flex h-full min-h-[16rem] flex-col items-center justify-center gap-2 text-center text-muted-foreground">
|
||||
<Cpu className="h-8 w-8 opacity-40" />
|
||||
|
||||
Reference in New Issue
Block a user