feat(preview-env): add production variable fallback for docker-compose

When preview environment variables are configured, fall back to production
variables for keys not overridden by preview values. This ensures variables
like DB_PASSWORD that exist only in production are available in the preview
.env file, enabling proper ${VAR} interpolation in docker-compose YAML.

Fallback only applies when preview variables are configured, preventing
unintended leakage of production values when previews aren't in use.

Also improves UI by hiding the Domains section when only database services
are present, and simplifies the logs view by removing status checks.
This commit is contained in:
Andras Bacsai committed 2026-03-25 13:26:50 +01:00
1 parent c2c18a2f0f
commit 3034e89edb
6 files changed
+318 -46

No files matched your search

@@ -4,7 +4,7 @@
</x-slot>
@if (
(data_get($application, 'fqdn') ||
collect(json_decode($this->application->docker_compose_domains))->count() > 0 ||
collect(json_decode($this->application->docker_compose_domains))->contains(fn($fqdn) => !empty(data_get($fqdn, 'domain'))) ||
data_get($application, 'previews', collect([]))->count() > 0 ||
data_get($application, 'ports_mappings_array')) &&
data_get($application, 'settings.is_raw_compose_deployment_enabled') !== true)
@@ -49,7 +49,13 @@
!is_null($parsedServices) &&
count($parsedServices) > 0 &&
!$application->settings->is_raw_compose_deployment_enabled)
<h3 class="pt-6">Domains</h3>
@php
$hasNonDatabaseService = collect(data_get($parsedServices, 'services', []))
->contains(fn($service) => !isDatabaseImage(data_get($service, 'image')));
@endphp
@if ($hasNonDatabaseService)
<h3 class="pt-6">Domains</h3>
@endif
@foreach (data_get($parsedServices, 'services') as $serviceName => $service)
@if (!isDatabaseImage(data_get($service, 'image')))
<div class="flex items-end gap-2">
@@ -86,18 +92,20 @@
]" />
@endcan
@endif
<div class="w-96 pb-6">
@if ($application->could_set_build_commands())
<x-forms.checkbox instantSave id="isStatic" label="Is it a static site?"
helper="If your application is a static site or the final build assets should be served as a static site, enable this."
x-bind:disabled="!canUpdate" />
@endif
@if ($isStatic && $buildPack !== 'static')
<x-forms.checkbox label="Is it a SPA (Single Page Application)?"
helper="If your application is a SPA, enable this." id="isSpa" instantSave
x-bind:disabled="!canUpdate"></x-forms.checkbox>
@endif
</div>
@if ($application->could_set_build_commands() || ($isStatic && $buildPack !== 'static'))
<div class="w-96 pb-6">
@if ($application->could_set_build_commands())
<x-forms.checkbox instantSave id="isStatic" label="Is it a static site?"
helper="If your application is a static site or the final build assets should be served as a static site, enable this."
x-bind:disabled="!canUpdate" />
@endif
@if ($isStatic && $buildPack !== 'static')
<x-forms.checkbox label="Is it a SPA (Single Page Application)?"
helper="If your application is a SPA, enable this." id="isSpa" instantSave
x-bind:disabled="!canUpdate"></x-forms.checkbox>
@endif
</div>
@endif
@if ($buildPack !== 'dockercompose')
<div class="flex items-end gap-2">
@if ($application->settings->is_container_label_readonly_enabled == false)
@@ -209,7 +217,7 @@
@endif
</div>
@endif
<div>
<div class="pt-6">
<h3>Build</h3>
@if ($application->build_pack === 'dockerimage')
<x-forms.input
@@ -8,39 +8,35 @@
<livewire:project.application.heading :application="$resource" />
<div>
<h2>Logs</h2>
@if (str($status)->contains('exited'))
<div class="pt-4">The resource is not running.</div>
@else
<div class="pt-2" wire:loading wire:target="loadAllContainers">
Loading containers...
</div>
<div x-init="$wire.loadAllContainers()" wire:loading.remove wire:target="loadAllContainers">
@forelse ($servers as $server)
<div class="py-2">
<h4>Server: {{ $server->name }}</h4>
@if ($server->isFunctional())
@if (isset($serverContainers[$server->id]) && count($serverContainers[$server->id]) > 0)
@php
$totalContainers = collect($serverContainers)->flatten(1)->count();
@endphp
@foreach ($serverContainers[$server->id] as $container)
<livewire:project.shared.get-logs
wire:key="{{ data_get($container, 'ID', uniqid()) }}" :server="$server"
:resource="$resource" :container="data_get($container, 'Names')"
:expandByDefault="$totalContainers === 1" />
@endforeach
@else
<div class="pt-2">No containers are running on server: {{ $server->name }}</div>
@endif
<div class="pt-2" wire:loading wire:target="loadAllContainers">
Loading containers...
</div>
<div x-init="$wire.loadAllContainers()" wire:loading.remove wire:target="loadAllContainers">
@forelse ($servers as $server)
<div class="py-2">
<h4>Server: {{ $server->name }}</h4>
@if ($server->isFunctional())
@if (isset($serverContainers[$server->id]) && count($serverContainers[$server->id]) > 0)
@php
$totalContainers = collect($serverContainers)->flatten(1)->count();
@endphp
@foreach ($serverContainers[$server->id] as $container)
<livewire:project.shared.get-logs
wire:key="{{ data_get($container, 'ID', uniqid()) }}" :server="$server"
:resource="$resource" :container="data_get($container, 'Names')"
:expandByDefault="$totalContainers === 1" />
@endforeach
@else
<div class="pt-2">Server {{ $server->name }} is not functional.</div>
<div class="pt-2">No containers are running on server: {{ $server->name }}</div>
@endif
</div>
@empty
<div>No functional server found for the application.</div>
@endforelse
</div>
@endif
@else
<div class="pt-2">Server {{ $server->name }} is not functional.</div>
@endif
</div>
@empty
<div>No functional server found for the application.</div>
@endforelse
</div>
</div>
@elseif ($type === 'database')
<h1>Logs</h1>