Update virtual-machines.tsx

This commit is contained in:
MacRimi
2025-10-05 17:01:50 +02:00
parent fbcf755591
commit 79e7fd175e

View File

@@ -1,6 +1,6 @@
"use client"
import { useState, useMemo } from "react"
import { useState, useMemo, useEffect } from "react"
import { Card, CardContent, CardHeader, CardTitle } from "./ui/card"
import { Badge } from "./ui/badge"
import { Progress } from "./ui/progress"
@@ -36,6 +36,7 @@ interface VMData {
netout?: number
diskread?: number
diskwrite?: number
ip?: string
}
interface VMConfig {
@@ -109,8 +110,8 @@ const extractIPFromConfig = (config?: VMConfig): string => {
const netConfig = config[netKey]
if (netConfig && typeof netConfig === "string") {
// Look for ip=x.x.x.x/xx pattern
const ipMatch = netConfig.match(/ip=([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})(\/\d+)?/)
// Look for ip=x.x.x.x/xx or ip=x.x.x.x pattern
const ipMatch = netConfig.match(/ip=([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})/)
if (ipMatch) {
return ipMatch[1] // Return just the IP without CIDR
}
@@ -141,6 +142,36 @@ export function VirtualMachines() {
const [vmDetails, setVMDetails] = useState<VMDetails | null>(null)
const [controlLoading, setControlLoading] = useState(false)
const [detailsLoading, setDetailsLoading] = useState(false)
const [vmConfigs, setVmConfigs] = useState<Record<number, string>>({})
useEffect(() => {
const fetchLXCIPs = async () => {
if (!vmData) return
const lxcs = vmData.filter((vm) => vm.type === "lxc")
const configs: Record<number, string> = {}
await Promise.all(
lxcs.map(async (lxc) => {
try {
const response = await fetch(`/api/vms/${lxc.vmid}`)
if (response.ok) {
const details = await response.json()
if (details.config) {
configs[lxc.vmid] = extractIPFromConfig(details.config)
}
}
} catch (error) {
console.error(`Error fetching config for LXC ${lxc.vmid}:`, error)
}
}),
)
setVmConfigs(configs)
}
fetchLXCIPs()
}, [vmData])
const handleVMClick = async (vm: VMData) => {
setSelectedVM(vm)
@@ -249,7 +280,6 @@ export function VirtualMachines() {
return { color: "bg-purple-500/10 text-purple-500 border-purple-500/20", label: "VM" }
}
// Safe data handling with default empty array
const safeVMData = vmData || []
const totalAllocatedMemoryGB = useMemo(() => {
@@ -293,7 +323,6 @@ export function VirtualMachines() {
return (
<div className="space-y-6">
{/* VM Overview Cards */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
<Card className="bg-card border-border">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
@@ -350,6 +379,20 @@ export function VirtualMachines() {
</CardContent>
</Card>
<Card className="bg-card border-border">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium text-muted-foreground">Total Disk</CardTitle>
<HardDrive className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold text-foreground">
{(safeVMData.reduce((sum, vm) => sum + (vm.maxdisk || 0), 0) / 1024 ** 3).toFixed(1)} GB
</div>
<p className="text-xs text-muted-foreground mt-2">Allocated disk space</p>
</CardContent>
</Card>
</div>
<Card className="bg-card border-border">
<CardHeader>
<CardTitle className="text-foreground flex items-center">
@@ -368,7 +411,7 @@ export function VirtualMachines() {
const memGB = (vm.mem / 1024 ** 3).toFixed(1)
const maxMemGB = (vm.maxmem / 1024 ** 3).toFixed(1)
const typeBadge = getTypeBadge(vm.type)
const vmIP = extractIPFromConfig(vm.config)
const lxcIP = vm.type === "lxc" ? vmConfigs[vm.vmid] : null
return (
<div
@@ -379,15 +422,29 @@ export function VirtualMachines() {
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 mb-4">
<div className="flex items-center space-x-4">
<Server className="h-6 w-6 text-muted-foreground flex-shrink-0" />
<div className="min-w-0">
<div className="min-w-0 flex-1">
<div className="font-semibold text-foreground text-lg flex items-center flex-wrap gap-2">
<span className="truncate">{vm.name}</span>
<Badge variant="outline" className={`text-xs flex-shrink-0 ${typeBadge.color}`}>
{typeBadge.label}
</Badge>
</div>
<div className="flex items-center gap-2 flex-wrap">
<div className="text-sm text-muted-foreground">ID: {vm.vmid}</div>
<div className="text-sm text-muted-foreground">IP: {vmIP}</div>
{lxcIP && (
<>
<span className="text-muted-foreground"></span>
<div className="flex items-center gap-1 text-sm">
<Network
className={`h-3 w-3 ${lxcIP === "DHCP" ? "text-yellow-500" : "text-green-500"}`}
/>
<span className={lxcIP === "DHCP" ? "text-yellow-500" : "text-green-500"}>
IP: {lxcIP}
</span>
</div>
</>
)}
</div>
</div>
</div>
@@ -456,7 +513,6 @@ export function VirtualMachines() {
</CardContent>
</Card>
{/* VM Details Modal */}
<Dialog
open={!!selectedVM}
onOpenChange={() => {
@@ -563,7 +619,6 @@ export function VirtualMachines() {
</div>
</div>
{/* Resources Configuration */}
{detailsLoading ? (
<div className="text-center py-8 text-muted-foreground">Loading configuration...</div>
) : vmDetails?.config ? (
@@ -620,7 +675,6 @@ export function VirtualMachines() {
</div>
</div>
{/* Network Configuration */}
<div>
<h3 className="text-sm font-semibold text-muted-foreground mb-3 uppercase tracking-wide">
Network
@@ -659,7 +713,6 @@ export function VirtualMachines() {
</div>
</div>
{/* Options */}
<div>
<h3 className="text-sm font-semibold text-muted-foreground mb-3 uppercase tracking-wide">
Options
@@ -724,7 +777,6 @@ export function VirtualMachines() {
</>
) : null}
{/* Control Actions */}
<div>
<h3 className="text-sm font-semibold text-muted-foreground mb-3 uppercase tracking-wide">
Control Actions
@@ -774,6 +826,5 @@ export function VirtualMachines() {
</DialogContent>
</Dialog>
</div>
</div>
)
}