Merge branch 'v4-next' into notifications
This commit is contained in:
@@ -2,41 +2,51 @@
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
* {
|
||||
//outline: solid 0.25rem hsla(210, 100%, 100%, 0.5);
|
||||
@apply scrollbar-thumb-yellow-400 scrollbar-track-coolgray-200 scrollbar-w-2;
|
||||
.scrollbar {
|
||||
@apply scrollbar-thumb-coollabs-100 scrollbar-track-coolgray-200 scrollbar-w-1;
|
||||
}
|
||||
|
||||
html {
|
||||
@apply h-full min-h-full bg-coolgray-100;
|
||||
@apply min-h-screen h-full bg-coolgray-100;
|
||||
}
|
||||
|
||||
body {
|
||||
@apply bg-coolgray-100 text-neutral-400 min-h-full antialiased;
|
||||
@apply scrollbar min-h-screen bg-coolgray-100 text-neutral-400 antialiased ;
|
||||
}
|
||||
main {
|
||||
@apply px-32 xl:px-14 mx-auto max-w-screen-xl;
|
||||
}
|
||||
|
||||
input[type="checkbox"] {
|
||||
@apply toggle toggle-warning toggle-sm;
|
||||
@apply toggle toggle-warning toggle-xs rounded;
|
||||
}
|
||||
input {
|
||||
@apply input input-sm placeholder:text-neutral-700 text-white;
|
||||
@apply input input-sm placeholder:text-neutral-700 text-white rounded-none;
|
||||
}
|
||||
input[type="text"],[type="number"],[type="email"],[type="password"] {
|
||||
@apply read-only:opacity-40;
|
||||
}
|
||||
.label-text, label {
|
||||
@apply text-neutral-400 text-sm;
|
||||
}
|
||||
|
||||
textarea {
|
||||
@apply textarea placeholder:text-neutral-700 text-white;
|
||||
@apply textarea placeholder:text-neutral-700 text-white rounded-none;
|
||||
}
|
||||
select {
|
||||
@apply select select-sm disabled:opacity-40 font-normal placeholder:text-neutral-700 text-white;
|
||||
@apply select select-sm disabled:opacity-40 font-normal placeholder:text-neutral-700 text-white rounded-none;
|
||||
}
|
||||
.breadcrumbs > ul > li::before {
|
||||
@apply text-warning opacity-100;
|
||||
}
|
||||
|
||||
button[type="button"] {
|
||||
@apply btn btn-xs btn-ghost no-animation normal-case text-white;
|
||||
@apply btn btn-xs mt-1 bg-coolgray-200 no-animation normal-case text-white rounded;
|
||||
}
|
||||
button[type="submit"] {
|
||||
@apply btn btn-xs no-animation normal-case text-white btn-primary;
|
||||
@apply btn btn-xs mt-1 no-animation normal-case text-white btn-primary rounded;
|
||||
}
|
||||
button[isWarning] {
|
||||
@apply btn-error text-white;
|
||||
@apply text-error;
|
||||
}
|
||||
button[isHighlighted] {
|
||||
@apply btn-primary text-white;
|
||||
@@ -54,8 +64,17 @@ a {
|
||||
@apply text-neutral-400 hover:text-white text-sm link link-hover hover:bg-transparent;
|
||||
}
|
||||
|
||||
.main-navbar {
|
||||
@apply fixed h-full overflow-hidden;
|
||||
}
|
||||
.icon {
|
||||
@apply w-6 h-6;
|
||||
}
|
||||
.icon:hover {
|
||||
@apply text-white;
|
||||
}
|
||||
.box {
|
||||
@apply flex items-center justify-center text-sm rounded cursor-pointer h-14 bg-coolgray-200 hover:bg-coollabs-100 hover:text-white p-2 hover:no-underline;
|
||||
@apply flex items-center justify-center text-sm rounded-none min-h-12 bg-coolgray-200 hover:bg-coollabs-100 hover:text-white p-2 hover:no-underline transition-colors;
|
||||
}
|
||||
|
||||
.main-menu {
|
||||
@@ -63,17 +82,51 @@ a {
|
||||
}
|
||||
.main-menu:after {
|
||||
content: "/";
|
||||
@apply absolute border border-dotted rounded border-neutral-600 right-0 top-0 text-warning mx-1 px-2 mt-[0.7rem];
|
||||
@apply absolute border border-dotted rounded border-neutral-600 right-0 top-0 text-warning mx-1 px-2 mt-[0.3rem] text-sm;
|
||||
}
|
||||
.magic-badge {
|
||||
@apply min-w-fit px-2 rounded text-center border border-dotted border-primary text-white text-xs;
|
||||
}
|
||||
.magic-input {
|
||||
@apply input w-96 placeholder:text-neutral-700 text-sm;
|
||||
@apply input input-sm w-80 xl:w-96 placeholder:text-neutral-700 text-sm rounded-none;
|
||||
}
|
||||
.magic-items {
|
||||
@apply absolute top-16 mt-2 w-[24rem] bg-coolgray-200 rounded-xl outline outline-coolgray-500;
|
||||
@apply absolute top-12 mt-2 w-[24rem] bg-coolgray-200 rounded z-50;
|
||||
}
|
||||
.magic-item {
|
||||
@apply text-sm flex items-center gap-4 m-2 py-2 pl-4 cursor-pointer hover:bg-coolgray-500 text-neutral-400 hover:text-white rounded-xl transition-colors hover:shadow;
|
||||
@apply text-sm flex items-center gap-4 m-2 py-2 pl-4 cursor-pointer hover:bg-coolgray-500 text-neutral-400 hover:text-white transition-colors hover:shadow;
|
||||
}
|
||||
.magic-item-focused {
|
||||
@apply bg-neutral-700 text-white;
|
||||
@apply bg-coolgray-400 text-white;
|
||||
}
|
||||
|
||||
|
||||
.lds-heart {
|
||||
animation: lds-heart 1.2s infinite cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||
}
|
||||
@keyframes lds-heart {
|
||||
0% {
|
||||
transform: scale(1);
|
||||
}
|
||||
5% {
|
||||
transform: scale(1.2);
|
||||
}
|
||||
39% {
|
||||
transform: scale(0.85);
|
||||
}
|
||||
45% {
|
||||
transform: scale(1);
|
||||
}
|
||||
60% {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
100% {
|
||||
transform: scale(0.9);
|
||||
}
|
||||
}
|
||||
.bg-coollabs-gradient {
|
||||
@apply text-transparent bg-clip-text bg-gradient-to-r from-purple-500 via-pink-500 to-red-500;
|
||||
}
|
||||
.text-helper {
|
||||
@apply inline-block font-bold text-warning
|
||||
}
|
||||
50
resources/views/auth/forgot-password.blade.php
Normal file
50
resources/views/auth/forgot-password.blade.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<x-layout-simple>
|
||||
Forgot Password
|
||||
<form>
|
||||
@csrf
|
||||
<x-forms.input required value="test@example.com" type="email" name="email" label="{{ __('input.email') }}"
|
||||
autofocus />
|
||||
</form>
|
||||
@if (session('status'))
|
||||
<div class="mb-4 text-sm font-medium text-green-600">
|
||||
{{ session('status') }}
|
||||
</div>
|
||||
@endif
|
||||
{{-- <div class="flex items-center justify-center h-screen">
|
||||
<div>
|
||||
<div class="pb-8 text-5xl font-bold tracking-tight text-center text-white">Coolify</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<h1 class="pb-0">{{ __('auth.login') }}</h1>
|
||||
@if ($is_registration_enabled)
|
||||
<a href="/register" class="flex justify-center pt-2 hover:no-underline">
|
||||
<button
|
||||
class="normal-case rounded-none btn btn-sm btn-primary bg-coollabs-gradient">{{ __('auth.register-now') }}</button>
|
||||
</a>
|
||||
@endif
|
||||
</div>
|
||||
<div class="w-96">
|
||||
<form action="/login" method="POST" class="flex flex-col gap-2">
|
||||
@csrf
|
||||
@env('local')
|
||||
<x-forms.input required value="test@example.com" type="email" name="email"
|
||||
label="{{ __('input.email') }}" autofocus />
|
||||
<x-forms.input required value="password" type="password" name="password"
|
||||
label="{{ __('input.password') }}" />
|
||||
@else
|
||||
<x-forms.input required type="email" name="email" label="{{ __('input.email') }}" autofocus />
|
||||
<x-forms.input required type="password" name="password" label="{{ __('input.password') }}" />
|
||||
@endenv
|
||||
@if ($errors->any())
|
||||
<div class="text-center text-error">
|
||||
<span>{{ __('auth.failed') }}</span>
|
||||
</div>
|
||||
@endif
|
||||
<x-forms.button type="submit">{{ __('auth.login') }}</x-forms.button>
|
||||
@if (!$is_registration_enabled)
|
||||
<div class="text-sm text-center">{{ __('auth.registration_disabled') }}</div>
|
||||
@endif
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div> --}}
|
||||
</x-layout-simple>
|
||||
@@ -1,30 +1,39 @@
|
||||
<x-layout-simple>
|
||||
<div class="flex items-center justify-center h-screen">
|
||||
<div>
|
||||
<div>
|
||||
<form action="/login" method="POST" class="flex flex-col gap-2">
|
||||
@csrf
|
||||
<input type="email" name="email" placeholder="{{ __('input.email') }}"
|
||||
@env('local') value="test@example.com" @endenv autofocus />
|
||||
<input type="password" name="password" placeholder="{{ __('input.password') }}"
|
||||
@env('local') value="password" @endenv />
|
||||
<x-inputs.button type="submit">{{ __('auth.login') }}</x-inputs.button>
|
||||
</form>
|
||||
@if ($errors->any())
|
||||
<div class="alert alert-danger">
|
||||
<ul>
|
||||
<li>{{ __('auth.failed') }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pb-8 text-5xl font-bold tracking-tight text-center text-white">Coolify</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<h1 class="pb-0">{{ __('auth.login') }}</h1>
|
||||
@if ($is_registration_enabled)
|
||||
<a href="/register" class="flex justify-center pt-2 hover:no-underline">
|
||||
<button
|
||||
class="normal-case rounded-none btn btn-sm btn-primary bg-coollabs-gradient">{{ __('auth.register-now') }}</button>
|
||||
</a>
|
||||
@endif
|
||||
</div>
|
||||
@if ($is_registration_enabled)
|
||||
<a href="/register" class="flex justify-center pt-2">
|
||||
<button>{{ __('auth.register') }}</button>
|
||||
</a>
|
||||
@else
|
||||
<div>{{ __('auth.registration_disabled') }}</div>
|
||||
@endif
|
||||
<div class="w-96">
|
||||
<form action="/login" method="POST" class="flex flex-col gap-2">
|
||||
@csrf
|
||||
@env('local')
|
||||
<x-forms.input required value="test@example.com" type="email" name="email"
|
||||
label="{{ __('input.email') }}" autofocus />
|
||||
<x-forms.input required value="password" type="password" name="password"
|
||||
label="{{ __('input.password') }}" />
|
||||
@else
|
||||
<x-forms.input required type="email" name="email" label="{{ __('input.email') }}" autofocus />
|
||||
<x-forms.input required type="password" name="password" label="{{ __('input.password') }}" />
|
||||
@endenv
|
||||
@if ($errors->any())
|
||||
<div class="text-center text-error">
|
||||
<span>{{ __('auth.failed') }}</span>
|
||||
</div>
|
||||
@endif
|
||||
<x-forms.button type="submit">{{ __('auth.login') }}</x-forms.button>
|
||||
@if (!$is_registration_enabled)
|
||||
<div class="text-sm text-center">{{ __('auth.registration_disabled') }}</div>
|
||||
@endif
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</x-layout-simple>
|
||||
|
||||
@@ -1,28 +1,45 @@
|
||||
<x-layout-simple>
|
||||
<div class="flex items-center justify-center h-screen">
|
||||
<div class="flex items-center justify-center min-h-screen">
|
||||
<div>
|
||||
<div class="pb-8 text-5xl font-bold tracking-tight text-center text-white">Coolify</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<h1 class="pb-0">{{ __('auth.register') }}</h1>
|
||||
<a href="/login" class="flex justify-center pt-2 hover:no-underline">
|
||||
<button
|
||||
class="normal-case rounded-none btn btn-sm btn-primary bg-coollabs-gradient">{{ __('auth.already-registered') }}</button>
|
||||
</a>
|
||||
</div>
|
||||
<form action="/register" method="POST" class="flex flex-col gap-2">
|
||||
@csrf
|
||||
<input type="text" name="name" placeholder="{{ __('input.name') }}"
|
||||
@env('local') value="root" @endenv />
|
||||
<input type="email" name="email" placeholder="{{ __('input.email') }}"
|
||||
@env('local') value="test@example.com" @endenv />
|
||||
<input type="password" name="password" placeholder="{{ __('input.password') }}"
|
||||
@env('local') value="password" @endenv />
|
||||
<input type="password" name="password_confirmation" placeholder="{{ __('input.password.again') }}"
|
||||
@env('local') value="password" @endenv />
|
||||
<x-inputs.button type="submit">{{ __('auth.register') }}</x-inputs.button>
|
||||
@env('local')
|
||||
<x-forms.input required value="test3 normal user" type="text" name="name"
|
||||
label="{{ __('input.name') }}" />
|
||||
<x-forms.input required value="test3@example.com" type="email" name="email"
|
||||
label="{{ __('input.email') }}" />
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input required value="password" type="password" name="password"
|
||||
label="{{ __('input.password') }}" />
|
||||
<x-forms.input required value="password" type="password" name="password_confirmation"
|
||||
label="{{ __('input.password.again') }}" />
|
||||
</div>
|
||||
@else
|
||||
<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_confirmation"
|
||||
label="{{ __('input.password.again') }}" />
|
||||
</div>
|
||||
@endenv
|
||||
<x-forms.button type="submit">{{ __('auth.register') }}</x-forms.button>
|
||||
</form>
|
||||
@if ($errors->any())
|
||||
<div class="alert alert-danger">
|
||||
<div class="fixed top-0 text-xs alert alert-error">
|
||||
<ul>
|
||||
<li>{{ __('auth.failed') }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
<a href="/login" class="flex justify-center pt-2">
|
||||
<button>{{ __('auth.login') }}</button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</x-layout-simple>
|
||||
|
||||
@@ -1,50 +1,64 @@
|
||||
<nav class="flex gap-4 py-2 border-b-2 border-solid border-coolgray-200">
|
||||
<a
|
||||
<nav class="flex items-center gap-4 py-2 border-b-2 border-solid border-coolgray-200">
|
||||
<a class="{{ request()->routeIs('project.application.configuration') ? 'text-white' : '' }}"
|
||||
href="{{ route('project.application.configuration', [
|
||||
'project_uuid' => Route::current()->parameters()['project_uuid'],
|
||||
'application_uuid' => Route::current()->parameters()['application_uuid'],
|
||||
'environment_name' => Route::current()->parameters()['environment_name'],
|
||||
]) }}">
|
||||
Configuration
|
||||
<button>Configuration</button>
|
||||
</a>
|
||||
<a
|
||||
<a class="{{ request()->routeIs('project.application.deployments') ? 'text-white' : '' }}"
|
||||
href="{{ route('project.application.deployments', [
|
||||
'project_uuid' => Route::current()->parameters()['project_uuid'],
|
||||
'application_uuid' => Route::current()->parameters()['application_uuid'],
|
||||
'environment_name' => Route::current()->parameters()['environment_name'],
|
||||
]) }}">
|
||||
Deployments
|
||||
<button>Deployments</button>
|
||||
</a>
|
||||
<div class="flex-1"></div>
|
||||
<div class="dropdown dropdown-hover">
|
||||
<x-inputs.button>Links👇 </x-inputs.button>
|
||||
|
||||
<div class="dropdown dropdown-bottom">
|
||||
<label tabindex="0">
|
||||
<x-forms.button>
|
||||
Open
|
||||
<x-chevron-down />
|
||||
</x-forms.button>
|
||||
</label>
|
||||
<ul tabindex="0"
|
||||
class="p-2 text-xs text-white normal-case rounded min-w-max dropdown-content menu bg-coolgray-200">
|
||||
<li>
|
||||
<a class="text-xs"target="_blank" href="{{ $application->gitBranchLocation }}">
|
||||
Open on Git
|
||||
<x-external-link />
|
||||
</a>
|
||||
</li>
|
||||
class="mt-1 text-xs text-white normal-case rounded min-w-max dropdown-content menu bg-coolgray-200">
|
||||
@if (data_get($application, 'fqdn'))
|
||||
<li>
|
||||
<a class="text-xs hover:no-underline hover:bg-coollabs" target="_blank"
|
||||
href="{{ $application->fqdn }}">
|
||||
{{ $application->fqdn }}
|
||||
<x-external-link />
|
||||
</a>
|
||||
</li>
|
||||
@endif
|
||||
@if (data_get($application, 'ports_mappings_array'))
|
||||
@foreach ($application->ports_mappings_array as $port)
|
||||
@if (config('app.env') === 'local')
|
||||
<li>
|
||||
<a class="text-xs" target="_blank" href="http://localhost:{{ explode(':', $port)[0] }}">Open
|
||||
<a class="text-xs hover:no-underline hover:bg-coollabs" target="_blank"
|
||||
href="http://localhost:{{ explode(':', $port)[0] }}">Port
|
||||
{{ explode(':', $port)[0] }}
|
||||
<x-external-link />
|
||||
</a>
|
||||
</li>
|
||||
@else
|
||||
<li>
|
||||
<a class="text-xs" target="_blank"
|
||||
href="http://{{ $application->destination->server->ip }}:{{ explode(':', $port)[0] }}">Open
|
||||
{{ $port }}</a>
|
||||
<a class="text-xs hover:no-underline hover:bg-coollabs" target="_blank"
|
||||
href="http://{{ $application->destination->server->ip }}:{{ explode(':', $port)[0] }}">Port
|
||||
{{ $port }}
|
||||
<x-external-link />
|
||||
</a>
|
||||
</li>
|
||||
@endif
|
||||
@endforeach
|
||||
@endif
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<livewire:project.application.deploy :applicationId="$application->id" />
|
||||
<livewire:project.application.status :application="$application" />
|
||||
</nav>
|
||||
|
||||
5
resources/views/components/chevron-down.blade.php
Normal file
5
resources/views/components/chevron-down.blade.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4" 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" />
|
||||
<path d="M6 9l6 6l6 -6" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 276 B |
@@ -22,8 +22,8 @@
|
||||
<div class="flex flex-col items-center justify-center h-full">
|
||||
<div class="pb-5 text-white" x-text="message"></div>
|
||||
<div>
|
||||
<x-inputs.button x-on:click='confirmed()'>Confirm</x-inputs.button>
|
||||
<x-inputs.button x-on:click="open = false">Cancel</x-inputs.button>
|
||||
<x-forms.button x-on:click='confirmed()'>Confirm</x-forms.button>
|
||||
<x-forms.button x-on:click="open = false">Cancel</x-forms.button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1 +1 @@
|
||||
<img class="inline-flex w-3 h-3 mb-1 ml-2" src="{{ asset('svgs/external-link.svg') }}">
|
||||
<img class="inline-flex w-3 h-3" src="{{ asset('svgs/external-link.svg') }}">
|
||||
|
||||
38
resources/views/components/forms/button.blade.php
Normal file
38
resources/views/components/forms/button.blade.php
Normal file
@@ -0,0 +1,38 @@
|
||||
@props([
|
||||
'type' => $attributes->get('type') ?? 'button',
|
||||
'disabled' => null,
|
||||
'confirm' => null,
|
||||
'confirmAction' => null,
|
||||
'tooltip' => null,
|
||||
])
|
||||
@isset($tooltip)
|
||||
<div class="tooltip tooltip-warning" data-tip="{{ $tooltip }}">
|
||||
@endisset
|
||||
@if ($type === 'submit')
|
||||
<button {{ $attributes }} type="submit" @if ($disabled !== null) disabled @endif wire:target="submit"
|
||||
wire:loading.delay.shorter.class="loading"
|
||||
@isset($confirm)
|
||||
x-on:click="toggleConfirmModal('{{ $confirm }}', '{{ explode('(', $confirmAction)[0] }}')"
|
||||
@endisset
|
||||
@isset($confirmAction)
|
||||
x-on:{{ explode('(', $confirmAction)[0] }}.window="$wire.{{ explode('(', $confirmAction)[0] }}"
|
||||
@endisset>
|
||||
{{ $slot }}
|
||||
</button>
|
||||
@elseif($type === 'button')
|
||||
<button {{ $attributes }} @if ($disabled !== null) disabled @endif type="button"
|
||||
wire:target="{{ explode('(', $attributes->whereStartsWith('wire:click')->first())[0] }}"
|
||||
wire:loading.delay.shorter.class="loading"
|
||||
@isset($confirm)
|
||||
x-on:click="toggleConfirmModal('{{ $confirm }}', '{{ explode('(', $confirmAction)[0] }}')"
|
||||
@endisset
|
||||
@isset($confirmAction)
|
||||
x-on:{{ explode('(', $confirmAction)[0] }}.window="$wire.{{ explode('(', $confirmAction)[0] }}"
|
||||
@endisset>
|
||||
{{ $slot }}
|
||||
</button>
|
||||
@endif
|
||||
|
||||
@isset($tooltip)
|
||||
</div>
|
||||
@endisset
|
||||
@@ -16,7 +16,7 @@
|
||||
{{ $id }}
|
||||
@endif
|
||||
@if ($helper)
|
||||
<div class="-mb-1 dropdown dropdown-right">
|
||||
<div class="-mb-1 dropdown dropdown-right dropdown-hover">
|
||||
<label tabindex="0" class="cursor-pointer text-warning">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
||||
class="w-4 h-4 stroke-current">
|
||||
@@ -25,7 +25,7 @@
|
||||
</svg>
|
||||
</label>
|
||||
<div tabindex="0"
|
||||
class="border-2 shadow whitespace-nowrap w-max-fit border-coolgray-500 card compact dropdown-content bg-coolgray-200">
|
||||
class="border rounded shadow border-coolgray-400 card compact dropdown-content bg-coolgray-200 w-96">
|
||||
<div class="card-body">
|
||||
{!! $helper !!}
|
||||
</div>
|
||||
@@ -1,28 +1,22 @@
|
||||
@props([
|
||||
'id' => $attributes->has('id') || $attributes->has('label'),
|
||||
'id' => $attributes->has('id'),
|
||||
'type' => $attributes->get('type') ?? 'text',
|
||||
'required' => null,
|
||||
'label' => $attributes->has('label'),
|
||||
'helper' => $attributes->has('helper'),
|
||||
'noLabel' => $attributes->has('noLabel'),
|
||||
'noDirty' => $attributes->has('noDirty'),
|
||||
'required' => null,
|
||||
'disabled' => null,
|
||||
'helper' => $attributes->has('helper'),
|
||||
'noDirty' => $attributes->has('noDirty'),
|
||||
])
|
||||
|
||||
<div {{ $attributes->merge(['class' => 'w-full form-control']) }}>
|
||||
@if (!$noLabel)
|
||||
@if ($label)
|
||||
<label class="label">
|
||||
<span class="label-text">
|
||||
@if ($label)
|
||||
{{ $label }}
|
||||
@else
|
||||
{{ $id }}
|
||||
@endif
|
||||
{{ $label }}
|
||||
@if ($required)
|
||||
<span class="text-warning">*</span>
|
||||
@endif
|
||||
@if ($helper)
|
||||
<div class="-mb-1 dropdown dropdown-right">
|
||||
<div class="-mb-1 dropdown dropdown-right dropdown-hover">
|
||||
<label tabindex="0" class="cursor-pointer text-warning">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
||||
class="w-4 h-4 stroke-current">
|
||||
@@ -31,7 +25,7 @@
|
||||
</svg>
|
||||
</label>
|
||||
<div tabindex="0"
|
||||
class="border-2 shadow w-96 border-coolgray-500 card compact dropdown-content bg-coolgray-200">
|
||||
class="border rounded shadow border-coolgray-400 card compact dropdown-content bg-coolgray-200 w-96">
|
||||
<div class="card-body">
|
||||
{!! $helper !!}
|
||||
</div>
|
||||
@@ -41,9 +35,11 @@
|
||||
</span>
|
||||
</label>
|
||||
@endif
|
||||
<input {{ $attributes }} type={{ $type }} name={{ $id }} wire:model.defer={{ $id }}
|
||||
@if ($disabled !== null) disabled @endif @if ($required !== null) required @endif
|
||||
@if (!$noDirty) wire:dirty.class="input-warning" @endif />
|
||||
<input type={{ $type }}
|
||||
@if ($id) name={{ $id }} wire:model.defer={{ $id }} @endisset
|
||||
@if ($disabled !== null) disabled @endif
|
||||
@if ($required !== null) required @endif
|
||||
@if (!$noDirty && $id) wire:dirty.class="input-warning" @endif {{ $attributes }} />
|
||||
@error($id)
|
||||
<label class="label">
|
||||
<span class="text-red-500 label-text-alt">{{ $message }}</span>
|
||||
@@ -25,16 +25,18 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
@livewireScripts
|
||||
@auth
|
||||
<x-navbar />
|
||||
@endauth
|
||||
<main class="min-h-full px-8 pt-10 mx-auto max-w-7xl">
|
||||
<div class="flex justify-center w-full pt-4 min-h-12">
|
||||
<x-magic-bar />
|
||||
</div>
|
||||
<main>
|
||||
{{ $slot }}
|
||||
</main>
|
||||
<a
|
||||
class="fixed text-xs cursor-pointer left-2 bottom-1 opacity-20 hover:opacity-100 hover:text-white">v{{ config('version') }}</a>
|
||||
class="fixed text-xs cursor-pointer right-2 bottom-1 opacity-60 hover:opacity-100 hover:text-white">v{{ config('version') }}</a>
|
||||
@auth
|
||||
<script>
|
||||
window.addEventListener("keydown", function(event) {
|
||||
@@ -45,48 +47,6 @@
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
function checkIfIamDead() {
|
||||
console.log('Checking server\'s pulse...')
|
||||
checkIfIamDeadInterval = setInterval(async () => {
|
||||
try {
|
||||
const res = await fetch('/api/health');
|
||||
if (res.ok) {
|
||||
console.log('I\'m alive. Waiting for server to be dead...');
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('I\'m dead. Charging... Standby... Bzz... Bzz...')
|
||||
checkHealth();
|
||||
if (checkIfIamDeadInterval) clearInterval(checkIfIamDeadInterval);
|
||||
}
|
||||
|
||||
return;
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
function checkHealth() {
|
||||
console.log('Checking server\'s health...')
|
||||
checkHealthInterval = setInterval(async () => {
|
||||
try {
|
||||
const res = await fetch('/api/health');
|
||||
if (res.ok) {
|
||||
console.log('Server is back online. Reloading...')
|
||||
if (checkHealthInterval) clearInterval(checkHealthInterval);
|
||||
window.location.reload();
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('Waiting for server to come back from dead...');
|
||||
}
|
||||
|
||||
return;
|
||||
}, 2000);
|
||||
}
|
||||
Livewire.on('updateInitiated', () => {
|
||||
let checkHealthInterval = null;
|
||||
let checkIfIamDeadInterval = null;
|
||||
console.log('Update initiated. Waiting for server to be dead...')
|
||||
checkIfIamDead();
|
||||
})
|
||||
Livewire.on('reloadWindow', () => {
|
||||
window.location.reload();
|
||||
})
|
||||
@@ -100,7 +60,6 @@
|
||||
})
|
||||
</script>
|
||||
@endauth
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div x-data="magicsearchbar" @slash.window="mainMenu = true">
|
||||
<div x-data="magicbar" @slash.window="mainMenu = true">
|
||||
{{-- Main --}}
|
||||
<template x-cloak x-if="isMainMenu">
|
||||
<div>
|
||||
@@ -13,14 +13,10 @@
|
||||
<template x-for="(item,index) in filteredItems" :key="item.name">
|
||||
<div x-on:click="await set(item.next ?? 'server',item.name)"
|
||||
:class="focusedIndex === index && 'magic-item-focused'" class="magic-item">
|
||||
<span class="w-12 badge badge-primary badge-sm" x-show="item.type === 'Apps'"
|
||||
x-text="item.type"></span>
|
||||
<span class="w-12 badge badge-secondary badge-sm" x-show="item.type === 'Add'"
|
||||
x-text="item.type"></span>
|
||||
<span class="w-12 badge badge-success badge-sm" x-show="item.type === 'Jump'"
|
||||
x-text="item.type"></span>
|
||||
<span class="w-12 badge badge-success badge-sm" x-show="item.type === 'New'"
|
||||
x-text="item.type"></span>
|
||||
<span class="magic-badge" x-show="item.type === 'Apps'" x-text="item.type"></span>
|
||||
<span class="magic-badge" x-show="item.type === 'Add'" x-text="item.type"></span>
|
||||
<span class="magic-badge" x-show="item.type === 'Jump'" x-text="item.type"></span>
|
||||
<span class="magic-badge" x-show="item.type === 'New'" x-text="item.type"></span>
|
||||
<span x-text="item.name"></span>
|
||||
</div>
|
||||
</template>
|
||||
@@ -42,7 +38,7 @@
|
||||
<template x-for="(server,index) in filteredServers" :key="server.name ?? server">
|
||||
<div x-on:click="await set('destination',server.uuid)"
|
||||
:class="focusedIndex === index && 'magic-item-focused'" class="magic-item">
|
||||
<span class="badge badge-primary badge-sm">Server</span>
|
||||
<span class="magic-badge">Server</span>
|
||||
<span x-text="server.name"></span>
|
||||
</div>
|
||||
</template>
|
||||
@@ -65,7 +61,7 @@
|
||||
<template x-for="(destination,index) in filteredDestinations" :key="destination.name ?? destination">
|
||||
<div x-on:click="await set('project',destination.uuid)"
|
||||
:class="focusedIndex === index && 'magic-item-focused'" class="magic-item">
|
||||
<span class=" badge badge-primary badge-sm">Destination</span>
|
||||
<span class=" magic-badge">Destination</span>
|
||||
<span x-text="destination.name"></span>
|
||||
</div>
|
||||
</template>
|
||||
@@ -88,7 +84,7 @@
|
||||
<template x-for="(project,index) in filteredProjects" :key="project.name ?? project">
|
||||
<div x-on:click="await set('environment',project.uuid)"
|
||||
:class="focusedIndex === index + 1 && 'magic-item-focused'" class="magic-item">
|
||||
<span class="badge badge-primary badge-sm">Project</span>
|
||||
<span class="magic-badge">Project</span>
|
||||
<span x-text="project.name"></span>
|
||||
</div>
|
||||
</template>
|
||||
@@ -98,7 +94,8 @@
|
||||
{{-- Environments --}}
|
||||
<template x-cloak x-if="environmentMenu">
|
||||
<div x-on:click.outside="closeMenus">
|
||||
<input class="magic-input" x-ref="search" x-model="search" placeholder="Select a environment..."
|
||||
<input class="magic-input" x-ref="search" x-model="search"
|
||||
placeholder="Enter the new environment name or select one..."
|
||||
x-on:keydown.down="focusNext(environments.length + 1)"
|
||||
x-on:keydown.up="focusPrev(environments.length + 1)" x-on:keyup.escape="closeMenus"
|
||||
x-on:keyup.enter="focusedIndex !== '' && await set('jump',filteredEnvironments()[focusedIndex - 1]?.name)" />
|
||||
@@ -106,12 +103,12 @@
|
||||
<div x-on:click="await newEnvironment" :class="focusedIndex === 0 && 'magic-item-focused'"
|
||||
class="magic-item">
|
||||
<span>New Environment</span>
|
||||
<span x-text="search"></span>
|
||||
<span class="text-warning" x-text="search"></span>
|
||||
</div>
|
||||
<template x-for="(environment,index) in filteredEnvironments" :key="environment.name ?? environment">
|
||||
<div x-on:click="await set('jump',environment.name)"
|
||||
:class="focusedIndex === index + 1 && 'magic-item-focused'" class="magic-item">
|
||||
<span class="badge badge-primary badge-sm">Env</span>
|
||||
<span class="magic-badge">Env</span>
|
||||
<span x-text="environment.name"></span>
|
||||
</div>
|
||||
</template>
|
||||
@@ -121,9 +118,9 @@
|
||||
{{-- Projects --}}
|
||||
<template x-cloak x-if="projectsMenu">
|
||||
<div x-on:click.outside="closeMenus">
|
||||
<input x-ref="search" x-model="search" class="magic-input" placeholder="Select a project..."
|
||||
x-on:keyup.escape="closeMenus" x-on:keydown.down="focusNext(projects.length)"
|
||||
x-on:keydown.up="focusPrev(projects.length)"
|
||||
<input x-ref="search" x-model="search" class="magic-input"
|
||||
placeholder="Enter the new project name or select one..." x-on:keyup.escape="closeMenus"
|
||||
x-on:keydown.down="focusNext(projects.length)" x-on:keydown.up="focusPrev(projects.length)"
|
||||
x-on:keyup.enter="focusedIndex !== '' && await set('jumpToProject',filteredProjects()[focusedIndex]?.uuid)" />
|
||||
<div class="magic-items">
|
||||
<template x-if="projects.length === 0">
|
||||
@@ -134,7 +131,7 @@
|
||||
<template x-for="(project,index) in filteredProjects" :key="project.name ?? project">
|
||||
<div x-on:click="await set('jumpToProject',project.uuid)"
|
||||
:class="focusedIndex === index && 'magic-item-focused'" class="magic-item">
|
||||
<span class="badge badge-primary badge-sm">Jump</span>
|
||||
<span class="magic-badge">Jump</span>
|
||||
<span x-text="project.name"></span>
|
||||
</div>
|
||||
</template>
|
||||
@@ -157,7 +154,7 @@
|
||||
<template x-for="(destination,index) in filteredDestinations" :key="destination.name ?? destination">
|
||||
<div x-on:click="await set('jumpToDestination',destination.uuid)"
|
||||
:class="focusedIndex === index && 'magic-item-focused'" class="magic-item">
|
||||
<span class="badge badge-primary badge-sm">Jump</span>
|
||||
<span class="magic-badge">Jump</span>
|
||||
<span x-text="destination.name"></span>
|
||||
</div>
|
||||
</template>
|
||||
@@ -180,7 +177,7 @@
|
||||
<template x-for="(privateKey,index) in filteredPrivateKeys" :key="privateKey.name ?? privateKey">
|
||||
<div x-on:click="await set('jumpToPrivateKey',privateKey.uuid)"
|
||||
:class="focusedIndex === index && 'magic-item-focused'" class="magic-item">
|
||||
<span class="badge badge-primary badge-sm">Jump</span>
|
||||
<span class="magic-badge">Jump</span>
|
||||
<span x-text="privateKey.name"></span>
|
||||
</div>
|
||||
</template>
|
||||
@@ -203,7 +200,7 @@
|
||||
<template x-for="(source,index) in filteredSources" :key="source.name ?? source">
|
||||
<div x-on:click="await set('jumpToSource',source)"
|
||||
:class="focusedIndex === index && 'magic-item-focused'" class="magic-item">
|
||||
<span class="badge badge-primary badge-sm">Jump</span>
|
||||
<span class="magic-badge">Jump</span>
|
||||
<span x-text="source.name"></span>
|
||||
</div>
|
||||
</template>
|
||||
@@ -214,7 +211,7 @@
|
||||
|
||||
<script>
|
||||
document.addEventListener('alpine:init', () => {
|
||||
Alpine.data('magicsearchbar', () => ({
|
||||
Alpine.data('magicbar', () => ({
|
||||
isMainMenu() {
|
||||
return !this.serverMenu &&
|
||||
!this.destinationMenu &&
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
])
|
||||
<div x-cloak x-show="{{ $show }}" x-transition class="modal modal-open">
|
||||
<div class="relative modal-box">
|
||||
<div class="pb-8 text-base font-bold">{{ $message }}</div>
|
||||
<div class="pb-8 text-base font-bold text-white">{{ $message }}</div>
|
||||
<div class="flex justify-end gap-4 text-xs">
|
||||
<x-inputs.button isWarning wire:click='{{ $action }}' x-on:click="{{ $show }} = false">
|
||||
<x-forms.button wire:click='{{ $action }}' x-on:click="{{ $show }} = false">
|
||||
Yes
|
||||
</x-inputs.button>
|
||||
<x-inputs.button x-on:click="{{ $show }} = false">No</x-inputs.button>
|
||||
</x-forms.button>
|
||||
<x-forms.button x-on:click="{{ $show }} = false">No</x-forms.button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,100 +1,122 @@
|
||||
@auth
|
||||
<div class="navbar">
|
||||
<div class="navbar-start">
|
||||
<div class="dropdown">
|
||||
<label tabindex="0" class="btn btn-ghost xl:hidden">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" fill="none" viewBox="0 0 24 24"
|
||||
<nav class="main-navbar">
|
||||
<ul class="gap-2 p-1 pt-2 menu" title="Dashboard">
|
||||
<li class="{{ request()->is('/') ? 'text-warning' : '' }}">
|
||||
<a @if (!request()->is('/')) href="/" @endif>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon" fill="none" viewBox="0 0 24 24"
|
||||
stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h8m-8 6h16" />
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" />
|
||||
</svg>
|
||||
</label>
|
||||
<ul tabindex="0" class="p-2 mt-3 shadow menu menu-compact dropdown-content bg-base-100 rounded-box w-52">
|
||||
<li>
|
||||
<a href="/">
|
||||
Dashboard
|
||||
</a>
|
||||
</li>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@if (auth()->user()->isRoot())
|
||||
<li>
|
||||
<a href="/settings">
|
||||
Settings
|
||||
</a>
|
||||
</li>
|
||||
@endif
|
||||
<li>
|
||||
<a href="/profile">
|
||||
Profile
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/profile/team">
|
||||
Team
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/command-center">
|
||||
Command Center
|
||||
</a>
|
||||
</li>
|
||||
@if (auth()->user()->isRoot())
|
||||
<li>
|
||||
<livewire:force-upgrade />
|
||||
</li>
|
||||
@endif
|
||||
<li>
|
||||
<form action="/logout" method="POST">
|
||||
@csrf
|
||||
<button>Logout</button>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div href="/" class="text-xl text-white normal-case btn btn-ghost hover:bg-transparent">Coolify</div>
|
||||
<div class="form-control">
|
||||
<x-magic-bar />
|
||||
</div>
|
||||
</div>
|
||||
<div class="hidden navbar-end xl:flex">
|
||||
<ul class="px-1 menu menu-horizontal text-neutral-400">
|
||||
<li>
|
||||
<a href="/">
|
||||
Dashboard
|
||||
<li class="{{ request()->is('server/*') || request()->is('servers') ? 'text-warning' : '' }}" title="Servers">
|
||||
<a @if (!request()->is('servers')) href="/servers" @endif>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon" 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" />
|
||||
<path d="M3 4m0 3a3 3 0 0 1 3 -3h12a3 3 0 0 1 3 3v2a3 3 0 0 1 -3 3h-12a3 3 0 0 1 -3 -3z" />
|
||||
<path d="M15 20h-9a3 3 0 0 1 -3 -3v-2a3 3 0 0 1 3 -3h12" />
|
||||
<path d="M7 8v.01" />
|
||||
<path d="M7 16v.01" />
|
||||
<path d="M20 15l-2 3h3l-2 3" />
|
||||
</svg>
|
||||
</a>
|
||||
</li>
|
||||
<li class="{{ request()->is('project/*') || request()->is('projects') ? 'text-warning' : '' }}"
|
||||
title="Projects">
|
||||
<a @if (!request()->is('projects')) href="/projects" @endif>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon" 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" />
|
||||
<path d="M12 4l-8 4l8 4l8 -4l-8 -4" />
|
||||
<path d="M4 12l8 4l8 -4" />
|
||||
<path d="M4 16l8 4l8 -4" />
|
||||
</svg>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
@if (auth()->user()->isPartOfRootTeam())
|
||||
<li class="{{ request()->is('command-center') ? 'text-warning' : '' }}" title="Command Center">
|
||||
<a @if (!request()->is('command-center')) href="/command-center" @endif>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon" 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" />
|
||||
<path d="M5 7l5 5l-5 5" />
|
||||
<path d="M12 19l7 0" />
|
||||
</svg>
|
||||
</a>
|
||||
</li>
|
||||
@if (auth()->user()->isRoot())
|
||||
<li>
|
||||
<a href="/settings">
|
||||
Settings
|
||||
</a>
|
||||
</li>
|
||||
@endif
|
||||
<li class="{{ request()->is('settings') ? 'text-warning' : ' ' }}" title="Settings">
|
||||
<a @if (!request()->is('settings')) href="/settings" @endif>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon" 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" />
|
||||
<path
|
||||
d="M10.325 4.317c.426 -1.756 2.924 -1.756 3.35 0a1.724 1.724 0 0 0 2.573 1.066c1.543 -.94 3.31 .826 2.37 2.37a1.724 1.724 0 0 0 1.065 2.572c1.756 .426 1.756 2.924 0 3.35a1.724 1.724 0 0 0 -1.066 2.573c.94 1.543 -.826 3.31 -2.37 2.37a1.724 1.724 0 0 0 -2.572 1.065c-.426 1.756 -2.924 1.756 -3.35 0a1.724 1.724 0 0 0 -2.573 -1.066c-1.543 .94 -3.31 -.826 -2.37 -2.37a1.724 1.724 0 0 0 -1.065 -2.572c-1.756 -.426 -1.756 -2.924 0 -3.35a1.724 1.724 0 0 0 1.066 -2.573c-.94 -1.543 .826 -3.31 2.37 -2.37c1 .608 2.296 .07 2.572 -1.065z" />
|
||||
<path d="M9 12a3 3 0 1 0 6 0a3 3 0 0 0 -6 0" />
|
||||
</svg>
|
||||
</a>
|
||||
</li>
|
||||
@endif
|
||||
</ul>
|
||||
</nav>
|
||||
<div class="fixed top-0 right-0 p-2">
|
||||
<div class="dropdown dropdown-left dropdown-hover">
|
||||
<label tabindex="0" class="btn btn-ghost no-animation hover:bg-transparent hover:text-warning">
|
||||
<div class="flex items-center justify-center gap-2 placeholder">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6" 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" />
|
||||
<path d="M4 6l16 0" />
|
||||
<path d="M4 12l16 0" />
|
||||
<path d="M4 18l16 0" />
|
||||
</svg>
|
||||
</div>
|
||||
</label>
|
||||
<ul tabindex="0"
|
||||
class="p-2 mt-3 text-white rounded shadow menu menu-compact dropdown-content bg-coolgray-200 w-52">
|
||||
<li>
|
||||
<a href="/profile">
|
||||
Profile
|
||||
<a class="hover:no-underline hover:bg-coollabs" href="/profile">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon" 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" />
|
||||
<path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0" />
|
||||
<path d="M12 10m-3 0a3 3 0 1 0 6 0a3 3 0 1 0 -6 0" />
|
||||
<path d="M6.168 18.849a4 4 0 0 1 3.832 -2.849h4a4 4 0 0 1 3.834 2.855" />
|
||||
</svg> Profile
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/profile/team">
|
||||
Team
|
||||
<a class="hover:no-underline hover:bg-coollabs" href="/profile/team">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon" 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" />
|
||||
<path d="M10 13a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" />
|
||||
<path d="M8 21v-1a2 2 0 0 1 2 -2h4a2 2 0 0 1 2 2v1" />
|
||||
<path d="M15 5a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" />
|
||||
<path d="M17 10h2a2 2 0 0 1 2 2v1" />
|
||||
<path d="M5 5a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" />
|
||||
<path d="M3 13v-1a2 2 0 0 1 2 -2h2" />
|
||||
</svg> Team
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/command-center">
|
||||
Command Center
|
||||
</a>
|
||||
</li>
|
||||
@if (auth()->user()->isRoot())
|
||||
<form action="/logout" method="POST">
|
||||
<li>
|
||||
<livewire:force-upgrade />
|
||||
</li>
|
||||
@endif
|
||||
<li>
|
||||
<form action="/logout" method="POST" class="hover:bg-transparent">
|
||||
@csrf
|
||||
<button class="text-sm link link-hover hover:text-white">Logout</button>
|
||||
</form>
|
||||
</li>
|
||||
<button class="text-sm hover:bg-coollabs"> <svg xmlns="http://www.w3.org/2000/svg" class="icon"
|
||||
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" />
|
||||
<path d="M13 12v.01" />
|
||||
<path d="M3 21h18" />
|
||||
<path d="M5 21v-16a2 2 0 0 1 2 -2h7.5m2.5 10.5v7.5" />
|
||||
<path d="M14 7h7m-3 -3l3 3l-3 3" />
|
||||
</svg>Logout</button>
|
||||
</li>
|
||||
</form>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,55 +1,6 @@
|
||||
<x-layout>
|
||||
@if ($servers->count() === 0)
|
||||
<div class="flex flex-col items-center justify-center h-full pt-32">
|
||||
<div class="">Without a server, you won't be able to do much</div>
|
||||
<div class="text-2xl">Let's create <a class="underline" href="{{ route('server.new') }}">your
|
||||
first</a> one!</div>
|
||||
</div>
|
||||
@else
|
||||
<h1>Projects </h1>
|
||||
<div class="flex gap-2">
|
||||
@forelse ($projects as $project)
|
||||
<a href="{{ route('project.environments', [$project->uuid]) }}"
|
||||
class="box">{{ data_get($project, 'name') }}</a>
|
||||
@empty
|
||||
<p>No projects found.</p>
|
||||
@endforelse
|
||||
</div>
|
||||
<h1>Servers </h1>
|
||||
<div class="flex gap-2">
|
||||
@forelse ($servers as $server)
|
||||
<a href="{{ route('server.show', [$server->uuid]) }}" class="box">{{ data_get($server, 'name') }}</a>
|
||||
@empty
|
||||
<p>No servers found.</p>
|
||||
@endforelse
|
||||
</div>
|
||||
{{-- <h1>Destinations </h1>
|
||||
<div class="flex gap-2">
|
||||
@forelse ($destinations as $destination)
|
||||
<a href="{{ route('destination.show', [$destination->uuid]) }}"
|
||||
class="box">{{ data_get($destination, 'name') }}</a>
|
||||
@empty
|
||||
<p>No destinations found.</p>
|
||||
@endforelse
|
||||
</div> --}}
|
||||
{{-- <h1>Private Keys </h1>
|
||||
<div class="flex gap-2">
|
||||
@forelse ($private_keys as $private_key)
|
||||
<a href="{{ route('private-key.show', [$private_key->uuid]) }}"
|
||||
class="box">{{ data_get($private_key, 'name') }}</a>
|
||||
@empty
|
||||
<p>No servers found.</p>
|
||||
@endforelse
|
||||
</div> --}}
|
||||
{{-- <h1>GitHub Apps </h1>
|
||||
<div class="flex">
|
||||
@forelse ($github_apps as $github_app)
|
||||
<a href="{{ route('source.github.show', [$github_app->uuid]) }}"
|
||||
class="box">{{ data_get($github_app, 'name') }}</a>
|
||||
@empty
|
||||
<p>No servers found.</p>
|
||||
@endforelse
|
||||
</div> --}}
|
||||
@endif
|
||||
|
||||
<h1>Dashboard</h1>
|
||||
<div class="">
|
||||
Something useful will be here.
|
||||
</div>
|
||||
</x-layout>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
<x-layout>
|
||||
<h1>New Destination</h1>
|
||||
<livewire:destination.new.standalone-docker :servers="$servers" :server_id="$server_id" />
|
||||
</x-layout>
|
||||
|
||||
@@ -1,53 +1,57 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<title>@yield('title')</title>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<!-- Styles -->
|
||||
<style>
|
||||
html, body {
|
||||
background-color: #fff;
|
||||
color: #636b6f;
|
||||
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
font-weight: 100;
|
||||
height: 100vh;
|
||||
margin: 0;
|
||||
}
|
||||
<title>@yield('title')</title>
|
||||
|
||||
.full-height {
|
||||
height: 100vh;
|
||||
}
|
||||
<!-- Styles -->
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
background-color: #fff;
|
||||
color: #636b6f;
|
||||
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
font-weight: 100;
|
||||
height: 100vh;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.flex-center {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.full-height {
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.position-ref {
|
||||
position: relative;
|
||||
}
|
||||
.flex-center {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.content {
|
||||
text-align: center;
|
||||
}
|
||||
.position-ref {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 36px;
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="flex-center position-ref full-height">
|
||||
<div class="content">
|
||||
<div class="title">
|
||||
@yield('message')
|
||||
</div>
|
||||
.content {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 36px;
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="flex-center position-ref full-height">
|
||||
<div class="content">
|
||||
<div class="title">
|
||||
@yield('message')
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<div>
|
||||
@if ($this->activity)
|
||||
<div
|
||||
class="flex flex-col-reverse w-full overflow-y-auto border border-solid rounded border-coolgray-300 max-h-[32rem] p-4">
|
||||
<pre class="whitespace-pre-wrap" @if ($isPollingActive) wire:poll.750ms="polling" @endif>{{ \App\Actions\CoolifyTask\RunRemoteProcess::decodeOutput($this->activity) }}</pre>
|
||||
class="scrollbar flex flex-col-reverse w-full overflow-y-auto border border-solid rounded border-coolgray-300 max-h-[32rem] p-4 text-xs text-white">
|
||||
<pre class="font-mono whitespace-pre-wrap" @if ($isPollingActive) wire:poll.2000ms="polling" @endif>{{ \App\Actions\CoolifyTask\RunRemoteProcess::decodeOutput($this->activity) }}</pre>
|
||||
{{-- @else
|
||||
<pre class="whitespace-pre-wrap">Output will be here...</pre> --}}
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<div>
|
||||
<x-inputs.button wire:click='checkUpdate' type="submit">
|
||||
Check Update</x-inputs.button>
|
||||
<x-forms.button wire:click='checkUpdate' type="submit">
|
||||
Check Update</x-forms.button>
|
||||
@if ($updateAvailable)
|
||||
Update available
|
||||
@endif
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
<div x-data="{ deleteDestination: false }">
|
||||
<x-naked-modal show="deleteDestination" message='Are you sure you would like to delete this destination?' />
|
||||
<form class="flex flex-col gap-4" wire:submit.prevent='submit'>
|
||||
<x-inputs.input id="destination.name" label="Name" />
|
||||
<x-inputs.input id="destination.server.ip" label="Server IP" readonly />
|
||||
<x-forms.input id="destination.name" label="Name" />
|
||||
<x-forms.input id="destination.server.ip" label="Server IP" readonly />
|
||||
@if ($destination->getMorphClass() === 'App\Models\StandaloneDocker')
|
||||
<x-inputs.input id="destination.network" label="Docker Network" readonly />
|
||||
<x-forms.input id="destination.network" label="Docker Network" readonly />
|
||||
@endif
|
||||
<div>
|
||||
<x-inputs.button type="submit">
|
||||
<x-forms.button type="submit">
|
||||
Save
|
||||
</x-inputs.button>
|
||||
<x-inputs.button x-on:click.prevent="deleteDestination = true">
|
||||
</x-forms.button>
|
||||
<x-forms.button x-on:click.prevent="deleteDestination = true">
|
||||
Delete
|
||||
</x-inputs.button>
|
||||
</x-forms.button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
<div>
|
||||
<form class="flex items-end gap-4" wire:submit.prevent='submit'>
|
||||
<x-inputs.input id="name" label="Name" required />
|
||||
<x-inputs.input id="network" label="Network" required />
|
||||
<x-inputs.select id="server_id" label="Select a server" required>
|
||||
<form class="flex flex-col gap-4" wire:submit.prevent='submit'>
|
||||
<div class="flex gap-2">
|
||||
<h1>New Destination</h1>
|
||||
<x-forms.button type="submit">
|
||||
Save
|
||||
</x-forms.button>
|
||||
</div>
|
||||
<x-forms.input id="name" label="Name" required />
|
||||
<x-forms.input id="network" label="Network" required />
|
||||
<x-forms.select id="server_id" label="Select a server" required>
|
||||
@foreach ($servers as $server)
|
||||
<option disabled>Select a server</option>
|
||||
<option value="{{ $server->id }}">{{ $server->name }}</option>
|
||||
@endforeach
|
||||
</x-inputs.select>
|
||||
<x-inputs.button type="submit">
|
||||
Submit
|
||||
</x-inputs.button>
|
||||
</x-forms.select>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,75 @@
|
||||
<a href="#" class="justify-between font-normal link link-hover hover:bg-transparent hover:text-white"
|
||||
wire:click='upgrade'>Force
|
||||
Upgrade</a>
|
||||
<div class="flex gap-10 text-xs text-white" x-data="{ visible: @entangle('visible') }">
|
||||
<button x-cloak x-show="!visible"
|
||||
class="gap-2 text-white normal-case btn btn-ghost hover:no-underline bg-coollabs hover:bg-coollabs-100"
|
||||
wire:click='upgrade'>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon" 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" />
|
||||
<path d="M10 20.777a8.942 8.942 0 0 1 -2.48 -.969" />
|
||||
<path d="M14 3.223a9.003 9.003 0 0 1 0 17.554" />
|
||||
<path d="M4.579 17.093a8.961 8.961 0 0 1 -1.227 -2.592" />
|
||||
<path d="M3.124 10.5c.16 -.95 .468 -1.85 .9 -2.675l.169 -.305" />
|
||||
<path d="M6.907 4.579a8.954 8.954 0 0 1 3.093 -1.356" />
|
||||
<path d="M12 9l-2 3h4l-2 3" />
|
||||
</svg>Force Upgrade
|
||||
</button>
|
||||
<template x-if="visible">
|
||||
<div class="bg-coollabs-gradient">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-10 h-10 mx-auto text-pink-500 lds-heart"
|
||||
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" />
|
||||
<path d="M19.5 13.572l-7.5 7.428l-7.5 -7.428m0 0a5 5 0 1 1 7.5 -6.566a5 5 0 1 1 7.5 6.572" />
|
||||
</svg> Upgrading, please wait...
|
||||
<script>
|
||||
function checkHealth() {
|
||||
console.log('Checking server\'s health...')
|
||||
checkHealthInterval = setInterval(async () => {
|
||||
try {
|
||||
const res = await fetch('/api/health');
|
||||
if (res.ok) {
|
||||
console.log('Server is back online. Reloading...')
|
||||
if (checkHealthInterval) clearInterval(checkHealthInterval);
|
||||
window.location.reload();
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('Waiting for server to come back from dead...');
|
||||
}
|
||||
|
||||
return;
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
function checkIfIamDead() {
|
||||
console.log('Checking server\'s pulse...')
|
||||
checkIfIamDeadInterval = setInterval(async () => {
|
||||
try {
|
||||
const res = await fetch('/api/health');
|
||||
if (res.ok) {
|
||||
console.log('I\'m alive. Waiting for server to be dead...');
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('I\'m dead. Charging... Standby... Bzz... Bzz...')
|
||||
checkHealth();
|
||||
if (checkIfIamDeadInterval) clearInterval(checkIfIamDeadInterval);
|
||||
}
|
||||
|
||||
return;
|
||||
}, 2000);
|
||||
}
|
||||
let checkHealthInterval = null;
|
||||
let checkIfIamDeadInterval = null;
|
||||
console.log('Update initiated. Waiting for server to be dead...')
|
||||
checkIfIamDead();
|
||||
</script>
|
||||
</div>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-8 h-8 mx-auto lds-heart" 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" />
|
||||
<path d="M19.5 12.572l-7.5 7.428l-7.5 -7.428a5 5 0 1 1 7.5 -6.566a5 5 0 1 1 7.5 6.572" />
|
||||
<path d="M12 6l-2 4l4 3l-2 4v3" />
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
{{-- <livewire:upgrading /> --}}
|
||||
</div>
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
<div x-data="{ deletePrivateKey: false }">
|
||||
<x-naked-modal show="deletePrivateKey" message='Are you sure you would like to delete this private key?' />
|
||||
<form class="flex flex-col gap-2" wire:submit.prevent='changePrivateKey'>
|
||||
<x-inputs.input id="private_key.name" label="Name" required />
|
||||
<x-inputs.input id="private_key.description" label="Description" />
|
||||
<x-inputs.textarea rows="10" id="private_key.private_key" label="Private Key" required />
|
||||
<x-forms.input id="private_key.name" label="Name" required />
|
||||
<x-forms.input id="private_key.description" label="Description" />
|
||||
<x-forms.textarea rows="10" id="private_key.private_key" label="Private Key" required />
|
||||
<div>
|
||||
<x-inputs.button type="submit">
|
||||
<x-forms.button type="submit">
|
||||
Save
|
||||
</x-inputs.button>
|
||||
<x-inputs.button x-on:click.prevent="deletePrivateKey = true">
|
||||
</x-forms.button>
|
||||
<x-forms.button x-on:click.prevent="deletePrivateKey = true">
|
||||
Delete
|
||||
</x-inputs.button>
|
||||
</x-forms.button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<div>
|
||||
<form class="flex flex-col gap-2 " wire:submit.prevent='createPrivateKey'>
|
||||
<x-inputs.input id="name" label="Name" required />
|
||||
<x-inputs.input id="description" label="Description" />
|
||||
<x-inputs.input type="textarea" id="value" label="Private Key" required />
|
||||
<x-inputs.button type="submit" wire.click.prevent>
|
||||
<x-forms.input id="name" label="Name" required />
|
||||
<x-forms.input id="description" label="Description" />
|
||||
<x-forms.textarea id="value" rows="10" placeholder="-----BEGIN OPENSSH PRIVATE KEY-----"
|
||||
label="Private Key" required />
|
||||
<x-forms.button type="submit" wire.click.prevent>
|
||||
Save
|
||||
</x-inputs.button>
|
||||
</x-forms.button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
10
resources/views/livewire/profile/form.blade.php
Normal file
10
resources/views/livewire/profile/form.blade.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<div>
|
||||
<form wire:submit.prevent='submit'>
|
||||
<div class="flex items-center gap-2">
|
||||
<h3>Profile</h3>
|
||||
<x-forms.button type="submit" label="Save">Save</x-forms.button>
|
||||
</div>
|
||||
<x-forms.input id="name" label="Name" required />
|
||||
<x-forms.input id="email" label="Email" readonly />
|
||||
</form>
|
||||
</div>
|
||||
@@ -1,5 +1,9 @@
|
||||
<div x-data="{ deleteApplication: false }">
|
||||
<h2>Danger Zone</h2>
|
||||
<h2 class="pb-0">Danger Zone</h2>
|
||||
<div class="text-sm">Woah. I hope you know what are you doing.</div>
|
||||
<h3 class="pb-0">Delete Application</h3>
|
||||
<div class="text-sm">This will stop your containers, delete all related data, etc. Beware! There is no coming back!
|
||||
</div>
|
||||
<x-naked-modal show="deleteApplication" />
|
||||
<x-inputs.button isWarning x-on:click.prevent="deleteApplication = true">Delete this application</x-inputs.button>
|
||||
<x-forms.button x-on:click.prevent="deleteApplication = true">Delete</x-forms.button>
|
||||
</div>
|
||||
|
||||
@@ -1,38 +1,40 @@
|
||||
<div class="flex items-center gap-2">
|
||||
@if ($application->status === 'running')
|
||||
<div class="btn-group">
|
||||
<x-inputs.button isWarning wire:click='stop'>Stop</x-inputs.button>
|
||||
<div class="border-none dropdown dropdown-hover btn btn-xs bg-coollabs hover:bg-coollabs-100 no-animation">
|
||||
<button tabindex="0" class="flex items-center justify-center h-full">👇</button>
|
||||
<ul tabindex="0"
|
||||
class="text-xs text-white normal-case rounded min-w-max dropdown-content menu bg-coolgray-200">
|
||||
<li>
|
||||
<div wire:click='forceRebuild'>Force deploy without cache</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="dropdown dropdown-bottom">
|
||||
<x-forms.button isHighlighted tabindex="0" class="">
|
||||
Actions
|
||||
<x-chevron-down />
|
||||
</x-forms.button>
|
||||
<ul tabindex="0"
|
||||
class="mt-1 text-xs text-white normal-case rounded min-w-max dropdown-content menu bg-coolgray-200">
|
||||
<li>
|
||||
<div class="hover:bg-coollabs" wire:click='deploy'>Restart</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="hover:bg-coollabs" wire:click='deploy(true)'>Force deploy without cache</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="hover:bg-red-500" wire:click='stop'>Stop</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@else
|
||||
<div class="btn-group">
|
||||
<x-inputs.button isHighlighted wire:click='start'>Deploy</x-inputs.button>
|
||||
<div class="border-none dropdown dropdown-hover btn btn-xs bg-coollabs hover:bg-coollabs-100 no-animation">
|
||||
<button tabindex="0" class="flex items-center justify-center h-full">👇</button>
|
||||
<ul tabindex="0"
|
||||
class="text-xs text-white normal-case rounded min-w-max dropdown-content menu bg-coolgray-200">
|
||||
<li>
|
||||
<div wire:click='forceRebuild'>Deploy without cache</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="dropdown dropdown-bottom">
|
||||
<label tabindex="0">
|
||||
<x-forms.button isHighlighted>
|
||||
Actions
|
||||
<x-chevron-down />
|
||||
</x-forms.button>
|
||||
</label>
|
||||
<ul tabindex="0"
|
||||
class="mt-1 text-xs text-white normal-case rounded min-w-max dropdown-content menu bg-coolgray-200">
|
||||
<li>
|
||||
<div class="hover:bg-coollabs" wire:click='deploy'>Deploy</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="hover:bg-coollabs" wire:click='deploy(true)'>Deploy without cache</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
<span wire:poll.5000ms='pollingStatus'>
|
||||
{{-- @if ($application->status === 'running')
|
||||
<span class="text-xs text-pink-600" wire:loading.delay.longer>Loading current status...</span>
|
||||
<span class="text-green-500" wire:loading.remove.delay.longer>{{ $application->status }}</span>
|
||||
@else
|
||||
<span class="text-xs text-pink-600" wire:loading.delay.longer>Loading current status...</span>
|
||||
<span class="text-red-500" wire:loading.remove.delay.longer>{{ $application->status }}</span>
|
||||
@endif --}}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
<div>
|
||||
<livewire:project.application.deployment-navbar :activity="$activity" :application="$application" :deployment_uuid="$deployment_uuid" />
|
||||
<h3 class="pb-0">Logs</h3>
|
||||
@if (data_get($activity, 'properties.status') === 'in_progress')
|
||||
<div class="pt-2 text-sm">Deployment is
|
||||
<span class="text-warning">{{ Str::headline(data_get($activity, 'properties.status')) }}</span>. Logs will
|
||||
be updated
|
||||
automatically.
|
||||
</div>
|
||||
@else
|
||||
<div class="pt-2 text-sm">Deployment is <span
|
||||
class="text-warning">{{ Str::headline(data_get($activity, 'properties.status')) }}</span>.</div>
|
||||
@endif
|
||||
<div
|
||||
class="scrollbar flex flex-col-reverse w-full overflow-y-auto border border-solid rounded border-coolgray-300 max-h-[32rem] p-4 mt-4 text-xs text-white">
|
||||
<pre class="font-mono whitespace-pre-wrap" @if ($isKeepAliveOn) wire:poll.2000ms="polling" @endif>{{ \App\Actions\CoolifyTask\RunRemoteProcess::decodeOutput($activity) }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,8 @@
|
||||
<div>
|
||||
<h3>Actions</h3>
|
||||
@if (data_get($activity, 'properties.status') === 'in_progress')
|
||||
<x-forms.button wire:click.prevent="cancel">Cancel deployment</x-forms.button>
|
||||
@else
|
||||
<x-forms.button disabled>Cancel deployment</x-forms.button>
|
||||
@endif
|
||||
</div>
|
||||
@@ -0,0 +1,95 @@
|
||||
<div class="flex flex-col gap-2" wire:init='load_deployments'
|
||||
@if ($skip == 0) wire:poll.5000ms='reload_deployments' @endif>
|
||||
<div>
|
||||
<h3>Actions</h3>
|
||||
@if ($show_next)
|
||||
<x-forms.button isHighlighted wire:click="load_deployments({{ $default_take }})">Load Previous
|
||||
Deployments</x-forms.button>
|
||||
@else
|
||||
<x-forms.button disabled>No More Deployments</x-forms.button>
|
||||
@endif
|
||||
</div>
|
||||
<h3>Deployments <span class="text-xs">({{ $deployments_count }})</span></h3>
|
||||
@foreach ($deployments as $deployment)
|
||||
<a @class([
|
||||
'bg-coolgray-200 p-2 border-l border-dashed transition-colors hover:no-underline',
|
||||
'cursor-not-allowed hover:bg-coolgray-200' =>
|
||||
data_get($deployment, 'status') === 'queued' ||
|
||||
data_get($deployment, 'status') === 'cancelled by system',
|
||||
'border-warning hover:bg-warning hover:text-black' =>
|
||||
data_get($deployment, 'status') === 'in_progress',
|
||||
'border-error hover:bg-error' =>
|
||||
data_get($deployment, 'status') === 'error',
|
||||
'border-success hover:bg-success' =>
|
||||
data_get($deployment, 'status') === 'finished',
|
||||
]) @if (data_get($deployment, 'status') !== 'cancelled by system' && data_get($deployment, 'status') !== 'queued')
|
||||
href="{{ $current_url . '/' . data_get($deployment, 'deployment_uuid') }}"
|
||||
@endif
|
||||
class="hover:no-underline">
|
||||
<div class="flex flex-col justify-start">
|
||||
<div>
|
||||
{{ $deployment->id }} <span class="text-sm text-warning">></span> {{ $deployment->deployment_uuid }} <span
|
||||
class="text-sm text-warning">></span>
|
||||
{{ $deployment->status }}
|
||||
</div>
|
||||
@if (data_get($deployment, 'pull_request_id'))
|
||||
<div>
|
||||
Pull Request #{{ data_get($deployment, 'pull_request_id') }}
|
||||
@if (data_get($deployment, 'is_webhook'))
|
||||
(Webhook)
|
||||
@endif
|
||||
</div>
|
||||
@elseif (data_get($deployment, 'is_webhook'))
|
||||
<div>Webhook (sha
|
||||
@if (data_get($deployment, 'commit'))
|
||||
{{ data_get($deployment, 'commit') }})
|
||||
@else
|
||||
HEAD)
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
<div class="flex flex-col" x-data="elapsedTime('{{ $deployment->deployment_uuid }}', '{{ $deployment->status }}', '{{ $deployment->created_at }}', '{{ $deployment->updated_at }}')">
|
||||
<div>Finished <span x-text="measure_since_started()">0s</span> in <span class="font-bold"
|
||||
x-text="measure_finished_time()">0s</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
@endforeach
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/dayjs@1/dayjs.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/dayjs@1/plugin/utc.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/dayjs@1/plugin/relativeTime.js"></script>
|
||||
<script>
|
||||
document.addEventListener('alpine:init', () => {
|
||||
let timers = {};
|
||||
|
||||
dayjs.extend(window.dayjs_plugin_utc);
|
||||
dayjs.extend(window.dayjs_plugin_relativeTime);
|
||||
|
||||
Alpine.data('elapsedTime', (uuid, status, created_at, updated_at) => ({
|
||||
finished_time: '0s',
|
||||
started_time: '0s',
|
||||
init() {
|
||||
if (timers[uuid]) {
|
||||
clearInterval(timers[uuid]);
|
||||
}
|
||||
if (status === 'in_progress') {
|
||||
timers[uuid] = setInterval(() => {
|
||||
this.finished_time = dayjs().diff(dayjs.utc(created_at),
|
||||
'second') + 's'
|
||||
}, 1000);
|
||||
} else {
|
||||
let seconds = dayjs.utc(updated_at).diff(dayjs.utc(created_at), 'second')
|
||||
this.finished_time = seconds + 's';
|
||||
}
|
||||
},
|
||||
measure_finished_time() {
|
||||
return this.finished_time;
|
||||
},
|
||||
measure_since_started() {
|
||||
return dayjs.utc(created_at).fromNow();
|
||||
}
|
||||
}))
|
||||
})
|
||||
</script>
|
||||
</div>
|
||||
@@ -1,8 +1,8 @@
|
||||
<div>
|
||||
<h2>Destination</h2>
|
||||
<p>Server Name: {{ data_get($destination, 'server.name') }}</p>
|
||||
@if (data_get($destination, 'server.description'))
|
||||
<p>Description: {{ data_get($destination, 'server.description') }}</p>
|
||||
@endif
|
||||
<p>Docker Network: {{ $destination->network }}</p>
|
||||
<h2 class="pb-0">Destination</h2>
|
||||
<div class="text-sm">The destination server / network where your application will be deployed to.</div>
|
||||
<div class="py-4">
|
||||
<p>Server: {{ data_get($destination, 'server.name') }}</p>
|
||||
<p>Destination: {{ $destination->network }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<form wire:submit.prevent='submit' class="flex flex-col px-2 max-w-fit">
|
||||
<form wire:submit.prevent='submit' class="flex flex-col max-w-fit">
|
||||
<div class="flex gap-2">
|
||||
<x-inputs.input placeholder="NODE_ENV" noDirty id="key" label="Name" required />
|
||||
<x-inputs.input placeholder="production" noDirty id="value" label="Value" required />
|
||||
<x-inputs.checkbox noDirty class="flex-col items-center" id="is_build_time" label="Build Variable?" />
|
||||
<x-forms.input placeholder="NODE_ENV" noDirty id="key" label="Name" required />
|
||||
<x-forms.input placeholder="production" noDirty id="value" label="Value" required />
|
||||
<x-forms.checkbox noDirty class="flex-col items-center" id="is_build_time" label="Build Variable?" />
|
||||
</div>
|
||||
<div class="pt-2">
|
||||
<x-inputs.button type="submit">
|
||||
<x-forms.button type="submit">
|
||||
Add
|
||||
</x-inputs.button>
|
||||
</x-forms.button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
<div class="flex flex-col gap-2">
|
||||
<h2>Environment Variables</h2>
|
||||
<div>
|
||||
<h2 class="pb-0">Environment Variables</h2>
|
||||
<div class="text-sm">Environment (secrets) configuration. You can set variables for your Preview Deployments as
|
||||
well
|
||||
here.</div>
|
||||
</div>
|
||||
@forelse ($application->environment_variables as $env)
|
||||
<livewire:project.application.environment-variable.show wire:key="environment-{{ $env->id }}"
|
||||
:env="$env" />
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
<div x-data="{ deleteEnvironment: false }">
|
||||
<form wire:submit.prevent='submit' class="flex flex-col px-2 max-w-fit">
|
||||
<form wire:submit.prevent='submit' class="flex flex-col max-w-fit">
|
||||
<div class="flex gap-2">
|
||||
<x-inputs.input label="Name" id="env.key" />
|
||||
<x-inputs.input label="Value" id="env.value" />
|
||||
<x-inputs.checkbox disabled class="flex-col items-center" id="env.is_build_time" label="Build Variable?" />
|
||||
<x-forms.input label="Name" id="env.key" />
|
||||
<x-forms.input label="Value" id="env.value" />
|
||||
<x-forms.checkbox disabled class="flex-col items-center" id="env.is_build_time" label="Build Variable?" />
|
||||
</div>
|
||||
<div class="pt-2">
|
||||
<x-inputs.button type="submit">
|
||||
<x-forms.button type="submit">
|
||||
Update
|
||||
</x-inputs.button>
|
||||
<x-inputs.button x-on:click.prevent="deleteEnvironment = true">
|
||||
</x-forms.button>
|
||||
<x-forms.button x-on:click.prevent="deleteEnvironment = true">
|
||||
Delete
|
||||
</x-inputs.button>
|
||||
</x-forms.button>
|
||||
</div>
|
||||
</form>
|
||||
<x-naked-modal show="deleteEnvironment" message="Are you sure you want to delete {{ $env->key }}?" />
|
||||
|
||||
@@ -1,66 +1,91 @@
|
||||
<div>
|
||||
<form wire:submit.prevent='submit' class="flex flex-col">
|
||||
<div class="flex gap-2">
|
||||
<h2>General</h2>
|
||||
<x-inputs.button type="submit">
|
||||
<h2 class="pb-0">General</h2>
|
||||
<x-forms.button type="submit">
|
||||
Save
|
||||
</x-inputs.button>
|
||||
</x-forms.button>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2 pb-4">
|
||||
<div class="flex flex-col gap-2 xl:flex-row">
|
||||
<x-inputs.input class="w-full" id="application.name" label="Name" required />
|
||||
<x-inputs.input placeholder="https://coolify.io" class="w-full" id="application.fqdn" label="Domains"
|
||||
helper="You can specify one domain with path or more with comma.<br><span class='inline-block font-bold text-warning'>Example</span>- http://app.coolify.io, https://cloud.coolify.io/dashboard<br>- http://app.coolify.io/api/v3" />
|
||||
<div class="text-sm">General configuration for your application.</div>
|
||||
<div class="flex flex-col gap-2 py-4">
|
||||
<div class="flex flex-col items-end gap-2 xl:flex-row">
|
||||
<x-forms.input class="w-full" id="application.name" label="Name" required />
|
||||
<x-forms.input placeholder="https://coolify.io" class="w-full" id="application.fqdn" label="Domains"
|
||||
helper="You can specify one domain with path or more with comma.<br><span class='text-helper'>Example</span>- http://app.coolify.io, https://cloud.coolify.io/dashboard<br>- http://app.coolify.io/api/v3" />
|
||||
|
||||
</div>
|
||||
<x-inputs.select id="application.build_pack" label="Build Pack" required>
|
||||
@if ($wildcard_domain)
|
||||
<div class="pb-6">
|
||||
<div class="text-sm">Set Random Domain</div>
|
||||
@if ($global_wildcard_domain)
|
||||
<x-forms.button isHighlighted wire:click="generateGlobalRandomDomain">Global Wildcard
|
||||
</x-forms.button>
|
||||
@endif
|
||||
@if ($project_wildcard_domain)
|
||||
<x-forms.button isHighlighted wire:click="generateProjectRandomDomain">Project Wildcard
|
||||
</x-forms.button>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
<x-forms.select id="application.build_pack" label="Build Pack" required>
|
||||
<option value="nixpacks">Nixpacks</option>
|
||||
<option disabled value="docker">Docker</option>
|
||||
<option disabled value="compose">Compose</option>
|
||||
</x-inputs.select>
|
||||
</x-forms.select>
|
||||
<x-forms.checkbox instantSave id="is_static" label="Static website?" />
|
||||
@if ($application->settings->is_static)
|
||||
<x-inputs.select id="application.static_image" label="Static Image" required>
|
||||
<x-forms.select id="application.static_image" label="Static Image" required>
|
||||
<option value="nginx:alpine">nginx:alpine</option>
|
||||
<option disabled value="apache:alpine">apache:alpine</option>
|
||||
</x-inputs.select>
|
||||
</x-forms.select>
|
||||
@endif
|
||||
<h3>Build</h3>
|
||||
<div class="flex flex-col gap-2 xl:flex-row">
|
||||
<x-inputs.input placeholder="pnpm install" id="application.install_command" label="Install Command" />
|
||||
<x-inputs.input placeholder="pnpm build" id="application.build_command" label="Build Command" />
|
||||
<x-inputs.input placeholder="pnpm start" id="application.start_command" label="Start Command" />
|
||||
<x-forms.input placeholder="pnpm install" id="application.install_command" label="Install Command" />
|
||||
<x-forms.input placeholder="pnpm build" id="application.build_command" label="Build Command" />
|
||||
<x-forms.input placeholder="pnpm start" id="application.start_command" label="Start Command" />
|
||||
</div>
|
||||
<div class="flex flex-col gap-2 xl:flex-row">
|
||||
<x-inputs.input placeholder="/" id="application.base_directory" label="Base Directory"
|
||||
<x-forms.input placeholder="/" id="application.base_directory" label="Base Directory"
|
||||
helper="Directory to use as root. Useful for monorepos." />
|
||||
@if ($application->settings->is_static)
|
||||
<x-inputs.input placeholder="/dist" id="application.publish_directory" label="Publish Directory"
|
||||
<x-forms.input placeholder="/dist" id="application.publish_directory" label="Publish Directory"
|
||||
required />
|
||||
@else
|
||||
<x-inputs.input placeholder="/" id="application.publish_directory" label="Publish Directory" />
|
||||
<x-forms.input placeholder="/" id="application.publish_directory" label="Publish Directory" />
|
||||
@endif
|
||||
</div>
|
||||
<h3>Network</h3>
|
||||
<div class="flex flex-col gap-2 xl:flex-row">
|
||||
@if ($application->settings->is_static)
|
||||
<x-inputs.input id="application.ports_exposes" label="Ports Exposes" readonly />
|
||||
<x-forms.input id="application.ports_exposes" label="Ports Exposes" readonly />
|
||||
@else
|
||||
<x-inputs.input placeholder="3000,3001" id="application.ports_exposes" label="Ports Exposes"
|
||||
required helper="A comma separated list of ports you would like to expose for the proxy." />
|
||||
<x-forms.input placeholder="3000,3001" id="application.ports_exposes" label="Ports Exposes" required
|
||||
helper="A comma separated list of ports you would like to expose for the proxy." />
|
||||
@endif
|
||||
<x-inputs.input placeholder="3000:3000" id="application.ports_mappings" label="Ports Mappings"
|
||||
<x-forms.input placeholder="3000:3000" id="application.ports_mappings" label="Ports Mappings"
|
||||
helper="A comma separated list of ports you would like to map to the host system. Useful when you do not want to use domains.<br><span class='inline-block font-bold text-warning'>Example</span>3000:3000,3002:3002" />
|
||||
</div>
|
||||
</div>
|
||||
<h3>Advanced</h3>
|
||||
<div class="flex flex-col">
|
||||
<x-inputs.checkbox helper="More logs will be visible during a deployment." instantSave id="is_debug"
|
||||
<x-forms.checkbox helper="More logs will be visible during a deployment." instantSave id="is_debug_enabled"
|
||||
label="Debug" />
|
||||
<x-inputs.checkbox instantSave id="is_static" label="Static website?" />
|
||||
<x-inputs.checkbox helper="Git Webhooks won't deploy your application is you turn it off." instantSave
|
||||
id="is_auto_deploy" label="Auto Deploy?" />
|
||||
<x-inputs.checkbox helper="Preview deployments" instantSave id="is_previews" label="Previews?" />
|
||||
<x-inputs.checkbox instantSave id="is_git_submodules_allowed" label="Git Submodules Allowed?" />
|
||||
<x-inputs.checkbox instantSave id="is_git_lfs_allowed" label="Git LFS Allowed?" />
|
||||
{{-- <x-inputs.checkbox disabled instantSave id="is_dual_cert" label="Dual Certs?" />
|
||||
<x-inputs.checkbox disabled instantSave id="is_custom_ssl" label="Is Custom SSL?" />
|
||||
<x-inputs.checkbox disabled instantSave id="is_http2" label="Is Http2?" /> --}}
|
||||
<x-forms.checkbox
|
||||
helper="Your application will be available only on https if your domain starts with https://..."
|
||||
instantSave id="is_force_https_enabled" label="Force Https" />
|
||||
<x-forms.checkbox helper="Automatically deploy new commits based on Git webhooks." instantSave
|
||||
id="is_auto_deploy_enabled" label="Auto Deploy" />
|
||||
<x-forms.checkbox
|
||||
helper="Automatically deploy Preview Deployments for all opened PR's. Closed PRs deletes Preview Deployments."
|
||||
instantSave id="is_preview_deployments_enabled" label="Auto Previews Deployments" />
|
||||
<x-forms.checkbox instantSave id="is_git_submodules_enabled" label="Git Submodules"
|
||||
helper="Allow Git Submodules during build process." />
|
||||
<x-forms.checkbox instantSave id="is_git_lfs_enabled" label="Git LFS"
|
||||
helper="Allow Git LFS during build process." />
|
||||
{{-- <x-forms.checkbox disabled instantSave id="is_dual_cert" label="Dual Certs?" />
|
||||
<x-forms.checkbox disabled instantSave id="is_custom_ssl" label="Is Custom SSL?" />
|
||||
<x-forms.checkbox disabled instantSave id="is_http2" label="Is Http2?" /> --}}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
<div>
|
||||
<a @if ($status === 'in_progress' || $status === 'queued') wire:poll='polling' @endif href="{{ url()->current() }}/{{ $deployment_uuid }}">
|
||||
{{ $created_at }}
|
||||
{{ $deployment_uuid }}</a>
|
||||
{{ $status }}
|
||||
</div>
|
||||
@@ -1,4 +0,0 @@
|
||||
<div
|
||||
class="flex flex-col-reverse w-full overflow-y-auto border border-solid rounded border-coolgray-300 max-h-[32rem] p-4">
|
||||
<pre @if ($isKeepAliveOn) wire:poll.750ms="polling" @endif>{{ \App\Actions\CoolifyTask\RunRemoteProcess::decodeOutput($activity) }}</pre>
|
||||
</div>
|
||||
@@ -0,0 +1,13 @@
|
||||
<form wire:submit.prevent='submit'>
|
||||
<div class="flex gap-2">
|
||||
<h2 class="pb-0">Previews Deployments</h2>
|
||||
<x-forms.button type="submit">Save</x-forms.button>
|
||||
<x-forms.button wire:click="resetToDefault">Reset to default</x-forms.button>
|
||||
</div>
|
||||
<div class="pb-4 text-sm">Preview Deployments based on pull requests are here.</div>
|
||||
<div class="flex flex-col gap-2 pb-4">
|
||||
<x-forms.input id="application.preview_url_template" label="Preview URL Template"
|
||||
helper="Templates:<span class='text-helper'>@@{{ random }}</span> to generate random sub-domain each time a PR is deployed, <span class='text-helper'>@@{{ pr_id }}</span> to use pull request ID as sub-domain or <span class='text-helper'>@@{{ domain }}</span> to replace the domain name with the application's domain name." />
|
||||
<div class="text-sm">Domain Preview: {{ $preview_url_template }}</div>
|
||||
</div>
|
||||
</form>
|
||||
@@ -1,8 +1,67 @@
|
||||
<div>
|
||||
<h2>Previews</h2>
|
||||
<div class="flex gap-2">
|
||||
@foreach ($application->previews as $preview)
|
||||
<div class="box">{{ $preview['pullRequestId'] }} | {{ $preview['branch'] }}</div>
|
||||
@endforeach
|
||||
<livewire:project.application.preview.form :application="$application" />
|
||||
<h3>Pull Requests on Git</h3>
|
||||
<div>
|
||||
<x-forms.button wire:click="load_prs">Load Opened Pull Requests
|
||||
</x-forms.button>
|
||||
@isset($rate_limit_remaining)
|
||||
<div class="pt-1 text-sm">Requests remaning till rate limited by Git: {{ $rate_limit_remaining }}</div>
|
||||
@endisset
|
||||
@if (count($pull_requests) > 0)
|
||||
<div wire:loading.remove wire:target='load_prs' class="flex gap-4 py-8">
|
||||
@foreach ($pull_requests as $pull_request)
|
||||
<div class="flex flex-col gap-4 p-4 text-sm bg-coolgray-200 hover:bg-coolgray-300">
|
||||
<div class="text-base font-bold text-white">PR #{{ data_get($pull_request, 'number') }} |
|
||||
{{ data_get($pull_request, 'title') }}</div>
|
||||
<div class="flex items-center justify-start gap-2">
|
||||
<x-forms.button isHighlighted
|
||||
wire:click="deploy('{{ data_get($pull_request, 'number') }}', '{{ data_get($pull_request, 'html_url') }}')">
|
||||
Deploy
|
||||
</x-forms.button>
|
||||
<a target="_blank" class="text-xs" href="{{ data_get($pull_request, 'html_url') }}">Open PR
|
||||
on
|
||||
Git
|
||||
<x-external-link />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@if ($application->previews->count() > 0)
|
||||
<h3>Preview Deployments</h3>
|
||||
<div class="flex gap-6 text-sm">
|
||||
@foreach ($application->previews as $preview)
|
||||
<div class="flex flex-col p-4 bg-coolgray-200 " x-init="$wire.loadStatus('{{ data_get($preview, 'pull_request_id') }}')">
|
||||
<div>PR #{{ data_get($preview, 'pull_request_id') }} | {{ data_get($preview, 'status') }}
|
||||
@if (data_get($preview, 'status') !== 'exited')
|
||||
| <a target="_blank" href="{{ data_get($preview, 'fqdn') }}">Open Preview
|
||||
<x-external-link />
|
||||
</a>
|
||||
@endif
|
||||
|
|
||||
<a target="_blank" href="{{ data_get($preview, 'pull_request_html_url') }}">Open PR on Git
|
||||
<x-external-link />
|
||||
</a>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 pt-6">
|
||||
<x-forms.button isHighlighted wire:click="deploy({{ data_get($preview, 'pull_request_id') }})">
|
||||
@if (data_get($preview, 'status') === 'exited')
|
||||
Deploy
|
||||
@else
|
||||
Redeploy
|
||||
@endif
|
||||
</x-forms.button>
|
||||
@if (data_get($preview, 'status') !== 'exited')
|
||||
<x-forms.button wire:click="stop({{ data_get($preview, 'pull_request_id') }})">Remove
|
||||
Preview
|
||||
</x-forms.button>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
<div>
|
||||
<form wire:submit.prevent='submit' class="flex flex-col">
|
||||
<div class="flex gap-2">
|
||||
<h2>Resource Limits</h2>
|
||||
<x-inputs.button type='submit'>Save</x-inputs.button>
|
||||
<h2 class="pb-0">Resource Limits</h2>
|
||||
<x-forms.button type='submit'>Save</x-forms.button>
|
||||
</div>
|
||||
<div>Limit your container resources by CPU & memory.</div>
|
||||
<h3>CPU</h3>
|
||||
<x-inputs.input placeholder="1.5" label="Number of CPUs" id="application.limits_cpus" />
|
||||
<x-inputs.input placeholder="0-2" label="CPU set to use" id="application.limits_cpuset" />
|
||||
<x-inputs.input placeholder="1024" label="CPU Weight" id="application.limits_cpu_shares" />
|
||||
<h3>Memory</h3>
|
||||
<x-inputs.input placeholder="69b or 420k or 1337m or 1g" label="Limit" id="application.limits_memory" />
|
||||
<x-inputs.input placeholder="69b or 420k or 1337m or 1g" label="Swap" id="application.limits_memory_swap" />
|
||||
<x-inputs.input placeholder="0-100" type="number" min="0" max="100" label="Swappiness"
|
||||
id="application.limits_memory_swappiness" />
|
||||
<x-inputs.input placeholder="69b or 420k or 1337m or 1g" label="Soft Limit"
|
||||
<div class="text-sm">Limit your container resources by CPU & memory.</div>
|
||||
<h3>Limit CPUs</h3>
|
||||
<x-forms.input placeholder="1.5" label="Number of CPUs" id="application.limits_cpus" />
|
||||
<x-forms.input placeholder="0-2" label="CPU sets to use" id="application.limits_cpuset" />
|
||||
<x-forms.input placeholder="1024" label="CPU Weight" id="application.limits_cpu_shares" />
|
||||
<h3>Limit Memory</h3>
|
||||
<x-forms.input placeholder="69b or 420k or 1337m or 1g" label="Soft Memory Limit"
|
||||
id="application.limits_memory_reservation" />
|
||||
<x-inputs.checkbox label="Disable OOM kill" id="application.limits_memory_oom_kill" />
|
||||
<x-forms.input placeholder="69b or 420k or 1337m or 1g" label="Maximum Memory Limit"
|
||||
id="application.limits_memory" />
|
||||
<x-forms.input placeholder="69b or 420k or 1337m or 1g" label="Maximum Swap Limit"
|
||||
id="application.limits_memory_swap" />
|
||||
<x-forms.input placeholder="0-100" type="number" min="0" max="100" label="Swappiness"
|
||||
id="application.limits_memory_swappiness" />
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -1,31 +1,38 @@
|
||||
<div x-init="$wire.loadImages">
|
||||
<div class="flex gap-2">
|
||||
<h2>Rollback</h2>
|
||||
<x-inputs.button isHighlighted wire:click='loadImages'>Refresh</x-inputs.button>
|
||||
<h2 class="pb-0">Rollback</h2>
|
||||
<x-forms.button isHighlighted wire:click='loadImages'>Reload Available Images</x-forms.button>
|
||||
</div>
|
||||
<div class="pb-4 text-sm">You can easily rollback to a previously built image quickly.</div>
|
||||
<div wire:loading wire:target='loadImages'>
|
||||
<x-loading />
|
||||
</div>
|
||||
<div wire:loading.remove wire:target='loadImages'>
|
||||
<div class="flex flex-wrap">
|
||||
@forelse ($images as $image)
|
||||
<div class="w-1/2 p-2">
|
||||
<div class="rounded-lg shadow-lg bg-coolgray-200">
|
||||
<div class="w-2/4 p-2">
|
||||
<div class="rounded shadow-lg bg-coolgray-200">
|
||||
<div class="p-2">
|
||||
<div class="text-sm">
|
||||
@if (data_get($image, 'is_current'))
|
||||
<span class="font-bold text-coollabs">LIVE</span>
|
||||
<span class="font-bold text-warning">LIVE</span>
|
||||
|
|
||||
@endif
|
||||
{{ data_get($image, 'tag') }}
|
||||
SHA: {{ data_get($image, 'tag') }}
|
||||
</div>
|
||||
|
||||
<div class="text-xs">{{ data_get($image, 'created_at') }}</div>
|
||||
</div>
|
||||
<div class="flex justify-end p-2">
|
||||
<x-inputs.button wire:click="revertImage('{{ data_get($image, 'tag') }}')">
|
||||
Revert
|
||||
</x-inputs.button>
|
||||
@if (data_get($image, 'is_current'))
|
||||
<x-forms.button disabled tooltip="This image is currently running.">
|
||||
Rollback
|
||||
</x-forms.button>
|
||||
@else
|
||||
<x-forms.button isHighlighted
|
||||
wire:click="rollbackImage('{{ data_get($image, 'tag') }}')">
|
||||
Rollback
|
||||
</x-forms.button>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,22 +1,25 @@
|
||||
<div>
|
||||
<form wire:submit.prevent='submit' class="flex flex-col gap-2">
|
||||
<div class="flex gap-4">
|
||||
<h2>Source</h2>
|
||||
<x-inputs.button type="submit">Save</x-inputs.button>
|
||||
<a target="_blank" href="{{ $application->gitCommits }}">
|
||||
Commits
|
||||
<x-external-link />
|
||||
<form wire:submit.prevent='submit' class="flex flex-col">
|
||||
<div class="flex items-center gap-2">
|
||||
<h2 class="pb-0">Source</h2>
|
||||
<x-forms.button type="submit">Save</x-forms.button>
|
||||
</div>
|
||||
<div class="text-sm">Code source of your application.</div>
|
||||
<div class="py-4 ">
|
||||
<a target="_blank" class="hover:no-underline" href="{{ $application->gitCommits }}">
|
||||
<x-forms.button>Open Commits on Git
|
||||
<x-external-link />
|
||||
</x-forms.button>
|
||||
</a>
|
||||
<a target="_blank" class="hover:no-underline" href="{{ $application->gitBranchLocation }}">
|
||||
<x-forms.button>Open Repository on Git
|
||||
<x-external-link />
|
||||
</x-forms.button>
|
||||
</a>
|
||||
</div>
|
||||
{{-- <div>{{ data_get($application, 'source.name') }}
|
||||
@if (data_get($application, 'source.is_public'))
|
||||
<span class="text-xs">public</span>
|
||||
@endif
|
||||
</div> --}}
|
||||
<x-inputs.input placeholder="coollabsio/coolify-example" id="application.git_repository" label="Repository" />
|
||||
<x-inputs.input placeholder="main" id="application.git_branch" label=" Branch" />
|
||||
<x-inputs.input placeholder="HEAD" id="application.git_commit_sha" placeholder="HEAD" label="Commit SHA" />
|
||||
<x-forms.input placeholder="coollabsio/coolify-example" id="application.git_repository" label="Repository" />
|
||||
<x-forms.input placeholder="main" id="application.git_branch" label=" Branch" />
|
||||
<x-forms.input placeholder="HEAD" id="application.git_commit_sha" placeholder="HEAD" label="Commit SHA" />
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<div wire:poll.5000ms='applicationStatusChanged'>
|
||||
@if ($application->status === 'running')
|
||||
<span class="text-xs text-pink-600" wire:loading.delay.longer>Loading current status...</span>
|
||||
<div class="flex items-center gap-2 text-sm" wire:loading.remove.delay.longer>
|
||||
<span class="flex w-3 h-3 rounded-full bg-success"></span>
|
||||
<span class="text-green-500">Running</span>
|
||||
</div>
|
||||
@else
|
||||
<span class="text-xs text-pink-600" wire:loading.delay.longer>Loading current status...</span>
|
||||
<div class="flex items-center gap-2 text-sm" wire:loading.remove.delay.longer>
|
||||
<span class="flex w-3 h-3 rounded-full bg-error"></span>
|
||||
<span class="text-error">Stopped</span>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@@ -1,12 +1,10 @@
|
||||
<form wire:submit.prevent='submit' class="flex flex-col px-2 pt-10 max-w-fit">
|
||||
<div class="flex gap-2">
|
||||
<x-inputs.input placeholder="pv-name" noDirty id="name" label="Name" required />
|
||||
<x-inputs.input placeholder="/root" noDirty id="host_path" label="Source Path" />
|
||||
<x-inputs.input placeholder="/tmp/root" noDirty id="mount_path" label="Destination Path" required />
|
||||
</div>
|
||||
<div class="pt-2">
|
||||
<x-inputs.button type="submit">
|
||||
<div class="flex items-end gap-2">
|
||||
<x-forms.input placeholder="pv-name" noDirty id="name" label="Name" required />
|
||||
<x-forms.input placeholder="/root" noDirty id="host_path" label="Source Path" />
|
||||
<x-forms.input placeholder="/tmp/root" noDirty id="mount_path" label="Destination Path" required />
|
||||
<x-forms.button type="submit">
|
||||
Add
|
||||
</x-inputs.button>
|
||||
</x-forms.button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
<div class="flex flex-col gap-2">
|
||||
<h2>Storages</h2>
|
||||
@forelse ($application->persistentStorages as $storage)
|
||||
<livewire:project.application.storages.show wire:key="storage-{{ $storage->id }}" :storage="$storage" />
|
||||
@empty
|
||||
<p>There are no persistent storages attached for this application.</p>
|
||||
@endforelse
|
||||
<div>
|
||||
<h2 class="pb-0">Storages</h2>
|
||||
<div class="text-sm">Persistent storage to preserve data between deployments.</div>
|
||||
<div class="flex flex-col gap-2 py-4">
|
||||
@forelse ($application->persistentStorages as $storage)
|
||||
<livewire:project.application.storages.show wire:key="storage-{{ $storage->id }}" :storage="$storage" />
|
||||
@empty
|
||||
<p>There are no persistent storages attached for this application.</p>
|
||||
@endforelse
|
||||
</div>
|
||||
<livewire:project.application.storages.add />
|
||||
</div>
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
<div x-data="{ deleteStorage: false }">
|
||||
<form wire:submit.prevent='submit' class="flex flex-col px-2 max-w-fit">
|
||||
<div class="flex gap-2">
|
||||
<x-inputs.input id="storage.name" label="Name" required />
|
||||
<x-inputs.input id="storage.host_path" label="Source Path" />
|
||||
<x-inputs.input id="storage.mount_path" label="Destination Path" required />
|
||||
</div>
|
||||
<div class="pt-2">
|
||||
<x-inputs.button type="submit">
|
||||
<form wire:submit.prevent='submit' class="flex flex-col px-2">
|
||||
<div class="flex items-end gap-2">
|
||||
<x-forms.input id="storage.name" label="Name" required />
|
||||
<x-forms.input id="storage.host_path" label="Source Path" />
|
||||
<x-forms.input id="storage.mount_path" label="Destination Path" required />
|
||||
<x-forms.button type="submit">
|
||||
Update
|
||||
</x-inputs.button>
|
||||
<x-inputs.button x-on:click.prevent="deleteStorage = true">
|
||||
</x-forms.button>
|
||||
<x-forms.button x-on:click.prevent="deleteStorage = true">
|
||||
Delete
|
||||
</x-inputs.button>
|
||||
</x-forms.button>
|
||||
</div>
|
||||
</form>
|
||||
<x-naked-modal show="deleteStorage" message="Are you sure you want to delete {{ $storage->name }}?" />
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<div x-data="{ deleteEnvironment: false }">
|
||||
<x-naked-modal show="deleteEnvironment" message='Are you sure you would like to delete this environment?' />
|
||||
@if ($resource_count > 0)
|
||||
<x-forms.button tooltip="First delete all resources." disabled>
|
||||
Delete
|
||||
</x-forms.button>
|
||||
@else
|
||||
<x-forms.button x-on:click.prevent="deleteEnvironment = true">
|
||||
Delete
|
||||
</x-forms.button>
|
||||
@endif
|
||||
</div>
|
||||
@@ -1,13 +1,12 @@
|
||||
<div x-data="{ deleteProject: false }">
|
||||
<x-naked-modal show="deleteProject" message='Are you sure you would like to delete this project?' />
|
||||
@if ($resource_count > 0)
|
||||
<x-inputs.button disabled="First delete all resources.">
|
||||
<x-forms.button disabled="First delete all resources.">
|
||||
Delete
|
||||
</x-inputs.button>
|
||||
</x-forms.button>
|
||||
@else
|
||||
<x-inputs.button x-on:click.prevent="deleteProject = true">
|
||||
<x-forms.button x-on:click.prevent="deleteProject = true">
|
||||
Delete
|
||||
</x-inputs.button>
|
||||
</x-forms.button>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
@@ -1 +1 @@
|
||||
<x-inputs.button wire:click='createEmptyProject'>Empty Project</x-inputs.button>
|
||||
<x-forms.button wire:click='createEmptyProject'>Empty Project</x-forms.button>
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
<h1>Select a private key</h1>
|
||||
@foreach ($private_keys as $key)
|
||||
@if ($private_key_id == $key->id)
|
||||
<x-inputs.button class="bg-blue-500" wire:click.defer="setPrivateKey('{{ $key->id }}')">
|
||||
{{ $key->name }}</x-inputs.button>
|
||||
<x-forms.button class="bg-blue-500" wire:click.defer="setPrivateKey('{{ $key->id }}')">
|
||||
{{ $key->name }}</x-forms.button>
|
||||
@else
|
||||
<x-inputs.button wire:click.defer="setPrivateKey('{{ $key->id }}')">{{ $key->name }}
|
||||
</x-inputs.button>
|
||||
<x-forms.button wire:click.defer="setPrivateKey('{{ $key->id }}')">{{ $key->name }}
|
||||
</x-forms.button>
|
||||
@endif
|
||||
@endforeach
|
||||
</div>
|
||||
@@ -15,17 +15,17 @@
|
||||
<h1>Choose a repository</h1>
|
||||
<form wire:submit.prevent='submit'>
|
||||
<div class="flex items-end gap-2 pb-2">
|
||||
<x-inputs.input class="w-96" id="repository_url" label="Repository URL" />
|
||||
<x-forms.input class="w-96" id="repository_url" label="Repository URL" />
|
||||
@if ($is_static)
|
||||
<x-inputs.input id="publish_directory" label="Publish Directory" />
|
||||
<x-forms.input id="publish_directory" label="Publish Directory" />
|
||||
@else
|
||||
<x-inputs.input type="number" id="port" label="Port" :readonly="$is_static" />
|
||||
<x-forms.input type="number" id="port" label="Port" :readonly="$is_static" />
|
||||
@endif
|
||||
<x-inputs.input instantSave type="checkbox" id="is_static" label="Static Site?" />
|
||||
<x-forms.input instantSave type="checkbox" id="is_static" label="Static Site?" />
|
||||
</div>
|
||||
<x-inputs.button type="submit">
|
||||
<x-forms.button type="submit">
|
||||
Submit
|
||||
</x-inputs.button>
|
||||
</x-forms.button>
|
||||
</form>
|
||||
@endisset
|
||||
</div>
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
@if ($github_apps->count() > 0)
|
||||
<h1>Choose a GitHub App</h1>
|
||||
@foreach ($github_apps as $ghapp)
|
||||
<x-inputs.button wire:key="{{ $ghapp->id }}" wire:click="loadRepositories({{ $ghapp->id }})">
|
||||
<x-forms.button wire:key="{{ $ghapp->id }}" wire:click="loadRepositories({{ $ghapp->id }})">
|
||||
{{ $ghapp->name }}
|
||||
</x-inputs.button>
|
||||
</x-forms.button>
|
||||
@endforeach
|
||||
<div>
|
||||
@if ($repositories->count() > 0)
|
||||
@@ -18,7 +18,7 @@
|
||||
@endif
|
||||
@endforeach
|
||||
</select>
|
||||
<x-inputs.button wire:click="loadBranches">Select Repository</x-inputs.button>
|
||||
<x-forms.button wire:click="loadBranches">Select Repository</x-forms.button>
|
||||
@endif
|
||||
</div>
|
||||
<div>
|
||||
@@ -35,7 +35,7 @@
|
||||
@endif
|
||||
@endforeach
|
||||
</select>
|
||||
<x-inputs.button wire:click="submit">Save</x-inputs.button>
|
||||
<x-forms.button wire:click="submit">Save</x-forms.button>
|
||||
@endif
|
||||
</div>
|
||||
@else
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
<div>
|
||||
<h1>Enter a public repository URL</h1>
|
||||
<form class="flex flex-col gap-2" wire:submit.prevent='submit'>
|
||||
<x-inputs.checkbox instantSave id="is_static" label="Is it a static site?" />
|
||||
<x-forms.checkbox instantSave id="is_static" label="Is it a static site?" />
|
||||
<div class="flex gap-2">
|
||||
<x-inputs.input id="repository_url" label="Repository URL"
|
||||
helper="<span class='inline-block font-bold text-warning'>Example</span>https://github.com/coollabsio/coolify-examples => main branch will be selected<br>https://github.com/coollabsio/coolify-examples/tree/nodejs-fastify => nodejs-fastify branch will be selected" />
|
||||
<x-forms.input id="repository_url" label="Repository URL"
|
||||
helper="<span class='text-helper'>Example</span>https://github.com/coollabsio/coolify-examples => main branch will be selected<br>https://github.com/coollabsio/coolify-examples/tree/nodejs-fastify => nodejs-fastify branch will be selected" />
|
||||
@if ($is_static)
|
||||
<x-inputs.input id="publish_directory" label="Publish Directory"
|
||||
<x-forms.input id="publish_directory" label="Publish Directory"
|
||||
helper="If there is a build process involved (like Svelte, React, Next, etc..), please specify the output directory for the build assets." />
|
||||
@else
|
||||
<x-inputs.input type="number" id="port" label="Port" :readonly="$is_static"
|
||||
<x-forms.input type="number" id="port" label="Port" :readonly="$is_static"
|
||||
helper="The port your application listens on." />
|
||||
@endif
|
||||
</div>
|
||||
<x-inputs.button type="submit">
|
||||
<x-forms.button type="submit">
|
||||
Submit
|
||||
</x-inputs.button>
|
||||
</x-forms.button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<div>
|
||||
<h1 class="pb-2">Command Center</h1>
|
||||
<div class="pb-4 text-sm">Outputs are not saved at the moment, only available until you refresh or navigate.</div>
|
||||
<form class="flex items-end justify-center gap-2" wire:submit.prevent='runCommand'>
|
||||
<x-inputs.input placeholder="ls -l" autofocus noDirty noLabel id="command" label="Command" required />
|
||||
<select wire:model.defer="server">
|
||||
<x-forms.input placeholder="ls -l" autofocus noDirty id="command" label="Command" required />
|
||||
<x-forms.select label="Server" id="server" required>
|
||||
@foreach ($servers as $server)
|
||||
@if ($loop->first)
|
||||
<option selected value="{{ $server->uuid }}">{{ $server->name }}</option>
|
||||
@@ -9,8 +11,8 @@
|
||||
<option value="{{ $server->uuid }}">{{ $server->name }}</option>
|
||||
@endif
|
||||
@endforeach
|
||||
</select>
|
||||
<x-inputs.button class="btn-xl" type="submit">Run</x-inputs.button>
|
||||
</x-forms.select>
|
||||
<x-forms.button class="btn-xl" type="submit">Run</x-forms.button>
|
||||
</form>
|
||||
<div class="container w-full pt-10 mx-auto">
|
||||
<livewire:activity-monitor />
|
||||
|
||||
@@ -1,44 +1,54 @@
|
||||
<div x-data="{ deleteServer: false }">
|
||||
<h2>General</h2>
|
||||
<x-naked-modal show="deleteServer" message='Are you sure you would like to delete this server?' />
|
||||
<form wire:submit.prevent='submit' class="flex flex-col">
|
||||
<div class="flex gap-2">
|
||||
<h2>General</h2>
|
||||
<x-forms.button type="submit">Save</x-forms.button>
|
||||
@if ($server_id !== 0)
|
||||
<x-forms.button x-on:click.prevent="deleteServer = true">
|
||||
Delete
|
||||
</x-forms.button>
|
||||
@endif
|
||||
</div>
|
||||
<div class="flex flex-col gap-2 xl:flex-row">
|
||||
<div class="flex flex-col w-96">
|
||||
<x-inputs.input id="server.name" label="Name" required />
|
||||
<x-inputs.input id="server.description" label="Description" />
|
||||
<x-inputs.checkbox disabled type="checkbox" id="server.settings.is_part_of_swarm"
|
||||
label="Is it part of a Swarm cluster?" />
|
||||
</div>
|
||||
<div class="flex flex-col w-96">
|
||||
@if ($server->id === 0)
|
||||
<x-inputs.input id="server.ip" label="IP Address" readonly />
|
||||
<x-inputs.input id="server.user" label="User" readonly />
|
||||
<x-inputs.input type="number" id="server.port" label="Port" readonly />
|
||||
<x-forms.input id="server.name" label="Name" readonly required />
|
||||
<x-forms.input id="server.description" label="Description" readonly />
|
||||
@else
|
||||
<x-inputs.input id="server.ip" label="IP Address" required readonly />
|
||||
<x-inputs.input id="server.user" label="User" required />
|
||||
<x-inputs.input type="number" id="server.port" label="Port" required />
|
||||
<x-forms.input id="server.name" label="Name" required />
|
||||
<x-forms.input id="server.description" label="Description" />
|
||||
@endif
|
||||
|
||||
{{-- <x-forms.checkbox disabled type="checkbox" id="server.settings.is_part_of_swarm"
|
||||
label="Is it part of a Swarm cluster?" /> --}}
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
@if ($server->id === 0)
|
||||
<x-forms.input id="server.ip" label="IP Address" readonly required />
|
||||
<x-forms.input id="server.user" label="User" readonly required />
|
||||
<x-forms.input type="number" id="server.port" label="Port" readonly required />
|
||||
@else
|
||||
<x-forms.input id="server.ip" label="IP Address" readonly required />
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input id="server.user" label="User" required />
|
||||
<x-forms.input type="number" id="server.port" label="Port" required />
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>Quick Actions</h3>
|
||||
<div class="flex items-center gap-2">
|
||||
<x-inputs.button type="submit">Save</x-inputs.button>
|
||||
|
||||
<x-inputs.button wire:click.prevent='validateServer'>
|
||||
<x-forms.button wire:click.prevent='validateServer'>
|
||||
@if ($server->settings->is_validated)
|
||||
Check Connection
|
||||
@else
|
||||
Validate Server
|
||||
@endif
|
||||
</x-inputs.button>
|
||||
|
||||
{{-- <x-inputs.button wire:click.prevent='installDocker'>Install Docker</x-inputs.button> --}}
|
||||
<x-inputs.button x-on:click.prevent="deleteServer = true">
|
||||
Delete
|
||||
</x-inputs.button>
|
||||
</x-forms.button>
|
||||
{{-- <x-forms.button wire:click.prevent='installDocker'>Install Docker</x-forms.button> --}}
|
||||
</div>
|
||||
<div class="pt-3">
|
||||
<div class="pt-3 text-sm">
|
||||
@isset($uptime)
|
||||
<p>Uptime: {{ $uptime }}</p>
|
||||
@endisset
|
||||
@@ -51,27 +61,25 @@
|
||||
</div>
|
||||
</form>
|
||||
<div class="flex items-center gap-2 py-4">
|
||||
<div class="font-bold">Private Key</div>
|
||||
<a class="px-2"
|
||||
href="{{ route('private-key.show', ['private_key_uuid' => data_get($server, 'privateKey.uuid')]) }}">
|
||||
{{ data_get($server, 'privateKey.uuid') }}
|
||||
</a>
|
||||
<h3>Private Key</h3>
|
||||
<a href="{{ route('server.private-key', ['server_uuid' => $server->uuid]) }}">
|
||||
<x-inputs.button>Change</x-inputs.button>
|
||||
<x-forms.button>Change</x-forms.button>
|
||||
</a>
|
||||
</div>
|
||||
<a href="{{ route('private-key.show', ['private_key_uuid' => data_get($server, 'privateKey.uuid')]) }}">
|
||||
<button class="text-white btn-link">{{ data_get($server, 'privateKey.name') }}</button>
|
||||
</a>
|
||||
<div class="flex items-center gap-2 py-4">
|
||||
<div class="font-bold">Destinations</div>
|
||||
<div>
|
||||
@foreach ($server->standaloneDockers as $docker)
|
||||
<a class="px-2"
|
||||
href="{{ route('destination.show', ['destination_uuid' => data_get($docker, 'uuid')]) }}">
|
||||
{{ data_get($docker, 'network') }}
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
<h3>Destinations</h3>
|
||||
<a href="{{ route('destination.new', ['server_id' => $server->id]) }}">
|
||||
<x-inputs.button>Add</x-inputs.button>
|
||||
<x-forms.button>Add</x-forms.button>
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
@foreach ($server->standaloneDockers as $docker)
|
||||
<a href="{{ route('destination.show', ['destination_uuid' => data_get($docker, 'uuid')]) }}">
|
||||
<button class="text-white btn-link">{{ data_get($docker, 'network') }}</button>
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
<div>
|
||||
<form class="flex flex-col gap-1" wire:submit.prevent='submit'>
|
||||
<h1>New Server</h1>
|
||||
<x-inputs.input id="name" label="Name" required />
|
||||
<x-inputs.input id="description" label="Description" />
|
||||
<x-inputs.input id="ip" label="IP Address" required />
|
||||
<x-inputs.input id="user" label="User" />
|
||||
<x-inputs.input type="number" id="port" label="Port" />
|
||||
<div class="flex items-center gap-2">
|
||||
<h1>New Server</h1>
|
||||
<x-forms.button type="submit">
|
||||
Save
|
||||
</x-forms.button>
|
||||
</div>
|
||||
<x-forms.input id="name" label="Name" required />
|
||||
<x-forms.input id="description" label="Description" />
|
||||
<x-forms.input id="ip" label="IP Address" required
|
||||
helper="Could be IP Address (127.0.0.1) or Domain Name (duckduckgo.com)." />
|
||||
<x-forms.input id="user" label="User" required />
|
||||
<x-forms.input type="number" id="port" label="Port" required />
|
||||
<label>Private Key</label>
|
||||
<x-inputs.select wire:model.defer="private_key_id">
|
||||
<x-forms.select wire:model.defer="private_key_id">
|
||||
<option disabled>Select a private key</option>
|
||||
@foreach ($private_keys as $key)
|
||||
@if ($loop->first)
|
||||
@@ -16,11 +22,8 @@
|
||||
<option value="{{ $key->id }}">{{ $key->name }}</option>
|
||||
@endif
|
||||
@endforeach
|
||||
</x-inputs.select>
|
||||
<x-inputs.input instantSave noDirty type="checkbox" id="is_part_of_swarm"
|
||||
label="Is it part of a Swarm cluster?" />
|
||||
<x-inputs.button type="submit">
|
||||
Save
|
||||
</x-inputs.button>
|
||||
</x-forms.select>
|
||||
<x-forms.checkbox instantSave noDirty id="is_part_of_swarm" label="Is it part of a Swarm cluster?" />
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
<div>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
@forelse ($private_keys as $private_key)
|
||||
<x-inputs.button wire:click='setPrivateKey({{ $private_key->id }})'>{{ $private_key->name }}</x-inputs.button>
|
||||
<div class="w-64 box">
|
||||
<button wire:click='setPrivateKey({{ $private_key->id }})'>{{ $private_key->name }}
|
||||
</button>
|
||||
</div>
|
||||
@empty
|
||||
<p>No private keys found</p>
|
||||
@endforelse
|
||||
|
||||
@@ -2,53 +2,61 @@
|
||||
<x-naked-modal show="stopProxy" action="stopProxy"
|
||||
message='Are you sure you would like to stop the proxy? All resources will be unavailable.' />
|
||||
@if ($server->settings->is_validated)
|
||||
<div class="flex items-center gap-2 mb-4">
|
||||
<h2>Proxy</h2>
|
||||
<div>{{ $server->extra_attributes->proxy_status }}</div>
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<h2 class="pb-0">Proxy</h2>
|
||||
@if ($server->extra_attributes->proxy_type)
|
||||
<x-forms.button isHighlighted wire:click.prevent="installProxy">
|
||||
Start/Reconfigure Proxy
|
||||
</x-forms.button>
|
||||
<x-forms.button x-on:click.prevent="stopProxy = true">Stop
|
||||
</x-forms.button>
|
||||
<div wire:poll.5000ms="proxyStatus">
|
||||
@if (
|
||||
$server->extra_attributes->last_applied_proxy_settings &&
|
||||
$server->extra_attributes->last_saved_proxy_settings !== $server->extra_attributes->last_applied_proxy_settings)
|
||||
<div class="text-red-500">Configuration out of sync.</div>
|
||||
@endif
|
||||
|
||||
|
||||
</div>
|
||||
@endif
|
||||
@if ($server->extra_attributes->proxy_status === 'running')
|
||||
<span class="text-xs text-pink-600" wire:loading.delay.longer>Loading current status...</span>
|
||||
<div class="flex items-center gap-2 text-sm" wire:loading.remove.delay.longer>
|
||||
<span class="flex w-3 h-3 rounded-full bg-success"></span>
|
||||
<span class="text-green-500">Running</span>
|
||||
</div>
|
||||
@else
|
||||
<span class="text-xs text-pink-600" wire:loading.delay.longer>Loading current status...</span>
|
||||
<div class="flex items-center gap-2 text-sm" wire:loading.remove.delay.longer>
|
||||
<span class="flex w-3 h-3 rounded-full bg-error"></span>
|
||||
<span class="text-error">Stopped</span>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<livewire:activity-monitor />
|
||||
@if ($server->extra_attributes->proxy_type)
|
||||
<div wire:poll="proxyStatus">
|
||||
@if (
|
||||
$server->extra_attributes->last_applied_proxy_settings &&
|
||||
$server->extra_attributes->last_saved_proxy_settings !== $server->extra_attributes->last_applied_proxy_settings)
|
||||
<div class="text-red-500">Configuration out of sync.</div>
|
||||
<x-inputs.button wire:click="installProxy">
|
||||
Reconfigure
|
||||
</x-inputs.button>
|
||||
@endif
|
||||
@if ($server->extra_attributes->proxy_status !== 'running')
|
||||
<x-inputs.button wire:click="installProxy">
|
||||
Start
|
||||
</x-inputs.button>
|
||||
@else
|
||||
<x-inputs.button x-on:click.prevent="stopProxy = true">Stop
|
||||
</x-inputs.button>
|
||||
@endif
|
||||
<div class="py-4">
|
||||
<livewire:activity-monitor />
|
||||
</div>
|
||||
<div x-init="$wire.checkProxySettingsInSync">
|
||||
<div wire:loading wire:target="checkProxySettingsInSync">
|
||||
<x-loading />
|
||||
</div>
|
||||
@isset($proxy_settings)
|
||||
<h3>Configuration</h3>
|
||||
@if ($selectedProxy->value === 'TRAEFIK_V2')
|
||||
<form wire:submit.prevent='saveConfiguration'>
|
||||
<div class="py-2 pb-8">
|
||||
<x-inputs.button type="submit">Save</x-inputs.button>
|
||||
<x-inputs.button wire:click.prevent="resetProxy">
|
||||
Reset Configuration
|
||||
</x-inputs.button>
|
||||
</div>
|
||||
<h4>traefik.conf</h4>
|
||||
<x-inputs.textarea noDirty name="proxy_settings" wire:model.defer="proxy_settings"
|
||||
rows="30" />
|
||||
</form>
|
||||
@endif
|
||||
@endisset
|
||||
<div x-init="$wire.checkProxySettingsInSync">
|
||||
<div wire:loading wire:target="checkProxySettingsInSync">
|
||||
<x-loading />
|
||||
</div>
|
||||
@isset($proxy_settings)
|
||||
@if ($selectedProxy->value === 'TRAEFIK_V2')
|
||||
<form wire:submit.prevent='saveConfiguration'>
|
||||
<div class="flex items-center gap-2">
|
||||
<h3>Configuration</h3>
|
||||
<x-forms.button type="submit">Save</x-forms.button>
|
||||
<x-forms.button wire:click.prevent="resetProxy">
|
||||
Reset Configuration
|
||||
</x-forms.button>
|
||||
</div>
|
||||
<h4>traefik.conf</h4>
|
||||
<x-forms.textarea class="text-xs" noDirty name="proxy_settings"
|
||||
wire:model.defer="proxy_settings" rows="30" />
|
||||
</form>
|
||||
@endif
|
||||
@endisset
|
||||
</div>
|
||||
@else
|
||||
<select wire:model="selectedProxy">
|
||||
@@ -56,10 +64,9 @@
|
||||
{{ \App\Enums\ProxyTypes::TRAEFIK_V2 }}
|
||||
</option>
|
||||
</select>
|
||||
<x-inputs.button wire:click="setProxy">Set Proxy</x-inputs.button>
|
||||
<x-forms.button wire:click="setProxy">Set Proxy</x-forms.button>
|
||||
@endif
|
||||
@else
|
||||
<p>Server is not validated. Validate first.</p>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
|
||||
@@ -1,23 +1,36 @@
|
||||
<div>
|
||||
<form wire:submit.prevent='submit' class="flex flex-col">
|
||||
<div class="flex flex-col gap-2 xl:flex-row">
|
||||
<div class="flex flex-col w-96">
|
||||
<x-inputs.input id="settings.fqdn" label="FQDN" />
|
||||
<x-inputs.input id="settings.wildcard_domain" label="Wildcard Domain" />
|
||||
<div class="flex gap-2">
|
||||
<h1 class="pb-2">Settings</h1>
|
||||
<x-forms.button type="submit">
|
||||
Save
|
||||
</x-forms.button>
|
||||
</div>
|
||||
<div class="pb-4 text-sm">Instance wide settings for Coolify.
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input id="settings.fqdn" label="Coolify's Domain" />
|
||||
<x-forms.input id="settings.wildcard_domain" label="Wildcard Domain"
|
||||
helper="Wildcard domain for your applications. If you set this, you will get a random generated domain for your new applications.<br><span class='font-bold text-white'>Example</span>In case you set:<span class='text-helper'>https://example.com</span>your applications will get: <span class='text-helper'>https://randomId.example.com</span>" />
|
||||
<x-forms.input id="settings.default_redirect_404" label="Default Redirect 404"
|
||||
helper="All urls that has no service available will be redirected to this domain.<span class='text-helper'>You can set to your main marketing page or your social media link.</span>" />
|
||||
</div>
|
||||
<div class="flex flex-col w-96">
|
||||
<x-inputs.input type="number" id="settings.public_port_min" label="Public Port Min" />
|
||||
<x-inputs.input type="number" id="settings.public_port_max" label="Public Port Max" />
|
||||
<div class="flex gap-2 ">
|
||||
<x-forms.input type="number" id="settings.public_port_min" label="Public Port Min" />
|
||||
<x-forms.input type="number" id="settings.public_port_max" label="Public Port Max" />
|
||||
</div>
|
||||
</div>
|
||||
<x-inputs.button class="w-16 mt-4" type="submit">
|
||||
Submit
|
||||
</x-inputs.button>
|
||||
</form>
|
||||
<div class="flex flex-col pt-4 text-right w-52">
|
||||
<x-inputs.input instantSave type="checkbox" id="do_not_track" label="Do Not Track" />
|
||||
<x-inputs.input instantSave type="checkbox" id="is_auto_update_enabled" label="Auto Update?" />
|
||||
<x-inputs.input instantSave type="checkbox" id="is_registration_enabled" label="Registration Enabled?" />
|
||||
<x-inputs.input instantSave type="checkbox" id="is_https_forced" label="Force https?" />
|
||||
|
||||
<h3>Advanced</h3>
|
||||
<div class="flex flex-col text-right w-52">
|
||||
<x-forms.checkbox instantSave id="is_auto_update_enabled" label="Auto Update Coolify" />
|
||||
<x-forms.checkbox instantSave id="is_registration_enabled" label="Registration Allowed" />
|
||||
{{-- <x-forms.checkbox instantSave id="is_https_forced" label="Force https?" /> --}}
|
||||
<x-forms.checkbox instantSave id="do_not_track" label="Do Not Track" />
|
||||
</div>
|
||||
@if (auth()->user()->isPartOfRootTeam())
|
||||
<livewire:force-upgrade />
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
<div>
|
||||
<form wire:submit.prevent='createGitHubApp'>
|
||||
<x-inputs.button type="submit">
|
||||
Submit
|
||||
</x-inputs.button>
|
||||
<h3 class="pt-4">General</h3>
|
||||
<x-inputs.input id="name" label="Name" required />
|
||||
<x-inputs.input helper="If empty, your user will be used." id="organization" label="Organization" />
|
||||
<h3 class="pt-4">Advanced</h3>
|
||||
<x-inputs.input id="html_url" label="HTML Url" required />
|
||||
<x-inputs.input id="api_url" label="API Url" required />
|
||||
<x-inputs.input id="custom_user" label="Custom Git User" required />
|
||||
<x-inputs.input id="custom_port" label="Custom Git Port" required />
|
||||
<x-inputs.checkbox class="pt-2" id="is_system_wide" label="System Wide" />
|
||||
</form>
|
||||
</div>
|
||||
@@ -5,12 +5,12 @@
|
||||
<h1>GitHub App</h1>
|
||||
<div class="flex gap-2 ">
|
||||
@if ($github_app->app_id)
|
||||
<x-inputs.button type="submit">Save</x-inputs.button>
|
||||
<x-inputs.button x-on:click.prevent="deleteSource = true">
|
||||
<x-forms.button type="submit">Save</x-forms.button>
|
||||
<x-forms.button x-on:click.prevent="deleteSource = true">
|
||||
Delete
|
||||
</x-inputs.button>
|
||||
</x-forms.button>
|
||||
<a href="{{ $installation_url }}">
|
||||
<x-inputs.button>
|
||||
<x-forms.button>
|
||||
@if ($github_app->installation_id)
|
||||
Update Repositories
|
||||
<x-external-link />
|
||||
@@ -18,43 +18,54 @@
|
||||
Install Repositories
|
||||
<x-external-link />
|
||||
@endif
|
||||
</x-inputs.button>
|
||||
</x-forms.button>
|
||||
</a>
|
||||
@else
|
||||
<x-inputs.button disabled type="submit">Save</x-inputs.button>
|
||||
<x-inputs.button x-on:click.prevent="deleteSource = true">
|
||||
<x-forms.button disabled type="submit">Save</x-forms.button>
|
||||
<x-forms.button x-on:click.prevent="deleteSource = true">
|
||||
Delete
|
||||
</x-inputs.button>
|
||||
<form x-data>
|
||||
<x-inputs.button isHighlighted x-on:click.prevent="createGithubApp">Create GitHub Application
|
||||
</x-inputs.button>
|
||||
</form>
|
||||
</x-forms.button>
|
||||
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<x-inputs.input id="github_app.name" label="App Name" required />
|
||||
@if (!$github_app->app_id)
|
||||
<div class="pb-4">
|
||||
<div class="text-sm">You need to register a GitHub App before using this source!</div>
|
||||
<form>
|
||||
<x-forms.button isHighlighted x-on:click.prevent="createGithubApp">Register a GitHub
|
||||
Application
|
||||
</x-forms.button>
|
||||
</form>
|
||||
</div>
|
||||
@endif
|
||||
<x-forms.input id="github_app.name" label="App Name" required />
|
||||
|
||||
@if ($github_app->app_id)
|
||||
<x-inputs.input id="github_app.organization" label="Organization" disabled
|
||||
<x-forms.input id="github_app.organization" label="Organization" disabled
|
||||
placeholder="Personal user if empty" />
|
||||
@else
|
||||
<x-inputs.input id="github_app.organization" label="Organization" placeholder="Personal user if empty" />
|
||||
<x-forms.input id="github_app.organization" label="Organization" placeholder="Personal user if empty" />
|
||||
@endif
|
||||
<x-forms.input id="github_app.html_url" label="HTML Url" disabled />
|
||||
<x-forms.input id="github_app.api_url" label="API Url" disabled />
|
||||
@if ($github_app->html_url === 'https://github.com')
|
||||
<x-forms.input id="github_app.custom_user" label="User" disabled />
|
||||
<x-forms.input type="number" id="github_app.custom_port" label="Port" disabled />
|
||||
@else
|
||||
<x-forms.input id="github_app.custom_user" label="User" required />
|
||||
<x-forms.input type="number" id="github_app.custom_port" label="Port" required />
|
||||
@endif
|
||||
<x-inputs.input id="github_app.api_url" label="API Url" disabled />
|
||||
<x-inputs.input id="github_app.html_url" label="HTML Url" disabled />
|
||||
<x-inputs.input id="github_app.custom_user" label="User" required />
|
||||
<x-inputs.input type="number" id="github_app.custom_port" label="Port" required />
|
||||
|
||||
@if ($github_app->app_id)
|
||||
<x-inputs.input type="number" id="github_app.app_id" label="App Id" disabled />
|
||||
<x-inputs.input type="number" id="github_app.installation_id" label="Installation Id" disabled />
|
||||
<x-inputs.input id="github_app.client_id" label="Client Id" type="password" disabled />
|
||||
<x-inputs.input id="github_app.client_secret" label="Client Secret" type="password" disabled />
|
||||
<x-inputs.input id="github_app.webhook_secret" label="Webhook Secret" type="password" disabled />
|
||||
<x-inputs.checkbox noDirty label="System Wide?" instantSave id="is_system_wide" />
|
||||
<x-forms.input type="number" id="github_app.app_id" label="App Id" disabled />
|
||||
<x-forms.input type="number" id="github_app.installation_id" label="Installation Id" disabled />
|
||||
<x-forms.input id="github_app.client_id" label="Client Id" type="password" disabled />
|
||||
<x-forms.input id="github_app.client_secret" label="Client Secret" type="password" disabled />
|
||||
<x-forms.input id="github_app.webhook_secret" label="Webhook Secret" type="password" disabled />
|
||||
<x-forms.checkbox noDirty label="System Wide?" instantSave id="is_system_wide" />
|
||||
@else
|
||||
<x-inputs.checkbox noDirty label="System Wide?" instantSave id="is_system_wide" />
|
||||
<x-forms.checkbox noDirty label="System Wide?" instantSave id="is_system_wide" />
|
||||
<div class="py-2">
|
||||
|
||||
</div>
|
||||
|
||||
18
resources/views/livewire/source/github/create.blade.php
Normal file
18
resources/views/livewire/source/github/create.blade.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<div>
|
||||
<form wire:submit.prevent='createGitHubApp'>
|
||||
<div class="flex items-start gap-2 pt-6">
|
||||
<h2 class="">General</h2>
|
||||
<x-forms.button type="submit">
|
||||
Save
|
||||
</x-forms.button>
|
||||
</div>
|
||||
<x-forms.input id="name" label="Name" required />
|
||||
<x-forms.input helper="If empty, your GitHub user will be used." id="organization" label="Organization" />
|
||||
<h3 class="pt-4">Advanced</h3>
|
||||
<x-forms.input id="html_url" label="HTML Url" required />
|
||||
<x-forms.input id="api_url" label="API Url" required />
|
||||
<x-forms.input id="custom_user" label="Custom Git User" required />
|
||||
<x-forms.input id="custom_port" label="Custom Git Port" required />
|
||||
<x-forms.checkbox class="pt-2" id="is_system_wide" label="System Wide" />
|
||||
</form>
|
||||
</div>
|
||||
@@ -1,10 +1,12 @@
|
||||
<div class="pt-4">
|
||||
<h3>Other Teams</h3>
|
||||
<div class="flex flex-col gap-2">
|
||||
@foreach (auth()->user()->otherTeams() as $team)
|
||||
<x-inputs.button wire:key="{{ $team->id }}" wire:click="switch_to('{{ $team->id }}')">Switch
|
||||
to:
|
||||
{{ $team->name }}</x-inputs.button>
|
||||
@endforeach
|
||||
</div>
|
||||
<h3>Switch Team</h3>
|
||||
@if (auth()->user()->otherTeams()->count() > 0)
|
||||
<div class="flex gap-2">
|
||||
@foreach (auth()->user()->otherTeams() as $team)
|
||||
<x-forms.button isHighlighted wire:key="{{ $team->id }}"
|
||||
wire:click="switch_to('{{ $team->id }}')">
|
||||
{{ $team->name }}</x-forms.button>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
58
resources/views/livewire/upgrading.blade.php
Normal file
58
resources/views/livewire/upgrading.blade.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<div x-data="{ visible: @entangle('visible') }" class="flex text-xs text-white">
|
||||
<template x-if="visible">
|
||||
<div class="bg-coollabs-gradient">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-10 h-10 mx-auto text-pink-500 lds-heart" 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" />
|
||||
<path d="M19.5 13.572l-7.5 7.428l-7.5 -7.428m0 0a5 5 0 1 1 7.5 -6.566a5 5 0 1 1 7.5 6.572" />
|
||||
</svg> Upgrading, please wait...
|
||||
<script>
|
||||
function checkHealth() {
|
||||
console.log('Checking server\'s health...')
|
||||
checkHealthInterval = setInterval(async () => {
|
||||
try {
|
||||
const res = await fetch('/api/health');
|
||||
if (res.ok) {
|
||||
console.log('Server is back online. Reloading...')
|
||||
if (checkHealthInterval) clearInterval(checkHealthInterval);
|
||||
window.location.reload();
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('Waiting for server to come back from dead...');
|
||||
}
|
||||
|
||||
return;
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
function checkIfIamDead() {
|
||||
console.log('Checking server\'s pulse...')
|
||||
checkIfIamDeadInterval = setInterval(async () => {
|
||||
try {
|
||||
const res = await fetch('/api/health');
|
||||
if (res.ok) {
|
||||
console.log('I\'m alive. Waiting for server to be dead...');
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('I\'m dead. Charging... Standby... Bzz... Bzz...')
|
||||
checkHealth();
|
||||
if (checkIfIamDeadInterval) clearInterval(checkIfIamDeadInterval);
|
||||
}
|
||||
|
||||
return;
|
||||
}, 2000);
|
||||
}
|
||||
let checkHealthInterval = null;
|
||||
let checkIfIamDeadInterval = null;
|
||||
console.log('Update initiated. Waiting for server to be dead...')
|
||||
checkIfIamDead();
|
||||
</script>
|
||||
</div>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-8 h-8 mx-auto lds-heart" 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" />
|
||||
<path d="M19.5 12.572l-7.5 7.428l-7.5 -7.428a5 5 0 1 1 7.5 -6.566a5 5 0 1 1 7.5 6.572" />
|
||||
<path d="M12 6l-2 4l4 3l-2 4v3" />
|
||||
</svg>
|
||||
</template>
|
||||
</div>
|
||||
@@ -1,10 +1,3 @@
|
||||
<x-layout>
|
||||
<div>
|
||||
<div>
|
||||
<h3>User</h3>
|
||||
<p>Name: {{ auth()->user()->name }}</p>
|
||||
<p>Id: {{ auth()->user()->id }}</p>
|
||||
<p>Uuid: {{ auth()->user()->uuid }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<livewire:profile.form />
|
||||
</x-layout>
|
||||
|
||||
@@ -1,6 +1,17 @@
|
||||
<x-layout>
|
||||
<h1 class="pb-0">Configuration</h1>
|
||||
<div class="pb-10 text-sm breadcrumbs">
|
||||
<ul>
|
||||
<li><a href="{{ route('project.show', ['project_uuid' => request()->route('project_uuid')]) }}">
|
||||
{{ $application->environment->project->name }}</a>
|
||||
</li>
|
||||
<li><a
|
||||
href="{{ route('project.resources', ['environment_name' => request()->route('environment_name'), 'project_uuid' => request()->route('project_uuid')]) }}">{{ request()->route('environment_name') }}</a>
|
||||
</li>
|
||||
<li>{{ data_get($application, 'name') }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<x-applications.navbar :application="$application" />
|
||||
<h1 class="py-10">Configuration</h1>
|
||||
<div x-data="{ activeTab: window.location.hash ? window.location.hash.substring(1) : 'general' }" class="flex h-full pt-6">
|
||||
<div class="flex flex-col gap-4 min-w-fit">
|
||||
<a :class="activeTab === 'general' && 'text-white'"
|
||||
@@ -18,6 +29,10 @@
|
||||
<a :class="activeTab === 'storages' && 'text-white'"
|
||||
@click.prevent="activeTab = 'storages'; window.location.hash = 'storages'" href="#">Storages
|
||||
</a>
|
||||
<a :class="activeTab === 'previews' && 'text-white'"
|
||||
@click.prevent="activeTab = 'previews'; window.location.hash = 'previews'" href="#">Previews
|
||||
Deployments
|
||||
</a>
|
||||
<a :class="activeTab === 'rollback' && 'text-white'"
|
||||
@click.prevent="activeTab = 'rollback'; window.location.hash = 'rollback'" href="#">Rollback
|
||||
</a>
|
||||
@@ -48,6 +63,9 @@
|
||||
<div x-cloak x-show="activeTab === 'storages'">
|
||||
<livewire:project.application.storages.all :application="$application" />
|
||||
</div>
|
||||
<div x-cloak x-show="activeTab === 'previews'">
|
||||
<livewire:project.application.previews :application="$application" />
|
||||
</div>
|
||||
<div x-cloak x-show="activeTab === 'rollback'">
|
||||
<livewire:project.application.rollback :application="$application" />
|
||||
</div>
|
||||
@@ -57,7 +75,6 @@
|
||||
<div x-cloak x-show="activeTab === 'danger'">
|
||||
<livewire:project.application.danger :application="$application" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</x-layout>
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
<x-layout>
|
||||
<h1 class="py-0">Deployment</h1>
|
||||
<div class="pb-10 text-sm breadcrumbs">
|
||||
<ul>
|
||||
<li><a
|
||||
href="{{ route('project.show', ['project_uuid' => request()->route('project_uuid')]) }}">{{ $application->environment->project->name }}</a>
|
||||
</li>
|
||||
<li><a
|
||||
href="{{ route('project.resources', ['environment_name' => request()->route('environment_name'), 'project_uuid' => request()->route('project_uuid')]) }}">{{ request()->route('environment_name') }}</a>
|
||||
</li>
|
||||
<li>{{ data_get($application, 'name') }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<x-applications.navbar :application="$application" />
|
||||
<h1 class="py-10">Deployment</h1>
|
||||
<livewire:project.application.poll-deployment :activity="$activity" :deployment_uuid="$deployment_uuid" />
|
||||
<livewire:project.application.deployment-logs :activity="$activity" :application="$application" :deployment_uuid="$deployment_uuid" />
|
||||
</x-layout>
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
<x-layout>
|
||||
<x-applications.navbar :application="$application" />
|
||||
<h1 class="py-10">Deployments</h1>
|
||||
<div class="pt-2">
|
||||
@forelse ($deployments as $deployment)
|
||||
<livewire:project.application.get-deployments :deployment_uuid="data_get($deployment->properties, 'type_uuid')" :created_at="data_get($deployment, 'created_at')" :status="data_get($deployment->properties, 'status')" />
|
||||
@empty
|
||||
<p>No deployments found.</p>
|
||||
@endforelse
|
||||
<h1 class="pb-0">Deployments</h1>
|
||||
<div class="pb-10 text-sm breadcrumbs">
|
||||
<ul>`
|
||||
<li><a
|
||||
href="{{ route('project.show', ['project_uuid' => request()->route('project_uuid')]) }}">{{ $application->environment->project->name }}</a>
|
||||
</li>
|
||||
<li><a
|
||||
href="{{ route('project.resources', ['environment_name' => request()->route('environment_name'), 'project_uuid' => request()->route('project_uuid')]) }}">{{ request()->route('environment_name') }}</a>
|
||||
</li>
|
||||
<li>{{ data_get($application, 'name') }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<x-applications.navbar :application="$application" />
|
||||
<livewire:project.application.deployments :application_id="$application->id" />
|
||||
</x-layout>
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
<x-layout>
|
||||
<h1>Environments</h1>
|
||||
@foreach ($project->environments as $environment)
|
||||
<div>
|
||||
<a href="{{ route('project.resources', [$project->uuid, $environment->name]) }}">
|
||||
{{ $environment->name }}
|
||||
</a>
|
||||
</div>
|
||||
@endforeach
|
||||
</x-layout>
|
||||
@@ -1,12 +1,26 @@
|
||||
<x-layout>
|
||||
<div class="flex items-center gap-2">
|
||||
<h1>Resources</h1>
|
||||
<livewire:project.delete :project_id="$project->id" :resource_count="$project->applications->count()" />
|
||||
<div class="flex flex-col">
|
||||
<div class="flex items-center gap-2">
|
||||
<h1 class="pb-0">Resources</h1>
|
||||
<livewire:project.delete-environment :environment_id="$environment->id" :resource_count="$environment->applications->count()" />
|
||||
</div>
|
||||
<div class="pb-10 text-sm breadcrumbs">
|
||||
<ul>
|
||||
<li>
|
||||
<a href="{{ route('project.show', ['project_uuid' => request()->route('project_uuid')]) }}">
|
||||
{{ $project->name }}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
{{ request()->route('environment_name') }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@if ($environment->applications->count() === 0)
|
||||
<p>No resources yet.</p>
|
||||
<p>No resources found.</p>
|
||||
@endif
|
||||
<div class="flex gap-2">
|
||||
<div class="flex flex-col gap-2">
|
||||
@foreach ($environment->applications->sortBy('name') as $application)
|
||||
<a class="box"
|
||||
href="{{ route('project.application.configuration', [$project->uuid, $environment->name, $application->uuid]) }}">
|
||||
|
||||
20
resources/views/project/show.blade.php
Normal file
20
resources/views/project/show.blade.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<x-layout>
|
||||
<div class="flex items-center gap-2">
|
||||
<h1 class="pb-0">Environments</h1>
|
||||
<livewire:project.delete-project :project_id="$project->id" :resource_count="$project->applications->count()" />
|
||||
</div>
|
||||
<div class="pb-10 text-sm breadcrumbs">
|
||||
<ul>
|
||||
<li>{{ $project->name }} </li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
@forelse ($project->environments as $environment)
|
||||
<a class="box" href="{{ route('project.resources', [$project->uuid, $environment->name]) }}">
|
||||
{{ $environment->name }}
|
||||
</a>
|
||||
@empty
|
||||
<p>No environments found.</p>
|
||||
@endforelse
|
||||
</div>
|
||||
</x-layout>
|
||||
22
resources/views/projects.blade.php
Normal file
22
resources/views/projects.blade.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<x-layout>
|
||||
<h1 class="py-0">Projects</h1>
|
||||
<div class="pb-10 text-sm breadcrumbs">
|
||||
<ul>
|
||||
<li>
|
||||
All Projects
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
@forelse ($projects as $project)
|
||||
<a href="{{ route('project.show', ['project_uuid' => data_get($project, 'uuid')]) }}"
|
||||
class="box">{{ $project->name }}</a>
|
||||
@empty
|
||||
<div x-data>
|
||||
No project found. Use the <button x-on:click="$dispatch('slash')" class='text-white underline'>magic
|
||||
bar</button> to create a new
|
||||
project.
|
||||
</div>
|
||||
@endforelse
|
||||
</div>
|
||||
</x-layout>
|
||||
@@ -1,6 +1,6 @@
|
||||
<x-layout>
|
||||
@if ($private_keys->count() === 0)
|
||||
<h2>Create private key</h2>
|
||||
<h2>Create Private Key</h2>
|
||||
<div>You need to create a private key before you can create a server.</div>
|
||||
<livewire:private-key.create from="server" />
|
||||
@else
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
<x-layout>
|
||||
<h1>Server</h1>
|
||||
<div x-data="{ activeTab: window.location.hash ? window.location.hash.substring(1) : 'general' }" class="flex pt-6">
|
||||
<h1 class="pb-0">Server</h1>
|
||||
<div class="text-sm breadcrumbs">
|
||||
<ul>
|
||||
<li>{{ data_get($server, 'name') }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div x-data="{ activeTab: window.location.hash ? window.location.hash.substring(1) : 'general' }" class="flex pt-10">
|
||||
<div class="flex flex-col gap-4 min-w-fit">
|
||||
<a :class="activeTab === 'general' && 'text-white'"
|
||||
@click.prevent="activeTab = 'general'; window.location.hash = 'general'" href="#">General</a>
|
||||
|
||||
20
resources/views/servers.blade.php
Normal file
20
resources/views/servers.blade.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<x-layout>
|
||||
<h1 class="py-0">Servers</h1>
|
||||
<div class="pb-10 text-sm breadcrumbs">
|
||||
<ul>
|
||||
<li>
|
||||
All Servers
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@forelse ($servers as $server)
|
||||
<a href="{{ route('server.show', ['server_uuid' => data_get($server, 'uuid')]) }}"
|
||||
class="box">{{ $server->name }}</a>
|
||||
@empty
|
||||
<div class="flex flex-col">
|
||||
<div>Without a server, you won't be able to do much.</div>
|
||||
<div>Let's <a class="text-lg underline text-warning" href="{{ route('server.new') }}">create</a> your
|
||||
first one.</div>
|
||||
</div>
|
||||
@endforelse
|
||||
</x-layout>
|
||||
@@ -1,7 +1,4 @@
|
||||
<x-layout>
|
||||
<h1>Settings</h1>
|
||||
|
||||
<h3>General</h3>
|
||||
<livewire:settings.form :settings="$settings" />
|
||||
|
||||
</x-layout>
|
||||
|
||||
4
resources/views/source/github/new.blade.php
Normal file
4
resources/views/source/github/new.blade.php
Normal file
@@ -0,0 +1,4 @@
|
||||
<x-layout>
|
||||
<h1>New GitHub Source</h1>
|
||||
|
||||
</x-layout>
|
||||
@@ -1,4 +1,21 @@
|
||||
<x-layout>
|
||||
<h1>New Git App</h1>
|
||||
<livewire:source.create />
|
||||
<h1>New Source</h1>
|
||||
<div x-data="{ activeTab: window.location.hash ? window.location.hash.substring(1) : '' }">
|
||||
<div class="flex justify-center h-full gap-2">
|
||||
<a class="flex items-center justify-center w-1/2 p-2 text-sm transition-colors rounded-none min-h-12 bg-coolgray-200 hover:bg-coollabs-100 hover:text-white hover:no-underline"
|
||||
:class="activeTab === 'github' && 'bg-coollabs text-white'"
|
||||
@click.prevent="activeTab = 'github'; window.location.hash = 'github'" href="#">GitHub
|
||||
</a>
|
||||
<a class="flex items-center justify-center w-1/2 p-2 text-sm transition-colors rounded-none min-h-12 bg-coolgray-200 hover:bg-coollabs-100 hover:text-white hover:no-underline"
|
||||
:class="activeTab === 'gitlab' && 'bg-coollabs text-white'"
|
||||
@click.prevent="activeTab = 'gitlab'; window.location.hash = 'gitlab'" href="#">GitLab
|
||||
</a>
|
||||
</div>
|
||||
<div x-cloak x-show="activeTab === 'github'" class="h-full">
|
||||
<livewire:source.github.create />
|
||||
</div>
|
||||
<div x-cloak x-show="activeTab === 'gitlab'" class="h-full">
|
||||
GitLab here
|
||||
</div>
|
||||
</div>
|
||||
</x-layout>
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
<div>
|
||||
<h3>Current Team</h3>
|
||||
<p>Name: {{ session('currentTeam.name') }}</p>
|
||||
<livewire:switch-team/>
|
||||
<livewire:switch-team />
|
||||
<div class="h-12"></div>
|
||||
<h3>Notifications</h3>
|
||||
<livewire:notifications.discord-settings :model="session('currentTeam')" />
|
||||
<livewire:notifications.email-settings :model="session('currentTeam')" />
|
||||
<div class="h-12"></div>
|
||||
</div>
|
||||
<livewire:switch-team>
|
||||
</x-layout>
|
||||
|
||||
Reference in New Issue
Block a user