fix: multiline env variables
This commit is contained in:
@@ -17,9 +17,14 @@ class Edit extends Component
|
|||||||
public function saveKey($data)
|
public function saveKey($data)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
$found = $this->project->environment_variables()->where('key', $data['key'])->first();
|
||||||
|
if ($found) {
|
||||||
|
throw new \Exception('Variable already exists.');
|
||||||
|
}
|
||||||
$this->project->environment_variables()->create([
|
$this->project->environment_variables()->create([
|
||||||
'key' => $data['key'],
|
'key' => $data['key'],
|
||||||
'value' => $data['value'],
|
'value' => $data['value'],
|
||||||
|
'is_multiline' => $data['is_multiline'],
|
||||||
'type' => 'project',
|
'type' => 'project',
|
||||||
'team_id' => currentTeam()->id,
|
'team_id' => currentTeam()->id,
|
||||||
]);
|
]);
|
||||||
|
@@ -21,9 +21,14 @@ class EnvironmentEdit extends Component
|
|||||||
public function saveKey($data)
|
public function saveKey($data)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
$found = $this->environment->environment_variables()->where('key', $data['key'])->first();
|
||||||
|
if ($found) {
|
||||||
|
throw new \Exception('Variable already exists.');
|
||||||
|
}
|
||||||
$this->environment->environment_variables()->create([
|
$this->environment->environment_variables()->create([
|
||||||
'key' => $data['key'],
|
'key' => $data['key'],
|
||||||
'value' => $data['value'],
|
'value' => $data['value'],
|
||||||
|
'is_multiline' => $data['is_multiline'],
|
||||||
'type' => 'environment',
|
'type' => 'environment',
|
||||||
'team_id' => currentTeam()->id,
|
'team_id' => currentTeam()->id,
|
||||||
]);
|
]);
|
||||||
|
@@ -11,17 +11,20 @@ class Add extends Component
|
|||||||
public string $key;
|
public string $key;
|
||||||
public ?string $value = null;
|
public ?string $value = null;
|
||||||
public bool $is_build_time = false;
|
public bool $is_build_time = false;
|
||||||
|
public bool $is_multiline = false;
|
||||||
|
|
||||||
protected $listeners = ['clearAddEnv' => 'clear'];
|
protected $listeners = ['clearAddEnv' => 'clear'];
|
||||||
protected $rules = [
|
protected $rules = [
|
||||||
'key' => 'required|string',
|
'key' => 'required|string',
|
||||||
'value' => 'nullable',
|
'value' => 'nullable',
|
||||||
'is_build_time' => 'required|boolean',
|
'is_build_time' => 'required|boolean',
|
||||||
|
'is_multiline' => 'required|boolean',
|
||||||
];
|
];
|
||||||
protected $validationAttributes = [
|
protected $validationAttributes = [
|
||||||
'key' => 'key',
|
'key' => 'key',
|
||||||
'value' => 'value',
|
'value' => 'value',
|
||||||
'is_build_time' => 'build',
|
'is_build_time' => 'build',
|
||||||
|
'is_multiline' => 'multiline',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
@@ -43,6 +46,7 @@ class Add extends Component
|
|||||||
'key' => $this->key,
|
'key' => $this->key,
|
||||||
'value' => $this->value,
|
'value' => $this->value,
|
||||||
'is_build_time' => $this->is_build_time,
|
'is_build_time' => $this->is_build_time,
|
||||||
|
'is_multiline' => $this->is_multiline,
|
||||||
'is_preview' => $this->is_preview,
|
'is_preview' => $this->is_preview,
|
||||||
]);
|
]);
|
||||||
$this->clear();
|
$this->clear();
|
||||||
@@ -53,5 +57,6 @@ class Add extends Component
|
|||||||
$this->key = '';
|
$this->key = '';
|
||||||
$this->value = '';
|
$this->value = '';
|
||||||
$this->is_build_time = false;
|
$this->is_build_time = false;
|
||||||
|
$this->is_multiline = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -11,7 +11,7 @@ class All extends Component
|
|||||||
{
|
{
|
||||||
public $resource;
|
public $resource;
|
||||||
public bool $showPreview = false;
|
public bool $showPreview = false;
|
||||||
public string|null $modalId = null;
|
public ?string $modalId = null;
|
||||||
public ?string $variables = null;
|
public ?string $variables = null;
|
||||||
public ?string $variablesPreview = null;
|
public ?string $variablesPreview = null;
|
||||||
public string $view = 'normal';
|
public string $view = 'normal';
|
||||||
@@ -34,6 +34,9 @@ class All extends Component
|
|||||||
if ($item->is_shown_once) {
|
if ($item->is_shown_once) {
|
||||||
return "$item->key=(locked secret)";
|
return "$item->key=(locked secret)";
|
||||||
}
|
}
|
||||||
|
if ($item->is_multiline) {
|
||||||
|
return "$item->key=(multiline, edit in normal view)";
|
||||||
|
}
|
||||||
return "$item->key=$item->value";
|
return "$item->key=$item->value";
|
||||||
})->sort()->join('
|
})->sort()->join('
|
||||||
');
|
');
|
||||||
@@ -42,6 +45,9 @@ class All extends Component
|
|||||||
if ($item->is_shown_once) {
|
if ($item->is_shown_once) {
|
||||||
return "$item->key=(locked secret)";
|
return "$item->key=(locked secret)";
|
||||||
}
|
}
|
||||||
|
if ($item->is_multiline) {
|
||||||
|
return "$item->key=(multiline, edit in normal view)";
|
||||||
|
}
|
||||||
return "$item->key=$item->value";
|
return "$item->key=$item->value";
|
||||||
})->sort()->join('
|
})->sort()->join('
|
||||||
');
|
');
|
||||||
@@ -67,7 +73,7 @@ class All extends Component
|
|||||||
$found = $this->resource->environment_variables()->where('key', $key)->first();
|
$found = $this->resource->environment_variables()->where('key', $key)->first();
|
||||||
}
|
}
|
||||||
if ($found) {
|
if ($found) {
|
||||||
if ($found->is_shown_once) {
|
if ($found->is_shown_once || $found->is_multiline) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$found->value = $variable;
|
$found->value = $variable;
|
||||||
@@ -144,6 +150,7 @@ class All extends Component
|
|||||||
$environment->key = $data['key'];
|
$environment->key = $data['key'];
|
||||||
$environment->value = $data['value'];
|
$environment->value = $data['value'];
|
||||||
$environment->is_build_time = $data['is_build_time'];
|
$environment->is_build_time = $data['is_build_time'];
|
||||||
|
$environment->is_multiline = $data['is_multiline'];
|
||||||
$environment->is_preview = $data['is_preview'];
|
$environment->is_preview = $data['is_preview'];
|
||||||
|
|
||||||
switch ($this->resource->type()) {
|
switch ($this->resource->type()) {
|
||||||
|
@@ -13,9 +13,14 @@ class TeamSharedVariablesIndex extends Component
|
|||||||
public function saveKey($data)
|
public function saveKey($data)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
$found = $this->team->environment_variables()->where('key', $data['key'])->first();
|
||||||
|
if ($found) {
|
||||||
|
throw new \Exception('Variable already exists.');
|
||||||
|
}
|
||||||
$this->team->environment_variables()->create([
|
$this->team->environment_variables()->create([
|
||||||
'key' => $data['key'],
|
'key' => $data['key'],
|
||||||
'value' => $data['value'],
|
'value' => $data['value'],
|
||||||
|
'is_multiline' => $data['is_multiline'],
|
||||||
'type' => 'team',
|
'type' => 'team',
|
||||||
'team_id' => currentTeam()->id,
|
'team_id' => currentTeam()->id,
|
||||||
]);
|
]);
|
||||||
|
@@ -49,7 +49,7 @@ class EnvironmentVariable extends Model
|
|||||||
set: fn (?string $value = null) => $this->set_environment_variables($value),
|
set: fn (?string $value = null) => $this->set_environment_variables($value),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
public function realValue(): Attribute
|
public function resource()
|
||||||
{
|
{
|
||||||
$resource = null;
|
$resource = null;
|
||||||
if ($this->application_id) {
|
if ($this->application_id) {
|
||||||
@@ -71,9 +71,19 @@ class EnvironmentVariable extends Model
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return $resource;
|
||||||
|
}
|
||||||
|
public function realValue(): Attribute
|
||||||
|
{
|
||||||
|
$resource = $this->resource();
|
||||||
return Attribute::make(
|
return Attribute::make(
|
||||||
get: function () use ($resource) {
|
get: function () use ($resource) {
|
||||||
return $this->get_real_environment_variables($this->value, $resource);
|
$env = $this->get_real_environment_variables($this->value, $resource);
|
||||||
|
return data_get($env, 'value', $env);
|
||||||
|
if (is_string($env)) {
|
||||||
|
return $env;
|
||||||
|
}
|
||||||
|
return $env->value;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -89,7 +99,7 @@ class EnvironmentVariable extends Model
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private function get_real_environment_variables(?string $environment_variable = null, $resource = null): string|null
|
private function get_real_environment_variables(?string $environment_variable = null, $resource = null)
|
||||||
{
|
{
|
||||||
if (!$environment_variable || !$resource) {
|
if (!$environment_variable || !$resource) {
|
||||||
return null;
|
return null;
|
||||||
@@ -112,7 +122,7 @@ class EnvironmentVariable extends Model
|
|||||||
}
|
}
|
||||||
$environment_variable_found = SharedEnvironmentVariable::where("type", $type)->where('key', $variable)->where('team_id', $resource->team()->id)->where("{$type}_id", $id)->first();
|
$environment_variable_found = SharedEnvironmentVariable::where("type", $type)->where('key', $variable)->where('team_id', $resource->team()->id)->where("{$type}_id", $id)->first();
|
||||||
if ($environment_variable_found) {
|
if ($environment_variable_found) {
|
||||||
return $environment_variable_found->value;
|
return $environment_variable_found;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $environment_variable;
|
return $environment_variable;
|
||||||
|
@@ -24,8 +24,9 @@ class Textarea extends Component
|
|||||||
public bool $readonly = false,
|
public bool $readonly = false,
|
||||||
public ?string $helper = null,
|
public ?string $helper = null,
|
||||||
public bool $realtimeValidation = false,
|
public bool $realtimeValidation = false,
|
||||||
// public bool $allowToPeak = true,
|
public bool $allowToPeak = true,
|
||||||
public string $defaultClass = "textarea leading-normal bg-coolgray-100 rounded text-white scrollbar disabled:bg-coolgray-200/50 disabled:border-none placeholder:text-coolgray-500 read-only:text-neutral-500 read-only:bg-coolgray-200/50"
|
public string $defaultClass = "textarea leading-normal bg-coolgray-100 rounded text-white w-full scrollbar disabled:bg-coolgray-200/50 disabled:border-none placeholder:text-coolgray-500 read-only:text-neutral-500 read-only:bg-coolgray-200/50",
|
||||||
|
public string $defaultClassInput = "input input-sm bg-coolgray-100 rounded text-white w-full disabled:bg-coolgray-200/50 disabled:border-none placeholder:text-coolgray-500 read-only:text-neutral-500 read-only:bg-coolgray-200/50"
|
||||||
) {
|
) {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
@@ -14,6 +14,9 @@ return new class extends Migration
|
|||||||
Schema::table('environment_variables', function (Blueprint $table) {
|
Schema::table('environment_variables', function (Blueprint $table) {
|
||||||
$table->boolean('is_multiline')->default(false);
|
$table->boolean('is_multiline')->default(false);
|
||||||
});
|
});
|
||||||
|
Schema::table('shared_environment_variables', function (Blueprint $table) {
|
||||||
|
$table->boolean('is_multiline')->default(false);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -24,5 +27,8 @@ return new class extends Migration
|
|||||||
Schema::table('environment_variables', function (Blueprint $table) {
|
Schema::table('environment_variables', function (Blueprint $table) {
|
||||||
$table->dropColumn('is_multiline');
|
$table->dropColumn('is_multiline');
|
||||||
});
|
});
|
||||||
|
Schema::table('shared_environment_variables', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('is_multiline');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
<div class="w-full">
|
<div class="flex-1">
|
||||||
@if ($label)
|
@if ($label)
|
||||||
<label for="small-input" class="flex items-center gap-1 mb-1 text-sm font-medium">{{ $label }}
|
<label for="small-input" class="flex items-center gap-1 mb-1 text-sm font-medium">{{ $label }}
|
||||||
@if ($required)
|
@if ($required)
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
</label>
|
</label>
|
||||||
@endif
|
@endif
|
||||||
@if ($type === 'password')
|
@if ($type === 'password')
|
||||||
<div class="relative" x-data>
|
<div class="relative" x-data="{ type: 'password' }">
|
||||||
@if ($allowToPeak)
|
@if ($allowToPeak)
|
||||||
<div x-on:click="changePasswordFieldType"
|
<div x-on:click="changePasswordFieldType"
|
||||||
class="absolute inset-y-0 right-0 flex items-center pr-2 cursor-pointer hover:text-white">
|
class="absolute inset-y-0 right-0 flex items-center pr-2 cursor-pointer hover:text-white">
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
<input value="{{ $value }}" {{ $attributes->merge(['class' => $defaultClass]) }}
|
<input x-cloak x-show="type" value="{{ $value }}" {{ $attributes->merge(['class' => $defaultClass]) }}
|
||||||
@required($required) @if ($id !== 'null') wire:model={{ $id }} @endif
|
@required($required) @if ($id !== 'null') wire:model={{ $id }} @endif
|
||||||
wire:dirty.class.remove='text-white' wire:dirty.class="input-warning" wire:loading.attr="disabled"
|
wire:dirty.class.remove='text-white' wire:dirty.class="input-warning" wire:loading.attr="disabled"
|
||||||
type="{{ $type }}" @readonly($readonly) @disabled($disabled) id="{{ $id }}"
|
type="{{ $type }}" @readonly($readonly) @disabled($disabled) id="{{ $id }}"
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
<div class="form-control">
|
<div class="flex-1 form-control">
|
||||||
@if ($label)
|
@if ($label)
|
||||||
<label for="small-input" class="flex items-center gap-1 mb-1 text-sm font-medium">{{ $label }}
|
<label for="small-input" class="flex items-center gap-1 mb-1 text-sm font-medium">{{ $label }}
|
||||||
@if ($required)
|
@if ($required)
|
||||||
@@ -9,13 +9,46 @@
|
|||||||
@endif
|
@endif
|
||||||
</label>
|
</label>
|
||||||
@endif
|
@endif
|
||||||
<textarea placeholder="{{ $placeholder }}" {{ $attributes->merge(['class' => $defaultClass]) }}
|
@if ($type === 'password')
|
||||||
@if ($realtimeValidation) wire:model.debounce.200ms="{{ $id }}"
|
<div class="relative" x-data="{ type: 'password' }">
|
||||||
|
@if ($allowToPeak)
|
||||||
|
<div x-on:click="changePasswordFieldType"
|
||||||
|
class="absolute inset-y-0 right-0 flex items-center h-6 pt-2 pr-2 cursor-pointer hover:text-white">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6" viewBox="0 0 24 24" stroke-width="1.5"
|
||||||
|
stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||||
|
<path d="M10 12a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" />
|
||||||
|
<path d="M21 12c-2.4 4 -5.4 6 -9 6c-3.6 0 -6.6 -2 -9 -6c2.4 -4 5.4 -6 9 -6c3.6 0 6.6 2 9 6" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
<input x-cloak x-show="type === 'password'" value="{{ $value }}"
|
||||||
|
{{ $attributes->merge(['class' => $defaultClassInput]) }} @required($required)
|
||||||
|
@if ($id !== 'null') wire:model={{ $id }} @endif
|
||||||
|
wire:dirty.class.remove='text-white' wire:dirty.class="input-warning" wire:loading.attr="disabled"
|
||||||
|
type="{{ $type }}" @readonly($readonly) @disabled($disabled) id="{{ $id }}"
|
||||||
|
name="{{ $name }}" placeholder="{{ $attributes->get('placeholder') }}"
|
||||||
|
aria-placeholder="{{ $attributes->get('placeholder') }}">
|
||||||
|
<textarea x-cloak x-show="type !== 'password'" placeholder="{{ $placeholder }}"
|
||||||
|
{{ $attributes->merge(['class' => $defaultClass]) }}
|
||||||
|
@if ($realtimeValidation) wire:model.debounce.200ms="{{ $id }}"
|
||||||
|
@else
|
||||||
|
wire:model={{ $value ?? $id }}
|
||||||
|
wire:dirty.class="input-warning" @endif
|
||||||
|
@disabled($disabled) @readonly($readonly) @required($required) id="{{ $id }}"
|
||||||
|
name="{{ $name }}" name={{ $id }}></textarea>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
@else
|
||||||
|
<textarea placeholder="{{ $placeholder }}" {{ $attributes->merge(['class' => $defaultClass]) }}
|
||||||
|
@if ($realtimeValidation) wire:model.debounce.200ms="{{ $id }}"
|
||||||
@else
|
@else
|
||||||
wire:model={{ $value ?? $id }}
|
wire:model={{ $value ?? $id }}
|
||||||
wire:dirty.class="input-warning" @endif
|
wire:dirty.class="input-warning" @endif
|
||||||
@disabled($disabled) @readonly($readonly) @required($required) id="{{ $id }}" name="{{ $name }}"
|
@disabled($disabled) @readonly($readonly) @required($required) id="{{ $id }}"
|
||||||
name={{ $id }}></textarea>
|
name="{{ $name }}" name={{ $id }}></textarea>
|
||||||
|
@endif
|
||||||
|
|
||||||
@error($id)
|
@error($id)
|
||||||
<label class="label">
|
<label class="label">
|
||||||
<span class="text-red-500 label-text-alt">{{ $message }}</span>
|
<span class="text-red-500 label-text-alt">{{ $message }}</span>
|
||||||
|
@@ -76,11 +76,13 @@
|
|||||||
element = element.parentElement;
|
element = element.parentElement;
|
||||||
}
|
}
|
||||||
element = element.children[1];
|
element = element.children[1];
|
||||||
if (element.nodeName === 'INPUT') {
|
if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {
|
||||||
if (element.type === 'password') {
|
if (element.type === 'password') {
|
||||||
element.type = 'text';
|
element.type = 'text';
|
||||||
|
this.type = 'text';
|
||||||
} else {
|
} else {
|
||||||
element.type = 'password';
|
element.type = 'password';
|
||||||
|
this.type = 'password';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,9 +1,11 @@
|
|||||||
<form class="flex flex-col gap-2 rounded" wire:submit='submit'>
|
<form class="flex flex-col gap-2 rounded" wire:submit='submit'>
|
||||||
<x-forms.input placeholder="NODE_ENV" id="key" label="Name" required />
|
<x-forms.input placeholder="NODE_ENV" id="key" label="Name" required />
|
||||||
<x-forms.input placeholder="production" id="value" label="Value" required />
|
<x-forms.textarea x-show="$wire.is_multiline === true" x-cloak id="value" label="Value" required />
|
||||||
|
<x-forms.input x-show="$wire.is_multiline === false" x-cloak placeholder="production" id="value" x-bind:label="$wire.is_multiline === false && 'Value'" required />
|
||||||
@if (data_get($parameters, 'application_uuid'))
|
@if (data_get($parameters, 'application_uuid'))
|
||||||
<x-forms.checkbox id="is_build_time" label="Build Variable?" />
|
<x-forms.checkbox id="is_build_time" label="Build Variable?" />
|
||||||
@endif
|
@endif
|
||||||
|
<x-forms.checkbox id="is_multiline" label="Is Multiline?" />
|
||||||
<x-forms.button type="submit" @click="slideOverOpen=false">
|
<x-forms.button type="submit" @click="slideOverOpen=false">
|
||||||
Save
|
Save
|
||||||
</x-forms.button>
|
</x-forms.button>
|
||||||
|
@@ -21,17 +21,17 @@
|
|||||||
@endif
|
@endif
|
||||||
@else
|
@else
|
||||||
@if ($env->is_multiline)
|
@if ($env->is_multiline)
|
||||||
<x-forms.input class="h-12" id="env.key" />
|
<x-forms.input id="env.key" />
|
||||||
<textarea wire:model.lazy="env.value" rows="1" id="env.value"
|
<x-forms.textarea type="password" id="env.value" />
|
||||||
class="w-full leading-normal text-white rounded textarea bg-coolgray-100 scrollbar disabled:bg-coolgray-200/50 disabled:border-none placeholder:text-coolgray-500 read-only:text-neutral-500 read-only:bg-coolgray-200/50"></textarea>
|
|
||||||
@else
|
@else
|
||||||
<x-forms.input id="env.key" />
|
<x-forms.input id="env.key" />
|
||||||
<x-forms.input type="password" id="env.value" />
|
<x-forms.input type="password" id="env.value" />
|
||||||
@endif
|
@endif
|
||||||
@if ($env->is_shared)
|
@if ($env->is_shared)
|
||||||
<x-forms.input disabled type="password" id="env.real_value" />
|
<x-forms.input disabled type="password" id="env.real_value" />
|
||||||
|
@else
|
||||||
|
<x-forms.checkbox instantSave id="env.is_multiline" label="Is Multiline?" />
|
||||||
@endif
|
@endif
|
||||||
<x-forms.checkbox instantSave id="env.is_multiline" label="Is Multiline?" />
|
|
||||||
@if ($type !== 'service' && !$isSharedVariable)
|
@if ($type !== 'service' && !$isSharedVariable)
|
||||||
<x-forms.checkbox instantSave id="env.is_build_time" label="Build Variable?" />
|
<x-forms.checkbox instantSave id="env.is_build_time" label="Build Variable?" />
|
||||||
@endif
|
@endif
|
||||||
|
Reference in New Issue
Block a user