diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index fd4c508a0..17ef4397c 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -44,8 +44,8 @@ protected function schedule(Schedule $schedule): void // Instance Jobs $schedule->command('horizon:snapshot')->everyFiveMinutes(); $schedule->command('cleanup:unreachable-servers')->daily()->onOneServer(); - $schedule->job(new PullCoolifyImageJob)->cron($settings->update_check_frequency)->onOneServer(); - $schedule->job(new PullTemplatesFromCDN)->cron($settings->update_check_frequency)->onOneServer(); + $schedule->job(new PullCoolifyImageJob)->cron($settings->update_check_frequency)->timezone($settings->instance_timezone)->onOneServer(); + $schedule->job(new PullTemplatesFromCDN)->cron($settings->update_check_frequency)->timezone($settings->instance_timezone)->onOneServer(); $schedule->job(new CleanupInstanceStuffsJob)->everyTwoMinutes()->onOneServer(); $this->schedule_updates($schedule); @@ -73,9 +73,12 @@ private function pull_images($schedule) if ($status !== 'running') { PullSentinelImageJob::dispatch($server); } - })->cron($settings->update_check_frequency)->onOneServer(); + })->cron($settings->update_check_frequency)->timezone($settings->instance_timezone)->onOneServer(); } - $schedule->job(new PullHelperImageJob($server))->cron($settings->update_check_frequency)->onOneServer(); + $schedule->job(new PullHelperImageJob($server)) + ->cron($settings->update_check_frequency) + ->timezone($settings->instance_timezone) + ->onOneServer(); } } @@ -84,11 +87,17 @@ private function schedule_updates($schedule) $settings = InstanceSettings::get(); $updateCheckFrequency = $settings->update_check_frequency; - $schedule->job(new CheckForUpdatesJob)->cron($updateCheckFrequency)->onOneServer(); + $schedule->job(new CheckForUpdatesJob) + ->cron($updateCheckFrequency) + ->timezone($settings->instance_timezone) + ->onOneServer(); if ($settings->is_auto_update_enabled) { $autoUpdateFrequency = $settings->auto_update_frequency; - $schedule->job(new UpdateCoolifyJob)->cron($autoUpdateFrequency)->onOneServer(); + $schedule->job(new UpdateCoolifyJob) + ->cron($autoUpdateFrequency) + ->timezone($settings->instance_timezone) + ->onOneServer(); } } @@ -103,15 +112,12 @@ private function check_resources($schedule) } foreach ($servers as $server) { $schedule->job(new ServerCheckJob($server))->everyMinute()->onOneServer(); - //The lines below need to be added as soon as timzone is merged!! - //$serverTimezone = $server->settings->server_timezone; - //$schedule->job(new DockerCleanupJob($server))->cron($server->settings->docker_cleanup_frequency)->timezone($serverTimezone)->onOneServer(); + $serverTimezone = $server->settings->server_timezone; if ($server->settings->force_docker_cleanup) { - $schedule->job(new DockerCleanupJob($server))->cron($server->settings->docker_cleanup_frequency)->onOneServer(); + $schedule->job(new DockerCleanupJob($server))->cron($server->settings->docker_cleanup_frequency)->timezone($serverTimezone)->onOneServer(); } else { - $schedule->job(new DockerCleanupJob($server))->everyTenMinutes()->onOneServer(); + $schedule->job(new DockerCleanupJob($server))->everyTenMinutes()->timezone($serverTimezone)->onOneServer(); } - } } @@ -128,16 +134,18 @@ private function check_scheduled_backups($schedule) if (is_null(data_get($scheduled_backup, 'database'))) { ray('database not found'); $scheduled_backup->delete(); - continue; } + $server = $scheduled_backup->server(); + $serverTimezone = $server->settings->server_timezone; + if (isset(VALID_CRON_STRINGS[$scheduled_backup->frequency])) { $scheduled_backup->frequency = VALID_CRON_STRINGS[$scheduled_backup->frequency]; } $schedule->job(new DatabaseBackupJob( backup: $scheduled_backup - ))->cron($scheduled_backup->frequency)->onOneServer(); + ))->cron($scheduled_backup->frequency)->timezone($serverTimezone)->onOneServer(); } } @@ -157,7 +165,6 @@ private function check_scheduled_tasks($schedule) if (! $application && ! $service) { ray('application/service attached to scheduled task does not exist'); $scheduled_task->delete(); - continue; } if ($application) { @@ -170,19 +177,23 @@ private function check_scheduled_tasks($schedule) continue; } } + + $server = $scheduled_task->server(); + $serverTimezone = $server->settings->server_timezone ?: config('app.timezone'); + if (isset(VALID_CRON_STRINGS[$scheduled_task->frequency])) { $scheduled_task->frequency = VALID_CRON_STRINGS[$scheduled_task->frequency]; } $schedule->job(new ScheduledTaskJob( task: $scheduled_task - ))->cron($scheduled_task->frequency)->onOneServer(); + ))->cron($scheduled_task->frequency)->timezone($serverTimezone)->onOneServer(); } } protected function commands(): void { - $this->load(__DIR__.'/Commands'); + $this->load(__DIR__ . '/Commands'); require base_path('routes/console.php'); } -} +} \ No newline at end of file diff --git a/app/Jobs/ScheduledTaskJob.php b/app/Jobs/ScheduledTaskJob.php index 819e28f89..93d5fca70 100644 --- a/app/Jobs/ScheduledTaskJob.php +++ b/app/Jobs/ScheduledTaskJob.php @@ -36,6 +36,8 @@ class ScheduledTaskJob implements ShouldQueue public array $containers = []; + public string $server_timezone; + public function __construct($task) { $this->task = $task; @@ -47,6 +49,19 @@ public function __construct($task) throw new \RuntimeException('ScheduledTaskJob failed: No resource found.'); } $this->team = Team::find($task->team_id); + $this->server_timezone = $this->getServerTimezone(); + } + + private function getServerTimezone(): string + { + if ($this->resource instanceof Application) { + $timezone = $this->resource->destination->server->settings->server_timezone; + return $timezone; + } elseif ($this->resource instanceof Service) { + $timezone = $this->resource->server->settings->server_timezone; + return $timezone; + } + return 'UTC'; } public function middleware(): array @@ -61,6 +76,7 @@ public function uniqueId(): int public function handle(): void { + try { $this->task_log = ScheduledTaskExecution::create([ 'scheduled_task_id' => $this->task->id, @@ -78,12 +94,12 @@ public function handle(): void } elseif ($this->resource->type() == 'service') { $this->resource->applications()->get()->each(function ($application) { if (str(data_get($application, 'status'))->contains('running')) { - $this->containers[] = data_get($application, 'name').'-'.data_get($this->resource, 'uuid'); + $this->containers[] = data_get($application, 'name') . '-' . data_get($this->resource, 'uuid'); } }); $this->resource->databases()->get()->each(function ($database) { if (str(data_get($database, 'status'))->contains('running')) { - $this->containers[] = data_get($database, 'name').'-'.data_get($this->resource, 'uuid'); + $this->containers[] = data_get($database, 'name') . '-' . data_get($this->resource, 'uuid'); } }); } @@ -96,8 +112,8 @@ public function handle(): void } foreach ($this->containers as $containerName) { - if (count($this->containers) == 1 || str_starts_with($containerName, $this->task->container.'-'.$this->resource->uuid)) { - $cmd = "sh -c '".str_replace("'", "'\''", $this->task->command)."'"; + if (count($this->containers) == 1 || str_starts_with($containerName, $this->task->container . '-' . $this->resource->uuid)) { + $cmd = "sh -c '" . str_replace("'", "'\''", $this->task->command) . "'"; $exec = "docker exec {$containerName} {$cmd}"; $this->task_output = instant_remote_process([$exec], $this->server, true); $this->task_log->update([ @@ -121,6 +137,7 @@ public function handle(): void $this->team?->notify(new TaskFailed($this->task, $e->getMessage())); // send_internal_notification('ScheduledTaskJob failed with: ' . $e->getMessage()); throw $e; + } finally { } } } diff --git a/app/Livewire/Project/Database/BackupExecutions.php b/app/Livewire/Project/Database/BackupExecutions.php index c9db7f5fc..5d56ea53d 100644 --- a/app/Livewire/Project/Database/BackupExecutions.php +++ b/app/Livewire/Project/Database/BackupExecutions.php @@ -8,9 +8,8 @@ class BackupExecutions extends Component { public ?ScheduledDatabaseBackup $backup = null; - + public $database; public $executions = []; - public $setDeletableBackup; public function getListeners() @@ -61,4 +60,50 @@ public function refreshBackupExecutions(): void $this->executions = $this->backup->executions()->get(); } } + + public function mount(ScheduledDatabaseBackup $backup) + { + $this->backup = $backup; + $this->database = $backup->database; + $this->refreshBackupExecutions(); + } + + public function server() + { + if ($this->database) { + $server = null; + + if ($this->database instanceof \App\Models\ServiceDatabase) { + $server = $this->database->service->destination->server; + } elseif ($this->database->destination && $this->database->destination->server) { + $server = $this->database->destination->server; + } + if ($server) { + return $server; + } + } + return null; + } + + public function getServerTimezone() + { + $server = $this->server(); + if (!$server) { + return 'UTC'; + } + $serverTimezone = $server->settings->server_timezone; + return $serverTimezone; + } + + public function formatDateInServerTimezone($date) + { + $serverTimezone = $this->getServerTimezone(); + $dateObj = new \DateTime($date); + try { + $dateObj->setTimezone(new \DateTimeZone($serverTimezone)); + } catch (\Exception $e) { + $dateObj->setTimezone(new \DateTimeZone('UTC')); + } + return $dateObj->format('Y-m-d H:i:s T'); + } } diff --git a/app/Livewire/Project/Shared/ScheduledTask/Executions.php b/app/Livewire/Project/Shared/ScheduledTask/Executions.php index 7a2e14e89..5bd6b4b9b 100644 --- a/app/Livewire/Project/Shared/ScheduledTask/Executions.php +++ b/app/Livewire/Project/Shared/ScheduledTask/Executions.php @@ -7,8 +7,8 @@ class Executions extends Component { public $executions = []; - public $selectedKey; + public $task; public function getListeners() { @@ -26,4 +26,44 @@ public function selectTask($key): void } $this->selectedKey = $key; } + + public function server() + { + if (!$this->task) { + return null; + } + + if ($this->task->application) { + if ($this->task->application->destination && $this->task->application->destination->server) { + return $this->task->application->destination->server; + } + } elseif ($this->task->service) { + if ($this->task->service->destination && $this->task->service->destination->server) { + return $this->task->service->destination->server; + } + } + return null; + } + + public function getServerTimezone() + { + $server = $this->server(); + if (!$server) { + return 'UTC'; + } + $serverTimezone = $server->settings->server_timezone; + return $serverTimezone; + } + + public function formatDateInServerTimezone($date) + { + $serverTimezone = $this->getServerTimezone(); + $dateObj = new \DateTime($date); + try { + $dateObj->setTimezone(new \DateTimeZone($serverTimezone)); + } catch (\Exception $e) { + $dateObj->setTimezone(new \DateTimeZone('UTC')); + } + return $dateObj->format('Y-m-d H:i:s T'); + } } diff --git a/app/Livewire/Server/Form.php b/app/Livewire/Server/Form.php index 1ab70c004..106d3d761 100644 --- a/app/Livewire/Server/Form.php +++ b/app/Livewire/Server/Form.php @@ -5,7 +5,8 @@ use App\Actions\Server\StartSentinel; use App\Actions\Server\StopSentinel; use App\Jobs\PullSentinelImageJob; -use App\Models\Server; +use App\Models\Server;; + use Livewire\Component; class Form extends Component @@ -43,6 +44,7 @@ class Form extends Component 'server.settings.metrics_history_days' => 'required|integer|min:1', 'wildcard_domain' => 'nullable|url', 'server.settings.is_server_api_enabled' => 'required|boolean', + 'server.settings.server_timezone' => 'required|string|timezone', 'server.settings.force_docker_cleanup' => 'required|boolean', 'server.settings.docker_cleanup_frequency' => 'required_if:server.settings.force_docker_cleanup,true|string', 'server.settings.docker_cleanup_threshold' => 'required_if:server.settings.force_docker_cleanup,false|integer|min:1|max:100', @@ -66,10 +68,15 @@ class Form extends Component 'server.settings.metrics_refresh_rate_seconds' => 'Metrics Interval', 'server.settings.metrics_history_days' => 'Metrics History', 'server.settings.is_server_api_enabled' => 'Server API', + 'server.settings.server_timezone' => 'Server Timezone', ]; - public function mount() + public $timezones; + + public function mount(Server $server) { + $this->server = $server; + $this->timezones = collect(timezone_identifiers_list())->sort()->values()->toArray(); $this->wildcard_domain = $this->server->settings->wildcard_domain; $this->server->settings->docker_cleanup_threshold = $this->server->settings->docker_cleanup_threshold; $this->server->settings->docker_cleanup_frequency = $this->server->settings->docker_cleanup_frequency; @@ -167,7 +174,7 @@ public function checkLocalhostConnection() $this->server->settings->save(); $this->dispatch('proxyStatusUpdated'); } else { - $this->dispatch('error', 'Server is not reachable.', 'Please validate your configuration and connection.

