Merge branch 'next' into supabase

This commit is contained in:
Andras Bacsai 2024-03-18 11:08:28 +01:00 committed by GitHub
commit 047d320665
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 248 additions and 68 deletions

View File

@ -1128,9 +1128,9 @@ private function generate_compose_file()
$this->custom_healthcheck_found = false; $this->custom_healthcheck_found = false;
if ($this->application->build_pack === 'dockerfile' || $this->application->dockerfile) { if ($this->application->build_pack === 'dockerfile' || $this->application->dockerfile) {
$this->execute_remote_command([ $this->execute_remote_command([
executeInDocker($this->deployment_uuid, "cat {$this->workdir}{$this->dockerfile_location}"), "hidden" => true, "save" => 'dockerfile', "ignore_errors" => true executeInDocker($this->deployment_uuid, "cat {$this->workdir}{$this->dockerfile_location}"), "hidden" => true, "save" => 'dockerfile_from_repo', "ignore_errors" => true
]); ]);
$dockerfile = collect(Str::of($this->saved_outputs->get('dockerfile'))->trim()->explode("\n")); $dockerfile = collect(Str::of($this->saved_outputs->get('dockerfile_from_repo'))->trim()->explode("\n"));
if (str($dockerfile)->contains('HEALTHCHECK')) { if (str($dockerfile)->contains('HEALTHCHECK')) {
$this->custom_healthcheck_found = true; $this->custom_healthcheck_found = true;
} }
@ -1359,23 +1359,58 @@ private function generate_environment_variables($ports)
$environment_variables = collect(); $environment_variables = collect();
if ($this->pull_request_id === 0) { if ($this->pull_request_id === 0) {
foreach ($this->application->runtime_environment_variables as $env) { foreach ($this->application->runtime_environment_variables as $env) {
$environment_variables->push("$env->key=$env->real_value"); // This is necessary because we have to escape the value of the environment variable
// but only if the environment variable is created after the 15th of March 2024
// when I implemented the escaping feature.
// Old environment variables are not escaped, because it could break the application
// as the application could expect the unescaped value.
// Yes, I worked on March 15th, 2024, and I implemented this feature.
// It was a national holiday in Hungary.
// Welcome to the life of a solopreneur.
if ($env->created_at > '2024-03-15T20:42:42.000000Z') {
$real_value = escapeEnvVariables($env->real_value);
} else {
$real_value = $env->value;
}
$environment_variables->push("$env->key=$real_value");
} }
foreach ($this->application->nixpacks_environment_variables as $env) { foreach ($this->application->nixpacks_environment_variables as $env) {
$environment_variables->push("$env->key=$env->real_value"); if ($env->created_at > '2024-03-15T20:42:42.000000Z') {
$real_value = escapeEnvVariables($env->real_value);
} else {
$real_value = $env->value;
}
$environment_variables->push("$env->key=$real_value");
} }
} else { } else {
foreach ($this->application->runtime_environment_variables_preview as $env) { foreach ($this->application->runtime_environment_variables_preview as $env) {
$environment_variables->push("$env->key=$env->real_value"); if ($env->created_at > '2024-03-15T20:42:42.000000Z') {
$real_value = escapeEnvVariables($env->real_value);
} else {
$real_value = $env->value;
}
$environment_variables->push("$env->key=$real_value");
} }
foreach ($this->application->nixpacks_environment_variables_preview as $env) { foreach ($this->application->nixpacks_environment_variables_preview as $env) {
$environment_variables->push("$env->key=$env->real_value"); if ($env->created_at > '2024-03-15T20:42:42.000000Z') {
$real_value = escapeEnvVariables($env->real_value);
} else {
$real_value = $env->value;
}
$environment_variables->push("$env->key=$real_value");
} }
} }
// Add PORT if not exists, use the first port as default // Add PORT if not exists, use the first port as default
if ($environment_variables->filter(fn ($env) => Str::of($env)->startsWith('PORT'))->isEmpty()) { if ($environment_variables->filter(fn ($env) => Str::of($env)->startsWith('PORT'))->isEmpty()) {
$environment_variables->push("PORT={$ports[0]}"); $environment_variables->push("PORT={$ports[0]}");
} }
// Add HOST if not exists
if ($environment_variables->filter(fn ($env) => Str::of($env)->startsWith('HOST'))->isEmpty()) {
$environment_variables->push("HOST=0.0.0.0");
}
if ($environment_variables->filter(fn ($env) => Str::of($env)->startsWith('SOURCE_COMMIT'))->isEmpty()) { if ($environment_variables->filter(fn ($env) => Str::of($env)->startsWith('SOURCE_COMMIT'))->isEmpty()) {
if (!is_null($this->commit)) { if (!is_null($this->commit)) {
$environment_variables->push("SOURCE_COMMIT={$this->commit}"); $environment_variables->push("SOURCE_COMMIT={$this->commit}");
@ -1383,6 +1418,7 @@ private function generate_environment_variables($ports)
$environment_variables->push("SOURCE_COMMIT=unknown"); $environment_variables->push("SOURCE_COMMIT=unknown");
} }
} }
ray($environment_variables->all());
return $environment_variables->all(); return $environment_variables->all();
} }

