From 13dd4007956296ae7a81216da2a861356df2f470 Mon Sep 17 00:00:00 2001 From: MacRimi Date: Thu, 23 Oct 2025 15:31:25 +0200 Subject: [PATCH] Update hardware.tsx --- AppImage/components/hardware.tsx | 1041 +++++++++++++++++++++++++++--- 1 file changed, 966 insertions(+), 75 deletions(-) diff --git a/AppImage/components/hardware.tsx b/AppImage/components/hardware.tsx index bc5a437..980459d 100644 --- a/AppImage/components/hardware.tsx +++ b/AppImage/components/hardware.tsx @@ -2,8 +2,22 @@ import { Card } from "@/components/ui/card" import { Badge } from "@/components/ui/badge" +import { Progress } from "@/components/ui/progress" import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog" -import { Thermometer, CpuIcon, HardDrive, Cpu, MemoryStick, Cpu as Gpu } from "lucide-react" +import { + Thermometer, + CpuIcon, + Zap, + HardDrive, + Network, + FanIcon, + PowerIcon, + Battery, + Cpu, + MemoryStick, + Cpu as Gpu, + Loader2, +} from "lucide-react" import useSWR from "swr" import { useState, useEffect } from "react" import { type HardwareData, type GPU, type PCIDevice, type StorageDevice, fetcher } from "../types/hardware" @@ -404,54 +418,6 @@ export default function Hardware() { )} - {/* Storage Summary - Clickable */} - {hardwareData?.storage_devices && hardwareData.storage_devices.length > 0 && ( - -
- -

Storage Summary

- - { - hardwareData.storage_devices.filter( - (device) => - device.type === "disk" && !device.name.startsWith("zd") && !device.name.startsWith("loop"), - ).length - }{" "} - devices - -
- -
- {hardwareData.storage_devices - .filter( - (device) => device.type === "disk" && !device.name.startsWith("zd") && !device.name.startsWith("loop"), - ) - .map((device, index) => ( -
setSelectedDisk(device)} - className="cursor-pointer rounded-lg border border-white/10 sm:border-border bg-white/5 sm:bg-card sm:hover:bg-white/5 p-3 transition-colors" - > -
- {device.name} - - {device.type} - -
- {device.size &&

{formatMemory(parseLsblkSize(device.size))}

} - {device.model && ( -

{device.model}

- )} - {device.driver && ( -

Driver: {device.driver}

- )} -
- ))} -
-

Click on a device for detailed hardware information

