Merge branch 'coollabsio:main' into mongodb-restore

This commit is contained in:
Evan
2024-04-25 23:02:37 +02:00
committed by GitHub
157 changed files with 2233 additions and 715 deletions

View File

@@ -13,6 +13,7 @@ class ActivityMonitor extends Component
public $activityId;
public $eventToDispatch = 'activityFinished';
public $isPollingActive = false;
public bool $fullHeight = false;
public bool $showWaiting = false;
protected $activity;

View File

@@ -11,15 +11,17 @@ class NewActivityMonitor extends Component
public ?string $header = null;
public $activityId;
public $eventToDispatch = 'activityFinished';
public $eventData = null;
public $isPollingActive = false;
protected $activity;
protected $listeners = ['newActivityMonitor' => 'newMonitorActivity'];
public function newMonitorActivity($activityId, $eventToDispatch = 'activityFinished')
public function newMonitorActivity($activityId, $eventToDispatch = 'activityFinished', $eventData = null)
{
$this->activityId = $activityId;
$this->eventToDispatch = $eventToDispatch;
$this->eventData = $eventData;
$this->hydrateActivity();
@@ -55,8 +57,12 @@ class NewActivityMonitor extends Component
}
return;
}
$this->dispatch($this->eventToDispatch);
ray('Dispatched event: ' . $this->eventToDispatch);
if (!is_null($this->eventData)) {
$this->dispatch($this->eventToDispatch, $this->eventData);
} else {
$this->dispatch($this->eventToDispatch);
}
ray('Dispatched event: ' . $this->eventToDispatch . ' with data: ' . $this->eventData);
}
}
}

View File

@@ -3,6 +3,7 @@
namespace App\Livewire\Project\Application;
use App\Models\Application;
use App\Models\LocalFileVolume;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
use Livewire\Component;
@@ -124,7 +125,7 @@ class General extends Component
}
$this->parsedServiceDomains = $this->application->docker_compose_domains ? json_decode($this->application->docker_compose_domains, true) : [];
$this->ports_exposes = $this->application->ports_exposes;
$this->customLabels = $this->application->parseContainerLabels();
$this->customLabels = $this->application->parseContainerLabels();
if (!$this->customLabels && $this->application->destination->server->proxyType() !== 'NONE') {
$this->customLabels = str(implode("|", generateLabelsApplication($this->application)))->replace("|", "\n");
$this->application->custom_labels = base64_encode($this->customLabels);
@@ -156,8 +157,36 @@ class General extends Component
return;
}
['parsedServices' => $this->parsedServices, 'initialDockerComposeLocation' => $this->initialDockerComposeLocation, 'initialDockerComposePrLocation' => $this->initialDockerComposePrLocation] = $this->application->loadComposeFile($isInit);
$compose = $this->application->parseCompose();
$services = data_get($compose, 'services');
if ($services) {
$volumes = collect($services)->map(function ($service) {
return data_get($service, 'volumes');
})->flatten()->filter(function ($volume) {
return str($volume)->startsWith('/data/coolify');
})->unique()->values();
foreach ($volumes as $volume) {
$source = Str::of($volume)->before(':');
$target = Str::of($volume)->after(':')->beforeLast(':');
LocalFileVolume::updateOrCreate(
[
'mount_path' => $target,
'resource_id' => $this->application->id,
'resource_type' => get_class($this->application)
],
[
'fs_path' => $source,
'mount_path' => $target,
'resource_id' => $this->application->id,
'resource_type' => get_class($this->application)
]
);
}
}
$this->dispatch('success', 'Docker compose file loaded.');
$this->dispatch('compose_loaded');
$this->dispatch('refresh_storages');
} catch (\Throwable $e) {
$this->application->docker_compose_location = $this->initialDockerComposeLocation;
$this->application->docker_compose_pr_location = $this->initialDockerComposePrLocation;
@@ -165,7 +194,6 @@ class General extends Component
return handleError($e, $this);
} finally {
$this->initLoadingCompose = false;
}
}
public function generateDomain(string $serviceName)
@@ -184,7 +212,14 @@ class General extends Component
$this->loadComposeFile();
}
}
public function updatedApplicationFqdn() {
public function updatedApplicationFqdn()
{
$this->application->fqdn = str($this->application->fqdn)->replaceEnd(',', '')->trim();
$this->application->fqdn = str($this->application->fqdn)->replaceStart(',', '')->trim();
$this->application->fqdn = str($this->application->fqdn)->trim()->explode(',')->map(function ($domain) {
return str($domain)->trim()->lower();
});
$this->application->fqdn = $this->application->fqdn->unique()->implode(',');
$this->resetDefaultLabels();
}
public function updatedApplicationBuildPack()

View File

@@ -18,7 +18,6 @@ class Rollback extends Component
{
$this->parameters = get_route_parameters();
}
public function rollbackImage($commit)
{
$deployment_uuid = new Cuid2(7);
@@ -27,6 +26,7 @@ class Rollback extends Component
application: $this->application,
deployment_uuid: $deployment_uuid,
commit: $commit,
rollback: true,
force_rebuild: false,
);
return redirect()->route('project.application.deployment.show', [

View File

@@ -25,6 +25,7 @@ class Edit extends Component
'key' => $data['key'],
'value' => $data['value'],
'is_multiline' => $data['is_multiline'],
'is_literal' => $data['is_literal'],
'type' => 'project',
'team_id' => currentTeam()->id,
]);

View File

@@ -29,6 +29,7 @@ class EnvironmentEdit extends Component
'key' => $data['key'],
'value' => $data['value'],
'is_multiline' => $data['is_multiline'],
'is_literal' => $data['is_literal'],
'type' => 'environment',
'team_id' => currentTeam()->id,
]);

