+ {networkData.bridge_interfaces.map((interface_, index) => {
+ const typeBadge = getInterfaceTypeBadge(interface_.type)
- return (
-
setSelectedInterface(interface_)}
- >
- {/* First row: Icon, Name, Type Badge, Physical Interface, Status */}
-
-
-
-
{interface_.name}
-
- {typeBadge.label}
-
- {interface_.bridge_physical_interface && (
-
- → {interface_.bridge_physical_interface}
- {interface_.bridge_physical_interface.startsWith("bond") &&
- networkData.physical_interfaces && (
- <>
- {(() => {
- const bondInterface = networkData.physical_interfaces.find(
- (iface) => iface.name === interface_.bridge_physical_interface,
- )
- if (bondInterface?.bond_slaves && bondInterface.bond_slaves.length > 0) {
- return (
-
- ({bondInterface.bond_slaves.join(", ")})
-
+ return (
+
setSelectedInterface(interface_)}
+ >
+ {/* First row: Icon, Name, Type Badge, Physical Interface, Status */}
+
+
+
+
{interface_.name}
+
+ {typeBadge.label}
+
+ {interface_.bridge_physical_interface && (
+
+ → {interface_.bridge_physical_interface}
+ {interface_.bridge_physical_interface.startsWith("bond") &&
+ networkData.physical_interfaces && (
+ <>
+ {(() => {
+ const bondInterface = networkData.physical_interfaces.find(
+ (iface) => iface.name === interface_.bridge_physical_interface,
)
- }
- return null
- })()}
- >
+ if (bondInterface?.bond_slaves && bondInterface.bond_slaves.length > 0) {
+ return (
+
+ ({bondInterface.bond_slaves.join(", ")})
+
+ )
+ }
+ return null
+ })()}
+ >
+ )}
+ {interface_.bridge_bond_slaves && interface_.bridge_bond_slaves.length > 0 && (
+
+ ({interface_.bridge_bond_slaves.join(", ")})
+
)}
- {interface_.bridge_bond_slaves && interface_.bridge_bond_slaves.length > 0 && (
-
- ({interface_.bridge_bond_slaves.join(", ")})
-
- )}
-
- )}
-
-
- {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)}
- {" / "}
- ↑ {formatBytes(interface_.bytes_sent)}
-
-
-
- {interface_.mac_address && (
-
-
MAC
-
- {interface_.mac_address}
-
-
- )}
-
-
- )
- })}
-
-
-
- )}
-
- {networkData.vm_lxc_interfaces && networkData.vm_lxc_interfaces.length > 0 && (
-
-
-
-
- VM & LXC Network Interfaces
-
- {networkData.vm_lxc_active_count ?? 0} / {networkData.vm_lxc_total_count ?? 0} Active
-
-
-
-
-
- {networkData.vm_lxc_interfaces.map((interface_, index) => {
- const vmTypeBadge = getVMTypeBadge(interface_.vm_type)
-
- return (
-
setSelectedInterface(interface_)}
- >
- {/* First row: Icon, Name, VM/LXC Badge, VM Name, Status */}
-
-
-
-
{interface_.name}
-
- {vmTypeBadge.label}
+
+ {interface_.status.toUpperCase()}
- {interface_.vm_name && (
- → {interface_.vm_name}
- )}
-
-
- {interface_.status.toUpperCase()}
-
-
-
- {/* Second row: Details - Responsive layout */}
-
-
-
VMID
-
{interface_.vmid ?? "N/A"}
-
-
Speed
-
-
- {formatSpeed(interface_.speed)}
-
-
-
-
-
Traffic
-
- ↓ {formatBytes(interface_.bytes_recv)}
- {" / "}
- ↑ {formatBytes(interface_.bytes_sent)}
-
-
-
- {interface_.mac_address && (
-
-
MAC
-
- {interface_.mac_address}
+ {/* 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)}
+ {" / "}
+ ↑ {formatBytes(interface_.bytes_sent)}
+
+
+
+ {interface_.mac_address && (
+
+
MAC
+
+ {interface_.mac_address}
+
+
+ )}
+
-
- )
- })}
-
-
-
- )}
+ )
+ })}
+
+
+
+ )}
+
+ {networkData.vm_lxc_interfaces && networkData.vm_lxc_interfaces.length > 0 && (
+
+
+
+
+ VM & LXC Network Interfaces
+
+ {networkData.vm_lxc_active_count ?? 0} / {networkData.vm_lxc_total_count ?? 0} Active
+
+
+
+
+
+ {networkData.vm_lxc_interfaces.map((interface_, index) => {
+ const vmTypeBadge = getVMTypeBadge(interface_.vm_type)
+
+ return (
+
setSelectedInterface(interface_)}
+ >
+ {/* First row: Icon, Name, VM/LXC Badge, VM Name, Status */}
+
+
+
+
{interface_.name}
+
+ {vmTypeBadge.label}
+
+ {interface_.vm_name && (
+
→ {interface_.vm_name}
+ )}
+
+
+ {interface_.status.toUpperCase()}
+
+
+
+ {/* Second row: Details - Responsive layout */}
+
+
+
VMID
+
{interface_.vmid ?? "N/A"}
+
+
+
+
Speed
+
+
+ {formatSpeed(interface_.speed)}
+
+
+
+
+
Traffic
+
+ ↓ {formatBytes(interface_.bytes_recv)}
+ {" / "}
+ ↑ {formatBytes(interface_.bytes_sent)}
+
+
+
+ {interface_.mac_address && (
+
+
MAC
+
+ {interface_.mac_address}
+
+
+ )}
+
+
+ )
+ })}
+
+
+
+ )}
+
{/* Interface Details Modal */}
)}
{selectedInterface.type === "vm_lxc" && selectedInterface.vm_name && (
diff --git a/AppImage/components/virtual-machines.tsx b/AppImage/components/virtual-machines.tsx
index 75abecd..ac5c561 100644
--- a/AppImage/components/virtual-machines.tsx
+++ b/AppImage/components/virtual-machines.tsx
@@ -19,6 +19,7 @@ import {
RotateCcw,
StopCircle,
AlertTriangle,
+ CheckCircle,
} from "lucide-react"
import useSWR from "swr"
@@ -37,6 +38,7 @@ interface VMData {
netout?: number
diskread?: number
diskwrite?: number
+ ipaddress?: string
}
interface VMConfig {
@@ -251,6 +253,32 @@ export function VirtualMachines() {
return false
}, [totalAllocatedMemoryGB, physicalMemoryGB])
+ const getMemoryOvercommitBadge = () => {
+ if (!physicalMemoryGB) return null
+
+ const allocated = Number.parseFloat(totalAllocatedMemoryGB)
+ const physical = Number.parseFloat(physicalMemoryGB)
+ const overcommitPercent = ((allocated / physical) * 100).toFixed(0)
+
+ if (allocated > physical) {
+ return {
+ color: "bg-yellow-500/10 text-yellow-500 border-yellow-500/20",
+ icon:
,
+ label: "Overcommit",
+ message: `${overcommitPercent}% de memoria física`,
+ }
+ }
+
+ return {
+ color: "bg-green-500/10 text-green-500 border-green-500/20",
+ icon:
,
+ label: "Normal",
+ message: `${overcommitPercent}% de memoria física`,
+ }
+ }
+
+ const memoryBadge = getMemoryOvercommitBadge()
+
if (isLoading) {
return (
@@ -306,22 +334,20 @@ export function VirtualMachines() {
Total Memory
-
- {isMemoryOvercommit &&
}
-
-
+
{totalAllocatedMemoryGB} GB
- {isMemoryOvercommit ? (
-
-
- Overcommit: Excede memoria física ({physicalMemoryGB} GB)
-
- ) : (
- Allocated RAM
+ {memoryBadge && (
+
+
+ {memoryBadge.icon}
+ {memoryBadge.label}
+
+
{memoryBadge.message}
+
)}
@@ -396,6 +422,13 @@ export function VirtualMachines() {
+ {vm.type === "lxc" && vm.ipaddress && (
+
+
IP Address
+
{vm.ipaddress}
+
+ )}
+
CPU Usage
@@ -496,6 +529,12 @@ export function VirtualMachines() {
VMID
{selectedVM.vmid}
+ {selectedVM.type === "lxc" && selectedVM.ipaddress && (
+
+
IP Address
+
{selectedVM.ipaddress}
+
+ )}
CPU Usage
Uptime
-
{formatUptime(selectedVM.uptime)}
+
{formatUptime(selectedVM.uptime)}