View File

@ -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,
]); ]);

View File

@ -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,
]); ]);

View File

@ -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 @@ public function submit()
'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 @@ public function clear()
$this->key = ''; $this->key = '';
$this->value = ''; $this->value = '';
$this->is_build_time = false; $this->is_build_time = false;
$this->is_multiline = false;
} }
} }

View File

@ -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 @@ public function getDevView()
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 @@ public function getDevView()
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 @@ public function saveVariables($isPreview)
$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 @@ public function submit($data)
$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()) {

View File

@ -21,6 +21,7 @@ class Show extends Component
'env.key' => 'required|string', 'env.key' => 'required|string',
'env.value' => 'nullable', 'env.value' => 'nullable',
'env.is_build_time' => 'required|boolean', 'env.is_build_time' => 'required|boolean',
'env.is_multiline' => 'required|boolean',
'env.is_shown_once' => 'required|boolean', 'env.is_shown_once' => 'required|boolean',
'env.real_value' => 'nullable', 'env.real_value' => 'nullable',
]; ];
@ -28,6 +29,7 @@ class Show extends Component
'env.key' => 'Key', 'env.key' => 'Key',
'env.value' => 'Value', 'env.value' => 'Value',
'env.is_build_time' => 'Build Time', 'env.is_build_time' => 'Build Time',
'env.is_multiline' => 'Multiline',
'env.is_shown_once' => 'Shown Once', 'env.is_shown_once' => 'Shown Once',
]; ];

View File