View File

@@ -89,9 +89,11 @@ class PublicGitRepository extends Component
public function load_branch()
{
try {
$this->validate([
'repository_url' => 'required|url'
]);
if (str($this->repository_url)->startsWith('git@')) {
$github_instance = str($this->repository_url)->after('git@')->before(':');
$repository = str($this->repository_url)->after(':')->before('.git');
$this->repository_url = 'https://' . str($github_instance) . '/' . $repository;
}
} catch (\Throwable $e) {
return handleError($e, $this);
}

View File

@@ -40,7 +40,7 @@ class Create extends Component
$database = create_standalone_keydb($environment->id, $destination_uuid);
} else if ($type->value() === 'dragonfly') {
$database = create_standalone_dragonfly($environment->id, $destination_uuid);
}else if ($type->value() === 'clickhouse') {
} else if ($type->value() === 'clickhouse') {
$database = create_standalone_clickhouse($environment->id, $destination_uuid);
}
return redirect()->route('project.database.configuration', [
@@ -60,14 +60,19 @@ class Create extends Component
}
if ($oneClickService) {
$destination = StandaloneDocker::whereUuid($destination_uuid)->first();
$service = Service::create([
$service_payload = [
'name' => "$oneClickServiceName-" . str()->random(10),
'docker_compose_raw' => base64_decode($oneClickService),
'environment_id' => $environment->id,
'service_type' => $oneClickServiceName,
'server_id' => (int) $server_id,
'destination_id' => $destination->id,
'destination_type' => $destination->getMorphClass(),
]);
];
if ($oneClickServiceName === 'cloudflared') {
data_set($service_payload, 'connect_to_docker_network', true);
}
$service = Service::create($service_payload);
$service->name = "$oneClickServiceName-" . $service->uuid;
$service->save();
if ($oneClickDotEnvs?->count() > 0) {

View File

@@ -13,11 +13,13 @@ class EditCompose extends Component
'service.docker_compose_raw' => 'required',
'service.docker_compose' => 'required',
];
public function mount() {
public function mount()
{
$this->service = Service::find($this->serviceId);
}
public function saveEditedCompose() {
public function saveEditedCompose()
{
$this->dispatch('info', "Saving new docker compose...");
$this->dispatch('saveCompose', $this->service->docker_compose_raw);
}

View File

@@ -41,7 +41,7 @@ class EditDomain extends Component
} catch (\Throwable $e) {
return handleError($e, $this);
} finally {
$this->dispatch('generateDockerCompose');
$this->application->service->parse();
$this->dispatch('refresh');
$this->dispatch('configurationChanged');
}

View File

@@ -2,6 +2,7 @@
namespace App\Livewire\Project\Service;
use App\Models\Application;
use App\Models\LocalFileVolume;
use App\Models\ServiceApplication;
use App\Models\ServiceDatabase;
@@ -12,7 +13,7 @@ use Illuminate\Support\Str;
class FileStorage extends Component
{
public LocalFileVolume $fileStorage;
public ServiceApplication|ServiceDatabase|StandaloneClickhouse $resource;
public ServiceApplication|ServiceDatabase|StandaloneClickhouse|Application $resource;
public string $fs_path;
public ?string $workdir = null;
@@ -33,6 +34,43 @@ class FileStorage extends Component
$this->fs_path = $this->fileStorage->fs_path;
}
}
public function convertToDirectory() {
try {
$this->fileStorage->deleteStorageOnServer();
$this->fileStorage->is_directory = true;
$this->fileStorage->content = null;
$this->fileStorage->save();
$this->fileStorage->saveStorageOnServer();
} catch (\Throwable $e) {
return handleError($e, $this);
} finally {
$this->dispatch('refresh_storages');
}
}
public function convertToFile() {
try {
$this->fileStorage->deleteStorageOnServer();
$this->fileStorage->is_directory = false;
$this->fileStorage->content = null;
$this->fileStorage->save();
$this->fileStorage->saveStorageOnServer();
} catch (\Throwable $e) {
return handleError($e, $this);
} finally {
$this->dispatch('refresh_storages');
}
}
public function delete() {
try {
$this->fileStorage->deleteStorageOnServer();
$this->fileStorage->delete();
$this->dispatch('success', 'File deleted.');
} catch (\Throwable $e) {
return handleError($e, $this);
} finally {
$this->dispatch('refresh_storages');
}
}
public function submit()
{
$original = $this->fileStorage->getOriginal();

View File

@@ -3,12 +3,13 @@
namespace App\Livewire\Project\Service;
use App\Models\Service;
use Illuminate\Support\Collection;
use Livewire\Component;
class StackForm extends Component
{
public Service $service;
public $fields = [];
public Collection $fields;
protected $listeners = ["saveCompose"];
public $rules = [
'service.docker_compose_raw' => 'required',
@@ -20,6 +21,7 @@ class StackForm extends Component
public $validationAttributes = [];
public function mount()
{
$this->fields = collect([]);
$extraFields = $this->service->extraFields();
foreach ($extraFields as $serviceName => $fields) {
foreach ($fields as $fieldKey => $field) {
@@ -27,18 +29,20 @@ class StackForm extends Component
$value = data_get($field, 'value');
$rules = data_get($field, 'rules', 'nullable');
$isPassword = data_get($field, 'isPassword');
$this->fields[$key] = [
$this->fields->put($key, [
"serviceName" => $serviceName,
"key" => $key,
"name" => $fieldKey,
"value" => $value,
"isPassword" => $isPassword,
"rules" => $rules
];
]);
$this->rules["fields.$key.value"] = $rules;
$this->validationAttributes["fields.$key.value"] = $fieldKey;
}
}
$this->fields = $this->fields->sortDesc();
}
public function saveCompose($raw)
{

View File

@@ -7,12 +7,13 @@ use Livewire\Component;
class Storage extends Component
{
protected $listeners = ['addNewVolume'];
public $resource;
public function render()
public function getListeners()
{
return view('livewire.project.service.storage');
return [
'addNewVolume',
'refresh_storages' => '$refresh',
];
}
public function addNewVolume($data)
{
@@ -27,9 +28,13 @@ class Storage extends Component
$this->resource->refresh();
$this->dispatch('success', 'Storage added successfully');
$this->dispatch('clearAddStorage');
$this->dispatch('refreshStorages');
$this->dispatch('refresh_storages');
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function render()
{
return view('livewire.project.service.storage');
}
}

View File

@@ -7,11 +7,13 @@ use Livewire\Component;
class Add extends Component
{
public $parameters;
public bool $shared = false;
public bool $is_preview = false;
public string $key;
public ?string $value = null;
public bool $is_build_time = false;
public bool $is_multiline = false;
public bool $is_literal = false;
protected $listeners = ['clearAddEnv' => 'clear'];
protected $rules = [
@@ -19,12 +21,14 @@ class Add extends Component
'value' => 'nullable',
'is_build_time' => 'required|boolean',
'is_multiline' => 'required|boolean',
'is_literal' => 'required|boolean',
];
protected $validationAttributes = [
'key' => 'key',
'value' => 'value',
'is_build_time' => 'build',
'is_multiline' => 'multiline',
'is_literal' => 'literal',
];
public function mount()
@@ -47,6 +51,7 @@ class Add extends Component
'value' => $this->value,
'is_build_time' => $this->is_build_time,
'is_multiline' => $this->is_multiline,
'is_literal' => $this->is_literal,
'is_preview' => $this->is_preview,
]);
$this->clear();
@@ -58,5 +63,6 @@ class Add extends Component
$this->value = '';
$this->is_build_time = false;
$this->is_multiline = false;
$this->is_literal = false;
}
}

View File

@@ -15,8 +15,10 @@ class All extends Component
public ?string $variables = null;
public ?string $variablesPreview = null;
public string $view = 'normal';
protected $listeners = ['refreshEnvs', 'saveKey' => 'submit'];
protected $listeners = [
'refreshEnvs',
'saveKey' => 'submit',
];
public function mount()
{
$resourceClass = get_class($this->resource);
@@ -161,6 +163,7 @@ class All extends Component
$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()) {

View File

@@ -16,12 +16,16 @@ class Show extends Component
public bool $isLocked = false;
public bool $isSharedVariable = false;
public string $type;
protected $listeners = [
"compose_loaded" => '$refresh',
];
protected $rules = [
'env.key' => 'required|string',
'env.value' => 'nullable',
'env.is_build_time' => 'required|boolean',
'env.is_multiline' => 'required|boolean',
'env.is_literal' => 'required|boolean',
'env.is_shown_once' => 'required|boolean',
'env.real_value' => 'nullable',
];
@@ -30,6 +34,7 @@ class Show extends Component
'env.value' => 'Value',
'env.is_build_time' => 'Build Time',
'env.is_multiline' => 'Multiline',
'env.is_literal' => 'Literal',
'env.is_shown_once' => 'Shown Once',
];
@@ -45,9 +50,9 @@ class Show extends Component
public function checkEnvs()
{
$this->isDisabled = false;
if (str($this->env->key)->startsWith('SERVICE_FQDN') || str($this->env->key)->startsWith('SERVICE_URL')) {
$this->isDisabled = true;
}
// if (str($this->env->key)->startsWith('SERVICE_FQDN') || str($this->env->key)->startsWith('SERVICE_URL')) {
// $this->isDisabled = true;
// }
if ($this->env->is_shown_once) {
$this->isLocked = true;
}

View File

@@ -44,7 +44,7 @@ class Logs extends Component
} else {
$containers = getCurrentApplicationContainerStatus($server, $this->resource->id, includePullrequests: true);
}
$server->containers = $containers;
$server->containers = $containers->sort();
} catch (\Exception $e) {
return handleError($e, $this);
}
@@ -94,6 +94,7 @@ class Logs extends Component
$this->servers = $this->servers->push($this->resource->server);
}
}
$this->containers = $this->containers->sort();
} catch (\Exception $e) {
return handleError($e, $this);
}