Check this documentation for further help.

Error: '.$error); + $this->dispatch('error', 'Server is not reachable.', 'Please validate your configuration and connection.

Check this documentation for further help.

Error: ' . $error); return; } @@ -207,6 +214,23 @@ public function submit() } else { $this->server->settings->docker_cleanup_threshold = $this->server->settings->docker_cleanup_threshold; } + $currentTimezone = $this->server->settings->getOriginal('server_timezone'); + $newTimezone = $this->server->settings->server_timezone; + if ($currentTimezone !== $newTimezone || $currentTimezone === '') { + try { + $timezoneUpdated = $this->updateServerTimezone($newTimezone); + if ($timezoneUpdated) { + $this->server->settings->server_timezone = $newTimezone; + $this->server->settings->save(); + } else { + return; + } + } catch (\Exception $e) { + $this->dispatch('error', 'Failed to update server timezone: ' . $e->getMessage()); + return; + } + } + $this->server->settings->save(); $this->server->save(); $this->dispatch('success', 'Server updated.'); @@ -214,4 +238,90 @@ public function submit() return handleError($e, $this); } } + + public function updatedServerTimezone($value) + { + if (!is_string($value) || !in_array($value, timezone_identifiers_list())) { + $this->addError('server.settings.server_timezone', 'Invalid timezone.'); + return; + } + $this->server->settings->server_timezone = $value; + $this->updateServerTimezone($value); + } + + private function updateServerTimezone($desired_timezone) + { + try { + $commands = [ + "if command -v timedatectl > /dev/null 2>&1 && pidof systemd > /dev/null; then", + " timedatectl set-timezone " . escapeshellarg($desired_timezone), + "elif [ -f /etc/timezone ]; then", + " echo " . escapeshellarg($desired_timezone) . " > /etc/timezone", + " rm -f /etc/localtime", + " ln -sf /usr/share/zoneinfo/" . escapeshellarg($desired_timezone) . " /etc/localtime", + "elif [ -f /etc/localtime ]; then", + " rm -f /etc/localtime", + " ln -sf /usr/share/zoneinfo/" . escapeshellarg($desired_timezone) . " /etc/localtime", + "else", + " echo 'Unable to set timezone'", + " exit 1", + "fi", + "if command -v dpkg-reconfigure > /dev/null 2>&1; then", + " dpkg-reconfigure -f noninteractive tzdata", + "elif command -v tzdata-update > /dev/null 2>&1; then", + " tzdata-update", + "elif [ -f /etc/sysconfig/clock ]; then", + " sed -i 's/^ZONE=.*/ZONE=\"" . $desired_timezone . "\"/' /etc/sysconfig/clock", + " source /etc/sysconfig/clock", + "fi", + "if command -v systemctl > /dev/null 2>&1 && pidof systemd > /dev/null; then", + " systemctl try-restart systemd-timesyncd.service || true", + "elif command -v service > /dev/null 2>&1; then", + " service ntpd restart || service ntp restart || true", + "fi", + "echo \"Timezone updated to: $desired_timezone\"", + "date" + ]; + + instant_remote_process($commands, $this->server); + + $verificationCommands = [ + "readlink /etc/localtime | sed 's#/usr/share/zoneinfo/##'", + "date +'%Z %:z'" + ]; + $verificationResult = instant_remote_process($verificationCommands, $this->server, false); + $verificationLines = explode("\n", trim($verificationResult)); + + if (count($verificationLines) !== 2) { + $this->dispatch('error', 'Failed to verify timezone update. Unexpected server response.'); + return false; + } + + $actualTimezone = trim($verificationLines[0]); + [$abbreviation, $offset] = explode(' ', trim($verificationLines[1])); + + $desiredTz = new \DateTimeZone($desired_timezone); + $desiredAbbr = (new \DateTime('now', $desiredTz))->format('T'); + $desiredOffset = $this->formatOffset($desiredTz->getOffset(new \DateTime('now', $desiredTz))); + + if ($actualTimezone === $desired_timezone && $abbreviation === $desiredAbbr && $offset === $desiredOffset) { + $this->server->settings->server_timezone = $desired_timezone; + $this->server->settings->save(); + return true; + } else { + $this->dispatch('error', 'Failed to update server timezone. The server reported a different timezone than requested.'); + return false; + } + } catch (\Exception $e) { + $this->dispatch('error', 'Failed to update server timezone: ' . $e->getMessage()); + return false; + } + } + + private function formatOffset($offsetSeconds) + { + $hours = abs($offsetSeconds) / 3600; + $minutes = (abs($offsetSeconds) % 3600) / 60; + return sprintf('%s%02d:%02d', $offsetSeconds >= 0 ? '+' : '-', $hours, $minutes); + } } diff --git a/app/Livewire/Settings/Index.php b/app/Livewire/Settings/Index.php index f593fb78b..eff09f0e5 100644 --- a/app/Livewire/Settings/Index.php +++ b/app/Livewire/Settings/Index.php @@ -40,6 +40,7 @@ class Index extends Component 'settings.is_auto_update_enabled' => 'boolean', 'auto_update_frequency' => 'string', 'update_check_frequency' => 'string', + 'settings.instance_timezone' => 'required|string|timezone', ]; protected $validationAttributes = [ @@ -54,6 +55,8 @@ class Index extends Component 'update_check_frequency' => 'Update Check Frequency', ]; + public $timezones; + public function mount() { if (isInstanceAdmin()) { @@ -65,6 +68,7 @@ public function mount() $this->is_api_enabled = $this->settings->is_api_enabled; $this->auto_update_frequency = $this->settings->auto_update_frequency; $this->update_check_frequency = $this->settings->update_check_frequency; + $this->timezones = collect(timezone_identifiers_list())->sort()->values()->toArray(); } else { return redirect()->route('dashboard'); } @@ -170,4 +174,4 @@ public function render() { return view('livewire.settings.index'); } -} +} \ No newline at end of file diff --git a/app/Models/ScheduledDatabaseBackup.php b/app/Models/ScheduledDatabaseBackup.php index edd840e7d..2d0e200da 100644 --- a/app/Models/ScheduledDatabaseBackup.php +++ b/app/Models/ScheduledDatabaseBackup.php @@ -34,4 +34,14 @@ public function get_last_days_backup_status($days = 7) { return $this->hasMany(ScheduledDatabaseBackupExecution::class)->where('created_at', '>=', now()->subDays($days))->get(); } + public function server() + { + if ($this->database) { + if ($this->database->destination && $this->database->destination->server) { + $server = $this->database->destination->server; + return $server; + } + } + return null; + } } diff --git a/app/Models/ScheduledTask.php b/app/Models/ScheduledTask.php index afff4ef11..7b1c0d275 100644 --- a/app/Models/ScheduledTask.php +++ b/app/Models/ScheduledTask.php @@ -4,6 +4,8 @@ use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasOne; +use App\Models\Service; +use App\Models\Application; class ScheduledTask extends BaseModel { @@ -28,4 +30,25 @@ public function executions(): HasMany { return $this->hasMany(ScheduledTaskExecution::class)->orderBy('created_at', 'desc'); } + + public function server() + { + if ($this->application) { + if ($this->application->destination && $this->application->destination->server) { + $server = $this->application->destination->server; + return $server; + } + } elseif ($this->service) { + if ($this->service->destination && $this->service->destination->server) { + $server = $this->service->destination->server; + return $server; + } + } elseif ($this->database) { + if ($this->database->destination && $this->database->destination->server) { + $server = $this->database->destination->server; + return $server; + } + } + return null; + } } diff --git a/database/migrations/2024_08_12_155023_add_timezone_to_server_and_instance_settings.php b/database/migrations/2024_08_12_155023_add_timezone_to_server_and_instance_settings.php new file mode 100644 index 000000000..5bc73a54e --- /dev/null +++ b/database/migrations/2024_08_12_155023_add_timezone_to_server_and_instance_settings.php @@ -0,0 +1,30 @@ +string('server_timezone')->default(''); + }); + + Schema::table('instance_settings', function (Blueprint $table) { + $table->string('instance_timezone')->default('UTC'); + }); + } + + public function down() + { + Schema::table('server_settings', function (Blueprint $table) { + $table->dropColumn('server_timezone'); + }); + + Schema::table('instance_settings', function (Blueprint $table) { + $table->dropColumn('instance_timezone'); + }); + } +} diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index b3fac350f..736646ec6 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -33,6 +33,7 @@ public function run(): void ScheduledDatabaseBackupSeeder::class, ScheduledDatabaseBackupExecutionSeeder::class, OauthSettingSeeder::class, + ServerTimezoneSeeder::class, ]); } } diff --git a/database/seeders/ProductionSeeder.php b/database/seeders/ProductionSeeder.php index c88a35f6a..a3bdab536 100644 --- a/database/seeders/ProductionSeeder.php +++ b/database/seeders/ProductionSeeder.php @@ -79,7 +79,8 @@ public function run(): void ], [ 'name' => 'localhost\'s key', - 'description' => 'The private key for the Coolify host machine (localhost).', 'private_key' => $coolify_key, + 'description' => 'The private key for the Coolify host machine (localhost).', + 'private_key' => $coolify_key, ] ); } else { @@ -180,5 +181,8 @@ public function run(): void $oauth_settings_seeder = new OauthSettingSeeder; $oauth_settings_seeder->run(); + + $server_timezone_seeder = new ServerTimezoneSeeder; + $server_timezone_seeder->run(); } } diff --git a/database/seeders/ServerTimezoneSeeder.php b/database/seeders/ServerTimezoneSeeder.php new file mode 100644 index 000000000..9dd6636f9 --- /dev/null +++ b/database/seeders/ServerTimezoneSeeder.php @@ -0,0 +1,58 @@ +whereNull('server_timezone')->orWhere('server_timezone', ''); + })->each(function ($server) use ($defaultTimezone) { + DB::transaction(function () use ($server, $defaultTimezone) { + $this->updateServerTimezone($server, $defaultTimezone); + }); + }); + } + + private function updateServerTimezone($server, $desired_timezone) + { + $commands = [ + "if command -v timedatectl > /dev/null 2>&1 && pidof systemd > /dev/null; then", + " timedatectl set-timezone " . escapeshellarg($desired_timezone), + "elif [ -f /etc/timezone ]; then", + " echo " . escapeshellarg($desired_timezone) . " > /etc/timezone", + " rm -f /etc/localtime", + " ln -sf /usr/share/zoneinfo/" . escapeshellarg($desired_timezone) . " /etc/localtime", + "elif [ -f /etc/localtime ]; then", + " rm -f /etc/localtime", + " ln -sf /usr/share/zoneinfo/" . escapeshellarg($desired_timezone) . " /etc/localtime", + "fi", + "if command -v dpkg-reconfigure > /dev/null 2>&1; then", + " dpkg-reconfigure -f noninteractive tzdata", + "elif command -v tzdata-update > /dev/null 2>&1; then", + " tzdata-update", + "elif [ -f /etc/sysconfig/clock ]; then", + " sed -i 's/^ZONE=.*/ZONE=\"" . $desired_timezone . "\"/' /etc/sysconfig/clock", + " source /etc/sysconfig/clock", + "fi", + "if command -v systemctl > /dev/null 2>&1 && pidof systemd > /dev/null; then", + " systemctl try-restart systemd-timesyncd.service || true", + "elif command -v service > /dev/null 2>&1; then", + " service ntpd restart || service ntp restart || true", + "fi" + ]; + + instant_remote_process($commands, $server); + + $server->settings->server_timezone = $desired_timezone; + $server->settings->save(); + } +} diff --git a/resources/views/livewire/project/database/backup-executions.blade.php b/resources/views/livewire/project/database/backup-executions.blade.php index 644ac9fa4..b1cc7fa66 100644 --- a/resources/views/livewire/project/database/backup-executions.blade.php +++ b/resources/views/livewire/project/database/backup-executions.blade.php @@ -1,57 +1,66 @@
@isset($backup) -
-

