From a052b4b9e5be01ed4b6f1e801ed41293706e430b Mon Sep 17 00:00:00 2001 From: Yannick Seeger Date: Wed, 12 Aug 2026 14:20:38 +0200 Subject: [PATCH] fix(ui): replace the project layer-2 bar with a page header The project navbar rendered a single Resources tab that was only ever active on project.resource.index, a page that never rendered the bar, and rendered nothing at all without an environment, leaving project and environment settings with no title. Co-Authored-By: Claude Opus 5 (1M context) --- DESIGN.md | 8 +++ .../views/components/project/navbar.blade.php | 58 ------------------- .../views/livewire/project/clone-me.blade.php | 11 +++- .../views/livewire/project/edit.blade.php | 9 ++- .../project/environment-edit.blade.php | 29 +++++++--- .../views/livewire/project/show.blade.php | 2 - tests/Feature/PageTitleXlHiddenTest.php | 1 - .../ProjectEnvironmentPageHeaderTest.php | 52 +++++++++++++++++ .../ResourceHeadingUnifiedNavbarTest.php | 1 - 9 files changed, 96 insertions(+), 75 deletions(-) delete mode 100644 resources/views/components/project/navbar.blade.php create mode 100644 tests/Feature/ProjectEnvironmentPageHeaderTest.php diff --git a/DESIGN.md b/DESIGN.md index 5546b28f0..69f4f91ef 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -162,6 +162,14 @@ primary action in the page header instead. When tabs are useful, their left edge uses the same compact `pl-2` alignment as application navigation rather than the content container's wide horizontal padding. +A layer-2 tab must be active on the page that renders it. A bar whose only tab +points at a different route reads as broken navigation, so project and +environment pages (`project.show`, `project.edit`, `project.environment.edit`, +`project.clone-me`) carry a plain page header with a 24px title and a 13px +muted summary instead of a bar. The environment identity and the way back to +its resources already live in `x-top-breadcrumb`; do not restate them in a +sub-header. + The dashboard is a compact overview, not a metrics wall. Use two full-width sections that follow the projects-page grid pattern: projects first, then servers. Keep one `New` action in the page header and let its modal choose the diff --git a/resources/views/components/project/navbar.blade.php b/resources/views/components/project/navbar.blade.php deleted file mode 100644 index 2eddaad5b..000000000 --- a/resources/views/components/project/navbar.blade.php +++ /dev/null @@ -1,58 +0,0 @@ -@props([ - 'project', - 'environment' => null, -]) - -@php - $projectParameters = ['project_uuid' => $project->uuid]; - $environmentParameters = $environment - ? [...$projectParameters, 'environment_uuid' => $environment->uuid] - : []; - - $items = $environment - ? [ - ['label' => 'Resources', 'route' => 'project.resource.index', 'active' => request()->routeIs('project.resource.index'), 'icon' => 'grid'], - ] - : []; - - $routeParameters = $environment ? $environmentParameters : $projectParameters; -@endphp - -@if ($environment) - -@endif diff --git a/resources/views/livewire/project/clone-me.blade.php b/resources/views/livewire/project/clone-me.blade.php index c6b2e3323..6d945775b 100644 --- a/resources/views/livewire/project/clone-me.blade.php +++ b/resources/views/livewire/project/clone-me.blade.php @@ -1,8 +1,14 @@
{{ data_get_str($project, 'name')->limit(10) }} > Clone | Coolify - +
+
+

{{ $environment->name }}

+

+ Clone this environment inside {{ $project->name }} +

+
-
+
@@ -143,5 +149,6 @@
+
diff --git a/resources/views/livewire/project/edit.blade.php b/resources/views/livewire/project/edit.blade.php index 35696726d..b56ac5017 100644 --- a/resources/views/livewire/project/edit.blade.php +++ b/resources/views/livewire/project/edit.blade.php @@ -1,8 +1,12 @@
{{ data_get_str($project, 'name')->limit(10) }} > Edit | Coolify - +
+
+

{{ $project->name }}

+

Project settings

