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
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -7,8 +7,8 @@
<link rel="manifest" href="/manifest.webmanifest" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<title>Mission Control 2.0</title>
<script type="module" crossorigin src="/assets/index-BUUZ5n0A.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-Cs_NgMMZ.css">
<script type="module" crossorigin src="/assets/index-Dk6KzQ7B.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-nR6_L3dg.css">
</head>
<body>
<div id="root"></div>
+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)