"use client" import { useEffect, useState } from "react" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { HardDrive, Database, AlertTriangle, CheckCircle2, XCircle, Thermometer } from "lucide-react" import { Badge } from "@/components/ui/badge" import { Progress } from "@/components/ui/progress" interface DiskInfo { name: string size?: string temperature: number health: string power_on_hours?: number smart_status?: string model?: string serial?: string mountpoint?: string fstype?: string total?: number used?: number available?: number usage_percent?: number } interface ZFSPool { name: string size: string allocated: string free: string health: string } interface StorageData { total: number used: number available: number disks: DiskInfo[] zfs_pools: ZFSPool[] error?: string } export function StorageOverview() { const [storageData, setStorageData] = useState(null) const [loading, setLoading] = useState(true) const fetchStorageData = async () => { try { const baseUrl = typeof window !== "undefined" ? `${window.location.protocol}//${window.location.hostname}:8008` : "" const response = await fetch(`${baseUrl}/api/storage`) const data = await response.json() setStorageData(data) } catch (error) { console.error("Error fetching storage data:", error) } finally { setLoading(false) } } useEffect(() => { fetchStorageData() const interval = setInterval(fetchStorageData, 15000) // Update every 15 seconds return () => clearInterval(interval) }, []) const getHealthIcon = (health: string) => { switch (health.toLowerCase()) { case "healthy": case "passed": case "online": return case "warning": return case "critical": case "failed": case "degraded": return default: return } } const getHealthBadge = (health: string) => { switch (health.toLowerCase()) { case "healthy": case "passed": case "online": return Healthy case "warning": return Warning case "critical": case "failed": case "degraded": return Critical default: return Unknown } } const getTempColor = (temp: number) => { if (temp === 0) return "text-gray-500" if (temp < 45) return "text-green-500" if (temp < 60) return "text-yellow-500" return "text-red-500" } if (loading) { return (
Loading storage information...
) } if (!storageData || storageData.error) { return (
Error loading storage data: {storageData?.error || "Unknown error"}
) } return (
{/* Storage Summary */}
Total Storage
{storageData.total} GB
Used Storage
{storageData.used} GB

{storageData.total > 0 ? Math.round((storageData.used / storageData.total) * 100) : 0}% used

Available Storage
{storageData.available} GB
{/* ZFS Pools */} {storageData.zfs_pools && storageData.zfs_pools.length > 0 && ( ZFS Pools
{storageData.zfs_pools.map((pool) => (

{pool.name}

{getHealthBadge(pool.health)}
{getHealthIcon(pool.health)}

Size

{pool.size}

Allocated

{pool.allocated}

Free

{pool.free}

))}
)} {/* Physical Disks */} Physical Disks & SMART Status
{storageData.disks.map((disk) => (

/dev/{disk.name}

{disk.model && disk.model !== "Unknown" && (

{disk.model}

)}
{disk.temperature > 0 && (
{disk.temperature}°C
)} {getHealthBadge(disk.health)}
{disk.size && (

Size

{disk.size}

)} {disk.smart_status && disk.smart_status !== "unknown" && (

SMART Status

{disk.smart_status}

)} {disk.power_on_hours && disk.power_on_hours > 0 && (

Power On Hours

{disk.power_on_hours.toLocaleString()}h

)} {disk.serial && disk.serial !== "Unknown" && (

Serial

{disk.serial}

)}
{disk.mountpoint && (
Mounted at: {disk.mountpoint} {disk.fstype && ({disk.fstype})}
{disk.usage_percent !== undefined && ( {disk.usage_percent}% )}
{disk.usage_percent !== undefined && } {disk.total && disk.used && disk.available && (
{disk.used} GB used {disk.available} GB free of {disk.total} GB
)}
)}
))}
) }