From 23ae0677eb4681cf8aad510ec1dffbc3c3146e07 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Wed, 15 Jan 2025 14:02:33 +0100 Subject: [PATCH 01/18] feat: move docker cleanup to its own tab --- app/Livewire/Server/Advanced.php | 40 -------- app/Livewire/Server/DockerCleanup.php | 99 +++++++++++++++++++ .../views/components/server/sidebar.blade.php | 3 + .../views/livewire/server/advanced.blade.php | 61 ------------ .../livewire/server/docker-cleanup.blade.php | 77 +++++++++++++++ routes/web.php | 2 + 6 files changed, 181 insertions(+), 101 deletions(-) create mode 100644 app/Livewire/Server/DockerCleanup.php create mode 100644 resources/views/livewire/server/docker-cleanup.blade.php diff --git a/app/Livewire/Server/Advanced.php b/app/Livewire/Server/Advanced.php index 577730f24..6d9d1010f 100644 --- a/app/Livewire/Server/Advanced.php +++ b/app/Livewire/Server/Advanced.php @@ -2,7 +2,6 @@ namespace App\Livewire\Server; -use App\Jobs\DockerCleanupJob; use App\Models\Server; use Livewire\Attributes\Validate; use Livewire\Component; @@ -19,21 +18,6 @@ class Advanced extends Component #[Validate(['integer', 'min:1', 'max:99'])] public int $serverDiskUsageNotificationThreshold = 50; - #[Validate(['string', 'required'])] - public string $dockerCleanupFrequency = '*/10 * * * *'; - - #[Validate(['integer', 'min:1', 'max:99'])] - public int $dockerCleanupThreshold = 10; - - #[Validate('boolean')] - public bool $forceDockerCleanup = false; - - #[Validate('boolean')] - public bool $deleteUnusedVolumes = false; - - #[Validate('boolean')] - public bool $deleteUnusedNetworks = false; - #[Validate(['integer', 'min:1'])] public int $concurrentBuilds = 1; @@ -57,23 +41,13 @@ class Advanced extends Component $this->validate(); $this->server->settings->concurrent_builds = $this->concurrentBuilds; $this->server->settings->dynamic_timeout = $this->dynamicTimeout; - $this->server->settings->force_docker_cleanup = $this->forceDockerCleanup; - $this->server->settings->docker_cleanup_frequency = $this->dockerCleanupFrequency; - $this->server->settings->docker_cleanup_threshold = $this->dockerCleanupThreshold; $this->server->settings->server_disk_usage_notification_threshold = $this->serverDiskUsageNotificationThreshold; - $this->server->settings->delete_unused_volumes = $this->deleteUnusedVolumes; - $this->server->settings->delete_unused_networks = $this->deleteUnusedNetworks; $this->server->settings->server_disk_usage_check_frequency = $this->serverDiskUsageCheckFrequency; $this->server->settings->save(); } else { $this->concurrentBuilds = $this->server->settings->concurrent_builds; $this->dynamicTimeout = $this->server->settings->dynamic_timeout; - $this->forceDockerCleanup = $this->server->settings->force_docker_cleanup; - $this->dockerCleanupFrequency = $this->server->settings->docker_cleanup_frequency; - $this->dockerCleanupThreshold = $this->server->settings->docker_cleanup_threshold; $this->serverDiskUsageNotificationThreshold = $this->server->settings->server_disk_usage_notification_threshold; - $this->deleteUnusedVolumes = $this->server->settings->delete_unused_volumes; - $this->deleteUnusedNetworks = $this->server->settings->delete_unused_networks; $this->serverDiskUsageCheckFrequency = $this->server->settings->server_disk_usage_check_frequency; } } @@ -88,23 +62,9 @@ class Advanced extends Component } } - public function manualCleanup() - { - try { - DockerCleanupJob::dispatch($this->server, true); - $this->dispatch('success', 'Manual cleanup job started. Depending on the amount of data, this might take a while.'); - } catch (\Throwable $e) { - return handleError($e, $this); - } - } - public function submit() { try { - if (! validate_cron_expression($this->dockerCleanupFrequency)) { - $this->dockerCleanupFrequency = $this->server->settings->getOriginal('docker_cleanup_frequency'); - throw new \Exception('Invalid Cron / Human expression for Docker Cleanup Frequency.'); - } if (! validate_cron_expression($this->serverDiskUsageCheckFrequency)) { $this->serverDiskUsageCheckFrequency = $this->server->settings->getOriginal('server_disk_usage_check_frequency'); throw new \Exception('Invalid Cron / Human expression for Disk Usage Check Frequency.'); diff --git a/app/Livewire/Server/DockerCleanup.php b/app/Livewire/Server/DockerCleanup.php new file mode 100644 index 000000000..8ece7ccc2 --- /dev/null +++ b/app/Livewire/Server/DockerCleanup.php @@ -0,0 +1,99 @@ +server = Server::ownedByCurrentTeam()->whereUuid($server_uuid)->firstOrFail(); + $this->parameters = get_route_parameters(); + $this->syncData(); + } catch (\Throwable) { + return redirect()->route('server.show'); + } + } + + public function syncData(bool $toModel = false) + { + if ($toModel) { + $this->validate(); + $this->server->settings->force_docker_cleanup = $this->forceDockerCleanup; + $this->server->settings->docker_cleanup_frequency = $this->dockerCleanupFrequency; + $this->server->settings->docker_cleanup_threshold = $this->dockerCleanupThreshold; + $this->server->settings->delete_unused_volumes = $this->deleteUnusedVolumes; + $this->server->settings->delete_unused_networks = $this->deleteUnusedNetworks; + $this->server->settings->save(); + } else { + $this->forceDockerCleanup = $this->server->settings->force_docker_cleanup; + $this->dockerCleanupFrequency = $this->server->settings->docker_cleanup_frequency; + $this->dockerCleanupThreshold = $this->server->settings->docker_cleanup_threshold; + $this->deleteUnusedVolumes = $this->server->settings->delete_unused_volumes; + $this->deleteUnusedNetworks = $this->server->settings->delete_unused_networks; + } + } + + public function instantSave() + { + try { + $this->syncData(true); + $this->dispatch('success', 'Server updated.'); + } catch (\Throwable $e) { + return handleError($e, $this); + } + } + + public function manualCleanup() + { + try { + DockerCleanupJob::dispatch($this->server, true); + $this->dispatch('success', 'Manual cleanup job started. Depending on the amount of data, this might take a while.'); + } catch (\Throwable $e) { + return handleError($e, $this); + } + } + + public function submit() + { + try { + if (! validate_cron_expression($this->dockerCleanupFrequency)) { + $this->dockerCleanupFrequency = $this->server->settings->getOriginal('docker_cleanup_frequency'); + throw new \Exception('Invalid Cron / Human expression for Docker Cleanup Frequency.'); + } + $this->syncData(true); + $this->dispatch('success', 'Server updated.'); + } catch (\Throwable $e) { + return handleError($e, $this); + } + } + + public function render() + { + return view('livewire.server.docker-cleanup'); + } +} diff --git a/resources/views/components/server/sidebar.blade.php b/resources/views/components/server/sidebar.blade.php index f86e0ef8c..e3ed98450 100644 --- a/resources/views/components/server/sidebar.blade.php +++ b/resources/views/components/server/sidebar.blade.php @@ -5,6 +5,9 @@ Advanced + Docker Cleanup + @endif Private Key diff --git a/resources/views/livewire/server/advanced.blade.php b/resources/views/livewire/server/advanced.blade.php index 40ff6c8b5..b6dcf0ea0 100644 --- a/resources/views/livewire/server/advanced.blade.php +++ b/resources/views/livewire/server/advanced.blade.php @@ -27,67 +27,6 @@ -
-
-

Docker Cleanup

- -
-
- - @if (!$forceDockerCleanup) - - @endif -
- -
- -
-

- Warning: Enable these - options only if you fully understand their implications and - consequences!
Improper use will result in data loss and could cause - functional issues. -

-
- - -
-
-

Builds

Customize the build process.
diff --git a/resources/views/livewire/server/docker-cleanup.blade.php b/resources/views/livewire/server/docker-cleanup.blade.php new file mode 100644 index 000000000..70bbb5db7 --- /dev/null +++ b/resources/views/livewire/server/docker-cleanup.blade.php @@ -0,0 +1,77 @@ +
+ + {{ data_get_str($server, 'name')->limit(10) }} > Docker Cleanup | Coolify + + +
+ +
+
+
+

Docker Cleanup

+
+
Configure Docker cleanup settings for your server.
+
+ +
+
+

Docker Cleanup

+ +
+
+ + @if (!$forceDockerCleanup) + + @endif +
+ +
+
+

+ Warning: Enable these + options only if you fully understand their implications and + consequences!
Improper use will result in data loss and could cause + functional issues. +

