wip: migrate to livewire 3

This commit is contained in:
Andras Bacsai
2023-12-07 19:06:32 +01:00
parent 2f286a6595
commit 718603e37e
254 changed files with 930 additions and 936 deletions

View File

@@ -1,56 +0,0 @@
<?php
namespace App\Http\Livewire;
use App\Enums\ProcessStatus;
use Livewire\Component;
use Spatie\Activitylog\Models\Activity;
class ActivityMonitor extends Component
{
public string|null $header = null;
public $activityId;
public $isPollingActive = false;
protected $activity;
protected $listeners = ['newMonitorActivity'];
public function newMonitorActivity($activityId)
{
$this->activityId = $activityId;
$this->hydrateActivity();
$this->isPollingActive = true;
}
public function hydrateActivity()
{
$this->activity = Activity::query()
->find($this->activityId);
}
public function polling()
{
$this->hydrateActivity();
$this->setStatus(ProcessStatus::IN_PROGRESS);
$exit_code = data_get($this->activity, 'properties.exitCode');
if ($exit_code !== null) {
if ($exit_code === 0) {
$this->setStatus(ProcessStatus::FINISHED);
} else {
$this->setStatus(ProcessStatus::ERROR);
}
$this->isPollingActive = false;
$this->emit('activityFinished');
}
}
protected function setStatus($status)
{
$this->activity->properties = $this->activity->properties->merge([
'status' => $status,
]);
$this->activity->save();
}
}

View File

@@ -1,295 +0,0 @@
<?php
namespace App\Http\Livewire\Boarding;
use App\Actions\Server\InstallDocker;
use App\Models\PrivateKey;
use App\Models\Project;
use App\Models\Server;
use App\Models\Team;
use Illuminate\Support\Collection;
use Livewire\Component;
class Index extends Component
{
public string $currentState = 'welcome';
public ?string $selectedServerType = null;
public ?Collection $privateKeys = null;
public ?int $selectedExistingPrivateKey = null;
public ?string $privateKeyType = null;
public ?string $privateKey = null;
public ?string $publicKey = null;
public ?string $privateKeyName = null;
public ?string $privateKeyDescription = null;
public ?PrivateKey $createdPrivateKey = null;
public ?Collection $servers = null;
public ?int $selectedExistingServer = null;
public ?string $remoteServerName = null;
public ?string $remoteServerDescription = null;
public ?string $remoteServerHost = null;
public ?int $remoteServerPort = 22;
public ?string $remoteServerUser = 'root';
public bool $isSwarmManager = false;
public bool $isCloudflareTunnel = false;
public ?Server $createdServer = null;
public Collection $projects;
public ?int $selectedExistingProject = null;
public ?Project $createdProject = null;
public bool $dockerInstallationStarted = false;
public string $serverPublicKey;
public bool $serverReachable = true;
public function mount()
{
$this->privateKeyName = generate_random_name();
$this->remoteServerName = generate_random_name();
if (isDev()) {
$this->privateKey = '-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevAAAAJi/QySHv0Mk
hwAAAAtzc2gtZWQyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevA
AAAECBQw4jg1WRT2IGHMncCiZhURCts2s24HoDS0thHnnRKVuGmoeGq/pojrsyP1pszcNV
uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
-----END OPENSSH PRIVATE KEY-----';
$this->privateKeyDescription = 'Created by Coolify';
$this->remoteServerDescription = 'Created by Coolify';
$this->remoteServerHost = 'coolify-testing-host';
}
}
public function explanation()
{
if (isCloud()) {
return $this->setServerType('remote');
}
$this->currentState = 'select-server-type';
}
public function restartBoarding()
{
return redirect()->route('boarding');
}
public function skipBoarding()
{
Team::find(currentTeam()->id)->update([
'show_boarding' => false
]);
refreshSession();
return redirect()->route('dashboard');
}
public function setServerType(string $type)
{
$this->selectedServerType = $type;
if ($this->selectedServerType === 'localhost') {
$this->createdServer = Server::find(0);
if (!$this->createdServer) {
return $this->emit('error', 'Localhost server is not found. Something went wrong during installation. Please try to reinstall or contact support.');
}
$this->serverPublicKey = $this->createdServer->privateKey->publicKey();
return $this->validateServer('localhost');
} elseif ($this->selectedServerType === 'remote') {
$this->privateKeys = PrivateKey::ownedByCurrentTeam(['name'])->where('id', '!=', 0)->get();
if ($this->privateKeys->count() > 0) {
$this->selectedExistingPrivateKey = $this->privateKeys->first()->id;
}
$this->servers = Server::ownedByCurrentTeam(['name'])->where('id', '!=', 0)->get();
if ($this->servers->count() > 0) {
$this->selectedExistingServer = $this->servers->first()->id;
$this->currentState = 'select-existing-server';
return;
}
$this->currentState = 'private-key';
}
}
public function selectExistingServer()
{
$this->createdServer = Server::find($this->selectedExistingServer);
if (!$this->createdServer) {
$this->emit('error', 'Server is not found.');
$this->currentState = 'private-key';
return;
}
$this->selectedExistingPrivateKey = $this->createdServer->privateKey->id;
$this->serverPublicKey = $this->createdServer->privateKey->publicKey();
$this->validateServer();
}
public function getProxyType()
{
$proxyTypeSet = $this->createdServer->proxy->type;
if (!$proxyTypeSet) {
$this->currentState = 'select-proxy';
return;
}
$this->getProjects();
}
public function selectExistingPrivateKey()
{
$this->createdPrivateKey = PrivateKey::find($this->selectedExistingPrivateKey);
$this->privateKey = $this->createdPrivateKey->private_key;
$this->currentState = 'create-server';
}
public function createNewServer()
{
$this->selectedExistingServer = null;
$this->currentState = 'private-key';
}
public function setPrivateKey(string $type)
{
$this->selectedExistingPrivateKey = null;
$this->privateKeyType = $type;
if ($type === 'create') {
$this->createNewPrivateKey();
}
$this->currentState = 'create-private-key';
}
public function savePrivateKey()
{
$this->validate([
'privateKeyName' => 'required',
'privateKey' => 'required',
]);
$this->createdPrivateKey = PrivateKey::create([
'name' => $this->privateKeyName,
'description' => $this->privateKeyDescription,
'private_key' => $this->privateKey,
'team_id' => currentTeam()->id
]);
$this->createdPrivateKey->save();
$this->currentState = 'create-server';
}
public function saveServer()
{
$this->validate([
'remoteServerName' => 'required',
'remoteServerHost' => 'required',
'remoteServerPort' => 'required|integer',
'remoteServerUser' => 'required',
]);
$this->privateKey = formatPrivateKey($this->privateKey);
$foundServer = Server::whereIp($this->remoteServerHost)->first();
if ($foundServer) {
return $this->emit('error', 'IP address is already in use by another team.');
}
$this->createdServer = Server::create([
'name' => $this->remoteServerName,
'ip' => $this->remoteServerHost,
'port' => $this->remoteServerPort,
'user' => $this->remoteServerUser,
'description' => $this->remoteServerDescription,
'private_key_id' => $this->createdPrivateKey->id,
'team_id' => currentTeam()->id,
]);
$this->createdServer->settings->is_swarm_manager = $this->isSwarmManager;
$this->createdServer->settings->is_cloudflare_tunnel = $this->isCloudflareTunnel;
$this->createdServer->settings->save();
$this->createdServer->addInitialNetwork();
$this->validateServer();
}
public function validateServer()
{
try {
config()->set('coolify.mux_enabled', false);
instant_remote_process(['uptime'], $this->createdServer, true);
$this->createdServer->settings()->update([
'is_reachable' => true,
]);
} catch (\Throwable $e) {
$this->serverReachable = false;
$this->createdServer->delete();
return handleError(error: $e, livewire: $this);
}
try {
$dockerVersion = instant_remote_process(["docker version|head -2|grep -i version| awk '{print $2}'"], $this->createdServer, true);
$dockerVersion = checkMinimumDockerEngineVersion($dockerVersion);
if (is_null($dockerVersion)) {
$this->currentState = 'install-docker';
throw new \Exception('Docker not found or old version is installed.');
}
$this->createdServer->settings()->update([
'is_usable' => true,
]);
$this->getProxyType();
} catch (\Throwable $e) {
// $this->dockerInstallationStarted = false;
return handleError(error: $e, livewire: $this);
}
}
public function installDocker()
{
try {
$this->dockerInstallationStarted = true;
$activity = InstallDocker::run($this->createdServer);
$this->emit('installDocker');
$this->emit('newMonitorActivity', $activity->id);
} catch (\Throwable $e) {
$this->dockerInstallationStarted = false;
return handleError(error: $e, livewire: $this);
}
}
public function dockerInstalledOrSkipped()
{
$this->validateServer();
}
public function selectProxy(string|null $proxyType = null)
{
if (!$proxyType) {
return $this->getProjects();
}
$this->createdServer->proxy->type = $proxyType;
$this->createdServer->proxy->status = 'exited';
$this->createdServer->save();
$this->getProjects();
}
public function getProjects()
{
$this->projects = Project::ownedByCurrentTeam(['name'])->get();
if ($this->projects->count() > 0) {
$this->selectedExistingProject = $this->projects->first()->id;
}
$this->currentState = 'create-project';
}
public function selectExistingProject()
{
$this->createdProject = Project::find($this->selectedExistingProject);
$this->currentState = 'create-resource';
}
public function createNewProject()
{
$this->createdProject = Project::create([
'name' => "My first project",
'team_id' => currentTeam()->id
]);
$this->currentState = 'create-resource';
}
public function showNewResource()
{
$this->skipBoarding();
return redirect()->route(
'project.resources.new',
[
'project_uuid' => $this->createdProject->uuid,
'environment_name' => 'production',
'server' => $this->createdServer->id,
]
);
}
private function createNewPrivateKey()
{
$this->privateKeyName = generate_random_name();
$this->privateKeyDescription = 'Created by Coolify';
['private' => $this->privateKey, 'public' => $this->publicKey] = generateSSHKey();
}
public function render()
{
return view('livewire.boarding.index')->layout('layouts.boarding');
}
}

View File

@@ -1,44 +0,0 @@
<?php
namespace App\Http\Livewire;
use App\Actions\License\CheckResaleLicense;
use App\Models\InstanceSettings;
use Livewire\Component;
class CheckLicense extends Component
{
public InstanceSettings|null $settings = null;
public string|null $instance_id = null;
protected $rules = [
'settings.resale_license' => 'nullable',
'settings.is_resale_license_active' => 'nullable',
];
protected $validationAttributes = [
'settings.resale_license' => 'License',
'instance_id' => 'Instance Id (Do not change this)',
'settings.is_resale_license_active' => 'Is License Active',
];
public function mount()
{
$this->instance_id = config('app.id');
$this->settings = InstanceSettings::get();
}
public function submit()
{
$this->validate();
$this->settings->save();
if ($this->settings->resale_license) {
try {
CheckResaleLicense::run();
$this->emit('reloadWindow');
} catch (\Throwable $e) {
session()->flash('error', 'Something went wrong. Please contact support. <br>Error: ' . $e->getMessage());
ray($e->getMessage());
return redirect()->to('/settings/license');
}
}
}
}

View File

@@ -1,31 +0,0 @@
<?php
namespace App\Http\Livewire;
use App\Models\Project;
use App\Models\Server;
use Livewire\Component;
class Dashboard extends Component
{
public $projects = [];
public $servers = [];
public function mount()
{
$this->servers = Server::ownedByCurrentTeam()->get();
$this->projects = Project::ownedByCurrentTeam()->get();
}
// public function getIptables()
// {
// $servers = Server::ownedByCurrentTeam()->get();
// foreach ($servers as $server) {
// checkRequiredCommands($server);
// $iptables = instant_remote_process(['docker run --privileged --net=host --pid=host --ipc=host --volume /:/host busybox chroot /host bash -c "iptables -L -n | jc --iptables"'], $server);
// ray($iptables);
// }
// }
public function render()
{
return view('livewire.dashboard');
}
}

View File

