fix(ui): uniform action-element height + live fleet status / alerts
Two things the badge/live-update fixes missed: Height — the enable/disable TOGGLES (Alerts, Servers, Commands, Settings) were custom buttons at min-h-9 (36px) while x-btn / x-modal-trigger / status-pill are h-8 (32px), so a status toggle never lined up with the Delete/Create buttons next to it. Normalise those toggles to h-8. Verified: Enabled/Delete/Create all render at 32px now. Live — the topbar "X/Y online" pill and the sidebar server-switcher were static Blade, so a server going up/down (shown live on the dashboard via Reverb) didn't reach them until a navigate/refresh. Make the topbar pill a small polled Livewire island (Shell\FleetStatus) and add wire:poll to the server-switcher + the Alerts page, so fleet status and firing/ resolved incidents update live without a refresh. (The alert e-mail is confirmed sending over SMTP — queued mail no longer hits the log mailer, and a synchronous send to the admin returned SEND_OK from mail.thinkidoo.com:587. Non-delivery is downstream: spam filtering or missing SPF/DKIM for hello@clusev.com via that relay — a DNS/mail- server config, not a panel code issue.) 750 tests; R12-verified (uniform heights, topbar is a live island, zero console errors). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>feat/v1-foundation
parent
6dbe2303a4
commit
f9a08a98d2
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace App\Livewire\Shell;
|
||||
|
||||
use App\Models\Server;
|
||||
use Livewire\Component;
|
||||
|
||||
/**
|
||||
* Topbar "X / Y online" pill. A tiny polled Livewire island so the fleet-online count reflects a
|
||||
* server going up or down live (like the dashboard), instead of only on a page navigate/refresh.
|
||||
*/
|
||||
class FleetStatus extends Component
|
||||
{
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.shell.fleet-status', [
|
||||
'online' => Server::where('status', 'online')->count(),
|
||||
'total' => Server::count(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
@ -22,10 +22,7 @@
|
|||
<x-icon name="command" class="h-3.5 w-3.5" />
|
||||
<span class="font-mono text-[10px] uppercase tracking-wider">{{ __('shell.shortcut_ctrl_k') }}</span>
|
||||
</button>
|
||||
@php
|
||||
$fleetTotal = \App\Models\Server::count();
|
||||
$fleetOnline = \App\Models\Server::where('status', 'online')->count();
|
||||
@endphp
|
||||
<x-status-pill :status="$fleetOnline > 0 ? 'online' : 'offline'">{{ __('shell.fleet_online', ['online' => $fleetOnline, 'total' => $fleetTotal]) }}</x-status-pill>
|
||||
{{-- Live-polled island so the online count updates when a server goes up/down (not just on nav). --}}
|
||||
<livewire:shell.fleet-status />
|
||||
</div>
|
||||
</header>
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@
|
|||
};
|
||||
@endphp
|
||||
|
||||
<div class="space-y-5">
|
||||
{{-- Poll so firing/resolved incidents appear live, matching the dashboard, without a manual refresh. --}}
|
||||
<div class="space-y-5" wire:poll.10s>
|
||||
{{-- Header --}}
|
||||
<div>
|
||||
<p class="font-mono text-[11px] uppercase tracking-[0.2em] text-accent-text">{{ __('alerts.eyebrow') }}</p>
|
||||
|
|
@ -140,7 +141,7 @@
|
|||
</div>
|
||||
<button type="button" wire:click="toggleRule('{{ $rule->uuid }}')"
|
||||
@class([
|
||||
'inline-flex min-h-9 shrink-0 items-center gap-1.5 rounded-md border px-2.5 text-xs transition-colors',
|
||||
'inline-flex h-8 shrink-0 items-center gap-1.5 rounded-md border px-2.5 text-xs transition-colors',
|
||||
'border-online/20 bg-online/10 text-online' => $rule->enabled,
|
||||
'border-line bg-inset text-ink-3 hover:bg-raised' => ! $rule->enabled,
|
||||
])>
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
@foreach (['all', 'group', 'servers'] as $s)
|
||||
<button type="button" wire:click="$set('scopeType', '{{ $s }}')"
|
||||
@class([
|
||||
'inline-flex min-h-9 items-center rounded-md border px-3 text-xs transition-colors',
|
||||
'inline-flex h-8 items-center rounded-md border px-3 text-xs transition-colors',
|
||||
'border-accent/25 bg-accent/10 text-ink' => $scopeType === $s,
|
||||
'border-line bg-inset text-ink-2 hover:bg-raised hover:text-ink' => $scopeType !== $s,
|
||||
])>{{ __('commands.scope_'.$s) }}</button>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
<div x-data="{ open: false }" @click.outside="open = false" @keydown.escape="open = false" class="relative">
|
||||
{{-- Poll so the active + fleet status dots reflect a server going up/down live (Livewire morph keeps
|
||||
the Alpine `open` dropdown state across re-renders). --}}
|
||||
<div x-data="{ open: false }" @click.outside="open = false" @keydown.escape="open = false" class="relative" wire:poll.10s>
|
||||
<button type="button" @click="open = ! open"
|
||||
class="flex min-h-11 w-full items-center gap-2.5 rounded-md border border-line bg-inset px-3 py-2 text-left transition-colors hover:border-line-strong"
|
||||
:aria-expanded="open" aria-haspopup="listbox">
|
||||
|
|
|
|||
|
|
@ -31,14 +31,14 @@
|
|||
<div class="flex flex-wrap items-center gap-1.5" role="group" aria-label="{{ __('groups.filter_label') }}">
|
||||
<button type="button" wire:click="$set('group', null)"
|
||||
@class([
|
||||
'inline-flex min-h-9 items-center rounded-md border px-3 text-xs transition-colors',
|
||||
'inline-flex h-8 items-center rounded-md border px-3 text-xs transition-colors',
|
||||
'border-accent/25 bg-accent/10 text-ink' => ! $activeGroup,
|
||||
'border-line bg-inset text-ink-2 hover:bg-raised hover:text-ink' => $activeGroup,
|
||||
])>{{ __('groups.filter_all') }}</button>
|
||||
@foreach ($groups as $g)
|
||||
<button type="button" wire:click="$set('group', '{{ $g->uuid }}')"
|
||||
@class([
|
||||
'inline-flex min-h-9 items-center gap-1.5 rounded-md border px-3 text-xs transition-colors',
|
||||
'inline-flex h-8 items-center gap-1.5 rounded-md border px-3 text-xs transition-colors',
|
||||
'border-accent/25 bg-accent/10 text-ink' => $activeGroup?->id === $g->id,
|
||||
'border-line bg-inset text-ink-2 hover:bg-raised hover:text-ink' => $activeGroup?->id !== $g->id,
|
||||
])>
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<button type="button" x-data @click="window.dispatchEvent(new CustomEvent('onboarding:start'))"
|
||||
class="inline-flex min-h-9 items-center gap-1.5 rounded-md border border-line px-3 font-mono text-[11px] text-ink-2 transition-colors hover:border-accent/40 hover:text-accent-text">
|
||||
class="inline-flex h-8 items-center gap-1.5 rounded-md border border-line px-3 font-mono text-[11px] text-ink-2 transition-colors hover:border-accent/40 hover:text-accent-text">
|
||||
<x-icon name="help-circle" class="h-3.5 w-3.5" />{{ __('onboarding.relaunch') }}
|
||||
</button>
|
||||
<x-badge tone="neutral">{{ $u->role?->label() ?? __('settings.role_admin') }}</x-badge>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
<div wire:poll.10s>
|
||||
<x-status-pill :status="$online > 0 ? 'online' : 'offline'">{{ __('shell.fleet_online', ['online' => $online, 'total' => $total]) }}</x-status-pill>
|
||||
</div>
|
||||
Loading…
Reference in New Issue