Merge branch 'next' into feat/scheduled-tasks-cron

This commit is contained in:
Andras Bacsai 2024-01-10 12:03:48 +01:00 committed by GitHub
commit ce0b38035c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
166 changed files with 1827 additions and 1542 deletions

View File

@ -31,7 +31,7 @@ ## Github Sponsors ($15+)
<a href="https://github.com/whitesidest"><img src="https://avatars.githubusercontent.com/u/12365916?s=52&v=4" width="60px" alt="Tyler Whitesides" /></a> <a href="https://github.com/whitesidest"><img src="https://avatars.githubusercontent.com/u/12365916?s=52&v=4" width="60px" alt="Tyler Whitesides" /></a>
<a href="https://github.com/aniftyco"><img src="https://github.com/aniftyco.png" width="60px" alt="NiftyCo" /></a> <a href="https://github.com/aniftyco"><img src="https://github.com/aniftyco.png" width="60px" alt="NiftyCo" /></a>
<a href="https://github.com/iujlaki"><img src="https://github.com/iujlaki.png" width="60px" alt="Imre Ujlaki" /></a> <a href="https://github.com/iujlaki"><img src="https://github.com/iujlaki.png" width="60px" alt="Imre Ujlaki" /></a>
<a href="https://github.com/Illyism"><img src="https://github.com/Illyism.png" width="60px" alt="Ilias Ism" /></a> <a href="https://il.ly"><img src="https://github.com/Illyism.png" width="60px" alt="Ilias Ism" /></a>
<a href="https://github.com/urtho"><img src="https://github.com/urtho.png" width="60px" alt="Paweł Pierścionek" /></a> <a href="https://github.com/urtho"><img src="https://github.com/urtho.png" width="60px" alt="Paweł Pierścionek" /></a>
<a href="https://github.com/monocursive"><img src="https://github.com/monocursive.png" width="60px" alt="Michael Mazurczak" /></a> <a href="https://github.com/monocursive"><img src="https://github.com/monocursive.png" width="60px" alt="Michael Mazurczak" /></a>

View File