+
+ + +
+
+
+
+
\ No newline at end of file diff --git a/routes/web.php b/routes/web.php index ec4923941..618e4e090 100644 --- a/routes/web.php +++ b/routes/web.php @@ -42,6 +42,7 @@ use App\Livewire\Server\Charts as ServerCharts; use App\Livewire\Server\CloudflareTunnels; use App\Livewire\Server\Delete as DeleteServer; use App\Livewire\Server\Destinations as ServerDestinations; +use App\Livewire\Server\DockerCleanup; use App\Livewire\Server\Index as ServerIndex; use App\Livewire\Server\LogDrains; use App\Livewire\Server\PrivateKey\Show as PrivateKeyShow; @@ -256,6 +257,7 @@ Route::middleware(['auth', 'verified'])->group(function () { Route::get('/proxy/dynamic', ProxyDynamicConfigurations::class)->name('server.proxy.dynamic-confs'); Route::get('/proxy/logs', ProxyLogs::class)->name('server.proxy.logs'); Route::get('/terminal', ExecuteContainerCommand::class)->name('server.command'); + Route::get('/docker-cleanup', DockerCleanup::class)->name('server.docker-cleanup'); }); Route::get('/destinations', DestinationIndex::class)->name('destination.index'); Route::get('/destination/{destination_uuid}', DestinationShow::class)->name('destination.show'); From 52abc7cc925689995e21c680219c700b77204769 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Wed, 15 Jan 2025 17:11:15 +0100 Subject: [PATCH 02/18] feat: DB and Model for docker cleanup executions --- app/Models/DockerCleanupExecution.php | 15 +++++++++ ...create_docker_cleanup_executions_table.php | 32 +++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 app/Models/DockerCleanupExecution.php create mode 100644 database/migrations/2025_01_15_130416_create_docker_cleanup_executions_table.php diff --git a/app/Models/DockerCleanupExecution.php b/app/Models/DockerCleanupExecution.php new file mode 100644 index 000000000..405037e30 --- /dev/null +++ b/app/Models/DockerCleanupExecution.php @@ -0,0 +1,15 @@ +belongsTo(Server::class); + } +} diff --git a/database/migrations/2025_01_15_130416_create_docker_cleanup_executions_table.php b/database/migrations/2025_01_15_130416_create_docker_cleanup_executions_table.php new file mode 100644 index 000000000..800038ba6 --- /dev/null +++ b/database/migrations/2025_01_15_130416_create_docker_cleanup_executions_table.php @@ -0,0 +1,32 @@ +id(); + $table->string('uuid')->unique(); + $table->enum('status', ['success', 'failed', 'running'])->default('running'); + $table->text('message')->nullable(); + $table->text('cleanup_details')->nullable(); + $table->foreignId('server_id'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('docker_cleanup_executions'); + } +}; From 222af12ef020bd03986cb4ba998b8dbf4495e327 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Wed, 15 Jan 2025 17:14:05 +0100 Subject: [PATCH 03/18] feat: dockerCleanupExecutions relationship --- app/Models/Server.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/Models/Server.php b/app/Models/Server.php index 2867f95cb..f3edd82fb 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -199,6 +199,11 @@ class Server extends BaseModel return $this->hasOne(ServerSetting::class); } + public function dockerCleanupExecutions() + { + return $this->hasMany(DockerCleanupExecution::class); + } + public function proxySet() { return $this->proxyType() && $this->proxyType() !== 'NONE' && $this->isFunctional() && ! $this->isSwarmWorker() && ! $this->settings->is_build_server; From 25e6e376f9bc2e3d8619cb18aeae4a0df782d469 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Wed, 15 Jan 2025 17:19:32 +0100 Subject: [PATCH 04/18] feat: DockerCleanupDone event --- app/Events/DockerCleanupDone.php | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 app/Events/DockerCleanupDone.php diff --git a/app/Events/DockerCleanupDone.php b/app/Events/DockerCleanupDone.php new file mode 100644 index 000000000..2bd7fee19 --- /dev/null +++ b/app/Events/DockerCleanupDone.php @@ -0,0 +1,24 @@ +execution->server->team->id), + ]; + } +} From 85f38b7cb5fd083e08ce91e197c9999bda20d0f1 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Wed, 15 Jan 2025 18:35:20 +0100 Subject: [PATCH 05/18] refactor: improve data formatting and UI - move date and duration functions to a shared function - remove duplicate code - redesigned the deployment executions tab - added start and end times for backups, scheduled tasks, deployments and docker cleanup executions - calculated the duration for backups, scheduled tasks, deployments and Docker cleanup executions - redesigned status badges with colors to make it easier to see your current status - removed dependency on dayjs - fixed calculation of execution time was sometimes incorrect --- .../Project/Database/BackupExecutions.php | 23 --- .../Shared/ScheduledTask/Executions.php | 13 -- bootstrap/helpers/timezone.php | 42 +++++ .../application/deployment/index.blade.php | 155 +++++++----------- .../database/backup-executions.blade.php | 36 +++- .../scheduled-task/executions.blade.php | 38 +++-- 6 files changed, 154 insertions(+), 153 deletions(-) create mode 100644 bootstrap/helpers/timezone.php diff --git a/app/Livewire/Project/Database/BackupExecutions.php b/app/Livewire/Project/Database/BackupExecutions.php index 7eef1a539..3fc721fda 100644 --- a/app/Livewire/Project/Database/BackupExecutions.php +++ b/app/Livewire/Project/Database/BackupExecutions.php @@ -117,29 +117,6 @@ class BackupExecutions extends Component return null; } - public function getServerTimezone() - { - $server = $this->server(); - if (! $server) { - return 'UTC'; - } - - return $server->settings->server_timezone; - } - - public function formatDateInServerTimezone($date) - { - $serverTimezone = $this->getServerTimezone(); - $dateObj = new \DateTime($date); - try { - $dateObj->setTimezone(new \DateTimeZone($serverTimezone)); - } catch (\Exception) { - $dateObj->setTimezone(new \DateTimeZone('UTC')); - } - - return $dateObj->format('Y-m-d H:i:s T'); - } - public function render() { return view('livewire.project.database.backup-executions', [ diff --git a/app/Livewire/Project/Shared/ScheduledTask/Executions.php b/app/Livewire/Project/Shared/ScheduledTask/Executions.php index 74eac7132..6f62a5b5b 100644 --- a/app/Livewire/Project/Shared/ScheduledTask/Executions.php +++ b/app/Livewire/Project/Shared/ScheduledTask/Executions.php @@ -141,17 +141,4 @@ class Executions extends Component return $lines->count() > ($this->currentPage * $this->logsPerPage); } - - public function formatDateInServerTimezone($date) - { - $serverTimezone = $this->serverTimezone; - $dateObj = new \DateTime($date); - try { - $dateObj->setTimezone(new \DateTimeZone($serverTimezone)); - } catch (\Exception) { - $dateObj->setTimezone(new \DateTimeZone('UTC')); - } - - return $dateObj->format('Y-m-d H:i:s T'); - } } diff --git a/bootstrap/helpers/timezone.php b/bootstrap/helpers/timezone.php new file mode 100644 index 000000000..96d9ba6cf --- /dev/null +++ b/bootstrap/helpers/timezone.php @@ -0,0 +1,42 @@ +setTimezone(new \DateTimeZone($serverTimezone)); + } catch (\Exception) { + $dateObj->setTimezone(new \DateTimeZone('UTC')); + } + + return $dateObj->format('Y-m-d H:i:s T'); +} + +function calculateDuration($startDate, $endDate = null) +{ + if (! $endDate) { + return null; + } + + $start = new \DateTime($startDate); + $end = new \DateTime($endDate); + $interval = $start->diff($end); + + if ($interval->days > 0) { + return $interval->format('%dd %Hh %Im %Ss'); + } elseif ($interval->h > 0) { + return $interval->format('%Hh %Im %Ss'); + } else { + return $interval->format('%Im %Ss'); + } +} diff --git a/resources/views/livewire/project/application/deployment/index.blade.php b/resources/views/livewire/project/application/deployment/index.blade.php index 3fa52b7f3..0555f90d7 100644 --- a/resources/views/livewire/project/application/deployment/index.blade.php +++ b/resources/views/livewire/project/application/deployment/index.blade.php @@ -32,135 +32,96 @@ @forelse ($deployments as $deployment)
- data_get($deployment, 'status') === 'in_progress' || - data_get($deployment, 'status') === 'cancelled-by-user', - 'border-error border-dashed ' => - data_get($deployment, 'status') === 'failed', + 'border-blue-500/50 border-dashed' => data_get($deployment, 'status') === 'in_progress', + 'border-purple-500/50 border-dashed' => data_get($deployment, 'status') === 'queued', + 'border-white border-dashed' => data_get($deployment, 'status') === 'cancelled-by-user', + 'border-error' => data_get($deployment, 'status') === 'failed', 'border-success' => data_get($deployment, 'status') === 'finished', ]) x-on:click.stop="goto('{{ $current_url . '/' . data_get($deployment, 'deployment_uuid') }}')">
-
- {{ $deployment->created_at }} UTC - > - {{ $deployment->status }} +
+ data_get($deployment, 'status') === 'in_progress', + 'bg-purple-100/80 text-purple-700 dark:bg-purple-500/20 dark:text-purple-300 dark:shadow-purple-900/5' => data_get($deployment, 'status') === 'queued', + 'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-200 dark:shadow-red-900/5' => data_get($deployment, 'status') === 'failed', + 'bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-200 dark:shadow-green-900/5' => data_get($deployment, 'status') === 'finished', + 'bg-gray-100 text-gray-700 dark:bg-gray-600/30 dark:text-gray-300 dark:shadow-gray-900/5' => data_get($deployment, 'status') === 'cancelled-by-user', + ])> + @php + $statusText = match(data_get($deployment, 'status')) { + 'finished' => 'Success', + 'in_progress' => 'In Progress', + 'cancelled-by-user' => 'Cancelled', + 'queued' => 'Queued', + default => ucfirst(data_get($deployment, 'status')) + }; + @endphp + {{ $statusText }} +
- @if (data_get($deployment, 'is_webhook') || data_get($deployment, 'pull_request_id')) -
- @if (data_get($deployment, 'is_webhook')) - Webhook - @endif - @if (data_get($deployment, 'pull_request_id')) - @if (data_get($deployment, 'is_webhook')) - | - @endif - Pull Request #{{ data_get($deployment, 'pull_request_id') }} + @if(data_get($deployment, 'status') !== 'queued') +
+ Started: {{ formatDateInServerTimezone(data_get($deployment, 'created_at'), data_get($application, 'destination.server')) }} + @if($deployment->status !== 'in_progress') +
Ended: {{ formatDateInServerTimezone(data_get($deployment, 'updated_at'), data_get($application, 'destination.server')) }} +
Duration: {{ calculateDuration(data_get($deployment, 'created_at'), data_get($deployment, 'updated_at')) }} + @else +
Running for: {{ calculateDuration(data_get($deployment, 'created_at'), now()) }} @endif +
+ @endif + +
+
@if (data_get($deployment, 'commit')) -
-
+ + Commit: @if ($deployment->commitMessage()) - ({{ data_get_str($deployment, 'commit')->limit(7) }} - - {{ $deployment->commitMessage() }}) + {{ data_get_str($deployment, 'commit')->limit(7) }} - {{ $deployment->commitMessage() }} @else {{ data_get_str($deployment, 'commit')->limit(7) }} @endif -
-
+ + @endif -
- @else -
- @if (data_get($deployment, 'rollback') === true) - Rollback - @else - @if (data_get($deployment, 'is_api')) + + @if (data_get($deployment, 'is_webhook')) + Webhook + @if (data_get($deployment, 'pull_request_id')) + | Pull Request #{{ data_get($deployment, 'pull_request_id') }} + @endif + @elseif (data_get($deployment, 'pull_request_id')) + Pull Request #{{ data_get($deployment, 'pull_request_id') }} + @elseif (data_get($deployment, 'rollback') === true) + Rollback + @elseif (data_get($deployment, 'is_api')) API @else Manual @endif - @endif - @if (data_get($deployment, 'commit')) -
-
- @if ($deployment->commitMessage()) - ({{ data_get_str($deployment, 'commit')->limit(7) }} - - {{ $deployment->commitMessage() }}) - @else - {{ data_get_str($deployment, 'commit')->limit(7) }} - @endif -
-
- @endif +
- @endif +
+ @if (data_get($deployment, 'server_name') && $application->additional_servers->count() > 0) -
+
Server: {{ data_get($deployment, 'server_name') }}
@endif
- -
-
- @if ($deployment->status !== 'in_progress') - Finished 0s ago in - 0s - @else - Running for 0s - @endif - -
-
@empty
No deployments found
@endforelse @if ($deployments_count > 0) - - - @endif
diff --git a/resources/views/livewire/project/database/backup-executions.blade.php b/resources/views/livewire/project/database/backup-executions.blade.php index 7f8350a3e..b42db371c 100644 --- a/resources/views/livewire/project/database/backup-executions.blade.php +++ b/resources/views/livewire/project/database/backup-executions.blade.php @@ -7,22 +7,40 @@
@forelse($executions as $execution)
data_get($execution, 'status') === 'success', - 'border-red-500' => data_get($execution, 'status') === 'failed', - 'border-yellow-500' => data_get($execution, 'status') === 'running', + 'flex flex-col border-l-2 transition-colors p-4 bg-white dark:bg-coolgray-100 text-black dark:text-white', + 'border-blue-500/50 border-dashed' => data_get($execution, 'status') === 'running', + 'border-error' => data_get($execution, 'status') === 'failed', + 'border-success' => data_get($execution, 'status') === 'success', ])> @if (data_get($execution, 'status') === 'running')
@endif -
Status: - {{ data_get($execution, 'status') }}
+
+ data_get($execution, 'status') === 'running', + 'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-200 dark:shadow-red-900/5' => data_get($execution, 'status') === 'failed', + 'bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-200 dark:shadow-green-900/5' => data_get($execution, 'status') === 'success', + ])> + @php + $statusText = match(data_get($execution, 'status')) { + 'success' => 'Success', + 'running' => 'In Progress', + 'failed' => 'Failed', + default => ucfirst(data_get($execution, 'status')) + }; + @endphp + {{ $statusText }} + +
- Started At: {{ $this->formatDateInServerTimezone(data_get($execution, 'created_at')) }} + Started: {{ formatDateInServerTimezone(data_get($execution, 'created_at'), $this->server()) }} + @if(data_get($execution, 'status') !== 'running') +
Ended: {{ formatDateInServerTimezone(data_get($execution, 'updated_at'), $this->server()) }} +
Duration: {{ calculateDuration(data_get($execution, 'created_at'), data_get($execution, 'updated_at')) }} + @endif
Database: {{ data_get($execution, 'database_name', 'N/A') }} diff --git a/resources/views/livewire/project/shared/scheduled-task/executions.blade.php b/resources/views/livewire/project/shared/scheduled-task/executions.blade.php index c1400f5ec..63cbfd748 100644 --- a/resources/views/livewire/project/shared/scheduled-task/executions.blade.php +++ b/resources/views/livewire/project/shared/scheduled-task/executions.blade.php @@ -14,25 +14,41 @@ }"> @forelse($executions as $execution) - data_get($execution, 'id') == $selectedKey, - 'border-green-500' => data_get($execution, 'status') === 'success', - 'border-red-500' => data_get($execution, 'status') === 'failed', - 'border-yellow-500' => data_get($execution, 'status') === 'running', + 'flex flex-col border-l-2 transition-colors p-4 cursor-pointer bg-white hover:bg-gray-100 dark:bg-coolgray-100 dark:hover:bg-coolgray-200 text-black dark:text-white', + 'bg-gray-200 dark:bg-coolgray-200' => data_get($execution, 'id') == $selectedKey, + 'border-blue-500/50 border-dashed' => data_get($execution, 'status') === 'running', + 'border-error' => data_get($execution, 'status') === 'failed', + 'border-success' => data_get($execution, 'status') === 'success', ])> - @if (data_get($execution, 'status') === 'running')
@endif -
Status: {{ data_get($execution, 'status') }} +
+ data_get($execution, 'status') === 'running', + 'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-200 dark:shadow-red-900/5' => data_get($execution, 'status') === 'failed', + 'bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-200 dark:shadow-green-900/5' => data_get($execution, 'status') === 'success', + ])> + @php + $statusText = match(data_get($execution, 'status')) { + 'success' => 'Success', + 'running' => 'In Progress', + 'failed' => 'Failed', + default => ucfirst(data_get($execution, 'status')) + }; + @endphp + {{ $statusText }} +
- Started At: {{ $this->formatDateInServerTimezone(data_get($execution, 'created_at', now())) }} + Started: {{ formatDateInServerTimezone(data_get($execution, 'created_at', now()), data_get($task, 'application.destination.server') ?? data_get($task, 'service.destination.server')) }} + @if(data_get($execution, 'status') !== 'running') +
Ended: {{ formatDateInServerTimezone(data_get($execution, 'updated_at'), data_get($task, 'application.destination.server') ?? data_get($task, 'service.destination.server')) }} +
Duration: {{ calculateDuration(data_get($execution, 'created_at'), data_get($execution, 'updated_at')) }} + @endif
@if (strlen($execution->message) > 0) From 7bdef134e6dac48983dbc64a8922a8d53da4810d Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Wed, 15 Jan 2025 19:54:58 +0100 Subject: [PATCH 06/18] feat: get command and output for logs from CleanupDocker --- app/Actions/Server/CleanupDocker.php | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/app/Actions/Server/CleanupDocker.php b/app/Actions/Server/CleanupDocker.php index 0349ead89..ba4c2311a 100644 --- a/app/Actions/Server/CleanupDocker.php +++ b/app/Actions/Server/CleanupDocker.php @@ -25,17 +25,25 @@ class CleanupDocker "docker images --filter before=$helperImageWithVersion --filter reference=$helperImage | grep $helperImage | awk '{print $3}' | xargs -r docker rmi -f", ]; - $serverSettings = $server->settings; - if ($serverSettings->delete_unused_volumes) { + if ($server->settings->delete_unused_volumes) { $commands[] = 'docker volume prune -af'; } - if ($serverSettings->delete_unused_networks) { + if ($server->settings->delete_unused_networks) { $commands[] = 'docker network prune -f'; } + $cleanupLog = []; foreach ($commands as $command) { - instant_remote_process([$command], $server, false); + $commandOutput = instant_remote_process([$command], $server, false); + if ($commandOutput !== null) { + $cleanupLog[] = [ + 'command' => $command, + 'output' => $commandOutput, + ]; + } } + + return $cleanupLog; } } From 4986485448b174fb957a22a530e9f9af17ccf3bc Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Wed, 15 Jan 2025 19:56:01 +0100 Subject: [PATCH 07/18] fix: use json as it is just better than string for huge amount of logs --- ...2025_01_15_130416_create_docker_cleanup_executions_table.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/database/migrations/2025_01_15_130416_create_docker_cleanup_executions_table.php b/database/migrations/2025_01_15_130416_create_docker_cleanup_executions_table.php index 800038ba6..1c24bfa3d 100644 --- a/database/migrations/2025_01_15_130416_create_docker_cleanup_executions_table.php +++ b/database/migrations/2025_01_15_130416_create_docker_cleanup_executions_table.php @@ -16,7 +16,7 @@ return new class extends Migration $table->string('uuid')->unique(); $table->enum('status', ['success', 'failed', 'running'])->default('running'); $table->text('message')->nullable(); - $table->text('cleanup_details')->nullable(); + $table->json('cleanup_log')->nullable(); $table->foreignId('server_id'); $table->timestamps(); }); From 684d3dd3126b9b240e2dc71dd53383badf6541da Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Wed, 15 Jan 2025 20:02:44 +0100 Subject: [PATCH 08/18] feat: new sidebar menu and order --- .../views/components/server/sidebar.blade.php | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/resources/views/components/server/sidebar.blade.php b/resources/views/components/server/sidebar.blade.php index e3ed98450..f1413b474 100644 --- a/resources/views/components/server/sidebar.blade.php +++ b/resources/views/components/server/sidebar.blade.php @@ -1,14 +1,6 @@
General - @if ($server->isFunctional()) - Advanced - - Docker Cleanup - - @endif Private Key @@ -18,9 +10,15 @@ Tunnels @endif @if ($server->isFunctional()) + Docker Cleanup + Destinations + Advanced + Log Drains From 65a262923735187e0c38f76c17c1f5c6b62adf8b Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Wed, 15 Jan 2025 20:11:40 +0100 Subject: [PATCH 09/18] feat: Docker cleanup executions UI --- .../Server/DockerCleanupExecutions.php | 132 ++++++++++++++++++ .../docker-cleanup-executions.blade.php | 127 +++++++++++++++++ .../livewire/server/docker-cleanup.blade.php | 5 + 3 files changed, 264 insertions(+) create mode 100644 app/Livewire/Server/DockerCleanupExecutions.php create mode 100644 resources/views/livewire/server/docker-cleanup-executions.blade.php diff --git a/app/Livewire/Server/DockerCleanupExecutions.php b/app/Livewire/Server/DockerCleanupExecutions.php new file mode 100644 index 000000000..56d613064 --- /dev/null +++ b/app/Livewire/Server/DockerCleanupExecutions.php @@ -0,0 +1,132 @@ +user()->currentTeam()->id; + + return [ + "echo-private:team.{$teamId},DockerCleanupDone" => 'refreshExecutions', + ]; + } + + public function mount(Server $server) + { + $this->server = $server; + $this->refreshExecutions(); + } + + public function refreshExecutions(): void + { + $this->executions = $this->server->dockerCleanupExecutions() + ->orderBy('created_at', 'desc') + ->take(20) + ->get(); + + if ($this->selectedKey) { + $this->selectedExecution = DockerCleanupExecution::find($this->selectedKey); + if ($this->selectedExecution && $this->selectedExecution->status !== 'running') { + $this->isPollingActive = false; + } + } + } + + public function selectExecution($key): void + { + if ($key == $this->selectedKey) { + $this->selectedKey = null; + $this->selectedExecution = null; + $this->currentPage = 1; + $this->isPollingActive = false; + + return; + } + $this->selectedKey = $key; + $this->selectedExecution = DockerCleanupExecution::find($key); + $this->currentPage = 1; + + if ($this->selectedExecution && $this->selectedExecution->status === 'running') { + $this->isPollingActive = true; + } + } + + public function polling() + { + if ($this->selectedExecution && $this->isPollingActive) { + $this->selectedExecution->refresh(); + if ($this->selectedExecution->status !== 'running') { + $this->isPollingActive = false; + } + } + $this->refreshExecutions(); + } + + public function loadMoreLogs() + { + $this->currentPage++; + } + + public function getLogLinesProperty() + { + if (! $this->selectedExecution) { + return collect(); + } + + if (! $this->selectedExecution->message) { + return collect(['Waiting for execution output...']); + } + + $lines = collect(explode("\n", $this->selectedExecution->message)); + + return $lines->take($this->currentPage * $this->logsPerPage); + } + + public function downloadLogs(int $executionId) + { + $execution = $this->executions->firstWhere('id', $executionId); + if (! $execution) { + return; + } + + return response()->streamDownload(function () use ($execution) { + echo $execution->message; + }, "docker-cleanup-{$execution->uuid}.log"); + } + + public function hasMoreLogs() + { + if (! $this->selectedExecution || ! $this->selectedExecution->message) { + return false; + } + $lines = collect(explode("\n", $this->selectedExecution->message)); + + return $lines->count() > ($this->currentPage * $this->logsPerPage); + } + + public function render() + { + return view('livewire.server.docker-cleanup-executions'); + } +} diff --git a/resources/views/livewire/server/docker-cleanup-executions.blade.php b/resources/views/livewire/server/docker-cleanup-executions.blade.php new file mode 100644 index 000000000..ea0aa7098 --- /dev/null +++ b/resources/views/livewire/server/docker-cleanup-executions.blade.php @@ -0,0 +1,127 @@ +
+ @forelse($executions as $execution) + data_get($execution, 'id') == $selectedKey, + 'border-blue-500/50 border-dashed' => data_get($execution, 'status') === 'running', + 'border-error' => data_get($execution, 'status') === 'failed', + 'border-success' => data_get($execution, 'status') === 'success', + ])> + @if (data_get($execution, 'status') === 'running') +
+ +
+ @endif +
+ data_get($execution, 'status') === 'running', + 'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-200 dark:shadow-red-900/5' => data_get($execution, 'status') === 'failed', + 'bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-200 dark:shadow-green-900/5' => data_get($execution, 'status') === 'success', + ])> + @php + $statusText = match(data_get($execution, 'status')) { + 'success' => 'Success', + 'running' => 'In Progress', + 'failed' => 'Failed', + default => ucfirst(data_get($execution, 'status')) + }; + @endphp + {{ $statusText }} + +
+
+ Started: {{ formatDateInServerTimezone(data_get($execution, 'created_at', now()), $server) }} + @if(data_get($execution, 'status') !== 'running') +
Ended: {{ formatDateInServerTimezone(data_get($execution, 'updated_at'), $server) }} +
Duration: {{ calculateDuration(data_get($execution, 'created_at'), data_get($execution, 'updated_at')) }} + @endif +
+
+ @if (strlen(data_get($execution, 'message', '')) > 0) +
+ + Download Logs + +
+ @endif + @if (data_get($execution, 'id') == $selectedKey) +
+
+ @if (data_get($execution, 'status') === 'running') +
+ Execution is running... + +
+ @endif + @if ($this->logLines->isNotEmpty()) +
+

