"use client" import { useState, useEffect } from "react" import { Card, CardContent, CardHeader, CardTitle } from "./ui/card" import { Progress } from "./ui/progress" import { Badge } from "./ui/badge" import { Button } from "./ui/button" import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "./ui/dialog" import { HardDrive, Database, Archive, AlertTriangle, CheckCircle, Activity, AlertCircle, Thermometer, Info, } from "lucide-react" interface StorageData { total: number used: number available: number disks: DiskInfo[] } interface DiskInfo { name: string mountpoint: string fstype: string total: number used: number available: number usage_percent: number health: string temperature: number disk_type?: string model?: string serial?: string smart_status?: string power_on_hours?: number power_cycles?: number reallocated_sectors?: number pending_sectors?: number crc_errors?: number percentage_used?: number // NVMe ssd_life_left?: number // SSD wear_leveling_count?: number // SSD media_wearout_indicator?: number // SSD total_lbas_written?: number // Both } const TEMP_THRESHOLDS = { HDD: { safe: 45, warning: 55 }, SSD: { safe: 55, warning: 65 }, NVMe: { safe: 60, warning: 70 }, } const getTempStatus = (temp: number, diskType: string): "safe" | "warning" | "critical" => { const thresholds = TEMP_THRESHOLDS[diskType as keyof typeof TEMP_THRESHOLDS] || TEMP_THRESHOLDS.HDD if (temp <= thresholds.safe) return "safe" if (temp <= thresholds.warning) return "warning" return "critical" } const getTempColor = (status: "safe" | "warning" | "critical"): string => { switch (status) { case "safe": return "text-green-500" case "warning": return "text-yellow-500" case "critical": return "text-red-500" default: return "text-muted-foreground" } } const getDiskTypeBadgeColor = (diskType: string): string => { switch (diskType) { case "HDD": return "bg-blue-500/10 text-blue-500 border-blue-500/20" case "SSD": return "bg-purple-500/10 text-purple-500 border-purple-500/20" case "NVMe": return "bg-orange-500/10 text-orange-500 border-orange-500/20" default: return "bg-gray-500/10 text-gray-500 border-gray-500/20" } } const getWearStatus = (lifeLeft: number): { status: string; color: string } => { if (lifeLeft >= 80) return { status: "Excellent", color: "text-green-500" } if (lifeLeft >= 50) return { status: "Good", color: "text-yellow-500" } if (lifeLeft >= 20) return { status: "Fair", color: "text-orange-500" } return { status: "Poor", color: "text-red-500" } } const fetchStorageData = async (): Promise => { try { const response = await fetch("/api/storage", { method: "GET", headers: { "Content-Type": "application/json", }, signal: AbortSignal.timeout(5000), }) if (!response.ok) { throw new Error(`Flask server responded with status: ${response.status}`) } const data = await response.json() return data } catch (error) { console.error("Failed to fetch storage data from Flask server:", error) return null } } export function StorageMetrics() { const [storageData, setStorageData] = useState(null) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [selectedDisk, setSelectedDisk] = useState(null) const [showDiskDetails, setShowDiskDetails] = useState(false) const [showTempInfo, setShowTempInfo] = useState(false) useEffect(() => { const fetchData = async () => { setLoading(true) setError(null) const result = await fetchStorageData() if (!result) { setError("Flask server not available. Please ensure the server is running.") } else { setStorageData(result) } setLoading(false) } fetchData() const interval = setInterval(fetchData, 60000) return () => clearInterval(interval) }, []) if (loading) { return (
Loading storage data...
) } if (error || !storageData) { return (
Flask Server Not Available
{error || "Unable to connect to the Flask server. Please ensure the server is running and try again."}
) } const usagePercent = storageData.total > 0 ? (storageData.used / storageData.total) * 100 : 0 const disksByType = storageData.disks.reduce( (acc, disk) => { const type = disk.disk_type || "Unknown" if (!acc[type]) { acc[type] = [] } acc[type].push(disk) return acc }, {} as Record, ) const tempByType = Object.entries(disksByType) .map(([type, disks]) => { const avgTemp = disks.reduce((sum, disk) => sum + disk.temperature, 0) / disks.length const status = getTempStatus(avgTemp, type) return { type, avgTemp: Math.round(avgTemp), status, count: disks.length } }) .filter((item) => item.type !== "Unknown") return (
{/* Storage Overview Cards */}
Total Storage
{storageData.total.toFixed(1)} GB

{storageData.used.toFixed(1)} GB used • {storageData.available.toFixed(1)} GB available

Used Storage
{storageData.used.toFixed(1)} GB

{usagePercent.toFixed(1)}% of total space

Available
{storageData.available.toFixed(1)} GB
{((storageData.available / storageData.total) * 100).toFixed(1)}% Free

Available space

Disks
{storageData.disks.length}
{storageData.disks.filter((d) => d.health === "healthy").length} Healthy

Storage devices

{/* Temperature cards by disk type */} {tempByType.length > 0 ? (
{tempByType.map(({ type, avgTemp, status, count }) => { return (
Avg Temperature
{type}
{avgTemp}°C

{count} {type} disk{count > 1 ? "s" : ""}

{status === "safe" ? "Optimal" : status === "warning" ? "Warning" : "Critical"}
) })}
) : null} {/* Disk Details */} Storage Devices
{storageData.disks.map((disk, index) => { const diskType = disk.disk_type || "HDD" const tempStatus = getTempStatus(disk.temperature, diskType) let lifeLeft: number | null = null let wearLabel = "" if (diskType === "NVMe" && disk.percentage_used !== undefined && disk.percentage_used !== null) { lifeLeft = 100 - disk.percentage_used wearLabel = "Life Left" } else if (diskType === "SSD") { if (disk.ssd_life_left !== undefined && disk.ssd_life_left !== null) { lifeLeft = disk.ssd_life_left wearLabel = "Life Left" } else if (disk.media_wearout_indicator !== undefined && disk.media_wearout_indicator !== null) { lifeLeft = disk.media_wearout_indicator wearLabel = "Health" } else if (disk.wear_leveling_count !== undefined && disk.wear_leveling_count !== null) { lifeLeft = disk.wear_leveling_count wearLabel = "Wear Level" } } return (
{ setSelectedDisk(disk) setShowDiskDetails(true) }} >
{disk.name} {disk.disk_type && ( {disk.disk_type} )}
{disk.fstype} • {disk.mountpoint}
{disk.used.toFixed(1)} GB / {disk.total.toFixed(1)} GB
Temp
{disk.temperature}°C
{lifeLeft !== null && (diskType === "SSD" || diskType === "NVMe") && (
{wearLabel}
{lifeLeft.toFixed(0)}%
)} {disk.health === "healthy" ? ( ) : ( )} {disk.health}
) })}
Temperature Thresholds by Disk Type Recommended operating temperature ranges for different storage devices
Disk Type Safe Zone Warning Zone Critical Zone
HDD ≤ 45°C 46 – 55°C > 55°C
SSD ≤ 55°C 56 – 65°C > 65°C
NVMe ≤ 60°C 61 – 70°C > 70°C