@ -99,7 +99,7 @@ private function alive()
return; return;
} }
try { try {
Http::get("https://get.coollabs.io/coolify/v4/alive?appId=$id&version=$version"); Http::get("https://undead.coollabs.io/coolify/v4/alive?appId=$id&version=$version");
echo "I am alive!\n"; echo "I am alive!\n";
} catch (\Throwable $e) { } catch (\Throwable $e) {
echo "Error in alive: {$e->getMessage()}\n"; echo "Error in alive: {$e->getMessage()}\n";
@ -142,83 +142,83 @@ private function cleanup_stucked_resources()
try { try {
$applications = Application::withTrashed()->whereNotNull('deleted_at')->get(); $applications = Application::withTrashed()->whereNotNull('deleted_at')->get();
foreach ($applications as $application) { foreach ($applications as $application) {
echo "Deleting stucked application: {$application->name}\n"; echo "Deleting stuck application: {$application->name}\n";
$application->forceDelete(); $application->forceDelete();
} }
} catch (\Throwable $e) { } catch (\Throwable $e) {
echo "Error in cleaning stucked application: {$e->getMessage()}\n"; echo "Error in cleaning stuck application: {$e->getMessage()}\n";
} }
try { try {
$postgresqls = StandalonePostgresql::withTrashed()->whereNotNull('deleted_at')->get(); $postgresqls = StandalonePostgresql::withTrashed()->whereNotNull('deleted_at')->get();
foreach ($postgresqls as $postgresql) { foreach ($postgresqls as $postgresql) {
echo "Deleting stucked postgresql: {$postgresql->name}\n"; echo "Deleting stuck postgresql: {$postgresql->name}\n";
$postgresql->forceDelete(); $postgresql->forceDelete();
} }
} catch (\Throwable $e) { } catch (\Throwable $e) {
echo "Error in cleaning stucked postgresql: {$e->getMessage()}\n"; echo "Error in cleaning stuck postgresql: {$e->getMessage()}\n";
} }
try { try {
$redis = StandaloneRedis::withTrashed()->whereNotNull('deleted_at')->get(); $redis = StandaloneRedis::withTrashed()->whereNotNull('deleted_at')->get();
foreach ($redis as $redis) { foreach ($redis as $redis) {
echo "Deleting stucked redis: {$redis->name}\n"; echo "Deleting stuck redis: {$redis->name}\n";
$redis->forceDelete(); $redis->forceDelete();
} }
} catch (\Throwable $e) { } catch (\Throwable $e) {
echo "Error in cleaning stucked redis: {$e->getMessage()}\n"; echo "Error in cleaning stuck redis: {$e->getMessage()}\n";
} }
try { try {
$mongodbs = StandaloneMongodb::withTrashed()->whereNotNull('deleted_at')->get(); $mongodbs = StandaloneMongodb::withTrashed()->whereNotNull('deleted_at')->get();
foreach ($mongodbs as $mongodb) { foreach ($mongodbs as $mongodb) {
echo "Deleting stucked mongodb: {$mongodb->name}\n"; echo "Deleting stuck mongodb: {$mongodb->name}\n";
$mongodb->forceDelete(); $mongodb->forceDelete();
} }
} catch (\Throwable $e) { } catch (\Throwable $e) {
echo "Error in cleaning stucked mongodb: {$e->getMessage()}\n"; echo "Error in cleaning stuck mongodb: {$e->getMessage()}\n";
} }
try { try {
$mysqls = StandaloneMysql::withTrashed()->whereNotNull('deleted_at')->get(); $mysqls = StandaloneMysql::withTrashed()->whereNotNull('deleted_at')->get();
foreach ($mysqls as $mysql) { foreach ($mysqls as $mysql) {
echo "Deleting stucked mysql: {$mysql->name}\n"; echo "Deleting stuck mysql: {$mysql->name}\n";
$mysql->forceDelete(); $mysql->forceDelete();
} }
} catch (\Throwable $e) { } catch (\Throwable $e) {
echo "Error in cleaning stucked mysql: {$e->getMessage()}\n"; echo "Error in cleaning stuck mysql: {$e->getMessage()}\n";
} }
try { try {
$mariadbs = StandaloneMariadb::withTrashed()->whereNotNull('deleted_at')->get(); $mariadbs = StandaloneMariadb::withTrashed()->whereNotNull('deleted_at')->get();
foreach ($mariadbs as $mariadb) { foreach ($mariadbs as $mariadb) {
echo "Deleting stucked mariadb: {$mariadb->name}\n"; echo "Deleting stuck mariadb: {$mariadb->name}\n";
$mariadb->forceDelete(); $mariadb->forceDelete();
} }
} catch (\Throwable $e) { } catch (\Throwable $e) {
echo "Error in cleaning stucked mariadb: {$e->getMessage()}\n"; echo "Error in cleaning stuck mariadb: {$e->getMessage()}\n";
} }
try { try {
$services = Service::withTrashed()->whereNotNull('deleted_at')->get(); $services = Service::withTrashed()->whereNotNull('deleted_at')->get();
foreach ($services as $service) { foreach ($services as $service) {
echo "Deleting stucked service: {$service->name}\n"; echo "Deleting stuck service: {$service->name}\n";
$service->forceDelete(); $service->forceDelete();
} }
} catch (\Throwable $e) { } catch (\Throwable $e) {
echo "Error in cleaning stucked service: {$e->getMessage()}\n"; echo "Error in cleaning stuck service: {$e->getMessage()}\n";
} }
try { try {
$serviceApps = ServiceApplication::withTrashed()->whereNotNull('deleted_at')->get(); $serviceApps = ServiceApplication::withTrashed()->whereNotNull('deleted_at')->get();
foreach ($serviceApps as $serviceApp) { foreach ($serviceApps as $serviceApp) {
echo "Deleting stucked serviceapp: {$serviceApp->name}\n"; echo "Deleting stuck serviceapp: {$serviceApp->name}\n";
$serviceApp->forceDelete(); $serviceApp->forceDelete();
} }
} catch (\Throwable $e) { } catch (\Throwable $e) {
echo "Error in cleaning stucked serviceapp: {$e->getMessage()}\n"; echo "Error in cleaning stuck serviceapp: {$e->getMessage()}\n";
} }
try { try {
$serviceDbs = ServiceDatabase::withTrashed()->whereNotNull('deleted_at')->get(); $serviceDbs = ServiceDatabase::withTrashed()->whereNotNull('deleted_at')->get();
foreach ($serviceDbs as $serviceDb) { foreach ($serviceDbs as $serviceDb) {
echo "Deleting stucked serviceapp: {$serviceDb->name}\n"; echo "Deleting stuck serviceapp: {$serviceDb->name}\n";
$serviceDb->forceDelete(); $serviceDb->forceDelete();
} }
} catch (\Throwable $e) { } catch (\Throwable $e) {
echo "Error in cleaning stucked serviceapp: {$e->getMessage()}\n"; echo "Error in cleaning stuck serviceapp: {$e->getMessage()}\n";
} }
// Cleanup any resources that are not attached to any environment or destination or server // Cleanup any resources that are not attached to any environment or destination or server

View File

@ -2,11 +2,13 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Events\TestEvent;
use App\Models\InstanceSettings; use App\Models\InstanceSettings;
use App\Models\S3Storage; use App\Models\S3Storage;
use App\Models\StandalonePostgresql; use App\Models\StandalonePostgresql;
use App\Models\TeamInvitation; use App\Models\TeamInvitation;
use App\Models\User; use App\Models\User;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Validation\ValidatesRequests; use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController; use Illuminate\Routing\Controller as BaseController;
@ -14,11 +16,55 @@
use Illuminate\Support\Facades\Crypt; use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use Laravel\Fortify\Fortify;
use Laravel\Fortify\Contracts\FailedPasswordResetLinkRequestResponse;
use Laravel\Fortify\Contracts\SuccessfulPasswordResetLinkRequestResponse;
use Illuminate\Support\Facades\Password;
class Controller extends BaseController class Controller extends BaseController
{ {
use AuthorizesRequests, ValidatesRequests; use AuthorizesRequests, ValidatesRequests;
public function realtime_test() {
if (auth()->user()?->currentTeam()->id !== 0) {
return redirect(RouteServiceProvider::HOME);
}
TestEvent::dispatch();
return 'Look at your other tab.';
}
public function verify() {
return view('auth.verify-email');
}
public function email_verify() {
request()->fulfill();
$name = request()->user()?->name;
send_internal_notification("User {$name} verified their email address.");
return redirect(RouteServiceProvider::HOME);
}
public function forgot_password() {
if (is_transactional_emails_active()) {
$arrayOfRequest = request()->only(Fortify::email());
request()->merge([
'email' => Str::lower($arrayOfRequest['email']),
]);
$type = set_transanctional_email_settings();
if (!$type) {
return response()->json(['message' => 'Transactional emails are not active'], 400);
}
request()->validate([Fortify::email() => 'required|email']);
$status = Password::broker(config('fortify.passwords'))->sendResetLink(
request()->only(Fortify::email())
);
if ($status == Password::RESET_LINK_SENT) {
return app(SuccessfulPasswordResetLinkRequestResponse::class, ['status' => $status]);
}
if ($status == Password::RESET_THROTTLED) {
return response('Already requested a password reset in the past minutes.', 400);
}
return app(FailedPasswordResetLinkRequestResponse::class, ['status' => $status]);
}
return response()->json(['message' => 'Transactional emails are not active'], 400);
}
public function link() public function link()
{ {
$token = request()->get('token'); $token = request()->get('token');
@ -51,90 +97,7 @@ public function link()
return redirect()->route('login')->with('error', 'Invalid credentials.'); return redirect()->route('login')->with('error', 'Invalid credentials.');
} }
public function license() public function accept_invitation()
{
if (!isCloud()) {
abort(404);
}
return view('settings.license', [
'settings' => InstanceSettings::get(),
]);
}
public function force_passoword_reset()
{
return view('auth.force-password-reset');
}
public function boarding()
{
if (currentTeam()->boarding || isDev()) {
return view('boarding');
} else {
return redirect()->route('dashboard');
}
}
public function settings()
{
if (isInstanceAdmin()) {
$settings = InstanceSettings::get();
$database = StandalonePostgresql::whereName('coolify-db')->first();
if ($database) {
if ($database->status !== 'running') {
$database->status = 'running';
$database->save();
}
$s3s = S3Storage::whereTeamId(0)->get();
}
return view('settings.configuration', [
'settings' => $settings,
'database' => $database,
's3s' => $s3s ?? [],
]);
} else {
return redirect()->route('dashboard');
}
}
public function team()
{
$invitations = [];
if (auth()->user()->isAdminFromSession()) {
$invitations = TeamInvitation::whereTeamId(currentTeam()->id)->get();
}
return view('team.index', [
'invitations' => $invitations,
]);
}
public function storages()
{
$s3 = S3Storage::ownedByCurrentTeam()->get();
return view('team.storages.all', [
's3' => $s3,
]);
}
public function storages_show()
{
$storage = S3Storage::ownedByCurrentTeam()->whereUuid(request()->storage_uuid)->firstOrFail();
return view('team.storages.show', [
'storage' => $storage,
]);
}
public function members()
{
$invitations = [];
if (auth()->user()->isAdminFromSession()) {
$invitations = TeamInvitation::whereTeamId(currentTeam()->id)->get();
}
return view('team.members', [
'invitations' => $invitations,
]);
}
public function acceptInvitation()
{ {
try { try {
$resetPassword = request()->query('reset-password'); $resetPassword = request()->query('reset-password');
@ -169,7 +132,7 @@ public function acceptInvitation()
} }
} }
public function revokeInvitation() public function revoke_invitation()
{ {
try { try {
$invitation = TeamInvitation::whereUuid(request()->route('uuid'))->firstOrFail(); $invitation = TeamInvitation::whereUuid(request()->route('uuid'))->firstOrFail();

View File

@ -1,84 +0,0 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Validation\ValidatesRequests;
class DatabaseController extends Controller
{
use AuthorizesRequests, ValidatesRequests;
public function configuration()
{
$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');
}
$database = $environment->databases()->where('uuid', request()->route('database_uuid'))->first();
if (!$database) {
return redirect()->route('dashboard');
}
return view('project.database.configuration', ['database' => $database]);
}
public function executions()
{
$backup_uuid = request()->route('backup_uuid');
$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');
}
$database = $environment->databases()->where('uuid', request()->route('database_uuid'))->first();
if (!$database) {
return redirect()->route('dashboard');
}
$backup = $database->scheduledBackups->where('uuid', $backup_uuid)->first();
if (!$backup) {
return redirect()->route('dashboard');
}
$executions = collect($backup->executions)->sortByDesc('created_at');
return view('project.database.backups.executions', [
'database' => $database,
'backup' => $backup,
'executions' => $executions,
's3s' => currentTeam()->s3s,
]);
}
public function backups()
{
$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');
}
$database = $environment->databases()->where('uuid', request()->route('database_uuid'))->first();
if (!$database) {
return redirect()->route('dashboard');
}
// No backups for redis
if ($database->getMorphClass() === 'App\Models\StandaloneRedis') {
return redirect()->route('project.database.configuration', [
'project_uuid' => $project->uuid,
'environment_name' => $environment->name,
'database_uuid' => $database->uuid,
]);
}
return view('project.database.backups.all', [
'database' => $database,
's3s' => currentTeam()->s3s,
]);
}
}

View File

@ -30,6 +30,7 @@
use Symfony\Component\Yaml\Yaml; use Symfony\Component\Yaml\Yaml;
use Throwable; use Throwable;
use Visus\Cuid2\Cuid2; use Visus\Cuid2\Cuid2;
use Yosymfony\Toml\Toml;
class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
{ {
@ -73,6 +74,8 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
private $env_args; private $env_args;
private $docker_compose; private $docker_compose;
private $docker_compose_base64; private $docker_compose_base64;
private ?string $nixpacks_plan = null;
private ?string $nixpacks_type = null;
private string $dockerfile_location = '/Dockerfile'; private string $dockerfile_location = '/Dockerfile';
private string $docker_compose_location = '/docker-compose.yml'; private string $docker_compose_location = '/docker-compose.yml';
private ?string $docker_compose_custom_start_command = null; private ?string $docker_compose_custom_start_command = null;
@ -170,7 +173,7 @@ public function handle(): void
if ($containerName === 'coolify-proxy') { if ($containerName === 'coolify-proxy') {
continue; continue;
} }
if (preg_match('/-(\d{12})/',$containerName)) { if (preg_match('/-(\d{12})/', $containerName)) {
continue; continue;
} }
$containerIp = data_get($container, 'IPv4Address'); $containerIp = data_get($container, 'IPv4Address');
@ -347,6 +350,9 @@ private function just_restart()
$this->generate_image_names(); $this->generate_image_names();
$this->check_image_locally_or_remotely(); $this->check_image_locally_or_remotely();
if (str($this->saved_outputs->get('local_image_found'))->isNotEmpty()) { if (str($this->saved_outputs->get('local_image_found'))->isNotEmpty()) {
$this->execute_remote_command([
"echo 'Image found ({$this->production_image_name}) with the same Git Commit SHA. Restarting container.'",
]);
$this->create_workdir(); $this->create_workdir();
$this->generate_compose_file(); $this->generate_compose_file();
$this->rolling_update(); $this->rolling_update();
@ -579,7 +585,7 @@ private function deploy_nixpacks_buildpack()
$this->generate_nixpacks_confs(); $this->generate_nixpacks_confs();
$this->generate_compose_file(); $this->generate_compose_file();
$this->generate_build_env_variables(); $this->generate_build_env_variables();
$this->add_build_env_variables_to_dockerfile(); // $this->add_build_env_variables_to_dockerfile();
$this->build_image(); $this->build_image();
$this->rolling_update(); $this->rolling_update();
} }
@ -601,6 +607,24 @@ private function deploy_static_buildpack()
$this->rolling_update(); $this->rolling_update();
} }
private function framework_based_notification()
{
// Laravel old env variables
if ($this->pull_request_id === 0) {
$nixpacks_php_fallback_path = $this->application->environment_variables->where('key', 'NIXPACKS_PHP_FALLBACK_PATH')->first();
$nixpacks_php_root_dir = $this->application->environment_variables->where('key', 'NIXPACKS_PHP_ROOT_DIR')->first();
} else {
$nixpacks_php_fallback_path = $this->application->environment_variables_preview->where('key', 'NIXPACKS_PHP_FALLBACK_PATH')->first();
$nixpacks_php_root_dir = $this->application->environment_variables_preview->where('key', 'NIXPACKS_PHP_ROOT_DIR')->first();
}
if ($nixpacks_php_fallback_path?->value === '/index.php' && $nixpacks_php_root_dir?->value === '/app/public' && $this->newVersionIsHealthy === false) {
$this->execute_remote_command(
[
"echo 'There was a change in how Laravel is deployed. Please update your environment variables to match the new deployment method. More details here: https://coolify.io/docs/frameworks/laravel#requirements'", 'type' => 'err'
],
);
}
}
private function rolling_update() private function rolling_update()
{ {
if ($this->server->isSwarm()) { if ($this->server->isSwarm()) {
@ -637,6 +661,7 @@ private function rolling_update()
$this->application_deployment_queue->addLogEntry("Rolling update completed."); $this->application_deployment_queue->addLogEntry("Rolling update completed.");
} }
} }
$this->framework_based_notification();
} }
private function health_check() private function health_check()
{ {
@ -676,7 +701,7 @@ private function health_check()
"echo 'Attempt {$counter} of {$this->application->health_check_retries} | Healthcheck status: {$this->saved_outputs->get('health_check')}'" "echo 'Attempt {$counter} of {$this->application->health_check_retries} | Healthcheck status: {$this->saved_outputs->get('health_check')}'"
], ],
); );
if (Str::of($this->saved_outputs->get('health_check'))->contains('healthy')) { if (Str::of($this->saved_outputs->get('health_check'))->replace('"', '')->value() === 'healthy') {
$this->newVersionIsHealthy = true; $this->newVersionIsHealthy = true;
$this->application->update(['status' => 'running']); $this->application->update(['status' => 'running']);
$this->execute_remote_command( $this->execute_remote_command(
@ -686,6 +711,10 @@ private function health_check()
); );
break; break;
} }
if (Str::of($this->saved_outputs->get('health_check'))->replace('"', '')->value() === 'unhealthy') {
$this->newVersionIsHealthy = false;
break;
}
$counter++; $counter++;
sleep($this->application->health_check_interval); sleep($this->application->health_check_interval);
} }
@ -870,20 +899,28 @@ private function generate_nixpacks_confs()
[ [
"echo -n 'Generating nixpacks configuration with: $nixpacks_command'", "echo -n 'Generating nixpacks configuration with: $nixpacks_command'",
], ],
[executeInDocker($this->deployment_uuid, $nixpacks_command)], [executeInDocker($this->deployment_uuid, $nixpacks_command), "save" => "nixpacks_plan", "hidden" => true],
[executeInDocker($this->deployment_uuid, "cp {$this->workdir}/.nixpacks/Dockerfile {$this->workdir}/Dockerfile")], [executeInDocker($this->deployment_uuid, "nixpacks detect {$this->workdir}"), "save" => "nixpacks_type", "hidden" => true],
[executeInDocker($this->deployment_uuid, "rm -f {$this->workdir}/.nixpacks/Dockerfile")]
); );
if ($this->saved_outputs->get('nixpacks_type')) {
$this->nixpacks_type = $this->saved_outputs->get('nixpacks_type');
}
if ($this->saved_outputs->get('nixpacks_plan')) {
$this->nixpacks_plan = $this->saved_outputs->get('nixpacks_plan');
if ($this->nixpacks_plan) {
$parsed = Toml::Parse($this->nixpacks_plan);
// Do any modifications here
$cmds = collect(data_get($parsed, 'phases.setup.cmds', []));
data_set($parsed, 'phases.setup.cmds', $cmds);
$this->nixpacks_plan = json_encode($parsed);
}
}
} }
private function nixpacks_build_cmd() private function nixpacks_build_cmd()
{ {
$this->generate_env_variables(); $this->generate_env_variables();
// $cacheKey = $this->application->uuid; $nixpacks_command = "nixpacks plan -f toml {$this->env_args}";
// if ($this->pull_request_id !== 0) {
// $cacheKey = "{$this->application->uuid}-pr-{$this->pull_request_id}";
// }
$nixpacks_command = "nixpacks build {$this->env_args} --no-error-without-start";
if ($this->application->build_command) { if ($this->application->build_command) {
$nixpacks_command .= " --build-cmd \"{$this->application->build_command}\""; $nixpacks_command .= " --build-cmd \"{$this->application->build_command}\"";
} }
@ -893,7 +930,7 @@ private function nixpacks_build_cmd()
if ($this->application->install_command) { if ($this->application->install_command) {
$nixpacks_command .= " --install-cmd \"{$this->application->install_command}\""; $nixpacks_command .= " --install-cmd \"{$this->application->install_command}\"";
} }
$nixpacks_command .= " -o {$this->workdir} {$this->workdir}"; $nixpacks_command .= " {$this->workdir}";
return $nixpacks_command; return $nixpacks_command;
} }
@ -904,10 +941,16 @@ private function generate_env_variables()
foreach ($this->application->nixpacks_environment_variables as $env) { foreach ($this->application->nixpacks_environment_variables as $env) {
$this->env_args->push("--env {$env->key}={$env->value}"); $this->env_args->push("--env {$env->key}={$env->value}");
} }
foreach ($this->application->build_environment_variables as $env) {
$this->env_args->push("--env {$env->key}={$env->value}");
}
} else { } else {
foreach ($this->application->nixpacks_environment_variables_preview as $env) { foreach ($this->application->nixpacks_environment_variables_preview as $env) {
$this->env_args->push("--env {$env->key}={$env->value}"); $this->env_args->push("--env {$env->key}={$env->value}");
} }
foreach ($this->application->build_environment_variables_preview as $env) {
$this->env_args->push("--env {$env->key}={$env->value}");
}
} }
$this->env_args = $this->env_args->implode(' '); $this->env_args = $this->env_args->implode(' ');
@ -1231,22 +1274,28 @@ private function build_image()
}"); }");
} else { } else {
if ($this->application->build_pack === 'nixpacks') { if ($this->application->build_pack === 'nixpacks') {
$this->execute_remote_command( $this->nixpacks_plan = base64_encode($this->nixpacks_plan);
[ $this->execute_remote_command([executeInDocker($this->deployment_uuid, "echo '{$this->nixpacks_plan}' | base64 -d > {$this->workdir}/thegameplan.json"), "hidden" => true]);
executeInDocker($this->deployment_uuid, "cp {$this->workdir}/Dockerfile {$this->workdir}/.nixpacks/Dockerfile") if ($this->force_rebuild) {
], $this->execute_remote_command([
); executeInDocker($this->deployment_uuid, "nixpacks build -c thegameplan.json --no-cache --no-error-without-start -n {$this->build_image_name} {$this->workdir}"), "hidden" => true
} ]);
if ($this->force_rebuild) { } else {
$this->execute_remote_command([ $this->execute_remote_command([
executeInDocker($this->deployment_uuid, "docker build --no-cache $this->buildTarget $this->addHosts --network host -f {$this->workdir}{$this->dockerfile_location} {$this->build_args} --progress plain -t $this->build_image_name {$this->workdir}"), "hidden" => true executeInDocker($this->deployment_uuid, "nixpacks build -c thegameplan.json --cache-key '{$this->application->uuid}' --no-error-without-start -n {$this->build_image_name} {$this->workdir}"), "hidden" => true
]); ]);
}
} else { } else {
$this->execute_remote_command([ if ($this->force_rebuild) {
executeInDocker($this->deployment_uuid, "docker build $this->buildTarget $this->addHosts --network host -f {$this->workdir}{$this->dockerfile_location} {$this->build_args} --progress plain -t $this->build_image_name {$this->workdir}"), "hidden" => true $this->execute_remote_command([
]); executeInDocker($this->deployment_uuid, "docker build --no-cache {$this->buildTarget} --network {$this->destination->network} -f {$this->workdir}{$this->dockerfile_location} {$this->build_args} --progress plain -t $this->build_image_name {$this->workdir}"), "hidden" => true
]);
} else {
$this->execute_remote_command([
executeInDocker($this->deployment_uuid, "docker build {$this->buildTarget} --network {$this->destination->network} -f {$this->workdir}{$this->dockerfile_location} {$this->build_args} --progress plain -t $this->build_image_name {$this->workdir}"), "hidden" => true
]);
}
} }
// }
$dockerfile = base64_encode("FROM {$this->application->static_image} $dockerfile = base64_encode("FROM {$this->application->static_image}
WORKDIR /usr/share/nginx/html/ WORKDIR /usr/share/nginx/html/
@ -1279,32 +1328,38 @@ private function build_image()
executeInDocker($this->deployment_uuid, "echo '{$nginx_config}' | base64 -d > {$this->workdir}/nginx.conf") executeInDocker($this->deployment_uuid, "echo '{$nginx_config}' | base64 -d > {$this->workdir}/nginx.conf")
], ],
[ [
executeInDocker($this->deployment_uuid, "docker build $this->addHosts --network host -f {$this->workdir}/Dockerfile {$this->build_args} --progress plain -t $this->production_image_name {$this->workdir}"), "hidden" => true executeInDocker($this->deployment_uuid, "docker build {$this->addHosts} --network host -f {$this->workdir}/Dockerfile {$this->build_args} --progress plain -t {$this->production_image_name} {$this->workdir}"), "hidden" => true
] ]
); );
} else { } else {
// Pure Dockerfile based deployment // Pure Dockerfile based deployment
if ($this->application->dockerfile) { if ($this->application->dockerfile) {
$this->execute_remote_command([ $this->execute_remote_command([
executeInDocker($this->deployment_uuid, "docker build --pull $this->buildTarget $this->addHosts --network host -f {$this->workdir}{$this->dockerfile_location} {$this->build_args} --progress plain -t $this->production_image_name {$this->workdir}"), "hidden" => true executeInDocker($this->deployment_uuid, "docker build --pull {$this->buildTarget} {$this->addHosts} --network host -f {$this->workdir}{$this->dockerfile_location} {$this->build_args} --progress plain -t {$this->production_image_name} {$this->workdir}"), "hidden" => true
]); ]);
} else { } else {
if ($this->application->build_pack === 'nixpacks') { if ($this->application->build_pack === 'nixpacks') {
$this->execute_remote_command( $this->nixpacks_plan = base64_encode($this->nixpacks_plan);
[ $this->execute_remote_command([executeInDocker($this->deployment_uuid, "echo '{$this->nixpacks_plan}' | base64 -d > {$this->workdir}/thegameplan.json"), "hidden" => true]);
executeInDocker($this->deployment_uuid, "cp {$this->workdir}/Dockerfile {$this->workdir}/.nixpacks/Dockerfile") if ($this->force_rebuild) {
], $this->execute_remote_command([
); executeInDocker($this->deployment_uuid, "nixpacks build -c thegameplan.json --no-cache --no-error-without-start -n {$this->production_image_name} {$this->workdir}"), "hidden" => true
} ]);
} else {
if ($this->force_rebuild) { $this->execute_remote_command([
$this->execute_remote_command([ executeInDocker($this->deployment_uuid, "nixpacks build -c thegameplan.json --cache-key '{$this->application->uuid}' --no-error-without-start -n {$this->production_image_name} {$this->workdir}"), "hidden" => true
executeInDocker($this->deployment_uuid, "docker build --no-cache $this->buildTarget $this->addHosts --network host -f {$this->workdir}{$this->dockerfile_location} {$this->build_args} --progress plain -t $this->production_image_name {$this->workdir}"), "hidden" => true ]);
]); }
} else { } else {
$this->execute_remote_command([ if ($this->force_rebuild) {
executeInDocker($this->deployment_uuid, "docker build $this->buildTarget $this->addHosts --network host -f {$this->workdir}{$this->dockerfile_location} {$this->build_args} --progress plain -t $this->production_image_name {$this->workdir}"), "hidden" => true $this->execute_remote_command([
]); executeInDocker($this->deployment_uuid, "docker build --no-cache {$this->buildTarget} {$this->addHosts} --network host -f {$this->workdir}{$this->dockerfile_location} {$this->build_args} --progress plain -t {$this->production_image_name} {$this->workdir}"), "hidden" => true
]);
} else {
$this->execute_remote_command([
executeInDocker($this->deployment_uuid, "docker build {$this->buildTarget} {$this->addHosts} --network host -f {$this->workdir}{$this->dockerfile_location} {$this->build_args} --progress plain -t {$this->production_image_name} {$this->workdir}"), "hidden" => true
]);
}
} }
} }
} }

