sprinkle some css

This commit is contained in:
Andras Bacsai 2023-05-12 15:39:07 +02:00
parent 0731b1fe6e
commit d6dc540236
21 changed files with 285 additions and 175 deletions

View File

@ -2,8 +2,6 @@
namespace App\Http\Livewire;
use App\Models\Server;
use Illuminate\Support\Facades\Http;
use Livewire\Component;
class CheckUpdate extends Component

View File

@ -27,7 +27,9 @@ public function mount()
if (request()->query('server_id')) {
$this->server_id = request()->query('server_id');
} else {
$this->server_id = Server::validated()->first()->id;
if ($this->servers->count() > 0) {
$this->server_id = $this->servers->first()->id;
}
}
}
$this->network = new Cuid2(7);

View File

@ -3,15 +3,14 @@
namespace App\Http\Livewire\PrivateKey;
use App\Models\PrivateKey;
use Illuminate\Routing\Route as RoutingRoute;
use Illuminate\Support\Facades\Route;
use Livewire\Component;
class Create extends Component
{
public $private_key_value;
public $private_key_name;
public $private_key_description;
public string $name;
public string|null $description;
public string $value;
public string $currentRoute;
public function mount()
@ -20,14 +19,14 @@ public function mount()
}
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";
$this->value = trim($this->value);
if (!str_ends_with($this->value, "\n")) {
$this->value .= "\n";
}
$new_private_key = PrivateKey::create([
'name' => $this->private_key_name,
'description' => $this->private_key_description,
'private_key' => $this->private_key_value,
'name' => $this->name,
'description' => $this->description,
'private_key' => $this->value,
'team_id' => session('currentTeam')->id
]);
session('currentTeam')->privateKeys = PrivateKey::where('team_id', session('currentTeam')->id)->get();

View File

@ -8,7 +8,7 @@
class RunCommand extends Component
{
public $command;
public string $command;
public $server;
public $servers = [];
@ -16,16 +16,20 @@ class RunCommand extends Component
'server' => 'required',
'command' => 'required',
];
public function mount()
public function mount($servers)
{
$this->servers = Server::where('team_id', session('currentTeam')->id)->get();
$this->server = $this->servers[0]->uuid;
$this->servers = $servers;
$this->server = $servers[0]->uuid;
}
public function runCommand()
{
try {
$this->validate();
$activity = remoteProcess([$this->command], Server::where('uuid', $this->server)->first(), ActivityTypes::INLINE->value);
$this->emit('newMonitorActivity', $activity->id);
} catch (\Exception $e) {
return generalErrorHandler($e);
}
}
}

View File

@ -9,7 +9,7 @@
class ByIp extends Component
{
public $private_keys;
public int $private_key_id;
public int|null $private_key_id = null;
public $new_private_key_name;
public $new_private_key_description;
public $new_private_key_value;
@ -20,21 +20,28 @@ class ByIp extends Component
public string $user = 'root';
public int $port = 22;
protected $rules = [
'name' => 'required',
'ip' => 'required',
'user' => 'required',
'port' => 'required|integer',
];
public function mount()
{
$this->name = generateRandomName();
$this->private_keys = PrivateKey::where('team_id', session('currentTeam')->id)->get();
}
public function setPrivateKey($private_key_id)
public function setPrivateKey(string $private_key_id)
{
$this->private_key_id = $private_key_id;
}
public function submit()
{
try {
if (!$this->private_key_id) {
$this->addError('private_key_id', 'The private key field is required.');
return;
return $this->emit('error', 'You must select a private key');
}
$this->validate();
$server = Server::create([
'name' => $this->name,
'description' => $this->description,
@ -45,5 +52,8 @@ public function submit()
'private_key_id' => $this->private_key_id
]);
return redirect()->route('server.show', $server->uuid);
} catch (\Exception $e) {
return generalErrorHandler($e);
}
}
}

View File

@ -40,7 +40,7 @@ function generalErrorHandler(\Throwable $e, $that = null, $isJson = false)
'error' => $error->getMessage(),
]);
} else {
dump('Duplicate entry found.');
dump($error);
}
}
}

View File

