mirror of
https://github.com/ershisan99/coolify.git
synced 2026-01-03 12:34:08 +00:00
Compare commits
20 Commits
v4.0.0-bet
...
v4.0.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
655d004ce7 | ||
|
|
56981d134c | ||
|
|
b9d49d2951 | ||
|
|
0c1e7c499e | ||
|
|
32fead5753 | ||
|
|
e5e9faba35 | ||
|
|
2852630d6c | ||
|
|
a4cc406114 | ||
|
|
53b15a5762 | ||
|
|
929a4e6474 | ||
|
|
45b597bbab | ||
|
|
0d1a2aa5d1 | ||
|
|
b82353d5e2 | ||
|
|
b17c09f7a7 | ||
|
|
f6c3fe7888 | ||
|
|
2e855e030f | ||
|
|
49f86621f4 | ||
|
|
03d9f93397 | ||
|
|
c472042a94 | ||
|
|
9f4356f67d |
@@ -30,19 +30,19 @@ class StartProxy
|
||||
$server->save();
|
||||
|
||||
$activity = remote_process([
|
||||
"echo 'Creating required Docker networks...'",
|
||||
"echo '####### Creating required Docker networks...'",
|
||||
...$create_networks_command,
|
||||
"cd $proxy_path",
|
||||
"echo 'Creating Docker Compose file...'",
|
||||
"echo 'Pulling docker image...'",
|
||||
'docker compose pull -q',
|
||||
"echo 'Stopping existing proxy...'",
|
||||
"echo '####### Creating Docker Compose file...'",
|
||||
"echo '####### Pulling docker image...'",
|
||||
'docker compose pull',
|
||||
"echo '####### Stopping existing proxy...'",
|
||||
'docker compose down -v --remove-orphans',
|
||||
"lsof -nt -i:80 | xargs -r kill -9",
|
||||
"lsof -nt -i:443 | xargs -r kill -9",
|
||||
"echo 'Starting proxy...'",
|
||||
"echo '####### Starting proxy...'",
|
||||
'docker compose up -d --remove-orphans',
|
||||
"echo 'Proxy installed successfully...'"
|
||||
"echo '####### Proxy installed successfully...'"
|
||||
], $server);
|
||||
|
||||
return $activity;
|
||||
|
||||
@@ -18,42 +18,42 @@ class InstallDocker
|
||||
"max-file": "3"
|
||||
}
|
||||
}');
|
||||
$found = StandaloneDocker::where('server_id', $server->id);
|
||||
if ($found->count() == 0) {
|
||||
StandaloneDocker::create([
|
||||
'name' => 'coolify',
|
||||
'network' => 'coolify',
|
||||
'server_id' => $server->id,
|
||||
]);
|
||||
}
|
||||
if (isDev()) {
|
||||
$activity = remote_process([
|
||||
"echo ####### Installing Prerequisites...",
|
||||
"echo ####### Installing/updating Docker Engine...",
|
||||
"echo ####### Configuring Docker Engine (merging existing configuration with the required)...",
|
||||
"echo ####### Restarting Docker Engine...",
|
||||
return remote_process([
|
||||
"echo '####### Installing Prerequisites...'",
|
||||
"sleep 1",
|
||||
"echo '####### Installing/updating Docker Engine...'",
|
||||
"echo '####### Configuring Docker Engine (merging existing configuration with the required)...'",
|
||||
"sleep 4",
|
||||
"echo '####### Restarting Docker Engine...'",
|
||||
"ls -l /tmp"
|
||||
], $server);
|
||||
} else {
|
||||
$activity = remote_process([
|
||||
"echo ####### Installing Prerequisites...",
|
||||
return remote_process([
|
||||
"echo '####### Installing Prerequisites...'",
|
||||
"command -v jq >/dev/null || apt-get update",
|
||||
"command -v jq >/dev/null || apt install -y jq",
|
||||
"echo ####### Installing/updating Docker Engine...",
|
||||
"echo '####### Installing/updating Docker Engine...'",
|
||||
"curl https://releases.rancher.com/install-docker/{$dockerVersion}.sh | sh",
|
||||
"echo ####### Configuring Docker Engine (merging existing configuration with the required)...",
|
||||
"echo '####### Configuring Docker Engine (merging existing configuration with the required)...'",
|
||||
"test -s /etc/docker/daemon.json && cp /etc/docker/daemon.json \"/etc/docker/daemon.json.original-`date +\"%Y%m%d-%H%M%S\"`\" || echo '{$config}' | base64 -d > /etc/docker/daemon.json",
|
||||
"echo '{$config}' | base64 -d > /etc/docker/daemon.json.coolify",
|
||||
"cat <<< $(jq . /etc/docker/daemon.json.coolify) > /etc/docker/daemon.json.coolify",
|
||||
"cat <<< $(jq -s '.[0] * .[1]' /etc/docker/daemon.json /etc/docker/daemon.json.coolify) > /etc/docker/daemon.json",
|
||||
"echo ####### Restarting Docker Engine...",
|
||||
"echo '####### Restarting Docker Engine...'",
|
||||
"systemctl restart docker",
|
||||
"echo ####### Creating default network...",
|
||||
"docker network create --attachable coolify",
|
||||
"echo ####### Done!"
|
||||
"echo '####### Creating default Docker network (coolify)...'",
|
||||
"docker network create --attachable coolify >/dev/null 2>&1 || true",
|
||||
"echo '####### Done!'"
|
||||
], $server);
|
||||
$found = StandaloneDocker::where('server_id', $server->id);
|
||||
if ($found->count() == 0) {
|
||||
StandaloneDocker::create([
|
||||
'name' => 'coolify',
|
||||
'network' => 'coolify',
|
||||
'server_id' => $server->id,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return $activity;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ use Mail;
|
||||
use Str;
|
||||
|
||||
use function Laravel\Prompts\select;
|
||||
use function Laravel\Prompts\text;
|
||||
|
||||
class TestEmail extends Command
|
||||
{
|
||||
@@ -44,9 +45,10 @@ class TestEmail extends Command
|
||||
* Execute the console command.
|
||||
*/
|
||||
private ?MailMessage $mail = null;
|
||||
private string $email = 'andras.bacsai@protonmail.com';
|
||||
public function handle()
|
||||
{
|
||||
$email = select(
|
||||
$type = select(
|
||||
'Which Email should be sent?',
|
||||
options: [
|
||||
'emails-test' => 'Test',
|
||||
@@ -60,15 +62,15 @@ class TestEmail extends Command
|
||||
'waitlist-confirmation' => 'Waitlist Confirmation',
|
||||
],
|
||||
);
|
||||
$type = set_transanctional_email_settings();
|
||||
if (!$type) {
|
||||
throw new Exception('No email settings found.');
|
||||
}
|
||||
$this->email = text('Email Address to send to');
|
||||
set_transanctional_email_settings();
|
||||
|
||||
$this->mail = new MailMessage();
|
||||
$this->mail->subject("Test Email");
|
||||
switch ($email) {
|
||||
switch ($type) {
|
||||
case 'emails-test':
|
||||
$this->mail = (new Test())->toMail();
|
||||
$this->sendEmail();
|
||||
break;
|
||||
case 'application-deployment-success':
|
||||
$application = Application::all()->first();
|
||||
@@ -172,11 +174,7 @@ class TestEmail extends Command
|
||||
[],
|
||||
[],
|
||||
fn (Message $message) => $message
|
||||
->from(
|
||||
'internal@example.com',
|
||||
'Test Email',
|
||||
)
|
||||
->to('test@example.com')
|
||||
->to($this->email)
|
||||
->subject($this->mail->subject)
|
||||
->html((string)$this->mail->render())
|
||||
);
|
||||
|
||||
@@ -74,6 +74,11 @@ class Kernel extends ConsoleKernel
|
||||
if (!$scheduled_backup->enabled) {
|
||||
continue;
|
||||
}
|
||||
if (is_null(data_get($scheduled_backup,'database'))) {
|
||||
ray('database not found');
|
||||
$scheduled_backup->delete();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isset(VALID_CRON_STRINGS[$scheduled_backup->frequency])) {
|
||||
$scheduled_backup->frequency = VALID_CRON_STRINGS[$scheduled_backup->frequency];
|
||||
|
||||
@@ -6,6 +6,7 @@ use App\Actions\Server\InstallDocker;
|
||||
use App\Models\PrivateKey;
|
||||
use App\Models\Project;
|
||||
use App\Models\Server;
|
||||
use App\Models\Team;
|
||||
use Illuminate\Support\Collection;
|
||||
use Livewire\Component;
|
||||
|
||||
@@ -70,9 +71,10 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
||||
}
|
||||
public function skipBoarding()
|
||||
{
|
||||
currentTeam()->update([
|
||||
Team::find(currentTeam()->id)->update([
|
||||
'show_boarding' => false
|
||||
]);
|
||||
ray(currentTeam());
|
||||
refreshSession();
|
||||
return redirect()->route('dashboard');
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ class Create extends Component
|
||||
if ($this->from === 'server') {
|
||||
return redirect()->route('server.create');
|
||||
}
|
||||
return redirect()->route('private-key.show', ['private_key_uuid' => $private_key->uuid]);
|
||||
return redirect()->route('security.private-key.show', ['private_key_uuid' => $private_key->uuid]);
|
||||
} catch (\Exception $e) {
|
||||
return general_error_handler(err: $e, that: $this);
|
||||
}
|
||||
|
||||
@@ -54,13 +54,19 @@ class Form extends Component
|
||||
['uptime' => $uptime, 'dockerVersion' => $dockerVersion] = validateServer($this->server);
|
||||
if ($uptime) {
|
||||
$this->uptime = $uptime;
|
||||
$this->emit('success', 'Server is reachable!');
|
||||
} else {
|
||||
throw new \Exception('Server is not rachable');
|
||||
}
|
||||
if ($dockerVersion) {
|
||||
$this->dockerVersion = $dockerVersion;
|
||||
$this->emit('proxyStatusUpdated');
|
||||
$this->emit('success', 'Docker Engine 23+ is installed!');
|
||||
} else {
|
||||
throw new \Exception('Old Docker version detected (lower than 23).');
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return general_error_handler(customErrorMessage: "Server is not reachable. Reason: {$e->getMessage()}", that: $this);
|
||||
return general_error_handler($e, that: $this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,8 +83,6 @@ class Form extends Component
|
||||
} catch (\Exception $e) {
|
||||
return general_error_handler(err: $e, that: $this);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
public function submit()
|
||||
{
|
||||
|
||||
@@ -4,7 +4,6 @@ namespace App\Http\Livewire\Server;
|
||||
|
||||
use App\Models\Server;
|
||||
use Livewire\Component;
|
||||
use Masmerise\Toaster\Toaster;
|
||||
|
||||
class ShowPrivateKey extends Component
|
||||
{
|
||||
@@ -12,14 +11,24 @@ class ShowPrivateKey extends Component
|
||||
public $privateKeys;
|
||||
public $parameters;
|
||||
|
||||
public function setPrivateKey($private_key_id)
|
||||
public function setPrivateKey($newPrivateKeyId)
|
||||
{
|
||||
$this->server->update([
|
||||
'private_key_id' => $private_key_id
|
||||
]);
|
||||
refresh_server_connection($this->server->privateKey);
|
||||
$this->server->refresh();
|
||||
$this->checkConnection();
|
||||
try {
|
||||
$oldPrivateKeyId = $this->server->private_key_id;
|
||||
$this->server->update([
|
||||
'private_key_id' => $newPrivateKeyId
|
||||
]);
|
||||
$this->server->refresh();
|
||||
refresh_server_connection($this->server->privateKey);
|
||||
$this->checkConnection();
|
||||
} catch (\Exception $e) {
|
||||
$this->server->update([
|
||||
'private_key_id' => $oldPrivateKeyId
|
||||
]);
|
||||
$this->server->refresh();
|
||||
refresh_server_connection($this->server->privateKey);
|
||||
return general_error_handler($e, that: $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function checkConnection()
|
||||
@@ -27,13 +36,17 @@ class ShowPrivateKey extends Component
|
||||
try {
|
||||
['uptime' => $uptime, 'dockerVersion' => $dockerVersion] = validateServer($this->server);
|
||||
if ($uptime) {
|
||||
Toaster::success('Server is reachable with this private key.');
|
||||
$this->emit('success', 'Server is reachable with this private key.');
|
||||
} else {
|
||||
throw new \Exception('Server is not reachable with this private key.');
|
||||
}
|
||||
if ($dockerVersion) {
|
||||
Toaster::success('Server is usable for Coolify.');
|
||||
$this->emit('success', 'Server is usable for Coolify.');
|
||||
} else {
|
||||
throw new \Exception('Old Docker version detected (lower than 23).');
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return general_error_handler(customErrorMessage: "Server is not reachable. Reason: {$e->getMessage()}", that: $this);
|
||||
throw new \Exception($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,6 @@ class Email extends Component
|
||||
$this->validate([
|
||||
'settings.resend_api_key' => 'required'
|
||||
]);
|
||||
$this->settings->smtp_enabled = false;
|
||||
$this->settings->save();
|
||||
$this->emit('success', 'Settings saved successfully.');
|
||||
} catch (\Exception $e) {
|
||||
@@ -68,9 +67,18 @@ class Email extends Component
|
||||
return general_error_handler($e, $this);
|
||||
}
|
||||
}
|
||||
public function instantSaveResend() {
|
||||
try {
|
||||
$this->settings->smtp_enabled = false;
|
||||
$this->submitResend();
|
||||
} catch (\Exception $e) {
|
||||
return general_error_handler($e, $this);
|
||||
}
|
||||
}
|
||||
public function instantSave()
|
||||
{
|
||||
try {
|
||||
$this->settings->resend_enabled = false;
|
||||
$this->submit();
|
||||
} catch (\Exception $e) {
|
||||
return general_error_handler($e, $this);
|
||||
@@ -89,7 +97,6 @@ class Email extends Component
|
||||
'settings.smtp_password' => 'nullable',
|
||||
'settings.smtp_timeout' => 'nullable',
|
||||
]);
|
||||
$this->settings->resend_enabled = false;
|
||||
$this->settings->save();
|
||||
$this->emit('success', 'Settings saved successfully.');
|
||||
} catch (\Exception $e) {
|
||||
|
||||
@@ -23,7 +23,7 @@ class SwitchTeam extends Component
|
||||
if (!$team_to_switch_to) {
|
||||
return;
|
||||
}
|
||||
session(['currentTeam' => $team_to_switch_to]);
|
||||
refreshSession($team_to_switch_to);
|
||||
return redirect(request()->header('Referer'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ class IsBoardingFlow
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
// ray()->showQueries()->color('orange');
|
||||
ray()->showQueries()->color('orange');
|
||||
if (showBoarding() && !in_array($request->path(), allowedPathsForBoardingAccounts())) {
|
||||
return redirect('boarding');
|
||||
}
|
||||
|
||||
@@ -26,10 +26,8 @@ class DatabaseBackupJob implements ShouldQueue
|
||||
|
||||
public ?Team $team = null;
|
||||
public Server $server;
|
||||
public ?ScheduledDatabaseBackup $backup = null;
|
||||
public string $database_type;
|
||||
public ?StandalonePostgresql $database = null;
|
||||
public string $database_status;
|
||||
public ScheduledDatabaseBackup $backup;
|
||||
public StandalonePostgresql $database;
|
||||
|
||||
public ?string $container_name = null;
|
||||
public ?ScheduledDatabaseBackupExecution $backup_log = null;
|
||||
@@ -45,14 +43,8 @@ class DatabaseBackupJob implements ShouldQueue
|
||||
{
|
||||
$this->backup = $backup;
|
||||
$this->team = Team::find($backup->team_id);
|
||||
$this->database = $this->backup->database;
|
||||
if (!$this->database) {
|
||||
ray('Database not found');
|
||||
return;
|
||||
}
|
||||
$this->database_type = $this->database->type();
|
||||
$this->database = data_get($this->backup, 'database');
|
||||
$this->server = $this->database->destination->server;
|
||||
$this->database_status = $this->database->status;
|
||||
$this->s3 = $this->backup->s3;
|
||||
}
|
||||
|
||||
@@ -69,7 +61,7 @@ class DatabaseBackupJob implements ShouldQueue
|
||||
public function handle(): void
|
||||
{
|
||||
try {
|
||||
if ($this->database_status !== 'running') {
|
||||
if (data_get($this->database, 'status') !== 'running') {
|
||||
ray('database not running');
|
||||
return;
|
||||
}
|
||||
@@ -88,7 +80,7 @@ class DatabaseBackupJob implements ShouldQueue
|
||||
'filename' => $this->backup_location,
|
||||
'scheduled_database_backup_id' => $this->backup->id,
|
||||
]);
|
||||
if ($this->database_type === 'standalone-postgresql') {
|
||||
if ($this->database->type() === 'standalone-postgresql') {
|
||||
$this->backup_standalone_postgresql();
|
||||
}
|
||||
$this->calculate_size();
|
||||
@@ -103,7 +95,6 @@ class DatabaseBackupJob implements ShouldQueue
|
||||
send_internal_notification('DatabaseBackupJob failed with: ' . $th->getMessage());
|
||||
throw $th;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function backup_standalone_postgresql(): void
|
||||
|
||||
@@ -28,6 +28,11 @@ class StandalonePostgresql extends BaseModel
|
||||
'is_readonly' => true
|
||||
]);
|
||||
});
|
||||
static::deleted(function ($database) {
|
||||
$database->scheduledBackups()->delete();
|
||||
$database->persistentStorages()->delete();
|
||||
instant_remote_process(['docker volume rm postgres-data-' . $database->uuid], $database->destination->server, false);
|
||||
});
|
||||
}
|
||||
|
||||
public function portsMappings(): Attribute
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace App\Models;
|
||||
|
||||
use App\Notifications\Channels\SendsEmail;
|
||||
use App\Notifications\TransactionalEmails\ResetPassword as TransactionalEmailsResetPassword;
|
||||
use Cache;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
@@ -94,7 +95,9 @@ class User extends Authenticatable implements SendsEmail
|
||||
|
||||
public function currentTeam()
|
||||
{
|
||||
return Team::find(session('currentTeam')->id);
|
||||
return Cache::remember('team:' . auth()->user()->id, 3600, function() {
|
||||
return Team::find(session('currentTeam')->id);
|
||||
});
|
||||
}
|
||||
|
||||
public function otherTeams()
|
||||
|
||||
@@ -16,6 +16,7 @@ class DeploymentFailed extends Notification implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
public $tries = 5;
|
||||
public Application $application;
|
||||
public string $deployment_uuid;
|
||||
public ?ApplicationPreview $preview = null;
|
||||
|
||||
@@ -16,6 +16,7 @@ class DeploymentSuccess extends Notification implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
public $tries = 5;
|
||||
public Application $application;
|
||||
public string $deployment_uuid;
|
||||
public ApplicationPreview|null $preview = null;
|
||||
|
||||
@@ -14,6 +14,7 @@ class StatusChanged extends Notification implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
public $tries = 5;
|
||||
public $application;
|
||||
|
||||
public string $application_name;
|
||||
|
||||
@@ -14,6 +14,7 @@ class BackupFailed extends Notification implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
public $tries = 5;
|
||||
public string $name;
|
||||
public string $frequency;
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ class BackupSuccess extends Notification implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
public $tries = 5;
|
||||
public string $name;
|
||||
public string $frequency;
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ class GeneralNotification extends Notification implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
public $tries = 5;
|
||||
public function __construct(public string $message)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ class NotReachable extends Notification implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
public $tries = 5;
|
||||
public function __construct(public Server $server)
|
||||
{
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ class Test extends Notification implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
public $tries = 5;
|
||||
public function __construct(public string|null $emails = null)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ class InvitationLink extends Notification implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
public $tries = 5;
|
||||
public function via(): array
|
||||
{
|
||||
return [TransactionalEmailChannel::class];
|
||||
|
||||
@@ -12,6 +12,7 @@ class Test extends Notification implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
public $tries = 5;
|
||||
public function __construct(public string $emails)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ class Modal extends Component
|
||||
public string|null $modalTitle = null,
|
||||
public string|null $modalBody = null,
|
||||
public string|null $modalSubmit = null,
|
||||
public bool $noSubmit = false,
|
||||
public bool $yesOrNo = false,
|
||||
public string $action = 'delete'
|
||||
) {
|
||||
|
||||
@@ -164,9 +164,9 @@ function refresh_server_connection(PrivateKey $private_key)
|
||||
// Delete the old ssh mux file to force a new one to be created
|
||||
Storage::disk('ssh-mux')->delete($server->muxFilename());
|
||||
// check if user is authenticated
|
||||
if (currentTeam()->id) {
|
||||
currentTeam()->privateKeys = PrivateKey::where('team_id', currentTeam()->id)->get();
|
||||
}
|
||||
// if (currentTeam()->id) {
|
||||
// currentTeam()->privateKeys = PrivateKey::where('team_id', currentTeam()->id)->get();
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,7 +184,7 @@ function validateServer(Server $server)
|
||||
}
|
||||
$server->settings->is_reachable = true;
|
||||
|
||||
$dockerVersion = instant_remote_process(['docker version|head -2|grep -i version'], $server, false);
|
||||
$dockerVersion = instant_remote_process(["docker version|head -2|grep -i version| awk '{print $2}'"], $server, false);
|
||||
if (!$dockerVersion) {
|
||||
$dockerVersion = null;
|
||||
return [
|
||||
@@ -192,7 +192,13 @@ function validateServer(Server $server)
|
||||
"dockerVersion" => null,
|
||||
];
|
||||
}
|
||||
$server->settings->is_usable = true;
|
||||
$majorDockerVersion = Str::of($dockerVersion)->before('.')->value();
|
||||
if ($majorDockerVersion <= 22) {
|
||||
$dockerVersion = null;
|
||||
$server->settings->is_usable = false;
|
||||
} else {
|
||||
$server->settings->is_usable = true;
|
||||
}
|
||||
return [
|
||||
"uptime" => $uptime,
|
||||
"dockerVersion" => $dockerVersion,
|
||||
@@ -202,7 +208,7 @@ function validateServer(Server $server)
|
||||
$server->settings->is_usable = false;
|
||||
throw $e;
|
||||
} finally {
|
||||
$server->settings->save();
|
||||
if(data_get($server,'settings')) $server->settings->save();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -57,9 +57,15 @@ function showBoarding(): bool
|
||||
{
|
||||
return currentTeam()->show_boarding ?? false;
|
||||
}
|
||||
function refreshSession(): void
|
||||
function refreshSession(?Team $team = null): void
|
||||
{
|
||||
$team = Team::find(currentTeam()->id);
|
||||
if (!$team) {
|
||||
$team = Team::find(currentTeam()->id);
|
||||
}
|
||||
Cache::forget('team:' . auth()->user()->id);
|
||||
Cache::remember('team:' . auth()->user()->id, 3600, function() use ($team) {
|
||||
return $team;
|
||||
});
|
||||
session(['currentTeam' => $team]);
|
||||
}
|
||||
function general_error_handler(Throwable | null $err = null, $that = null, $isJson = false, $customErrorMessage = null): mixed
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
return [
|
||||
|
||||
// @see https://docs.sentry.io/product/sentry-basics/dsn-explainer/
|
||||
'dsn' => 'https://abe219b6573947128ecf523c835f5f38@o1082494.ingest.sentry.io/4505347448045568',
|
||||
'dsn' => 'https://62de992090e4e0cb28f18231835ea006@o1082494.ingest.sentry.io/4505347448045568',
|
||||
|
||||
// The release version of your application
|
||||
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
|
||||
'release' => '4.0.0-beta.28',
|
||||
'release' => '4.0.0-beta.31',
|
||||
'server_name' => env('APP_ID', 'coolify'),
|
||||
// When left empty or `null` the Laravel environment will be used
|
||||
'environment' => config('app.env'),
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<?php
|
||||
|
||||
return '4.0.0-beta.28';
|
||||
return '4.0.0-beta.31';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<dialog id="{{ $modalId }}" class="modal">
|
||||
@if ($yesOrNo)
|
||||
<form method="dialog" class="rounded modal-box" wire:submit.prevent='submit'>
|
||||
<form method="dialog" class="rounded modal-box" @if(!$noSubmit) wire:submit.prevent='submit' @endif>
|
||||
<div class="flex items-start">
|
||||
<div class="flex items-center justify-center flex-shrink-0 w-10 h-10 mr-4 rounded-full">
|
||||
<svg class="w-8 h-8 text-error" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
|
||||
@@ -34,7 +34,7 @@
|
||||
</form>
|
||||
@else
|
||||
<form method="dialog" class="flex flex-col w-11/12 max-w-5xl gap-2 rounded modal-box"
|
||||
wire:submit.prevent='submit'>
|
||||
@if(!$noSubmit) wire:submit.prevent='submit' @endif>
|
||||
@isset($modalTitle)
|
||||
<h3 class="text-lg font-bold">{{ $modalTitle }}</h3>
|
||||
@endisset
|
||||
|
||||
@@ -20,20 +20,31 @@
|
||||
id="team.discord_webhook_url" label="Webhook" />
|
||||
</form>
|
||||
@if (data_get($team, 'discord_enabled'))
|
||||
<h3 class="mt-4">Subscribe to events</h3>
|
||||
<h2 class="mt-4">Subscribe to events</h2>
|
||||
<div class="w-64">
|
||||
|
||||
|
||||
@if (isDev())
|
||||
<x-forms.checkbox instantSave="saveModel" id="team.discord_notifications_test" label="Test" />
|
||||
<h3 class="mt-4">Test</h3>
|
||||
<div class="flex items-end gap-10">
|
||||
<x-forms.checkbox instantSave="saveModel" id="team.discord_notifications_test" label="Enabled" />
|
||||
</div>
|
||||
@endif
|
||||
<h4 class="mt-4">General</h4>
|
||||
<x-forms.checkbox instantSave="saveModel" id="team.discord_notifications_status_changes"
|
||||
label="Container Status Changes" />
|
||||
<h4 class="mt-4">Applications</h4>
|
||||
<x-forms.checkbox instantSave="saveModel" id="team.discord_notifications_deployments"
|
||||
label="Deployments" />
|
||||
<h4 class="mt-4">Databases</h4>
|
||||
<x-forms.checkbox instantSave="saveModel" id="team.discord_notifications_database_backups"
|
||||
label="Backup Statuses" />
|
||||
<h3 class="mt-4">Container Status Changes</h3>
|
||||
<div class="flex items-end gap-10">
|
||||
<x-forms.checkbox instantSave="saveModel" id="team.discord_notifications_status_changes"
|
||||
label="Enabled" />
|
||||
</div>
|
||||
<h3 class="mt-4">Application Deployments</h3>
|
||||
<div class="flex items-end gap-10">
|
||||
<x-forms.checkbox instantSave="saveModel" id="team.discord_notifications_deployments"
|
||||
label="Enabled" />
|
||||
</div>
|
||||
<h3 class="mt-4">Backup Status</h3>
|
||||
<div class="flex items-end gap-10">
|
||||
<x-forms.checkbox instantSave="saveModel" id="team.discord_notifications_database_backups"
|
||||
label="Enabled" />
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
Copy from Instance Settings
|
||||
</x-forms.button>
|
||||
@endif
|
||||
@if (isEmailEnabled($team) || data_get($team, 'use_instance_email_settings'))
|
||||
@if (isEmailEnabled($team) && auth()->user()->isAdminFromSession())
|
||||
<x-forms.button onclick="sendTestEmail.showModal()"
|
||||
class="text-white normal-case btn btn-xs no-animation btn-primary">
|
||||
Send Test Email
|
||||
@@ -36,12 +36,11 @@
|
||||
label="Use hosted email service" />
|
||||
</div>
|
||||
@else
|
||||
<div class="pb-4 w-96">
|
||||
<x-forms.checkbox disabled id="team.use_instance_email_settings"
|
||||
label="Use hosted email service (Pro+ subscription required)" />
|
||||
</div>
|
||||
<div class="pb-4 w-96">
|
||||
<x-forms.checkbox disabled id="team.use_instance_email_settings"
|
||||
label="Use hosted email service (Pro+ subscription required)" />
|
||||
</div>
|
||||
@endif
|
||||
<h3 class="pb-4">Custom Email Service</h3>
|
||||
@if (!$team->use_instance_email_settings)
|
||||
<form class="flex flex-col items-end gap-2 pb-4 xl:flex-row" wire:submit.prevent='submitFromFields'>
|
||||
<x-forms.input required id="team.smtp_from_name" helper="Name used in emails." label="From Name" />
|
||||
@@ -110,19 +109,27 @@
|
||||
</div>
|
||||
@endif
|
||||
@if (isEmailEnabled($team) || data_get($team, 'use_instance_email_settings'))
|
||||
<h3 class="mt-4">Subscribe to events</h3>
|
||||
<h2 class="mt-4">Subscribe to events</h2>
|
||||
<div class="w-64">
|
||||
@if (isDev())
|
||||
<x-forms.checkbox instantSave="saveModel" id="team.smtp_notifications_test" label="Test" />
|
||||
<h3 class="mt-4">Test</h3>
|
||||
<div class="flex items-end gap-10">
|
||||
<x-forms.checkbox instantSave="saveModel" id="team.smtp_notifications_test" label="Enabled" />
|
||||
</div>
|
||||
@endif
|
||||
<h4 class="mt-4">General</h4>
|
||||
<x-forms.checkbox instantSave="saveModel" id="team.smtp_notifications_status_changes"
|
||||
label="Container Status Changes" />
|
||||
<h4 class="mt-4">Applications</h4>
|
||||
<x-forms.checkbox instantSave="saveModel" id="team.smtp_notifications_deployments" label="Deployments" />
|
||||
<h4 class="mt-4">Databases</h4>
|
||||
<x-forms.checkbox instantSave="saveModel" id="team.smtp_notifications_database_backups"
|
||||
label="Backup Statuses" />
|
||||
<h3 class="mt-4">Container Status Changes</h3>
|
||||
<div class="flex items-end gap-10">
|
||||
<x-forms.checkbox instantSave="saveModel" id="team.smtp_notifications_status_changes" label="Enabled" />
|
||||
</div>
|
||||
<h3 class="mt-4">Application Deployments</h3>
|
||||
<div class="flex items-end gap-10">
|
||||
<x-forms.checkbox instantSave="saveModel" id="team.smtp_notifications_deployments" label="Enabled" />
|
||||
</div>
|
||||
<h3 class="mt-4">Backup Status</h3>
|
||||
<div class="flex items-end gap-10">
|
||||
<x-forms.checkbox instantSave="saveModel" id="team.smtp_notifications_database_backups"
|
||||
label="Enabled" />
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@@ -18,11 +18,6 @@
|
||||
@else
|
||||
<x-forms.button type="submit">Save</x-forms.button>
|
||||
@endif
|
||||
@if (!$server->settings->is_reachable || !$server->settings->is_usable)
|
||||
<x-forms.button wire:click.prevent='validateServer'>
|
||||
Validate Server
|
||||
</x-forms.button>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
@if (!$server->settings->is_reachable || !$server->settings->is_usable)
|
||||
@@ -51,43 +46,25 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@if ($server->settings->is_reachable)
|
||||
@if (!$server->settings->is_reachable)
|
||||
<x-forms.button class="mt-8 mb-4 box" wire:click.prevent='validateServer'>
|
||||
Validate Server
|
||||
</x-forms.button>
|
||||
@endif
|
||||
@if ($server->settings->is_reachable && !$server->settings->is_usable && $server->id !== 0)
|
||||
<x-forms.button wire:poll.2000ms='validateServer' class="mt-8 mb-4 box" onclick="installDocker.showModal()" wire:click.prevent='installDocker' isHighlighted>
|
||||
Install Docker Engine 24.0
|
||||
</x-forms.button>
|
||||
@endif
|
||||
@if ($server->settings->is_usable)
|
||||
<h3 class="py-4">Settings</h3>
|
||||
<div class="flex items-center w-64 gap-2">
|
||||
<x-forms.input id="cleanup_after_percentage" label="Disk Cleanup threshold (%)" required
|
||||
helper="Disk cleanup job will be executed if disk usage is more than this number." />
|
||||
</div>
|
||||
|
||||
<h3 class="py-4">Actions</h3>
|
||||
<div class="flex items-center gap-2">
|
||||
<x-forms.button wire:click.prevent='validateServer'>
|
||||
Check Server Details
|
||||
</x-forms.button>
|
||||
@if ($server->id !== 0)
|
||||
<x-forms.button wire:click.prevent='installDocker' isHighlighted>
|
||||
@if ($server->settings->is_usable)
|
||||
Reconfigure Docker Engine
|
||||
@else
|
||||
Install Docker Engine
|
||||
@endif
|
||||
</x-forms.button>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
<div class="container w-full py-4 mx-auto">
|
||||
<livewire:activity-monitor header="Logs" />
|
||||
</div>
|
||||
@isset($uptime)
|
||||
<h3 class="pb-3">Server Info</h3>
|
||||
<div class="py-2 pb-4">
|
||||
<p>Uptime: {{ $uptime }}</p>
|
||||
@isset($dockerVersion)
|
||||
<p>Docker Engine {{ $dockerVersion }}</p>
|
||||
@endisset
|
||||
</div>
|
||||
@endisset
|
||||
</form>
|
||||
<h2>Danger Zone</h2>
|
||||
<h2 class="pt-4">Danger Zone</h2>
|
||||
<div class="">Woah. I hope you know what are you doing.</div>
|
||||
<h4 class="pt-4">Delete Server</h4>
|
||||
<div class="pb-4">This will remove this server from Coolify. Beware! There is no coming
|
||||
|
||||
@@ -22,11 +22,13 @@
|
||||
@endif
|
||||
|
||||
</div>
|
||||
<h3 class="pb-4">Select a different Private Key</h3>
|
||||
<div class="grid gap-2">
|
||||
<h3 class="pb-4">Choose another Key</h3>
|
||||
<div class="grid grid-cols-3 gap-2">
|
||||
@forelse ($privateKeys as $private_key)
|
||||
<div class="cursor-pointer box" wire:click='setPrivateKey({{ $private_key->id }})'>{{ $private_key->name }}
|
||||
</div>
|
||||
<x-forms.button class="flex flex-col box" wire:click='setPrivateKey({{ $private_key->id }})'>
|
||||
<div>{{ $private_key->name }}</div>
|
||||
<div class="text-xs">{{ $private_key->description }}</div>
|
||||
</x-forms.button>
|
||||
@empty
|
||||
<div>No private keys found.
|
||||
<x-use-magic-bar link="/security/private-key/new" />
|
||||
|
||||
@@ -1,4 +1,14 @@
|
||||
<div>
|
||||
<x-modal noSubmit modalId="installDocker">
|
||||
<x-slot:modalBody>
|
||||
<livewire:activity-monitor header="Installation Logs" />
|
||||
</x-slot:modalBody>
|
||||
<x-slot:modalSubmit>
|
||||
<x-forms.button onclick="installDocker.close()" type="submit">
|
||||
Close
|
||||
</x-forms.button>
|
||||
</x-slot:modalSubmit>
|
||||
</x-modal>
|
||||
<x-server.navbar :server="$server" />
|
||||
<livewire:server.form :server="$server" />
|
||||
</div>
|
||||
|
||||
@@ -22,12 +22,12 @@
|
||||
<x-forms.button type="submit">
|
||||
Save
|
||||
</x-forms.button>
|
||||
@if ($settings->resend_enabled || $settings->smtp_enabled)
|
||||
<x-forms.button onclick="sendTestEmail.showModal()"
|
||||
class="text-white normal-case btn btn-xs no-animation btn-primary">
|
||||
Send Test Email
|
||||
</x-forms.button>
|
||||
@endif
|
||||
@if (isEmailEnabled($settings))
|
||||
<x-forms.button onclick="sendTestEmail.showModal()"
|
||||
class="text-white normal-case btn btn-xs no-animation btn-primary">
|
||||
Send Test Email
|
||||
</x-forms.button>
|
||||
@endif
|
||||
</div>
|
||||
</form>
|
||||
<div class="flex flex-col gap-4">
|
||||
@@ -67,14 +67,15 @@
|
||||
<summary class="text-xl collapse-title">
|
||||
<div>Resend</div>
|
||||
<div class="w-32">
|
||||
<x-forms.checkbox instantSave='submitResend' id="settings.resend_enabled" label="Enabled" />
|
||||
<x-forms.checkbox instantSave='instantSaveResend' id="settings.resend_enabled" label="Enabled" />
|
||||
</div>
|
||||
</summary>
|
||||
<div class="collapse-content">
|
||||
<form wire:submit.prevent='submitResend' class="flex flex-col">
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="flex flex-col w-full gap-2 xl:flex-row">
|
||||
<x-forms.input type="password" id="settings.resend_api_key" placeholder="API key" label="Host" />
|
||||
<x-forms.input type="password" id="settings.resend_api_key" placeholder="API key"
|
||||
label="Host" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-end gap-4 pt-6">
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"version": "3.12.36"
|
||||
},
|
||||
"v4": {
|
||||
"version": "4.0.0-beta.28"
|
||||
"version": "4.0.0-beta.31"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user