diff --git a/AppImage/components/hardware.tsx b/AppImage/components/hardware.tsx
index 7714e0f..6fe121c 100644
--- a/AppImage/components/hardware.tsx
+++ b/AppImage/components/hardware.tsx
@@ -1614,11 +1614,23 @@ export default function Hardware() {
(device) => device.type === "disk" && !device.name.startsWith("zd") && !device.name.startsWith("loop"),
)
.map((device, index) => {
- const getDiskTypeBadge = (diskName: string, rotationRate: number | undefined) => {
+ const getDiskTypeBadge = (diskName: string, rotationRate: number | string | undefined) => {
let diskType = "HDD"
+
+ // Check if it's NVMe
if (diskName.startsWith("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"
}
@@ -1655,9 +1667,6 @@ export default function Hardware() {
{device.model && (
{device.model}
)}
- {device.driver && (
- Driver: {device.driver}
- )}
)
})}
@@ -1681,10 +1690,44 @@ export default function Hardware() {
{selectedDisk.name}
- {selectedDisk.type && (
+ {selectedDisk.name && (
Type
- {selectedDisk.type}
+ {(() => {
+ 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 = {
+ 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 {diskBadge.label}
+ })()}
)}
@@ -1737,10 +1780,16 @@ export default function Hardware() {
)}
- {selectedDisk.rotation_rate && (
+ {selectedDisk.rotation_rate !== undefined && selectedDisk.rotation_rate !== null && (
Rotation Rate
- {selectedDisk.rotation_rate}
+
+ {typeof selectedDisk.rotation_rate === "number" && selectedDisk.rotation_rate > 0
+ ? `${selectedDisk.rotation_rate} rpm`
+ : typeof selectedDisk.rotation_rate === "string"
+ ? selectedDisk.rotation_rate
+ : "Solid State Device"}
+
)}
diff --git a/AppImage/scripts/flask_server.py b/AppImage/scripts/flask_server.py
index 57fb399..7533f0b 100644
--- a/AppImage/scripts/flask_server.py
+++ b/AppImage/scripts/flask_server.py
@@ -936,6 +936,10 @@ def get_smart_data(disk_name):
'wear_leveling_count': None, # SSD: Wear Leveling Count
'total_lbas_written': None, # SSD/NVMe: Total LBAs Written
'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}")
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)
try:
# Try nvidia-smi first
diff --git a/AppImage/types/hardware.ts b/AppImage/types/hardware.ts
index b80d500..6907646 100644
--- a/AppImage/types/hardware.ts
+++ b/AppImage/types/hardware.ts
@@ -30,7 +30,7 @@ export interface StorageDevice {
serial?: string
family?: string
firmware?: string
- rotation_rate?: string
+ rotation_rate?: number | string
form_factor?: string
sata_version?: string
}