From 19f7ea70f06e93555129cfe4208b4248f4fe2888 Mon Sep 17 00:00:00 2001 From: MacRimi Date: Sun, 5 Oct 2025 14:16:21 +0200 Subject: [PATCH] Update AppImage --- AppImage/components/network-metrics.tsx | 60 ++++++++--- AppImage/components/virtual-machines.tsx | 124 ++++++++++++++++------- 2 files changed, 129 insertions(+), 55 deletions(-) diff --git a/AppImage/components/network-metrics.tsx b/AppImage/components/network-metrics.tsx index 1debcb8..6be8ec9 100644 --- a/AppImage/components/network-metrics.tsx +++ b/AppImage/components/network-metrics.tsx @@ -4,7 +4,7 @@ import { useState } from "react" import { Card, CardContent, CardHeader, CardTitle } from "./ui/card" import { Badge } from "./ui/badge" import { Dialog, DialogContent, DialogHeader, DialogTitle } from "./ui/dialog" -import { Wifi, Activity, Network, Router, AlertCircle, Zap } from "lucide-react" +import { Wifi, Activity, Network, Router, AlertCircle, Zap, Shield } from "lucide-react" import useSWR from "swr" interface NetworkData { @@ -214,6 +214,36 @@ export function NetworkMetrics() { + + + Firewall Status + + + +
Active
+ + Protected + +

System protected

+
+
+ + + + Packets + + + +
{packetsRecvK}K
+ + Received + +

No packet loss

+
+
+ + + {networkData.physical_interfaces && networkData.physical_interfaces.length > 0 && ( @@ -225,20 +255,19 @@ export function NetworkMetrics() { -
+
{networkData.physical_interfaces.map((interface_, index) => { const typeBadge = getInterfaceTypeBadge(interface_.type) return (
setSelectedInterface(interface_)} > - {/* First row: Icon, Name, Type Badge, Status */} -
- -
+
+
+
{interface_.name}
{typeBadge.label} @@ -248,32 +277,31 @@ export function NetworkMetrics() { variant="outline" className={ interface_.status === "up" - ? "bg-green-500/10 text-green-500 border-green-500/20 ml-auto" - : "bg-red-500/10 text-red-500 border-red-500/20 ml-auto" + ? "bg-green-500/10 text-green-500 border-green-500/20" + : "bg-red-500/10 text-red-500 border-red-500/20" } > {interface_.status.toUpperCase()}
- {/* Second row: Details - Responsive layout */} -
+
IP Address
-
+
{interface_.addresses.length > 0 ? interface_.addresses[0].ip : "N/A"}
Speed
-
+
{formatSpeed(interface_.speed)}
-
+
Traffic
↓ {formatBytes(interface_.bytes_recv)} @@ -283,7 +311,7 @@ export function NetworkMetrics() {
{interface_.mac_address && ( -
+
MAC
{interface_.mac_address} @@ -297,7 +325,7 @@ export function NetworkMetrics() {
-
+ )} {networkData.bridge_interfaces && networkData.bridge_interfaces.length > 0 && ( diff --git a/AppImage/components/virtual-machines.tsx b/AppImage/components/virtual-machines.tsx index 8126b85..75abecd 100644 --- a/AppImage/components/virtual-machines.tsx +++ b/AppImage/components/virtual-machines.tsx @@ -1,6 +1,6 @@ "use client" -import { useState } from "react" +import { useState, useMemo } from "react" import { Card, CardContent, CardHeader, CardTitle } from "./ui/card" import { Badge } from "./ui/badge" import { Progress } from "./ui/progress" @@ -18,6 +18,7 @@ import { Power, RotateCcw, StopCircle, + AlertTriangle, } from "lucide-react" import useSWR from "swr" @@ -227,6 +228,29 @@ export function VirtualMachines() { // Safe data handling with default empty array const safeVMData = vmData || [] + const totalAllocatedMemoryGB = useMemo(() => { + return (safeVMData.reduce((sum, vm) => sum + (vm.maxmem || 0), 0) / 1024 ** 3).toFixed(1) + }, [safeVMData]) + + const { data: overviewData } = useSWR("/api/overview", fetcher, { + refreshInterval: 30000, + revalidateOnFocus: false, + }) + + const physicalMemoryGB = useMemo(() => { + if (overviewData && overviewData.memory) { + return (overviewData.memory.total / 1024 ** 3).toFixed(1) + } + return null + }, [overviewData]) + + const isMemoryOvercommit = useMemo(() => { + if (physicalMemoryGB) { + return Number.parseFloat(totalAllocatedMemoryGB) > Number.parseFloat(physicalMemoryGB) + } + return false + }, [totalAllocatedMemoryGB, physicalMemoryGB]) + if (isLoading) { return (
@@ -279,16 +303,26 @@ export function VirtualMachines() { - + Total Memory - +
+ {isMemoryOvercommit && } + +
-
- {(safeVMData.reduce((sum, vm) => sum + (vm.maxmem || 0), 0) / 1024 ** 3).toFixed(1)} GB +
+ {totalAllocatedMemoryGB} GB
-

Allocated RAM

+ {isMemoryOvercommit ? ( +

+ + Overcommit: Excede memoria física ({physicalMemoryGB} GB) +

+ ) : ( +

Allocated RAM

+ )} @@ -339,13 +373,13 @@ export function VirtualMachines() { className="p-6 rounded-lg border border-border bg-card/50 hover:bg-card/80 transition-colors cursor-pointer" onClick={() => handleVMClick(vm)} > -
+
- -
-
- {vm.name} - + +
+
+ {vm.name} + {typeBadge.label}
@@ -353,12 +387,13 @@ export function VirtualMachines() {
-
- - {getStatusIcon(vm.status)} - {vm.status.toUpperCase()} - -
+ + {getStatusIcon(vm.status)} + {vm.status.toUpperCase()} +
@@ -376,7 +411,7 @@ export function VirtualMachines() {
-
+
Disk I/O
@@ -390,7 +425,7 @@ export function VirtualMachines() {
-
+
Network I/O
@@ -427,15 +462,17 @@ export function VirtualMachines() { > - - - {selectedVM?.name} + +
+ + {selectedVM?.name} +
{selectedVM && ( -
- +
+ {getTypeBadge(selectedVM.type).label} - + {selectedVM.status.toUpperCase()}
@@ -446,7 +483,6 @@ export function VirtualMachines() {
{selectedVM && ( <> - {/* Basic Information */}

Basic Information @@ -456,22 +492,10 @@ export function VirtualMachines() {
Name
{selectedVM.name}

-
-
Type
- - {getTypeBadge(selectedVM.type).label} - -
VMID
{selectedVM.vmid}
-
-
Status
- - {selectedVM.status.toUpperCase()} - -
CPU Usage
Uptime
{formatUptime(selectedVM.uptime)}
+
+
Disk I/O
+
+
+ ↓ {formatBytes(selectedVM.diskread)} +
+
+ ↑ {formatBytes(selectedVM.diskwrite)} +
+
+
+
+
Network I/O
+
+
+ ↓ {formatBytes(selectedVM.netin)} +
+
+ ↑ {formatBytes(selectedVM.netout)} +
+
+