feat: add Vorhanden / In Benutzung filter mode to Model Manager

This commit is contained in:
Hitonabi
2026-06-26 08:23:50 +02:00
parent f32e4baf5b
commit 563e7837b9
6 changed files with 420 additions and 380 deletions
+67 -27
View File
@@ -139,6 +139,14 @@ function Cockpit() {
const [copied, setCopied] = useState(false)
const [hoveredNode, setHoveredNode] = useState<string | null>(null)
const [viewMode, setViewMode] = useState<"grid" | "list">("grid")
const [filterMode, setFilterMode] = useState<"all" | "in_use">("all")
const filteredModels = models.filter((m) => {
if (filterMode === "in_use") {
return !!m.role || running.includes(m.name)
}
return true
})
// Canvas pixel tracking for pixel-perfect connection graph without non-uniform scaling
const [dimensions, setDimensions] = useState({ width: 800, height: 360 })
@@ -729,38 +737,68 @@ function Cockpit() {
{/* ZONE C: Library list cards & Upgrade Radar */}
<div className="space-y-4">
<div className="flex items-center justify-between px-1">
<div className="text-xs font-bold uppercase tracking-wider text-muted-foreground">Installierte Modell-Bibliothek</div>
<div className="flex rounded-lg border border-border/40 bg-card/45 p-0.5">
<button
onClick={() => setViewMode("grid")}
className={cn(
"px-2.5 py-1 rounded-md text-[9px] font-bold uppercase transition-all cursor-pointer",
viewMode === "grid" ? "bg-primary text-primary-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
)}
>
Grid
</button>
<button
onClick={() => setViewMode("list")}
className={cn(
"px-2.5 py-1 rounded-md text-[9px] font-bold uppercase transition-all cursor-pointer",
viewMode === "list" ? "bg-primary text-primary-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
)}
>
List
</button>
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-3 px-1">
<div className="text-xs font-bold uppercase tracking-wider text-muted-foreground">
Installierte Modell-Bibliothek ({filteredModels.length} von {models.length})
</div>
<div className="flex items-center gap-3">
{/* Filter mode selector */}
<div className="flex rounded-lg border border-border/40 bg-card/45 p-0.5">
<button
onClick={() => setFilterMode("all")}
className={cn(
"px-2.5 py-1 rounded-md text-[9px] font-bold uppercase transition-all cursor-pointer",
filterMode === "all" ? "bg-primary text-primary-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
)}
>
Vorhanden
</button>
<button
onClick={() => setFilterMode("in_use")}
className={cn(
"px-2.5 py-1 rounded-md text-[9px] font-bold uppercase transition-all cursor-pointer",
filterMode === "in_use" ? "bg-primary text-primary-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
)}
>
In Benutzung
</button>
</div>
{/* Grid/List layout selector */}
<div className="flex rounded-lg border border-border/40 bg-card/45 p-0.5">
<button
onClick={() => setViewMode("grid")}
className={cn(
"px-2.5 py-1 rounded-md text-[9px] font-bold uppercase transition-all cursor-pointer",
viewMode === "grid" ? "bg-primary text-primary-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
)}
>
Grid
</button>
<button
onClick={() => setViewMode("list")}
className={cn(
"px-2.5 py-1 rounded-md text-[9px] font-bold uppercase transition-all cursor-pointer",
viewMode === "list" ? "bg-primary text-primary-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
)}
>
List
</button>
</div>
</div>
</div>
{viewMode === "grid" ? (
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
{models.length === 0 ? (
{filteredModels.length === 0 ? (
<div className="col-span-full text-xs text-muted-foreground border border-dashed border-border/60 rounded-2xl p-12 text-center select-none">
Keine Modelle konfiguriert. Verwende den Tab "Modelle finden" zum Herunterladen.
{filterMode === "in_use"
? "Keine Modelle in Benutzung (keine Zuweisung oder warm geladene Modelle)."
: "Keine Modelle konfiguriert. Verwende den Tab \"Modelle finden\" zum Herunterladen."}
</div>
) : (
models.map((m) => {
filteredModels.map((m) => {
const isRunning = running.includes(m.name)
const hasUpgrade = updates?.model_list.find((u) => u.role === m.role)
const brand = getBrandInfo(m.name)
@@ -884,12 +922,14 @@ function Cockpit() {
</div>
) : (
<div className="space-y-2">
{models.length === 0 ? (
{filteredModels.length === 0 ? (
<div className="text-xs text-muted-foreground border border-dashed border-border/60 rounded-2xl p-12 text-center select-none">
Keine Modelle konfiguriert. Verwende den Tab "Modelle finden" zum Herunterladen.
{filterMode === "in_use"
? "Keine Modelle in Benutzung (keine Zuweisung oder warm geladene Modelle)."
: "Keine Modelle konfiguriert. Verwende den Tab \"Modelle finden\" zum Herunterladen."}
</div>
) : (
models.map((m) => {
filteredModels.map((m) => {
const isRunning = running.includes(m.name)
const brand = getBrandInfo(m.name)