Update AppImage

This commit is contained in:
MacRimi
2025-10-19 17:16:35 +02:00
parent 71af9345a5
commit f662ce0b7a
3 changed files with 133 additions and 54 deletions

View File

@@ -20,6 +20,7 @@ import {
Container, Container,
} from "lucide-react" } from "lucide-react"
import useSWR from "swr" import useSWR from "swr"
import { MetricsDialog } from "./metrics-dialog"
interface VMData { interface VMData {
vmid: number vmid: number
@@ -184,6 +185,8 @@ export function VirtualMachines() {
const [controlLoading, setControlLoading] = useState(false) const [controlLoading, setControlLoading] = useState(false)
const [detailsLoading, setDetailsLoading] = useState(false) const [detailsLoading, setDetailsLoading] = useState(false)
const [vmConfigs, setVmConfigs] = useState<Record<number, string>>({}) const [vmConfigs, setVmConfigs] = useState<Record<number, string>>({})
const [metricsDialogOpen, setMetricsDialogOpen] = useState(false)
const [selectedMetric, setSelectedMetric] = useState<"cpu" | "memory" | "disk" | "network" | null>(null)
useEffect(() => { useEffect(() => {
const fetchLXCIPs = async () => { const fetchLXCIPs = async () => {
@@ -540,7 +543,16 @@ export function VirtualMachines() {
<div className="grid grid-cols-2 md:grid-cols-5 gap-3"> <div className="grid grid-cols-2 md:grid-cols-5 gap-3">
<div> <div>
<div className="text-xs text-muted-foreground mb-1">CPU Usage</div> <div className="text-xs text-muted-foreground mb-1">CPU Usage</div>
<div className={`text-sm font-semibold mb-1 ${getUsageColor(Number.parseFloat(cpuPercent))}`}> <div
className="cursor-pointer hover:opacity-80 transition-opacity"
onClick={() => {
setSelectedMetric("cpu")
setMetricsDialogOpen(true)
}}
>
<div
className={`text-sm font-semibold mb-1 ${getUsageColor(Number.parseFloat(cpuPercent))}`}
>
{cpuPercent}% {cpuPercent}%
</div> </div>
<Progress <Progress
@@ -548,10 +560,20 @@ export function VirtualMachines() {
className={`h-1.5 ${getProgressColor(Number.parseFloat(cpuPercent))}`} className={`h-1.5 ${getProgressColor(Number.parseFloat(cpuPercent))}`}
/> />
</div> </div>
</div>
<div> <div>
<div className="text-xs text-muted-foreground mb-1">Memory</div> <div className="text-xs text-muted-foreground mb-1">Memory</div>
<div className={`text-sm font-semibold mb-1 ${getUsageColor(Number.parseFloat(memPercent))}`}> <div
className="cursor-pointer hover:opacity-80 transition-opacity"
onClick={() => {
setSelectedMetric("memory")
setMetricsDialogOpen(true)
}}
>
<div
className={`text-sm font-semibold mb-1 ${getUsageColor(Number.parseFloat(memPercent))}`}
>
{memGB} / {maxMemGB} GB {memGB} / {maxMemGB} GB
</div> </div>
<Progress <Progress
@@ -559,9 +581,17 @@ export function VirtualMachines() {
className={`h-1.5 ${getProgressColor(Number.parseFloat(memPercent))}`} className={`h-1.5 ${getProgressColor(Number.parseFloat(memPercent))}`}
/> />
</div> </div>
</div>
<div> <div>
<div className="text-xs text-muted-foreground mb-1">Disk Usage</div> <div className="text-xs text-muted-foreground mb-1">Disk Usage</div>
<div
className="cursor-pointer hover:opacity-80 transition-opacity"
onClick={() => {
setSelectedMetric("disk")
setMetricsDialogOpen(true)
}}
>
<div <div
className={`text-sm font-semibold mb-1 ${getUsageColor(Number.parseFloat(diskPercent))}`} className={`text-sm font-semibold mb-1 ${getUsageColor(Number.parseFloat(diskPercent))}`}
> >
@@ -572,6 +602,7 @@ export function VirtualMachines() {
className={`h-1.5 ${getProgressColor(Number.parseFloat(diskPercent))}`} className={`h-1.5 ${getProgressColor(Number.parseFloat(diskPercent))}`}
/> />
</div> </div>
</div>
<div className="hidden md:block"> <div className="hidden md:block">
<div className="text-xs text-muted-foreground mb-1">Disk I/O</div> <div className="text-xs text-muted-foreground mb-1">Disk I/O</div>
@@ -718,6 +749,13 @@ export function VirtualMachines() {
</div> </div>
<div> <div>
<div className="text-xs text-muted-foreground mb-1">CPU Usage</div> <div className="text-xs text-muted-foreground mb-1">CPU Usage</div>
<div
className="cursor-pointer hover:opacity-80 transition-opacity"
onClick={() => {
setSelectedMetric("cpu")
setMetricsDialogOpen(true)
}}
>
<div className={`font-semibold mb-1 ${getUsageColor(selectedVM.cpu * 100)}`}> <div className={`font-semibold mb-1 ${getUsageColor(selectedVM.cpu * 100)}`}>
{(selectedVM.cpu * 100).toFixed(1)}% {(selectedVM.cpu * 100).toFixed(1)}%
</div> </div>
@@ -726,8 +764,16 @@ export function VirtualMachines() {
className={`h-1.5 ${getModalProgressColor(selectedVM.cpu * 100)}`} className={`h-1.5 ${getModalProgressColor(selectedVM.cpu * 100)}`}
/> />
</div> </div>
</div>
<div> <div>
<div className="text-xs text-muted-foreground mb-1">Memory</div> <div className="text-xs text-muted-foreground mb-1">Memory</div>
<div
className="cursor-pointer hover:opacity-80 transition-opacity"
onClick={() => {
setSelectedMetric("memory")
setMetricsDialogOpen(true)
}}
>
<div <div
className={`font-semibold mb-1 ${getUsageColor((selectedVM.mem / selectedVM.maxmem) * 100)}`} className={`font-semibold mb-1 ${getUsageColor((selectedVM.mem / selectedVM.maxmem) * 100)}`}
> >
@@ -738,41 +784,67 @@ export function VirtualMachines() {
className={`h-1.5 ${getModalProgressColor((selectedVM.mem / selectedVM.maxmem) * 100)}`} className={`h-1.5 ${getModalProgressColor((selectedVM.mem / selectedVM.maxmem) * 100)}`}
/> />
</div> </div>
</div>
<div> <div>
<div className="text-xs text-muted-foreground mb-1">Disk</div> <div className="text-xs text-muted-foreground mb-1">Disk</div>
<div
className="cursor-pointer hover:opacity-80 transition-opacity"
onClick={() => {
setSelectedMetric("disk")
setMetricsDialogOpen(true)
}}
>
<div <div
className={`font-semibold mb-1 ${getUsageColor((selectedVM.disk / selectedVM.maxdisk) * 100)}`} className={`font-semibold mb-1 ${getUsageColor((selectedVM.disk / selectedVM.maxdisk) * 100)}`}
> >
{(selectedVM.disk / 1024 ** 3).toFixed(1)} / {(selectedVM.maxdisk / 1024 ** 3).toFixed(1)} GB {(selectedVM.disk / 1024 ** 3).toFixed(1)} / {(selectedVM.maxdisk / 1024 ** 3).toFixed(1)}{" "}
GB
</div> </div>
<Progress <Progress
value={(selectedVM.disk / selectedVM.maxdisk) * 100} value={(selectedVM.disk / selectedVM.maxdisk) * 100}
className={`h-1.5 ${getModalProgressColor((selectedVM.disk / selectedVM.maxdisk) * 100)}`} className={`h-1.5 ${getModalProgressColor((selectedVM.disk / selectedVM.maxdisk) * 100)}`}
/> />
</div> </div>
</div>
<div> <div>
<div className="text-xs text-muted-foreground mb-1">Uptime</div> <div className="text-xs text-muted-foreground mb-1">Uptime</div>
<div className="font-semibold text-foreground">{formatUptime(selectedVM.uptime)}</div> <div className="font-semibold text-foreground">{formatUptime(selectedVM.uptime)}</div>
</div> </div>
<div> <div>
<div className="text-xs text-muted-foreground mb-1">Disk I/O</div> <div className="text-xs text-muted-foreground mb-1">Disk I/O</div>
<div className="text-sm font-semibold"> <div
<div className="flex items-center gap-1"> className="cursor-pointer hover:opacity-80 transition-opacity"
<span className="text-green-500"> {formatBytes(selectedVM.diskread)}</span> onClick={() => {
setSelectedMetric("disk")
setMetricsDialogOpen(true)
}}
>
<div className="text-sm text-green-500 flex items-center gap-1">
<span></span>
<span>{((selectedVM.diskread || 0) / 1024 ** 2).toFixed(2)} MB</span>
</div> </div>
<div className="flex items-center gap-1"> <div className="text-sm text-blue-500 flex items-center gap-1">
<span className="text-blue-500"> {formatBytes(selectedVM.diskwrite)}</span> <span></span>
<span>{((selectedVM.diskwrite || 0) / 1024 ** 2).toFixed(2)} MB</span>
</div> </div>
</div> </div>
</div> </div>
<div> <div>
<div className="text-xs text-muted-foreground mb-1">Network I/O</div> <div className="text-xs text-muted-foreground mb-1">Network I/O</div>
<div className="text-sm font-semibold"> <div
<div className="flex items-center gap-1"> className="cursor-pointer hover:opacity-80 transition-opacity"
<span className="text-green-500"> {formatBytes(selectedVM.netin)}</span> onClick={() => {
setSelectedMetric("network")
setMetricsDialogOpen(true)
}}
>
<div className="text-sm text-green-500 flex items-center gap-1">
<span></span>
<span>{((selectedVM.netin || 0) / 1024 ** 2).toFixed(2)} MB</span>
</div> </div>
<div className="flex items-center gap-1"> <div className="text-sm text-blue-500 flex items-center gap-1">
<span className="text-blue-500"> {formatBytes(selectedVM.netout)}</span> <span></span>
<span>{((selectedVM.netout || 0) / 1024 ** 2).toFixed(2)} MB</span>
</div> </div>
</div> </div>
</div> </div>
@@ -978,18 +1050,25 @@ export function VirtualMachines() {
<StopCircle className="h-4 w-4 mr-2" /> <StopCircle className="h-4 w-4 mr-2" />
Force Stop Force Stop
</Button> </Button>
<Button
className="w-full col-span-2 bg-purple-600 hover:bg-purple-700 text-white"
disabled={controlLoading}
onClick={() => selectedVM && handleDownloadLogs(selectedVM.vmid, selectedVM.name)}
>
<HardDrive className="h-4 w-4 mr-2" />
Download Logs
</Button>
</div> </div>
</div> </div>
</DialogContent> </DialogContent>
</Dialog> </Dialog>
{/* MetricsDialog component usage */}
{selectedVM && selectedMetric && (
<MetricsDialog
open={metricsDialogOpen}
onClose={() => {
setMetricsDialogOpen(false)
setSelectedMetric(null)
}}
vmid={selectedVM.vmid}
vmName={selectedVM.name}
vmType={selectedVM.type}
metricType={selectedMetric}
/>
)}
</div> </div>
) )
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB