diff --git a/AppImage/components/network-metrics.tsx b/AppImage/components/network-metrics.tsx index 724bd80..3248165 100644 --- a/AppImage/components/network-metrics.tsx +++ b/AppImage/components/network-metrics.tsx @@ -1,6 +1,6 @@ "use client" -import { useState } from "react" +import { useEffect, useState } from "react" import { Card, CardContent, CardHeader, CardTitle } from "./ui/card" import { Badge } from "./ui/badge" import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "./ui/dialog" @@ -132,6 +132,13 @@ const fetcher = async (url: string): Promise => { return fetchApi(url) } +const getUnitsSettings = (): "Bytes" | "Bits" => { + const raw = localStorage.getItem("proxmenux-network-unit"); + const networkUnit = raw && raw.toLowerCase() === "bits" ? "Bits" : "Bytes"; + console.log("[v0] Loaded network unit from localStorage:", networkUnit); + return networkUnit; +}; + export function NetworkMetrics() { const { data: networkData, @@ -160,6 +167,13 @@ export function NetworkMetrics() { revalidateOnFocus: false, }) + const [networkUnit, setNetworkUnit] = useState<"Bytes" | "Bits">("Bytes"); + + useEffect(() => { + const networkUnitSetting = getUnitsSettings(); + setNetworkUnit(networkUnitSetting); + }, []); + if (isLoading) { return (
@@ -375,7 +389,7 @@ export function NetworkMetrics() { - + diff --git a/AppImage/components/network-traffic-chart.tsx b/AppImage/components/network-traffic-chart.tsx index 7d9eac0..809d3bf 100644 --- a/AppImage/components/network-traffic-chart.tsx +++ b/AppImage/components/network-traffic-chart.tsx @@ -17,33 +17,16 @@ interface NetworkTrafficChartProps { interfaceName?: string onTotalsCalculated?: (totals: { received: number; sent: number }) => void refreshInterval?: number // En milisegundos, por defecto 60000 (60 segundos) + networkUnit?: "Bytes" | "Bits" } -const CustomNetworkTooltip = ({ active, payload, label }: any) => { - if (active && payload && payload.length) { - return ( -
-

{label}

-
- {payload.map((entry: any, index: number) => ( -
-
- {entry.name}: - {entry.value.toFixed(3)} GB -
- ))} -
-
- ) - } - return null -} export function NetworkTrafficChart({ timeframe, interfaceName, onTotalsCalculated, refreshInterval = 60000, + networkUnit = "Bits", }: NetworkTrafficChartProps) { const [data, setData] = useState([]) const [loading, setLoading] = useState(true) @@ -138,6 +121,15 @@ export function NetworkTrafficChart({ const netInBytes = (item.netin || 0) * intervalSeconds const netOutBytes = (item.netout || 0) * intervalSeconds + if (networkUnit === "Bits") { + return { + time: timeLabel, + timestamp: item.time, + netIn: Number((netInBytes * 8 / 1024 / 1024 / 1024).toFixed(4)), + netOut: Number((netOutBytes * 8 / 1024 / 1024 / 1024).toFixed(4)), + } + } + return { time: timeLabel, timestamp: item.time, @@ -222,6 +214,26 @@ export function NetworkTrafficChart({ ) } + const CustomNetworkTooltip = ({ active, payload, label }: any) => { + if (active && payload && payload.length) { + return ( +
+

{label}

+
+ {payload.map((entry: any, index: number) => ( +
+
+ {entry.name}: + {entry.value.toFixed(3)} {networkUnit === "Bits" ? "Gb" : "GB"} +
+ ))} +
+
+ ) + } + return null +} + return ( @@ -240,7 +252,7 @@ export function NetworkTrafficChart({ stroke="currentColor" className="text-foreground" tick={{ fill: "currentColor", fontSize: 12 }} - label={{ value: "GB", angle: -90, position: "insideLeft", fill: "currentColor" }} + label={{ value: networkUnit === "Bits" ? "Gb" : "GB", angle: -90, position: "insideLeft", fill: "currentColor" }} domain={[0, "auto"]} /> } /> diff --git a/AppImage/components/settings.tsx b/AppImage/components/settings.tsx index 81b6fe8..c84aa36 100644 --- a/AppImage/components/settings.tsx +++ b/AppImage/components/settings.tsx @@ -19,10 +19,12 @@ import { Copy, Eye, EyeOff, + Ruler, } from "lucide-react" import { APP_VERSION } from "./release-notes-modal" import { getApiUrl, fetchApi } from "../lib/api-config" import { TwoFactorSetup } from "./two-factor-setup" +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./ui/select" interface ProxMenuxTool { key: string @@ -59,6 +61,9 @@ export function Settings() { [APP_VERSION]: true, // Current version expanded by default }) + const [networkUnitSettings, setNetworkUnitSettings] = useState("Bytes"); + const [loadingUnitSettings, setLoadingUnitSettings] = useState(true); + // API Token state management const [showApiTokenSection, setShowApiTokenSection] = useState(false) const [apiToken, setApiToken] = useState("") @@ -71,8 +76,22 @@ export function Settings() { useEffect(() => { checkAuthStatus() loadProxmenuxTools() + getUnitsSettings(); }, []) + const changeNetworkUnit = (unit: string) => { + localStorage.setItem("proxmenux-network-unit", unit); + setNetworkUnitSettings(unit); + }; + + const getUnitsSettings = () => { + const networkUnit = + localStorage.getItem("proxmenux-network-unit") || "Bytes"; + console.log("[v0] Loaded network unit from localStorage:", networkUnit); + setNetworkUnitSettings(networkUnit); + setLoadingUnitSettings(false); + }; + const checkAuthStatus = async () => { try { const response = await fetch(getApiUrl("/api/auth/status")) @@ -854,6 +873,42 @@ export function Settings() { )} + + {/* ProxMenux unit settings*/} + + +
+ + ProxMenux unit settings +
+ Change settings related to units +
+ + {loadingUnitSettings ? ( +
+
+
+ ) : ( +
+
+ Network Unit Display +
+ +
+ )} + + {/* ProxMenux Optimizations */} @@ -907,4 +962,4 @@ export function Settings() { />
) -} +} \ No newline at end of file diff --git a/AppImage/components/system-overview.tsx b/AppImage/components/system-overview.tsx index 546b3c4..47c6c40 100644 --- a/AppImage/components/system-overview.tsx +++ b/AppImage/components/system-overview.tsx @@ -146,6 +146,13 @@ const fetchProxmoxStorageData = async (): Promise => } } +const getUnitsSettings = (): "Bytes" | "Bits" => { + const raw = localStorage.getItem("proxmenux-network-unit"); + const networkUnit = raw && raw.toLowerCase() === "bits" ? "Bits" : "Bytes"; + console.log("[v0] Loaded network unit from localStorage:", networkUnit); + return networkUnit; +}; + export function SystemOverview() { const [systemData, setSystemData] = useState(null) const [vmData, setVmData] = useState([]) @@ -161,6 +168,7 @@ export function SystemOverview() { const [error, setError] = useState(null) const [networkTimeframe, setNetworkTimeframe] = useState("day") const [networkTotals, setNetworkTotals] = useState<{ received: number; sent: number }>({ received: 0, sent: 0 }) + const [networkUnit, setNetworkUnit] = useState<"Bytes" | "Bits">("Bytes"); useEffect(() => { const fetchAllData = async () => { @@ -178,6 +186,9 @@ export function SystemOverview() { return } + const networkUnitSetting = getUnitsSettings(); + setNetworkUnit(networkUnitSetting); + setSystemData(systemResult) setVmData(vmResult) setStorageData(storageResults[0]) @@ -298,13 +309,19 @@ export function SystemOverview() { return (bytes / 1024 ** 3).toFixed(2) } - const formatStorage = (sizeInGB: number): string => { - if (sizeInGB < 1) { - return `${(sizeInGB * 1024).toFixed(1)} MB` - } else if (sizeInGB > 999) { - return `${(sizeInGB / 1024).toFixed(2)} TB` + const formatStorage = (sizeInGB: number, unit: "Bytes" | "Bits" = "Bytes"): string => { + let size = sizeInGB; + let sufix = "B"; + if (unit === "Bits") { + size = size * 8; + sufix = "b"; + } + if (size < 1) { + return `${(size * 1024).toFixed(1)} M${sufix}` + } else if (size > 999) { + return `${(size / 1024).toFixed(2)} T${sufix}` } else { - return `${sizeInGB.toFixed(2)} GB` + return `${size.toFixed(2)} G${sufix}` } } @@ -667,21 +684,21 @@ export function SystemOverview() {
Received: - ↓ {formatStorage(networkTotals.received)} + ↓ {formatStorage(networkTotals.received, networkUnit)} ({getTimeframeLabel(networkTimeframe)})
Sent: - ↑ {formatStorage(networkTotals.sent)} + ↑ {formatStorage(networkTotals.sent, networkUnit)} ({getTimeframeLabel(networkTimeframe)})
- +
) : (