diff --git a/app/Actions/Database/StartMariadb.php b/app/Actions/Database/StartMariadb.php index b557476a6..c0958acb8 100644 --- a/app/Actions/Database/StartMariadb.php +++ b/app/Actions/Database/StartMariadb.php @@ -140,7 +140,7 @@ private function generate_environment_variables() { $environment_variables = collect(); foreach ($this->database->runtime_environment_variables as $env) { - $environment_variables->push("$env->key=$env->value"); + $environment_variables->push("$env->key=$env->real_value"); } if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('MARIADB_ROOT_PASSWORD'))->isEmpty()) { diff --git a/app/Actions/Database/StartMongodb.php b/app/Actions/Database/StartMongodb.php index fb60d778f..3b9b07c49 100644 --- a/app/Actions/Database/StartMongodb.php +++ b/app/Actions/Database/StartMongodb.php @@ -156,7 +156,7 @@ private function generate_environment_variables() { $environment_variables = collect(); foreach ($this->database->runtime_environment_variables as $env) { - $environment_variables->push("$env->key=$env->value"); + $environment_variables->push("$env->key=$env->real_value"); } if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('MONGO_INITDB_ROOT_USERNAME'))->isEmpty()) { diff --git a/app/Actions/Database/StartMysql.php b/app/Actions/Database/StartMysql.php index 12bbc03ee..b7ce74771 100644 --- a/app/Actions/Database/StartMysql.php +++ b/app/Actions/Database/StartMysql.php @@ -140,7 +140,7 @@ private function generate_environment_variables() { $environment_variables = collect(); foreach ($this->database->runtime_environment_variables as $env) { - $environment_variables->push("$env->key=$env->value"); + $environment_variables->push("$env->key=$env->real_value"); } if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('MYSQL_ROOT_PASSWORD'))->isEmpty()) { diff --git a/app/Actions/Database/StartPostgresql.php b/app/Actions/Database/StartPostgresql.php index edf4a27e1..e1427ae53 100644 --- a/app/Actions/Database/StartPostgresql.php +++ b/app/Actions/Database/StartPostgresql.php @@ -164,7 +164,7 @@ private function generate_environment_variables() ray('Generate Environment Variables')->green(); ray($this->database->runtime_environment_variables)->green(); foreach ($this->database->runtime_environment_variables as $env) { - $environment_variables->push("$env->key=$env->value"); + $environment_variables->push("$env->key=$env->real_value"); } if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('POSTGRES_USER'))->isEmpty()) { diff --git a/app/Actions/Database/StartRedis.php b/app/Actions/Database/StartRedis.php index dc17636a7..966015746 100644 --- a/app/Actions/Database/StartRedis.php +++ b/app/Actions/Database/StartRedis.php @@ -151,7 +151,7 @@ private function generate_environment_variables() { $environment_variables = collect(); foreach ($this->database->runtime_environment_variables as $env) { - $environment_variables->push("$env->key=$env->value"); + $environment_variables->push("$env->key=$env->real_value"); } if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('REDIS_PASSWORD'))->isEmpty()) { diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index d9a7176a8..595e22240 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -417,11 +417,11 @@ private function save_environment_variables() $envs = collect([]); if ($this->pull_request_id !== 0) { foreach ($this->application->environment_variables_preview as $env) { - $envs->push($env->key . '=' . $env->value); + $envs->push($env->key . '=' . $env->real_value); } } else { foreach ($this->application->environment_variables as $env) { - $envs->push($env->key . '=' . $env->value); + $envs->push($env->key . '=' . $env->real_value); } } $envs_base64 = base64_encode($envs->implode("\n")); @@ -929,11 +929,11 @@ private function generate_nixpacks_env_variables() $this->env_nixpacks_args = collect([]); if ($this->pull_request_id === 0) { foreach ($this->application->nixpacks_environment_variables as $env) { - $this->env_nixpacks_args->push("--env {$env->key}={$env->value}"); + $this->env_nixpacks_args->push("--env {$env->key}={$env->real_value}"); } } else { foreach ($this->application->nixpacks_environment_variables_preview as $env) { - $this->env_nixpacks_args->push("--env {$env->key}={$env->value}"); + $this->env_nixpacks_args->push("--env {$env->key}={$env->real_value}"); } } @@ -944,11 +944,11 @@ private function generate_env_variables() $this->env_args = collect([]); if ($this->pull_request_id === 0) { foreach ($this->application->build_environment_variables as $env) { - $this->env_args->put($env->key, $env->value); + $this->env_args->put($env->key, $env->real_value); } } else { foreach ($this->application->build_environment_variables_preview as $env) { - $this->env_args->put($env->key, $env->value); + $this->env_args->put($env->key, $env->real_value); } } $this->env_args->put('SOURCE_COMMIT', $this->commit); @@ -1159,22 +1159,19 @@ private function generate_local_persistent_volumes_only_volume_names() private function generate_environment_variables($ports) { $environment_variables = collect(); - // ray('Generate Environment Variables')->green(); if ($this->pull_request_id === 0) { - // ray($this->application->runtime_environment_variables)->green(); foreach ($this->application->runtime_environment_variables as $env) { - $environment_variables->push("$env->key=$env->value"); + $environment_variables->push("$env->key=$env->real_value"); } foreach ($this->application->nixpacks_environment_variables as $env) { - $environment_variables->push("$env->key=$env->value"); + $environment_variables->push("$env->key=$env->real_value"); } } else { - // ray($this->application->runtime_environment_variables_preview)->green(); foreach ($this->application->runtime_environment_variables_preview as $env) { - $environment_variables->push("$env->key=$env->value"); + $environment_variables->push("$env->key=$env->real_value"); } foreach ($this->application->nixpacks_environment_variables_preview as $env) { - $environment_variables->push("$env->key=$env->value"); + $environment_variables->push("$env->key=$env->real_value"); } } // Add PORT if not exists, use the first port as default @@ -1457,12 +1454,12 @@ private function generate_build_env_variables() $this->build_args = collect(["--build-arg SOURCE_COMMIT=\"{$this->commit}\""]); if ($this->pull_request_id === 0) { foreach ($this->application->build_environment_variables as $env) { - $value = escapeshellarg($env->value); + $value = escapeshellarg($env->real_value); $this->build_args->push("--build-arg {$env->key}={$value}"); } } else { foreach ($this->application->build_environment_variables_preview as $env) { - $value = escapeshellarg($env->value); + $value = escapeshellarg($env->real_value); $this->build_args->push("--build-arg {$env->key}={$value}"); } } @@ -1478,11 +1475,11 @@ private function add_build_env_variables_to_dockerfile() $dockerfile = collect(Str::of($this->saved_outputs->get('dockerfile'))->trim()->explode("\n")); if ($this->pull_request_id === 0) { foreach ($this->application->build_environment_variables as $env) { - $dockerfile->splice(1, 0, "ARG {$env->key}={$env->value}"); + $dockerfile->splice(1, 0, "ARG {$env->key}={$env->real_value}"); } } else { foreach ($this->application->build_environment_variables_preview as $env) { - $dockerfile->splice(1, 0, "ARG {$env->key}={$env->value}"); + $dockerfile->splice(1, 0, "ARG {$env->key}={$env->real_value}"); } } $dockerfile_base64 = base64_encode($dockerfile->implode("\n")); diff --git a/app/Livewire/Project/Edit.php b/app/Livewire/Project/Edit.php index e674e3dd9..b2cda7a47 100644 --- a/app/Livewire/Project/Edit.php +++ b/app/Livewire/Project/Edit.php @@ -12,7 +12,24 @@ class Edit extends Component 'project.name' => 'required|min:3|max:255', 'project.description' => 'nullable|string|max:255', ]; - public function mount() { + protected $listeners = ['refreshEnvs' => '$refresh', 'saveKey' => 'saveKey']; + + public function saveKey($data) + { + try { + $this->project->environment_variables()->create([ + 'key' => $data['key'], + 'value' => $data['value'], + 'type' => 'project', + 'team_id' => currentTeam()->id, + ]); + $this->project->refresh(); + } catch (\Throwable $e) { + return handleError($e, $this); + } + } + public function mount() + { $projectUuid = request()->route('project_uuid'); $teamId = currentTeam()->id; $project = Project::where('team_id', $teamId)->where('uuid', $projectUuid)->first(); diff --git a/app/Livewire/Project/EnvironmentEdit.php b/app/Livewire/Project/EnvironmentEdit.php index a87e2092b..276aa58df 100644 --- a/app/Livewire/Project/EnvironmentEdit.php +++ b/app/Livewire/Project/EnvironmentEdit.php @@ -12,14 +12,30 @@ class EnvironmentEdit extends Component public Application $application; public $environment; public array $parameters; - protected $rules = [ 'environment.name' => 'required|min:3|max:255', 'environment.description' => 'nullable|min:3|max:255', ]; - public function mount() { - $this->parameters = get_route_parameters(); + protected $listeners = ['refreshEnvs' => '$refresh', 'saveKey' => 'saveKey']; + public function saveKey($data) + { + try { + $this->environment->environment_variables()->create([ + 'key' => $data['key'], + 'value' => $data['value'], + 'type' => 'environment', + 'team_id' => currentTeam()->id, + ]); + $this->environment->refresh(); + } catch (\Throwable $e) { + return handleError($e, $this); + } + } + + public function mount() + { + $this->parameters = get_route_parameters(); $this->project = Project::ownedByCurrentTeam()->where('uuid', request()->route('project_uuid'))->first(); $this->environment = $this->project->environments()->where('name', request()->route('environment_name'))->first(); } diff --git a/app/Livewire/Project/Shared/EnvironmentVariable/Add.php b/app/Livewire/Project/Shared/EnvironmentVariable/Add.php index 1d6e09b43..78ed3c780 100644 --- a/app/Livewire/Project/Shared/EnvironmentVariable/Add.php +++ b/app/Livewire/Project/Shared/EnvironmentVariable/Add.php @@ -32,7 +32,6 @@ public function mount() public function submit() { $this->validate(); - ray($this->key, $this->value, $this->is_build_time); $this->dispatch('saveKey', [ 'key' => $this->key, 'value' => $this->value, diff --git a/app/Livewire/Project/Shared/EnvironmentVariable/Show.php b/app/Livewire/Project/Shared/EnvironmentVariable/Show.php index 10a8856da..f8709afd8 100644 --- a/app/Livewire/Project/Shared/EnvironmentVariable/Show.php +++ b/app/Livewire/Project/Shared/EnvironmentVariable/Show.php @@ -3,16 +3,18 @@ namespace App\Livewire\Project\Shared\EnvironmentVariable; use App\Models\EnvironmentVariable as ModelsEnvironmentVariable; +use App\Models\SharedEnvironmentVariable; use Livewire\Component; use Visus\Cuid2\Cuid2; class Show extends Component { public $parameters; - public ModelsEnvironmentVariable $env; + public ModelsEnvironmentVariable|SharedEnvironmentVariable $env; public ?string $modalId = null; public bool $isDisabled = false; public bool $isLocked = false; + public bool $isSharedVariable = false; public string $type; protected $rules = [ @@ -20,16 +22,20 @@ class Show extends Component 'env.value' => 'nullable', 'env.is_build_time' => 'required|boolean', 'env.is_shown_once' => 'required|boolean', + 'env.real_value' => 'nullable', ]; protected $validationAttributes = [ - 'key' => 'Key', - 'value' => 'Value', - 'is_build_time' => 'Build Time', - 'is_shown_once' => 'Shown Once', + 'env.key' => 'Key', + 'env.value' => 'Value', + 'env.is_build_time' => 'Build Time', + 'env.is_shown_once' => 'Shown Once', ]; public function mount() { + if ($this->env->getMorphClass() === 'App\Models\SharedEnvironmentVariable') { + $this->isSharedVariable = true; + } $this->modalId = new Cuid2(7); $this->parameters = get_route_parameters(); $this->checkEnvs(); @@ -44,9 +50,16 @@ public function checkEnvs() $this->isLocked = true; } } + public function serialize() { + data_forget($this->env, 'real_value'); + if ($this->env->getMorphClass() === 'App\Models\SharedEnvironmentVariable') { + data_forget($this->env, 'is_build_time'); + } + } public function lock() { $this->env->is_shown_once = true; + $this->serialize(); $this->env->save(); $this->checkEnvs(); $this->dispatch('refreshEnvs'); @@ -57,10 +70,23 @@ public function instantSave() } public function submit() { - $this->validate(); - $this->env->save(); - $this->dispatch('success', 'Environment variable updated successfully.'); - $this->dispatch('refreshEnvs'); + try { + if ($this->isSharedVariable) { + $this->validate([ + 'env.key' => 'required|string', + 'env.value' => 'nullable', + 'env.is_shown_once' => 'required|boolean', + ]); + } else { + $this->validate(); + } + $this->serialize(); + $this->env->save(); + $this->dispatch('success', 'Environment variable updated successfully.'); + $this->dispatch('refreshEnvs'); + } catch(\Exception $e) { + return handleError($e); + } } public function delete() diff --git a/app/Livewire/TeamSharedVariablesIndex.php b/app/Livewire/TeamSharedVariablesIndex.php new file mode 100644 index 000000000..d2776e8b2 --- /dev/null +++ b/app/Livewire/TeamSharedVariablesIndex.php @@ -0,0 +1,36 @@ + '$refresh', 'saveKey' => 'saveKey']; + + public function saveKey($data) + { + try { + $this->team->environment_variables()->create([ + 'key' => $data['key'], + 'value' => $data['value'], + 'type' => 'team', + 'team_id' => currentTeam()->id, + ]); + $this->team->refresh(); + } catch (\Throwable $e) { + return handleError($e, $this); + } + } + + public function mount() + { + $this->team = currentTeam(); + } + public function render() + { + return view('livewire.team-shared-variables-index'); + } +} diff --git a/app/Models/Application.php b/app/Models/Application.php index 4e845fe0d..79f888797 100644 --- a/app/Models/Application.php +++ b/app/Models/Application.php @@ -263,6 +263,10 @@ public function portsExposesArray(): Attribute : explode(',', $this->ports_exposes) ); } + public function team() + { + return data_get($this, 'environment.project.team'); + } public function serviceType() { $found = str(collect(SPECIFIC_SERVICES)->filter(function ($service) { @@ -431,7 +435,7 @@ public function isConfigurationChanged($save = false) { $newConfigHash = $this->fqdn . $this->git_repository . $this->git_branch . $this->git_commit_sha . $this->build_pack . $this->static_image . $this->install_command . $this->build_command . $this->start_command . $this->port_exposes . $this->port_mappings . $this->base_directory . $this->publish_directory . $this->dockerfile . $this->dockerfile_location . $this->custom_labels; if ($this->pull_request_id === 0 || $this->pull_request_id === null) { - $newConfigHash .= json_encode($this->environment_variables->all()); + $newConfigHash .= json_encode($this->environment_variables()); } else { $newConfigHash .= json_encode($this->environment_variables_preview->all()); } diff --git a/app/Models/Environment.php b/app/Models/Environment.php index 430a02cdb..726b9078b 100644 --- a/app/Models/Environment.php +++ b/app/Models/Environment.php @@ -17,6 +17,9 @@ public function isEmpty() $this->services()->count() == 0; } + public function environment_variables() { + return $this->hasMany(SharedEnvironmentVariable::class); + } public function applications() { return $this->hasMany(Application::class); diff --git a/app/Models/EnvironmentVariable.php b/app/Models/EnvironmentVariable.php index 5450f0127..3179a54f9 100644 --- a/app/Models/EnvironmentVariable.php +++ b/app/Models/EnvironmentVariable.php @@ -15,6 +15,7 @@ class EnvironmentVariable extends Model 'value' => 'encrypted', 'is_build_time' => 'boolean', ]; + protected $appends = ['real_value', 'is_shared']; protected static function booted() { @@ -48,24 +49,94 @@ protected function value(): Attribute set: fn (?string $value = null) => $this->set_environment_variables($value), ); } - - private function get_environment_variables(?string $environment_variable = null): string|null + protected function realValue(): Attribute + { + return Attribute::make( + get: fn () => $this->get_real_environment_variables($this->value), + ); + } + protected function isShared(): Attribute + { + return Attribute::make( + get: function () { + $type = str($this->value)->after("{{")->before(".")->value; + if (str($this->value)->startsWith('{{' . $type) && str($this->value)->endsWith('}}')) { + return true; + } + return false; + } + ); + } + private function team() + { + if ($this->application_id) { + $application = Application::find($this->application_id); + if ($application) { + return $application->team(); + } + } + if ($this->service_id) { + $service = Service::find($this->service_id); + if ($service) { + return $service->team(); + } + } + if ($this->standalone_postgresql_id) { + $standalone_postgresql = StandalonePostgresql::find($this->standalone_postgresql_id); + if ($standalone_postgresql) { + return $standalone_postgresql->team(); + } + } + if ($this->standalone_mysql_id) { + $standalone_mysql = StandaloneMysql::find($this->standalone_mysql_id); + if ($standalone_mysql) { + return $standalone_mysql->team(); + } + } + if ($this->standalone_redis_id) { + $standalone_redis = StandaloneRedis::find($this->standalone_redis_id); + if ($standalone_redis) { + return $standalone_redis->team(); + } + } + if ($this->standalone_mongodb_id) { + $standalone_mongodb = StandaloneMongodb::find($this->standalone_mongodb_id); + if ($standalone_mongodb) { + return $standalone_mongodb->team(); + } + } + if ($this->standalone_mariadb_id) { + $standalone_mariadb = StandaloneMariadb::find($this->standalone_mariadb_id); + if ($standalone_mariadb) { + return $standalone_mariadb->team(); + } + } + } + private function get_real_environment_variables(?string $environment_variable = null): string|null { - // $team_id = currentTeam()->id; if (!$environment_variable) { return null; } - $environment_variable = trim(decrypt($environment_variable)); - if (Str::startsWith($environment_variable, '{{') && Str::endsWith($environment_variable, '}}') && Str::contains($environment_variable, 'global.')) { - $variable = Str::after($environment_variable, 'global.'); + $environment_variable = trim($environment_variable); + $type = str($environment_variable)->after("{{")->before(".")->value; + if (str($environment_variable)->startsWith("{{" . $type) && str($environment_variable)->endsWith('}}')) { + $variable = Str::after($environment_variable, "{$type}."); $variable = Str::before($variable, '}}'); $variable = Str::of($variable)->trim()->value; - // $environment_variable = GlobalEnvironmentVariable::where('name', $environment_variable)->where('team_id', $team_id)->first()?->value; - ray('global env variable'); - return $environment_variable; + $environment_variable_found = SharedEnvironmentVariable::where("type", $type)->where('key', $variable)->where('team_id', $this->team()->id)->first(); + if ($environment_variable_found) { + return $environment_variable_found->value; + } } return $environment_variable; } + private function get_environment_variables(?string $environment_variable = null): string|null + { + if (!$environment_variable) { + return null; + } + return trim(decrypt($environment_variable)); + } private function set_environment_variables(?string $environment_variable = null): string|null { @@ -73,6 +144,10 @@ private function set_environment_variables(?string $environment_variable = null) return null; } $environment_variable = trim($environment_variable); + $type = str($environment_variable)->after("{{")->before(".")->value; + if (str($environment_variable)->startsWith("{{" . $type) && str($environment_variable)->endsWith('}}')) { + return encrypt((string) str($environment_variable)->replace(' ', '')); + } return encrypt($environment_variable); } diff --git a/app/Models/Project.php b/app/Models/Project.php index 1668d4059..d5f1bdd54 100644 --- a/app/Models/Project.php +++ b/app/Models/Project.php @@ -27,7 +27,9 @@ protected static function booted() $project->settings()->delete(); }); } - + public function environment_variables() { + return $this->hasMany(SharedEnvironmentVariable::class); + } public function environments() { return $this->hasMany(Environment::class); diff --git a/app/Models/Service.php b/app/Models/Service.php index 7f71ff865..42cb01108 100644 --- a/app/Models/Service.php +++ b/app/Models/Service.php @@ -8,6 +8,7 @@ use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Support\Collection; use Illuminate\Support\Str; +use Symfony\Component\Yaml\Yaml; class Service extends BaseModel { @@ -17,6 +18,10 @@ public function type() { return 'service'; } + public function team() + { + return data_get($this, 'environment.project.team'); + } public function extraFields() { $fields = collect([]); @@ -423,7 +428,7 @@ public function saveComposeConfigs() $envs = $this->environment_variables()->get(); $commands[] = "rm -f .env || true"; foreach ($envs as $env) { - $commands[] = "echo '{$env->key}={$env->value}' >> .env"; + $commands[] = "echo '{$env->key}={$env->real_value}' >> .env"; } if ($envs->count() === 0) { $commands[] = "touch .env"; diff --git a/app/Models/SharedEnvironmentVariable.php b/app/Models/SharedEnvironmentVariable.php new file mode 100644 index 000000000..260f16afb --- /dev/null +++ b/app/Models/SharedEnvironmentVariable.php @@ -0,0 +1,14 @@ + 'string', + 'value' => 'encrypted', + ]; +} diff --git a/app/Models/StandaloneMariadb.php b/app/Models/StandaloneMariadb.php index 33c00260e..8b3f3412d 100644 --- a/app/Models/StandaloneMariadb.php +++ b/app/Models/StandaloneMariadb.php @@ -42,6 +42,10 @@ protected static function booted() $database->environment_variables()->delete(); }); } + public function team() + { + return data_get($this, 'environment.project.team'); + } public function link() { if (data_get($this, 'environment.project.uuid')) { diff --git a/app/Models/StandaloneMongodb.php b/app/Models/StandaloneMongodb.php index d08c04adb..de2e7f2eb 100644 --- a/app/Models/StandaloneMongodb.php +++ b/app/Models/StandaloneMongodb.php @@ -45,6 +45,10 @@ protected static function booted() $database->environment_variables()->delete(); }); } + public function team() + { + return data_get($this, 'environment.project.team'); + } public function isLogDrainEnabled() { return data_get($this, 'is_log_drain_enabled', false); diff --git a/app/Models/StandaloneMysql.php b/app/Models/StandaloneMysql.php index 02f8f82c4..c9608f1cc 100644 --- a/app/Models/StandaloneMysql.php +++ b/app/Models/StandaloneMysql.php @@ -42,6 +42,10 @@ protected static function booted() $database->environment_variables()->delete(); }); } + public function team() + { + return data_get($this, 'environment.project.team'); + } public function link() { if (data_get($this, 'environment.project.uuid')) { diff --git a/app/Models/StandalonePostgresql.php b/app/Models/StandalonePostgresql.php index df9d28460..577904260 100644 --- a/app/Models/StandalonePostgresql.php +++ b/app/Models/StandalonePostgresql.php @@ -74,7 +74,10 @@ public function portsMappingsArray(): Attribute ); } - + public function team() + { + return data_get($this, 'environment.project.team'); + } public function type(): string { return 'standalone-postgresql'; diff --git a/app/Models/StandaloneRedis.php b/app/Models/StandaloneRedis.php index 7ccde7f68..5f4279183 100644 --- a/app/Models/StandaloneRedis.php +++ b/app/Models/StandaloneRedis.php @@ -37,6 +37,10 @@ protected static function booted() $database->environment_variables()->delete(); }); } + public function team() + { + return data_get($this, 'environment.project.team'); + } public function link() { if (data_get($this, 'environment.project.uuid')) { diff --git a/app/Models/Team.php b/app/Models/Team.php index 8021b1e97..042f74789 100644 --- a/app/Models/Team.php +++ b/app/Models/Team.php @@ -70,7 +70,9 @@ public function limits(): Attribute ); } - + public function environment_variables() { + return $this->hasMany(SharedEnvironmentVariable::class)->whereNull('project_id')->whereNull('environment_id'); + } public function members() { return $this->belongsToMany(User::class, 'team_user', 'team_id', 'user_id')->withPivot('role'); diff --git a/app/View/Components/Forms/Select.php b/app/View/Components/Forms/Select.php index 381b86dce..e1f2fc759 100644 --- a/app/View/Components/Forms/Select.php +++ b/app/View/Components/Forms/Select.php @@ -19,7 +19,7 @@ public function __construct( public string|null $label = null, public string|null $helper = null, public bool $required = false, - public string $defaultClass = "select select-sm w-full rounded text-white text-sm bg-coolgray-100 font-normal disabled:bg-coolgray-200/50 disabled:border-none" + public string $defaultClass = "select select-sm w-full rounded text-sm bg-coolgray-100 font-normal disabled:bg-coolgray-200/50 disabled:border-none" ) { // } diff --git a/database/migrations/2024_01_23_113129_create_shared_environment_variables_table.php b/database/migrations/2024_01_23_113129_create_shared_environment_variables_table.php new file mode 100644 index 000000000..994a02a40 --- /dev/null +++ b/database/migrations/2024_01_23_113129_create_shared_environment_variables_table.php @@ -0,0 +1,37 @@ +id(); + $table->string('key'); + $table->string('value')->nullable(); + $table->boolean('is_shown_once')->default(false); + $table->enum('type', ['team', 'project', 'environment'])->default('team'); + + $table->foreignId('team_id')->constrained()->onDelete('cascade'); + $table->foreignId('project_id')->nullable()->constrained()->onDelete('cascade'); + $table->foreignId('environment_id')->nullable()->constrained()->onDelete('cascade'); + $table->unique(['key', 'project_id', 'team_id']); + $table->unique(['key', 'environment_id', 'team_id']); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('shared_environment_variables'); + } +}; diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 2a2767d78..9f93c7e9e 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -18,6 +18,7 @@ public function run(): void ProjectSeeder::class, ProjectSettingSeeder::class, EnvironmentSeeder::class, + TeamEnvironmentVariableSeeder::class, StandaloneDockerSeeder::class, SwarmDockerSeeder::class, KubernetesSeeder::class, diff --git a/database/seeders/SharedEnvironmentVariableSeeder.php b/database/seeders/SharedEnvironmentVariableSeeder.php new file mode 100644 index 000000000..54643fe3b --- /dev/null +++ b/database/seeders/SharedEnvironmentVariableSeeder.php @@ -0,0 +1,36 @@ + 'NODE_ENV', + 'value' => 'team_env', + 'type' => 'team', + 'team_id' => 0, + ]); + SharedEnvironmentVariable::create([ + 'key' => 'NODE_ENV', + 'value' => 'env_env', + 'type' => 'environment', + 'environment_id' => 1, + 'team_id' => 0, + ]); + SharedEnvironmentVariable::create([ + 'key' => 'NODE_ENV', + 'value' => 'project_env', + 'type' => 'project', + 'project_id' => 1, + 'team_id' => 0, + ]); + } +} diff --git a/resources/css/app.css b/resources/css/app.css index cd383c1cd..5778b9529 100644 --- a/resources/css/app.css +++ b/resources/css/app.css @@ -168,3 +168,6 @@ .fullscreen { input.input-sm { @apply pr-10; } +option{ + @apply text-white; +} diff --git a/resources/views/components/navbar-subscription.blade.php b/resources/views/components/navbar-subscription.blade.php index 4636db475..8638430e5 100644 --- a/resources/views/components/navbar-subscription.blade.php +++ b/resources/views/components/navbar-subscription.blade.php @@ -13,7 +13,7 @@ class="transition rounded w-11 h-11" src="{{ asset('coolify-transparent.png') }}
  • - + diff --git a/resources/views/components/slide-over.blade.php b/resources/views/components/slide-over.blade.php new file mode 100644 index 000000000..af22bd396 --- /dev/null +++ b/resources/views/components/slide-over.blade.php @@ -0,0 +1,48 @@ +
    + {{ $slot }} + +
    diff --git a/resources/views/components/team/navbar.blade.php b/resources/views/components/team/navbar.blade.php index 3b7fb1f40..4f18477e3 100644 --- a/resources/views/components/team/navbar.blade.php +++ b/resources/views/components/team/navbar.blade.php @@ -14,20 +14,24 @@ class="text-warning">{{ session('currentTeam.name') }}
  • @@ -41,4 +41,18 @@ +
    +

    Shared Variables

    + + Add + +
    +
    You can use this anywhere.
    +
    + @forelse ($environment->environment_variables->sort()->sortBy('real_value') as $env) + + @empty +
    No environment variables found.
    + @endforelse +
    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 ae59cf907..5999267fc 100644 --- a/resources/views/livewire/project/shared/environment-variable/all.blade.php +++ b/resources/views/livewire/project/shared/environment-variable/all.blade.php @@ -2,15 +2,33 @@

    Environment Variables

    - + Add - + @if ($resource->type() !== 'service') + + Add Environment Variables + +
    + + + + Save + + +
    + +
    + {{-- + Add --}} + @endif {{ $view === 'normal' ? 'Developer view' : 'Normal view' }}
    Environment variables (secrets) for this resource.
    + @if ($resource->type() === 'service') +
    If you cannot find a variable here, or need a new one, define it in the Docker Compose file.
    + @endif
    @if ($view === 'normal') - @forelse ($resource->environment_variables as $env) + @forelse ($resource->environment_variables->sort()->sortBy('real_value') as $env) @empty @@ -21,7 +39,7 @@

    Preview Deployments

    Environment (secrets) variables for Preview Deployments.
    - @foreach ($resource->environment_variables_preview as $env) + @foreach ($resource->environment_variables_preview->sort()->sortBy('real_value') as $env) @endforeach diff --git a/resources/views/livewire/project/shared/environment-variable/show.blade.php b/resources/views/livewire/project/shared/environment-variable/show.blade.php index befdb1ca8..7a80e4979 100644 --- a/resources/views/livewire/project/shared/environment-variable/show.blade.php +++ b/resources/views/livewire/project/shared/environment-variable/show.blade.php @@ -19,13 +19,19 @@ class="flex flex-col gap-2 p-4 m-2 border lg:items-center border-coolgray-300 lg @if ($isDisabled) - @if ($type !== 'service') + @if ($env->is_shared) + + @endif + @if ($type !== 'service' && !$isSharedVariable) @endif @else - @if ($type !== 'service') + @if ($env->is_shared) + + @endif + @if ($type !== 'service' && !$isSharedVariable) @endif @endif diff --git a/resources/views/livewire/security/private-key/create.blade.php b/resources/views/livewire/security/private-key/create.blade.php index 10ef5185d..ea9e7a58f 100644 --- a/resources/views/livewire/security/private-key/create.blade.php +++ b/resources/views/livewire/security/private-key/create.blade.php @@ -1,5 +1,5 @@
    -

    Create a new Private Key

    +

    Private Key

    Private Keys are used to connect to your servers without passwords.
    Generate new SSH key for me
    diff --git a/resources/views/livewire/server/create.blade.php b/resources/views/livewire/server/create.blade.php index 7f87e77ac..e07e06cc0 100644 --- a/resources/views/livewire/server/create.blade.php +++ b/resources/views/livewire/server/create.blade.php @@ -2,7 +2,7 @@ @if ($private_keys->count() === 0)

    Create Private Key

    You need to create a private key before you can create a server.
    - + @else @endif diff --git a/resources/views/livewire/team-shared-variables-index.blade.php b/resources/views/livewire/team-shared-variables-index.blade.php new file mode 100644 index 000000000..25eaea1a4 --- /dev/null +++ b/resources/views/livewire/team-shared-variables-index.blade.php @@ -0,0 +1,17 @@ +
    + +
    +

    Shared Variables

    + + Add + +
    +
    You can use this anywhere.
    +
    + @forelse ($team->environment_variables->sort()->sortBy('real_value') as $env) + + @empty +
    No environment variables found.
    + @endforelse +
    +
    diff --git a/resources/views/livewire/team/notification/index.blade.php b/resources/views/livewire/team/notification/index.blade.php index 26270b480..ed961deb0 100644 --- a/resources/views/livewire/team/notification/index.blade.php +++ b/resources/views/livewire/team/notification/index.blade.php @@ -22,3 +22,4 @@
    + diff --git a/routes/web.php b/routes/web.php index 65f5057fc..9b469463f 100644 --- a/routes/web.php +++ b/routes/web.php @@ -67,6 +67,7 @@ use App\Livewire\Source\Github\Change as GitHubChange; use App\Livewire\Subscription\Index as SubscriptionIndex; +use App\Livewire\TeamSharedVariablesIndex; use App\Livewire\Waitlist\Index as WaitlistIndex; use Illuminate\Foundation\Auth\EmailVerificationRequest; use Illuminate\Support\Facades\Password; @@ -117,6 +118,7 @@ Route::get('/new', TeamCreate::class)->name('team.create'); Route::get('/members', TeamMemberIndex::class)->name('team.member.index'); Route::get('/notifications', TeamNotificationIndex::class)->name('team.notification.index'); + Route::get('/shared-variables', TeamSharedVariablesIndex::class)->name('team.shared-variables.index'); Route::get('/storages', TeamStorageIndex::class)->name('team.storage.index'); Route::get('/storages/new', TeamStorageCreate::class)->name('team.storage.create'); Route::get('/storages/{storage_uuid}', TeamStorageShow::class)->name('team.storage.show'); diff --git a/tailwind.config.js b/tailwind.config.js index d44267e6a..bfc322748 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -14,17 +14,8 @@ module.exports = { sans: ["Inter", "sans-serif"], }, colors: { - // applications: "#16A34A", - // databases: "#9333EA", - // "databases-100": "#9b46ea", - // destinations: "#0284C7", - // sources: "#EA580C", - // services: "#DB2777", - // settings: "#FEE440", - // iam: "#C026D3", coollabs: "#6B16ED", "coollabs-100": "#7317FF", - // coolblack: "#141414", "coolgray-100": "#181818", "coolgray-200": "#202020", "coolgray-300": "#242424", diff --git a/tests/Feature/Livewire/TeamSharedVariablesIndexTest.php b/tests/Feature/Livewire/TeamSharedVariablesIndexTest.php new file mode 100644 index 000000000..13a556b95 --- /dev/null +++ b/tests/Feature/Livewire/TeamSharedVariablesIndexTest.php @@ -0,0 +1,9 @@ +assertStatus(200); +});