From 4b119726d97eab2d5c25dc38871d40ccadfd1d58 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Tue, 2 Dec 2025 13:08:40 +0100 Subject: [PATCH 01/12] Fix Traefik email notification with clickable server links MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add URL generation to notification class using base_url() helper - Replace config('app.url') with proper base_url() for accurate instance URL - Make server names clickable links to proxy configuration page - Use data_get() with fallback values for safer template data access - Add comprehensive tests for URL generation and email rendering 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../Server/TraefikVersionOutdated.php | 12 ++- .../emails/traefik-version-outdated.blade.php | 30 ++++--- tests/Feature/CheckTraefikVersionJobTest.php | 87 +++++++++++++++++++ 3 files changed, 115 insertions(+), 14 deletions(-) diff --git a/app/Notifications/Server/TraefikVersionOutdated.php b/app/Notifications/Server/TraefikVersionOutdated.php index 09ef4257d..c94cc1732 100644 --- a/app/Notifications/Server/TraefikVersionOutdated.php +++ b/app/Notifications/Server/TraefikVersionOutdated.php @@ -43,9 +43,19 @@ public function toMail($notifiable = null): MailMessage $mail = new MailMessage; $count = $this->servers->count(); + // Transform servers to include URLs + $serversWithUrls = $this->servers->map(function ($server) { + return [ + 'name' => $server->name, + 'uuid' => $server->uuid, + 'url' => base_url().'/server/'.$server->uuid.'/proxy', + 'outdatedInfo' => $server->outdatedInfo ?? [], + ]; + }); + $mail->subject("Coolify: Traefik proxy outdated on {$count} server(s)"); $mail->view('emails.traefik-version-outdated', [ - 'servers' => $this->servers, + 'servers' => $serversWithUrls, 'count' => $count, ]); diff --git a/resources/views/emails/traefik-version-outdated.blade.php b/resources/views/emails/traefik-version-outdated.blade.php index 28effabf3..91c627a73 100644 --- a/resources/views/emails/traefik-version-outdated.blade.php +++ b/resources/views/emails/traefik-version-outdated.blade.php @@ -5,10 +5,12 @@ @foreach ($servers as $server) @php - $info = $server->outdatedInfo ?? []; - $current = $info['current'] ?? 'unknown'; - $latest = $info['latest'] ?? 'unknown'; - $isPatch = ($info['type'] ?? 'patch_update') === 'patch_update'; + $serverName = data_get($server, 'name', 'Unknown Server'); + $serverUrl = data_get($server, 'url', '#'); + $info = data_get($server, 'outdatedInfo', []); + $current = data_get($info, 'current', 'unknown'); + $latest = data_get($info, 'latest', 'unknown'); + $isPatch = (data_get($info, 'type', 'patch_update') === 'patch_update'); $hasNewerBranch = isset($info['newer_branch_target']); $hasUpgrades = $hasUpgrades ?? false; if (!$isPatch || $hasNewerBranch) { @@ -19,8 +21,9 @@ $latest = str_starts_with($latest, 'v') ? $latest : "v{$latest}"; // For minor upgrades, use the upgrade_target (e.g., "v3.6") - if (!$isPatch && isset($info['upgrade_target'])) { - $upgradeTarget = str_starts_with($info['upgrade_target'], 'v') ? $info['upgrade_target'] : "v{$info['upgrade_target']}"; + if (!$isPatch && data_get($info, 'upgrade_target')) { + $upgradeTarget = data_get($info, 'upgrade_target'); + $upgradeTarget = str_starts_with($upgradeTarget, 'v') ? $upgradeTarget : "v{$upgradeTarget}"; } else { // For patch updates, show the full version $upgradeTarget = $latest; @@ -28,22 +31,23 @@ // Get newer branch info if available if ($hasNewerBranch) { - $newerBranchTarget = $info['newer_branch_target']; - $newerBranchLatest = str_starts_with($info['newer_branch_latest'], 'v') ? $info['newer_branch_latest'] : "v{$info['newer_branch_latest']}"; + $newerBranchTarget = data_get($info, 'newer_branch_target', 'unknown'); + $newerBranchLatest = data_get($info, 'newer_branch_latest', 'unknown'); + $newerBranchLatest = str_starts_with($newerBranchLatest, 'v') ? $newerBranchLatest : "v{$newerBranchLatest}"; } @endphp @if ($isPatch && $hasNewerBranch) -- **{{ $server->name }}**: {{ $current }} → {{ $upgradeTarget }} (patch update available) | Also available: {{ $newerBranchTarget }} (latest patch: {{ $newerBranchLatest }}) - new minor version +- [**{{ $serverName }}**]({{ $serverUrl }}): {{ $current }} → {{ $upgradeTarget }} (patch update available) | Also available: {{ $newerBranchTarget }} (latest patch: {{ $newerBranchLatest }}) - new minor version @elseif ($isPatch) -- **{{ $server->name }}**: {{ $current }} → {{ $upgradeTarget }} (patch update available) +- [**{{ $serverName }}**]({{ $serverUrl }}): {{ $current }} → {{ $upgradeTarget }} (patch update available) @else -- **{{ $server->name }}**: {{ $current }} (latest patch: {{ $latest }}) → {{ $upgradeTarget }} (new minor version available) +- [**{{ $serverName }}**]({{ $serverUrl }}): {{ $current }} (latest patch: {{ $latest }}) → {{ $upgradeTarget }} (new minor version available) @endif @endforeach ## Recommendation -It is recommended to test the new Traefik version before switching it in production environments. You can update your proxy configuration through your [Coolify Dashboard]({{ config('app.url') }}). +It is recommended to test the new Traefik version before switching it in production environments. You can update your proxy configuration by clicking on any server name above. @if ($hasUpgrades ?? false) **Important for minor version upgrades:** Before upgrading to a new minor version, please read the [Traefik changelog](https://github.com/traefik/traefik/releases) to understand breaking changes and new features. @@ -58,5 +62,5 @@ --- -You can manage your server proxy settings in your Coolify Dashboard. +Click on any server name above to manage its proxy settings. diff --git a/tests/Feature/CheckTraefikVersionJobTest.php b/tests/Feature/CheckTraefikVersionJobTest.php index b7c5dd50d..cee156485 100644 --- a/tests/Feature/CheckTraefikVersionJobTest.php +++ b/tests/Feature/CheckTraefikVersionJobTest.php @@ -214,3 +214,90 @@ expect($notification->servers)->toHaveCount(1); expect($notification->servers->first()->outdatedInfo['type'])->toBe('patch_update'); }); + +it('notification generates correct server proxy URLs', function () { + $team = Team::factory()->create(); + $server = Server::factory()->create([ + 'name' => 'Test Server', + 'team_id' => $team->id, + 'uuid' => 'test-uuid-123', + ]); + + $server->outdatedInfo = [ + 'current' => '3.5.0', + 'latest' => '3.5.6', + 'type' => 'patch_update', + ]; + + $notification = new TraefikVersionOutdated(collect([$server])); + $mail = $notification->toMail($team); + + // Verify the mail has the transformed servers with URLs + expect($mail->viewData['servers'])->toHaveCount(1); + expect($mail->viewData['servers'][0]['name'])->toBe('Test Server'); + expect($mail->viewData['servers'][0]['uuid'])->toBe('test-uuid-123'); + expect($mail->viewData['servers'][0]['url'])->toBe(base_url().'/server/test-uuid-123/proxy'); + expect($mail->viewData['servers'][0]['outdatedInfo'])->toBeArray(); +}); + +it('notification transforms multiple servers with URLs correctly', function () { + $team = Team::factory()->create(); + $server1 = Server::factory()->create([ + 'name' => 'Server 1', + 'team_id' => $team->id, + 'uuid' => 'uuid-1', + ]); + $server1->outdatedInfo = [ + 'current' => '3.5.0', + 'latest' => '3.5.6', + 'type' => 'patch_update', + ]; + + $server2 = Server::factory()->create([ + 'name' => 'Server 2', + 'team_id' => $team->id, + 'uuid' => 'uuid-2', + ]); + $server2->outdatedInfo = [ + 'current' => '3.4.0', + 'latest' => '3.6.0', + 'type' => 'minor_upgrade', + 'upgrade_target' => 'v3.6', + ]; + + $servers = collect([$server1, $server2]); + $notification = new TraefikVersionOutdated($servers); + $mail = $notification->toMail($team); + + // Verify both servers have URLs + expect($mail->viewData['servers'])->toHaveCount(2); + + expect($mail->viewData['servers'][0]['name'])->toBe('Server 1'); + expect($mail->viewData['servers'][0]['url'])->toBe(base_url().'/server/uuid-1/proxy'); + + expect($mail->viewData['servers'][1]['name'])->toBe('Server 2'); + expect($mail->viewData['servers'][1]['url'])->toBe(base_url().'/server/uuid-2/proxy'); +}); + +it('notification uses base_url helper not config app.url', function () { + $team = Team::factory()->create(); + $server = Server::factory()->create([ + 'name' => 'Test Server', + 'team_id' => $team->id, + 'uuid' => 'test-uuid', + ]); + + $server->outdatedInfo = [ + 'current' => '3.5.0', + 'latest' => '3.5.6', + 'type' => 'patch_update', + ]; + + $notification = new TraefikVersionOutdated(collect([$server])); + $mail = $notification->toMail($team); + + // Verify URL starts with base_url() not config('app.url') + $generatedUrl = $mail->viewData['servers'][0]['url']; + expect($generatedUrl)->toStartWith(base_url()); + expect($generatedUrl)->not->toContain('localhost'); +}); From 33d16615306cad3cb75c19a4bf713fab680ae0b5 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Tue, 2 Dec 2025 13:11:15 +0100 Subject: [PATCH 02/12] Improve Advanced Settings helper texts for clarity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - API Access: Explain what REST API access enables and where to configure tokens - Registration Allowed: Simplify wording while keeping both states clear - Do Not Track: Clarify it only tracks instance count to coolify.io - DNS Validation: Explain the benefit (prevents deployment failures) - Custom DNS Servers: Add example format and note about system defaults - Sponsorship Popup: Make purpose and action clearer, less verbose These improvements provide users with meaningful, actionable information instead of redundant or vague descriptions. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- resources/views/livewire/settings/advanced.blade.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/resources/views/livewire/settings/advanced.blade.php b/resources/views/livewire/settings/advanced.blade.php index c47c2cfef..7d714a409 100644 --- a/resources/views/livewire/settings/advanced.blade.php +++ b/resources/views/livewire/settings/advanced.blade.php @@ -18,28 +18,28 @@ class="flex flex-col h-full gap-8 sm:flex-row">

