Skip to main content

Data display

Status Page code

Copy the implementation or inspect every file that belongs to this component unit.

resources/views/components/ui/status-page.blade.php

@props([
    'services' => [],
    'overall' => null,
    'title' => null,
    'updatedAt' => null,
    'period' => '90 days',
])

@php
    /*
    | Service status board. A coloured overall banner sits above a list of
    | services, each with a status badge, an optional uptime percentage and an
    | uptime history strip (see <x-ui.uptime-bar>). When `overall` is omitted it
    | is derived from the worst service status.
    |
    | Each service: ['name' => ?, 'status' => 'operational', 'description' => ?,
    |                'uptime' => '99.99%', 'days' => [...]]
    | Statuses: operational, degraded, partial, major, maintenance
    |
    | Usage:
    |   <x-ui.status-page updated-at="2 minutes ago" :services="[
    |       ['name' => 'API', 'status' => 'operational', 'uptime' => '99.99%', 'days' => array_fill(0, 90, 'operational')],
    |       ['name' => 'Dashboard', 'status' => 'degraded', 'uptime' => '99.41%', 'days' => [...]],
    |   ]" />
    */
    $meta = [
        'operational' => ['variant' => 'green', 'icon' => 'check-circle', 'label' => 'Operational', 'banner' => 'All systems operational', 'rank' => 0,
            'tint' => 'bg-green-50 text-green-700 dark:bg-green-950/40 dark:text-green-300', 'iconColor' => 'text-green-500'],
        'maintenance' => ['variant' => 'blue', 'icon' => 'wrench', 'label' => 'Maintenance', 'banner' => 'Maintenance in progress', 'rank' => 1,
            'tint' => 'bg-accent-50 text-accent-700 dark:bg-accent-950/40 dark:text-accent-300', 'iconColor' => 'text-accent-500'],
        'degraded' => ['variant' => 'amber', 'icon' => 'warning', 'label' => 'Degraded', 'banner' => 'Degraded performance', 'rank' => 2,
            'tint' => 'bg-amber-50 text-amber-700 dark:bg-amber-950/40 dark:text-amber-300', 'iconColor' => 'text-amber-500'],
        'partial' => ['variant' => 'amber', 'icon' => 'warning-circle', 'label' => 'Partial outage', 'banner' => 'Partial system outage', 'rank' => 3,
            'tint' => 'bg-amber-50 text-amber-700 dark:bg-amber-950/40 dark:text-amber-300', 'iconColor' => 'text-amber-500'],
        'major' => ['variant' => 'red', 'icon' => 'x-circle', 'label' => 'Major outage', 'banner' => 'Major system outage', 'rank' => 4,
            'tint' => 'bg-red-50 text-red-700 dark:bg-red-950/40 dark:text-red-300', 'iconColor' => 'text-red-500'],
    ];

    $resolvedOverall = $overall;

    if ($resolvedOverall === null) {
        $worstRank = collect($services)
            ->map(fn (array $service): int => $meta[$service['status'] ?? 'operational']['rank'] ?? 0)
            ->max() ?? 0;

        $rankToKey = collect($meta)->mapWithKeys(fn (array $m, string $key): array => [$m['rank'] => $key]);
        $resolvedOverall = $rankToKey[$worstRank] ?? 'operational';
    }

    $overallMeta = $meta[$resolvedOverall] ?? $meta['operational'];
    $bannerTitle = $title ?? $overallMeta['banner'];
@endphp

<div {{ $attributes->merge(['class' => 'overflow-hidden rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-gray-900']) }}>
    {{-- Overall banner --}}
    <div class="flex items-center gap-3 p-5 {{ $overallMeta['tint'] }}">
        <x-ui.icon :name="$overallMeta['icon']" weight="fill" size="2xl" :class="$overallMeta['iconColor']" />
        <div class="min-w-0 flex-1">
            <p class="text-base font-semibold">{{ $bannerTitle }}</p>
            @if ($updatedAt)
                <p class="text-sm opacity-80">Last updated {{ $updatedAt }}</p>
            @endif
        </div>
    </div>

    {{-- Services --}}
    <ul class="divide-y divide-gray-100 dark:divide-gray-800">
        @foreach ($services as $service)
            @php
                $serviceStatus = $service['status'] ?? 'operational';
                $serviceMeta = $meta[$serviceStatus] ?? $meta['operational'];
            @endphp
            <li class="p-5">
                <div class="flex items-center justify-between gap-3">
                    <div class="min-w-0">
                        <p class="truncate text-sm font-medium text-gray-900 dark:text-white">{{ $service['name'] ?? '' }}</p>
                        @if (! empty($service['description']))
                            <p class="mt-0.5 truncate text-sm text-gray-500 dark:text-gray-400">{{ $service['description'] }}</p>
                        @endif
                    </div>
                    <div class="flex shrink-0 items-center gap-3">
                        @if (! empty($service['uptime']))
                            <span class="hidden text-xs tabular-nums text-gray-400 dark:text-gray-500 sm:inline">{{ $service['uptime'] }}</span>
                        @endif
                        <x-ui.badge :variant="$serviceMeta['variant']" :icon="$serviceMeta['icon']" size="sm">{{ $serviceMeta['label'] }}</x-ui.badge>
                    </div>
                </div>

                @if (! empty($service['days']))
                    <div class="mt-3">
                        <x-ui.uptime-bar :days="$service['days']" size="sm" />
                        <div class="mt-1.5 flex items-center justify-between text-[11px] text-gray-400 dark:text-gray-500">
                            <span>{{ $period }} ago</span>
                            @if (! empty($service['uptime']))
                                <span class="tabular-nums">{{ $service['uptime'] }} uptime</span>
                            @endif
                            <span>Today</span>
                        </div>
                    </div>
                @endif
            </li>
        @endforeach
    </ul>

    {{-- Legend --}}
    <div class="flex flex-wrap items-center gap-x-4 gap-y-2 border-t border-gray-200 bg-gray-50/60 px-5 py-3 text-xs text-gray-500 dark:border-gray-800 dark:bg-gray-900/40 dark:text-gray-400">
        @foreach (['operational' => 'bg-green-500', 'degraded' => 'bg-amber-400', 'partial' => 'bg-amber-500', 'major' => 'bg-red-500', 'maintenance' => 'bg-accent-400'] as $key => $swatch)
            <span class="inline-flex items-center gap-1.5">
                <span class="h-2.5 w-2.5 rounded-sm {{ $swatch }}"></span>
                {{ $meta[$key]['label'] }}
            </span>
        @endforeach
    </div>
</div>