These thresholds are based on industry standards and manufacturer recommendations. Operating within the safe zone ensures optimal performance and longevity.

{selectedDisk && ( <> Disk Details: {selectedDisk.name} Complete SMART information and health status
{/* Basic Info */}
Model
{selectedDisk.model || "Unknown"}
Serial Number
{selectedDisk.serial || "Unknown"}
Capacity
{selectedDisk.total.toFixed(1)}G
Health Status
{selectedDisk.health === "healthy" ? "Healthy" : "Warning"}
{(selectedDisk.disk_type === "SSD" || selectedDisk.disk_type === "NVMe") && (

Wear & Life Indicators

{selectedDisk.disk_type === "NVMe" && selectedDisk.percentage_used !== undefined && selectedDisk.percentage_used !== null && ( <>
Percentage Used
{selectedDisk.percentage_used}%
Life Remaining
{(100 - selectedDisk.percentage_used).toFixed(0)}%
)} {selectedDisk.disk_type === "SSD" && ( <> {selectedDisk.ssd_life_left !== undefined && selectedDisk.ssd_life_left !== null && (
SSD Life Left
{selectedDisk.ssd_life_left}%
)} {selectedDisk.wear_leveling_count !== undefined && selectedDisk.wear_leveling_count !== null && (
Wear Leveling Count
{selectedDisk.wear_leveling_count}
)} {selectedDisk.media_wearout_indicator !== undefined && selectedDisk.media_wearout_indicator !== null && (
Media Wearout Indicator
{selectedDisk.media_wearout_indicator}%
)} )} {selectedDisk.total_lbas_written !== undefined && selectedDisk.total_lbas_written !== null && (
Total Data Written
{(selectedDisk.total_lbas_written / 1000000).toFixed(2)} TB
)}
)} {/* SMART Attributes */}

SMART Attributes

Temperature
{selectedDisk.temperature}°C
Power On Hours
{selectedDisk.power_on_hours ? `${selectedDisk.power_on_hours}h (${Math.floor(selectedDisk.power_on_hours / 24)}d)` : "N/A"}
Rotation Rate
{selectedDisk.disk_type || "Unknown"}
Power Cycles
{selectedDisk.power_cycles || 0}
SMART Status
{selectedDisk.smart_status === "passed" ? "Passed" : "Unknown"}
Reallocated Sectors
{selectedDisk.reallocated_sectors || 0}
Pending Sectors
{selectedDisk.pending_sectors || 0}
CRC Errors
{selectedDisk.crc_errors || 0}
)}
) }