mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2025-11-18 03:26:17 +00:00
Update AppImage
This commit is contained in:
@@ -640,20 +640,22 @@ export function NetworkMetrics() {
|
|||||||
<Router className="h-5 w-5" />
|
<Router className="h-5 w-5" />
|
||||||
{selectedInterface?.name} - Interface Details
|
{selectedInterface?.name} - Interface Details
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<div className="flex justify-end pt-2">
|
{selectedInterface?.status.toLowerCase() === "up" && selectedInterface?.vm_type !== "vm" && (
|
||||||
<Select value={modalTimeframe} onValueChange={(value: any) => setModalTimeframe(value)}>
|
<div className="flex justify-end pt-2">
|
||||||
<SelectTrigger className="w-[140px] bg-card border-border">
|
<Select value={modalTimeframe} onValueChange={(value: any) => setModalTimeframe(value)}>
|
||||||
<SelectValue />
|
<SelectTrigger className="w-[140px] bg-card border-border">
|
||||||
</SelectTrigger>
|
<SelectValue />
|
||||||
<SelectContent>
|
</SelectTrigger>
|
||||||
<SelectItem value="hour">1 Hour</SelectItem>
|
<SelectContent>
|
||||||
<SelectItem value="day">24 Hours</SelectItem>
|
<SelectItem value="hour">1 Hour</SelectItem>
|
||||||
<SelectItem value="week">7 Days</SelectItem>
|
<SelectItem value="day">24 Hours</SelectItem>
|
||||||
<SelectItem value="month">30 Days</SelectItem>
|
<SelectItem value="week">7 Days</SelectItem>
|
||||||
<SelectItem value="year">1 Year</SelectItem>
|
<SelectItem value="month">30 Days</SelectItem>
|
||||||
</SelectContent>
|
<SelectItem value="year">1 Year</SelectItem>
|
||||||
</Select>
|
</SelectContent>
|
||||||
</div>
|
</Select>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
{selectedInterface && (
|
{selectedInterface && (
|
||||||
@@ -789,99 +791,122 @@ export function NetworkMetrics() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div>
|
{/* Network Traffic Statistics - Only show if interface is UP and NOT a VM interface */}
|
||||||
<h3 className="text-sm font-semibold text-muted-foreground mb-4">
|
{selectedInterface.status.toLowerCase() === "up" && selectedInterface.vm_type !== "vm" ? (
|
||||||
Network Traffic Statistics (
|
<div>
|
||||||
{modalTimeframe === "hour"
|
<h3 className="text-sm font-semibold text-muted-foreground mb-4">
|
||||||
? "Last Hour"
|
Network Traffic Statistics (
|
||||||
: modalTimeframe === "day"
|
{modalTimeframe === "hour"
|
||||||
? "Last 24 Hours"
|
? "Last Hour"
|
||||||
: modalTimeframe === "week"
|
: modalTimeframe === "day"
|
||||||
? "Last 7 Days"
|
? "Last 24 Hours"
|
||||||
: modalTimeframe === "month"
|
: modalTimeframe === "week"
|
||||||
? "Last 30 Days"
|
? "Last 7 Days"
|
||||||
: "Last Year"}
|
: modalTimeframe === "month"
|
||||||
)
|
? "Last 30 Days"
|
||||||
</h3>
|
: "Last Year"}
|
||||||
<div className="space-y-4">
|
)
|
||||||
{/* Traffic Data - Top Row */}
|
</h3>
|
||||||
|
<div className="space-y-4">
|
||||||
|
{/* Traffic Data - Top Row */}
|
||||||
|
<div className="grid grid-cols-2 gap-4">
|
||||||
|
<div>
|
||||||
|
<div className="text-sm text-muted-foreground">Bytes Received</div>
|
||||||
|
<div className="font-medium text-green-500 text-lg">
|
||||||
|
{formatStorage(interfaceTotals.received * 1024 * 1024 * 1024)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="text-sm text-muted-foreground">Bytes Sent</div>
|
||||||
|
<div className="font-medium text-blue-500 text-lg">
|
||||||
|
{formatStorage(interfaceTotals.sent * 1024 * 1024 * 1024)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Network Traffic Chart - Full Width Below */}
|
||||||
|
<div className="bg-muted/30 rounded-lg p-4">
|
||||||
|
<NetworkTrafficChart
|
||||||
|
timeframe={modalTimeframe}
|
||||||
|
interfaceName={selectedInterface.name}
|
||||||
|
onTotalsCalculated={setInterfaceTotals}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : selectedInterface.status.toLowerCase() === "up" && selectedInterface.vm_type === "vm" ? (
|
||||||
|
<div className="bg-muted/30 rounded-lg p-6 text-center">
|
||||||
|
<AlertCircle className="h-12 w-12 text-muted-foreground mx-auto mb-3" />
|
||||||
|
<h3 className="text-lg font-semibold text-foreground mb-2">Historical Metrics Not Available</h3>
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
Proxmox does not store historical network metrics for individual VM interfaces. Only cumulative
|
||||||
|
statistics since last boot are available below.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="bg-muted/30 rounded-lg p-6 text-center">
|
||||||
|
<AlertCircle className="h-12 w-12 text-muted-foreground mx-auto mb-3" />
|
||||||
|
<h3 className="text-lg font-semibold text-foreground mb-2">Interface Inactive</h3>
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
This interface is currently down. Network traffic statistics are not available.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Cumulative Statistics - Only show if interface is UP */}
|
||||||
|
{selectedInterface.status.toLowerCase() === "up" && (
|
||||||
|
<div>
|
||||||
|
<h3 className="text-sm font-semibold text-muted-foreground mb-4">
|
||||||
|
Cumulative Statistics (Since Last Boot)
|
||||||
|
</h3>
|
||||||
<div className="grid grid-cols-2 gap-4">
|
<div className="grid grid-cols-2 gap-4">
|
||||||
<div>
|
<div>
|
||||||
<div className="text-sm text-muted-foreground">Bytes Received</div>
|
<div className="text-sm text-muted-foreground">Packets Received</div>
|
||||||
<div className="font-medium text-green-500 text-lg">
|
<div className="font-medium">{selectedInterface.packets_recv?.toLocaleString() || "N/A"}</div>
|
||||||
{formatStorage(interfaceTotals.received * 1024 * 1024 * 1024)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="text-sm text-muted-foreground">Bytes Sent</div>
|
<div className="text-sm text-muted-foreground">Packets Sent</div>
|
||||||
<div className="font-medium text-blue-500 text-lg">
|
<div className="font-medium">{selectedInterface.packets_sent?.toLocaleString() || "N/A"}</div>
|
||||||
{formatStorage(interfaceTotals.sent * 1024 * 1024 * 1024)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div>
|
||||||
|
<div className="text-sm text-muted-foreground">Errors In</div>
|
||||||
{/* Network Traffic Chart - Full Width Below */}
|
<div className="font-medium text-red-500">{selectedInterface.errors_in || 0}</div>
|
||||||
<div className="bg-muted/30 rounded-lg p-4">
|
</div>
|
||||||
<NetworkTrafficChart
|
<div>
|
||||||
timeframe={modalTimeframe}
|
<div className="text-sm text-muted-foreground">Errors Out</div>
|
||||||
interfaceName={selectedInterface.name}
|
<div className="font-medium text-red-500">{selectedInterface.errors_out || 0}</div>
|
||||||
onTotalsCalculated={setInterfaceTotals}
|
</div>
|
||||||
/>
|
<div>
|
||||||
|
<div className="text-sm text-muted-foreground">Drops In</div>
|
||||||
|
<div className="font-medium text-yellow-500">{selectedInterface.drops_in || 0}</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="text-sm text-muted-foreground">Drops Out</div>
|
||||||
|
<div className="font-medium text-yellow-500">{selectedInterface.drops_out || 0}</div>
|
||||||
|
</div>
|
||||||
|
{selectedInterface.packet_loss_in !== undefined && (
|
||||||
|
<div>
|
||||||
|
<div className="text-sm text-muted-foreground">Packet Loss In</div>
|
||||||
|
<div
|
||||||
|
className={`font-medium ${selectedInterface.packet_loss_in > 1 ? "text-red-500" : "text-green-500"}`}
|
||||||
|
>
|
||||||
|
{selectedInterface.packet_loss_in}%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{selectedInterface.packet_loss_out !== undefined && (
|
||||||
|
<div>
|
||||||
|
<div className="text-sm text-muted-foreground">Packet Loss Out</div>
|
||||||
|
<div
|
||||||
|
className={`font-medium ${selectedInterface.packet_loss_out > 1 ? "text-red-500" : "text-green-500"}`}
|
||||||
|
>
|
||||||
|
{selectedInterface.packet_loss_out}%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
|
|
||||||
<div>
|
|
||||||
<h3 className="text-sm font-semibold text-muted-foreground mb-4">
|
|
||||||
Cumulative Statistics (Since Last Boot)
|
|
||||||
</h3>
|
|
||||||
<div className="grid grid-cols-2 gap-4">
|
|
||||||
<div>
|
|
||||||
<div className="text-sm text-muted-foreground">Packets Received</div>
|
|
||||||
<div className="font-medium">{selectedInterface.packets_recv?.toLocaleString() || "N/A"}</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm text-muted-foreground">Packets Sent</div>
|
|
||||||
<div className="font-medium">{selectedInterface.packets_sent?.toLocaleString() || "N/A"}</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm text-muted-foreground">Errors In</div>
|
|
||||||
<div className="font-medium text-red-500">{selectedInterface.errors_in || 0}</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm text-muted-foreground">Errors Out</div>
|
|
||||||
<div className="font-medium text-red-500">{selectedInterface.errors_out || 0}</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm text-muted-foreground">Drops In</div>
|
|
||||||
<div className="font-medium text-yellow-500">{selectedInterface.drops_in || 0}</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm text-muted-foreground">Drops Out</div>
|
|
||||||
<div className="font-medium text-yellow-500">{selectedInterface.drops_out || 0}</div>
|
|
||||||
</div>
|
|
||||||
{selectedInterface.packet_loss_in !== undefined && (
|
|
||||||
<div>
|
|
||||||
<div className="text-sm text-muted-foreground">Packet Loss In</div>
|
|
||||||
<div
|
|
||||||
className={`font-medium ${selectedInterface.packet_loss_in > 1 ? "text-red-500" : "text-green-500"}`}
|
|
||||||
>
|
|
||||||
{selectedInterface.packet_loss_in}%
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{selectedInterface.packet_loss_out !== undefined && (
|
|
||||||
<div>
|
|
||||||
<div className="text-sm text-muted-foreground">Packet Loss Out</div>
|
|
||||||
<div
|
|
||||||
className={`font-medium ${selectedInterface.packet_loss_out > 1 ? "text-red-500" : "text-green-500"}`}
|
|
||||||
>
|
|
||||||
{selectedInterface.packet_loss_out}%
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Bond Information */}
|
{/* Bond Information */}
|
||||||
{selectedInterface.type === "bond" && selectedInterface.bond_slaves && (
|
{selectedInterface.type === "bond" && selectedInterface.bond_slaves && (
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ export function NetworkTrafficChart({ timeframe, interfaceName, onTotalsCalculat
|
|||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-center h-[200px]">
|
<div className="flex items-center justify-center h-[300px]">
|
||||||
<Loader2 className="h-8 w-8 animate-spin text-muted-foreground" />
|
<Loader2 className="h-8 w-8 animate-spin text-muted-foreground" />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
@@ -191,7 +191,7 @@ export function NetworkTrafficChart({ timeframe, interfaceName, onTotalsCalculat
|
|||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col items-center justify-center h-[200px] gap-2">
|
<div className="flex flex-col items-center justify-center h-[300px] gap-2">
|
||||||
<p className="text-muted-foreground text-sm">Network metrics not available yet</p>
|
<p className="text-muted-foreground text-sm">Network metrics not available yet</p>
|
||||||
<p className="text-xs text-red-500">{error}</p>
|
<p className="text-xs text-red-500">{error}</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -200,15 +200,15 @@ export function NetworkTrafficChart({ timeframe, interfaceName, onTotalsCalculat
|
|||||||
|
|
||||||
if (data.length === 0) {
|
if (data.length === 0) {
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-center h-[200px]">
|
<div className="flex items-center justify-center h-[300px]">
|
||||||
<p className="text-muted-foreground text-sm">No network metrics available</p>
|
<p className="text-muted-foreground text-sm">No network metrics available</p>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ResponsiveContainer width="100%" height={200}>
|
<ResponsiveContainer width="100%" height={300}>
|
||||||
<AreaChart data={data} margin={{ bottom: 40, left: 10, right: 10 }}>
|
<AreaChart data={data} margin={{ bottom: 80, left: 10 }}>
|
||||||
<CartesianGrid strokeDasharray="3 3" stroke="currentColor" className="text-border" />
|
<CartesianGrid strokeDasharray="3 3" stroke="currentColor" className="text-border" />
|
||||||
<XAxis
|
<XAxis
|
||||||
dataKey="time"
|
dataKey="time"
|
||||||
@@ -217,7 +217,7 @@ export function NetworkTrafficChart({ timeframe, interfaceName, onTotalsCalculat
|
|||||||
tick={{ fill: "currentColor", fontSize: 12 }}
|
tick={{ fill: "currentColor", fontSize: 12 }}
|
||||||
angle={-45}
|
angle={-45}
|
||||||
textAnchor="end"
|
textAnchor="end"
|
||||||
height={40}
|
height={60}
|
||||||
interval={tickInterval}
|
interval={tickInterval}
|
||||||
/>
|
/>
|
||||||
<YAxis
|
<YAxis
|
||||||
|
|||||||
Reference in New Issue
Block a user