From 1ab4b9aa31c6ed85815527d06f100afd2c87cb9b Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Sun, 26 Oct 2025 23:39:40 +0100 Subject: [PATCH 1/6] refactor: simplify project data retrieval and enhance OAuth settings handling --- app/Livewire/Project/Index.php | 22 +---- app/Livewire/Project/Shared/GetLogs.php | 2 + app/Livewire/Server/New/ByIp.php | 32 ------- app/Livewire/SettingsOauth.php | 49 ++++++++++- resources/views/components/navbar.blade.php | 2 +- resources/views/layouts/app.blade.php | 2 +- .../views/livewire/project/edit.blade.php | 30 +++---- .../views/livewire/project/index.blade.php | 41 +++++---- .../project/shared/get-logs.blade.php | 4 +- .../views/livewire/server/new/by-ip.blade.php | 38 +-------- .../livewire/server/proxy/logs.blade.php | 2 +- .../server/security/patches.blade.php | 85 ++++++++++--------- .../views/livewire/server/show.blade.php | 4 +- .../views/livewire/settings-oauth.blade.php | 32 +++---- 14 files changed, 158 insertions(+), 187 deletions(-) diff --git a/app/Livewire/Project/Index.php b/app/Livewire/Project/Index.php index a27a3652f..0e4f15a5c 100644 --- a/app/Livewire/Project/Index.php +++ b/app/Livewire/Project/Index.php @@ -18,20 +18,7 @@ class Index extends Component public function mount() { $this->private_keys = PrivateKey::ownedByCurrentTeam()->get(); - $this->projects = Project::ownedByCurrentTeam()->get()->map(function ($project) { - $project->settingsRoute = route('project.edit', ['project_uuid' => $project->uuid]); - $project->canUpdate = auth()->user()->can('update', $project); - $project->canCreateResource = auth()->user()->can('createAnyResource'); - $firstEnvironment = $project->environments->first(); - $project->addResourceRoute = $firstEnvironment - ? route('project.resource.create', [ - 'project_uuid' => $project->uuid, - 'environment_uuid' => $firstEnvironment->uuid, - ]) - : null; - - return $project; - }); + $this->projects = Project::ownedByCurrentTeam()->get(); $this->servers = Server::ownedByCurrentTeam()->count(); } @@ -39,11 +26,4 @@ public function render() { return view('livewire.project.index'); } - - public function navigateToProject($projectUuid) - { - $project = collect($this->projects)->firstWhere('uuid', $projectUuid); - - return $this->redirect($project->navigateTo(), navigate: false); - } } diff --git a/app/Livewire/Project/Shared/GetLogs.php b/app/Livewire/Project/Shared/GetLogs.php index 43fd97c34..304f7b411 100644 --- a/app/Livewire/Project/Shared/GetLogs.php +++ b/app/Livewire/Project/Shared/GetLogs.php @@ -33,6 +33,8 @@ class GetLogs extends Component public ?string $container = null; + public ?string $displayName = null; + public ?string $pull_request = null; public ?bool $streamLogs = false; diff --git a/app/Livewire/Server/New/ByIp.php b/app/Livewire/Server/New/ByIp.php index 116775a6f..35526d59e 100644 --- a/app/Livewire/Server/New/ByIp.php +++ b/app/Livewire/Server/New/ByIp.php @@ -7,7 +7,6 @@ use App\Models\Team; use App\Support\ValidationPatterns; use Illuminate\Foundation\Auth\Access\AuthorizesRequests; -use Illuminate\Support\Collection; use Livewire\Attributes\Locked; use Livewire\Component; @@ -39,25 +38,12 @@ class ByIp extends Component public int $port = 22; - public bool $is_swarm_manager = false; - - public bool $is_swarm_worker = false; - - public $selected_swarm_cluster = null; - public bool $is_build_server = false; - #[Locked] - public Collection $swarm_managers; - public function mount() { $this->name = generate_random_name(); $this->private_key_id = $this->private_keys->first()?->id; - $this->swarm_managers = Server::isUsable()->get()->where('settings.is_swarm_manager', true); - if ($this->swarm_managers->count() > 0) { - $this->selected_swarm_cluster = $this->swarm_managers->first()->id; - } } protected function rules(): array @@ -72,9 +58,6 @@ protected function rules(): array 'ip' => 'required|string', 'user' => 'required|string', 'port' => 'required|integer|between:1,65535', - 'is_swarm_manager' => 'required|boolean', - 'is_swarm_worker' => 'required|boolean', - 'selected_swarm_cluster' => 'nullable|integer', 'is_build_server' => 'required|boolean', ]; } @@ -94,11 +77,6 @@ protected function messages(): array 'port.required' => 'The Port field is required.', 'port.integer' => 'The Port field must be an integer.', 'port.between' => 'The Port field must be between 1 and 65535.', - 'is_swarm_manager.required' => 'The Swarm Manager field is required.', - 'is_swarm_manager.boolean' => 'The Swarm Manager field must be true or false.', - 'is_swarm_worker.required' => 'The Swarm Worker field is required.', - 'is_swarm_worker.boolean' => 'The Swarm Worker field must be true or false.', - 'selected_swarm_cluster.integer' => 'The Swarm Cluster field must be an integer.', 'is_build_server.required' => 'The Build Server field is required.', 'is_build_server.boolean' => 'The Build Server field must be true or false.', ]); @@ -140,9 +118,6 @@ public function submit() 'team_id' => currentTeam()->id, 'private_key_id' => $this->private_key_id, ]; - if ($this->is_swarm_worker) { - $payload['swarm_cluster'] = $this->selected_swarm_cluster; - } if ($this->is_build_server) { data_forget($payload, 'proxy'); } @@ -150,13 +125,6 @@ public function submit() $server->proxy->set('status', 'exited'); $server->proxy->set('type', ProxyTypes::TRAEFIK->value); $server->save(); - if ($this->is_build_server) { - $this->is_swarm_manager = false; - $this->is_swarm_worker = false; - } else { - $server->settings->is_swarm_manager = $this->is_swarm_manager; - $server->settings->is_swarm_worker = $this->is_swarm_worker; - } $server->settings->is_build_server = $this->is_build_server; $server->settings->save(); diff --git a/app/Livewire/SettingsOauth.php b/app/Livewire/SettingsOauth.php index e23f94a73..f17730a10 100644 --- a/app/Livewire/SettingsOauth.php +++ b/app/Livewire/SettingsOauth.php @@ -29,7 +29,16 @@ public function mount() return redirect()->route('home'); } $this->oauth_settings_map = OauthSetting::all()->sortBy('provider')->reduce(function ($carry, $setting) { - $carry[$setting->provider] = $setting; + $carry[$setting->provider] = [ + 'id' => $setting->id, + 'provider' => $setting->provider, + 'enabled' => $setting->enabled, + 'client_id' => $setting->client_id, + 'client_secret' => $setting->client_secret, + 'redirect_uri' => $setting->redirect_uri, + 'tenant' => $setting->tenant, + 'base_url' => $setting->base_url, + ]; return $carry; }, []); @@ -38,16 +47,48 @@ public function mount() private function updateOauthSettings(?string $provider = null) { if ($provider) { - $oauth = $this->oauth_settings_map[$provider]; + $oauthData = $this->oauth_settings_map[$provider]; + $oauth = OauthSetting::find($oauthData['id']); + + $oauth->fill([ + 'enabled' => $oauthData['enabled'], + 'client_id' => $oauthData['client_id'], + 'client_secret' => $oauthData['client_secret'], + 'redirect_uri' => $oauthData['redirect_uri'], + 'tenant' => $oauthData['tenant'], + 'base_url' => $oauthData['base_url'], + ]); + if (! $oauth->couldBeEnabled()) { $oauth->update(['enabled' => false]); throw new \Exception('OAuth settings are not complete for '.$oauth->provider.'.
Please fill in all required fields.'); } $oauth->save(); + + // Update the array with fresh data + $this->oauth_settings_map[$provider] = [ + 'id' => $oauth->id, + 'provider' => $oauth->provider, + 'enabled' => $oauth->enabled, + 'client_id' => $oauth->client_id, + 'client_secret' => $oauth->client_secret, + 'redirect_uri' => $oauth->redirect_uri, + 'tenant' => $oauth->tenant, + 'base_url' => $oauth->base_url, + ]; + $this->dispatch('success', 'OAuth settings for '.$oauth->provider.' updated successfully!'); } else { - foreach (array_values($this->oauth_settings_map) as &$setting) { - $setting->save(); + foreach (array_values($this->oauth_settings_map) as $settingData) { + $oauth = OauthSetting::find($settingData['id']); + $oauth->update([ + 'enabled' => $settingData['enabled'], + 'client_id' => $settingData['client_id'], + 'client_secret' => $settingData['client_secret'], + 'redirect_uri' => $settingData['redirect_uri'], + 'tenant' => $settingData['tenant'], + 'base_url' => $settingData['base_url'], + ]); } } } diff --git a/resources/views/components/navbar.blade.php b/resources/views/components/navbar.blade.php index 4b152dd11..84502872e 100644 --- a/resources/views/components/navbar.blade.php +++ b/resources/views/components/navbar.blade.php @@ -79,7 +79,7 @@ }">
-
Coolify
+ Coolify
diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php index a1ff81e84..0a7909761 100644 --- a/resources/views/layouts/app.blade.php +++ b/resources/views/layouts/app.blade.php @@ -47,7 +47,7 @@
-
Coolify
+ Coolify
All your projects are here.
-
- + @endforeach
diff --git a/resources/views/livewire/project/shared/get-logs.blade.php b/resources/views/livewire/project/shared/get-logs.blade.php index c54f69dde..2aff4fc1c 100644 --- a/resources/views/livewire/project/shared/get-logs.blade.php +++ b/resources/views/livewire/project/shared/get-logs.blade.php @@ -34,7 +34,9 @@ } }">
- @if ($resource?->type() === 'application' || str($resource?->type())->startsWith('standalone')) + @if ($displayName) +