Executions

- Cleanup Failed Backups +
+

Executions

+ Cleanup Failed Backups +
+
+ @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', + ])> + @if (data_get($execution, 'status') === 'running') +
+ +
+ @endif +
Status: {{ data_get($execution, 'status') }}
+
+ Started At: {{ $this->formatDateInServerTimezone(data_get($execution, 'created_at')) }} +
+
+ Database: {{ data_get($execution, 'database_name', 'N/A') }} +
+
+ Size: {{ data_get($execution, 'size') }} B / + {{ round((int) data_get($execution, 'size') / 1024, 2) }} kB / + {{ round((int) data_get($execution, 'size') / 1024 / 1024, 3) }} MB +
+
+ Location: {{ data_get($execution, 'filename', 'N/A') }} +
+ @if (data_get($execution, 'message')) +
+
{{ data_get($execution, 'message') }}
+
+ @endif +
+ @if (data_get($execution, 'status') === 'success') + Download + @endif + + + Delete + + This will delete this backup. It is not reversible.
Please think again. +
+
-
- @forelse($executions as $execution) -
data_get($execution, 'status') === 'success', - 'border-red-500' => data_get($execution, 'status') === 'failed', - ])> - @if (data_get($execution, 'status') === 'running') -
- -
- @endif -
Database: {{ data_get($execution, 'database_name', 'N/A') }}
-
Status: {{ data_get($execution, 'status') }}
-
Started At: {{ data_get($execution, 'created_at') }}
- @if (data_get($execution, 'message')) -
Message: {{ data_get($execution, 'message') }}
- @endif -
Size: {{ data_get($execution, 'size') }} B / - {{ round((int) data_get($execution, 'size') / 1024, 2) }} - kB / {{ round((int) data_get($execution, 'size') / 1024 / 1024, 3) }} MB -
-
Location: {{ data_get($execution, 'filename', 'N/A') }}
-
-
- @if (data_get($execution, 'status') === 'success') - Download - @endif - - - Delete - - This will delete this backup. It is not reversible.
Please think again. -
-
-
- - @empty -
No executions found.
- @endforelse -
- + @empty +
No executions found.
+ @endforelse +
+ @endisset - -
+
\ No newline at end of file diff --git a/resources/views/livewire/project/database/scheduled-backups.blade.php b/resources/views/livewire/project/database/scheduled-backups.blade.php index 66b28eb39..d1ab8a3c1 100644 --- a/resources/views/livewire/project/database/scheduled-backups.blade.php +++ b/resources/views/livewire/project/database/scheduled-backups.blade.php @@ -1,38 +1,37 @@
@forelse($database->scheduledBackups as $backup) - @if ($type == 'database') - -
-
Frequency: {{ $backup->frequency }}
-
Last backup: {{ data_get($backup->latest_log, 'status', 'No backup yet') }}
-
Number of backups to keep (locally): {{ $backup->number_of_backups_locally }}
-
-
- @else -
-
- data_get($backup, 'id') === data_get($selectedBackup, 'id'), - 'flex flex-col border-l-2 border-transparent', - ])> -
Frequency: {{ $backup->frequency }}
-
Last backup: {{ data_get($backup->latest_log, 'status', 'No backup yet') }}
-
Number of backups to keep (locally): {{ $backup->number_of_backups_locally }}
-
-
- @endif + @if ($type == 'database') + +
+
Frequency: {{ $backup->frequency }}
+
Last backup: {{ data_get($backup->latest_log, 'status', 'No backup yet') }}
+
Number of backups to keep (locally): {{ $backup->number_of_backups_locally }}
+
+
+ @else +
+
+ data_get($backup, 'id') === data_get($selectedBackup, 'id'), + 'flex flex-col border-l-2 border-transparent', + ])> +
Frequency: {{ $backup->frequency }}
+
Last backup: {{ data_get($backup->latest_log, 'status', 'No backup yet') }}
+
Number of backups to keep (locally): {{ $backup->number_of_backups_locally }}
+
+
+ @endif @empty -
No scheduled backups configured.
+
No scheduled backups configured.
@endforelse
@if ($type === 'service-database' && $selectedBackup) -
- -

