fix: service ui structure

This commit is contained in:
Andras Bacsai
2024-12-17 11:13:13 +01:00
parent 99947422c2
commit b7748479d4
6 changed files with 93 additions and 84 deletions

View File

@@ -9,16 +9,22 @@ use Livewire\Component;
class Configuration extends Component class Configuration extends Component
{ {
public $currentRoute;
public $project;
public $environment;
public ?Service $service = null; public ?Service $service = null;
public $applications; public $applications;
public $databases; public $databases;
public array $parameters;
public array $query; public array $query;
public array $parameters;
public function getListeners() public function getListeners()
{ {
$userId = Auth::id(); $userId = Auth::id();
@@ -38,11 +44,21 @@ class Configuration extends Component
public function mount() public function mount()
{ {
$this->parameters = get_route_parameters(); $this->parameters = get_route_parameters();
$this->currentRoute = request()->route()->getName();
$this->query = request()->query(); $this->query = request()->query();
$this->service = Service::whereUuid($this->parameters['service_uuid'])->first(); $project = currentTeam()
if (! $this->service) { ->projects()
return redirect()->route('dashboard'); ->select('id', 'uuid', 'team_id')
} ->where('uuid', request()->route('project_uuid'))
->firstOrFail();
$environment = $project->environments()
->select('id', 'name', 'project_id')
->where('name', request()->route('environment_name'))
->firstOrFail();
$this->service = $environment->services()->whereUuid(request()->route('service_uuid'))->firstOrFail();
$this->project = $project;
$this->environment = $environment;
$this->applications = $this->service->applications->sort(); $this->applications = $this->service->applications->sort();
$this->databases = $this->service->databases->sort(); $this->databases = $this->service->databases->sort();
} }

View File

@@ -2,17 +2,21 @@
<x-resources.breadcrumbs :resource="$application" :parameters="$parameters" :title="$lastDeploymentInfo" :lastDeploymentLink="$lastDeploymentLink" /> <x-resources.breadcrumbs :resource="$application" :parameters="$parameters" :title="$lastDeploymentInfo" :lastDeploymentLink="$lastDeploymentLink" />
<div class="navbar-main"> <div class="navbar-main">
<nav class="flex flex-shrink-0 gap-6 items-center whitespace-nowrap scrollbar min-h-10"> <nav class="flex flex-shrink-0 gap-6 items-center whitespace-nowrap scrollbar min-h-10">
<a href="{{ route('project.application.configuration', $parameters) }}"> <a class="{{ request()->routeIs('project.application.configuration') ? 'dark:text-white' : '' }}"
href="{{ route('project.application.configuration', $parameters) }}">
Configuration Configuration
</a> </a>
<a href="{{ route('project.application.deployment.index', $parameters) }}"> <a class="{{ request()->routeIs('project.application.deployment.index') ? 'dark:text-white' : '' }}"
href="{{ route('project.application.deployment.index', $parameters) }}">
<button>Deployments</button> <button>Deployments</button>
</a> </a>
<a href="{{ route('project.application.logs', $parameters) }}"> <a class="{{ request()->routeIs('project.application.logs') ? 'dark:text-white' : '' }}"
href="{{ route('project.application.logs', $parameters) }}">
<button>Logs</button> <button>Logs</button>
</a> </a>
@if (!$application->destination->server->isSwarm()) @if (!$application->destination->server->isSwarm())
<a href="{{ route('project.application.command', $parameters) }}"> <a class="{{ request()->routeIs('project.application.command') ? 'dark:text-white' : '' }}"
href="{{ route('project.application.command', $parameters) }}">
<button>Terminal</button> <button>Terminal</button>
</a> </a>
@endif @endif

View File

@@ -1,50 +1,42 @@
<div x-data="{ activeTab: window.location.hash ? window.location.hash.substring(1) : 'service-stack' }"> <div>
<x-slot:title> <x-slot:title>
{{ data_get_str($service, 'name')->limit(10) }} > Configuration | Coolify {{ data_get_str($service, 'name')->limit(10) }} > Configuration | Coolify
</x-slot> </x-slot>
<livewire:project.service.navbar :service="$service" :parameters="$parameters" :query="$query" /> <livewire:project.service.navbar :service="$service" :parameters="$parameters" :query="$query" />
<div class="flex flex-col gap-8 pt-6 h-full sm:flex-row">
<div class="flex flex-col gap-2 items-start min-w-fit"> <div class="flex flex-col h-full gap-8 pt-6 sm:flex-row">
<div class="flex flex-col items-start gap-2 min-w-fit">
<a class="menu-item sm:min-w-fit" target="_blank" href="{{ $service->documentation() }}">Documentation <a class="menu-item sm:min-w-fit" target="_blank" href="{{ $service->documentation() }}">Documentation
<x-external-link /></a> <x-external-link /></a>
<a class="menu-item sm:min-w-fit" :class="activeTab === 'service-stack' && 'menu-item-active'" <a class='menu-item' wire:current.exact="menu-item-active"
@click.prevent="activeTab = 'service-stack'; href="{{ route('project.service.configuration', ['project_uuid' => $project->uuid, 'environment_name' => $environment->name, 'service_uuid' => $service->uuid]) }}"
window.location.hash = 'service-stack'" wire:navigate>General</a>
href="#">Service Stack</a> <a class='menu-item' wire:current.exact="menu-item-active"
<a class="menu-item sm:min-w-fit" :class="activeTab === 'environment-variables' && 'menu-item-active'" href="{{ route('project.service.environment-variables', ['project_uuid' => $project->uuid, 'environment_name' => $environment->name, 'service_uuid' => $service->uuid]) }}"
@click.prevent="activeTab = 'environment-variables'; window.location.hash = 'environment-variables'" wire:navigate>Environment Variables</a>
href="#">Environment <a class='menu-item' wire:current.exact="menu-item-active"
Variables</a> href="{{ route('project.service.storages', ['project_uuid' => $project->uuid, 'environment_name' => $environment->name, 'service_uuid' => $service->uuid]) }}"
<a class="menu-item sm:min-w-fit" :class="activeTab === 'storages' && 'menu-item-active'" wire:navigate>Persistent Storages</a>
@click.prevent="activeTab = 'storages'; <a class='menu-item' wire:current.exact="menu-item-active"
window.location.hash = 'storages'" href="{{ route('project.service.scheduled-tasks.show', ['project_uuid' => $project->uuid, 'environment_name' => $environment->name, 'service_uuid' => $service->uuid]) }}"
href="#">Storages</a> wire:navigate>Scheduled Tasks</a>
<a class="menu-item" :class="activeTab === 'scheduled-tasks' && 'menu-item-active'" <a class='menu-item' wire:current.exact="menu-item-active"
@click.prevent="activeTab = 'scheduled-tasks'; window.location.hash = 'scheduled-tasks'" href="{{ route('project.service.webhooks', ['project_uuid' => $project->uuid, 'environment_name' => $environment->name, 'service_uuid' => $service->uuid]) }}"
href="#">Scheduled Tasks wire:navigate>Webhooks</a>
</a> <a class='menu-item' wire:current.exact="menu-item-active"
<a class="menu-item sm:min-w-fit" :class="activeTab === 'logs' && 'menu-item-active'" href="{{ route('project.service.resource-operations', ['project_uuid' => $project->uuid, 'environment_name' => $environment->name, 'service_uuid' => $service->uuid]) }}"
@click.prevent="activeTab = 'logs'; wire:navigate>Resource Operations</a>
window.location.hash = 'logs'"
href="#">Logs</a> <a class='menu-item' wire:current.exact="menu-item-active"
<a class="menu-item sm:min-w-fit" :class="activeTab === 'webhooks' && 'menu-item-active'" href="{{ route('project.service.tags', ['project_uuid' => $project->uuid, 'environment_name' => $environment->name, 'service_uuid' => $service->uuid]) }}"
@click.prevent="activeTab = 'webhooks'; window.location.hash = 'webhooks'" href="#">Webhooks wire:navigate>Tags</a>
</a>
<a class="menu-item sm:min-w-fit" :class="activeTab === 'resource-operations' && 'menu-item-active'" <a class='menu-item' wire:current.exact="menu-item-active"
@click.prevent="activeTab = 'resource-operations'; window.location.hash = 'resource-operations'" href="{{ route('project.service.danger', ['project_uuid' => $project->uuid, 'environment_name' => $environment->name, 'service_uuid' => $service->uuid]) }}"
href="#">Resource Operations wire:navigate>Danger Zone</a>
</a>
<a class="menu-item sm:min-w-fit" :class="activeTab === 'tags' && 'menu-item-active'"
@click.prevent="activeTab = 'tags'; window.location.hash = 'tags'" href="#">Tags
</a>
<a class="menu-item sm:min-w-fit" :class="activeTab === 'danger' && 'menu-item-active'"
@click.prevent="activeTab = 'danger';
window.location.hash = 'danger'"
href="#">Danger Zone
</a>
</div> </div>
<div class="w-full"> <div class="w-full">
<div x-cloak x-show="activeTab === 'service-stack'"> @if (request()->route()->getName() === 'project.service.configuration')
<livewire:project.service.stack-form :service="$service" /> <livewire:project.service.stack-form :service="$service" />
<h3>Services</h3> <h3>Services</h3>
<div class="grid grid-cols-1 gap-2 pt-4 xl:grid-cols-1"> <div class="grid grid-cols-1 gap-2 pt-4 xl:grid-cols-1">
@@ -103,7 +95,7 @@
</div> </div>
<div class="flex items-center px-4"> <div class="flex items-center px-4">
<a class="mx-4 text-xs font-bold hover:underline" <a class="mx-4 text-xs font-bold hover:underline"
href="{{ route('project.service.index', [...$parameters, 'stack_service_uuid' => $application->uuid]) }}"> href="{{ route('project.service.index', ['project_uuid' => $project->uuid, 'environment_name' => $environment->name, 'service_uuid' => $service->uuid, 'stack_service_uuid' => $application->uuid]) }}">
Settings Settings
</a> </a>
@if (str($application->status)->contains('running')) @if (str($application->status)->contains('running'))
@@ -151,12 +143,12 @@
<div class="flex items-center px-4"> <div class="flex items-center px-4">
@if ($database->isBackupSolutionAvailable()) @if ($database->isBackupSolutionAvailable())
<a class="mx-4 text-xs font-bold hover:underline" <a class="mx-4 text-xs font-bold hover:underline"
href="{{ route('project.service.index', [...$parameters, 'stack_service_uuid' => $database->uuid]) }}#backups"> href="{{ route('project.service.index', ['project_uuid' => $project->uuid, 'environment_name' => $environment->name, 'service_uuid' => $service->uuid, 'stack_service_uuid' => $database->uuid]) }}#backups">
Backups Backups
</a> </a>
@endif @endif
<a class="mx-4 text-xs font-bold hover:underline" <a class="mx-4 text-xs font-bold hover:underline"
href="{{ route('project.service.index', [...$parameters, 'stack_service_uuid' => $database->uuid]) }}"> href="{{ route('project.service.index', ['project_uuid' => $project->uuid, 'environment_name' => $environment->name, 'service_uuid' => $service->uuid, 'stack_service_uuid' => $database->uuid]) }}">
Settings Settings
</a> </a>
@if (str($database->status)->contains('running')) @if (str($database->status)->contains('running'))
@@ -173,8 +165,9 @@
</div> </div>
@endforeach @endforeach
</div> </div>
</div> @elseif (request()->route()->getName() === 'project.service.environment-variables')
<div x-cloak x-show="activeTab === 'storages'"> <livewire:project.shared.environment-variable.all :resource="$service" />
@elseif (request()->route()->getName() === 'project.service.storages')
<div class="flex gap-2 items-center"> <div class="flex gap-2 items-center">
<h2>Storages</h2> <h2>Storages</h2>
</div> </div>
@@ -182,35 +175,23 @@
<div class="pb-4 dark:text-warning text-coollabs">If you would like to add a volume, you must add it to <div class="pb-4 dark:text-warning text-coollabs">If you would like to add a volume, you must add it to
your compose file (Service Stack tab).</div> your compose file (Service Stack tab).</div>
@foreach ($applications as $application) @foreach ($applications as $application)
<livewire:project.service.storage wire:key="application-{{ $application->id }}" :resource="$application" <livewire:project.service.storage wire:key="application-{{ $application->id }}"
lazy /> :resource="$application" />
@endforeach @endforeach
@foreach ($databases as $database) @foreach ($databases as $database)
<livewire:project.service.storage wire:key="database-{{ $database->id }}" :resource="$database" <livewire:project.service.storage wire:key="database-{{ $database->id }}" :resource="$database" />
lazy />
@endforeach @endforeach
</div> @elseif (request()->route()->getName() === 'project.service.scheduled-tasks.show')
<div x-cloak x-show="activeTab === 'scheduled-tasks'">
<livewire:project.shared.scheduled-task.all :resource="$service" /> <livewire:project.shared.scheduled-task.all :resource="$service" />
</div> @elseif (request()->route()->getName() === 'project.service.webhooks')
<div x-cloak x-show="activeTab === 'webhooks'">
<livewire:project.shared.webhooks :resource="$service" /> <livewire:project.shared.webhooks :resource="$service" />
</div> @elseif (request()->route()->getName() === 'project.service.resource-operations')
<div x-cloak x-show="activeTab === 'logs'">
<livewire:project.shared.logs :resource="$service" />
</div>
<div x-cloak x-show="activeTab === 'environment-variables'">
<livewire:project.shared.environment-variable.all :resource="$service" />
</div>
<div x-cloak x-show="activeTab === 'resource-operations'">
<livewire:project.shared.resource-operations :resource="$service" /> <livewire:project.shared.resource-operations :resource="$service" />
</div> @elseif (request()->route()->getName() === 'project.service.tags')
<div x-cloak x-show="activeTab === 'tags'">
<livewire:project.shared.tags :resource="$service" /> <livewire:project.shared.tags :resource="$service" />
</div> @elseif (request()->route()->getName() === 'project.service.danger')
<div x-cloak x-show="activeTab === 'danger'">
<livewire:project.shared.danger :resource="$service" /> <livewire:project.shared.danger :resource="$service" />
</div> @endif
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,4 +1,4 @@
<div wire:poll.10000ms="check_status_without_notification"> <div>
<livewire:project.shared.configuration-checker :resource="$service" /> <livewire:project.shared.configuration-checker :resource="$service" />
<x-slide-over @startservice.window="slideOverOpen = true" closeWithX fullScreen> <x-slide-over @startservice.window="slideOverOpen = true" closeWithX fullScreen>
<x-slot:title>Service Startup</x-slot:title> <x-slot:title>Service Startup</x-slot:title>
@@ -14,6 +14,10 @@
href="{{ route('project.service.configuration', $parameters) }}"> href="{{ route('project.service.configuration', $parameters) }}">
<button>Configuration</button> <button>Configuration</button>
</a> </a>
<a class="{{ request()->routeIs('project.service.logs') ? 'dark:text-white' : '' }}"
href="{{ route('project.service.logs', $parameters) }}">
<button>Logs</button>
</a>
<a class="{{ request()->routeIs('project.service.command') ? 'dark:text-white' : '' }}" <a class="{{ request()->routeIs('project.service.command') ? 'dark:text-white' : '' }}"
href="{{ route('project.service.command', $parameters) }}"> href="{{ route('project.service.command', $parameters) }}">
<button>Terminal</button> <button>Terminal</button>

View File

@@ -7,7 +7,6 @@
<h1>Logs</h1> <h1>Logs</h1>
<livewire:project.application.heading :application="$resource" /> <livewire:project.application.heading :application="$resource" />
<div class="pt-4"> <div class="pt-4">
<h2>Logs</h2>
<div class="subtitle">Here you can see the logs of the application.</div> <div class="subtitle">Here you can see the logs of the application.</div>
<div class="pt-2" wire:loading wire:target="loadContainers"> <div class="pt-2" wire:loading wire:target="loadContainers">
Loading containers... Loading containers...
@@ -31,10 +30,8 @@
<h1>Logs</h1> <h1>Logs</h1>
<livewire:project.database.heading :database="$resource" /> <livewire:project.database.heading :database="$resource" />
<div class="pt-4"> <div class="pt-4">
<div class="subtitle">Here you can see the logs of the database.</div>
@forelse ($containers as $container) @forelse ($containers as $container)
@if ($loop->first)
<h2 class="pb-4">Logs</h2>
@endif
@if (data_get($servers, '0')) @if (data_get($servers, '0'))
<livewire:project.shared.get-logs :server="data_get($servers, '0')" :resource="$resource" :container="$container" /> <livewire:project.shared.get-logs :server="data_get($servers, '0')" :resource="$resource" :container="$container" />
@else @else
@@ -45,11 +42,10 @@
@endforelse @endforelse
</div> </div>
@elseif ($type === 'service') @elseif ($type === 'service')
<div> <livewire:project.service.navbar :service="$resource" :parameters="$parameters" :query="$query" title="Logs" />
<div class="pt-4">
<div class="subtitle">Here you can see the logs of the service.</div>
@forelse ($containers as $container) @forelse ($containers as $container)
@if ($loop->first)
<h2 class="pb-4">Logs</h2>
@endif
@if (data_get($servers, '0')) @if (data_get($servers, '0'))
<livewire:project.shared.get-logs :server="data_get($servers, '0')" :resource="$resource" :container="$container" /> <livewire:project.shared.get-logs :server="data_get($servers, '0')" :resource="$resource" :container="$container" />
@else @else

View File

@@ -215,6 +215,14 @@ Route::middleware(['auth', 'verified'])->group(function () {
}); });
Route::prefix('project/{project_uuid}/{environment_name}/service/{service_uuid}')->group(function () { Route::prefix('project/{project_uuid}/{environment_name}/service/{service_uuid}')->group(function () {
Route::get('/', ServiceConfiguration::class)->name('project.service.configuration'); Route::get('/', ServiceConfiguration::class)->name('project.service.configuration');
Route::get('/logs', Logs::class)->name('project.service.logs');
Route::get('/environment-variables', ServiceConfiguration::class)->name('project.service.environment-variables');
Route::get('/storages', ServiceConfiguration::class)->name('project.service.storages');
Route::get('/scheduled-tasks', ServiceConfiguration::class)->name('project.service.scheduled-tasks.show');
Route::get('/webhooks', ServiceConfiguration::class)->name('project.service.webhooks');
Route::get('/resource-operations', ServiceConfiguration::class)->name('project.service.resource-operations');
Route::get('/tags', ServiceConfiguration::class)->name('project.service.tags');
Route::get('/danger', ServiceConfiguration::class)->name('project.service.danger');
Route::get('/terminal', ExecuteContainerCommand::class)->name('project.service.command'); Route::get('/terminal', ExecuteContainerCommand::class)->name('project.service.command');
Route::get('/{stack_service_uuid}', ServiceIndex::class)->name('project.service.index'); Route::get('/{stack_service_uuid}', ServiceIndex::class)->name('project.service.index');
Route::get('/tasks/{task_uuid}', ScheduledTaskShow::class)->name('project.service.scheduled-tasks'); Route::get('/tasks/{task_uuid}', ScheduledTaskShow::class)->name('project.service.scheduled-tasks');