Merge branch 'next' into docker-network-aliases
This commit is contained in:
@@ -22,6 +22,7 @@ class Configuration extends Component
|
||||
public function mount()
|
||||
{
|
||||
$this->currentRoute = request()->route()->getName();
|
||||
|
||||
$project = currentTeam()
|
||||
->projects()
|
||||
->select('id', 'uuid', 'team_id')
|
||||
@@ -39,6 +40,9 @@ class Configuration extends Component
|
||||
$this->project = $project;
|
||||
$this->environment = $environment;
|
||||
$this->application = $application;
|
||||
if ($this->application->build_pack === 'dockercompose' && $this->currentRoute === 'project.application.healthcheck') {
|
||||
return redirect()->route('project.application.configuration', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'application_uuid' => $application->uuid]);
|
||||
}
|
||||
}
|
||||
|
||||
public function render()
|
||||
|
||||
@@ -87,6 +87,7 @@ class General extends Component
|
||||
'application.post_deployment_command_container' => 'nullable',
|
||||
'application.custom_nginx_configuration' => 'nullable',
|
||||
'application.settings.is_static' => 'boolean|required',
|
||||
'application.settings.is_spa' => 'boolean|required',
|
||||
'application.settings.is_build_server_enabled' => 'boolean|required',
|
||||
'application.settings.is_container_label_escape_enabled' => 'boolean|required',
|
||||
'application.settings.is_container_label_readonly_enabled' => 'boolean|required',
|
||||
@@ -126,6 +127,7 @@ class General extends Component
|
||||
'application.docker_compose_custom_build_command' => 'Docker compose custom build command',
|
||||
'application.custom_nginx_configuration' => 'Custom Nginx configuration',
|
||||
'application.settings.is_static' => 'Is static',
|
||||
'application.settings.is_spa' => 'Is SPA',
|
||||
'application.settings.is_build_server_enabled' => 'Is build server enabled',
|
||||
'application.settings.is_container_label_escape_enabled' => 'Is container label escape enabled',
|
||||
'application.settings.is_container_label_readonly_enabled' => 'Is container label readonly',
|
||||
@@ -173,6 +175,9 @@ class General extends Component
|
||||
|
||||
public function instantSave()
|
||||
{
|
||||
if ($this->application->settings->isDirty('is_spa')) {
|
||||
$this->generateNginxConfiguration($this->application->settings->is_spa ? 'spa' : 'static');
|
||||
}
|
||||
$this->application->settings->save();
|
||||
$this->dispatch('success', 'Settings saved.');
|
||||
$this->application->refresh();
|
||||
@@ -192,6 +197,7 @@ class General extends Component
|
||||
if ($this->application->settings->is_container_label_readonly_enabled) {
|
||||
$this->resetDefaultLabels(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function loadComposeFile($isInit = false)
|
||||
@@ -289,9 +295,9 @@ class General extends Component
|
||||
}
|
||||
}
|
||||
|
||||
public function generateNginxConfiguration()
|
||||
public function generateNginxConfiguration($type = 'static')
|
||||
{
|
||||
$this->application->custom_nginx_configuration = defaultNginxConfiguration();
|
||||
$this->application->custom_nginx_configuration = defaultNginxConfiguration($type);
|
||||
$this->application->save();
|
||||
$this->dispatch('success', 'Nginx configuration generated.');
|
||||
}
|
||||
@@ -371,6 +377,9 @@ class General extends Component
|
||||
if ($this->application->isDirty('redirect')) {
|
||||
$this->setRedirect();
|
||||
}
|
||||
if ($this->application->isDirty('dockerfile')) {
|
||||
$this->application->parseHealthcheckFromDockerfile($this->application->dockerfile);
|
||||
}
|
||||
|
||||
$this->checkFqdns();
|
||||
|
||||
@@ -448,7 +457,6 @@ class General extends Component
|
||||
{
|
||||
$config = GenerateConfig::run($this->application, true);
|
||||
$fileName = str($this->application->name)->slug()->append('_config.json');
|
||||
dd($config);
|
||||
|
||||
return response()->streamDownload(function () use ($config) {
|
||||
echo $config;
|
||||
|
||||
@@ -4,8 +4,11 @@ namespace App\Livewire\Project\Database\Dragonfly;
|
||||
|
||||
use App\Actions\Database\StartDatabaseProxy;
|
||||
use App\Actions\Database\StopDatabaseProxy;
|
||||
use App\Helpers\SslHelper;
|
||||
use App\Models\Server;
|
||||
use App\Models\SslCertificate;
|
||||
use App\Models\StandaloneDragonfly;
|
||||
use Carbon\Carbon;
|
||||
use Exception;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Livewire\Attributes\Validate;
|
||||
@@ -50,12 +53,19 @@ class General extends Component
|
||||
#[Validate(['nullable', 'boolean'])]
|
||||
public bool $isLogDrainEnabled = false;
|
||||
|
||||
public ?Carbon $certificateValidUntil = null;
|
||||
|
||||
#[Validate(['nullable', 'boolean'])]
|
||||
public bool $enable_ssl = false;
|
||||
|
||||
public function getListeners()
|
||||
{
|
||||
$userId = Auth::id();
|
||||
$teamId = Auth::user()->currentTeam()->id;
|
||||
|
||||
return [
|
||||
"echo-private:team.{$teamId},DatabaseProxyStopped" => 'databaseProxyStopped',
|
||||
"echo-private:user.{$userId},DatabaseStatusChanged" => '$refresh',
|
||||
];
|
||||
}
|
||||
|
||||
@@ -64,6 +74,12 @@ class General extends Component
|
||||
try {
|
||||
$this->syncData();
|
||||
$this->server = data_get($this->database, 'destination.server');
|
||||
|
||||
$existingCert = $this->database->sslCertificates()->first();
|
||||
|
||||
if ($existingCert) {
|
||||
$this->certificateValidUntil = $existingCert->valid_until;
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
@@ -82,6 +98,7 @@ class General extends Component
|
||||
$this->database->public_port = $this->publicPort;
|
||||
$this->database->custom_docker_run_options = $this->customDockerRunOptions;
|
||||
$this->database->is_log_drain_enabled = $this->isLogDrainEnabled;
|
||||
$this->database->enable_ssl = $this->enable_ssl;
|
||||
$this->database->save();
|
||||
|
||||
$this->dbUrl = $this->database->internal_db_url;
|
||||
@@ -96,6 +113,7 @@ class General extends Component
|
||||
$this->publicPort = $this->database->public_port;
|
||||
$this->customDockerRunOptions = $this->database->custom_docker_run_options;
|
||||
$this->isLogDrainEnabled = $this->database->is_log_drain_enabled;
|
||||
$this->enable_ssl = $this->database->enable_ssl;
|
||||
$this->dbUrl = $this->database->internal_db_url;
|
||||
$this->dbUrlPublic = $this->database->external_db_url;
|
||||
}
|
||||
@@ -174,4 +192,61 @@ class General extends Component
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function instantSaveSSL()
|
||||
{
|
||||
try {
|
||||
$this->syncData(true);
|
||||
$this->dispatch('success', 'SSL configuration updated.');
|
||||
} catch (Exception $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function regenerateSslCertificate()
|
||||
{
|
||||
try {
|
||||
$existingCert = $this->database->sslCertificates()->first();
|
||||
|
||||
if (! $existingCert) {
|
||||
$this->dispatch('error', 'No existing SSL certificate found for this database.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$server = $this->database->destination->server;
|
||||
|
||||
$caCert = SslCertificate::where('server_id', $server->id)
|
||||
->where('is_ca_certificate', true)
|
||||
->first();
|
||||
|
||||
if (! $caCert) {
|
||||
$server->generateCaCertificate();
|
||||
$caCert = SslCertificate::where('server_id', $server->id)->where('is_ca_certificate', true)->first();
|
||||
}
|
||||
|
||||
if (! $caCert) {
|
||||
$this->dispatch('error', 'No CA certificate found for this database. Please generate a CA certificate for this server in the server/advanced page.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
SslHelper::generateSslCertificate(
|
||||
commonName: $existingCert->commonName,
|
||||
subjectAlternativeNames: $existingCert->subjectAlternativeNames ?? [],
|
||||
resourceType: $existingCert->resource_type,
|
||||
resourceId: $existingCert->resource_id,
|
||||
serverId: $existingCert->server_id,
|
||||
caCert: $caCert->ssl_certificate,
|
||||
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.');
|
||||
} catch (Exception $e) {
|
||||
handleError($e, $this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -4,8 +4,11 @@ namespace App\Livewire\Project\Database\Keydb;
|
||||
|
||||
use App\Actions\Database\StartDatabaseProxy;
|
||||
use App\Actions\Database\StopDatabaseProxy;
|
||||
use App\Helpers\SslHelper;
|
||||
use App\Models\Server;
|
||||
use App\Models\SslCertificate;
|
||||
use App\Models\StandaloneKeydb;
|
||||
use Carbon\Carbon;
|
||||
use Exception;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Livewire\Attributes\Validate;
|
||||
@@ -53,12 +56,20 @@ class General extends Component
|
||||
#[Validate(['nullable', 'boolean'])]
|
||||
public bool $isLogDrainEnabled = false;
|
||||
|
||||
public ?Carbon $certificateValidUntil = null;
|
||||
|
||||
#[Validate(['boolean'])]
|
||||
public bool $enable_ssl = false;
|
||||
|
||||
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',
|
||||
];
|
||||
}
|
||||
|
||||
@@ -67,6 +78,12 @@ class General extends Component
|
||||
try {
|
||||
$this->syncData();
|
||||
$this->server = data_get($this->database, 'destination.server');
|
||||
|
||||
$existingCert = $this->database->sslCertificates()->first();
|
||||
|
||||
if ($existingCert) {
|
||||
$this->certificateValidUntil = $existingCert->valid_until;
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
@@ -86,6 +103,7 @@ class General extends Component
|
||||
$this->database->public_port = $this->publicPort;
|
||||
$this->database->custom_docker_run_options = $this->customDockerRunOptions;
|
||||
$this->database->is_log_drain_enabled = $this->isLogDrainEnabled;
|
||||
$this->database->enable_ssl = $this->enable_ssl;
|
||||
$this->database->save();
|
||||
|
||||
$this->dbUrl = $this->database->internal_db_url;
|
||||
@@ -101,6 +119,7 @@ class General extends Component
|
||||
$this->publicPort = $this->database->public_port;
|
||||
$this->customDockerRunOptions = $this->database->custom_docker_run_options;
|
||||
$this->isLogDrainEnabled = $this->database->is_log_drain_enabled;
|
||||
$this->enable_ssl = $this->database->enable_ssl;
|
||||
$this->dbUrl = $this->database->internal_db_url;
|
||||
$this->dbUrlPublic = $this->database->external_db_url;
|
||||
}
|
||||
@@ -179,4 +198,48 @@ class General extends Component
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function instantSaveSSL()
|
||||
{
|
||||
try {
|
||||
$this->syncData(true);
|
||||
$this->dispatch('success', 'SSL configuration updated.');
|
||||
} catch (Exception $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function regenerateSslCertificate()
|
||||
{
|
||||
try {
|
||||
$existingCert = $this->database->sslCertificates()->first();
|
||||
|
||||
if (! $existingCert) {
|
||||
$this->dispatch('error', 'No existing SSL certificate found for this database.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$caCert = SslCertificate::where('server_id', $existingCert->server_id)
|
||||
->where('is_ca_certificate', true)
|
||||
->first();
|
||||
|
||||
SslHelper::generateSslCertificate(
|
||||
commonName: $existingCert->commonName,
|
||||
subjectAlternativeNames: $existingCert->subjectAlternativeNames ?? [],
|
||||
resourceType: $existingCert->resource_type,
|
||||
resourceId: $existingCert->resource_id,
|
||||
serverId: $existingCert->server_id,
|
||||
caCert: $caCert->ssl_certificate,
|
||||
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.');
|
||||
} catch (Exception $e) {
|
||||
handleError($e, $this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,13 @@ namespace App\Livewire\Project\Database\Mariadb;
|
||||
|
||||
use App\Actions\Database\StartDatabaseProxy;
|
||||
use App\Actions\Database\StopDatabaseProxy;
|
||||
use App\Helpers\SslHelper;
|
||||
use App\Models\Server;
|
||||
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
|
||||
@@ -21,6 +25,18 @@ class General extends Component
|
||||
|
||||
public ?string $db_url_public = null;
|
||||
|
||||
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',
|
||||
@@ -35,6 +51,7 @@ class General extends Component
|
||||
'database.public_port' => 'nullable|integer',
|
||||
'database.is_log_drain_enabled' => 'nullable|boolean',
|
||||
'database.custom_docker_run_options' => 'nullable',
|
||||
'database.enable_ssl' => 'boolean',
|
||||
];
|
||||
|
||||
protected $validationAttributes = [
|
||||
@@ -50,6 +67,7 @@ class General extends Component
|
||||
'database.is_public' => 'Is Public',
|
||||
'database.public_port' => 'Public Port',
|
||||
'database.custom_docker_run_options' => 'Custom Docker Options',
|
||||
'database.enable_ssl' => 'Enable SSL',
|
||||
];
|
||||
|
||||
public function mount()
|
||||
@@ -57,6 +75,12 @@ class General extends Component
|
||||
$this->db_url = $this->database->internal_db_url;
|
||||
$this->db_url_public = $this->database->external_db_url;
|
||||
$this->server = data_get($this->database, 'destination.server');
|
||||
|
||||
$existingCert = $this->database->sslCertificates()->first();
|
||||
|
||||
if ($existingCert) {
|
||||
$this->certificateValidUntil = $existingCert->valid_until;
|
||||
}
|
||||
}
|
||||
|
||||
public function instantSaveAdvanced()
|
||||
@@ -127,6 +151,48 @@ class General extends Component
|
||||
}
|
||||
}
|
||||
|
||||
public function instantSaveSSL()
|
||||
{
|
||||
try {
|
||||
$this->database->save();
|
||||
$this->dispatch('success', 'SSL configuration updated.');
|
||||
} catch (Exception $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function regenerateSslCertificate()
|
||||
{
|
||||
try {
|
||||
$existingCert = $this->database->sslCertificates()->first();
|
||||
|
||||
if (! $existingCert) {
|
||||
$this->dispatch('error', 'No existing SSL certificate found for this database.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$caCert = SslCertificate::where('server_id', $existingCert->server_id)->where('is_ca_certificate', true)->first();
|
||||
|
||||
SslHelper::generateSslCertificate(
|
||||
commonName: $existingCert->common_name,
|
||||
subjectAlternativeNames: $existingCert->subject_alternative_names ?? [],
|
||||
resourceType: $existingCert->resource_type,
|
||||
resourceId: $existingCert->resource_id,
|
||||
serverId: $existingCert->server_id,
|
||||
caCert: $caCert->ssl_certificate,
|
||||
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.');
|
||||
} catch (Exception $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function refresh(): void
|
||||
{
|
||||
$this->database->refresh();
|
||||
|
||||
@@ -4,9 +4,13 @@ namespace App\Livewire\Project\Database\Mongodb;
|
||||
|
||||
use App\Actions\Database\StartDatabaseProxy;
|
||||
use App\Actions\Database\StopDatabaseProxy;
|
||||
use App\Helpers\SslHelper;
|
||||
use App\Models\Server;
|
||||
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
|
||||
@@ -21,6 +25,18 @@ class General extends Component
|
||||
|
||||
public ?string $db_url_public = null;
|
||||
|
||||
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',
|
||||
@@ -34,6 +50,8 @@ class General extends Component
|
||||
'database.public_port' => 'nullable|integer',
|
||||
'database.is_log_drain_enabled' => 'nullable|boolean',
|
||||
'database.custom_docker_run_options' => 'nullable',
|
||||
'database.enable_ssl' => 'boolean',
|
||||
'database.ssl_mode' => 'nullable|string|in:allow,prefer,require,verify-full',
|
||||
];
|
||||
|
||||
protected $validationAttributes = [
|
||||
@@ -48,6 +66,8 @@ class General extends Component
|
||||
'database.is_public' => 'Is Public',
|
||||
'database.public_port' => 'Public Port',
|
||||
'database.custom_docker_run_options' => 'Custom Docker Run Options',
|
||||
'database.enable_ssl' => 'Enable SSL',
|
||||
'database.ssl_mode' => 'SSL Mode',
|
||||
];
|
||||
|
||||
public function mount()
|
||||
@@ -55,6 +75,12 @@ class General extends Component
|
||||
$this->db_url = $this->database->internal_db_url;
|
||||
$this->db_url_public = $this->database->external_db_url;
|
||||
$this->server = data_get($this->database, 'destination.server');
|
||||
|
||||
$existingCert = $this->database->sslCertificates()->first();
|
||||
|
||||
if ($existingCert) {
|
||||
$this->certificateValidUntil = $existingCert->valid_until;
|
||||
}
|
||||
}
|
||||
|
||||
public function instantSaveAdvanced()
|
||||
@@ -128,6 +154,53 @@ class General extends Component
|
||||
}
|
||||
}
|
||||
|
||||
public function updatedDatabaseSslMode()
|
||||
{
|
||||
$this->instantSaveSSL();
|
||||
}
|
||||
|
||||
public function instantSaveSSL()
|
||||
{
|
||||
try {
|
||||
$this->database->save();
|
||||
$this->dispatch('success', 'SSL configuration updated.');
|
||||
} catch (Exception $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function regenerateSslCertificate()
|
||||
{
|
||||
try {
|
||||
$existingCert = $this->database->sslCertificates()->first();
|
||||
|
||||
if (! $existingCert) {
|
||||
$this->dispatch('error', 'No existing SSL certificate found for this database.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$caCert = SslCertificate::where('server_id', $existingCert->server_id)->where('is_ca_certificate', true)->first();
|
||||
|
||||
SslHelper::generateSslCertificate(
|
||||
commonName: $existingCert->common_name,
|
||||
subjectAlternativeNames: $existingCert->subject_alternative_names ?? [],
|
||||
resourceType: $existingCert->resource_type,
|
||||
resourceId: $existingCert->resource_id,
|
||||
serverId: $existingCert->server_id,
|
||||
caCert: $caCert->ssl_certificate,
|
||||
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.');
|
||||
} catch (Exception $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function refresh(): void
|
||||
{
|
||||
$this->database->refresh();
|
||||
|
||||
@@ -4,9 +4,13 @@ namespace App\Livewire\Project\Database\Mysql;
|
||||
|
||||
use App\Actions\Database\StartDatabaseProxy;
|
||||
use App\Actions\Database\StopDatabaseProxy;
|
||||
use App\Helpers\SslHelper;
|
||||
use App\Models\Server;
|
||||
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
|
||||
@@ -21,6 +25,18 @@ class General extends Component
|
||||
|
||||
public ?string $db_url_public = null;
|
||||
|
||||
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',
|
||||
@@ -35,6 +51,8 @@ class General extends Component
|
||||
'database.public_port' => 'nullable|integer',
|
||||
'database.is_log_drain_enabled' => 'nullable|boolean',
|
||||
'database.custom_docker_run_options' => 'nullable',
|
||||
'database.enable_ssl' => 'boolean',
|
||||
'database.ssl_mode' => 'nullable|string|in:PREFERRED,REQUIRED,VERIFY_CA,VERIFY_IDENTITY',
|
||||
];
|
||||
|
||||
protected $validationAttributes = [
|
||||
@@ -50,6 +68,8 @@ class General extends Component
|
||||
'database.is_public' => 'Is Public',
|
||||
'database.public_port' => 'Public Port',
|
||||
'database.custom_docker_run_options' => 'Custom Docker Run Options',
|
||||
'database.enable_ssl' => 'Enable SSL',
|
||||
'database.ssl_mode' => 'SSL Mode',
|
||||
];
|
||||
|
||||
public function mount()
|
||||
@@ -57,6 +77,12 @@ class General extends Component
|
||||
$this->db_url = $this->database->internal_db_url;
|
||||
$this->db_url_public = $this->database->external_db_url;
|
||||
$this->server = data_get($this->database, 'destination.server');
|
||||
|
||||
$existingCert = $this->database->sslCertificates()->first();
|
||||
|
||||
if ($existingCert) {
|
||||
$this->certificateValidUntil = $existingCert->valid_until;
|
||||
}
|
||||
}
|
||||
|
||||
public function instantSaveAdvanced()
|
||||
@@ -127,6 +153,53 @@ class General extends Component
|
||||
}
|
||||
}
|
||||
|
||||
public function updatedDatabaseSslMode()
|
||||
{
|
||||
$this->instantSaveSSL();
|
||||
}
|
||||
|
||||
public function instantSaveSSL()
|
||||
{
|
||||
try {
|
||||
$this->database->save();
|
||||
$this->dispatch('success', 'SSL configuration updated.');
|
||||
} catch (Exception $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function regenerateSslCertificate()
|
||||
{
|
||||
try {
|
||||
$existingCert = $this->database->sslCertificates()->first();
|
||||
|
||||
if (! $existingCert) {
|
||||
$this->dispatch('error', 'No existing SSL certificate found for this database.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$caCert = SslCertificate::where('server_id', $existingCert->server_id)->where('is_ca_certificate', true)->first();
|
||||
|
||||
SslHelper::generateSslCertificate(
|
||||
commonName: $existingCert->common_name,
|
||||
subjectAlternativeNames: $existingCert->subject_alternative_names ?? [],
|
||||
resourceType: $existingCert->resource_type,
|
||||
resourceId: $existingCert->resource_id,
|
||||
serverId: $existingCert->server_id,
|
||||
caCert: $caCert->ssl_certificate,
|
||||
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.');
|
||||
} catch (Exception $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function refresh(): void
|
||||
{
|
||||
$this->database->refresh();
|
||||
|
||||
@@ -4,9 +4,13 @@ namespace App\Livewire\Project\Database\Postgresql;
|
||||
|
||||
use App\Actions\Database\StartDatabaseProxy;
|
||||
use App\Actions\Database\StopDatabaseProxy;
|
||||
use App\Helpers\SslHelper;
|
||||
use App\Models\Server;
|
||||
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
|
||||
@@ -23,10 +27,15 @@ class General extends Component
|
||||
|
||||
public ?string $db_url_public = null;
|
||||
|
||||
public ?Carbon $certificateValidUntil = null;
|
||||
|
||||
public function getListeners()
|
||||
{
|
||||
$userId = Auth::id();
|
||||
|
||||
return [
|
||||
'refresh',
|
||||
"echo-private:user.{$userId},DatabaseStatusChanged" => '$refresh',
|
||||
'refresh' => '$refresh',
|
||||
'save_init_script',
|
||||
'delete_init_script',
|
||||
];
|
||||
@@ -48,6 +57,8 @@ class General extends Component
|
||||
'database.public_port' => 'nullable|integer',
|
||||
'database.is_log_drain_enabled' => 'nullable|boolean',
|
||||
'database.custom_docker_run_options' => 'nullable',
|
||||
'database.enable_ssl' => 'boolean',
|
||||
'database.ssl_mode' => 'nullable|string|in:allow,prefer,require,verify-ca,verify-full',
|
||||
];
|
||||
|
||||
protected $validationAttributes = [
|
||||
@@ -65,6 +76,8 @@ class General extends Component
|
||||
'database.is_public' => 'Is Public',
|
||||
'database.public_port' => 'Public Port',
|
||||
'database.custom_docker_run_options' => 'Custom Docker Run Options',
|
||||
'database.enable_ssl' => 'Enable SSL',
|
||||
'database.ssl_mode' => 'SSL Mode',
|
||||
];
|
||||
|
||||
public function mount()
|
||||
@@ -72,6 +85,12 @@ class General extends Component
|
||||
$this->db_url = $this->database->internal_db_url;
|
||||
$this->db_url_public = $this->database->external_db_url;
|
||||
$this->server = data_get($this->database, 'destination.server');
|
||||
|
||||
$existingCert = $this->database->sslCertificates()->first();
|
||||
|
||||
if ($existingCert) {
|
||||
$this->certificateValidUntil = $existingCert->valid_until;
|
||||
}
|
||||
}
|
||||
|
||||
public function instantSaveAdvanced()
|
||||
@@ -91,6 +110,53 @@ class General extends Component
|
||||
}
|
||||
}
|
||||
|
||||
public function updatedDatabaseSslMode()
|
||||
{
|
||||
$this->instantSaveSSL();
|
||||
}
|
||||
|
||||
public function instantSaveSSL()
|
||||
{
|
||||
try {
|
||||
$this->database->save();
|
||||
$this->dispatch('success', 'SSL configuration updated.');
|
||||
} catch (Exception $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function regenerateSslCertificate()
|
||||
{
|
||||
try {
|
||||
$existingCert = $this->database->sslCertificates()->first();
|
||||
|
||||
if (! $existingCert) {
|
||||
$this->dispatch('error', 'No existing SSL certificate found for this database.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$caCert = SslCertificate::where('server_id', $existingCert->server_id)->where('is_ca_certificate', true)->first();
|
||||
|
||||
SslHelper::generateSslCertificate(
|
||||
commonName: $existingCert->common_name,
|
||||
subjectAlternativeNames: $existingCert->subject_alternative_names ?? [],
|
||||
resourceType: $existingCert->resource_type,
|
||||
resourceId: $existingCert->resource_id,
|
||||
serverId: $existingCert->server_id,
|
||||
caCert: $caCert->ssl_certificate,
|
||||
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.');
|
||||
} catch (Exception $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function instantSave()
|
||||
{
|
||||
try {
|
||||
@@ -143,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;
|
||||
@@ -184,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;
|
||||
@@ -201,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([
|
||||
|
||||
@@ -4,25 +4,24 @@ namespace App\Livewire\Project\Database\Redis;
|
||||
|
||||
use App\Actions\Database\StartDatabaseProxy;
|
||||
use App\Actions\Database\StopDatabaseProxy;
|
||||
use App\Helpers\SslHelper;
|
||||
use App\Models\Server;
|
||||
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;
|
||||
|
||||
public string $redis_username;
|
||||
|
||||
public string $redis_password;
|
||||
public ?string $redis_password;
|
||||
|
||||
public string $redis_version;
|
||||
|
||||
@@ -30,6 +29,19 @@ class General extends Component
|
||||
|
||||
public ?string $db_url_public = null;
|
||||
|
||||
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',
|
||||
@@ -42,6 +54,7 @@ class General extends Component
|
||||
'database.custom_docker_run_options' => 'nullable',
|
||||
'redis_username' => 'required',
|
||||
'redis_password' => 'required',
|
||||
'database.enable_ssl' => 'boolean',
|
||||
];
|
||||
|
||||
protected $validationAttributes = [
|
||||
@@ -55,12 +68,18 @@ class General extends Component
|
||||
'database.custom_docker_run_options' => 'Custom Docker Options',
|
||||
'redis_username' => 'Redis Username',
|
||||
'redis_password' => 'Redis Password',
|
||||
'database.enable_ssl' => 'Enable SSL',
|
||||
];
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->server = data_get($this->database, 'destination.server');
|
||||
$this->refreshView();
|
||||
$existingCert = $this->database->sslCertificates()->first();
|
||||
|
||||
if ($existingCert) {
|
||||
$this->certificateValidUntil = $existingCert->valid_until;
|
||||
}
|
||||
}
|
||||
|
||||
public function instantSaveAdvanced()
|
||||
@@ -136,6 +155,48 @@ class General extends Component
|
||||
}
|
||||
}
|
||||
|
||||
public function instantSaveSSL()
|
||||
{
|
||||
try {
|
||||
$this->database->save();
|
||||
$this->dispatch('success', 'SSL configuration updated.');
|
||||
} catch (Exception $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function regenerateSslCertificate()
|
||||
{
|
||||
try {
|
||||
$existingCert = $this->database->sslCertificates()->first();
|
||||
|
||||
if (! $existingCert) {
|
||||
$this->dispatch('error', 'No existing SSL certificate found for this database.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$caCert = SslCertificate::where('server_id', $existingCert->server_id)->where('is_ca_certificate', true)->first();
|
||||
|
||||
SslHelper::generateSslCertificate(
|
||||
commonName: $existingCert->commonName,
|
||||
subjectAlternativeNames: $existingCert->subjectAlternativeNames ?? [],
|
||||
resourceType: $existingCert->resource_type,
|
||||
resourceId: $existingCert->resource_id,
|
||||
serverId: $existingCert->server_id,
|
||||
caCert: $caCert->ssl_certificate,
|
||||
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.');
|
||||
} catch (Exception $e) {
|
||||
handleError($e, $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function refresh(): void
|
||||
{
|
||||
$this->database->refresh();
|
||||
|
||||
@@ -7,7 +7,6 @@ use App\Models\Project;
|
||||
use App\Models\Service;
|
||||
use App\Models\StandaloneDocker;
|
||||
use App\Models\SwarmDocker;
|
||||
use Illuminate\Support\Str;
|
||||
use Livewire\Component;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
@@ -66,7 +65,6 @@ class DockerCompose extends Component
|
||||
$destination_class = $destination->getMorphClass();
|
||||
|
||||
$service = Service::create([
|
||||
'name' => 'service'.Str::random(10),
|
||||
'docker_compose_raw' => $this->dockerComposeRaw,
|
||||
'environment_id' => $environment->id,
|
||||
'server_id' => (int) $server_id,
|
||||
@@ -85,8 +83,6 @@ class DockerCompose extends Component
|
||||
'resourceable_type' => $service->getMorphClass(),
|
||||
]);
|
||||
}
|
||||
$service->name = "service-$service->uuid";
|
||||
|
||||
$service->parse(isNew: true);
|
||||
|
||||
return redirect()->route('project.service.configuration', [
|
||||
|
||||
@@ -106,11 +106,15 @@ class GithubPrivateRepository extends Component
|
||||
$this->selected_github_app_id = $github_app_id;
|
||||
$this->github_app = GithubApp::where('id', $github_app_id)->first();
|
||||
$this->token = generateGithubInstallationToken($this->github_app);
|
||||
$this->loadRepositoryByPage();
|
||||
$repositories = loadRepositoryByPage($this->github_app, $this->token, $this->page);
|
||||
$this->total_repositories_count = $repositories['total_count'];
|
||||
$this->repositories = $this->repositories->concat(collect($repositories['repositories']));
|
||||
if ($this->repositories->count() < $this->total_repositories_count) {
|
||||
while ($this->repositories->count() < $this->total_repositories_count) {
|
||||
$this->page++;
|
||||
$this->loadRepositoryByPage();
|
||||
$repositories = loadRepositoryByPage($this->github_app, $this->token, $this->page);
|
||||
$this->total_repositories_count = $repositories['total_count'];
|
||||
$this->repositories = $this->repositories->concat(collect($repositories['repositories']));
|
||||
}
|
||||
}
|
||||
$this->repositories = $this->repositories->sortBy('name');
|
||||
@@ -120,21 +124,6 @@ class GithubPrivateRepository extends Component
|
||||
$this->current_step = 'repository';
|
||||
}
|
||||
|
||||
protected function loadRepositoryByPage()
|
||||
{
|
||||
$response = Http::withToken($this->token)->get("{$this->github_app->api_url}/installation/repositories?per_page=100&page={$this->page}");
|
||||
$json = $response->json();
|
||||
if ($response->status() !== 200) {
|
||||
return $this->dispatch('error', $json['message']);
|
||||
}
|
||||
|
||||
if ($json['total_count'] === 0) {
|
||||
return;
|
||||
}
|
||||
$this->total_repositories_count = $json['total_count'];
|
||||
$this->repositories = $this->repositories->concat(collect($json['repositories']));
|
||||
}
|
||||
|
||||
public function loadBranches()
|
||||
{
|
||||
$this->selected_repository_owner = $this->repositories->where('id', $this->selected_repository_id)->first()['owner']['login'];
|
||||
|
||||
@@ -74,7 +74,7 @@ CMD ["nginx", "-g", "daemon off;"]
|
||||
'fqdn' => $fqdn,
|
||||
]);
|
||||
|
||||
$application->parseHealthcheckFromDockerfile(dockerfile: collect(str($this->dockerfile)->trim()->explode("\n")), isInit: true);
|
||||
$application->parseHealthcheckFromDockerfile(dockerfile: $this->dockerfile, isInit: true);
|
||||
|
||||
return redirect()->route('project.application.configuration', [
|
||||
'application_uuid' => $application->uuid,
|
||||
|
||||
@@ -73,7 +73,6 @@ class Create extends Component
|
||||
if ($oneClickService) {
|
||||
$destination = StandaloneDocker::whereUuid($destination_uuid)->first();
|
||||
$service_payload = [
|
||||
'name' => "$oneClickServiceName-".str()->random(10),
|
||||
'docker_compose_raw' => base64_decode($oneClickService),
|
||||
'environment_id' => $environment->id,
|
||||
'service_type' => $oneClickServiceName,
|
||||
|
||||
@@ -49,7 +49,6 @@ class FileStorage extends Component
|
||||
$this->workdir = null;
|
||||
$this->fs_path = $this->fileStorage->fs_path;
|
||||
}
|
||||
$this->fileStorage->loadStorageOnServer();
|
||||
}
|
||||
|
||||
public function convertToDirectory()
|
||||
@@ -68,6 +67,18 @@ class FileStorage extends Component
|
||||
}
|
||||
}
|
||||
|
||||
public function loadStorageOnServer()
|
||||
{
|
||||
try {
|
||||
$this->fileStorage->loadStorageOnServer();
|
||||
$this->dispatch('success', 'File storage loaded from server.');
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
} finally {
|
||||
$this->dispatch('refreshStorages');
|
||||
}
|
||||
}
|
||||
|
||||
public function convertToFile()
|
||||
{
|
||||
try {
|
||||
|
||||
@@ -3,10 +3,13 @@
|
||||
namespace App\Livewire\Project\Shared\EnvironmentVariable;
|
||||
|
||||
use App\Models\EnvironmentVariable;
|
||||
use App\Traits\EnvironmentVariableProtection;
|
||||
use Livewire\Component;
|
||||
|
||||
class All extends Component
|
||||
{
|
||||
use EnvironmentVariableProtection;
|
||||
|
||||
public $resource;
|
||||
|
||||
public string $resourceClass;
|
||||
@@ -138,17 +141,57 @@ class All extends Component
|
||||
private function handleBulkSubmit()
|
||||
{
|
||||
$variables = parseEnvFormatToArray($this->variables);
|
||||
$changesMade = false;
|
||||
$errorOccurred = false;
|
||||
|
||||
$this->deleteRemovedVariables(false, $variables);
|
||||
$this->updateOrCreateVariables(false, $variables);
|
||||
// Try to delete removed variables
|
||||
$deletedCount = $this->deleteRemovedVariables(false, $variables);
|
||||
if ($deletedCount > 0) {
|
||||
$changesMade = true;
|
||||
} elseif ($deletedCount === 0 && $this->resource->environment_variables()->whereNotIn('key', array_keys($variables))->exists()) {
|
||||
// If we tried to delete but couldn't (due to Docker Compose), mark as error
|
||||
$errorOccurred = true;
|
||||
}
|
||||
|
||||
// Update or create variables
|
||||
$updatedCount = $this->updateOrCreateVariables(false, $variables);
|
||||
if ($updatedCount > 0) {
|
||||
$changesMade = true;
|
||||
}
|
||||
|
||||
if ($this->showPreview) {
|
||||
$previewVariables = parseEnvFormatToArray($this->variablesPreview);
|
||||
$this->deleteRemovedVariables(true, $previewVariables);
|
||||
$this->updateOrCreateVariables(true, $previewVariables);
|
||||
|
||||
// Try to delete removed preview variables
|
||||
$deletedPreviewCount = $this->deleteRemovedVariables(true, $previewVariables);
|
||||
if ($deletedPreviewCount > 0) {
|
||||
$changesMade = true;
|
||||
} elseif ($deletedPreviewCount === 0 && $this->resource->environment_variables_preview()->whereNotIn('key', array_keys($previewVariables))->exists()) {
|
||||
// If we tried to delete but couldn't (due to Docker Compose), mark as error
|
||||
$errorOccurred = true;
|
||||
}
|
||||
|
||||
// Update or create preview variables
|
||||
$updatedPreviewCount = $this->updateOrCreateVariables(true, $previewVariables);
|
||||
if ($updatedPreviewCount > 0) {
|
||||
$changesMade = true;
|
||||
}
|
||||
}
|
||||
|
||||
$this->dispatch('success', 'Environment variables updated.');
|
||||
// Debug information
|
||||
\Log::info('Environment variables update status', [
|
||||
'deletedCount' => $deletedCount,
|
||||
'updatedCount' => $updatedCount,
|
||||
'deletedPreviewCount' => $deletedPreviewCount ?? 0,
|
||||
'updatedPreviewCount' => $updatedPreviewCount ?? 0,
|
||||
'changesMade' => $changesMade,
|
||||
'errorOccurred' => $errorOccurred,
|
||||
]);
|
||||
|
||||
// Only show success message if changes were actually made and no errors occurred
|
||||
if ($changesMade && ! $errorOccurred) {
|
||||
$this->dispatch('success', 'Environment variables updated.');
|
||||
}
|
||||
}
|
||||
|
||||
private function handleSingleSubmit($data)
|
||||
@@ -184,11 +227,46 @@ class All extends Component
|
||||
private function deleteRemovedVariables($isPreview, $variables)
|
||||
{
|
||||
$method = $isPreview ? 'environment_variables_preview' : 'environment_variables';
|
||||
|
||||
// Get all environment variables that will be deleted
|
||||
$variablesToDelete = $this->resource->$method()->whereNotIn('key', array_keys($variables))->get();
|
||||
|
||||
// If there are no variables to delete, return 0
|
||||
if ($variablesToDelete->isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check for system variables that shouldn't be deleted
|
||||
foreach ($variablesToDelete as $envVar) {
|
||||
if ($this->isProtectedEnvironmentVariable($envVar->key)) {
|
||||
$this->dispatch('error', "Cannot delete system environment variable '{$envVar->key}'.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if any of these variables are used in Docker Compose
|
||||
if ($this->resource->type() === 'service' || $this->resource->build_pack === 'dockercompose') {
|
||||
foreach ($variablesToDelete as $envVar) {
|
||||
[$isUsed, $reason] = $this->isEnvironmentVariableUsedInDockerCompose($envVar->key, $this->resource->docker_compose);
|
||||
|
||||
if ($isUsed) {
|
||||
$this->dispatch('error', "Cannot delete environment variable '{$envVar->key}' <br><br>Please remove it from the Docker Compose file first.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we get here, no variables are used in Docker Compose, so we can delete them
|
||||
$this->resource->$method()->whereNotIn('key', array_keys($variables))->delete();
|
||||
|
||||
return $variablesToDelete->count();
|
||||
}
|
||||
|
||||
private function updateOrCreateVariables($isPreview, $variables)
|
||||
{
|
||||
$count = 0;
|
||||
foreach ($variables as $key => $value) {
|
||||
if (str($key)->startsWith('SERVICE_FQDN') || str($key)->startsWith('SERVICE_URL')) {
|
||||
continue;
|
||||
@@ -198,8 +276,12 @@ class All extends Component
|
||||
|
||||
if ($found) {
|
||||
if (! $found->is_shown_once && ! $found->is_multiline) {
|
||||
$found->value = $value;
|
||||
$found->save();
|
||||
// Only count as a change if the value actually changed
|
||||
if ($found->value !== $value) {
|
||||
$found->value = $value;
|
||||
$found->save();
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$environment = new EnvironmentVariable;
|
||||
@@ -212,8 +294,11 @@ class All extends Component
|
||||
$environment->resourceable_type = $this->resource->getMorphClass();
|
||||
|
||||
$environment->save();
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
public function refreshEnvs()
|
||||
|
||||
@@ -4,10 +4,13 @@ namespace App\Livewire\Project\Shared\EnvironmentVariable;
|
||||
|
||||
use App\Models\EnvironmentVariable as ModelsEnvironmentVariable;
|
||||
use App\Models\SharedEnvironmentVariable;
|
||||
use App\Traits\EnvironmentVariableProtection;
|
||||
use Livewire\Component;
|
||||
|
||||
class Show extends Component
|
||||
{
|
||||
use EnvironmentVariableProtection;
|
||||
|
||||
public $parameters;
|
||||
|
||||
public ModelsEnvironmentVariable|SharedEnvironmentVariable $env;
|
||||
@@ -40,6 +43,8 @@ class Show extends Component
|
||||
|
||||
public bool $is_really_required = false;
|
||||
|
||||
public bool $is_redis_credential = false;
|
||||
|
||||
protected $listeners = [
|
||||
'refreshEnvs' => 'refresh',
|
||||
'refresh',
|
||||
@@ -65,7 +70,9 @@ class Show extends Component
|
||||
}
|
||||
$this->parameters = get_route_parameters();
|
||||
$this->checkEnvs();
|
||||
|
||||
if ($this->type === 'standalone-redis' && ($this->env->key === 'REDIS_PASSWORD' || $this->env->key === 'REDIS_USERNAME')) {
|
||||
$this->is_redis_credential = true;
|
||||
}
|
||||
}
|
||||
|
||||
public function refresh()
|
||||
@@ -171,6 +178,24 @@ class Show extends Component
|
||||
public function delete()
|
||||
{
|
||||
try {
|
||||
// Check if the variable is protected
|
||||
if ($this->isProtectedEnvironmentVariable($this->env->key)) {
|
||||
$this->dispatch('error', "Cannot delete system environment variable '{$this->env->key}'.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the variable is used in Docker Compose
|
||||
if ($this->type === 'service' || $this->type === 'application' && $this->env->resource()?->docker_compose) {
|
||||
[$isUsed, $reason] = $this->isEnvironmentVariableUsedInDockerCompose($this->env->key, $this->env->resource()?->docker_compose);
|
||||
|
||||
if ($isUsed) {
|
||||
$this->dispatch('error', "Cannot delete environment variable '{$this->env->key}' <br><br>Please remove it from the Docker Compose file first.");
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$this->env->delete();
|
||||
$this->dispatch('environmentVariableDeleted');
|
||||
$this->dispatch('success', 'Environment variable deleted successfully.');
|
||||
|
||||
Reference in New Issue
Block a user