mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2025-11-18 11:36:17 +00:00
Update network-metrics.tsx
This commit is contained in:
@@ -157,6 +157,12 @@ export function NetworkMetrics() {
|
|||||||
const [networkTotals, setNetworkTotals] = useState<{ received: number; sent: number }>({ received: 0, sent: 0 })
|
const [networkTotals, setNetworkTotals] = useState<{ received: number; sent: number }>({ received: 0, sent: 0 })
|
||||||
const [interfaceTotals, setInterfaceTotals] = useState<{ received: number; sent: number }>({ received: 0, sent: 0 })
|
const [interfaceTotals, setInterfaceTotals] = useState<{ received: number; sent: number }>({ received: 0, sent: 0 })
|
||||||
|
|
||||||
|
const { data: modalNetworkData } = useSWR<NetworkData>(selectedInterface ? "/api/network" : null, fetcher, {
|
||||||
|
refreshInterval: 15000, // Refresh every 15 seconds when modal is open
|
||||||
|
revalidateOnFocus: false,
|
||||||
|
revalidateOnReconnect: true,
|
||||||
|
})
|
||||||
|
|
||||||
const { data: interfaceHistoricalData } = useSWR<any>(`/api/node/metrics?timeframe=${timeframe}`, fetcher, {
|
const { data: interfaceHistoricalData } = useSWR<any>(`/api/node/metrics?timeframe=${timeframe}`, fetcher, {
|
||||||
refreshInterval: 30000,
|
refreshInterval: 30000,
|
||||||
revalidateOnFocus: false,
|
revalidateOnFocus: false,
|
||||||
@@ -220,7 +226,11 @@ export function NetworkMetrics() {
|
|||||||
...(networkData.vm_lxc_interfaces || []),
|
...(networkData.vm_lxc_interfaces || []),
|
||||||
]
|
]
|
||||||
|
|
||||||
const vmLxcInterfaces = networkData.vm_lxc_interfaces || []
|
const vmLxcInterfaces = (networkData.vm_lxc_interfaces || []).sort((a, b) => {
|
||||||
|
const vmidA = a.vmid ?? Number.MAX_SAFE_INTEGER
|
||||||
|
const vmidB = b.vmid ?? Number.MAX_SAFE_INTEGER
|
||||||
|
return vmidA - vmidB
|
||||||
|
})
|
||||||
|
|
||||||
const topInterface =
|
const topInterface =
|
||||||
vmLxcInterfaces.length > 0
|
vmLxcInterfaces.length > 0
|
||||||
@@ -586,7 +596,7 @@ export function NetworkMetrics() {
|
|||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{networkData.vm_lxc_interfaces.map((interface_, index) => {
|
{vmLxcInterfaces.map((interface_, index) => {
|
||||||
const vmTypeBadge = getVMTypeBadge(interface_.vm_type)
|
const vmTypeBadge = getVMTypeBadge(interface_.vm_type)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -688,32 +698,46 @@ export function NetworkMetrics() {
|
|||||||
|
|
||||||
{selectedInterface && (
|
{selectedInterface && (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
|
{(() => {
|
||||||
|
// Find the current interface data from modalNetworkData if available
|
||||||
|
const currentInterfaceData = modalNetworkData
|
||||||
|
? [
|
||||||
|
...(modalNetworkData.physical_interfaces || []),
|
||||||
|
...(modalNetworkData.bridge_interfaces || []),
|
||||||
|
...(modalNetworkData.vm_lxc_interfaces || []),
|
||||||
|
].find((iface) => iface.name === selectedInterface.name)
|
||||||
|
: selectedInterface
|
||||||
|
|
||||||
|
const displayInterface = currentInterfaceData || selectedInterface
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
{/* Basic Information */}
|
{/* Basic Information */}
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-sm font-semibold text-muted-foreground mb-3">Basic Information</h3>
|
<h3 className="text-sm font-semibold text-muted-foreground mb-3">Basic Information</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">Interface Name</div>
|
<div className="text-sm text-muted-foreground">Interface Name</div>
|
||||||
<div className="font-medium">{selectedInterface.name}</div>
|
<div className="font-medium">{displayInterface.name}</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="text-sm text-muted-foreground">Type</div>
|
<div className="text-sm text-muted-foreground">Type</div>
|
||||||
<Badge variant="outline" className={getInterfaceTypeBadge(selectedInterface.type).color}>
|
<Badge variant="outline" className={getInterfaceTypeBadge(displayInterface.type).color}>
|
||||||
{getInterfaceTypeBadge(selectedInterface.type).label}
|
{getInterfaceTypeBadge(displayInterface.type).label}
|
||||||
</Badge>
|
</Badge>
|
||||||
</div>
|
</div>
|
||||||
{selectedInterface.type === "bridge" && selectedInterface.bridge_physical_interface && (
|
{displayInterface.type === "bridge" && displayInterface.bridge_physical_interface && (
|
||||||
<div className="col-span-2">
|
<div className="col-span-2">
|
||||||
<div className="text-sm text-muted-foreground">Physical Interface</div>
|
<div className="text-sm text-muted-foreground">Physical Interface</div>
|
||||||
<div className="font-medium text-blue-500 text-lg break-all">
|
<div className="font-medium text-blue-500 text-lg break-all">
|
||||||
{selectedInterface.bridge_physical_interface}
|
{displayInterface.bridge_physical_interface}
|
||||||
</div>
|
</div>
|
||||||
{selectedInterface.bridge_physical_interface.startsWith("bond") &&
|
{displayInterface.bridge_physical_interface.startsWith("bond") &&
|
||||||
networkData?.physical_interfaces && (
|
modalNetworkData?.physical_interfaces && (
|
||||||
<>
|
<>
|
||||||
{(() => {
|
{(() => {
|
||||||
const bondInterface = networkData.physical_interfaces.find(
|
const bondInterface = modalNetworkData.physical_interfaces.find(
|
||||||
(iface) => iface.name === selectedInterface.bridge_physical_interface,
|
(iface) => iface.name === displayInterface.bridge_physical_interface,
|
||||||
)
|
)
|
||||||
if (bondInterface?.bond_slaves && bondInterface.bond_slaves.length > 0) {
|
if (bondInterface?.bond_slaves && bondInterface.bond_slaves.length > 0) {
|
||||||
return (
|
return (
|
||||||
@@ -737,11 +761,11 @@ export function NetworkMetrics() {
|
|||||||
})()}
|
})()}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{selectedInterface.bridge_bond_slaves && selectedInterface.bridge_bond_slaves.length > 0 && (
|
{displayInterface.bridge_bond_slaves && displayInterface.bridge_bond_slaves.length > 0 && (
|
||||||
<div className="mt-2">
|
<div className="mt-2">
|
||||||
<div className="text-sm text-muted-foreground mb-2">Bond Members</div>
|
<div className="text-sm text-muted-foreground mb-2">Bond Members</div>
|
||||||
<div className="flex flex-wrap gap-2">
|
<div className="flex flex-wrap gap-2">
|
||||||
{selectedInterface.bridge_bond_slaves.map((slave, idx) => (
|
{displayInterface.bridge_bond_slaves.map((slave, idx) => (
|
||||||
<Badge
|
<Badge
|
||||||
key={idx}
|
key={idx}
|
||||||
variant="outline"
|
variant="outline"
|
||||||
@@ -755,14 +779,14 @@ export function NetworkMetrics() {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{selectedInterface.type === "vm_lxc" && selectedInterface.vm_name && (
|
{displayInterface.type === "vm_lxc" && displayInterface.vm_name && (
|
||||||
<div className="col-span-2">
|
<div className="col-span-2">
|
||||||
<div className="text-sm text-muted-foreground">VM/LXC Name</div>
|
<div className="text-sm text-muted-foreground">VM/LXC Name</div>
|
||||||
<div className="font-medium text-orange-500 text-lg flex items-center gap-2">
|
<div className="font-medium text-orange-500 text-lg flex items-center gap-2">
|
||||||
{selectedInterface.vm_name}
|
{displayInterface.vm_name}
|
||||||
{selectedInterface.vm_type && (
|
{displayInterface.vm_type && (
|
||||||
<Badge variant="outline" className={getVMTypeBadge(selectedInterface.vm_type).color}>
|
<Badge variant="outline" className={getVMTypeBadge(displayInterface.vm_type).color}>
|
||||||
{getVMTypeBadge(selectedInterface.vm_type).label}
|
{getVMTypeBadge(displayInterface.vm_type).label}
|
||||||
</Badge>
|
</Badge>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -773,41 +797,41 @@ export function NetworkMetrics() {
|
|||||||
<Badge
|
<Badge
|
||||||
variant="outline"
|
variant="outline"
|
||||||
className={
|
className={
|
||||||
selectedInterface.status === "up"
|
displayInterface.status === "up"
|
||||||
? "bg-green-500/10 text-green-500 border-green-500/20"
|
? "bg-green-500/10 text-green-500 border-green-500/20"
|
||||||
: "bg-red-500/10 text-red-500 border-red-500/20"
|
: "bg-red-500/10 text-red-500 border-red-500/20"
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{selectedInterface.status.toUpperCase()}
|
{displayInterface.status.toUpperCase()}
|
||||||
</Badge>
|
</Badge>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="text-sm text-muted-foreground">Speed</div>
|
<div className="text-sm text-muted-foreground">Speed</div>
|
||||||
<div className="font-medium">{formatSpeed(selectedInterface.speed)}</div>
|
<div className="font-medium">{formatSpeed(displayInterface.speed)}</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="text-sm text-muted-foreground">Duplex</div>
|
<div className="text-sm text-muted-foreground">Duplex</div>
|
||||||
<div className="font-medium capitalize">{selectedInterface.duplex}</div>
|
<div className="font-medium capitalize">{displayInterface.duplex}</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="text-sm text-muted-foreground">MTU</div>
|
<div className="text-sm text-muted-foreground">MTU</div>
|
||||||
<div className="font-medium">{selectedInterface.mtu}</div>
|
<div className="font-medium">{displayInterface.mtu}</div>
|
||||||
</div>
|
</div>
|
||||||
{selectedInterface.mac_address && (
|
{displayInterface.mac_address && (
|
||||||
<div className="col-span-2">
|
<div className="col-span-2">
|
||||||
<div className="text-sm text-muted-foreground">MAC Address</div>
|
<div className="text-sm text-muted-foreground">MAC Address</div>
|
||||||
<div className="font-medium font-mono">{selectedInterface.mac_address}</div>
|
<div className="font-medium font-mono">{displayInterface.mac_address}</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* IP Addresses */}
|
{/* IP Addresses */}
|
||||||
{selectedInterface.addresses.length > 0 && (
|
{displayInterface.addresses.length > 0 && (
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-sm font-semibold text-muted-foreground mb-3">IP Addresses</h3>
|
<h3 className="text-sm font-semibold text-muted-foreground mb-3">IP Addresses</h3>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
{selectedInterface.addresses.map((addr, idx) => (
|
{displayInterface.addresses.map((addr, idx) => (
|
||||||
<div key={idx} className="flex items-center justify-between p-3 rounded-lg bg-muted/50">
|
<div key={idx} className="flex items-center justify-between p-3 rounded-lg bg-muted/50">
|
||||||
<div>
|
<div>
|
||||||
<div className="font-medium font-mono">{addr.ip}</div>
|
<div className="font-medium font-mono">{addr.ip}</div>
|
||||||
@@ -820,7 +844,7 @@ export function NetworkMetrics() {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Network Traffic Statistics - Only show if interface is UP and NOT a VM interface */}
|
{/* Network Traffic Statistics - Only show if interface is UP and NOT a VM interface */}
|
||||||
{selectedInterface.status.toLowerCase() === "up" && selectedInterface.vm_type !== "vm" ? (
|
{displayInterface.status.toLowerCase() === "up" && displayInterface.vm_type !== "vm" ? (
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-sm font-semibold text-muted-foreground mb-4">
|
<h3 className="text-sm font-semibold text-muted-foreground mb-4">
|
||||||
Network Traffic Statistics (
|
Network Traffic Statistics (
|
||||||
@@ -856,69 +880,73 @@ export function NetworkMetrics() {
|
|||||||
<div className="bg-muted/30 rounded-lg p-4">
|
<div className="bg-muted/30 rounded-lg p-4">
|
||||||
<NetworkTrafficChart
|
<NetworkTrafficChart
|
||||||
timeframe={modalTimeframe}
|
timeframe={modalTimeframe}
|
||||||
interfaceName={selectedInterface.name}
|
interfaceName={displayInterface.name}
|
||||||
onTotalsCalculated={setInterfaceTotals}
|
onTotalsCalculated={setInterfaceTotals}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : selectedInterface.status.toLowerCase() === "up" && selectedInterface.vm_type === "vm" ? (
|
) : displayInterface.status.toLowerCase() === "up" && displayInterface.vm_type === "vm" ? (
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-sm font-semibold text-muted-foreground mb-4">Traffic since last boot</h3>
|
<h3 className="text-sm font-semibold text-muted-foreground mb-4">Traffic 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">Bytes Received</div>
|
||||||
<div className="font-medium text-green-500 text-lg">
|
<div className="font-medium text-green-500 text-lg">
|
||||||
{formatBytes(selectedInterface.bytes_recv)}
|
{formatBytes(displayInterface.bytes_recv)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="text-sm text-muted-foreground">Bytes Sent</div>
|
<div className="text-sm text-muted-foreground">Bytes Sent</div>
|
||||||
<div className="font-medium text-blue-500 text-lg">
|
<div className="font-medium text-blue-500 text-lg">
|
||||||
{formatBytes(selectedInterface.bytes_sent)}
|
{formatBytes(displayInterface.bytes_sent)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="text-sm text-muted-foreground">Packets Received</div>
|
<div className="text-sm text-muted-foreground">Packets Received</div>
|
||||||
<div className="font-medium">{selectedInterface.packets_recv?.toLocaleString() || "N/A"}</div>
|
<div className="font-medium">
|
||||||
|
{displayInterface.packets_recv?.toLocaleString() || "N/A"}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="text-sm text-muted-foreground">Packets Sent</div>
|
<div className="text-sm text-muted-foreground">Packets Sent</div>
|
||||||
<div className="font-medium">{selectedInterface.packets_sent?.toLocaleString() || "N/A"}</div>
|
<div className="font-medium">
|
||||||
|
{displayInterface.packets_sent?.toLocaleString() || "N/A"}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="text-sm text-muted-foreground">Errors In</div>
|
<div className="text-sm text-muted-foreground">Errors In</div>
|
||||||
<div className="font-medium text-red-500">{selectedInterface.errors_in || 0}</div>
|
<div className="font-medium text-red-500">{displayInterface.errors_in || 0}</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="text-sm text-muted-foreground">Errors Out</div>
|
<div className="text-sm text-muted-foreground">Errors Out</div>
|
||||||
<div className="font-medium text-red-500">{selectedInterface.errors_out || 0}</div>
|
<div className="font-medium text-red-500">{displayInterface.errors_out || 0}</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="text-sm text-muted-foreground">Drops In</div>
|
<div className="text-sm text-muted-foreground">Drops In</div>
|
||||||
<div className="font-medium text-yellow-500">{selectedInterface.drops_in || 0}</div>
|
<div className="font-medium text-yellow-500">{displayInterface.drops_in || 0}</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="text-sm text-muted-foreground">Drops Out</div>
|
<div className="text-sm text-muted-foreground">Drops Out</div>
|
||||||
<div className="font-medium text-yellow-500">{selectedInterface.drops_out || 0}</div>
|
<div className="font-medium text-yellow-500">{displayInterface.drops_out || 0}</div>
|
||||||
</div>
|
</div>
|
||||||
{selectedInterface.packet_loss_in !== undefined && (
|
{displayInterface.packet_loss_in !== undefined && (
|
||||||
<div>
|
<div>
|
||||||
<div className="text-sm text-muted-foreground">Packet Loss In</div>
|
<div className="text-sm text-muted-foreground">Packet Loss In</div>
|
||||||
<div
|
<div
|
||||||
className={`font-medium ${selectedInterface.packet_loss_in > 1 ? "text-red-500" : "text-green-500"}`}
|
className={`font-medium ${displayInterface.packet_loss_in > 1 ? "text-red-500" : "text-green-500"}`}
|
||||||
>
|
>
|
||||||
{selectedInterface.packet_loss_in}%
|
{displayInterface.packet_loss_in}%
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{selectedInterface.packet_loss_out !== undefined && (
|
{displayInterface.packet_loss_out !== undefined && (
|
||||||
<div>
|
<div>
|
||||||
<div className="text-sm text-muted-foreground">Packet Loss Out</div>
|
<div className="text-sm text-muted-foreground">Packet Loss Out</div>
|
||||||
<div
|
<div
|
||||||
className={`font-medium ${selectedInterface.packet_loss_out > 1 ? "text-red-500" : "text-green-500"}`}
|
className={`font-medium ${displayInterface.packet_loss_out > 1 ? "text-red-500" : "text-green-500"}`}
|
||||||
>
|
>
|
||||||
{selectedInterface.packet_loss_out}%
|
{displayInterface.packet_loss_out}%
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -935,7 +963,7 @@ export function NetworkMetrics() {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Cumulative Statistics - Only show if interface is UP and NOT a VM interface */}
|
{/* Cumulative Statistics - Only show if interface is UP and NOT a VM interface */}
|
||||||
{selectedInterface.status.toLowerCase() === "up" && selectedInterface.vm_type !== "vm" && (
|
{displayInterface.status.toLowerCase() === "up" && displayInterface.vm_type !== "vm" && (
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-sm font-semibold text-muted-foreground mb-4">
|
<h3 className="text-sm font-semibold text-muted-foreground mb-4">
|
||||||
Cumulative Statistics (Since Last Boot)
|
Cumulative Statistics (Since Last Boot)
|
||||||
@@ -943,45 +971,49 @@ export function NetworkMetrics() {
|
|||||||
<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">Packets Received</div>
|
<div className="text-sm text-muted-foreground">Packets Received</div>
|
||||||
<div className="font-medium">{selectedInterface.packets_recv?.toLocaleString() || "N/A"}</div>
|
<div className="font-medium">
|
||||||
|
{displayInterface.packets_recv?.toLocaleString() || "N/A"}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="text-sm text-muted-foreground">Packets Sent</div>
|
<div className="text-sm text-muted-foreground">Packets Sent</div>
|
||||||
<div className="font-medium">{selectedInterface.packets_sent?.toLocaleString() || "N/A"}</div>
|
<div className="font-medium">
|
||||||
|
{displayInterface.packets_sent?.toLocaleString() || "N/A"}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="text-sm text-muted-foreground">Errors In</div>
|
<div className="text-sm text-muted-foreground">Errors In</div>
|
||||||
<div className="font-medium text-red-500">{selectedInterface.errors_in || 0}</div>
|
<div className="font-medium text-red-500">{displayInterface.errors_in || 0}</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="text-sm text-muted-foreground">Errors Out</div>
|
<div className="text-sm text-muted-foreground">Errors Out</div>
|
||||||
<div className="font-medium text-red-500">{selectedInterface.errors_out || 0}</div>
|
<div className="font-medium text-red-500">{displayInterface.errors_out || 0}</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="text-sm text-muted-foreground">Drops In</div>
|
<div className="text-sm text-muted-foreground">Drops In</div>
|
||||||
<div className="font-medium text-yellow-500">{selectedInterface.drops_in || 0}</div>
|
<div className="font-medium text-yellow-500">{displayInterface.drops_in || 0}</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="text-sm text-muted-foreground">Drops Out</div>
|
<div className="text-sm text-muted-foreground">Drops Out</div>
|
||||||
<div className="font-medium text-yellow-500">{selectedInterface.drops_out || 0}</div>
|
<div className="font-medium text-yellow-500">{displayInterface.drops_out || 0}</div>
|
||||||
</div>
|
</div>
|
||||||
{selectedInterface.packet_loss_in !== undefined && (
|
{displayInterface.packet_loss_in !== undefined && (
|
||||||
<div>
|
<div>
|
||||||
<div className="text-sm text-muted-foreground">Packet Loss In</div>
|
<div className="text-sm text-muted-foreground">Packet Loss In</div>
|
||||||
<div
|
<div
|
||||||
className={`font-medium ${selectedInterface.packet_loss_in > 1 ? "text-red-500" : "text-green-500"}`}
|
className={`font-medium ${displayInterface.packet_loss_in > 1 ? "text-red-500" : "text-green-500"}`}
|
||||||
>
|
>
|
||||||
{selectedInterface.packet_loss_in}%
|
{displayInterface.packet_loss_in}%
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{selectedInterface.packet_loss_out !== undefined && (
|
{displayInterface.packet_loss_out !== undefined && (
|
||||||
<div>
|
<div>
|
||||||
<div className="text-sm text-muted-foreground">Packet Loss Out</div>
|
<div className="text-sm text-muted-foreground">Packet Loss Out</div>
|
||||||
<div
|
<div
|
||||||
className={`font-medium ${selectedInterface.packet_loss_out > 1 ? "text-red-500" : "text-green-500"}`}
|
className={`font-medium ${displayInterface.packet_loss_out > 1 ? "text-red-500" : "text-green-500"}`}
|
||||||
>
|
>
|
||||||
{selectedInterface.packet_loss_out}%
|
{displayInterface.packet_loss_out}%
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -990,24 +1022,24 @@ export function NetworkMetrics() {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Bond Information */}
|
{/* Bond Information */}
|
||||||
{selectedInterface.type === "bond" && selectedInterface.bond_slaves && (
|
{displayInterface.type === "bond" && displayInterface.bond_slaves && (
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-sm font-semibold text-muted-foreground mb-3">Bond Configuration</h3>
|
<h3 className="text-sm font-semibold text-muted-foreground mb-3">Bond Configuration</h3>
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<div>
|
<div>
|
||||||
<div className="text-sm text-muted-foreground">Bonding Mode</div>
|
<div className="text-sm text-muted-foreground">Bonding Mode</div>
|
||||||
<div className="font-medium">{selectedInterface.bond_mode || "Unknown"}</div>
|
<div className="font-medium">{displayInterface.bond_mode || "Unknown"}</div>
|
||||||
</div>
|
</div>
|
||||||
{selectedInterface.bond_active_slave && (
|
{displayInterface.bond_active_slave && (
|
||||||
<div>
|
<div>
|
||||||
<div className="text-sm text-muted-foreground">Active Slave</div>
|
<div className="text-sm text-muted-foreground">Active Slave</div>
|
||||||
<div className="font-medium">{selectedInterface.bond_active_slave}</div>
|
<div className="font-medium">{displayInterface.bond_active_slave}</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div>
|
<div>
|
||||||
<div className="text-sm text-muted-foreground mb-2">Slave Interfaces</div>
|
<div className="text-sm text-muted-foreground mb-2">Slave Interfaces</div>
|
||||||
<div className="flex flex-wrap gap-2">
|
<div className="flex flex-wrap gap-2">
|
||||||
{selectedInterface.bond_slaves.map((slave, idx) => (
|
{displayInterface.bond_slaves.map((slave, idx) => (
|
||||||
<Badge
|
<Badge
|
||||||
key={idx}
|
key={idx}
|
||||||
variant="outline"
|
variant="outline"
|
||||||
@@ -1023,14 +1055,14 @@ export function NetworkMetrics() {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Bridge Information */}
|
{/* Bridge Information */}
|
||||||
{selectedInterface.type === "bridge" && selectedInterface.bridge_members && (
|
{displayInterface.type === "bridge" && displayInterface.bridge_members && (
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-sm font-semibold text-muted-foreground mb-3">Bridge Configuration</h3>
|
<h3 className="text-sm font-semibold text-muted-foreground mb-3">Bridge Configuration</h3>
|
||||||
<div>
|
<div>
|
||||||
<div className="text-sm text-muted-foreground mb-2">Virtual Member Interfaces</div>
|
<div className="text-sm text-muted-foreground mb-2">Virtual Member Interfaces</div>
|
||||||
<div className="flex flex-wrap gap-2">
|
<div className="flex flex-wrap gap-2">
|
||||||
{selectedInterface.bridge_members.length > 0 ? (
|
{displayInterface.bridge_members.length > 0 ? (
|
||||||
selectedInterface.bridge_members
|
displayInterface.bridge_members
|
||||||
.filter(
|
.filter(
|
||||||
(member) =>
|
(member) =>
|
||||||
!member.startsWith("enp") &&
|
!member.startsWith("enp") &&
|
||||||
@@ -1056,6 +1088,9 @@ export function NetworkMetrics() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
})()}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
|||||||
Reference in New Issue
Block a user