-
+
@if ($server->isFunctional())
diff --git a/tests/Feature/LoadingComponentTest.php b/tests/Feature/LoadingComponentTest.php
index c32b222f6..0b8abec8e 100644
--- a/tests/Feature/LoadingComponentTest.php
+++ b/tests/Feature/LoadingComponentTest.php
@@ -5,7 +5,8 @@ it('uses the current neutral loading indicator styles', function () {
expect($loading)
->toContain('gap-2 text-[13px] text-neutral-500 dark:text-fg-dim')
- ->toContain('size-4 shrink-0 animate-spin')
+ ->toContain("'size-3' => \$compact")
+ ->toContain("'size-4' => ! \$compact")
->toContain('stroke="currentColor" stroke-width="2"')
->not->toContain('text-coollabs')
->not->toContain('dark:text-warning');
diff --git a/tests/Feature/ResourceHeadingUnifiedNavbarTest.php b/tests/Feature/ResourceHeadingUnifiedNavbarTest.php
index 41ac43f4e..0eed129af 100644
--- a/tests/Feature/ResourceHeadingUnifiedNavbarTest.php
+++ b/tests/Feature/ResourceHeadingUnifiedNavbarTest.php
@@ -255,10 +255,13 @@ it('keeps Links dropdowns outside the scrollable tabs strip', function () {
it('shows an icon in application and service Links controls', function () {
$applicationLinks = file_get_contents(resource_path('views/components/applications/links.blade.php'));
$serviceLinks = file_get_contents(resource_path('views/components/services/links.blade.php'));
+ $serviceLinksComponent = file_get_contents(app_path('View/Components/Services/Links.php'));
expect($applicationLinks)->toContain("@props(['application', 'fullWidth' => false])")
->toContain('and($serviceLinks)->toContain('and($serviceLinksComponent)->toContain('public bool $fullWidth = false')
+ ->and($serviceLinks)
+ ->toContain('and($applicationLinks)->not->toContain('and($serviceLinks)->not->toContain('toContain('toContain('full-width')
->toContain('resource-heading-menus')
->not->toContain('toContain("'button w-full justify-between' => \$fullWidth")
+ ->toContain('toContain('No links available');
+
// One mobile + one desktop instance.
expect(substr_count($application, 'toBe(2);
expect(substr_count($service, 'toBe(2);
diff --git a/tests/Feature/ServerNavbarStatusLayoutTest.php b/tests/Feature/ServerNavbarStatusLayoutTest.php
index 605520615..7bdab0875 100644
--- a/tests/Feature/ServerNavbarStatusLayoutTest.php
+++ b/tests/Feature/ServerNavbarStatusLayoutTest.php
@@ -1,23 +1,28 @@
toContain('data-testid="server-status-summary"')
- ->toContain('toContain('label="Proxy"')
- ->toContain('label="Sentinel"')
- ->toContain('as="button"')
- ->toContain("wire:click='checkProxyStatus'")
- ->toContain('status="Refresh"')
- ->toContain('border-transparent')
- ->toContain('wire:loading.attr="disabled"')
- ->not->toContain('status="Refreshing..."')
- ->not->toContain('justify-between')
- ->not->toContain('')
- ->not->toContain('');
+ ->toContain('not->toContain('label="Proxy" status="Running"')
+ ->not->toContain('label="Sentinel"')
+ ->and($summaryView)
+ ->toContain("['Attention required', 'warning']")
+ ->toContain("['Ready', 'success']")
+ ->toContain('System status')
+ ->toContain('Refresh status')
+ ->toContain('toContain(":class=\"open && 'rotate-180'\"")
+ ->toContain('wire:click="checkProxyStatus"')
+ ->toContain('wire:loading.remove wire:target="checkProxyStatus"')
+ ->toContain('wire:loading.flex wire:target="checkProxyStatus"')
+ ->toContain('Refreshing status')
+ ->toContain('')
+ ->toContain('name="refresh" class="size-3 opacity-70"')
+ ->not->toContain('@click="open = false" role="menuitem"');
expect($badgeView)
->not->toContain('text-neutral-500')
diff --git a/tests/Feature/ServerSidebarIconsTest.php b/tests/Feature/ServerSidebarIconsTest.php
new file mode 100644
index 000000000..c405dfba0
--- /dev/null
+++ b/tests/Feature/ServerSidebarIconsTest.php
@@ -0,0 +1,46 @@
+toContain("'{$name}' => ");
+
+ $html = Blade::render("");
+
+ expect($html)
+ ->toContain('viewBox="0 0 24 24"')
+ ->toContain('fill="currentColor"')
+ ->toContain('menu-item-icon')
+ ->not->toBe('');
+})->with(['broom', 'shield-star', 'network']);
+
+it('uses the broom reicon for docker cleanup in the server sidebar', function () {
+ $contents = file_get_contents(resource_path('views/components/server/sidebar.blade.php'));
+
+ expect($contents)
+ ->toContain("'label' => 'Docker Cleanup'")
+ ->toContain("'icon' => 'broom'")
+ ->not->toMatch("/'label' => 'Docker Cleanup',\s*'route' => 'server\.docker-cleanup',\s*'active' => \$activeMenu === 'docker-cleanup',\s*'icon' => 'storages'/s");
+});
+
+it('uses the shield-star reicon for sentinel in the server sidebar', function () {
+ $contents = file_get_contents(resource_path('views/components/server/sidebar.blade.php'));
+
+ expect($contents)
+ ->toContain("'label' => 'Sentinel'")
+ ->toMatch("/'label' => 'Sentinel',\s*'route' => 'server\.sentinel',\s*'active' => request\(\)->routeIs\('server\.sentinel', 'server\.sentinel\.\*'\),\s*'icon' => 'shield-star'/s");
+});
+
+it('uses the network reicon for proxy in the server sidebar', function () {
+ $contents = file_get_contents(resource_path('views/components/server/sidebar.blade.php'));
+
+ expect($contents)
+ ->toContain("'label' => 'Proxy'")
+ ->toMatch("/'label' => 'Proxy',\s*'route' => 'server\.proxy',\s*'active' => request\(\)->routeIs\('server\.proxy', 'server\.proxy\.\*'\),\s*'icon' => 'network'/s")
+ ->not->toMatch("/'label' => 'Proxy',\s*'route' => 'server\.proxy',\s*'active' => request\(\)->routeIs\('server\.proxy', 'server\.proxy\.\*'\),\s*'icon' => 'settings'/s");
+});
diff --git a/tests/Feature/ServiceComposeResourcesViewSwitcherTest.php b/tests/Feature/ServiceComposeResourcesViewSwitcherTest.php
index e5bc753ca..091b977f6 100644
--- a/tests/Feature/ServiceComposeResourcesViewSwitcherTest.php
+++ b/tests/Feature/ServiceComposeResourcesViewSwitcherTest.php
@@ -10,6 +10,8 @@ it('provides grid and table views for compose resources without sorting controls
->toContain("setViewMode('grid')")
->toContain('aria-label="Table view"')
->toContain('aria-label="Grid view"')
+ ->toContain('mb-3 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between')
+ ->toContain('flex w-full items-center justify-between gap-2 sm:w-auto sm:justify-start')
->toContain("localStorage.setItem('service-compose-resources-view', mode)")
->not->toContain('>Sort')
->and($resourceCard)
diff --git a/tests/Feature/ServiceDatabaseVerticalNavigationTest.php b/tests/Feature/ServiceDatabaseVerticalNavigationTest.php
index 8b90f05af..a5ad3ad9f 100644
--- a/tests/Feature/ServiceDatabaseVerticalNavigationTest.php
+++ b/tests/Feature/ServiceDatabaseVerticalNavigationTest.php
@@ -92,7 +92,7 @@ it('shows the database sidebar in the terminal', function () {
$terminal = file_get_contents(resource_path('views/livewire/project/shared/execute-container-command.blade.php'));
expect($terminal)
- ->toContain("in_array(\$type, ['application', 'database', 'service'], true)")
+ ->toContain("in_array(\$type, ['application', 'database', 'service', 'server'], true)")
->toContain('toContain("in_array(\$type, ['application', 'database', 'service'], true)")
->toContain('and($terminal)
- ->toContain("in_array(\$type, ['application', 'database', 'service'], true)")
+ ->toContain("in_array(\$type, ['application', 'database', 'service', 'server'], true)")
->toContain('and($sidebar)
->toContain("'Logs' => ['Runtime']")
diff --git a/tests/Feature/SidebarNavigationMarkupTest.php b/tests/Feature/SidebarNavigationMarkupTest.php
index 35b7aad2d..e536ff4db 100644
--- a/tests/Feature/SidebarNavigationMarkupTest.php
+++ b/tests/Feature/SidebarNavigationMarkupTest.php
@@ -55,3 +55,23 @@ it('shows section titles and descriptions above settings navigation on smaller s
['settings/layout.blade.php', 'Instance Settings', 'Configure global settings for this Coolify instance.'],
['team/settings-layout.blade.php', 'Team', 'Manage your team, members, and access settings.'],
]);
+
+it('uses the structured sidebar and action HUD for server navigation', function () {
+ $navbar = file_get_contents(resource_path('views/livewire/server/navbar.blade.php'));
+ $sidebar = file_get_contents(resource_path('views/components/server/sidebar.blade.php'));
+ $resources = file_get_contents(resource_path('views/livewire/server/resources.blade.php'));
+ $terminal = file_get_contents(resource_path('views/livewire/project/shared/execute-container-command.blade.php'));
+
+ expect($navbar)
+ ->toContain('class="hidden xl:fixed xl:top-14 xl:right-4 xl:z-30 xl:flex')
+ ->toContain('')
+ ->toContain('dark:bg-coolgray-100! dark:text-white!')
+ ->and($sidebar)
+ ->toContain("'label' => 'Proxy'")
+ ->toContain("'label' => 'Sentinel'")
+ ->toContain("'label' => 'Resources'")
+ ->toContain("'label' => 'Terminal'")
+ ->toContain("'label' => 'Security'")
+ ->and($resources)->toContain('')
+ ->and($terminal)->toContain('');
+});