View File

@@ -7,10 +7,5 @@ use Livewire\Component;
class All extends Component
{
public $resource;
protected $listeners = ['refreshStorages'];
public function refreshStorages()
{
$this->resource->refresh();
}
protected $listeners = ['refresh_storages' => '$refresh'];
}

View File

@@ -39,6 +39,6 @@ class Show extends Component
public function delete()
{
$this->storage->delete();
$this->dispatch('refreshStorages');
$this->dispatch('refresh_storages');
}
}

View File

@@ -76,14 +76,14 @@ class Form extends Component
public function checkLocalhostConnection()
{
$this->submit();
$uptime = $this->server->validateConnection();
['uptime' => $uptime, 'error' => $error] = $this->server->validateConnection();
if ($uptime) {
$this->dispatch('success', 'Server is reachable.');
$this->server->settings->is_reachable = true;
$this->server->settings->is_usable = true;
$this->server->settings->save();
} else {
$this->dispatch('error', 'Server is not reachable.', 'Please validate your configuration and connection.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help.');
$this->dispatch('error', 'Server is not reachable.', 'Please validate your configuration and connection.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help. <br><br>Error: ' . $error);
return;
}
}

View File

@@ -23,7 +23,8 @@ class Deploy extends Component
'proxyStatusUpdated',
'traefikDashboardAvailable',
'serverRefresh' => 'proxyStatusUpdated',
"checkProxy", "startProxy"
"checkProxy",
"startProxy"
];
}

