Infrastructure
Forge Disk Usage Card code
Copy the implementation or inspect every file that belongs to this component unit.
resources/views/components/ui/forge-disk-usage-card.blade.php
@props([
'path',
'mount' => null,
'filesystem' => null,
'used' => null,
'total' => null,
'available' => null,
'percent' => null,
'inodesUsed' => null,
'inodesTotal' => null,
'status' => 'Healthy',
'statusVariant' => 'green',
'updatedAt' => null,
'files' => [],
])
@php
/*
| Disk usage card for Forge-style server dashboards. Surfaces mount usage,
| inode pressure, scan freshness and the largest files by size.
|
| Usage:
| <x-ui.forge-disk-usage-card
| path="/home/forge/app.example.com"
| mount="/dev/vda1"
| filesystem="ext4"
| used="48.2 GB"
| total="80 GB"
| available="31.8 GB"
| :percent="60"
| updated-at="2 minutes ago"
| :files="[
| ['path' => 'storage/logs/laravel.log', 'size' => '842 MB', 'modified' => 'Jun 24, 2026 09:12'],
| ]"
| />
*/
$files = collect($files)->map(function (array $file): array {
return [
'path' => $file['path'] ?? $file['name'] ?? 'Unknown',
'size' => $file['size'] ?? null,
'modified' => $file['modified'] ?? $file['touchedAt'] ?? $file['lastModified'] ?? null,
'href' => $file['href'] ?? null,
];
})->values();
$stats = array_filter([
'Used' => $used,
'Available' => $available,
'Total' => $total,
], fn (?string $value): bool => filled($value));
$meterPercent = $percent === null ? null : max(0, min(100, (int) $percent));
$progressVariant = match (true) {
$meterPercent === null => 'brand',
$meterPercent >= 90 => 'red',
$meterPercent >= 75 => 'amber',
default => 'brand',
};
$mountLabel = collect([$mount, $filesystem])->filter()->implode(' · ');
$usageLabelId = 'forge-disk-usage-'.substr(md5($path), 0, 8);
$usageValueText = ($used && $total) ? "{$used} of {$total}" : ($meterPercent !== null ? "{$meterPercent} percent" : null);
@endphp
<article {{ $attributes->merge(['class' => 'min-w-0 overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm dark:border-gray-800 dark:bg-gray-900']) }}>
<div class="border-b border-gray-200 px-5 py-4 dark:border-gray-800 sm:px-6">
<div class="flex min-w-0 flex-col gap-3 sm:flex-row sm:items-start sm:justify-between sm:gap-4">
<div class="min-w-0">
<p class="truncate font-mono text-sm font-semibold text-gray-900 dark:text-white">{{ $path }}</p>
@if ($mountLabel)
<p class="mt-1 truncate text-xs text-gray-500 dark:text-gray-400">{{ $mountLabel }}</p>
@endif
</div>
<x-ui.badge :variant="$statusVariant" size="sm" dot class="w-fit sm:shrink-0" aria-label="Disk status: {{ $status }}">{{ $status }}</x-ui.badge>
</div>
@if (! empty($stats))
<dl class="mt-5 grid gap-3 sm:grid-cols-3">
@foreach ($stats as $label => $value)
<div class="min-w-0 rounded-lg bg-gray-50 p-3 dark:bg-gray-950/40">
<dt class="text-xs text-gray-500 dark:text-gray-400">{{ $label }}</dt>
<dd class="mt-1 truncate text-sm font-semibold tabular-nums text-gray-900 dark:text-white">{{ $value }}</dd>
</div>
@endforeach
</dl>
@endif
@if ($meterPercent !== null)
<div class="mt-5">
<div class="mb-1.5 flex items-center justify-between text-xs text-gray-500 dark:text-gray-400">
<span id="{{ $usageLabelId }}" class="font-medium text-gray-700 dark:text-gray-300">Disk usage</span>
<span class="tabular-nums">
@if ($used && $total)
{{ $used }} of {{ $total }}
@else
{{ $meterPercent }}%
@endif
</span>
</div>
<x-ui.progress
:value="$meterPercent"
size="sm"
:variant="$progressVariant"
:aria-labelledby="$usageLabelId"
:aria-valuetext="$usageValueText"
/>
</div>
@endif
<x-ui.status-bar class="mt-5" :items="array_values(array_filter([
$updatedAt ? ['icon' => 'clock-counter-clockwise', 'label' => 'Updated', 'value' => $updatedAt] : null,
filled($inodesUsed) && filled($inodesTotal) ? ['icon' => 'folders', 'label' => 'Inodes', 'value' => $inodesUsed.' / '.$inodesTotal] : null,
]))" />
</div>
@if ($files->isNotEmpty())
<div class="overflow-x-auto">
<table class="w-full min-w-[36rem] table-fixed divide-y divide-gray-200 text-sm dark:divide-gray-800">
<caption class="sr-only">Largest files for {{ $path }}</caption>
<thead class="bg-gray-50 text-xs text-gray-500 dark:bg-gray-950/40 dark:text-gray-400">
<tr>
<th scope="col" class="w-full px-5 py-3 text-left font-medium sm:px-6">Largest files</th>
<th scope="col" class="w-28 px-5 py-3 text-right font-medium whitespace-nowrap sm:px-6">Size</th>
<th scope="col" class="hidden w-44 px-5 py-3 text-right font-medium whitespace-nowrap sm:table-cell sm:px-6">Last touched</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200 dark:divide-gray-800">
@foreach ($files as $file)
<tr>
<td class="max-w-0 px-5 py-3 sm:px-6">
@if ($file['href'])
<a href="{{ $file['href'] }}" class="block min-w-0 font-mono text-sm text-brand-600 hover:text-brand-700 dark:text-brand-400 dark:hover:text-brand-300">
<span class="truncate">{{ $file['path'] }}</span>
</a>
@else
<p class="truncate font-mono text-sm text-gray-900 dark:text-white">{{ $file['path'] }}</p>
@endif
@if ($file['modified'])
<p class="mt-0.5 text-xs text-gray-500 dark:text-gray-400 sm:hidden">{{ $file['modified'] }}</p>
@endif
</td>
<td class="px-5 py-3 text-right font-medium tabular-nums text-gray-900 dark:text-white sm:px-6">{{ $file['size'] ?? '—' }}</td>
<td class="hidden px-5 py-3 text-right text-gray-500 dark:text-gray-400 sm:table-cell sm:px-6">{{ $file['modified'] ?? '—' }}</td>
</tr>
@endforeach
</tbody>
</table>
</div>
@endif
</article>