mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2025-11-18 03:26:17 +00:00
Update AppImage
This commit is contained in:
@@ -1614,11 +1614,23 @@ export default function Hardware() {
|
|||||||
(device) => device.type === "disk" && !device.name.startsWith("zd") && !device.name.startsWith("loop"),
|
(device) => device.type === "disk" && !device.name.startsWith("zd") && !device.name.startsWith("loop"),
|
||||||
)
|
)
|
||||||
.map((device, index) => {
|
.map((device, index) => {
|
||||||
const getDiskTypeBadge = (diskName: string, rotationRate: number | undefined) => {
|
const getDiskTypeBadge = (diskName: string, rotationRate: number | string | undefined) => {
|
||||||
let diskType = "HDD"
|
let diskType = "HDD"
|
||||||
|
|
||||||
|
// Check if it's NVMe
|
||||||
if (diskName.startsWith("nvme")) {
|
if (diskName.startsWith("nvme")) {
|
||||||
diskType = "NVMe"
|
diskType = "NVMe"
|
||||||
} else if (!rotationRate || rotationRate === 0) {
|
}
|
||||||
|
// Check rotation rate for SSD vs HDD
|
||||||
|
else if (rotationRate !== undefined && rotationRate !== null) {
|
||||||
|
// Handle both number and string formats
|
||||||
|
const rateNum = typeof rotationRate === "string" ? Number.parseInt(rotationRate) : rotationRate
|
||||||
|
if (rateNum === 0 || isNaN(rateNum)) {
|
||||||
|
diskType = "SSD"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If rotation_rate is "Solid State Device" string
|
||||||
|
else if (typeof rotationRate === "string" && rotationRate.includes("Solid State")) {
|
||||||
diskType = "SSD"
|
diskType = "SSD"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1655,9 +1667,6 @@ export default function Hardware() {
|
|||||||
{device.model && (
|
{device.model && (
|
||||||
<p className="text-xs text-muted-foreground line-clamp-2 break-words">{device.model}</p>
|
<p className="text-xs text-muted-foreground line-clamp-2 break-words">{device.model}</p>
|
||||||
)}
|
)}
|
||||||
{device.driver && (
|
|
||||||
<p className="mt-1 font-mono text-xs text-green-500 truncate">Driver: {device.driver}</p>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
@@ -1681,10 +1690,44 @@ export default function Hardware() {
|
|||||||
<span className="font-mono text-sm">{selectedDisk.name}</span>
|
<span className="font-mono text-sm">{selectedDisk.name}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{selectedDisk.type && (
|
{selectedDisk.name && (
|
||||||
<div className="flex justify-between border-b border-border/50 pb-2">
|
<div className="flex justify-between border-b border-border/50 pb-2">
|
||||||
<span className="text-sm font-medium text-muted-foreground">Type</span>
|
<span className="text-sm font-medium text-muted-foreground">Type</span>
|
||||||
<Badge className="bg-blue-500/10 text-blue-500 border-blue-500/20">{selectedDisk.type}</Badge>
|
{(() => {
|
||||||
|
const getDiskTypeBadge = (diskName: string, rotationRate: number | string | undefined) => {
|
||||||
|
let diskType = "HDD"
|
||||||
|
|
||||||
|
if (diskName.startsWith("nvme")) {
|
||||||
|
diskType = "NVMe"
|
||||||
|
} else if (rotationRate !== undefined && rotationRate !== null) {
|
||||||
|
const rateNum = typeof rotationRate === "string" ? Number.parseInt(rotationRate) : rotationRate
|
||||||
|
if (rateNum === 0 || isNaN(rateNum)) {
|
||||||
|
diskType = "SSD"
|
||||||
|
}
|
||||||
|
} else if (typeof rotationRate === "string" && rotationRate.includes("Solid State")) {
|
||||||
|
diskType = "SSD"
|
||||||
|
}
|
||||||
|
|
||||||
|
const badgeStyles: Record<string, { className: string; label: string }> = {
|
||||||
|
NVMe: {
|
||||||
|
className: "bg-purple-500/10 text-purple-500 border-purple-500/20",
|
||||||
|
label: "NVMe SSD",
|
||||||
|
},
|
||||||
|
SSD: {
|
||||||
|
className: "bg-cyan-500/10 text-cyan-500 border-cyan-500/20",
|
||||||
|
label: "SSD",
|
||||||
|
},
|
||||||
|
HDD: {
|
||||||
|
className: "bg-blue-500/10 text-blue-500 border-blue-500/20",
|
||||||
|
label: "HDD",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return badgeStyles[diskType]
|
||||||
|
}
|
||||||
|
|
||||||
|
const diskBadge = getDiskTypeBadge(selectedDisk.name, selectedDisk.rotation_rate)
|
||||||
|
return <Badge className={diskBadge.className}>{diskBadge.label}</Badge>
|
||||||
|
})()}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -1737,10 +1780,16 @@ export default function Hardware() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{selectedDisk.rotation_rate && (
|
{selectedDisk.rotation_rate !== undefined && selectedDisk.rotation_rate !== null && (
|
||||||
<div className="flex justify-between border-b border-border/50 pb-2">
|
<div className="flex justify-between border-b border-border/50 pb-2">
|
||||||
<span className="text-sm font-medium text-muted-foreground">Rotation Rate</span>
|
<span className="text-sm font-medium text-muted-foreground">Rotation Rate</span>
|
||||||
<span className="text-sm">{selectedDisk.rotation_rate}</span>
|
<span className="text-sm">
|
||||||
|
{typeof selectedDisk.rotation_rate === "number" && selectedDisk.rotation_rate > 0
|
||||||
|
? `${selectedDisk.rotation_rate} rpm`
|
||||||
|
: typeof selectedDisk.rotation_rate === "string"
|
||||||
|
? selectedDisk.rotation_rate
|
||||||
|
: "Solid State Device"}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -936,6 +936,10 @@ def get_smart_data(disk_name):
|
|||||||
'wear_leveling_count': None, # SSD: Wear Leveling Count
|
'wear_leveling_count': None, # SSD: Wear Leveling Count
|
||||||
'total_lbas_written': None, # SSD/NVMe: Total LBAs Written
|
'total_lbas_written': None, # SSD/NVMe: Total LBAs Written
|
||||||
'ssd_life_left': None, # SSD: SSD Life Left percentage
|
'ssd_life_left': None, # SSD: SSD Life Left percentage
|
||||||
|
'firmware': None, # Added firmware
|
||||||
|
'family': None, # Added model family
|
||||||
|
'sata_version': None, # Added SATA version
|
||||||
|
'form_factor': None # Added Form Factor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -3802,6 +3806,105 @@ def get_hardware_info():
|
|||||||
# print(f"[v0] Error getting storage info: {e}")
|
# print(f"[v0] Error getting storage info: {e}")
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = subprocess.run(['lsblk', '-J', '-o', 'NAME,SIZE,TYPE,MOUNTPOINT,MODEL'],
|
||||||
|
capture_output=True, text=True, timeout=5)
|
||||||
|
if result.returncode == 0:
|
||||||
|
import json
|
||||||
|
lsblk_data = json.loads(result.stdout)
|
||||||
|
storage_devices = []
|
||||||
|
for device in lsblk_data.get('blockdevices', []):
|
||||||
|
if device.get('type') == 'disk':
|
||||||
|
disk_name = device.get('name', '')
|
||||||
|
|
||||||
|
# Get SMART data for this disk
|
||||||
|
smart_data = get_smart_data(disk_name)
|
||||||
|
|
||||||
|
# Determine interface type
|
||||||
|
interface_type = None
|
||||||
|
if disk_name.startswith('nvme'):
|
||||||
|
interface_type = 'PCIe/NVMe'
|
||||||
|
elif disk_name.startswith('sd'):
|
||||||
|
interface_type = 'ATA'
|
||||||
|
elif disk_name.startswith('hd'):
|
||||||
|
interface_type = 'IDE'
|
||||||
|
|
||||||
|
# Get driver information
|
||||||
|
driver = None
|
||||||
|
try:
|
||||||
|
sys_block_path = f'/sys/block/{disk_name}'
|
||||||
|
if os.path.exists(sys_block_path):
|
||||||
|
device_path = os.path.join(sys_block_path, 'device')
|
||||||
|
if os.path.exists(device_path):
|
||||||
|
driver_path = os.path.join(device_path, 'driver')
|
||||||
|
if os.path.exists(driver_path):
|
||||||
|
driver = os.path.basename(os.readlink(driver_path))
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Parse SATA version from smartctl output
|
||||||
|
sata_version = None
|
||||||
|
try:
|
||||||
|
result_smart = subprocess.run(['smartctl', '-i', f'/dev/{disk_name}'],
|
||||||
|
capture_output=True, text=True, timeout=5)
|
||||||
|
if result_smart.returncode == 0:
|
||||||
|
for line in result_smart.stdout.split('\n'):
|
||||||
|
if 'SATA Version is:' in line:
|
||||||
|
sata_version = line.split(':', 1)[1].strip()
|
||||||
|
break
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Parse form factor from smartctl output
|
||||||
|
form_factor = None
|
||||||
|
try:
|
||||||
|
result_smart = subprocess.run(['smartctl', '-i', f'/dev/{disk_name}'],
|
||||||
|
capture_output=True, text=True, timeout=5)
|
||||||
|
if result_smart.returncode == 0:
|
||||||
|
for line in result_smart.stdout.split('\n'):
|
||||||
|
if 'Form Factor:' in line:
|
||||||
|
form_factor = line.split(':', 1)[1].strip()
|
||||||
|
break
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Build storage device with all available information
|
||||||
|
storage_device = {
|
||||||
|
'name': disk_name,
|
||||||
|
'size': device.get('size', ''),
|
||||||
|
'model': smart_data.get('model', device.get('model', 'Unknown')),
|
||||||
|
'type': device.get('type', 'disk'),
|
||||||
|
'serial': smart_data.get('serial', 'Unknown'),
|
||||||
|
'firmware': smart_data.get('firmware'),
|
||||||
|
'interface': interface_type,
|
||||||
|
'driver': driver,
|
||||||
|
'rotation_rate': smart_data.get('rotation_rate', 0),
|
||||||
|
'form_factor': form_factor,
|
||||||
|
'sata_version': sata_version,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Add family if available (from smartctl)
|
||||||
|
try:
|
||||||
|
result_smart = subprocess.run(['smartctl', '-i', f'/dev/{disk_name}'],
|
||||||
|
capture_output=True, text=True, timeout=5)
|
||||||
|
if result_smart.returncode == 0:
|
||||||
|
for line in result_smart.stdout.split('\n'):
|
||||||
|
if 'Model Family:' in line:
|
||||||
|
storage_device['family'] = line.split(':', 1)[1].strip()
|
||||||
|
break
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
storage_devices.append(storage_device)
|
||||||
|
|
||||||
|
hardware_data['storage_devices'] = storage_devices
|
||||||
|
# print(f"[v0] Storage devices: {len(storage_devices)} found with full SMART data")
|
||||||
|
pass
|
||||||
|
except Exception as e:
|
||||||
|
# print(f"[v0] Error getting storage info: {e}")
|
||||||
|
pass
|
||||||
|
|
||||||
# Graphics Cards (from lspci - will be duplicated by new PCI device listing, but kept for now)
|
# Graphics Cards (from lspci - will be duplicated by new PCI device listing, but kept for now)
|
||||||
try:
|
try:
|
||||||
# Try nvidia-smi first
|
# Try nvidia-smi first
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export interface StorageDevice {
|
|||||||
serial?: string
|
serial?: string
|
||||||
family?: string
|
family?: string
|
||||||
firmware?: string
|
firmware?: string
|
||||||
rotation_rate?: string
|
rotation_rate?: number | string
|
||||||
form_factor?: string
|
form_factor?: string
|
||||||
sata_version?: string
|
sata_version?: string
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user