Executions

- -
+
+ +

Executions

+ +
@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 afbf1ea93..a52713522 100644 --- a/resources/views/livewire/project/shared/scheduled-task/executions.blade.php +++ b/resources/views/livewire/project/shared/scheduled-task/executions.blade.php @@ -1,32 +1,36 @@ -
+
@forelse($executions as $execution) - @if (data_get($execution, 'id') == $selectedKey) -
- @if (data_get($execution, 'message')) -
-
{{ data_get($execution, 'message') }}
-
- @else -
No output was recorded for this execution.
- @endif -
+ @if (data_get($execution, 'id') == $selectedKey) + + @endif + 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', + ])> + @if (data_get($execution, 'status') === 'running') +
+ +
+ @endif +
Status: {{ data_get($execution, 'status') }}
+
+ Started At: {{ $this->formatDateInServerTimezone(data_get($execution, 'created_at', now())) }} +
+
@empty -
No executions found.
+
No executions found.
@endforelse -
+
\ No newline at end of file diff --git a/resources/views/livewire/project/shared/scheduled-task/show.blade.php b/resources/views/livewire/project/shared/scheduled-task/show.blade.php index b69463a0e..125a431a4 100644 --- a/resources/views/livewire/project/shared/scheduled-task/show.blade.php +++ b/resources/views/livewire/project/shared/scheduled-task/show.blade.php @@ -1,47 +1,47 @@
{{ data_get_str($resource, 'name')->limit(10) }} > Scheduled Tasks | Coolify - - @if ($type === 'application') + + @if ($type === 'application')

