fix(application): defer Docker Compose loading and preserve domains

Load the compose file only after the user confirms its location, initialize the default compose path when switching build packs, and retain existing application domains.
This commit is contained in:
Andras Bacsai 2026-08-31 21:12:28 +02:00
parent c97649bda2
commit ff8b019296
4 changed files with 47 additions and 21 deletions

View file

@ -321,17 +321,6 @@ public function mount()
} }
} }
$this->initialDockerComposeLocation = $this->application->docker_compose_location; $this->initialDockerComposeLocation = $this->application->docker_compose_location;
if ($this->application->build_pack === 'dockercompose' && ! $this->application->docker_compose_raw) {
// Only load compose file if user has update permission
try {
$this->authorize('update', $this->application);
$this->initLoadingCompose = true;
$this->dispatch('info', 'Loading docker compose file.');
} catch (AuthorizationException $e) {
// User doesn't have update permission, skip loading compose file
}
}
if (str($this->application->status)->startsWith('running') && is_null($this->application->config_hash)) { if (str($this->application->status)->startsWith('running') && is_null($this->application->config_hash)) {
$this->dispatch('configurationChanged'); $this->dispatch('configurationChanged');
} }
@ -608,14 +597,9 @@ public function updatedBuildPack()
$this->resetDefaultLabels(false); $this->resetDefaultLabels(false);
} }
if ($this->buildPack === 'dockercompose') { if ($this->buildPack === 'dockercompose') {
// Only update if user has permission if (blank($this->dockerComposeLocation)) {
try { $this->dockerComposeLocation = '/docker-compose.yaml';
$this->authorize('update', $this->application); $this->application->docker_compose_location = $this->dockerComposeLocation;
$this->fqdn = null;
$this->application->fqdn = null;
$this->application->settings->save();
} catch (AuthorizationException $e) {
// User doesn't have update permission, just continue without saving
} }
} }
if ($this->buildPack === 'static') { if ($this->buildPack === 'static') {

View file

@ -119,8 +119,7 @@
@else @else
<div class="flex flex-col gap-5"> <div class="flex flex-col gap-5">
@if ($buildPack === 'dockercompose') @if ($buildPack === 'dockercompose')
<div class="flex flex-col gap-2" <div class="flex flex-col gap-2">
@can('update', $application) x-init="$wire.dispatch('loadCompose', true)" @endcan>
<div x-data="{ <div x-data="{
baseDir: @entangle('baseDirectory'), baseDir: @entangle('baseDirectory'),
composeLocation: @entangle('dockerComposeLocation'), composeLocation: @entangle('dockerComposeLocation'),

View file

@ -15,6 +15,19 @@
uses(RefreshDatabase::class); uses(RefreshDatabase::class);
class GeneralWithoutBuildpackSubmitSideEffects extends General
{
public function render(): mixed
{
return view('livewire.project.application.general');
}
public function submit($showToaster = true): void
{
$this->application->save();
}
}
beforeEach(function () { beforeEach(function () {
$this->team = Team::factory()->create(); $this->team = Team::factory()->create();
$this->user = User::factory()->create(); $this->user = User::factory()->create();
@ -85,3 +98,25 @@
->assertDontSee('Railpack (Beta)') ->assertDontSee('Railpack (Beta)')
->assertDontSee('Railpack (beta)'); ->assertDontSee('Railpack (beta)');
}); });
test('switching from railpack to compose preserves the existing application domains', function () {
$application = Application::factory()->create([
'environment_id' => $this->environment->id,
'destination_id' => $this->destination->id,
'destination_type' => StandaloneDocker::class,
'build_pack' => 'railpack',
'static_image' => 'nginx:alpine',
'base_directory' => '/',
'fqdn' => 'https://example.com,https://www.example.com',
'is_http_basic_auth_enabled' => false,
'redirect' => 'no',
]);
Livewire::test(GeneralWithoutBuildpackSubmitSideEffects::class, ['application' => $application])
->assertSuccessful()
->set('buildPack', 'dockercompose')
->assertSet('dockerComposeLocation', '/docker-compose.yaml');
expect($application->refresh()->fqdn)
->toBe('https://example.com,https://www.example.com');
});

View file

@ -13,6 +13,14 @@
->toContain('Reload compose'); ->toContain('Reload compose');
}); });
test('compose file loading waits for the user to confirm the file location', function () {
$view = file_get_contents(resource_path('views/livewire/project/application/general.blade.php'));
expect($view)
->toContain('x-on:click="$wire.dispatch(\'loadCompose\', false)"')
->not->toContain('x-init="$wire.dispatch(\'loadCompose\', true)"');
});
test('docker compose heading separates its title and action', function () { test('docker compose heading separates its title and action', function () {
$view = file_get_contents(resource_path('views/livewire/project/application/general.blade.php')); $view = file_get_contents(resource_path('views/livewire/project/application/general.blade.php'));