View File

@ -162,6 +162,10 @@ public function handle()
// Notify user that this container should not be there. // Notify user that this container should not be there.
} }
} }
if (data_get($container,'Name') === '/coolify-db') {
$foundDatabases[] = 0;
}
} }
$serviceLabelId = data_get($labels, 'coolify.serviceId'); $serviceLabelId = data_get($labels, 'coolify.serviceId');
if ($serviceLabelId) { if ($serviceLabelId) {
@ -212,7 +216,7 @@ public function handle()
} }
$name = data_get($exitedService, 'name'); $name = data_get($exitedService, 'name');
$fqdn = data_get($exitedService, 'fqdn'); $fqdn = data_get($exitedService, 'fqdn');
$containerName = $name ? "$name ($fqdn)" : $fqdn; $containerName = $name ? "$name, available at $fqdn" : $fqdn;
$projectUuid = data_get($service, 'environment.project.uuid'); $projectUuid = data_get($service, 'environment.project.uuid');
$serviceUuid = data_get($service, 'uuid'); $serviceUuid = data_get($service, 'uuid');
$environmentName = data_get($service, 'environment.name'); $environmentName = data_get($service, 'environment.name');

View File

@ -274,7 +274,7 @@ public function showNewResource()
{ {
$this->skipBoarding(); $this->skipBoarding();
return redirect()->route( return redirect()->route(
'project.resources.new', 'project.resource.create',
[ [
'project_uuid' => $this->createdProject->uuid, 'project_uuid' => $this->createdProject->uuid,
'environment_name' => 'production', 'environment_name' => 'production',

View File

@ -0,0 +1,18 @@
<?php
namespace App\Livewire\CommandCenter;
use App\Models\Server;
use Livewire\Component;
class Index extends Component
{
public $servers = [];
public function mount() {
$this->servers = Server::isReachable()->get();
}
public function render()
{
return view('livewire.command-center.index');
}
}

View File

@ -22,6 +22,10 @@ public function mount()
{ {
$this->email = auth()->user()->email; $this->email = auth()->user()->email;
} }
public function render()
{
return view('livewire.force-password-reset')->layout('layouts.simple');
}
public function submit() public function submit()
{ {
try { try {

View File

@ -5,21 +5,19 @@
use Livewire\Attributes\Validate; use Livewire\Attributes\Validate;
use Livewire\Component; use Livewire\Component;
class Form extends Component class Index extends Component
{ {
public int $userId; public int $userId;
public string $email; public string $email;
#[Validate('required')] #[Validate('required')]
public string $name; public string $name;
public function mount() public function mount()
{ {
$this->userId = auth()->user()->id; $this->userId = auth()->user()->id;
$this->name = auth()->user()->name; $this->name = auth()->user()->name;
$this->email = auth()->user()->email; $this->email = auth()->user()->email;
} }
public function submit() public function submit()
{ {
@ -34,4 +32,8 @@ public function submit()
return handleError($e, $this); return handleError($e, $this);
} }
} }
public function render()
{
return view('livewire.profile.index');
}
} }

View File

@ -27,7 +27,7 @@ public function submit()
'project_id' => $this->project->id, 'project_id' => $this->project->id,
]); ]);
return redirect()->route('project.resources', [ return redirect()->route('project.resource.index', [
'project_uuid' => $this->project->uuid, 'project_uuid' => $this->project->uuid,
'environment_name' => $environment->name, 'environment_name' => $environment->name,
]); ]);

View File

@ -4,13 +4,14 @@
use App\Models\Application; use App\Models\Application;
use App\Models\Server; use App\Models\Server;
use App\Models\StandaloneDocker;
use Livewire\Component; use Livewire\Component;
class Configuration extends Component class Configuration extends Component
{ {
public Application $application; public Application $application;
public $servers; public $servers;
protected $listeners = ['build_pack_updated' => '$refresh'];
public function mount() public function mount()
{ {
$project = currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first(); $project = currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();

View File

@ -1,15 +1,15 @@
<?php <?php
namespace App\Livewire\Project\Application; namespace App\Livewire\Project\Application\Deployment;
use App\Models\Application; use App\Models\Application;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Livewire\Component; use Livewire\Component;
class Deployments extends Component class Index extends Component
{ {
public Application $application; public Application $application;
public Array|Collection $deployments = []; public array|Collection $deployments = [];
public int $deployments_count = 0; public int $deployments_count = 0;
public string $current_url; public string $current_url;
public int $skip = 0; public int $skip = 0;
@ -19,11 +19,28 @@ class Deployments extends Component
protected $queryString = ['pull_request_id']; protected $queryString = ['pull_request_id'];
public function mount() 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');
}
['deployments' => $deployments, 'count' => $count] = $application->deployments(0, 40);
$this->application = $application;
$this->deployments = $deployments;
$this->deployments_count = $count;
$this->current_url = url()->current(); $this->current_url = url()->current();
$this->show_pull_request_only(); $this->show_pull_request_only();
$this->show_more(); $this->show_more();
} }
private function show_pull_request_only() { private function show_pull_request_only()
{
if ($this->pull_request_id) { if ($this->pull_request_id) {
$this->deployments = $this->deployments->where('pull_request_id', $this->pull_request_id); $this->deployments = $this->deployments->where('pull_request_id', $this->pull_request_id);
} }
@ -57,4 +74,8 @@ public function load_deployments(int|null $take = null)
$this->show_pull_request_only(); $this->show_pull_request_only();
$this->show_more(); $this->show_more();
} }
public function render()
{
return view('livewire.project.application.deployment.index');
}
} }

View File

@ -1,35 +1,20 @@
<?php <?php
namespace App\Http\Controllers; namespace App\Livewire\Project\Application\Deployment;
use App\Models\Application;
use App\Models\ApplicationDeploymentQueue; use App\Models\ApplicationDeploymentQueue;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Livewire\Component;
use Illuminate\Foundation\Validation\ValidatesRequests;
class ApplicationController extends Controller class Show extends Component
{ {
use AuthorizesRequests, ValidatesRequests; public Application $application;
public ApplicationDeploymentQueue $application_deployment_queue;
public string $deployment_uuid;
public $isKeepAliveOn = true;
protected $listeners = ['refreshQueue'];
public function deployments() 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');
}
['deployments' => $deployments, 'count' => $count] = $application->deployments(0, 40);
return view('project.application.deployments', ['application' => $application, 'deployments' => $deployments, 'deployments_count' => $count]);
}
public function deployment()
{
$deploymentUuid = request()->route('deployment_uuid'); $deploymentUuid = request()->route('deployment_uuid');
$project = currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first(); $project = currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
@ -46,7 +31,7 @@ public function deployment()
} }
// $activity = Activity::where('properties->type_uuid', '=', $deploymentUuid)->first(); // $activity = Activity::where('properties->type_uuid', '=', $deploymentUuid)->first();
// if (!$activity) { // if (!$activity) {
// return redirect()->route('project.application.deployments', [ // return redirect()->route('project.application.deployment.index', [
// 'project_uuid' => $project->uuid, // 'project_uuid' => $project->uuid,
// 'environment_name' => $environment->name, // 'environment_name' => $environment->name,
// 'application_uuid' => $application->uuid, // 'application_uuid' => $application->uuid,
@ -54,17 +39,32 @@ public function deployment()
// } // }
$application_deployment_queue = ApplicationDeploymentQueue::where('deployment_uuid', $deploymentUuid)->first(); $application_deployment_queue = ApplicationDeploymentQueue::where('deployment_uuid', $deploymentUuid)->first();
if (!$application_deployment_queue) { if (!$application_deployment_queue) {
return redirect()->route('project.application.deployments', [ return redirect()->route('project.application.deployment.index', [
'project_uuid' => $project->uuid, 'project_uuid' => $project->uuid,
'environment_name' => $environment->name, 'environment_name' => $environment->name,
'application_uuid' => $application->uuid, 'application_uuid' => $application->uuid,
]); ]);
} }
return view('project.application.deployment', [ $this->application = $application;
'application' => $application, $this->application_deployment_queue = $application_deployment_queue;
// 'activity' => $activity, $this->deployment_uuid = $deploymentUuid;
'application_deployment_queue' => $application_deployment_queue, }
'deployment_uuid' => $deploymentUuid,
]); public function refreshQueue()
{
$this->application_deployment_queue->refresh();
}
public function polling()
{
$this->dispatch('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;
}
}
public function render()
{
return view('livewire.project.application.deployment.show');
} }
} }