{{ $displayName }}

+ @elseif ($resource?->type() === 'application' || str($resource?->type())->startsWith('standalone'))

{{ $container }}

@else

{{ str($container)->beforeLast('-')->headline() }}

diff --git a/resources/views/livewire/server/new/by-ip.blade.php b/resources/views/livewire/server/new/by-ip.blade.php index 94d0fccbd..e41342ca2 100644 --- a/resources/views/livewire/server/new/by-ip.blade.php +++ b/resources/views/livewire/server/new/by-ip.blade.php @@ -31,45 +31,9 @@ class="font-bold underline" target="_blank" helper="Build servers are used to build your applications, so you cannot deploy applications to it." label="Use it as a build server?" />
-
-

Swarm (experimental)

-
Read the docs here.
- @if ($is_swarm_worker || $is_build_server) - - @else - - @endif - @if ($is_swarm_manager || $is_build_server) - - @else - - @endif - @if ($is_swarm_worker && count($swarm_managers) > 0) -
- - @foreach ($swarm_managers as $server) - @if ($loop->first) - - @else - - @endif - @endforeach - -
- @endif -
Continue @endif -
+ \ No newline at end of file diff --git a/resources/views/livewire/server/proxy/logs.blade.php b/resources/views/livewire/server/proxy/logs.blade.php index ea4a68674..17fe65f4c 100644 --- a/resources/views/livewire/server/proxy/logs.blade.php +++ b/resources/views/livewire/server/proxy/logs.blade.php @@ -7,7 +7,7 @@

