diff --git a/resources/views/components/server/status-summary.blade.php b/resources/views/components/server/status-summary.blade.php index 8be64a7711..ea2306397e 100644 --- a/resources/views/components/server/status-summary.blade.php +++ b/resources/views/components/server/status-summary.blade.php @@ -16,7 +16,13 @@ $traefikUpdateAvailable => 'Update available', default => str($proxyStatus ?: 'unknown')->headline(), }; - $sentinelNeedsAttention = $showSentinelStatus && ! $server->isSentinelLive(); + $sentinelStatus = $server->sentinelStatus(); + $sentinelNeedsAttention = $showSentinelStatus && $sentinelStatus === 'out_of_sync'; + $sentinelStatusLabel = match ($sentinelStatus) { + 'waiting' => 'Waiting for first report', + 'in_sync' => 'In sync', + default => 'Out of sync', + }; [$summaryLabel, $summaryType] = match (true) { ! $serverReady => ['Unavailable', 'error'], @@ -80,11 +86,12 @@ class="listbox-option gap-2.5!" @click="open = false" role="menuitem"> ! $sentinelNeedsAttention, - 'bg-warning' => $sentinelNeedsAttention, + 'bg-success' => $sentinelStatus === 'in_sync', + 'bg-neutral-400 dark:bg-fg-faint' => $sentinelStatus === 'waiting', + 'bg-warning' => $sentinelStatus === 'out_of_sync', ])> Sentinel - {{ $server->isSentinelLive() ? 'In sync' : 'Out of sync' }} + {{ $sentinelStatusLabel }} @endif diff --git a/resources/views/livewire/dashboard.blade.php b/resources/views/livewire/dashboard.blade.php index e83dc1a5cc..91c74cfba5 100644 --- a/resources/views/livewire/dashboard.blade.php +++ b/resources/views/livewire/dashboard.blade.php @@ -161,7 +161,7 @@ @foreach ($dashboardServers as $server) @php $proxyNeedsAttention = $server->proxySet() && ($server->proxy->status !== 'running' || $server->hasCurrentTraefikOutdatedInfo()); - $sentinelNeedsAttention = $server->isSentinelEnabled() && ! $server->isSentinelLive(); + $sentinelNeedsAttention = $server->isSentinelEnabled() && $server->sentinelStatus() === 'out_of_sync'; [$serverStatus, $serverStatusType] = match (true) { $server->settings->force_disabled => ['Disabled', 'error'], diff --git a/resources/views/livewire/server/index.blade.php b/resources/views/livewire/server/index.blade.php index c86b499396..cfe6b78f33 100644 --- a/resources/views/livewire/server/index.blade.php +++ b/resources/views/livewire/server/index.blade.php @@ -35,7 +35,7 @@ && ! $isTransferredAway; $proxyNeedsAttention = $isReady && $server->proxySet() && ($server->proxy->status !== 'running' || $server->hasCurrentTraefikOutdatedInfo()); - $sentinelNeedsAttention = $isReady && $server->isSentinelEnabled() && ! $server->isSentinelLive(); + $sentinelNeedsAttention = $isReady && $server->isSentinelEnabled() && $server->sentinelStatus() === 'out_of_sync'; $status = match (true) { $isTransferredAway => 'Transferred away', diff --git a/resources/views/livewire/server/sentinel/logs.blade.php b/resources/views/livewire/server/sentinel/logs.blade.php index 8211633e3a..ed2f350c66 100644 --- a/resources/views/livewire/server/sentinel/logs.blade.php +++ b/resources/views/livewire/server/sentinel/logs.blade.php @@ -11,9 +11,16 @@ helper="Search, filter, follow, copy, or download recent output from the Sentinel container." flush class="logs-settings-section"> @if ($server->isSentinelEnabled()) + @php + $sentinelStatus = $server->sentinelStatus(); + [$sentinelStatusLabel, $sentinelStatusType] = match ($sentinelStatus) { + 'waiting' => ['Waiting for first report', 'neutral'], + 'in_sync' => ['In sync', 'success'], + default => ['Out of sync', 'warning'], + }; + @endphp -
diff --git a/tests/Feature/ServerNavbarStatusVisibilityTest.php b/tests/Feature/ServerNavbarStatusVisibilityTest.php index ca35fb8d4f..fc9d46ab0f 100644 --- a/tests/Feature/ServerNavbarStatusVisibilityTest.php +++ b/tests/Feature/ServerNavbarStatusVisibilityTest.php @@ -54,6 +54,20 @@ it('shows sentinel sync status after the server is validated', function () { ->assertSee('In sync'); }); +it('shows the first Sentinel report as pending instead of requiring attention', function () { + [$server] = makeNavbarServer(isFunctional: true); + $server->forceFill([ + 'sentinel_updated_at' => now()->subDay(), + 'sentinel_waiting_since' => now(), + ])->save(); + + Livewire::test('server.navbar', ['server' => $server->fresh()]) + ->assertSee('Ready') + ->assertSee('Waiting for first report') + ->assertDontSee('Attention required') + ->assertDontSee('Out of sync'); +}); + it('places mobile status badges on a separate row below the server title', function () { $navbar = file_get_contents(resource_path('views/livewire/server/navbar.blade.php')); @@ -75,7 +89,7 @@ it('places mobile status badges on a separate row below the server title', funct ->toString(); $titlePos = strpos($titleBlock, 'data-testid="server-subtitle"'); - $badgesRowPos = strpos($titleBlock, 'flex min-w-0 flex-wrap items-center gap-2'); + $badgesRowPos = strpos($titleBlock, 'flex w-full min-w-0 items-center gap-2'); expect($titlePos)->not->toBeFalse() ->and($badgesRowPos)->not->toBeFalse() diff --git a/tests/Feature/ServerStatusIndicatorDesignTest.php b/tests/Feature/ServerStatusIndicatorDesignTest.php index 4b31a51d85..d9b35bd344 100644 --- a/tests/Feature/ServerStatusIndicatorDesignTest.php +++ b/tests/Feature/ServerStatusIndicatorDesignTest.php @@ -14,7 +14,7 @@ test('server cards use warning icons instead of colored icon borders', function expect(substr_count($serverIndex, 'toBe(1) ->and($serverIndex) ->toContain("&& (\$server->proxy->status !== 'running' || \$server->hasCurrentTraefikOutdatedInfo())") - ->toContain('$sentinelNeedsAttention = $isReady && $server->isSentinelEnabled() && ! $server->isSentinelLive()') + ->toContain("\$sentinelNeedsAttention = \$isReady && \$server->isSentinelEnabled() && \$server->sentinelStatus() === 'out_of_sync'") ->toContain("\$proxyNeedsAttention || \$sentinelNeedsAttention => 'warning'") ->toContain("\$isReady => 'success'") ->toContain("\$isTransferredAway || \$server->settings->force_disabled => 'error'") @@ -30,7 +30,7 @@ test('dashboard server cards warn when proxy or sentinel needs attention', funct expect($dashboard) ->toContain("\$proxyNeedsAttention = \$server->proxySet() && (\$server->proxy->status !== 'running' || \$server->hasCurrentTraefikOutdatedInfo())") - ->toContain('$sentinelNeedsAttention = $server->isSentinelEnabled() && ! $server->isSentinelLive()') + ->toContain("\$sentinelNeedsAttention = \$server->isSentinelEnabled() && \$server->sentinelStatus() === 'out_of_sync'") ->toContain("\$proxyNeedsAttention || \$sentinelNeedsAttention => ['Attention required', 'warning']"); }); @@ -39,15 +39,27 @@ test('server status summary uses warning indicators for proxy updates and sentin expect($summary) ->toContain('$server->hasCurrentTraefikOutdatedInfo()') + ->toContain('$sentinelStatus = $server->sentinelStatus()') + ->toContain("'waiting' => 'Waiting for first report'") ->toContain('$proxyStatusLabel = match (true)') ->toContain("\$proxyConfigurationPending => 'Restart required'") ->toContain("\$traefikUpdateAvailable => 'Update available'") ->toContain('{{ $proxyStatusLabel }}') ->toContain("'bg-warning' => \$proxyNeedsAttention && (\$proxyUpdateAvailable") - ->toContain("'bg-warning' => \$sentinelNeedsAttention") + ->toContain("'bg-warning' => \$sentinelStatus === 'out_of_sync'") ->not->toContain("\$server->isSentinelLive() ? 'bg-success' : 'bg-error'"); }); +test('Sentinel logs show the pending first report state without an out-of-sync warning', function () { + $logs = file_get_contents(resource_path('views/livewire/server/sentinel/logs.blade.php')); + + expect($logs) + ->toContain("'waiting' => ['Waiting for first report', 'neutral']") + ->toContain("'in_sync' => ['In sync', 'success']") + ->toContain("default => ['Out of sync', 'warning']") + ->not->toContain("\$server->isSentinelLive() ? 'In sync' : 'Out of sync'"); +}); + test('server table keeps status text without a badge', function () { $serverIndex = file_get_contents(resource_path('views/livewire/server/index.blade.php'));