DNS Settings

API Settings

+ helper="If enabled, authenticated requests to Coolify's REST API will be allowed. Configure API tokens in Security > API Tokens." />

Confirmation Settings

+ helper="Show monthly sponsorship reminders to support Coolify development. Disable to hide these messages permanently." />
From 0959eefe96ae9b3c7158d971b120bc609186b3c2 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Tue, 2 Dec 2025 15:11:07 +0100 Subject: [PATCH 03/12] Add Simple View toggle for logs with localStorage persistence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Users can now switch between the enhanced color-coded log view and the original simple raw text view using a new toggle checkbox. The preference is saved to localStorage and persists across page reloads and different resources. 🤖 Generated with Claude Code Co-Authored-By: Claude --- .../forms/checkbox-alpine.blade.php | 23 +++ .../project/shared/get-logs.blade.php | 134 ++++++++++-------- 2 files changed, 96 insertions(+), 61 deletions(-) create mode 100644 resources/views/components/forms/checkbox-alpine.blade.php diff --git a/resources/views/components/forms/checkbox-alpine.blade.php b/resources/views/components/forms/checkbox-alpine.blade.php new file mode 100644 index 000000000..e9bc4044f --- /dev/null +++ b/resources/views/components/forms/checkbox-alpine.blade.php @@ -0,0 +1,23 @@ +@props([ + 'label' => null, + 'disabled' => false, + 'defaultClass' => 'dark:border-neutral-700 text-coolgray-400 dark:bg-coolgray-100 rounded-sm cursor-pointer dark:disabled:bg-base dark:disabled:cursor-not-allowed focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-coollabs dark:focus-visible:ring-warning focus-visible:ring-offset-2 dark:focus-visible:ring-offset-base', +]) + +
!$disabled, +])> + +
diff --git a/resources/views/livewire/project/shared/get-logs.blade.php b/resources/views/livewire/project/shared/get-logs.blade.php index f6477a882..6800c10d7 100644 --- a/resources/views/livewire/project/shared/get-logs.blade.php +++ b/resources/views/livewire/project/shared/get-logs.blade.php @@ -3,6 +3,7 @@ fullscreen: false, alwaysScroll: false, intervalId: null, + useSimpleView: localStorage.getItem('logView') === 'simple', makeFullscreen() { this.fullscreen = !this.fullscreen; if (this.fullscreen === false) { @@ -12,7 +13,7 @@ }, toggleScroll() { this.alwaysScroll = !this.alwaysScroll; - + if (this.alwaysScroll) { this.intervalId = setInterval(() => { const screen = document.getElementById('screen'); @@ -31,6 +32,9 @@ clearInterval(this.intervalId); const screen = document.getElementById('screen'); screen.scrollTop = 0; + }, + toggleLogView() { + localStorage.setItem('logView', this.useSimpleView ? 'simple' : 'enhanced'); } }">
@@ -57,6 +61,7 @@ Refresh +
@@ -68,16 +73,16 @@ {{-- --}}
@if ($outputs)
- @foreach (explode("\n", trim($outputs)) as $line) - @if (!empty(trim($line))) - @php - $lowerLine = strtolower($line); - $isError = - str_contains($lowerLine, 'error') || - str_contains($lowerLine, 'err') || - str_contains($lowerLine, 'failed') || - str_contains($lowerLine, 'exception'); - $isWarning = - str_contains($lowerLine, 'warn') || - str_contains($lowerLine, 'warning') || - str_contains($lowerLine, 'wrn'); - $isDebug = - str_contains($lowerLine, 'debug') || - str_contains($lowerLine, 'dbg') || - str_contains($lowerLine, 'trace'); - $barColor = $isError - ? 'bg-red-500 dark:bg-red-400' - : ($isWarning - ? 'bg-warning-500 dark:bg-warning-400' - : ($isDebug - ? 'bg-purple-500 dark:bg-purple-400' - : 'bg-blue-500 dark:bg-blue-400')); - $bgColor = $isError - ? 'bg-red-50/50 dark:bg-red-900/20 hover:bg-red-100/50 dark:hover:bg-red-800/30' - : ($isWarning - ? 'bg-warning-50/50 dark:bg-warning-900/20 hover:bg-warning-100/50 dark:hover:bg-warning-800/30' - : ($isDebug - ? 'bg-purple-50/50 dark:bg-purple-900/20 hover:bg-purple-100/50 dark:hover:bg-purple-800/30' - : 'bg-blue-50/50 dark:bg-blue-900/20 hover:bg-blue-100/50 dark:hover:bg-blue-800/30')); + +
+
{{ $outputs }}
+
- // Check for timestamp at the beginning (ISO 8601 format) - $timestampPattern = '/^(\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z?)\s+/'; - $hasTimestamp = preg_match($timestampPattern, $line, $matches); - $timestamp = $hasTimestamp ? $matches[1] : null; - $logContent = $hasTimestamp ? preg_replace($timestampPattern, '', $line) : $line; - @endphp -
-
-
- @if ($hasTimestamp) - {{ $timestamp }} - {{ $logContent }} - @else - {{ $line }} - @endif + +
+ @foreach (explode("\n", trim($outputs)) as $line) + @if (!empty(trim($line))) + @php + $lowerLine = strtolower($line); + $isError = + str_contains($lowerLine, 'error') || + str_contains($lowerLine, 'err') || + str_contains($lowerLine, 'failed') || + str_contains($lowerLine, 'exception'); + $isWarning = + str_contains($lowerLine, 'warn') || + str_contains($lowerLine, 'warning') || + str_contains($lowerLine, 'wrn'); + $isDebug = + str_contains($lowerLine, 'debug') || + str_contains($lowerLine, 'dbg') || + str_contains($lowerLine, 'trace'); + $barColor = $isError + ? 'bg-red-500 dark:bg-red-400' + : ($isWarning + ? 'bg-warning-500 dark:bg-warning-400' + : ($isDebug + ? 'bg-purple-500 dark:bg-purple-400' + : 'bg-blue-500 dark:bg-blue-400')); + $bgColor = $isError + ? 'bg-red-50/50 dark:bg-red-900/20 hover:bg-red-100/50 dark:hover:bg-red-800/30' + : ($isWarning + ? 'bg-warning-50/50 dark:bg-warning-900/20 hover:bg-warning-100/50 dark:hover:bg-warning-800/30' + : ($isDebug + ? 'bg-purple-50/50 dark:bg-purple-900/20 hover:bg-purple-100/50 dark:hover:bg-purple-800/30' + : 'bg-blue-50/50 dark:bg-blue-900/20 hover:bg-blue-100/50 dark:hover:bg-blue-800/30')); + + // Check for timestamp at the beginning (ISO 8601 format) + $timestampPattern = '/^(\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z?)\s+/'; + $hasTimestamp = preg_match($timestampPattern, $line, $matches); + $timestamp = $hasTimestamp ? $matches[1] : null; + $logContent = $hasTimestamp ? preg_replace($timestampPattern, '', $line) : $line; + @endphp +
+
+
+ @if ($hasTimestamp) + {{ $timestamp }} + {{ $logContent }} + @else + {{ $line }} + @endif +
-
- @endif - @endforeach + @endif + @endforeach +
@else
@@ -164,4 +176,4 @@ class="text-xs text-gray-500 dark:text-gray-400 font-mono mr-2">{{ $timestamp }}
- + \ No newline at end of file From 7436d93747f55ec33f74dbd05c83c621b12059f8 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Tue, 2 Dec 2025 15:18:54 +0100 Subject: [PATCH 04/12] Refactor Simple View checkbox for improved readability and remove commented-out buttons --- .../livewire/project/shared/get-logs.blade.php | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/resources/views/livewire/project/shared/get-logs.blade.php b/resources/views/livewire/project/shared/get-logs.blade.php index 6800c10d7..7cc97128e 100644 --- a/resources/views/livewire/project/shared/get-logs.blade.php +++ b/resources/views/livewire/project/shared/get-logs.blade.php @@ -61,7 +61,8 @@ Refresh - +
@@ -70,21 +71,6 @@
- {{-- - --}} + --}}
@if ($outputs)
- -
-
{{ $outputs }}
-
+ @foreach (explode("\n", trim($outputs)) as $line) + @if (!empty(trim($line))) + @php + $lowerLine = strtolower($line); + $isError = + str_contains($lowerLine, 'error') || + str_contains($lowerLine, 'err') || + str_contains($lowerLine, 'failed') || + str_contains($lowerLine, 'exception'); + $isWarning = + str_contains($lowerLine, 'warn') || + str_contains($lowerLine, 'warning') || + str_contains($lowerLine, 'wrn'); + $isDebug = + str_contains($lowerLine, 'debug') || + str_contains($lowerLine, 'dbg') || + str_contains($lowerLine, 'trace'); + $barColor = $isError + ? 'bg-red-500 dark:bg-red-400' + : ($isWarning + ? 'bg-warning-500 dark:bg-warning-400' + : ($isDebug + ? 'bg-purple-500 dark:bg-purple-400' + : 'bg-blue-500 dark:bg-blue-400')); + $bgColor = $isError + ? 'bg-red-50/50 dark:bg-red-900/20 hover:bg-red-100/50 dark:hover:bg-red-800/30' + : ($isWarning + ? 'bg-warning-50/50 dark:bg-warning-900/20 hover:bg-warning-100/50 dark:hover:bg-warning-800/30' + : ($isDebug + ? 'bg-purple-50/50 dark:bg-purple-900/20 hover:bg-purple-100/50 dark:hover:bg-purple-800/30' + : 'bg-blue-50/50 dark:bg-blue-900/20 hover:bg-blue-100/50 dark:hover:bg-blue-800/30')); - -
- @foreach (explode("\n", trim($outputs)) as $line) - @if (!empty(trim($line))) - @php - $lowerLine = strtolower($line); - $isError = - str_contains($lowerLine, 'error') || - str_contains($lowerLine, 'err') || - str_contains($lowerLine, 'failed') || - str_contains($lowerLine, 'exception'); - $isWarning = - str_contains($lowerLine, 'warn') || - str_contains($lowerLine, 'warning') || - str_contains($lowerLine, 'wrn'); - $isDebug = - str_contains($lowerLine, 'debug') || - str_contains($lowerLine, 'dbg') || - str_contains($lowerLine, 'trace'); - $barColor = $isError - ? 'bg-red-500 dark:bg-red-400' - : ($isWarning - ? 'bg-warning-500 dark:bg-warning-400' - : ($isDebug - ? 'bg-purple-500 dark:bg-purple-400' - : 'bg-blue-500 dark:bg-blue-400')); - $bgColor = $isError - ? 'bg-red-50/50 dark:bg-red-900/20 hover:bg-red-100/50 dark:hover:bg-red-800/30' - : ($isWarning - ? 'bg-warning-50/50 dark:bg-warning-900/20 hover:bg-warning-100/50 dark:hover:bg-warning-800/30' - : ($isDebug - ? 'bg-purple-50/50 dark:bg-purple-900/20 hover:bg-purple-100/50 dark:hover:bg-purple-800/30' - : 'bg-blue-50/50 dark:bg-blue-900/20 hover:bg-blue-100/50 dark:hover:bg-blue-800/30')); - - // Check for timestamp at the beginning (ISO 8601 format) - $timestampPattern = '/^(\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z?)\s+/'; - $hasTimestamp = preg_match($timestampPattern, $line, $matches); - $timestamp = $hasTimestamp ? $matches[1] : null; - $logContent = $hasTimestamp ? preg_replace($timestampPattern, '', $line) : $line; - @endphp -
-
-
- @if ($hasTimestamp) - {{ $timestamp }} - {{ $logContent }} - @else - {{ $line }} - @endif -
+ // Check for timestamp at the beginning (ISO 8601 format) + $timestampPattern = '/^(\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z?)\s+/'; + $hasTimestamp = preg_match($timestampPattern, $line, $matches); + $timestamp = $hasTimestamp ? $matches[1] : null; + $logContent = $hasTimestamp ? preg_replace($timestampPattern, '', $line) : $line; + @endphp +
+
+
+ @if ($hasTimestamp) + {{ $timestamp }} + {{ $logContent }} + @else + {{ $line }} + @endif
- @endif - @endforeach -
+
+ @endif + @endforeach
@else
@@ -134,4 +164,4 @@ class="text-xs text-gray-500 dark:text-gray-400 font-mono mr-2">{{ $timestamp }}
- \ No newline at end of file + From e10bd011c5ae5c6ec067801c7bc7b6b7c7971bc6 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Wed, 3 Dec 2025 09:09:12 +0100 Subject: [PATCH 10/12] Enable timestamps in log display and improve styling for better readability --- app/Livewire/Project/Shared/GetLogs.php | 2 +- .../project/shared/get-logs.blade.php | 88 ++++--------------- 2 files changed, 20 insertions(+), 70 deletions(-) diff --git a/app/Livewire/Project/Shared/GetLogs.php b/app/Livewire/Project/Shared/GetLogs.php index 3ed2befba..304f7b411 100644 --- a/app/Livewire/Project/Shared/GetLogs.php +++ b/app/Livewire/Project/Shared/GetLogs.php @@ -39,7 +39,7 @@ class GetLogs extends Component public ?bool $streamLogs = false; - public ?bool $showTimeStamps = false; + public ?bool $showTimeStamps = true; public ?int $numberOfLines = 100; diff --git a/resources/views/livewire/project/shared/get-logs.blade.php b/resources/views/livewire/project/shared/get-logs.blade.php index f6477a882..bc4eff557 100644 --- a/resources/views/livewire/project/shared/get-logs.blade.php +++ b/resources/views/livewire/project/shared/get-logs.blade.php @@ -65,21 +65,6 @@
- {{-- - --}}
@if ($outputs) -
- @foreach (explode("\n", trim($outputs)) as $line) - @if (!empty(trim($line))) - @php - $lowerLine = strtolower($line); - $isError = - str_contains($lowerLine, 'error') || - str_contains($lowerLine, 'err') || - str_contains($lowerLine, 'failed') || - str_contains($lowerLine, 'exception'); - $isWarning = - str_contains($lowerLine, 'warn') || - str_contains($lowerLine, 'warning') || - str_contains($lowerLine, 'wrn'); - $isDebug = - str_contains($lowerLine, 'debug') || - str_contains($lowerLine, 'dbg') || - str_contains($lowerLine, 'trace'); - $barColor = $isError - ? 'bg-red-500 dark:bg-red-400' - : ($isWarning - ? 'bg-warning-500 dark:bg-warning-400' - : ($isDebug - ? 'bg-purple-500 dark:bg-purple-400' - : 'bg-blue-500 dark:bg-blue-400')); - $bgColor = $isError - ? 'bg-red-50/50 dark:bg-red-900/20 hover:bg-red-100/50 dark:hover:bg-red-800/30' - : ($isWarning - ? 'bg-warning-50/50 dark:bg-warning-900/20 hover:bg-warning-100/50 dark:hover:bg-warning-800/30' - : ($isDebug - ? 'bg-purple-50/50 dark:bg-purple-900/20 hover:bg-purple-100/50 dark:hover:bg-purple-800/30' - : 'bg-blue-50/50 dark:bg-blue-900/20 hover:bg-blue-100/50 dark:hover:bg-blue-800/30')); +
+ @foreach (explode("\n", $outputs) as $line) + @php + // Skip empty lines + if (trim($line) === '') { + continue; + } - // Check for timestamp at the beginning (ISO 8601 format) - $timestampPattern = '/^(\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z?)\s+/'; - $hasTimestamp = preg_match($timestampPattern, $line, $matches); - $timestamp = $hasTimestamp ? $matches[1] : null; - $logContent = $hasTimestamp ? preg_replace($timestampPattern, '', $line) : $line; - @endphp -
-
-
- @if ($hasTimestamp) - {{ $timestamp }} - {{ $logContent }} - @else - {{ $line }} - @endif -
-
- @endif + // Style timestamps by replacing them inline + $styledLine = preg_replace( + '/(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+Z)/', + '$1', + htmlspecialchars($line), + ); + @endphp +
+ {!! $styledLine !!} +
@endforeach
@else -
- Refresh to get the logs... -
+
Refresh to get the logs...
@endif
From a18e920e4cf397759044ba0f2bacbbcb178d1349 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Wed, 3 Dec 2025 09:16:28 +0100 Subject: [PATCH 11/12] fix: remove logging of cleanup failures to prevent false deployment errors --- app/Jobs/ApplicationDeploymentJob.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index 9ca69e265..87a507794 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -3194,7 +3194,6 @@ private function stop_running_container(bool $force = false) 'stderr', hidden: true ); - \Log::warning("Failed to stop running container {$this->container_name}: {$e->getMessage()}"); return; // Don't re-throw - cleanup failures shouldn't fail successful deployments } From a767ca30e6957e58e254e3f91b9c7134d59fe723 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Wed, 3 Dec 2025 09:18:32 +0100 Subject: [PATCH 12/12] fix: log unhealthy container status during health check --- app/Jobs/ApplicationDeploymentJob.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index 87a507794..bcd7a729d 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -1813,9 +1813,9 @@ private function health_check() $this->application->update(['status' => 'running']); $this->application_deployment_queue->addLogEntry('New container is healthy.'); break; - } - if (str($this->saved_outputs->get('health_check'))->replace('"', '')->value() === 'unhealthy') { + } elseif (str($this->saved_outputs->get('health_check'))->replace('"', '')->value() === 'unhealthy') { $this->newVersionIsHealthy = false; + $this->application_deployment_queue->addLogEntry('New container is unhealthy.', type: 'error'); $this->query_logs(); break; }