Status Message:

+
+@foreach ($this->logLines as $line)
+{{ $line }}
+@endforeach
+
+
+ @if ($this->hasMoreLogs()) + + Load More + + @endif +
+
+ @else +
+
Status Message:
+
No output was recorded for this execution.
+
+ @endif + + @if (data_get($execution, 'cleanup_log')) +
+

Cleanup Log:

+ @foreach(json_decode(data_get($execution, 'cleanup_log'), true) as $result) +
+
+ + + + {{ data_get($result, 'command') }} +
+ @php + $output = data_get($result, 'output'); + $hasOutput = !empty(trim($output)); + @endphp +
+ @if($hasOutput) +
{{ $output }}
+ @else +

+ No output returned - command completed successfully +

+ @endif +
+
+ @endforeach +
+ @endif +
+
+ @endif + @empty +
No executions found.
+ @endforelse +
diff --git a/resources/views/livewire/server/docker-cleanup.blade.php b/resources/views/livewire/server/docker-cleanup.blade.php index 70bbb5db7..da3f8bcba 100644 --- a/resources/views/livewire/server/docker-cleanup.blade.php +++ b/resources/views/livewire/server/docker-cleanup.blade.php @@ -72,6 +72,11 @@ " />
+ +
+

Recent executions (click to check output)

