diff --git a/app/Actions/Database/StartDatabaseProxy.php b/app/Actions/Database/StartDatabaseProxy.php
index 744bbaa50..21fd6eb97 100644
--- a/app/Actions/Database/StartDatabaseProxy.php
+++ b/app/Actions/Database/StartDatabaseProxy.php
@@ -27,6 +27,8 @@ class StartDatabaseProxy
$server = data_get($database, 'destination.server');
$containerName = data_get($database, 'uuid');
$proxyContainerName = "{$database->uuid}-proxy";
+ $isSSLEnabled = $database->enable_ssl ?? false;
+
if ($database->getMorphClass() === \App\Models\ServiceDatabase::class) {
$databaseType = $database->databaseType();
$network = $database->service->uuid;
@@ -42,6 +44,12 @@ class StartDatabaseProxy
'standalone-mongodb' => 27017,
default => throw new \Exception("Unsupported database type: $databaseType"),
};
+ if ($isSSLEnabled) {
+ $internalPort = match ($databaseType) {
+ 'standalone-redis', 'standalone-keydb', 'standalone-dragonfly' => 6380,
+ default => throw new \Exception("Unsupported database type: $databaseType"),
+ };
+ }
$configuration_dir = database_proxy_dir($database->uuid);
if (isDev()) {
diff --git a/app/Actions/Service/StartService.php b/app/Actions/Service/StartService.php
index d48594e62..dfef6a566 100644
--- a/app/Actions/Service/StartService.php
+++ b/app/Actions/Service/StartService.php
@@ -19,6 +19,7 @@ class StartService
StopService::run(service: $service, dockerCleanup: false);
}
$service->saveComposeConfigs();
+ $service->isConfigurationChanged(save: true);
$commands[] = 'cd '.$service->workdir();
$commands[] = "echo 'Saved configuration files to {$service->workdir()}.'";
if ($pullLatestImages) {
diff --git a/app/Jobs/CleanupInstanceStuffsJob.php b/app/Jobs/CleanupInstanceStuffsJob.php
index 53e344daf..60ae58489 100644
--- a/app/Jobs/CleanupInstanceStuffsJob.php
+++ b/app/Jobs/CleanupInstanceStuffsJob.php
@@ -23,7 +23,7 @@ class CleanupInstanceStuffsJob implements ShouldBeEncrypted, ShouldBeUnique, Sho
public function middleware(): array
{
- return [(new WithoutOverlapping('cleanup-instance-stuffs'))->dontRelease()];
+ return [(new WithoutOverlapping('cleanup-instance-stuffs'))->expireAfter(60)->dontRelease()];
}
public function handle(): void
diff --git a/app/Jobs/DockerCleanupJob.php b/app/Jobs/DockerCleanupJob.php
index 00dfd150a..519728ab0 100644
--- a/app/Jobs/DockerCleanupJob.php
+++ b/app/Jobs/DockerCleanupJob.php
@@ -31,7 +31,7 @@ class DockerCleanupJob implements ShouldBeEncrypted, ShouldQueue
public function middleware(): array
{
- return [(new WithoutOverlapping('docker-cleanup-'.$this->server->uuid))->dontRelease()];
+ return [(new WithoutOverlapping('docker-cleanup-'.$this->server->uuid))->expireAfter(600)->dontRelease()];
}
public function __construct(public Server $server, public bool $manualCleanup = false) {}
diff --git a/app/Jobs/PushServerUpdateJob.php b/app/Jobs/PushServerUpdateJob.php
index 65c72c8c9..61206da6f 100644
--- a/app/Jobs/PushServerUpdateJob.php
+++ b/app/Jobs/PushServerUpdateJob.php
@@ -70,7 +70,7 @@ class PushServerUpdateJob implements ShouldBeEncrypted, ShouldQueue
public function middleware(): array
{
- return [(new WithoutOverlapping('push-server-update-'.$this->server->uuid))->dontRelease()];
+ return [(new WithoutOverlapping('push-server-update-'.$this->server->uuid))->expireAfter(30)->dontRelease()];
}
public function backoff(): int
diff --git a/app/Jobs/RestartProxyJob.php b/app/Jobs/RestartProxyJob.php
index 49cfbba53..dba4f4ac8 100644
--- a/app/Jobs/RestartProxyJob.php
+++ b/app/Jobs/RestartProxyJob.php
@@ -23,7 +23,7 @@ class RestartProxyJob implements ShouldBeEncrypted, ShouldQueue
public function middleware(): array
{
- return [(new WithoutOverlapping('restart-proxy-'.$this->server->uuid))->dontRelease()];
+ return [(new WithoutOverlapping('restart-proxy-'.$this->server->uuid))->expireAfter(60)->dontRelease()];
}
public function __construct(public Server $server) {}
diff --git a/app/Jobs/ServerCheckJob.php b/app/Jobs/ServerCheckJob.php
index dcbac9ac3..499035237 100644
--- a/app/Jobs/ServerCheckJob.php
+++ b/app/Jobs/ServerCheckJob.php
@@ -28,7 +28,7 @@ class ServerCheckJob implements ShouldBeEncrypted, ShouldQueue
public function middleware(): array
{
- return [(new WithoutOverlapping('server-check-'.$this->server->uuid))->dontRelease()];
+ return [(new WithoutOverlapping('server-check-'.$this->server->uuid))->expireAfter(60)->dontRelease()];
}
public function __construct(public Server $server) {}
diff --git a/app/Jobs/ServerPatchCheckJob.php b/app/Jobs/ServerPatchCheckJob.php
index 7d1b853b1..18999c009 100644
--- a/app/Jobs/ServerPatchCheckJob.php
+++ b/app/Jobs/ServerPatchCheckJob.php
@@ -19,11 +19,11 @@ class ServerPatchCheckJob implements ShouldBeEncrypted, ShouldQueue
public $tries = 3;
- public $timeout = 600; // 10 minutes timeout
+ public $timeout = 600;
public function middleware(): array
{
- return [(new WithoutOverlapping('server-patch-check-'.$this->server->uuid))->dontRelease()];
+ return [(new WithoutOverlapping('server-patch-check-'.$this->server->uuid))->expireAfter(600)->dontRelease()];
}
public function __construct(public Server $server) {}
diff --git a/app/Livewire/Project/CloneMe.php b/app/Livewire/Project/CloneMe.php
index fefaff4f2..a7c44577c 100644
--- a/app/Livewire/Project/CloneMe.php
+++ b/app/Livewire/Project/CloneMe.php
@@ -56,7 +56,6 @@ class CloneMe extends Component
$this->project_id = $this->project->id;
$this->servers = currentTeam()
->servers()
- ->with('destinations')
->get()
->reject(fn ($server) => $server->isBuildServer());
$this->newName = str($this->project->name.'-clone-'.(string) new Cuid2)->slug();
diff --git a/app/Livewire/Project/Service/Heading.php b/app/Livewire/Project/Service/Heading.php
index d78fbe9ed..3492da324 100644
--- a/app/Livewire/Project/Service/Heading.php
+++ b/app/Livewire/Project/Service/Heading.php
@@ -63,7 +63,7 @@ class Heading extends Component
$this->service->databases->each(function ($database) {
$database->refresh();
});
- if (is_null($this->service->config_hash) || $this->service->isConfigurationChanged()) {
+ if (is_null($this->service->config_hash)) {
$this->service->isConfigurationChanged(true);
}
$this->dispatch('configurationChanged');
diff --git a/app/Livewire/Project/Shared/EnvironmentVariable/Show.php b/app/Livewire/Project/Shared/EnvironmentVariable/Show.php
index 535ac6c67..966d626b1 100644
--- a/app/Livewire/Project/Shared/EnvironmentVariable/Show.php
+++ b/app/Livewire/Project/Shared/EnvironmentVariable/Show.php
@@ -170,6 +170,7 @@ class Show extends Component
$this->syncData(true);
$this->dispatch('success', 'Environment variable updated.');
$this->dispatch('envsUpdated');
+ $this->dispatch('configurationChanged');
} catch (\Exception $e) {
return handleError($e);
}
diff --git a/app/Livewire/Project/Shared/Terminal.php b/app/Livewire/Project/Shared/Terminal.php
index 819d364e2..de2deeed4 100644
--- a/app/Livewire/Project/Shared/Terminal.php
+++ b/app/Livewire/Project/Shared/Terminal.php
@@ -68,11 +68,16 @@ class Terminal extends Component
// Escape the identifier for shell usage
$escapedIdentifier = escapeshellarg($identifier);
- $command = SshMultiplexingHelper::generateSshCommand($server, "docker exec -it {$escapedIdentifier} sh -c 'PATH=\$PATH:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin && if [ -f ~/.profile ]; then . ~/.profile; fi && if [ -n \"\$SHELL\" ]; then exec \$SHELL; else sh; fi'");
+ $shellCommand = 'PATH=$PATH:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin && '.
+ 'if [ -f ~/.profile ]; then . ~/.profile; fi && '.
+ 'if [ -n "$SHELL" ] && [ -x "$SHELL" ]; then exec $SHELL; else sh; fi';
+ $command = SshMultiplexingHelper::generateSshCommand($server, "docker exec -it {$escapedIdentifier} sh -c '{$shellCommand}'");
} else {
- $command = SshMultiplexingHelper::generateSshCommand($server, 'PATH=$PATH:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin && if [ -f ~/.profile ]; then . ~/.profile; fi && if [ -n "$SHELL" ]; then exec $SHELL; else sh; fi');
+ $shellCommand = 'PATH=$PATH:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin && '.
+ 'if [ -f ~/.profile ]; then . ~/.profile; fi && '.
+ 'if [ -n "$SHELL" ] && [ -x "$SHELL" ]; then exec $SHELL; else sh; fi';
+ $command = SshMultiplexingHelper::generateSshCommand($server, $shellCommand);
}
-
// ssh command is sent back to frontend then to websocket
// this is done because the websocket connection is not available here
// a better solution would be to remove websocket on NodeJS and work with something like
diff --git a/app/Livewire/Settings/Advanced.php b/app/Livewire/Settings/Advanced.php
new file mode 100644
index 000000000..4425b414d
--- /dev/null
+++ b/app/Livewire/Settings/Advanced.php
@@ -0,0 +1,118 @@
+route('dashboard');
+ }
+ $this->server = Server::findOrFail(0);
+ $this->settings = instanceSettings();
+ $this->custom_dns_servers = $this->settings->custom_dns_servers;
+ $this->allowed_ips = $this->settings->allowed_ips;
+ $this->do_not_track = $this->settings->do_not_track;
+ $this->is_registration_enabled = $this->settings->is_registration_enabled;
+ $this->is_dns_validation_enabled = $this->settings->is_dns_validation_enabled;
+ $this->is_api_enabled = $this->settings->is_api_enabled;
+ $this->disable_two_step_confirmation = $this->settings->disable_two_step_confirmation;
+ $this->is_sponsorship_popup_enabled = $this->settings->is_sponsorship_popup_enabled;
+ }
+
+ public function submit()
+ {
+ try {
+ $this->validate();
+
+ $this->custom_dns_servers = str($this->custom_dns_servers)->replaceEnd(',', '')->trim();
+ $this->custom_dns_servers = str($this->custom_dns_servers)->trim()->explode(',')->map(function ($dns) {
+ return str($dns)->trim()->lower();
+ })->unique()->implode(',');
+
+ $this->allowed_ips = str($this->allowed_ips)->replaceEnd(',', '')->trim();
+ $this->allowed_ips = str($this->allowed_ips)->trim()->explode(',')->map(function ($ip) {
+ return str($ip)->trim();
+ })->unique()->implode(',');
+
+ $this->instantSave();
+ } catch (\Exception $e) {
+ return handleError($e, $this);
+ }
+ }
+
+ public function instantSave()
+ {
+ try {
+ $this->settings->is_registration_enabled = $this->is_registration_enabled;
+ $this->settings->do_not_track = $this->do_not_track;
+ $this->settings->is_dns_validation_enabled = $this->is_dns_validation_enabled;
+ $this->settings->custom_dns_servers = $this->custom_dns_servers;
+ $this->settings->is_api_enabled = $this->is_api_enabled;
+ $this->settings->allowed_ips = $this->allowed_ips;
+ $this->settings->is_sponsorship_popup_enabled = $this->is_sponsorship_popup_enabled;
+ $this->settings->disable_two_step_confirmation = $this->disable_two_step_confirmation;
+ $this->settings->save();
+ $this->dispatch('success', 'Settings updated!');
+ } catch (\Exception $e) {
+ return handleError($e, $this);
+ }
+ }
+
+ public function toggleTwoStepConfirmation($password): bool
+ {
+ if (! Hash::check($password, Auth::user()->password)) {
+ $this->addError('password', 'The provided password is incorrect.');
+
+ return false;
+ }
+
+ $this->settings->disable_two_step_confirmation = $this->disable_two_step_confirmation = true;
+ $this->settings->save();
+ $this->dispatch('success', 'Two step confirmation has been disabled.');
+
+ return true;
+ }
+
+ public function render()
+ {
+ return view('livewire.settings.advanced');
+ }
+}
diff --git a/app/Livewire/Settings/Index.php b/app/Livewire/Settings/Index.php
index f9df7ee33..bce343224 100644
--- a/app/Livewire/Settings/Index.php
+++ b/app/Livewire/Settings/Index.php
@@ -2,11 +2,8 @@
namespace App\Livewire\Settings;
-use App\Jobs\CheckForUpdatesJob;
use App\Models\InstanceSettings;
use App\Models\Server;
-use Illuminate\Support\Facades\Auth;
-use Illuminate\Support\Facades\Hash;
use Livewire\Attributes\Computed;
use Livewire\Attributes\Validate;
use Livewire\Component;
@@ -15,10 +12,7 @@ class Index extends Component
{
public InstanceSettings $settings;
- protected Server $server;
-
- #[Validate('boolean')]
- public bool $is_auto_update_enabled;
+ public Server $server;
#[Validate('nullable|string|max:255')]
public ?string $fqdn = null;
@@ -29,48 +23,18 @@ class Index extends Component
#[Validate('required|integer|min:1025|max:65535')]
public int $public_port_max;
- #[Validate('nullable|string')]
- public ?string $custom_dns_servers = null;
-
#[Validate('nullable|string|max:255')]
public ?string $instance_name = null;
- #[Validate('nullable|string')]
- public ?string $allowed_ips = null;
-
#[Validate('nullable|string')]
public ?string $public_ipv4 = null;
#[Validate('nullable|string')]
public ?string $public_ipv6 = null;
- #[Validate('string')]
- public string $auto_update_frequency;
-
- #[Validate('string|required')]
- public string $update_check_frequency;
-
#[Validate('required|string|timezone')]
public string $instance_timezone;
- #[Validate('boolean')]
- public bool $do_not_track;
-
- #[Validate('boolean')]
- public bool $is_registration_enabled;
-
- #[Validate('boolean')]
- public bool $is_dns_validation_enabled;
-
- #[Validate('boolean')]
- public bool $is_api_enabled;
-
- #[Validate('boolean')]
- public bool $disable_two_step_confirmation;
-
- #[Validate('boolean')]
- public bool $is_sponsorship_popup_enabled;
-
public function render()
{
return view('livewire.settings.index');
@@ -80,27 +44,16 @@ class Index extends Component
{
if (! isInstanceAdmin()) {
return redirect()->route('dashboard');
- } else {
- $this->settings = instanceSettings();
- $this->fqdn = $this->settings->fqdn;
- $this->public_port_min = $this->settings->public_port_min;
- $this->public_port_max = $this->settings->public_port_max;
- $this->custom_dns_servers = $this->settings->custom_dns_servers;
- $this->instance_name = $this->settings->instance_name;
- $this->allowed_ips = $this->settings->allowed_ips;
- $this->public_ipv4 = $this->settings->public_ipv4;
- $this->public_ipv6 = $this->settings->public_ipv6;
- $this->do_not_track = $this->settings->do_not_track;
- $this->is_auto_update_enabled = $this->settings->is_auto_update_enabled;
- $this->is_registration_enabled = $this->settings->is_registration_enabled;
- $this->is_dns_validation_enabled = $this->settings->is_dns_validation_enabled;
- $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->instance_timezone = $this->settings->instance_timezone;
- $this->disable_two_step_confirmation = $this->settings->disable_two_step_confirmation;
- $this->is_sponsorship_popup_enabled = $this->settings->is_sponsorship_popup_enabled;
}
+ $this->settings = instanceSettings();
+ $this->server = Server::findOrFail(0);
+ $this->fqdn = $this->settings->fqdn;
+ $this->public_port_min = $this->settings->public_port_min;
+ $this->public_port_max = $this->settings->public_port_max;
+ $this->instance_name = $this->settings->instance_name;
+ $this->public_ipv4 = $this->settings->public_ipv4;
+ $this->public_ipv6 = $this->settings->public_ipv6;
+ $this->instance_timezone = $this->settings->instance_timezone;
}
#[Computed]
@@ -115,30 +68,13 @@ class Index extends Component
public function instantSave($isSave = true)
{
$this->validate();
- if ($this->settings->is_auto_update_enabled === true) {
- $this->validate([
- 'auto_update_frequency' => ['required', 'string'],
- ]);
- }
-
$this->settings->fqdn = $this->fqdn;
$this->settings->public_port_min = $this->public_port_min;
$this->settings->public_port_max = $this->public_port_max;
- $this->settings->custom_dns_servers = $this->custom_dns_servers;
$this->settings->instance_name = $this->instance_name;
- $this->settings->allowed_ips = $this->allowed_ips;
$this->settings->public_ipv4 = $this->public_ipv4;
$this->settings->public_ipv6 = $this->public_ipv6;
- $this->settings->do_not_track = $this->do_not_track;
- $this->settings->is_auto_update_enabled = $this->is_auto_update_enabled;
- $this->settings->is_registration_enabled = $this->is_registration_enabled;
- $this->settings->is_dns_validation_enabled = $this->is_dns_validation_enabled;
- $this->settings->is_api_enabled = $this->is_api_enabled;
- $this->settings->auto_update_frequency = $this->auto_update_frequency;
- $this->settings->update_check_frequency = $this->update_check_frequency;
- $this->settings->disable_two_step_confirmation = $this->disable_two_step_confirmation;
$this->settings->instance_timezone = $this->instance_timezone;
- $this->settings->is_sponsorship_popup_enabled = $this->is_sponsorship_popup_enabled;
if ($isSave) {
$this->settings->save();
$this->dispatch('success', 'Settings updated!');
@@ -149,7 +85,6 @@ class Index extends Component
{
try {
$error_show = false;
- $this->server = Server::findOrFail(0);
$this->resetErrorBag();
if (! validate_timezone($this->instance_timezone)) {
@@ -166,46 +101,15 @@ class Index extends Component
}
$this->validate();
- if ($this->is_auto_update_enabled && ! validate_cron_expression($this->auto_update_frequency)) {
- $this->dispatch('error', 'Invalid Cron / Human expression for Auto Update Frequency.');
- if (empty($this->auto_update_frequency)) {
- $this->auto_update_frequency = '0 0 * * *';
- }
-
- return;
- }
-
- if (! validate_cron_expression($this->update_check_frequency)) {
- $this->dispatch('error', 'Invalid Cron / Human expression for Update Check Frequency.');
- if (empty($this->update_check_frequency)) {
- $this->update_check_frequency = '0 * * * *';
- }
-
- return;
- }
-
- if ($this->settings->is_dns_validation_enabled && $this->settings->fqdn) {
- if (! validate_dns_entry($this->settings->fqdn, $this->server)) {
- $this->dispatch('error', "Validating DNS failed.
Make sure you have added the DNS records correctly.
{$this->settings->fqdn}->{$this->server->ip}
Check this documentation for further help.");
+ if ($this->settings->is_dns_validation_enabled && $this->fqdn) {
+ if (! validate_dns_entry($this->fqdn, $this->server)) {
+ $this->dispatch('error', "Validating DNS failed.
Make sure you have added the DNS records correctly.
{$this->fqdn}->{$this->server->ip}
Check this documentation for further help.");
$error_show = true;
}
}
- if ($this->settings->fqdn) {
- check_domain_usage(domain: $this->settings->fqdn);
+ if ($this->fqdn) {
+ check_domain_usage(domain: $this->fqdn);
}
- $this->settings->custom_dns_servers = str($this->settings->custom_dns_servers)->replaceEnd(',', '')->trim();
- $this->settings->custom_dns_servers = str($this->settings->custom_dns_servers)->trim()->explode(',')->map(function ($dns) {
- return str($dns)->trim()->lower();
- });
- $this->settings->custom_dns_servers = $this->settings->custom_dns_servers->unique();
- $this->settings->custom_dns_servers = $this->settings->custom_dns_servers->implode(',');
-
- $this->settings->allowed_ips = str($this->settings->allowed_ips)->replaceEnd(',', '')->trim();
- $this->settings->allowed_ips = str($this->settings->allowed_ips)->trim()->explode(',')->map(function ($ip) {
- return str($ip)->trim();
- });
- $this->settings->allowed_ips = $this->settings->allowed_ips->unique();
- $this->settings->allowed_ips = $this->settings->allowed_ips->implode(',');
$this->instantSave(isSave: false);
@@ -218,31 +122,4 @@ class Index extends Component
return handleError($e, $this);
}
}
-
- public function checkManually()
- {
- CheckForUpdatesJob::dispatchSync();
- $this->dispatch('updateAvailable');
- $settings = instanceSettings();
- if ($settings->new_version_available) {
- $this->dispatch('success', 'New version available!');
- } else {
- $this->dispatch('success', 'No new version available.');
- }
- }
-
- public function toggleTwoStepConfirmation($password): bool
- {
- if (! Hash::check($password, Auth::user()->password)) {
- $this->addError('password', 'The provided password is incorrect.');
-
- return false;
- }
-
- $this->settings->disable_two_step_confirmation = $this->disable_two_step_confirmation = true;
- $this->settings->save();
- $this->dispatch('success', 'Two step confirmation has been disabled.');
-
- return true;
- }
}
diff --git a/app/Livewire/Settings/Updates.php b/app/Livewire/Settings/Updates.php
new file mode 100644
index 000000000..fe20763b6
--- /dev/null
+++ b/app/Livewire/Settings/Updates.php
@@ -0,0 +1,101 @@
+server = Server::findOrFail(0);
+
+ $this->settings = instanceSettings();
+ $this->auto_update_frequency = $this->settings->auto_update_frequency;
+ $this->update_check_frequency = $this->settings->update_check_frequency;
+ $this->is_auto_update_enabled = $this->settings->is_auto_update_enabled;
+ }
+
+ public function instantSave()
+ {
+ try {
+ if ($this->settings->is_auto_update_enabled === true) {
+ $this->validate([
+ 'auto_update_frequency' => ['required', 'string'],
+ ]);
+ }
+ $this->settings->auto_update_frequency = $this->auto_update_frequency;
+ $this->settings->update_check_frequency = $this->update_check_frequency;
+ $this->settings->is_auto_update_enabled = $this->is_auto_update_enabled;
+ $this->settings->save();
+ $this->dispatch('success', 'Settings updated!');
+ } catch (\Exception $e) {
+ return handleError($e, $this);
+ }
+ }
+
+ public function submit()
+ {
+ try {
+ $this->resetErrorBag();
+ $this->validate();
+
+ if ($this->is_auto_update_enabled && ! validate_cron_expression($this->auto_update_frequency)) {
+ $this->dispatch('error', 'Invalid Cron / Human expression for Auto Update Frequency.');
+ if (empty($this->auto_update_frequency)) {
+ $this->auto_update_frequency = '0 0 * * *';
+ }
+
+ return;
+ }
+
+ if (! validate_cron_expression($this->update_check_frequency)) {
+ $this->dispatch('error', 'Invalid Cron / Human expression for Update Check Frequency.');
+ if (empty($this->update_check_frequency)) {
+ $this->update_check_frequency = '0 * * * *';
+ }
+
+ return;
+ }
+
+ $this->instantSave();
+ $this->server->setupDynamicProxyConfiguration();
+ } catch (\Exception $e) {
+ return handleError($e, $this);
+ }
+ }
+
+ public function checkManually()
+ {
+ CheckForUpdatesJob::dispatchSync();
+ $this->dispatch('updateAvailable');
+ $settings = instanceSettings();
+ if ($settings->new_version_available) {
+ $this->dispatch('success', 'New version available!');
+ } else {
+ $this->dispatch('success', 'No new version available.');
+ }
+ }
+
+ public function render()
+ {
+ return view('livewire.settings.updates');
+ }
+}
diff --git a/app/Livewire/SettingsBackup.php b/app/Livewire/SettingsBackup.php
index bb5ed0aa8..57cb79fca 100644
--- a/app/Livewire/SettingsBackup.php
+++ b/app/Livewire/SettingsBackup.php
@@ -46,32 +46,31 @@ class SettingsBackup extends Component
{
if (! isInstanceAdmin()) {
return redirect()->route('dashboard');
- } else {
- $settings = instanceSettings();
- $this->server = Server::findOrFail(0);
- $this->database = StandalonePostgresql::whereName('coolify-db')->first();
- $s3s = S3Storage::whereTeamId(0)->get() ?? [];
- if ($this->database) {
- $this->uuid = $this->database->uuid;
- $this->name = $this->database->name;
- $this->description = $this->database->description;
- $this->postgres_user = $this->database->postgres_user;
- $this->postgres_password = $this->database->postgres_password;
-
- if ($this->database->status !== 'running') {
- $this->database->status = 'running';
- $this->database->save();
- }
- $this->backup = $this->database->scheduledBackups->first();
- if ($this->backup && ! $this->server->isFunctional()) {
- $this->backup->enabled = false;
- $this->backup->save();
- }
- $this->executions = $this->backup->executions;
- }
- $this->settings = $settings;
- $this->s3s = $s3s;
}
+ $settings = instanceSettings();
+ $this->server = Server::findOrFail(0);
+ $this->database = StandalonePostgresql::whereName('coolify-db')->first();
+ $s3s = S3Storage::whereTeamId(0)->get() ?? [];
+ if ($this->database) {
+ $this->uuid = $this->database->uuid;
+ $this->name = $this->database->name;
+ $this->description = $this->database->description;
+ $this->postgres_user = $this->database->postgres_user;
+ $this->postgres_password = $this->database->postgres_password;
+
+ if ($this->database->status !== 'running') {
+ $this->database->status = 'running';
+ $this->database->save();
+ }
+ $this->backup = $this->database->scheduledBackups->first();
+ if ($this->backup && ! $this->server->isFunctional()) {
+ $this->backup->enabled = false;
+ $this->backup->save();
+ }
+ $this->executions = $this->backup->executions;
+ }
+ $this->settings = $settings;
+ $this->s3s = $s3s;
}
public function addCoolifyDatabase()
diff --git a/app/Livewire/Storage/Form.php b/app/Livewire/Storage/Form.php
index 8ca0020c7..ad1627863 100644
--- a/app/Livewire/Storage/Form.php
+++ b/app/Livewire/Storage/Form.php
@@ -31,7 +31,7 @@ class Form extends Component
'storage.endpoint' => 'Endpoint',
];
- public function test_s3_connection()
+ public function testConnection()
{
try {
$this->storage->testConnection(shouldSave: true);
@@ -45,6 +45,8 @@ class Form extends Component
public function delete()
{
try {
+ $this->authorize('delete', $this->storage);
+
$this->storage->delete();
return redirect()->route('storage.index');
@@ -57,7 +59,7 @@ class Form extends Component
{
$this->validate();
try {
- $this->test_s3_connection();
+ $this->testConnection();
} catch (\Throwable $e) {
return handleError($e, $this);
}
diff --git a/app/Models/Server.php b/app/Models/Server.php
index eac5bbcc1..41ecdafb8 100644
--- a/app/Models/Server.php
+++ b/app/Models/Server.php
@@ -887,7 +887,7 @@ $schema://$host {
public function muxFilename()
{
- return $this->uuid;
+ return 'mux_'.$this->uuid;
}
public function team()
diff --git a/app/Policies/S3StoragePolicy.php b/app/Policies/S3StoragePolicy.php
new file mode 100644
index 000000000..28f5f8426
--- /dev/null
+++ b/app/Policies/S3StoragePolicy.php
@@ -0,0 +1,66 @@
+teams()->where('id', $storage->team_id)->exists();
+ }
+
+ /**
+ * Determine whether the user can create models.
+ */
+ public function create(User $user): bool
+ {
+ return true;
+ }
+
+ /**
+ * Determine whether the user can update the model.
+ */
+ public function update(User $user, Server $server): bool
+ {
+ return $user->teams()->get()->firstWhere('id', $server->team_id) !== null;
+ }
+
+ /**
+ * Determine whether the user can delete the model.
+ */
+ public function delete(User $user, S3Storage $storage): bool
+ {
+ return $user->teams()->where('id', $storage->team_id)->exists();
+ }
+
+ /**
+ * Determine whether the user can restore the model.
+ */
+ public function restore(User $user, S3Storage $storage): bool
+ {
+ return false;
+ }
+
+ /**
+ * Determine whether the user can permanently delete the model.
+ */
+ public function forceDelete(User $user, S3Storage $storage): bool
+ {
+ return false;
+ }
+}
diff --git a/config/constants.php b/config/constants.php
index 2ab7596ff..946c41f60 100644
--- a/config/constants.php
+++ b/config/constants.php
@@ -2,7 +2,7 @@
return [
'coolify' => [
- 'version' => '4.0.0-beta.420.1',
+ 'version' => '4.0.0-beta.420.2',
'helper_version' => '1.0.8',
'realtime_version' => '1.0.9',
'self_hosted' => env('SELF_HOSTED', true),
diff --git a/other/nightly/versions.json b/other/nightly/versions.json
index 9fde1e53b..8d362115e 100644
--- a/other/nightly/versions.json
+++ b/other/nightly/versions.json
@@ -1,10 +1,10 @@
{
"coolify": {
"v4": {
- "version": "4.0.0-beta.420"
+ "version": "4.0.0-beta.420.2"
},
"nightly": {
- "version": "4.0.0-beta.421"
+ "version": "4.0.0-beta.420.3"
},
"helper": {
"version": "1.0.8"
diff --git a/public/svgs/excalidraw.svg b/public/svgs/excalidraw.svg
new file mode 100644
index 000000000..ee996762e
--- /dev/null
+++ b/public/svgs/excalidraw.svg
@@ -0,0 +1,7 @@
+
diff --git a/resources/css/utilities.css b/resources/css/utilities.css
index fe0cd10ed..d09d7f49c 100644
--- a/resources/css/utilities.css
+++ b/resources/css/utilities.css
@@ -42,7 +42,7 @@
}
@utility button {
- @apply flex gap-2 justify-center items-center px-2 py-1 text-sm text-black normal-case rounded-sm border outline-0 cursor-pointer bg-neutral-200/50 border-neutral-300 hover:bg-neutral-300 dark:bg-coolgray-200 dark:text-white dark:hover:text-white dark:hover:bg-coolgray-500 dark:border-coolgray-300 hover:text-black disabled:cursor-not-allowed min-w-fit dark:disabled:text-neutral-600 disabled:border-none disabled:hover:bg-transparent disabled:bg-transparent disabled:text-neutral-300;
+ @apply flex gap-2 justify-center items-center px-2 py-1 text-sm text-black normal-case rounded-sm border outline-0 cursor-pointer bg-neutral-200/50 border-neutral-300 hover:bg-neutral-300 dark:bg-coolgray-200 dark:text-white dark:hover:text-white dark:hover:bg-coolgray-500 dark:border-coolgray-300 hover:text-black disabled:cursor-not-allowed min-w-fit dark:disabled:text-neutral-600 disabled:border-transparent disabled:hover:bg-transparent disabled:bg-transparent disabled:text-neutral-300;
}
@utility alert-success {
diff --git a/resources/views/components/settings/navbar.blade.php b/resources/views/components/settings/navbar.blade.php
index a54dc1886..395c0953e 100644
--- a/resources/views/components/settings/navbar.blade.php
+++ b/resources/views/components/settings/navbar.blade.php
@@ -5,19 +5,19 @@
diff --git a/resources/views/components/settings/sidebar.blade.php b/resources/views/components/settings/sidebar.blade.php
new file mode 100644
index 000000000..ef2f0d5d2
--- /dev/null
+++ b/resources/views/components/settings/sidebar.blade.php
@@ -0,0 +1,8 @@
+