Update AppImage

This commit is contained in:
MacRimi
2025-10-05 21:44:22 +02:00
parent efb7cad993
commit 4beba53675
2 changed files with 90 additions and 153 deletions

View File

@@ -170,13 +170,14 @@ export default function Hardware() {
const storageSummary = hardwareData.storage_devices.reduce(
(acc, disk) => {
const sizeMatch = disk.size.match(/(\d+\.?\d*)\s*([KMGT]B)/)
const sizeMatch = disk.size.match(/(\d+\.?\d*)\s*([KMGT]?B)/)
if (sizeMatch) {
let sizeInGB = Number.parseFloat(sizeMatch[1])
const unit = sizeMatch[2]
if (unit === "TB") sizeInGB *= 1024
else if (unit === "MB") sizeInGB /= 1024
else if (unit === "KB") sizeInGB /= 1024 * 1024
if (unit === "TB" || unit === "T") sizeInGB *= 1024
else if (unit === "GB" || unit === "G") sizeInGB *= 1
else if (unit === "MB" || unit === "M") sizeInGB /= 1024
else if (unit === "KB" || unit === "K") sizeInGB /= 1024 * 1024
acc.totalCapacity += sizeInGB
}
@@ -330,7 +331,7 @@ export default function Hardware() {
</Card>
)}
{/* Storage Summary - Simplified */}
{/* Storage Summary - Improved */}
{hardwareData.storage_devices.length > 0 && (
<Card className="border-border/50 bg-card/50 p-6">
<div className="mb-4 flex items-center gap-2">
@@ -349,7 +350,7 @@ export default function Hardware() {
{storageSummary.ssd > 0 && (
<div className="space-y-1">
<p className="text-sm text-muted-foreground">SSD Drives</p>
<p className="text-sm text-muted-foreground">SSD/NVMe Drives</p>
<p className="text-2xl font-semibold">{storageSummary.ssd}</p>
</div>
)}
@@ -368,67 +369,6 @@ export default function Hardware() {
</Card>
)}
{/* Storage Devices */}
{hardwareData.storage_devices.length > 0 && (
<Card className="border-border/50 bg-card/50 p-6">
<div className="mb-4 flex items-center gap-2">
<HardDrive className="h-5 w-5 text-primary" />
<h2 className="text-lg font-semibold">Storage Devices</h2>
<Badge variant="outline" className="ml-auto">
{hardwareData.storage_devices.length} devices
</Badge>
</div>
<div className="space-y-4">
{hardwareData.storage_devices.map((disk, index) => (
<Card key={index} className="border-border/30 bg-background/50 p-4">
<div className="flex items-start justify-between">
<div className="space-y-2 flex-1">
<div className="flex items-center gap-2">
<span className="font-medium">/dev/{disk.name}</span>
{getHealthBadge(disk.health)}
{disk.rotation_rate === 0 && (
<Badge variant="outline" className="text-xs">
SSD
</Badge>
)}
{disk.rotation_rate > 0 && (
<Badge variant="outline" className="text-xs">
{disk.rotation_rate} RPM
</Badge>
)}
</div>
<div className="grid gap-2 text-sm md:grid-cols-2">
<div className="flex justify-between">
<span className="text-muted-foreground">Model</span>
<span className="font-mono text-xs">{disk.model}</span>
</div>
<div className="flex justify-between">
<span className="text-muted-foreground">Size</span>
<span className="font-mono">{disk.size}</span>
</div>
{disk.temperature > 0 && (
<div className="flex justify-between">
<span className="text-muted-foreground">Temperature</span>
<span className={`font-mono ${getTempColor(disk.temperature)}`}>{disk.temperature}°C</span>
</div>
)}
{disk.power_on_hours > 0 && (
<div className="flex justify-between">
<span className="text-muted-foreground">Power On Hours</span>
<span className="font-mono">{disk.power_on_hours.toLocaleString()}h</span>
</div>
)}
</div>
</div>
</div>
</Card>
))}
</div>
</Card>
)}
{/* Graphics Cards */}
{hardwareData.graphics_cards.length > 0 && (
<Card className="border-border/50 bg-card/50 p-6">
@@ -505,80 +445,53 @@ export default function Hardware() {
</Card>
)}
{/* Network Cards */}
{hardwareData.network_cards.length > 0 && (
{/* Thermal Monitoring */}
{hardwareData.sensors.temperatures.length > 0 && (
<Card className="border-border/50 bg-card/50 p-6">
<div className="mb-4 flex items-center gap-2">
<Network className="h-5 w-5 text-primary" />
<h2 className="text-lg font-semibold">Network Cards</h2>
<Badge variant="outline" className="ml-auto">
{hardwareData.network_cards.length} NIC{hardwareData.network_cards.length > 1 ? "s" : ""}
</Badge>
<Thermometer className="h-5 w-5 text-primary" />
<h2 className="text-lg font-semibold">Thermal Monitoring</h2>
</div>
<div className="grid gap-3 md:grid-cols-2">
{hardwareData.network_cards.map((nic, index) => (
<Card key={index} className="border-border/30 bg-background/50 p-3">
{hardwareData.sensors.temperatures.map((sensor, index) => (
<div key={index} className="space-y-1">
<div className="flex items-center justify-between text-sm">
<span className="font-mono text-xs">{nic.name}</span>
<Badge variant="outline" className="text-xs">
{nic.type}
</Badge>
<span className="text-muted-foreground">{sensor.name}</span>
<span
className={`font-mono font-medium ${getTempColor(sensor.current, sensor.high, sensor.critical)}`}
>
{sensor.current.toFixed(1)}°C
</span>
</div>
</Card>
<Progress value={getTempProgress(sensor.current, sensor.critical)} className="h-1.5" />
</div>
))}
</div>
</Card>
)}
{/* Sensors (Temperature & Fans) */}
{hasSensors && (
{/* Fan Monitoring */}
{hardwareData.sensors.fans.length > 0 && (
<Card className="border-border/50 bg-card/50 p-6">
<div className="mb-4 flex items-center gap-2">
<Thermometer className="h-5 w-5 text-primary" />
<h2 className="text-lg font-semibold">Thermal & Fan Monitoring</h2>
<Fan className="h-5 w-5 text-primary" />
<h2 className="text-lg font-semibold">Fan Monitoring</h2>
</div>
<div className="grid gap-6 md:grid-cols-2">
{/* Temperatures */}
{hardwareData.sensors.temperatures.length > 0 && (
<div className="space-y-3">
<h3 className="text-sm font-medium text-muted-foreground">Temperatures</h3>
<div className="space-y-3">
{hardwareData.sensors.temperatures.map((sensor, index) => (
<div key={index} className="space-y-1">
<div className="flex items-center justify-between text-sm">
<span className="text-muted-foreground">{sensor.name}</span>
<span
className={`font-mono font-medium ${getTempColor(sensor.current, sensor.high, sensor.critical)}`}
>
{sensor.current.toFixed(1)}°C
</span>
</div>
<Progress value={getTempProgress(sensor.current, sensor.critical)} className="h-1.5" />
</div>
))}
<div className="grid gap-3 md:grid-cols-2 lg:grid-cols-3">
{hardwareData.sensors.fans.map((fan, index) => (
<div
key={index}
className="flex items-center justify-between rounded-lg border border-border/30 bg-background/50 p-3"
>
<div className="flex items-center gap-2">
<Fan className="h-4 w-4 text-muted-foreground" />
<span className="text-sm text-muted-foreground">{fan.name}</span>
</div>
<span className="font-mono font-medium text-sm">{fan.current_rpm} RPM</span>
</div>
)}
{/* Fans */}
{hardwareData.sensors.fans.length > 0 && (
<div className="space-y-3">
<h3 className="text-sm font-medium text-muted-foreground">Fans</h3>
<div className="space-y-3">
{hardwareData.sensors.fans.map((fan, index) => (
<div key={index} className="flex items-center justify-between text-sm">
<div className="flex items-center gap-2">
<Fan className="h-4 w-4 text-muted-foreground" />
<span className="text-muted-foreground">{fan.name}</span>
</div>
<span className="font-mono font-medium">{fan.current_rpm} RPM</span>
</div>
))}
</div>
</div>
)}
))}
</div>
</Card>
)}

View File

@@ -310,48 +310,72 @@ export function ProxmoxDashboard() {
</div>
<SheetContent side="top" className="bg-card border-border">
<div className="flex flex-col gap-2 mt-4">
<TabsTrigger
value="overview"
onClick={() => setMobileMenuOpen(false)}
className="w-full justify-start data-[state=active]:bg-primary data-[state=active]:text-primary-foreground"
<Button
variant="ghost"
onClick={() => {
const overviewTab = document.querySelector('[value="overview"]') as HTMLButtonElement
overviewTab?.click()
setMobileMenuOpen(false)
}}
className="w-full justify-start"
>
Overview
</TabsTrigger>
<TabsTrigger
value="storage"
onClick={() => setMobileMenuOpen(false)}
className="w-full justify-start data-[state=active]:bg-primary data-[state=active]:text-primary-foreground"
</Button>
<Button
variant="ghost"
onClick={() => {
const storageTab = document.querySelector('[value="storage"]') as HTMLButtonElement
storageTab?.click()
setMobileMenuOpen(false)
}}
className="w-full justify-start"
>
Storage
</TabsTrigger>
<TabsTrigger
value="network"
onClick={() => setMobileMenuOpen(false)}
className="w-full justify-start data-[state=active]:bg-primary data-[state=active]:text-primary-foreground"
</Button>
<Button
variant="ghost"
onClick={() => {
const networkTab = document.querySelector('[value="network"]') as HTMLButtonElement
networkTab?.click()
setMobileMenuOpen(false)
}}
className="w-full justify-start"
>
Network
</TabsTrigger>
<TabsTrigger
value="vms"
onClick={() => setMobileMenuOpen(false)}
className="w-full justify-start data-[state=active]:bg-primary data-[state=active]:text-primary-foreground"
</Button>
<Button
variant="ghost"
onClick={() => {
const vmsTab = document.querySelector('[value="vms"]') as HTMLButtonElement
vmsTab?.click()
setMobileMenuOpen(false)
}}
className="w-full justify-start"
>
Virtual Machines
</TabsTrigger>
<TabsTrigger
value="hardware"
onClick={() => setMobileMenuOpen(false)}
className="w-full justify-start data-[state=active]:bg-primary data-[state=active]:text-primary-foreground"
</Button>
<Button
variant="ghost"
onClick={() => {
const hardwareTab = document.querySelector('[value="hardware"]') as HTMLButtonElement
hardwareTab?.click()
setMobileMenuOpen(false)
}}
className="w-full justify-start"
>
Hardware
</TabsTrigger>
<TabsTrigger
value="logs"
onClick={() => setMobileMenuOpen(false)}
className="w-full justify-start data-[state=active]:bg-primary data-[state=active]:text-primary-foreground"
</Button>
<Button
variant="ghost"
onClick={() => {
const logsTab = document.querySelector('[value="logs"]') as HTMLButtonElement
logsTab?.click()
setMobileMenuOpen(false)
}}
className="w-full justify-start"
>
System Logs
</TabsTrigger>
</Button>
</div>
</SheetContent>
</Sheet>