Scheduled Task

- @elseif ($type === 'service') + @elseif ($type === 'service') - @endif + @endif -
-
-
-

Scheduled Task

- - Save - - - You will delete scheduled task {{ $task->name }}. - + +
+
+

Scheduled Task

+ + Save + + + You will delete scheduled task {{ $task->name }}. + +
+
+ +
-
- -
-
-
- - - - @if ($type === 'application') +
+ + + + @if ($type === 'application') - @elseif ($type === 'service') + @elseif ($type === 'service') - @endif -
- + @endif +
+ -
-

Recent executions (click to check output)

- -
+
+

Recent executions (click to check output)

+ +
diff --git a/resources/views/livewire/server/form.blade.php b/resources/views/livewire/server/form.blade.php index 474521c9c..a3722cb44 100644 --- a/resources/views/livewire/server/form.blade.php +++ b/resources/views/livewire/server/form.blade.php @@ -3,69 +3,104 @@

General

@if ($server->id === 0) - - You could lose a lot of functionalities if you change the server details of the server where Coolify - is - running on.
Please think again. -
+ + You could lose a lot of functionalities if you change the server details of the server where Coolify + is + running on.
Please think again. +
@else - Save - @if ($server->isFunctional()) - - Validate & configure - - - - - Revalidate server - - - @endif - @endif -
- @if ($server->isFunctional()) - Server is reachable and validated. - @else - You can't use this server until it is validated. - @endif - @if ((!$server->settings->is_reachable || !$server->settings->is_usable) && $server->id !== 0) + Save + @if ($server->isFunctional()) Validate & configure - + - - Validate Server & Install Docker Engine + + Revalidate server - @if ($server->validation_logs) -