+
-
+
@@ -31,5 +35,6 @@
+
diff --git a/resources/views/livewire/project/environment-edit.blade.php b/resources/views/livewire/project/environment-edit.blade.php index f6d51f5de..1d267e09a 100644 --- a/resources/views/livewire/project/environment-edit.blade.php +++ b/resources/views/livewire/project/environment-edit.blade.php @@ -1,8 +1,25 @@
{{ data_get_str($environment, 'name')->limit(10) }} > Edit | Coolify - +
+
+
+

{{ $environment->name }}

+

+ Environment settings in {{ $project->name }} +

+
+ @can('createAnyResource') + + @endcan +
-
+
@@ -11,13 +28,6 @@

Environment details

Name and describe this environment inside {{ $project->name }}.

- @can('createAnyResource') - - - Clone environment - - @endcan
@@ -44,5 +54,6 @@
@endcan +
diff --git a/resources/views/livewire/project/show.blade.php b/resources/views/livewire/project/show.blade.php index c1d4b4c43..a3c1bbdf3 100644 --- a/resources/views/livewire/project/show.blade.php +++ b/resources/views/livewire/project/show.blade.php @@ -2,8 +2,6 @@ {{ data_get_str($project, 'name')->limit(10) }} > Environments | Coolify - -
diff --git a/tests/Feature/PageTitleXlHiddenTest.php b/tests/Feature/PageTitleXlHiddenTest.php index 9f86b62c3..29a9b4371 100644 --- a/tests/Feature/PageTitleXlHiddenTest.php +++ b/tests/Feature/PageTitleXlHiddenTest.php @@ -16,7 +16,6 @@ test('dashboard navbar hides family titles at lg to match the desktop shell', fu test('fixed layer-2 spacers match the fixed bar height', function () { $paths = [ resource_path('views/components/dashboard/navbar.blade.php'), - resource_path('views/components/project/navbar.blade.php'), resource_path('views/livewire/server/navbar.blade.php'), resource_path('views/livewire/project/application/heading.blade.php'), resource_path('views/livewire/project/database/heading.blade.php'), diff --git a/tests/Feature/ProjectEnvironmentPageHeaderTest.php b/tests/Feature/ProjectEnvironmentPageHeaderTest.php new file mode 100644 index 000000000..5a7605697 --- /dev/null +++ b/tests/Feature/ProjectEnvironmentPageHeaderTest.php @@ -0,0 +1,52 @@ +toBeFalse(); + + foreach ($projectPages as $page) { + expect(file_get_contents(resource_path($page))) + ->not->toContain('not->toContain('resource-heading-navbar'); + } +}); + +it('gives every project and environment page an in-flow title', function () use ($projectPages) { + foreach ($projectPages as $page) { + expect(file_get_contents(resource_path($page))) + ->toContain('

') + ->toContain('class="mt-1 text-[13px] text-neutral-500 dark:text-fg-dim"'); + } +}); + +it('keeps the environment clone action in the page header', function () { + $view = file_get_contents(resource_path('views/livewire/project/environment-edit.blade.php')); + + expect($view) + ->toContain('{{ $environment->name }}

') + ->toContain('Environment settings in {{ $project->name }}') + ->toContain('Clone environment') + // The action moved out of the card header into the page header. + ->toMatch('/]*>.*Clone environment.*<\/header>/s'); +}); + +it('does not repeat the resources action outside the resources page', function () { + foreach (['views/livewire/project/environment-edit.blade.php', 'views/livewire/project/clone-me.blade.php'] as $page) { + expect(file_get_contents(resource_path($page)))->not->toContain('New resource'); + } + + expect(file_get_contents(resource_path('views/livewire/project/resource/index.blade.php'))) + ->toContain('New resource'); +}); diff --git a/tests/Feature/ResourceHeadingUnifiedNavbarTest.php b/tests/Feature/ResourceHeadingUnifiedNavbarTest.php index d13135bb6..ee85f3650 100644 --- a/tests/Feature/ResourceHeadingUnifiedNavbarTest.php +++ b/tests/Feature/ResourceHeadingUnifiedNavbarTest.php @@ -470,7 +470,6 @@ it('shows application and service Links on mobile headings', function () { it('uses overflow scroll arrows on resource heading navbars', function () { $files = [ resource_path('views/livewire/server/navbar.blade.php'), - resource_path('views/components/project/navbar.blade.php'), ]; foreach ($files as $path) {