-
- )} - {/* Thermal Monitoring */} {hardwareData?.temperatures && hardwareData.temperatures.length > 0 && ( @@ -784,42 +750,281 @@ export default function Hardware() { {findPCIDeviceForGPU(selectedGPU)?.driver || selectedGPU.pci_driver} {realtimeGPUData?.has_monitoring_tool === true && ( - - Monitoring Available + + {realtimeGPUData?.driver_version ? `✓ v${realtimeGPUData.driver_version}` : "✓"} )} )} + {(findPCIDeviceForGPU(selectedGPU)?.kernel_module || selectedGPU.pci_kernel_module) && ( +
+ Kernel Module + + {findPCIDeviceForGPU(selectedGPU)?.kernel_module || selectedGPU.pci_kernel_module} + +
+ )} - {/* Real-Time Data */} - {realtimeGPUData && hasRealtimeData() && ( -
-

- Real-Time Data -

-
- {realtimeGPUData.data.map((data, index) => ( -
- {data.name} - {data.value} -
- ))} -
+ {detailsLoading ? ( +
+ +

Loading real-time data...

- )} + ) : realtimeGPUData?.has_monitoring_tool === true ? ( + <> +
+
+ Updating every 3 seconds +
- {/* Monitoring Tool Recommendation */} - {!hasRealtimeData() && ( -
-

- Monitoring Tool Recommendation -

-

- {getMonitoringToolRecommendation(selectedGPU.vendor)} -

+
+

+ Real-Time Metrics +

+
+ {realtimeGPUData.clock_graphics && ( +
+ Graphics Clock + {formatClock(realtimeGPUData.clock_graphics)} +
+ )} + {realtimeGPUData.clock_memory && ( +
+ Memory Clock + {formatClock(realtimeGPUData.clock_memory)} +
+ )} + {realtimeGPUData.power_draw && realtimeGPUData.power_draw !== "0.00 W" && ( +
+ Power Draw + {realtimeGPUData.power_draw} +
+ )} + {realtimeGPUData.temperature !== undefined && realtimeGPUData.temperature !== null && ( +
+ Temperature + + {realtimeGPUData.temperature}°C + +
+ )} +
+
+ + {/* Engine Utilization (Intel/AMD) */} + {(realtimeGPUData.engine_render !== undefined || + realtimeGPUData.engine_blitter !== undefined || + realtimeGPUData.engine_video !== undefined || + realtimeGPUData.engine_video_enhance !== undefined) && ( +
+

+ Engine Utilization (Total) +

+
+ {realtimeGPUData.engine_render !== undefined && ( +
+
+ Render/3D + + {typeof realtimeGPUData.engine_render === "number" + ? `${realtimeGPUData.engine_render.toFixed(1)}%` + : realtimeGPUData.engine_render} + +
+ +
+ )} + {realtimeGPUData.engine_video !== undefined && ( +
+
+ Video + + {typeof realtimeGPUData.engine_video === "number" + ? `${realtimeGPUData.engine_video.toFixed(1)}%` + : realtimeGPUData.engine_video} + +
+ +
+ )} + {realtimeGPUData.engine_blitter !== undefined && ( +
+
+ Blitter + + {typeof realtimeGPUData.engine_blitter === "number" + ? `${realtimeGPUData.engine_blitter.toFixed(1)}%` + : realtimeGPUData.engine_blitter} + +
+ +
+ )} + {realtimeGPUData.engine_video_enhance !== undefined && ( +
+
+ VideoEnhance + + {typeof realtimeGPUData.engine_video_enhance === "number" + ? `${realtimeGPUData.engine_video_enhance.toFixed(1)}%` + : realtimeGPUData.engine_video_enhance} + +
+ +
+ )} +
+
+ )} + + {/* CHANGE: Changed process name badge from blue to purple to match Intel/AMD */} + {realtimeGPUData.processes && realtimeGPUData.processes.length > 0 && ( +
+

+ Active Processes ({realtimeGPUData.processes.length}) +

+
+ {realtimeGPUData.processes.map((proc: any, idx: number) => ( +
+
+
+ + {proc.name} + +

PID: {proc.pid}

+
+ {proc.memory && ( + + {typeof proc.memory === "object" + ? formatMemory(proc.memory.resident / 1024) + : formatMemory(proc.memory)} + + )} +
+ + {proc.engines && Object.keys(proc.engines).length > 0 && ( +
+

Engine Utilization:

+ {Object.entries(proc.engines).map(([engineName, engineData]: [string, any]) => { + const utilization = + typeof engineData === "object" ? engineData.busy || 0 : engineData + const utilizationNum = + typeof utilization === "string" ? Number.parseFloat(utilization) : utilization + + if (utilizationNum === 0 || isNaN(utilizationNum)) return null + + return ( +
+
+ {engineName} + {utilizationNum.toFixed(1)}% +
+ +
+ ) + })} +
+ )} +
+ ))} +
+
+ )} + + {realtimeGPUData.processes && realtimeGPUData.processes.length === 0 && ( +
+

No active processes using the GPU

+
+ )} + + {/* Memory Info (NVIDIA) */} + {realtimeGPUData.memory_total && ( +
+

+ Memory +

+
+
+ Total + {realtimeGPUData.memory_total} +
+
+ Used + {realtimeGPUData.memory_used} +
+
+ Free + {realtimeGPUData.memory_free} +
+ {realtimeGPUData.utilization_memory !== undefined && ( +
+
+ Memory Utilization + {realtimeGPUData.utilization_memory}% +
+ +
+ )} +
+
+ )} + + ) : ( +
+
+
+ + + +
+
+

Extended Monitoring Not Available

+

+ {getMonitoringToolRecommendation(selectedGPU.vendor)} +

+
+
)}
@@ -827,6 +1032,692 @@ export default function Hardware() { )} + + {/* PCI Devices - Changed to modal */} + {hardwareData?.pci_devices && hardwareData.pci_devices.length > 0 && ( + +
+ +

PCI Devices

+ + {hardwareData.pci_devices.length} devices + +
+ +
+ {hardwareData.pci_devices.map((device, index) => ( +
setSelectedPCIDevice(device)} + className="cursor-pointer rounded-lg border border-white/10 sm:border-border bg-white/5 sm:bg-card sm:hover:bg-white/5 p-3 transition-colors" + > +
+ {device.type} + {device.slot} +
+

{device.device}

+

{device.vendor}

+ {device.driver && ( +

Driver: {device.driver}

+ )} +
+ ))} +
+
+ )} + + {/* PCI Device Detail Modal */} + setSelectedPCIDevice(null)}> + + + {selectedPCIDevice?.device} + PCI Device Information + + + {selectedPCIDevice && ( +
+
+ Device Type + {selectedPCIDevice.type} +
+ +
+ PCI Slot + {selectedPCIDevice.slot} +
+ +
+ Device Name + {selectedPCIDevice.device} +
+ +
+ Vendor + {selectedPCIDevice.vendor} +
+ +
+ Class + {selectedPCIDevice.class} +
+ + {selectedPCIDevice.driver && ( +
+ Driver + {selectedPCIDevice.driver} +
+ )} + + {selectedPCIDevice.kernel_module && ( +
+ Kernel Module + {selectedPCIDevice.kernel_module} +
+ )} +
+ )} +
+
+ + {/* Power Consumption */} + {hardwareData?.power_meter && ( + +
+ +

Power Consumption

+
+ +
+
+
+

{hardwareData.power_meter.name}

+ {hardwareData.power_meter.adapter && ( +

{hardwareData.power_meter.adapter}

+ )} +
+
+

{hardwareData.power_meter.watts.toFixed(1)} W

+

Current Draw

+
+
+
+
+ )} + + {/* Power Supplies */} + {hardwareData?.power_supplies && hardwareData.power_supplies.length > 0 && ( + +
+ +

Power Supplies

+ + {hardwareData.power_supplies.length} PSUs + +
+ +
+ {hardwareData.power_supplies.map((psu, index) => ( +
+
+ {psu.name} + {psu.status && ( + {psu.status} + )} +
+

{psu.watts} W

+

Current Output

+
+ ))} +
+
+ )} + + {/* Fans */} + {hardwareData?.fans && hardwareData.fans.length > 0 && ( + +
+ +

System Fans

+ + {hardwareData.fans.length} fans + +
+ +
+ {hardwareData.fans.map((fan, index) => { + const isPercentage = fan.unit === "percent" || fan.unit === "%" + const percentage = isPercentage ? fan.speed : Math.min((fan.speed / 5000) * 100, 100) + + return ( +
+
+ {fan.name} + + {isPercentage ? `${fan.speed.toFixed(0)} percent` : `${fan.speed.toFixed(0)} ${fan.unit}`} + +
+
+
+
+ {fan.adapter && {fan.adapter}} +
+ ) + })} +
+ + )} + + {/* UPS */} + {hardwareData?.ups && Array.isArray(hardwareData.ups) && hardwareData.ups.length > 0 && ( + +
+ +

UPS Status

+ + {hardwareData.ups.length} UPS + +
+ +
+ {hardwareData.ups.map((ups: any, index: number) => { + const batteryCharge = + ups.battery_charge_raw || Number.parseFloat(ups.battery_charge?.replace("%", "") || "0") + const loadPercent = ups.load_percent_raw || Number.parseFloat(ups.load_percent?.replace("%", "") || "0") + + // Determine status badge color + const getStatusColor = (status: string) => { + if (!status) return "bg-gray-500/10 text-gray-500 border-gray-500/20" + const statusUpper = status.toUpperCase() + if (statusUpper.includes("OL")) return "bg-green-500/10 text-green-500 border-green-500/20" + if (statusUpper.includes("OB")) return "bg-yellow-500/10 text-yellow-500 border-yellow-500/20" + if (statusUpper.includes("LB")) return "bg-red-500/10 text-red-500 border-red-500/20" + return "bg-blue-500/10 text-blue-500 border-blue-500/20" + } + + return ( +
setSelectedUPS(ups)} + className="cursor-pointer rounded-lg border border-white/10 sm:border-border bg-white/5 sm:bg-card sm:hover:bg-white/5 p-4 transition-colors" + > +
+
+ {ups.model || ups.name} + {ups.is_remote && Remote: {ups.host}} +
+ {ups.status || "Unknown"} +
+ +
+ {ups.battery_charge && ( +
+
+ Battery Charge + {ups.battery_charge} +
+ +
+ )} + + {ups.load_percent && ( +
+
+ Load + {ups.load_percent} +
+ +
+ )} + + {ups.time_left && ( +
+ Runtime +
+ {ups.time_left} +
+
+ )} + + {ups.input_voltage && ( +
+ Input Voltage +
+ {ups.input_voltage} +
+
+ )} +
+
+ ) + })} +
+
+ )} + + setSelectedUPS(null)}> + + {selectedUPS && ( + <> + + {selectedUPS.model || selectedUPS.name} + + UPS Detailed Information + {selectedUPS.is_remote && ` • Remote: ${selectedUPS.host}`} + + + +
+ {/* Status Overview */} +
+

+ Status Overview +

+
+
+ Status + + {selectedUPS.status || "Unknown"} + +
+
+ Connection + {selectedUPS.connection_type} +
+ {selectedUPS.host && ( +
+ Host + {selectedUPS.host} +
+ )} +
+
+ + {/* Battery Information */} +
+

+ Battery Information +

+
+ {selectedUPS.battery_charge && ( +
+
+ Charge Level + {selectedUPS.battery_charge} +
+ +
+ )} + {selectedUPS.time_left && ( +
+ Runtime Remaining + + {selectedUPS.time_left} + +
+ )} + {selectedUPS.battery_voltage && ( +
+ Battery Voltage + {selectedUPS.battery_voltage} +
+ )} + {selectedUPS.battery_date && ( +
+ Battery Date + {selectedUPS.battery_date} +
+ )} +
+
+ + {/* Input/Output Information */} +
+

+ Power Information +

+
+ {selectedUPS.input_voltage && ( +
+ Input Voltage + {selectedUPS.input_voltage} +
+ )} + {selectedUPS.output_voltage && ( +
+ Output Voltage + {selectedUPS.output_voltage} +
+ )} + {selectedUPS.input_frequency && ( +
+ Input Frequency + {selectedUPS.input_frequency} +
+ )} + {selectedUPS.output_frequency && ( +
+ Output Frequency + {selectedUPS.output_frequency} +
+ )} + {selectedUPS.load_percent && ( +
+
+ Load + {selectedUPS.load_percent} +
+ +
+ )} + {selectedUPS.real_power && ( +
+ Real Power + {selectedUPS.real_power} +
+ )} + {selectedUPS.apparent_power && ( +
+ Apparent Power + {selectedUPS.apparent_power} +
+ )} +
+
+ + {/* Device Information */} +
+

+ Device Information +

+
+ {selectedUPS.manufacturer && ( +
+ Manufacturer + {selectedUPS.manufacturer} +
+ )} + {selectedUPS.model && ( +
+ Model + {selectedUPS.model} +
+ )} + {selectedUPS.serial && ( +
+ Serial Number + {selectedUPS.serial} +
+ )} + {selectedUPS.firmware && ( +
+ Firmware + {selectedUPS.firmware} +
+ )} + {selectedUPS.driver && ( +
+ Driver + {selectedUPS.driver} +
+ )} +
+
+
+ + )} +
+
+ + {/* Network Summary - Clickable */} + {hardwareData?.pci_devices && + hardwareData.pci_devices.filter((d) => d.type.toLowerCase().includes("network")).length > 0 && ( + +
+ +

Network Summary

+ + {hardwareData.pci_devices.filter((d) => d.type.toLowerCase().includes("network")).length} interfaces + +
+ +
+ {hardwareData.pci_devices + .filter((d) => d.type.toLowerCase().includes("network")) + .map((device, index) => ( +
setSelectedNetwork(device)} + className="cursor-pointer rounded-lg border border-white/10 sm:border-border bg-white/5 sm:bg-card sm:hover:bg-white/5 p-3 transition-colors" + > +
+ {device.device} + + Ethernet + +
+

{device.vendor}

+ {device.driver && ( +

Driver: {device.driver}

+ )} +
+ ))} +
+

Click on an interface for detailed information

+
+ )} + + {/* Network Detail Modal */} + setSelectedNetwork(null)}> + + + {selectedNetwork?.device} + Network Interface Information + + + {selectedNetwork && ( +
+
+ Device Type + {selectedNetwork.type} +
+ +
+ PCI Slot + {selectedNetwork.slot} +
+ +
+ Vendor + {selectedNetwork.vendor} +
+ +
+ Class + {selectedNetwork.class} +
+ + {selectedNetwork.driver && ( +
+ Driver + {selectedNetwork.driver} +
+ )} + + {selectedNetwork.kernel_module && ( +
+ Kernel Module + {selectedNetwork.kernel_module} +
+ )} +
+ )} +
+
+ + {/* Storage Summary - Clickable */} + {hardwareData?.storage_devices && hardwareData.storage_devices.length > 0 && ( + +
+ +

Storage Summary

+ + { + hardwareData.storage_devices.filter( + (device) => + device.type === "disk" && !device.name.startsWith("zd") && !device.name.startsWith("loop"), + ).length + }{" "} + devices + +
+ +
+ {hardwareData.storage_devices + .filter( + (device) => device.type === "disk" && !device.name.startsWith("zd") && !device.name.startsWith("loop"), + ) + .map((device, index) => ( +
setSelectedDisk(device)} + className="cursor-pointer rounded-lg border border-white/10 sm:border-border bg-white/5 sm:bg-card sm:hover:bg-white/5 p-3 transition-colors" + > +
+ {device.name} + + {device.type} + +
+ {device.size &&

{formatMemory(parseLsblkSize(device.size))}

} + {device.model && ( +

{device.model}

+ )} + {device.driver && ( +

Driver: {device.driver}

+ )} +
+ ))} +
+

Click on a device for detailed hardware information

+
+ )} + + {/* Disk Detail Modal */} + setSelectedDisk(null)}> + + + {selectedDisk?.name} + Storage Device Hardware Information + + + {selectedDisk && ( +
+
+ Device Name + {selectedDisk.name} +
+ + {selectedDisk.type && ( +
+ Type + {selectedDisk.type} +
+ )} + + {selectedDisk.size && ( +
+ Capacity + {formatMemory(parseLsblkSize(selectedDisk.size))} +
+ )} + + {selectedDisk.model && ( +
+ Model + {selectedDisk.model} +
+ )} + + {selectedDisk.family && ( +
+ Family + {selectedDisk.family} +
+ )} + + {selectedDisk.serial && ( +
+ Serial Number + {selectedDisk.serial} +
+ )} + + {selectedDisk.firmware && ( +
+ Firmware + {selectedDisk.firmware} +
+ )} + + {selectedDisk.interface && ( +
+ Interface + {selectedDisk.interface} +
+ )} + + {selectedDisk.driver && ( +
+ Driver + {selectedDisk.driver} +
+ )} + + {selectedDisk.rotation_rate && ( +
+ Rotation Rate + {selectedDisk.rotation_rate} +
+ )} + + {selectedDisk.form_factor && ( +
+ Form Factor + {selectedDisk.form_factor} +
+ )} + + {selectedDisk.sata_version && ( +
+ SATA Version + {selectedDisk.sata_version} +
+ )} +
+ )} +
+
) }