Previous Validation Logs

-
- {!! $server->validation_logs !!} -
@endif + @endif +
+ @if ($server->isFunctional()) + Server is reachable and validated. + @else + You can't use this server until it is validated. + @endif + @if ((!$server->settings->is_reachable || !$server->settings->is_usable) && $server->id !== 0) + + Validate & configure + + + + + Validate Server & Install Docker Engine + + + @if ($server->validation_logs) +

Previous Validation Logs

+
+ {!! $server->validation_logs !!} +
+ @endif @endif @if ((!$server->settings->is_reachable || !$server->settings->is_usable) && $server->id === 0) - - Validate Server - + + Validate Server + @endif @if ($server->isForceDisabled() && isCloud()) -
The system has disabled the server because you have exceeded the - number of servers for which you have paid.
+
The system has disabled the server because you have exceeded the + number of servers for which you have paid.
@endif
@if (!$server->settings->is_swarm_worker && !$server->settings->is_build_server) - + @endif - +
+
+ + +
+
+ +
+ +
+
+
@if ($server->isFunctional()) - @if (!$server->isLocalhost()) - -
-

Cloudflare Tunnels -

- -
- @if ($server->settings->is_cloudflare_tunnel) - - @else - - - - @endif - @if (!$server->isBuildServer()) -

