Complete Livewire legacy model binding migration (25+ components)

This completes the migration from Livewire's legacy `id="model.property"`
pattern to explicit properties with manual synchronization. This allows
disabling the `legacy_model_binding` feature flag.

**Components Migrated (Final Session - 9 components):**
- Server/Proxy.php (1 field)
- Service/EditDomain.php (1 field) - Fixed Collection/string bug & parent sync
- Application/Previews.php (2 fields - array handling)
- Service/EditCompose.php (4 fields)
- Service/FileStorage.php (6 fields)
- Service/Database.php (7 fields)
- Service/ServiceApplicationView.php (10 fields)
- Application/General.php (53 fields) - LARGEST migration
- Application/PreviewsCompose.php (1 field)

**Total Migration Summary:**
- 25+ components migrated across all phases
- 150+ explicit properties added
- 0 legacy bindings remaining (verified via grep)
- All wire:model, id, @entangle bindings updated
- All updater hooks renamed (updatedApplicationX → updatedX)

**Technical Changes:**
- Added explicit public properties (camelCase)
- Implemented syncData(bool $toModel) bidirectional sync
- Updated validation rules (removed model. prefix)
- Updated all action methods (mount, submit, instantSave)
- Fixed updater hooks: updatedBuildPack, updatedBaseDirectory, updatedIsStatic
- Updated Blade views (id & wire:model bindings)
- Applied Collection/string confusion fixes
- Added model refresh + re-sync pattern

**Critical Fixes:**
- EditDomain.php Collection/string confusion (use intermediate variables)
- EditDomain.php parent component sync (refresh + re-sync after save)
- General.php domain field empty (syncData at end of mount)
- General.php wire:model bindings (application.* → property)
- General.php updater hooks (wrong naming convention)

**Files Modified:** 34 files
- 17 PHP Livewire components
- 17 Blade view templates
- 1 MIGRATION_REPORT.md (documentation)