@ -71,6 +71,9 @@ public function instantSave()
} }
public function getLogs($refresh = false) public function getLogs($refresh = false)
{ {
if (!$this->server->isFunctional()) {
return;
}
if ($this->resource?->getMorphClass() === 'App\Models\Application') { if ($this->resource?->getMorphClass() === 'App\Models\Application') {
if (str($this->container)->contains('-pr-')) { if (str($this->container)->contains('-pr-')) {
$this->pull_request = "Pull Request: " . str($this->container)->afterLast('-pr-')->beforeLast('_')->value(); $this->pull_request = "Pull Request: " . str($this->container)->afterLast('-pr-')->beforeLast('_')->value();
@ -79,6 +82,9 @@ public function getLogs($refresh = false)
} }
} }
if (!$refresh && ($this->resource?->getMorphClass() === 'App\Models\Service' || str($this->container)->contains('-pr-'))) return; if (!$refresh && ($this->resource?->getMorphClass() === 'App\Models\Service' || str($this->container)->contains('-pr-'))) return;
if (!$this->numberOfLines) {
$this->numberOfLines = 1000;
}
if ($this->container) { if ($this->container) {
if ($this->showTimeStamps) { if ($this->showTimeStamps) {
if ($this->server->isSwarm()) { if ($this->server->isSwarm()) {

View File

@ -29,6 +29,9 @@ public function loadContainers($server_id)
{ {
try { try {
$server = $this->servers->firstWhere('id', $server_id); $server = $this->servers->firstWhere('id', $server_id);
if (!$server->isFunctional()) {
return;
}
if ($server->isSwarm()) { if ($server->isSwarm()) {
$containers = collect([ $containers = collect([
[ [
@ -96,7 +99,6 @@ public function mount()
$this->resource->databases()->get()->each(function ($database) { $this->resource->databases()->get()->each(function ($database) {
$this->containers->push(data_get($database, 'name') . '-' . data_get($this->resource, 'uuid')); $this->containers->push(data_get($database, 'name') . '-' . data_get($this->resource, 'uuid'));
}); });
if ($this->resource->server->isFunctional()) { if ($this->resource->server->isFunctional()) {
$this->servers = $this->servers->push($this->resource->server); $this->servers = $this->servers->push($this->resource->server);
} }

View File

@ -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,
]); ]);

View File

@ -49,7 +49,7 @@ protected function value(): Attribute
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 @@ public function realValue(): Attribute
} }
} }
} }
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 @@ protected function isShared(): Attribute
} }
); );
} }
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 @@ private function get_real_environment_variables(?string $environment_variable =
} }
$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;

View File

@ -10,15 +10,15 @@
class Input extends Component class Input extends Component
{ {
public function __construct( public function __construct(
public string|null $id = null, public ?string $id = null,
public string|null $name = null, public ?string $name = null,
public string|null $type = 'text', public ?string $type = 'text',
public string|null $value = null, public ?string $value = null,
public string|null $label = null, public ?string $label = null,
public bool $required = false, public bool $required = false,
public bool $disabled = false, public bool $disabled = false,
public bool $readonly = false, public bool $readonly = false,
public string|null $helper = null, public ?string $helper = null,
public bool $allowToPeak = true, public bool $allowToPeak = true,
public string $defaultClass = "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" public string $defaultClass = "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"
) { ) {

View File

@ -4,7 +4,6 @@
use Closure; use Closure;
use Illuminate\Contracts\View\View; use Illuminate\Contracts\View\View;
use Illuminate\Support\Str;
use Illuminate\View\Component; use Illuminate\View\Component;
use Visus\Cuid2\Cuid2; use Visus\Cuid2\Cuid2;
@ -14,18 +13,20 @@ class Textarea extends Component
* Create a new component instance. * Create a new component instance.
*/ */
public function __construct( public function __construct(
public string|null $id = null, public ?string $id = null,
public string|null $name = null, public ?string $name = null,
public string|null $type = 'text', public ?string $type = 'text',
public string|null $value = null, public ?string $value = null,
public string|null $label = null, public ?string $label = null,
public string|null $placeholder = null, public ?string $placeholder = null,
public bool $required = false, public bool $required = false,
public bool $disabled = false, public bool $disabled = false,
public bool $readonly = false, public bool $readonly = false,
public string|null $helper = null, public ?string $helper = null,
public bool $realtimeValidation = false, public bool $realtimeValidation = false,
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 bool $allowToPeak = true,
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"
) { ) {
// //
} }

View File

@ -557,7 +557,8 @@ function convert_docker_run_to_compose(?string $custom_docker_run_options = null
return $compose_options->toArray(); return $compose_options->toArray();
} }
function validateComposeFile(string $compose, int $server_id): string|Throwable { function validateComposeFile(string $compose, int $server_id): string|Throwable
{
return 'OK'; return 'OK';
try { try {
$uuid = Str::random(10); $uuid = Str::random(10);
@ -578,3 +579,10 @@ function validateComposeFile(string $compose, int $server_id): string|Throwable
], $server); ], $server);
} }
} }
function escapeEnvVariables($value)
{
$search = array("\\", "\r", "\t", "\x0", '"', "'", "$");
$replace = array("\\\\", "\\r", "\\t", "\\0", '\"', "\'", "$$");
return str_replace($search, $replace, $value);
}

View File

@ -7,7 +7,7 @@
// The release version of your application // The release version of your application
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD')) // Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
'release' => '4.0.0-beta.238', 'release' => '4.0.0-beta.240',
// When left empty or `null` the Laravel environment will be used // When left empty or `null` the Laravel environment will be used
'environment' => config('app.env'), 'environment' => config('app.env'),

View File

@ -1,3 +1,3 @@
<?php <?php
return '4.0.0-beta.238'; return '4.0.0-beta.240';

View File

@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('environment_variables', function (Blueprint $table) {
$table->boolean('is_multiline')->default(false);
});
Schema::table('shared_environment_variables', function (Blueprint $table) {
$table->boolean('is_multiline')->default(false);
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('environment_variables', function (Blueprint $table) {
$table->dropColumn('is_multiline');
});
Schema::table('shared_environment_variables', function (Blueprint $table) {
$table->dropColumn('is_multiline');
});
}
};

View File

@ -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 @@ class="absolute inset-y-0 right-0 flex items-center pr-2 cursor-pointer hover:te
</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 }}"

