From 85613b01baa1b28fa7ee75493f984667000d2f2a Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Wed, 5 Aug 2026 19:54:48 +0200 Subject: [PATCH] feat(ui): expand server sidebar and extract status summary Move proxy, sentinel, resources, and terminal into the server sidebar with nested routes and icons; extract navbar status into a shared status-summary component; add full-width service links and compact loading support. --- app/View/Components/Services/Links.php | 2 +- resources/views/components/loading.blade.php | 5 +- resources/views/components/reicon.blade.php | 3 + .../views/components/server/sidebar.blade.php | 70 +++++++++++++++- .../server/status-summary.blade.php | 80 +++++++++++++++++++ .../views/components/services/links.blade.php | 44 +++++----- .../project/service/configuration.blade.php | 4 +- .../project/service/heading.blade.php | 2 +- .../execute-container-command.blade.php | 8 +- .../views/livewire/server/navbar.blade.php | 76 +++--------------- .../proxy/dynamic-configurations.blade.php | 2 +- .../livewire/server/proxy/logs.blade.php | 2 +- .../livewire/server/proxy/show.blade.php | 2 +- .../views/livewire/server/resources.blade.php | 5 +- .../server/security/patches.blade.php | 2 +- .../server/security/terminal-access.blade.php | 2 +- .../livewire/server/sentinel/logs.blade.php | 2 +- .../livewire/server/sentinel/show.blade.php | 2 +- tests/Feature/LoadingComponentTest.php | 3 +- .../ResourceHeadingUnifiedNavbarTest.php | 12 ++- .../Feature/ServerNavbarStatusLayoutTest.php | 33 ++++---- tests/Feature/ServerSidebarIconsTest.php | 46 +++++++++++ ...erviceComposeResourcesViewSwitcherTest.php | 2 + .../ServiceDatabaseVerticalNavigationTest.php | 4 +- tests/Feature/SidebarNavigationMarkupTest.php | 20 +++++ 25 files changed, 312 insertions(+), 121 deletions(-) create mode 100644 resources/views/components/server/status-summary.blade.php create mode 100644 tests/Feature/ServerSidebarIconsTest.php diff --git a/app/View/Components/Services/Links.php b/app/View/Components/Services/Links.php index 0497aebae..147b49d68 100644 --- a/app/View/Components/Services/Links.php +++ b/app/View/Components/Services/Links.php @@ -12,7 +12,7 @@ class Links extends Component { public Collection $links; - public function __construct(public Service $service) + public function __construct(public Service $service, public bool $fullWidth = false) { $this->links = collect([]); $service->applications()->get()->map(function ($application) { diff --git a/resources/views/components/loading.blade.php b/resources/views/components/loading.blade.php index bcc07b9bd..16166b6e1 100644 --- a/resources/views/components/loading.blade.php +++ b/resources/views/components/loading.blade.php @@ -1,8 +1,9 @@ -@props(['text' => null]) +@props(['text' => null, 'compact' => false])
merge(['class' => 'inline-flex items-center justify-center gap-2 text-[13px] text-neutral-500 dark:text-fg-dim']) }} role="status" aria-live="polite"> - {{ $menuItem['label'] }} + @if ($menuItem['active'] && isset($menuItem['children'])) +
+ @foreach (collect($menuItem['children'])->filter(fn (array $child): bool => $child['visible'] ?? true) as $child) + $child['active']]) + @if ($child['navigate'] ?? true) {{ wireNavigate() }} @endif + href="{{ route($child['route'], $serverRouteParameters) }}"> + + {{ $child['label'] }} + + @endforeach +
+ @endif @endforeach @endforeach diff --git a/resources/views/components/server/status-summary.blade.php b/resources/views/components/server/status-summary.blade.php new file mode 100644 index 000000000..ccf68af29 --- /dev/null +++ b/resources/views/components/server/status-summary.blade.php @@ -0,0 +1,80 @@ +@props([ + 'server', + 'proxyStatus' => null, + 'showSentinelStatus' => false, +]) + +@php + $serverReady = $server->isFunctional(); + $proxyNeedsAttention = $server->proxySet() && ! in_array($proxyStatus, ['running'], true); + $sentinelNeedsAttention = $showSentinelStatus && ! $server->isSentinelLive(); + + [$summaryLabel, $summaryType] = match (true) { + ! $serverReady => ['Unavailable', 'error'], + $proxyNeedsAttention || $sentinelNeedsAttention => ['Attention required', 'warning'], + default => ['Ready', 'success'], + }; +@endphp + +
+ + $summaryType === 'success', + 'bg-warning' => $summaryType === 'warning', + 'bg-error' => $summaryType === 'error', + ])> + {{ $summaryLabel }} + + + + + + +
diff --git a/resources/views/components/services/links.blade.php b/resources/views/components/services/links.blade.php index 276fbd38e..ed34389d8 100644 --- a/resources/views/components/services/links.blade.php +++ b/resources/views/components/services/links.blade.php @@ -1,26 +1,30 @@ @php - $linkItemClasses = - 'flex items-center gap-2 px-3 h-8 text-[13px] transition-colors text-neutral-600 dark:text-fg-dim hover:bg-neutral-100 dark:hover:bg-white/[0.06] hover:text-black dark:hover:text-fg'; + $linkItemClasses = 'listbox-option justify-start! gap-2.5!'; @endphp -@if ($links->count() > 0) -
- -
- @foreach ($links as $link) - - {{ $link }} - - @endforeach -
+ + + + + + -@endif +
diff --git a/resources/views/livewire/project/service/configuration.blade.php b/resources/views/livewire/project/service/configuration.blade.php index da3cd4b37..6b4fd5afd 100644 --- a/resources/views/livewire/project/service/configuration.blade.php +++ b/resources/views/livewire/project/service/configuration.blade.php @@ -101,14 +101,14 @@ localStorage.setItem('service-compose-resources-view', mode); } }"> -
+