**Ready to disable legacy_model_binding flag in config/livewire.php**

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Andras Bacsai
2025-10-13 15:38:59 +02:00
parent bb9ddd089a
commit f77ad4cbd9
35 changed files with 1597 additions and 501 deletions
@@ -16,14 +16,14 @@
<div>General configuration for your application.</div>
<div class="flex flex-col gap-2 py-4">
<div class="flex flex-col items-end gap-2 xl:flex-row">
<x-forms.input x-bind:disabled="shouldDisable()" id="application.name" label="Name" required />
<x-forms.input x-bind:disabled="shouldDisable()" id="application.description" label="Description" />
<x-forms.input x-bind:disabled="shouldDisable()" id="name" label="Name" required />
<x-forms.input x-bind:disabled="shouldDisable()" id="description" label="Description" />
</div>
@if (!$application->dockerfile && $application->build_pack !== 'dockerimage')
<div class="flex flex-col gap-2">
<div class="flex gap-2">
<x-forms.select x-bind:disabled="shouldDisable()" wire:model.live="application.build_pack"
<x-forms.select x-bind:disabled="shouldDisable()" wire:model.live="build_pack"
label="Build Pack" required>
<option value="nixpacks">Nixpacks</option>
<option value="static">Static</option>
@@ -31,7 +31,7 @@
<option value="dockercompose">Docker Compose</option>
</x-forms.select>
@if ($application->settings->is_static || $application->build_pack === 'static')
<x-forms.select x-bind:disabled="!canUpdate" id="application.static_image"
<x-forms.select x-bind:disabled="!canUpdate" id="static_image"
label="Static Image" required>
<option value="nginx:alpine">nginx:alpine</option>
<option disabled value="apache:alpine">apache:alpine</option>
@@ -66,7 +66,7 @@
</div>
@endif
@if ($application->settings->is_static || $application->build_pack === 'static')
<x-forms.textarea id="application.custom_nginx_configuration"
<x-forms.textarea id="custom_nginx_configuration"
placeholder="Empty means default configuration will be used." label="Custom Nginx Configuration"
helper="You can add custom Nginx configuration here." x-bind:disabled="!canUpdate" />
@can('update', $application)
@@ -77,25 +77,25 @@
@endif
<div class="w-96 pb-6">
@if ($application->could_set_build_commands())
<x-forms.checkbox instantSave id="application.settings.is_static" label="Is it a static site?"
<x-forms.checkbox instantSave id="is_static" 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 ($application->settings->is_static && $application->build_pack !== 'static')
<x-forms.checkbox label="Is it a SPA (Single Page Application)?"
helper="If your application is a SPA, enable this." id="application.settings.is_spa" instantSave
helper="If your application is a SPA, enable this." id="is_spa" instantSave
x-bind:disabled="!canUpdate"></x-forms.checkbox>
@endif
</div>
@if ($application->build_pack !== 'dockercompose')
<div class="flex items-end gap-2">
@if ($application->settings->is_container_label_readonly_enabled == false)
<x-forms.input placeholder="https://coolify.io" wire:model.blur="application.fqdn"
<x-forms.input placeholder="https://coolify.io" wire:model.blur="fqdn"
label="Domains" readonly
helper="Readonly labels are disabled. You can set the domains in the labels section."
x-bind:disabled="!canUpdate" />
@else
<x-forms.input placeholder="https://coolify.io" wire:model.blur="application.fqdn"
<x-forms.input placeholder="https://coolify.io" wire:model.blur="fqdn"
label="Domains"
helper="You can specify one domain with path or more with comma. You can specify a port to bind the domain to.<br><br><span class='text-helper'>Example</span><br>- http://app.coolify.io,https://cloud.coolify.io/dashboard<br>- http://app.coolify.io/api/v3<br>- http://app.coolify.io:3000 -> app.coolify.io will point to port 3000 inside the container. "
x-bind:disabled="!canUpdate" />
@@ -121,7 +121,7 @@
x-bind:disabled="!canUpdate" />
@endif
@else
<x-forms.select label="Direction" id="application.redirect" required
<x-forms.select label="Direction" id="redirect" required
helper="You must need to add www and non-www as an A DNS record. Make sure the www domain is added under Domains."
x-bind:disabled="!canUpdate">
<option value="both">Allow www & non-www.</option>
@@ -164,15 +164,15 @@
<div class="flex flex-col gap-2 xl:flex-row">
@if ($application->build_pack === 'dockerimage')
@if ($application->destination->server->isSwarm())
<x-forms.input required id="application.docker_registry_image_name" label="Docker Image"
<x-forms.input required id="docker_registry_image_name" label="Docker Image"
x-bind:disabled="!canUpdate" />
<x-forms.input id="application.docker_registry_image_tag" label="Docker Image Tag or Hash"
<x-forms.input id="docker_registry_image_tag" label="Docker Image Tag or Hash"
helper="Enter a tag (e.g., 'latest', 'v1.2.3') or SHA256 hash (e.g., 'sha256-59e02939b1bf39f16c93138a28727aec520bb916da021180ae502c61626b3cf0')"
x-bind:disabled="!canUpdate" />
@else
<x-forms.input id="application.docker_registry_image_name" label="Docker Image"
<x-forms.input id="docker_registry_image_name" label="Docker Image"
x-bind:disabled="!canUpdate" />
<x-forms.input id="application.docker_registry_image_tag" label="Docker Image Tag or Hash"
<x-forms.input id="docker_registry_image_tag" label="Docker Image Tag or Hash"
helper="Enter a tag (e.g., 'latest', 'v1.2.3') or SHA256 hash (e.g., 'sha256-59e02939b1bf39f16c93138a28727aec520bb916da021180ae502c61626b3cf0')"
x-bind:disabled="!canUpdate" />
@endif
@@ -181,18 +181,18 @@
$application->destination->server->isSwarm() ||
$application->additional_servers->count() > 0 ||
$application->settings->is_build_server_enabled)
<x-forms.input id="application.docker_registry_image_name" required label="Docker Image"
<x-forms.input id="docker_registry_image_name" required label="Docker Image"
placeholder="Required!" x-bind:disabled="!canUpdate" />
<x-forms.input id="application.docker_registry_image_tag"
<x-forms.input id="docker_registry_image_tag"
helper="If set, it will tag the built image with this tag too. <br><br>Example: If you set it to 'latest', it will push the image with the commit sha tag + with the latest tag."
placeholder="Empty means latest will be used." label="Docker Image Tag"
x-bind:disabled="!canUpdate" />
@else
<x-forms.input id="application.docker_registry_image_name"
<x-forms.input id="docker_registry_image_name"
helper="Empty means it won't push the image to a docker registry. Pre-tag the image with your registry url if you want to push it to a private registry (default: Dockerhub). <br><br>Example: ghcr.io/myimage"
placeholder="Empty means it won't push the image to a docker registry."
label="Docker Image" x-bind:disabled="!canUpdate" />
<x-forms.input id="application.docker_registry_image_tag"
<x-forms.input id="docker_registry_image_tag"
placeholder="Empty means only push commit sha tag."
helper="If set, it will tag the built image with this tag too. <br><br>Example: If you set it to 'latest', it will push the image with the commit sha tag + with the latest tag."
label="Docker Image Tag" x-bind:disabled="!canUpdate" />
@@ -206,20 +206,20 @@
<x-forms.input
helper="You can add custom docker run options that will be used when your container is started.<br>Note: Not all options are supported, as they could mess up Coolify's automation and could cause bad experience for users.<br><br>Check the <a class='underline dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/custom-commands'>docs.</a>"
placeholder="--cap-add SYS_ADMIN --device=/dev/fuse --security-opt apparmor:unconfined --ulimit nofile=1024:1024 --tmpfs /run:rw,noexec,nosuid,size=65536k --hostname=myapp"
id="application.custom_docker_run_options" label="Custom Docker Options"
id="custom_docker_run_options" label="Custom Docker Options"
x-bind:disabled="!canUpdate" />
@else
@if ($application->could_set_build_commands())
@if ($application->build_pack === 'nixpacks')
<div class="flex flex-col gap-2 xl:flex-row">
<x-forms.input helper="If you modify this, you probably need to have a nixpacks.toml"
id="application.install_command" label="Install Command"
id="install_command" label="Install Command"
x-bind:disabled="!canUpdate" />
<x-forms.input helper="If you modify this, you probably need to have a nixpacks.toml"
id="application.build_command" label="Build Command"
id="build_command" label="Build Command"
x-bind:disabled="!canUpdate" />
<x-forms.input helper="If you modify this, you probably need to have a nixpacks.toml"
id="application.start_command" label="Start Command"
id="start_command" label="Start Command"
x-bind:disabled="!canUpdate" />
</div>
<div class="pt-1 text-xs">Nixpacks will detect the required configuration
@@ -239,16 +239,16 @@
@endcan
<div class="flex gap-2">
<x-forms.input x-bind:disabled="shouldDisable()" placeholder="/"
id="application.base_directory" label="Base Directory"
id="base_directory" label="Base Directory"
helper="Directory to use as root. Useful for monorepos." />
<x-forms.input x-bind:disabled="shouldDisable()"
placeholder="/docker-compose.yaml"
id="application.docker_compose_location" label="Docker Compose Location"
id="docker_compose_location" label="Docker Compose Location"
helper="It is calculated together with the Base Directory:<br><span class='dark:text-warning'>{{ Str::start($application->base_directory . $application->docker_compose_location, '/') }}</span>" />
</div>
<div class="w-96">
<x-forms.checkbox instantSave
id="application.settings.is_preserve_repository_enabled"
id="is_preserve_repository_enabled"
label="Preserve Repository During Deployment"
helper="Git repository (based on the base directory settings) will be copied to the deployment directory."
x-bind:disabled="shouldDisable()" />
@@ -261,12 +261,12 @@
<div class="flex gap-2">
<x-forms.input x-bind:disabled="shouldDisable()"
placeholder="docker compose build"
id="application.docker_compose_custom_build_command"
id="docker_compose_custom_build_command"
helper="If you use this, you need to specify paths relatively and should use the same compose file in the custom command, otherwise the automatically configured labels / etc won't work.<br><br>So in your case, use: <span class='dark:text-warning'>docker compose -f .{{ Str::start($application->base_directory . $application->docker_compose_location, '/') }} build</span>"
label="Custom Build Command" />
<x-forms.input x-bind:disabled="shouldDisable()"
placeholder="docker compose up -d"
id="application.docker_compose_custom_start_command"
id="docker_compose_custom_start_command"
helper="If you use this, you need to specify paths relatively and should use the same compose file in the custom command, otherwise the automatically configured labels / etc won't work.<br><br>So in your case, use: <span class='dark:text-warning'>docker compose -f .{{ Str::start($application->base_directory . $application->docker_compose_location, '/') }} up -d</span>"
label="Custom Start Command" />
</div>
@@ -274,36 +274,36 @@
<div class="pt-4">
<x-forms.textarea
helper="Order-based pattern matching to filter Git webhook deployments. Supports wildcards (*, **, ?) and negation (!). Last matching pattern wins."
placeholder="services/api/**" id="application.watch_paths"
placeholder="services/api/**" id="watch_paths"
label="Watch Paths" x-bind:disabled="shouldDisable()" />
</div>
@endif
</div>
@else
<div class="flex flex-col gap-2 xl:flex-row">
<x-forms.input placeholder="/" id="application.base_directory"
<x-forms.input placeholder="/" id="base_directory"
label="Base Directory"
helper="Directory to use as root. Useful for monorepos."
x-bind:disabled="!canUpdate" />
@if ($application->build_pack === 'dockerfile' && !$application->dockerfile)
<x-forms.input placeholder="/Dockerfile" id="application.dockerfile_location"
<x-forms.input placeholder="/Dockerfile" id="dockerfile_location"
label="Dockerfile Location"
helper="It is calculated together with the Base Directory:<br><span class='dark:text-warning'>{{ Str::start($application->base_directory . $application->dockerfile_location, '/') }}</span>"
x-bind:disabled="!canUpdate" />
@endif
@if ($application->build_pack === 'dockerfile')
<x-forms.input id="application.dockerfile_target_build"
<x-forms.input id="dockerfile_target_build"
label="Docker Build Stage Target"
helper="Useful if you have multi-staged dockerfile."
x-bind:disabled="!canUpdate" />
@endif
@if ($application->could_set_build_commands())
@if ($application->settings->is_static)
<x-forms.input placeholder="/dist" id="application.publish_directory"
<x-forms.input placeholder="/dist" id="publish_directory"
label="Publish Directory" required x-bind:disabled="!canUpdate" />
@else
<x-forms.input placeholder="/" id="application.publish_directory"
<x-forms.input placeholder="/" id="publish_directory"
label="Publish Directory" x-bind:disabled="!canUpdate" />
@endif
@endif
@@ -313,21 +313,21 @@
<div class="pb-4">
<x-forms.textarea
helper="Order-based pattern matching to filter Git webhook deployments. Supports wildcards (*, **, ?) and negation (!). Last matching pattern wins."
placeholder="src/pages/**" id="application.watch_paths"
placeholder="src/pages/**" id="watch_paths"
label="Watch Paths" x-bind:disabled="!canUpdate" />
</div>
@endif
<x-forms.input
helper="You can add custom docker run options that will be used when your container is started.<br>Note: Not all options are supported, as they could mess up Coolify's automation and could cause bad experience for users.<br><br>Check the <a class='underline dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/custom-commands'>docs.</a>"
placeholder="--cap-add SYS_ADMIN --device=/dev/fuse --security-opt apparmor:unconfined --ulimit nofile=1024:1024 --tmpfs /run:rw,noexec,nosuid,size=65536k --hostname=myapp"
id="application.custom_docker_run_options" label="Custom Docker Options"
id="custom_docker_run_options" label="Custom Docker Options"
x-bind:disabled="!canUpdate" />
@if ($application->build_pack !== 'dockercompose')
<div class="pt-2 w-96">
<x-forms.checkbox
helper="Use a build server to build your application. You can configure your build server in the Server settings. For more info, check the <a href='https://coolify.io/docs/knowledge-base/server/build-server' class='underline' target='_blank'>documentation</a>."
instantSave id="application.settings.is_build_server_enabled"
instantSave id="is_build_server_enabled"
label="Use a Build Server?" x-bind:disabled="!canUpdate" />
</div>
@endif
@@ -344,18 +344,18 @@
@endcan
</div>
@if ($application->settings->is_raw_compose_deployment_enabled)
<x-forms.textarea rows="10" readonly id="application.docker_compose_raw"
<x-forms.textarea rows="10" readonly id="docker_compose_raw"
label="Docker Compose Content (applicationId: {{ $application->id }})"
helper="You need to modify the docker compose file in the git repository."
monacoEditorLanguage="yaml" useMonacoEditor />
@else
@if ((int) $application->compose_parsing_version >= 3)
<x-forms.textarea rows="10" readonly id="application.docker_compose_raw"
<x-forms.textarea rows="10" readonly id="docker_compose_raw"
label="Docker Compose Content (raw)"
helper="You need to modify the docker compose file in the git repository."
monacoEditorLanguage="yaml" useMonacoEditor />
@endif
<x-forms.textarea rows="10" readonly id="application.docker_compose"
<x-forms.textarea rows="10" readonly id="docker_compose"
label="Docker Compose Content"
helper="You need to modify the docker compose file in the git repository."
monacoEditorLanguage="yaml" useMonacoEditor />
@@ -363,45 +363,45 @@
<div class="w-96">
<x-forms.checkbox label="Escape special characters in labels?"
helper="By default, $ (and other chars) is escaped. So if you write $ in the labels, it will be saved as $$.<br><br>If you want to use env variables inside the labels, turn this off."
id="application.settings.is_container_label_escape_enabled" instantSave
id="is_container_label_escape_enabled" instantSave
x-bind:disabled="!canUpdate"></x-forms.checkbox>
{{-- <x-forms.checkbox label="Readonly labels"
helper="Labels are readonly by default. Readonly means that edits you do to the labels could be lost and Coolify will autogenerate the labels for you. If you want to edit the labels directly, disable this option. <br><br>Be careful, it could break the proxy configuration after you restart the container as Coolify will now NOT autogenerate the labels for you (ofc you can always reset the labels to the coolify defaults manually)."
id="application.settings.is_container_label_readonly_enabled" instantSave></x-forms.checkbox> --}}
id="is_container_label_readonly_enabled" instantSave></x-forms.checkbox> --}}
</div>
@endif
@if ($application->dockerfile)
<x-forms.textarea label="Dockerfile" id="application.dockerfile" monacoEditorLanguage="dockerfile"
<x-forms.textarea label="Dockerfile" id="dockerfile" monacoEditorLanguage="dockerfile"
useMonacoEditor rows="6" x-bind:disabled="!canUpdate"> </x-forms.textarea>
@endif
@if ($application->build_pack !== 'dockercompose')
<h3 class="pt-8">Network</h3>
<div class="flex flex-col gap-2 xl:flex-row">
@if ($application->settings->is_static || $application->build_pack === 'static')
<x-forms.input id="application.ports_exposes" label="Ports Exposes" readonly
<x-forms.input id="ports_exposes" label="Ports Exposes" readonly
x-bind:disabled="!canUpdate" />
@else
@if ($application->settings->is_container_label_readonly_enabled === false)
<x-forms.input placeholder="3000,3001" id="application.ports_exposes"
<x-forms.input placeholder="3000,3001" id="ports_exposes"
label="Ports Exposes" readonly
helper="Readonly labels are disabled. You can set the ports manually in the labels section."
x-bind:disabled="!canUpdate" />
@else
<x-forms.input placeholder="3000,3001" id="application.ports_exposes"
<x-forms.input placeholder="3000,3001" id="ports_exposes"
label="Ports Exposes" required
helper="A comma separated list of ports your application uses. The first port will be used as default healthcheck port if nothing defined in the Healthcheck menu. Be sure to set this correctly."
x-bind:disabled="!canUpdate" />
@endif
@endif
@if (!$application->destination->server->isSwarm())
<x-forms.input placeholder="3000:3000" id="application.ports_mappings" label="Ports Mappings"
<x-forms.input placeholder="3000:3000" id="ports_mappings" label="Ports Mappings"
helper="A comma separated list of ports you would like to map to the host system. Useful when you do not want to use domains.<br><br><span class='inline-block font-bold dark:text-warning'>Example:</span><br>3000:3000,3002:3002<br><br>Rolling update is not supported if you have a port mapped to the host."
x-bind:disabled="!canUpdate" />
@endif
@if (!$application->destination->server->isSwarm())
<x-forms.input id="application.custom_network_aliases" label="Network Aliases"
<x-forms.input id="custom_network_aliases" label="Network Aliases"
helper="A comma separated list of custom network aliases you would like to add for container in Docker network.<br><br><span class='inline-block font-bold dark:text-warning'>Example:</span><br>api.internal,api.local"
wire:model="application.custom_network_aliases" x-bind:disabled="!canUpdate" />
wire:model="custom_network_aliases" x-bind:disabled="!canUpdate" />
@endif
</div>
@@ -409,14 +409,14 @@
<div>
<div class="w-96">
<x-forms.checkbox helper="This will add the proper proxy labels to the container." instantSave
label="Enable" id="application.is_http_basic_auth_enabled"
label="Enable" id="is_http_basic_auth_enabled"
x-bind:disabled="!canUpdate" />
</div>
@if ($application->is_http_basic_auth_enabled)
<div class="flex gap-2 py-2">
<x-forms.input id="application.http_basic_auth_username" label="Username" required
<x-forms.input id="http_basic_auth_username" label="Username" required
x-bind:disabled="!canUpdate" />
<x-forms.input id="application.http_basic_auth_password" type="password" label="Password"
<x-forms.input id="http_basic_auth_password" type="password" label="Password"
required x-bind:disabled="!canUpdate" />
</div>
@endif
@@ -432,11 +432,11 @@
<div class="w-96">
<x-forms.checkbox label="Readonly labels"
helper="Labels are readonly by default. Readonly means that edits you do to the labels could be lost and Coolify will autogenerate the labels for you. If you want to edit the labels directly, disable this option. <br><br>Be careful, it could break the proxy configuration after you restart the container as Coolify will now NOT autogenerate the labels for you (ofc you can always reset the labels to the coolify defaults manually)."
id="application.settings.is_container_label_readonly_enabled" instantSave
id="is_container_label_readonly_enabled" instantSave
x-bind:disabled="!canUpdate"></x-forms.checkbox>
<x-forms.checkbox label="Escape special characters in labels?"
helper="By default, $ (and other chars) is escaped. So if you write $ in the labels, it will be saved as $$.<br><br>If you want to use env variables inside the labels, turn this off."
id="application.settings.is_container_label_escape_enabled" instantSave
id="is_container_label_escape_enabled" instantSave
x-bind:disabled="!canUpdate"></x-forms.checkbox>
</div>
@can('update', $application)
@@ -455,21 +455,21 @@
<h3 class="pt-8">Pre/Post Deployment Commands</h3>
<div class="flex flex-col gap-2 xl:flex-row">
<x-forms.input x-bind:disabled="shouldDisable()" placeholder="php artisan migrate"
id="application.pre_deployment_command" label="Pre-deployment "
id="pre_deployment_command" label="Pre-deployment "
helper="An optional script or command to execute in the existing container before the deployment begins.<br>It is always executed with 'sh -c', so you do not need add it manually." />
@if ($application->build_pack === 'dockercompose')
<x-forms.input x-bind:disabled="shouldDisable()" id="application.pre_deployment_command_container"
<x-forms.input x-bind:disabled="shouldDisable()" id="pre_deployment_command_container"
label="Container Name"
helper="The name of the container to execute within. You can leave it blank if your application only has one container." />
@endif
</div>
<div class="flex flex-col gap-2 xl:flex-row">
<x-forms.input x-bind:disabled="shouldDisable()" placeholder="php artisan migrate"
id="application.post_deployment_command" label="Post-deployment "
id="post_deployment_command" label="Post-deployment "
helper="An optional script or command to execute in the newly built container after the deployment completes.<br>It is always executed with 'sh -c', so you do not need add it manually." />
@if ($application->build_pack === 'dockercompose')
<x-forms.input x-bind:disabled="shouldDisable()"
id="application.post_deployment_command_container" label="Container Name"
id="post_deployment_command_container" label="Container Name"
helper="The name of the container to execute within. You can leave it blank if your application only has one container." />
@endif
</div>
@@ -1,6 +1,6 @@
<form wire:submit="save" class="flex items-end gap-2">
<x-forms.input helper="One domain per preview." label="Domains for {{ str($serviceName)->headline() }}"
id="service.domain" canGate="update" :canResource="$preview->application"></x-forms.input>
id="domain" canGate="update" :canResource="$preview->application"></x-forms.input>
<x-forms.button type="submit">Save</x-forms.button>
<x-forms.button wire:click="generate">Generate
Domain</x-forms.button>
@@ -112,7 +112,7 @@
<form wire:submit="save_preview('{{ $preview->id }}')"
class="flex items-end gap-2 pt-4">
<x-forms.input label="Domain" helper="One domain per preview."
id="application.previews.{{ $previewName }}.fqdn" canGate="update" :canResource="$application"></x-forms.input>
id="previewFqdns.{{ $previewName }}" canGate="update" :canResource="$application"></x-forms.input>
@can('update', $application)
<x-forms.button type="submit">Save</x-forms.button>
<x-forms.button wire:click="generate_preview('{{ $preview->id }}')">Generate
@@ -130,7 +130,7 @@
@else
<form wire:submit="save_preview('{{ $preview->id }}')" class="flex items-end gap-2 pt-4">
<x-forms.input label="Domain" helper="One domain per preview."
id="application.previews.{{ $previewName }}.fqdn" canGate="update" :canResource="$application"></x-forms.input>
id="previewFqdns.{{ $previewName }}" canGate="update" :canResource="$application"></x-forms.input>
@can('update', $application)
<x-forms.button type="submit">Save</x-forms.button>
<x-forms.button wire:click="generate_preview('{{ $preview->id }}')">Generate
@@ -23,16 +23,16 @@
</div>
<div class="flex flex-col gap-2">
<div class="flex gap-2">
<x-forms.input canGate="update" :canResource="$database" label="Name" id="database.human_name" placeholder="Name"></x-forms.input>
<x-forms.input canGate="update" :canResource="$database" label="Description" id="database.description"></x-forms.input>
<x-forms.input canGate="update" :canResource="$database" label="Name" id="humanName" placeholder="Name"></x-forms.input>
<x-forms.input canGate="update" :canResource="$database" label="Description" id="description"></x-forms.input>
<x-forms.input canGate="update" :canResource="$database" required
helper="You can change the image you would like to deploy.<br><br><span class='dark:text-warning'>WARNING. You could corrupt your data. Only do it if you know what you are doing.</span>"
label="Image" id="database.image"></x-forms.input>
label="Image" id="image"></x-forms.input>
</div>
<div class="flex items-end gap-2">
<x-forms.input canGate="update" :canResource="$database" placeholder="5432" disabled="{{ $database->is_public }}" id="database.public_port"
<x-forms.input canGate="update" :canResource="$database" placeholder="5432" disabled="{{ $database->is_public }}" id="publicPort"
label="Public Port" />
<x-forms.checkbox canGate="update" :canResource="$database" instantSave id="database.is_public" label="Make it publicly available" />
<x-forms.checkbox canGate="update" :canResource="$database" instantSave id="isPublic" label="Make it publicly available" />
</div>
@if ($db_url_public)
<x-forms.input label="Database IP:PORT (public)"
@@ -44,9 +44,9 @@
<div class="w-96">
<x-forms.checkbox canGate="update" :canResource="$database" instantSave="instantSaveExclude" label="Exclude from service status"
helper="If you do not need to monitor this resource, enable. Useful if this service is optional."
id="database.exclude_from_status"></x-forms.checkbox>
id="excludeFromStatus"></x-forms.checkbox>
<x-forms.checkbox canGate="update" :canResource="$database" helper="Drain logs to your configured log drain endpoint in your Server settings."
instantSave="instantSaveLogDrain" id="database.is_log_drain_enabled" label="Drain Logs" />
instantSave="instantSaveLogDrain" id="isLogDrainEnabled" label="Drain Logs" />
</div>
</form>
</div>
@@ -6,24 +6,24 @@
<div x-cloak x-show="raw" class="font-mono">
<div x-cloak x-show="showNormalTextarea">
<x-forms.textarea rows="20" id="service.docker_compose_raw">
<x-forms.textarea rows="20" id="dockerComposeRaw">
</x-forms.textarea>
</div>
<div x-cloak x-show="!showNormalTextarea">
<x-forms.textarea allowTab useMonacoEditor monacoEditorLanguage="yaml" rows="20"
id="service.docker_compose_raw">
id="dockerComposeRaw">
</x-forms.textarea>
</div>
</div>
<div x-cloak x-show="raw === false" class="font-mono">
<x-forms.textarea rows="20" readonly id="service.docker_compose">
<x-forms.textarea rows="20" readonly id="dockerCompose">
</x-forms.textarea>
</div>
<div class="pt-2 flex gap-2">
<div class="flex flex-col gap-2">
<x-forms.checkbox label="Escape special characters in labels?"
helper="By default, $ (and other chars) is escaped. So if you write $ in the labels, it will be saved as $$.<br><br>If you want to use env variables inside the labels, turn this off."
id="service.is_container_label_escape_enabled" instantSave></x-forms.checkbox>
id="isContainerLabelEscapeEnabled" instantSave></x-forms.checkbox>
<x-forms.checkbox label="Show Normal Textarea" x-model="showNormalTextarea"></x-forms.checkbox>
</div>
@@ -3,7 +3,7 @@
<div class="pb-2">Note: If a service has a defined port, do not delete it. <br>If you want to use your custom
domain, you can add it with a port.</div>
<x-forms.input canGate="update" :canResource="$application" placeholder="https://app.coolify.io" label="Domains"
id="application.fqdn"
id="fqdn"
helper="You can specify one domain with path or more with comma. You can specify a port to bind the domain to.<br><br><span class='text-helper'>Example</span><br>- http://app.coolify.io,https://cloud.coolify.io/dashboard<br>- http://app.coolify.io/api/v3<br>- http://app.coolify.io:3000 -> app.coolify.io will point to port 3000 inside the container. "></x-forms.input>
<x-forms.button canGate="update" :canResource="$application" type="submit">Save</x-forms.button>
</form>
@@ -60,12 +60,12 @@
@if (data_get($resource, 'settings.is_preserve_repository_enabled'))
<div class="w-96">
<x-forms.checkbox instantSave label="Is this based on the Git repository?"
id="fileStorage.is_based_on_git"></x-forms.checkbox>
id="isBasedOnGit"></x-forms.checkbox>
</div>
@endif
<x-forms.textarea
label="{{ $fileStorage->is_based_on_git ? 'Content (refreshed after a successful deployment)' : 'Content' }}"
rows="20" id="fileStorage.content"
rows="20" id="content"
readonly="{{ $fileStorage->is_based_on_git || $fileStorage->is_binary }}"></x-forms.textarea>
@if (!$fileStorage->is_based_on_git && !$fileStorage->is_binary)
<x-forms.button class="w-full" type="submit">Save</x-forms.button>
@@ -74,12 +74,12 @@
@if (data_get($resource, 'settings.is_preserve_repository_enabled'))
<div class="w-96">
<x-forms.checkbox disabled label="Is this based on the Git repository?"
id="fileStorage.is_based_on_git"></x-forms.checkbox>
id="isBasedOnGit"></x-forms.checkbox>
</div>
@endif
<x-forms.textarea
label="{{ $fileStorage->is_based_on_git ? 'Content (refreshed after a successful deployment)' : 'Content' }}"
rows="20" id="fileStorage.content" disabled></x-forms.textarea>
rows="20" id="content" disabled></x-forms.textarea>
@endcan
@endif
@else
@@ -88,12 +88,12 @@
@if (data_get($resource, 'settings.is_preserve_repository_enabled'))
<div class="w-96">
<x-forms.checkbox disabled label="Is this based on the Git repository?"
id="fileStorage.is_based_on_git"></x-forms.checkbox>
id="isBasedOnGit"></x-forms.checkbox>
</div>
@endif
<x-forms.textarea
label="{{ $fileStorage->is_based_on_git ? 'Content (refreshed after a successful deployment)' : 'Content' }}"
rows="20" id="fileStorage.content" disabled></x-forms.textarea>
rows="20" id="content" disabled></x-forms.textarea>
@endif
@endif
</form>
@@ -23,48 +23,48 @@
</div>
<div class="flex flex-col gap-2">
<div class="flex gap-2">
<x-forms.input canGate="update" :canResource="$application" label="Name" id="application.human_name"
<x-forms.input canGate="update" :canResource="$application" label="Name" id="humanName"
placeholder="Human readable name"></x-forms.input>
<x-forms.input canGate="update" :canResource="$application" label="Description"
id="application.description"></x-forms.input>
id="description"></x-forms.input>
</div>
<div class="flex gap-2">
@if (!$application->serviceType()?->contains(str($application->image)->before(':')))
@if ($application->required_fqdn)
<x-forms.input canGate="update" :canResource="$application" required placeholder="https://app.coolify.io"
label="Domains" id="application.fqdn"
label="Domains" id="fqdn"
helper="You can specify one domain with path or more with comma. You can specify a port to bind the domain to.<br><br><span class='text-helper'>Example</span><br>- http://app.coolify.io,https://cloud.coolify.io/dashboard<br>- http://app.coolify.io/api/v3<br>- http://app.coolify.io:3000 -> app.coolify.io will point to port 3000 inside the container. "></x-forms.input>
@else
<x-forms.input canGate="update" :canResource="$application" placeholder="https://app.coolify.io"
label="Domains" id="application.fqdn"
label="Domains" id="fqdn"
helper="You can specify one domain with path or more with comma. You can specify a port to bind the domain to.<br><br><span class='text-helper'>Example</span><br>- http://app.coolify.io,https://cloud.coolify.io/dashboard<br>- http://app.coolify.io/api/v3<br>- http://app.coolify.io:3000 -> app.coolify.io will point to port 3000 inside the container. "></x-forms.input>
@endif
@endif
<x-forms.input canGate="update" :canResource="$application"
helper="You can change the image you would like to deploy.<br><br><span class='dark:text-warning'>WARNING. You could corrupt your data. Only do it if you know what you are doing.</span>"
label="Image" id="application.image"></x-forms.input>
label="Image" id="image"></x-forms.input>
</div>
</div>
<h3 class="py-2 pt-4">Advanced</h3>
<div class="w-96 flex flex-col gap-1">
@if (str($application->image)->contains('pocketbase'))
<x-forms.checkbox canGate="update" :canResource="$application" instantSave id="application.is_gzip_enabled"
<x-forms.checkbox canGate="update" :canResource="$application" instantSave id="isGzipEnabled"
label="Enable Gzip Compression"
helper="Pocketbase does not need gzip compression, otherwise SSE will not work." disabled />
@else
<x-forms.checkbox canGate="update" :canResource="$application" instantSave id="application.is_gzip_enabled"
<x-forms.checkbox canGate="update" :canResource="$application" instantSave id="isGzipEnabled"
label="Enable Gzip Compression"
helper="You can disable gzip compression if you want. Some services are compressing data by default. In this case, you do not need this." />
@endif
<x-forms.checkbox canGate="update" :canResource="$application" instantSave id="application.is_stripprefix_enabled"
<x-forms.checkbox canGate="update" :canResource="$application" instantSave id="isStripprefixEnabled"
label="Strip Prefixes"
helper="Strip Prefix is used to remove prefixes from paths. Like /api/ to /api." />
<x-forms.checkbox canGate="update" :canResource="$application" instantSave label="Exclude from service status"
helper="If you do not need to monitor this resource, enable. Useful if this service is optional."
id="application.exclude_from_status"></x-forms.checkbox>
id="excludeFromStatus"></x-forms.checkbox>
<x-forms.checkbox canGate="update" :canResource="$application"
helper="Drain logs to your configured log drain endpoint in your Server settings."
instantSave="instantSaveAdvanced" id="application.is_log_drain_enabled" label="Drain Logs" />
instantSave="instantSaveAdvanced" id="isLogDrainEnabled" label="Drain Logs" />
</div>
</form>
@@ -15,11 +15,11 @@
<div>Configuration</div>
</div>
<div class="flex gap-2">
<x-forms.input canGate="update" :canResource="$service" id="service.name" required label="Service Name" placeholder="My super WordPress site" />
<x-forms.input canGate="update" :canResource="$service" id="service.description" label="Description" />
<x-forms.input canGate="update" :canResource="$service" id="name" required label="Service Name" placeholder="My super WordPress site" />
<x-forms.input canGate="update" :canResource="$service" id="description" label="Description" />
</div>
<div class="w-96">
<x-forms.checkbox canGate="update" :canResource="$service" instantSave id="service.connect_to_docker_network" label="Connect To Predefined Network"
<x-forms.checkbox canGate="update" :canResource="$service" instantSave id="connectToDockerNetwork" label="Connect To Predefined Network"
helper="By default, you do not reach the Coolify defined networks.<br>Starting a docker compose based resource will have an internal network. <br>If you connect to a Coolify defined network, you maybe need to use different internal DNS names to connect to a resource.<br><br>For more information, check <a class='underline dark:text-white' target='_blank' href='https://coolify.io/docs/knowledge-base/docker/compose#connect-to-predefined-networks'>this</a>." />
</div>
@if ($fields->count() > 0)
@@ -2,7 +2,7 @@
<div class="flex items-center gap-2">
<h2>Healthchecks</h2>
<x-forms.button canGate="update" :canResource="$resource" type="submit">Save</x-forms.button>
@if (!$resource->health_check_enabled)
@if (!$healthCheckEnabled)
<x-modal-confirmation title="Confirm Healthcheck Enable?" buttonTitle="Enable Healthcheck"
submitAction="toggleHealthcheck" :actions="['Enable healthcheck for this resource.']"
warningMessage="If the health check fails, your application will become inaccessible. Please review the <a href='https://coolify.io/docs/knowledge-base/health-checks' target='_blank' class='underline text-white'>Health Checks</a> guide before proceeding!"
@@ -15,37 +15,37 @@
</div>
<div class="mt-1 pb-4">Define how your resource's health should be checked.</div>
<div class="flex flex-col gap-4">
@if ($resource->custom_healthcheck_found)
@if ($customHealthcheckFound)
<x-callout type="warning" title="Caution">
<p>A custom health check has been detected. If you enable this health check, it will disable the custom one and use this instead.</p>
</x-callout>
@endif
<div class="flex gap-2">
<x-forms.select canGate="update" :canResource="$resource" id="resource.health_check_method" label="Method" required>
<x-forms.select canGate="update" :canResource="$resource" id="healthCheckMethod" label="Method" required>
<option value="GET">GET</option>
<option value="POST">POST</option>
</x-forms.select>
<x-forms.select canGate="update" :canResource="$resource" id="resource.health_check_scheme" label="Scheme" required>
<x-forms.select canGate="update" :canResource="$resource" id="healthCheckScheme" label="Scheme" required>
<option value="http">http</option>
<option value="https">https</option>
</x-forms.select>
<x-forms.input canGate="update" :canResource="$resource" id="resource.health_check_host" placeholder="localhost" label="Host" required />
<x-forms.input canGate="update" :canResource="$resource" type="number" id="resource.health_check_port"
<x-forms.input canGate="update" :canResource="$resource" id="healthCheckHost" placeholder="localhost" label="Host" required />
<x-forms.input canGate="update" :canResource="$resource" type="number" id="healthCheckPort"
helper="If no port is defined, the first exposed port will be used." placeholder="80" label="Port" />
<x-forms.input canGate="update" :canResource="$resource" id="resource.health_check_path" placeholder="/health" label="Path" required />
<x-forms.input canGate="update" :canResource="$resource" id="healthCheckPath" placeholder="/health" label="Path" required />
</div>
<div class="flex gap-2">
<x-forms.input canGate="update" :canResource="$resource" type="number" id="resource.health_check_return_code" placeholder="200" label="Return Code"
<x-forms.input canGate="update" :canResource="$resource" type="number" id="healthCheckReturnCode" placeholder="200" label="Return Code"
required />
<x-forms.input canGate="update" :canResource="$resource" id="resource.health_check_response_text" placeholder="OK" label="Response Text" />
<x-forms.input canGate="update" :canResource="$resource" id="healthCheckResponseText" placeholder="OK" label="Response Text" />
</div>
<div class="flex gap-2">
<x-forms.input canGate="update" :canResource="$resource" min="1" type="number" id="resource.health_check_interval" placeholder="30"
<x-forms.input canGate="update" :canResource="$resource" min="1" type="number" id="healthCheckInterval" placeholder="30"
label="Interval (s)" required />
<x-forms.input canGate="update" :canResource="$resource" type="number" id="resource.health_check_timeout" placeholder="30" label="Timeout (s)"
<x-forms.input canGate="update" :canResource="$resource" type="number" id="healthCheckTimeout" placeholder="30" label="Timeout (s)"
required />
<x-forms.input canGate="update" :canResource="$resource" type="number" id="resource.health_check_retries" placeholder="3" label="Retries" required />
<x-forms.input canGate="update" :canResource="$resource" min=1 type="number" id="resource.health_check_start_period" placeholder="30"
<x-forms.input canGate="update" :canResource="$resource" type="number" id="healthCheckRetries" placeholder="3" label="Retries" required />
<x-forms.input canGate="update" :canResource="$resource" min=1 type="number" id="healthCheckStartPeriod" placeholder="30"
label="Start Period (s)" required />
</div>
</div>
@@ -9,32 +9,32 @@
<div class="flex gap-2">
<x-forms.input canGate="update" :canResource="$resource" placeholder="1.5"
helper="0 means use all CPUs. Floating point number, like 0.002 or 1.5. More info <a class='underline dark:text-white' target='_blank' href='https://docs.docker.com/engine/reference/run/#cpu-share-constraint'>here</a>."
label="Number of CPUs" id="resource.limits_cpus" />
label="Number of CPUs" id="limitsCpus" />
<x-forms.input canGate="update" :canResource="$resource" placeholder="0-2"
helper="Empty means, use all CPU sets. 0-2 will use CPU 0, CPU 1 and CPU 2. More info <a class='underline dark:text-white' target='_blank' href='https://docs.docker.com/engine/reference/run/#cpu-share-constraint'>here</a>."
label="CPU sets to use" id="resource.limits_cpuset" />
label="CPU sets to use" id="limitsCpuset" />
<x-forms.input canGate="update" :canResource="$resource" placeholder="1024"
helper="More info <a class='underline dark:text-white' target='_blank' href='https://docs.docker.com/engine/reference/run/#cpu-share-constraint'>here</a>."
label="CPU Weight" id="resource.limits_cpu_shares" />
label="CPU Weight" id="limitsCpuShares" />
</div>
<h3 class="pt-4">Limit Memory</h3>
<div class="flex flex-col gap-2">
<div class="flex gap-2">
<x-forms.input canGate="update" :canResource="$resource"
helper="Examples: 69b (byte) or 420k (kilobyte) or 1337m (megabyte) or 1g (gigabyte).<br>More info <a class='underline dark:text-white' target='_blank' href='https://docs.docker.com/compose/compose-file/05-services/#mem_reservation'>here</a>."
label="Soft Memory Limit" id="resource.limits_memory_reservation" />
label="Soft Memory Limit" id="limitsMemoryReservation" />
<x-forms.input canGate="update" :canResource="$resource"
helper="0-100.<br>More info <a class='underline dark:text-white' target='_blank' href='https://docs.docker.com/compose/compose-file/05-services/#mem_swappiness'>here</a>."
type="number" min="0" max="100" label="Swappiness"
id="resource.limits_memory_swappiness" />
id="limitsMemorySwappiness" />
</div>
<div class="flex gap-2">
<x-forms.input canGate="update" :canResource="$resource"
helper="Examples: 69b (byte) or 420k (kilobyte) or 1337m (megabyte) or 1g (gigabyte).<br>More info <a class='underline dark:text-white' target='_blank' href='https://docs.docker.com/compose/compose-file/05-services/#mem_limit'>here</a>."
label="Maximum Memory Limit" id="resource.limits_memory" />
label="Maximum Memory Limit" id="limitsMemory" />
<x-forms.input canGate="update" :canResource="$resource"
helper="Examples:69b (byte) or 420k (kilobyte) or 1337m (megabyte) or 1g (gigabyte).<br>More info <a class='underline dark:text-white' target='_blank' href='https://docs.docker.com/compose/compose-file/05-services/#memswap_limit'>here</a>."
label="Maximum Swap Limit" id="resource.limits_memory_swap" />
label="Maximum Swap Limit" id="limitsMemorySwap" />
</div>
</div>
</form>
@@ -9,47 +9,47 @@
@if (
$storage->resource_type === 'App\Models\ServiceApplication' ||
$storage->resource_type === 'App\Models\ServiceDatabase')
<x-forms.input id="storage.name" label="Volume Name" required readonly
<x-forms.input id="name" label="Volume Name" required readonly
helper="Warning: Changing the volume name after the initial start could cause problems. Only use it when you know what are you doing." />
@else
<x-forms.input id="storage.name" label="Volume Name" required readonly
<x-forms.input id="name" label="Volume Name" required readonly
helper="Warning: Changing the volume name after the initial start could cause problems. Only use it when you know what are you doing." />
@endif
@if ($isService || $startedAt)
<x-forms.input id="storage.host_path" readonly helper="Directory on the host system."
<x-forms.input id="hostPath" readonly helper="Directory on the host system."
label="Source Path"
helper="Warning: Changing the source path after the initial start could cause problems. Only use it when you know what are you doing." />
<x-forms.input id="storage.mount_path" label="Destination Path"
<x-forms.input id="mountPath" label="Destination Path"
helper="Directory inside the container." required readonly />
@else
<x-forms.input id="storage.host_path" readonly helper="Directory on the host system."
<x-forms.input id="hostPath" readonly helper="Directory on the host system."
label="Source Path"
helper="Warning: Changing the source path after the initial start could cause problems. Only use it when you know what are you doing." />
<x-forms.input id="storage.mount_path" label="Destination Path"
<x-forms.input id="mountPath" label="Destination Path"
helper="Directory inside the container." required readonly />
@endif
</div>
@else
<div class="flex gap-2 items-end w-full">
<x-forms.input id="storage.name" required readonly />
<x-forms.input id="storage.host_path" readonly />
<x-forms.input id="storage.mount_path" required readonly />
<x-forms.input id="name" required readonly />
<x-forms.input id="hostPath" readonly />
<x-forms.input id="mountPath" required readonly />
</div>
@endif
@else
@can('update', $resource)
@if ($isFirst)
<div class="flex gap-2 items-end w-full">
<x-forms.input id="storage.name" label="Volume Name" required />
<x-forms.input id="storage.host_path" helper="Directory on the host system." label="Source Path" />
<x-forms.input id="storage.mount_path" label="Destination Path"
<x-forms.input id="name" label="Volume Name" required />
<x-forms.input id="hostPath" helper="Directory on the host system." label="Source Path" />
<x-forms.input id="mountPath" label="Destination Path"
helper="Directory inside the container." required />
</div>
@else
<div class="flex gap-2 items-end w-full">
<x-forms.input id="storage.name" required />
<x-forms.input id="storage.host_path" />
<x-forms.input id="storage.mount_path" required />
<x-forms.input id="name" required />
<x-forms.input id="hostPath" />
<x-forms.input id="mountPath" required />
</div>
@endif
<div class="flex gap-2">
@@ -67,17 +67,17 @@
@else
@if ($isFirst)
<div class="flex gap-2 items-end w-full">
<x-forms.input id="storage.name" label="Volume Name" required disabled />
<x-forms.input id="storage.host_path" helper="Directory on the host system." label="Source Path"
<x-forms.input id="name" label="Volume Name" required disabled />
<x-forms.input id="hostPath" helper="Directory on the host system." label="Source Path"
disabled />
<x-forms.input id="storage.mount_path" label="Destination Path"
<x-forms.input id="mountPath" label="Destination Path"
helper="Directory inside the container." required disabled />
</div>
@else
<div class="flex gap-2 items-end w-full">
<x-forms.input id="storage.name" required disabled />
<x-forms.input id="storage.host_path" disabled />
<x-forms.input id="storage.mount_path" required disabled />
<x-forms.input id="name" required disabled />
<x-forms.input id="hostPath" disabled />
<x-forms.input id="mountPath" required disabled />
</div>
@endif
@endcan