Feat: UI-Audit — Telegram/MCP/PC-Status, incomplete-Badge, SSH-Karte ersetzt

- backend: PC_EXECUTOR_URL Env-Var + 3 neue agent_status()-Felder
  (telegram_enabled, mcp_server_count, pc_executor_reachable)
- AgentStatusCard: 2x2-Grid (Gateway/WebUI/Gehirn/Verdrahtung) +
  echte Status-Footer-Zeilen fuer Telegram, MCP-Server-Anzahl, PC
- TokenStatsCard: 'Juni 2026' entfernt, Null-Fallback fuer pricing
- AgentView: SSH-Bypass-Karte ersetzt durch PC-Executor-Statuskarte
- Cockpit + RolesCard: Datei-fehlt-Badge + Load-Button disabled fuer incomplete-Modelle
- api.ts: AgentStatus-Interface um 3 neue Felder erweitert

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-06-27 00:01:36 +02:00
parent 6a464bf653
commit 0afddcdfdc
13 changed files with 546 additions and 455 deletions
@@ -1,5 +1,5 @@
import { useState } from "react"
import { Bot, ExternalLink, Cpu, Layers, X, Check } from "lucide-react"
import { Bot, ExternalLink, Cpu, Layers, Wrench, X, Check } from "lucide-react"
import { api } from "@/lib/api"
import { useAgentStatus, useModels, useQueryClient, qk } from "@/lib/queries"
import { useDialog } from "@/lib/useDialog"
@@ -51,37 +51,43 @@ export function AgentStatusCard() {
</div>
{agent ? (
<div className="space-y-3">
<div className="grid grid-cols-2 gap-3">
<div className="p-3 bg-background/20 rounded-xl border border-border/40">
<div className="text-[10px] text-muted-foreground uppercase font-semibold">Gateway</div>
<div className="flex items-center gap-2 mt-1">
<span className={cn("h-2 w-2 rounded-full", agent.gateway_reachable ? "bg-emerald-500 animate-pulse" : "bg-amber-500")} />
<span className="text-xs font-medium">{agent.gateway_reachable ? "Online" : "Offline"}</span>
</div>
</div>
<div className="p-3 bg-background/20 rounded-xl border border-border/40">
<div className="text-[10px] text-muted-foreground uppercase font-semibold">WebUI</div>
<div className="flex items-center gap-2 mt-1">
<span className={cn("h-2 w-2 rounded-full", agent.webui_reachable ? "bg-emerald-500 animate-pulse" : "bg-amber-500")} />
<span className="text-xs font-medium">{agent.webui_reachable ? "Online" : "Offline"}</span>
</div>
<div className="grid grid-cols-2 gap-3">
<div className="p-3 bg-background/20 rounded-xl border border-border/40">
<div className="text-[10px] text-muted-foreground uppercase font-semibold">Gateway</div>
<div className="flex items-center gap-2 mt-1">
<span className={cn("h-2 w-2 rounded-full", agent.gateway_reachable ? "bg-emerald-500 animate-pulse" : "bg-amber-500")} />
<span className="text-xs font-medium">{agent.gateway_reachable ? "Online" : "Offline"}</span>
</div>
</div>
<div className="p-3 bg-background/20 rounded-xl border border-border/40">
<div className="text-[10px] text-muted-foreground uppercase font-semibold">WebUI</div>
<div className="flex items-center gap-2 mt-1">
<span className={cn("h-2 w-2 rounded-full", agent.webui_reachable ? "bg-emerald-500 animate-pulse" : "bg-amber-500")} />
<span className="text-xs font-medium">{agent.webui_reachable ? "Online" : "Offline"}</span>
</div>
</div>
<div
onClick={() => setShowBrainSelect(true)}
className="p-3 bg-background/20 rounded-xl border border-border/40 hover:border-primary/45 hover:bg-background/30 transition-all duration-300 cursor-pointer group"
className="p-3 bg-background/20 rounded-xl border border-border/40 hover:border-primary/45 hover:bg-background/30 transition-all duration-300 cursor-pointer"
>
<div className="flex justify-between items-center">
<span className="text-[10px] text-muted-foreground uppercase font-semibold">Aktives Gehirn</span>
<button className="flex items-center gap-1 text-[9px] font-bold uppercase tracking-wider text-primary border border-primary/20 bg-primary/10 hover:bg-primary/20 px-1.5 py-0.5 rounded transition-all cursor-pointer font-space">
<Cpu className="h-3 w-3" /> Ändern
</button>
<span className="text-[10px] text-muted-foreground uppercase font-semibold">Gehirn</span>
<Cpu className="h-3 w-3 text-primary" />
</div>
<div className="text-xs font-medium mt-1 font-mono text-primary flex items-center gap-1.5">
<Layers className="h-3.5 w-3.5" />
{agent.brain_model ? `model: ${agent.brain_model}` : "model: auto"}
<div className="text-xs font-medium mt-1 font-mono text-primary truncate flex items-center gap-1">
<Layers className="h-3 w-3 shrink-0" />
{agent.brain_model || "auto"}
</div>
</div>
<div className="p-3 bg-background/20 rounded-xl border border-border/40">
<div className="flex justify-between items-center">
<span className="text-[10px] text-muted-foreground uppercase font-semibold">Verdrahtung</span>
<Wrench className="h-3 w-3 text-primary" />
</div>
<div className="text-[10px] font-mono mt-1 space-y-0.5 text-muted-foreground">
<div>Config: {agent.has_config ? <span className="text-emerald-400"></span> : "—"}</div>
<div>Skills: {agent.has_skills ? <span className="text-emerald-400"></span> : "—"}</div>
<div>Memory: {agent.has_memories ? <span className="text-emerald-400"></span> : "—"}</div>
</div>
</div>
</div>
@@ -89,9 +95,26 @@ export function AgentStatusCard() {
<div className="h-28 flex items-center justify-center text-xs text-muted-foreground">Lade Agenten-Status</div>
)}
</div>
<div className="mt-3 text-[10px] text-muted-foreground/80 border-t border-border/30 pt-3">
Gedächtnis & Stack-Tools via MCP gekoppelt.
</div>
{agent && (
<div className="mt-3 border-t border-border/30 pt-3 space-y-1.5">
<div className="flex items-center justify-between text-[10px] text-muted-foreground">
<span>Telegram</span>
<span className={cn("font-semibold", agent.telegram_enabled ? "text-emerald-400" : "")}>
{agent.telegram_enabled ? "aktiv" : "nicht konfiguriert"}
</span>
</div>
<div className="flex items-center justify-between text-[10px] text-muted-foreground">
<span>MCP-Server</span>
<span className="font-semibold text-foreground">{agent.mcp_server_count ?? 0} verbunden</span>
</div>
<div className="flex items-center justify-between text-[10px] text-muted-foreground">
<span>PC Executor</span>
<span className={cn("font-semibold", agent.pc_executor_reachable ? "text-emerald-400" : "")}>
{agent.pc_executor_reachable ? "erreichbar" : "nicht verbunden"}
</span>
</div>
</div>
)}
{agent && showBrainSelect && (
<div className="fixed inset-0 z-50 bg-black/60 backdrop-blur-sm flex items-center justify-center p-4">
@@ -68,6 +68,11 @@ export function RolesCard() {
SLOTS: {m.parallel_slots}
</span>
)}
{m.incomplete && (
<span className="text-[7px] leading-none font-mono font-bold bg-amber-500/10 text-amber-400 border border-amber-500/20 px-1 py-0.5 rounded" title="GGUF-Datei fehlt">
fehlt
</span>
)}
</div>
)}
</div>
@@ -51,9 +51,9 @@ export function TokenStatsCard() {
)}
</div>
<div className="mt-4 text-[9px] text-muted-foreground/70 border-t border-border/30 pt-2.5 leading-normal">
Berechnet im Vergleich zu Cloud-APIs von Juni 2026
Berechnet ggü. Cloud-APIs
{tokenStats?.pricing?.heavy
? `${tokenStats.pricing.heavy.in.toFixed(2).replace(".", ",")} $ / ${tokenStats.pricing.heavy.out.toFixed(2).replace(".", ",")} $ pro 1M tkn).`
? `${(tokenStats.pricing.heavy.in ?? 0).toFixed(2).replace(".", ",")} $ / ${(tokenStats.pricing.heavy.out ?? 0).toFixed(2).replace(".", ",")} $ pro 1M tkn).`
: "."}
</div>
</div>