mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2025-11-18 03:26:17 +00:00
Update AppImage
This commit is contained in:
@@ -13,6 +13,7 @@ interface NetworkMetricsData {
|
|||||||
|
|
||||||
interface NetworkTrafficChartProps {
|
interface NetworkTrafficChartProps {
|
||||||
timeframe: string
|
timeframe: string
|
||||||
|
onTotalsCalculated?: (totals: { received: number; sent: number }) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const CustomNetworkTooltip = ({ active, payload, label }: any) => {
|
const CustomNetworkTooltip = ({ active, payload, label }: any) => {
|
||||||
@@ -25,7 +26,7 @@ const CustomNetworkTooltip = ({ active, payload, label }: any) => {
|
|||||||
<div key={index} className="flex items-center gap-2">
|
<div key={index} className="flex items-center gap-2">
|
||||||
<div className="w-2.5 h-2.5 rounded-full flex-shrink-0" style={{ backgroundColor: entry.color }} />
|
<div className="w-2.5 h-2.5 rounded-full flex-shrink-0" style={{ backgroundColor: entry.color }} />
|
||||||
<span className="text-xs text-gray-300 min-w-[60px]">{entry.name}:</span>
|
<span className="text-xs text-gray-300 min-w-[60px]">{entry.name}:</span>
|
||||||
<span className="text-sm font-semibold text-white">{entry.value} GB</span>
|
<span className="text-sm font-semibold text-white">{entry.value.toFixed(3)} GB</span>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@@ -35,7 +36,7 @@ const CustomNetworkTooltip = ({ active, payload, label }: any) => {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
export function NetworkTrafficChart({ timeframe }: NetworkTrafficChartProps) {
|
export function NetworkTrafficChart({ timeframe, onTotalsCalculated }: NetworkTrafficChartProps) {
|
||||||
const [data, setData] = useState<NetworkMetricsData[]>([])
|
const [data, setData] = useState<NetworkMetricsData[]>([])
|
||||||
const [loading, setLoading] = useState(true)
|
const [loading, setLoading] = useState(true)
|
||||||
const [error, setError] = useState<string | null>(null)
|
const [error, setError] = useState<string | null>(null)
|
||||||
@@ -75,7 +76,8 @@ export function NetworkTrafficChart({ timeframe }: NetworkTrafficChartProps) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const transformedData = result.data.map((item: any) => {
|
// RRD data contains rate (bytes/second), we need to calculate traffic per interval
|
||||||
|
const transformedData = result.data.map((item: any, index: number) => {
|
||||||
const date = new Date(item.time * 1000)
|
const date = new Date(item.time * 1000)
|
||||||
let timeLabel = ""
|
let timeLabel = ""
|
||||||
|
|
||||||
@@ -105,15 +107,33 @@ export function NetworkTrafficChart({ timeframe }: NetworkTrafficChartProps) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculate time interval between data points (in seconds)
|
||||||
|
let intervalSeconds = 60 // Default to 1 minute
|
||||||
|
if (index > 0) {
|
||||||
|
intervalSeconds = item.time - result.data[index - 1].time
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert rate (bytes/second) to traffic in this interval (GB)
|
||||||
|
// netin and netout are in bytes/second, multiply by interval to get total bytes
|
||||||
|
const netInBytes = (item.netin || 0) * intervalSeconds
|
||||||
|
const netOutBytes = (item.netout || 0) * intervalSeconds
|
||||||
|
|
||||||
return {
|
return {
|
||||||
time: timeLabel,
|
time: timeLabel,
|
||||||
timestamp: item.time,
|
timestamp: item.time,
|
||||||
netIn: item.netin ? Number((item.netin / 1024 / 1024 / 1024).toFixed(2)) : 0,
|
netIn: Number((netInBytes / 1024 / 1024 / 1024).toFixed(4)),
|
||||||
netOut: item.netout ? Number((item.netout / 1024 / 1024 / 1024).toFixed(2)) : 0,
|
netOut: Number((netOutBytes / 1024 / 1024 / 1024).toFixed(4)),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
setData(transformedData)
|
setData(transformedData)
|
||||||
|
|
||||||
|
const totalReceived = transformedData.reduce((sum: number, item: NetworkMetricsData) => sum + item.netIn, 0)
|
||||||
|
const totalSent = transformedData.reduce((sum: number, item: NetworkMetricsData) => sum + item.netOut, 0)
|
||||||
|
|
||||||
|
if (onTotalsCalculated) {
|
||||||
|
onTotalsCalculated({ received: totalReceived, sent: totalSent })
|
||||||
|
}
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
console.error("[v0] Error fetching network metrics:", err)
|
console.error("[v0] Error fetching network metrics:", err)
|
||||||
setError(err.message || "Error loading metrics")
|
setError(err.message || "Error loading metrics")
|
||||||
@@ -197,7 +217,7 @@ export function NetworkTrafficChart({ timeframe }: NetworkTrafficChartProps) {
|
|||||||
className="text-foreground"
|
className="text-foreground"
|
||||||
tick={{ fill: "currentColor", fontSize: 12 }}
|
tick={{ fill: "currentColor", fontSize: 12 }}
|
||||||
label={{ value: "GB", angle: -90, position: "insideLeft", fill: "currentColor" }}
|
label={{ value: "GB", angle: -90, position: "insideLeft", fill: "currentColor" }}
|
||||||
domain={[0, "dataMax"]}
|
domain={[0, "auto"]}
|
||||||
/>
|
/>
|
||||||
<Tooltip content={<CustomNetworkTooltip />} />
|
<Tooltip content={<CustomNetworkTooltip />} />
|
||||||
<Legend verticalAlign="top" height={36} content={renderLegend} />
|
<Legend verticalAlign="top" height={36} content={renderLegend} />
|
||||||
|
|||||||
@@ -232,6 +232,7 @@ export function SystemOverview() {
|
|||||||
const [loading, setLoading] = useState(true)
|
const [loading, setLoading] = useState(true)
|
||||||
const [error, setError] = useState<string | null>(null)
|
const [error, setError] = useState<string | null>(null)
|
||||||
const [networkTimeframe, setNetworkTimeframe] = useState("day")
|
const [networkTimeframe, setNetworkTimeframe] = useState("day")
|
||||||
|
const [networkTotals, setNetworkTotals] = useState<{ received: number; sent: number }>({ received: 0, sent: 0 })
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
@@ -396,7 +397,7 @@ export function SystemOverview() {
|
|||||||
return `${sizeInGB.toFixed(1)} GB`
|
return `${sizeInGB.toFixed(1)} GB`
|
||||||
} else {
|
} else {
|
||||||
// 1024 GB or more, show in TB
|
// 1024 GB or more, show in TB
|
||||||
return `${(sizeInGB / 1024).toFixed(1)} TB`
|
return `${(sizeInGB / 1024).toFixed(2)} TB`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -459,6 +460,21 @@ export function SystemOverview() {
|
|||||||
|
|
||||||
const loadStatus = getLoadStatus(systemData.load_average[0], systemData.cpu_cores || 8)
|
const loadStatus = getLoadStatus(systemData.load_average[0], systemData.cpu_cores || 8)
|
||||||
|
|
||||||
|
const getTimeframeLabel = (timeframe: string): string => {
|
||||||
|
switch (timeframe) {
|
||||||
|
case "hour":
|
||||||
|
return "1h"
|
||||||
|
case "day":
|
||||||
|
return "24h"
|
||||||
|
case "week":
|
||||||
|
return "7d"
|
||||||
|
case "month":
|
||||||
|
return "30d"
|
||||||
|
default:
|
||||||
|
return timeframe
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
{/* Key Metrics Cards */}
|
{/* Key Metrics Cards */}
|
||||||
@@ -693,19 +709,21 @@ export function SystemOverview() {
|
|||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<span className="text-sm text-muted-foreground">Received:</span>
|
<span className="text-sm text-muted-foreground">Received:</span>
|
||||||
<span className="text-lg font-semibold text-green-500 flex items-center gap-1">
|
<span className="text-lg font-semibold text-green-500 flex items-center gap-1">
|
||||||
↓ {formatStorage(networkData.traffic.bytes_recv / 1024 ** 3)}
|
↓ {formatStorage(networkTotals.received)}
|
||||||
|
<span className="text-xs text-muted-foreground">({getTimeframeLabel(networkTimeframe)})</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<span className="text-sm text-muted-foreground">Sent:</span>
|
<span className="text-sm text-muted-foreground">Sent:</span>
|
||||||
<span className="text-lg font-semibold text-blue-500 flex items-center gap-1">
|
<span className="text-lg font-semibold text-blue-500 flex items-center gap-1">
|
||||||
↑ {formatStorage(networkData.traffic.bytes_sent / 1024 ** 3)}
|
↑ {formatStorage(networkTotals.sent)}
|
||||||
|
<span className="text-xs text-muted-foreground">({getTimeframeLabel(networkTimeframe)})</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="pt-3 border-t border-border">
|
<div className="pt-3 border-t border-border">
|
||||||
<NetworkTrafficChart timeframe={networkTimeframe} />
|
<NetworkTrafficChart timeframe={networkTimeframe} onTotalsCalculated={setNetworkTotals} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
Reference in New Issue
Block a user