@@ -1,44 +0,0 @@
<?php
namespace App\Http\Livewire\Destination;
use Livewire\Component;
class Form extends Component
{
public mixed $destination;
protected $rules = [
'destination.name' => 'required',
'destination.network' => 'required',
'destination.server.ip' => 'required',
];
protected $validationAttributes = [
'destination.name' => 'name',
'destination.network' => 'network',
'destination.server.ip' => 'IP Address/Domain',
];
public function submit()
{
$this->validate();
$this->destination->save();
}
public function delete()
{
try {
if ($this->destination->getMorphClass() === 'App\Models\StandaloneDocker') {
if ($this->destination->attachedTo()) {
return $this->emit('error', 'You must delete all resources before deleting this destination.');
}
instant_remote_process(["docker network disconnect {$this->destination->network} coolify-proxy"], $this->destination->server, throwError: false);
instant_remote_process(['docker network rm -f ' . $this->destination->network], $this->destination->server);
}
$this->destination->delete();
return redirect()->route('dashboard');
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
}

View File

@@ -1,84 +0,0 @@
<?php
namespace App\Http\Livewire\Destination\New;
use App\Models\Server;
use App\Models\StandaloneDocker as ModelsStandaloneDocker;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Str;
use Livewire\Component;
use Visus\Cuid2\Cuid2;
class StandaloneDocker extends Component
{
public string $name;
public string $network;
public Collection $servers;
public Server $server;
public int|null $server_id = null;
protected $rules = [
'name' => 'required|string',
'network' => 'required|string',
'server_id' => 'required|integer'
];
protected $validationAttributes = [
'name' => 'name',
'network' => 'network',
'server_id' => 'server'
];
public function mount()
{
if (request()->query('server_id')) {
$this->server_id = request()->query('server_id');
} else {
if ($this->servers->count() > 0) {
$this->server_id = $this->servers->first()->id;
}
}
if (request()->query('network_name')) {
$this->network = request()->query('network_name');
} else {
$this->network = new Cuid2(7);
}
$this->name = Str::kebab("{$this->servers->first()->name}-{$this->network}");
}
public function generate_name()
{
$this->server = Server::find($this->server_id);
$this->name = Str::kebab("{$this->server->name}-{$this->network}");
}
public function submit()
{
$this->validate();
try {
$this->server = Server::find($this->server_id);
$found = $this->server->standaloneDockers()->where('network', $this->network)->first();
if ($found) {
$this->createNetworkAndAttachToProxy();
$this->emit('error', 'Network already added to this server.');
return;
} else {
$docker = ModelsStandaloneDocker::create([
'name' => $this->name,
'network' => $this->network,
'server_id' => $this->server_id,
]);
}
$this->createNetworkAndAttachToProxy();
return redirect()->route('destination.show', $docker->uuid);
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
private function createNetworkAndAttachToProxy()
{
$connectProxyToDockerNetworks = connectProxyToNetworks($this->server);
instant_remote_process($connectProxyToDockerNetworks, $this->server, false);
}
}

View File

@@ -1,27 +0,0 @@
<?php
namespace App\Http\Livewire\Destination;
use App\Models\Server;
use Illuminate\Support\Collection;
use Livewire\Component;
class Show extends Component
{
public Server $server;
public Collection|array $networks = [];
public function scan()
{
$alreadyAddedNetworks = $this->server->standaloneDockers;
$networks = instant_remote_process(['docker network ls --format "{{json .}}"'], $this->server, false);
$this->networks = format_docker_command_output_to_json($networks)->filter(function ($network) {
return $network['Name'] !== 'bridge' && $network['Name'] !== 'host' && $network['Name'] !== 'none';
})->filter(function ($network) use ($alreadyAddedNetworks) {
return !$alreadyAddedNetworks->contains('network', $network['Name']);
});
if ($this->networks->count() === 0) {
$this->emit('success', 'No new networks found.');
}
}
}

View File

@@ -1,28 +0,0 @@
<?php
namespace App\Http\Livewire\Dev;
use Livewire\Component;
class Compose extends Component
{
public string $compose = '';
public string $base64 = '';
public $services;
public function mount() {
$this->services = getServiceTemplates();
}
public function setService(string $selected) {
$this->base64 = data_get($this->services, $selected . '.compose');
if ($this->base64) {
$this->compose = base64_decode($this->base64);
}
}
public function updatedCompose($value) {
$this->base64 = base64_encode($value);
}
public function render()
{
return view('livewire.dev.compose');
}
}

View File

@@ -1,43 +0,0 @@
<?php
namespace App\Http\Livewire;
use Illuminate\Support\Facades\Hash;
use DanHarrin\LivewireRateLimiting\WithRateLimiting;
use Livewire\Component;
class ForcePasswordReset extends Component
{
use WithRateLimiting;
public string $email;
public string $password;
public string $password_confirmation;
protected $rules = [
'email' => 'required|email',
'password' => 'required|min:8',
'password_confirmation' => 'required|same:password',
];
public function mount()
{
$this->email = auth()->user()->email;
}
public function submit()
{
try {
$this->rateLimit(10);
$this->validate();
$firstLogin = auth()->user()->created_at == auth()->user()->updated_at;
auth()->user()->forceFill([
'password' => Hash::make($this->password),
'force_password_reset' => false,
])->save();
if ($firstLogin) {
send_internal_notification('First login for ' . auth()->user()->email);
}
return redirect()->route('dashboard');
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
}

View File

@@ -1,54 +0,0 @@
<?php
namespace App\Http\Livewire;
use DanHarrin\LivewireRateLimiting\WithRateLimiting;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Support\Facades\Route;
use Livewire\Component;
class Help extends Component
{
use WithRateLimiting;
public string $description;
public string $subject;
public ?string $path = null;
protected $rules = [
'description' => 'required|min:10',
'subject' => 'required|min:3'
];
public function mount()
{
$this->path = Route::current()?->uri() ?? null;
if (isDev()) {
$this->description = "I'm having trouble with {$this->path}";
$this->subject = "Help with {$this->path}";
}
}
public function submit()
{
try {
$this->rateLimit(3, 60);
$this->validate();
$subscriptionType = auth()->user()?->subscription?->type() ?? 'Free';
$debug = "Route: {$this->path}";
$mail = new MailMessage();
$mail->view(
'emails.help',
[
'description' => $this->description,
'debug' => $debug
]
);
$mail->subject("[HELP - {$subscriptionType}]: {$this->subject}");
send_user_an_email($mail, auth()->user()?->email, 'hi@coollabs.io');
$this->emit('success', 'Your message has been sent successfully. <br>We will get in touch with you as soon as possible.');
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function render()
{
return view('livewire.help')->layout('layouts.app');
}
}

View File

@@ -1,29 +0,0 @@
<?php
namespace App\Http\Livewire\Modal;
use App\Models\Service;
use Livewire\Component;
use LivewireUI\Modal\ModalComponent;
class EditCompose extends ModalComponent
{
public Service $service;
public $serviceId;
protected $rules = [
'service.docker_compose_raw' => 'required',
'service.docker_compose' => 'required',
];
public function mount() {
$this->service = Service::find($this->serviceId);
}
public function render()
{
return view('livewire.modal.edit-compose');
}
public function submit() {
$this->emit('warning', "Saving new docker compose...");
$this->emit('saveCompose', $this->service->docker_compose_raw);
$this->closeModal();
}
}

View File

@@ -1,58 +0,0 @@
<?php
namespace App\Http\Livewire\Notifications;
use App\Models\Team;
use App\Notifications\Test;
use Livewire\Component;
class DiscordSettings extends Component
{
public Team $team;
protected $rules = [
'team.discord_enabled' => 'nullable|boolean',
'team.discord_webhook_url' => 'required|url',
'team.discord_notifications_test' => 'nullable|boolean',
'team.discord_notifications_deployments' => 'nullable|boolean',
'team.discord_notifications_status_changes' => 'nullable|boolean',
'team.discord_notifications_database_backups' => 'nullable|boolean',
];
protected $validationAttributes = [
'team.discord_webhook_url' => 'Discord Webhook',
];
public function mount()
{
$this->team = auth()->user()->currentTeam();
}
public function instantSave()
{
try {
$this->submit();
} catch (\Throwable $e) {
ray($e->getMessage());
$this->team->discord_enabled = false;
$this->validate();
}
}
public function submit()
{
$this->resetErrorBag();
$this->validate();
$this->saveModel();
}
public function saveModel()
{
$this->team->save();
refreshSession();
$this->emit('success', 'Settings saved.');
}
public function sendTestNotification()
{
$this->team->notify(new Test());
$this->emit('success', 'Test notification sent.');
}
}

View File

@@ -1,192 +0,0 @@
<?php
namespace App\Http\Livewire\Notifications;
use App\Models\InstanceSettings;
use App\Models\Team;
use App\Notifications\Test;
use Livewire\Component;
use Log;
class EmailSettings extends Component
{
public Team $team;
public string $emails;
public bool $sharedEmailEnabled = false;
protected $rules = [
'team.smtp_enabled' => 'nullable|boolean',
'team.smtp_from_address' => 'required|email',
'team.smtp_from_name' => 'required',
'team.smtp_recipients' => 'nullable',
'team.smtp_host' => 'required',
'team.smtp_port' => 'required',
'team.smtp_encryption' => 'nullable',
'team.smtp_username' => 'nullable',
'team.smtp_password' => 'nullable',
'team.smtp_timeout' => 'nullable',
'team.smtp_notifications_test' => 'nullable|boolean',
'team.smtp_notifications_deployments' => 'nullable|boolean',
'team.smtp_notifications_status_changes' => 'nullable|boolean',
'team.smtp_notifications_database_backups' => 'nullable|boolean',
'team.use_instance_email_settings' => 'boolean',
'team.resend_enabled' => 'nullable|boolean',
'team.resend_api_key' => 'nullable',
];
protected $validationAttributes = [
'team.smtp_from_address' => 'From Address',
'team.smtp_from_name' => 'From Name',
'team.smtp_recipients' => 'Recipients',
'team.smtp_host' => 'Host',
'team.smtp_port' => 'Port',
'team.smtp_encryption' => 'Encryption',
'team.smtp_username' => 'Username',
'team.smtp_password' => 'Password',
'team.smtp_timeout' => 'Timeout',
'team.resend_enabled' => 'Resend Enabled',
'team.resend_api_key' => 'Resend API Key',
];
public function mount()
{
$this->team = auth()->user()->currentTeam();
['sharedEmailEnabled' => $this->sharedEmailEnabled] = $this->team->limits;
$this->emails = auth()->user()->email;
}
public function submitFromFields()
{
try {
$this->resetErrorBag();
$this->validate([
'team.smtp_from_address' => 'required|email',
'team.smtp_from_name' => 'required',
]);
$this->team->save();
refreshSession();
$this->emit('success', 'Settings saved successfully.');
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function sendTestNotification()
{
$this->team->notify(new Test($this->emails));
$this->emit('success', 'Test Email sent successfully.');
}
public function instantSaveInstance()
{
try {
if (!$this->sharedEmailEnabled) {
throw new \Exception('Not allowed to change settings. Please upgrade your subscription.');
}
$this->team->smtp_enabled = false;
$this->team->resend_enabled = false;
$this->team->save();
refreshSession();
$this->emit('success', 'Settings saved successfully.');
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function instantSaveResend()
{
try {
$this->team->smtp_enabled = false;
$this->submitResend();
} catch (\Throwable $e) {
$this->team->smtp_enabled = false;
return handleError($e, $this);
}
}
public function instantSave()
{
try {
$this->team->resend_enabled = false;
$this->submit();
} catch (\Throwable $e) {
$this->team->smtp_enabled = false;
return handleError($e, $this);
}
}
public function saveModel()
{
$this->team->save();
refreshSession();
$this->emit('success', 'Settings saved.');
}
public function submit()
{
try {
$this->resetErrorBag();
$this->validate([
'team.smtp_from_address' => 'required|email',
'team.smtp_from_name' => 'required',
'team.smtp_host' => 'required',
'team.smtp_port' => 'required|numeric',
'team.smtp_encryption' => 'nullable',
'team.smtp_username' => 'nullable',
'team.smtp_password' => 'nullable',
'team.smtp_timeout' => 'nullable',
]);
$this->team->save();
refreshSession();
$this->emit('success', 'Settings saved successfully.');
} catch (\Throwable $e) {
$this->team->smtp_enabled = false;
return handleError($e, $this);
}
}
public function submitResend()
{
try {
$this->resetErrorBag();
$this->validate([
'team.smtp_from_address' => 'required|email',
'team.smtp_from_name' => 'required',
'team.resend_api_key' => 'required'
]);
$this->team->save();
refreshSession();
$this->emit('success', 'Settings saved successfully.');
} catch (\Throwable $e) {
$this->team->resend_enabled = false;
return handleError($e, $this);
}
}
public function copyFromInstanceSettings()
{
$settings = InstanceSettings::get();
if ($settings->smtp_enabled) {
$team = currentTeam();
$team->update([
'smtp_enabled' => $settings->smtp_enabled,
'smtp_from_address' => $settings->smtp_from_address,
'smtp_from_name' => $settings->smtp_from_name,
'smtp_recipients' => $settings->smtp_recipients,
'smtp_host' => $settings->smtp_host,
'smtp_port' => $settings->smtp_port,
'smtp_encryption' => $settings->smtp_encryption,
'smtp_username' => $settings->smtp_username,
'smtp_password' => $settings->smtp_password,
'smtp_timeout' => $settings->smtp_timeout,
]);
refreshSession();
$this->team = $team;
$this->emit('success', 'Settings saved.');
return;
}
if ($settings->resend_enabled) {
$team = currentTeam();
$team->update([
'resend_enabled' => $settings->resend_enabled,
'resend_api_key' => $settings->resend_api_key,
]);
refreshSession();
$this->team = $team;
$this->emit('success', 'Settings saved.');
return;
}
$this->emit('error', 'Instance SMTP/Resend settings are not enabled.');
}
}

View File

@@ -1,64 +0,0 @@
<?php
namespace App\Http\Livewire\Notifications;
use App\Models\Team;
use App\Notifications\Test;
use Livewire\Component;
class TelegramSettings extends Component
{
public Team $team;
protected $rules = [
'team.telegram_enabled' => 'nullable|boolean',
'team.telegram_token' => 'required|string',
'team.telegram_chat_id' => 'required|string',
'team.telegram_notifications_test' => 'nullable|boolean',
'team.telegram_notifications_deployments' => 'nullable|boolean',
'team.telegram_notifications_status_changes' => 'nullable|boolean',
'team.telegram_notifications_database_backups' => 'nullable|boolean',
'team.telegram_notifications_test_message_thread_id' => 'nullable|string',
'team.telegram_notifications_deployments_message_thread_id' => 'nullable|string',
'team.telegram_notifications_status_changes_message_thread_id' => 'nullable|string',
'team.telegram_notifications_database_backups_message_thread_id' => 'nullable|string',
];
protected $validationAttributes = [
'team.telegram_token' => 'Token',
'team.telegram_chat_id' => 'Chat ID',
];
public function mount()
{
$this->team = auth()->user()->currentTeam();
}
public function instantSave()
{
try {
$this->submit();
} catch (\Throwable $e) {
ray($e->getMessage());
$this->team->telegram_enabled = false;
$this->validate();
}
}
public function submit()
{
$this->resetErrorBag();
$this->validate();
$this->saveModel();
}
public function saveModel()
{
$this->team->save();
refreshSession();
$this->emit('success', 'Settings saved.');
}
public function sendTestNotification()
{
$this->team->notify(new Test());
$this->emit('success', 'Test notification sent.');
}
}

View File

@@ -1,56 +0,0 @@
<?php
namespace App\Http\Livewire\PrivateKey;
use App\Models\PrivateKey;
use Livewire\Component;
class Change extends Component
{
public PrivateKey $private_key;
public $public_key;
protected $rules = [
'private_key.name' => 'required|string',
'private_key.description' => 'nullable|string',
'private_key.private_key' => 'required|string',
'private_key.is_git_related' => 'nullable|boolean'
];
protected $validationAttributes = [
'private_key.name' => 'name',
'private_key.description' => 'description',
'private_key.private_key' => 'private key'
];
public function mount()
{
try {
$this->public_key = $this->private_key->publicKey();
}catch(\Throwable $e) {
return handleError($e, $this);
}
}
public function delete()
{
try {
if ($this->private_key->isEmpty()) {
$this->private_key->delete();
currentTeam()->privateKeys = PrivateKey::where('team_id', currentTeam()->id)->get();
return redirect()->route('security.private-key.index');
}
$this->emit('error', 'This private key is in use and cannot be deleted. Please delete all servers, applications, and GitHub/GitLab apps that use this private key before deleting it.');
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function changePrivateKey()
{
try {
$this->private_key->private_key = formatPrivateKey($this->private_key->private_key);
$this->private_key->save();
refresh_server_connection($this->private_key);
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
}

View File

@@ -1,77 +0,0 @@
<?php
namespace App\Http\Livewire\PrivateKey;
use App\Models\PrivateKey;
use DanHarrin\LivewireRateLimiting\WithRateLimiting;
use Livewire\Component;
use phpseclib3\Crypt\PublicKeyLoader;
class Create extends Component
{
use WithRateLimiting;
public string $name;
public string $value;
public ?string $from = null;
public ?string $description = null;
public ?string $publicKey = null;
protected $rules = [
'name' => 'required|string',
'value' => 'required|string',
];
protected $validationAttributes = [
'name' => 'name',
'value' => 'private Key',
];
public function generateNewKey()
{
try {
$this->rateLimit(10);
$this->name = generate_random_name();
$this->description = 'Created by Coolify';
['private' => $this->value, 'public' => $this->publicKey] = generateSSHKey();
} catch(\Throwable $e) {
return handleError($e, $this);
}
}
public function updated($updateProperty)
{
if ($updateProperty === 'value') {
try {
$this->publicKey = PublicKeyLoader::load($this->$updateProperty)->getPublicKey()->toString('OpenSSH',['comment' => '']);
} catch (\Throwable $e) {
if ($this->$updateProperty === "") {
$this->publicKey = "";
} else {
$this->publicKey = "Invalid private key";
}
}
}
$this->validateOnly($updateProperty);
}
public function createPrivateKey()
{
$this->validate();
try {
$this->value = trim($this->value);
if (!str_ends_with($this->value, "\n")) {
$this->value .= "\n";
}
$private_key = PrivateKey::create([
'name' => $this->name,
'description' => $this->description,
'private_key' => $this->value,
'team_id' => currentTeam()->id
]);
if ($this->from === 'server') {
return redirect()->route('server.create');
}
return redirect()->route('security.private-key.show', ['private_key_uuid' => $private_key->uuid]);
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
}

View File

@@ -1,40 +0,0 @@
<?php
namespace App\Http\Livewire\Profile;
use App\Models\User;
use Livewire\Component;
class Form extends Component
{
public int $userId;
public string $name;
public string $email;
protected $rules = [
'name' => 'required',
];
protected $validationAttributes = [
'name' => 'name',
];
public function mount()
{
$this->userId = auth()->user()->id;
$this->name = auth()->user()->name;
$this->email = auth()->user()->email;
}
public function submit()
{
try {
$this->validate();
User::where('id', $this->userId)->update([
'name' => $this->name,
]);
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
}

View File

@@ -1,37 +0,0 @@
<?php
namespace App\Http\Livewire\Project;
use App\Models\Project;
use Livewire\Component;
class AddEmpty extends Component
{
public string $name = '';
public string $description = '';
protected $rules = [
'name' => 'required|string|min:3',
'description' => 'nullable|string',
];
protected $validationAttributes = [
'name' => 'Project Name',
'description' => 'Project Description',
];
public function submit()
{
try {
$this->validate();
$project = Project::create([
'name' => $this->name,
'description' => $this->description,
'team_id' => currentTeam()->id,
]);
return redirect()->route('project.show', $project->uuid);
} catch (\Throwable $e) {
return handleError($e, $this);
} finally {
$this->name = '';
}
}
}

View File

@@ -1,40 +0,0 @@
<?php
namespace App\Http\Livewire\Project;
use App\Models\Environment;
use App\Models\Project;
use Livewire\Component;
class AddEnvironment extends Component
{
public Project $project;
public string $name = '';
public string $description = '';
protected $rules = [
'name' => 'required|string|min:3',
];
protected $validationAttributes = [
'name' => 'Environment Name',
];
public function submit()
{
try {
$this->validate();
$environment = Environment::create([
'name' => $this->name,
'project_id' => $this->project->id,
]);
return redirect()->route('project.resources', [
'project_uuid' => $this->project->uuid,
'environment_name' => $environment->name,
]);
} catch (\Throwable $e) {
handleError($e, $this);
} finally {
$this->name = '';
}
}
}

View File

@@ -1,54 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Application;
use App\Models\Application;
use Livewire\Component;
class Advanced extends Component
{
public Application $application;
protected $rules = [
'application.settings.is_git_submodules_enabled' => 'boolean|required',
'application.settings.is_git_lfs_enabled' => 'boolean|required',
'application.settings.is_preview_deployments_enabled' => 'boolean|required',
'application.settings.is_auto_deploy_enabled' => 'boolean|required',
'application.settings.is_force_https_enabled' => 'boolean|required',
'application.settings.is_log_drain_enabled' => 'boolean|required',
'application.settings.is_gpu_enabled' => 'boolean|required',
'application.settings.gpu_driver' => 'string|required',
'application.settings.gpu_count' => 'string|required',
'application.settings.gpu_device_ids' => 'string|required',
'application.settings.gpu_options' => 'string|required',
];
public function instantSave()
{
if ($this->application->isLogDrainEnabled()) {
if (!$this->application->destination->server->isLogDrainEnabled()) {
$this->application->settings->is_log_drain_enabled = false;
$this->emit('error', 'Log drain is not enabled on this server.');
return;
}
}
if ($this->application->settings->is_force_https_enabled) {
$this->emit('resetDefaultLabels', false);
}
$this->application->settings->save();
$this->emit('success', 'Settings saved.');
}
public function submit() {
if ($this->application->settings->gpu_count && $this->application->settings->gpu_device_ids) {
$this->emit('error', 'You cannot set both GPU count and GPU device IDs.');
$this->application->settings->gpu_count = null;
$this->application->settings->gpu_device_ids = null;
$this->application->settings->save();
return;
}
$this->application->settings->save();
$this->emit('success', 'Settings saved.');
}
public function render()
{
return view('livewire.project.application.advanced');
}
}

View File

@@ -1,110 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Application;
use App\Models\Application;
use App\Models\Server;
use App\Models\Service;
use App\Models\StandaloneMariadb;
use App\Models\StandaloneMongodb;
use App\Models\StandaloneMysql;
use App\Models\StandalonePostgresql;
use App\Models\StandaloneRedis;
use Livewire\Component;
class Command extends Component
{
public string $command;
public string $container;
public $containers;
public $parameters;
public $resource;
public string $type;
public string $workDir = '';
public Server $server;
public $servers = [];
protected $rules = [
'server' => 'required',
'container' => 'required',
'command' => 'required',
'workDir' => 'nullable',
];
public function mount()
{
$this->containers = collect();
$this->parameters = get_route_parameters();
if (data_get($this->parameters, 'application_uuid')) {
$this->type = 'application';
$this->resource = Application::where('uuid', $this->parameters['application_uuid'])->firstOrFail();
$this->server = $this->resource->destination->server;
$containers = getCurrentApplicationContainerStatus($this->server, $this->resource->id, 0);
if ($containers->count() > 0) {
$containers->each(function ($container) {
$this->containers->push(str_replace('/', '', $container['Names']));
});
}
} else if (data_get($this->parameters, 'database_uuid')) {
$this->type = 'database';
$resource = StandalonePostgresql::where('uuid', $this->parameters['database_uuid'])->first();
if (is_null($resource)) {
$resource = StandaloneRedis::where('uuid', $this->parameters['database_uuid'])->first();
if (is_null($resource)) {
$resource = StandaloneMongodb::where('uuid', $this->parameters['database_uuid'])->first();
if (is_null($resource)) {
$resource = StandaloneMysql::where('uuid', $this->parameters['database_uuid'])->first();
if (is_null($resource)) {
$resource = StandaloneMariadb::where('uuid', $this->parameters['database_uuid'])->first();
if (is_null($resource)) {
abort(404);
}
}
}
}
}
$this->resource = $resource;
$this->server = $this->resource->destination->server;
$this->container = $this->resource->uuid;
$this->containers->push($this->container);
} else if (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) {
if (str(data_get($application, 'status'))->contains('running')) {
$this->containers->push(data_get($application, 'name') . '-' . data_get($this->resource, 'uuid'));
}
});
$this->resource->databases()->get()->each(function ($database) {
if (str(data_get($database, 'status'))->contains('running')) {
$this->containers->push(data_get($database, 'name') . '-' . data_get($this->resource, 'uuid'));
}
});
$this->server = $this->resource->server;
}
if ($this->containers->count() > 1) {
$this->container = $this->containers->first();
}
}
public function runCommand()
{
$this->validate();
try {
if (!empty($this->workDir)) {
$exec = "docker exec -w {$this->workDir} {$this->container} {$this->command}";
} else {
$exec = "docker exec {$this->container} {$this->command}";
}
$activity = remote_process([$exec], $this->server, ignore_errors: true);
$this->emit('newMonitorActivity', $activity->id);
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function render()
{
return view('livewire.project.shared.execute-container-command');
}
}

View File

@@ -1,39 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Application;
use App\Models\Application;
use App\Models\Server;
use App\Models\StandaloneDocker;
use Livewire\Component;
class Configuration extends Component
{
public Application $application;
public $servers;
public function mount()
{
$project = currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
if (!$project) {
return redirect()->route('dashboard');
}
$environment = $project->load(['environments'])->environments->where('name', request()->route('environment_name'))->first()->load(['applications']);
if (!$environment) {
return redirect()->route('dashboard');
}
$application = $environment->applications->where('uuid', request()->route('application_uuid'))->first();
if (!$application) {
return redirect()->route('dashboard');
}
$this->application = $application;
$mainServer = $this->application->destination->server;
$servers = Server::ownedByCurrentTeam()->get();
$this->servers = $servers->filter(function ($server) use ($mainServer) {
return $server->id != $mainServer->id;
});
}
public function render()
{
return view('livewire.project.application.configuration');
}
}

View File

@@ -1,27 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Application;
use App\Models\ApplicationDeploymentQueue;
use Livewire\Component;
class DeploymentLogs extends Component
{
public ApplicationDeploymentQueue $application_deployment_queue;
public $isKeepAliveOn = true;
protected $listeners = ['refreshQueue'];
public function refreshQueue()
{
$this->application_deployment_queue->refresh();
}
public function polling()
{
$this->emit('deploymentFinished');
$this->application_deployment_queue->refresh();
if (data_get($this->application_deployment_queue, 'status') == 'finished' || data_get($this->application_deployment_queue, 'status') == 'failed') {
$this->isKeepAliveOn = false;
}
}
}

View File

@@ -1,74 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Application;
use App\Enums\ApplicationDeploymentStatus;
use App\Models\Application;
use App\Models\ApplicationDeploymentQueue;
use App\Models\Server;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Process;
use Illuminate\Support\Str;
use Livewire\Component;
class DeploymentNavbar extends Component
{
public ApplicationDeploymentQueue $application_deployment_queue;
public Application $application;
public Server $server;
public bool $is_debug_enabled = false;
protected $listeners = ['deploymentFinished'];
public function mount()
{
$this->application = Application::find($this->application_deployment_queue->application_id);
$this->server = $this->application->destination->server;
$this->is_debug_enabled = $this->application->settings->is_debug_enabled;
}
public function deploymentFinished()
{
$this->application_deployment_queue->refresh();
}
public function show_debug()
{
$this->application->settings->is_debug_enabled = !$this->application->settings->is_debug_enabled;
$this->application->settings->save();
$this->is_debug_enabled = $this->application->settings->is_debug_enabled;
$this->emit('refreshQueue');
}
public function cancel()
{
try {
$kill_command = "kill -9 {$this->application_deployment_queue->current_process_id}";
if ($this->application_deployment_queue->current_process_id) {
$process = Process::run("ps -p {$this->application_deployment_queue->current_process_id} -o command --no-headers");
if (Str::of($process->output())->contains([$this->server->ip, 'EOF-COOLIFY-SSH'])) {
Process::run($kill_command);
}
$previous_logs = json_decode($this->application_deployment_queue->logs, associative: true, flags: JSON_THROW_ON_ERROR);
$new_log_entry = [
'command' => $kill_command,
'output' => "Deployment cancelled by user.",
'type' => 'stderr',
'order' => count($previous_logs) + 1,
'timestamp' => Carbon::now('UTC'),
'hidden' => false,
];
$previous_logs[] = $new_log_entry;
$this->application_deployment_queue->update([
'logs' => json_encode($previous_logs, flags: JSON_THROW_ON_ERROR),
]);
}
} catch (\Throwable $e) {
return handleError($e, $this);
} finally {
$this->application_deployment_queue->update([
'current_process_id' => null,
'status' => ApplicationDeploymentStatus::CANCELLED_BY_USER->value,
]);
queue_next_deployment($this->application);
}
}
}

View File

@@ -1,60 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Application;
use App\Models\Application;
use Illuminate\Support\Collection;
use Livewire\Component;
class Deployments extends Component
{
public Application $application;
public Array|Collection $deployments = [];
public int $deployments_count = 0;
public string $current_url;
public int $skip = 0;
public int $default_take = 40;
public bool $show_next = false;
public ?string $pull_request_id = null;
protected $queryString = ['pull_request_id'];
public function mount()
{
$this->current_url = url()->current();
$this->show_pull_request_only();
$this->show_more();
}
private function show_pull_request_only() {
if ($this->pull_request_id) {
$this->deployments = $this->deployments->where('pull_request_id', $this->pull_request_id);
}
}
private function show_more()
{
if (count($this->deployments) !== 0) {
$this->show_next = true;
if (count($this->deployments) < $this->default_take) {
$this->show_next = false;
}
return;
}
}
public function reload_deployments()
{
$this->load_deployments();
}
public function load_deployments(int|null $take = null)
{
if ($take) {
$this->skip = $this->skip + $take;
}
$take = $this->default_take;
['deployments' => $deployments, 'count' => $count] = $this->application->deployments($this->skip, $take);
$this->deployments = $deployments;
$this->deployments_count = $count;
$this->show_pull_request_only();
$this->show_more();
}
}

View File

@@ -1,252 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Application;
use App\Models\Application;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
use Livewire\Component;
use Visus\Cuid2\Cuid2;
class General extends Component
{
public string $applicationId;
public Application $application;
public Collection $services;
public string $name;
public ?string $fqdn = null;
public string $git_repository;
public string $git_branch;
public ?string $git_commit_sha = null;
public string $build_pack;
public ?string $ports_exposes = null;
public $customLabels;
public bool $labelsChanged = false;
public bool $isConfigurationChanged = false;
public ?string $initialDockerComposeLocation = null;
public ?string $initialDockerComposePrLocation = null;
public $parsedServices = [];
public $parsedServiceDomains = [];
protected $listeners = [
'resetDefaultLabels'
];
protected $rules = [
'application.name' => 'required',
'application.description' => 'nullable',
'application.fqdn' => 'nullable',
'application.git_repository' => 'required',
'application.git_branch' => 'required',
'application.git_commit_sha' => 'nullable',
'application.install_command' => 'nullable',
'application.build_command' => 'nullable',
'application.start_command' => 'nullable',
'application.build_pack' => 'required',
'application.static_image' => 'required',
'application.base_directory' => 'required',
'application.publish_directory' => 'nullable',
'application.ports_exposes' => 'required',
'application.ports_mappings' => 'nullable',
'application.dockerfile' => 'nullable',
'application.docker_registry_image_name' => 'nullable',
'application.docker_registry_image_tag' => 'nullable',
'application.dockerfile_location' => 'nullable',
'application.docker_compose_location' => 'nullable',
'application.docker_compose_pr_location' => 'nullable',
'application.docker_compose' => 'nullable',
'application.docker_compose_pr' => 'nullable',
'application.docker_compose_raw' => 'nullable',
'application.docker_compose_pr_raw' => 'nullable',
'application.custom_labels' => 'nullable',
'application.dockerfile_target_build' => 'nullable',
'application.settings.is_static' => 'boolean|required',
];
protected $validationAttributes = [
'application.name' => 'name',
'application.description' => 'description',
'application.fqdn' => 'FQDN',
'application.git_repository' => 'Git repository',
'application.git_branch' => 'Git branch',
'application.git_commit_sha' => 'Git commit SHA',
'application.install_command' => 'Install command',
'application.build_command' => 'Build command',
'application.start_command' => 'Start command',
'application.build_pack' => 'Build pack',
'application.static_image' => 'Static image',
'application.base_directory' => 'Base directory',
'application.publish_directory' => 'Publish directory',
'application.ports_exposes' => 'Ports exposes',
'application.ports_mappings' => 'Ports mappings',
'application.dockerfile' => 'Dockerfile',
'application.docker_registry_image_name' => 'Docker registry image name',
'application.docker_registry_image_tag' => 'Docker registry image tag',
'application.dockerfile_location' => 'Dockerfile location',
'application.docker_compose_location' => 'Docker compose location',
'application.docker_compose_pr_location' => 'Docker compose location',
'application.docker_compose' => 'Docker compose',
'application.docker_compose_pr' => 'Docker compose',
'application.docker_compose_raw' => 'Docker compose raw',
'application.docker_compose_pr_raw' => 'Docker compose raw',
'application.custom_labels' => 'Custom labels',
'application.dockerfile_target_build' => 'Dockerfile target build',
'application.settings.is_static' => 'Is static',
];
public function mount()
{
try {
$this->parsedServices = $this->application->parseCompose();
} catch (\Throwable $e) {
$this->emit('error', $e->getMessage());
}
$this->parsedServiceDomains = $this->application->docker_compose_domains ? json_decode($this->application->docker_compose_domains, true) : [];
$this->ports_exposes = $this->application->ports_exposes;
if (str($this->application->status)->startsWith('running') && is_null($this->application->config_hash)) {
$this->application->isConfigurationChanged(true);
}
$this->isConfigurationChanged = $this->application->isConfigurationChanged();
if (is_null(data_get($this->application, 'custom_labels'))) {
$this->customLabels = str(implode(",", generateLabelsApplication($this->application)))->replace(',', "\n");
} else {
$this->customLabels = str($this->application->custom_labels)->replace(',', "\n");
}
$this->initialDockerComposeLocation = $this->application->docker_compose_location;
$this->checkLabelUpdates();
}
public function instantSave()
{
$this->application->settings->save();
$this->emit('success', 'Settings saved.');
$this->application->refresh();
if ($this->ports_exposes !== $this->application->ports_exposes) {
$this->resetDefaultLabels(false);
}
}
public function loadComposeFile($isInit = false)
{
try {
if ($isInit && $this->application->docker_compose_raw) {
return;
}
['parsedServices' => $this->parsedServices, 'initialDockerComposeLocation' => $this->initialDockerComposeLocation, 'initialDockerComposePrLocation' => $this->initialDockerComposePrLocation] = $this->application->loadComposeFile($isInit);
$this->emit('success', 'Docker compose file loaded.');
} catch (\Throwable $e) {
$this->application->docker_compose_location = $this->initialDockerComposeLocation;
$this->application->docker_compose_pr_location = $this->initialDockerComposePrLocation;
$this->application->save();
return handleError($e, $this);
}
}
public function generateDomain(string $serviceName)
{
$domain = $this->parsedServiceDomains[$serviceName]['domain'] ?? null;
if (!$domain) {
$uuid = new Cuid2(7);
$domain = generateFqdn($this->application->destination->server, $uuid);
$this->parsedServiceDomains[$serviceName]['domain'] = $domain;
$this->application->docker_compose_domains = json_encode($this->parsedServiceDomains);
$this->application->save();
$this->emit('success', 'Domain generated.');
}
return $domain;
}
public function updatedApplicationBuildPack()
{
if ($this->application->build_pack !== 'nixpacks') {
$this->application->settings->is_static = false;
$this->application->settings->save();
}
if ($this->application->build_pack === 'dockercompose') {
$this->application->fqdn = null;
$this->application->settings->save();
}
$this->submit();
}
public function checkLabelUpdates()
{
if (md5($this->application->custom_labels) !== md5(implode(",", generateLabelsApplication($this->application)))) {
$this->labelsChanged = true;
} else {
$this->labelsChanged = false;
}
}
public function getWildcardDomain()
{
$server = data_get($this->application, 'destination.server');
if ($server) {
$fqdn = generateFqdn($server, $this->application->uuid);
$this->application->fqdn = $fqdn;
$this->application->save();
$this->updatedApplicationFqdn();
}
}
public function resetDefaultLabels($showToaster = true)
{
$this->customLabels = str(implode(",", generateLabelsApplication($this->application)))->replace(',', "\n");
$this->ports_exposes = $this->application->ports_exposes;
$this->submit($showToaster);
}
public function updatedApplicationFqdn()
{
$this->resetDefaultLabels(false);
$this->emit('success', 'Labels reseted to default!');
}
public function submit($showToaster = true)
{
try {
if ($this->application->build_pack === 'dockercompose' && ($this->initialDockerComposeLocation !== $this->application->docker_compose_location || $this->initialDockerComposePrLocation !== $this->application->docker_compose_pr_location)) {
$this->loadComposeFile();
}
$this->validate();
if ($this->ports_exposes !== $this->application->ports_exposes) {
$this->resetDefaultLabels(false);
}
if (data_get($this->application, 'build_pack') === 'dockerimage') {
$this->validate([
'application.docker_registry_image_name' => 'required',
'application.docker_registry_image_tag' => 'required',
]);
}
if (data_get($this->application, 'fqdn')) {
$domains = Str::of($this->application->fqdn)->trim()->explode(',')->map(function ($domain) {
return Str::of($domain)->trim()->lower();
});
$this->application->fqdn = $domains->implode(',');
}
if (data_get($this->application, 'dockerfile')) {
$port = get_port_from_dockerfile($this->application->dockerfile);
if ($port && !$this->application->ports_exposes) {
$this->application->ports_exposes = $port;
}
}
if ($this->application->base_directory && $this->application->base_directory !== '/') {
$this->application->base_directory = rtrim($this->application->base_directory, '/');
}
if ($this->application->publish_directory && $this->application->publish_directory !== '/') {
$this->application->publish_directory = rtrim($this->application->publish_directory, '/');
}
if (gettype($this->customLabels) === 'string') {
$this->customLabels = str($this->customLabels)->replace(',', "\n");
}
$this->application->custom_labels = $this->customLabels->explode("\n")->implode(',');
if ($this->application->build_pack === 'dockercompose') {
$this->application->docker_compose_domains = json_encode($this->parsedServiceDomains);
$this->parsedServices = $this->application->parseCompose();
}
$this->application->save();
$showToaster && $this->emit('success', 'Application settings updated!');
} catch (\Throwable $e) {
return handleError($e, $this);
} finally {
$this->checkLabelUpdates();
$this->isConfigurationChanged = $this->application->isConfigurationChanged();
}
}
}

View File

@@ -1,126 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Application;
use App\Actions\Application\StopApplication;
use App\Jobs\ContainerStatusJob;
use App\Jobs\ServerStatusJob;
use App\Models\Application;
use Livewire\Component;
use Visus\Cuid2\Cuid2;
class Heading extends Component
{
public Application $application;
public array $parameters;
protected string $deploymentUuid;
public function mount()
{
$this->parameters = get_route_parameters();
}
public function check_status()
{
if ($this->application->destination->server->isFunctional()) {
dispatch(new ContainerStatusJob($this->application->destination->server));
$this->application->refresh();
$this->application->previews->each(function ($preview) {
$preview->refresh();
});
} else {
dispatch(new ServerStatusJob($this->application->destination->server));
}
}
public function force_deploy_without_cache()
{
$this->deploy(force_rebuild: true);
}
public function deployNew()
{
if ($this->application->build_pack === 'dockercompose' && is_null($this->application->docker_compose_raw)) {
$this->emit('error', 'Please load a Compose file first.');
return;
}
$this->setDeploymentUuid();
queue_application_deployment(
application_id: $this->application->id,
deployment_uuid: $this->deploymentUuid,
force_rebuild: false,
is_new_deployment: true,
);
return redirect()->route('project.application.deployment', [
'project_uuid' => $this->parameters['project_uuid'],
'application_uuid' => $this->parameters['application_uuid'],
'deployment_uuid' => $this->deploymentUuid,
'environment_name' => $this->parameters['environment_name'],
]);
}
public function deploy(bool $force_rebuild = false)
{
if ($this->application->build_pack === 'dockercompose' && is_null($this->application->docker_compose_raw)) {
$this->emit('error', 'Please load a Compose file first.');
return;
}
$this->setDeploymentUuid();
queue_application_deployment(
application_id: $this->application->id,
deployment_uuid: $this->deploymentUuid,
force_rebuild: $force_rebuild,
);
return redirect()->route('project.application.deployment', [
'project_uuid' => $this->parameters['project_uuid'],
'application_uuid' => $this->parameters['application_uuid'],
'deployment_uuid' => $this->deploymentUuid,
'environment_name' => $this->parameters['environment_name'],
]);
}
protected function setDeploymentUuid()
{
$this->deploymentUuid = new Cuid2(7);
$this->parameters['deployment_uuid'] = $this->deploymentUuid;
}
public function stop()
{
StopApplication::run($this->application);
$this->application->status = 'exited';
$this->application->save();
$this->application->refresh();
}
public function restartNew()
{
$this->setDeploymentUuid();
queue_application_deployment(
application_id: $this->application->id,
deployment_uuid: $this->deploymentUuid,
restart_only: true,
is_new_deployment: true,
);
return redirect()->route('project.application.deployment', [
'project_uuid' => $this->parameters['project_uuid'],
'application_uuid' => $this->parameters['application_uuid'],
'deployment_uuid' => $this->deploymentUuid,
'environment_name' => $this->parameters['environment_name'],
]);
}
public function restart()
{
$this->setDeploymentUuid();
queue_application_deployment(
application_id: $this->application->id,
deployment_uuid: $this->deploymentUuid,
restart_only: true,
);
return redirect()->route('project.application.deployment', [
'project_uuid' => $this->parameters['project_uuid'],
'application_uuid' => $this->parameters['application_uuid'],
'deployment_uuid' => $this->deploymentUuid,
'environment_name' => $this->parameters['environment_name'],
]);
}
}

View File

@@ -1,52 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Application\Preview;
use App\Models\Application;
use Illuminate\Support\Str;
use Livewire\Component;
use Spatie\Url\Url;
class Form extends Component
{
public Application $application;
public string $preview_url_template;
protected $rules = [
'application.preview_url_template' => 'required',
];
protected $validationAttributes = [
'application.preview_url_template' => 'preview url template',
];
public function resetToDefault()
{
$this->application->preview_url_template = '{{pr_id}}.{{domain}}';
$this->preview_url_template = $this->application->preview_url_template;
$this->application->save();
$this->generate_real_url();
}
public function generate_real_url()
{
if (data_get($this->application, 'fqdn')) {
$firstFqdn = Str::of($this->application->fqdn)->before(',');
$url = Url::fromString($firstFqdn);
$host = $url->getHost();
$this->preview_url_template = Str::of($this->application->preview_url_template)->replace('{{domain}}', $host);
}
}
public function mount()
{
$this->generate_real_url();
}
public function submit()
{
$this->validate();
$this->application->preview_url_template = str_replace(' ', '', $this->application->preview_url_template);
$this->application->save();
$this->emit('success', 'Preview url template updated successfully.');
$this->generate_real_url();
}
}

View File

@@ -1,93 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Application;
use App\Models\Application;
use App\Models\ApplicationPreview;
use Illuminate\Support\Collection;
use Livewire\Component;
use Visus\Cuid2\Cuid2;
class Previews extends Component
{
public Application $application;
public string $deployment_uuid;
public array $parameters;
public Collection $pull_requests;
public int $rate_limit_remaining;
public function mount()
{
$this->pull_requests = collect();
$this->parameters = get_route_parameters();
}
public function load_prs()
{
try {
['rate_limit_remaining' => $rate_limit_remaining, 'data' => $data] = githubApi(source: $this->application->source, endpoint: "/repos/{$this->application->git_repository}/pulls");
$this->rate_limit_remaining = $rate_limit_remaining;
$this->pull_requests = $data->sortBy('number')->values();
} catch (\Throwable $e) {
$this->rate_limit_remaining = 0;
return handleError($e, $this);
}
}
public function deploy(int $pull_request_id, string|null $pull_request_html_url = null)
{
try {
$this->setDeploymentUuid();
$found = ApplicationPreview::where('application_id', $this->application->id)->where('pull_request_id', $pull_request_id)->first();
if (!$found && !is_null($pull_request_html_url)) {
ApplicationPreview::create([
'application_id' => $this->application->id,
'pull_request_id' => $pull_request_id,
'pull_request_html_url' => $pull_request_html_url
]);
}
queue_application_deployment(
application_id: $this->application->id,
deployment_uuid: $this->deployment_uuid,
force_rebuild: true,
pull_request_id: $pull_request_id,
);
return redirect()->route('project.application.deployment', [
'project_uuid' => $this->parameters['project_uuid'],
'application_uuid' => $this->parameters['application_uuid'],
'deployment_uuid' => $this->deployment_uuid,
'environment_name' => $this->parameters['environment_name'],
]);
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
protected function setDeploymentUuid()
{
$this->deployment_uuid = new Cuid2(7);
$this->parameters['deployment_uuid'] = $this->deployment_uuid;
}
public function stop(int $pull_request_id)
{
try {
$containers = getCurrentApplicationContainerStatus($this->application->destination->server, $this->application->id, $pull_request_id);
foreach ($containers as $container) {
$name = str_replace('/', '', $container['Names']);
instant_remote_process(["docker rm -f $name"], $this->application->destination->server, throwError: false);
}
ApplicationPreview::where('application_id', $this->application->id)->where('pull_request_id', $pull_request_id)->first()->delete();
$this->application->refresh();
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function previewRefresh()
{
$this->application->previews->each(function ($preview) {
$preview->refresh();
});
}
}

View File

@@ -1,75 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Application;
use App\Models\Application;
use Illuminate\Support\Str;
use Livewire\Component;
use Visus\Cuid2\Cuid2;
class Rollback extends Component
{
public Application $application;
public $images = [];
public string|null $current;
public array $parameters;
public function mount()
{
$this->parameters = get_route_parameters();
}
public function rollbackImage($commit)
{
$deployment_uuid = new Cuid2(7);
queue_application_deployment(
application_id: $this->application->id,
deployment_uuid: $deployment_uuid,
commit: $commit,
force_rebuild: false,
);
return redirect()->route('project.application.deployment', [
'project_uuid' => $this->parameters['project_uuid'],
'application_uuid' => $this->parameters['application_uuid'],
'deployment_uuid' => $deployment_uuid,
'environment_name' => $this->parameters['environment_name'],
]);
}
public function loadImages($showToast = false)
{
try {
$image = $this->application->docker_registry_image_name ?? $this->application->uuid;
if ($this->application->destination->server->isFunctional()) {
$output = instant_remote_process([
"docker inspect --format='{{.Config.Image}}' {$this->application->uuid}",
], $this->application->destination->server, throwError: false);
$current_tag = Str::of($output)->trim()->explode(":");
$this->current = data_get($current_tag, 1);
$output = instant_remote_process([
"docker images --format '{{.Repository}}#{{.Tag}}#{{.CreatedAt}}'",
], $this->application->destination->server);
$this->images = Str::of($output)->trim()->explode("\n")->filter(function ($item) use ($image) {
return Str::of($item)->contains($image);
})->map(function ($item) {
$item = Str::of($item)->explode('#');
if ($item[1] === $this->current) {
// $is_current = true;
}
return [
'tag' => $item[1],
'created_at' => $item[2],
'is_current' => $is_current ?? null,
];
})->toArray();
}
$showToast && $this->emit('success', 'Images loaded.');
return [];
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
}

View File

@@ -1,54 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Application;
use App\Models\Application;
use App\Models\PrivateKey;
use Livewire\Component;
class Source extends Component
{
public $applicationId;
public Application $application;
public $private_keys;
protected $rules = [
'application.git_repository' => 'required',
'application.git_branch' => 'required',
'application.git_commit_sha' => 'nullable',
];
protected $validationAttributes = [
'application.git_repository' => 'repository',
'application.git_branch' => 'branch',
'application.git_commit_sha' => 'commit sha',
];
public function mount()
{
$this->get_private_keys();
}
private function get_private_keys()
{
$this->private_keys = PrivateKey::whereTeamId(currentTeam()->id)->get()->reject(function ($key) {
return $key->id == $this->application->private_key_id;
});
}
public function setPrivateKey(int $private_key_id)
{
$this->application->private_key_id = $private_key_id;
$this->application->save();
$this->application->refresh();
$this->get_private_keys();
}
public function submit()
{
$this->validate();
if (!$this->application->git_commit_sha) {
$this->application->git_commit_sha = 'HEAD';
}
$this->application->save();
$this->emit('success', 'Application source updated!');
}
}

View File

@@ -1,159 +0,0 @@
<?php
namespace App\Http\Livewire\Project;
use App\Models\Environment;
use App\Models\Project;
use App\Models\Server;
use Livewire\Component;
use Visus\Cuid2\Cuid2;
class CloneProject extends Component
{
public string $project_uuid;
public string $environment_name;
public int $project_id;
public Project $project;
public $environments;
public $servers;
public ?Environment $environment = null;
public ?int $selectedServer = null;
public ?Server $server = null;
public $resources = [];
public string $newProjectName = '';
protected $messages = [
'selectedServer' => 'Please select a server.',
'newProjectName' => 'Please enter a name for the new project.',
];
public function mount($project_uuid)
{
$this->project_uuid = $project_uuid;
$this->project = Project::where('uuid', $project_uuid)->firstOrFail();
$this->environment = $this->project->environments->where('name', $this->environment_name)->first();
$this->project_id = $this->project->id;
$this->servers = currentTeam()->servers;
$this->newProjectName = $this->project->name . ' (clone)';
}
public function render()
{
return view('livewire.project.clone-project');
}
public function selectServer($server_id)
{
$this->selectedServer = $server_id;
$this->server = $this->servers->where('id', $server_id)->first();
}
public function clone()
{
try {
$this->validate([
'selectedServer' => 'required',
'newProjectName' => 'required',
]);
$foundProject = Project::where('name', $this->newProjectName)->first();
if ($foundProject) {
throw new \Exception('Project with the same name already exists.');
}
$newProject = Project::create([
'name' => $this->newProjectName,
'team_id' => currentTeam()->id,
'description' => $this->project->description . ' (clone)',
]);
if ($this->environment->name !== 'production') {
$newProject->environments()->create([
'name' => $this->environment->name,
]);
}
$newEnvironment = $newProject->environments->where('name', $this->environment->name)->first();
// Clone Applications
$applications = $this->environment->applications;
$databases = $this->environment->databases();
$services = $this->environment->services;
foreach ($applications as $application) {
$uuid = (string)new Cuid2(7);
$newApplication = $application->replicate()->fill([
'uuid' => $uuid,
'fqdn' => generateFqdn($this->server, $uuid),
'status' => 'exited',
'environment_id' => $newEnvironment->id,
'destination_id' => $this->selectedServer,
]);
$newApplication->save();
$environmentVaribles = $application->environment_variables()->get();
foreach ($environmentVaribles as $environmentVarible) {
$newEnvironmentVariable = $environmentVarible->replicate()->fill([
'application_id' => $newApplication->id,
]);
$newEnvironmentVariable->save();
}
$persistentVolumes = $application->persistentStorages()->get();
foreach ($persistentVolumes as $volume) {
$newPersistentVolume = $volume->replicate()->fill([
'name' => $newApplication->uuid . '-' . str($volume->name)->afterLast('-'),
'resource_id' => $newApplication->id,
]);
$newPersistentVolume->save();
}
}
foreach ($databases as $database) {
$uuid = (string)new Cuid2(7);
$newDatabase = $database->replicate()->fill([
'uuid' => $uuid,
'status' => 'exited',
'started_at' => null,
'environment_id' => $newEnvironment->id,
'destination_id' => $this->selectedServer,
]);
$newDatabase->save();
$environmentVaribles = $database->environment_variables()->get();
foreach ($environmentVaribles as $environmentVarible) {
$payload = [];
if ($database->type() === 'standalone-postgresql') {
$payload['standalone_postgresql_id'] = $newDatabase->id;
} else if ($database->type() === 'standalone-redis') {
$payload['standalone_redis_id'] = $newDatabase->id;
} else if ($database->type() === 'standalone-mongodb') {
$payload['standalone_mongodb_id'] = $newDatabase->id;
} else if ($database->type() === 'standalone-mysql') {
$payload['standalone_mysql_id'] = $newDatabase->id;
} else if ($database->type() === 'standalone-mariadb') {
$payload['standalone_mariadb_id'] = $newDatabase->id;
}
$newEnvironmentVariable = $environmentVarible->replicate()->fill($payload);
$newEnvironmentVariable->save();
}
}
foreach ($services as $service) {
$uuid = (string)new Cuid2(7);
$newService = $service->replicate()->fill([
'uuid' => $uuid,
'environment_id' => $newEnvironment->id,
'destination_id' => $this->selectedServer,
]);
$newService->save();
foreach ($newService->applications() as $application) {
$application->update([
'status' => 'exited',
]);
}
foreach ($newService->databases() as $database) {
$database->update([
'status' => 'exited',
]);
}
$newService->parse();
}
return redirect()->route('project.resources', [
'project_uuid' => $newProject->uuid,
'environment_name' => $newEnvironment->name,
]);
} catch (\Exception $e) {
return handleError($e, $this);
}
}
}

View File

@@ -1,98 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Database;
use Livewire\Component;
use Spatie\Url\Url;
class BackupEdit extends Component
{
public $backup;
public $s3s;
public ?string $status = null;
public array $parameters;
protected $rules = [
'backup.enabled' => 'required|boolean',
'backup.frequency' => 'required|string',
'backup.number_of_backups_locally' => 'required|integer|min:1',
'backup.save_s3' => 'required|boolean',
'backup.s3_storage_id' => 'nullable|integer',
'backup.databases_to_backup' => 'nullable',
];
protected $validationAttributes = [
'backup.enabled' => 'Enabled',
'backup.frequency' => 'Frequency',
'backup.number_of_backups_locally' => 'Number of Backups Locally',
'backup.save_s3' => 'Save to S3',
'backup.s3_storage_id' => 'S3 Storage',
'backup.databases_to_backup' => 'Databases to Backup',
];
protected $messages = [
'backup.s3_storage_id' => 'Select a S3 Storage',
];
public function mount()
{
$this->parameters = get_route_parameters();
if (is_null($this->backup->s3_storage_id)) {
$this->backup->s3_storage_id = 'default';
}
}
public function delete()
{
// TODO: Delete backup from server and add a confirmation modal
$this->backup->delete();
if ($this->backup->database->getMorphClass() === 'App\Models\ServiceDatabase') {
$previousUrl = url()->previous();
$url = Url::fromString($previousUrl);
$url = $url->withoutQueryParameter('selectedBackupId');
$url = $url->withFragment('backups');
$url = $url->getPath() . "#{$url->getFragment()}";
return redirect()->to($url);
} else {
redirect()->route('project.database.backups.all', $this->parameters);
}
}
public function instantSave()
{
try {
$this->custom_validate();
$this->backup->save();
$this->backup->refresh();
$this->emit('success', 'Backup updated successfully');
} catch (\Throwable $e) {
$this->emit('error', $e->getMessage());
}
}
private function custom_validate()
{
if (!is_numeric($this->backup->s3_storage_id)) {
$this->backup->s3_storage_id = null;
}
$isValid = validate_cron_expression($this->backup->frequency);
if (!$isValid) {
throw new \Exception('Invalid Cron / Human expression');
}
$this->validate();
}
public function submit()
{
try {
$this->custom_validate();
if ($this->backup->databases_to_backup == '' || $this->backup->databases_to_backup === null) {
$this->backup->databases_to_backup = null;
}
$this->backup->save();
$this->backup->refresh();
$this->emit('success', 'Backup updated successfully');
} catch (\Throwable $e) {
$this->emit('error', $e->getMessage());
}
}
}

View File

@@ -1,62 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Database;
use Illuminate\Support\Facades\Storage;
use Livewire\Component;
class BackupExecutions extends Component
{
public $backup;
public $executions;
public $setDeletableBackup;
protected $listeners = ['refreshBackupExecutions', 'deleteBackup'];
public function deleteBackup($exeuctionId)
{
$execution = $this->backup->executions()->where('id', $exeuctionId)->first();
if (is_null($execution)) {
$this->emit('error', 'Backup execution not found.');
return;
}
if ($execution->scheduledDatabaseBackup->database->getMorphClass() === 'App\Models\ServiceDatabase') {
delete_backup_locally($execution->filename, $execution->scheduledDatabaseBackup->database->service->destination->server);
} else {
delete_backup_locally($execution->filename, $execution->scheduledDatabaseBackup->database->destination->server);
}
$execution->delete();
$this->emit('success', 'Backup deleted successfully.');
$this->emit('refreshBackupExecutions');
}
public function download($exeuctionId)
{
try {
$execution = $this->backup->executions()->where('id', $exeuctionId)->first();
if (is_null($execution)) {
$this->emit('error', 'Backup execution not found.');
return;
}
$filename = data_get($execution, 'filename');
if ($execution->scheduledDatabaseBackup->database->getMorphClass() === 'App\Models\ServiceDatabase') {
$server = $execution->scheduledDatabaseBackup->database->service->destination->server;
} else {
$server = $execution->scheduledDatabaseBackup->database->destination->server;
}
$privateKeyLocation = savePrivateKeyToFs($server);
$disk = Storage::build([
'driver' => 'sftp',
'host' => $server->ip,
'port' => $server->port,
'username' => $server->user,
'privateKey' => $privateKeyLocation,
]);
return $disk->download($filename);
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function refreshBackupExecutions(): void
{
$this->executions = $this->backup->executions;
}
}

View File

@@ -1,18 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Database;
use App\Jobs\DatabaseBackupJob;
use Livewire\Component;
class BackupNow extends Component
{
public $backup;
public function backup_now()
{
dispatch(new DatabaseBackupJob(
backup: $this->backup
));
$this->emit('success', 'Backup queued. It will be available in a few minutes.');
}
}

View File

@@ -1,71 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Database;
use App\Models\ScheduledDatabaseBackup;
use Livewire\Component;
class CreateScheduledBackup extends Component
{
public $database;
public $frequency;
public bool $enabled = true;
public bool $save_s3 = false;
public $s3_storage_id;
public $s3s;
protected $rules = [
'frequency' => 'required|string',
'save_s3' => 'required|boolean',
];
protected $validationAttributes = [
'frequency' => 'Backup Frequency',
'save_s3' => 'Save to S3',
];
public function mount()
{
if ($this->s3s->count() > 0) {
$this->s3_storage_id = $this->s3s->first()->id;
}
}
public function submit(): void
{
try {
$this->validate();
$isValid = validate_cron_expression($this->frequency);
if (!$isValid) {
$this->emit('error', 'Invalid Cron / Human expression.');
return;
}
$payload = [
'enabled' => true,
'frequency' => $this->frequency,
'save_s3' => $this->save_s3,
's3_storage_id' => $this->s3_storage_id,
'database_id' => $this->database->id,
'database_type' => $this->database->getMorphClass(),
'team_id' => currentTeam()->id,
];
if ($this->database->type() === 'standalone-postgresql') {
$payload['databases_to_backup'] = $this->database->postgres_db;
} else if ($this->database->type() === 'standalone-mysql') {
$payload['databases_to_backup'] = $this->database->mysql_database;
} else if ($this->database->type() === 'standalone-mariadb') {
$payload['databases_to_backup'] = $this->database->mariadb_database;
}
$databaseBackup = ScheduledDatabaseBackup::create($payload);
if ($this->database->getMorphClass() === 'App\Models\ServiceDatabase') {
$this->emit('refreshScheduledBackups', $databaseBackup->id);
} else {
$this->emit('refreshScheduledBackups');
}
} catch (\Throwable $e) {
handleError($e, $this);
} finally {
$this->frequency = '';
$this->save_s3 = true;
}
}
}

View File

@@ -1,68 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Database;
use App\Actions\Database\StartMariadb;
use App\Actions\Database\StartMongodb;
use App\Actions\Database\StartMysql;
use App\Actions\Database\StartPostgresql;
use App\Actions\Database\StartRedis;
use App\Actions\Database\StopDatabase;
use App\Jobs\ContainerStatusJob;
use Livewire\Component;
class Heading extends Component
{
public $database;
public array $parameters;
protected $listeners = ['activityFinished'];
public function activityFinished()
{
$this->database->update([
'started_at' => now(),
]);
$this->emit('refresh');
$this->check_status();
}
public function check_status()
{
dispatch_sync(new ContainerStatusJob($this->database->destination->server));
$this->database->refresh();
}
public function mount()
{
$this->parameters = get_route_parameters();
}
public function stop()
{
StopDatabase::run($this->database);
$this->database->status = 'exited';
$this->database->save();
$this->check_status();
}
public function start()
{
if ($this->database->type() === 'standalone-postgresql') {
$activity = StartPostgresql::run($this->database);
$this->emit('newMonitorActivity', $activity->id);
} else if ($this->database->type() === 'standalone-redis') {
$activity = StartRedis::run($this->database);
$this->emit('newMonitorActivity', $activity->id);
} else if ($this->database->type() === 'standalone-mongodb') {
$activity = StartMongodb::run($this->database);
$this->emit('newMonitorActivity', $activity->id);
} else if ($this->database->type() === 'standalone-mysql') {
$activity = StartMysql::run($this->database);
$this->emit('newMonitorActivity', $activity->id);
} else if ($this->database->type() === 'standalone-mariadb') {
$activity = StartMariadb::run($this->database);
$this->emit('newMonitorActivity', $activity->id);
}
}
}

View File

@@ -1,47 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Database;
use Livewire\Component;
class InitScript extends Component
{
public array $script;
public int $index;
public string|null $filename;
public string|null $content;
protected $rules = [
'filename' => 'required|string',
'content' => 'required|string',
];
protected $validationAttributes = [
'filename' => 'Filename',
'content' => 'Content',
];
public function mount()
{
$this->index = data_get($this->script, 'index');
$this->filename = data_get($this->script, 'filename');
$this->content = data_get($this->script, 'content');
}
public function submit()
{
$this->validate();
try {
$this->script['index'] = $this->index;
$this->script['content'] = $this->content;
$this->script['filename'] = $this->filename;
$this->emitUp('save_init_script', $this->script);
} catch (Exception $e) {
return handleError($e, $this);
}
}
public function delete()
{
$this->emitUp('delete_init_script', $this->script);
}
}

View File

@@ -1,118 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Database\Mariadb;
use App\Actions\Database\StartDatabaseProxy;
use App\Actions\Database\StopDatabaseProxy;
use App\Models\StandaloneMariadb;
use Exception;
use Livewire\Component;
class General extends Component
{
protected $listeners = ['refresh'];
public StandaloneMariadb $database;
public ?string $db_url = null;
public ?string $db_url_public = null;
protected $rules = [
'database.name' => 'required',
'database.description' => 'nullable',
'database.mariadb_root_password' => 'required',
'database.mariadb_user' => 'required',
'database.mariadb_password' => 'required',
'database.mariadb_database' => 'required',
'database.mariadb_conf' => 'nullable',
'database.image' => 'required',
'database.ports_mappings' => 'nullable',
'database.is_public' => 'nullable|boolean',
'database.public_port' => 'nullable|integer',
'database.is_log_drain_enabled' => 'nullable|boolean',
];
protected $validationAttributes = [
'database.name' => 'Name',
'database.description' => 'Description',
'database.mariadb_root_password' => 'Root Password',
'database.mariadb_user' => 'User',
'database.mariadb_password' => 'Password',
'database.mariadb_database' => 'Database',
'database.mariadb_conf' => 'MariaDB Configuration',
'database.image' => 'Image',
'database.ports_mappings' => 'Port Mapping',
'database.is_public' => 'Is Public',
'database.public_port' => 'Public Port',
];
public function mount()
{
$this->db_url = $this->database->getDbUrl(true);
if ($this->database->is_public) {
$this->db_url_public = $this->database->getDbUrl();
}
}
public function instantSaveAdvanced() {
try {
if (!$this->database->destination->server->isLogDrainEnabled()) {
$this->database->is_log_drain_enabled = false;
$this->emit('error', 'Log drain is not enabled on the server. Please enable it first.');
return;
}
$this->database->save();
$this->emit('success', 'Database updated successfully.');
$this->emit('success', 'You need to restart the service for the changes to take effect.');
} catch (Exception $e) {
return handleError($e, $this);
}
}
public function submit()
{
try {
if (str($this->database->public_port)->isEmpty()) {
$this->database->public_port = null;
}
$this->validate();
$this->database->save();
$this->emit('success', 'Database updated successfully.');
} catch (Exception $e) {
return handleError($e, $this);
}
}
public function instantSave()
{
try {
if ($this->database->is_public && !$this->database->public_port) {
$this->emit('error', 'Public port is required.');
$this->database->is_public = false;
return;
}
if ($this->database->is_public) {
if (!str($this->database->status)->startsWith('running')) {
$this->emit('error', 'Database must be started to be publicly accessible.');
$this->database->is_public = false;
return;
}
StartDatabaseProxy::run($this->database);
$this->db_url_public = $this->database->getDbUrl();
$this->emit('success', 'Database is now publicly accessible.');
} else {
StopDatabaseProxy::run($this->database);
$this->db_url_public = null;
$this->emit('success', 'Database is no longer publicly accessible.');
}
$this->database->save();
} catch (\Throwable $e) {
$this->database->is_public = !$this->database->is_public;
return handleError($e, $this);
}
}
public function refresh(): void
{
$this->database->refresh();
}
public function render()
{
return view('livewire.project.database.mariadb.general');
}
}

View File

@@ -1,120 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Database\Mongodb;
use App\Actions\Database\StartDatabaseProxy;
use App\Actions\Database\StopDatabaseProxy;
use App\Models\StandaloneMongodb;
use Exception;
use Livewire\Component;
class General extends Component
{
protected $listeners = ['refresh'];
public StandaloneMongodb $database;
public ?string $db_url = null;
public ?string $db_url_public = null;
protected $rules = [
'database.name' => 'required',
'database.description' => 'nullable',
'database.mongo_conf' => 'nullable',
'database.mongo_initdb_root_username' => 'required',
'database.mongo_initdb_root_password' => 'required',
'database.mongo_initdb_database' => 'required',
'database.image' => 'required',
'database.ports_mappings' => 'nullable',
'database.is_public' => 'nullable|boolean',
'database.public_port' => 'nullable|integer',
'database.is_log_drain_enabled' => 'nullable|boolean',
];
protected $validationAttributes = [
'database.name' => 'Name',
'database.description' => 'Description',
'database.mongo_conf' => 'Mongo Configuration',
'database.mongo_initdb_root_username' => 'Root Username',
'database.mongo_initdb_root_password' => 'Root Password',
'database.mongo_initdb_database' => 'Database',
'database.image' => 'Image',
'database.ports_mappings' => 'Port Mapping',
'database.is_public' => 'Is Public',
'database.public_port' => 'Public Port',
];
public function mount()
{
$this->db_url = $this->database->getDbUrl(true);
if ($this->database->is_public) {
$this->db_url_public = $this->database->getDbUrl();
}
}
public function instantSaveAdvanced()
{
try {
if (!$this->database->destination->server->isLogDrainEnabled()) {
$this->database->is_log_drain_enabled = false;
$this->emit('error', 'Log drain is not enabled on the server. Please enable it first.');
return;
}
$this->database->save();
$this->emit('success', 'Database updated successfully.');
$this->emit('success', 'You need to restart the service for the changes to take effect.');
} catch (Exception $e) {
return handleError($e, $this);
}
}
public function submit()
{
try {
if (str($this->database->public_port)->isEmpty()) {
$this->database->public_port = null;
}
if (str($this->database->mongo_conf)->isEmpty()) {
$this->database->mongo_conf = null;
}
$this->validate();
$this->database->save();
$this->emit('success', 'Database updated successfully.');
} catch (Exception $e) {
return handleError($e, $this);
}
}
public function instantSave()
{
try {
if ($this->database->is_public && !$this->database->public_port) {
$this->emit('error', 'Public port is required.');
$this->database->is_public = false;
return;
}
if ($this->database->is_public) {
if (!str($this->database->status)->startsWith('running')) {
$this->emit('error', 'Database must be started to be publicly accessible.');
$this->database->is_public = false;
return;
}
StartDatabaseProxy::run($this->database);
$this->db_url_public = $this->database->getDbUrl();
$this->emit('success', 'Database is now publicly accessible.');
} else {
StopDatabaseProxy::run($this->database);
$this->db_url_public = null;
$this->emit('success', 'Database is no longer publicly accessible.');
}
$this->database->save();
} catch (\Throwable $e) {
$this->database->is_public = !$this->database->is_public;
return handleError($e, $this);
}
}
public function refresh(): void
{
$this->database->refresh();
}
public function render()
{
return view('livewire.project.database.mongodb.general');
}
}

View File

@@ -1,119 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Database\Mysql;
use App\Actions\Database\StartDatabaseProxy;
use App\Actions\Database\StopDatabaseProxy;
use App\Models\StandaloneMysql;
use Exception;
use Livewire\Component;
class General extends Component
{
protected $listeners = ['refresh'];
public StandaloneMysql $database;
public ?string $db_url = null;
public ?string $db_url_public = null;
protected $rules = [
'database.name' => 'required',
'database.description' => 'nullable',
'database.mysql_root_password' => 'required',
'database.mysql_user' => 'required',
'database.mysql_password' => 'required',
'database.mysql_database' => 'required',
'database.mysql_conf' => 'nullable',
'database.image' => 'required',
'database.ports_mappings' => 'nullable',
'database.is_public' => 'nullable|boolean',
'database.public_port' => 'nullable|integer',
'database.is_log_drain_enabled' => 'nullable|boolean',
];
protected $validationAttributes = [
'database.name' => 'Name',
'database.description' => 'Description',
'database.mysql_root_password' => 'Root Password',
'database.mysql_user' => 'User',
'database.mysql_password' => 'Password',
'database.mysql_database' => 'Database',
'database.mysql_conf' => 'MySQL Configuration',
'database.image' => 'Image',
'database.ports_mappings' => 'Port Mapping',
'database.is_public' => 'Is Public',
'database.public_port' => 'Public Port',
];
public function mount()
{
$this->db_url = $this->database->getDbUrl(true);
if ($this->database->is_public) {
$this->db_url_public = $this->database->getDbUrl();
}
}
public function instantSaveAdvanced()
{
try {
if (!$this->database->destination->server->isLogDrainEnabled()) {
$this->database->is_log_drain_enabled = false;
$this->emit('error', 'Log drain is not enabled on the server. Please enable it first.');
return;
}
$this->database->save();
$this->emit('success', 'Database updated successfully.');
$this->emit('success', 'You need to restart the service for the changes to take effect.');
} catch (Exception $e) {
return handleError($e, $this);
}
}
public function submit()
{
try {
if (str($this->database->public_port)->isEmpty()) {
$this->database->public_port = null;
}
$this->validate();
$this->database->save();
$this->emit('success', 'Database updated successfully.');
} catch (Exception $e) {
return handleError($e, $this);
}
}
public function instantSave()
{
try {
if ($this->database->is_public && !$this->database->public_port) {
$this->emit('error', 'Public port is required.');
$this->database->is_public = false;
return;
}
if ($this->database->is_public) {
if (!str($this->database->status)->startsWith('running')) {
$this->emit('error', 'Database must be started to be publicly accessible.');
$this->database->is_public = false;
return;
}
StartDatabaseProxy::run($this->database);
$this->db_url_public = $this->database->getDbUrl();
$this->emit('success', 'Database is now publicly accessible.');
} else {
StopDatabaseProxy::run($this->database);
$this->db_url_public = null;
$this->emit('success', 'Database is no longer publicly accessible.');
}
$this->database->save();
} catch (\Throwable $e) {
$this->database->is_public = !$this->database->is_public;
return handleError($e, $this);
}
}
public function refresh(): void
{
$this->database->refresh();
}
public function render()
{
return view('livewire.project.database.mysql.general');
}
}

View File

@@ -1,169 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Database\Postgresql;
use App\Actions\Database\StartDatabaseProxy;
use App\Actions\Database\StopDatabaseProxy;
use App\Models\StandalonePostgresql;
use Exception;
use Livewire\Component;
use function Aws\filter;
class General extends Component
{
public StandalonePostgresql $database;
public string $new_filename;
public string $new_content;
public ?string $db_url = null;
public ?string $db_url_public = null;
protected $listeners = ['refresh', 'save_init_script', 'delete_init_script'];
protected $rules = [
'database.name' => 'required',
'database.description' => 'nullable',
'database.postgres_user' => 'required',
'database.postgres_password' => 'required',
'database.postgres_db' => 'required',
'database.postgres_initdb_args' => 'nullable',
'database.postgres_host_auth_method' => 'nullable',
'database.postgres_conf' => 'nullable',
'database.init_scripts' => 'nullable',
'database.image' => 'required',
'database.ports_mappings' => 'nullable',
'database.is_public' => 'nullable|boolean',
'database.public_port' => 'nullable|integer',
'database.is_log_drain_enabled' => 'nullable|boolean',
];
protected $validationAttributes = [
'database.name' => 'Name',
'database.description' => 'Description',
'database.postgres_user' => 'Postgres User',
'database.postgres_password' => 'Postgres Password',
'database.postgres_db' => 'Postgres DB',
'database.postgres_initdb_args' => 'Postgres Initdb Args',
'database.postgres_host_auth_method' => 'Postgres Host Auth Method',
'database.postgres_conf' => 'Postgres Configuration',
'database.init_scripts' => 'Init Scripts',
'database.image' => 'Image',
'database.ports_mappings' => 'Port Mapping',
'database.is_public' => 'Is Public',
'database.public_port' => 'Public Port',
];
public function mount()
{
$this->db_url = $this->database->getDbUrl(true);
if ($this->database->is_public) {
$this->db_url_public = $this->database->getDbUrl();
}
}
public function instantSaveAdvanced() {
try {
if (!$this->database->destination->server->isLogDrainEnabled()) {
$this->database->is_log_drain_enabled = false;
$this->emit('error', 'Log drain is not enabled on the server. Please enable it first.');
return;
}
$this->database->save();
$this->emit('success', 'Database updated successfully.');
$this->emit('success', 'You need to restart the service for the changes to take effect.');
} catch (Exception $e) {
return handleError($e, $this);
}
}
public function instantSave()
{
try {
if ($this->database->is_public && !$this->database->public_port) {
$this->emit('error', 'Public port is required.');
$this->database->is_public = false;
return;
}
if ($this->database->is_public) {
if (!str($this->database->status)->startsWith('running')) {
$this->emit('error', 'Database must be started to be publicly accessible.');
$this->database->is_public = false;
return;
}
StartDatabaseProxy::run($this->database);
$this->db_url_public = $this->database->getDbUrl();
$this->emit('success', 'Database is now publicly accessible.');
} else {
StopDatabaseProxy::run($this->database);
$this->db_url_public = null;
$this->emit('success', 'Database is no longer publicly accessible.');
}
$this->database->save();
} catch (\Throwable $e) {
$this->database->is_public = !$this->database->is_public;
return handleError($e, $this);
}
}
public function save_init_script($script)
{
$this->database->init_scripts = filter($this->database->init_scripts, fn ($s) => $s['filename'] !== $script['filename']);
$this->database->init_scripts = array_merge($this->database->init_scripts, [$script]);
$this->database->save();
$this->emit('success', 'Init script saved successfully.');
}
public function delete_init_script($script)
{
$collection = collect($this->database->init_scripts);
$found = $collection->firstWhere('filename', $script['filename']);
if ($found) {
$this->database->init_scripts = $collection->filter(fn ($s) => $s['filename'] !== $script['filename'])->toArray();
$this->database->save();
$this->refresh();
$this->emit('success', 'Init script deleted successfully.');
return;
}
}
public function refresh(): void
{
$this->database->refresh();
}
public function save_new_init_script()
{
$this->validate([
'new_filename' => 'required|string',
'new_content' => 'required|string',
]);
$found = collect($this->database->init_scripts)->firstWhere('filename', $this->new_filename);
if ($found) {
$this->emit('error', 'Filename already exists.');
return;
}
if (!isset($this->database->init_scripts)) {
$this->database->init_scripts = [];
}
$this->database->init_scripts = array_merge($this->database->init_scripts, [
[
'index' => count($this->database->init_scripts),
'filename' => $this->new_filename,
'content' => $this->new_content,
]
]);
$this->database->save();
$this->emit('success', 'Init script added successfully.');
$this->new_content = '';
$this->new_filename = '';
}
public function submit()
{
try {
if (str($this->database->public_port)->isEmpty()) {
$this->database->public_port = null;
}
$this->validate();
$this->database->save();
$this->emit('success', 'Database updated successfully.');
} catch (Exception $e) {
return handleError($e, $this);
}
}
}

View File

@@ -1,111 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Database\Redis;
use App\Actions\Database\StartDatabaseProxy;
use App\Actions\Database\StopDatabaseProxy;
use App\Models\StandaloneRedis;
use Exception;
use Livewire\Component;
class General extends Component
{
protected $listeners = ['refresh'];
public StandaloneRedis $database;
public ?string $db_url = null;
public ?string $db_url_public = null;
protected $rules = [
'database.name' => 'required',
'database.description' => 'nullable',
'database.redis_conf' => 'nullable',
'database.redis_password' => 'required',
'database.image' => 'required',
'database.ports_mappings' => 'nullable',
'database.is_public' => 'nullable|boolean',
'database.public_port' => 'nullable|integer',
'database.is_log_drain_enabled' => 'nullable|boolean',
];
protected $validationAttributes = [
'database.name' => 'Name',
'database.description' => 'Description',
'database.redis_conf' => 'Redis Configuration',
'database.redis_password' => 'Redis Password',
'database.image' => 'Image',
'database.ports_mappings' => 'Port Mapping',
'database.is_public' => 'Is Public',
'database.public_port' => 'Public Port',
];
public function mount()
{
$this->db_url = $this->database->getDbUrl(true);
if ($this->database->is_public) {
$this->db_url_public = $this->database->getDbUrl();
}
}
public function instantSaveAdvanced() {
try {
if (!$this->database->destination->server->isLogDrainEnabled()) {
$this->database->is_log_drain_enabled = false;
$this->emit('error', 'Log drain is not enabled on the server. Please enable it first.');
return;
}
$this->database->save();
$this->emit('success', 'Database updated successfully.');
$this->emit('success', 'You need to restart the service for the changes to take effect.');
} catch (Exception $e) {
return handleError($e, $this);
}
}
public function submit()
{
try {
$this->validate();
if ($this->database->redis_conf === "") {
$this->database->redis_conf = null;
}
$this->database->save();
$this->emit('success', 'Database updated successfully.');
} catch (Exception $e) {
return handleError($e, $this);
}
}
public function instantSave()
{
try {
if ($this->database->is_public && !$this->database->public_port) {
$this->emit('error', 'Public port is required.');
$this->database->is_public = false;
return;
}
if ($this->database->is_public) {
if (!str($this->database->status)->startsWith('running')) {
$this->emit('error', 'Database must be started to be publicly accessible.');
$this->database->is_public = false;
return;
}
StartDatabaseProxy::run($this->database);
$this->db_url_public = $this->database->getDbUrl();
$this->emit('success', 'Database is now publicly accessible.');
} else {
StopDatabaseProxy::run($this->database);
$this->db_url_public = null;
$this->emit('success', 'Database is no longer publicly accessible.');
}
$this->database->save();
} catch (\Throwable $e) {
$this->database->is_public = !$this->database->is_public;
return handleError($e, $this);
}
}
public function refresh(): void
{
$this->database->refresh();
}
public function render()
{
return view('livewire.project.database.redis.general');
}
}

View File

@@ -1,52 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Database;
use Livewire\Component;
class ScheduledBackups extends Component
{
public $database;
public $parameters;
public $type;
public $selectedBackup;
public $selectedBackupId;
public $s3s;
protected $listeners = ['refreshScheduledBackups'];
protected $queryString = ['selectedBackupId'];
public function mount(): void
{
if ($this->selectedBackupId) {
$this->setSelectedBackup($this->selectedBackupId);
}
$this->parameters = get_route_parameters();
if ($this->database->getMorphClass() === 'App\Models\ServiceDatabase') {
$this->type = 'service-database';
} else {
$this->type = 'database';
}
$this->s3s = currentTeam()->s3s;
}
public function setSelectedBackup($backupId) {
$this->selectedBackupId = $backupId;
$this->selectedBackup = $this->database->scheduledBackups->find($this->selectedBackupId);
if (is_null($this->selectedBackup)) {
$this->selectedBackupId = null;
}
}
public function delete($scheduled_backup_id): void
{
$this->database->scheduledBackups->find($scheduled_backup_id)->delete();
$this->emit('success', 'Scheduled backup deleted successfully.');
$this->refreshScheduledBackups();
}
public function refreshScheduledBackups(?int $id = null): void
{
$this->database->refresh();
if ($id) {
$this->setSelectedBackup($id);
}
}
}

View File

@@ -1,30 +0,0 @@
<?php
namespace App\Http\Livewire\Project;
use App\Models\Environment;
use Livewire\Component;
class DeleteEnvironment extends Component
{
public array $parameters;
public int $environment_id;
public function mount()
{
$this->parameters = get_route_parameters();
}
public function delete()
{
$this->validate([
'environment_id' => 'required|int',
]);
$environment = Environment::findOrFail($this->environment_id);
if ($environment->isEmpty()) {
$environment->delete();
return redirect()->route('project.show', ['project_uuid' => $this->parameters['project_uuid']]);
}
return $this->emit('error', 'Environment has defined resources, please delete them first.');
}
}

View File

@@ -1,30 +0,0 @@
<?php
namespace App\Http\Livewire\Project;
use App\Models\Project;
use Livewire\Component;
class DeleteProject extends Component
{
public array $parameters;
public int $project_id;
public function mount()
{
$this->parameters = get_route_parameters();
}
public function delete()
{
$this->validate([
'project_id' => 'required|int',
]);
$project = Project::findOrFail($this->project_id);
if ($project->applications->count() > 0) {
return $this->emit('error', 'Project has resources defined, please delete them first.');
}
$project->delete();
return redirect()->route('projects');
}
}

View File

@@ -1,26 +0,0 @@
<?php
namespace App\Http\Livewire\Project;
use App\Models\Project;
use Livewire\Component;
class Edit extends Component
{
public Project $project;
protected $rules = [
'project.name' => 'required|min:3|max:255',
'project.description' => 'nullable|string|max:255',
];
public function submit()
{
$this->validate();
try {
$this->project->save();
$this->emit('saved');
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
}

View File

@@ -1,81 +0,0 @@
<?php
namespace App\Http\Livewire\Project\New;
use App\Models\EnvironmentVariable;
use App\Models\Project;
use App\Models\Service;
use Livewire\Component;
use Illuminate\Support\Str;
use Symfony\Component\Yaml\Yaml;
class DockerCompose extends Component
{
public string $dockerComposeRaw = '';
public string $envFile = '';
public array $parameters;
public array $query;
public function mount()
{
$this->parameters = get_route_parameters();
$this->query = request()->query();
if (isDev()) {
$this->dockerComposeRaw = 'services:
appsmith:
build:
context: .
dockerfile_inline: |
FROM nginx
ARG GIT_COMMIT
ARG GIT_BRANCH
RUN echo "Hello World ${GIT_COMMIT} ${GIT_BRANCH}"
args:
- GIT_COMMIT=cdc3b19
- GIT_BRANCH=${GIT_BRANCH}
environment:
- APPSMITH_MAIL_ENABLED=${APPSMITH_MAIL_ENABLED}
';
}
}
public function submit()
{
try {
$this->validate([
'dockerComposeRaw' => 'required'
]);
$this->dockerComposeRaw = Yaml::dump(Yaml::parse($this->dockerComposeRaw), 10, 2, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK);
$server_id = $this->query['server_id'];
$project = Project::where('uuid', $this->parameters['project_uuid'])->first();
$environment = $project->load(['environments'])->environments->where('name', $this->parameters['environment_name'])->first();
$service = Service::create([
'name' => 'service' . Str::random(10),
'docker_compose_raw' => $this->dockerComposeRaw,
'environment_id' => $environment->id,
'server_id' => (int) $server_id,
]);
$variables = parseEnvFormatToArray($this->envFile);
foreach ($variables as $key => $variable) {
EnvironmentVariable::create([
'key' => $key,
'value' => $variable,
'is_build_time' => false,
'is_preview' => false,
'service_id' => $service->id,
]);
}
$service->name = "service-$service->uuid";
$service->parse(isNew: true);
return redirect()->route('project.service.configuration', [
'service_uuid' => $service->uuid,
'environment_name' => $environment->name,
'project_uuid' => $project->uuid,
]);
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
}

View File

@@ -1,78 +0,0 @@
<?php
namespace App\Http\Livewire\Project\New;
use App\Models\Application;
use App\Models\Project;
use App\Models\StandaloneDocker;
use App\Models\SwarmDocker;
use Livewire\Component;
use Visus\Cuid2\Cuid2;
use Illuminate\Support\Str;
class DockerImage extends Component
{
public string $dockerImage = '';
public array $parameters;
public array $query;
public function mount()
{
$this->parameters = get_route_parameters();
$this->query = request()->query();
}
public function submit()
{
$this->validate([
'dockerImage' => 'required'
]);
$image = Str::of($this->dockerImage)->before(':');
if (Str::of($this->dockerImage)->contains(':')) {
$tag = Str::of($this->dockerImage)->after(':');
} else {
$tag = 'latest';
}
$destination_uuid = $this->query['destination'];
$destination = StandaloneDocker::where('uuid', $destination_uuid)->first();
if (!$destination) {
$destination = SwarmDocker::where('uuid', $destination_uuid)->first();
}
if (!$destination) {
throw new \Exception('Destination not found. What?!');
}
$destination_class = $destination->getMorphClass();
$project = Project::where('uuid', $this->parameters['project_uuid'])->first();
$environment = $project->load(['environments'])->environments->where('name', $this->parameters['environment_name'])->first();
ray($image,$tag);
$application = Application::create([
'name' => 'docker-image-' . new Cuid2(7),
'repository_project_id' => 0,
'git_repository' => "coollabsio/coolify",
'git_branch' => 'main',
'build_pack' => 'dockerimage',
'ports_exposes' => 80,
'docker_registry_image_name' => $image,
'docker_registry_image_tag' => $tag,
'environment_id' => $environment->id,
'destination_id' => $destination->id,
'destination_type' => $destination_class,
'health_check_enabled' => false,
]);
$fqdn = generateFqdn($destination->server, $application->uuid);
$application->update([
'name' => 'docker-image-' . $application->uuid,
'fqdn' => $fqdn
]);
redirect()->route('project.application.configuration', [
'application_uuid' => $application->uuid,
'environment_name' => $environment->name,
'project_uuid' => $project->uuid,
]);
}
public function render()
{
return view('livewire.project.new.docker-image');
}
}

View File

@@ -1,18 +0,0 @@
<?php
namespace App\Http\Livewire\Project\New;
use App\Models\Project;
use Livewire\Component;
class EmptyProject extends Component
{
public function createEmptyProject()
{
$project = Project::create([
'name' => generate_random_name(),
'team_id' => currentTeam()->id,
]);
return redirect()->route('project.show', ['project_uuid' => $project->uuid, 'environment_name' => 'production']);
}
}

View File

@@ -1,175 +0,0 @@
<?php
namespace App\Http\Livewire\Project\New;
use App\Models\Application;
use App\Models\GithubApp;
use App\Models\Project;
use App\Models\StandaloneDocker;
use App\Models\SwarmDocker;
use App\Traits\SaveFromRedirect;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Route;
use Livewire\Component;
class GithubPrivateRepository extends Component
{
use SaveFromRedirect;
public $current_step = 'github_apps';
public $github_apps;
public GithubApp $github_app;
public $parameters;
public $currentRoute;
public $query;
public $type;
public int $selected_repository_id;
public int $selected_github_app_id;
public string $selected_repository_owner;
public string $selected_repository_repo;
public string $selected_branch_name = 'main';
public string $token;
public $repositories;
public int $total_repositories_count = 0;
public $branches;
public int $total_branches_count = 0;
public int $port = 3000;
public bool $is_static = false;
public string|null $publish_directory = null;
protected int $page = 1;
public function mount()
{
$this->currentRoute = Route::currentRouteName();
$this->parameters = get_route_parameters();
$this->query = request()->query();
$this->repositories = $this->branches = collect();
$this->github_apps = GithubApp::private();
}
public function loadRepositories($github_app_id)
{
$this->repositories = collect();
$this->page = 1;
$this->selected_github_app_id = $github_app_id;
$this->github_app = GithubApp::where('id', $github_app_id)->first();
$this->token = generate_github_installation_token($this->github_app);
$this->loadRepositoryByPage();
if ($this->repositories->count() < $this->total_repositories_count) {
while ($this->repositories->count() < $this->total_repositories_count) {
$this->page++;
$this->loadRepositoryByPage();
}
}
$this->selected_repository_id = $this->repositories[0]['id'];
$this->current_step = 'repository';
}
protected function loadRepositoryByPage()
{
$response = Http::withToken($this->token)->get("{$this->github_app->api_url}/installation/repositories?per_page=100&page={$this->page}");
$json = $response->json();
if ($response->status() !== 200) {
return $this->emit('error', $json['message']);
}
if ($json['total_count'] === 0) {
return;
}
$this->total_repositories_count = $json['total_count'];
$this->repositories = $this->repositories->concat(collect($json['repositories']));
}
public function loadBranches()
{
$this->selected_repository_owner = $this->repositories->where('id', $this->selected_repository_id)->first()['owner']['login'];
$this->selected_repository_repo = $this->repositories->where('id', $this->selected_repository_id)->first()['name'];
$this->branches = collect();
$this->page = 1;
$this->loadBranchByPage();
if ($this->total_branches_count === 100) {
while ($this->total_branches_count === 100) {
$this->page++;
$this->loadBranchByPage();
}
}
$this->selected_branch_name = data_get($this->branches,'0.name');
}
protected function loadBranchByPage()
{
ray('Loading page ' . $this->page);
$response = Http::withToken($this->token)->get("{$this->github_app->api_url}/repos/{$this->selected_repository_owner}/{$this->selected_repository_repo}/branches?per_page=100&page={$this->page}");
$json = $response->json();
if ($response->status() !== 200) {
return $this->emit('error', $json['message']);
}
$this->total_branches_count = count($json);
$this->branches = $this->branches->concat(collect($json));
}
public function submit()
{
try {
$destination_uuid = $this->query['destination'];
$destination = StandaloneDocker::where('uuid', $destination_uuid)->first();
if (!$destination) {
$destination = SwarmDocker::where('uuid', $destination_uuid)->first();
}
if (!$destination) {
throw new \Exception('Destination not found. What?!');
}
$destination_class = $destination->getMorphClass();
$project = Project::where('uuid', $this->parameters['project_uuid'])->first();
$environment = $project->load(['environments'])->environments->where('name', $this->parameters['environment_name'])->first();
$application = Application::create([
'name' => generate_application_name($this->selected_repository_owner . '/' . $this->selected_repository_repo, $this->selected_branch_name),
'repository_project_id' => $this->selected_repository_id,
'git_repository' => "{$this->selected_repository_owner}/{$this->selected_repository_repo}",
'git_branch' => $this->selected_branch_name,
'build_pack' => 'nixpacks',
'ports_exposes' => $this->port,
'publish_directory' => $this->publish_directory,
'environment_id' => $environment->id,
'destination_id' => $destination->id,
'destination_type' => $destination_class,
'source_id' => $this->github_app->id,
'source_type' => $this->github_app->getMorphClass()
]);
$application->settings->is_static = $this->is_static;
$application->settings->save();
$fqdn = generateFqdn($destination->server, $application->uuid);
$application->fqdn = $fqdn;
$application->name = generate_application_name($this->selected_repository_owner . '/' . $this->selected_repository_repo, $this->selected_branch_name, $application->uuid);
$application->save();
redirect()->route('project.application.configuration', [
'application_uuid' => $application->uuid,
'environment_name' => $environment->name,
'project_uuid' => $project->uuid,
]);
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function instantSave()
{
if ($this->is_static) {
$this->port = 80;
$this->publish_directory = '/dist';
} else {
$this->port = 3000;
$this->publish_directory = null;
}
$this->emit('success', 'Application settings updated!');
}
}

View File

@@ -1,164 +0,0 @@
<?php
namespace App\Http\Livewire\Project\New;
use App\Models\Application;
use App\Models\GithubApp;
use App\Models\GitlabApp;
use App\Models\PrivateKey;
use App\Models\Project;
use App\Models\StandaloneDocker;
use App\Models\SwarmDocker;
use Livewire\Component;
use Spatie\Url\Url;
use Illuminate\Support\Str;
class GithubPrivateRepositoryDeployKey extends Component
{
public $current_step = 'private_keys';
public $parameters;
public $query;
public $private_keys;
public int $private_key_id;
public int $port = 3000;
public string $type;
public bool $is_static = false;
public null|string $publish_directory = null;
public string $repository_url;
public string $branch;
protected $rules = [
'repository_url' => 'required',
'branch' => 'required|string',
'port' => 'required|numeric',
'is_static' => 'required|boolean',
'publish_directory' => 'nullable|string',
];
protected $validationAttributes = [
'repository_url' => 'Repository',
'branch' => 'Branch',
'port' => 'Port',
'is_static' => 'Is static',
'publish_directory' => 'Publish directory',
];
private object $repository_url_parsed;
private GithubApp|GitlabApp|string $git_source = 'other';
private ?string $git_host = null;
private string $git_repository;
public function mount()
{
if (isDev()) {
$this->repository_url = 'https://github.com/coollabsio/coolify-examples';
}
$this->parameters = get_route_parameters();
$this->query = request()->query();
$this->private_keys = PrivateKey::where('team_id', currentTeam()->id)->where('id', '!=', 0)->get();
}
public function instantSave()
{
if ($this->is_static) {
$this->port = 80;
$this->publish_directory = '/dist';
} else {
$this->port = 3000;
$this->publish_directory = null;
}
}
public function setPrivateKey($private_key_id)
{
$this->private_key_id = $private_key_id;
$this->current_step = 'repository';
}
public function submit()
{
$this->validate();
try {
$destination_uuid = $this->query['destination'];
$destination = StandaloneDocker::where('uuid', $destination_uuid)->first();
if (!$destination) {
$destination = SwarmDocker::where('uuid', $destination_uuid)->first();
}
if (!$destination) {
throw new \Exception('Destination not found. What?!');
}
$destination_class = $destination->getMorphClass();
$this->get_git_source();
$project = Project::where('uuid', $this->parameters['project_uuid'])->first();
$environment = $project->load(['environments'])->environments->where('name', $this->parameters['environment_name'])->first();
if ($this->git_source === 'other') {
$application_init = [
'name' => generate_random_name(),
'git_repository' => $this->git_repository,
'git_branch' => $this->branch,
'build_pack' => 'nixpacks',
'ports_exposes' => $this->port,
'publish_directory' => $this->publish_directory,
'environment_id' => $environment->id,
'destination_id' => $destination->id,
'destination_type' => $destination_class,
'private_key_id' => $this->private_key_id,
];
} else {
$application_init = [
'name' => generate_random_name(),
'git_repository' => $this->git_repository,
'git_branch' => $this->branch,
'build_pack' => 'nixpacks',
'ports_exposes' => $this->port,
'publish_directory' => $this->publish_directory,
'environment_id' => $environment->id,
'destination_id' => $destination->id,
'destination_type' => $destination_class,
'private_key_id' => $this->private_key_id,
'source_id' => $this->git_source->id,
'source_type' => $this->git_source->getMorphClass()
];
}
$application = Application::create($application_init);
$application->settings->is_static = $this->is_static;
$application->settings->save();
$fqdn = generateFqdn($destination->server, $application->uuid);
$application->fqdn = $fqdn;
$application->name = generate_random_name($application->uuid);
$application->save();
return redirect()->route('project.application.configuration', [
'project_uuid' => $project->uuid,
'environment_name' => $environment->name,
'application_uuid' => $application->uuid,
]);
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
private function get_git_source()
{
$this->repository_url_parsed = Url::fromString($this->repository_url);
$this->git_host = $this->repository_url_parsed->getHost();
$this->git_repository = $this->repository_url_parsed->getSegment(1) . '/' . $this->repository_url_parsed->getSegment(2);
if ($this->git_host == 'github.com') {
$this->git_source = GithubApp::where('name', 'Public GitHub')->first();
return;
}
if (Str::of($this->repository_url)->startsWith('http')) {
$this->git_host = $this->repository_url_parsed->getHost();
$this->git_repository = $this->repository_url_parsed->getSegment(1) . '/' . $this->repository_url_parsed->getSegment(2);
$this->git_repository = Str::finish("git@$this->git_host:$this->git_repository", '.git');
} else {
$this->git_repository = $this->repository_url;
}
$this->git_source = 'other';
}
}

View File

@@ -1,196 +0,0 @@
<?php
namespace App\Http\Livewire\Project\New;
use App\Models\Application;
use App\Models\GithubApp;
use App\Models\GitlabApp;
use App\Models\Project;
use App\Models\StandaloneDocker;
use App\Models\SwarmDocker;
use Carbon\Carbon;
use Livewire\Component;
use Spatie\Url\Url;
class PublicGitRepository extends Component
{
public string $repository_url;
public int $port = 3000;
public string $type;
public $parameters;
public $query;
public bool $branch_found = false;
public string $selected_branch = 'main';
public bool $is_static = false;
public string|null $publish_directory = null;
public string $git_branch = 'main';
public int $rate_limit_remaining = 0;
public $rate_limit_reset = 0;
private object $repository_url_parsed;
public GithubApp|GitlabApp|string $git_source = 'other';
public string $git_host;
public string $git_repository;
protected $rules = [
'repository_url' => 'required|url',
'port' => 'required|numeric',
'is_static' => 'required|boolean',
'publish_directory' => 'nullable|string',
];
protected $validationAttributes = [
'repository_url' => 'repository',
'port' => 'port',
'is_static' => 'static',
'publish_directory' => 'publish directory',
];
public function mount()
{
if (isDev()) {
$this->repository_url = 'https://github.com/coollabsio/coolify-examples';
$this->port = 3000;
}
$this->parameters = get_route_parameters();
$this->query = request()->query();
}
public function instantSave()
{
if ($this->is_static) {
$this->port = 80;
$this->publish_directory = '/dist';
} else {
$this->port = 3000;
$this->publish_directory = null;
}
$this->emit('success', 'Application settings updated!');
}
public function load_any_git()
{
$this->branch_found = true;
}
public function load_branch()
{
try {
$this->validate([
'repository_url' => 'required|url'
]);
} catch (\Throwable $e) {
return handleError($e, $this);
}
try {
$this->branch_found = false;
$this->get_git_source();
$this->get_branch();
$this->selected_branch = $this->git_branch;
} catch (\Throwable $e) {
ray($e->getMessage());
if (!$this->branch_found && $this->git_branch == 'main') {
try {
$this->git_branch = 'master';
$this->get_branch();
} catch (\Throwable $e) {
return handleError($e, $this);
}
} else {
return handleError($e, $this);
}
}
}
private function get_git_source()
{
$this->repository_url_parsed = Url::fromString($this->repository_url);
$this->git_host = $this->repository_url_parsed->getHost();
$this->git_repository = $this->repository_url_parsed->getSegment(1) . '/' . $this->repository_url_parsed->getSegment(2);
$this->git_branch = $this->repository_url_parsed->getSegment(4) ?? 'main';
if ($this->git_host == 'github.com') {
$this->git_source = GithubApp::where('name', 'Public GitHub')->first();
return;
}
$this->git_repository = $this->repository_url;
$this->git_source = 'other';
}
private function get_branch()
{
if ($this->git_source === 'other') {
$this->branch_found = true;
return;
}
if ($this->git_source->getMorphClass() === 'App\Models\GithubApp') {
['rate_limit_remaining' => $this->rate_limit_remaining, 'rate_limit_reset' => $this->rate_limit_reset] = githubApi(source: $this->git_source, endpoint: "/repos/{$this->git_repository}/branches/{$this->git_branch}");
$this->rate_limit_reset = Carbon::parse((int)$this->rate_limit_reset)->format('Y-M-d H:i:s');
$this->branch_found = true;
}
}
public function submit()
{
try {
$this->validate();
$destination_uuid = $this->query['destination'];
$project_uuid = $this->parameters['project_uuid'];
$environment_name = $this->parameters['environment_name'];
$destination = StandaloneDocker::where('uuid', $destination_uuid)->first();
if (!$destination) {
$destination = SwarmDocker::where('uuid', $destination_uuid)->first();
}
if (!$destination) {
throw new \Exception('Destination not found. What?!');
}
$destination_class = $destination->getMorphClass();
$project = Project::where('uuid', $project_uuid)->first();
$environment = $project->load(['environments'])->environments->where('name', $environment_name)->first();
if ($this->git_source === 'other') {
$application_init = [
'name' => generate_random_name(),
'git_repository' => $this->git_repository,
'git_branch' => $this->git_branch,
'build_pack' => 'nixpacks',
'ports_exposes' => $this->port,
'publish_directory' => $this->publish_directory,
'environment_id' => $environment->id,
'destination_id' => $destination->id,
'destination_type' => $destination_class,
];
} else {
$application_init = [
'name' => generate_application_name($this->git_repository, $this->git_branch),
'git_repository' => $this->git_repository,
'git_branch' => $this->git_branch,
'build_pack' => 'nixpacks',
'ports_exposes' => $this->port,
'publish_directory' => $this->publish_directory,
'environment_id' => $environment->id,
'destination_id' => $destination->id,
'destination_type' => $destination_class,
'source_id' => $this->git_source->id,
'source_type' => $this->git_source->getMorphClass()
];
}
$application = Application::create($application_init);
$application->settings->is_static = $this->is_static;
$application->settings->save();
$fqdn = generateFqdn($destination->server, $application->uuid);
$application->fqdn = $fqdn;
$application->save();
return redirect()->route('project.application.configuration', [
'project_uuid' => $project->uuid,
'environment_name' => $environment->name,
'application_uuid' => $application->uuid,
]);
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
}

View File

@@ -1,149 +0,0 @@
<?php
namespace App\Http\Livewire\Project\New;
use App\Models\Project;
use App\Models\Server;
use Countable;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cache;
use Livewire\Component;
class Select extends Component
{
public $current_step = 'type';
public ?int $server = null;
public string $type;
public string $server_id;
public string $destination_uuid;
public Countable|array|Server $servers = [];
public Collection|array $standaloneDockers = [];
public Collection|array $swarmDockers = [];
public array $parameters;
public Collection|array $services = [];
public Collection|array $allServices = [];
public bool $loadingServices = true;
public bool $loading = false;
public $environments = [];
public ?string $selectedEnvironment = null;
public ?string $existingPostgresqlUrl = null;
public ?string $search = null;
protected $queryString = [
'server',
'search'
];
public function mount()
{
$this->parameters = get_route_parameters();
if (isDev()) {
$this->existingPostgresqlUrl = 'postgres://coolify:password@coolify-db:5432';
}
$projectUuid = data_get($this->parameters, 'project_uuid');
$this->environments = Project::whereUuid($projectUuid)->first()->environments;
$this->selectedEnvironment = data_get($this->parameters, 'environment_name');
}
public function render()
{
if ($this->search) $this->loadServices();
return view('livewire.project.new.select');
}
public function updatedSelectedEnvironment()
{
return redirect()->route('project.resources.new', [
'project_uuid' => $this->parameters['project_uuid'],
'environment_name' => $this->selectedEnvironment,
]);
}
// public function addExistingPostgresql()
// {
// try {
// instantCommand("psql {$this->existingPostgresqlUrl} -c 'SELECT 1'");
// $this->emit('success', 'Successfully connected to the database.');
// } catch (\Throwable $e) {
// return handleError($e, $this);
// }
// }
public function loadServices()
{
try {
if (count($this->allServices) > 0) {
if (!$this->search) {
$this->services = $this->allServices;
return;
}
$this->services = $this->allServices->filter(function ($service, $key) {
$tags = collect(data_get($service, 'tags', []));
return str_contains(strtolower($key), strtolower($this->search)) || $tags->contains(function ($tag) {
return str_contains(strtolower($tag), strtolower($this->search));
});
});
} else {
$this->search = null;
$this->allServices = getServiceTemplates();
$this->services = $this->allServices->filter(function ($service, $key) {
return str_contains(strtolower($key), strtolower($this->search));
});;
$this->emit('success', 'Successfully loaded services.');
}
} catch (\Throwable $e) {
return handleError($e, $this);
} finally {
$this->loadingServices = false;
}
}
public function setType(string $type)
{
$this->type = $type;
if ($this->loading) return;
$this->loading = true;
if ($type === "existing-postgresql") {
$this->current_step = $type;
return;
}
if (count($this->servers) === 1) {
$server = $this->servers->first();
$this->setServer($server);
if (count($server->destinations()) === 1) {
$this->setDestination($server->destinations()->first()->uuid);
}
}
if (!is_null($this->server)) {
$foundServer = $this->servers->where('id', $this->server)->first();
if ($foundServer) {
return $this->setServer($foundServer);
}
}
$this->current_step = 'servers';
}
public function setServer(Server $server)
{
$this->server_id = $server->id;
$this->standaloneDockers = $server->standaloneDockers;
$this->swarmDockers = $server->swarmDockers;
$this->current_step = 'destinations';
}
public function setDestination(string $destination_uuid)
{
$this->destination_uuid = $destination_uuid;
redirect()->route('project.resources.new', [
'project_uuid' => $this->parameters['project_uuid'],
'environment_name' => $this->parameters['environment_name'],
'type' => $this->type,
'destination' => $this->destination_uuid,
'server_id' => $this->server_id,
]);
}
public function loadServers()
{
$this->servers = Server::isUsable()->get();
}
}

View File

@@ -1,79 +0,0 @@
<?php
namespace App\Http\Livewire\Project\New;
use App\Models\Application;
use App\Models\GithubApp;
use App\Models\Project;
use App\Models\StandaloneDocker;
use App\Models\SwarmDocker;
use Livewire\Component;
use Visus\Cuid2\Cuid2;
class SimpleDockerfile extends Component
{
public string $dockerfile = '';
public array $parameters;
public array $query;
public function mount()
{
$this->parameters = get_route_parameters();
$this->query = request()->query();
if (isDev()) {
$this->dockerfile = 'FROM nginx
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
';
}
}
public function submit()
{
$this->validate([
'dockerfile' => 'required'
]);
$destination_uuid = $this->query['destination'];
$destination = StandaloneDocker::where('uuid', $destination_uuid)->first();
if (!$destination) {
$destination = SwarmDocker::where('uuid', $destination_uuid)->first();
}
if (!$destination) {
throw new \Exception('Destination not found. What?!');
}
$destination_class = $destination->getMorphClass();
$project = Project::where('uuid', $this->parameters['project_uuid'])->first();
$environment = $project->load(['environments'])->environments->where('name', $this->parameters['environment_name'])->first();
$port = get_port_from_dockerfile($this->dockerfile);
if (!$port) {
$port = 80;
}
$application = Application::create([
'name' => 'dockerfile-' . new Cuid2(7),
'repository_project_id' => 0,
'git_repository' => "coollabsio/coolify",
'git_branch' => 'main',
'build_pack' => 'dockerfile',
'dockerfile' => $this->dockerfile,
'ports_exposes' => $port,
'environment_id' => $environment->id,
'destination_id' => $destination->id,
'destination_type' => $destination_class,
'health_check_enabled' => false,
'source_id' => 0,
'source_type' => GithubApp::class
]);
$fqdn = generateFqdn($destination->server, $application->uuid);
$application->update([
'name' => 'dockerfile-' . $application->uuid,
'fqdn' => $fqdn
]);
redirect()->route('project.application.configuration', [
'application_uuid' => $application->uuid,
'environment_name' => $environment->name,
'project_uuid' => $project->uuid,
]);
}
}

View File

@@ -1,66 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Service;
use App\Models\ServiceApplication;
use Livewire\Component;
class Application extends Component
{
public ServiceApplication $application;
public $parameters;
protected $rules = [
'application.human_name' => 'nullable',
'application.description' => 'nullable',
'application.fqdn' => 'nullable',
'application.image' => 'required',
'application.exclude_from_status' => 'required|boolean',
'application.required_fqdn' => 'required|boolean',
'application.is_log_drain_enabled' => 'nullable|boolean',
];
public function render()
{
return view('livewire.project.service.application');
}
public function instantSave()
{
$this->submit();
}
public function instantSaveAdvanced()
{
if (!$this->application->service->destination->server->isLogDrainEnabled()) {
$this->application->is_log_drain_enabled = false;
$this->emit('error', 'Log drain is not enabled on the server. Please enable it first.');
return;
}
$this->application->save();
$this->emit('success', 'You need to restart the service for the changes to take effect.');
}
public function delete()
{
try {
$this->application->delete();
$this->emit('success', 'Application deleted successfully.');
return redirect()->route('project.service.configuration', $this->parameters);
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function mount()
{
$this->parameters = get_route_parameters();
}
public function submit()
{
try {
$this->validate();
$this->application->save();
updateCompose($this->application);
$this->emit('success', 'Application saved successfully.');
} catch (\Throwable $e) {
return handleError($e, $this);
} finally {
$this->emit('generateDockerCompose');
}
}
}

View File

@@ -1,87 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Service;
use App\Actions\Database\StartDatabaseProxy;
use App\Actions\Database\StopDatabaseProxy;
use App\Models\ServiceDatabase;
use Livewire\Component;
class Database extends Component
{
public ServiceDatabase $database;
public ?string $db_url_public = null;
public $fileStorages;
protected $listeners = ["refreshFileStorages"];
protected $rules = [
'database.human_name' => 'nullable',
'database.description' => 'nullable',
'database.image' => 'required',
'database.exclude_from_status' => 'required|boolean',
'database.public_port' => 'nullable|integer',
'database.is_public' => 'required|boolean',
'database.is_log_drain_enabled' => 'required|boolean',
];
public function render()
{
return view('livewire.project.service.database');
}
public function mount()
{
if ($this->database->is_public) {
$this->db_url_public = $this->database->getServiceDatabaseUrl();
}
$this->refreshFileStorages();
}
public function instantSaveAdvanced()
{
if (!$this->database->service->destination->server->isLogDrainEnabled()) {
$this->database->is_log_drain_enabled = false;
$this->emit('error', 'Log drain is not enabled on the server. Please enable it first.');
return;
}
$this->submit();
$this->emit('success', 'You need to restart the service for the changes to take effect.');
}
public function instantSave()
{
if ($this->database->is_public && !$this->database->public_port) {
$this->emit('error', 'Public port is required.');
$this->database->is_public = false;
return;
}
if ($this->database->is_public) {
if (!str($this->database->status)->startsWith('running')) {
$this->emit('error', 'Database must be started to be publicly accessible.');
$this->database->is_public = false;
return;
}
StartDatabaseProxy::run($this->database);
$this->db_url_public = $this->database->getServiceDatabaseUrl();
$this->emit('success', 'Database is now publicly accessible.');
} else {
StopDatabaseProxy::run($this->database);
$this->db_url_public = null;
$this->emit('success', 'Database is no longer publicly accessible.');
}
$this->submit();
}
public function refreshFileStorages()
{
$this->fileStorages = $this->database->fileStorages()->get();
}
public function submit()
{
try {
$this->validate();
$this->database->save();
updateCompose($this->database);
$this->emit('success', 'Database saved successfully.');
} catch (\Throwable $e) {
ray($e);
} finally {
$this->emit('generateDockerCompose');
}
}
}

View File

@@ -1,60 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Service;
use App\Models\LocalFileVolume;
use App\Models\ServiceApplication;
use App\Models\ServiceDatabase;
use Livewire\Component;
use Illuminate\Support\Str;
class FileStorage extends Component
{
public LocalFileVolume $fileStorage;
public ServiceApplication|ServiceDatabase $service;
public string $fs_path;
public ?string $workdir = null;
protected $rules = [
'fileStorage.is_directory' => 'required',
'fileStorage.fs_path' => 'required',
'fileStorage.mount_path' => 'required',
'fileStorage.content' => 'nullable',
];
public function mount()
{
$this->service = $this->fileStorage->service;
if (Str::of($this->fileStorage->fs_path)->startsWith('.')) {
$this->workdir = $this->service->service->workdir();
$this->fs_path = Str::of($this->fileStorage->fs_path)->after('.');
} else {
$this->workdir = null;
$this->fs_path = $this->fileStorage->fs_path;
}
}
public function submit()
{
$original = $this->fileStorage->getOriginal();
try {
$this->validate();
if ($this->fileStorage->is_directory) {
$this->fileStorage->content = null;
}
$this->fileStorage->save();
$this->fileStorage->saveStorageOnServer($this->service);
$this->emit('success', 'File updated successfully.');
} catch (\Throwable $e) {
$this->fileStorage->setRawAttributes($original);
$this->fileStorage->save();
return handleError($e, $this);
}
}
public function instantSave()
{
$this->submit();
}
public function render()
{
return view('livewire.project.service.file-storage');
}
}

View File

@@ -1,45 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Service;
use App\Jobs\ContainerStatusJob;
use App\Models\Service;
use Livewire\Component;
class Index extends Component
{
public Service $service;
public $applications;
public $databases;
public array $parameters;
public array $query;
protected $listeners = ["refreshStacks", "checkStatus"];
public function render()
{
return view('livewire.project.service.index');
}
public function mount()
{
$this->parameters = get_route_parameters();
$this->query = request()->query();
$this->service = Service::whereUuid($this->parameters['service_uuid'])->firstOrFail();
$this->applications = $this->service->applications->sort();
$this->databases = $this->service->databases->sort();
}
public function checkStatus()
{
dispatch(new ContainerStatusJob($this->service->server));
$this->refreshStacks();
}
public function refreshStacks()
{
$this->applications = $this->service->applications->sort();
$this->applications->each(function ($application) {
$application->refresh();
});
$this->databases = $this->service->databases->sort();
$this->databases->each(function ($database) {
$database->refresh();
});
}
}

View File

@@ -1,16 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Service;
use Livewire\Component;
class Modal extends Component
{
public function checkStatus() {
$this->emit('checkStatus');
}
public function render()
{
return view('livewire.project.service.modal');
}
}

View File

@@ -1,41 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Service;
use App\Actions\Service\StartService;
use App\Actions\Service\StopService;
use App\Models\Service;
use Livewire\Component;
class Navbar extends Component
{
public Service $service;
public array $parameters;
public array $query;
protected $listeners = ["checkStatus"];
public function render()
{
return view('livewire.project.service.navbar');
}
public function checkStatus() {
$this->service->refresh();
}
public function deploy()
{
$this->service->parse();
$activity = StartService::run($this->service);
$this->emit('newMonitorActivity', $activity->id);
}
public function stop(bool $forceCleanup = false)
{
StopService::run($this->service);
$this->service->refresh();
if ($forceCleanup) {
$this->emit('success', 'Force cleanup service successfully.');
} else {
$this->emit('success', 'Service stopped successfully.');
}
$this->emit('checkStatus');
}
}

View File

@@ -1,52 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Service;
use App\Models\Service;
use App\Models\ServiceApplication;
use App\Models\ServiceDatabase;
use Illuminate\Support\Collection;
use Livewire\Component;
class Show extends Component
{
public Service $service;
public ?ServiceApplication $serviceApplication = null;
public ?ServiceDatabase $serviceDatabase = null;
public array $parameters;
public array $query;
public Collection $services;
public $s3s;
protected $listeners = ['generateDockerCompose'];
public function mount()
{
try {
$this->services = collect([]);
$this->parameters = get_route_parameters();
$this->query = request()->query();
$this->service = Service::whereUuid($this->parameters['service_uuid'])->firstOrFail();
$service = $this->service->applications()->whereName($this->parameters['service_name'])->first();
if ($service) {
$this->serviceApplication = $service;
$this->serviceApplication->getFilesFromServer();
} else {
$this->serviceDatabase = $this->service->databases()->whereName($this->parameters['service_name'])->first();
$this->serviceDatabase->getFilesFromServer();
}
$this->s3s = currentTeam()->s3s;
} catch(\Throwable $e) {
return handleError($e, $this);
}
}
public function generateDockerCompose()
{
$this->service->parse();
}
public function render()
{
return view('livewire.project.service.show');
}
}

View File

@@ -1,68 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Service;
use Livewire\Component;
class StackForm extends Component
{
public $service;
public $fields = [];
protected $listeners = ["saveCompose"];
public $rules = [
'service.docker_compose_raw' => 'required',
'service.docker_compose' => 'required',
'service.name' => 'required',
'service.description' => 'nullable',
];
public $validationAttributes = [];
public function mount()
{
$extraFields = $this->service->extraFields();
foreach ($extraFields as $serviceName => $fields) {
foreach ($fields as $fieldKey => $field) {
$key = data_get($field, 'key');
$value = data_get($field, 'value');
$rules = data_get($field, 'rules', 'nullable');
$isPassword = data_get($field, 'isPassword');
$this->fields[$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;
}
}
}
public function saveCompose($raw)
{
$this->service->docker_compose_raw = $raw;
$this->submit();
}
public function submit()
{
try {
$this->validate();
$this->service->save();
$this->service->saveExtraFields($this->fields);
$this->service->parse();
$this->service->refresh();
$this->service->saveComposeConfigs();
$this->emit('refreshStacks');
$this->emit('refreshEnvs');
$this->emit('success', 'Service saved successfully.');
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function render()
{
return view('livewire.project.service.stack-form');
}
}

View File

@@ -1,35 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Service;
use App\Models\LocalPersistentVolume;
use Livewire\Component;
class Storage extends Component
{
protected $listeners = ['addNewVolume'];
public $resource;
public function render()
{
return view('livewire.project.service.storage');
}
public function addNewVolume($data)
{
try {
LocalPersistentVolume::create([
'name' => $data['name'],
'mount_path' => $data['mount_path'],
'host_path' => $data['host_path'],
'resource_id' => $this->resource->id,
'resource_type' => $this->resource->getMorphClass(),
]);
$this->resource->refresh();
$this->emit('success', 'Storage added successfully');
$this->emit('clearAddStorage');
$this->emit('refreshStorages');
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
}

View File

@@ -1,33 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Shared;
use App\Jobs\DeleteResourceJob;
use Livewire\Component;
use Visus\Cuid2\Cuid2;
class Danger extends Component
{
public $resource;
public array $parameters;
public ?string $modalId = null;
public function mount()
{
$this->modalId = new Cuid2(7);
$this->parameters = get_route_parameters();
}
public function delete()
{
try {
DeleteResourceJob::dispatchSync($this->resource);
return redirect()->route('project.resources', [
'project_uuid' => $this->parameters['project_uuid'],
'environment_name' => $this->parameters['environment_name']
]);
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
}

View File

@@ -1,12 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Shared;
use Livewire\Component;
class Destination extends Component
{
public $resource;
public $servers = [];
public $additionalServers = [];
}

View File

@@ -1,51 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Shared\EnvironmentVariable;
use Livewire\Component;
class Add extends Component
{
public $parameters;
public bool $is_preview = false;
public string $key;
public ?string $value = null;
public bool $is_build_time = false;
protected $listeners = ['clearAddEnv' => 'clear'];
protected $rules = [
'key' => 'required|string',
'value' => 'nullable',
'is_build_time' => 'required|boolean',
];
protected $validationAttributes = [
'key' => 'key',
'value' => 'value',
'is_build_time' => 'build',
];
public function mount()
{
$this->parameters = get_route_parameters();
}
public function submit()
{
$this->validate();
ray($this->key, $this->value, $this->is_build_time);
$this->emitUp('submit', [
'key' => $this->key,
'value' => $this->value,
'is_build_time' => $this->is_build_time,
'is_preview' => $this->is_preview,
]);
$this->clear();
}
public function clear()
{
$this->key = '';
$this->value = '';
$this->is_build_time = false;
}
}

View File

@@ -1,153 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Shared\EnvironmentVariable;
use App\Models\EnvironmentVariable;
use Livewire\Component;
use Visus\Cuid2\Cuid2;
use Illuminate\Support\Str;
class All extends Component
{
public $resource;
public bool $showPreview = false;
public string|null $modalId = null;
public ?string $variables = null;
public ?string $variablesPreview = null;
public string $view = 'normal';
protected $listeners = ['refreshEnvs', 'submit'];
public function mount()
{
$resourceClass = get_class($this->resource);
$resourceWithPreviews = ['App\Models\Application'];
$simpleDockerfile = !is_null(data_get($this->resource, 'dockerfile'));
if (Str::of($resourceClass)->contains($resourceWithPreviews) && !$simpleDockerfile) {
$this->showPreview = true;
}
$this->modalId = new Cuid2(7);
$this->getDevView();
}
public function getDevView()
{
$this->variables = $this->resource->environment_variables->map(function ($item) {
if ($item->is_shown_once) {
return "$item->key=(locked secret)";
}
return "$item->key=$item->value";
})->sort()->join('
');
if ($this->showPreview) {
$this->variablesPreview = $this->resource->environment_variables_preview->map(function ($item) {
if ($item->is_shown_once) {
return "$item->key=(locked secret)";
}
return "$item->key=$item->value";
})->sort()->join('
');
}
}
public function switch()
{
$this->view = $this->view === 'normal' ? 'dev' : 'normal';
}
public function saveVariables($isPreview)
{
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();
} else {
$found = $this->resource->environment_variables()->where('key', $key)->first();
}
if ($found) {
if ($found->is_shown_once) {
continue;
}
$found->value = $variable;
$found->save();
continue;
} else {
$environment = new EnvironmentVariable();
$environment->key = $key;
$environment->value = $variable;
$environment->is_build_time = 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 'service':
$environment->service_id = $this->resource->id;
break;
}
$environment->save();
}
}
if ($isPreview) {
$this->emit('success', 'Preview environment variables updated successfully.');
} else {
$this->emit('success', 'Environment variables updated successfully.');
}
$this->refreshEnvs();
}
public function refreshEnvs()
{
$this->resource->refresh();
$this->getDevView();
}
public function submit($data)
{
try {
$found = $this->resource->environment_variables()->where('key', $data['key'])->first();
if ($found) {
$this->emit('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_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 'service':
$environment->service_id = $this->resource->id;
break;
}
$environment->save();
$this->refreshEnvs();
$this->emit('success', 'Environment variable added successfully.');
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
}

View File

@@ -1,71 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Shared\EnvironmentVariable;
use App\Models\EnvironmentVariable as ModelsEnvironmentVariable;
use Livewire\Component;
use Visus\Cuid2\Cuid2;
class Show extends Component
{
public $parameters;
public ModelsEnvironmentVariable $env;
public ?string $modalId = null;
public bool $isDisabled = false;
public bool $isLocked = false;
public string $type;
protected $rules = [
'env.key' => 'required|string',
'env.value' => 'nullable',
'env.is_build_time' => 'required|boolean',
'env.is_shown_once' => 'required|boolean',
];
protected $validationAttributes = [
'key' => 'Key',
'value' => 'Value',
'is_build_time' => 'Build Time',
'is_shown_once' => 'Shown Once',
];
public function mount()
{
$this->modalId = new Cuid2(7);
$this->parameters = get_route_parameters();
$this->checkEnvs();
}
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 ($this->env->is_shown_once) {
$this->isLocked = true;
}
}
public function lock()
{
$this->env->is_shown_once = true;
$this->env->save();
$this->checkEnvs();
$this->emit('refreshEnvs');
}
public function instantSave()
{
$this->submit();
}
public function submit()
{
$this->validate();
$this->env->save();
$this->emit('success', 'Environment variable updated successfully.');
$this->emit('refreshEnvs');
}
public function delete()
{
$this->env->delete();
$this->emit('refreshEnvs');
}
}

View File

@@ -1,110 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Shared;
use App\Models\Application;
use App\Models\Server;
use App\Models\Service;
use App\Models\StandaloneMariadb;
use App\Models\StandaloneMongodb;
use App\Models\StandaloneMysql;
use App\Models\StandalonePostgresql;
use App\Models\StandaloneRedis;
use Livewire\Component;
class ExecuteContainerCommand extends Component
{
public string $command;
public string $container;
public $containers;
public $parameters;
public $resource;
public string $type;
public string $workDir = '';
public Server $server;
public $servers = [];
protected $rules = [
'server' => 'required',
'container' => 'required',
'command' => 'required',
'workDir' => 'nullable',
];
public function mount()
{
$this->containers = collect();
$this->parameters = get_route_parameters();
if (data_get($this->parameters, 'application_uuid')) {
$this->type = 'application';
$this->resource = Application::where('uuid', $this->parameters['application_uuid'])->firstOrFail();
$this->server = $this->resource->destination->server;
$containers = getCurrentApplicationContainerStatus($this->server, $this->resource->id, 0);
if ($containers->count() > 0) {
$containers->each(function ($container) {
$this->containers->push(str_replace('/', '', $container['Names']));
});
}
} else if (data_get($this->parameters, 'database_uuid')) {
$this->type = 'database';
$resource = StandalonePostgresql::where('uuid', $this->parameters['database_uuid'])->first();
if (is_null($resource)) {
$resource = StandaloneRedis::where('uuid', $this->parameters['database_uuid'])->first();
if (is_null($resource)) {
$resource = StandaloneMongodb::where('uuid', $this->parameters['database_uuid'])->first();
if (is_null($resource)) {
$resource = StandaloneMysql::where('uuid', $this->parameters['database_uuid'])->first();
if (is_null($resource)) {
$resource = StandaloneMariadb::where('uuid', $this->parameters['database_uuid'])->first();
if (is_null($resource)) {
abort(404);
}
}
}
}
}
$this->resource = $resource;
$this->server = $this->resource->destination->server;
$this->container = $this->resource->uuid;
$this->containers->push($this->container);
} else if (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) {
if (str(data_get($application, 'status'))->contains('running')) {
$this->containers->push(data_get($application, 'name') . '-' . data_get($this->resource, 'uuid'));
}
});
$this->resource->databases()->get()->each(function ($database) {
if (str(data_get($database, 'status'))->contains('running')) {
$this->containers->push(data_get($database, 'name') . '-' . data_get($this->resource, 'uuid'));
}
});
$this->server = $this->resource->server;
}
if ($this->containers->count() > 0) {
$this->container = $this->containers->first();
}
}
public function runCommand()
{
$this->validate();
try {
if (!empty($this->workDir)) {
$exec = "docker exec -w {$this->workDir} {$this->container} {$this->command}";
} else {
$exec = "docker exec {$this->container} {$this->command}";
}
$activity = remote_process([$exec], $this->server, ignore_errors: true);
$this->emit('newMonitorActivity', $activity->id);
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function render()
{
return view('livewire.project.shared.execute-container-command');
}
}

View File

@@ -1,88 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Shared;
use App\Models\Application;
use App\Models\Server;
use App\Models\Service;
use App\Models\ServiceApplication;
use App\Models\ServiceDatabase;
use App\Models\StandaloneMariadb;
use App\Models\StandaloneMongodb;
use App\Models\StandaloneMysql;
use App\Models\StandalonePostgresql;
use App\Models\StandaloneRedis;
use Illuminate\Support\Facades\Process;
use Livewire\Component;
class GetLogs extends Component
{
public string $outputs = '';
public string $errors = '';
public Application|Service|StandalonePostgresql|StandaloneRedis|StandaloneMongodb|StandaloneMysql|StandaloneMariadb $resource;
public ServiceApplication|ServiceDatabase|null $servicesubtype = null;
public Server $server;
public ?string $container = null;
public ?bool $streamLogs = false;
public ?bool $showTimeStamps = true;
public int $numberOfLines = 100;
public function mount()
{
if ($this->resource->getMorphClass() === 'App\Models\Application') {
$this->showTimeStamps = $this->resource->settings->is_include_timestamps;
} else {
if ($this->servicesubtype) {
$this->showTimeStamps = $this->servicesubtype->is_include_timestamps;
} else {
$this->showTimeStamps = $this->resource->is_include_timestamps;
}
}
}
public function doSomethingWithThisChunkOfOutput($output)
{
$this->outputs .= removeAnsiColors($output);
}
public function instantSave()
{
if ($this->resource->getMorphClass() === 'App\Models\Application') {
$this->resource->settings->is_include_timestamps = $this->showTimeStamps;
$this->resource->settings->save();
} else {
if ($this->servicesubtype) {
$this->servicesubtype->is_include_timestamps = $this->showTimeStamps;
$this->servicesubtype->save();
} else {
$this->resource->is_include_timestamps = $this->showTimeStamps;
$this->resource->save();
}
}
}
public function getLogs($refresh = false)
{
if ($this->container) {
if ($this->showTimeStamps) {
$sshCommand = generateSshCommand($this->server, "docker logs -n {$this->numberOfLines} -t {$this->container}");
} else {
$sshCommand = generateSshCommand($this->server, "docker logs -n {$this->numberOfLines} {$this->container}");
}
if ($refresh) {
$this->outputs = '';
}
Process::run($sshCommand, function (string $type, string $output) {
$this->doSomethingWithThisChunkOfOutput($output);
});
if ($this->showTimeStamps) {
$this->outputs = str($this->outputs)->split('/\n/')->sort(function ($a, $b) {
$a = explode(' ', $a);
$b = explode(' ', $b);
return $a[0] <=> $b[0];
})->join("\n");
}
}
}
public function render()
{
return view('livewire.project.shared.get-logs');
}
}

View File

@@ -1,47 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Shared;
use Livewire\Component;
class HealthChecks extends Component
{
public $resource;
protected $rules = [
'resource.health_check_enabled' => 'boolean',
'resource.health_check_path' => 'string',
'resource.health_check_port' => 'nullable|string',
'resource.health_check_host' => 'string',
'resource.health_check_method' => 'string',
'resource.health_check_return_code' => 'integer',
'resource.health_check_scheme' => 'string',
'resource.health_check_response_text' => 'nullable|string',
'resource.health_check_interval' => 'integer',
'resource.health_check_timeout' => 'integer',
'resource.health_check_retries' => 'integer',
'resource.health_check_start_period' => 'integer',
];
public function instantSave()
{
$this->resource->save();
$this->emit('success', 'Health check updated.');
}
public function submit()
{
try {
$this->validate();
$this->resource->save();
$this->emit('success', 'Health check updated.');
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function render()
{
return view('livewire.project.shared.health-checks');
}
}

View File

@@ -1,83 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Shared;
use App\Models\Application;
use App\Models\Server;
use App\Models\Service;
use App\Models\StandaloneMariadb;
use App\Models\StandaloneMongodb;
use App\Models\StandaloneMysql;
use App\Models\StandalonePostgresql;
use App\Models\StandaloneRedis;
use Livewire\Component;
class Logs extends Component
{
public ?string $type = null;
public Application|Service|StandalonePostgresql|StandaloneRedis|StandaloneMongodb|StandaloneMysql|StandaloneMariadb $resource;
public Server $server;
public $container = [];
public $containers;
public $parameters;
public $query;
public $status;
public $serviceSubType;
public function mount()
{
$this->containers = collect();
$this->parameters = get_route_parameters();
$this->query = request()->query();
if (data_get($this->parameters, 'application_uuid')) {
$this->type = 'application';
$this->resource = Application::where('uuid', $this->parameters['application_uuid'])->firstOrFail();
$this->status = $this->resource->status;
$this->server = $this->resource->destination->server;
$containers = getCurrentApplicationContainerStatus($this->server, $this->resource->id, 0);
if ($containers->count() > 0) {
$containers->each(function ($container) {
$this->containers->push(str_replace('/', '', $container['Names']));
});
}
} else if (data_get($this->parameters, 'database_uuid')) {
$this->type = 'database';
$resource = StandalonePostgresql::where('uuid', $this->parameters['database_uuid'])->first();
if (is_null($resource)) {
$resource = StandaloneRedis::where('uuid', $this->parameters['database_uuid'])->first();
if (is_null($resource)) {
$resource = StandaloneMongodb::where('uuid', $this->parameters['database_uuid'])->first();
if (is_null($resource)) {
$resource = StandaloneMysql::where('uuid', $this->parameters['database_uuid'])->first();
if (is_null($resource)) {
$resource = StandaloneMariadb::where('uuid', $this->parameters['database_uuid'])->first();
if (is_null($resource)) {
abort(404);
}
}
}
}
}
$this->resource = $resource;
$this->status = $this->resource->status;
$this->server = $this->resource->destination->server;
$this->container = $this->resource->uuid;
} else if (data_get($this->parameters, 'service_uuid')) {
$this->type = 'service';
$this->resource = Service::where('uuid', $this->parameters['service_uuid'])->firstOrFail();
$service_name = data_get($this->parameters, 'service_name');
$this->serviceSubType = $this->resource->applications()->where('name', $service_name)->first();
if (!$this->serviceSubType) {
$this->serviceSubType = $this->resource->databases()->where('name', $service_name)->first();
}
$this->status = $this->resource->status;
$this->server = $this->resource->server;
$this->container = data_get($this->parameters, 'service_name') . '-' . $this->resource->uuid;
}
}
public function render()
{
return view('livewire.project.shared.logs');
}
}

View File

@@ -1,60 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Shared;
use Livewire\Component;
class ResourceLimits extends Component
{
public $resource;
protected $rules = [
'resource.limits_memory' => 'required|string',
'resource.limits_memory_swap' => 'required|string',
'resource.limits_memory_swappiness' => 'required|integer|min:0|max:100',
'resource.limits_memory_reservation' => 'required|string',
'resource.limits_cpus' => 'nullable',
'resource.limits_cpuset' => 'nullable',
'resource.limits_cpu_shares' => 'nullable',
];
protected $validationAttributes = [
'resource.limits_memory' => 'memory',
'resource.limits_memory_swap' => 'swap',
'resource.limits_memory_swappiness' => 'swappiness',
'resource.limits_memory_reservation' => 'reservation',
'resource.limits_cpus' => 'cpus',
'resource.limits_cpuset' => 'cpuset',
'resource.limits_cpu_shares' => 'cpu shares',
];
public function submit()
{
try {
if (!$this->resource->limits_memory) {
$this->resource->limits_memory = "0";
}
if (!$this->resource->limits_memory_swap) {
$this->resource->limits_memory_swap = "0";
}
if (!$this->resource->limits_memory_swappiness) {
$this->resource->limits_memory_swappiness = "60";
}
if (!$this->resource->limits_memory_reservation) {
$this->resource->limits_memory_reservation = "0";
}
if (!$this->resource->limits_cpus) {
$this->resource->limits_cpus = "0";
}
if (!$this->resource->limits_cpuset) {
$this->resource->limits_cpuset = "0";
}
if (!$this->resource->limits_cpu_shares) {
$this->resource->limits_cpu_shares = 1024;
}
$this->validate();
$this->resource->save();
$this->emit('success', 'Resource limits updated successfully.');
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
}

View File

@@ -1,49 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Shared\Storages;
use Livewire\Component;
class Add extends Component
{
public $uuid;
public $parameters;
public string $name;
public string $mount_path;
public string|null $host_path = null;
protected $listeners = ['clearAddStorage' => 'clear'];
protected $rules = [
'name' => 'required|string',
'mount_path' => 'required|string',
'host_path' => 'string|nullable',
];
protected $validationAttributes = [
'name' => 'name',
'mount_path' => 'mount',
'host_path' => 'host',
];
public function mount()
{
$this->parameters = get_route_parameters();
}
public function submit()
{
$this->validate();
$name = $this->uuid . '-' . $this->name;
$this->emit('addNewVolume', [
'name' => $name,
'mount_path' => $this->mount_path,
'host_path' => $this->host_path,
]);
}
public function clear()
{
$this->name = '';
$this->mount_path = '';
$this->host_path = null;
}
}

View File

@@ -1,17 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Shared\Storages;
use App\Models\LocalPersistentVolume;
use Livewire\Component;
class All extends Component
{
public $resource;
protected $listeners = ['refreshStorages'];
public function refreshStorages()
{
$this->resource->refresh();
}
}

View File

@@ -1,44 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Shared\Storages;
use App\Models\LocalPersistentVolume;
use Livewire\Component;
use Visus\Cuid2\Cuid2;
class Show extends Component
{
public LocalPersistentVolume $storage;
public bool $isReadOnly = false;
public ?string $modalId = null;
public bool $isFirst = true;
protected $rules = [
'storage.name' => 'required|string',
'storage.mount_path' => 'required|string',
'storage.host_path' => 'string|nullable',
];
protected $validationAttributes = [
'name' => 'name',
'mount_path' => 'mount',
'host_path' => 'host',
];
public function mount()
{
$this->modalId = new Cuid2(7);
}
public function submit()
{
$this->validate();
$this->storage->save();
$this->emit('success', 'Storage updated successfully');
}
public function delete()
{
$this->storage->delete();
$this->emit('refreshStorages');
}
}

View File

@@ -1,37 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Shared;
use Livewire\Component;
class Webhooks extends Component
{
public $resource;
public ?string $deploywebhook = null;
public ?string $githubManualWebhook = null;
public ?string $gitlabManualWebhook = null;
protected $rules = [
'resource.manual_webhook_secret_github' => 'nullable|string',
'resource.manual_webhook_secret_gitlab' => 'nullable|string',
];
public function saveSecret()
{
try {
$this->validate();
$this->resource->save();
$this->emit('success','Secret Saved.');
} catch (\Exception $e) {
return handleError($e, $this);
}
}
public function mount()
{
$this->deploywebhook = generateDeployWebhook($this->resource);
$this->githubManualWebhook = generateGitManualWebhook($this->resource, 'github');
$this->gitlabManualWebhook = generateGitManualWebhook($this->resource, 'gitlab');
}
public function render()
{
return view('livewire.project.shared.webhooks');
}
}

View File

@@ -1,39 +0,0 @@
<?php
namespace App\Http\Livewire;
use App\Models\Server;
use Livewire\Component;
class RunCommand extends Component
{
public string $command;
public $server;
public $servers = [];
protected $rules = [
'server' => 'required',
'command' => 'required',
];
protected $validationAttributes = [
'server' => 'server',
'command' => 'command',
];
public function mount($servers)
{
$this->servers = $servers;
$this->server = $servers[0]->uuid;
}
public function runCommand()
{
$this->validate();
try {
$activity = remote_process([$this->command], Server::where('uuid', $this->server)->first(), ignore_errors: true);
$this->emit('newMonitorActivity', $activity->id);
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
}

View File

@@ -1,38 +0,0 @@
<?php
namespace App\Http\Livewire\Security;
use Livewire\Component;
class ApiTokens extends Component
{
public ?string $description = null;
public $tokens = [];
public function render()
{
return view('livewire.security.api-tokens');
}
public function mount()
{
$this->tokens = auth()->user()->tokens;
}
public function addNewToken()
{
try {
$this->validate([
'description' => 'required|min:3|max:255',
]);
$token = auth()->user()->createToken($this->description);
$this->tokens = auth()->user()->tokens;
session()->flash('token', $token->plainTextToken);
} catch (\Exception $e) {
return handleError($e, $this);
}
}
public function revoke(int $id)
{
$token = auth()->user()->tokens()->where('id', $id)->first();
$token->delete();
$this->tokens = auth()->user()->tokens;
}
}

View File

@@ -1,20 +0,0 @@
<?php
namespace App\Http\Livewire\Server;
use App\Models\Server;
use Illuminate\Database\Eloquent\Collection;
use Livewire\Component;
class All extends Component
{
public ?Collection $servers = null;
public function mount () {
$this->servers = Server::ownedByCurrentTeam()->get();
}
public function render()
{
return view('livewire.server.all');
}
}

View File

@@ -1,29 +0,0 @@
<?php
namespace App\Http\Livewire\Server;
use App\Models\PrivateKey;
use Livewire\Component;
class Create extends Component
{
public $private_keys = [];
public bool $limit_reached = false;
public function mount()
{
$this->private_keys = PrivateKey::ownedByCurrentTeam()->get();
if (!isCloud()) {
$this->limit_reached = false;
return;
}
$team = currentTeam();
$servers = $team->servers->count();
['serverLimit' => $serverLimit] = $team->limits;
$this->limit_reached = $servers >= $serverLimit;
}
public function render()
{
return view('livewire.server.create');
}
}

View File

@@ -1,31 +0,0 @@
<?php
namespace App\Http\Livewire\Server;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Livewire\Component;
class Delete extends Component
{
use AuthorizesRequests;
public $server;
public function delete()
{
try {
$this->authorize('delete', $this->server);
if ($this->server->hasDefinedResources()) {
$this->emit('error', 'Server has defined resources. Please delete them first.');
return;
}
$this->server->delete();
return redirect()->route('server.all');
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function render()
{
return view('livewire.server.delete');
}
}

View File

@@ -1,28 +0,0 @@
<?php
namespace App\Http\Livewire\Server\Destination;
use App\Models\Server;
use Livewire\Component;
class Show extends Component
{
public ?Server $server = null;
public $parameters = [];
public function mount()
{
$this->parameters = get_route_parameters();
try {
$this->server = Server::ownedByCurrentTeam(['name', 'proxy'])->whereUuid(request()->server_uuid)->first();
if (is_null($this->server)) {
return redirect()->route('server.all');
}
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function render()
{
return view('livewire.server.destination.show');
}
}

View File

@@ -1,148 +0,0 @@
<?php
namespace App\Http\Livewire\Server;
use App\Actions\Server\InstallDocker;
use App\Models\Server;
use Livewire\Component;
class Form extends Component
{
public Server $server;
public bool $isValidConnection = false;
public bool $isValidDocker = false;
public ?string $wildcard_domain = null;
public int $cleanup_after_percentage;
public bool $dockerInstallationStarted = false;
protected $listeners = ['serverRefresh'];
protected $rules = [
'server.name' => 'required',
'server.description' => 'nullable',
'server.ip' => 'required',
'server.user' => 'required',
'server.port' => 'required',
'server.settings.is_cloudflare_tunnel' => 'required|boolean',
'server.settings.is_reachable' => 'required',
'server.settings.is_swarm_manager' => 'required|boolean',
// 'server.settings.is_swarm_worker' => 'required|boolean',
'wildcard_domain' => 'nullable|url',
];
protected $validationAttributes = [
'server.name' => 'Name',
'server.description' => 'Description',
'server.ip' => 'IP address/Domain',
'server.user' => 'User',
'server.port' => 'Port',
'server.settings.is_cloudflare_tunnel' => 'Cloudflare Tunnel',
'server.settings.is_reachable' => 'Is reachable',
'server.settings.is_swarm_manager' => 'Swarm Manager',
// 'server.settings.is_swarm_worker' => 'Swarm Worker',
];
public function mount()
{
$this->wildcard_domain = $this->server->settings->wildcard_domain;
$this->cleanup_after_percentage = $this->server->settings->cleanup_after_percentage;
$this->validateServer();
}
public function serverRefresh($install = true)
{
$this->validateServer($install);
}
public function instantSave()
{
try {
refresh_server_connection($this->server->privateKey);
$this->validateServer(false);
$this->server->settings->save();
$this->emit('success', 'Server updated successfully.');
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function installDocker()
{
$this->emit('installDocker');
$this->dockerInstallationStarted = true;
$activity = InstallDocker::run($this->server);
$this->emit('newMonitorActivity', $activity->id);
}
public function checkLocalhostConnection()
{
$uptime = $this->server->validateConnection();
if ($uptime) {
$this->emit('success', 'Server is reachable.');
$this->server->settings->is_reachable = true;
$this->server->settings->is_usable = true;
$this->server->settings->save();
} else {
$this->emit('error', 'Server is not reachable. Please check your connection and configuration.');
return;
}
}
public function validateServer($install = true)
{
try {
$uptime = $this->server->validateConnection();
if (!$uptime) {
$install && $this->emit('error', 'Server is not reachable. Please check your connection and configuration.');
return;
}
$supported_os_type = $this->server->validateOS();
if (!$supported_os_type) {
$install && $this->emit('error', 'Server OS type is not supported for automated installation. Please install Docker manually before continuing: <a target="_blank" class="underline" href="https://coolify.io/docs/servers#install-docker-engine-manually">documentation</a>.');
return;
}
$dockerInstalled = $this->server->validateDockerEngine();
if ($dockerInstalled) {
$install && $this->emit('success', 'Docker Engine is installed.<br> Checking version.');
} else {
$install && $this->installDocker();
return;
}
$dockerVersion = $this->server->validateDockerEngineVersion();
if ($dockerVersion) {
$install && $this->emit('success', 'Docker Engine version is 22+.');
} else {
$install && $this->installDocker();
return;
}
if ($this->server->isSwarm()) {
$swarmInstalled = $this->server->validateDockerSwarm();
if ($swarmInstalled) {
$install && $this->emit('success', 'Docker Swarm is initiated.');
}
}
} catch (\Throwable $e) {
return handleError($e, $this);
} finally {
$this->emit('proxyStatusUpdated');
}
}
public function submit()
{
if (isCloud() && !isDev()) {
$this->validate();
$this->validate([
'server.ip' => 'required',
]);
} else {
$this->validate();
}
$uniqueIPs = Server::all()->reject(function (Server $server) {
return $server->id === $this->server->id;
})->pluck('ip')->toArray();
if (in_array($this->server->ip, $uniqueIPs)) {
$this->emit('error', 'IP address is already in use by another team.');
return;
}
refresh_server_connection($this->server->privateKey);
$this->server->settings->wildcard_domain = $this->wildcard_domain;
$this->server->settings->cleanup_after_percentage = $this->cleanup_after_percentage;
$this->server->settings->save();
$this->server->save();
$this->emit('success', 'Server updated successfully.');
}
}

View File

@@ -1,157 +0,0 @@
<?php
namespace App\Http\Livewire\Server;
use App\Actions\Server\InstallLogDrain;
use App\Models\Server;
use Livewire\Component;
class LogDrains extends Component
{
public Server $server;
public $parameters = [];
protected $rules = [
'server.settings.is_logdrain_newrelic_enabled' => 'required|boolean',
'server.settings.logdrain_newrelic_license_key' => 'required|string',
'server.settings.logdrain_newrelic_base_uri' => 'required|string',
'server.settings.is_logdrain_highlight_enabled' => 'required|boolean',
'server.settings.logdrain_highlight_project_id' => 'required|string',
'server.settings.is_logdrain_axiom_enabled' => 'required|boolean',
'server.settings.logdrain_axiom_dataset_name' => 'required|string',
'server.settings.logdrain_axiom_api_key' => 'required|string',
'server.settings.is_logdrain_custom_enabled' => 'required|boolean',
'server.settings.logdrain_custom_config' => 'required|string',
'server.settings.logdrain_custom_config_parser' => 'nullable',
];
protected $validationAttributes = [
'server.settings.is_logdrain_newrelic_enabled' => 'New Relic log drain',
'server.settings.logdrain_newrelic_license_key' => 'New Relic license key',
'server.settings.logdrain_newrelic_base_uri' => 'New Relic base URI',
'server.settings.is_logdrain_highlight_enabled' => 'Highlight log drain',
'server.settings.logdrain_highlight_project_id' => 'Highlight project ID',
'server.settings.is_logdrain_axiom_enabled' => 'Axiom log drain',
'server.settings.logdrain_axiom_dataset_name' => 'Axiom dataset name',
'server.settings.logdrain_axiom_api_key' => 'Axiom API key',
'server.settings.is_logdrain_custom_enabled' => 'Custom log drain',
'server.settings.logdrain_custom_config' => 'Custom log drain configuration',
'server.settings.logdrain_custom_config_parser' => 'Custom log drain configuration parser',
];
public function mount()
{
$this->parameters = get_route_parameters();
try {
$server = Server::ownedByCurrentTeam(['name', 'description', 'ip', 'port', 'user', 'proxy'])->whereUuid(request()->server_uuid)->first();
if (is_null($server)) {
return redirect()->route('server.all');
}
$this->server = $server;
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function configureLogDrain()
{
try {
InstallLogDrain::run($this->server);
if (!$this->server->isLogDrainEnabled()) {
$this->emit('serverRefresh');
$this->emit('success', 'Log drain service stopped.');
return;
}
$this->emit('serverRefresh');
$this->emit('success', 'Log drain service started successfully.');
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function instantSave(string $type)
{
try {
$ok = $this->submit($type);
if (!$ok) {
return;
}
$this->configureLogDrain();
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function submit(string $type)
{
try {
$this->resetErrorBag();
if ($type === 'newrelic') {
$this->validate([
'server.settings.is_logdrain_newrelic_enabled' => 'required|boolean',
'server.settings.logdrain_newrelic_license_key' => 'required|string',
'server.settings.logdrain_newrelic_base_uri' => 'required|string',
]);
$this->server->settings->update([
'is_logdrain_highlight_enabled' => false,
'is_logdrain_axiom_enabled' => false,
'is_logdrain_custom_enabled' => false,
]);
} else if ($type === 'highlight') {
$this->validate([
'server.settings.is_logdrain_highlight_enabled' => 'required|boolean',
'server.settings.logdrain_highlight_project_id' => 'required|string',
]);
$this->server->settings->update([
'is_logdrain_newrelic_enabled' => false,
'is_logdrain_axiom_enabled' => false,
'is_logdrain_custom_enabled' => false,
]);
} else if ($type === 'axiom') {
$this->validate([
'server.settings.is_logdrain_axiom_enabled' => 'required|boolean',
'server.settings.logdrain_axiom_dataset_name' => 'required|string',
'server.settings.logdrain_axiom_api_key' => 'required|string',
]);
$this->server->settings->update([
'is_logdrain_newrelic_enabled' => false,
'is_logdrain_highlight_enabled' => false,
'is_logdrain_custom_enabled' => false,
]);
} else if ($type === 'custom') {
$this->validate([
'server.settings.is_logdrain_custom_enabled' => 'required|boolean',
'server.settings.logdrain_custom_config' => 'required|string',
'server.settings.logdrain_custom_config_parser' => 'nullable',
]);
$this->server->settings->update([
'is_logdrain_newrelic_enabled' => false,
'is_logdrain_highlight_enabled' => false,
'is_logdrain_axiom_enabled' => false,
]);
}
$this->server->settings->save();
$this->emit('success', 'Settings saved successfully.');
return true;
} catch (\Throwable $e) {
if ($type === 'newrelic') {
$this->server->settings->update([
'is_logdrain_newrelic_enabled' => false,
]);
} else if ($type === 'highlight') {
$this->server->settings->update([
'is_logdrain_highlight_enabled' => false,
]);
} else if ($type === 'axiom') {
$this->server->settings->update([
'is_logdrain_axiom_enabled' => false,
]);
} else if ($type === 'custom') {
$this->server->settings->update([
'is_logdrain_custom_enabled' => false,
]);
}
handleError($e, $this);
return false;
}
}
public function render()
{
return view('livewire.server.log-drains');
}
}

View File

@@ -1,87 +0,0 @@
<?php
namespace App\Http\Livewire\Server\New;
use App\Enums\ProxyStatus;
use App\Enums\ProxyTypes;
use App\Models\Server;
use Livewire\Component;
class ByIp extends Component
{
public $private_keys;
public $limit_reached;
public ?int $private_key_id = null;
public $new_private_key_name;
public $new_private_key_description;
public $new_private_key_value;
public string $name;
public ?string $description = null;
public string $ip;
public string $user = 'root';
public int $port = 22;
public bool $is_swarm_manager = false;
protected $rules = [
'name' => 'required|string',
'description' => 'nullable|string',
'ip' => 'required',
'user' => 'required|string',
'port' => 'required|integer',
'is_swarm_manager' => 'required|boolean',
];
protected $validationAttributes = [
'name' => 'Name',
'description' => 'Description',
'ip' => 'IP Address/Domain',
'user' => 'User',
'port' => 'Port',
'is_swarm_manager' => 'Swarm Manager',
];
public function mount()
{
$this->name = generate_random_name();
$this->private_key_id = $this->private_keys->first()->id;
}
public function setPrivateKey(string $private_key_id)
{
$this->private_key_id = $private_key_id;
}
public function instantSave()
{
$this->emit('success', 'Application settings updated!');
}
public function submit()
{
$this->validate();
try {
if (is_null($this->private_key_id)) {
return $this->emit('error', 'You must select a private key');
}
$server = Server::create([
'name' => $this->name,
'description' => $this->description,
'ip' => $this->ip,
'user' => $this->user,
'port' => $this->port,
'team_id' => currentTeam()->id,
'private_key_id' => $this->private_key_id,
'proxy' => [
"type" => ProxyTypes::TRAEFIK_V2->value,
"status" => ProxyStatus::EXITED->value,
],
]);
$server->settings->is_swarm_manager = $this->is_swarm_manager;
$server->settings->save();
$server->addInitialNetwork();
return redirect()->route('server.show', $server->uuid);
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
}

View File

@@ -1,31 +0,0 @@
<?php
namespace App\Http\Livewire\Server\PrivateKey;
use App\Models\PrivateKey;
use App\Models\Server;
use Livewire\Component;
class Show extends Component
{
public ?Server $server = null;
public $privateKeys = [];
public $parameters = [];
public function mount()
{
$this->parameters = get_route_parameters();
try {
$this->server = Server::ownedByCurrentTeam()->whereUuid(request()->server_uuid)->first();
if (is_null($this->server)) {
return redirect()->route('server.all');
}
$this->privateKeys = PrivateKey::ownedByCurrentTeam()->get()->where('is_git_related', false);
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function render()
{
return view('livewire.server.private-key.show');
}
}

View File

@@ -1,85 +0,0 @@
<?php
namespace App\Http\Livewire\Server;
use App\Actions\Proxy\CheckConfiguration;
use App\Actions\Proxy\SaveConfiguration;
use App\Models\Server;
use Livewire\Component;
use Illuminate\Support\Str;
class Proxy extends Component
{
public Server $server;
public ?string $selectedProxy = null;
public $proxy_settings = null;
public ?string $redirect_url = null;
protected $listeners = ['proxyStatusUpdated', 'saveConfiguration' => 'submit'];
public function mount()
{
$this->selectedProxy = data_get($this->server, 'proxy.type');
$this->redirect_url = data_get($this->server, 'proxy.redirect_url');
}
public function proxyStatusUpdated()
{
$this->server->refresh();
}
public function change_proxy()
{
$this->server->proxy = null;
$this->server->save();
$this->emit('proxyStatusUpdated');
}
public function select_proxy($proxy_type)
{
$this->server->proxy->set('status', 'exited');
$this->server->proxy->set('type', $proxy_type);
$this->server->save();
$this->selectedProxy = $this->server->proxy->type;
$this->emit('proxyStatusUpdated');
}
public function submit()
{
try {
SaveConfiguration::run($this->server, $this->proxy_settings);
$this->server->proxy->redirect_url = $this->redirect_url;
$this->server->save();
setup_default_redirect_404(redirect_url: $this->server->proxy->redirect_url, server: $this->server);
$this->emit('success', 'Proxy configuration saved.');
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function reset_proxy_configuration()
{
try {
$this->proxy_settings = CheckConfiguration::run($this->server, true);
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function loadProxyConfiguration()
{
try {
$this->proxy_settings = CheckConfiguration::run($this->server);
if (Str::of($this->proxy_settings)->contains('--api.dashboard=true') && Str::of($this->proxy_settings)->contains('--api.insecure=true')) {
$this->emit('traefikDashboardAvailable', true);
} else {
$this->emit('traefikDashboardAvailable', false);
}
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
}

View File

@@ -1,82 +0,0 @@
<?php
namespace App\Http\Livewire\Server\Proxy;
use App\Actions\Proxy\CheckProxy;
use App\Actions\Proxy\StartProxy;
use App\Models\Server;
use Livewire\Component;
class Deploy extends Component
{
public Server $server;
public bool $traefikDashboardAvailable = false;
public ?string $currentRoute = null;
public ?string $serverIp = null;
protected $listeners = ['proxyStatusUpdated', 'traefikDashboardAvailable', 'serverRefresh' => 'proxyStatusUpdated', "checkProxy", "startProxy"];
public function mount()
{
if ($this->server->id === 0) {
$this->serverIp = base_ip();
} else {
$this->serverIp = $this->server->ip;
}
$this->currentRoute = request()->route()->getName();
}
public function traefikDashboardAvailable(bool $data)
{
$this->traefikDashboardAvailable = $data;
}
public function proxyStatusUpdated()
{
$this->server->refresh();
}
public function ip()
{
}
public function checkProxy()
{
try {
CheckProxy::run($this->server, true);
$this->emit('startProxyPolling');
$this->emit('proxyChecked');
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function startProxy()
{
try {
$activity = StartProxy::run($this->server);
$this->emit('newMonitorActivity', $activity->id);
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function stop()
{
try {
if ($this->server->isSwarm()) {
instant_remote_process([
"docker service rm coolify-proxy_traefik",
], $this->server);
$this->server->proxy->status = 'exited';
$this->server->save();
$this->emit('proxyStatusUpdated');
} else {
instant_remote_process([
"docker rm -f coolify-proxy",
], $this->server);
$this->server->proxy->status = 'exited';
$this->server->save();
$this->emit('proxyStatusUpdated');
}
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
}

View File

@@ -1,28 +0,0 @@
<?php
namespace App\Http\Livewire\Server\Proxy;
use App\Models\Server;
use Livewire\Component;
class Logs extends Component
{
public ?Server $server = null;
public $parameters = [];
public function mount()
{
$this->parameters = get_route_parameters();
try {
$this->server = Server::ownedByCurrentTeam(['name', 'proxy'])->whereUuid(request()->server_uuid)->first();
if (is_null($this->server)) {
return redirect()->route('server.all');
}
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function render()
{
return view('livewire.server.proxy.logs');
}
}

View File

@@ -1,16 +0,0 @@
<?php
namespace App\Http\Livewire\Server\Proxy;
use App\Models\Server;
use Livewire\Component;
class Modal extends Component
{
public Server $server;
public function proxyStatusUpdated()
{
$this->emit('proxyStatusUpdated');
}
}

View File

@@ -1,33 +0,0 @@
<?php
namespace App\Http\Livewire\Server\Proxy;
use App\Models\Server;
use Livewire\Component;
class Show extends Component
{
public ?Server $server = null;
public $parameters = [];
protected $listeners = ['proxyStatusUpdated'];
public function proxyStatusUpdated()
{
$this->server->refresh();
}
public function mount()
{
$this->parameters = get_route_parameters();
try {
$this->server = Server::ownedByCurrentTeam(['name', 'proxy'])->whereUuid(request()->server_uuid)->first();
if (is_null($this->server)) {
return redirect()->route('server.all');
}
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function render()
{
return view('livewire.server.proxy.show');
}
}

View File

@@ -1,61 +0,0 @@
<?php
namespace App\Http\Livewire\Server\Proxy;
use App\Actions\Proxy\CheckProxy;
use App\Jobs\ContainerStatusJob;
use App\Models\Server;
use Livewire\Component;
class Status extends Component
{
public Server $server;
public bool $polling = false;
public int $numberOfPolls = 0;
protected $listeners = ['proxyStatusUpdated', 'startProxyPolling'];
public function mount() {
$this->checkProxy();
}
public function startProxyPolling()
{
$this->checkProxy();
}
public function proxyStatusUpdated()
{
$this->server->refresh();
}
public function checkProxy(bool $notification = false)
{
try {
if ($this->polling) {
if ($this->numberOfPolls >= 10) {
$this->polling = false;
$this->numberOfPolls = 0;
$notification && $this->emit('error', 'Proxy is not running.');
return;
}
$this->numberOfPolls++;
}
CheckProxy::run($this->server, true);
$this->emit('proxyStatusUpdated');
if ($this->server->proxy->status === 'running') {
$this->polling = false;
$notification && $this->emit('success', 'Proxy is running.');
} else {
$notification && $this->emit('error', 'Proxy is not running.');
}
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function getProxyStatus()
{
try {
dispatch_sync(new ContainerStatusJob($this->server));
$this->emit('proxyStatusUpdated');
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
}

View File

@@ -1,35 +0,0 @@
<?php
namespace App\Http\Livewire\Server;
use App\Models\Server;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Livewire\Component;
class Show extends Component
{
use AuthorizesRequests;
public ?Server $server = null;
public $parameters = [];
public function mount()
{
$this->parameters = get_route_parameters();
try {
$this->server = Server::ownedByCurrentTeam(['name', 'description', 'ip', 'port', 'user', 'proxy'])->whereUuid(request()->server_uuid)->first();
if (is_null($this->server)) {
return redirect()->route('server.all');
}
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function submit()
{
$this->emit('serverRefresh',false);
}
public function render()
{
return view('livewire.server.show');
}
}

View File

@@ -1,54 +0,0 @@
<?php
namespace App\Http\Livewire\Server;
use App\Models\Server;
use Livewire\Component;
class ShowPrivateKey extends Component
{
public Server $server;
public $privateKeys;
public $parameters;
public function setPrivateKey($newPrivateKeyId)
{
try {
$oldPrivateKeyId = $this->server->private_key_id;
refresh_server_connection($this->server->privateKey);
$this->server->update([
'private_key_id' => $newPrivateKeyId
]);
$this->server->refresh();
refresh_server_connection($this->server->privateKey);
$this->checkConnection();
} catch (\Throwable $e) {
$this->server->update([
'private_key_id' => $oldPrivateKeyId
]);
$this->server->refresh();
refresh_server_connection($this->server->privateKey);
return handleError($e, $this);
}
}
public function checkConnection()
{
try {
$uptime = $this->server->validateConnection();
if ($uptime) {
$this->emit('success', 'Server is reachable.');
} else {
$this->emit('error', 'Server is not reachable. Please check your connection and private key configuration.');
return;
}
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function mount()
{
$this->parameters = get_route_parameters();
}
}

View File

@@ -1,86 +0,0 @@
<?php
namespace App\Http\Livewire\Settings;
use App\Jobs\DatabaseBackupJob;
use App\Models\InstanceSettings;
use App\Models\S3Storage;
use App\Models\ScheduledDatabaseBackup;
use App\Models\Server;
use App\Models\StandalonePostgresql;
use Livewire\Component;
class Backup extends Component
{
public InstanceSettings $settings;
public $s3s;
public StandalonePostgresql|null|array $database = [];
public ScheduledDatabaseBackup|null|array $backup = [];
public $executions = [];
protected $rules = [
'database.uuid' => 'required',
'database.name' => 'required',
'database.description' => 'nullable',
'database.postgres_user' => 'required',
'database.postgres_password' => 'required',
];
protected $validationAttributes = [
'database.uuid' => 'uuid',
'database.name' => 'name',
'database.description' => 'description',
'database.postgres_user' => 'postgres user',
'database.postgres_password' => 'postgres password',
];
public function mount()
{
$this->backup = $this->database?->scheduledBackups->first() ?? [];
$this->executions = $this->backup?->executions ?? [];
}
public function add_coolify_database()
{
$server = Server::find(0);
$out = instant_remote_process(['docker inspect coolify-db'], $server);
$envs = format_docker_envs_to_json($out);
$postgres_password = $envs['POSTGRES_PASSWORD'];
$postgres_user = $envs['POSTGRES_USER'];
$postgres_db = $envs['POSTGRES_DB'];
$this->database = StandalonePostgresql::create([
'id' => 0,
'name' => 'coolify-db',
'description' => 'Coolify database',
'postgres_user' => $postgres_user,
'postgres_password' => $postgres_password,
'postgres_db' => $postgres_db,
'status' => 'running',
'destination_type' => 'App\Models\StandaloneDocker',
'destination_id' => 0,
]);
$this->backup = ScheduledDatabaseBackup::create([
'id' => 0,
'enabled' => true,
'save_s3' => false,
'frequency' => '0 0 * * *',
'database_id' => $this->database->id,
'database_type' => 'App\Models\StandalonePostgresql',
'team_id' => currentTeam()->id,
]);
$this->database->refresh();
$this->backup->refresh();
$this->s3s = S3Storage::whereTeamId(0)->get();
}
public function backup_now()
{
dispatch(new DatabaseBackupJob(
backup: $this->backup
));
$this->emit('success', 'Backup queued. It will be available in a few minutes.');
}
public function submit()
{
$this->emit('success', 'Backup updated successfully.');
}
}

View File

@@ -1,153 +0,0 @@
<?php
namespace App\Http\Livewire\Settings;
use App\Jobs\ContainerStatusJob;
use App\Models\InstanceSettings as ModelsInstanceSettings;
use App\Models\Server;
use Livewire\Component;
use Spatie\Url\Url;
use Symfony\Component\Yaml\Yaml;
class Configuration extends Component
{
public ModelsInstanceSettings $settings;
public bool $do_not_track;
public bool $is_auto_update_enabled;
public bool $is_registration_enabled;
public bool $next_channel;
protected string $dynamic_config_path = '/data/coolify/proxy/dynamic';
protected Server $server;
protected $rules = [
'settings.fqdn' => 'nullable',
'settings.resale_license' => 'nullable',
'settings.public_port_min' => 'required',
'settings.public_port_max' => 'required',
];
protected $validationAttributes = [
'settings.fqdn' => 'FQDN',
'settings.resale_license' => 'Resale License',
'settings.public_port_min' => 'Public port min',
'settings.public_port_max' => 'Public port max',
];
public function mount()
{
$this->do_not_track = $this->settings->do_not_track;
$this->is_auto_update_enabled = $this->settings->is_auto_update_enabled;
$this->is_registration_enabled = $this->settings->is_registration_enabled;
$this->next_channel = $this->settings->next_channel;
}
public function instantSave()
{
$this->settings->do_not_track = $this->do_not_track;
$this->settings->is_auto_update_enabled = $this->is_auto_update_enabled;
$this->settings->is_registration_enabled = $this->is_registration_enabled;
if ($this->next_channel) {
$this->settings->next_channel = false;
$this->next_channel = false;
} else {
$this->settings->next_channel = $this->next_channel;
}
$this->settings->save();
$this->emit('success', 'Settings updated!');
}
public function submit()
{
$this->resetErrorBag();
if ($this->settings->public_port_min > $this->settings->public_port_max) {
$this->addError('settings.public_port_min', 'The minimum port must be lower than the maximum port.');
return;
}
$this->validate();
$this->settings->save();
$this->server = Server::findOrFail(0);
$this->setup_instance_fqdn();
$this->emit('success', 'Instance settings updated successfully!');
}
private function setup_instance_fqdn()
{
$file = "$this->dynamic_config_path/coolify.yaml";
if (empty($this->settings->fqdn)) {
instant_remote_process([
"rm -f $file",
], $this->server);
} else {
$url = Url::fromString($this->settings->fqdn);
$host = $url->getHost();
$schema = $url->getScheme();
$traefik_dynamic_conf = [
'http' =>
[
'routers' =>
[
'coolify-http' =>
[
'entryPoints' => [
0 => 'http',
],
'service' => 'coolify',
'rule' => "Host(`{$host}`)",
],
],
'services' =>
[
'coolify' =>
[
'loadBalancer' =>
[
'servers' =>
[
0 =>
[
'url' => 'http://coolify:80',
],
],
],
],
],
],
];
if ($schema === 'https') {
$traefik_dynamic_conf['http']['routers']['coolify-http']['middlewares'] = [
0 => 'redirect-to-https@docker',
];
$traefik_dynamic_conf['http']['routers']['coolify-https'] = [
'entryPoints' => [
0 => 'https',
],
'service' => 'coolify',
'rule' => "Host(`{$host}`)",
'tls' => [
'certresolver' => 'letsencrypt',
],
];
}
$this->save_configuration_to_disk($traefik_dynamic_conf, $file);
}
}
private function save_configuration_to_disk(array $traefik_dynamic_conf, string $file)
{
$yaml = Yaml::dump($traefik_dynamic_conf, 12, 2);
$yaml =
"# This file is automatically generated by Coolify.\n" .
"# Do not edit it manually (only if you know what are you doing).\n\n" .
$yaml;
$base64 = base64_encode($yaml);
instant_remote_process([
"mkdir -p $this->dynamic_config_path",
"echo '$base64' | base64 -d > $file",
], $this->server);
if (config('app.env') == 'local') {
ray($yaml);
}
}
}

View File

@@ -1,112 +0,0 @@
<?php
namespace App\Http\Livewire\Settings;
use App\Models\InstanceSettings;
use App\Notifications\TransactionalEmails\Test;
use Livewire\Component;
class Email extends Component
{
public InstanceSettings $settings;
public string $emails;
protected $rules = [
'settings.smtp_enabled' => 'nullable|boolean',
'settings.smtp_host' => 'required',
'settings.smtp_port' => 'required|numeric',
'settings.smtp_encryption' => 'nullable',
'settings.smtp_username' => 'nullable',
'settings.smtp_password' => 'nullable',
'settings.smtp_timeout' => 'nullable',
'settings.smtp_from_address' => 'required|email',
'settings.smtp_from_name' => 'required',
'settings.resend_enabled' => 'nullable|boolean',
'settings.resend_api_key' => 'nullable'
];
protected $validationAttributes = [
'settings.smtp_from_address' => 'From Address',
'settings.smtp_from_name' => 'From Name',
'settings.smtp_recipients' => 'Recipients',
'settings.smtp_host' => 'Host',
'settings.smtp_port' => 'Port',
'settings.smtp_encryption' => 'Encryption',
'settings.smtp_username' => 'Username',
'settings.smtp_password' => 'Password',
'settings.smtp_timeout' => 'Timeout',
'settings.resend_api_key' => 'Resend API Key'
];
public function mount()
{
$this->emails = auth()->user()->email;
}
public function submitFromFields() {
try {
$this->resetErrorBag();
$this->validate([
'settings.smtp_from_address' => 'required|email',
'settings.smtp_from_name' => 'required',
]);
$this->settings->save();
$this->emit('success', 'Settings saved successfully.');
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function submitResend() {
try {
$this->resetErrorBag();
$this->validate([
'settings.resend_api_key' => 'required'
]);
$this->settings->save();
$this->emit('success', 'Settings saved successfully.');
} catch (\Throwable $e) {
$this->settings->resend_enabled = false;
return handleError($e, $this);
}
}
public function instantSaveResend() {
try {
$this->settings->smtp_enabled = false;
$this->submitResend();
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function instantSave()
{
try {
$this->settings->resend_enabled = false;
$this->submit();
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function submit()
{
try {
$this->resetErrorBag();
$this->validate([
'settings.smtp_host' => 'required',
'settings.smtp_port' => 'required|numeric',
'settings.smtp_encryption' => 'nullable',
'settings.smtp_username' => 'nullable',
'settings.smtp_password' => 'nullable',
'settings.smtp_timeout' => 'nullable',
]);
$this->settings->save();
$this->emit('success', 'Settings saved successfully.');
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function sendTestNotification()
{
$this->settings->notify(new Test($this->emails));
$this->emit('success', 'Test email sent.');
}
}

View File

@@ -1,113 +0,0 @@
<?php
namespace App\Http\Livewire\Source\Github;
use App\Models\GithubApp;
use App\Models\InstanceSettings;
use Livewire\Component;
class Change extends Component
{
public string $webhook_endpoint;
public ?string $ipv4;
public ?string $ipv6;
public ?string $fqdn;
public ?bool $default_permissions = true;
public ?bool $preview_deployment_permissions = true;
public $parameters;
public GithubApp $github_app;
public string $name;
public bool $is_system_wide;
protected $rules = [
'github_app.name' => 'required|string',
'github_app.organization' => 'nullable|string',
'github_app.api_url' => 'required|string',
'github_app.html_url' => 'required|string',
'github_app.custom_user' => 'required|string',
'github_app.custom_port' => 'required|int',
'github_app.app_id' => 'required|int',
'github_app.installation_id' => 'required|int',
'github_app.client_id' => 'required|string',
'github_app.client_secret' => 'required|string',
'github_app.webhook_secret' => 'required|string',
'github_app.is_system_wide' => 'required|bool',
];
public function mount()
{
$github_app_uuid = request()->github_app_uuid;
$this->github_app = GithubApp::where('uuid', $github_app_uuid)->first();
if (!$this->github_app) {
return redirect()->route('source.all');
}
$settings = InstanceSettings::get();
$this->github_app->makeVisible('client_secret')->makeVisible('webhook_secret');
$this->name = str($this->github_app->name)->kebab();
$this->fqdn = $settings->fqdn;
if ($settings->public_ipv4) {
$this->ipv4 = 'http://' . $settings->public_ipv4 . ':' . config('app.port');
}
if ($settings->public_ipv6) {
$this->ipv6 = 'http://' . $settings->public_ipv6 . ':' . config('app.port');
}
if ($this->github_app->installation_id && session('from')) {
$source_id = data_get(session('from'), 'source_id');
if (!$source_id || $this->github_app->id !== $source_id) {
session()->forget('from');
} else {
$parameters = data_get(session('from'), 'parameters');
$back = data_get(session('from'), 'back');
$environment_name = data_get($parameters, 'environment_name');
$project_uuid = data_get($parameters, 'project_uuid');
$type = data_get($parameters, 'type');
$destination = data_get($parameters, 'destination');
session()->forget('from');
return redirect()->route($back, [
'environment_name' => $environment_name,
'project_uuid' => $project_uuid,
'type' => $type,
'destination' => $destination,
]);
}
}
$this->parameters = get_route_parameters();
if (isCloud() && !isDev()) {
$this->webhook_endpoint = config('app.url');
} else {
$this->webhook_endpoint = $this->ipv4;
$this->is_system_wide = $this->github_app->is_system_wide;
}
}
public function submit()
{
try {
$this->github_app->makeVisible('client_secret')->makeVisible('webhook_secret');
$this->validate();
$this->github_app->save();
$this->emit('success', 'Github App updated successfully.');
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function instantSave()
{
$this->submit();
}
public function delete()
{
try {
$this->github_app->delete();
redirect()->route('source.all');
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
}

Some files were not shown because too many files have changed in this diff Show More