Merge pull request #5416 from coollabsio/next

v4.0.0-beta.400
This commit is contained in:
Andras Bacsai 2025-03-27 10:37:36 +01:00 committed by GitHub
commit 6f648e4672
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
32 changed files with 574 additions and 325 deletions

View file

@ -183,7 +183,7 @@ public function handle(StandaloneMariadb $database)
$docker_compose = generateCustomDockerRunOptionsForDatabases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
if ($this->database->enable_ssl) {
$docker_compose['services'][$container_name]['command'] = [
'mysqld',
'mariadbd',
'--ssl-cert=/etc/mysql/certs/server.crt',
'--ssl-key=/etc/mysql/certs/server.key',
'--ssl-ca=/etc/mysql/certs/coolify-ca.crt',

View file

@ -30,10 +30,6 @@ public function handle(Server $server, $fromUI = false): bool
if (is_null($proxyType) || $proxyType === 'NONE' || $server->proxy->force_stop) {
return false;
}
['uptime' => $uptime, 'error' => $error] = $server->validateConnection();
if (! $uptime) {
throw new \Exception($error);
}
if (! $server->isProxyShouldRun()) {
if ($fromUI) {
throw new \Exception('Proxy should not run. You selected the Custom Proxy.');
@ -68,6 +64,38 @@ public function handle(Server $server, $fromUI = false): bool
$portsToCheck = ['80', '443'];
foreach ($portsToCheck as $port) {
// Try multiple methods to check port availability
$commands = [
// Method 1: Check /proc/net/tcp directly (convert port to hex)
"cat /proc/net/tcp | grep -q '00000000:".str_pad(dechex($port), 4, '0', STR_PAD_LEFT)."'",
// Method 2: Use ss command (modern alternative to netstat)
"ss -tuln | grep -q ':$port '",
// Method 3: Use lsof if available
"lsof -i :$port >/dev/null 2>&1",
// Method 4: Use fuser if available
"fuser $port/tcp >/dev/null 2>&1",
];
$portInUse = false;
foreach ($commands as $command) {
try {
instant_remote_process([$command], $server);
$portInUse = true;
break;
} catch (\Throwable $e) {
continue;
}
}
if ($portInUse) {
if ($fromUI) {
throw new \Exception("Port $port is in use.<br>You must stop the process using this port.<br><br>Docs: <a target='_blank' class='dark:text-white hover:underline' href='https://coolify.io/docs'>https://coolify.io/docs</a><br>Discord: <a target='_blank' class='dark:text-white hover:underline' href='https://coolify.io/discord'>https://coolify.io/discord</a>");
} else {
return false;
}
}
}
try {
if ($server->proxyType() !== ProxyTypes::NONE->value) {
$proxyCompose = CheckConfiguration::run($server);
@ -94,16 +122,6 @@ public function handle(Server $server, $fromUI = false): bool
if (count($portsToCheck) === 0) {
return false;
}
foreach ($portsToCheck as $port) {
$connection = @fsockopen($ip, $port);
if (is_resource($connection) && fclose($connection)) {
if ($fromUI) {
throw new \Exception("Port $port is in use.<br>You must stop the process using this port.<br>Docs: <a target='_blank' href='https://coolify.io/docs'>https://coolify.io/docs</a><br>Discord: <a target='_blank' href='https://coollabs.io/discord'>https://coollabs.io/discord</a>");
} else {
return false;
}
}
}
return true;
}

View file

@ -60,10 +60,12 @@ class General extends Component
public function getListeners()
{
$userId = Auth::id();
$teamId = Auth::user()->currentTeam()->id;
return [
"echo-private:team.{$teamId},DatabaseProxyStopped" => 'databaseProxyStopped',
"echo-private:user.{$userId},DatabaseStatusChanged" => '$refresh',
];
}
@ -226,6 +228,7 @@ public function regenerateSslCertificate()
caKey: $caCert->ssl_private_key,
configurationDir: $existingCert->configuration_dir,
mountPath: $existingCert->mount_path,
isPemKeyFileRequired: true,
);
$this->dispatch('success', 'SSL certificates regenerated. Restart database to apply changes.');

View file

@ -31,8 +31,8 @@ public function activityFinished()
$this->database->update([
'started_at' => now(),
]);
$this->dispatch('refresh');
$this->check_status();
if (is_null($this->database->config_hash) || $this->database->isConfigurationChanged()) {
$this->database->isConfigurationChanged(true);
$this->dispatch('configurationChanged');
@ -44,7 +44,7 @@ public function activityFinished()
public function check_status($showNotification = false)
{
if ($this->database->destination->server->isFunctional()) {
GetContainersStatus::dispatch($this->database->destination->server);
GetContainersStatus::run($this->database->destination->server);
}
if ($showNotification) {
@ -63,6 +63,7 @@ public function stop()
$this->database->status = 'exited';
$this->database->save();
$this->check_status();
$this->dispatch('refresh');
}
public function restart()

View file

@ -63,10 +63,13 @@ class General extends Component
public function getListeners()
{
$userId = Auth::id();
$teamId = Auth::user()->currentTeam()->id;
return [
"echo-private:team.{$teamId},DatabaseProxyStopped" => 'databaseProxyStopped',
"echo-private:user.{$userId},DatabaseStatusChanged" => '$refresh',
'refresh' => '$refresh',
];
}
@ -231,6 +234,7 @@ public function regenerateSslCertificate()
caKey: $caCert->ssl_private_key,
configurationDir: $existingCert->configuration_dir,
mountPath: $existingCert->mount_path,
isPemKeyFileRequired: true,
);
$this->dispatch('success', 'SSL certificates regenerated. Restart database to apply changes.');

View file

@ -10,6 +10,7 @@
use App\Models\StandaloneMariadb;
use Carbon\Carbon;
use Exception;
use Illuminate\Support\Facades\Auth;
use Livewire\Component;
class General extends Component
@ -26,6 +27,16 @@ class General extends Component
public ?Carbon $certificateValidUntil = null;
public function getListeners()
{
$userId = Auth::id();
return [
"echo-private:user.{$userId},DatabaseStatusChanged" => '$refresh',
'refresh' => '$refresh',
];
}
protected $rules = [
'database.name' => 'required',
'database.description' => 'nullable',
@ -173,6 +184,7 @@ public function regenerateSslCertificate()
caKey: $caCert->ssl_private_key,
configurationDir: $existingCert->configuration_dir,
mountPath: $existingCert->mount_path,
isPemKeyFileRequired: true,
);
$this->dispatch('success', 'SSL certificates have been regenerated. Please restart the database for changes to take effect.');

View file

@ -10,6 +10,7 @@
use App\Models\StandaloneMongodb;
use Carbon\Carbon;
use Exception;
use Illuminate\Support\Facades\Auth;
use Livewire\Component;
class General extends Component
@ -26,6 +27,16 @@ class General extends Component
public ?Carbon $certificateValidUntil = null;
public function getListeners()
{
$userId = Auth::id();
return [
"echo-private:user.{$userId},DatabaseStatusChanged" => '$refresh',
'refresh' => '$refresh',
];
}
protected $rules = [
'database.name' => 'required',
'database.description' => 'nullable',
@ -181,6 +192,7 @@ public function regenerateSslCertificate()
caKey: $caCert->ssl_private_key,
configurationDir: $existingCert->configuration_dir,
mountPath: $existingCert->mount_path,
isPemKeyFileRequired: true,
);
$this->dispatch('success', 'SSL certificates have been regenerated. Please restart the database for changes to take effect.');

View file

@ -10,6 +10,7 @@
use App\Models\StandaloneMysql;
use Carbon\Carbon;
use Exception;
use Illuminate\Support\Facades\Auth;
use Livewire\Component;
class General extends Component
@ -26,6 +27,16 @@ class General extends Component
public ?Carbon $certificateValidUntil = null;
public function getListeners()
{
$userId = Auth::id();
return [
"echo-private:user.{$userId},DatabaseStatusChanged" => '$refresh',
'refresh' => '$refresh',
];
}
protected $rules = [
'database.name' => 'required',
'database.description' => 'nullable',
@ -180,6 +191,7 @@ public function regenerateSslCertificate()
caKey: $caCert->ssl_private_key,
configurationDir: $existingCert->configuration_dir,
mountPath: $existingCert->mount_path,
isPemKeyFileRequired: true,
);
$this->dispatch('success', 'SSL certificates have been regenerated. Please restart the database for changes to take effect.');

View file

@ -10,6 +10,7 @@
use App\Models\StandalonePostgresql;
use Carbon\Carbon;
use Exception;
use Illuminate\Support\Facades\Auth;
use Livewire\Component;
class General extends Component
@ -30,8 +31,11 @@ class General extends Component
public function getListeners()
{
$userId = Auth::id();
return [
'refresh',
"echo-private:user.{$userId},DatabaseStatusChanged" => '$refresh',
'refresh' => '$refresh',
'save_init_script',
'delete_init_script',
];
@ -144,6 +148,7 @@ public function regenerateSslCertificate()
caKey: $caCert->ssl_private_key,
configurationDir: $existingCert->configuration_dir,
mountPath: $existingCert->mount_path,
isPemKeyFileRequired: true,
);
$this->dispatch('success', 'SSL certificates have been regenerated. Please restart the database for changes to take effect.');
@ -204,7 +209,7 @@ public function save_init_script($script)
$delete_command = "rm -f $old_file_path";
try {
instant_remote_process([$delete_command], $this->server);
} catch (\Exception $e) {
} catch (Exception $e) {
$this->dispatch('error', 'Failed to remove old init script from server: '.$e->getMessage());
return;
@ -245,7 +250,7 @@ public function delete_init_script($script)
$command = "rm -f $file_path";
try {
instant_remote_process([$command], $this->server);
} catch (\Exception $e) {
} catch (Exception $e) {
$this->dispatch('error', 'Failed to remove init script from server: '.$e->getMessage());
return;
@ -262,16 +267,11 @@ public function delete_init_script($script)
$this->database->init_scripts = $updatedScripts;
$this->database->save();
$this->refresh();
$this->dispatch('refresh')->self();
$this->dispatch('success', 'Init script deleted from the database and the server.');
}
}
public function refresh(): void
{
$this->database->refresh();
}
public function save_new_init_script()
{
$this->validate([

View file

@ -10,15 +10,11 @@
use App\Models\StandaloneRedis;
use Carbon\Carbon;
use Exception;
use Illuminate\Support\Facades\Auth;
use Livewire\Component;
class General extends Component
{
protected $listeners = [
'envsUpdated' => 'refresh',
'refresh',
];
public Server $server;
public StandaloneRedis $database;
@ -35,6 +31,17 @@ class General extends Component
public ?Carbon $certificateValidUntil = null;
public function getListeners()
{
$userId = Auth::id();
return [
"echo-private:user.{$userId},DatabaseStatusChanged" => '$refresh',
'envsUpdated' => 'refresh',
'refresh',
];
}
protected $rules = [
'database.name' => 'required',
'database.description' => 'nullable',
@ -181,6 +188,7 @@ public function regenerateSslCertificate()
caKey: $caCert->ssl_private_key,
configurationDir: $existingCert->configuration_dir,
mountPath: $existingCert->mount_path,
isPemKeyFileRequired: true,
);
$this->dispatch('success', 'SSL certificates regenerated. Restart database to apply changes.');

View file

@ -70,10 +70,6 @@ public function team()
public function isEnabled()
{
if (isCloud()) {
return true;
}
return $this->smtp_enabled || $this->resend_enabled || $this->use_instance_email_settings;
}
}

View file

@ -248,9 +248,9 @@ protected function internalDbUrl(): Attribute
$encodedPass = rawurlencode($this->mongo_initdb_root_password);
$url = "mongodb://{$encodedUser}:{$encodedPass}@{$this->uuid}:27017/?directConnection=true";
if ($this->enable_ssl) {
$url .= '&tls=true';
$url .= '&tls=true&tlsCAFile=/etc/mongo/certs/ca.pem';
if (in_array($this->ssl_mode, ['verify-full'])) {
$url .= '&tlsCAFile=/etc/ssl/certs/coolify-ca.crt';
$url .= '&tlsCertificateKeyFile=/etc/mongo/certs/server.pem';
}
}
@ -268,9 +268,9 @@ protected function externalDbUrl(): Attribute
$encodedPass = rawurlencode($this->mongo_initdb_root_password);
$url = "mongodb://{$encodedUser}:{$encodedPass}@{$this->destination->server->getIp}:{$this->public_port}/?directConnection=true";
if ($this->enable_ssl) {
$url .= '&tls=true';
$url .= '&tls=true&tlsCAFile=/etc/mongo/certs/ca.pem';
if (in_array($this->ssl_mode, ['verify-full'])) {
$url .= '&tlsCAFile=/etc/ssl/certs/coolify-ca.crt';
$url .= '&tlsCertificateKeyFile=/etc/mongo/certs/server.pem';
}
}

View file

@ -83,7 +83,7 @@ public function toTelegram(): array
'buttons' => [
[
'text' => 'Go to your dashboard',
'url' => base_url(),
'url' => isDev() ? 'https://staging-but-dev.coolify.io' : base_url(),
],
],
];

View file

@ -18,6 +18,7 @@ public function __construct(
public ?string $label = null,
public ?string $helper = null,
public bool $required = false,
public bool $disabled = false,
public string $defaultClass = 'select w-full'
) {
//

View file

@ -2,7 +2,7 @@
return [
'coolify' => [
'version' => '4.0.0-beta.399',
'version' => '4.0.0-beta.400',
'helper_version' => '1.0.7',
'realtime_version' => '1.0.6',
'self_hosted' => env('SELF_HOSTED', true),

View file

@ -19,21 +19,53 @@ public function up(): void
});
if (DB::table('local_file_volumes')->exists()) {
DB::beginTransaction();
DB::table('local_file_volumes')
->orderBy('id')
->chunk(100, function ($volumes) {
foreach ($volumes as $volume) {
try {
$fs_path = $volume->fs_path;
$mount_path = $volume->mount_path;
$content = $volume->content;
// Check if fields are already encrypted by attempting to decrypt
try {
if ($fs_path) {
Crypt::decryptString($fs_path);
}
} catch (\Exception $e) {
$fs_path = $fs_path ? Crypt::encryptString($fs_path) : null;
}
try {
if ($mount_path) {
Crypt::decryptString($mount_path);
}
} catch (\Exception $e) {
$mount_path = $mount_path ? Crypt::encryptString($mount_path) : null;
}
try {
if ($content) {
Crypt::decryptString($content);
}
} catch (\Exception $e) {
$content = $content ? Crypt::encryptString($content) : null;
}
DB::table('local_file_volumes')->where('id', $volume->id)->update([
'fs_path' => $volume->fs_path ? Crypt::encryptString($volume->fs_path) : null,
'mount_path' => $volume->mount_path ? Crypt::encryptString($volume->mount_path) : null,
'content' => $volume->content ? Crypt::encryptString($volume->content) : null,
'fs_path' => $fs_path,
'mount_path' => $mount_path,
'content' => $content,
]);
echo "Updated volume {$volume->id}\n";
} catch (\Exception $e) {
echo "Error encrypting local file volume fields: {$e->getMessage()}\n";
Log::error('Error encrypting local file volume fields: '.$e->getMessage());
}
}
});
DB::commit();
}
}
@ -49,21 +81,53 @@ public function down(): void
});
if (DB::table('local_file_volumes')->exists()) {
DB::beginTransaction();
DB::table('local_file_volumes')
->orderBy('id')
->chunk(100, function ($volumes) {
foreach ($volumes as $volume) {
try {
$fs_path = $volume->fs_path;
$mount_path = $volume->mount_path;
$content = $volume->content;
// Check if fields are already decrypted by attempting to decrypt
try {
if ($fs_path) {
Crypt::decryptString($fs_path);
}
} catch (\Exception $e) {
$fs_path = $fs_path ? Crypt::decryptString($fs_path) : null;
}
try {
if ($mount_path) {
Crypt::decryptString($mount_path);
}
} catch (\Exception $e) {
$mount_path = $mount_path ? Crypt::decryptString($mount_path) : null;
}
try {
if ($content) {
Crypt::decryptString($content);
}
} catch (\Exception $e) {
$content = $content ? Crypt::decryptString($content) : null;
}
DB::table('local_file_volumes')->where('id', $volume->id)->update([
'fs_path' => $volume->fs_path ? Crypt::decryptString($volume->fs_path) : null,
'mount_path' => $volume->mount_path ? Crypt::decryptString($volume->mount_path) : null,
'content' => $volume->content ? Crypt::decryptString($volume->content) : null,
'fs_path' => $fs_path,
'mount_path' => $mount_path,
'content' => $content,
]);
echo "Updated volume {$volume->id}\n";
} catch (\Exception $e) {
echo "Error decrypting local file volume fields: {$e->getMessage()}\n";
Log::error('Error decrypting local file volume fields: '.$e->getMessage());
}
}
});
DB::commit();
}
}
};

View file

@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('standalone_mongodbs', function (Blueprint $table) {
$table->boolean('enable_ssl')->default(false)->change();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('standalone_mongodbs', function (Blueprint $table) {
$table->boolean('enable_ssl')->default(true)->change();
});
}
};

View file

@ -30,9 +30,11 @@ fi
# Make sure coolify network exists
# It is created when starting Coolify with docker compose
if ! docker network create --attachable --ipv6 coolify 2>/dev/null; then
echo "Failed to create coolify network with ipv6. Trying without ipv6..."
docker network create --attachable coolify 2>/dev/null
if ! docker network inspect coolify >/dev/null 2>&1; then
if ! docker network create --attachable --ipv6 coolify 2>/dev/null; then
echo "Failed to create coolify network with ipv6. Trying without ipv6..."
docker network create --attachable coolify 2>/dev/null
fi
fi
# docker network create --attachable --driver=overlay coolify-overlay 2>/dev/null

View file

@ -1,10 +1,10 @@
{
"coolify": {
"v4": {
"version": "4.0.0-beta.397"
"version": "4.0.0-beta.400"
},
"nightly": {
"version": "4.0.0-beta.398"
"version": "4.0.0-beta.401"
},
"helper": {
"version": "1.0.7"

226
package-lock.json generated
View file

@ -15,14 +15,14 @@
"devDependencies": {
"@vitejs/plugin-vue": "5.2.1",
"autoprefixer": "10.4.20",
"axios": "1.7.9",
"axios": "1.8.2",
"laravel-echo": "2.0.2",
"laravel-vite-plugin": "^1.2.0",
"postcss": "8.5.3",
"pusher-js": "8.4.0",
"tailwind-scrollbar": "^3.1.0",
"tailwindcss": "3.4.17",
"vite": "^6.1.1",
"vite": "^6.2.3",
"vue": "3.5.13"
}
},
@ -88,9 +88,9 @@
}
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz",
"integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==",
"version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.1.tgz",
"integrity": "sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==",
"cpu": [
"ppc64"
],
@ -105,9 +105,9 @@
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.2.tgz",
"integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==",
"version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.1.tgz",
"integrity": "sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==",
"cpu": [
"arm"
],
@ -122,9 +122,9 @@
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz",
"integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==",
"version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.1.tgz",
"integrity": "sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==",
"cpu": [
"arm64"
],
@ -139,9 +139,9 @@
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.2.tgz",
"integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==",
"version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.1.tgz",
"integrity": "sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==",
"cpu": [
"x64"
],
@ -156,9 +156,9 @@
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz",
"integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==",
"version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.1.tgz",
"integrity": "sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==",
"cpu": [
"arm64"
],
@ -173,9 +173,9 @@
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz",
"integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==",
"version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.1.tgz",
"integrity": "sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==",
"cpu": [
"x64"
],
@ -190,9 +190,9 @@
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz",
"integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==",
"version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.1.tgz",
"integrity": "sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==",
"cpu": [
"arm64"
],
@ -207,9 +207,9 @@
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz",
"integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==",
"version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.1.tgz",
"integrity": "sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==",
"cpu": [
"x64"
],
@ -224,9 +224,9 @@
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz",
"integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==",
"version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.1.tgz",
"integrity": "sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==",
"cpu": [
"arm"
],
@ -241,9 +241,9 @@
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz",
"integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==",
"version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.1.tgz",
"integrity": "sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==",
"cpu": [
"arm64"
],
@ -258,9 +258,9 @@
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz",
"integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==",
"version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.1.tgz",
"integrity": "sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==",
"cpu": [
"ia32"
],
@ -275,9 +275,9 @@
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz",
"integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==",
"version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.1.tgz",
"integrity": "sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==",
"cpu": [
"loong64"
],
@ -292,9 +292,9 @@
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz",
"integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==",
"version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.1.tgz",
"integrity": "sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==",
"cpu": [
"mips64el"
],
@ -309,9 +309,9 @@
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz",
"integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==",
"version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.1.tgz",
"integrity": "sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==",
"cpu": [
"ppc64"
],
@ -326,9 +326,9 @@
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz",
"integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==",
"version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.1.tgz",
"integrity": "sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==",
"cpu": [
"riscv64"
],
@ -343,9 +343,9 @@
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz",
"integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==",
"version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.1.tgz",
"integrity": "sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==",
"cpu": [
"s390x"
],
@ -360,9 +360,9 @@
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz",
"integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==",
"version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.1.tgz",
"integrity": "sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==",
"cpu": [
"x64"
],
@ -377,9 +377,9 @@
}
},
"node_modules/@esbuild/netbsd-arm64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz",
"integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==",
"version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.1.tgz",
"integrity": "sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g==",
"cpu": [
"arm64"
],
@ -394,9 +394,9 @@
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz",
"integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==",
"version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.1.tgz",
"integrity": "sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==",
"cpu": [
"x64"
],
@ -411,9 +411,9 @@
}
},
"node_modules/@esbuild/openbsd-arm64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz",
"integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==",
"version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.1.tgz",
"integrity": "sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg==",
"cpu": [
"arm64"
],
@ -428,9 +428,9 @@
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz",
"integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==",
"version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.1.tgz",
"integrity": "sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==",
"cpu": [
"x64"
],
@ -445,9 +445,9 @@
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz",
"integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==",
"version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.1.tgz",
"integrity": "sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==",
"cpu": [
"x64"
],
@ -462,9 +462,9 @@
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz",
"integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==",
"version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.1.tgz",
"integrity": "sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==",
"cpu": [
"arm64"
],
@ -479,9 +479,9 @@
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz",
"integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==",
"version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.1.tgz",
"integrity": "sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==",
"cpu": [
"ia32"
],
@ -496,9 +496,9 @@
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz",
"integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==",
"version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.1.tgz",
"integrity": "sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==",
"cpu": [
"x64"
],
@ -1220,9 +1220,9 @@
}
},
"node_modules/axios": {
"version": "1.7.9",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz",
"integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==",
"version": "1.8.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.8.2.tgz",
"integrity": "sha512-ls4GYBm5aig9vWx8AWDSGLpnpDQRtWAfrjU+EuytuODrFBkqesN2RkOQCBzrA1RQNHw1SmRMSDDDSwzNAYQ6Rg==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -1520,9 +1520,9 @@
}
},
"node_modules/esbuild": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz",
"integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==",
"version": "0.25.1",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.1.tgz",
"integrity": "sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
@ -1533,31 +1533,31 @@
"node": ">=18"
},
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.24.2",
"@esbuild/android-arm": "0.24.2",
"@esbuild/android-arm64": "0.24.2",
"@esbuild/android-x64": "0.24.2",
"@esbuild/darwin-arm64": "0.24.2",
"@esbuild/darwin-x64": "0.24.2",
"@esbuild/freebsd-arm64": "0.24.2",
"@esbuild/freebsd-x64": "0.24.2",
"@esbuild/linux-arm": "0.24.2",
"@esbuild/linux-arm64": "0.24.2",
"@esbuild/linux-ia32": "0.24.2",
"@esbuild/linux-loong64": "0.24.2",
"@esbuild/linux-mips64el": "0.24.2",
"@esbuild/linux-ppc64": "0.24.2",
"@esbuild/linux-riscv64": "0.24.2",
"@esbuild/linux-s390x": "0.24.2",
"@esbuild/linux-x64": "0.24.2",
"@esbuild/netbsd-arm64": "0.24.2",
"@esbuild/netbsd-x64": "0.24.2",
"@esbuild/openbsd-arm64": "0.24.2",
"@esbuild/openbsd-x64": "0.24.2",
"@esbuild/sunos-x64": "0.24.2",
"@esbuild/win32-arm64": "0.24.2",
"@esbuild/win32-ia32": "0.24.2",
"@esbuild/win32-x64": "0.24.2"
"@esbuild/aix-ppc64": "0.25.1",
"@esbuild/android-arm": "0.25.1",
"@esbuild/android-arm64": "0.25.1",
"@esbuild/android-x64": "0.25.1",
"@esbuild/darwin-arm64": "0.25.1",
"@esbuild/darwin-x64": "0.25.1",
"@esbuild/freebsd-arm64": "0.25.1",
"@esbuild/freebsd-x64": "0.25.1",
"@esbuild/linux-arm": "0.25.1",
"@esbuild/linux-arm64": "0.25.1",
"@esbuild/linux-ia32": "0.25.1",
"@esbuild/linux-loong64": "0.25.1",
"@esbuild/linux-mips64el": "0.25.1",
"@esbuild/linux-ppc64": "0.25.1",
"@esbuild/linux-riscv64": "0.25.1",
"@esbuild/linux-s390x": "0.25.1",
"@esbuild/linux-x64": "0.25.1",
"@esbuild/netbsd-arm64": "0.25.1",
"@esbuild/netbsd-x64": "0.25.1",
"@esbuild/openbsd-arm64": "0.25.1",
"@esbuild/openbsd-x64": "0.25.1",
"@esbuild/sunos-x64": "0.25.1",
"@esbuild/win32-arm64": "0.25.1",
"@esbuild/win32-ia32": "0.25.1",
"@esbuild/win32-x64": "0.25.1"
}
},
"node_modules/escalade": {
@ -2802,14 +2802,14 @@
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
"node_modules/vite": {
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/vite/-/vite-6.1.1.tgz",
"integrity": "sha512-4GgM54XrwRfrOp297aIYspIti66k56v16ZnqHvrIM7mG+HjDlAwS7p+Srr7J6fGvEdOJ5JcQ/D9T7HhtdXDTzA==",
"version": "6.2.3",
"resolved": "https://registry.npmjs.org/vite/-/vite-6.2.3.tgz",
"integrity": "sha512-IzwM54g4y9JA/xAeBPNaDXiBF8Jsgl3VBQ2YQ/wOY6fyW3xMdSoltIV3Bo59DErdqdE6RxUfv8W69DvUorE4Eg==",
"dev": true,
"license": "MIT",
"dependencies": {
"esbuild": "^0.24.2",
"postcss": "^8.5.2",
"esbuild": "^0.25.0",
"postcss": "^8.5.3",
"rollup": "^4.30.1"
},
"bin": {

View file

@ -9,14 +9,14 @@
"devDependencies": {
"@vitejs/plugin-vue": "5.2.1",
"autoprefixer": "10.4.20",
"axios": "1.7.9",
"axios": "1.8.2",
"laravel-echo": "2.0.2",
"laravel-vite-plugin": "^1.2.0",
"postcss": "8.5.3",
"pusher-js": "8.4.0",
"tailwind-scrollbar": "^3.1.0",
"tailwindcss": "3.4.17",
"vite": "^6.1.1",
"vite": "^6.2.3",
"vue": "3.5.13"
},
"dependencies": {

View file

@ -46,7 +46,7 @@ .select {
.input,
.select {
@apply text-black dark:bg-coolgray-100 dark:text-white ring-neutral-200 dark:ring-coolgray-300 block w-full py-1.5 rounded border-0 text-sm ring-1 ring-inset;
@apply text-black dark:bg-coolgray-100 dark:text-white ring-neutral-200 dark:ring-coolgray-300 block w-full py-1.5 rounded border-0 text-sm ring-1 ring-inset disabled:dark:bg-coolgray-100/40 disabled:dark:ring-transparent disabled:bg-neutral-200 disabled:text-neutral-500;
}
.select {
@ -97,6 +97,7 @@ label {
@apply dark:text-neutral-400;
}
table {
@apply min-w-full divide-y dark:divide-coolgray-200 divide-neutral-300;
}

View file

@ -1,6 +1,7 @@
<div class="w-full">
@if ($label)
<label class="flex gap-1 items-center mb-1 text-sm font-medium">{{ $label }}
<label
class="flex gap-1 items-center mb-1 text-sm font-medium {{ $disabled ? 'text-neutral-600' : '' }}">{{ $label }}
@if ($required)
<x-highlighted text="*" />
@endif
@ -9,7 +10,7 @@
@endif
</label>
@endif
<select {{ $attributes->merge(['class' => $defaultClass]) }} @required($required)
<select {{ $attributes->merge(['class' => $defaultClass]) }} @disabled($disabled) @required($required)
wire:dirty.class.remove='dark:focus:ring-coolgray-300 dark:ring-coolgray-300'
wire:dirty.class="dark:focus:ring-warning dark:ring-warning" wire:loading.attr="disabled" name={{ $id }}
@if ($attributes->whereStartsWith('wire:model')->first()) {{ $attributes->whereStartsWith('wire:model')->first() }} @else wire:model={{ $id }} @endif>

View file

@ -76,8 +76,16 @@
</span>
@endif
<div class="flex flex-col gap-2">
<x-forms.checkbox id="enable_ssl" label="Enable SSL" wire:model.live="enable_ssl"
instantSave="instantSaveSSL" />
<div class="w-64">
@if (str($database->status)->contains('exited'))
<x-forms.checkbox id="enable_ssl" label="Enable SSL" wire:model.live="enable_ssl"
instantSave="instantSaveSSL" />
@else
<x-forms.checkbox id="enable_ssl" label="Enable SSL" wire:model.live="enable_ssl"
instantSave="instantSaveSSL" disabled
helper="Database should be stopped to change this settings." />
@endif
</div>
</div>
</div>
<div>

View file

@ -53,34 +53,39 @@
<div class="flex items-center justify-between py-2">
<div class="flex items-center justify-between w-full">
<h3>SSL Configuration</h3>
@if($database->enable_ssl && $certificateValidUntil)
<x-modal-confirmation
title="Regenerate SSL Certificates"
buttonTitle="Regenerate SSL Certificates"
:actions="[
@if ($database->enable_ssl && $certificateValidUntil)
<x-modal-confirmation title="Regenerate SSL Certificates"
buttonTitle="Regenerate SSL Certificates" :actions="[
'The SSL certificate of this database will be regenerated.',
'You must restart the database after regenerating the certificate to start using the new certificate.'
'You must restart the database after regenerating the certificate to start using the new certificate.',
]"
submitAction="regenerateSslCertificate"
:confirmWithText="false"
:confirmWithPassword="false"
/>
submitAction="regenerateSslCertificate" :confirmWithText="false" :confirmWithPassword="false" />
@endif
</div>
</div>
@if($database->enable_ssl && $certificateValidUntil)
<span class="text-sm">Valid until:
@if(now()->gt($certificateValidUntil))
<span class="text-red-500">{{ $certificateValidUntil->format('d.m.Y H:i:s') }} - Expired</span>
@elseif(now()->addDays(30)->gt($certificateValidUntil))
<span class="text-red-500">{{ $certificateValidUntil->format('d.m.Y H:i:s') }} - Expiring soon</span>
@else
<span>{{ $certificateValidUntil->format('d.m.Y H:i:s') }}</span>
@endif
@if ($database->enable_ssl && $certificateValidUntil)
<span class="text-sm">Valid until:
@if (now()->gt($certificateValidUntil))
<span class="text-red-500">{{ $certificateValidUntil->format('d.m.Y H:i:s') }} - Expired</span>
@elseif(now()->addDays(30)->gt($certificateValidUntil))
<span class="text-red-500">{{ $certificateValidUntil->format('d.m.Y H:i:s') }} - Expiring
soon</span>
@else
<span>{{ $certificateValidUntil->format('d.m.Y H:i:s') }}</span>
@endif
</span>
@endif
<div class="flex flex-col gap-2">
<x-forms.checkbox id="enable_ssl" label="Enable SSL" wire:model.live="enable_ssl" instantSave="instantSaveSSL" />
<div class="w-64">
@if (str($database->status)->contains('exited'))
<x-forms.checkbox id="enable_ssl" label="Enable SSL" wire:model.live="enable_ssl"
instantSave="instantSaveSSL" />
@else
<x-forms.checkbox id="enable_ssl" label="Enable SSL" wire:model.live="enable_ssl"
instantSave="instantSaveSSL" disabled
helper="Database should be stopped to change this settings." />
@endif
</div>
</div>
</div>
<div>

View file

@ -70,36 +70,44 @@
<div class="flex items-center justify-between py-2">
<div class="flex items-center justify-between w-full">
<h3>SSL Configuration</h3>
@if($database->enable_ssl && $certificateValidUntil)
<x-modal-confirmation
title="Regenerate SSL Certificates"
buttonTitle="Regenerate SSL Certificates"
:actions="['The SSL certificate of this database will be regenerated.','You must restart the database after regenerating the certificate to start using the new certificate.']"
submitAction="regenerateSslCertificate"
:confirmWithText="false"
:confirmWithPassword="false"
/>
@if ($database->enable_ssl && $certificateValidUntil)
<x-modal-confirmation title="Regenerate SSL Certificates"
buttonTitle="Regenerate SSL Certificates" :actions="[
'The SSL certificate of this database will be regenerated.',
'You must restart the database after regenerating the certificate to start using the new certificate.',
]"
submitAction="regenerateSslCertificate" :confirmWithText="false" :confirmWithPassword="false" />
@endif
</div>
</div>
@if($database->enable_ssl && $certificateValidUntil)
<span class="text-sm">Valid until:
@if(now()->gt($certificateValidUntil))
<span class="text-red-500">{{ $certificateValidUntil->format('d.m.Y H:i:s') }} - Expired</span>
@elseif(now()->addDays(30)->gt($certificateValidUntil))
<span class="text-red-500">{{ $certificateValidUntil->format('d.m.Y H:i:s') }} - Expiring soon</span>
@else
<span>{{ $certificateValidUntil->format('d.m.Y H:i:s') }}</span>
@endif
@if ($database->enable_ssl && $certificateValidUntil)
<span class="text-sm">Valid until:
@if (now()->gt($certificateValidUntil))
<span class="text-red-500">{{ $certificateValidUntil->format('d.m.Y H:i:s') }} - Expired</span>
@elseif(now()->addDays(30)->gt($certificateValidUntil))
<span class="text-red-500">{{ $certificateValidUntil->format('d.m.Y H:i:s') }} - Expiring
soon</span>
@else
<span>{{ $certificateValidUntil->format('d.m.Y H:i:s') }}</span>
@endif
</span>
@endif
</div>
<div class="flex flex-col gap-2">
<div class="flex flex-col gap-2">
<x-forms.checkbox id="database.enable_ssl" label="Enable SSL" wire:model.live="database.enable_ssl" instantSave="instantSaveSSL" />
<div class="w-64">
@if (str($database->status)->contains('exited'))
<x-forms.checkbox id="database.enable_ssl" label="Enable SSL"
wire:model.live="database.enable_ssl" instantSave="instantSaveSSL" />
@else
<x-forms.checkbox id="database.enable_ssl" label="Enable SSL"
wire:model.live="database.enable_ssl" instantSave="instantSaveSSL" disabled
helper="Database should be stopped to change this settings." />
@endif
</div>
</div>
</div>
<div>
<div class="flex flex-col py-2 w-64">
<div class="flex items-center gap-2 pb-2">

View file

@ -85,52 +85,71 @@
</div>
<div class="flex flex-col gap-2">
<div class="flex flex-col gap-2">
<x-forms.checkbox id="database.enable_ssl" label="Enable SSL" wire:model.live="database.enable_ssl"
instantSave="instantSaveSSL" />
<div class="w-64">
@if (str($database->status)->contains('exited'))
<x-forms.checkbox id="database.enable_ssl" label="Enable SSL"
wire:model.live="database.enable_ssl" instantSave="instantSaveSSL" />
@else
<x-forms.checkbox id="database.enable_ssl" label="Enable SSL"
wire:model.live="database.enable_ssl" instantSave="instantSaveSSL" disabled
helper="Database should be stopped to change this settings." />
@endif
</div>
@if ($database->enable_ssl)
<div class="mx-2">
<x-forms.select id="database.ssl_mode" label="SSL Mode" wire:model.live="database.ssl_mode"
instantSave="instantSaveSSL"
helper="Choose the SSL verification mode for MongoDB connections">
<option value="allow" title="Allow insecure connections">allow (insecure)</option>
<option value="prefer" title="Prefer secure connections">prefer (secure)</option>
<option value="require" title="Require secure connections">require (secure)</option>
<option value="verify-full" title="Verify full certificate">verify-full (secure)</option>
</x-forms.select>
@if (str($database->status)->contains('exited'))
<x-forms.select id="database.ssl_mode" label="SSL Mode" wire:model.live="database.ssl_mode"
instantSave="instantSaveSSL"
helper="Choose the SSL verification mode for MongoDB connections">
<option value="allow" title="Allow insecure connections">allow (insecure)</option>
<option value="prefer" title="Prefer secure connections">prefer (secure)</option>
<option value="require" title="Require secure connections">require (secure)</option>
<option value="verify-full" title="Verify full certificate">verify-full (secure)
</option>
</x-forms.select>
@else
<x-forms.select id="database.ssl_mode" label="SSL Mode" instantSave="instantSaveSSL"
disabled helper="Database should be stopped to change this settings.">
<option value="allow" title="Allow insecure connections">allow (insecure)</option>
<option value="prefer" title="Prefer secure connections">prefer (secure)</option>
<option value="require" title="Require secure connections">require (secure)</option>
<option value="verify-full" title="Verify full certificate">verify-full (secure)
</option>
</x-forms.select>
@endif
</div>
@endif
</div>
</div>
<div>
<div class="flex flex-col py-2 w-64">
<div class="flex items-center gap-2 pb-2">
<div class="flex items-center">
<h3>Proxy</h3>
<x-loading wire:loading wire:target="instantSave" />
<div>
<div class="flex flex-col py-2 w-64">
<div class="flex items-center gap-2 pb-2">
<div class="flex items-center">
<h3>Proxy</h3>
<x-loading wire:loading wire:target="instantSave" />
</div>
@if (data_get($database, 'is_public'))
<x-slide-over fullScreen>
<x-slot:title>Proxy Logs</x-slot:title>
<x-slot:content>
<livewire:project.shared.get-logs :server="$server" :resource="$database"
container="{{ data_get($database, 'uuid') }}-proxy" lazy />
</x-slot:content>
<x-forms.button disabled="{{ !data_get($database, 'is_public') }}"
@click="slideOverOpen=true">Logs</x-forms.button>
</x-slide-over>
@endif
</div>
@if (data_get($database, 'is_public'))
<x-slide-over fullScreen>
<x-slot:title>Proxy Logs</x-slot:title>
<x-slot:content>
<livewire:project.shared.get-logs :server="$server" :resource="$database"
container="{{ data_get($database, 'uuid') }}-proxy" lazy />
</x-slot:content>
<x-forms.button disabled="{{ !data_get($database, 'is_public') }}"
@click="slideOverOpen=true">Logs</x-forms.button>
</x-slide-over>
@endif
<x-forms.checkbox instantSave id="database.is_public" label="Make it publicly available" />
</div>
<x-forms.checkbox instantSave id="database.is_public" label="Make it publicly available" />
<x-forms.input placeholder="5432" disabled="{{ data_get($database, 'is_public') }}"
id="database.public_port" label="Public Port" />
</div>
<x-forms.textarea label="Custom MongoDB Configuration" rows="10" id="database.mongo_conf" />
<h3 class="pt-4">Advanced</h3>
<div class="flex flex-col">
<x-forms.checkbox helper="Drain logs to your configured log drain endpoint in your Server settings."
instantSave="instantSaveAdvanced" id="database.is_log_drain_enabled" label="Drain Logs" />
</div>
<x-forms.input placeholder="5432" disabled="{{ data_get($database, 'is_public') }}"
id="database.public_port" label="Public Port" />
</div>
<x-forms.textarea label="Custom MongoDB Configuration" rows="10" id="database.mongo_conf" />
<h3 class="pt-4">Advanced</h3>
<div class="flex flex-col">
<x-forms.checkbox helper="Drain logs to your configured log drain endpoint in your Server settings."
instantSave="instantSaveAdvanced" id="database.is_log_drain_enabled" label="Drain Logs" />
</div>
</form>
</div>

View file

@ -95,19 +95,38 @@
</div>
<div class="flex flex-col gap-2">
<div class="flex flex-col gap-2">
<x-forms.checkbox id="database.enable_ssl" label="Enable SSL" wire:model.live="database.enable_ssl"
instantSave="instantSaveSSL" />
<div class="w-64">
@if (str($database->status)->contains('exited'))
<x-forms.checkbox id="database.enable_ssl" label="Enable SSL"
wire:model.live="database.enable_ssl" instantSave="instantSaveSSL" />
@else
<x-forms.checkbox id="database.enable_ssl" label="Enable SSL"
wire:model.live="database.enable_ssl" instantSave="instantSaveSSL" disabled
helper="Database should be stopped to change this settings." />
@endif
</div>
@if ($database->enable_ssl)
<div class="mx-2">
<x-forms.select id="database.ssl_mode" label="SSL Mode" wire:model.live="database.ssl_mode"
instantSave="instantSaveSSL"
helper="Choose the SSL verification mode for MySQL connections">
<option value="PREFERRED" title="Prefer secure connections">Prefer (secure)</option>
<option value="REQUIRED" title="Require secure connections">Require (secure)</option>
<option value="VERIFY_CA" title="Verify CA certificate">Verify CA (secure)</option>
<option value="VERIFY_IDENTITY" title="Verify full certificate">Verify Full (secure)
</option>
</x-forms.select>
@if (str($database->status)->contains('exited'))
<x-forms.select id="database.ssl_mode" label="SSL Mode" wire:model.live="database.ssl_mode"
instantSave="instantSaveSSL"
helper="Choose the SSL verification mode for MySQL connections">
<option value="PREFERRED" title="Prefer secure connections">Prefer (secure)</option>
<option value="REQUIRED" title="Require secure connections">Require (secure)</option>
<option value="VERIFY_CA" title="Verify CA certificate">Verify CA (secure)</option>
<option value="VERIFY_IDENTITY" title="Verify full certificate">Verify Full (secure)
</option>
</x-forms.select>
@else
<x-forms.select id="database.ssl_mode" label="SSL Mode" instantSave="instantSaveSSL"
disabled helper="Database should be stopped to change this settings.">
<option value="PREFERRED" title="Prefer secure connections">Prefer (secure)</option>
<option value="REQUIRED" title="Require secure connections">Require (secure)</option>
<option value="VERIFY_CA" title="Verify CA certificate">Verify CA (secure)</option>
<option value="VERIFY_IDENTITY" title="Verify full certificate">Verify Full (secure)
</option>
</x-forms.select>
@endif
</div>
@endif
</div>

View file

@ -102,52 +102,72 @@
</div>
<div class="flex flex-col gap-2">
<div class="flex flex-col gap-2">
<x-forms.checkbox id="database.enable_ssl" label="Enable SSL" wire:model.live="database.enable_ssl"
instantSave="instantSaveSSL" />
<div class="w-64" wire:key='enable_ssl'>
@if ($database->isExited())
<x-forms.checkbox id="database.enable_ssl" label="Enable SSL"
wire:model.live="database.enable_ssl" instantSave="instantSaveSSL" />
@else
<x-forms.checkbox id="database.enable_ssl" label="Enable SSL"
wire:model.live="database.enable_ssl" instantSave="instantSaveSSL" disabled
helper="Database should be stopped to change this settings." />
@endif
</div>
@if ($database->enable_ssl)
<div class="mx-2">
<x-forms.select id="database.ssl_mode" label="SSL Mode" wire:model.live="database.ssl_mode"
instantSave="instantSaveSSL"
helper="Choose the SSL verification mode for PostgreSQL connections">
<option value="allow" title="Allow insecure connections">allow (insecure)</option>
<option value="prefer" title="Prefer secure connections">prefer (secure)</option>
<option value="require" title="Require secure connections">require (secure)</option>
<option value="verify-ca" title="Verify CA certificate">verify-ca (secure)</option>
<option value="verify-full" title="Verify full certificate">verify-full (secure)</option>
</x-forms.select>
@if ($database->isExited())
<x-forms.select id="database.ssl_mode" label="SSL Mode"
wire:model.live="database.ssl_mode" instantSave="instantSaveSSL"
helper="Choose the SSL verification mode for PostgreSQL connections">
<option value="allow" title="Allow insecure connections">allow (insecure)</option>
<option value="prefer" title="Prefer secure connections">prefer (secure)</option>
<option value="require" title="Require secure connections">require (secure)</option>
<option value="verify-ca" title="Verify CA certificate">verify-ca (secure)</option>
<option value="verify-full" title="Verify full certificate">verify-full (secure)
</option>
</x-forms.select>
@else
<x-forms.select id="database.ssl_mode" label="SSL Mode" instantSave="instantSaveSSL"
disabled helper="Database should be stopped to change this settings.">
<option value="allow" title="Allow insecure connections">allow (insecure)</option>
<option value="prefer" title="Prefer secure connections">prefer (secure)</option>
<option value="require" title="Require secure connections">require (secure)</option>
<option value="verify-ca" title="Verify CA certificate">verify-ca (secure)</option>
<option value="verify-full" title="Verify full certificate">verify-full (secure)
</option>
</x-forms.select>
@endif
</div>
@endif
</div>
</div>
<div class="flex flex-col gap-2">
<div class="flex items-center justify-between py-2">
<div class="flex items-center gap-2">
<h3>Proxy</h3>
<x-loading wire:loading wire:target="instantSave" />
<div class="flex flex-col gap-2">
<div class="flex items-center justify-between py-2">
<div class="flex items-center gap-2">
<h3>Proxy</h3>
<x-loading wire:loading wire:target="instantSave" />
</div>
@if (data_get($database, 'is_public'))
<x-slide-over fullScreen>
<x-slot:title>Proxy Logs</x-slot:title>
<x-slot:content>
<livewire:project.shared.get-logs :server="$server" :resource="$database"
container="{{ data_get($database, 'uuid') }}-proxy" lazy />
</x-slot:content>
<x-forms.button disabled="{{ !data_get($database, 'is_public') }}"
@click="slideOverOpen=true">Logs</x-forms.button>
</x-slide-over>
@endif
</div>
<div class="flex flex-col gap-2">
<x-forms.checkbox instantSave id="database.is_public" label="Make it publicly available" />
<x-forms.input placeholder="5432" disabled="{{ data_get($database, 'is_public') }}"
id="database.public_port" label="Public Port" />
</div>
</div>
@if (data_get($database, 'is_public'))
<x-slide-over fullScreen>
<x-slot:title>Proxy Logs</x-slot:title>
<x-slot:content>
<livewire:project.shared.get-logs :server="$server" :resource="$database"
container="{{ data_get($database, 'uuid') }}-proxy" lazy />
</x-slot:content>
<x-forms.button disabled="{{ !data_get($database, 'is_public') }}"
@click="slideOverOpen=true">Logs</x-forms.button>
</x-slide-over>
@endif
</div>
<div class="flex flex-col gap-2">
<x-forms.checkbox instantSave id="database.is_public" label="Make it publicly available" />
<x-forms.input placeholder="5432" disabled="{{ data_get($database, 'is_public') }}"
id="database.public_port" label="Public Port" />
</div>
</div>
<div class="flex flex-col gap-2">
<x-forms.textarea label="Custom PostgreSQL Configuration" rows="10" id="database.postgres_conf" />
</div>
<div class="flex flex-col gap-2">
<x-forms.textarea label="Custom PostgreSQL Configuration" rows="10"
id="database.postgres_conf" />
</div>
</form>
<div class="flex flex-col gap-4 pt-4">

View file

@ -53,34 +53,39 @@
<div class="flex items-center justify-between py-2">
<div class="flex items-center justify-between w-full">
<h3>SSL Configuration</h3>
@if($database->enable_ssl && $certificateValidUntil)
<x-modal-confirmation
title="Regenerate SSL Certificates"
buttonTitle="Regenerate SSL Certificates"
:actions="[
@if ($database->enable_ssl && $certificateValidUntil)
<x-modal-confirmation title="Regenerate SSL Certificates"
buttonTitle="Regenerate SSL Certificates" :actions="[
'The SSL certificate of this database will be regenerated.',
'You must restart the database after regenerating the certificate to start using the new certificate.'
'You must restart the database after regenerating the certificate to start using the new certificate.',
]"
submitAction="regenerateSslCertificate"
:confirmWithText="false"
:confirmWithPassword="false"
/>
submitAction="regenerateSslCertificate" :confirmWithText="false" :confirmWithPassword="false" />
@endif
</div>
</div>
@if($database->enable_ssl && $certificateValidUntil)
<span class="text-sm">Valid until:
@if(now()->gt($certificateValidUntil))
<span class="text-red-500">{{ $certificateValidUntil->format('d.m.Y H:i:s') }} - Expired</span>
@elseif(now()->addDays(30)->gt($certificateValidUntil))
<span class="text-red-500">{{ $certificateValidUntil->format('d.m.Y H:i:s') }} - Expiring soon</span>
@else
<span>{{ $certificateValidUntil->format('d.m.Y H:i:s') }}</span>
@endif
@if ($database->enable_ssl && $certificateValidUntil)
<span class="text-sm">Valid until:
@if (now()->gt($certificateValidUntil))
<span class="text-red-500">{{ $certificateValidUntil->format('d.m.Y H:i:s') }} - Expired</span>
@elseif(now()->addDays(30)->gt($certificateValidUntil))
<span class="text-red-500">{{ $certificateValidUntil->format('d.m.Y H:i:s') }} - Expiring
soon</span>
@else
<span>{{ $certificateValidUntil->format('d.m.Y H:i:s') }}</span>
@endif
</span>
@endif
<div class="flex flex-col gap-2">
<x-forms.checkbox id="database.enable_ssl" label="Enable SSL" wire:model.live="database.enable_ssl" instantSave="instantSaveSSL" />
<div class="w-64" wire:key='enable_ssl'>
@if (str($database->status)->contains('exited'))
<x-forms.checkbox id="database.enable_ssl" label="Enable SSL"
wire:model.live="database.enable_ssl" instantSave="instantSaveSSL" />
@else
<x-forms.checkbox id="database.enable_ssl" label="Enable SSL"
wire:model.live="database.enable_ssl" instantSave="instantSaveSSL" disabled
helper="Database should be stopped to change this settings." />
@endif
</div>
</div>
</div>
<div>

View file

@ -30,9 +30,11 @@ fi
# Make sure coolify network exists
# It is created when starting Coolify with docker compose
if ! docker network create --attachable --ipv6 coolify 2>/dev/null; then
echo "Failed to create coolify network with ipv6. Trying without ipv6..."
docker network create --attachable coolify 2>/dev/null
if ! docker network inspect coolify >/dev/null 2>&1; then
if ! docker network create --attachable --ipv6 coolify 2>/dev/null; then
echo "Failed to create coolify network with ipv6. Trying without ipv6..."
docker network create --attachable coolify 2>/dev/null
fi
fi
# docker network create --attachable --driver=overlay coolify-overlay 2>/dev/null

View file

@ -1,10 +1,10 @@
{
"coolify": {
"v4": {
"version": "4.0.0-beta.399"
"version": "4.0.0-beta.400"
},
"nightly": {
"version": "4.0.0-beta.400"
"version": "4.0.0-beta.401"
},
"helper": {
"version": "1.0.7"