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
32 changed files with 574 additions and 325 deletions

View File

@@ -183,7 +183,7 @@ class StartMariadb
$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 @@ class CheckProxy
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 @@ class CheckProxy
$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 @@ class CheckProxy
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 @@ class General extends Component
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 @@ class Heading extends Component
$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 @@ class Heading extends Component
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 @@ class Heading extends Component
$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 @@ class General extends Component
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\SslCertificate;
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 @@ class General extends Component
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\SslCertificate;
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 @@ class General extends Component
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\SslCertificate;
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 @@ class General extends Component
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\SslCertificate;
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 @@ class General extends Component
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 @@ class General extends Component
$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 @@ class General extends Component
$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 @@ class General extends Component
$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\SslCertificate;
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 @@ class General extends Component
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 @@ class EmailNotificationSettings extends Model
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 @@ class StandaloneMongodb extends BaseModel
$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 @@ class StandaloneMongodb extends BaseModel
$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 @@ class Test extends Notification implements ShouldQueue
'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 @@ class Select extends Component
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 @@ return new class extends Migration
});
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 @@ return new class extends Migration
});
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 @@ body {
.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"