diff --git a/app/Livewire/Project/Shared/EnvironmentVariable/All.php b/app/Livewire/Project/Shared/EnvironmentVariable/All.php index 9e6760293..95e2bfbbd 100644 --- a/app/Livewire/Project/Shared/EnvironmentVariable/All.php +++ b/app/Livewire/Project/Shared/EnvironmentVariable/All.php @@ -9,22 +9,16 @@ use Visus\Cuid2\Cuid2; class All extends Component { public $resource; - public string $resourceClass; - public bool $showPreview = false; - public ?string $modalId = null; - public ?string $variables = null; - public ?string $variablesPreview = null; - public string $view = 'normal'; protected $listeners = [ - 'refreshEnvs', 'saveKey' => 'submit', + 'environmentVariableDeleted' => 'refreshEnvs', ]; protected $rules = [ @@ -35,225 +29,236 @@ class All extends Component { $this->resourceClass = get_class($this->resource); $resourceWithPreviews = ['App\Models\Application']; - $simpleDockerfile = ! is_null(data_get($this->resource, 'dockerfile')); - if (str($this->resourceClass)->contains($resourceWithPreviews) && ! $simpleDockerfile) { + $simpleDockerfile = !is_null(data_get($this->resource, 'dockerfile')); + if (str($this->resourceClass)->contains($resourceWithPreviews) && !$simpleDockerfile) { $this->showPreview = true; } $this->modalId = new Cuid2; - $this->sortMe(); - $this->getDevView(); - } - - public function sortMe() - { - if ($this->resourceClass === 'App\Models\Application' && data_get($this->resource, 'build_pack') !== 'dockercompose') { - if ($this->resource->settings->is_env_sorting_enabled) { - $this->resource->environment_variables = $this->resource->environment_variables->sortBy('key'); - $this->resource->environment_variables_preview = $this->resource->environment_variables_preview->sortBy('key'); - } else { - $this->resource->environment_variables = $this->resource->environment_variables->sortBy('id'); - $this->resource->environment_variables_preview = $this->resource->environment_variables_preview->sortBy('id'); - } - } - $this->getDevView(); + $this->sortEnvironmentVariables(); } public function instantSave() { - if ($this->resourceClass === 'App\Models\Application' && data_get($this->resource, 'build_pack') !== 'dockercompose') { - $this->resource->settings->save(); - $this->dispatch('success', 'Environment variable settings updated.'); - $this->sortMe(); - } + $this->resource->settings->save(); + $this->sortEnvironmentVariables(); + $this->dispatch('success', 'Environment variable settings updated.'); + } + + public function sortEnvironmentVariables() + { + $this->resource->load(['environment_variables', 'environment_variables_preview']); + + $sortBy = $this->resource->settings->is_env_sorting_enabled ? 'key' : 'order'; + + $sortFunction = function ($variables) use ($sortBy) { + if ($sortBy === 'key') { + return $variables->sortBy(function ($item) { + return strtolower($item->key); + }, SORT_NATURAL | SORT_FLAG_CASE)->values(); + } else { + return $variables->sortBy('order')->values(); + } + }; + + $this->resource->environment_variables = $sortFunction($this->resource->environment_variables); + $this->resource->environment_variables_preview = $sortFunction($this->resource->environment_variables_preview); + + $this->getDevView(); } public function getDevView() { - $this->variables = $this->resource->environment_variables->map(function ($item) { + $this->variables = $this->formatEnvironmentVariables($this->resource->environment_variables); + if ($this->showPreview) { + $this->variablesPreview = $this->formatEnvironmentVariables($this->resource->environment_variables_preview); + } + } + + private function formatEnvironmentVariables($variables) + { + return $variables->map(function ($item) { if ($item->is_shown_once) { - return "$item->key=(locked secret)"; + return "$item->key=(Locked Secret, delete and add again to change)"; } if ($item->is_multiline) { - return "$item->key=(multiline, edit in normal view)"; + return "$item->key=(Multiline environment variable, edit in normal view)"; } - return "$item->key=$item->value"; - })->join(' -'); - if ($this->showPreview) { - $this->variablesPreview = $this->resource->environment_variables_preview->map(function ($item) { - if ($item->is_shown_once) { - return "$item->key=(locked secret)"; - } - if ($item->is_multiline) { - return "$item->key=(multiline, edit in normal view)"; - } - - return "$item->key=$item->value"; - })->join(' -'); - } + })->join("\n"); } public function switch() { - if ($this->view === 'normal') { - $this->view = 'dev'; - } else { - $this->view = 'normal'; - } - $this->sortMe(); + $this->view = $this->view === 'normal' ? 'dev' : 'normal'; + $this->sortEnvironmentVariables(); } - public function saveVariables($isPreview) + public function submit($data = null) { - if ($isPreview) { - $variables = parseEnvFormatToArray($this->variablesPreview); - $this->resource->environment_variables_preview()->whereNotIn('key', array_keys($variables))->delete(); - } else { - $variables = parseEnvFormatToArray($this->variables); - $this->resource->environment_variables()->whereNotIn('key', array_keys($variables))->delete(); - } - foreach ($variables as $key => $variable) { - if ($isPreview) { - $found = $this->resource->environment_variables_preview()->where('key', $key)->first(); + try { + if ($data === null) { + $this->handleBulkSubmit(); } else { - $found = $this->resource->environment_variables()->where('key', $key)->first(); + $this->handleSingleSubmit($data); } - if ($found) { - if ($found->is_shown_once || $found->is_multiline) { - continue; + + $this->updateOrder(); + $this->sortEnvironmentVariables(); + } catch (\Throwable $e) { + return handleError($e, $this); + } + } + + private function updateOrder() + { + $variables = parseEnvFormatToArray($this->variables); + $order = 1; + foreach ($variables as $key => $value) { + $env = $this->resource->environment_variables()->where('key', $key)->first(); + if ($env) { + $env->order = $order; + $env->save(); + } + $order++; + } + + if ($this->showPreview) { + $previewVariables = parseEnvFormatToArray($this->variablesPreview); + $order = 1; + foreach ($previewVariables as $key => $value) { + $env = $this->resource->environment_variables_preview()->where('key', $key)->first(); + if ($env) { + $env->order = $order; + $env->save(); } - $found->value = $variable; - // if (str($found->value)->startsWith('{{') && str($found->value)->endsWith('}}')) { - // $type = str($found->value)->after('{{')->before('.')->value; - // if (! collect(SHARED_VARIABLE_TYPES)->contains($type)) { - // $this->dispatch('error', 'Invalid shared variable type.', 'Valid types are: team, project, environment.'); + $order++; + } + } + } - // return; - // } - // } - $found->save(); + private function handleBulkSubmit() + { + $variables = parseEnvFormatToArray($this->variables); + $this->deleteRemovedVariables(false, $variables); + $this->updateOrCreateVariables(false, $variables); - continue; + if ($this->showPreview) { + $previewVariables = parseEnvFormatToArray($this->variablesPreview); + $this->deleteRemovedVariables(true, $previewVariables); + $this->updateOrCreateVariables(true, $previewVariables); + } + + $this->dispatch('success', 'Environment variables updated.'); + } + + private function handleSingleSubmit($data) + { + $found = $this->resource->environment_variables()->where('key', $data['key'])->first(); + if ($found) { + $this->dispatch('error', 'Environment variable already exists.'); + return; + } + + $maxOrder = $this->resource->environment_variables()->max('order') ?? 0; + $environment = $this->createEnvironmentVariable($data); + $environment->order = $maxOrder + 1; + $environment->save(); + } + + private function createEnvironmentVariable($data) + { + $environment = new EnvironmentVariable; + $environment->key = $data['key']; + $environment->value = $data['value']; + $environment->is_build_time = $data['is_build_time'] ?? false; + $environment->is_multiline = $data['is_multiline'] ?? false; + $environment->is_literal = $data['is_literal'] ?? false; + $environment->is_preview = $data['is_preview'] ?? false; + + $resourceType = $this->resource->type(); + $resourceIdField = $this->getResourceIdField($resourceType); + + if ($resourceIdField) { + $environment->$resourceIdField = $this->resource->id; + } + + return $environment; + } + + private function getResourceIdField($resourceType) + { + $resourceTypes = [ + 'application' => 'application_id', + 'standalone-postgresql' => 'standalone_postgresql_id', + 'standalone-redis' => 'standalone_redis_id', + 'standalone-mongodb' => 'standalone_mongodb_id', + 'standalone-mysql' => 'standalone_mysql_id', + 'standalone-mariadb' => 'standalone_mariadb_id', + 'standalone-keydb' => 'standalone_keydb_id', + 'standalone-dragonfly' => 'standalone_dragonfly_id', + 'standalone-clickhouse' => 'standalone_clickhouse_id', + 'service' => 'service_id', + ]; + + return $resourceTypes[$resourceType] ?? null; + } + + private function deleteRemovedVariables($isPreview, $variables) + { + $method = $isPreview ? 'environment_variables_preview' : 'environment_variables'; + $this->resource->$method()->whereNotIn('key', array_keys($variables))->delete(); + } + + private function updateOrCreateVariables($isPreview, $variables) + { + foreach ($variables as $key => $value) { + $method = $isPreview ? 'environment_variables_preview' : 'environment_variables'; + $found = $this->resource->$method()->where('key', $key)->first(); + + if ($found) { + if (!$found->is_shown_once && !$found->is_multiline) { + $found->value = $value; + $found->save(); + } } else { $environment = new EnvironmentVariable; $environment->key = $key; - $environment->value = $variable; - // if (str($environment->value)->startsWith('{{') && str($environment->value)->endsWith('}}')) { - // $type = str($environment->value)->after('{{')->before('.')->value; - // if (! collect(SHARED_VARIABLE_TYPES)->contains($type)) { - // $this->dispatch('error', 'Invalid shared variable type.', 'Valid types are: team, project, environment.'); - - // return; - // } - // } + $environment->value = $value; $environment->is_build_time = false; $environment->is_multiline = false; - $environment->is_preview = $isPreview ? true : false; - switch ($this->resource->type()) { - case 'application': - $environment->application_id = $this->resource->id; - break; - case 'standalone-postgresql': - $environment->standalone_postgresql_id = $this->resource->id; - break; - case 'standalone-redis': - $environment->standalone_redis_id = $this->resource->id; - break; - case 'standalone-mongodb': - $environment->standalone_mongodb_id = $this->resource->id; - break; - case 'standalone-mysql': - $environment->standalone_mysql_id = $this->resource->id; - break; - case 'standalone-mariadb': - $environment->standalone_mariadb_id = $this->resource->id; - break; - case 'standalone-keydb': - $environment->standalone_keydb_id = $this->resource->id; - break; - case 'standalone-dragonfly': - $environment->standalone_dragonfly_id = $this->resource->id; - break; - case 'standalone-clickhouse': - $environment->standalone_clickhouse_id = $this->resource->id; - break; - case 'service': - $environment->service_id = $this->resource->id; - break; - } + $environment->is_preview = $isPreview; + + $this->setEnvironmentResourceId($environment); $environment->save(); } } - if ($isPreview) { - $this->dispatch('success', 'Preview environment variables updated.'); - } else { - $this->dispatch('success', 'Environment variables updated.'); + } + + private function setEnvironmentResourceId($environment) + { + $resourceTypes = [ + 'application' => 'application_id', + 'standalone-postgresql' => 'standalone_postgresql_id', + 'standalone-redis' => 'standalone_redis_id', + 'standalone-mongodb' => 'standalone_mongodb_id', + 'standalone-mysql' => 'standalone_mysql_id', + 'standalone-mariadb' => 'standalone_mariadb_id', + 'standalone-keydb' => 'standalone_keydb_id', + 'standalone-dragonfly' => 'standalone_dragonfly_id', + 'standalone-clickhouse' => 'standalone_clickhouse_id', + 'service' => 'service_id', + ]; + + $resourceType = $this->resource->type(); + if (isset($resourceTypes[$resourceType])) { + $environment->{$resourceTypes[$resourceType]} = $this->resource->id; } - $this->refreshEnvs(); } public function refreshEnvs() { $this->resource->refresh(); + $this->sortEnvironmentVariables(); $this->getDevView(); } - - public function submit($data) - { - try { - $found = $this->resource->environment_variables()->where('key', $data['key'])->first(); - if ($found) { - $this->dispatch('error', 'Environment variable already exists.'); - - return; - } - $environment = new EnvironmentVariable; - $environment->key = $data['key']; - $environment->value = $data['value']; - $environment->is_build_time = $data['is_build_time']; - $environment->is_multiline = $data['is_multiline']; - $environment->is_literal = $data['is_literal']; - $environment->is_preview = $data['is_preview']; - - switch ($this->resource->type()) { - case 'application': - $environment->application_id = $this->resource->id; - break; - case 'standalone-postgresql': - $environment->standalone_postgresql_id = $this->resource->id; - break; - case 'standalone-redis': - $environment->standalone_redis_id = $this->resource->id; - break; - case 'standalone-mongodb': - $environment->standalone_mongodb_id = $this->resource->id; - break; - case 'standalone-mysql': - $environment->standalone_mysql_id = $this->resource->id; - break; - case 'standalone-mariadb': - $environment->standalone_mariadb_id = $this->resource->id; - break; - case 'standalone-keydb': - $environment->standalone_keydb_id = $this->resource->id; - break; - case 'standalone-dragonfly': - $environment->standalone_dragonfly_id = $this->resource->id; - break; - case 'standalone-clickhouse': - $environment->standalone_clickhouse_id = $this->resource->id; - break; - case 'service': - $environment->service_id = $this->resource->id; - break; - } - $environment->save(); - $this->refreshEnvs(); - $this->dispatch('success', 'Environment variable added.'); - } catch (\Throwable $e) { - return handleError($e, $this); - } - } -} +} \ No newline at end of file diff --git a/app/Livewire/Project/Shared/EnvironmentVariable/Show.php b/app/Livewire/Project/Shared/EnvironmentVariable/Show.php index 342259fd1..cbc4314f0 100644 --- a/app/Livewire/Project/Shared/EnvironmentVariable/Show.php +++ b/app/Livewire/Project/Shared/EnvironmentVariable/Show.php @@ -130,9 +130,10 @@ class Show extends Component { try { $this->env->delete(); - $this->dispatch('refreshEnvs'); + $this->dispatch('environmentVariableDeleted'); + $this->dispatch('success', 'Environment variable deleted successfully.'); } catch (\Exception $e) { return handleError($e); } } -} +} \ No newline at end of file diff --git a/database/migrations/2024_08_14_183120_add_order_to_environment_variables_table.php b/database/migrations/2024_08_14_183120_add_order_to_environment_variables_table.php new file mode 100644 index 000000000..527535827 --- /dev/null +++ b/database/migrations/2024_08_14_183120_add_order_to_environment_variables_table.php @@ -0,0 +1,28 @@ +integer('order')->nullable(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('environment_variables', function (Blueprint $table) { + $table->dropColumn('order'); + }); + } +}; diff --git a/resources/views/livewire/project/shared/environment-variable/all.blade.php b/resources/views/livewire/project/shared/environment-variable/all.blade.php index 649d59a20..813ee5c52 100644 --- a/resources/views/livewire/project/shared/environment-variable/all.blade.php +++ b/resources/views/livewire/project/shared/environment-variable/all.blade.php @@ -2,9 +2,11 @@

Environment Variables

- - - +
+ + + +
{{ $view === 'normal' ? 'Developer view' : 'Normal view' }}
@@ -12,7 +14,7 @@ @if ($this->resourceClass === 'App\Models\Application' && data_get($this->resource, 'build_pack') !== 'dockercompose')
@endif @@ -31,6 +33,10 @@ @endif
@if ($view === 'normal') +
+

Production Environment Variables

+
Environment (secrets) variables for Production.
+
@forelse ($resource->environment_variables as $env) @@ -39,7 +45,7 @@ @endforelse @if ($resource->type() === 'application' && $resource->environment_variables_preview->count() > 0 && $showPreview)
-

Preview Deployments

+

Preview Deployments Environment Variables

Environment (secrets) variables for Preview Deployments.
@foreach ($resource->environment_variables_preview as $env) @@ -48,16 +54,15 @@ @endforeach @endif @else -
- - Save + + + + @if ($showPreview) + + @endif + + Save All Environment Variables
- @if ($showPreview) -
- - Save -
- @endif @endif - + \ No newline at end of file