Merge branch 'next' into fix-#2546-deletion-issues
This commit is contained in:
@@ -23,8 +23,9 @@ class All extends Component
|
||||
public string $view = 'normal';
|
||||
|
||||
protected $listeners = [
|
||||
'refreshEnvs',
|
||||
'saveKey' => 'submit',
|
||||
'refreshEnvs',
|
||||
'environmentVariableDeleted' => 'refreshEnvs',
|
||||
];
|
||||
|
||||
protected $rules = [
|
||||
@@ -40,220 +41,240 @@ class All extends Component
|
||||
$this->showPreview = true;
|
||||
}
|
||||
$this->modalId = new Cuid2;
|
||||
$this->sortMe();
|
||||
$this->getDevView();
|
||||
}
|
||||
|
||||
public function sortMe()
|
||||
{
|
||||
if ($this->resourceClass === 'App\Models\Application' && data_get($this->resource, 'build_pack') !== 'dockercompose') {
|
||||
if ($this->resource->settings->is_env_sorting_enabled) {
|
||||
$this->resource->environment_variables = $this->resource->environment_variables->sortBy('key');
|
||||
$this->resource->environment_variables_preview = $this->resource->environment_variables_preview->sortBy('key');
|
||||
} else {
|
||||
$this->resource->environment_variables = $this->resource->environment_variables->sortBy('id');
|
||||
$this->resource->environment_variables_preview = $this->resource->environment_variables_preview->sortBy('id');
|
||||
}
|
||||
}
|
||||
$this->getDevView();
|
||||
$this->sortEnvironmentVariables();
|
||||
}
|
||||
|
||||
public function instantSave()
|
||||
{
|
||||
if ($this->resourceClass === 'App\Models\Application' && data_get($this->resource, 'build_pack') !== 'dockercompose') {
|
||||
$this->resource->settings->save();
|
||||
$this->dispatch('success', 'Environment variable settings updated.');
|
||||
$this->sortMe();
|
||||
$this->resource->settings->save();
|
||||
$this->sortEnvironmentVariables();
|
||||
$this->dispatch('success', 'Environment variable settings updated.');
|
||||
}
|
||||
|
||||
public function sortEnvironmentVariables()
|
||||
{
|
||||
if ($this->resource->type() === 'application') {
|
||||
$this->resource->load(['environment_variables', 'environment_variables_preview']);
|
||||
} else {
|
||||
$this->resource->load(['environment_variables']);
|
||||
}
|
||||
|
||||
$sortBy = data_get($this->resource, 'settings.is_env_sorting_enabled') ? 'key' : 'order';
|
||||
|
||||
$sortFunction = function ($variables) use ($sortBy) {
|
||||
if (! $variables) {
|
||||
return $variables;
|
||||
}
|
||||
if ($sortBy === 'key') {
|
||||
return $variables->sortBy(function ($item) {
|
||||
return strtolower($item->key);
|
||||
}, SORT_NATURAL | SORT_FLAG_CASE)->values();
|
||||
} else {
|
||||
return $variables->sortBy('order')->values();
|
||||
}
|
||||
};
|
||||
|
||||
$this->resource->environment_variables = $sortFunction($this->resource->environment_variables);
|
||||
$this->resource->environment_variables_preview = $sortFunction($this->resource->environment_variables_preview);
|
||||
|
||||
$this->getDevView();
|
||||
}
|
||||
|
||||
public function getDevView()
|
||||
{
|
||||
$this->variables = $this->resource->environment_variables->map(function ($item) {
|
||||
$this->variables = $this->formatEnvironmentVariables($this->resource->environment_variables);
|
||||
if ($this->showPreview) {
|
||||
$this->variablesPreview = $this->formatEnvironmentVariables($this->resource->environment_variables_preview);
|
||||
}
|
||||
}
|
||||
|
||||
private function formatEnvironmentVariables($variables)
|
||||
{
|
||||
return $variables->map(function ($item) {
|
||||
if ($item->is_shown_once) {
|
||||
return "$item->key=(locked secret)";
|
||||
return "$item->key=(Locked Secret, delete and add again to change)";
|
||||
}
|
||||
if ($item->is_multiline) {
|
||||
return "$item->key=(multiline, edit in normal view)";
|
||||
return "$item->key=(Multiline environment variable, edit in normal view)";
|
||||
}
|
||||
|
||||
return "$item->key=$item->value";
|
||||
})->join('
|
||||
');
|
||||
if ($this->showPreview) {
|
||||
$this->variablesPreview = $this->resource->environment_variables_preview->map(function ($item) {
|
||||
if ($item->is_shown_once) {
|
||||
return "$item->key=(locked secret)";
|
||||
}
|
||||
if ($item->is_multiline) {
|
||||
return "$item->key=(multiline, edit in normal view)";
|
||||
}
|
||||
|
||||
return "$item->key=$item->value";
|
||||
})->join('
|
||||
');
|
||||
}
|
||||
})->join("\n");
|
||||
}
|
||||
|
||||
public function switch()
|
||||
{
|
||||
if ($this->view === 'normal') {
|
||||
$this->view = 'dev';
|
||||
} else {
|
||||
$this->view = 'normal';
|
||||
}
|
||||
$this->sortMe();
|
||||
$this->view = $this->view === 'normal' ? 'dev' : 'normal';
|
||||
$this->sortEnvironmentVariables();
|
||||
}
|
||||
|
||||
public function saveVariables($isPreview)
|
||||
public function submit($data = null)
|
||||
{
|
||||
if ($isPreview) {
|
||||
$variables = parseEnvFormatToArray($this->variablesPreview);
|
||||
$this->resource->environment_variables_preview()->whereNotIn('key', array_keys($variables))->delete();
|
||||
} else {
|
||||
$variables = parseEnvFormatToArray($this->variables);
|
||||
$this->resource->environment_variables()->whereNotIn('key', array_keys($variables))->delete();
|
||||
}
|
||||
foreach ($variables as $key => $variable) {
|
||||
if ($isPreview) {
|
||||
$found = $this->resource->environment_variables_preview()->where('key', $key)->first();
|
||||
try {
|
||||
if ($data === null) {
|
||||
$this->handleBulkSubmit();
|
||||
} else {
|
||||
$found = $this->resource->environment_variables()->where('key', $key)->first();
|
||||
$this->handleSingleSubmit($data);
|
||||
}
|
||||
if ($found) {
|
||||
if ($found->is_shown_once || $found->is_multiline) {
|
||||
continue;
|
||||
|
||||
$this->updateOrder();
|
||||
$this->sortEnvironmentVariables();
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
}
|
||||
|
||||
private function updateOrder()
|
||||
{
|
||||
$variables = parseEnvFormatToArray($this->variables);
|
||||
$order = 1;
|
||||
foreach ($variables as $key => $value) {
|
||||
$env = $this->resource->environment_variables()->where('key', $key)->first();
|
||||
if ($env) {
|
||||
$env->order = $order;
|
||||
$env->save();
|
||||
}
|
||||
$order++;
|
||||
}
|
||||
|
||||
if ($this->showPreview) {
|
||||
$previewVariables = parseEnvFormatToArray($this->variablesPreview);
|
||||
$order = 1;
|
||||
foreach ($previewVariables as $key => $value) {
|
||||
$env = $this->resource->environment_variables_preview()->where('key', $key)->first();
|
||||
if ($env) {
|
||||
$env->order = $order;
|
||||
$env->save();
|
||||
}
|
||||
$found->value = $variable;
|
||||
// if (str($found->value)->startsWith('{{') && str($found->value)->endsWith('}}')) {
|
||||
// $type = str($found->value)->after('{{')->before('.')->value;
|
||||
// if (! collect(SHARED_VARIABLE_TYPES)->contains($type)) {
|
||||
// $this->dispatch('error', 'Invalid shared variable type.', 'Valid types are: team, project, environment.');
|
||||
$order++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
$found->save();
|
||||
private function handleBulkSubmit()
|
||||
{
|
||||
$variables = parseEnvFormatToArray($this->variables);
|
||||
$this->deleteRemovedVariables(false, $variables);
|
||||
$this->updateOrCreateVariables(false, $variables);
|
||||
|
||||
continue;
|
||||
if ($this->showPreview) {
|
||||
$previewVariables = parseEnvFormatToArray($this->variablesPreview);
|
||||
$this->deleteRemovedVariables(true, $previewVariables);
|
||||
$this->updateOrCreateVariables(true, $previewVariables);
|
||||
}
|
||||
|
||||
$this->dispatch('success', 'Environment variables updated.');
|
||||
}
|
||||
|
||||
private function handleSingleSubmit($data)
|
||||
{
|
||||
$found = $this->resource->environment_variables()->where('key', $data['key'])->first();
|
||||
if ($found) {
|
||||
$this->dispatch('error', 'Environment variable already exists.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$maxOrder = $this->resource->environment_variables()->max('order') ?? 0;
|
||||
$environment = $this->createEnvironmentVariable($data);
|
||||
$environment->order = $maxOrder + 1;
|
||||
$environment->save();
|
||||
}
|
||||
|
||||
private function createEnvironmentVariable($data)
|
||||
{
|
||||
$environment = new EnvironmentVariable;
|
||||
$environment->key = $data['key'];
|
||||
$environment->value = $data['value'];
|
||||
$environment->is_build_time = $data['is_build_time'] ?? false;
|
||||
$environment->is_multiline = $data['is_multiline'] ?? false;
|
||||
$environment->is_literal = $data['is_literal'] ?? false;
|
||||
$environment->is_preview = $data['is_preview'] ?? false;
|
||||
|
||||
$resourceType = $this->resource->type();
|
||||
$resourceIdField = $this->getResourceIdField($resourceType);
|
||||
|
||||
if ($resourceIdField) {
|
||||
$environment->$resourceIdField = $this->resource->id;
|
||||
}
|
||||
|
||||
return $environment;
|
||||
}
|
||||
|
||||
private function getResourceIdField($resourceType)
|
||||
{
|
||||
$resourceTypes = [
|
||||
'application' => 'application_id',
|
||||
'standalone-postgresql' => 'standalone_postgresql_id',
|
||||
'standalone-redis' => 'standalone_redis_id',
|
||||
'standalone-mongodb' => 'standalone_mongodb_id',
|
||||
'standalone-mysql' => 'standalone_mysql_id',
|
||||
'standalone-mariadb' => 'standalone_mariadb_id',
|
||||
'standalone-keydb' => 'standalone_keydb_id',
|
||||
'standalone-dragonfly' => 'standalone_dragonfly_id',
|
||||
'standalone-clickhouse' => 'standalone_clickhouse_id',
|
||||
'service' => 'service_id',
|
||||
];
|
||||
|
||||
return $resourceTypes[$resourceType] ?? null;
|
||||
}
|
||||
|
||||
private function deleteRemovedVariables($isPreview, $variables)
|
||||
{
|
||||
$method = $isPreview ? 'environment_variables_preview' : 'environment_variables';
|
||||
$this->resource->$method()->whereNotIn('key', array_keys($variables))->delete();
|
||||
}
|
||||
|
||||
private function updateOrCreateVariables($isPreview, $variables)
|
||||
{
|
||||
foreach ($variables as $key => $value) {
|
||||
$method = $isPreview ? 'environment_variables_preview' : 'environment_variables';
|
||||
$found = $this->resource->$method()->where('key', $key)->first();
|
||||
|
||||
if ($found) {
|
||||
if (! $found->is_shown_once && ! $found->is_multiline) {
|
||||
$found->value = $value;
|
||||
$found->save();
|
||||
}
|
||||
} else {
|
||||
$environment = new EnvironmentVariable;
|
||||
$environment->key = $key;
|
||||
$environment->value = $variable;
|
||||
// if (str($environment->value)->startsWith('{{') && str($environment->value)->endsWith('}}')) {
|
||||
// $type = str($environment->value)->after('{{')->before('.')->value;
|
||||
// if (! collect(SHARED_VARIABLE_TYPES)->contains($type)) {
|
||||
// $this->dispatch('error', 'Invalid shared variable type.', 'Valid types are: team, project, environment.');
|
||||
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
$environment->value = $value;
|
||||
$environment->is_build_time = false;
|
||||
$environment->is_multiline = false;
|
||||
$environment->is_preview = $isPreview ? true : false;
|
||||
switch ($this->resource->type()) {
|
||||
case 'application':
|
||||
$environment->application_id = $this->resource->id;
|
||||
break;
|
||||
case 'standalone-postgresql':
|
||||
$environment->standalone_postgresql_id = $this->resource->id;
|
||||
break;
|
||||
case 'standalone-redis':
|
||||
$environment->standalone_redis_id = $this->resource->id;
|
||||
break;
|
||||
case 'standalone-mongodb':
|
||||
$environment->standalone_mongodb_id = $this->resource->id;
|
||||
break;
|
||||
case 'standalone-mysql':
|
||||
$environment->standalone_mysql_id = $this->resource->id;
|
||||
break;
|
||||
case 'standalone-mariadb':
|
||||
$environment->standalone_mariadb_id = $this->resource->id;
|
||||
break;
|
||||
case 'standalone-keydb':
|
||||
$environment->standalone_keydb_id = $this->resource->id;
|
||||
break;
|
||||
case 'standalone-dragonfly':
|
||||
$environment->standalone_dragonfly_id = $this->resource->id;
|
||||
break;
|
||||
case 'standalone-clickhouse':
|
||||
$environment->standalone_clickhouse_id = $this->resource->id;
|
||||
break;
|
||||
case 'service':
|
||||
$environment->service_id = $this->resource->id;
|
||||
break;
|
||||
}
|
||||
$environment->is_preview = $isPreview;
|
||||
|
||||
$this->setEnvironmentResourceId($environment);
|
||||
$environment->save();
|
||||
}
|
||||
}
|
||||
if ($isPreview) {
|
||||
$this->dispatch('success', 'Preview environment variables updated.');
|
||||
} else {
|
||||
$this->dispatch('success', 'Environment variables updated.');
|
||||
}
|
||||
|
||||
private function setEnvironmentResourceId($environment)
|
||||
{
|
||||
$resourceTypes = [
|
||||
'application' => 'application_id',
|
||||
'standalone-postgresql' => 'standalone_postgresql_id',
|
||||
'standalone-redis' => 'standalone_redis_id',
|
||||
'standalone-mongodb' => 'standalone_mongodb_id',
|
||||
'standalone-mysql' => 'standalone_mysql_id',
|
||||
'standalone-mariadb' => 'standalone_mariadb_id',
|
||||
'standalone-keydb' => 'standalone_keydb_id',
|
||||
'standalone-dragonfly' => 'standalone_dragonfly_id',
|
||||
'standalone-clickhouse' => 'standalone_clickhouse_id',
|
||||
'service' => 'service_id',
|
||||
];
|
||||
|
||||
$resourceType = $this->resource->type();
|
||||
if (isset($resourceTypes[$resourceType])) {
|
||||
$environment->{$resourceTypes[$resourceType]} = $this->resource->id;
|
||||
}
|
||||
$this->refreshEnvs();
|
||||
}
|
||||
|
||||
public function refreshEnvs()
|
||||
{
|
||||
$this->resource->refresh();
|
||||
$this->sortEnvironmentVariables();
|
||||
$this->getDevView();
|
||||
}
|
||||
|
||||
public function submit($data)
|
||||
{
|
||||
try {
|
||||
$found = $this->resource->environment_variables()->where('key', $data['key'])->first();
|
||||
if ($found) {
|
||||
$this->dispatch('error', 'Environment variable already exists.');
|
||||
|
||||
return;
|
||||
}
|
||||
$environment = new EnvironmentVariable;
|
||||
$environment->key = $data['key'];
|
||||
$environment->value = $data['value'];
|
||||
$environment->is_build_time = $data['is_build_time'];
|
||||
$environment->is_multiline = $data['is_multiline'];
|
||||
$environment->is_literal = $data['is_literal'];
|
||||
$environment->is_preview = $data['is_preview'];
|
||||
|
||||
switch ($this->resource->type()) {
|
||||
case 'application':
|
||||
$environment->application_id = $this->resource->id;
|
||||
break;
|
||||
case 'standalone-postgresql':
|
||||
$environment->standalone_postgresql_id = $this->resource->id;
|
||||
break;
|
||||
case 'standalone-redis':
|
||||
$environment->standalone_redis_id = $this->resource->id;
|
||||
break;
|
||||
case 'standalone-mongodb':
|
||||
$environment->standalone_mongodb_id = $this->resource->id;
|
||||
break;
|
||||
case 'standalone-mysql':
|
||||
$environment->standalone_mysql_id = $this->resource->id;
|
||||
break;
|
||||
case 'standalone-mariadb':
|
||||
$environment->standalone_mariadb_id = $this->resource->id;
|
||||
break;
|
||||
case 'standalone-keydb':
|
||||
$environment->standalone_keydb_id = $this->resource->id;
|
||||
break;
|
||||
case 'standalone-dragonfly':
|
||||
$environment->standalone_dragonfly_id = $this->resource->id;
|
||||
break;
|
||||
case 'standalone-clickhouse':
|
||||
$environment->standalone_clickhouse_id = $this->resource->id;
|
||||
break;
|
||||
case 'service':
|
||||
$environment->service_id = $this->resource->id;
|
||||
break;
|
||||
}
|
||||
$environment->save();
|
||||
$this->refreshEnvs();
|
||||
$this->dispatch('success', 'Environment variable added.');
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,8 @@ class Show extends Component
|
||||
public string $type;
|
||||
|
||||
protected $listeners = [
|
||||
'refresh' => 'refresh',
|
||||
'refreshEnvs' => 'refresh',
|
||||
'refresh',
|
||||
'compose_loaded' => '$refresh',
|
||||
];
|
||||
|
||||
@@ -129,7 +130,8 @@ class Show extends Component
|
||||
{
|
||||
try {
|
||||
$this->env->delete();
|
||||
$this->dispatch('refreshEnvs');
|
||||
$this->dispatch('environmentVariableDeleted');
|
||||
$this->dispatch('success', 'Environment variable deleted successfully.');
|
||||
} catch (\Exception $e) {
|
||||
return handleError($e);
|
||||
}
|
||||
|
||||
@@ -2,18 +2,16 @@
|
||||
|
||||
namespace App\Livewire\Project\Shared;
|
||||
|
||||
use App\Actions\Server\RunCommand;
|
||||
use App\Models\Application;
|
||||
use App\Models\Server;
|
||||
use App\Models\Service;
|
||||
use Illuminate\Support\Collection;
|
||||
use Livewire\Attributes\On;
|
||||
use Livewire\Component;
|
||||
|
||||
class ExecuteContainerCommand extends Component
|
||||
{
|
||||
public string $command;
|
||||
|
||||
public string $container;
|
||||
public $container;
|
||||
|
||||
public Collection $containers;
|
||||
|
||||
@@ -23,8 +21,6 @@ class ExecuteContainerCommand extends Component
|
||||
|
||||
public string $type;
|
||||
|
||||
public string $workDir = '';
|
||||
|
||||
public Server $server;
|
||||
|
||||
public Collection $servers;
|
||||
@@ -33,11 +29,13 @@ class ExecuteContainerCommand extends Component
|
||||
'server' => 'required',
|
||||
'container' => 'required',
|
||||
'command' => 'required',
|
||||
'workDir' => 'nullable',
|
||||
];
|
||||
|
||||
public function mount()
|
||||
{
|
||||
if (! auth()->user()->isAdmin()) {
|
||||
abort(403);
|
||||
}
|
||||
$this->parameters = get_route_parameters();
|
||||
$this->containers = collect();
|
||||
$this->servers = collect();
|
||||
@@ -62,24 +60,13 @@ class ExecuteContainerCommand extends Component
|
||||
if ($this->resource->destination->server->isFunctional()) {
|
||||
$this->servers = $this->servers->push($this->resource->destination->server);
|
||||
}
|
||||
$this->container = $this->resource->uuid;
|
||||
$this->containers->push($this->container);
|
||||
} elseif (data_get($this->parameters, 'service_uuid')) {
|
||||
$this->type = 'service';
|
||||
$this->resource = Service::where('uuid', $this->parameters['service_uuid'])->firstOrFail();
|
||||
$this->resource->applications()->get()->each(function ($application) {
|
||||
$this->containers->push(data_get($application, 'name').'-'.data_get($this->resource, 'uuid'));
|
||||
});
|
||||
$this->resource->databases()->get()->each(function ($database) {
|
||||
$this->containers->push(data_get($database, 'name').'-'.data_get($this->resource, 'uuid'));
|
||||
});
|
||||
if ($this->resource->server->isFunctional()) {
|
||||
$this->servers = $this->servers->push($this->resource->server);
|
||||
}
|
||||
}
|
||||
if ($this->containers->count() > 0) {
|
||||
$this->container = $this->containers->first();
|
||||
}
|
||||
}
|
||||
|
||||
public function loadContainers()
|
||||
@@ -102,44 +89,65 @@ class ExecuteContainerCommand extends Component
|
||||
];
|
||||
$this->containers = $this->containers->push($payload);
|
||||
}
|
||||
} elseif (data_get($this->parameters, 'database_uuid')) {
|
||||
if ($this->resource->isRunning()) {
|
||||
$this->containers = $this->containers->push([
|
||||
'server' => $server,
|
||||
'container' => [
|
||||
'Names' => $this->resource->uuid,
|
||||
],
|
||||
]);
|
||||
}
|
||||
} elseif (data_get($this->parameters, 'service_uuid')) {
|
||||
$this->resource->applications()->get()->each(function ($application) {
|
||||
ray($application);
|
||||
if ($application->isRunning()) {
|
||||
$this->containers->push([
|
||||
'server' => $this->resource->server,
|
||||
'container' => [
|
||||
'Names' => data_get($application, 'name').'-'.data_get($this->resource, 'uuid'),
|
||||
],
|
||||
]);
|
||||
}
|
||||
});
|
||||
$this->resource->databases()->get()->each(function ($database) {
|
||||
if ($database->isRunning()) {
|
||||
$this->containers->push([
|
||||
'server' => $this->resource->server,
|
||||
'container' => [
|
||||
'Names' => data_get($database, 'name').'-'.data_get($this->resource, 'uuid'),
|
||||
],
|
||||
]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
if ($this->containers->count() > 0) {
|
||||
if (data_get($this->parameters, 'application_uuid')) {
|
||||
$this->container = data_get($this->containers->first(), 'container.Names');
|
||||
} elseif (data_get($this->parameters, 'database_uuid')) {
|
||||
$this->container = $this->containers->first();
|
||||
} elseif (data_get($this->parameters, 'service_uuid')) {
|
||||
$this->container = $this->containers->first();
|
||||
}
|
||||
$this->container = $this->containers->first();
|
||||
}
|
||||
}
|
||||
|
||||
public function runCommand()
|
||||
#[On('connectToContainer')]
|
||||
public function connectToContainer()
|
||||
{
|
||||
try {
|
||||
if (data_get($this->parameters, 'application_uuid')) {
|
||||
$container = $this->containers->where('container.Names', $this->container)->first();
|
||||
$container_name = data_get($container, 'container.Names');
|
||||
if (is_null($container)) {
|
||||
throw new \RuntimeException('Container not found.');
|
||||
}
|
||||
$server = data_get($container, 'server');
|
||||
} else {
|
||||
$container_name = $this->container;
|
||||
$server = $this->servers->first();
|
||||
$container_name = data_get($this->container, 'container.Names');
|
||||
if (is_null($container_name)) {
|
||||
throw new \RuntimeException('Container not found.');
|
||||
}
|
||||
$server = data_get($this->container, 'server');
|
||||
|
||||
if ($server->isForceDisabled()) {
|
||||
throw new \RuntimeException('Server is disabled.');
|
||||
}
|
||||
$cmd = "sh -c 'if [ -f ~/.profile ]; then . ~/.profile; fi; ".str_replace("'", "'\''", $this->command)."'";
|
||||
if (! empty($this->workDir)) {
|
||||
$exec = "docker exec -w {$this->workDir} {$container_name} {$cmd}";
|
||||
} else {
|
||||
$exec = "docker exec {$container_name} {$cmd}";
|
||||
}
|
||||
$activity = RunCommand::run(server: $server, command: $exec);
|
||||
$this->dispatch('activityMonitor', $activity->id);
|
||||
|
||||
$this->dispatch('send-terminal-command',
|
||||
true,
|
||||
$container_name,
|
||||
$server->uuid,
|
||||
);
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ class GetLogs extends Component
|
||||
if (! $refresh && ($this->resource?->getMorphClass() === 'App\Models\Service' || str($this->container)->contains('-pr-'))) {
|
||||
return;
|
||||
}
|
||||
if (! $this->numberOfLines) {
|
||||
if ($this->numberOfLines <= 0) {
|
||||
$this->numberOfLines = 1000;
|
||||
}
|
||||
if ($this->container) {
|
||||
|
||||
@@ -26,7 +26,7 @@ class All extends Component
|
||||
$this->containerNames = $this->containerNames->merge($this->resource->databases()->pluck('name'));
|
||||
} elseif ($this->resource->type() == 'application') {
|
||||
if ($this->resource->build_pack === 'dockercompose') {
|
||||
$parsed = $this->resource->parseCompose();
|
||||
$parsed = $this->resource->parse();
|
||||
$containers = collect(data_get($parsed, 'services'))->keys();
|
||||
$this->containerNames = $containers;
|
||||
} else {
|
||||
|
||||
@@ -7,8 +7,8 @@ use Livewire\Component;
|
||||
class Executions extends Component
|
||||
{
|
||||
public $executions = [];
|
||||
|
||||
public $selectedKey;
|
||||
public $task;
|
||||
|
||||
public function getListeners()
|
||||
{
|
||||
@@ -26,4 +26,44 @@ class Executions extends Component
|
||||
}
|
||||
$this->selectedKey = $key;
|
||||
}
|
||||
|
||||
public function server()
|
||||
{
|
||||
if (!$this->task) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->task->application) {
|
||||
if ($this->task->application->destination && $this->task->application->destination->server) {
|
||||
return $this->task->application->destination->server;
|
||||
}
|
||||
} elseif ($this->task->service) {
|
||||
if ($this->task->service->destination && $this->task->service->destination->server) {
|
||||
return $this->task->service->destination->server;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getServerTimezone()
|
||||
{
|
||||
$server = $this->server();
|
||||
if (!$server) {
|
||||
return 'UTC';
|
||||
}
|
||||
$serverTimezone = $server->settings->server_timezone;
|
||||
return $serverTimezone;
|
||||
}
|
||||
|
||||
public function formatDateInServerTimezone($date)
|
||||
{
|
||||
$serverTimezone = $this->getServerTimezone();
|
||||
$dateObj = new \DateTime($date);
|
||||
try {
|
||||
$dateObj->setTimezone(new \DateTimeZone($serverTimezone));
|
||||
} catch (\Exception $e) {
|
||||
$dateObj->setTimezone(new \DateTimeZone('UTC'));
|
||||
}
|
||||
return $dateObj->format('Y-m-d H:i:s T');
|
||||
}
|
||||
}
|
||||
|
||||
43
app/Livewire/Project/Shared/Terminal.php
Normal file
43
app/Livewire/Project/Shared/Terminal.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Livewire\Project\Shared;
|
||||
|
||||
use App\Models\Server;
|
||||
use Livewire\Attributes\On;
|
||||
use Livewire\Component;
|
||||
|
||||
class Terminal extends Component
|
||||
{
|
||||
#[On('send-terminal-command')]
|
||||
public function sendTerminalCommand($isContainer, $identifier, $serverUuid)
|
||||
{
|
||||
|
||||
$server = Server::ownedByCurrentTeam()->whereUuid($serverUuid)->firstOrFail();
|
||||
|
||||
if ($isContainer) {
|
||||
$status = getContainerStatus($server, $identifier);
|
||||
if ($status !== 'running') {
|
||||
return;
|
||||
}
|
||||
$command = generateSshCommand($server, "docker exec -it {$identifier} sh -c 'if [ -f ~/.profile ]; then . ~/.profile; fi; if [ -n \"\$SHELL\" ]; then exec \$SHELL; else sh; fi'");
|
||||
} else {
|
||||
$command = generateSshCommand($server, "sh -c 'if [ -f ~/.profile ]; then . ~/.profile; fi; if [ -n \"\$SHELL\" ]; then exec \$SHELL; else sh; fi'");
|
||||
}
|
||||
|
||||
// ssh command is sent back to frontend then to websocket
|
||||
// this is done because the websocket connection is not available here
|
||||
// a better solution would be to remove websocket on NodeJS and work with something like
|
||||
// 1. Laravel Pusher/Echo connection (not possible without a sdk)
|
||||
// 2. Ratchet / Revolt / ReactPHP / Event Loop (possible but hard to implement and huge dependencies)
|
||||
// 3. Just found out about this https://github.com/sirn-se/websocket-php, perhaps it can be used
|
||||
// 4. Follow-up discussions here:
|
||||
// - https://github.com/coollabsio/coolify/issues/2298
|
||||
// - https://github.com/coollabsio/coolify/discussions/3362
|
||||
$this->dispatch('send-back-command', $command);
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.project.shared.terminal');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user