Logs

- +
diff --git a/resources/views/livewire/server/security/patches.blade.php b/resources/views/livewire/server/security/patches.blade.php index fd7b61ad9..7627cf91f 100644 --- a/resources/views/livewire/server/security/patches.blade.php +++ b/resources/views/livewire/server/security/patches.blade.php @@ -56,48 +56,53 @@ step2ButtonText="Update All Packages" /> - - - - - @if ($packageManager !== 'dnf') - - @endif - - - - - - @foreach ($updates as $update) +
+
PackageCurrent VersionNew VersionAction
+ - - @if ($packageManager !== 'dnf') - - @endif - - + + + - @endforeach - -
- @if (data_get_str($update, 'package')->contains('docker') || data_get_str($update, 'package')->contains('kernel')) - - - - - - - - - @endif - {{ data_get($update, 'package') }} - {{ data_get($update, 'current_version') }}{{ data_get($update, 'new_version') }} - Update - PackageVersionAction
+ + + @foreach ($updates as $update) + + +
+ @if (data_get_str($update, 'package')->contains('docker') || data_get_str($update, 'package')->contains('kernel')) + + + + + + + + + @endif + {{ data_get($update, 'package') }} +
+ + +
+ {{ data_get($update, 'new_version') }} + @if ($packageManager !== 'dnf' && data_get($update, 'current_version')) + + @endif +
+ + + Update + + + @endforeach + + + @endif @endif diff --git a/resources/views/livewire/server/show.blade.php b/resources/views/livewire/server/show.blade.php index 5f99ad97f..4cce11e20 100644 --- a/resources/views/livewire/server/show.blade.php +++ b/resources/views/livewire/server/show.blade.php @@ -337,7 +337,7 @@ class="w-full input opacity-50 cursor-not-allowed" Sentinel Logs + container="coolify-sentinel" displayName="Sentinel" lazy /> Logs @@ -353,7 +353,7 @@ class="w-full input opacity-50 cursor-not-allowed" Sentinel Logs + container="coolify-sentinel" displayName="Sentinel" lazy /> Logs diff --git a/resources/views/livewire/settings-oauth.blade.php b/resources/views/livewire/settings-oauth.blade.php index 6a967504d..7650a5654 100644 --- a/resources/views/livewire/settings-oauth.blade.php +++ b/resources/views/livewire/settings-oauth.blade.php @@ -16,33 +16,33 @@
@foreach ($oauth_settings_map as $oauth_setting)
-