+ +
\ No newline at end of file From 42f883cc5bf31cb26776be1b499b304af30d26b3 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Wed, 15 Jan 2025 20:31:44 +0100 Subject: [PATCH 10/18] feat: Add execution log to dockerCleanupJob --- app/Jobs/DockerCleanupJob.php | 66 ++++++++++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 8 deletions(-) diff --git a/app/Jobs/DockerCleanupJob.php b/app/Jobs/DockerCleanupJob.php index 103c137b9..30fe6c5bc 100644 --- a/app/Jobs/DockerCleanupJob.php +++ b/app/Jobs/DockerCleanupJob.php @@ -3,6 +3,8 @@ namespace App\Jobs; use App\Actions\Server\CleanupDocker; +use App\Events\DockerCleanupDone; +use App\Models\DockerCleanupExecution; use App\Models\Server; use App\Notifications\Server\DockerCleanupFailed; use App\Notifications\Server\DockerCleanupSuccess; @@ -24,6 +26,8 @@ class DockerCleanupJob implements ShouldBeEncrypted, ShouldQueue public ?string $usageBefore = null; + public ?DockerCleanupExecution $execution_log = null; + public function middleware(): array { return [(new WithoutOverlapping($this->server->uuid))->dontRelease()]; @@ -38,35 +42,81 @@ class DockerCleanupJob implements ShouldBeEncrypted, ShouldQueue return; } + $this->execution_log = DockerCleanupExecution::create([ + 'server_id' => $this->server->id, + ]); + $this->usageBefore = $this->server->getDiskUsage(); if ($this->manualCleanup || $this->server->settings->force_docker_cleanup) { - CleanupDocker::run(server: $this->server); + $cleanup_log = CleanupDocker::run(server: $this->server); $usageAfter = $this->server->getDiskUsage(); - $this->server->team?->notify(new DockerCleanupSuccess($this->server, ($this->manualCleanup ? 'Manual' : 'Forced').' Docker cleanup job executed successfully. Disk usage before: '.$this->usageBefore.'%, Disk usage after: '.$usageAfter.'%.')); + $message = ($this->manualCleanup ? 'Manual' : 'Forced').' Docker cleanup job executed successfully. Disk usage before: '.$this->usageBefore.'%, Disk usage after: '.$usageAfter.'%.'; + + $this->execution_log->update([ + 'status' => 'success', + 'message' => $message, + 'cleanup_log' => $cleanup_log, + ]); + + $this->server->team?->notify(new DockerCleanupSuccess($this->server, $message)); + event(new DockerCleanupDone($this->execution_log)); return; } if (str($this->usageBefore)->isEmpty() || $this->usageBefore === null || $this->usageBefore === 0) { - CleanupDocker::run(server: $this->server); - $this->server->team?->notify(new DockerCleanupSuccess($this->server, 'Docker cleanup job executed successfully, but no disk usage could be determined.')); + $cleanup_log = CleanupDocker::run(server: $this->server); + $message = 'Docker cleanup job executed successfully, but no disk usage could be determined.'; + + $this->execution_log->update([ + 'status' => 'success', + 'message' => $message, + 'cleanup_log' => $cleanup_log, + ]); + + $this->server->team?->notify(new DockerCleanupSuccess($this->server, $message)); + event(new DockerCleanupDone($this->execution_log)); } if ($this->usageBefore >= $this->server->settings->docker_cleanup_threshold) { - CleanupDocker::run(server: $this->server); + $cleanup_log = CleanupDocker::run(server: $this->server); $usageAfter = $this->server->getDiskUsage(); $diskSaved = $this->usageBefore - $usageAfter; if ($diskSaved > 0) { - $this->server->team?->notify(new DockerCleanupSuccess($this->server, 'Saved '.$diskSaved.'% disk space. Disk usage before: '.$this->usageBefore.'%, Disk usage after: '.$usageAfter.'%.')); + $message = 'Saved '.$diskSaved.'% disk space. Disk usage before: '.$this->usageBefore.'%, Disk usage after: '.$usageAfter.'%.'; } else { - $this->server->team?->notify(new DockerCleanupSuccess($this->server, 'Docker cleanup job executed successfully, but no disk space was saved. Disk usage before: '.$this->usageBefore.'%, Disk usage after: '.$usageAfter.'%.')); + $message = 'Docker cleanup job executed successfully, but no disk space was saved. Disk usage before: '.$this->usageBefore.'%, Disk usage after: '.$usageAfter.'%.'; } + + $this->execution_log->update([ + 'status' => 'success', + 'message' => $message, + 'cleanup_log' => $cleanup_log, + ]); + + $this->server->team?->notify(new DockerCleanupSuccess($this->server, $message)); + event(new DockerCleanupDone($this->execution_log)); } else { - $this->server->team?->notify(new DockerCleanupSuccess($this->server, 'No cleanup needed for '.$this->server->name)); + $message = 'No cleanup needed for '.$this->server->name; + + $this->execution_log->update([ + 'status' => 'success', + 'message' => $message, + ]); + + $this->server->team?->notify(new DockerCleanupSuccess($this->server, $message)); + event(new DockerCleanupDone($this->execution_log)); } } catch (\Throwable $e) { + if ($this->execution_log) { + $this->execution_log->update([ + 'status' => 'failed', + 'message' => $e->getMessage(), + ]); + event(new DockerCleanupDone($this->execution_log)); + } $this->server->team?->notify(new DockerCleanupFailed($this->server, 'Docker cleanup job failed with the following error: '.$e->getMessage())); throw $e; } From f5bc80b5808b53030ceb76c82933ccddeb97b264 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Thu, 16 Jan 2025 11:24:22 +0100 Subject: [PATCH 11/18] fix: use `wire:navigate` on server sidebar --- resources/views/components/server/sidebar.blade.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/resources/views/components/server/sidebar.blade.php b/resources/views/components/server/sidebar.blade.php index 93ec20785..092e306a5 100644 --- a/resources/views/components/server/sidebar.blade.php +++ b/resources/views/components/server/sidebar.blade.php @@ -1,7 +1,7 @@
General - Private Key @if (!$server->isLocalhost()) @@ -10,16 +10,16 @@ Tunnels @endif @if ($server->isFunctional()) - Docker Cleanup - Destinations - Advanced - Log Drains Date: Thu, 16 Jan 2025 14:42:33 +0100 Subject: [PATCH 12/18] chore: remove limit on commit message --- app/Jobs/ApplicationDeploymentJob.php | 2 +- app/Models/ApplicationDeploymentQueue.php | 2 +- ..._text_in_application_deployment_queues.php | 28 +++++++++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 database/migrations/2025_01_16_110406_change_commit_message_to_text_in_application_deployment_queues.php diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index 21b2b6d18..fd958ba3c 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -1497,7 +1497,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue ] ); if ($this->saved_outputs->get('commit_message')) { - $commit_message = str($this->saved_outputs->get('commit_message'))->limit(47); + $commit_message = str($this->saved_outputs->get('commit_message')); $this->application_deployment_queue->commit_message = $commit_message->value(); ApplicationDeploymentQueue::whereCommit($this->commit)->whereApplicationId($this->application->id)->update( ['commit_message' => $commit_message->value()] diff --git a/app/Models/ApplicationDeploymentQueue.php b/app/Models/ApplicationDeploymentQueue.php index 95c78d725..fd8f1cba2 100644 --- a/app/Models/ApplicationDeploymentQueue.php +++ b/app/Models/ApplicationDeploymentQueue.php @@ -81,7 +81,7 @@ class ApplicationDeploymentQueue extends Model return null; } - return str($this->commit_message)->trim()->limit(50)->value(); + return str($this->commit_message)->value(); } public function addLogEntry(string $message, string $type = 'stdout', bool $hidden = false) diff --git a/database/migrations/2025_01_16_110406_change_commit_message_to_text_in_application_deployment_queues.php b/database/migrations/2025_01_16_110406_change_commit_message_to_text_in_application_deployment_queues.php new file mode 100644 index 000000000..6c64bf38d --- /dev/null +++ b/database/migrations/2025_01_16_110406_change_commit_message_to_text_in_application_deployment_queues.php @@ -0,0 +1,28 @@ +text('commit_message')->nullable()->change(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('application_deployment_queues', function (Blueprint $table) { + $table->string('commit_message', 50)->nullable()->change(); + }); + } +}; From 1169a49373dddcb6409cffc29aad90c44203dec9 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Thu, 16 Jan 2025 14:48:41 +0100 Subject: [PATCH 13/18] chore: remove dayjs --- public/js/dayjs-plugin-relativeTime.js | 1 - public/js/dayjs-plugin-utc.js | 1 - public/js/dayjs.min.js | 1 - resources/views/layouts/base.blade.php | 3 --- 4 files changed, 6 deletions(-) delete mode 100644 public/js/dayjs-plugin-relativeTime.js delete mode 100644 public/js/dayjs-plugin-utc.js delete mode 100644 public/js/dayjs.min.js diff --git a/public/js/dayjs-plugin-relativeTime.js b/public/js/dayjs-plugin-relativeTime.js deleted file mode 100644 index 898eee6d0..000000000 --- a/public/js/dayjs-plugin-relativeTime.js +++ /dev/null @@ -1 +0,0 @@ -!function(r,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(r="undefined"!=typeof globalThis?globalThis:r||self).dayjs_plugin_relativeTime=e()}(this,(function(){"use strict";return function(r,e,t){r=r||{};var n=e.prototype,o={future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"};function i(r,e,t,o){return n.fromToBase(r,e,t,o)}t.en.relativeTime=o,n.fromToBase=function(e,n,i,d,u){for(var f,a,s,l=i.$locale().relativeTime||o,h=r.thresholds||[{l:"s",r:44,d:"second"},{l:"m",r:89},{l:"mm",r:44,d:"minute"},{l:"h",r:89},{l:"hh",r:21,d:"hour"},{l:"d",r:35},{l:"dd",r:25,d:"day"},{l:"M",r:45},{l:"MM",r:10,d:"month"},{l:"y",r:17},{l:"yy",d:"year"}],m=h.length,c=0;c0,p<=y.r||!y.r){p<=1&&c>0&&(y=h[c-1]);var v=l[y.l];u&&(p=u(""+p)),a="string"==typeof v?v.replace("%d",p):v(p,n,y.l,s);break}}if(n)return a;var M=s?l.future:l.past;return"function"==typeof M?M(a):M.replace("%s",a)},n.to=function(r,e){return i(r,e,this,!0)},n.from=function(r,e){return i(r,e,this)};var d=function(r){return r.$u?t.utc():t()};n.toNow=function(r){return this.to(d(this),r)},n.fromNow=function(r){return this.from(d(this),r)}}})); \ No newline at end of file diff --git a/public/js/dayjs-plugin-utc.js b/public/js/dayjs-plugin-utc.js deleted file mode 100644 index 608771e95..000000000 --- a/public/js/dayjs-plugin-utc.js +++ /dev/null @@ -1 +0,0 @@ -!function(t,i){"object"==typeof exports&&"undefined"!=typeof module?module.exports=i():"function"==typeof define&&define.amd?define(i):(t="undefined"!=typeof globalThis?globalThis:t||self).dayjs_plugin_utc=i()}(this,(function(){"use strict";var t="minute",i=/[+-]\d\d(?::?\d\d)?/g,e=/([+-]|\d\d)/g;return function(s,f,n){var u=f.prototype;n.utc=function(t){var i={date:t,utc:!0,args:arguments};return new f(i)},u.utc=function(i){var e=n(this.toDate(),{locale:this.$L,utc:!0});return i?e.add(this.utcOffset(),t):e},u.local=function(){return n(this.toDate(),{locale:this.$L,utc:!1})};var o=u.parse;u.parse=function(t){t.utc&&(this.$u=!0),this.$utils().u(t.$offset)||(this.$offset=t.$offset),o.call(this,t)};var r=u.init;u.init=function(){if(this.$u){var t=this.$d;this.$y=t.getUTCFullYear(),this.$M=t.getUTCMonth(),this.$D=t.getUTCDate(),this.$W=t.getUTCDay(),this.$H=t.getUTCHours(),this.$m=t.getUTCMinutes(),this.$s=t.getUTCSeconds(),this.$ms=t.getUTCMilliseconds()}else r.call(this)};var a=u.utcOffset;u.utcOffset=function(s,f){var n=this.$utils().u;if(n(s))return this.$u?0:n(this.$offset)?a.call(this):this.$offset;if("string"==typeof s&&(s=function(t){void 0===t&&(t="");var s=t.match(i);if(!s)return null;var f=(""+s[0]).match(e)||["-",0,0],n=f[0],u=60*+f[1]+ +f[2];return 0===u?0:"+"===n?u:-u}(s),null===s))return this;var u=Math.abs(s)<=16?60*s:s,o=this;if(f)return o.$offset=u,o.$u=0===s,o;if(0!==s){var r=this.$u?this.toDate().getTimezoneOffset():-1*this.utcOffset();(o=this.local().add(u+r,t)).$offset=u,o.$x.$localOffset=r}else o=this.utc();return o};var h=u.format;u.format=function(t){var i=t||(this.$u?"YYYY-MM-DDTHH:mm:ss[Z]":"");return h.call(this,i)},u.valueOf=function(){var t=this.$utils().u(this.$offset)?0:this.$offset+(this.$x.$localOffset||this.$d.getTimezoneOffset());return this.$d.valueOf()-6e4*t},u.isUTC=function(){return!!this.$u},u.toISOString=function(){return this.toDate().toISOString()},u.toString=function(){return this.toDate().toUTCString()};var l=u.toDate;u.toDate=function(t){return"s"===t&&this.$offset?n(this.format("YYYY-MM-DD HH:mm:ss:SSS")).toDate():l.call(this)};var c=u.diff;u.diff=function(t,i,e){if(t&&this.$u===t.$u)return c.call(this,t,i,e);var s=this.local(),f=n(t).local();return c.call(s,f,i,e)}}})); diff --git a/public/js/dayjs.min.js b/public/js/dayjs.min.js deleted file mode 100644 index 76f599020..000000000 --- a/public/js/dayjs.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).dayjs=e()}(this,(function(){"use strict";var t=1e3,e=6e4,n=36e5,r="millisecond",i="second",s="minute",u="hour",a="day",o="week",c="month",f="quarter",h="year",d="date",l="Invalid Date",$=/^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/,y=/\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,M={name:"en",weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),ordinal:function(t){var e=["th","st","nd","rd"],n=t%100;return"["+t+(e[(n-20)%10]||e[n]||e[0])+"]"}},m=function(t,e,n){var r=String(t);return!r||r.length>=e?t:""+Array(e+1-r.length).join(n)+t},v={s:m,z:function(t){var e=-t.utcOffset(),n=Math.abs(e),r=Math.floor(n/60),i=n%60;return(e<=0?"+":"-")+m(r,2,"0")+":"+m(i,2,"0")},m:function t(e,n){if(e.date()1)return t(u[0])}else{var a=e.name;D[a]=e,i=a}return!r&&i&&(g=i),i||!r&&g},O=function(t,e){if(S(t))return t.clone();var n="object"==typeof e?e:{};return n.date=t,n.args=arguments,new _(n)},b=v;b.l=w,b.i=S,b.w=function(t,e){return O(t,{locale:e.$L,utc:e.$u,x:e.$x,$offset:e.$offset})};var _=function(){function M(t){this.$L=w(t.locale,null,!0),this.parse(t),this.$x=this.$x||t.x||{},this[p]=!0}var m=M.prototype;return m.parse=function(t){this.$d=function(t){var e=t.date,n=t.utc;if(null===e)return new Date(NaN);if(b.u(e))return new Date;if(e instanceof Date)return new Date(e);if("string"==typeof e&&!/Z$/i.test(e)){var r=e.match($);if(r){var i=r[2]-1||0,s=(r[7]||"0").substring(0,3);return n?new Date(Date.UTC(r[1],i,r[3]||1,r[4]||0,r[5]||0,r[6]||0,s)):new Date(r[1],i,r[3]||1,r[4]||0,r[5]||0,r[6]||0,s)}}return new Date(e)}(t),this.init()},m.init=function(){var t=this.$d;this.$y=t.getFullYear(),this.$M=t.getMonth(),this.$D=t.getDate(),this.$W=t.getDay(),this.$H=t.getHours(),this.$m=t.getMinutes(),this.$s=t.getSeconds(),this.$ms=t.getMilliseconds()},m.$utils=function(){return b},m.isValid=function(){return!(this.$d.toString()===l)},m.isSame=function(t,e){var n=O(t);return this.startOf(e)<=n&&n<=this.endOf(e)},m.isAfter=function(t,e){return O(t) - - - @endauth @section('body') From 48b10de4f3cd09c5226ce2642650cbebd75e8d2b Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Thu, 16 Jan 2025 14:53:49 +0100 Subject: [PATCH 14/18] feat: improve deployment UI - show full commit message with an expand button - show only the first 7 characters of the commit hash, like on GitHub --- .../application/deployment/index.blade.php | 193 +++++++++++------- 1 file changed, 121 insertions(+), 72 deletions(-) diff --git a/resources/views/livewire/project/application/deployment/index.blade.php b/resources/views/livewire/project/application/deployment/index.blade.php index 444dfc2d4..cc097e99a 100644 --- a/resources/views/livewire/project/application/deployment/index.blade.php +++ b/resources/views/livewire/project/application/deployment/index.blade.php @@ -9,7 +9,7 @@ @if ($skip == 0) wire:poll.5000ms='reload_deployments' @endif>

Deployments ({{ $deployments_count }})

- @if ($deployments_count > 0 && $deployments_count > $default_take) + @if ($deployments_count > 0) data_get($deployment, 'status') === 'in_progress', 'border-purple-500/50 border-dashed' => data_get($deployment, 'status') === 'queued', 'border-white border-dashed' => data_get($deployment, 'status') === 'cancelled-by-user', 'border-error' => data_get($deployment, 'status') === 'failed', 'border-success' => data_get($deployment, 'status') === 'finished', - ]) wire:navigate - href="{{ $current_url . '/' . data_get($deployment, 'deployment_uuid') }}"> -
-
- data_get($deployment, 'status') === 'in_progress', - 'bg-purple-100/80 text-purple-700 dark:bg-purple-500/20 dark:text-purple-300 dark:shadow-purple-900/5' => data_get($deployment, 'status') === 'queued', - 'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-200 dark:shadow-red-900/5' => data_get($deployment, 'status') === 'failed', - 'bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-200 dark:shadow-green-900/5' => data_get($deployment, 'status') === 'finished', - 'bg-gray-100 text-gray-700 dark:bg-gray-600/30 dark:text-gray-300 dark:shadow-gray-900/5' => data_get($deployment, 'status') === 'cancelled-by-user', - ])> - @php - $statusText = match(data_get($deployment, 'status')) { - 'finished' => 'Success', - 'in_progress' => 'In Progress', - 'cancelled-by-user' => 'Cancelled', - 'queued' => 'Queued', - default => ucfirst(data_get($deployment, 'status')) - }; - @endphp - {{ $statusText }} - -
- @if(data_get($deployment, 'status') !== 'queued') -
- Started: {{ formatDateInServerTimezone(data_get($deployment, 'created_at'), data_get($application, 'destination.server')) }} - @if($deployment->status !== 'in_progress') -
Ended: {{ formatDateInServerTimezone(data_get($deployment, 'updated_at'), data_get($application, 'destination.server')) }} -
Duration: {{ calculateDuration(data_get($deployment, 'created_at'), data_get($deployment, 'updated_at')) }} - @else -
Running for: {{ calculateDuration(data_get($deployment, 'created_at'), now()) }} - @endif -
- @endif - -
-
- @if (data_get($deployment, 'commit')) - - Commit: - @if ($deployment->commitMessage()) - {{ data_get_str($deployment, 'commit')->limit(7) }} - {{ $deployment->commitMessage() }} - @else - {{ data_get_str($deployment, 'commit')->limit(7) }} - @endif - - - @endif - - @if (data_get($deployment, 'is_webhook')) - Webhook - @if (data_get($deployment, 'pull_request_id')) - | Pull Request #{{ data_get($deployment, 'pull_request_id') }} - @endif - @elseif (data_get($deployment, 'pull_request_id')) - Pull Request #{{ data_get($deployment, 'pull_request_id') }} - @elseif (data_get($deployment, 'rollback') === true) - Rollback - @elseif (data_get($deployment, 'is_api')) - API - @else - Manual - @endif + ])> + +
+
+ data_get($deployment, 'status') === 'in_progress', + 'bg-purple-100/80 text-purple-700 dark:bg-purple-500/20 dark:text-purple-300 dark:shadow-purple-900/5' => data_get($deployment, 'status') === 'queued', + 'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-200 dark:shadow-red-900/5' => data_get($deployment, 'status') === 'failed', + 'bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-200 dark:shadow-green-900/5' => data_get($deployment, 'status') === 'finished', + 'bg-gray-100 text-gray-700 dark:bg-gray-600/30 dark:text-gray-300 dark:shadow-gray-900/5' => data_get($deployment, 'status') === 'cancelled-by-user', + ])> + @php + $statusText = match(data_get($deployment, 'status')) { + 'finished' => 'Success', + 'in_progress' => 'In Progress', + 'cancelled-by-user' => 'Cancelled', + 'queued' => 'Queued', + default => ucfirst(data_get($deployment, 'status')) + }; + @endphp + {{ $statusText }}
-
+ @if(data_get($deployment, 'status') !== 'queued') +
+ Started: {{ formatDateInServerTimezone(data_get($deployment, 'created_at'), data_get($application, 'destination.server')) }} + @if($deployment->status !== 'in_progress') +
Ended: {{ formatDateInServerTimezone(data_get($deployment, 'updated_at'), data_get($application, 'destination.server')) }} +
Duration: {{ calculateDuration(data_get($deployment, 'created_at'), data_get($deployment, 'updated_at')) }} + @else +
Running for: {{ calculateDuration(data_get($deployment, 'created_at'), now()) }} + @endif +
+ @endif - @if (data_get($deployment, 'server_name') && $application->additional_servers->count() > 0)
- Server: {{ data_get($deployment, 'server_name') }} +
+ @if (data_get($deployment, 'commit')) +
+
+ Commit: + + {{ substr(data_get($deployment, 'commit'), 0, 7) }} + + @if (!$deployment->commitMessage()) + + @if (data_get($deployment, 'is_webhook')) + Webhook + @if (data_get($deployment, 'pull_request_id')) + | Pull Request #{{ data_get($deployment, 'pull_request_id') }} + @endif + @elseif (data_get($deployment, 'pull_request_id')) + Pull Request #{{ data_get($deployment, 'pull_request_id') }} + @elseif (data_get($deployment, 'rollback') === true) + Rollback + @elseif (data_get($deployment, 'is_api')) + API + @else + Manual + @endif + + @endif + @if ($deployment->commitMessage()) + - + + {{ Str::before($deployment->commitMessage(), "\n") }} + + + + @if (data_get($deployment, 'is_webhook')) + Webhook + @if (data_get($deployment, 'pull_request_id')) + | Pull Request #{{ data_get($deployment, 'pull_request_id') }} + @endif + @elseif (data_get($deployment, 'pull_request_id')) + Pull Request #{{ data_get($deployment, 'pull_request_id') }} + @elseif (data_get($deployment, 'rollback') === true) + Rollback + @elseif (data_get($deployment, 'is_api')) + API + @else + Manual + @endif + + @endif +
+ @if ($deployment->commitMessage()) +
+ {{ Str::after($deployment->commitMessage(), "\n") }} +
+ @endif +
+ @endif +
- @endif -
+ + @if (data_get($deployment, 'server_name') && $application->additional_servers->count() > 0) +
+ Server: {{ data_get($deployment, 'server_name') }} +
+ @endif +
+
@empty
No deployments found
From 30f36f96db35609f1bcb9e81657ad7573cc8dd10 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Thu, 16 Jan 2025 15:12:57 +0100 Subject: [PATCH 15/18] fix: use finished_at for the end time instead of created_at --- app/Jobs/ApplicationDeploymentJob.php | 2 +- app/Jobs/DatabaseBackupJob.php | 5 +++ app/Jobs/DockerCleanupJob.php | 7 ++++ app/Jobs/ScheduledTaskJob.php | 6 +++ ...create_docker_cleanup_executions_table.php | 1 + ...30238_add_deployment_queue_finished_at.php | 22 ----------- ...8_add_finished_at_to_executions_tables.php | 38 +++++++++++++++++++ .../application/deployment/index.blade.php | 4 +- .../database/backup-executions.blade.php | 4 +- .../scheduled-task/executions.blade.php | 4 +- .../docker-cleanup-executions.blade.php | 4 +- 11 files changed, 66 insertions(+), 31 deletions(-) delete mode 100644 database/migrations/2025_01_16_130238_add_deployment_queue_finished_at.php create mode 100644 database/migrations/2025_01_16_130238_add_finished_at_to_executions_tables.php diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index e518d43e7..143ff6d1e 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -317,7 +317,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue throw $e; } finally { $this->application_deployment_queue->update([ - 'finished_at' => now(), + 'finished_at' => Carbon::now()->toImmutable(), ]); if ($this->use_build_server) { diff --git a/app/Jobs/DatabaseBackupJob.php b/app/Jobs/DatabaseBackupJob.php index 577c1f11a..0861c6bcc 100644 --- a/app/Jobs/DatabaseBackupJob.php +++ b/app/Jobs/DatabaseBackupJob.php @@ -331,6 +331,11 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue if ($this->team) { BackupCreated::dispatch($this->team->id); } + if ($this->backup_log) { + $this->backup_log->update([ + 'finished_at' => Carbon::now()->toImmutable(), + ]); + } } } diff --git a/app/Jobs/DockerCleanupJob.php b/app/Jobs/DockerCleanupJob.php index 30fe6c5bc..05a4aa8de 100644 --- a/app/Jobs/DockerCleanupJob.php +++ b/app/Jobs/DockerCleanupJob.php @@ -8,6 +8,7 @@ use App\Models\DockerCleanupExecution; use App\Models\Server; use App\Notifications\Server\DockerCleanupFailed; use App\Notifications\Server\DockerCleanupSuccess; +use Carbon\Carbon; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldBeEncrypted; use Illuminate\Contracts\Queue\ShouldQueue; @@ -119,6 +120,12 @@ class DockerCleanupJob implements ShouldBeEncrypted, ShouldQueue } $this->server->team?->notify(new DockerCleanupFailed($this->server, 'Docker cleanup job failed with the following error: '.$e->getMessage())); throw $e; + } finally { + if ($this->execution_log) { + $this->execution_log->update([ + 'finished_at' => Carbon::now()->toImmutable(), + ]); + } } } } diff --git a/app/Jobs/ScheduledTaskJob.php b/app/Jobs/ScheduledTaskJob.php index 90a10f3e9..6c0c017e7 100644 --- a/app/Jobs/ScheduledTaskJob.php +++ b/app/Jobs/ScheduledTaskJob.php @@ -11,6 +11,7 @@ use App\Models\Service; use App\Models\Team; use App\Notifications\ScheduledTask\TaskFailed; use App\Notifications\ScheduledTask\TaskSuccess; +use Carbon\Carbon; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; @@ -131,6 +132,11 @@ class ScheduledTaskJob implements ShouldQueue throw $e; } finally { ScheduledTaskDone::dispatch($this->team->id); + if ($this->task_log) { + $this->task_log->update([ + 'finished_at' => Carbon::now()->toImmutable(), + ]); + } } } } diff --git a/database/migrations/2025_01_15_130416_create_docker_cleanup_executions_table.php b/database/migrations/2025_01_15_130416_create_docker_cleanup_executions_table.php index 1c24bfa3d..c96213125 100644 --- a/database/migrations/2025_01_15_130416_create_docker_cleanup_executions_table.php +++ b/database/migrations/2025_01_15_130416_create_docker_cleanup_executions_table.php @@ -19,6 +19,7 @@ return new class extends Migration $table->json('cleanup_log')->nullable(); $table->foreignId('server_id'); $table->timestamps(); + $table->timestamp('finished_at')->nullable(); }); } diff --git a/database/migrations/2025_01_16_130238_add_deployment_queue_finished_at.php b/database/migrations/2025_01_16_130238_add_deployment_queue_finished_at.php deleted file mode 100644 index 34b652ee0..000000000 --- a/database/migrations/2025_01_16_130238_add_deployment_queue_finished_at.php +++ /dev/null @@ -1,22 +0,0 @@ -timestamp('finished_at')->nullable(); - }); - } - - public function down() - { - Schema::table('application_deployment_queues', function (Blueprint $table) { - $table->dropColumn('finished_at'); - }); - } -}; diff --git a/database/migrations/2025_01_16_130238_add_finished_at_to_executions_tables.php b/database/migrations/2025_01_16_130238_add_finished_at_to_executions_tables.php new file mode 100644 index 000000000..0b78c8998 --- /dev/null +++ b/database/migrations/2025_01_16_130238_add_finished_at_to_executions_tables.php @@ -0,0 +1,38 @@ +timestamp('finished_at')->nullable(); + }); + Schema::table('scheduled_database_backup_executions', function (Blueprint $table) { + $table->timestamp('finished_at')->nullable(); + }); + + Schema::table('scheduled_task_executions', function (Blueprint $table) { + $table->timestamp('finished_at')->nullable(); + }); + + } + + public function down() + { + Schema::table('application_deployment_queues', function (Blueprint $table) { + $table->dropColumn('finished_at'); + }); + + Schema::table('scheduled_database_backup_executions', function (Blueprint $table) { + $table->dropColumn('finished_at'); + }); + + Schema::table('scheduled_task_executions', function (Blueprint $table) { + $table->dropColumn('finished_at'); + }); + } +}; diff --git a/resources/views/livewire/project/application/deployment/index.blade.php b/resources/views/livewire/project/application/deployment/index.blade.php index cc097e99a..37364ba12 100644 --- a/resources/views/livewire/project/application/deployment/index.blade.php +++ b/resources/views/livewire/project/application/deployment/index.blade.php @@ -66,8 +66,8 @@
Started: {{ formatDateInServerTimezone(data_get($deployment, 'created_at'), data_get($application, 'destination.server')) }} @if($deployment->status !== 'in_progress') -
Ended: {{ formatDateInServerTimezone(data_get($deployment, 'updated_at'), data_get($application, 'destination.server')) }} -
Duration: {{ calculateDuration(data_get($deployment, 'created_at'), data_get($deployment, 'updated_at')) }} +
Ended: {{ formatDateInServerTimezone(data_get($deployment, 'finished_at'), data_get($application, 'destination.server')) }} +
Duration: {{ calculateDuration(data_get($deployment, 'created_at'), data_get($deployment, 'finished_at')) }} @else
Running for: {{ calculateDuration(data_get($deployment, 'created_at'), now()) }} @endif diff --git a/resources/views/livewire/project/database/backup-executions.blade.php b/resources/views/livewire/project/database/backup-executions.blade.php index b42db371c..2f46a4657 100644 --- a/resources/views/livewire/project/database/backup-executions.blade.php +++ b/resources/views/livewire/project/database/backup-executions.blade.php @@ -38,8 +38,8 @@
Started: {{ formatDateInServerTimezone(data_get($execution, 'created_at'), $this->server()) }} @if(data_get($execution, 'status') !== 'running') -
Ended: {{ formatDateInServerTimezone(data_get($execution, 'updated_at'), $this->server()) }} -
Duration: {{ calculateDuration(data_get($execution, 'created_at'), data_get($execution, 'updated_at')) }} +
Ended: {{ formatDateInServerTimezone(data_get($execution, 'finished_at'), $this->server()) }} +
Duration: {{ calculateDuration(data_get($execution, 'created_at'), data_get($execution, 'finished_at')) }} @endif
diff --git a/resources/views/livewire/project/shared/scheduled-task/executions.blade.php b/resources/views/livewire/project/shared/scheduled-task/executions.blade.php index 63cbfd748..63be05a2d 100644 --- a/resources/views/livewire/project/shared/scheduled-task/executions.blade.php +++ b/resources/views/livewire/project/shared/scheduled-task/executions.blade.php @@ -46,8 +46,8 @@
Started: {{ formatDateInServerTimezone(data_get($execution, 'created_at', now()), data_get($task, 'application.destination.server') ?? data_get($task, 'service.destination.server')) }} @if(data_get($execution, 'status') !== 'running') -
Ended: {{ formatDateInServerTimezone(data_get($execution, 'updated_at'), data_get($task, 'application.destination.server') ?? data_get($task, 'service.destination.server')) }} -
Duration: {{ calculateDuration(data_get($execution, 'created_at'), data_get($execution, 'updated_at')) }} +
Ended: {{ formatDateInServerTimezone(data_get($execution, 'finished_at'), data_get($task, 'application.destination.server') ?? data_get($task, 'service.destination.server')) }} +
Duration: {{ calculateDuration(data_get($execution, 'created_at'), data_get($execution, 'finished_at')) }} @endif
diff --git a/resources/views/livewire/server/docker-cleanup-executions.blade.php b/resources/views/livewire/server/docker-cleanup-executions.blade.php index ea0aa7098..95460c62c 100644 --- a/resources/views/livewire/server/docker-cleanup-executions.blade.php +++ b/resources/views/livewire/server/docker-cleanup-executions.blade.php @@ -46,8 +46,8 @@
Started: {{ formatDateInServerTimezone(data_get($execution, 'created_at', now()), $server) }} @if(data_get($execution, 'status') !== 'running') -
Ended: {{ formatDateInServerTimezone(data_get($execution, 'updated_at'), $server) }} -
Duration: {{ calculateDuration(data_get($execution, 'created_at'), data_get($execution, 'updated_at')) }} +
Ended: {{ formatDateInServerTimezone(data_get($execution, 'finished_at'), $server) }} +
Duration: {{ calculateDuration(data_get($execution, 'created_at'), data_get($execution, 'finished_at')) }} @endif
From 794e5357c9b59865da94baa6e6adef1e0a067687 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Thu, 16 Jan 2025 15:39:53 +0100 Subject: [PATCH 16/18] chore: remove unused code and fix import --- app/Jobs/ApplicationDeploymentJob.php | 2 +- .../application/deployment/index.blade.php | 182 +++++++++--------- .../livewire/server/docker-cleanup.blade.php | 2 +- 3 files changed, 88 insertions(+), 98 deletions(-) diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index 143ff6d1e..37c73d10f 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -18,7 +18,7 @@ use App\Models\SwarmDocker; use App\Notifications\Application\DeploymentFailed; use App\Notifications\Application\DeploymentSuccess; use App\Traits\ExecuteRemoteCommand; -use Exception; +use Carbon\Carbon; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldBeEncrypted; use Illuminate\Contracts\Queue\ShouldQueue; diff --git a/resources/views/livewire/project/application/deployment/index.blade.php b/resources/views/livewire/project/application/deployment/index.blade.php index 37364ba12..143057280 100644 --- a/resources/views/livewire/project/application/deployment/index.blade.php +++ b/resources/views/livewire/project/application/deployment/index.blade.php @@ -1,25 +1,22 @@
- - {{ data_get_str($application, 'name')->limit(10) }} > Deployments | Coolify - + {{ data_get_str($application, 'name')->limit(10) }} > Deployments | Coolify