@ -1,18 +1,16 @@
/* @tailwind base; */
@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;
@apply bg-coolgray-100 text-white font-sans;
}
input, textarea {
@apply border-none p-2 bg-neutral-800 text-white disabled:text-neutral-600 read-only:text-neutral-600 read-only:select-none
@apply border-none p-2 bg-coolgray-200 text-white disabled:text-neutral-600 read-only:text-neutral-600 read-only:select-none outline-none ;
}
select {
@apply border-none p-2 bg-neutral-800 text-white disabled:text-neutral-600 read-only:select-none
@apply border-none p-2 bg-coolgray-200 text-white disabled:text-neutral-600 read-only:select-none outline-none;
}
button {
@ -23,13 +21,13 @@ .main-menu {
}
.main-menu:after {
content: '/';
@apply absolute right-0 top-0 text-neutral-400 px-2 pt-1;
@apply absolute right-0 top-0 text-neutral-400 px-2 pt-[0.3rem];
}
.magic-input {
@apply w-96 rounded shadow outline-none focus:bg-neutral-700;
@apply w-[25rem] rounded shadow outline-none focus:bg-neutral-700 text-white;
}
.magic-items {
@apply text-xs absolute top-11 w-[25rem] bg-neutral-800;
@apply absolute top-14 w-[25rem] bg-coolgray-200 border-b-2 border-r-2 border-l-2 border-solid border-coolgray-100 rounded-b;
}
.magic-item {
@apply m-2 py-2 pl-4 cursor-pointer hover:bg-neutral-700 text-neutral-300 hover:text-white;
@ -37,3 +35,12 @@ .magic-item {
.magic-item-focused {
@apply bg-neutral-700 text-white;
}
h1 {
@apply text-3xl font-bold py-4;
}
h2 {
@apply text-xl font-bold py-4;
}
.box {
@apply flex items-center justify-center text-sm rounded cursor-pointer h-14 bg-coolgray-200 hover:bg-coollabs p-2;
}

View File

@ -1,3 +1,3 @@
<x-layout>
<livewire:run-command />
<livewire:run-command :servers="$servers" />
</x-layout>

View File

@ -1,10 +1,10 @@
@props([
'isWarning' => null,
'disabled' => null,
'defaultClass' => 'text-white bg-neutral-800 hover:bg-violet-600 h-8',
'defaultWarningClass' => 'text-white bg-red-500 hover:bg-red-600 h-8',
'disabledClass' => 'text-neutral-400 bg-neutral-900 h-8',
'loadingClass' => 'text-black bg-green-500 h-8',
'defaultClass' => 'text-white hover:bg-coollabs h-8 rounded transition-colors',
'defaultWarningClass' => 'text-white bg-red-500 hover:bg-red-600 h-8 rounded',
'disabledClass' => 'text-coolgray-200 h-8 rounded',
'loadingClass' => 'text-black bg-green-500 h-8 rounded',
'confirm' => null,
'confirmAction' => null,
])

View File

@ -6,6 +6,7 @@
'instantSave' => $attributes->has('instantSave'),
'noLabel' => $attributes->has('noLabel'),
'noDirty' => $attributes->has('noDirty'),
'hidden' => $attributes->has('hidden'),
])
<span @class([
@ -14,7 +15,7 @@
])>
@if (!$noLabel)
<label for={{ $id }} @if (!$noDirty) wire:dirty.class="text-amber-300" @endif
wire:target={{ $id }}>
@if ($hidden) class="hidden" @endif wire:target={{ $id }}>
@if ($label)
{{ $label }}
@else
@ -23,6 +24,7 @@
@if ($required)
*
@endif
</label>
@endif
@if ($type === 'textarea')
@ -32,7 +34,8 @@
<input {{ $attributes }} @if ($required) required @endif
@if (!$noDirty) wire:dirty.class="text-black bg-amber-300" @endif
type={{ $type }} id={{ $id }} name={{ $id }}
@if ($instantSave) wire:click='instantSave' wire:model.defer={{ $id }} @else wire:model.defer={{ $value ?? $id }} @endif />
@if ($instantSave) wire:click='instantSave' wire:model.defer={{ $id }} @else wire:model.defer={{ $value ?? $id }} @endif
@if ($hidden) class="hidden" @endif />
@endif
@error($id)
<div class="text-red-500">{{ $message }}</div>

View File

@ -4,6 +4,8 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="preconnect" href="https://api.fonts.coollabs.io" crossorigin>
<link href="https://api.fonts.coollabs.io/css2?family=Inter&display=swap" rel="stylesheet">
@env('local')
<title>Coolify - localhost</title>
@endenv
@ -28,7 +30,7 @@ class="fixed text-xs cursor-pointer left-2 bottom-1 opacity-20 hover:opacity-100
@auth
<x-navbar />
@endauth
<main>
<main class="max-w-6xl pt-10 mx-auto">
{{ $slot }}
</main>

View File

@ -1,4 +1,4 @@
<div x-data="magicsearchbar" @slash.window="mainMenu = true">
<div x-data="magicsearchbar" @slash.window="mainMenu = true" class="pt-2">
{{-- Main --}}
<template x-cloak x-if="isMainMenu">
<div>
@ -13,11 +13,11 @@
<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="px-2 mr-1 text-xs bg-green-600 rounded" x-show="item.type === 'Add'"
<span class="px-2 mr-1 text-xs text-white bg-green-600 rounded" x-show="item.type === 'Add'"
x-text="item.type"></span>
<span class="px-2 mr-1 text-xs bg-purple-600 rounded" x-show="item.type === 'Jump'"
<span class="px-2 mr-1 text-xs text-white bg-purple-600 rounded" x-show="item.type === 'Jump'"
x-text="item.type"></span>
<span class="px-2 mr-1 text-xs bg-blue-600 rounded" x-show="item.type === 'New'"
<span class="px-2 mr-1 text-xs text-white bg-blue-600 rounded" x-show="item.type === 'New'"
x-text="item.type"></span>
<span x-text="item.name"></span>
</div>
@ -32,10 +32,15 @@
x-on:keydown.down="focusNext(servers.length)" x-on:keydown.up="focusPrev(servers.length)"
x-on:keyup.enter="focusedIndex !== '' && await set('destination',filteredServers()[focusedIndex].uuid)" />
<div class="magic-items">
<template x-if="servers.length === 0">
<div class="magic-item" x-on:click="set('newServer')">
<span>No server found. Click here to add a new one!</span>
</div>
</template>
<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="px-2 mr-1 text-xs bg-purple-600 rounded">Server</span>
<span class="px-2 mr-1 text-xs text-white bg-purple-600 rounded">Server</span>
<span x-text="server.name"></span>
</div>
</template>
@ -47,6 +52,7 @@
<div x-on:click.outside="closeMenus">
<input class="magic-input" x-ref="search" x-model="search" placeholder="Select a destination..."
x-on:keydown.down="focusNext(destinations.length)" x-on:keydown.up="focusPrev(destinations.length)"
x-on:keyup.escape="closeMenus"
x-on:keyup.enter="focusedIndex !== '' && await set('project',filteredDestinations()[focusedIndex].uuid)" />
<div class="magic-items">
<template x-if="destinations.length === 0">
@ -57,18 +63,19 @@
<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="px-2 mr-1 text-xs bg-purple-700 rounded">Destination</span>
<span class="px-2 mr-1 text-xs text-white bg-purple-700 rounded">Destination</span>
<span x-text="destination.name"></span>
</div>
</template>
</div>
</div>
</template>
{{-- Projects --}}
{{-- Project --}}
<template x-cloak x-if="projectMenu">
<div x-on:click.outside="closeMenus">
<input class="magic-input" x-ref="search" x-model="search" placeholder="Type your project name..."
x-on:keydown.down="focusNext(projects.length + 1)" x-on:keydown.up="focusPrev(projects.length + 1)"
x-on:keyup.escape="closeMenus"
x-on:keyup.enter="focusedIndex !== '' && await set('environment',filteredProjects()[focusedIndex - 1]?.uuid)" />
<div class="magic-items">
<div x-on:click="await newProject" class="magic-item"
@ -79,7 +86,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="px-2 mr-1 text-xs bg-purple-700 rounded">Project</span>
<span class="px-2 mr-1 text-xs text-white bg-purple-700 rounded">Project</span>
<span x-text="project.name"></span>
</div>
</template>
@ -91,7 +98,7 @@
<div x-on:click.outside="closeMenus">
<input class="magic-input" x-ref="search" x-model="search" placeholder="Select a environment..."
x-on:keydown.down="focusNext(environments.length + 1)"
x-on:keydown.up="focusPrev(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)" />
<div class="magic-items">
<div x-on:click="await newEnvironment" class="magic-item"
@ -102,7 +109,7 @@
<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="px-2 mr-1 text-xs bg-purple-700 rounded">Env</span>
<span class="px-2 mr-1 text-xs text-white bg-purple-700 rounded">Env</span>
<span x-text="environment.name"></span>
</div>
</template>
@ -113,14 +120,20 @@
<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:keydown.down="focusNext(projects.length)" x-on:keydown.up="focusPrev(projects.length)"
x-on:keyup.enter="focusedIndex !== '' && await set('jumpToProject',filteredProjects()[focusedIndex].uuid)" />
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">
<div class="magic-item hover:bg-neutral-800">
<span>No projects found.</span>
</div>
</template>
<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="py-2 pl-4 cursor-pointer hover:bg-neutral-700">
<span class="px-2 mr-1 text-xs bg-purple-700 rounded">Jump</span>
<span class="px-2 mr-1 text-xs text-white bg-purple-700 rounded">Jump</span>
<span x-text="project.name"></span>
</div>
</template>
@ -130,10 +143,16 @@ class="py-2 pl-4 cursor-pointer hover:bg-neutral-700">
{{-- Destinations --}}
<template x-cloak x-if="destinationsMenu">
<div x-on:click.outside="closeMenus">
<input x-ref="search" x-model="search" class="magic-items" placeholder="Select a destination..."
x-on:keydown.down="focusNext(destinations.length)" x-on:keydown.up="focusPrev(destinations.length)"
<input x-ref="search" x-model="search" class="magic-input" placeholder="Select a destination..."
x-on:keyup.escape="closeMenus" x-on:keydown.down="focusNext(destinations.length)"
x-on:keydown.up="focusPrev(destinations.length)"
x-on:keyup.enter="focusedIndex !== '' && await set('jumpToDestination',filteredDestinations()[focusedIndex].uuid)" />
<div class="magic-items">
<template x-if="destinations.length === 0">
<div class="magic-item" x-on:click="set('newDestination')">
<span>No destination found. Click here to add a new one!</span>
</div>
</template>
<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'"
@ -203,49 +222,50 @@ class="py-2 pl-4 cursor-pointer hover:bg-neutral-700">
focusedIndex: "",
items: [{
name: 'Server',
type: 'Add',
tags: 'new,server',
next: 'newServer'
},
{
name: 'Destination',
type: 'Add',
tags: 'new,destination',
next: 'newDestination'
},
{
name: 'Private Key',
type: 'Add',
tags: 'new,private-key,ssh,key',
next: 'newPrivateKey'
},
{
name: 'Source',
type: 'Add',
tags: 'new,source,github,gitlab,bitbucket',
next: 'newSource'
},
{
name: 'Public Repository',
type: 'Add',
tags: 'application,public,repository',
tags: 'application,public,repository,github,gitlab,bitbucket,git',
},
{
name: 'Private Repository (with GitHub App)',
type: 'Add',
tags: 'application,private,repository',
tags: 'application,private,repository,github,gitlab,bitbucket,git',
},
{
name: 'Private Repository (with Deploy Key)',
type: 'Add',
tags: 'application,private,repository',
tags: 'application,private,repository,github,gitlab,bitbucket,git',
},
{
name: 'Database',
type: 'Add',
tags: 'data,database,mysql,postgres,sql,sqlite,redis,mongodb,maria,percona',
},
{
name: 'Server',
type: 'New',
tags: 'new,server',
next: 'newServer'
},
{
name: 'Destination',
type: 'New',
tags: 'new,destination',
next: 'newDestination'
},
{
name: 'Private Key',
type: 'New',
tags: 'new,private-key,ssh,key',
next: 'newPrivateKey'
},
{
name: 'Source',
type: 'New',
tags: 'new,source,github,gitlab,bitbucket',
next: 'newSource'
},
{
name: 'Servers',
type: 'Jump',

View File

@ -1,23 +1,31 @@
<nav class="flex gap-2">
@auth
<div class="fixed left-0 top-2">
<a href="/">Home</a>
<a href="/command-center">Command Center</a>
<a href="/profile">Profile</a>
<div class="fixed flex gap-2 left-2 top-2">
<a href="/">
<x-inputs.button>Home</x-inputs.button>
</a>
<a href="/command-center">
<x-inputs.button>Command Center</x-inputs.button>
</a>
<a href="/profile">
<x-inputs.button>Profile</x-inputs.button>
</a>
@if (auth()->user()->isRoot())
<a href="/settings">Settings</a>
<a href="/settings">
<x-inputs.button>Settings</x-inputs.button>
</a>
@endif
</div>
<div class="flex-1"></div>
<x-magic-bar />
<div class="flex-1"></div>
<div class="fixed right-0 flex gap-2 top-2">
<div class="fixed flex gap-2 right-2 top-2">
{{-- <livewire:check-update /> --}}
<livewire:force-upgrade />
<form action="/logout" method="POST">
@csrf
<x-inputs.button type="submit">Logout</x-inputs.button>
</form>
<livewire:check-update />
<livewire:force-upgrade />
</div>
@endauth
</nav>

View File

@ -1,32 +1,56 @@
<x-layout>
@if ($servers->count() === 0)
<div class="flex flex-col items-center justify-center h-full pt-32">
<div class="pb-3">Without a server, you won't be able to do much.</div>
<div class="text-2xl">Let's create <a href="{{ route('server.new') }}"
class="p-2 rounded bg-coollabs hover:bg-coollabs-100">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]) }}">{{ data_get($project, 'name') }}</a>
<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]) }}">{{ data_get($server, 'name') }}</a>
<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]) }}">{{ data_get($destination, 'name') }}</a>
<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]) }}">{{ data_get($private_key, 'name') }}</a>
<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]) }}">{{ data_get($github_app, 'name') }}</a>
<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
</x-layout>

