95 lines
5.4 KiB
PHP
95 lines
5.4 KiB
PHP
<div class="space-y-5">
|
|
<div class="animate-rise">
|
|
<h1 class="text-2xl font-bold tracking-tight text-ink">{{ __('readiness.page_title') }}</h1>
|
|
<p class="mt-1 text-sm text-muted">{{ __('readiness.page_sub') }}</p>
|
|
</div>
|
|
|
|
{{-- The one line that matters. Everything below is detail. --}}
|
|
<div class="flex items-center gap-3 rounded-lg border p-5 shadow-xs animate-rise
|
|
{{ $ready ? 'border-success-border bg-success-bg' : 'border-warning-border bg-warning-bg' }}">
|
|
<x-ui.icon :name="$ready ? 'shield-check' : 'alert-triangle'"
|
|
class="{{ $ready ? 'text-success' : 'text-warning' }}" />
|
|
<p class="text-lg font-semibold {{ $ready ? 'text-success' : 'text-warning' }}">
|
|
@if ($ready)
|
|
{{ $mode->isTest() ? __('readiness.ready_test') : __('readiness.ready_live') }}
|
|
@else
|
|
{{ trans_choice('readiness.not_ready', $blockingCount, ['n' => $blockingCount]) }}
|
|
@endif
|
|
</p>
|
|
</div>
|
|
|
|
@foreach ($groups as $groupKey => $checks)
|
|
<div class="rounded-lg border border-line bg-surface p-5 shadow-xs animate-rise">
|
|
<h2 class="font-semibold text-ink">{{ __('readiness.group.'.$groupKey) }}</h2>
|
|
|
|
<ul class="mt-3 divide-y divide-line">
|
|
@foreach ($checks as $check)
|
|
@php
|
|
$badgeStatus = $check->satisfied ? 'active' : ($check->isBlocking() ? 'failed' : 'warning');
|
|
$statusLabel = $check->satisfied
|
|
? __('readiness.status.satisfied')
|
|
: ($check->isBlocking() ? __('readiness.status.blocking') : __('readiness.status.warning'));
|
|
$iconName = $check->satisfied ? 'check' : ($check->isBlocking() ? 'x' : 'alert-triangle');
|
|
$iconTone = $check->satisfied ? 'text-success' : ($check->isBlocking() ? 'text-danger' : 'text-warning');
|
|
$result = $results[$check->key] ?? null;
|
|
$heartbeat = $heartbeats[$check->key] ?? null;
|
|
@endphp
|
|
<li class="flex flex-wrap items-start gap-3 py-3">
|
|
<x-ui.icon :name="$iconName" class="mt-0.5 size-4 shrink-0 {{ $iconTone }}" />
|
|
|
|
<div class="min-w-0 flex-1">
|
|
<div class="flex flex-wrap items-center gap-2">
|
|
<span class="font-medium text-ink">{{ $check->label }}</span>
|
|
<x-ui.badge :status="$badgeStatus">{{ $statusLabel }}</x-ui.badge>
|
|
</div>
|
|
|
|
@unless ($check->satisfied)
|
|
<p class="mt-1 text-sm text-muted">{{ $check->breaks }}</p>
|
|
@endunless
|
|
|
|
@if ($heartbeat !== null)
|
|
<p class="mt-1 font-mono text-xs text-faint">
|
|
{{ __('readiness.last_heartbeat', ['when' => $heartbeat]) }}
|
|
</p>
|
|
@endif
|
|
|
|
@if ($result !== null)
|
|
<p class="mt-1 text-xs {{ $result['ok'] ? 'text-success' : 'text-danger' }}">
|
|
{{ $result['ok'] ? __('readiness.check_ok') : __('readiness.check_failed') }}
|
|
@if (($result['reason'] ?? null) !== null)
|
|
— <span class="font-mono">{{ $result['reason'] }}</span>
|
|
@endif
|
|
</p>
|
|
@endif
|
|
</div>
|
|
|
|
<div class="flex shrink-0 items-center gap-3">
|
|
{{-- mount() only requires hosts.manage OR secrets.manage, so an
|
|
Admin (hosts.manage alone) can reach this page — but runCheck()
|
|
itself demands secrets.manage and 403s otherwise. A button that
|
|
is visible and throws when pressed is worse than no button. --}}
|
|
@if (in_array($check->key, $runnable, true))
|
|
@can('secrets.manage')
|
|
<x-ui.button variant="secondary" size="sm"
|
|
wire:click="runCheck('{{ $check->key }}')"
|
|
wire:loading.attr="disabled"
|
|
wire:target="runCheck('{{ $check->key }}')">
|
|
<x-ui.icon name="refresh" class="size-4" />
|
|
{{ __('readiness.run_check') }}
|
|
</x-ui.button>
|
|
@endcan
|
|
@endif
|
|
|
|
<a href="{{ $this->checkUrl($check) }}" wire:navigate
|
|
class="inline-flex items-center gap-1 text-xs font-semibold text-accent-text hover:underline">
|
|
{{ __('readiness.fix_link') }}
|
|
<x-ui.icon name="external-link" class="size-4" />
|
|
</a>
|
|
</div>
|
|
</li>
|
|
@endforeach
|
|
</ul>
|
|
</div>
|
|
@endforeach
|
|
</div>
|