Skills-Ansicht: Umbenennung + aktiv/inaktiv + Karten-Ergebnisse im Auftragsbuch
User-Feedback 15.07.:
1) 'Von allein' heisst jetzt 'Skills' (id #eigenleben bleibt, Links halten).
2) Jeder Skill traegt aktiv/inaktiv - Quelle ist Hermes' EIGENE Wahrheit
(hermes_cli.banner.get_available_skills via Hermes-venv, dieselbe Logik
wie das eingebaute WebUI: Plattform/Voraussetzungen/Config). Bewusst NUR
die Datenquelle wiederverwendet, nicht deren UI - Skill-VERWALTUNG bleibt
im Hermes-GUI-Tab, alles andere waere Bloat/Doppelbau.
3) Auftragsbuch: fertige Queue-Karten sind aufklappbar und zeigen das
ERGEBNIS des Workers (kanban_complete-Summary, lazy via
GET /api/ideen/{id}/ergebnis) - 'Dinge werden getestet, ich sehe aber
das Ergebnis nicht' ist damit zu.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
import { useState } from "react"
|
||||
import { useEffect, useState } from "react"
|
||||
import {
|
||||
Inbox, Check, X, GitBranch, FileDiff, Loader2, AlertTriangle, Sparkles,
|
||||
ChevronDown, ChevronRight, Clock, Hammer, RefreshCw, Lightbulb, Send, HelpCircle,
|
||||
ChevronDown, ChevronRight, Clock, ClipboardCheck, Hammer, RefreshCw, Lightbulb, Send, HelpCircle,
|
||||
} from "lucide-react"
|
||||
import { api, type AuftragItem, type IdeenItem, type SkillKandidat } from "@/lib/api"
|
||||
import { api, type AuftragItem, type IdeenErgebnis, type IdeenItem, type SkillKandidat } from "@/lib/api"
|
||||
import { useAuftragsbuch, useIdeen, useIdeenLog, useQueryClient, qk } from "@/lib/queries"
|
||||
import { useDialog } from "@/lib/useDialog"
|
||||
import { cn } from "@/lib/utils"
|
||||
@@ -259,7 +259,9 @@ function IdeenSection() {
|
||||
{items.map((it: IdeenItem) => {
|
||||
const ui = IDEEN_STATE[it.status] ?? { label: it.status, cls: "text-muted-foreground border-border/60 bg-background/30" }
|
||||
const isOpen = openLog === it.id
|
||||
const canOpen = it.status === "triage" || it.status === "running"
|
||||
// Aufklappbar: laufende Karten zeigen das Live-Log, FERTIGE das Ergebnis
|
||||
// (User-Wunsch 15.07.: „Dinge werden getestet, ich sehe das Ergebnis nicht").
|
||||
const canOpen = it.status === "triage" || it.status === "running" || it.status === "done"
|
||||
const blocked = it.status === "blocked"
|
||||
const answering = !!busy["ans:" + it.id]
|
||||
return (
|
||||
@@ -283,7 +285,7 @@ function IdeenSection() {
|
||||
{canOpen && (
|
||||
<button
|
||||
onClick={() => setOpenLog(isOpen ? null : it.id)}
|
||||
title="Worker-Log anzeigen"
|
||||
title={it.status === "done" ? "Ergebnis anzeigen" : "Worker-Log anzeigen"}
|
||||
className="shrink-0 rounded-md p-1 text-muted-foreground/60 transition-colors hover:text-foreground cursor-pointer">
|
||||
{isOpen ? <ChevronDown className="h-3.5 w-3.5" /> : <ChevronRight className="h-3.5 w-3.5" />}
|
||||
</button>
|
||||
@@ -320,7 +322,7 @@ function IdeenSection() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isOpen && canOpen && (
|
||||
{isOpen && canOpen && it.status !== "done" && (
|
||||
<div className="ml-2 -mt-1">
|
||||
<div className="rounded-lg border border-border/50 bg-background/50 p-2">
|
||||
{logEnabled && logData.isLoading ? (
|
||||
@@ -337,6 +339,8 @@ function IdeenSection() {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isOpen && it.status === "done" && <ErgebnisPanel id={it.id} />}
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
@@ -351,6 +355,41 @@ function IdeenSection() {
|
||||
)
|
||||
}
|
||||
|
||||
// Ergebnis einer FERTIGEN Queue-Aufgabe: die Abschluss-Zusammenfassung des Workers
|
||||
// (kanban_complete). Lazy — wird erst beim Aufklappen geladen, ändert sich nie mehr.
|
||||
function ErgebnisPanel({ id }: { id: string }) {
|
||||
const [erg, setErg] = useState<IdeenErgebnis | null>(null)
|
||||
const [fehler, setFehler] = useState(false)
|
||||
useEffect(() => {
|
||||
let weg = false
|
||||
api<IdeenErgebnis>(`/api/ideen/${id}/ergebnis`)
|
||||
.then((r) => { if (!weg) setErg(r) })
|
||||
.catch(() => { if (!weg) setFehler(true) })
|
||||
return () => { weg = true }
|
||||
}, [id])
|
||||
const text = erg ? (erg.summary || erg.result) : ""
|
||||
return (
|
||||
<div className="ml-2 -mt-1">
|
||||
<div className="rounded-lg border border-emerald-500/25 bg-emerald-500/5 p-2.5">
|
||||
<p className="mb-1 flex items-center gap-1.5 text-[10px] font-bold uppercase tracking-wide text-emerald-300">
|
||||
<ClipboardCheck className="h-3 w-3" /> Ergebnis des Workers
|
||||
</p>
|
||||
{fehler ? (
|
||||
<p className="text-[10px] text-red-400">Ergebnis nicht ladbar</p>
|
||||
) : erg === null ? (
|
||||
<p className="text-[10px] text-muted-foreground animate-pulse">Wird geladen …</p>
|
||||
) : text ? (
|
||||
<p className="max-h-64 overflow-y-auto whitespace-pre-wrap text-xs leading-relaxed text-foreground/85">{text}</p>
|
||||
) : (
|
||||
<p className="text-[10px] text-muted-foreground italic">
|
||||
Der Worker hat keine Abschluss-Zusammenfassung hinterlassen (ältere Karte oder Protokollverstoß).
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function StateBadge({ item }: { item: AuftragItem }) {
|
||||
const st = item.status
|
||||
if (!st) return null
|
||||
|
||||
Reference in New Issue
Block a user