View File

@ -1,27 +0,0 @@
<?php
namespace App\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->dispatch('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

@ -165,12 +165,20 @@ public function updatedApplicationBuildPack()
if ($this->application->build_pack !== 'nixpacks') { if ($this->application->build_pack !== 'nixpacks') {
$this->application->settings->is_static = false; $this->application->settings->is_static = false;
$this->application->settings->save(); $this->application->settings->save();
} else {
$this->application->ports_exposes = $this->ports_exposes = 3000;
$this->resetDefaultLabels(false);
} }
if ($this->application->build_pack === 'dockercompose') { if ($this->application->build_pack === 'dockercompose') {
$this->application->fqdn = null; $this->application->fqdn = null;
$this->application->settings->save(); $this->application->settings->save();
} }
if ($this->application->build_pack === 'static') {
$this->application->ports_exposes = $this->ports_exposes = 80;
$this->resetDefaultLabels(false);
}
$this->submit(); $this->submit();
$this->dispatch('build_pack_updated');
} }
public function checkLabelUpdates() public function checkLabelUpdates()
{ {
@ -201,7 +209,7 @@ public function resetDefaultLabels($showToaster = true)
public function updatedApplicationFqdn() public function updatedApplicationFqdn()
{ {
$this->resetDefaultLabels(false); $this->resetDefaultLabels(false);
$this->dispatch('success', 'Labels reseted to default!'); $this->dispatch('success', 'Labels reset to default!');
} }
public function submit($showToaster = true) public function submit($showToaster = true)
{ {

View File

@ -39,7 +39,7 @@ public function check_status($showNotification = false)
} else { } else {
dispatch(new ServerStatusJob($this->application->destination->server)); dispatch(new ServerStatusJob($this->application->destination->server));
} }
if ($showNotification) $this->dispatch('success', 'Application status updated.'); if ($showNotification) $this->dispatch('success', "Application ({$this->application->name}) status updated.");
} }
public function force_deploy_without_cache() public function force_deploy_without_cache()
@ -60,7 +60,7 @@ public function deployNew()
force_rebuild: false, force_rebuild: false,
is_new_deployment: true, is_new_deployment: true,
); );
return redirect()->route('project.application.deployment', [ return redirect()->route('project.application.deployment.show', [
'project_uuid' => $this->parameters['project_uuid'], 'project_uuid' => $this->parameters['project_uuid'],
'application_uuid' => $this->parameters['application_uuid'], 'application_uuid' => $this->parameters['application_uuid'],
'deployment_uuid' => $this->deploymentUuid, 'deployment_uuid' => $this->deploymentUuid,
@ -83,7 +83,7 @@ public function deploy(bool $force_rebuild = false)
deployment_uuid: $this->deploymentUuid, deployment_uuid: $this->deploymentUuid,
force_rebuild: $force_rebuild, force_rebuild: $force_rebuild,
); );
return redirect()->route('project.application.deployment', [ return redirect()->route('project.application.deployment.show', [
'project_uuid' => $this->parameters['project_uuid'], 'project_uuid' => $this->parameters['project_uuid'],
'application_uuid' => $this->parameters['application_uuid'], 'application_uuid' => $this->parameters['application_uuid'],
'deployment_uuid' => $this->deploymentUuid, 'deployment_uuid' => $this->deploymentUuid,
@ -113,7 +113,7 @@ public function restartNew()
restart_only: true, restart_only: true,
is_new_deployment: true, is_new_deployment: true,
); );
return redirect()->route('project.application.deployment', [ return redirect()->route('project.application.deployment.show', [
'project_uuid' => $this->parameters['project_uuid'], 'project_uuid' => $this->parameters['project_uuid'],
'application_uuid' => $this->parameters['application_uuid'], 'application_uuid' => $this->parameters['application_uuid'],
'deployment_uuid' => $this->deploymentUuid, 'deployment_uuid' => $this->deploymentUuid,
@ -128,7 +128,7 @@ public function restart()
deployment_uuid: $this->deploymentUuid, deployment_uuid: $this->deploymentUuid,
restart_only: true, restart_only: true,
); );
return redirect()->route('project.application.deployment', [ return redirect()->route('project.application.deployment.show', [
'project_uuid' => $this->parameters['project_uuid'], 'project_uuid' => $this->parameters['project_uuid'],
'application_uuid' => $this->parameters['application_uuid'], 'application_uuid' => $this->parameters['application_uuid'],
'deployment_uuid' => $this->deploymentUuid, 'deployment_uuid' => $this->deploymentUuid,

View File

@ -52,7 +52,7 @@ public function deploy(int $pull_request_id, string|null $pull_request_html_url
force_rebuild: true, force_rebuild: true,
pull_request_id: $pull_request_id, pull_request_id: $pull_request_id,
); );
return redirect()->route('project.application.deployment', [ return redirect()->route('project.application.deployment.show', [
'project_uuid' => $this->parameters['project_uuid'], 'project_uuid' => $this->parameters['project_uuid'],
'application_uuid' => $this->parameters['application_uuid'], 'application_uuid' => $this->parameters['application_uuid'],
'deployment_uuid' => $this->deployment_uuid, 'deployment_uuid' => $this->deployment_uuid,

View File

@ -29,7 +29,7 @@ public function rollbackImage($commit)
commit: $commit, commit: $commit,
force_rebuild: false, force_rebuild: false,
); );
return redirect()->route('project.application.deployment', [ return redirect()->route('project.application.deployment.show', [
'project_uuid' => $this->parameters['project_uuid'], 'project_uuid' => $this->parameters['project_uuid'],
'application_uuid' => $this->parameters['application_uuid'], 'application_uuid' => $this->parameters['application_uuid'],
'deployment_uuid' => $deployment_uuid, 'deployment_uuid' => $deployment_uuid,

View File

@ -8,7 +8,7 @@
use Livewire\Component; use Livewire\Component;
use Visus\Cuid2\Cuid2; use Visus\Cuid2\Cuid2;
class CloneProject extends Component class CloneMe extends Component
{ {
public string $project_uuid; public string $project_uuid;
public string $environment_name; public string $environment_name;
@ -41,7 +41,7 @@ public function mount($project_uuid)
public function render() public function render()
{ {
return view('livewire.project.clone-project'); return view('livewire.project.clone-me');
} }
public function selectServer($server_id, $destination_id) public function selectServer($server_id, $destination_id)
@ -152,7 +152,7 @@ public function clone()
} }
$newService->parse(); $newService->parse();
} }
return redirect()->route('project.resources', [ return redirect()->route('project.resource.index', [
'project_uuid' => $newProject->uuid, 'project_uuid' => $newProject->uuid,
'environment_name' => $newEnvironment->name, 'environment_name' => $newEnvironment->name,
]); ]);

View File

@ -0,0 +1,41 @@
<?php
namespace App\Livewire\Project\Database\Backup;
use Livewire\Component;
class Execution extends Component
{
public $database;
public $backup;
public $executions;
public $s3s;
public function mount() {
$backup_uuid = request()->route('backup_uuid');
$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');
}
$database = $environment->databases()->where('uuid', request()->route('database_uuid'))->first();
if (!$database) {
return redirect()->route('dashboard');
}
$backup = $database->scheduledBackups->where('uuid', $backup_uuid)->first();
if (!$backup) {
return redirect()->route('dashboard');
}
$executions = collect($backup->executions)->sortByDesc('created_at');
$this->database = $database;
$this->backup = $backup;
$this->executions = $executions;
$this->s3s = currentTeam()->s3s;
}
public function render()
{
return view('livewire.project.database.backup.execution');
}
}

View File

@ -0,0 +1,39 @@
<?php
namespace App\Livewire\Project\Database\Backup;
use Livewire\Component;
class Index extends Component
{
public $database;
public $s3s;
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');
}
$database = $environment->databases()->where('uuid', request()->route('database_uuid'))->first();
if (!$database) {
return redirect()->route('dashboard');
}
// No backups for redis
if ($database->getMorphClass() === 'App\Models\StandaloneRedis') {
return redirect()->route('project.database.configuration', [
'project_uuid' => $project->uuid,
'environment_name' => $environment->name,
'database_uuid' => $database->uuid,
]);
}
$this->database = $database;
$this->s3s = currentTeam()->s3s;
}
public function render()
{
return view('livewire.project.database.backup.index');
}
}

View File

@ -52,7 +52,7 @@ public function delete()
$url = $url->getPath() . "#{$url->getFragment()}"; $url = $url->getPath() . "#{$url->getFragment()}";
return redirect($url); return redirect($url);
} else { } else {
return redirect()->route('project.database.backups.all', $this->parameters); return redirect()->route('project.database.backup.index', $this->parameters);
} }
} }

View File

@ -0,0 +1,29 @@
<?php
namespace App\Livewire\Project\Database;
use Livewire\Component;
class Configuration extends Component
{
public $database;
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');
}
$database = $environment->databases()->where('uuid', request()->route('database_uuid'))->first();
if (!$database) {
return redirect()->route('dashboard');
}
$this->database = $database;
}
public function render()
{
return view('livewire.project.database.configuration');
}
}

View File

@ -25,6 +25,6 @@ public function delete()
return $this->dispatch('error', 'Project has resources defined, please delete them first.'); return $this->dispatch('error', 'Project has resources defined, please delete them first.');
} }
$project->delete(); $project->delete();
return redirect()->route('projects'); return redirect()->route('project.index');
} }
} }

View File

