"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, DialogTrigger } from "./ui/dialog" import { HardDrive, Database, Archive, AlertTriangle, CheckCircle, Activity, AlertCircle, Info, Thermometer, } 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 percentage_used?: number ssd_life_left?: number wear_leveling_count?: number media_wearout_indicator?: number model?: string serial?: string power_on_hours?: number power_cycles?: number smart_status?: string reallocated_sectors?: number pending_sectors?: number crc_errors?: number rotation_rate?: number } 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() console.log("[v0] Storage data received:", data) console.log("[v0] Disks:", data.disks) if (data.disks && data.disks.length > 0) { console.log("[v0] First disk details:", data.disks[0]) console.log( "[v0] Disk types:", data.disks.map((d: DiskInfo) => ({ name: d.name, type: d.disk_type })), ) } return data } catch (error) { console.error("[v0] Failed to fetch storage data from Flask server:", error) return null } } const getTempStatus = (temp: number, diskType: string): "safe" | "warning" | "critical" => { if (diskType === "HDD") { if (temp > 55) return "critical" if (temp > 45) return "warning" return "safe" } else if (diskType === "SSD") { if (temp > 65) return "critical" if (temp > 55) return "warning" return "safe" } else if (diskType === "NVMe") { if (temp > 70) return "critical" if (temp > 60) return "warning" return "safe" } // Umbral genérico if (temp > 70) return "critical" if (temp > 60) return "warning" return "safe" } const groupDisksByType = (disks: DiskInfo[]): DiskGroup[] => { console.log("[v0] Grouping disks by type, total disks:", disks.length) const groups: { [key: string]: DiskInfo[] } = {} disks.forEach((disk) => { const type = disk.disk_type || "Unknown" console.log("[v0] Disk:", disk.name, "Type:", type, "Temp:", disk.temperature) if (!groups[type]) { groups[type] = [] } groups[type].push(disk) }) const result = Object.entries(groups).map(([type, disks]) => { const temps = disks.map((d) => d.temperature).filter((t) => t > 0) const avgTemp = temps.length > 0 ? Math.round(temps.reduce((a, b) => a + b, 0) / temps.length) : 0 // Determinar el estado más crítico del grupo let status: "safe" | "warning" | "critical" = "safe" disks.forEach((disk) => { const diskStatus = getTempStatus(disk.temperature, type) if (diskStatus === "critical") status = "critical" else if (diskStatus === "warning" && status !== "critical") status = "warning" }) console.log("[v0] Group:", type, "Disks:", disks.length, "Avg Temp:", avgTemp, "Status:", status) return { type, disks, avgTemp, status } }) console.log("[v0] Total groups created:", result.length) return result } interface DiskGroup { type: string disks: DiskInfo[] avgTemp: number status: "safe" | "warning" | "critical" } function DiskDetailsModal({ disk }: { disk: DiskInfo }) { const getHealthColor = (health: string) => { if (health === "healthy") return "bg-green-500/10 text-green-500 border-green-500/20" if (health === "warning") return "bg-yellow-500/10 text-yellow-500 border-yellow-500/20" return "bg-red-500/10 text-red-500 border-red-500/20" } const getLifeColor = (life: number) => { if (life >= 80) return "text-green-500" if (life >= 50) return "text-yellow-500" return "text-red-500" } return ( Disk Details: {disk.name} Complete SMART information and health status
{/* Basic Info */}
Model
{disk.model || "Unknown"}
Serial Number
{disk.serial || "Unknown"}
Capacity
{disk.total?.toFixed(1) || "N/A"}G
Health Status
{disk.health === "healthy" ? "Healthy" : disk.health}
{/* SSD/NVMe Wear Indicators */} {(disk.disk_type === "SSD" || disk.disk_type === "NVMe") && (

Indicadores de desgaste y salud

{disk.ssd_life_left !== undefined && (
Vida útil restante
{disk.ssd_life_left}%
)} {disk.disk_type === "NVMe" && disk.percentage_used !== undefined && (
Percentage Used
{disk.percentage_used}%
)} {disk.wear_leveling_count !== undefined && disk.wear_leveling_count > 0 && (
Wear Leveling Count
{disk.wear_leveling_count}%
)} {disk.media_wearout_indicator !== undefined && disk.media_wearout_indicator > 0 && (
Media Wearout Indicator
{disk.media_wearout_indicator}%
)}
)} {/* SMART Attributes */}

SMART Attributes

Temperature
{disk.temperature}°C
Power On Hours
{disk.power_on_hours ? `${disk.power_on_hours}h (${Math.floor(disk.power_on_hours / 24)}d)` : "N/A"}
Rotation Rate
{disk.rotation_rate === 0 || disk.disk_type === "SSD" || disk.disk_type === "NVMe" ? "SSD" : disk.rotation_rate ? `${disk.rotation_rate} RPM` : "N/A"}
Power Cycles
{disk.power_cycles || "N/A"}
SMART Status
{disk.smart_status === "passed" ? "Passed" : disk.smart_status || "Unknown"}
Reallocated Sectors
0 ? "text-red-500" : ""}`} > {disk.reallocated_sectors || 0}
Pending Sectors
0 ? "text-yellow-500" : ""}`} > {disk.pending_sectors || 0}
CRC Errors
0 ? "text-yellow-500" : ""}`}> {disk.crc_errors || 0}
) } function TemperatureThresholdsModal() { return ( Umbrales de temperatura por tipo de disco Rangos de temperatura recomendados para cada tipo de dispositivo de almacenamiento
Tipo de disco Temperatura de operación Zona segura Zona de advertencia Zona crítica
HDD 0°C – 60°C (común: 5–55°C) ≤ 45°C 46 – 55°C > 55°C
SSD 0°C – 70°C ≤ 55°C 56 – 65°C > 65°C
NVMe 0°C – 70°C ≤ 60°C 61 – 70°C > 70°C
) } export function StorageMetrics() { const [storageData, setStorageData] = useState(null) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) 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 diskGroups = groupDisksByType(storageData.disks) 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

{diskGroups.length > 0 && (

Temperatura por tipo de disco

{diskGroups.map((group) => (
{group.type} Temperature
{group.status === "safe" ? "Seguro" : group.status === "warning" ? "Advertencia" : "Crítico"}
{group.avgTemp}°C

Promedio de {group.disks.length} disco{group.disks.length > 1 ? "s" : ""}

{group.disks.map((disk, idx) => (
{disk.name} {disk.temperature}°C
))}
))}
)} {/* Disk Details */} Storage Devices
{storageData.disks.map((disk, index) => (
{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
{(disk.disk_type === "SSD" || disk.disk_type === "NVMe") && disk.ssd_life_left !== undefined && (
Vida útil
= 80 ? "text-green-500" : disk.ssd_life_left >= 50 ? "text-yellow-500" : "text-red-500" }`} > {disk.ssd_life_left}%
)} {disk.health === "healthy" ? ( ) : ( )} {disk.health}
))}
) }