From 352b564f3a13c9c48896be38864a418ccef8e85d Mon Sep 17 00:00:00 2001 From: Ben Date: Wed, 12 Aug 2026 16:33:57 +0200 Subject: [PATCH] Add DiskSpaceService and DiskSpaceBar component for monitoring disk usage Implement DiskSpaceService to provide snapshots of disk space usage, including total, free, and used bytes, as well as human-readable formats. Create DiskSpaceBar component to display disk usage information in the UI, including a progress bar that visually represents used space. Update app layout to include the DiskSpaceBar and add tests to ensure functionality of the disk space service and its integration in the layout. --- app/Services/DiskSpaceService.php | 75 +++++++++++++++++++ app/View/Components/DiskSpaceBar.php | 61 +++++++++++++++ .../views/components/disk-space-bar.blade.php | 29 +++++++ resources/views/layouts/app.blade.php | 2 + tests/Feature/DiskSpaceTest.php | 50 +++++++++++++ 5 files changed, 217 insertions(+) create mode 100644 app/Services/DiskSpaceService.php create mode 100644 app/View/Components/DiskSpaceBar.php create mode 100644 resources/views/components/disk-space-bar.blade.php create mode 100644 tests/Feature/DiskSpaceTest.php diff --git a/app/Services/DiskSpaceService.php b/app/Services/DiskSpaceService.php new file mode 100644 index 0000000..2d39d2e --- /dev/null +++ b/app/Services/DiskSpaceService.php @@ -0,0 +1,75 @@ +path(''); + + /** @var array{total_bytes: int, free_bytes: int, used_bytes: int, used_percent: float, free_percent: float, total_human: string, free_human: string, used_human: string}|null */ + return Cache::remember( + 'disk-space:'.md5($path), + now()->addSeconds(30), + fn () => $this->measure($path), + ); + } + + /** + * @return array{ + * total_bytes: int, + * free_bytes: int, + * used_bytes: int, + * used_percent: float, + * free_percent: float, + * total_human: string, + * free_human: string, + * used_human: string + * }|null + */ + private function measure(string $path): ?array + { + $total = @disk_total_space($path); + $free = @disk_free_space($path); + + if ($total === false || $free === false || $total <= 0) { + return null; + } + + $totalBytes = (int) $total; + $freeBytes = (int) max(0, $free); + $usedBytes = (int) max(0, $totalBytes - $freeBytes); + $usedPercent = round(($usedBytes / $totalBytes) * 100, 1); + $freePercent = round(($freeBytes / $totalBytes) * 100, 1); + + return [ + 'total_bytes' => $totalBytes, + 'free_bytes' => $freeBytes, + 'used_bytes' => $usedBytes, + 'used_percent' => $usedPercent, + 'free_percent' => $freePercent, + 'total_human' => Number::fileSize($totalBytes, precision: 1), + 'free_human' => Number::fileSize($freeBytes, precision: 1), + 'used_human' => Number::fileSize($usedBytes, precision: 1), + ]; + } +} diff --git a/app/View/Components/DiskSpaceBar.php b/app/View/Components/DiskSpaceBar.php new file mode 100644 index 0000000..904aeeb --- /dev/null +++ b/app/View/Components/DiskSpaceBar.php @@ -0,0 +1,61 @@ +disk = $diskSpace->snapshot(); + } + + public function shouldRender(): bool + { + return $this->disk !== null; + } + + /** + * Progress fill color based on remaining free space. + */ + public function barColor(): string + { + $freePercent = $this->disk['free_percent'] ?? 100; + + if ($freePercent <= 5) { + return 'bg-red-600'; + } + + if ($freePercent <= 15) { + return 'bg-amber-500'; + } + + return 'bg-teal-600'; + } + + /** + * Get the view / contents that represent the component. + */ + public function render(): View|Closure|string + { + return view('components.disk-space-bar'); + } +} diff --git a/resources/views/components/disk-space-bar.blade.php b/resources/views/components/disk-space-bar.blade.php new file mode 100644 index 0000000..eb81405 --- /dev/null +++ b/resources/views/components/disk-space-bar.blade.php @@ -0,0 +1,29 @@ +@php + /** @var array{used_percent: float, free_percent: float, free_human: string, total_human: string, used_human: string} $disk */ +@endphp +
+
+
+ Disk space + + {{ $disk['free_human'] }} free + ยท + {{ $disk['used_percent'] }}% used of {{ $disk['total_human'] }} + +
+
+
+
+
+
diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php index 53d5236..efa54b0 100644 --- a/resources/views/layouts/app.blade.php +++ b/resources/views/layouts/app.blade.php @@ -7,6 +7,8 @@ @vite(['resources/css/app.css', 'resources/js/app.js']) + +