Swarm (experimental)

-
Read the docs here. -
- @if ($server->settings->is_swarm_worker) - - @else - - @endif - - @if ($server->settings->is_swarm_manager) - - @else - - @endif - @endif - @endif + @if (!$server->isLocalhost()) + +
+

Cloudflare Tunnels +

+ +
+ @if ($server->settings->is_cloudflare_tunnel) + @else -
-

Cloudflare Tunnels -

- -
- @if ($server->settings->is_cloudflare_tunnel) - - @else - - - - @endif + + + + @endif + @if (!$server->isBuildServer()) +

Swarm (experimental)

+
Read the docs here. +
+ @if ($server->settings->is_swarm_worker) + + @else + + @endif + + @if ($server->settings->is_swarm_manager) + + @else + + @endif + @endif + @endif + @else +
+

Cloudflare Tunnels +

+ +
+ @if ($server->settings->is_cloudflare_tunnel) + + @else + + + + @endif @endif
@@ -159,21 +194,32 @@ class="w-full mt-8 mb-4 font-bold box-without-bg bg-coollabs hover:bg-coollabs-1 helper="The Docker cleanup tasks will run when the disk usage exceeds this threshold." /> @endif
-
- - + @else + +
+
+ @endif
-
-

Sentinel

- {{-- @if ($server->isSentinelEnabled()) --}} - {{-- Restart --}} - {{-- @endif --}} +
+ +
-
Metrics are disabled until a few bugs are fixed.
- {{--
+
+
+

Sentinel

+ {{-- @if ($server->isSentinelEnabled()) --}} + {{-- Restart --}} + {{-- @endif --}} +
+
Metrics are disabled until a few bugs are fixed.
+ {{--
diff --git a/resources/views/livewire/settings/index.blade.php b/resources/views/livewire/settings/index.blade.php index c0ba76d00..7ef2d2b2a 100644 --- a/resources/views/livewire/settings/index.blade.php +++ b/resources/views/livewire/settings/index.blade.php @@ -17,6 +17,37 @@

Instance Settings

+
+ +
+ +
+ +
+
+

DNS Validation

@@ -71,4 +102,4 @@
-
+
\ No newline at end of file