diff --git a/app/Livewire/SharedVariables/Environment/Show.php b/app/Livewire/SharedVariables/Environment/Show.php
index bee757a64..328986cea 100644
--- a/app/Livewire/SharedVariables/Environment/Show.php
+++ b/app/Livewire/SharedVariables/Environment/Show.php
@@ -5,6 +5,7 @@
use App\Models\Application;
use App\Models\Project;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
+use Illuminate\Support\Facades\DB;
use Livewire\Component;
class Show extends Component
@@ -19,7 +20,11 @@ class Show extends Component
public array $parameters;
- protected $listeners = ['refreshEnvs' => '$refresh', 'saveKey', 'environmentVariableDeleted' => '$refresh'];
+ public string $view = 'normal';
+
+ public ?string $variables = null;
+
+ protected $listeners = ['refreshEnvs' => 'refreshEnvs', 'saveKey', 'environmentVariableDeleted' => 'refreshEnvs'];
public function saveKey($data)
{
@@ -39,6 +44,7 @@ public function saveKey($data)
'team_id' => currentTeam()->id,
]);
$this->environment->refresh();
+ $this->getDevView();
} catch (\Throwable $e) {
return handleError($e, $this);
}
@@ -49,6 +55,119 @@ public function mount()
$this->parameters = get_route_parameters();
$this->project = Project::ownedByCurrentTeam()->where('uuid', request()->route('project_uuid'))->firstOrFail();
$this->environment = $this->project->environments()->where('uuid', request()->route('environment_uuid'))->firstOrFail();
+ $this->getDevView();
+ }
+
+ public function switch()
+ {
+ $this->view = $this->view === 'normal' ? 'dev' : 'normal';
+ $this->getDevView();
+ }
+
+ public function getDevView()
+ {
+ $this->variables = $this->formatEnvironmentVariables($this->environment->environment_variables->sortBy('key'));
+ }
+
+ private function formatEnvironmentVariables($variables)
+ {
+ return $variables->map(function ($item) {
+ if ($item->is_shown_once) {
+ return "$item->key=(Locked Secret, delete and add again to change)";
+ }
+ if ($item->is_multiline) {
+ return "$item->key=(Multiline environment variable, edit in normal view)";
+ }
+
+ return "$item->key=$item->value";
+ })->join("\n");
+ }
+
+ public function submit()
+ {
+ try {
+ $this->authorize('update', $this->environment);
+ $this->handleBulkSubmit();
+ $this->getDevView();
+ } catch (\Throwable $e) {
+ return handleError($e, $this);
+ } finally {
+ $this->refreshEnvs();
+ }
+ }
+
+ private function handleBulkSubmit()
+ {
+ $variables = parseEnvFormatToArray($this->variables);
+ $changesMade = false;
+
+ DB::transaction(function () use ($variables, &$changesMade) {
+ // Delete removed variables
+ $deletedCount = $this->deleteRemovedVariables($variables);
+ if ($deletedCount > 0) {
+ $changesMade = true;
+ }
+
+ // Update or create variables
+ $updatedCount = $this->updateOrCreateVariables($variables);
+ if ($updatedCount > 0) {
+ $changesMade = true;
+ }
+ });
+
+ // Only dispatch success after transaction has committed
+ if ($changesMade) {
+ $this->dispatch('success', 'Environment variables updated.');
+ }
+ }
+
+ private function deleteRemovedVariables($variables)
+ {
+ $variablesToDelete = $this->environment->environment_variables()->whereNotIn('key', array_keys($variables))->get();
+
+ if ($variablesToDelete->isEmpty()) {
+ return 0;
+ }
+
+ $this->environment->environment_variables()->whereNotIn('key', array_keys($variables))->delete();
+
+ return $variablesToDelete->count();
+ }
+
+ private function updateOrCreateVariables($variables)
+ {
+ $count = 0;
+ foreach ($variables as $key => $value) {
+ $found = $this->environment->environment_variables()->where('key', $key)->first();
+
+ if ($found) {
+ if (! $found->is_shown_once && ! $found->is_multiline) {
+ if ($found->value !== $value) {
+ $found->value = $value;
+ $found->save();
+ $count++;
+ }
+ }
+ } else {
+ $this->environment->environment_variables()->create([
+ 'key' => $key,
+ 'value' => $value,
+ 'is_multiline' => false,
+ 'is_literal' => false,
+ 'type' => 'environment',
+ 'team_id' => currentTeam()->id,
+ ]);
+ $count++;
+ }
+ }
+
+ return $count;
+ }
+
+ public function refreshEnvs()
+ {
+ $this->environment->refresh();
+ $this->getDevView();
}
public function render()
diff --git a/app/Livewire/SharedVariables/Project/Show.php b/app/Livewire/SharedVariables/Project/Show.php
index 712a9960b..93ead33a3 100644
--- a/app/Livewire/SharedVariables/Project/Show.php
+++ b/app/Livewire/SharedVariables/Project/Show.php
@@ -4,6 +4,7 @@
use App\Models\Project;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
+use Illuminate\Support\Facades\DB;
use Livewire\Component;
class Show extends Component
@@ -12,7 +13,11 @@ class Show extends Component
public Project $project;
- protected $listeners = ['refreshEnvs' => '$refresh', 'saveKey' => 'saveKey', 'environmentVariableDeleted' => '$refresh'];
+ public string $view = 'normal';
+
+ public ?string $variables = null;
+
+ protected $listeners = ['refreshEnvs' => 'refreshEnvs', 'saveKey' => 'saveKey', 'environmentVariableDeleted' => 'refreshEnvs'];
public function saveKey($data)
{
@@ -32,6 +37,7 @@ public function saveKey($data)
'team_id' => currentTeam()->id,
]);
$this->project->refresh();
+ $this->getDevView();
} catch (\Throwable $e) {
return handleError($e, $this);
}
@@ -46,6 +52,119 @@ public function mount()
return redirect()->route('dashboard');
}
$this->project = $project;
+ $this->getDevView();
+ }
+
+ public function switch()
+ {
+ $this->view = $this->view === 'normal' ? 'dev' : 'normal';
+ $this->getDevView();
+ }
+
+ public function getDevView()
+ {
+ $this->variables = $this->formatEnvironmentVariables($this->project->environment_variables->sortBy('key'));
+ }
+
+ private function formatEnvironmentVariables($variables)
+ {
+ return $variables->map(function ($item) {
+ if ($item->is_shown_once) {
+ return "$item->key=(Locked Secret, delete and add again to change)";
+ }
+ if ($item->is_multiline) {
+ return "$item->key=(Multiline environment variable, edit in normal view)";
+ }
+
+ return "$item->key=$item->value";
+ })->join("\n");
+ }
+
+ public function submit()
+ {
+ try {
+ $this->authorize('update', $this->project);
+ $this->handleBulkSubmit();
+ $this->getDevView();
+ } catch (\Throwable $e) {
+ return handleError($e, $this);
+ } finally {
+ $this->refreshEnvs();
+ }
+ }
+
+ private function handleBulkSubmit()
+ {
+ $variables = parseEnvFormatToArray($this->variables);
+
+ DB::transaction(function () use ($variables) {
+ $changesMade = false;
+
+ // Delete removed variables
+ $deletedCount = $this->deleteRemovedVariables($variables);
+ if ($deletedCount > 0) {
+ $changesMade = true;
+ }
+
+ // Update or create variables
+ $updatedCount = $this->updateOrCreateVariables($variables);
+ if ($updatedCount > 0) {
+ $changesMade = true;
+ }
+
+ if ($changesMade) {
+ $this->dispatch('success', 'Environment variables updated.');
+ }
+ });
+ }
+
+ private function deleteRemovedVariables($variables)
+ {
+ $variablesToDelete = $this->project->environment_variables()->whereNotIn('key', array_keys($variables))->get();
+
+ if ($variablesToDelete->isEmpty()) {
+ return 0;
+ }
+
+ $this->project->environment_variables()->whereNotIn('key', array_keys($variables))->delete();
+
+ return $variablesToDelete->count();
+ }
+
+ private function updateOrCreateVariables($variables)
+ {
+ $count = 0;
+ foreach ($variables as $key => $value) {
+ $found = $this->project->environment_variables()->where('key', $key)->first();
+
+ if ($found) {
+ if (! $found->is_shown_once && ! $found->is_multiline) {
+ if ($found->value !== $value) {
+ $found->value = $value;
+ $found->save();
+ $count++;
+ }
+ }
+ } else {
+ $this->project->environment_variables()->create([
+ 'key' => $key,
+ 'value' => $value,
+ 'is_multiline' => false,
+ 'is_literal' => false,
+ 'type' => 'project',
+ 'team_id' => currentTeam()->id,
+ ]);
+ $count++;
+ }
+ }
+
+ return $count;
+ }
+
+ public function refreshEnvs()
+ {
+ $this->project->refresh();
+ $this->getDevView();
}
public function render()
diff --git a/app/Livewire/SharedVariables/Team/Index.php b/app/Livewire/SharedVariables/Team/Index.php
index 82473528c..bd23bca82 100644
--- a/app/Livewire/SharedVariables/Team/Index.php
+++ b/app/Livewire/SharedVariables/Team/Index.php
@@ -4,6 +4,7 @@
use App\Models\Team;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
+use Illuminate\Support\Facades\DB;
use Livewire\Component;
class Index extends Component
@@ -12,7 +13,11 @@ class Index extends Component
public Team $team;
- protected $listeners = ['refreshEnvs' => '$refresh', 'saveKey' => 'saveKey', 'environmentVariableDeleted' => '$refresh'];
+ public string $view = 'normal';
+
+ public ?string $variables = null;
+
+ protected $listeners = ['refreshEnvs' => 'refreshEnvs', 'saveKey' => 'saveKey', 'environmentVariableDeleted' => 'refreshEnvs'];
public function saveKey($data)
{
@@ -32,6 +37,7 @@ public function saveKey($data)
'team_id' => currentTeam()->id,
]);
$this->team->refresh();
+ $this->getDevView();
} catch (\Throwable $e) {
return handleError($e, $this);
}
@@ -40,6 +46,119 @@ public function saveKey($data)
public function mount()
{
$this->team = currentTeam();
+ $this->getDevView();
+ }
+
+ public function switch()
+ {
+ $this->view = $this->view === 'normal' ? 'dev' : 'normal';
+ $this->getDevView();
+ }
+
+ public function getDevView()
+ {
+ $this->variables = $this->formatEnvironmentVariables($this->team->environment_variables->sortBy('key'));
+ }
+
+ private function formatEnvironmentVariables($variables)
+ {
+ return $variables->map(function ($item) {
+ if ($item->is_shown_once) {
+ return "$item->key=(Locked Secret, delete and add again to change)";
+ }
+ if ($item->is_multiline) {
+ return "$item->key=(Multiline environment variable, edit in normal view)";
+ }
+
+ return "$item->key=$item->value";
+ })->join("\n");
+ }
+
+ public function submit()
+ {
+ try {
+ $this->authorize('update', $this->team);
+ $this->handleBulkSubmit();
+ $this->getDevView();
+ } catch (\Throwable $e) {
+ return handleError($e, $this);
+ } finally {
+ $this->refreshEnvs();
+ }
+ }
+
+ private function handleBulkSubmit()
+ {
+ $variables = parseEnvFormatToArray($this->variables);
+
+ DB::transaction(function () use ($variables) {
+ $changesMade = false;
+
+ // Delete removed variables
+ $deletedCount = $this->deleteRemovedVariables($variables);
+ if ($deletedCount > 0) {
+ $changesMade = true;
+ }
+
+ // Update or create variables
+ $updatedCount = $this->updateOrCreateVariables($variables);
+ if ($updatedCount > 0) {
+ $changesMade = true;
+ }
+
+ if ($changesMade) {
+ $this->dispatch('success', 'Environment variables updated.');
+ }
+ });
+ }
+
+ private function deleteRemovedVariables($variables)
+ {
+ $variablesToDelete = $this->team->environment_variables()->whereNotIn('key', array_keys($variables))->get();
+
+ if ($variablesToDelete->isEmpty()) {
+ return 0;
+ }
+
+ $this->team->environment_variables()->whereNotIn('key', array_keys($variables))->delete();
+
+ return $variablesToDelete->count();
+ }
+
+ private function updateOrCreateVariables($variables)
+ {
+ $count = 0;
+ foreach ($variables as $key => $value) {
+ $found = $this->team->environment_variables()->where('key', $key)->first();
+
+ if ($found) {
+ if (! $found->is_shown_once && ! $found->is_multiline) {
+ if ($found->value !== $value) {
+ $found->value = $value;
+ $found->save();
+ $count++;
+ }
+ }
+ } else {
+ $this->team->environment_variables()->create([
+ 'key' => $key,
+ 'value' => $value,
+ 'is_multiline' => false,
+ 'is_literal' => false,
+ 'type' => 'team',
+ 'team_id' => currentTeam()->id,
+ ]);
+ $count++;
+ }
+ }
+
+ return $count;
+ }
+
+ public function refreshEnvs()
+ {
+ $this->team->refresh();
+ $this->getDevView();
}
public function render()
diff --git a/resources/views/livewire/shared-variables/environment/show.blade.php b/resources/views/livewire/shared-variables/environment/show.blade.php
index 0799a7422..fde2d0ae8 100644
--- a/resources/views/livewire/shared-variables/environment/show.blade.php
+++ b/resources/views/livewire/shared-variables/environment/show.blade.php
@@ -9,17 +9,26 @@