View File

@@ -68,7 +68,7 @@ class NewDynamicConfiguration extends Component
}
$base64_value = base64_encode($this->value);
instant_remote_process([
"echo '{$base64_value}' | base64 -d > {$file}",
"echo '{$base64_value}' | base64 -d | tee {$file} > /dev/null",
], $this->server);
if ($proxy_type === 'CADDY') {
$this->server->reloadCaddy();

View File

@@ -35,10 +35,11 @@ class ShowPrivateKey extends Component
public function checkConnection()
{
try {
$uptime = $this->server->validateConnection();
['uptime' => $uptime, 'error' => $error] = $this->server->validateConnection();
if ($uptime) {
$this->dispatch('success', 'Server is reachable.');
} else {
ray($error);
$this->dispatch('error', 'Server is not reachable.<br>Please validate your configuration and connection.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help.');
return;
}

View File

@@ -11,7 +11,7 @@ class ValidateAndInstall extends Component
{
public Server $server;
public int $number_of_tries = 0;
public int $max_tries = 1;
public int $max_tries = 3;
public bool $install = true;
public $uptime = null;
public $supported_os_type = null;
@@ -32,9 +32,8 @@ class ValidateAndInstall extends Component
'refresh' => '$refresh',
];
public function init(bool $install = true)
public function init(int $data = 0)
{
$this->install = $install;
$this->uptime = null;
$this->supported_os_type = null;
$this->docker_installed = null;
@@ -42,7 +41,7 @@ class ValidateAndInstall extends Component
$this->docker_compose_installed = null;
$this->proxy_started = null;
$this->error = null;
$this->number_of_tries = 0;
$this->number_of_tries = $data;
if (!$this->ask) {
$this->dispatch('validateConnection');
}
@@ -66,16 +65,15 @@ class ValidateAndInstall extends Component
} else {
$this->proxy_started = true;
}
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function validateConnection()
{
$this->uptime = $this->server->validateConnection();
['uptime' => $this->uptime, 'error' => $error] = $this->server->validateConnection();
if (!$this->uptime) {
$this->error = 'Server is not reachable. Please validate your configuration and connection.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help.';
$this->error = 'Server is not reachable. Please validate your configuration and connection.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help. <br><br>Error: ' . $error;
return;
}
$this->dispatch('validateOS');
@@ -99,10 +97,10 @@ class ValidateAndInstall extends Component
$this->error = 'Docker Engine could not be installed. Please install Docker manually before continuing: <a target="_blank" class="underline" href="https://docs.docker.com/engine/install/#server">documentation</a>.';
return;
} else {
if ($this->number_of_tries == 0) {
if ($this->number_of_tries <= $this->max_tries) {
$activity = $this->server->installDocker();
$this->number_of_tries++;
$this->dispatch('newActivityMonitor', $activity->id, 'init');
$this->dispatch('newActivityMonitor', $activity->id, 'init', $this->number_of_tries);
}
return;
}

View File

@@ -69,13 +69,14 @@ class Configuration extends Component
}
$this->validate();
if ($this->settings->is_dns_validation_enabled) {
if ($this->settings->is_dns_validation_enabled && $this->settings->fqdn) {
ray('asdf');
if (!validate_dns_entry($this->settings->fqdn, $this->server)) {
$this->dispatch('error', "Validating DNS ({$this->settings->fqdn}) failed.<br><br>Make sure you have added the DNS records correctly.<br><br>Check this <a target='_blank' class='underline dark:text-white' href='https://coolify.io/docs/knowledge-base/dns-configuration'>documentation</a> for further help.");
$error_show = true;
}
}
check_domain_usage(domain: $this->settings->fqdn);
if ($this->settings->fqdn) check_domain_usage(domain: $this->settings->fqdn);
$this->settings->custom_dns_servers = str($this->settings->custom_dns_servers)->replaceEnd(',', '')->trim();
$this->settings->custom_dns_servers = str($this->settings->custom_dns_servers)->trim()->explode(',')->map(function ($dns) {
return str($dns)->trim()->lower();

View File

@@ -54,6 +54,7 @@ class PricingPlans extends Component
return;
}
$payload = [
'allow_promotion_codes' => true,
'billing_address_collection' => 'required',
'client_reference_id' => auth()->user()->id . ':' . currentTeam()->id,
'line_items' => [[

View File

@@ -21,6 +21,7 @@ class TeamSharedVariablesIndex extends Component
'key' => $data['key'],
'value' => $data['value'],
'is_multiline' => $data['is_multiline'],
'is_literal' => $data['is_literal'],
'type' => 'team',
'team_id' => currentTeam()->id,
]);