{{ ucfirst($oauth_setting->provider) }}

+

{{ ucfirst($oauth_setting['provider']) }}

- +
- - - - @if ($oauth_setting->provider == 'azure') - + @if ($oauth_setting['provider'] == 'azure') + @endif - @if ($oauth_setting->provider == 'google') - @endif @if ( - $oauth_setting->provider == 'authentik' || - $oauth_setting->provider == 'clerk' || - $oauth_setting->provider == 'zitadel' || - $oauth_setting->provider == 'gitlab') - @endif
From 28fc3feab00d99bade5d4beeef959b8df011667e Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Mon, 27 Oct 2025 15:44:27 +0100 Subject: [PATCH 2/6] fix: remove wire:ignore from modal and add wire:key to EditCompose component MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove wire:ignore from modal-input.blade.php wrapper to allow child Livewire components to be properly tracked - Add unique wire:key to EditCompose component for proper identification when teleported - Fixes 'Unable to call component method' error when saving compose files 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- resources/views/components/modal-input.blade.php | 2 +- resources/views/livewire/project/service/stack-form.blade.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/views/components/modal-input.blade.php b/resources/views/components/modal-input.blade.php index b031740ca..b8f582588 100644 --- a/resources/views/components/modal-input.blade.php +++ b/resources/views/components/modal-input.blade.php @@ -13,7 +13,7 @@
+ class="relative w-auto h-auto"> @if ($content)
{{ $content }} diff --git a/resources/views/livewire/project/service/stack-form.blade.php b/resources/views/livewire/project/service/stack-form.blade.php index 5a8a3e420..ed38cda16 100644 --- a/resources/views/livewire/project/service/stack-form.blade.php +++ b/resources/views/livewire/project/service/stack-form.blade.php @@ -8,7 +8,7 @@ Save @can('update', $service) - + @endcan
From 974a8bdf647c0aea240469b979856a868c0499e6 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Mon, 27 Oct 2025 15:51:14 +0100 Subject: [PATCH 3/6] fix: add wire:ignore directive to modal component for improved functionality --- resources/views/components/modal-input.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/components/modal-input.blade.php b/resources/views/components/modal-input.blade.php index b8f582588..b031740ca 100644 --- a/resources/views/components/modal-input.blade.php +++ b/resources/views/components/modal-input.blade.php @@ -13,7 +13,7 @@
+ class="relative w-auto h-auto" wire:ignore> @if ($content)
{{ $content }} From f0db097a905df9e64b1c1a99abe52047cbea5dfc Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Mon, 27 Oct 2025 15:52:05 +0100 Subject: [PATCH 4/6] fix: clean up formatting and remove unnecessary key binding in stack form component --- .../project/service/stack-form.blade.php | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/resources/views/livewire/project/service/stack-form.blade.php b/resources/views/livewire/project/service/stack-form.blade.php index ed38cda16..8972345bc 100644 --- a/resources/views/livewire/project/service/stack-form.blade.php +++ b/resources/views/livewire/project/service/stack-form.blade.php @@ -5,21 +5,24 @@ @if (isDev())
{{ $service->compose_parsing_version }}
@endif - Save + Save @can('update', $service) - + @endcan
Configuration
- +
-
@if ($fields->count() > 0) @@ -36,10 +39,11 @@ class="font-bold">{{ data_get($field, 'serviceName') }}{{ data_get($field @endif
- @endforeach
@endif - + \ No newline at end of file From 8a3dc19d19dffae0f213cb1eba522c12bd73d417 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Mon, 27 Oct 2025 17:01:24 +0100 Subject: [PATCH 5/6] Update app/Livewire/SettingsOauth.php Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- app/Livewire/SettingsOauth.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/Livewire/SettingsOauth.php b/app/Livewire/SettingsOauth.php index f17730a10..77d3b36fc 100644 --- a/app/Livewire/SettingsOauth.php +++ b/app/Livewire/SettingsOauth.php @@ -50,6 +50,10 @@ private function updateOauthSettings(?string $provider = null) $oauthData = $this->oauth_settings_map[$provider]; $oauth = OauthSetting::find($oauthData['id']); + if (!$oauth) { + throw new \Exception('OAuth setting for '.$provider.' not found. It may have been deleted.'); + } + $oauth->fill([ 'enabled' => $oauthData['enabled'], 'client_id' => $oauthData['client_id'], From b1a68df65caef6df06c9495a817ff4c340a44d39 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Mon, 27 Oct 2025 17:04:33 +0100 Subject: [PATCH 6/6] fix: add null checks and validation to OAuth bulk update method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add null check before updating OAuth settings to prevent calling methods on null - Apply couldBeEnabled() validation for all settings in bulk update (not just instant save) - Disable OAuth providers that fail validation and collect error messages - Surface all validation errors to the user instead of silently failing - Update oauth_settings_map with fresh data after saving each setting This ensures bulk updates follow the same validation logic as instant-save paths and prevents bypassing model validation by directly calling update. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- app/Livewire/SettingsOauth.php | 35 ++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/app/Livewire/SettingsOauth.php b/app/Livewire/SettingsOauth.php index 77d3b36fc..6f949b716 100644 --- a/app/Livewire/SettingsOauth.php +++ b/app/Livewire/SettingsOauth.php @@ -50,7 +50,7 @@ private function updateOauthSettings(?string $provider = null) $oauthData = $this->oauth_settings_map[$provider]; $oauth = OauthSetting::find($oauthData['id']); - if (!$oauth) { + if (! $oauth) { throw new \Exception('OAuth setting for '.$provider.' not found. It may have been deleted.'); } @@ -83,9 +83,17 @@ private function updateOauthSettings(?string $provider = null) $this->dispatch('success', 'OAuth settings for '.$oauth->provider.' updated successfully!'); } else { + $errors = []; foreach (array_values($this->oauth_settings_map) as $settingData) { $oauth = OauthSetting::find($settingData['id']); - $oauth->update([ + + if (! $oauth) { + $errors[] = "OAuth setting for provider '{$settingData['provider']}' not found. It may have been deleted."; + + continue; + } + + $oauth->fill([ 'enabled' => $settingData['enabled'], 'client_id' => $settingData['client_id'], 'client_secret' => $settingData['client_secret'], @@ -93,6 +101,29 @@ private function updateOauthSettings(?string $provider = null) 'tenant' => $settingData['tenant'], 'base_url' => $settingData['base_url'], ]); + + if ($settingData['enabled'] && ! $oauth->couldBeEnabled()) { + $oauth->enabled = false; + $errors[] = "OAuth settings are incomplete for '{$oauth->provider}'. Required fields are missing. The provider has been disabled."; + } + + $oauth->save(); + + // Update the array with fresh data + $this->oauth_settings_map[$oauth->provider] = [ + 'id' => $oauth->id, + 'provider' => $oauth->provider, + 'enabled' => $oauth->enabled, + 'client_id' => $oauth->client_id, + 'client_secret' => $oauth->client_secret, + 'redirect_uri' => $oauth->redirect_uri, + 'tenant' => $oauth->tenant, + 'base_url' => $oauth->base_url, + ]; + } + + if (! empty($errors)) { + $this->dispatch('error', implode('
', $errors)); } } }