SMART: detect drives whose firmware rejects the self-test log (WD SN580) and hide the test buttons with an explanation

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Mitchell-Johnson
2026-09-18 11:37:49 -07:00
co-authored by Claude Fable 5.1
parent 340232b724
commit e9be94e32b
3 changed files with 33 additions and 3 deletions
+3 -2
View File
@@ -62,10 +62,11 @@ function SmartPanel({ dev, rotational }: { dev: string; rotational: boolean }) {
</tbody>
</table>
)}
<div className="svc-actions">
{!s.self_test_supported && <div className="muted small">Self-tests: {s.self_test_note || 'not available on this drive'}.</div>}
{s.self_test_supported && <div className="svc-actions">
<Btn className="btn" confirm={`Start a short self-test on ${dev}?`} onClick={async () => { if (await api.smartTest(dev, 'short').then(() => true, (e) => { toast(String(e.message ?? e), 'err'); return false })) { toast('short test started'); load(true) } }}>Short test</Btn>
<Btn className="btn" confirm={`Start a long self-test on ${dev}? ${rotational ? 'This can take hours on a spinning disk.' : ''}`} onClick={async () => { if (await api.smartTest(dev, 'long').then(() => true, (e) => { toast(String(e.message ?? e), 'err'); return false })) { toast('long test started'); load(true) } }}>Long test</Btn>
</div>
</div>}
</div>
)
}
+1 -1
View File
@@ -83,7 +83,7 @@ export interface UpdatesStatus { manager: string; can_upgrade: boolean; packages
export interface StoragePart { name: string; type: string; fstype?: string; mount?: string; label?: string; size: number; used?: number; fs_size?: number }
export interface StorageDevice { name: string; kind: string; model?: string; vendor?: string; serial?: string; tran?: string; size: number; rotational: boolean; removable: boolean; temp?: number; parts: StoragePart[] }
export interface SmartAttr { id: number; name: string; value: number; worst: number; thresh: number; raw: string; failed?: string; warn: boolean }
export interface SmartInfo { device: string; available: boolean; supported: boolean; standby: boolean; passed: boolean | null; temp: number; power_on_hours: number; power_cycles: number; model?: string; serial?: string; firmware?: string; attrs: SmartAttr[]; nvme?: { critical_warning: number; percentage_used: number; available_spare: number; spare_threshold: number; media_errors: number; error_log_entries: number; data_read_bytes: number; data_written_bytes: number; unsafe_shutdowns: number }; self_test?: string; self_test_remaining?: number; warnings: string[]; error?: string; fetched_at: number }
export interface SmartInfo { device: string; available: boolean; supported: boolean; standby: boolean; passed: boolean | null; temp: number; power_on_hours: number; power_cycles: number; model?: string; serial?: string; firmware?: string; attrs: SmartAttr[]; nvme?: { critical_warning: number; percentage_used: number; available_spare: number; spare_threshold: number; media_errors: number; error_log_entries: number; data_read_bytes: number; data_written_bytes: number; unsafe_shutdowns: number }; self_test?: string; self_test_remaining?: number; self_test_supported: boolean; self_test_note?: string; warnings: string[]; error?: string; fetched_at: number }
export interface ZFSSnapshot { name: string; used: number; created: number }
export interface ZFSInfo { available: boolean; message?: string; pools: { name: string; size: number; alloc: number; free: number; frag: number; cap: number; health: string; dedup: string; scan?: string; errors?: string; config?: string }[]; datasets: { name: string; type: string; used: number; avail: number; refer: number; used_by_snapshots: number; mount?: string; compressratio: string; snapshots: number }[] }