Deployments

-
+

Deployments ({{ $deployments_count }})

@if ($deployments_count > 0) - - - - - - + + + + + + + + + + @endif
@if ($deployments_count > 0) @@ -30,25 +27,23 @@ @endif @forelse ($deployments as $deployment)
data_get($deployment, 'status') === 'in_progress', 'border-purple-500/50 border-dashed' => data_get($deployment, 'status') === 'queued', 'border-white border-dashed' => data_get($deployment, 'status') === 'cancelled-by-user', 'border-error' => data_get($deployment, 'status') === 'failed', 'border-success' => data_get($deployment, 'status') === 'finished', ])> - -
+ +
data_get($deployment, 'status') === 'in_progress', - 'bg-purple-100/80 text-purple-700 dark:bg-purple-500/20 dark:text-purple-300 dark:shadow-purple-900/5' => data_get($deployment, 'status') === 'queued', - 'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-200 dark:shadow-red-900/5' => data_get($deployment, 'status') === 'failed', - 'bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-200 dark:shadow-green-900/5' => data_get($deployment, 'status') === 'finished', - 'bg-gray-100 text-gray-700 dark:bg-gray-600/30 dark:text-gray-300 dark:shadow-gray-900/5' => data_get($deployment, 'status') === 'cancelled-by-user', + 'px-3 py-1 rounded-md text-xs font-medium shadow-sm', + 'bg-blue-100/80 text-blue-700 dark:bg-blue-500/20 dark:text-blue-300' => data_get($deployment, 'status') === 'in_progress', + 'bg-purple-100/80 text-purple-700 dark:bg-purple-500/20 dark:text-purple-300' => data_get($deployment, 'status') === 'queued', + 'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-200' => data_get($deployment, 'status') === 'failed', + 'bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-200' => data_get($deployment, 'status') === 'finished', + 'bg-gray-100 text-gray-700 dark:bg-gray-600/30 dark:text-gray-300' => data_get($deployment, 'status') === 'cancelled-by-user', ])> @php $statusText = match(data_get($deployment, 'status')) { @@ -75,82 +70,77 @@ @endif
-
- @if (data_get($deployment, 'commit')) -
-
- Commit: + @if (data_get($deployment, 'commit')) +
+
+ Commit: + + {{ substr(data_get($deployment, 'commit'), 0, 7) }} + + @if (!$deployment->commitMessage()) + + @if (data_get($deployment, 'is_webhook')) + Webhook + @if (data_get($deployment, 'pull_request_id')) + | Pull Request #{{ data_get($deployment, 'pull_request_id') }} + @endif + @elseif (data_get($deployment, 'pull_request_id')) + Pull Request #{{ data_get($deployment, 'pull_request_id') }} + @elseif (data_get($deployment, 'rollback') === true) + Rollback + @elseif (data_get($deployment, 'is_api')) + API + @else + Manual + @endif + + @endif + @if ($deployment->commitMessage()) + - - {{ substr(data_get($deployment, 'commit'), 0, 7) }} + class="text-gray-600 dark:text-gray-400 truncate max-w-md underline"> + {{ Str::before($deployment->commitMessage(), "\n") }} - @if (!$deployment->commitMessage()) - - @if (data_get($deployment, 'is_webhook')) - Webhook - @if (data_get($deployment, 'pull_request_id')) - | Pull Request #{{ data_get($deployment, 'pull_request_id') }} - @endif - @elseif (data_get($deployment, 'pull_request_id')) - Pull Request #{{ data_get($deployment, 'pull_request_id') }} - @elseif (data_get($deployment, 'rollback') === true) - Rollback - @elseif (data_get($deployment, 'is_api')) - API - @else - Manual + + + @if (data_get($deployment, 'is_webhook')) + Webhook + @if (data_get($deployment, 'pull_request_id')) + | Pull Request #{{ data_get($deployment, 'pull_request_id') }} @endif - - @endif - @if ($deployment->commitMessage()) - - - - {{ Str::before($deployment->commitMessage(), "\n") }} - - - - @if (data_get($deployment, 'is_webhook')) - Webhook - @if (data_get($deployment, 'pull_request_id')) - | Pull Request #{{ data_get($deployment, 'pull_request_id') }} - @endif - @elseif (data_get($deployment, 'pull_request_id')) - Pull Request #{{ data_get($deployment, 'pull_request_id') }} - @elseif (data_get($deployment, 'rollback') === true) - Rollback - @elseif (data_get($deployment, 'is_api')) - API - @else - Manual - @endif - - @endif -
- @if ($deployment->commitMessage()) -
- {{ Str::after($deployment->commitMessage(), "\n") }} -
+ @elseif (data_get($deployment, 'pull_request_id')) + Pull Request #{{ data_get($deployment, 'pull_request_id') }} + @elseif (data_get($deployment, 'rollback') === true) + Rollback + @elseif (data_get($deployment, 'is_api')) + API + @else + Manual + @endif + @endif
- @endif -
+ @if ($deployment->commitMessage()) +
+ {{ Str::after($deployment->commitMessage(), "\n") }} +
+ @endif +
+ @endif
@if (data_get($deployment, 'server_name') && $application->additional_servers->count() > 0) @@ -162,7 +152,7 @@
@empty -
No deployments found
+
No deployments found
@endforelse
diff --git a/resources/views/livewire/server/docker-cleanup.blade.php b/resources/views/livewire/server/docker-cleanup.blade.php index da3f8bcba..cdf48c6aa 100644 --- a/resources/views/livewire/server/docker-cleanup.blade.php +++ b/resources/views/livewire/server/docker-cleanup.blade.php @@ -79,4 +79,4 @@
-
\ No newline at end of file +
From e0aeb35316e42242004fc64dc9d686e06d77f295 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Thu, 16 Jan 2025 15:43:48 +0100 Subject: [PATCH 17/18] fix: Cancelled deployments should not show end and duration time --- .../livewire/project/application/deployment/index.blade.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/views/livewire/project/application/deployment/index.blade.php b/resources/views/livewire/project/application/deployment/index.blade.php index 143057280..ec5cf0f98 100644 --- a/resources/views/livewire/project/application/deployment/index.blade.php +++ b/resources/views/livewire/project/application/deployment/index.blade.php @@ -60,10 +60,10 @@ @if(data_get($deployment, 'status') !== 'queued')
Started: {{ formatDateInServerTimezone(data_get($deployment, 'created_at'), data_get($application, 'destination.server')) }} - @if($deployment->status !== 'in_progress') + @if($deployment->status !== 'in_progress' && $deployment->status !== 'cancelled-by-user' && $deployment->status !== 'failed')
Ended: {{ formatDateInServerTimezone(data_get($deployment, 'finished_at'), data_get($application, 'destination.server')) }}
Duration: {{ calculateDuration(data_get($deployment, 'created_at'), data_get($deployment, 'finished_at')) }} - @else + @elseif($deployment->status === 'in_progress')
Running for: {{ calculateDuration(data_get($deployment, 'created_at'), now()) }} @endif
From a771993d97c666f02670fada19e5d1b4c1cd20b0 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 16 Jan 2025 21:35:48 +0100 Subject: [PATCH 18/18] fix: redirect to server index instead of show on error in Advanced and DockerCleanup components --- app/Livewire/Server/Advanced.php | 2 +- app/Livewire/Server/DockerCleanup.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Livewire/Server/Advanced.php b/app/Livewire/Server/Advanced.php index 6d9d1010f..b269c916f 100644 --- a/app/Livewire/Server/Advanced.php +++ b/app/Livewire/Server/Advanced.php @@ -31,7 +31,7 @@ class Advanced extends Component $this->parameters = get_route_parameters(); $this->syncData(); } catch (\Throwable) { - return redirect()->route('server.show'); + return redirect()->route('server.index'); } } diff --git a/app/Livewire/Server/DockerCleanup.php b/app/Livewire/Server/DockerCleanup.php index 8ece7ccc2..d3378d63f 100644 --- a/app/Livewire/Server/DockerCleanup.php +++ b/app/Livewire/Server/DockerCleanup.php @@ -35,7 +35,7 @@ class DockerCleanup extends Component $this->parameters = get_route_parameters(); $this->syncData(); } catch (\Throwable) { - return redirect()->route('server.show'); + return redirect()->route('server.index'); } }