View File

@ -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
@if ($type === 'password')
<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]) }} <textarea placeholder="{{ $placeholder }}" {{ $attributes->merge(['class' => $defaultClass]) }}
@if ($realtimeValidation) wire:model.debounce.200ms="{{ $id }}" @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>

View File

@ -76,11 +76,13 @@ function changePasswordFieldType(event) {
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';
} }
} }
} }

View File

@ -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>

View File

@ -19,11 +19,18 @@ class="flex flex-col gap-2 p-4 m-2 border lg:items-center border-coolgray-300 lg
@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
@else
@if ($env->is_multiline)
<x-forms.input id="env.key" />
<x-forms.textarea type="password" id="env.value" />
@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
@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
@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?" />

View File

@ -7,7 +7,7 @@
<div class="pt-2" wire:loading wire:target="loadContainers"> <div class="pt-2" wire:loading wire:target="loadContainers">
Loading containers... Loading containers...
</div> </div>
@foreach ($servers as $server) @forelse ($servers as $server)
<h3 x-init="$wire.loadContainers({{ $server->id }})"></h3> <h3 x-init="$wire.loadContainers({{ $server->id }})"></h3>
<div wire:loading.remove wire:target="loadContainers"> <div wire:loading.remove wire:target="loadContainers">
@forelse (data_get($server,'containers',[]) as $container) @forelse (data_get($server,'containers',[]) as $container)
@ -16,7 +16,9 @@
<div class="pt-2">No containers are not running on server: {{ $server->name }}</div> <div class="pt-2">No containers are not running on server: {{ $server->name }}</div>
@endforelse @endforelse
</div> </div>
@endforeach @empty
<div>No functional server found for the application.</div>
@endforelse
</div> </div>
@elseif ($type === 'database') @elseif ($type === 'database')
<h1>Logs</h1> <h1>Logs</h1>
@ -26,7 +28,11 @@
@if ($loop->first) @if ($loop->first)
<h2 class="pb-4">Logs</h2> <h2 class="pb-4">Logs</h2>
@endif @endif
<livewire:project.shared.get-logs :server="$servers[0]" :resource="$resource" :container="$container" /> @if (data_get($servers, '0'))
<livewire:project.shared.get-logs :server="data_get($servers, '0')" :resource="$resource" :container="$container" />
@else
<div> No functional server found for the database.</div>
@endif
@empty @empty
<div class="pt-2">No containers are not running.</div> <div class="pt-2">No containers are not running.</div>
@endforelse @endforelse
@ -37,7 +43,11 @@
@if ($loop->first) @if ($loop->first)
<h2 class="pb-4">Logs</h2> <h2 class="pb-4">Logs</h2>
@endif @endif
<livewire:project.shared.get-logs :server="$servers[0]" :resource="$resource" :container="$container" /> @if (data_get($servers, '0'))
<livewire:project.shared.get-logs :server="data_get($servers, '0')" :resource="$resource" :container="$container" />
@else
<div> No functional server found for the service.</div>
@endif
@empty @empty
<div class="pt-2">No containers are not running.</div> <div class="pt-2">No containers are not running.</div>
@endforelse @endforelse

View File

