Update UI elements and text content

This commit is contained in:
Andras Bacsai 2024-03-20 15:46:59 +01:00
parent 6b49d32102
commit fafc4fb71e
20 changed files with 576 additions and 539 deletions

View File

@ -2,22 +2,27 @@
namespace App\Livewire\Boarding;
use App\Actions\Server\InstallDocker;
use App\Enums\ProxyTypes;
use App\Models\PrivateKey;
use App\Models\Project;
use App\Models\Server;
use App\Models\Team;
use Illuminate\Support\Collection;
use Livewire\Attributes\Url;
use Livewire\Component;
class Index extends Component
{
protected $listeners = ['serverInstalled' => 'validateServer'];
public string $currentState = 'welcome';
#[Url()]
public string $state = 'welcome';
#[Url()]
public ?string $selectedServerType = null;
public ?Collection $privateKeys = null;
#[Url()]
public ?int $selectedExistingPrivateKey = null;
public ?string $privateKeyType = null;
public ?string $privateKey = null;
@ -27,6 +32,8 @@ class Index extends Component
public ?PrivateKey $createdPrivateKey = null;
public ?Collection $servers = null;
#[Url()]
public ?int $selectedExistingServer = null;
public ?string $remoteServerName = null;
public ?string $remoteServerDescription = null;
@ -38,7 +45,9 @@ class Index extends Component
public ?Server $createdServer = null;
public Collection $projects;
public ?int $selectedExistingProject = null;
#[Url()]
public ?int $selectedProject = null;
public ?Project $createdProject = null;
public bool $dockerInstallationStarted = false;
@ -62,13 +71,33 @@ public function mount()
$this->remoteServerDescription = 'Created by Coolify';
$this->remoteServerHost = 'coolify-testing-host';
}
if ($this->state === 'create-project') {
$this->getProjects();
}
if ($this->state === 'create-resource') {
$this->selectExistingServer();
$this->selectExistingProject();
}
if ($this->state === 'private-key') {
$this->setServerType('remote');
}
if ($this->state === 'create-server') {
$this->selectExistingPrivateKey();
}
if ($this->state === 'validate-server') {
$this->selectExistingServer();
}
if ($this->state === 'select-existing-server') {
$this->selectExistingServer();
}
}
public function explanation()
{
if (isCloud()) {
return $this->setServerType('remote');
}
$this->currentState = 'select-server-type';
$this->state = 'select-server-type';
}
public function restartBoarding()
@ -89,6 +118,7 @@ public function setServerType(string $type)
$this->selectedServerType = $type;
if ($this->selectedServerType === 'localhost') {
$this->createdServer = Server::find(0);
$this->selectedExistingServer = 0;
if (!$this->createdServer) {
return $this->dispatch('error', 'Localhost server is not found. Something went wrong during installation. Please try to reinstall or contact support.');
}
@ -106,10 +136,10 @@ public function setServerType(string $type)
$this->servers = Server::ownedByCurrentTeam(['name'])->where('id', '!=', 0)->get();
if ($this->servers->count() > 0) {
$this->selectedExistingServer = $this->servers->first()->id;
$this->currentState = 'select-existing-server';
$this->state = 'select-existing-server';
return;
}
$this->currentState = 'private-key';
$this->state = 'private-key';
}
}
public function selectExistingServer()
@ -117,12 +147,12 @@ public function selectExistingServer()
$this->createdServer = Server::find($this->selectedExistingServer);
if (!$this->createdServer) {
$this->dispatch('error', 'Server is not found.');
$this->currentState = 'private-key';
$this->state = 'private-key';
return;
}
$this->selectedExistingPrivateKey = $this->createdServer->privateKey->id;
$this->serverPublicKey = $this->createdServer->privateKey->publicKey();
$this->currentState = 'validate-server';
$this->state = 'validate-server';
}
public function getProxyType()
{
@ -130,7 +160,7 @@ public function getProxyType()
$this->selectProxy(ProxyTypes::TRAEFIK_V2->value);
// $proxyTypeSet = $this->createdServer->proxy->type;
// if (!$proxyTypeSet) {
// $this->currentState = 'select-proxy';
// $this->state = 'select-proxy';
// return;
// }
$this->getProjects();
@ -139,12 +169,12 @@ public function selectExistingPrivateKey()
{
$this->createdPrivateKey = PrivateKey::find($this->selectedExistingPrivateKey);
$this->privateKey = $this->createdPrivateKey->private_key;
$this->currentState = 'create-server';
$this->state = 'create-server';
}
public function createNewServer()
{
$this->selectedExistingServer = null;
$this->currentState = 'private-key';
$this->state = 'private-key';
}
public function setPrivateKey(string $type)
{
@ -153,7 +183,7 @@ public function setPrivateKey(string $type)
if ($type === 'create') {
$this->createNewPrivateKey();
}
$this->currentState = 'create-private-key';
$this->state = 'create-private-key';
}
public function savePrivateKey()
{
@ -168,7 +198,7 @@ public function savePrivateKey()
'team_id' => currentTeam()->id
]);
$this->createdPrivateKey->save();
$this->currentState = 'create-server';
$this->state = 'create-server';
}
public function saveServer()
{
@ -196,7 +226,8 @@ public function saveServer()
$this->createdServer->settings->is_cloudflare_tunnel = $this->isCloudflareTunnel;
$this->createdServer->settings->save();
$this->createdServer->addInitialNetwork();
$this->currentState = 'validate-server';
$this->selectedExistingServer = $this->createdServer->id;
$this->state = 'validate-server';
}
public function installServer()
{
@ -223,7 +254,7 @@ public function validateServer()
$dockerVersion = instant_remote_process(["docker version|head -2|grep -i version| awk '{print $2}'"], $this->createdServer, true);
$dockerVersion = checkMinimumDockerEngineVersion($dockerVersion);
if (is_null($dockerVersion)) {
$this->currentState = 'validate-server';
$this->state = 'validate-server';
throw new \Exception('Docker not found or old version is installed.');
}
$this->createdServer->settings()->update([
@ -249,14 +280,14 @@ public function getProjects()
{
$this->projects = Project::ownedByCurrentTeam(['name'])->get();
if ($this->projects->count() > 0) {
$this->selectedExistingProject = $this->projects->first()->id;
$this->selectedProject = $this->projects->first()->id;
}
$this->currentState = 'create-project';
$this->state = 'create-project';
}
public function selectExistingProject()
{
$this->createdProject = Project::find($this->selectedExistingProject);
$this->currentState = 'create-resource';
$this->createdProject = Project::find($this->selectedProject);
$this->state = 'create-resource';
}
public function createNewProject()
{
@ -264,7 +295,7 @@ public function createNewProject()
'name' => "My first project",
'team_id' => currentTeam()->id
]);
$this->currentState = 'create-resource';
$this->state = 'create-resource';
}
public function showNewResource()
{

View File

@ -20,7 +20,7 @@ protected function rules() {
}
public function mount() {
$this->oauth_settings_map = OauthSetting::all()->reduce(function($carry, $setting) {
$this->oauth_settings_map = OauthSetting::all()->sortBy('provider')->reduce(function($carry, $setting) {
$carry[$setting->provider] = $setting;
return $carry;
}, []);

View File

@ -9,7 +9,7 @@
"auth.confirm_password": "Confirm password",
"auth.forgot_password": "Forgot password",
"auth.forgot_password_send_email": "Send password reset email",
"auth.register_now": "Register a new account",
"auth.register_now": "Register",
"auth.logout": "Logout",
"auth.register": "Register",
"auth.registration_disabled": "Registration is disabled. Please contact the administrator.",

View File

@ -11,6 +11,9 @@ body {
@apply text-sm antialiased scrollbar;
}
.button {
@apply px-3 py-1.5 text-sm font-normal normal-case rounded bg-neutral-200 hover:bg-neutral-300 dark:bg-coolgray-200 dark:text-white dark:hover:bg-coolgray-100 dark:disabled:bg-coolgray-100/40 dark:disabled:text-neutral-800 min-w-fit flex items-center justify-center;
}
button[isError]:not(:disabled) {
@apply bg-red-600 hover:bg-red-700;
}
@ -19,9 +22,7 @@ button[isHighlighted]:not(:disabled) {
@apply bg-coollabs hover:bg-coollabs-100;
}
.button {
@apply px-3 py-1.5 text-sm font-normal normal-case rounded dark:bg-coolgray-200 dark:text-white dark:hover:bg-coolgray-100 dark:disabled:bg-coolgray-100/40 dark:disabled:text-neutral-800 min-w-fit flex items-center justify-center;
}
h1 {
@apply text-2xl font-bold dark:text-white text-neutral-800;
@ -82,6 +83,7 @@ tr td:first-child {
input {
@apply pr-10;
}
.input {
@apply block w-full py-1.5 rounded border-0 text-sm ring-inset ring-1 dark:bg-coolgray-100 dark:text-white text-black focus:ring-2 dark:focus:ring-coolgray-300 dark:ring-coolgray-300 dark:read-only:text-neutral-500 dark:read-only:ring-0 dark:read-only:bg-coolgray-100/40 dark:placeholder:text-neutral-700;
}
@ -89,12 +91,15 @@ .input {
option {
@apply text-white;
}
.alert-success {
@apply flex items-center gap-2 text-success;
}
.alert-error {
@apply flex items-center gap-2 text-error;
}
.dropdown-item {
@apply relative flex cursor-pointer select-none dark:hover:text-white dark:hover:bg-coollabs items-center px-2 py-1.5 text-xs justify-center outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 gap-2
}
@ -115,8 +120,6 @@ .badge-error {
@apply bg-error;
}
[type='checkbox']:checked {
background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='black' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e");
}
@ -126,11 +129,11 @@ .menu {
}
.menu-item {
@apply flex items-center w-full gap-2 px-4 py-1 min-w-48 hover:bg-coolgray-100 dark:hover:text-white;
@apply flex items-center w-full gap-2 py-1 pl-2 dark:hover:bg-coolgray-100 dark:hover:text-white hover:bg-neutral-300;
}
.menu-item-active {
@apply rounded-none dark:bg-coolgray-200 dark:text-warning;
@apply text-black rounded-none dark:bg-coolgray-200 dark:text-warning bg-neutral-200;
}
.icon {
@ -170,15 +173,21 @@ .icon:hover {
}
.box {
@apply flex p-2 transition-colors cursor-pointer min-h-[4rem] bg-coolgray-100 hover:bg-coollabs-100 hover:text-white hover:no-underline;
@apply flex p-2 transition-colors cursor-pointer min-h-[4rem] dark:bg-coolgray-100 bg-neutral-50 hover:bg-neutral-200 dark:hover:bg-coollabs-100 dark:hover:text-white hover:no-underline;
}
.box-without-bg {
@apply flex p-2 transition-colors hover:text-white hover:no-underline min-h-[4rem];
@apply flex p-2 transition-colors dark:hover:text-white hover:no-underline min-h-[4rem];
}
.box-title {
@apply font-bold text-black dark:text-white group-hover:dark:text-white;
}
.box-description {
@apply text-xs font-bold text-neutral-500 group-hover:dark:text-white group-hover:text-black;
}
.description {
@apply text-xs font-bold text-neutral-500 group-hover:text-white;
@apply text-xs font-bold text-neutral-500 group-hover:dark:text-white group-hover:text-black;
}
.lds-heart {
@ -224,8 +233,9 @@ .buyme {
}
.title {
@apply hidden pb-0 lg:block lg:pb-8 ;
@apply hidden pb-0 lg:block lg:pb-8;
}
.subtitle {
@apply pt-2 pb-10;
}
@ -237,4 +247,3 @@ .fullscreen {
.toast {
z-index: 1;
}

View File

@ -1,26 +1,12 @@
<x-layout-simple>
<div class="min-h-screen hero">
<div class="w-96 min-w-fit">
<div class="flex flex-col items-center pb-8">
<div class="text-5xl font-extrabold tracking-tight text-center text-white">Coolify</div>
</div>
<div class="flex items-center gap-2">
<h1>{{ __('auth.login') }}</h1>
@if ($is_registration_enabled)
@if (config('coolify.waitlist'))
<a href="/waitlist"
class="text-xs text-center text-white normal-case bg-transparent border-none rounded no-animation hover:no-underline btn btn-sm bg-coollabs-gradient">
Join the waitlist
<section class="bg-gray-50 dark:bg-base">
<div class="flex flex-col items-center justify-center px-6 py-8 mx-auto md:h-screen lg:py-0">
<a class="flex items-center mb-6 text-5xl font-extrabold tracking-tight text-gray-900 dark:text-white">
Coolify
</a>
@else
<a href="/register"
class="text-xs text-center text-white normal-case bg-transparent border-none rounded no-animation hover:no-underline btn btn-sm bg-coollabs-gradient">
{{ __('auth.register_now') }}
</a>
@endif
@endif
</div>
<div>
<div
class="w-full bg-white rounded shadow dark:border md:mt-0 sm:max-w-md xl:p-0 dark:bg-base dark:border-coolgray-200">
<div class="p-6 space-y-4 md:space-y-6 sm:p-8">
<form action="/login" method="POST" class="flex flex-col gap-2">
@csrf
@env('local')
@ -33,20 +19,38 @@ class="text-xs text-center text-white normal-case bg-transparent border-none rou
{{ __('auth.forgot_password') }}?
</a>
@else
<x-forms.input type="email" name="email" required label="{{ __('input.email') }}" autofocus />
<x-forms.input type="email" name="email" required label="{{ __('input.email') }}"
autofocus />
<x-forms.input type="password" name="password" required label="{{ __('input.password') }}" />
<a href="/forgot-password" class="text-xs">
{{ __('auth.forgot_password') }}?
</a>
@endenv
<x-forms.button type="submit">{{ __('auth.login') }}</x-forms.button>
<x-forms.button class="mt-10" type="submit">{{ __('auth.login') }}</x-forms.button>
@if ($is_registration_enabled)
<a href="/register"
class="button bg-coollabs-gradient">
{{ __('auth.register_now') }}
</a>
@endif
@if ($enabled_oauth_providers->isNotEmpty())
<div class="relative">
<div class="absolute inset-0 flex items-center" aria-hidden="true">
<div class="w-full border-t dark:border-coolgray-200"></div>
</div>
<div class="relative flex justify-center">
<span class="px-2 text-sm dark:text-neutral-500 dark:bg-base">or</span>
</div>
</div>
@endif
@foreach ($enabled_oauth_providers as $provider_setting)
<x-forms.button type="button" onclick="document.location.href='/auth/{{$provider_setting->provider}}/redirect'">
<x-forms.button type="button"
onclick="document.location.href='/auth/{{ $provider_setting->provider }}/redirect'">
{{ __("auth.login.$provider_setting->provider") }}
</x-forms.button>
@endforeach
@if (!$is_registration_enabled)
<div class="text-center ">{{ __('auth.registration_disabled') }}</div>
<div class="text-center text-neutral-500">{{ __('auth.registration_disabled') }}</div>
@endif
@if ($errors->any())
<div class="text-xs text-center text-error">
@ -69,4 +73,5 @@ class="text-xs text-center text-white normal-case bg-transparent border-none rou
</div>
</div>
</div>
</section>
</x-layout-simple>

View File

@ -1,17 +1,15 @@
<x-layout-simple>
<div class="flex items-center justify-center min-h-screen ">
<div class="w-1/2">
<div class="flex flex-col items-center pb-8">
<div class="text-5xl font-bold tracking-tight text-center text-white">Coolify</div>
<x-version />
</div>
<div class="flex items-center gap-2">
<h1>{{ __('auth.register') }}</h1>
<a href="/login"
class="text-xs text-center text-white normal-case bg-transparent border-none rounded no-animation hover:no-underline btn btn-sm bg-coollabs-gradient">
{{ __('auth.already_registered') }}
<section class="bg-gray-50 dark:bg-base">
<div class="flex flex-col items-center justify-center px-6 py-8 mx-auto md:h-screen lg:py-0">
<a class="flex items-center mb-6 text-5xl font-extrabold tracking-tight text-gray-900 dark:text-white">
Coolify
</a>
</div>
<div
class="w-full bg-white rounded-lg shadow dark:border md:mt-0 sm:max-w-md xl:p-0 dark:bg-base dark:border-coolgray-200">
<div class="p-6 space-y-4 md:space-y-6 sm:p-8">
<h1 class="text-xl font-bold leading-tight tracking-tight text-gray-900 md:text-2xl dark:text-white">
Create an account
</h1>
<form action="/register" method="POST" class="flex flex-col gap-2">
@csrf
@env('local')
@ -29,12 +27,16 @@ class="text-xs text-center text-white normal-case bg-transparent border-none rou
<x-forms.input required type="text" name="name" label="{{ __('input.name') }}" />
<x-forms.input required type="email" name="email" label="{{ __('input.email') }}" />
<div class="flex gap-2">
<x-forms.input required type="password" name="password" label="{{ __('input.password') }}" />
<x-forms.input required type="password" name="password"
label="{{ __('input.password') }}" />
<x-forms.input required type="password" name="password_confirmation"
label="{{ __('input.password.again') }}" />
</div>
@endenv
<x-forms.button type="submit">{{ __('auth.register') }}</x-forms.button>
<x-forms.button class="mb-4" type="submit">Register</x-forms.button>
<a href="/login" class="button bg-coollabs-gradient">
{{ __('auth.already_registered') }}
</a>
</form>
@if ($errors->any())
<div class="text-xs text-center text-error">
@ -43,6 +45,9 @@ class="text-xs text-center text-white normal-case bg-transparent border-none rou
@endforeach
</div>
@endif
</div>
</div>
</div>
</section>
</x-layout-simple>

View File

@ -1,9 +1,9 @@
<div class="grid grid-cols-1 gap-4 md:grid-cols-3">
<div class="box-border col-span-2 min-w-[24rem] min-h-[21rem]">
<h1 class="text-5xl font-bold">{{ $title }}</h1>
<div class="py-6 ">
<div class="py-6">
@isset($question)
<p class="text-base">
<p class="text-base dark:text-neutral-400">
{{ $question }}
</p>
@endisset

View File

@ -1 +1 @@
<span class="inline-block text-warning">{{ $text }}</span>
<span class="inline-block font-bold text-warning">{{ $text }}</span>

View File

@ -1,5 +1,6 @@
@props(['text' => null])
<div class="inline-flex items-center justify-center" {{ $attributes }}>
<div>{{ $text }}</div>
<svg class="w-4 h-4 mx-1 ml-3 text-warning animate-spin" xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
@ -7,5 +8,4 @@
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z">
</path>
</svg>
<div>{{ $text }}</div>
</div>

View File

@ -1,11 +1,14 @@
<div class="flex items-center h-16 pt-2 lg:pt-4 shrink-0">
<a href="/" class="flex items-center w-12 h-12 -mx-1 text-xl font-bold text-white"><img
class="transition rounded " src="{{ asset('coolify-transparent.png') }}"></a>
</div>
<nav class="flex flex-col flex-1">
<nav class="flex flex-col flex-1 pl-4 border-r dark:border-coolgray-300 dark:bg-coolgray-100 bg-neutral-50">
<div class="flex w-full px-2 pt-6 pb-4">
<div class="flex flex-col">
<div class="text-2xl font-bold tracking-wide dark:text-white">Coolify</div>
<x-version />
</div>
<button onclick="changeTheme()">Dark/light</button>
</div>
<ul role="list" class="flex flex-col flex-1 gap-y-7">
<li class="flex-1">
<ul role="list" class="flex flex-col h-full -mx-2 space-y-1">
<li class="flex-1 ">
<ul role="list" class="flex flex-col h-full space-y-1.5">
<li>
<a title="Dashboard" href="/"
class="{{ request()->is('/') ? 'menu-item-active menu-item' : 'menu-item' }}">
@ -278,8 +281,8 @@ class="flex h-6 w-6 shrink-0 items-center justify-center rounded-lg border text-
</a>
</li>
</ul>
</li> --}}
{{-- <li class="mt-auto -mx-6">
</li>
<li class="mt-auto -mx-6">
<a href="#"
class="flex items-center px-6 py-3 text-sm font-semibold leading-6 text-gray-900 gap-x-4 hover:bg-gray-50">
<img class="w-8 h-8 rounded-full bg-gray-50"

View File

@ -1,2 +1,2 @@
<a {{ $attributes->merge(['class' => 'text-xs cursor-pointer opacity-60 hover:opacity-100 hover:text-white z-[60]']) }}
<a {{ $attributes->merge(['class' => 'text-xs cursor-pointer opacity-60 hover:opacity-100 dark:hover:text-white hover:text-black z-[60]']) }}
href="https://github.com/coollabsio/coolify/releases/tag/v{{ config('version') }}">v{{ config('version') }}</a>

View File

@ -10,7 +10,7 @@
<div class="relative z-50 lg:hidden" :class="open ? 'block' : 'hidden'" role="dialog" aria-modal="true">
<div class="fixed inset-0 bg-black/80"></div>
<div class="fixed inset-0 flex">
<div class="relative flex flex-1 w-full mr-16 max-w-56 ">
<div class="relative flex flex-1 w-full mr-16 max-w-48 ">
<div class="absolute top-0 flex justify-center w-16 pt-5 left-full">
<button type="button" class="-m-2.5 p-2.5" x-on:click="open = !open">
<span class="sr-only">Close sidebar</span>
@ -21,21 +21,20 @@
</button>
</div>
<div class="flex flex-col px-6 pb-2 overflow-y-auto dark:bg-coolgray-100 gap-y-5 scrollbar">
<div class="flex flex-col pb-2 overflow-y-auto min-w-48 dark:bg-coolgray-100 gap-y-5 scrollbar">
<x-navbar />
</div>
</div>
</div>
</div>
<div class="hidden lg:fixed lg:inset-y-0 lg:z-50 lg:flex lg:w-56 lg:flex-col">
<div class="flex flex-col px-4 overflow-y-auto grow gap-y-5 scrollbar">
<div class="hidden lg:fixed lg:inset-y-0 lg:z-50 lg:flex lg:w-48 lg:flex-col">
<div class="flex flex-col overflow-y-auto grow gap-y-5 scrollbar">
<x-navbar />
</div>
</div>
<div
class="sticky top-0 z-40 flex items-center px-4 py-4 gap-x-6 sm:px-6 lg:hidden">
<div class="sticky top-0 z-40 flex items-center px-4 py-4 gap-x-6 sm:px-6 lg:hidden">
<button type="button" class="-m-2.5 p-2.5 dark:text-warning lg:hidden" x-on:click="open = !open">
<span class="sr-only">Open sidebar</span>
<svg class="w-6 h-6" xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 24 24">
@ -52,7 +51,7 @@ class="sticky top-0 z-40 flex items-center px-4 py-4 gap-x-6 sm:px-6 lg:hidden">
</a> --}}
</div>
<main class="lg:pl-56">
<main class="lg:pl-48">
<div>
<div class="p-4 sm:px-6 lg:px-8 lg:py-6">
{{ $slot }}

View File

@ -38,10 +38,9 @@
@section('body')
<body>
{{-- <button onclick="changeTheme()" class="fixed z-50 left-52">Dark/light</button> --}}
@livewire('wire-elements-modal')
<x-toast />
<x-version class="fixed left-7 bottom-1" />
{{-- <x-version class="fixed left-7 bottom-1" /> --}}
<script data-navigate-once>
if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia(
'(prefers-color-scheme: dark)').matches)) {

View File

@ -1,22 +1,23 @@
@php use App\Enums\ProxyTypes; @endphp
<div>
<div>
@if ($currentState === 'welcome')
<section class="bg-gray-50 dark:bg-base">
<div class="flex flex-col items-center justify-center px-6 py-8 mx-auto max-w-7xl md:h-screen lg:py-0">
@if ($state === 'welcome')
<h1 class="text-5xl font-bold">Welcome to Coolify</h1>
<p class="py-6 text-xl text-center">Let me help you set up the basics.</p>
<div class="flex justify-center ">
<x-forms.button class="justify-center w-64 box" wire:click="$set('currentState','explanation')">Get
<x-forms.button class="justify-center w-64 box" wire:click="$set('state','explanation')">Get
Started
</x-forms.button>
</div>
@endif
</div>
<div>
@if ($currentState === 'explanation')
@if ($state === 'explanation')
<x-boarding-step title="What is Coolify?">
<x-slot:question>
Coolify is an all-in-one application to automate tasks on your servers, deploy application with Git
integrations, deploy databases and services, monitor these resources with notifications and alerts
Coolify is an all-in-one application to automate tasks on your servers, deploy application with
Git
integrations, deploy databases and services, monitor these resources with notifications and
alerts
without vendor lock-in
and <a href="https://coolify.io" class="text-white hover:underline">much much more</a>.
<br><br>
@ -24,11 +25,13 @@
<x-highlighted text="Self-hosting with superpowers!" /></span>
</x-slot:question>
<x-slot:explanation>
<p><x-highlighted text="Task automation:" /> You don't need to manage your servers anymore. Coolify does
<p><x-highlighted text="Task automation:" /> You don't need to manage your servers anymore.
Coolify does
it for you.</p>
<p><x-highlighted text="No vendor lock-in:" /> All configurations are stored on your servers, so
everything works without a connection to Coolify (except integrations and automations).</p>
<p><x-highlighted text="Monitoring:" />You can get notified on your favourite platforms (Discord,
<p><x-highlighted text="Monitoring:" />You can get notified on your favourite platforms
(Discord,
Telegram, Email, etc.) when something goes wrong, or an action is needed from your side.</p>
</x-slot:explanation>
<x-slot:actions>
@ -37,7 +40,7 @@
</x-slot:actions>
</x-boarding-step>
@endif
@if ($currentState === 'select-server-type')
@if ($state === 'select-server-type')
<x-boarding-step title="Server">
<x-slot:question>
Do you want to deploy your resources to your <x-highlighted text="Localhost" />
@ -54,7 +57,8 @@
@if (!$serverReachable)
Localhost is not reachable with the following public key.
<br /> <br />
Please make sure you have the correct public key in your ~/.ssh/authorized_keys file for user
Please make sure you have the correct public key in your ~/.ssh/authorized_keys file for
user
'root' or skip the boarding process and add a new private key manually to Coolify and to the
server.
<br />
@ -70,16 +74,18 @@
<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
<p><x-highlighted text="Localhost" /> is the server where Coolify is running on. It is not
recommended to use one server
for everything.</p>
<p>Remote Server is a server reachable through SSH. It can be hosted at home, or from any cloud
<p><x-highlighted text="A 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
</div>
<div>
@if ($currentState === 'private-key')
@if ($state === 'private-key')
<x-boarding-step title="SSH Key">
<x-slot:question>
Do you have your own SSH Private Key?
@ -115,7 +121,7 @@
@endif
</div>
<div>
@if ($currentState === 'select-existing-server')
@if ($state === 'select-existing-server')
<x-boarding-step title="Select a server">
<x-slot:question>
There are already servers available for your Team. Do you want to use one of them?
@ -123,7 +129,8 @@
<x-slot:actions>
<div class="flex flex-col gap-4">
<div>
<x-forms.button class="justify-center w-64 box" wire:click="createNewServer">No (create one
<x-forms.button class="justify-center w-64 box" wire:click="createNewServer">No (create
one
for
me)
</x-forms.button>
@ -143,11 +150,13 @@
@if (!$serverReachable)
This server is not reachable with the following public key.
<br /> <br />
Please make sure you have the correct public key in your ~/.ssh/authorized_keys file for user
Please make sure you have the correct public key in your ~/.ssh/authorized_keys file for
user
'root' or skip the boarding process and add a new private key manually to Coolify and to the
server.
<x-forms.input readonly id="serverPublicKey"></x-forms.input>
<x-forms.button class="w-64 box" wire:target="validateServer" wire:click="validateServer">Check
<x-forms.button class="w-64 box" wire:target="validateServer"
wire:click="validateServer">Check
again
</x-forms.button>
@endif
@ -163,7 +172,7 @@
@endif
</div>
<div>
@if ($currentState === 'create-private-key')
@if ($state === 'create-private-key')
<x-boarding-step title="Create Private Key">
<x-slot:question>
Please let me know your key details.
@ -174,11 +183,12 @@
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" />
<x-forms.textarea required placeholder="-----BEGIN OPENSSH PRIVATE KEY-----"
label="Private Key" id="privateKey" />
@if ($privateKeyType === 'create')
<x-forms.textarea rows="7" readonly label="Public Key" id="publicKey" />
<span class="font-bold text-warning">ACTION REQUIRED: Copy the 'Public Key' to your server's
<span class="font-bold text-warning">ACTION REQUIRED: Copy the 'Public Key' to your
server's
~/.ssh/authorized_keys
file.</span>
@endif
@ -196,7 +206,7 @@
@endif
</div>
<div>
@if ($currentState === 'create-server')
@if ($state === 'create-server')
<x-boarding-step title="Create Server">
<x-slot:question>
Please let me know your server details.
@ -210,12 +220,13 @@
label="Description" id="remoteServerDescription" />
</div>
<div class="flex gap-2">
<x-forms.input required placeholder="127.0.0.1" label="IP Address" id="remoteServerHost" />
<x-forms.input required placeholder="127.0.0.1" label="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" />
placeholder="Username to connect to your server. Default is root."
label="Username" id="remoteServerUser" />
</div>
<div class="w-64">
<x-forms.checkbox
@ -233,7 +244,7 @@
@endif
</div>
<div>
@if ($currentState === 'validate-server')
@if ($state === 'validate-server')
<x-boarding-step title="Validate & Configure Server">
<x-slot:question>
I need to validate your server (connection, Docker Engine, etc) and configure if something is
@ -253,7 +264,8 @@
</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.<br><br>Minimum Docker Engine version is: 22<br><br>To manually install Docker
to run optimal.<br><br>Minimum Docker Engine version is: 22<br><br>To manually install
Docker
Engine, check <a target="_blank" class="underline text-warning"
href="https://docs.docker.com/engine/install/#server">this
documentation</a>.</p>
@ -261,40 +273,13 @@
</x-boarding-step>
@endif
</div>
{{-- <div>
@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
</div> --}}
<div>
@if ($currentState === 'create-project')
@if ($state === 'create-project')
<x-boarding-step title="Project">
<x-slot:question>
@if (count($projects) > 0)
You already have some projects. Do you want to use one of them or should I create a new one for
You already have some projects. Do you want to use one of them or should I create a new one
for
you?
@else
Let's create an initial project for you. You can change all the details later on.
@ -306,8 +291,7 @@
<div>
@if (count($projects) > 0)
<form wire:submit='selectExistingProject' class="flex flex-col w-full gap-4 lg:w-96">
<x-forms.select label="Existing projects" class="w-96"
id='selectedExistingProject'>
<x-forms.select label="Existing projects" class="w-96" id='selectedProject'>
@foreach ($projects as $project)
<option wire:key="{{ $loop->index }}" value="{{ $project->id }}">
{{ $project->name }}</option>
@ -328,7 +312,7 @@
@endif
</div>
<div>
@if ($currentState === 'create-resource')
@if ($state === 'create-resource')
<x-boarding-step title="Resources">
<x-slot:question>
Let's go to the new resource page, where you can create your first resource.
@ -347,4 +331,5 @@
<a wire:click='skipBoarding'>Skip boarding process</a>
<a wire:click='restartBoarding'>Restart boarding process</a>
</div>
</div>
</div>
</section>

View File

@ -5,7 +5,7 @@
<h1 class="title">Dashboard</h1>
{{-- <div class="subtitle">Your self-hosted environment</div> --}}
@if (request()->query->get('success'))
<div class="mb-10 text-white rounded alert-success">
<div class="mb-10 rounded dark:text-white alert-success">
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 stroke-current shrink-0" fill="none"
viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
@ -22,26 +22,26 @@
@if (data_get($project, 'environments')->count() === 1)
<a class="flex flex-col flex-1 mx-6 hover:no-underline"
href="{{ route('project.resource.index', ['project_uuid' => data_get($project, 'uuid'), 'environment_name' => data_get($project, 'environments.0.name', 'production')]) }}">
<div class="font-bold text-white">{{ $project->name }}</div>
<div class="description">
<div class="box-title">{{ $project->name }}</div>
<div class="box-description">
{{ $project->description }}</div>
</a>
@else
<a class="flex flex-col flex-1 mx-6 hover:no-underline"
href="{{ route('project.show', ['project_uuid' => data_get($project, 'uuid')]) }}">
<div class="font-bold text-white">{{ $project->name }}</div>
<div class="description">
<div class="box-title">{{ $project->name }}</div>
<div class="box-description">
{{ $project->description }}</div>
</a>
@endif
<div class="flex items-center">
<a class="mx-4 rounded group-hover:text-white hover:no-underline"
<div class="flex items-center group">
<a class="mx-4 rounded hover:no-underline"
href="{{ route('project.resource.create', ['project_uuid' => data_get($project, 'uuid'), 'environment_name' => data_get($project, 'environments.0.name', 'production')]) }}">
<span class="font-bold hover:text-warning">+ Add Resource</span>
<span class="p-2 font-bold group-hover:dark:text-white group-hover:text-black dark:hover:bg-coollabs hover:bg-neutral-300">+ Add Resource</span>
</a>
<a class="mx-4 rounded group-hover:text-white"
<a class="mx-4 rounded group-hover:dark:text-white group-hover:text-black"
href="{{ route('project.edit', ['project_uuid' => data_get($project, 'uuid')]) }}">
<svg xmlns="http://www.w3.org/2000/svg" class="icon hover:text-warning" viewBox="0 0 24 24"
<svg xmlns="http://www.w3.org/2000/svg" class="icon hover:text-coollabs" viewBox="0 0 24 24"
stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round"
stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
@ -54,9 +54,9 @@
</div>
@empty
<div>
No projects found. Add your first server <a class="text-white underline"
No projects found. Add your first server <a class="underline dark:text-white"
onclick="newEmptyProject.showModal()">here</a> or
go to the <a class="text-white underline" href="{{ route('onboarding') }}">onboarding page.</a>
go to the <a class="underline dark:text-white" href="{{ route('onboarding') }}">onboarding page.</a>
<livewire:project.add-empty />
</div>
@endforelse
@ -71,10 +71,10 @@
'border-red-500' => !$server->settings->is_reachable,
])>
<div class="flex flex-col mx-6">
<div class="font-bold text-white">
<div class="box-title">
{{ $server->name }}
</div>
<div class="description">
<div class="box-description">
{{ $server->description }}</div>
<div class="flex gap-1 text-xs text-error">
@if (!$server->settings->is_reachable)
@ -93,8 +93,9 @@
@empty
<div>
No servers found.
Add your first server <a class="text-white underline" href="{{ route('server.create') }}">here</a> or
go to the <a class="text-white underline" href="{{ route('onboarding') }}">onboarding page.</a>
Add your first server <a class="underline dark:text-white" href="{{ route('server.create') }}">here</a>
or
go to the <a class="underline dark:text-white" href="{{ route('onboarding') }}">onboarding page.</a>
</div>
@endforelse
</div>
@ -116,15 +117,15 @@
'border-yellow-500' => data_get($deployment, 'status') === 'in_progress',
])>
<div class="flex flex-col mx-6">
<div class="font-bold text-white">
<div class="box-title">
{{ data_get($deployment, 'application_name') }}
</div>
@if (data_get($deployment, 'pull_request_id') !== 0)
<div class="description">
<div class="box-description">
PR #{{ data_get($deployment, 'pull_request_id') }}
</div>
@endif
<div class="description">
<div class="box-description">
{{ str(data_get($deployment, 'status'))->headline() }}
</div>
</div>

View File

@ -12,7 +12,7 @@
</x-slide-over>
@endif
</div>
<div class="subtitle">All your projects.</div>
<div class="subtitle">All your projects are here.</div>
<div class="grid gap-2 lg:grid-cols-2">
@if ($servers === 0)
<div>

View File

@ -52,7 +52,7 @@ class="items-center justify-center box">+ Add New Resource</a>
<a class="h-24 box group" :href="item.hrefLink">
<div class="flex flex-col w-full px-4 mx-2">
<div class="flex gap-2">
<div class="pb-2 font-bold text-white" x-text="item.name"></div>
<div class="pb-2 box-title" x-text="item.name"></div>
<template x-if="item.status.startsWith('running')">
<div title="running" class="mt-1 bg-success badge "></div>
</template>
@ -66,16 +66,16 @@ class="items-center justify-center box">+ Add New Resource</a>
<div title="degraded" class="mt-1 bg-warning badge "></div>
</template>
</div>
<div class="max-w-full truncate description" x-text="item.description"></div>
<div class="max-w-full truncate description" x-text="item.fqdn"></div>
<div class="max-w-full truncate box-description" x-text="item.description"></div>
<div class="max-w-full truncate box-description" x-text="item.fqdn"></div>
</div>
</a>
<div class="flex gap-1 pt-1 group-hover:text-white group min-h-6">
<div class="flex gap-1 pt-1 group-hover:dark:text-white group-hover:text-black group min-h-6">
<template x-for="tag in item.tags">
<div class="px-2 py-1 cursor-pointer description bg-coolgray-100 hover:bg-coolgray-300"
<div class="px-2 py-1 cursor-pointer box-description dark:bg-coolgray-100 dark:hover:bg-coolgray-300 bg-neutral-100 hover:bg-neutral-200"
@click.prevent="gotoTag(tag.name)" x-text="tag.name"></div>
</template>
<div class="flex items-center px-2 text-xs cursor-pointer text-neutral-500/20 group-hover:text-white hover:bg-coolgray-300"
<div class="flex items-center px-2 text-xs cursor-pointer dark:text-neutral-500/20 text-neutral-500 group-hover:text-neutral-700 group-hover:dark:text-white dark:hover:bg-coolgray-300 hover:bg-neutral-200"
@click.prevent="goto(item)">Add tag</div>
</div>
</span>
@ -85,7 +85,7 @@ class="items-center justify-center box">+ Add New Resource</a>
<a class="h-24 box group" :href="item.hrefLink">
<div class="flex flex-col px-4 mx-2">
<div class="flex gap-2">
<div class="pb-2 font-bold text-white" x-text="item.name"></div>
<div class="pb-2 font-bold box-title" x-text="item.name"></div>
<template x-if="item.status.startsWith('running')">
<div title="running" class="mt-1 bg-success badge "></div>
</template>
@ -99,10 +99,10 @@ class="items-center justify-center box">+ Add New Resource</a>
<div title="degraded" class="mt-1 bg-warning badge "></div>
</template>
</div>
<div class="max-w-full truncate description" x-text="item.description"></div>
<div class="max-w-full truncate box-description" x-text="item.description"></div>
</div>
</a>
<div class="flex gap-1 pt-1 group-hover:text-white group min-h-6">
<div class="flex gap-1 pt-1 group-hover:dark:text-white group-hover:text-black group min-h-6">
<template x-for="tag in item.tags">
<div class="px-2 py-1 cursor-pointer description bg-coolgray-100 hover:bg-coolgray-300"
@click.prevent="gotoTag(tag.name)" x-text="tag.name"></div>

View File

@ -5,7 +5,7 @@
<x-forms.button >+ Add</x-forms.button>
</a>
</div>
<div class="subtitle">All your projects.</div>
<div class="subtitle">All your servers are here.</div>
<div class="grid gap-2 lg:grid-cols-2">
@forelse ($servers as $server)

View File

@ -4,14 +4,14 @@
</div>
<div class="pb-4 ">Email settings for password resets, invitations, shared with Pro+ subscribers etc.</div>
<form wire:submit='submitFromFields' class="pb-4">
<div class="flex flex-col items-end w-full gap-2 xl:flex-row">
<div class="flex gap-2">
<x-forms.input required id="settings.smtp_from_name" helper="Name used in emails." label="From Name" />
<x-forms.input required id="settings.smtp_from_address" helper="Email address used in emails."
label="From Address" />
<x-forms.button type="submit">
Save
</x-forms.button>
@if (isEmailEnabled($settings) && auth()->user()->isAdminFromSession() && isTestEmailEnabled($settings))
{{-- @if (isEmailEnabled($settings) && auth()->user()->isAdminFromSession() && isTestEmailEnabled($settings))
<x-modal-input buttonTitle="Send Test Email" title="Send Test Email">
<form wire:submit='submit' class="flex flex-col gap-2">
<x-forms.input placeholder="test@example.com" id="emails" label="Recipients" required />
@ -21,16 +21,21 @@
</x-forms.button>
</form>
</x-modal-input>
@endif
@endif --}}
</div>
</form>
<div class="flex flex-col gap-4">
<div class="p-4 border border-coolgray-500">
<form wire:submit='submit' class="flex flex-col">
<div class="flex gap-2">
<h3>SMTP Server</h3>
<x-forms.button type="submit">
Save
</x-forms.button>
</div>
<div class="w-32">
<x-forms.checkbox instantSave id="settings.smtp_enabled" label="Enabled" />
</div>
<form wire:submit='submit' class="flex flex-col">
<div class="flex flex-col gap-4">
<div class="flex flex-col w-full gap-2 xl:flex-row">
<x-forms.input required id="settings.smtp_host" placeholder="smtp.mailgun.org" label="Host" />
@ -45,30 +50,25 @@
label="Timeout" />
</div>
</div>
<div class="flex justify-end gap-4 pt-6">
</form>
</div>
<div class="p-4 border border-coolgray-500">
<form wire:submit='submitResend' class="flex flex-col">
<div class="flex gap-2">
<h3>Resend</h3>
<x-forms.button type="submit">
Save
</x-forms.button>
</div>
</form>
</div>
<div class="p-4 border border-coolgray-500">
<h3>Resend</h3>
<div class="w-32">
<x-forms.checkbox instantSave='instantSaveResend' id="settings.resend_enabled" label="Enabled" />
</div>
<form wire:submit='submitResend' class="flex flex-col">
<div class="flex flex-col gap-4">
<div class="flex flex-col w-full gap-2 xl:flex-row">
<x-forms.input type="password" id="settings.resend_api_key" placeholder="API key" required
label="Host" />
</div>
</div>
<div class="flex justify-end gap-4 pt-6">
<x-forms.button type="submit">
Save
</x-forms.button>
</div>
</form>
</div>
</div>

View File

@ -10,7 +10,7 @@
@click.prevent="activeTab = 'smtp'; window.location.hash = 'smtp'" href="#">Transactional
Email</a>
<a :class="activeTab === 'auth' && 'text-white'"
@click.prevent="activeTab = 'auth'; window.location.hash = 'auth'" href="#">Authentication</a>
@click.prevent="activeTab = 'auth'; window.location.hash = 'auth'" href="#">Authentication (OAuth)</a>
</div>
<div class="w-full pl-8">
<div x-cloak x-show="activeTab === 'general'" class="h-full">