From e50108a90588f5704cdda39f1e41e3d9430f5277 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Fri, 7 Aug 2026 18:31:19 +0200 Subject: [PATCH] fix(ui): prefer Compose env values and polish error pages When a managed variable shares a Compose-defined key, show the hardcoded Compose value as read-only and exclude it from managed rows. Render Contact support as a button, use the collapsible component for 419 proxy help, and style its list/code markers. --- .../Shared/EnvironmentVariable/All.php | 38 +++++++++++++------ resources/css/app.css | 6 ++- .../views/components/error-page.blade.php | 7 ++-- resources/views/errors/419.blade.php | 6 +-- .../project/application/general.blade.php | 2 - .../project/application/heading.blade.php | 2 - .../Feature/EnvironmentVariableSearchTest.php | 28 ++++++++++++++ tests/Feature/ErrorPagesRedesignTest.php | 13 +++++++ 8 files changed, 78 insertions(+), 24 deletions(-) diff --git a/app/Livewire/Project/Shared/EnvironmentVariable/All.php b/app/Livewire/Project/Shared/EnvironmentVariable/All.php index 4c4907200..89130799a 100644 --- a/app/Livewire/Project/Shared/EnvironmentVariable/All.php +++ b/app/Livewire/Project/Shared/EnvironmentVariable/All.php @@ -512,6 +512,11 @@ class All extends Component ->where('resourceable_id', $this->resource->id) ->where('is_preview', $isPreview); + $hardcodedKeys = $this->hardcodedEnvironmentVariableKeys(); + if ($hardcodedKeys !== []) { + $query->whereNotIn('key', $hardcodedKeys); + } + if ($this->serviceFilters !== []) { $query->whereRaw('1 = 0'); } @@ -716,18 +721,6 @@ class All extends Component return ! str($key)->startsWith(['SERVICE_FQDN_', 'SERVICE_URL_', 'SERVICE_NAME_']); }); - // Filter out variables that exist in database (user has overridden/managed them) - // For preview, check against preview variables; for production, check against production variables - if ($isPreview) { - $managedKeys = $this->resource->environment_variables_preview()->pluck('key')->toArray(); - } else { - $managedKeys = $this->resource->environment_variables()->where('is_preview', false)->pluck('key')->toArray(); - } - - $hardcodedVars = $hardcodedVars->filter(function ($var) use ($managedKeys) { - return ! in_array($var['key'], $managedKeys); - }); - if ($this->searchTerm() !== '') { $hardcodedVars = $hardcodedVars->filter(function ($var) { return str($var['key'])->contains($this->searchTerm(), true); @@ -749,6 +742,27 @@ class All extends Component return $hardcodedVars; } + /** @return list */ + private function hardcodedEnvironmentVariableKeys(): array + { + if (! $this->showsHardcodedEnvironmentVariables()) { + return []; + } + + $dockerComposeRaw = $this->resource->docker_compose_raw ?? $this->resource->docker_compose; + + if (blank($dockerComposeRaw)) { + return []; + } + + return extractHardcodedEnvironmentVariables($dockerComposeRaw) + ->pluck('key') + ->reject(fn (string $key): bool => str($key)->startsWith(['SERVICE_FQDN_', 'SERVICE_URL_', 'SERVICE_NAME_'])) + ->unique() + ->values() + ->all(); + } + public function getDevView() { $this->variables = $this->formatEnvironmentVariables($this->getEnvironmentVariables(false, false)); diff --git a/resources/css/app.css b/resources/css/app.css index 98e7d3899..bcbabe389 100644 --- a/resources/css/app.css +++ b/resources/css/app.css @@ -1207,7 +1207,8 @@ html[data-theme="custom"] textarea:disabled { color: var(--color-accent); } -.error-extra details ul { +.error-extra details ul, +.error-proxy-help ul { margin: 0.5rem 0 0; padding-left: 1.125rem; display: flex; @@ -1215,7 +1216,8 @@ html[data-theme="custom"] textarea:disabled { gap: 0.375rem; } -.error-extra details code { +.error-extra details code, +.error-proxy-help code { font-family: var(--font-mono); font-size: 0.75rem; padding: 0.05rem 0.3rem; diff --git a/resources/views/components/error-page.blade.php b/resources/views/components/error-page.blade.php index 7a29eb0c3..11ca60cc8 100644 --- a/resources/views/components/error-page.blade.php +++ b/resources/views/components/error-page.blade.php @@ -55,10 +55,11 @@ - Contact support - + + Contact support + + @endif diff --git a/resources/views/errors/419.blade.php b/resources/views/errors/419.blade.php index c04efcf59..585e887a5 100644 --- a/resources/views/errors/419.blade.php +++ b/resources/views/errors/419.blade.php @@ -11,14 +11,14 @@ :show-dashboard="false" primary-href="/login" primary-label="Back to login"> -
- Using a reverse proxy or Cloudflare Tunnel? +
  • Set your domain in Settings → FQDN to match the URL you use to access Coolify.
  • Cloudflare users: disable Browser Integrity Check and Under Attack Mode for your Coolify domain, as these can interrupt login sessions.
  • If you can still access Coolify via localhost, log in there first to configure your FQDN.