@ -12,6 +12,15 @@ class Edit extends Component
'project.name' => 'required|min:3|max:255', 'project.name' => 'required|min:3|max:255',
'project.description' => 'nullable|string|max:255', 'project.description' => 'nullable|string|max:255',
]; ];
public function mount() {
$projectUuid = request()->route('project_uuid');
$teamId = currentTeam()->id;
$project = Project::where('team_id', $teamId)->where('uuid', $projectUuid)->first();
if (!$project) {
return redirect()->route('dashboard');
}
$this->project = $project;
}
public function submit() public function submit()
{ {

View File

@ -0,0 +1,21 @@
<?php
namespace App\Livewire\Project;
use App\Models\Project;
use App\Models\Server;
use Livewire\Component;
class Index extends Component
{
public $projects;
public $servers;
public function mount() {
$this->projects = Project::ownedByCurrentTeam()->get();
$this->servers = Server::ownedByCurrentTeam()->count();
}
public function render()
{
return view('livewire.project.index');
}
}

View File

@ -55,7 +55,7 @@ public function render()
public function updatedSelectedEnvironment() public function updatedSelectedEnvironment()
{ {
return redirect()->route('project.resources.new', [ return redirect()->route('project.resource.create', [
'project_uuid' => $this->parameters['project_uuid'], 'project_uuid' => $this->parameters['project_uuid'],
'environment_name' => $this->selectedEnvironment, 'environment_name' => $this->selectedEnvironment,
]); ]);
@ -157,7 +157,7 @@ public function setServer(Server $server)
public function setDestination(string $destination_uuid) public function setDestination(string $destination_uuid)
{ {
$this->destination_uuid = $destination_uuid; $this->destination_uuid = $destination_uuid;
return redirect()->route('project.resources.new', [ return redirect()->route('project.resource.create', [
'project_uuid' => $this->parameters['project_uuid'], 'project_uuid' => $this->parameters['project_uuid'],
'environment_name' => $this->parameters['environment_name'], 'environment_name' => $this->parameters['environment_name'],
'type' => $this->type, 'type' => $this->type,

View File

@ -1,52 +1,18 @@
<?php <?php
namespace App\Http\Controllers; namespace App\Livewire\Project\Resource;
use App\Models\EnvironmentVariable; use App\Models\EnvironmentVariable;
use App\Models\Project;
use App\Models\Server;
use App\Models\Service; use App\Models\Service;
use App\Models\StandaloneDocker; use App\Models\StandaloneDocker;
use Illuminate\Support\Str; use Livewire\Component;
class ProjectController extends Controller class Create extends Component
{ {
public function all() public $type;
{ public function mount() {
return view('projects', [
'projects' => Project::ownedByCurrentTeam()->get(),
'servers' => Server::ownedByCurrentTeam()->count(),
]);
}
public function edit()
{
$projectUuid = request()->route('project_uuid');
$teamId = currentTeam()->id;
$project = Project::where('team_id', $teamId)->where('uuid', $projectUuid)->first();
if (!$project) {
return redirect()->route('dashboard');
}
return view('project.edit', ['project' => $project]);
}
public function show()
{
$projectUuid = request()->route('project_uuid');
$teamId = currentTeam()->id;
$project = Project::where('team_id', $teamId)->where('uuid', $projectUuid)->first();
if (!$project) {
return redirect()->route('dashboard');
}
$project->load(['environments']);
return view('project.show', ['project' => $project]);
}
public function new()
{
$services = getServiceTemplates(); $services = getServiceTemplates();
$type = Str::of(request()->query('type')); $type = str(request()->query('type'));
$destination_uuid = request()->query('destination'); $destination_uuid = request()->query('destination');
$server_id = request()->query('server_id'); $server_id = request()->query('server_id');
@ -81,14 +47,14 @@ public function new()
$oneClickService = data_get($services, "$oneClickServiceName.compose"); $oneClickService = data_get($services, "$oneClickServiceName.compose");
$oneClickDotEnvs = data_get($services, "$oneClickServiceName.envs", null); $oneClickDotEnvs = data_get($services, "$oneClickServiceName.envs", null);
if ($oneClickDotEnvs) { if ($oneClickDotEnvs) {
$oneClickDotEnvs = Str::of(base64_decode($oneClickDotEnvs))->split('/\r\n|\r|\n/')->filter(function ($value) { $oneClickDotEnvs = str(base64_decode($oneClickDotEnvs))->split('/\r\n|\r|\n/')->filter(function ($value) {
return !empty($value); return !empty($value);
}); });
} }
if ($oneClickService) { if ($oneClickService) {
$destination = StandaloneDocker::whereUuid($destination_uuid)->first(); $destination = StandaloneDocker::whereUuid($destination_uuid)->first();
$service = Service::create([ $service = Service::create([
'name' => "$oneClickServiceName-" . Str::random(10), 'name' => "$oneClickServiceName-" . str()->random(10),
'docker_compose_raw' => base64_decode($oneClickService), 'docker_compose_raw' => base64_decode($oneClickService),
'environment_id' => $environment->id, 'environment_id' => $environment->id,
'server_id' => (int) $server_id, 'server_id' => (int) $server_id,
@ -99,8 +65,8 @@ public function new()
$service->save(); $service->save();
if ($oneClickDotEnvs?->count() > 0) { if ($oneClickDotEnvs?->count() > 0) {
$oneClickDotEnvs->each(function ($value) use ($service) { $oneClickDotEnvs->each(function ($value) use ($service) {
$key = Str::before($value, '='); $key = str()->before($value, '=');
$value = Str::of(Str::after($value, '=')); $value = str(str()->after($value, '='));
$generatedValue = $value; $generatedValue = $value;
if ($value->contains('SERVICE_')) { if ($value->contains('SERVICE_')) {
$command = $value->after('SERVICE_')->beforeLast('_'); $command = $value->after('SERVICE_')->beforeLast('_');
@ -123,24 +89,10 @@ public function new()
]); ]);
} }
} }
return view('project.new', [ $this->type = $type->value();
'type' => $type->value()
]);
} }
public function render()
public function resources()
{ {
$project = currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first(); return view('livewire.project.resource.create');
if (!$project) {
return redirect()->route('dashboard');
}
$environment = $project->load(['environments'])->environments->where('name', request()->route('environment_name'))->first();
if (!$environment) {
return redirect()->route('dashboard');
}
return view('project.resources', [
'project' => $project,
'environment' => $environment
]);
} }
} }

View File

@ -0,0 +1,29 @@
<?php
namespace App\Livewire\Project\Resource;
use App\Models\Environment;
use App\Models\Project;
use Livewire\Component;
class Index extends Component
{
public Project $project;
public Environment $environment;
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();
if (!$environment) {
return redirect()->route('dashboard');
}
$this->project = $project;
$this->environment = $environment;
}
public function render()
{
return view('livewire.project.resource.index');
}
}

View File

@ -0,0 +1,54 @@
<?php
namespace App\Livewire\Project\Service;
use App\Jobs\ContainerStatusJob;
use App\Models\Service;
use Livewire\Component;
class Configuration extends Component
{
public Service $service;
public $applications;
public $databases;
public array $parameters;
public array $query;
public function getListeners()
{
$userId = auth()->user()->id;
return [
"echo-private:user.{$userId},ServiceStatusChanged" => 'checkStatus',
"refreshStacks",
"checkStatus",
];
}
public function render()
{
return view('livewire.project.service.configuration');
}
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_sync(new ContainerStatusJob($this->service->server));
$this->refreshStacks();
$this->dispatch('serviceStatusChanged');
}
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

@ -2,53 +2,51 @@
namespace App\Livewire\Project\Service; namespace App\Livewire\Project\Service;
use App\Jobs\ContainerStatusJob;
use App\Models\Service; use App\Models\Service;
use App\Models\ServiceApplication;
use App\Models\ServiceDatabase;
use Illuminate\Support\Collection;
use Livewire\Component; use Livewire\Component;
class Index extends Component class Index extends Component
{ {
public Service $service; public Service $service;
public $applications; public ?ServiceApplication $serviceApplication = null;
public $databases; public ?ServiceDatabase $serviceDatabase = null;
public array $parameters; public array $parameters;
public array $query; public array $query;
public function getListeners() public Collection $services;
public $s3s;
protected $listeners = ['generateDockerCompose'];
public function mount()
{ {
$userId = auth()->user()->id; try {
return [ $this->services = collect([]);
"echo-private:user.{$userId},ServiceStatusChanged" => 'checkStatus', $this->parameters = get_route_parameters();
"refreshStacks", $this->query = request()->query();
"checkStatus", $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() public function render()
{ {
return view('livewire.project.service.index'); 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_sync(new ContainerStatusJob($this->service->server));
$this->refreshStacks();
$this->dispatch('serviceStatusChanged');
}
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,52 +0,0 @@
<?php
namespace App\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

@ -25,7 +25,7 @@ public function delete()
{ {
try { try {
DeleteResourceJob::dispatchSync($this->resource); DeleteResourceJob::dispatchSync($this->resource);
return redirect()->route('project.resources', [ return redirect()->route('project.resource.index', [
'project_uuid' => $this->projectUuid, 'project_uuid' => $this->projectUuid,
'environment_name' => $this->environmentName 'environment_name' => $this->environmentName
]); ]);

View File

@ -139,6 +139,18 @@ public function submit($data)
case 'standalone-postgresql': case 'standalone-postgresql':
$environment->standalone_postgresql_id = $this->resource->id; $environment->standalone_postgresql_id = $this->resource->id;
break; 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': case 'service':
$environment->service_id = $this->resource->id; $environment->service_id = $this->resource->id;
break; break;

View File

@ -10,7 +10,6 @@
use App\Models\StandaloneMysql; use App\Models\StandaloneMysql;
use App\Models\StandalonePostgresql; use App\Models\StandalonePostgresql;
use App\Models\StandaloneRedis; use App\Models\StandaloneRedis;
use Illuminate\Support\Sleep;
use Livewire\Component; use Livewire\Component;
class ExecuteContainerCommand extends Component class ExecuteContainerCommand extends Component

View File

@ -0,0 +1,26 @@
<?php
namespace App\Livewire\Project;
use App\Models\Project;
use Livewire\Component;
class Show extends Component
{
public Project $project;
public function mount() {
$projectUuid = request()->route('project_uuid');
$teamId = currentTeam()->id;
$project = Project::where('team_id', $teamId)->where('uuid', $projectUuid)->first();
if (!$project) {
return redirect()->route('dashboard');
}
$project->load(['environments']);
$this->project = $project;
}
public function render()
{
return view('livewire.project.show');
}
}

View File

@ -1,6 +1,6 @@
<?php <?php
namespace App\Livewire\PrivateKey; namespace App\Livewire\Security\PrivateKey;
use App\Models\PrivateKey; use App\Models\PrivateKey;
use DanHarrin\LivewireRateLimiting\WithRateLimiting; use DanHarrin\LivewireRateLimiting\WithRateLimiting;

View File

@ -1,11 +1,11 @@
<?php <?php
namespace App\Livewire\PrivateKey; namespace App\Livewire\Security\PrivateKey;
use App\Models\PrivateKey; use App\Models\PrivateKey;
use Livewire\Component; use Livewire\Component;
class Change extends Component class Show extends Component
{ {
public PrivateKey $private_key; public PrivateKey $private_key;
public $public_key; public $public_key;
@ -24,6 +24,7 @@ class Change extends Component
public function mount() public function mount()
{ {
try { try {
$this->private_key = PrivateKey::ownedByCurrentTeam(['name', 'description', 'private_key', 'is_git_related'])->whereUuid(request()->private_key_uuid)->firstOrFail();
$this->public_key = $this->private_key->publicKey(); $this->public_key = $this->private_key->publicKey();
}catch(\Throwable $e) { }catch(\Throwable $e) {
return handleError($e, $this); return handleError($e, $this);

View File

@ -19,7 +19,7 @@ public function delete()
return; return;
} }
$this->server->delete(); $this->server->delete();
return redirect()->route('server.all'); return redirect()->route('server.index');
} catch (\Throwable $e) { } catch (\Throwable $e) {
return handleError($e, $this); return handleError($e, $this);
} }

View File

@ -15,7 +15,7 @@ public function mount()
try { try {
$this->server = Server::ownedByCurrentTeam()->whereUuid(request()->server_uuid)->first(); $this->server = Server::ownedByCurrentTeam()->whereUuid(request()->server_uuid)->first();
if (is_null($this->server)) { if (is_null($this->server)) {
return redirect()->route('server.all'); return redirect()->route('server.index');
} }
} catch (\Throwable $e) { } catch (\Throwable $e) {
return handleError($e, $this); return handleError($e, $this);

View File

@ -6,7 +6,7 @@
use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Collection;
use Livewire\Component; use Livewire\Component;
class All extends Component class Index extends Component
{ {
public ?Collection $servers = null; public ?Collection $servers = null;
@ -15,6 +15,6 @@ public function mount () {
} }
public function render() public function render()
{ {
return view('livewire.server.all'); return view('livewire.server.index');
} }
} }

View File

@ -43,7 +43,7 @@ public function mount()
try { try {
$server = Server::ownedByCurrentTeam()->whereUuid(request()->server_uuid)->first(); $server = Server::ownedByCurrentTeam()->whereUuid(request()->server_uuid)->first();
if (is_null($server)) { if (is_null($server)) {
return redirect()->route('server.all'); return redirect()->route('server.index');
} }
$this->server = $server; $this->server = $server;
} catch (\Throwable $e) { } catch (\Throwable $e) {

View File

@ -17,7 +17,7 @@ public function mount()
try { try {
$this->server = Server::ownedByCurrentTeam()->whereUuid(request()->server_uuid)->first(); $this->server = Server::ownedByCurrentTeam()->whereUuid(request()->server_uuid)->first();
if (is_null($this->server)) { if (is_null($this->server)) {
return redirect()->route('server.all'); return redirect()->route('server.index');
} }
$this->privateKeys = PrivateKey::ownedByCurrentTeam()->get()->where('is_git_related', false); $this->privateKeys = PrivateKey::ownedByCurrentTeam()->get()->where('is_git_related', false);
} catch (\Throwable $e) { } catch (\Throwable $e) {

View File

@ -15,7 +15,7 @@ public function mount()
try { try {
$this->server = Server::ownedByCurrentTeam()->whereUuid(request()->server_uuid)->first(); $this->server = Server::ownedByCurrentTeam()->whereUuid(request()->server_uuid)->first();
if (is_null($this->server)) { if (is_null($this->server)) {
return redirect()->route('server.all'); return redirect()->route('server.index');
} }
} catch (\Throwable $e) { } catch (\Throwable $e) {
return handleError($e, $this); return handleError($e, $this);

View File

@ -20,7 +20,7 @@ public function mount()
try { try {
$this->server = Server::ownedByCurrentTeam()->whereUuid(request()->server_uuid)->first(); $this->server = Server::ownedByCurrentTeam()->whereUuid(request()->server_uuid)->first();
if (is_null($this->server)) { if (is_null($this->server)) {
return redirect()->route('server.all'); return redirect()->route('server.index');
} }
} catch (\Throwable $e) { } catch (\Throwable $e) {
return handleError($e, $this); return handleError($e, $this);

View File

@ -17,7 +17,7 @@ public function mount()
try { try {
$this->server = Server::ownedByCurrentTeam()->whereUuid(request()->server_uuid)->first(); $this->server = Server::ownedByCurrentTeam()->whereUuid(request()->server_uuid)->first();
if (is_null($this->server)) { if (is_null($this->server)) {
return redirect()->route('server.all'); return redirect()->route('server.index');
} }
} catch (\Throwable $e) { } catch (\Throwable $e) {

View File

@ -0,0 +1,38 @@
<?php
namespace App\Livewire\Settings;
use App\Models\InstanceSettings;
use App\Models\S3Storage;
use App\Models\StandalonePostgresql;
use Livewire\Component;
class Index extends Component
{
public InstanceSettings $settings;
public StandalonePostgresql $database;
public $s3s;
public function mount()
{
if (isInstanceAdmin()) {
$settings = InstanceSettings::get();
$database = StandalonePostgresql::whereName('coolify-db')->first();
$s3s = S3Storage::whereTeamId(0)->get() ?? [];
if ($database) {
if ($database->status !== 'running') {
$database->status = 'running';
$database->save();
}
$this->database = $database;
}
$this->settings = $settings;
$this->s3s = $s3s;
} else {
return redirect()->route('dashboard');
}
}
public function render()
{
return view('livewire.settings.index');
}
}

View File

@ -1,15 +1,16 @@
<?php <?php
namespace App\Livewire; namespace App\Livewire\Settings;
use App\Actions\License\CheckResaleLicense; use App\Actions\License\CheckResaleLicense;
use App\Models\InstanceSettings; use App\Models\InstanceSettings;
use Livewire\Component; use Livewire\Component;
class CheckLicense extends Component class License extends Component
{ {
public InstanceSettings|null $settings = null; public InstanceSettings $settings;
public string|null $instance_id = null; public string|null $instance_id = null;
protected $rules = [ protected $rules = [
'settings.resale_license' => 'nullable', 'settings.resale_license' => 'nullable',
'settings.is_resale_license_active' => 'nullable', 'settings.is_resale_license_active' => 'nullable',
@ -20,12 +21,17 @@ class CheckLicense extends Component
'settings.is_resale_license_active' => 'Is License Active', 'settings.is_resale_license_active' => 'Is License Active',
]; ];
public function mount() public function mount () {
{ if (!isCloud()) {
abort(404);
}
$this->instance_id = config('app.id'); $this->instance_id = config('app.id');
$this->settings = InstanceSettings::get(); $this->settings = InstanceSettings::get();
} }
public function render()
{
return view('livewire.settings.license')->layout('layouts.subscription');
}
public function submit() public function submit()
{ {
$this->validate(); $this->validate();

View File

@ -6,7 +6,7 @@
use App\Providers\RouteServiceProvider; use App\Providers\RouteServiceProvider;
use Livewire\Component; use Livewire\Component;
class Show extends Component class Index extends Component
{ {
public InstanceSettings $settings; public InstanceSettings $settings;
public bool $alreadySubscribed = false; public bool $alreadySubscribed = false;
@ -26,6 +26,6 @@ public function stripeCustomerPortal() {
} }
public function render() public function render()
{ {
return view('livewire.subscription.show')->layout('layouts.subscription'); return view('livewire.subscription.index')->layout('layouts.subscription');
} }
} }

View File

@ -1,29 +0,0 @@
<?php
namespace App\Livewire\Team;
use Illuminate\Support\Facades\DB;
use Livewire\Component;
class Delete extends Component
{
public function delete()
{
$currentTeam = currentTeam();
$currentTeam->delete();
$currentTeam->members->each(function ($user) use ($currentTeam) {
if ($user->id === auth()->user()->id) {
return;
}
$user->teams()->detach($currentTeam);
$session = DB::table('sessions')->where('user_id', $user->id)->first();
if ($session) {
DB::table('sessions')->where('id', $session->id)->delete();
}
});
refreshSession();
return redirect()->route('team.index');
}
}

View File

@ -1,35 +0,0 @@
<?php
namespace App\Livewire\Team;
use App\Models\Team;
use Livewire\Component;
class Form extends Component
{
public Team $team;
protected $rules = [
'team.name' => 'required|min:3|max:255',
'team.description' => 'nullable|min:3|max:255',
];
protected $validationAttributes = [
'team.name' => 'name',
'team.description' => 'description',
];
public function mount()
{
$this->team = currentTeam();
}
public function submit()
{
$this->validate();
try {
$this->team->save();
refreshSession();
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
}

View File

@ -0,0 +1,65 @@
<?php
namespace App\Livewire\Team;
use App\Models\Team;
use App\Models\TeamInvitation;
use Illuminate\Support\Facades\DB;
use Livewire\Component;
class Index extends Component
{
public $invitations = [];
public Team $team;
protected $rules = [
'team.name' => 'required|min:3|max:255',
'team.description' => 'nullable|min:3|max:255',
];
protected $validationAttributes = [
'team.name' => 'name',
'team.description' => 'description',
];
public function mount() {
$this->team = currentTeam();
if (auth()->user()->isAdminFromSession()) {
$this->invitations = TeamInvitation::whereTeamId(currentTeam()->id)->get();
}
}
public function render()
{
return view('livewire.team.index');
}
public function submit()
{
$this->validate();
try {
$this->team->save();
refreshSession();
$this->dispatch('success', 'Team updated successfully.');
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function delete()
{
$currentTeam = currentTeam();
$currentTeam->delete();
$currentTeam->members->each(function ($user) use ($currentTeam) {
if ($user->id === auth()->user()->id) {
return;
}
$user->teams()->detach($currentTeam);
$session = DB::table('sessions')->where('user_id', $user->id)->first();
if ($session) {
DB::table('sessions')->where('id', $session->id)->delete();
}
});
refreshSession();
return redirect()->route('team.index');
}
}

View File

@ -0,0 +1,20 @@
<?php
namespace App\Livewire\Team\Member;
use App\Models\TeamInvitation;
use Livewire\Component;
class Index extends Component
{
public $invitations = [];
public function mount() {
if (auth()->user()->isAdminFromSession()) {
$this->invitations = TeamInvitation::whereTeamId(currentTeam()->id)->get();
}
}
public function render()
{
return view('livewire.team.member.index');
}
}

View File

@ -0,0 +1,13 @@
<?php
namespace App\Livewire\Team\Notification;
use Livewire\Component;
class Index extends Component
{
public function render()
{
return view('livewire.team.notification.index');
}
}

View File

@ -65,7 +65,7 @@ public function submit()
$this->storage->team_id = currentTeam()->id; $this->storage->team_id = currentTeam()->id;
$this->storage->testConnection(); $this->storage->testConnection();
$this->storage->save(); $this->storage->save();
return redirect()->route('team.storages.show', $this->storage->uuid); return redirect()->route('team.storage.show', $this->storage->uuid);
} catch (\Throwable $e) { } catch (\Throwable $e) {
return handleError($e, $this); return handleError($e, $this);
} }

View File

@ -43,7 +43,7 @@ public function delete()
{ {
try { try {
$this->storage->delete(); $this->storage->delete();
return redirect()->route('team.storages.all'); return redirect()->route('team.storage.index');
} catch (\Throwable $e) { } catch (\Throwable $e) {
return handleError($e, $this); return handleError($e, $this);
} }

View File

@ -0,0 +1,18 @@
<?php
namespace App\Livewire\Team\Storage;
use App\Models\S3Storage;
use Livewire\Component;
class Index extends Component
{
public $s3;
public function mount() {
$this->s3 = S3Storage::ownedByCurrentTeam()->get();
}
public function render()
{
return view('livewire.team.storage.index');
}
}

View File

@ -0,0 +1,22 @@
<?php
namespace App\Livewire\Team\Storage;
use App\Models\S3Storage;
use Livewire\Component;
class Show extends Component
{
public $storage = null;
public function mount()
{
$this->storage = S3Storage::ownedByCurrentTeam()->whereUuid(request()->storage_uuid)->first();
if (!$this->storage) {
abort(404);
}
}
public function render()
{
return view('livewire.team.storage.show');
}
}

View File

@ -760,7 +760,6 @@ function rollingUpdateApplication(Server $server, ApplicationDeploymentQueue $de
// if (count($this->ports_mappings_array) > 0) { // if (count($this->ports_mappings_array) > 0) {
// $deployment->addLogEntry('Application has ports mapped to the host system, rolling update is not supported.'); // $deployment->addLogEntry('Application has ports mapped to the host system, rolling update is not supported.');
$containers = getCurrentApplicationContainerStatus($server, $this->id, $pullRequestId); $containers = getCurrentApplicationContainerStatus($server, $this->id, $pullRequestId);
ray($containers);
// if ($pullRequestId === 0) { // if ($pullRequestId === 0) {
// $containers = $containers->filter(function ($container) use ($containerName) { // $containers = $containers->filter(function ($container) use ($containerName) {
// return data_get($container, 'Names') !== $containerName; // return data_get($container, 'Names') !== $containerName;
@ -872,7 +871,6 @@ function generateGitImportCommands(string $deployment_uuid, int $pull_request_id
} else { } else {
$git_clone_command = $this->setGitImportSettings($deployment_uuid, $git_clone_command_base); $git_clone_command = $this->setGitImportSettings($deployment_uuid, $git_clone_command_base);
} }
ray($git_clone_command);
if ($exec_in_docker) { if ($exec_in_docker) {
$commands = collect([ $commands = collect([
executeInDocker($deployment_uuid, "mkdir -p /root/.ssh"), executeInDocker($deployment_uuid, "mkdir -p /root/.ssh"),

View File

@ -48,7 +48,7 @@ public function testConnection(bool $shouldSave = false)
if ($this->unusable_email_sent === false && is_transactional_emails_active()) { if ($this->unusable_email_sent === false && is_transactional_emails_active()) {
$mail = new MailMessage(); $mail = new MailMessage();
$mail->subject('Coolify: S3 Storage Connection Error'); $mail->subject('Coolify: S3 Storage Connection Error');
$mail->view('emails.s3-connection-error', ['name' => $this->name, 'reason' => $e->getMessage(), 'url' => route('team.storages.show', ['storage_uuid' => $this->uuid])]); $mail->view('emails.s3-connection-error', ['name' => $this->name, 'reason' => $e->getMessage(), 'url' => route('team.storage.show', ['storage_uuid' => $this->uuid])]);
$users = collect([]); $users = collect([]);
$members = $this->team->members()->get(); $members = $this->team->members()->get();
foreach ($members as $user) { foreach ($members as $user) {

View File

@ -358,10 +358,10 @@ public function isLogDrainEnabled()
public function validateOS(): bool | Stringable public function validateOS(): bool | Stringable
{ {
$os_release = instant_remote_process(['cat /etc/os-release'], $this); $os_release = instant_remote_process(['cat /etc/os-release'], $this);
$datas = collect(explode("\n", $os_release)); $releaseLines = collect(explode("\n", $os_release));
$collectedData = collect([]); $collectedData = collect([]);
foreach ($datas as $data) { foreach ($releaseLines as $line) {
$item = Str::of($data)->trim(); $item = Str::of($line)->trim();
$collectedData->put($item->before('=')->value(), $item->after('=')->lower()->replace('"', '')->value()); $collectedData->put($item->before('=')->value(), $item->after('=')->lower()->replace('"', '')->value());
} }
$ID = data_get($collectedData, 'ID'); $ID = data_get($collectedData, 'ID');

View File

@ -14,8 +14,8 @@ public function send(SendsEmail $notifiable, Notification $notification): void
{ {
try { try {
$this->bootConfigs($notifiable); $this->bootConfigs($notifiable);
$recepients = $notifiable->getRecepients($notification); $recipients = $notifiable->getRecepients($notification);
if (count($recepients) === 0) { if (count($recipients) === 0) {
throw new Exception('No email recipients found'); throw new Exception('No email recipients found');
} }
@ -24,7 +24,7 @@ public function send(SendsEmail $notifiable, Notification $notification): void
[], [],
[], [],
fn (Message $message) => $message fn (Message $message) => $message
->to($recepients) ->to($recipients)
->subject($mailMessage->subject) ->subject($mailMessage->subject)
->html((string)$mailMessage->render()) ->html((string)$mailMessage->render())
); );
@ -35,8 +35,8 @@ public function send(SendsEmail $notifiable, Notification $notification): void
} }
ray($e->getMessage()); ray($e->getMessage());
$message = "EmailChannel error: {$e->getMessage()}. Failed to send email to:"; $message = "EmailChannel error: {$e->getMessage()}. Failed to send email to:";
if (isset($recepients)) { if (isset($recipients)) {
$message .= implode(', ', $recepients); $message .= implode(', ', $recipients);
} }
if (isset($mailMessage)) { if (isset($mailMessage)) {
$message .= " with subject: {$mailMessage->subject}"; $message .= " with subject: {$mailMessage->subject}";

View File

@ -27,7 +27,7 @@ public function via(object $notifiable): array
public function toMail(): MailMessage public function toMail(): MailMessage
{ {
$mail = new MailMessage(); $mail = new MailMessage();
$mail->subject("Coolify: A service ({$this->name}) has been restarted automatically on {$this->server->name}"); $mail->subject("Coolify: A resource ({$this->name}) has been restarted automatically on {$this->server->name}");
$mail->view('emails.container-restarted', [ $mail->view('emails.container-restarted', [
'containerName' => $this->name, 'containerName' => $this->name,
'serverName' => $this->server->name, 'serverName' => $this->server->name,
@ -38,12 +38,12 @@ public function toMail(): MailMessage
public function toDiscord(): string public function toDiscord(): string
{ {
$message = "Coolify: A service ({$this->name}) has been restarted automatically on {$this->server->name}"; $message = "Coolify: A resource ({$this->name}) has been restarted automatically on {$this->server->name}";
return $message; return $message;
} }
public function toTelegram(): array public function toTelegram(): array
{ {
$message = "Coolify: A service ({$this->name}) has been restarted automatically on {$this->server->name}"; $message = "Coolify: A resource ({$this->name}) has been restarted automatically on {$this->server->name}";
$payload = [ $payload = [
"message" => $message, "message" => $message,
]; ];

View File

@ -26,7 +26,7 @@ public function via(object $notifiable): array
public function toMail(): MailMessage public function toMail(): MailMessage
{ {
$mail = new MailMessage(); $mail = new MailMessage();
$mail->subject("Coolify: A service ({$this->name}) has been stopped on {$this->server->name}"); $mail->subject("Coolify: A resource has been stopped unexpectedly on {$this->server->name}");
$mail->view('emails.container-stopped', [ $mail->view('emails.container-stopped', [
'containerName' => $this->name, 'containerName' => $this->name,
'serverName' => $this->server->name, 'serverName' => $this->server->name,
@ -37,12 +37,12 @@ public function toMail(): MailMessage
public function toDiscord(): string public function toDiscord(): string
{ {
$message = "Coolify: A service ({$this->name}) has been stopped on {$this->server->name}"; $message = "Coolify: A resource has been stopped unexpectedly on {$this->server->name}";
return $message; return $message;
} }
public function toTelegram(): array public function toTelegram(): array
{ {
$message = "Coolify: A service ($this->name} has been stopped on {$this->server->name}"; $message = "Coolify: A resource has been stopped unexpectedly on {$this->server->name}";
$payload = [ $payload = [
"message" => $message, "message" => $message,
]; ];

View File

@ -31,7 +31,7 @@ public function toResponse($request)
{ {
// First user (root) will be redirected to /settings instead of / on registration. // First user (root) will be redirected to /settings instead of / on registration.
if ($request->user()->currentTeam->id === 0) { if ($request->user()->currentTeam->id === 0) {
return redirect()->route('settings.configuration'); return redirect()->route('settings.index');
} }
return redirect(RouteServiceProvider::HOME); return redirect(RouteServiceProvider::HOME);
} }

View File

@ -226,8 +226,8 @@ function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_
if (is_null($port) && !is_null($onlyPort)) { if (is_null($port) && !is_null($onlyPort)) {
$port = $onlyPort; $port = $onlyPort;
} }
$http_label = "{$uuid}-{$loop}-http"; $http_label = "http-{$loop}-{$uuid}";
$https_label = "{$uuid}-{$loop}-https"; $https_label = "https-{$loop}-{$uuid}";
if ($schema === 'https') { if ($schema === 'https') {
// Set labels for https // Set labels for https
@ -249,6 +249,10 @@ function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_
// Set labels for http (redirect to https) // Set labels for http (redirect to https)
$labels->push("traefik.http.routers.{$http_label}.rule=Host(`{$host}`) && PathPrefix(`{$path}`)"); $labels->push("traefik.http.routers.{$http_label}.rule=Host(`{$host}`) && PathPrefix(`{$path}`)");
$labels->push("traefik.http.routers.{$http_label}.entryPoints=http"); $labels->push("traefik.http.routers.{$http_label}.entryPoints=http");
if ($port) {
$labels->push("traefik.http.services.{$http_label}.loadbalancer.server.port=$port");
$labels->push("traefik.http.routers.{$http_label}.service={$http_label}");
}
if ($is_force_https_enabled) { if ($is_force_https_enabled) {
$labels->push("traefik.http.routers.{$http_label}.middlewares=redirect-to-https"); $labels->push("traefik.http.routers.{$http_label}.middlewares=redirect-to-https");
} }
@ -258,27 +262,26 @@ function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_
$labels->push("traefik.http.routers.{$http_label}.entryPoints=http"); $labels->push("traefik.http.routers.{$http_label}.entryPoints=http");
$labels->push("traefik.http.routers.{$http_label}.middlewares=gzip"); $labels->push("traefik.http.routers.{$http_label}.middlewares=gzip");
if ($port) { if ($port) {
$labels->push("traefik.http.routers.{$http_label}.service={$http_label}");
$labels->push("traefik.http.services.{$http_label}.loadbalancer.server.port=$port"); $labels->push("traefik.http.services.{$http_label}.loadbalancer.server.port=$port");
$labels->push("traefik.http.routers.{$http_label}.service={$http_label}");
} }
if ($path !== '/') { if ($path !== '/') {
$labels->push("traefik.http.routers.{$http_label}.middlewares={$http_label}-stripprefix"); $labels->push("traefik.http.routers.{$http_label}.middlewares={$http_label}-stripprefix");
$labels->push("traefik.http.middlewares.{$http_label}-stripprefix.stripprefix.prefixes={$path}"); $labels->push("traefik.http.middlewares.{$http_label}-stripprefix.stripprefix.prefixes={$path}");
} }
} }
} catch(\Throwable $e) { } catch (\Throwable $e) {
continue; continue;
} }
} }
return $labels; return $labels->sort();
} }
function generateLabelsApplication(Application $application, ?ApplicationPreview $preview = null): array function generateLabelsApplication(Application $application, ?ApplicationPreview $preview = null): array
{ {
$ports = $application->settings->is_static ? [80] : $application->ports_exposes_array; $ports = $application->settings->is_static ? [80] : $application->ports_exposes_array;
$onlyPort = null; $onlyPort = null;
if (count($ports) === 1) { if (count($ports) > 0) {
$onlyPort = $ports[0]; $onlyPort = $ports[0];
} }
$pull_request_id = data_get($preview, 'pull_request_id', 0); $pull_request_id = data_get($preview, 'pull_request_id', 0);

View File

@ -101,7 +101,6 @@ function generate_default_proxy_configuration(Server $server)
$labels = [ $labels = [
"traefik.enable=true", "traefik.enable=true",
"traefik.http.routers.traefik.entrypoints=http", "traefik.http.routers.traefik.entrypoints=http",
"traefik.http.routers.traefik.middlewares=traefik-basic-auth@file",
"traefik.http.routers.traefik.service=api@internal", "traefik.http.routers.traefik.service=api@internal",
"traefik.http.services.traefik.loadbalancer.server.port=8080", "traefik.http.services.traefik.loadbalancer.server.port=8080",
// Global Middlewares // Global Middlewares
@ -156,7 +155,7 @@ function generate_default_proxy_configuration(Server $server)
], ],
]; ];
if (isDev()) { if (isDev()) {
$config['services']['traefik']['command'][] = "--log.level=debug"; // $config['services']['traefik']['command'][] = "--log.level=debug";
$config['services']['traefik']['command'][] = "--accesslog.filepath=/traefik/access.log"; $config['services']['traefik']['command'][] = "--accesslog.filepath=/traefik/access.log";
$config['services']['traefik']['command'][] = "--accesslog.bufferingsize=100"; $config['services']['traefik']['command'][] = "--accesslog.bufferingsize=100";
} }

View File

@ -408,7 +408,7 @@ function generateFqdn(Server $server, string $random)
} }
function sslip(Server $server) function sslip(Server $server)
{ {
if (isDev()) { if (isDev() && $server->id === 0) {
return "http://127.0.0.1.sslip.io"; return "http://127.0.0.1.sslip.io";
} }
if ($server->ip === 'host.docker.internal') { if ($server->ip === 'host.docker.internal') {

View File

@ -65,7 +65,7 @@
'driver' => 'redis', 'driver' => 'redis',
'connection' => 'default', 'connection' => 'default',
'queue' => env('REDIS_QUEUE', 'default'), 'queue' => env('REDIS_QUEUE', 'default'),
'retry_after' => 300, 'retry_after' => 3600,
'block_for' => null, 'block_for' => null,
'after_commit' => true, 'after_commit' => true,
], ],

View File

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

View File

@ -1,3 +1,3 @@
<?php <?php
return '4.0.0-beta.182'; return '4.0.0-beta.186';

View File

@ -16,7 +16,7 @@ RUN apt-get update
RUN apt-get install postgresql-client-$POSTGRES_VERSION -y RUN apt-get install postgresql-client-$POSTGRES_VERSION -y
# Coolify requirements # Coolify requirements
RUN apt-get install -y php-pgsql openssh-client git git-lfs jq lsof RUN apt-get install -y php8.2-pgsql openssh-client git git-lfs jq lsof
RUN apt-get -y autoremove && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/* RUN apt-get -y autoremove && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/*
COPY --chmod=755 docker/dev-ssu/etc/s6-overlay/ /etc/s6-overlay/ COPY --chmod=755 docker/dev-ssu/etc/s6-overlay/ /etc/s6-overlay/

View File

@ -31,7 +31,7 @@ RUN apt-get update
RUN apt-get install postgresql-client-$POSTGRES_VERSION -y RUN apt-get install postgresql-client-$POSTGRES_VERSION -y
# Coolify requirements # Coolify requirements
RUN apt-get install -y php-pgsql openssh-client git git-lfs jq lsof RUN apt-get install -y php8.2-pgsql openssh-client git git-lfs jq lsof
RUN apt-get -y autoremove && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/* RUN apt-get -y autoremove && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/*
COPY docker/prod-ssu/nginx.conf /etc/nginx/conf.d/custom.conf COPY docker/prod-ssu/nginx.conf /etc/nginx/conf.d/custom.conf

View File

@ -1,3 +0,0 @@
<x-layout-simple>
<livewire:force-password-reset />
</x-layout-simple>

View File

@ -13,8 +13,8 @@
href="{{ route('project.application.logs', $parameters) }}"> href="{{ route('project.application.logs', $parameters) }}">
<button>Logs</button> <button>Logs</button>
</a> </a>
<a class="{{ request()->routeIs('project.application.deployments') ? 'text-white' : '' }}" <a class="{{ request()->routeIs('project.application.deployment.index') ? 'text-white' : '' }}"
href="{{ route('project.application.deployments', $parameters) }}"> href="{{ route('project.application.deployment.index', $parameters) }}">
<button>Deployments</button> <button>Deployments</button>
</a> </a>
<x-applications.links :application="$application" /> <x-applications.links :application="$application" />

View File

@ -16,8 +16,8 @@
$database->getMorphClass() === 'App\Models\StandaloneMongodb' || $database->getMorphClass() === 'App\Models\StandaloneMongodb' ||
$database->getMorphClass() === 'App\Models\StandaloneMysql' || $database->getMorphClass() === 'App\Models\StandaloneMysql' ||
$database->getMorphClass() === 'App\Models\StandaloneMariadb') $database->getMorphClass() === 'App\Models\StandaloneMariadb')
<a class="{{ request()->routeIs('project.database.backups.all') ? 'text-white' : '' }}" <a class="{{ request()->routeIs('project.database.backup.index') ? 'text-white' : '' }}"
href="{{ route('project.database.backups.all', $parameters) }}"> href="{{ route('project.database.backup.index', $parameters) }}">
<button>Backups</button> <button>Backups</button>
</a> </a>
@endif @endif

View File

@ -302,7 +302,7 @@ class="grid max-w-sm grid-cols-1 -mt-16 divide-y divide-coolgray-500 isolate gap
</div> </div>
<div class="mt-1 text-base leading-7 text-gray-300"> <div class="mt-1 text-base leading-7 text-gray-300">
Once you connected your server, Coolify will start managing it and do a Once you connected your server, Coolify will start managing it and do a
lot of adminstrative tasks for you. You can also write your own scripts to lot of administrative tasks for you. You can also write your own scripts to
automate your server<span class="text-warning">*</span>. automate your server<span class="text-warning">*</span>.
</div> </div>
</div> </div>
@ -384,7 +384,7 @@ class="grid max-w-sm grid-cols-1 -mt-16 divide-y divide-coolgray-500 isolate gap
<div class="text-2xl font-semibold text-white">Powerful API</div> <div class="text-2xl font-semibold text-white">Powerful API</div>
</div> </div>
<div class="mt-1 text-base leading-7 text-gray-300"> <div class="mt-1 text-base leading-7 text-gray-300">
Programatically deploy, query, and manage your servers & resources. Programmatically deploy, query, and manage your servers & resources.
Integrate to your CI/CD pipelines, or build your own custom integrations. <span Integrate to your CI/CD pipelines, or build your own custom integrations. <span
class="text-warning">*</span> class="text-warning">*</span>
</div> </div>

View File

@ -1,7 +1,7 @@
<nav class="flex pt-2 pb-10"> <nav class="flex pt-2 pb-10">
<ol class="flex items-center"> <ol class="flex items-center">
<li class="inline-flex items-center"> <li class="inline-flex items-center">
<a wire:nagivate class="text-xs truncate lg:text-sm" <a wire:navigate class="text-xs truncate lg:text-sm"
href="{{ route('project.show', ['project_uuid' => $this->parameters['project_uuid']]) }}"> href="{{ route('project.show', ['project_uuid' => $this->parameters['project_uuid']]) }}">
{{ data_get($resource, 'environment.project.name', 'Undefined Name') }}</a> {{ data_get($resource, 'environment.project.name', 'Undefined Name') }}</a>
</li> </li>
@ -14,7 +14,7 @@
clip-rule="evenodd"></path> clip-rule="evenodd"></path>
</svg> </svg>
<a class="text-xs truncate lg:text-sm" <a class="text-xs truncate lg:text-sm"
href="{{ route('project.resources', ['environment_name' => $this->parameters['environment_name'], 'project_uuid' => $this->parameters['project_uuid']]) }}">{{ $this->parameters['environment_name'] }}</a> href="{{ route('project.resource.index', ['environment_name' => $this->parameters['environment_name'], 'project_uuid' => $this->parameters['project_uuid']]) }}">{{ $this->parameters['environment_name'] }}</a>
</div> </div>
</li> </li>
<li> <li>

View File

@ -2,8 +2,8 @@
<h1>Settings</h1> <h1>Settings</h1>
<div class="subtitle">Instance wide settings for Coolify.</div> <div class="subtitle">Instance wide settings for Coolify.</div>
<nav class="navbar-main"> <nav class="navbar-main">
<a class="{{ request()->routeIs('settings.configuration') ? 'text-white' : '' }}" <a class="{{ request()->routeIs('settings.index') ? 'text-white' : '' }}"
href="{{ route('settings.configuration') }}"> href="{{ route('settings.index') }}">
<button>Configuration</button> <button>Configuration</button>
</a> </a>
@if (isCloud()) @if (isCloud())

View File

@ -17,15 +17,15 @@ class="text-warning">{{ session('currentTeam.name') }}</span></span>
<a class="{{ request()->routeIs('team.index') ? 'text-white' : '' }}" href="{{ route('team.index') }}"> <a class="{{ request()->routeIs('team.index') ? 'text-white' : '' }}" href="{{ route('team.index') }}">
<button>General</button> <button>General</button>
</a> </a>
<a class="{{ request()->routeIs('team.members') ? 'text-white' : '' }}" href="{{ route('team.members') }}"> <a class="{{ request()->routeIs('team.member.index') ? 'text-white' : '' }}" href="{{ route('team.member.index') }}">
<button>Members</button> <button>Members</button>
</a> </a>
<a class="{{ request()->routeIs('team.storages.all') ? 'text-white' : '' }}" <a class="{{ request()->routeIs('team.storage.index') ? 'text-white' : '' }}"
href="{{ route('team.storages.all') }}"> href="{{ route('team.storage.index') }}">
<button>S3 Storages</button> <button>S3 Storages</button>
</a> </a>
<a class="{{ request()->routeIs('team.notifications') ? 'text-white' : '' }}" <a class="{{ request()->routeIs('team.notification.index') ? 'text-white' : '' }}"
href="{{ route('team.notifications') }}"> href="{{ route('team.notification.index') }}">
<button>Notifications</button> <button>Notifications</button>
</a> </a>
<div class="flex-1"></div> <div class="flex-1"></div>

View File

@ -1,11 +1,10 @@
<x-emails.layout> <x-emails.layout>
@if ($pull_request_id === 0) @if ($pull_request_id === 0)
Failed to deploy a new version of {{ $name }} at [{{ $fqdn }}]({{ $fqdn }}) . Failed to deploy a new version of {{ $name }} at [{{ $fqdn }}]({{ $fqdn }}) .
@else @else
Failed to deploy a pull request #{{ $pull_request_id }} of {{ $name }} at Failed to deploy a pull request #{{ $pull_request_id }} of {{ $name }} at
[{{ $fqdn }}]({{ $fqdn }}). [{{ $fqdn }}]({{ $fqdn }}).
@endif @endif
[View Deployment Logs]({{ $deployment_url }})
[View Deployment Logs]({{ $deployment_url }})
</x-emails.layout> </x-emails.layout>

View File

@ -1,11 +1,11 @@
<x-emails.layout> <x-emails.layout>
@if ($pull_request_id === 0) @if ($pull_request_id === 0)
A new version of {{ $name }} is available at [{{ $fqdn }}]({{ $fqdn }}) . A new version of {{ $name }} is available at [{{ $fqdn }}]({{ $fqdn }}) .
@else @else
Pull request #{{ $pull_request_id }} of {{ $name }} deployed successfully Pull request #{{ $pull_request_id }} of {{ $name }} deployed successfully
[{{ $fqdn }}]({{ $fqdn }}). [{{ $fqdn }}]({{ $fqdn }}).
@endif @endif
[View Deployment Logs]({{ $deployment_url }}) [View Deployment Logs]({{ $deployment_url }})
</x-emails.layout> </x-emails.layout>

View File

@ -1,9 +1,7 @@
<x-emails.layout> <x-emails.layout>
{{ $name }} has been stopped.
{{ $name }} has been stopped. If it was your intention to stop this application, you can ignore this email.
If it was your intention to stop this application, you can ignore this email.
If not, [check what is going on]({{ $application_url }}).
If not, [check what is going on]({{ $application_url }}).
</x-emails.layout> </x-emails.layout>

View File

@ -1,8 +1,7 @@
<x-emails.layout> <x-emails.layout>
Database backup for {{ $name }} with frequency of {{ $frequency }} was FAILED. Database backup for {{ $name }} with frequency of {{ $frequency }} was FAILED.
### Reason ### Reason
{{ $output }}
{{ $output }}
</x-emails.layout> </x-emails.layout>

View File

@ -1,3 +1,3 @@
<x-emails.layout> <x-emails.layout>
Database backup for {{ $name }} with frequency of {{ $frequency }} was successful. Database backup for {{ $name }} with frequency of {{ $frequency }} was successful.
</x-emails.layout> </x-emails.layout>

View File

@ -1,9 +1,7 @@
<x-emails.layout> <x-emails.layout>
We would like to inform you that a {{ config('constants.limits.trial_period') }} days of trial has been added to all We would like to inform you that a {{ config('constants.limits.trial_period') }} days of trial has been added to all subscription plans.
subscription plans.
You can try out Coolify, without payment information for free. If you like it, you can upgrade to a paid plan at any You can try out Coolify, without payment information for free. If you like it, you can upgrade to a paid plan at any time.
time.
[Click here](https://app.coolify.io/subscription) to start your trial. [Click here](https://app.coolify.io/subscription) to start your trial.
</x-emails.layout> </x-emails.layout>

View File

@ -1,13 +1,9 @@
<x-emails.layout> <x-emails.layout>
A resource ({{ $containerName }}) has been restarted automatically on {{ $serverName }}, because it was stopped unexpectedly.
A service ({{ $containerName }}) has been restarted automatically on {{ $serverName }}, because it was stopped @if ($containerName === 'coolify-proxy')
unexpectedly. Coolify Proxy should run on your server as you have FQDNs set up in one of your resources.
@if ($containerName === 'coolify-proxy')
Coolify Proxy should run on your server as you have FQDNs set up in one of your resources.
If you don't want to use Coolify Proxy, please remove FQDN from your resources or set Proxy type to
Custom(None).
@endif
If you don't want to use Coolify Proxy, please remove FQDN from your resources or set Proxy type to Custom(None).
@endif
</x-emails.layout> </x-emails.layout>

View File

@ -1,9 +1,7 @@
<x-emails.layout> <x-emails.layout>
A resource ({{ $containerName }}) has been stopped unexpectedly on {{ $serverName }}.
A service ({{ $containerName }}) has been stopped unexpectedly on {{ $serverName }}. @if ($url)
Please check what is going on [here]({{ $url }}).
@if ($url) @endif
Please check what is going on [here]({{ $url }}).
@endif
</x-emails.layout> </x-emails.layout>

View File

@ -1,3 +1,3 @@
<x-emails.layout> <x-emails.layout>
Verify your email [here]({{ $url }}). Verify your email [here]({{ $url }}).
</x-emails.layout> </x-emails.layout>

View File

@ -1,10 +1,7 @@
<x-emails.layout> <x-emails.layout>
Your server ({{ $name }}) has high disk usage ({{ $disk_usage }}% used). Threshold is {{ $threshold }}%.
Your server ({{ $name }}) has high disk usage ({{ $disk_usage }}% used). Threshold is Please cleanup your disk to prevent data-loss. Here are some [tips](https://coolify.io/docs/automated-cleanup).
{{ $threshold }}%.
Please cleanup your disk to prevent data-loss. Here are some [tips](https://coolify.io/docs/automated-cleanup).
(You can change the threshold in the Server Settings menu.)
(You can change the threshold in the Server Settings menu.)
</x-emails.layout> </x-emails.layout>

View File

@ -1,10 +1,9 @@
<x-emails.layout> <x-emails.layout>
You have been invited to "{{ $team }}" on "{{ config('app.name') }}".
You have been invited to "{{ $team }}" on "{{ config('app.name') }}". Please [click here]({{ $invitation_link }}) to accept the invitation.
Please [click here]({{ $invitation_link }}) to accept the invitation. If you have any questions, please contact the team owner.<br><br>
If you have any questions, please contact the team owner.<br><br> If it was not you who requested this invitation, please ignore this email.
If it was not you who requested this invitation, please ignore this email.
</x-emails.layout> </x-emails.layout>

View File

@ -1,7 +1,7 @@
<x-emails.layout> <x-emails.layout>
A password reset has been requested for this email address. A password reset has been requested for this email address.
Click [here]({{ $url }}) to reset your password. Click [here]({{ $url }}) to reset your password.
This link will expire in {{ $count }} minutes. This link will expire in {{ $count }} minutes.
</x-emails.layout> </x-emails.layout>

View File

@ -1,6 +1,6 @@
<x-emails.layout> <x-emails.layout>
Connection could not be establised with one of your S3 Storage ({{ $name }}). Please fix it
[here]({{ $url }}).
{{ $reason }} Connection could not be established with one of your S3 Storage ({{ $name }}). Please fix it [here]({{ $url }}).
{{ $reason }}
</x-emails.layout> </x-emails.layout>

View File

@ -1,12 +1,9 @@
<x-emails.layout> <x-emails.layout>
Coolify cannot connect to your server ({{ $name }}). Please check your server and make sure it is running.
Coolify cannot connect to your server ({{ $name }}). Please check your server and make sure it is running. All automations & integrations are turned off!
All automations & integrations are turned off! IMPORTANT: We automatically try to revive your server. If your server is back online, we will automatically turn onall automations & integrations.
IMPORTANT: We automatically try to revive your server. If your server is back online, we will automatically turn on
all automations & integrations.
If you have any questions, please contact us.
If you have any questions, please contact us.
</x-emails.layout> </x-emails.layout>

View File

@ -1,6 +1,3 @@
<x-emails.layout> <x-emails.layout>
Your server ({{ $name }}) was offline for a while, but it is back online now. All automations & integrationsare turned on again.
Your server ({{ $name }}) was offline for a while, but it is back online now. All automations & integrations
are turned on again.
</x-emails.layout> </x-emails.layout>

View File

@ -1,6 +1,5 @@
<x-emails.layout> <x-emails.layout>
Your last invoice has failed to be paid for Coolify Cloud. Your last invoice has failed to be paid for Coolify Cloud.
Please update payment details [here]({{ $stripeCustomerPortal }}).
Please update payment details [here]({{ $stripeCustomerPortal }}).
</x-emails.layout> </x-emails.layout>

View File

@ -1,3 +1,3 @@
<x-emails.layout> <x-emails.layout>
If you are seeing this, it means that your Email settings are correct. If you are seeing this, it means that your Email settings are correct.
</x-emails.layout> </x-emails.layout>

View File

@ -1,8 +1,5 @@
<x-emails.layout> <x-emails.layout>
Your trial ended. All automations and integrations are disabled for all of your servers.
Your trial ended. All automations and integrations are disabled for all of your servers. Please update payment details [here]({{ $stripeCustomerPortal }}) or in [Coolify Cloud](https://app.coolify.io) to continue using our services.
Please update payment details [here]({{ $stripeCustomerPortal }}) or in [Coolify Cloud](https://app.coolify.io) to
continue using our services.
</x-emails.layout> </x-emails.layout>

View File

@ -1,8 +1,5 @@
<x-emails.layout> <x-emails.layout>
Your trial ends soon. Please update payment details [here]({{ $stripeCustomerPortal }}),
Your trial ends soon. Please update payment details [here]({{ $stripeCustomerPortal }}), Your servers & deployed resources will be untouched, but you won't be able to deploy new resources and lost all automations and integrations.
Your servers & deployed resources will be untouched, but you won't be able to deploy new resources and lost all
automations and integrations.
</x-emails.layout> </x-emails.layout>

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