View File

@ -1,9 +1,10 @@
<div>
@isset($this->activity)
<span>Status: {{ $this->activity?->properties->get('status') }}</span>
<pre class="flex flex-col-reverse w-full overflow-y-hidden"
@if ($isPollingActive) wire:poll.750ms="polling" @endif>{{ \App\Actions\CoolifyTask\RunRemoteProcess::decodeOutput($this->activity) }}</pre>
<div
class="flex flex-col-reverse w-full overflow-y-auto border border-solid rounded border-coolgray-300 max-h-[32rem] p-4">
@if ($this->activity)
<pre class="whitespace-pre-wrap" @if ($isPollingActive) wire:poll.750ms="polling" @endif>{{ \App\Actions\CoolifyTask\RunRemoteProcess::decodeOutput($this->activity) }}</pre>
@else
<span>Output will be here...</span>
@endisset
<pre class="whitespace-pre-wrap">Output will be here...</pre>
@endif
</div>
</div>

View File

@ -1,10 +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
<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>
Save Private Key
</x-inputs.button>
</form>
</div>

View File

@ -1,9 +1,13 @@
<div>
<form class="flex items-end justify-center gap-2" wire:submit.prevent='runCommand'>
<x-inputs.input noDirty noLabel id="command" label="Command" required />
<x-inputs.input class="w-[32rem]" autofocus noDirty noLabel id="command" label="Command" required />
<select wire:model.defer="server">
@foreach ($servers as $server)
@if ($loop->first)
<option selected value="{{ $server->uuid }}">{{ $server->name }}</option>
@else
<option value="{{ $server->uuid }}">{{ $server->name }}</option>
@endif
@endforeach
</select>
<x-inputs.button type="submit">Run</x-inputs.button>

