diff --git a/app/Livewire/Project/Application/Advanced.php b/app/Livewire/Project/Application/Advanced.php index cf7ef3e0b..bb1e58067 100644 --- a/app/Livewire/Project/Application/Advanced.php +++ b/app/Livewire/Project/Application/Advanced.php @@ -70,6 +70,9 @@ class Advanced extends Component #[Validate(['string', 'nullable'])] public ?string $customInternalName = null; + #[Validate(['string', 'nullable'])] + public ?string $customContainerNamePrefix = null; + #[Validate(['boolean'])] public bool $isGzipEnabled = true; @@ -111,6 +114,7 @@ class Advanced extends Component $this->application->settings->is_build_server_enabled = $this->isBuildServerEnabled; $this->application->settings->is_consistent_container_name_enabled = $this->isConsistentContainerNameEnabled; $this->application->settings->custom_internal_name = $this->customInternalName; + $this->application->settings->custom_container_name_prefix = $this->customContainerNamePrefix; $this->application->settings->is_gzip_enabled = $this->isGzipEnabled; $this->application->settings->is_stripprefix_enabled = $this->isStripprefixEnabled; $this->application->settings->is_raw_compose_deployment_enabled = $this->isRawComposeDeploymentEnabled; @@ -139,6 +143,7 @@ class Advanced extends Component $this->isBuildServerEnabled = $this->application->settings->is_build_server_enabled; $this->isConsistentContainerNameEnabled = $this->application->settings->is_consistent_container_name_enabled; $this->customInternalName = $this->application->settings->custom_internal_name; + $this->customContainerNamePrefix = $this->application->settings->custom_container_name_prefix; $this->isRawComposeDeploymentEnabled = $this->application->settings->is_raw_compose_deployment_enabled; $this->isConnectToDockerNetworkEnabled = $this->application->settings->connect_to_docker_network; $this->disableBuildCache = $this->application->settings->disable_build_cache; @@ -231,12 +236,19 @@ class Advanced extends Component return; } + + $this->customContainerNamePrefix = null; $customInternalName = $this->customInternalName; $server = $this->application->destination->server; $allApplications = $server->applications(); $foundSameInternalName = $allApplications->filter(function ($application) { - return $application->id !== $this->application->id && $application->settings->custom_internal_name === $this->customInternalName; + if ($application->id === $this->application->id) { + return false; + } + + return $application->settings->custom_internal_name === $this->customInternalName + || $application->settings->custom_container_name_prefix === $this->customInternalName; }); if ($foundSameInternalName->isNotEmpty()) { $this->dispatch('error', 'This custom container name is already in use by another application on this server.'); @@ -252,6 +264,50 @@ class Advanced extends Component } } + public function saveCustomNamePrefix() + { + try { + $this->authorize('update', $this->application); + + if (str($this->customContainerNamePrefix)->isNotEmpty()) { + $this->customContainerNamePrefix = str($this->customContainerNamePrefix)->slug()->value(); + } else { + $this->customContainerNamePrefix = null; + } + + if (is_null($this->customContainerNamePrefix)) { + $this->syncData(true); + $this->dispatch('success', 'Custom container name prefix saved.'); + + return; + } + + $this->customInternalName = null; + $server = $this->application->destination->server; + $allApplications = $server->applications(); + + $foundDuplicate = $allApplications->filter(function ($application) { + if ($application->id === $this->application->id) { + return false; + } + + return $application->settings->custom_container_name_prefix === $this->customContainerNamePrefix + || $application->settings->custom_internal_name === $this->customContainerNamePrefix; + }); + + if ($foundDuplicate->isNotEmpty()) { + $this->dispatch('error', 'This custom container name prefix is already in use by another application on this server.'); + + return; + } + + $this->syncData(true); + $this->dispatch('success', 'Custom container name prefix saved.'); + } catch (\Throwable $e) { + return handleError($e, $this); + } + } + public function render() { return view('livewire.project.application.advanced'); diff --git a/bootstrap/helpers/docker.php b/bootstrap/helpers/docker.php index 7b74392cf..3372d5266 100644 --- a/bootstrap/helpers/docker.php +++ b/bootstrap/helpers/docker.php @@ -181,6 +181,7 @@ function generateApplicationContainerName(Application $application, $pull_reques // TODO: refactor generateApplicationContainerName, we do not need $application and $pull_request_id $consistent_container_name = $application->settings->is_consistent_container_name_enabled; + $custom_container_name_prefix = $application->settings->custom_container_name_prefix; $now = now()->format('Hisu'); if ($pull_request_id !== 0 && $pull_request_id !== null) { return $application->uuid.'-pr-'.$pull_request_id; @@ -189,7 +190,10 @@ function generateApplicationContainerName(Application $application, $pull_reques return $application->uuid; } - return $application->uuid.'-'.$now; + + $prefix = $custom_container_name_prefix ?? $application->uuid; + + return $prefix.'-'.$now; } } function get_port_from_dockerfile($dockerfile): ?int diff --git a/database/migrations/2026_02_02_000000_add_custom_container_name_prefix_to_application_settings.php b/database/migrations/2026_02_02_000000_add_custom_container_name_prefix_to_application_settings.php new file mode 100644 index 000000000..bbeb825e2 --- /dev/null +++ b/database/migrations/2026_02_02_000000_add_custom_container_name_prefix_to_application_settings.php @@ -0,0 +1,28 @@ +string('custom_container_name_prefix')->nullable(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('application_settings', function (Blueprint $table) { + $table->dropColumn('custom_container_name_prefix'); + }); + } +}; diff --git a/resources/views/livewire/project/application/advanced.blade.php b/resources/views/livewire/project/application/advanced.blade.php index 907500dfa..2c7e4d743 100644 --- a/resources/views/livewire/project/application/advanced.blade.php +++ b/resources/views/livewire/project/application/advanced.blade.php @@ -63,10 +63,20 @@ @if ($isConsistentContainerNameEnabled === false)
- Save + helper="You can add a custom name for your container.

The name will be converted to slug format when you save it. You will lose the rolling update feature!

Cannot be used together with Custom Container Name Prefix." + id="customInternalName" label="Custom Container Name" canGate="update" + :canResource="$application" :disabled="!empty($customContainerNamePrefix)" /> + Save + +
+ + Save @endif @if ($application->build_pack === 'dockercompose')