-
+ + @livewireScripts @endsection diff --git a/resources/views/livewire/project/application/general.blade.php b/resources/views/livewire/project/application/general.blade.php index 6445a155c..b3775a1dd 100644 --- a/resources/views/livewire/project/application/general.blade.php +++ b/resources/views/livewire/project/application/general.blade.php @@ -7,8 +7,6 @@ }">
- {{-- Temporarily hidden: the "Compose parser" dev hint and the "View details" - resource-details modal trigger. --}}
@if ($buildPack === 'dockercompose') diff --git a/resources/views/livewire/project/application/heading.blade.php b/resources/views/livewire/project/application/heading.blade.php index c524da243..be825792f 100644 --- a/resources/views/livewire/project/application/heading.blade.php +++ b/resources/views/livewire/project/application/heading.blade.php @@ -180,8 +180,6 @@
- {{-- Status badge temporarily hidden — will be redesigned later: - --}} @if ($application->build_pack === 'dockercompose' && is_null($application->docker_compose_raw)) Load a Compose file to deploy. @else diff --git a/tests/Feature/EnvironmentVariableSearchTest.php b/tests/Feature/EnvironmentVariableSearchTest.php index cc114ae61..a44124ea7 100644 --- a/tests/Feature/EnvironmentVariableSearchTest.php +++ b/tests/Feature/EnvironmentVariableSearchTest.php @@ -182,6 +182,34 @@ YAML, ->toBe(['API_TOKEN']); }); +it('shows a Compose-defined value as read-only when a managed variable has the same key', function () { + $service = Service::factory()->create([ + 'environment_id' => $this->environment->id, + 'docker_compose_raw' => <<<'YAML' +services: + app: + image: nginx + environment: + - API_TOKEN=from-compose +YAML, + ]); + + EnvironmentVariable::create([ + 'key' => 'API_TOKEN', + 'value' => 'from-environment-tab', + 'resourceable_type' => Service::class, + 'resourceable_id' => $service->id, + ]); + + $component = Livewire::test(All::class, ['resource' => $service]) + ->call('loadEnvironmentVariables'); + + expect($component->instance()->environmentVariablePageRows) + ->toHaveCount(1) + ->and($component->instance()->environmentVariablePageRows->first()['kind'])->toBe('hardcoded') + ->and($component->instance()->environmentVariablePageRows->first()['environmentVariable']['value'])->toBe('from-compose'); +}); + it('searches service environment variables without requiring preview variables', function () { $service = Service::factory()->create([ 'environment_id' => $this->environment->id, diff --git a/tests/Feature/ErrorPagesRedesignTest.php b/tests/Feature/ErrorPagesRedesignTest.php index a54a7e3a1..8d1c7ae32 100644 --- a/tests/Feature/ErrorPagesRedesignTest.php +++ b/tests/Feature/ErrorPagesRedesignTest.php @@ -57,9 +57,22 @@ it('uses login as primary action on session expired page', function () { ->toContain('/login') ->toContain('Back to login') ->toContain('Using a reverse proxy or Cloudflare Tunnel?') + ->toContain('x-data="{ open: false }"') + ->toContain('x-on:click="open = !open"') + ->toContain('livewire.js') ->not->toContain('>Dashboard $exception])->render(); + + expect($html) + ->toContain('href="'.config('constants.urls.contact').'"') + ->toMatch('/]*>\s*Contact support/s'); +}); + it('shows purified exception message on 500 page', function () { $exception = new RuntimeException('Database connection failed');