CluPilotCloud/resources/views/livewire/admin/readiness.blade.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>