@ -663,7 +663,7 @@ services:
kong: 'starts_with(string!(.appname), "supabase-kong")' kong: 'starts_with(string!(.appname), "supabase-kong")'
auth: 'starts_with(string!(.appname), "supabase-auth")' auth: 'starts_with(string!(.appname), "supabase-auth")'
rest: 'starts_with(string!(.appname), "supabase-rest")' rest: 'starts_with(string!(.appname), "supabase-rest")'
realtime: 'starts_with(string!(.appname), "supabase-realtime")' realtime: 'starts_with(string!(.appname), "realtime-dev.supabase-realtime")'
storage: 'starts_with(string!(.appname), "supabase-storage")' storage: 'starts_with(string!(.appname), "supabase-storage")'
functions: 'starts_with(string!(.appname), "supabase-functions")' functions: 'starts_with(string!(.appname), "supabase-functions")'
db: 'starts_with(string!(.appname), "supabase-db")' db: 'starts_with(string!(.appname), "supabase-db")'
@ -951,7 +951,7 @@ services:
- GOTRUE_EXTERNAL_PHONE_ENABLED=${ENABLE_PHONE_SIGNUP:-true} - GOTRUE_EXTERNAL_PHONE_ENABLED=${ENABLE_PHONE_SIGNUP:-true}
- GOTRUE_SMS_AUTOCONFIRM=${ENABLE_PHONE_AUTOCONFIRM:-true} - GOTRUE_SMS_AUTOCONFIRM=${ENABLE_PHONE_AUTOCONFIRM:-true}
supabase-realtime: realtime-dev.supabase-realtime:
# This container name looks inconsistent but is correct because realtime constructs tenant id by parsing the subdomain # This container name looks inconsistent but is correct because realtime constructs tenant id by parsing the subdomain
image: supabase/realtime:v2.25.66 image: supabase/realtime:v2.25.66
depends_on: depends_on:

View File

@ -8,7 +8,7 @@ services:
uptime-kuma: uptime-kuma:
image: louislam/uptime-kuma:1 image: louislam/uptime-kuma:1
environment: environment:
- SERVICE_FQDN_3001 - SERVICE_FQDN_UPTIME-KUMA_3001
volumes: volumes:
- uptime-kuma:/app/data - uptime-kuma:/app/data
healthcheck: healthcheck:

View File

@ -772,7 +772,7 @@
"uptime-kuma": { "uptime-kuma": {
"documentation": "https:\/\/github.com\/louislam\/uptime-kuma?tab=readme-ov-file", "documentation": "https:\/\/github.com\/louislam\/uptime-kuma?tab=readme-ov-file",
"slogan": "Uptime Kuma is a monitoring tool for tracking the status and performance of your applications in real-time.", "slogan": "Uptime Kuma is a monitoring tool for tracking the status and performance of your applications in real-time.",
"compose": "c2VydmljZXM6CiAgdXB0aW1lLWt1bWE6CiAgICBpbWFnZTogJ2xvdWlzbGFtL3VwdGltZS1rdW1hOjEnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX0ZRRE5fMzAwMQogICAgdm9sdW1lczoKICAgICAgLSAndXB0aW1lLWt1bWE6L2FwcC9kYXRhJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtIGV4dHJhL2hlYWx0aGNoZWNrCiAgICAgIGludGVydmFsOiAycwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMTUK", "compose": "c2VydmljZXM6CiAgdXB0aW1lLWt1bWE6CiAgICBpbWFnZTogJ2xvdWlzbGFtL3VwdGltZS1rdW1hOjEnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX0ZRRE5fVVBUSU1FLUtVTUFfMzAwMQogICAgdm9sdW1lczoKICAgICAgLSAndXB0aW1lLWt1bWE6L2FwcC9kYXRhJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtIGV4dHJhL2hlYWx0aGNoZWNrCiAgICAgIGludGVydmFsOiAycwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMTUK",
"tags": [ "tags": [
"monitoring", "monitoring",
"status", "status",

View File

@ -4,7 +4,7 @@
"version": "3.12.36" "version": "3.12.36"
}, },
"v4": { "v4": {
"version": "4.0.0-beta.238" "version": "4.0.0-beta.240"
} }
} }
} }