diff --git a/backend/routers/system.py b/backend/routers/system.py index 7ffdb11..0d9c3aa 100644 --- a/backend/routers/system.py +++ b/backend/routers/system.py @@ -168,7 +168,16 @@ async def get_network_traffic(): return result -# ============== DISK I/O ============== +# ============== DISK USAGE + I/O ============== + +@router.get("/disk-usage") +async def get_disk_usage(): + """Get filesystem disk usage from df (public)""" + result = system_info.get_disk_usage() + if "error" in result: + raise HTTPException(status_code=500, detail=result["error"]) + return result + @router.get("/diskio") async def get_diskio(): diff --git a/backend/services/system_info.py b/backend/services/system_info.py index e87271b..763b912 100644 --- a/backend/services/system_info.py +++ b/backend/services/system_info.py @@ -429,6 +429,42 @@ def get_all_units() -> Dict[str, Any]: return {"error": str(e)} +def get_disk_usage() -> Dict[str, Any]: + try: + result = subprocess.run( + ["/usr/bin/df", "-P", "-x", "tmpfs", "-x", "devtmpfs", "-x", "squashfs", "-x", "overlay"], + capture_output=True, text=True, timeout=5 + ) + if result.returncode != 0: + return {"error": result.stderr} + + filesystems = [] + for line in result.stdout.strip().split("\n")[1:]: + parts = line.split() + if len(parts) < 6: + continue + try: + total = int(parts[1]) * 1024 + used = int(parts[2]) * 1024 + available = int(parts[3]) * 1024 + capacity = int(parts[4].rstrip("%")) + filesystems.append({ + "filesystem": parts[0], + "mountpoint": parts[5], + "total": total, + "used": used, + "available": available, + "capacity": capacity, + }) + except (ValueError, IndexError): + continue + + return {"filesystems": filesystems} + except Exception as e: + logger.error(f"Error getting disk usage: {e}") + return {"error": str(e)} + + def get_journal_logs(limit: int = 20) -> Dict[str, Any]: try: result = subprocess.run( diff --git a/frontend/app/page.tsx b/frontend/app/page.tsx index 9146f9f..081e705 100644 --- a/frontend/app/page.tsx +++ b/frontend/app/page.tsx @@ -24,6 +24,7 @@ export default function Dashboard() { const [networkInfo, setNetworkInfo] = useState(null) const [networkTraffic, setNetworkTraffic] = useState(null) const [diskIO, setDiskIO] = useState(null) + const [diskUsage, setDiskUsage] = useState(null) // History buffers for sparklines (rolling window of 30 points, ~2.5 minutes at 5s intervals) const cpuHistoryRef = useRef([]) @@ -100,7 +101,7 @@ export default function Dashboard() { const loadSystemStats = async () => { try { - const [sysInfo, memInfo, cpuData, uptime, network, traffic, diskio] = await Promise.all([ + const [sysInfo, memInfo, cpuData, uptime, network, traffic, diskio, diskusage] = await Promise.all([ api.getSystemInfo().catch(() => null), api.getMemory().catch(() => null), api.getCpuInfo().catch(() => null), @@ -108,6 +109,7 @@ export default function Dashboard() { api.getNetwork().catch(() => null), api.getNetworkTraffic().catch(() => null), api.getDiskIO().catch(() => null), + api.getDiskUsage().catch(() => null), ]) setSystemInfo(sysInfo) setMemoryInfo(memInfo) @@ -116,6 +118,7 @@ export default function Dashboard() { setNetworkInfo(network) setNetworkTraffic(traffic) setDiskIO(diskio) + setDiskUsage(diskusage) // Add to history if (cpuData?.percent !== undefined) { @@ -524,6 +527,52 @@ export default function Dashboard() { )} + {/* Disk Usage (df-based, immer sichtbar wenn Daten vorhanden) */} + {diskUsage?.filesystems && diskUsage.filesystems.length > 0 && ( +
+

Disk Usage

+
+ {diskUsage.filesystems.map((fs: any) => { + const pct = fs.capacity + const barColor = pct > 85 ? "bg-red-500" : pct > 70 ? "bg-yellow-500" : "bg-blue-500" + return ( + + + + + {fs.mountpoint} + + + +
+
+
+
+ {pct}% +
+
+
+

Total

+

{formatBytes(fs.total)}

+
+
+

Used

+

{formatBytes(fs.used)}

+
+
+

Free

+

{formatBytes(fs.available)}

+
+
+

{fs.filesystem}

+ + + ) + })} +
+
+ )} + {/* Disk I/O */} {diskIO?.disks && diskIO.disks.length > 0 && (
diff --git a/frontend/lib/api.ts b/frontend/lib/api.ts index d101af7..6e259e8 100644 --- a/frontend/lib/api.ts +++ b/frontend/lib/api.ts @@ -426,6 +426,11 @@ export class ZFSManagerAPI { return response.data } + async getDiskUsage(): Promise<{ filesystems: { filesystem: string; mountpoint: string; total: number; used: number; available: number; capacity: number }[] }> { + const response = await this.client.get("/api/system/disk-usage") + return response.data + } + async getServices(): Promise<{ services: any[] }> { const response = await this.client.get("/api/system/services") return response.data