View File

@ -1,31 +1,32 @@
<div>
<form class="flex flex-col" wire:submit.prevent='submit'>
<form class="flex flex-col gap-1" wire:submit.prevent='submit'>
<div class="flex items-center gap-2">
<h1>New Server</h1>
<x-inputs.button type="submit">
Save
</x-inputs.button>
</div>
<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
</x-inputs.button>
</form>
<div class="flex gap-4">
<div>
<x-inputs.input id="private_key_id" label="Private Key Id" readonly hidden />
@if ($private_keys->count() > 0)
<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>
@else
<x-inputs.button wire:click.defer="setPrivateKey('{{ $key->id }}')">{{ $key->name }}
</x-inputs.button>
@endif
@endforeach
<div class="box" :class="{ 'bg-coollabs': {{ $private_key_id === $key->id }} }"
wire:click.defer.prevent="setPrivateKey('{{ $key->id }}')">
{{ $key->name }}
</div>
<div>
<h2>Add a new One</h2>
@endforeach
@endif
</form>
@if ($private_keys->count() > 0)
<h2>Or add a new private key</h2>
@else
<h2>Create private key</h2>
@endif
<livewire:private-key.create />
</div>
</div>
</div>

View File

@ -1,4 +1,3 @@
<x-layout>
<h1>New Server</h1>
<livewire:server.new.by-ip />
</x-layout>

View File

@ -130,7 +130,13 @@
})->name('update');
Route::get('/command-center', function () {
return view('command-center');
$servers = Server::validated();
if ($servers->count() === 0) {
return redirect()->route('dashboard');
}
return view('command-center', [
'servers' => $servers,
]);
})->name('command-center');
});

View File

@ -6,7 +6,29 @@ module.exports = {
"./resources/**/*.vue",
],
theme: {
extend: {},
extend: {
fontFamily: {
sans: ['Inter', 'sans-serif'],
},
colors: {
"applications": "#16A34A",
"databases": "#9333EA",
"databases-100": "#9b46ea",
"destinations": "#0284C7",
"sources": "#EA580C",
"services": "#DB2777",
"settings": "#FEE440",
"iam": "#C026D3",
'coollabs': '#6B16ED',
'coollabs-100': '#7317FF',
'coolblack': '#141414',
'coolgray-100': '#181818',
'coolgray-200': '#202020',
'coolgray-300': '#242424',
'coolgray-400': '#282828',
'coolgray-500': '#323232'
}
},
},
plugins: [],
}