mirror of
https://github.com/tiennm99/coolify.git
synced 2026-10-20 02:17:09 +00:00
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.
This commit is contained in:
1 parent
d6db943453
commit
85613b01ba
25 files changed
+312
-121
No files matched your search
@@ -46,6 +46,47 @@
|
||||
'group' => 'Networking',
|
||||
'visible' => ! $server->isLocalhost(),
|
||||
],
|
||||
[
|
||||
'label' => 'Proxy',
|
||||
'route' => 'server.proxy',
|
||||
'active' => request()->routeIs('server.proxy', 'server.proxy.*'),
|
||||
'icon' => 'network',
|
||||
'group' => 'Platform',
|
||||
'visible' => ! $server->isSwarmWorker() && ! $server->settings->is_build_server,
|
||||
'children' => [
|
||||
['label' => 'Configuration', 'route' => 'server.proxy', 'active' => request()->routeIs('server.proxy'), 'icon' => 'settings'],
|
||||
['label' => 'Dynamic Configurations', 'route' => 'server.proxy.dynamic-confs', 'active' => request()->routeIs('server.proxy.dynamic-confs'), 'icon' => 'sliders', 'visible' => $server->proxySet()],
|
||||
['label' => 'Logs', 'route' => 'server.proxy.logs', 'active' => request()->routeIs('server.proxy.logs'), 'icon' => 'file-content', 'visible' => $server->proxySet(), 'navigate' => false],
|
||||
],
|
||||
],
|
||||
[
|
||||
'label' => 'Sentinel',
|
||||
'route' => 'server.sentinel',
|
||||
'active' => request()->routeIs('server.sentinel', 'server.sentinel.*'),
|
||||
'icon' => 'shield-star',
|
||||
'group' => 'Platform',
|
||||
'visible' => $server->isFunctional() && ! $server->isSwarm() && ! $server->settings->is_build_server && auth()->user()?->can('viewSentinel', $server),
|
||||
'children' => [
|
||||
['label' => 'Configuration', 'route' => 'server.sentinel', 'active' => request()->routeIs('server.sentinel'), 'icon' => 'settings'],
|
||||
['label' => 'Logs', 'route' => 'server.sentinel.logs', 'active' => request()->routeIs('server.sentinel.logs'), 'icon' => 'file-content'],
|
||||
],
|
||||
],
|
||||
[
|
||||
'label' => 'Resources',
|
||||
'route' => 'server.resources',
|
||||
'active' => request()->routeIs('server.resources'),
|
||||
'icon' => 'projects',
|
||||
'group' => 'Platform',
|
||||
],
|
||||
[
|
||||
'label' => 'Terminal',
|
||||
'route' => 'server.command',
|
||||
'active' => request()->routeIs('server.command'),
|
||||
'icon' => 'browser-terminal',
|
||||
'group' => 'Operations',
|
||||
'navigate' => false,
|
||||
'visible' => auth()->user()?->can('canAccessTerminal'),
|
||||
],
|
||||
[
|
||||
'label' => 'Destinations',
|
||||
'route' => 'server.destinations',
|
||||
@@ -66,7 +107,7 @@
|
||||
'label' => 'Docker Cleanup',
|
||||
'route' => 'server.docker-cleanup',
|
||||
'active' => $activeMenu === 'docker-cleanup',
|
||||
'icon' => 'storages',
|
||||
'icon' => 'broom',
|
||||
'group' => 'Operations',
|
||||
'visible' => $server->isFunctional(),
|
||||
],
|
||||
@@ -86,6 +127,18 @@
|
||||
'group' => 'Operations',
|
||||
'visible' => $server->isFunctional(),
|
||||
],
|
||||
[
|
||||
'label' => 'Security',
|
||||
'route' => 'server.security.patches',
|
||||
'active' => request()->routeIs('server.security.*'),
|
||||
'icon' => 'shield-alert',
|
||||
'group' => 'Security',
|
||||
'visible' => auth()->user()?->can('update', $server),
|
||||
'children' => [
|
||||
['label' => 'Server Patching', 'route' => 'server.security.patches', 'active' => request()->routeIs('server.security.patches'), 'icon' => 'bandage'],
|
||||
['label' => 'Terminal Access', 'route' => 'server.security.terminal-access', 'active' => request()->routeIs('server.security.terminal-access'), 'icon' => 'browser-terminal', 'navigate' => false],
|
||||
],
|
||||
],
|
||||
[
|
||||
'label' => 'Danger',
|
||||
'route' => 'server.delete',
|
||||
@@ -119,11 +172,24 @@
|
||||
'menu-item',
|
||||
'menu-item-active' => $menuItem['active'],
|
||||
])
|
||||
{{ wireNavigate() }}
|
||||
@if ($menuItem['navigate'] ?? true) {{ wireNavigate() }} @endif
|
||||
href="{{ route($menuItem['route'], $serverRouteParameters) }}">
|
||||
<x-reicon :name="$menuItem['icon']" class="menu-item-icon" />
|
||||
<span class="menu-item-label">{{ $menuItem['label'] }}</span>
|
||||
</a>
|
||||
@if ($menuItem['active'] && isset($menuItem['children']))
|
||||
<div class="col-span-full grid grid-cols-2 gap-0.5 border-l border-neutral-200 pl-2 sm:grid-cols-3 xl:grid-cols-1 dark:border-white/[0.08]">
|
||||
@foreach (collect($menuItem['children'])->filter(fn (array $child): bool => $child['visible'] ?? true) as $child)
|
||||
<a wire:key="server-settings-child-{{ str($menuItem['label'].'-'.$child['label'])->slug() }}"
|
||||
@class(['menu-item', 'menu-item-active' => $child['active']])
|
||||
@if ($child['navigate'] ?? true) {{ wireNavigate() }} @endif
|
||||
href="{{ route($child['route'], $serverRouteParameters) }}">
|
||||
<x-reicon :name="$child['icon']" class="menu-item-icon" />
|
||||
<span class="menu-item-label">{{ $child['label'] }}</span>
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
@endforeach
|
||||
@endforeach
|
||||
</nav>
|
||||
|
||||
@@ -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
|
||||
|
||||
<div class="relative shrink-0" x-data="{ open: false }" @click.outside="open = false"
|
||||
@keydown.escape.window="open = false">
|
||||
<x-status-badge as="button" dynamic @click="open = !open" x-bind:aria-expanded="open" aria-haspopup="menu"
|
||||
class="cursor-pointer">
|
||||
<span @class([
|
||||
'size-1.5 shrink-0 rounded-full',
|
||||
'bg-success' => $summaryType === 'success',
|
||||
'bg-warning' => $summaryType === 'warning',
|
||||
'bg-error' => $summaryType === 'error',
|
||||
])></span>
|
||||
<span class="truncate">{{ $summaryLabel }}</span>
|
||||
<span class="inline-flex transition-transform" :class="open && 'rotate-180'">
|
||||
<x-reicon name="chevron-down" class="size-3 opacity-55" />
|
||||
</span>
|
||||
</x-status-badge>
|
||||
|
||||
<div x-cloak x-show="open" x-transition.origin.top.right
|
||||
class="listbox-panel top-8! right-0! left-auto! z-[90]! w-64! min-w-64!" role="menu">
|
||||
<div class="px-3 py-2 text-[11px] font-medium text-neutral-400 dark:text-fg-faint">System status</div>
|
||||
<div class="listbox-option cursor-default! gap-2.5!">
|
||||
<span @class([
|
||||
'size-1.5 shrink-0 rounded-full',
|
||||
'bg-success' => $serverReady,
|
||||
'bg-error' => ! $serverReady,
|
||||
])></span>
|
||||
<span class="flex-1">Server</span>
|
||||
<span>{{ $serverReady ? 'Ready' : 'Unavailable' }}</span>
|
||||
</div>
|
||||
@if ($server->proxySet())
|
||||
<div class="listbox-option cursor-default! gap-2.5!">
|
||||
<span @class([
|
||||
'size-1.5 shrink-0 rounded-full',
|
||||
'bg-success' => $proxyStatus === 'running',
|
||||
'bg-warning' => in_array($proxyStatus, ['starting', 'restarting', 'stopping'], true),
|
||||
'bg-error' => ! in_array($proxyStatus, ['running', 'starting', 'restarting', 'stopping'], true),
|
||||
])></span>
|
||||
<span class="flex-1">Proxy</span>
|
||||
<span>{{ str($proxyStatus ?: 'unknown')->headline() }}</span>
|
||||
</div>
|
||||
@endif
|
||||
@if ($showSentinelStatus)
|
||||
<div class="listbox-option cursor-default! gap-2.5!">
|
||||
<span class="size-1.5 shrink-0 rounded-full {{ $server->isSentinelLive() ? 'bg-success' : 'bg-error' }}"></span>
|
||||
<span class="flex-1">Sentinel</span>
|
||||
<span>{{ $server->isSentinelLive() ? 'In sync' : 'Out of sync' }}</span>
|
||||
</div>
|
||||
@endif
|
||||
@if ($server->proxySet())
|
||||
<button type="button" class="listbox-option justify-start! gap-2.5!" wire:click="checkProxyStatus"
|
||||
wire:loading.attr="disabled" wire:target="checkProxyStatus" role="menuitem">
|
||||
<span class="contents" wire:loading.remove wire:target="checkProxyStatus">
|
||||
<x-reicon name="refresh" class="size-3 opacity-70" />
|
||||
Refresh status
|
||||
</span>
|
||||
<span class="hidden items-center gap-2.5" wire:loading.flex wire:target="checkProxyStatus">
|
||||
<x-loading compact />
|
||||
Refreshing status
|
||||
</span>
|
||||
</button>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
Reference in new issue
Block a user