feat: add Vorhanden / In Benutzung filter mode to Model Manager
This commit is contained in:
-350
File diff suppressed because one or more lines are too long
-1
File diff suppressed because one or more lines are too long
+350
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
Vendored
+2
-2
@@ -7,8 +7,8 @@
|
|||||||
<link rel="manifest" href="/manifest.webmanifest" />
|
<link rel="manifest" href="/manifest.webmanifest" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||||
<title>Mission Control 2.0</title>
|
<title>Mission Control 2.0</title>
|
||||||
<script type="module" crossorigin src="/assets/index-BUUZ5n0A.js"></script>
|
<script type="module" crossorigin src="/assets/index-Dk6KzQ7B.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-Cs_NgMMZ.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-nR6_L3dg.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@@ -139,6 +139,14 @@ function Cockpit() {
|
|||||||
const [copied, setCopied] = useState(false)
|
const [copied, setCopied] = useState(false)
|
||||||
const [hoveredNode, setHoveredNode] = useState<string | null>(null)
|
const [hoveredNode, setHoveredNode] = useState<string | null>(null)
|
||||||
const [viewMode, setViewMode] = useState<"grid" | "list">("grid")
|
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
|
// Canvas pixel tracking for pixel-perfect connection graph without non-uniform scaling
|
||||||
const [dimensions, setDimensions] = useState({ width: 800, height: 360 })
|
const [dimensions, setDimensions] = useState({ width: 800, height: 360 })
|
||||||
@@ -729,38 +737,68 @@ function Cockpit() {
|
|||||||
|
|
||||||
{/* ZONE C: Library list cards & Upgrade Radar */}
|
{/* ZONE C: Library list cards & Upgrade Radar */}
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div className="flex items-center justify-between px-1">
|
<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</div>
|
<div className="text-xs font-bold uppercase tracking-wider text-muted-foreground">
|
||||||
<div className="flex rounded-lg border border-border/40 bg-card/45 p-0.5">
|
Installierte Modell-Bibliothek ({filteredModels.length} von {models.length})
|
||||||
<button
|
</div>
|
||||||
onClick={() => setViewMode("grid")}
|
|
||||||
className={cn(
|
<div className="flex items-center gap-3">
|
||||||
"px-2.5 py-1 rounded-md text-[9px] font-bold uppercase transition-all cursor-pointer",
|
{/* Filter mode selector */}
|
||||||
viewMode === "grid" ? "bg-primary text-primary-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
|
<div className="flex rounded-lg border border-border/40 bg-card/45 p-0.5">
|
||||||
)}
|
<button
|
||||||
>
|
onClick={() => setFilterMode("all")}
|
||||||
Grid
|
className={cn(
|
||||||
</button>
|
"px-2.5 py-1 rounded-md text-[9px] font-bold uppercase transition-all cursor-pointer",
|
||||||
<button
|
filterMode === "all" ? "bg-primary text-primary-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
|
||||||
onClick={() => setViewMode("list")}
|
)}
|
||||||
className={cn(
|
>
|
||||||
"px-2.5 py-1 rounded-md text-[9px] font-bold uppercase transition-all cursor-pointer",
|
Vorhanden
|
||||||
viewMode === "list" ? "bg-primary text-primary-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
|
</button>
|
||||||
)}
|
<button
|
||||||
>
|
onClick={() => setFilterMode("in_use")}
|
||||||
List
|
className={cn(
|
||||||
</button>
|
"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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{viewMode === "grid" ? (
|
{viewMode === "grid" ? (
|
||||||
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
<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">
|
<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>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
models.map((m) => {
|
filteredModels.map((m) => {
|
||||||
const isRunning = running.includes(m.name)
|
const isRunning = running.includes(m.name)
|
||||||
const hasUpgrade = updates?.model_list.find((u) => u.role === m.role)
|
const hasUpgrade = updates?.model_list.find((u) => u.role === m.role)
|
||||||
const brand = getBrandInfo(m.name)
|
const brand = getBrandInfo(m.name)
|
||||||
@@ -884,12 +922,14 @@ function Cockpit() {
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="space-y-2">
|
<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">
|
<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>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
models.map((m) => {
|
filteredModels.map((m) => {
|
||||||
const isRunning = running.includes(m.name)
|
const isRunning = running.includes(m.name)
|
||||||
const brand = getBrandInfo(m.name)
|
const brand = getBrandInfo(m.name)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user