Compose resources

Applications and databases defined in this service.

-
+
diff --git a/resources/views/livewire/project/shared/execute-container-command.blade.php b/resources/views/livewire/project/shared/execute-container-command.blade.php index a1a1446c8..887876813 100644 --- a/resources/views/livewire/project/shared/execute-container-command.blade.php +++ b/resources/views/livewire/project/shared/execute-container-command.blade.php @@ -41,10 +41,12 @@ ])->values(); @endphp - @if (in_array($type, ['application', 'database', 'service'], true)) + @if (in_array($type, ['application', 'database', 'service', 'server'], true))
- @if ($type === 'application') + @if ($type === 'server') + + @elseif ($type === 'application') @elseif ($type === 'database') @@ -210,7 +212,7 @@
@endif - @if (in_array($type, ['application', 'database', 'service'], true)) + @if (in_array($type, ['application', 'database', 'service', 'server'], true))
diff --git a/resources/views/livewire/server/navbar.blade.php b/resources/views/livewire/server/navbar.blade.php index 280284261..f0961731d 100644 --- a/resources/views/livewire/server/navbar.blade.php +++ b/resources/views/livewire/server/navbar.blade.php @@ -110,7 +110,7 @@ + class="h-7! w-full rounded-md! border-neutral-200! bg-white! py-0! pr-2! pl-7! text-[11px]! text-black! placeholder:text-neutral-400! dark:border-white/[0.1]! dark:bg-coolgray-100! dark:text-white! dark:placeholder:text-fg-faint!">
- - - + @endteleport @@ -170,33 +141,13 @@ class="min-w-0 truncate text-[24px]! leading-7! font-semibold! tracking-tight! text-black dark:text-fg"> {{ $server->name }} - @if ($server->proxySet() || $showSentinelStatus) -
- @if ($server->proxySet()) - @if ($proxyStatus === 'running') - - @elseif (in_array($proxyStatus, ['restarting', 'stopping', 'starting'])) - - @elseif (data_get($server, 'proxy.force_stop')) - - @elseif ($proxyStatus === 'exited') - - @endif - @endif - @if ($showSentinelStatus) - - @endif -
- @endif + - {{-- Phone-only actions + primary tabs. From md the desktop tab row is used. --}} -
+ {{-- Resource actions stay available below the desktop action HUD. Navigation lives in the sidebar. --}} +
@if ($server->proxySet()) @can('manageProxy', $server)
+ -