From 7c8da462db53cd0dcee3e537ba0a3dec1685023d Mon Sep 17 00:00:00 2001 From: MacRimi Date: Thu, 16 Apr 2026 16:42:11 +0200 Subject: [PATCH] update storage-overview.tsx --- AppImage/components/storage-overview.tsx | 78 +++++++++--------------- AppImage/scripts/flask_server.py | 5 +- 2 files changed, 34 insertions(+), 49 deletions(-) diff --git a/AppImage/components/storage-overview.tsx b/AppImage/components/storage-overview.tsx index 03a0c6bc..7007f519 100644 --- a/AppImage/components/storage-overview.tsx +++ b/AppImage/components/storage-overview.tsx @@ -1818,7 +1818,7 @@ export function StorageOverview() { } // Generate SMART Report HTML and open in new window (same pattern as Lynis/Latency reports) -function openSmartReport(disk: DiskInfo, testStatus: SmartTestStatus, smartAttributes: SmartAttribute[], observations: DiskObservation[] = [], lastTestDate?: string, targetWindow?: Window) { +function openSmartReport(disk: DiskInfo, testStatus: SmartTestStatus, smartAttributes: SmartAttribute[], observations: DiskObservation[] = [], lastTestDate?: string, targetWindow?: Window, isHistorical = false) { const now = new Date().toLocaleString() const logoUrl = `${window.location.origin}/images/proxmenux-logo.png` const reportId = `SMART-${Date.now().toString(36).toUpperCase()}` @@ -2417,7 +2417,7 @@ function openSmartReport(disk: DiskInfo, testStatus: SmartTestStatus, smartAttri
${now}
-
Last Test Type
+
${isHistorical ? 'Test Type' : 'Last Test Type'}
${testStatus.last_test?.type || 'N/A'}
@@ -2740,7 +2740,7 @@ ${!isNvmeDisk && diskType === 'SSD' ? (() => {
-
${isNvmeDisk ? '5' : '4'}. Last Self-Test Result
+
${isNvmeDisk ? '5' : '4'}. ${isHistorical ? 'Self-Test Result' : 'Last Self-Test Result'}
${testStatus.last_test ? `
@@ -2789,6 +2789,28 @@ ${!isNvmeDisk && diskType === 'SSD' ? (() => {
` : ''} + ` : lastTestDate ? ` +
+
+
${isHistorical ? 'Test Type' : 'Last Test Type'}
+
${testStatus.test_type || 'Extended'}
+
+
+
Result
+
Passed
+
+
+
Date
+
${new Date(lastTestDate).toLocaleString()}
+
+
+
At Power-On Hours
+
${fmtNum(powerOnHours)}h
+
+
+
+ Note: This disk's firmware does not maintain an internal self-test log. Test results are tracked by ProxMenux Monitor. +
` : `
No self-test history available. Run a SMART self-test to see results here. @@ -3353,51 +3375,11 @@ function HistoryTab({ disk }: { disk: DiskInfo }) { try { setViewingReport(entry.filename) - const jsonData = await fetchApi>(`/api/storage/smart/${disk.name}/history/${entry.filename}`) + // Fetch full SMART status from backend (same data as SMART tab uses) + const fullStatus = await fetchApi(`/api/storage/smart/${disk.name}`) + const attrs = fullStatus.smart_data?.attributes || [] - const isNvme = disk.name.includes('nvme') - let attrs: SmartAttribute[] = [] - - if (isNvme) { - const fieldMap: [string, string][] = [ - ['critical_warning', 'Critical Warning'], ['temperature', 'Temperature'], - ['avail_spare', 'Available Spare'], ['percent_used', 'Percentage Used'], - ['data_units_written', 'Data Units Written'], ['data_units_read', 'Data Units Read'], - ['power_cycles', 'Power Cycles'], ['power_on_hours', 'Power On Hours'], - ['unsafe_shutdowns', 'Unsafe Shutdowns'], ['media_errors', 'Media Errors'], - ['num_err_log_entries', 'Error Log Entries'], - ] - fieldMap.forEach(([key, name], i) => { - if (jsonData[key] !== undefined) { - const v = jsonData[key] as number - const status = (key === 'critical_warning' || key === 'media_errors') && v > 0 ? 'critical' as const : 'ok' as const - attrs.push({ id: i + 1, name, value: String(v), worst: '-', threshold: '-', raw_value: String(v), status }) - } - }) - } else { - const ataTable = (jsonData as Record)?.ata_smart_attributes as { table?: Array> } - if (ataTable?.table) { - attrs = ataTable.table.map(a => ({ - id: (a.id as number) || 0, - name: (a.name as string) || '', - value: (a.value as number) || 0, - worst: (a.worst as number) || 0, - threshold: (a.thresh as number) || 0, - raw_value: (a.raw as Record)?.string as string || String((a.raw as Record)?.value || 0), - status: 'ok' as const - })) - } - } - - const testStatus: SmartTestStatus = { - status: 'idle', - smart_data: { device: disk.name, model: disk.model || '', serial: disk.serial || '', firmware: '', smart_status: 'passed', temperature: disk.temperature, power_on_hours: disk.power_on_hours || 0, attributes: attrs } - } - - // Generate report — write directly into the already-open window (avoids popup blocker) - // openSmartReport creates a blob and calls window.open, but we already have a window. - // So we call the same logic but write to our existing window. - openSmartReport(disk, testStatus, attrs, [], entry.timestamp, reportWindow || undefined) + openSmartReport(disk, fullStatus, attrs, [], entry.timestamp, reportWindow || undefined, true) } catch { if (reportWindow && !reportWindow.closed) { reportWindow.document.body.innerHTML = '

Failed to load report data.

' @@ -3845,7 +3827,7 @@ function ScheduleTab({ disk }: { disk: DiskInfo }) { diff --git a/AppImage/scripts/flask_server.py b/AppImage/scripts/flask_server.py index ad4da480..aa411788 100644 --- a/AppImage/scripts/flask_server.py +++ b/AppImage/scripts/flask_server.py @@ -7156,7 +7156,10 @@ def api_smart_run_test(disk_name): [ -z "$op" ] || [ "$op" -eq 0 ] && break sleep {sleep_interval} done - nvme smart-log -o json {device} > {json_path} 2>/dev/null + # Save complete data: smartctl gives device info + health + self-test log in one JSON + smartctl -a --json=c {device} > {json_path} 2>/dev/null + # Fallback to nvme smart-log if smartctl fails + [ ! -s {json_path} ] && nvme smart-log -o json {device} > {json_path} 2>/dev/null ''', shell=True, start_new_session=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL