v4.0.0-beta.416 (#5729)
* feat(README): add InterviewPal sponsorship link and corresponding SVG icon
* chore(versions): update coolify version to 4.0.0-beta.413 and nightly version to 4.0.0-beta.414 in configuration files
* fix(terminal): enhance WebSocket client verification with authorized IPs in terminal server
* chore(versions): update realtime version to 1.0.8 in versions.json
* chore(versions): update realtime version to 1.0.8 in versions.json
* chore(docker): update soketi image version to 1.0.8 in production configuration files
* chore(versions): update coolify version to 4.0.0-beta.414 and nightly version to 4.0.0-beta.415 in configuration files
* fix(ApplicationDeploymentJob): ensure source is an object before checking GitHub app properties
* fix(ui): Disable livewire navigate feature (causing spam of setInterval())
* fix(ui): Remove required attribute from image input in service application view
* fix(ui): Change application image validation to be nullable in service application view
* fix(Server): Correct proxy path formatting for Traefik proxy type
* chore(versions): update coolify version to 4.0.0-beta.416 and nightly version to 4.0.0-beta.417 in configuration files; fix links in deployment view
* feat(Service): Add functionality to convert between applications and databases in docker-compose based applications
fix(ui): Fix service layout refresh on compose change
* fix(service): graceful shutdown of old container (#5731)
* refactor(Database): streamline container shutdown process and reduce timeout duration
* fix(ServerCheck): enhance proxy container check to ensure it is running before proceeding
* chore(seeder): update git branch from 'main' to 'v4.x' for multiple examples in ApplicationSeeder
* fix(applications): include pull_request_id in deployment queue check to prevent duplicate deployments
* refactor(core): streamline container stopping process and reduce timeout duration; update related methods for consistency
* fix(database): update label for image input field to improve clarity
* feat(migration): add 'is_migrated' and 'custom_type' columns to service_applications and service_databases tables
* feat(backup): implement custom database type selection and enhance scheduled backups management
* fix(ServerCheck): set default proxy status to 'exited' to handle missing container state
* fix(database): reduce container stop timeout from 300 to 30 seconds for improved responsiveness
* refactor(database): update DB facade usage for consistency across service files
* Update app/Livewire/Project/Service/Database.php
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* refactor(database): enhance application conversion logic and add existence checks for databases and applications
* refactor(actions): standardize method naming for network and configuration deletion across application and service classes
* refactor(logdrain): consolidate log drain stopping logic to reduce redundancy
* refactor(StandaloneMariadb): add type hint for destination method to improve code clarity
* refactor(DeleteResourceJob): streamline resource deletion logic and improve conditional checks for database types
* refactor(jobs): update middleware to prevent job release after expiration for CleanupInstanceStuffsJob, RestartProxyJob, and ServerCheckJob
* fix(ui): system theming for charts (#5740)
* chore(deps-dev): bump vite from 6.2.6 to 6.3.4 (#5743)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.2.6 to 6.3.4.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v6.3.4/packages/vite)
---
updated-dependencies:
- dependency-name: vite
  dependency-version: 6.3.4
  dependency-type: direct:development
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* fix(dev): mount points?!
* fix(dev): proxy mount point
* fix(ui): allow adding scheduled backups for non-migrated databases
* fix(DatabaseBackupJob): escape PostgreSQL password in backup command (#5759)
* fix(ui): correct closing div tag in service index view
* Revert "fix(dev): mount points?!"
This reverts commit 365bf3cbf0.
---------
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Jérémy <jeremy.derdaele@gmail.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Best Codes <106822363+The-Best-Codes@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: busybox <29630035+busybox11@users.noreply.github.com>
			
			
This commit is contained in:
		| @@ -91,8 +91,7 @@ | ||||
|                                 <div x-data="{ expanded: false }"> | ||||
|                                     <div class="flex items-center gap-2"> | ||||
|                                         <span class="font-medium">Commit:</span> | ||||
|                                         <a .prevent | ||||
|                                             href="{{ $application->gitCommitLink(data_get($deployment, 'commit')) }}" | ||||
|                                         <a href="{{ $application->gitCommitLink(data_get($deployment, 'commit')) }}" | ||||
|                                             target="_blank" class="underline"> | ||||
|                                             {{ substr(data_get($deployment, 'commit'), 0, 7) }} | ||||
|                                         </a> | ||||
| @@ -117,8 +116,7 @@ | ||||
|                                         @endif | ||||
|                                         @if ($deployment->commitMessage()) | ||||
|                                             <span class="text-gray-600 dark:text-gray-400">-</span> | ||||
|                                             <a .prevent | ||||
|                                                 href="{{ $application->gitCommitLink(data_get($deployment, 'commit')) }}" | ||||
|                                             <a href="{{ $application->gitCommitLink(data_get($deployment, 'commit')) }}" | ||||
|                                                 target="_blank" | ||||
|                                                 class="text-gray-600 dark:text-gray-400 truncate max-w-md underline"> | ||||
|                                                 {{ Str::before($deployment->commitMessage(), "\n") }} | ||||
|   | ||||
| @@ -117,7 +117,8 @@ | ||||
|     @script | ||||
|         <script> | ||||
|             $wire.$on('stopEvent', () => { | ||||
|                 $wire.$dispatch('info', 'Stopping application.'); | ||||
|                 $wire.$dispatch('info', | ||||
|                     'Gracefully stopping application, it could take a while depending on the application.'); | ||||
|                 $wire.$call('stop'); | ||||
|             }); | ||||
|         </script> | ||||
|   | ||||
| @@ -1,33 +1,52 @@ | ||||
| <div> | ||||
|     <div class="flex flex-col gap-2"> | ||||
|         @forelse($database->scheduledBackups as $backup) | ||||
|             @if ($type == 'database') | ||||
|                 <a class="box" | ||||
|                     href="{{ route('project.database.backup.execution', [...$parameters, 'backup_uuid' => $backup->uuid]) }}"> | ||||
|                     <div class="flex flex-col"> | ||||
|                         <div>Frequency: {{ $backup->frequency }} | ||||
|                             ({{ data_get($backup->server(), 'settings.server_timezone', 'Instance timezone') }}) | ||||
|                         </div> | ||||
|                         <div>Last backup: {{ data_get($backup->latest_log, 'status', 'No backup yet') }}</div> | ||||
|         @if ($database->is_migrated && blank($database->custom_type)) | ||||
|             <div> | ||||
|                 <div>Select the type of | ||||
|                     database to enable automated backups.</div> | ||||
|                 <div class="pb-4"> If your database is not listed, automated backups are not supported.</div> | ||||
|                 <form wire:submit="setCustomType" class="flex gap-2 items-end"> | ||||
|                     <div class="w-96"> | ||||
|                         <x-forms.select label="Type" id="custom_type"> | ||||
|                             <option selected value="mysql">MySQL</option> | ||||
|                             <option value="mariadb">MariaDB</option> | ||||
|                             <option value="postgresql">PostgreSQL</option> | ||||
|                             <option value="mongodb">MongoDB</option> | ||||
|                         </x-forms.select> | ||||
|                     </div> | ||||
|                 </a> | ||||
|             @else | ||||
|                 <div class="box" wire:click="setSelectedBackup('{{ data_get($backup, 'id') }}')"> | ||||
|                     <div @class([ | ||||
|                         'border-coollabs' => | ||||
|                             data_get($backup, 'id') === data_get($selectedBackup, 'id'), | ||||
|                         'flex flex-col border-l-2 border-transparent', | ||||
|                     ])> | ||||
|                         <div>Frequency: {{ $backup->frequency }} | ||||
|                             ({{ data_get($backup->server(), 'settings.server_timezone', 'Instance timezone') }}) | ||||
|                     <x-forms.button type="submit">Set</x-forms.button> | ||||
|                 </form> | ||||
|             </div> | ||||
|         @else | ||||
|             @forelse($database->scheduledBackups as $backup) | ||||
|                 @if ($type == 'database') | ||||
|                     <a class="box" | ||||
|                         href="{{ route('project.database.backup.execution', [...$parameters, 'backup_uuid' => $backup->uuid]) }}"> | ||||
|                         <div class="flex flex-col"> | ||||
|                             <div>Frequency: {{ $backup->frequency }} | ||||
|                                 ({{ data_get($backup->server(), 'settings.server_timezone', 'Instance timezone') }}) | ||||
|                             </div> | ||||
|                             <div>Last backup: {{ data_get($backup->latest_log, 'status', 'No backup yet') }}</div> | ||||
|                         </div> | ||||
|                     </a> | ||||
|                 @else | ||||
|                     <div class="box" wire:click="setSelectedBackup('{{ data_get($backup, 'id') }}')"> | ||||
|                         <div @class([ | ||||
|                             'border-coollabs' => | ||||
|                                 data_get($backup, 'id') === data_get($selectedBackup, 'id'), | ||||
|                             'flex flex-col border-l-2 border-transparent', | ||||
|                         ])> | ||||
|                             <div>Frequency: {{ $backup->frequency }} | ||||
|                                 ({{ data_get($backup->server(), 'settings.server_timezone', 'Instance timezone') }}) | ||||
|                             </div> | ||||
|                             <div>Last backup: {{ data_get($backup->latest_log, 'status', 'No backup yet') }}</div> | ||||
|                         </div> | ||||
|                         <div>Last backup: {{ data_get($backup->latest_log, 'status', 'No backup yet') }}</div> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             @endif | ||||
|         @empty | ||||
|             <div>No scheduled backups configured.</div> | ||||
|         @endforelse | ||||
|                 @endif | ||||
|             @empty | ||||
|                 <div>No scheduled backups configured.</div> | ||||
|             @endforelse | ||||
|         @endif | ||||
|     </div> | ||||
|     @if ($type === 'service-database' && $selectedBackup) | ||||
|         <div class="pt-10"> | ||||
|   | ||||
| @@ -39,7 +39,7 @@ | ||||
|                 <div class="grid grid-cols-1 gap-2 pt-4 xl:grid-cols-1" wire:poll.10000ms="check_status"> | ||||
|                     @foreach ($applications as $application) | ||||
|                         <div @class([ | ||||
|                             'border-l border-dashed border-red-500 ' => str( | ||||
|                             'border-l border-dashed border-red-500' => str( | ||||
|                                 $application->status)->contains(['exited']), | ||||
|                             'border-l border-dashed border-success' => str( | ||||
|                                 $application->status)->contains(['running']), | ||||
| @@ -138,7 +138,7 @@ | ||||
|                                     <div class="text-xs">{{ $database->status }}</div> | ||||
|                                 </div> | ||||
|                                 <div class="flex items-center px-4"> | ||||
|                                     @if ($database->isBackupSolutionAvailable()) | ||||
|                                     @if ($database->isBackupSolutionAvailable() || $database->is_migrated) | ||||
|                                         <a class="mx-4 text-xs font-bold hover:underline" | ||||
|                                             href="{{ route('project.service.index', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'service_uuid' => $service->uuid, 'stack_service_uuid' => $database->uuid]) }}#backups"> | ||||
|                                             Backups | ||||
|   | ||||
| @@ -7,6 +7,11 @@ | ||||
|                 <h2>{{ Str::headline($database->name) }}</h2> | ||||
|             @endif | ||||
|             <x-forms.button type="submit">Save</x-forms.button> | ||||
|             <x-modal-confirmation wire:click="convertToApplication" title="Convert to Application" | ||||
|                 buttonTitle="Convert to Application" submitAction="convertToApplication" :actions="['The selected resource will be converted to an application.']" | ||||
|                 confirmationText="{{ Str::headline($database->name) }}" | ||||
|                 confirmationLabel="Please confirm the execution of the actions by entering the Service Database Name below" | ||||
|                 shortConfirmationLabel="Service Database Name" step3ButtonText="Permanently Delete" /> | ||||
|             <x-modal-confirmation title="Confirm Service Database Deletion?" buttonTitle="Delete" isErrorButton | ||||
|                 submitAction="delete" :actions="['The selected service database container will be stopped and permanently deleted.']" confirmationText="{{ Str::headline($database->name) }}" | ||||
|                 confirmationLabel="Please confirm the execution of the actions by entering the Service Database Name below" | ||||
| @@ -18,7 +23,7 @@ | ||||
|                 <x-forms.input label="Description" id="database.description"></x-forms.input> | ||||
|                 <x-forms.input 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 Tag" id="database.image"></x-forms.input> | ||||
|                     label="Image" id="database.image"></x-forms.input> | ||||
|             </div> | ||||
|             <div class="flex items-end gap-2"> | ||||
|                 <x-forms.input placeholder="5432" disabled="{{ $database->is_public }}" id="database.public_port" | ||||
|   | ||||
| @@ -10,7 +10,7 @@ | ||||
|             <a class="menu-item" :class="activeTab === 'general' && 'menu-item-active'" | ||||
|                 @click.prevent="activeTab = 'general'; window.location.hash = 'general'; if(window.location.search) window.location.search = ''" | ||||
|                 href="#">General</a> | ||||
|             @if ($serviceDatabase?->isBackupSolutionAvailable()) | ||||
|             @if ($serviceDatabase?->isBackupSolutionAvailable() || $serviceDatabase?->is_migrated) | ||||
|                 <a :class="activeTab === 'backups' && 'menu-item-active'" class="menu-item" | ||||
|                     @click.prevent="activeTab = 'backups'; window.location.hash = 'backups'" href="#backups">Backups</a> | ||||
|             @endif | ||||
| @@ -33,18 +33,20 @@ | ||||
|                 <div x-cloak x-show="activeTab === 'general'" class="h-full"> | ||||
|                     <livewire:project.service.database :database="$serviceDatabase" /> | ||||
|                 </div> | ||||
|                 @if ($serviceDatabase->isBackupSolutionAvailable()) | ||||
|                 @if ($serviceDatabase?->isBackupSolutionAvailable() || $serviceDatabase?->is_migrated) | ||||
|                     <div x-cloak x-show="activeTab === 'backups'"> | ||||
|                         <div class="flex gap-2 "> | ||||
|                             <h2 class="pb-4">Scheduled Backups</h2> | ||||
|                             <x-modal-input buttonTitle="+ Add" title="New Scheduled Backup"> | ||||
|                                 <livewire:project.database.create-scheduled-backup :database="$serviceDatabase" /> | ||||
|                             </x-modal-input> | ||||
|                             @if (filled($serviceDatabase->custom_type) || !$serviceDatabase->is_migrated) | ||||
|                                 <x-modal-input buttonTitle="+ Add" title="New Scheduled Backup"> | ||||
|                                     <livewire:project.database.create-scheduled-backup :database="$serviceDatabase" /> | ||||
|                                 </x-modal-input> | ||||
|                             @endif | ||||
|                         </div> | ||||
|                         <livewire:project.database.scheduled-backups :database="$serviceDatabase" /> | ||||
|                     </div> | ||||
|                 @endif | ||||
|             </div> | ||||
|         @endisset | ||||
|             @endisset | ||||
|         </div> | ||||
|     </div> | ||||
| </div> | ||||
| </div> | ||||
|   | ||||
| @@ -138,7 +138,7 @@ | ||||
|     @script | ||||
|         <script> | ||||
|             $wire.$on('stopEvent', () => { | ||||
|                 $wire.$dispatch('info', 'Stopping service.'); | ||||
|                 $wire.$dispatch('info', 'Gracefully stopping service, it could take a while depending on the service.'); | ||||
|                 $wire.$call('stop'); | ||||
|             }); | ||||
|             $wire.$on('startEvent', async () => { | ||||
|   | ||||
| @@ -7,11 +7,15 @@ | ||||
|                 <h2>{{ Str::headline($application->name) }}</h2> | ||||
|             @endif | ||||
|             <x-forms.button type="submit">Save</x-forms.button> | ||||
|             <x-modal-confirmation title="Confirm Service Application Deletion?" buttonTitle="Delete" isErrorButton | ||||
|                 submitAction="delete" {{-- :checkboxes="$checkboxes"  --}} :actions="['The selected service application container will be stopped and permanently deleted.']" | ||||
|             <x-modal-confirmation wire:click="convertToDatabase" title="Convert to Database" | ||||
|                 buttonTitle="Convert to Database" submitAction="convertToDatabase" :actions="['The selected resource will be converted to a service database.']" | ||||
|                 confirmationText="{{ Str::headline($application->name) }}" | ||||
|                 confirmationLabel="Please confirm the execution of the actions by entering the Service Application Name below" | ||||
|                 shortConfirmationLabel="Service Application Name" step3ButtonText="Permanently Delete" /> | ||||
|             <x-modal-confirmation title="Confirm Service Application Deletion?" buttonTitle="Delete" isErrorButton | ||||
|                 submitAction="delete" :actions="['The selected service application container will be stopped and permanently deleted.']" confirmationText="{{ Str::headline($application->name) }}" | ||||
|                 confirmationLabel="Please confirm the execution of the actions by entering the Service Application Name below" | ||||
|                 shortConfirmationLabel="Service Application Name" step3ButtonText="Permanently Delete" /> | ||||
|         </div> | ||||
|         <div class="flex flex-col gap-2"> | ||||
|             <div class="flex gap-2"> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Andras Bacsai
					Andras Bacsai