Merge branch 'v4-next' into patricio-deploy-proxy

This commit is contained in:
Andras Bacsai 2023-05-03 20:53:51 +02:00
commit 4a97b762be
45 changed files with 431 additions and 248 deletions

View File

@ -0,0 +1,41 @@
<?php
namespace App\Http\Livewire\PrivateKey;
use App\Models\PrivateKey;
use Livewire\Component;
class Change extends Component
{
public string $private_key_uuid;
public PrivateKey $private_key;
protected $rules = [
'private_key.name' => 'required|string',
'private_key.description' => 'nullable|string',
'private_key.private_key' => 'required|string'
];
public function mount()
{
$this->private_key = PrivateKey::where('uuid', $this->private_key_uuid)->first();
}
public function delete($private_key_uuid)
{
PrivateKey::where('uuid', $private_key_uuid)->delete();
session('currentTeam')->privateKeys = PrivateKey::where('team_id', session('currentTeam')->id)->get();
redirect()->route('dashboard');
}
public function changePrivateKey()
{
try {
$this->private_key->private_key = trim($this->private_key->private_key);
if (!str_ends_with($this->private_key->private_key, "\n")) {
$this->private_key->private_key .= "\n";
}
$this->private_key->save();
session('currentTeam')->privateKeys = PrivateKey::where('team_id', session('currentTeam')->id)->get();
} catch (\Exception $e) {
$this->addError('private_key_value', $e->getMessage());
}
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace App\Http\Livewire\PrivateKey;
use App\Models\PrivateKey;
use Livewire\Component;
class Create extends Component
{
public $private_key_value;
public $private_key_name;
public $private_key_description;
public function createPrivateKey()
{
$this->private_key_value = trim($this->private_key_value);
if (!str_ends_with($this->private_key_value, "\n")) {
$this->private_key_value .= "\n";
}
$new_private_key = PrivateKey::create([
'name' => $this->private_key_name,
'description' => $this->private_key_description,
'private_key' => $this->private_key_value,
'team_id' => session('currentTeam')->id
]);
session('currentTeam')->privateKeys = PrivateKey::where('team_id', session('currentTeam')->id)->get();
redirect()->route('private-key.show', $new_private_key->uuid);
}
}

View File

@ -45,11 +45,11 @@ public function mount()
$this->parameters = Route::current()->parameters();
$this->servers = session('currentTeam')->load(['servers'])->servers;
}
public function chooseServer($server_id)
public function chooseServer($server)
{
$this->chosenServer = $server_id;
$this->standalone_docker = StandaloneDocker::where('server_id', $server_id)->get();
$this->swarm_docker = SwarmDocker::where('server_id', $server_id)->get();
$this->chosenServer = $server;
$this->standalone_docker = StandaloneDocker::where('server_id', $server['id'])->get();
$this->swarm_docker = SwarmDocker::where('server_id', $server['id'])->get();
}
public function setDestination($destination_uuid, $destination_type)
{

View File

@ -15,7 +15,7 @@ class ByIp extends Component
public $new_private_key_value;
public string $name;
public string $description;
public string|null $description = null;
public string $ip;
public string $user = 'root';
public int $port = 22;
@ -29,20 +29,6 @@ public function setPrivateKey($private_key_id)
{
$this->private_key_id = $private_key_id;
}
public function addPrivateKey()
{
$this->new_private_key_value = trim($this->new_private_key_value);
if (!str_ends_with($this->new_private_key_value, "\n")) {
$this->new_private_key_value .= "\n";
}
PrivateKey::create([
'name' => $this->new_private_key_name,
'description' => $this->new_private_key_description,
'private_key' => $this->new_private_key_value,
'team_id' => session('currentTeam')->id
]);
session('currentTeam')->privateKeys = $this->private_keys = PrivateKey::where('team_id', session('currentTeam')->id)->get();
}
public function submit()
{
if (!$this->private_key_id) {

View File

@ -0,0 +1,26 @@
<?php
namespace App\Http\Livewire\Server;
use App\Models\PrivateKey as ModelsPrivateKey;
use App\Models\Server;
use Illuminate\Support\Facades\Route;
use Livewire\Component;
class PrivateKey extends Component
{
public $private_keys;
public $parameters;
public function setPrivateKey($private_key_id)
{
Server::where('uuid', $this->parameters['server_uuid'])->update([
'private_key_id' => $private_key_id
]);
return redirect()->route('server.show', $this->parameters['server_uuid']);
}
public function mount()
{
$this->parameters = Route::current()->parameters();
$this->private_keys = ModelsPrivateKey::where('team_id', session('currentTeam')->id)->get();
}
}

View File

@ -222,10 +222,10 @@ public function handle(): void
Storage::disk('deployments')->put(Str::kebab($this->application->name) . '/docker-compose.yml', $this->docker_compose);
} catch (\Exception $e) {
$this->executeNow([
"echo 'Oops something is not okay, are you okay? 😢'",
"echo '\nOops something is not okay, are you okay? 😢'",
"echo '\n\n{$e->getMessage()}'",
]);
throw new \Exception('Deployment finished');
$this->fail($e->getMessage());
} finally {
$this->executeNow(["docker rm -f {$this->deployment_uuid} >/dev/null 2>&1"], hideFromOutput: true);
dispatch(new ContainerStatusJob($this->application_uuid));

View File

@ -24,4 +24,8 @@ public function applications()
{
return $this->hasManyThrough(Application::class, Project::class);
}
public function privateKeys()
{
return $this->hasMany(PrivateKey::class);
}
}

View File

@ -1,33 +0,0 @@
<?php
namespace App\View\Components;
use Closure;
use Illuminate\Contracts\View\View;
use Illuminate\View\Component;
class FormInput extends Component
{
/**
* Create a new component instance.
*/
public function __construct(
public string $id,
public bool $required = false,
public bool $readonly = false,
public string|null $label = null,
public string|null $type = 'text',
public bool $instantSave = false,
public bool $disabled = false,
public bool $hidden = false
) {
}
/**
* Get the view / contents that represent the component.
*/
public function render(): View|Closure|string
{
return view('components.form-input');
}
}

View File

@ -1,30 +0,0 @@
<?php
namespace App\View\Components;
use Closure;
use Illuminate\Contracts\View\View;
use Illuminate\View\Component;
class Input extends Component
{
/**
* Create a new component instance.
*/
public function __construct(
public string $id,
public bool $required = false,
public bool $readonly = false,
public string|null $label = null,
public string|null $type = 'text',
) {
}
/**
* Get the view / contents that represent the component.
*/
public function render(): View|Closure|string
{
return view('components.input');
}
}

View File

@ -67,7 +67,7 @@ function savePrivateKeyForServer(Server $server)
}
if (!function_exists('generateSshCommand')) {
function generateSshCommand(string $private_key_location, string $server_ip, string $user, string $port, string $command, bool $isMux = false)
function generateSshCommand(string $private_key_location, string $server_ip, string $user, string $port, string $command, bool $isMux = true)
{
$delimiter = 'EOF-COOLIFY-SSH';
Storage::disk('local')->makeDirectory('.ssh');
@ -79,6 +79,7 @@ function generateSshCommand(string $private_key_location, string $server_ip, str
. '-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null '
. '-o PasswordAuthentication=no '
. '-o ConnectTimeout=3600 '
. '-o ServerAliveInterval=60 '
. '-o RequestTTY=no '
. '-o LogLevel=ERROR '
. "-p {$port} "

View File

@ -1,7 +1,7 @@
<?php
return [
'version' => '4.0.0-nightly.1',
'version' => '4.0.0-nightly.2',
'project_path_on_host' => env('PROJECT_PATH_ON_HOST', '/var/www/html')
];

View File

@ -1,3 +1,16 @@
/* @tailwind base; */
@tailwind components;
@tailwind utilities;
body {
@apply bg-neutral-900 text-white font-sans;
}
a, a:visited {
@apply text-neutral-300 hover:text-purple-500;
}
input, select, textarea {
@apply border-none p-2 bg-neutral-800 text-white disabled:text-neutral-600;
}
button {
@apply border-none px-2 p-1 cursor-pointer;
}

View File

@ -12,7 +12,7 @@
<input type="text" name="email" placeholder="email" @env('local') value="test@example.com" @endenv
autofocus />
<input type="password" name="password" placeho lder="Password" @env('local') value="password" @endenv />
<button type="submit">Login</button>
<x-inputs.button type="submit">Login</x-inputs.button>
</form>
@if ($errors->any())
<div class="alert alert-danger">

View File

@ -9,7 +9,7 @@
<input type="password" name="password" placeholder="Password" @env('local') value="password" @endenv />
<input type="password" name="password_confirmation" placeholder="Password"
@env('local') value="password" @endenv />
<button type="submit">Register</button>
<x-inputs.button type="submit">Register</x-inputs.button>
</form>
@if ($errors->any())
<div class="alert alert-danger">

View File

@ -16,8 +16,8 @@
<div class="flex flex-col items-center justify-center h-full">
<div class="pb-5 text-white" x-text="message"></div>
<div>
<button x-on:click="open = false">Cancel</button>
<button x-on:click="$dispatch('confirm')">Confirm</button>
<x-inputs.button isWarning x-on:click="$dispatch('confirm')">Confirm</x-inputs.button>
<x-inputs.button x-on:click="open = false">Cancel</x-inputs.button>
</div>
</div>
</div>

View File

@ -1,11 +0,0 @@
<label for={{ $id }}>
@if ($label)
{{ $label }}
@else
{{ $id }}
@endif
@if ($required)
*
@endif
<input id={{ $id }} type={{ $type }} wire:model.defer={{ $id }}>
</label>

View File

@ -0,0 +1,24 @@
@props([
'isWarning' => null,
'defaultClass' => 'text-white bg-neutral-800 hover:bg-violet-600',
'defaultWarningClass' => 'text-white bg-red-500 hover:bg-red-600',
'loadingClass' => 'text-black bg-green-500',
'confirm' => null,
'confirmAction' => null,
])
<button {{ $attributes }} @class([
$defaultClass => !$confirm && !$isWarning,
$defaultWarningClass => $confirm || $isWarning,
]) @if ($attributes->whereStartsWith('wire:click'))
wire:target="{{ explode('(', $attributes->whereStartsWith('wire:click')->first())[0] }}"
wire:loading.delay.class="{{ $loadingClass }}" wire:loading.delay.attr="disabled"
wire:loading.delay.class.remove="{{ $defaultClass }} {{ $attributes->whereStartsWith('class')->first() }}"
@endif
@isset($confirm)
x-on:click="toggleConfirmModal('{{ $confirm }}')"
@endisset
@isset($confirmAction)
@confirm.window="$wire.{{ $confirmAction }}()"
@endisset>
{{ $slot }}
</button>

View File

@ -1,3 +1,15 @@
@props([
'id' => null,
'required' => false,
'readonly' => false,
'label' => null,
'type' => 'text',
'class' => '',
'instantSave' => false,
'disabled' => false,
'hidden' => false,
])
@if ($type === 'checkbox')
<label for={{ $id }}>
@if ($label)
@ -26,12 +38,13 @@
@endif
</label>
@if ($type === 'textarea')
<textarea type={{ $type }} id={{ $id }} wire:model.defer={{ $id }}
@if ($required) required @endif @if ($disabled) disabled @endif
@if ($readonly) readOnly disabled @endif></textarea>
<textarea class={{ $class }} type={{ $type }} id={{ $id }}
wire:model.defer={{ $id }} @if ($required) required @endif
@if ($disabled) disabled @endif @if ($readonly) readOnly disabled @endif></textarea>
@else
<input type={{ $type }} id={{ $id }} wire:model.defer={{ $id }}
@if ($required) required @endif @if ($disabled) disabled @endif
<input class={{ $class }} type={{ $type }} id={{ $id }}
wire:model.defer={{ $id }} @if ($required) required @endif
@if ($disabled) disabled @endif
@if ($readonly) readOnly disabled @endif />
@endif

View File

@ -11,7 +11,7 @@
@endif
<form action="/logout" method="POST">
@csrf
<button type="submit">Logout</button>
<x-inputs.button type="submit">Logout</x-inputs.button>
</form>
<livewire:check-update />
<livewire:force-upgrade />

View File

@ -1,19 +1,33 @@
<x-layout>
<h1>Projects <a href="{{ route('project.new') }}"><button>New</button></a></h1>
<h1>Projects <a href="{{ route('project.new') }}">
<x-inputs.button>New</x-inputs.button>
</a></h1>
@forelse ($projects as $project)
<a href="{{ route('project.environments', [$project->uuid]) }}">{{ data_get($project, 'name') }}</a>
@empty
<p>No projects found.</p>
@endforelse
<h1>Servers <a href="{{ route('server.new') }}"><button>New</button></a></h1>
<h1>Servers <a href="{{ route('server.new') }}">
<x-inputs.button>New</x-inputs.button>
</a></h1>
@forelse ($servers as $server)
<a href="{{ route('server.show', [$server->uuid]) }}">{{ data_get($server, 'name') }}</a>
@empty
<p>No servers found.</p>
@endforelse
<h1>Destinations <a href="{{ route('destination.new') }}"><button>New</button></a></h1>
<h1>Destinations <a href="{{ route('destination.new') }}">
<x-inputs.button>New</x-inputs.button>
</a></h1>
@forelse ($destinations as $destination)
<a href="{{ route('destination.show', [$destination->uuid]) }}">{{ data_get($destination, 'name') }}</a>
@empty
<p>No destinations found.</p>
@endforelse
<h1>Private Keys <a href="{{ route('private-key.new') }}">
<x-inputs.button>New</x-inputs.button>
</a></h1>
@forelse ($private_keys as $private_key)
<a href="{{ route('private-key.show', [$private_key->uuid]) }}">{{ data_get($private_key, 'name') }}</a>
@empty
<p>No servers found.</p>
@endforelse

View File

@ -1,4 +1,4 @@
<x-layout>
<h1>New Destination</h1>
<livewire:destination.new.standalone-docker />
<livewire:destination.new.standalone-docker :server_id="$server_id" />
</x-layout>

View File

@ -1,6 +1,5 @@
<div>
<button wire:loading.class="text-black bg-green-500" wire:loading.attr="disabled" wire:click='checkUpdate'>Check for
updates</button>
<x-inputs.button wire:click='checkUpdate' type="submit">Check for updates</x-inputs.button>
@if ($updateAvailable)
Update available
@endif

View File

@ -1,15 +1,21 @@
<div>
<form class="flex flex-col" wire:submit.prevent='submit'>
<x-form-input id="name" label="Name" required />
<x-form-input id="network" label="Network" required />
<x-form-input id="server_id" label="Server ID" required />
<x-inputs.input id="name" label="Name" required />
<x-inputs.input id="network" label="Network" required />
<x-inputs.input id="server_id" label="Server ID" required />
@foreach ($servers as $key)
<button @if ($server_id == $key->id) class="bg-green-500" @endif
wire:click.prevent="setServerId('{{ $key->id }}')">{{ $key->name }}</button>
@if ($server_id == $key->id)
<x-inputs.button class="bg-green-500" wire:click.prevent="setServerId('{{ $key->id }}')">
{{ $key->name }}
</x-inputs.button>
@else
<x-inputs.button wire:click.prevent="setServerId('{{ $key->id }}')">{{ $key->name }}
</x-inputs.button>
@endif
@endforeach
<button class="mt-4" type="submit">
<x-inputs.button class="mt-4" type="submit">
Submit
</button>
</x-inputs.button>
</form>
</div>

View File

@ -1,6 +1,5 @@
<div>
@if (auth()->user()->teams->contains(0))
<button wire:loading.class="text-black bg-green-500" wire:loading.attr="disabled" wire:click='upgrade'>Force
Upgrade</button>
<x-inputs.button wire:click='upgrade'>Force Upgrade</x-inputs.button>
@endif
</div>

View File

@ -0,0 +1,14 @@
<div>
<form class="flex flex-col gap-2 w-96" 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.input type="textarea" id="private_key.private_key" label="Private Key" required />
<x-inputs.button type="submit">
Submit
</x-inputs.button>
<x-inputs.button class="bg-red-500" confirm='Are you sure you would like to delete this private key?'
confirmAction="delete('{{ $private_key_uuid }}')">
Delete
</x-inputs.button>
</form>
</div>

View File

@ -0,0 +1,10 @@
<div>
<form class="flex flex-col gap-2 w-96" wire:submit.prevent='createPrivateKey'>
<x-inputs.input id="private_key_name" label="Name" required />
<x-inputs.input id="private_key_description" label="Longer Description" />
<x-inputs.input type="textarea" id="private_key_value" label="Private Key" required />
<x-inputs.button type="submit">
Submit
</x-inputs.button>
</form>
</div>

View File

@ -1,15 +1,15 @@
<div>
<button class="bg-red-500" @confirm.window="$wire.delete()"
x-on:click="toggleConfirmModal('Are you sure you would like to delete this application?')">
Delete</button>
@if ($application->status === 'running')
<button wire:click='start'>Restart</button>
<button wire:click='forceRebuild'>Force Rebuild</button>
<x-inputs.button wire:click='start'>Restart</x-inputs.button>
<x-inputs.button wire:click='forceRebuild'>Force Rebuild</x-inputs.button>
<x-inputs.button wire:click='stop'>Stop</x-inputs.button>
@else
<button wire:click='start'>Start</button>
<button wire:click='forceRebuild'>Start (no cache)</button>
<x-inputs.button wire:click='start'>Start</x-inputs.button>
<x-inputs.button wire:click='forceRebuild'>Start (no cache)</x-inputs.button>
@endif
<button wire:click='stop'>Stop</button>
<x-inputs.button confirmAction="delete" confirm='Are you sure you would like to delete this application?'>
Delete</x-inputs.button>
<span wire:poll.5000ms='pollingStatus'>
@if ($application->status === 'running')
@if (data_get($application, 'fqdn'))
@ -23,7 +23,7 @@
{{ explode(':', $port)[0] }}</a>
@else
<a target="_blank"
href="http://{{ $application->destination->server->ip }}:{{ $port }}">Open
href="http://{{ $application->destination->server->ip }}:{{ explode(':', $port)[0] }}">Open
{{ $port }}</a>
@endif
@endforeach

View File

@ -2,51 +2,51 @@
<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-form-input id="application.name" label="Name" required />
<x-form-input id="application.fqdn" label="FQDN" />
<x-inputs.input id="application.name" label="Name" required />
<x-inputs.input id="application.fqdn" label="FQDN" />
</div>
<div class="flex flex-col w-96">
<x-form-input id="application.install_command" label="Install Command" />
<x-form-input id="application.build_command" label="Build Command" />
<x-form-input id="application.start_command" label="Start Command" />
<x-form-input id="application.build_pack" label="Build Pack" />
<x-inputs.input id="application.install_command" label="Install Command" />
<x-inputs.input id="application.build_command" label="Build Command" />
<x-inputs.input id="application.start_command" label="Start Command" />
<x-inputs.input id="application.build_pack" label="Build Pack" />
@if ($application->settings->is_static)
<x-form-input id="application.static_image" label="Static Image" required />
<x-inputs.input id="application.static_image" label="Static Image" required />
@endif
</div>
<div class="flex flex-col w-96">
<x-form-input id="application.base_directory" label="Base Directory" />
<x-inputs.input id="application.base_directory" label="Base Directory" />
@if ($application->settings->is_static)
<x-form-input id="application.publish_directory" label="Publish Directory" required />
<x-inputs.input id="application.publish_directory" label="Publish Directory" required />
@else
<x-form-input id="application.publish_directory" label="Publish Directory" />
<x-inputs.input id="application.publish_directory" label="Publish Directory" />
@endif
</div>
<div class="flex flex-col w-96">
@if ($application->settings->is_static)
<x-form-input id="application.ports_exposes" label="Ports Exposes" disabled />
<x-inputs.input id="application.ports_exposes" label="Ports Exposes" disabled />
@else
<x-form-input id="application.ports_exposes" label="Ports Exposes" required />
<x-inputs.input id="application.ports_exposes" label="Ports Exposes" required />
@endif
<x-form-input id="application.ports_mappings" label="Ports Mappings" />
<x-inputs.input id="application.ports_mappings" label="Ports Mappings" />
</div>
</div>
<button class="flex mx-auto mt-4" type="submit">
<x-inputs.button class="flex mx-auto mt-4" type="submit">
Submit
</button>
</x-inputs.button>
</form>
<div class="flex flex-col pt-4 text-right w-52">
<x-form-input instantSave type="checkbox" id="is_static" label="Static website?" />
<x-form-input instantSave type="checkbox" id="is_auto_deploy" label="Auto Deploy?" />
<x-form-input instantSave type="checkbox" id="is_dual_cert" label="Dual Certs?" />
<x-form-input instantSave type="checkbox" id="is_previews" label="Previews?" />
<x-form-input instantSave type="checkbox" id="is_custom_ssl" label="Is Custom SSL?" />
<x-form-input instantSave type="checkbox" id="is_http2" label="Is Http2?" />
<x-form-input instantSave type="checkbox" id="is_git_submodules_allowed" label="Git Submodules Allowed?" />
<x-form-input instantSave type="checkbox" id="is_git_lfs_allowed" label="Git LFS Allowed?" />
<x-form-input instantSave type="checkbox" id="is_debug" label="Debug" />
<x-inputs.input instantSave type="checkbox" id="is_static" label="Static website?" />
<x-inputs.input instantSave type="checkbox" id="is_auto_deploy" label="Auto Deploy?" />
<x-inputs.input instantSave type="checkbox" id="is_dual_cert" label="Dual Certs?" />
<x-inputs.input instantSave type="checkbox" id="is_previews" label="Previews?" />
<x-inputs.input instantSave type="checkbox" id="is_custom_ssl" label="Is Custom SSL?" />
<x-inputs.input instantSave type="checkbox" id="is_http2" label="Is Http2?" />
<x-inputs.input instantSave type="checkbox" id="is_git_submodules_allowed" label="Git Submodules Allowed?" />
<x-inputs.input instantSave type="checkbox" id="is_git_lfs_allowed" label="Git LFS Allowed?" />
<x-inputs.input instantSave type="checkbox" id="is_debug" label="Debug" />
</div>
</div>

View File

@ -1,9 +1,9 @@
<div>
<p>Source Name: {{ data_get($application,'source.name') }}</p>
<p>Is Public Source: {{ data_get($application,'source.is_public') }}</p>
<p>Source Name: {{ data_get($application, 'source.name') }}</p>
<p>Is Public Source: {{ data_get($application, 'source.is_public') }}</p>
<div class="flex flex-col w-96">
<x-form-input id="application.git_repository" label="Git Repository" readonly />
<x-form-input id="application.git_branch" label="Git Branch" readonly />
<x-form-input id="application.git_commit_sha" label="Git Commit SHA" readonly />
<x-inputs.input id="application.git_repository" label="Git Repository" readonly />
<x-inputs.input id="application.git_branch" label="Git Branch" readonly />
<x-inputs.input id="application.git_commit_sha" label="Git Commit SHA" readonly />
</div>
</div>

View File

@ -1 +1 @@
<button wire:click='createEmptyProject'>Empty Project</button>
<x-inputs.button wire:click='createEmptyProject'>Empty Project</x-inputs.button>

View File

@ -1,35 +1,71 @@
<div>
@if ($servers->count() > 0)
<h1>Choose a server</h1>
@endif
@forelse ($servers as $server)
<button @if ($chosenServer == $server->id) class="bg-blue-500" @endif
wire:click="chooseServer({{ $server->id }})">{{ $server->name }}</button>
@if ($chosenServer && $chosenServer['id'] === $server->id)
<x-inputs.button class="bg-blue-500" wire:click="chooseServer({{ $server }})">{{ $server->name }}
</x-inputs.button>
@else
<x-inputs.button wire:click="chooseServer({{ $server }})">{{ $server->name }}</x-inputs.button>
@endif
@empty
No servers
No servers found.
<p>Did you forget to add a destination on the server?</p>
@endforelse
@isset($chosenServer)
<div>
@foreach ($standalone_docker as $standalone)
<button @if ($chosenDestination?->uuid == $standalone->uuid) class="bg-blue-500" @endif
wire:click="setDestination('{{ $standalone->uuid }}','StandaloneDocker')">{{ $standalone->network }}</button>
@endforeach
@foreach ($swarm_docker as $standalone)
<button @if ($chosenDestination?->uuid == $standalone->uuid) class="bg-blue-500" @endif
wire:click="setDestination('{{ $standalone->uuid }}','SwarmDocker')">{{ $standalone->uuid }}</button>
@endforeach
</div>
@if ($standalone_docker->count() > 0 || $swarm_docker->count() > 0)
<h1>Choose a destination</h1>
<div>
@foreach ($standalone_docker as $standalone)
@if ($chosenDestination?->uuid == $standalone->uuid)
<x-inputs.button class="bg-blue-500"
wire:click="setDestination('{{ $standalone->uuid }}','StandaloneDocker')">
{{ $standalone->network }}</x-inputs.button>
@else
<x-inputs.button wire:click="setDestination('{{ $standalone->uuid }}','StandaloneDocker')">
{{ $standalone->network }}</x-inputs.button>
@endif
@endforeach
@foreach ($swarm_docker as $standalone)
@if ($chosenDestination?->uuid == $standalone->uuid)
<x-inputs.button class="bg-blue-500"
wire:click="setDestination('{{ $standalone->uuid }}','SwarmDocker')">
{{ $standalone->network }}</x-inputs.button>
@else
<x-inputs.button wire:click="setDestination('{{ $standalone->uuid }}','SwarmDocker')">
{{ $standalone->uuid }}</x-inputs.button>
@endif
@endforeach
</div>
<div>
<a href="{{ route('destination.new', ['server_id' => $chosenServer['id']]) }}">Add
a new
destination</a>
</div>
@else
<h1>No destinations found on this server.</h1>
<a href="{{ route('destination.new', ['server_id' => $chosenServer['id']]) }}">Add
a
destination</a>
@endif
@endisset
@isset($chosenDestination)
<form wire:submit.prevent='submit'>
<x-form-input id="public_repository_url" label="Repository URL" />
<x-form-input instantSave type="checkbox" id="is_static" label="Static Site?" />
<h1>Choose a repository</h1>
<form class="flex flex-col gap-2 w-96" wire:submit.prevent='submit'>
<x-inputs.input class="w-96" id="public_repository_url" label="Repository URL" />
<x-inputs.input instantSave type="checkbox" id="is_static" label="Static Site?" />
@if ($is_static)
<x-form-input id="publish_directory" label="Publish Directory" />
<x-inputs.input id="publish_directory" label="Publish Directory" />
@else
<x-form-input type="number" id="port" label="Port" :disabled="$is_static" />
<x-inputs.input type="number" id="port" label="Port" :disabled="$is_static" />
@endif
<button type="submit">
<x-inputs.button type="submit">
Submit
</button>
</x-inputs.button>
</form>
@endisset

View File

@ -1,16 +1,16 @@
<div>
<div>
<label for="command">
<input autofocus id="command" wire:model.defer="command" type="text" wire:keydown.enter="runCommand"/>
<input autofocus id="command" wire:model.defer="command" type="text" wire:keydown.enter="runCommand" />
<select wire:model.defer="server">
@foreach ($servers as $server)
<option value="{{ $server->uuid }}">{{ $server->name }}</option>
@endforeach
</select>
</label>
<button wire:click="runCommand">Run command</button>
<button wire:click="runSleepingBeauty">Run sleeping beauty</button>
<button wire:click="runDummyProjectBuild">Build DummyProject</button>
<x-inputs.button wire:click="runCommand">Run command</x-inputs.button>
<x-inputs.button wire:click="runSleepingBeauty">Run sleeping beauty</x-inputs.button>
<x-inputs.button wire:click="runDummyProjectBuild">Build DummyProject</x-inputs.button>
</div>
<div>
@ -21,9 +21,6 @@
@endif
</div>
@isset($activity?->id)
<pre
style="width: 100%;overflow-y: scroll;"
@if ($isKeepAliveOn) wire:poll.750ms="polling" @endif
>{{ \App\Actions\CoolifyTask\RunRemoteProcess::decodeOutput($activity) }}</pre>
<pre style="width: 100%;overflow-y: scroll;" @if ($isKeepAliveOn) wire:poll.750ms="polling" @endif>{{ \App\Actions\CoolifyTask\RunRemoteProcess::decodeOutput($activity) }}</pre>
@endisset
</div>

View File

@ -2,30 +2,27 @@
<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-form-input id="server.name" label="Name" required />
<x-form-input id="server.description" label="Description" />
<x-inputs.input id="server.name" label="Name" required />
<x-inputs.input id="server.description" label="Description" />
</div>
<div class="flex flex-col w-96">
@if ($server->id === 0)
<x-form-input id="server.ip" label="IP Address" readonly />
<x-form-input id="server.user" label="User" readonly />
<x-form-input type="number" id="server.port" label="Port" readonly />
<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 />
@else
<x-form-input id="server.ip" label="IP Address" required readonly />
<x-form-input id="server.user" label="User" required />
<x-form-input type="number" id="server.port" label="Port" required />
<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 />
@endif
</div>
</div>
<div>
<button class="w-16 mt-4" type="submit">
Submit
</button>
<button wire:click.prevent='checkServer'>Check Server</button>
<button class="bg-red-500" @confirm.window="$wire.delete()"
x-on:click="toggleConfirmModal('Are you sure you would like to delete this application?')">
Delete</button>
{{-- <button wire:click.prevent='installDocker'>Install Docker</button> --}}
<x-inputs.button type="submit">Submit</x-inputs.button>
<x-inputs.button wire:click.prevent='checkServer'>Check Server</x-inputs.button>
<x-inputs.button class="bg-red-500" confirm="Are you sure you would like to delete this application?"
confirmAction="delete">Delete
</x-inputs.button>
</div>
</form>
@isset($uptime)

View File

@ -1,33 +1,31 @@
<div>
<form class="flex flex-col" wire:submit.prevent='submit'>
<x-form-input id="name" label="Name" required />
<x-form-input id="description" label="Description" />
<x-form-input id="ip" label="IP Address" required />
<x-form-input id="user" label="User" />
<x-form-input type="number" id="port" label="Port" />
<x-form-input id="private_key_id" label="Private Key" required hidden />
<button class="mt-4" type="submit">
<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" />
<x-inputs.input id="private_key_id" label="Private Key" required hidden />
<x-inputs.button class="mt-4" type="submit">
Submit
</button>
</x-inputs.button>
</form>
<div class="flex gap-4">
<div>
<h1>Select a private key</h1>
@foreach ($private_keys as $key)
<button @if ($private_key_id == $key->id) class="bg-green-500" @endif
wire:click.defer="setPrivateKey('{{ $key->id }}')">{{ $key->name }}</button>
@if ($private_key_id == $key->id)
<x-inputs.button class="bg-blue-500" wire:click.defer="setPrivateKey('{{ $key->id }}')">
{{ $key->name }}</x-inputs.button>
@else
<x-inputs.button wire:click.defer="setPrivateKey('{{ $key->id }}')">{{ $key->name }}
</x-inputs.button>
@endif
@endforeach
</div>
<div>
<h2>Add a new One</h2>
<form class="flex flex-col gap-2" wire:submit.prevent='addPrivateKey'>
<x-form-input id="new_private_key_name" label="Name" required />
<x-form-input id="new_private_key_description" label="Longer Description" />
<x-form-input type="textarea" id="new_private_key_value" label="Private Key" required />
<button type="submit">
Submit
</button>
</form>
<livewire:private-key.create />
</div>
</div>
</div>

View File

@ -0,0 +1,7 @@
<div>
@forelse ($private_keys as $private_key)
<x-inputs.button wire:click='setPrivateKey({{ $private_key->id }})'>{{ $private_key->name }}</x-inputs.button>
@empty
<p>No private keys found</p>
@endforelse
</div>

View File

@ -2,22 +2,22 @@
<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-form-input id="settings.fqdn" label="FQDN" />
<x-form-input id="settings.wildcard_domain" label="Wildcard Domain" />
<x-inputs.input id="settings.fqdn" label="FQDN" />
<x-inputs.input id="settings.wildcard_domain" label="Wildcard Domain" />
</div>
<div class="flex flex-col w-96">
<x-form-input type="number" id="settings.public_port_min" label="Public Port Min" />
<x-form-input type="number" id="settings.public_port_max" label="Public Port Max" />
<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>
</div>
<button class="w-16 mt-4" type="submit">
<x-inputs.button class="w-16 mt-4" type="submit">
Submit
</button>
</x-inputs.button>
</form>
<div class="flex flex-col pt-4 text-right w-52">
<x-form-input instantSave type="checkbox" id="do_not_track" label="Do Not Track" />
<x-form-input instantSave type="checkbox" id="is_auto_update_enabled" label="Auto Update?" />
<x-form-input instantSave type="checkbox" id="is_registration_enabled" label="Registration Enabled?" />
<x-form-input instantSave type="checkbox" id="is_https_forced" label="Force https?" />
<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?" />
</div>
</div>

View File

@ -1,6 +1,6 @@
<div>
@foreach (auth()->user()->otherTeams() as $team)
<button wire:key="{{ $team->id }}" wire:click="switch_to('{{ $team->id }}')">Switch to:
{{ $team->name }}</button>
<x-inputs.button wire:key="{{ $team->id }}" wire:click="switch_to('{{ $team->id }}')">Switch to:
{{ $team->name }}</x-inputs.button>
@endforeach
</div>

View File

@ -0,0 +1,4 @@
<x-layout>
<h1>New Private Key</h1>
<livewire:private-key.create />
</x-layout>

View File

@ -0,0 +1,4 @@
<x-layout>
<h1>Private Key</h1>
<livewire:private-key.change :private_key_uuid="$private_key->uuid" />
</x-layout>

View File

@ -3,16 +3,16 @@
<x-applications.navbar :applicationId="$application->id" />
<div x-data="{ activeTab: 'general' }">
<div class="flex gap-4">
<a :class="activeTab === 'general' && 'text-green-500'" @click.prevent="activeTab = 'general'"
<a :class="activeTab === 'general' && 'text-purple-500'" @click.prevent="activeTab = 'general'"
href="#">General</a>
<a :class="activeTab === 'envs' && 'text-green-500'" @click.prevent="activeTab = 'envs'"
<a :class="activeTab === 'envs' && 'text-purple-500'" @click.prevent="activeTab = 'envs'"
href="#">Environment Variables</a>
<a :class="activeTab === 'source' && 'text-green-500'" @click.prevent="activeTab = 'source'"
<a :class="activeTab === 'source' && 'text-purple-500'" @click.prevent="activeTab = 'source'"
href="#">Source</a>
<a :class="activeTab === 'destination' && 'text-green-500'" @click.prevent="activeTab = 'destination'"
<a :class="activeTab === 'destination' && 'text-purple-500'" @click.prevent="activeTab = 'destination'"
href="#">Destination
</a>
<a :class="activeTab === 'storages' && 'text-green-500'" @click.prevent="activeTab = 'storages'"
<a :class="activeTab === 'storages' && 'text-purple-500'" @click.prevent="activeTab = 'storages'"
href="#">Storage
</a>
</div>

View File

@ -6,8 +6,9 @@
@endif
<div x-data="{ activeTab: 'choose' }">
<div class="flex flex-col w-64 gap-2 mb-10">
<button @click.prevent="activeTab = 'public-repo'">Public Repository</button>
<button @click.prevent="activeTab = 'github-private-repo'">Private Repository (GitHub App)</button>
<x-inputs.button @click.prevent="activeTab = 'public-repo'">Public Repository</x-inputs.button>
<x-inputs.button @click.prevent="activeTab = 'github-private-repo'">Private Repository (GitHub App)
</x-inputs.button>
@if ($type === 'project')
<livewire:project.new.empty-project />
@endif
@ -19,8 +20,5 @@
<div x-cloak x-show="activeTab === 'github-private-repo'">
github-private-repo
</div>
<div x-cloak x-show="activeTab === 'choose'">
Choose any option
</div>
</div>
</x-layout>

View File

@ -1,5 +1,7 @@
<x-layout>
<h1>Resources <a href="{{ route('project.resources.new', Route::current()->parameters()) }}"><button>New</button></a>
<h1>Resources <a href="{{ route('project.resources.new', Route::current()->parameters()) }}">
<x-inputs.button>New</x-inputs.button>
</a>
</h1>
<div>
@foreach ($environment->applications as $application)

View File

@ -0,0 +1,4 @@
<x-layout>
<h1>Select a private Key</h1>
<livewire:server.private-key />
</x-layout>

View File

@ -1,7 +1,14 @@
<x-layout>
<h1>Server</h1>
<livewire:server.form :server_id="$server->id" />
<h2>Destinations</h2>
<h2>Private Key <a href="{{ route('server.private-key', ['server_uuid' => $server->uuid]) }}">
<x-inputs.button>Change</x-inputs.button>
</a>
</h2>
<p>{{ $server->privateKey->name }}</p>
<h2>Destinations <a href="{{ route('destination.new', ['server_id' => $server->id]) }}">
<x-inputs.button>New</x-inputs.button>
</a></h2>
@if ($server->standaloneDockers)
@foreach ($server->standaloneDockers as $docker)
<p>Network: {{ data_get($docker, 'network') }}</p>

View File

@ -4,6 +4,7 @@
use App\Http\Controllers\HomeController;
use App\Http\Controllers\ProjectController;
use App\Models\InstanceSettings;
use App\Models\PrivateKey;
use App\Models\StandaloneDocker;
use App\Models\SwarmDocker;
use App\Http\Controllers\ServerController;
@ -29,10 +30,13 @@
$destinations = $servers->map(function ($server) {
return $server->standaloneDockers->merge($server->swarmDockers);
})->flatten();
$private_keys = session('currentTeam')->load(['privateKeys'])->privateKeys;
return view('dashboard', [
'servers' => $servers->sortBy('name'),
'projects' => $projects->sortBy('name'),
'destinations' => $destinations->sortBy('name'),
'private_keys' => $private_keys->sortBy('name'),
]);
})->name('dashboard');
Route::get('/project/{project_uuid}', [ProjectController::class, 'environments'])->name('project.environments');
@ -70,6 +74,15 @@
})->name('demo');
});
Route::middleware(['auth'])->group(function () {
Route::get('/private-key/new', fn () => view('private-key.new'))->name('private-key.new');
Route::get('/private-key/{private_key_uuid}', function () {
$private_key = PrivateKey::where('uuid', request()->private_key_uuid)->first();
return view('private-key.show', [
'private_key' => $private_key,
]);
})->name('private-key.show');
});
Route::middleware(['auth'])->group(function () {
Route::get('/server/new', fn () => view('server.new'))->name('server.new');
Route::get('/server/{server_uuid}', function () {
@ -81,10 +94,22 @@
'server' => $server,
]);
})->name('server.show');
Route::get('/server/{server_uuid}/private-key', function () {
return view('server.private-key');
})->name('server.private-key');
});
Route::middleware(['auth'])->group(function () {
Route::get('/destination/new', fn () => view('destination.new'))->name('destination.new');
Route::get('/destination/new', function () {
$query_params = request()->query();
$server_id = null;
if (isset($query_params['server_id'])) {
$server_id = $query_params['server_id'];
}
return view('destination.new', [
'server_id' => $server_id,
]);
})->name('destination.new');
Route::get('/destination/{destination_uuid}', function () {
$standalone_dockers = StandaloneDocker::where('uuid', request()->destination_uuid)->first();
$swarm_dockers = SwarmDocker::where('uuid', request()->destination_uuid)->first();