refactor
This commit is contained in:
parent
fe68e45609
commit
4ad72fab7b
@ -48,23 +48,6 @@ class Controller extends BaseController
|
|||||||
public function force_passoword_reset() {
|
public function force_passoword_reset() {
|
||||||
return view('auth.force-password-reset');
|
return view('auth.force-password-reset');
|
||||||
}
|
}
|
||||||
// public function dashboard()
|
|
||||||
// {
|
|
||||||
// $projects = Project::ownedByCurrentTeam()->get();
|
|
||||||
// $servers = Server::ownedByCurrentTeam()->get();
|
|
||||||
// $s3s = S3Storage::ownedByCurrentTeam()->get();
|
|
||||||
// $resources = 0;
|
|
||||||
// foreach ($projects as $project) {
|
|
||||||
// $resources += $project->applications->count();
|
|
||||||
// $resources += $project->postgresqls->count();
|
|
||||||
// }
|
|
||||||
// return view('dashboard', [
|
|
||||||
// 'servers' => $servers->count(),
|
|
||||||
// 'projects' => $projects->count(),
|
|
||||||
// 'resources' => $resources,
|
|
||||||
// 's3s' => $s3s,
|
|
||||||
// ]);
|
|
||||||
// }
|
|
||||||
public function boarding() {
|
public function boarding() {
|
||||||
if (currentTeam()->boarding || isDev()) {
|
if (currentTeam()->boarding || isDev()) {
|
||||||
return view('boarding');
|
return view('boarding');
|
||||||
|
183
app/Http/Livewire/Boarding/Index.php
Normal file
183
app/Http/Livewire/Boarding/Index.php
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Livewire\Boarding;
|
||||||
|
use App\Actions\Server\InstallDocker;
|
||||||
|
use App\Models\PrivateKey;
|
||||||
|
use App\Models\Project;
|
||||||
|
use App\Models\Server;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class Index extends Component
|
||||||
|
{ public string $currentState = 'welcome';
|
||||||
|
|
||||||
|
public ?string $privateKeyType = null;
|
||||||
|
public ?string $privateKey = null;
|
||||||
|
public ?string $publicKey = null;
|
||||||
|
public ?string $privateKeyName = null;
|
||||||
|
public ?string $privateKeyDescription = null;
|
||||||
|
public ?PrivateKey $createdPrivateKey = null;
|
||||||
|
|
||||||
|
public ?string $remoteServerName = null;
|
||||||
|
public ?string $remoteServerDescription = null;
|
||||||
|
public ?string $remoteServerHost = null;
|
||||||
|
public ?int $remoteServerPort = 22;
|
||||||
|
public ?string $remoteServerUser = 'root';
|
||||||
|
public ?Server $createdServer = null;
|
||||||
|
|
||||||
|
public ?Project $createdProject = null;
|
||||||
|
|
||||||
|
public function mount()
|
||||||
|
{
|
||||||
|
$this->privateKeyName = generate_random_name();
|
||||||
|
$this->remoteServerName = generate_random_name();
|
||||||
|
if (isDev()) {
|
||||||
|
$this->privateKey = '-----BEGIN OPENSSH PRIVATE KEY-----
|
||||||
|
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
|
||||||
|
QyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevAAAAJi/QySHv0Mk
|
||||||
|
hwAAAAtzc2gtZWQyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevA
|
||||||
|
AAAECBQw4jg1WRT2IGHMncCiZhURCts2s24HoDS0thHnnRKVuGmoeGq/pojrsyP1pszcNV
|
||||||
|
uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
||||||
|
-----END OPENSSH PRIVATE KEY-----';
|
||||||
|
$this->privateKeyDescription = 'Created by Coolify';
|
||||||
|
$this->remoteServerDescription = 'Created by Coolify';
|
||||||
|
$this->remoteServerHost = 'coolify-testing-host';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function restartBoarding()
|
||||||
|
{
|
||||||
|
if ($this->createdServer) {
|
||||||
|
$this->createdServer->delete();
|
||||||
|
}
|
||||||
|
if ($this->createdPrivateKey) {
|
||||||
|
$this->createdPrivateKey->delete();
|
||||||
|
}
|
||||||
|
return redirect()->route('boarding');
|
||||||
|
}
|
||||||
|
public function skipBoarding()
|
||||||
|
{
|
||||||
|
currentTeam()->update([
|
||||||
|
'show_boarding' => false
|
||||||
|
]);
|
||||||
|
refreshSession();
|
||||||
|
return redirect()->route('dashboard');
|
||||||
|
}
|
||||||
|
public function setServer(string $type)
|
||||||
|
{
|
||||||
|
if ($type === 'localhost') {
|
||||||
|
$this->createdServer = Server::find(0);
|
||||||
|
if (!$this->createdServer) {
|
||||||
|
return $this->emit('error', 'Localhost server is not found. Something went wrong during installation. Please try to reinstall or contact support.');
|
||||||
|
}
|
||||||
|
$this->currentState = 'select-proxy';
|
||||||
|
} elseif ($type === 'remote') {
|
||||||
|
$this->currentState = 'private-key';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function setPrivateKey(string $type)
|
||||||
|
{
|
||||||
|
$this->privateKeyType = $type;
|
||||||
|
if ($type === 'create' && !isDev()) {
|
||||||
|
$this->createNewPrivateKey();
|
||||||
|
}
|
||||||
|
$this->currentState = 'create-private-key';
|
||||||
|
}
|
||||||
|
public function savePrivateKey()
|
||||||
|
{
|
||||||
|
$this->validate([
|
||||||
|
'privateKeyName' => 'required',
|
||||||
|
'privateKey' => 'required',
|
||||||
|
]);
|
||||||
|
$this->currentState = 'create-server';
|
||||||
|
}
|
||||||
|
public function saveServer()
|
||||||
|
{
|
||||||
|
$this->validate([
|
||||||
|
'remoteServerName' => 'required',
|
||||||
|
'remoteServerHost' => 'required',
|
||||||
|
'remoteServerPort' => 'required',
|
||||||
|
'remoteServerUser' => 'required',
|
||||||
|
]);
|
||||||
|
$this->privateKey = formatPrivateKey($this->privateKey);
|
||||||
|
$this->createdPrivateKey = PrivateKey::create([
|
||||||
|
'name' => $this->privateKeyName,
|
||||||
|
'description' => $this->privateKeyDescription,
|
||||||
|
'private_key' => $this->privateKey,
|
||||||
|
'team_id' => currentTeam()->id
|
||||||
|
]);
|
||||||
|
$this->createdServer = Server::create([
|
||||||
|
'name' => $this->remoteServerName,
|
||||||
|
'ip' => $this->remoteServerHost,
|
||||||
|
'port' => $this->remoteServerPort,
|
||||||
|
'user' => $this->remoteServerUser,
|
||||||
|
'description' => $this->remoteServerDescription,
|
||||||
|
'private_key_id' => $this->createdPrivateKey->id,
|
||||||
|
'team_id' => currentTeam()->id
|
||||||
|
]);
|
||||||
|
try {
|
||||||
|
['uptime' => $uptime, 'dockerVersion' => $dockerVersion] = validateServer($this->createdServer);
|
||||||
|
if (!$uptime) {
|
||||||
|
$this->createdServer->delete();
|
||||||
|
$this->createdPrivateKey->delete();
|
||||||
|
throw new \Exception('Server is not reachable.');
|
||||||
|
} else {
|
||||||
|
$this->createdServer->settings->update([
|
||||||
|
'is_reachable' => true,
|
||||||
|
]);
|
||||||
|
$this->emit('success', 'Server is reachable.');
|
||||||
|
}
|
||||||
|
if ($dockerVersion) {
|
||||||
|
$this->emit('error', 'Docker is not installed on the server.');
|
||||||
|
$this->currentState = 'install-docker';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return general_error_handler(customErrorMessage: "Server is not reachable. Reason: {$e->getMessage()}", that: $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function installDocker()
|
||||||
|
{
|
||||||
|
$activity = resolve(InstallDocker::class)($this->createdServer, currentTeam());
|
||||||
|
$this->emit('newMonitorActivity', $activity->id);
|
||||||
|
$this->currentState = 'select-proxy';
|
||||||
|
}
|
||||||
|
public function selectProxy(string|null $proxyType = null)
|
||||||
|
{
|
||||||
|
if (!$proxyType) {
|
||||||
|
return $this->currentState = 'create-project';
|
||||||
|
}
|
||||||
|
$this->createdServer->proxy->type = $proxyType;
|
||||||
|
$this->createdServer->proxy->status = 'exited';
|
||||||
|
$this->createdServer->save();
|
||||||
|
$this->currentState = 'create-project';
|
||||||
|
}
|
||||||
|
public function createNewProject()
|
||||||
|
{
|
||||||
|
$this->createdProject = Project::create([
|
||||||
|
'name' => "My first project",
|
||||||
|
'team_id' => currentTeam()->id
|
||||||
|
]);
|
||||||
|
$this->currentState = 'create-resource';
|
||||||
|
}
|
||||||
|
public function showNewResource()
|
||||||
|
{
|
||||||
|
$this->skipBoarding();
|
||||||
|
return redirect()->route(
|
||||||
|
'project.resources.new',
|
||||||
|
[
|
||||||
|
'project_uuid' => $this->createdProject->uuid,
|
||||||
|
'environment_name' => 'production',
|
||||||
|
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
private function createNewPrivateKey()
|
||||||
|
{
|
||||||
|
$this->privateKeyName = generate_random_name();
|
||||||
|
$this->privateKeyDescription = 'Created by Coolify';
|
||||||
|
['private' => $this->privateKey, 'public'=> $this->publicKey] = generateSSHKey();
|
||||||
|
}
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.boarding.index')->layout('layouts.boarding');
|
||||||
|
}
|
||||||
|
}
|
@ -1,13 +0,0 @@
|
|||||||
<x-layout-simple>
|
|
||||||
<livewire:boarding />
|
|
||||||
<x-modal modalId="installDocker">
|
|
||||||
<x-slot:modalBody>
|
|
||||||
<livewire:activity-monitor header="Installing Docker Logs" />
|
|
||||||
</x-slot:modalBody>
|
|
||||||
<x-slot:modalSubmit>
|
|
||||||
<x-forms.button onclick="installDocker.close()" type="submit">
|
|
||||||
Close
|
|
||||||
</x-forms.button>
|
|
||||||
</x-slot:modalSubmit>
|
|
||||||
</x-modal>
|
|
||||||
</x-layout-simple>
|
|
@ -1,68 +1 @@
|
|||||||
<!DOCTYPE html>
|
@extends('layouts.simple')
|
||||||
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<link rel="preconnect" href="https://api.fonts.coollabs.io" crossorigin>
|
|
||||||
<link href="https://api.fonts.coollabs.io/css2?family=Inter&display=swap" rel="stylesheet">
|
|
||||||
@env('local')
|
|
||||||
<title>Coolify - localhost</title>
|
|
||||||
<link rel="icon" href="{{ asset('favicon-dev.png') }}" type="image/x-icon" />
|
|
||||||
@else
|
|
||||||
<title>{{ $title ?? 'Coolify' }}</title>
|
|
||||||
<link rel="icon" href="{{ asset('coolify-transparent.png') }}" type="image/x-icon" />
|
|
||||||
@endenv
|
|
||||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
|
||||||
@vite(['resources/js/app.js', 'resources/css/app.css'])
|
|
||||||
<style>
|
|
||||||
[x-cloak] {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@livewireStyles
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
@livewireScripts
|
|
||||||
<x-toaster-hub />
|
|
||||||
<main>
|
|
||||||
{{ $slot }}
|
|
||||||
</main>
|
|
||||||
<x-version class="fixed left-2 bottom-1" />
|
|
||||||
<script>
|
|
||||||
Livewire.on('info', (message) => {
|
|
||||||
if (message) Toaster.info(message)
|
|
||||||
})
|
|
||||||
Livewire.on('error', (message) => {
|
|
||||||
if (message) Toaster.error(message)
|
|
||||||
})
|
|
||||||
Livewire.on('warning', (message) => {
|
|
||||||
if (message) Toaster.warning(message)
|
|
||||||
})
|
|
||||||
Livewire.on('success', (message) => {
|
|
||||||
if (message) Toaster.success(message)
|
|
||||||
})
|
|
||||||
|
|
||||||
function changePasswordFieldType(event) {
|
|
||||||
let element = event.target
|
|
||||||
for (let i = 0; i < 10; i++) {
|
|
||||||
if (element.className === "relative") {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
element = element.parentElement;
|
|
||||||
}
|
|
||||||
element = element.children[1];
|
|
||||||
if (element.nodeName === 'INPUT') {
|
|
||||||
if (element.type === 'password') {
|
|
||||||
element.type = 'text';
|
|
||||||
} else {
|
|
||||||
element.type = 'password';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
|
@ -1,86 +1 @@
|
|||||||
<!DOCTYPE html>
|
@extends('layouts.subscription')
|
||||||
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<link rel="preconnect" href="https://api.fonts.coollabs.io" crossorigin>
|
|
||||||
<link href="https://api.fonts.coollabs.io/css2?family=Inter&display=swap" rel="stylesheet">
|
|
||||||
@env('local')
|
|
||||||
<title>Coolify - localhost</title>
|
|
||||||
<link rel="icon" href="{{ asset('favicon-dev.png') }}" type="image/x-icon" />
|
|
||||||
@else
|
|
||||||
<title>{{ $title ?? 'Coolify' }}</title>
|
|
||||||
<link rel="icon" href="{{ asset('coolify-transparent.png') }}" type="image/x-icon" />
|
|
||||||
@endenv
|
|
||||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
|
||||||
@vite(['resources/js/app.js', 'resources/css/app.css'])
|
|
||||||
<style>
|
|
||||||
[x-cloak] {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@livewireStyles
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
@livewireScripts
|
|
||||||
<x-toaster-hub />
|
|
||||||
@if (isSubscriptionOnGracePeriod())
|
|
||||||
<div class="fixed top-3 left-4" id="vue">
|
|
||||||
<magic-bar></magic-bar>
|
|
||||||
</div>
|
|
||||||
<x-navbar />
|
|
||||||
@else
|
|
||||||
<x-navbar-subscription />
|
|
||||||
@endif
|
|
||||||
|
|
||||||
<main class="main max-w-screen-2xl">
|
|
||||||
{{ $slot }}
|
|
||||||
</main>
|
|
||||||
<x-version class="fixed left-2 bottom-1" />
|
|
||||||
<script>
|
|
||||||
function changePasswordFieldType(event) {
|
|
||||||
let element = event.target
|
|
||||||
for (let i = 0; i < 10; i++) {
|
|
||||||
if (element.className === "relative") {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
element = element.parentElement;
|
|
||||||
}
|
|
||||||
element = element.children[1];
|
|
||||||
if (element.nodeName === 'INPUT') {
|
|
||||||
if (element.type === 'password') {
|
|
||||||
element.type = 'text';
|
|
||||||
} else {
|
|
||||||
element.type = 'password';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Livewire.on('reloadWindow', (timeout) => {
|
|
||||||
if (timeout) {
|
|
||||||
setTimeout(() => {
|
|
||||||
window.location.reload();
|
|
||||||
}, timeout);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
window.location.reload();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
Livewire.on('info', (message) => {
|
|
||||||
if (message) Toaster.info(message)
|
|
||||||
})
|
|
||||||
Livewire.on('error', (message) => {
|
|
||||||
if (message) Toaster.error(message)
|
|
||||||
})
|
|
||||||
Livewire.on('warning', (message) => {
|
|
||||||
if (message) Toaster.warning(message)
|
|
||||||
})
|
|
||||||
Livewire.on('success', (message) => {
|
|
||||||
if (message) Toaster.success(message)
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
|
@ -1,133 +1 @@
|
|||||||
<!DOCTYPE html>
|
@extends('layouts.app')
|
||||||
<html data-theme="coollabs" lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<link rel="preconnect" href="https://api.fonts.coollabs.io" crossorigin>
|
|
||||||
<link href="https://api.fonts.coollabs.io/css2?family=Inter&display=swap" rel="stylesheet">
|
|
||||||
@env('local')
|
|
||||||
<title>Coolify - localhost</title>
|
|
||||||
<link rel="icon" href="{{ asset('favicon-dev.png') }}" type="image/x-icon" />
|
|
||||||
@else
|
|
||||||
<title>{{ $title ?? 'Coolify' }}</title>
|
|
||||||
<link rel="icon" href="{{ asset('coolify-transparent.png') }}" type="image/x-icon" />
|
|
||||||
@endenv
|
|
||||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
|
||||||
@vite(['resources/js/app.js', 'resources/css/app.css'])
|
|
||||||
<style>
|
|
||||||
[x-cloak] {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@livewireStyles
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
@livewireScripts
|
|
||||||
@auth
|
|
||||||
<x-toaster-hub />
|
|
||||||
<x-navbar />
|
|
||||||
<div class="fixed top-3 left-4" id="vue">
|
|
||||||
<magic-bar></magic-bar>
|
|
||||||
</div>
|
|
||||||
<main class="main max-w-screen-2xl">
|
|
||||||
{{ $slot }}
|
|
||||||
</main>
|
|
||||||
<x-version class="fixed left-2 bottom-1" />
|
|
||||||
<script>
|
|
||||||
let checkHealthInterval = null;
|
|
||||||
let checkIfIamDeadInterval = null;
|
|
||||||
|
|
||||||
function changePasswordFieldType(event) {
|
|
||||||
let element = event.target
|
|
||||||
for (let i = 0; i < 10; i++) {
|
|
||||||
if (element.className === "relative") {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
element = element.parentElement;
|
|
||||||
}
|
|
||||||
element = element.children[1];
|
|
||||||
if (element.nodeName === 'INPUT') {
|
|
||||||
if (element.type === 'password') {
|
|
||||||
element.type = 'text';
|
|
||||||
} else {
|
|
||||||
element.type = 'password';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function revive() {
|
|
||||||
if (checkHealthInterval) return true;
|
|
||||||
console.log('Checking server\'s health...')
|
|
||||||
checkHealthInterval = setInterval(() => {
|
|
||||||
fetch('/api/health')
|
|
||||||
.then(response => {
|
|
||||||
if (response.ok) {
|
|
||||||
Toaster.success('Coolify is back online. Reloading...')
|
|
||||||
if (checkHealthInterval) clearInterval(checkHealthInterval);
|
|
||||||
setTimeout(() => {
|
|
||||||
window.location.reload();
|
|
||||||
}, 5000)
|
|
||||||
} else {
|
|
||||||
console.log('Waiting for server to come back from dead...');
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
}, 2000);
|
|
||||||
}
|
|
||||||
|
|
||||||
function upgrade() {
|
|
||||||
if (checkIfIamDeadInterval) return true;
|
|
||||||
console.log('Update initiated.')
|
|
||||||
checkIfIamDeadInterval = setInterval(() => {
|
|
||||||
fetch('/api/health')
|
|
||||||
.then(response => {
|
|
||||||
if (response.ok) {
|
|
||||||
console.log('It\'s alive. Waiting for server to be dead...');
|
|
||||||
} else {
|
|
||||||
Toaster.success('Update done, restarting Coolify!')
|
|
||||||
console.log('It\'s dead. Reviving... Standby... Bzz... Bzz...')
|
|
||||||
if (checkIfIamDeadInterval) clearInterval(checkIfIamDeadInterval);
|
|
||||||
revive();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
}, 2000);
|
|
||||||
}
|
|
||||||
|
|
||||||
function copyToClipboard(text) {
|
|
||||||
navigator.clipboard.writeText(text);
|
|
||||||
Livewire.emit('message', 'Copied to clipboard.');
|
|
||||||
}
|
|
||||||
|
|
||||||
Livewire.on('reloadWindow', (timeout) => {
|
|
||||||
if (timeout) {
|
|
||||||
setTimeout(() => {
|
|
||||||
window.location.reload();
|
|
||||||
}, timeout);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
window.location.reload();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
Livewire.on('info', (message) => {
|
|
||||||
if (message) Toaster.info(message)
|
|
||||||
})
|
|
||||||
Livewire.on('error', (message) => {
|
|
||||||
if (message) Toaster.error(message)
|
|
||||||
})
|
|
||||||
Livewire.on('warning', (message) => {
|
|
||||||
if (message) Toaster.warning(message)
|
|
||||||
})
|
|
||||||
Livewire.on('success', (message) => {
|
|
||||||
if (message) Toaster.success(message)
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
@endauth
|
|
||||||
@guest
|
|
||||||
{{ $slot }}
|
|
||||||
@endguest
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
|
@ -1,133 +1,11 @@
|
|||||||
<!DOCTYPE html>
|
@extends('layouts.base')
|
||||||
<html data-theme="coollabs" lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
@section('body')
|
||||||
|
@parent
|
||||||
<head>
|
<x-navbar />
|
||||||
<meta charset="utf-8">
|
<div class="fixed top-3 left-4" id="vue">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<magic-bar></magic-bar>
|
||||||
<link rel="preconnect" href="https://api.fonts.coollabs.io" crossorigin>
|
</div>
|
||||||
<link href="https://api.fonts.coollabs.io/css2?family=Inter&display=swap" rel="stylesheet">
|
<main class="main max-w-screen-2xl">
|
||||||
@env('local')
|
|
||||||
<title>Coolify - localhost</title>
|
|
||||||
<link rel="icon" href="{{ asset('favicon-dev.png') }}" type="image/x-icon" />
|
|
||||||
@else
|
|
||||||
<title>{{ $title ?? 'Coolify' }}</title>
|
|
||||||
<link rel="icon" href="{{ asset('coolify-transparent.png') }}" type="image/x-icon" />
|
|
||||||
@endenv
|
|
||||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
|
||||||
@vite(['resources/js/app.js', 'resources/css/app.css'])
|
|
||||||
<style>
|
|
||||||
[x-cloak] {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@livewireStyles
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
@livewireScripts
|
|
||||||
@auth
|
|
||||||
<x-toaster-hub />
|
|
||||||
<x-navbar />
|
|
||||||
<div class="fixed top-3 left-4" id="vue">
|
|
||||||
<magic-bar></magic-bar>
|
|
||||||
</div>
|
|
||||||
<main class="main max-w-screen-2xl">
|
|
||||||
{{ $slot }}
|
|
||||||
</main>
|
|
||||||
<x-version class="fixed left-2 bottom-1" />
|
|
||||||
<script>
|
|
||||||
let checkHealthInterval = null;
|
|
||||||
let checkIfIamDeadInterval = null;
|
|
||||||
|
|
||||||
function changePasswordFieldType(event) {
|
|
||||||
let element = event.target
|
|
||||||
for (let i = 0; i < 10; i++) {
|
|
||||||
if (element.className === "relative") {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
element = element.parentElement;
|
|
||||||
}
|
|
||||||
element = element.children[1];
|
|
||||||
if (element.nodeName === 'INPUT') {
|
|
||||||
if (element.type === 'password') {
|
|
||||||
element.type = 'text';
|
|
||||||
} else {
|
|
||||||
element.type = 'password';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function revive() {
|
|
||||||
if (checkHealthInterval) return true;
|
|
||||||
console.log('Checking server\'s health...')
|
|
||||||
checkHealthInterval = setInterval(() => {
|
|
||||||
fetch('/api/health')
|
|
||||||
.then(response => {
|
|
||||||
if (response.ok) {
|
|
||||||
Toaster.success('Coolify is back online. Reloading...')
|
|
||||||
if (checkHealthInterval) clearInterval(checkHealthInterval);
|
|
||||||
setTimeout(() => {
|
|
||||||
window.location.reload();
|
|
||||||
}, 5000)
|
|
||||||
} else {
|
|
||||||
console.log('Waiting for server to come back from dead...');
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
}, 2000);
|
|
||||||
}
|
|
||||||
|
|
||||||
function upgrade() {
|
|
||||||
if (checkIfIamDeadInterval) return true;
|
|
||||||
console.log('Update initiated.')
|
|
||||||
checkIfIamDeadInterval = setInterval(() => {
|
|
||||||
fetch('/api/health')
|
|
||||||
.then(response => {
|
|
||||||
if (response.ok) {
|
|
||||||
console.log('It\'s alive. Waiting for server to be dead...');
|
|
||||||
} else {
|
|
||||||
Toaster.success('Update done, restarting Coolify!')
|
|
||||||
console.log('It\'s dead. Reviving... Standby... Bzz... Bzz...')
|
|
||||||
if (checkIfIamDeadInterval) clearInterval(checkIfIamDeadInterval);
|
|
||||||
revive();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
}, 2000);
|
|
||||||
}
|
|
||||||
|
|
||||||
function copyToClipboard(text) {
|
|
||||||
navigator.clipboard.writeText(text);
|
|
||||||
Livewire.emit('message', 'Copied to clipboard.');
|
|
||||||
}
|
|
||||||
|
|
||||||
Livewire.on('reloadWindow', (timeout) => {
|
|
||||||
if (timeout) {
|
|
||||||
setTimeout(() => {
|
|
||||||
window.location.reload();
|
|
||||||
}, timeout);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
window.location.reload();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
Livewire.on('info', (message) => {
|
|
||||||
if (message) Toaster.info(message)
|
|
||||||
})
|
|
||||||
Livewire.on('error', (message) => {
|
|
||||||
if (message) Toaster.error(message)
|
|
||||||
})
|
|
||||||
Livewire.on('warning', (message) => {
|
|
||||||
if (message) Toaster.warning(message)
|
|
||||||
})
|
|
||||||
Livewire.on('success', (message) => {
|
|
||||||
if (message) Toaster.success(message)
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
@endauth
|
|
||||||
@guest
|
|
||||||
{{ $slot }}
|
{{ $slot }}
|
||||||
@endguest
|
</main>
|
||||||
</body>
|
@endsection
|
||||||
|
|
||||||
</html>
|
|
||||||
|
88
resources/views/layouts/base.blade.php
Normal file
88
resources/views/layouts/base.blade.php
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html data-theme="light" lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="preconnect" href="https://api.fonts.coollabs.io" crossorigin>
|
||||||
|
<link href="https://api.fonts.coollabs.io/css2?family=Inter&display=swap" rel="stylesheet">
|
||||||
|
<title>Coolify</title>
|
||||||
|
@env('local')
|
||||||
|
<link rel="icon" href="{{ asset('favicon-dev.png') }}" type="image/x-icon" />
|
||||||
|
@else
|
||||||
|
<link rel="icon" href="{{ asset('coolify-transparent.png') }}" type="image/x-icon" />
|
||||||
|
@endenv
|
||||||
|
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||||
|
@vite(['resources/js/app.js', 'resources/css/app.css'])
|
||||||
|
<style>
|
||||||
|
[x-cloak] {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@livewireStyles
|
||||||
|
</head>
|
||||||
|
@section('body')
|
||||||
|
|
||||||
|
<body>
|
||||||
|
@livewireScripts
|
||||||
|
@auth
|
||||||
|
<x-toaster-hub />
|
||||||
|
<x-version class="fixed left-2 bottom-1" />
|
||||||
|
<script>
|
||||||
|
let checkHealthInterval = null;
|
||||||
|
let checkIfIamDeadInterval = null;
|
||||||
|
|
||||||
|
function changePasswordFieldType(event) {
|
||||||
|
let element = event.target
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
if (element.className === "relative") {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
element = element.parentElement;
|
||||||
|
}
|
||||||
|
element = element.children[1];
|
||||||
|
if (element.nodeName === 'INPUT') {
|
||||||
|
if (element.type === 'password') {
|
||||||
|
element.type = 'text';
|
||||||
|
} else {
|
||||||
|
element.type = 'password';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function copyToClipboard(text) {
|
||||||
|
navigator.clipboard.writeText(text);
|
||||||
|
Livewire.emit('message', 'Copied to clipboard.');
|
||||||
|
}
|
||||||
|
|
||||||
|
Livewire.on('reloadWindow', (timeout) => {
|
||||||
|
if (timeout) {
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.reload();
|
||||||
|
}, timeout);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
Livewire.on('info', (message) => {
|
||||||
|
if (message) Toaster.info(message)
|
||||||
|
})
|
||||||
|
Livewire.on('error', (message) => {
|
||||||
|
if (message) Toaster.error(message)
|
||||||
|
})
|
||||||
|
Livewire.on('warning', (message) => {
|
||||||
|
if (message) Toaster.warning(message)
|
||||||
|
})
|
||||||
|
Livewire.on('success', (message) => {
|
||||||
|
if (message) Toaster.success(message)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
@endauth
|
||||||
|
@guest
|
||||||
|
{{ $slot }}
|
||||||
|
@endguest
|
||||||
|
</body>
|
||||||
|
@show
|
||||||
|
|
||||||
|
</html>
|
9
resources/views/layouts/boarding.blade.php
Normal file
9
resources/views/layouts/boarding.blade.php
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
@extends('layouts.base')
|
||||||
|
@section('body')
|
||||||
|
<main class="min-h-screen hero">
|
||||||
|
<div class="hero-content">
|
||||||
|
{{ $slot }}
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
@parent
|
||||||
|
@endsection
|
7
resources/views/layouts/simple.blade.php
Normal file
7
resources/views/layouts/simple.blade.php
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
@extends('layouts.base')
|
||||||
|
@section('body')
|
||||||
|
@parent
|
||||||
|
<main>
|
||||||
|
{{ $slot }}
|
||||||
|
</main>
|
||||||
|
@endsection
|
16
resources/views/layouts/subscription.blade.php
Normal file
16
resources/views/layouts/subscription.blade.php
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
@extends('layouts.base')
|
||||||
|
@section('body')
|
||||||
|
@parent
|
||||||
|
@if (isSubscriptionOnGracePeriod())
|
||||||
|
<div class="fixed top-3 left-4" id="vue">
|
||||||
|
<magic-bar></magic-bar>
|
||||||
|
</div>
|
||||||
|
<x-navbar />
|
||||||
|
@else
|
||||||
|
<x-navbar-subscription />
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<main class="main max-w-screen-2xl">
|
||||||
|
{{ $slot }}
|
||||||
|
</main>
|
||||||
|
@endsection
|
@ -1,195 +0,0 @@
|
|||||||
@php use App\Enums\ProxyTypes; @endphp
|
|
||||||
<div class="min-h-screen hero">
|
|
||||||
<div class="hero-content">
|
|
||||||
<div>
|
|
||||||
@if ($currentState === 'welcome')
|
|
||||||
<h1 class="text-5xl font-bold">Welcome to Coolify</h1>
|
|
||||||
<p class="py-6 text-xl text-center">Let me help you to set the basics.</p>
|
|
||||||
<div class="flex justify-center ">
|
|
||||||
<div class="justify-center box" wire:click="$set('currentState', 'select-server')">Get Started
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
@if ($currentState === 'select-server')
|
|
||||||
<x-boarding-step title="Server">
|
|
||||||
<x-slot:question>
|
|
||||||
Do you want to deploy your resources on your <x-highlighted text="Localhost" />
|
|
||||||
or on a <x-highlighted text="Remote Server" />?
|
|
||||||
</x-slot:question>
|
|
||||||
<x-slot:actions>
|
|
||||||
<div class="justify-center box" wire:click="setServer('localhost')">Localhost
|
|
||||||
</div>
|
|
||||||
<div class="justify-center box" wire:click="setServer('remote')">Remote Server
|
|
||||||
</div>
|
|
||||||
</x-slot:actions>
|
|
||||||
<x-slot:explanation>
|
|
||||||
<p>Servers are the main building blocks, as they will host your applications, databases,
|
|
||||||
services, called resources. Any CPU intensive process will use the server's CPU where you
|
|
||||||
are deploying your resources.</p>
|
|
||||||
<p>Localhost is the server where Coolify is running on. It is not recommended to use one server
|
|
||||||
for everyting.</p>
|
|
||||||
<p>Remote Server is a server reachable through SSH. It can be hosted at home, or from any cloud
|
|
||||||
provider.</p>
|
|
||||||
</x-slot:explanation>
|
|
||||||
</x-boarding-step>
|
|
||||||
@endif
|
|
||||||
@if ($currentState === 'private-key')
|
|
||||||
<x-boarding-step title="SSH Key">
|
|
||||||
<x-slot:question>
|
|
||||||
Do you have your own SSH Private Key?
|
|
||||||
</x-slot:question>
|
|
||||||
<x-slot:actions>
|
|
||||||
<div class="justify-center box" wire:click="setPrivateKey('own')">Yes
|
|
||||||
</div>
|
|
||||||
<div class="justify-center box" wire:click="setPrivateKey('create')">No (create one for me)
|
|
||||||
</div>
|
|
||||||
</x-slot:actions>
|
|
||||||
<x-slot:explanation>
|
|
||||||
<p>SSH Keys are used to connect to a remote server through a secure shell, called SSH.</p>
|
|
||||||
<p>You can use your own ssh private key, or you can let Coolify to create one for you.</p>
|
|
||||||
<p>In both ways, you need to add the public version of your ssh private key to the remote
|
|
||||||
server's
|
|
||||||
<code class="text-warning">~/.ssh/authorized_keys</code> file.
|
|
||||||
</p>
|
|
||||||
</x-slot:explanation>
|
|
||||||
</x-boarding-step>
|
|
||||||
@endif
|
|
||||||
@if ($currentState === 'create-private-key')
|
|
||||||
<x-boarding-step title="Create Private Key">
|
|
||||||
<x-slot:question>
|
|
||||||
Please let me know your key details.
|
|
||||||
</x-slot:question>
|
|
||||||
<x-slot:actions>
|
|
||||||
<form wire:submit.prevent='savePrivateKey' class="flex flex-col w-full gap-4 pr-10">
|
|
||||||
<x-forms.input required placeholder="Choose a name for your Private Key. Could be anything."
|
|
||||||
label="Name" id="privateKeyName" />
|
|
||||||
<x-forms.input placeholder="Description, so others will know more about this."
|
|
||||||
label="Description" id="privateKeyDescription" />
|
|
||||||
<x-forms.textarea required placeholder="-----BEGIN OPENSSH PRIVATE KEY-----"
|
|
||||||
label="Private Key" id="privateKey" />
|
|
||||||
@if ($privateKeyType === 'create' && !isDev())
|
|
||||||
<span class="font-bold text-warning">Copy this to your server's ~/.ssh/authorized_keys file.</span>
|
|
||||||
<x-forms.textarea rows="7" readonly label="Public Key" id="publicKey" />
|
|
||||||
@endif
|
|
||||||
<x-forms.button type="submit">Save</x-forms.button>
|
|
||||||
</form>
|
|
||||||
</x-slot:actions>
|
|
||||||
<x-slot:explanation>
|
|
||||||
<p>Private Keys are used to connect to a remote server through a secure shell, called SSH.</p>
|
|
||||||
<p>You can use your own private key, or you can let Coolify to create one for you.</p>
|
|
||||||
<p>In both ways, you need to add the public version of your private key to the remote server's
|
|
||||||
<code>~/.ssh/authorized_keys</code> file.
|
|
||||||
</p>
|
|
||||||
</x-slot:explanation>
|
|
||||||
</x-boarding-step>
|
|
||||||
@endif
|
|
||||||
@if ($currentState === 'create-server')
|
|
||||||
<x-boarding-step title="Create Server">
|
|
||||||
<x-slot:question>
|
|
||||||
Please let me know your server details.
|
|
||||||
</x-slot:question>
|
|
||||||
<x-slot:actions>
|
|
||||||
<form wire:submit.prevent='saveServer' class="flex flex-col w-full gap-4 pr-10">
|
|
||||||
<div class="flex gap-2">
|
|
||||||
<x-forms.input required placeholder="Choose a name for your Server. Could be anything."
|
|
||||||
label="Name" id="remoteServerName" />
|
|
||||||
<x-forms.input placeholder="Description, so others will know more about this."
|
|
||||||
label="Description" id="remoteServerDescription" />
|
|
||||||
</div>
|
|
||||||
<div class="flex gap-2">
|
|
||||||
<x-forms.input required placeholder="Hostname or IP address"
|
|
||||||
label="Hostname or IP Address" id="remoteServerHost" />
|
|
||||||
<x-forms.input required placeholder="Port number of your server. Default is 22."
|
|
||||||
label="Port" id="remoteServerPort" />
|
|
||||||
<x-forms.input required readonly
|
|
||||||
placeholder="Username to connect to your server. Default is root." label="Username"
|
|
||||||
id="remoteServerUser" />
|
|
||||||
</div>
|
|
||||||
<x-forms.button type="submit">Save</x-forms.button>
|
|
||||||
</form>
|
|
||||||
</x-slot:actions>
|
|
||||||
<x-slot:explanation>
|
|
||||||
<p>Username should be <x-highlighted text="root" /> for now. We are working on to use
|
|
||||||
non-root users.</p>
|
|
||||||
</x-slot:explanation>
|
|
||||||
</x-boarding-step>
|
|
||||||
@endif
|
|
||||||
@if ($currentState === 'install-docker')
|
|
||||||
<x-boarding-step title="Install Docker">
|
|
||||||
<x-slot:question>
|
|
||||||
Could not find Docker Engine on your server. Do you want me to install it for you?
|
|
||||||
</x-slot:question>
|
|
||||||
<x-slot:actions>
|
|
||||||
<div class="justify-center box" wire:click="installDocker" onclick="installDocker.showModal()">
|
|
||||||
Let's do
|
|
||||||
it!</div>
|
|
||||||
</x-slot:actions>
|
|
||||||
<x-slot:explanation>
|
|
||||||
<p>This will install the latest Docker Engine on your server, configure a few things to be able
|
|
||||||
to run optimal.</p>
|
|
||||||
</x-slot:explanation>
|
|
||||||
</x-boarding-step>
|
|
||||||
@endif
|
|
||||||
@if ($currentState === 'select-proxy')
|
|
||||||
<x-boarding-step title="Select a Proxy">
|
|
||||||
<x-slot:question>
|
|
||||||
If you would like to attach any kind of domain to your resources, you need a proxy.
|
|
||||||
</x-slot:question>
|
|
||||||
<x-slot:actions>
|
|
||||||
<x-forms.button wire:click="selectProxy" class="w-64 box">
|
|
||||||
Decide later
|
|
||||||
</x-forms.button>
|
|
||||||
<x-forms.button class="w-32 box" wire:click="selectProxy('{{ ProxyTypes::TRAEFIK_V2 }}')">
|
|
||||||
Traefik
|
|
||||||
v2
|
|
||||||
</x-forms.button>
|
|
||||||
<x-forms.button disabled class="w-32 box">
|
|
||||||
Nginx
|
|
||||||
</x-forms.button>
|
|
||||||
<x-forms.button disabled class="w-32 box">
|
|
||||||
Caddy
|
|
||||||
</x-forms.button>
|
|
||||||
</x-slot:actions>
|
|
||||||
<x-slot:explanation>
|
|
||||||
<p>This will install the latest Docker Engine on your server, configure a few things to be able
|
|
||||||
to run optimal.</p>
|
|
||||||
</x-slot:explanation>
|
|
||||||
</x-boarding-step>
|
|
||||||
@endif
|
|
||||||
@if ($currentState === 'create-project')
|
|
||||||
<x-boarding-step title="Project">
|
|
||||||
<x-slot:question>
|
|
||||||
I will create an initial project for you. You can change all the details later on.
|
|
||||||
</x-slot:question>
|
|
||||||
<x-slot:actions>
|
|
||||||
<div class="justify-center box" wire:click="createNewProject">Let's do it!</div>
|
|
||||||
</x-slot:actions>
|
|
||||||
<x-slot:explanation>
|
|
||||||
<p>Projects are bound together several resources into one virtual group. There are no
|
|
||||||
limitations on the number of projects you could have.</p>
|
|
||||||
<p>Each project should have at least one environment. This helps you to create a production &
|
|
||||||
staging version of the same application, but grouped separately.</p>
|
|
||||||
</x-slot:explanation>
|
|
||||||
</x-boarding-step>
|
|
||||||
@endif
|
|
||||||
@if ($currentState === 'create-resource')
|
|
||||||
<x-boarding-step title="Resources">
|
|
||||||
<x-slot:question>
|
|
||||||
I will redirect you to the new resource page, where you can create your first resource.
|
|
||||||
</x-slot:question>
|
|
||||||
<x-slot:actions>
|
|
||||||
<div class="justify-center box" wire:click="showNewResource">Let's do
|
|
||||||
it!</div>
|
|
||||||
</x-slot:actions>
|
|
||||||
<x-slot:explanation>
|
|
||||||
<p>A resource could be an application, a database or a service (like WordPress).</p>
|
|
||||||
</x-slot:explanation>
|
|
||||||
</x-boarding-step>
|
|
||||||
@endif
|
|
||||||
<div class="flex justify-center gap-2 pt-4">
|
|
||||||
<a wire:click='skipBoarding'>Skip boarding process</a>
|
|
||||||
<a wire:click='restartBoarding'>Restart boarding process</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
192
resources/views/livewire/boarding/index.blade.php
Normal file
192
resources/views/livewire/boarding/index.blade.php
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
@php use App\Enums\ProxyTypes; @endphp
|
||||||
|
<div>
|
||||||
|
@if ($currentState === 'welcome')
|
||||||
|
<h1 class="text-5xl font-bold">Welcome to Coolify</h1>
|
||||||
|
<p class="py-6 text-xl text-center">Let me help you to set the basics.</p>
|
||||||
|
<div class="flex justify-center ">
|
||||||
|
<div class="justify-center box" wire:click="$set('currentState', 'select-server')">Get Started
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
@if ($currentState === 'select-server')
|
||||||
|
<x-boarding-step title="Server">
|
||||||
|
<x-slot:question>
|
||||||
|
Do you want to deploy your resources on your <x-highlighted text="Localhost" />
|
||||||
|
or on a <x-highlighted text="Remote Server" />?
|
||||||
|
</x-slot:question>
|
||||||
|
<x-slot:actions>
|
||||||
|
<div class="justify-center box" wire:click="setServer('localhost')">Localhost
|
||||||
|
</div>
|
||||||
|
<div class="justify-center box" wire:click="setServer('remote')">Remote Server
|
||||||
|
</div>
|
||||||
|
</x-slot:actions>
|
||||||
|
<x-slot:explanation>
|
||||||
|
<p>Servers are the main building blocks, as they will host your applications, databases,
|
||||||
|
services, called resources. Any CPU intensive process will use the server's CPU where you
|
||||||
|
are deploying your resources.</p>
|
||||||
|
<p>Localhost is the server where Coolify is running on. It is not recommended to use one server
|
||||||
|
for everyting.</p>
|
||||||
|
<p>Remote Server is a server reachable through SSH. It can be hosted at home, or from any cloud
|
||||||
|
provider.</p>
|
||||||
|
</x-slot:explanation>
|
||||||
|
</x-boarding-step>
|
||||||
|
@endif
|
||||||
|
@if ($currentState === 'private-key')
|
||||||
|
<x-boarding-step title="SSH Key">
|
||||||
|
<x-slot:question>
|
||||||
|
Do you have your own SSH Private Key?
|
||||||
|
</x-slot:question>
|
||||||
|
<x-slot:actions>
|
||||||
|
<div class="justify-center box" wire:click="setPrivateKey('own')">Yes
|
||||||
|
</div>
|
||||||
|
<div class="justify-center box" wire:click="setPrivateKey('create')">No (create one for me)
|
||||||
|
</div>
|
||||||
|
</x-slot:actions>
|
||||||
|
<x-slot:explanation>
|
||||||
|
<p>SSH Keys are used to connect to a remote server through a secure shell, called SSH.</p>
|
||||||
|
<p>You can use your own ssh private key, or you can let Coolify to create one for you.</p>
|
||||||
|
<p>In both ways, you need to add the public version of your ssh private key to the remote
|
||||||
|
server's
|
||||||
|
<code class="text-warning">~/.ssh/authorized_keys</code> file.
|
||||||
|
</p>
|
||||||
|
</x-slot:explanation>
|
||||||
|
</x-boarding-step>
|
||||||
|
@endif
|
||||||
|
@if ($currentState === 'create-private-key')
|
||||||
|
<x-boarding-step title="Create Private Key">
|
||||||
|
<x-slot:question>
|
||||||
|
Please let me know your key details.
|
||||||
|
</x-slot:question>
|
||||||
|
<x-slot:actions>
|
||||||
|
<form wire:submit.prevent='savePrivateKey' class="flex flex-col w-full gap-4 pr-10">
|
||||||
|
<x-forms.input required placeholder="Choose a name for your Private Key. Could be anything."
|
||||||
|
label="Name" id="privateKeyName" />
|
||||||
|
<x-forms.input placeholder="Description, so others will know more about this." label="Description"
|
||||||
|
id="privateKeyDescription" />
|
||||||
|
<x-forms.textarea required placeholder="-----BEGIN OPENSSH PRIVATE KEY-----" label="Private Key"
|
||||||
|
id="privateKey" />
|
||||||
|
@if ($privateKeyType === 'create' && !isDev())
|
||||||
|
<span class="font-bold text-warning">Copy this to your server's ~/.ssh/authorized_keys
|
||||||
|
file.</span>
|
||||||
|
<x-forms.textarea rows="7" readonly label="Public Key" id="publicKey" />
|
||||||
|
@endif
|
||||||
|
<x-forms.button type="submit">Save</x-forms.button>
|
||||||
|
</form>
|
||||||
|
</x-slot:actions>
|
||||||
|
<x-slot:explanation>
|
||||||
|
<p>Private Keys are used to connect to a remote server through a secure shell, called SSH.</p>
|
||||||
|
<p>You can use your own private key, or you can let Coolify to create one for you.</p>
|
||||||
|
<p>In both ways, you need to add the public version of your private key to the remote server's
|
||||||
|
<code>~/.ssh/authorized_keys</code> file.
|
||||||
|
</p>
|
||||||
|
</x-slot:explanation>
|
||||||
|
</x-boarding-step>
|
||||||
|
@endif
|
||||||
|
@if ($currentState === 'create-server')
|
||||||
|
<x-boarding-step title="Create Server">
|
||||||
|
<x-slot:question>
|
||||||
|
Please let me know your server details.
|
||||||
|
</x-slot:question>
|
||||||
|
<x-slot:actions>
|
||||||
|
<form wire:submit.prevent='saveServer' class="flex flex-col w-full gap-4 pr-10">
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<x-forms.input required placeholder="Choose a name for your Server. Could be anything."
|
||||||
|
label="Name" id="remoteServerName" />
|
||||||
|
<x-forms.input placeholder="Description, so others will know more about this."
|
||||||
|
label="Description" id="remoteServerDescription" />
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<x-forms.input required placeholder="Hostname or IP address" label="Hostname or IP Address"
|
||||||
|
id="remoteServerHost" />
|
||||||
|
<x-forms.input required placeholder="Port number of your server. Default is 22." label="Port"
|
||||||
|
id="remoteServerPort" />
|
||||||
|
<x-forms.input required readonly
|
||||||
|
placeholder="Username to connect to your server. Default is root." label="Username"
|
||||||
|
id="remoteServerUser" />
|
||||||
|
</div>
|
||||||
|
<x-forms.button type="submit">Save</x-forms.button>
|
||||||
|
</form>
|
||||||
|
</x-slot:actions>
|
||||||
|
<x-slot:explanation>
|
||||||
|
<p>Username should be <x-highlighted text="root" /> for now. We are working on to use
|
||||||
|
non-root users.</p>
|
||||||
|
</x-slot:explanation>
|
||||||
|
</x-boarding-step>
|
||||||
|
@endif
|
||||||
|
@if ($currentState === 'install-docker')
|
||||||
|
<x-boarding-step title="Install Docker">
|
||||||
|
<x-slot:question>
|
||||||
|
Could not find Docker Engine on your server. Do you want me to install it for you?
|
||||||
|
</x-slot:question>
|
||||||
|
<x-slot:actions>
|
||||||
|
<div class="justify-center box" wire:click="installDocker" onclick="installDocker.showModal()">
|
||||||
|
Let's do
|
||||||
|
it!</div>
|
||||||
|
</x-slot:actions>
|
||||||
|
<x-slot:explanation>
|
||||||
|
<p>This will install the latest Docker Engine on your server, configure a few things to be able
|
||||||
|
to run optimal.</p>
|
||||||
|
</x-slot:explanation>
|
||||||
|
</x-boarding-step>
|
||||||
|
@endif
|
||||||
|
@if ($currentState === 'select-proxy')
|
||||||
|
<x-boarding-step title="Select a Proxy">
|
||||||
|
<x-slot:question>
|
||||||
|
If you would like to attach any kind of domain to your resources, you need a proxy.
|
||||||
|
</x-slot:question>
|
||||||
|
<x-slot:actions>
|
||||||
|
<x-forms.button wire:click="selectProxy" class="w-64 box">
|
||||||
|
Decide later
|
||||||
|
</x-forms.button>
|
||||||
|
<x-forms.button class="w-32 box" wire:click="selectProxy('{{ ProxyTypes::TRAEFIK_V2 }}')">
|
||||||
|
Traefik
|
||||||
|
v2
|
||||||
|
</x-forms.button>
|
||||||
|
<x-forms.button disabled class="w-32 box">
|
||||||
|
Nginx
|
||||||
|
</x-forms.button>
|
||||||
|
<x-forms.button disabled class="w-32 box">
|
||||||
|
Caddy
|
||||||
|
</x-forms.button>
|
||||||
|
</x-slot:actions>
|
||||||
|
<x-slot:explanation>
|
||||||
|
<p>This will install the latest Docker Engine on your server, configure a few things to be able
|
||||||
|
to run optimal.</p>
|
||||||
|
</x-slot:explanation>
|
||||||
|
</x-boarding-step>
|
||||||
|
@endif
|
||||||
|
@if ($currentState === 'create-project')
|
||||||
|
<x-boarding-step title="Project">
|
||||||
|
<x-slot:question>
|
||||||
|
I will create an initial project for you. You can change all the details later on.
|
||||||
|
</x-slot:question>
|
||||||
|
<x-slot:actions>
|
||||||
|
<div class="justify-center box" wire:click="createNewProject">Let's do it!</div>
|
||||||
|
</x-slot:actions>
|
||||||
|
<x-slot:explanation>
|
||||||
|
<p>Projects are bound together several resources into one virtual group. There are no
|
||||||
|
limitations on the number of projects you could have.</p>
|
||||||
|
<p>Each project should have at least one environment. This helps you to create a production &
|
||||||
|
staging version of the same application, but grouped separately.</p>
|
||||||
|
</x-slot:explanation>
|
||||||
|
</x-boarding-step>
|
||||||
|
@endif
|
||||||
|
@if ($currentState === 'create-resource')
|
||||||
|
<x-boarding-step title="Resources">
|
||||||
|
<x-slot:question>
|
||||||
|
I will redirect you to the new resource page, where you can create your first resource.
|
||||||
|
</x-slot:question>
|
||||||
|
<x-slot:actions>
|
||||||
|
<div class="justify-center box" wire:click="showNewResource">Let's do
|
||||||
|
it!</div>
|
||||||
|
</x-slot:actions>
|
||||||
|
<x-slot:explanation>
|
||||||
|
<p>A resource could be an application, a database or a service (like WordPress).</p>
|
||||||
|
</x-slot:explanation>
|
||||||
|
</x-boarding-step>
|
||||||
|
@endif
|
||||||
|
<div class="flex justify-center gap-2 pt-4">
|
||||||
|
<a wire:click='skipBoarding'>Skip boarding process</a>
|
||||||
|
<a wire:click='restartBoarding'>Restart boarding process</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -6,6 +6,8 @@ use App\Http\Controllers\DatabaseController;
|
|||||||
use App\Http\Controllers\MagicController;
|
use App\Http\Controllers\MagicController;
|
||||||
use App\Http\Controllers\ProjectController;
|
use App\Http\Controllers\ProjectController;
|
||||||
use App\Http\Controllers\ServerController;
|
use App\Http\Controllers\ServerController;
|
||||||
|
use App\Http\Livewire\Boarding\Index;
|
||||||
|
use App\Http\Livewire\Boarding\Server as BoardingServer;
|
||||||
use App\Http\Livewire\Dashboard;
|
use App\Http\Livewire\Dashboard;
|
||||||
use App\Http\Livewire\Server\All;
|
use App\Http\Livewire\Server\All;
|
||||||
use App\Http\Livewire\Server\Show;
|
use App\Http\Livewire\Server\Show;
|
||||||
@ -92,7 +94,7 @@ Route::middleware(['auth'])->group(function () {
|
|||||||
|
|
||||||
Route::middleware(['auth'])->group(function () {
|
Route::middleware(['auth'])->group(function () {
|
||||||
Route::get('/', Dashboard::class)->name('dashboard');
|
Route::get('/', Dashboard::class)->name('dashboard');
|
||||||
Route::get('/boarding', [Controller::class, 'boarding'])->name('boarding');
|
Route::get('/boarding', Index::class)->name('boarding');
|
||||||
Route::middleware(['throttle:force-password-reset'])->group(function () {
|
Route::middleware(['throttle:force-password-reset'])->group(function () {
|
||||||
Route::get('/force-password-reset', [Controller::class, 'force_passoword_reset'])->name('auth.force-password-reset');
|
Route::get('/force-password-reset', [Controller::class, 'force_passoword_reset'])->name('auth.force-password-reset');
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user