fix: refactor database view

This commit is contained in:
Andras Bacsai
2024-12-17 12:10:55 +01:00
parent 43be0f4075
commit 38256af9b3
7 changed files with 145 additions and 144 deletions

View File

@@ -3,7 +3,6 @@
namespace App\Livewire\Project\Application; namespace App\Livewire\Project\Application;
use App\Models\Application; use App\Models\Application;
use App\Models\Server;
use Livewire\Component; use Livewire\Component;
class Configuration extends Component class Configuration extends Component
@@ -40,15 +39,7 @@ class Configuration extends Component
$this->project = $project; $this->project = $project;
$this->environment = $environment; $this->environment = $environment;
$this->application = $application; $this->application = $application;
if ($application->destination && $application->destination->server) {
$mainServer = $application->destination->server;
$this->servers = Server::ownedByCurrentTeam()
->select('id', 'name')
->where('id', '!=', $mainServer->id)
->get();
} else {
$this->servers = collect();
}
} }
public function render() public function render()

View File

@@ -6,23 +6,34 @@ use Livewire\Component;
class Configuration extends Component class Configuration extends Component
{ {
public $currentRoute;
public $database; public $database;
public $project;
public $environment;
public function mount() public function mount()
{ {
$project = currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first(); $this->currentRoute = request()->route()->getName();
if (! $project) {
return redirect()->route('dashboard'); $project = currentTeam()
} ->projects()
$environment = $project->load(['environments'])->environments->where('name', request()->route('environment_name'))->first()->load(['applications']); ->select('id', 'uuid', 'team_id')
if (! $environment) { ->where('uuid', request()->route('project_uuid'))
return redirect()->route('dashboard'); ->firstOrFail();
} $environment = $project->environments()
$database = $environment->databases()->where('uuid', request()->route('database_uuid'))->first(); ->select('id', 'name', 'project_id')
if (! $database) { ->where('name', request()->route('environment_name'))
return redirect()->route('dashboard'); ->firstOrFail();
} $database = $environment->databases()
->where('uuid', request()->route('database_uuid'))
->firstOrFail();
$this->database = $database; $this->database = $database;
$this->project = $project;
$this->environment = $environment;
if (str($this->database->status)->startsWith('running') && is_null($this->database->config_hash)) { if (str($this->database->status)->startsWith('running') && is_null($this->database->config_hash)) {
$this->database->isConfigurationChanged(true); $this->database->isConfigurationChanged(true);
$this->dispatch('configurationChanged'); $this->dispatch('configurationChanged');

View File

@@ -8,6 +8,7 @@ use App\Events\ApplicationStatusChanged;
use App\Models\InstanceSettings; use App\Models\InstanceSettings;
use App\Models\Server; use App\Models\Server;
use App\Models\StandaloneDocker; use App\Models\StandaloneDocker;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Hash;
use Livewire\Component; use Livewire\Component;
@@ -17,7 +18,7 @@ class Destination extends Component
{ {
public $resource; public $resource;
public $networks = []; public Collection $networks;
public function getListeners() public function getListeners()
{ {
@@ -30,6 +31,7 @@ class Destination extends Component
public function mount() public function mount()
{ {
$this->networks = collect([]);
$this->loadData(); $this->loadData();
} }
@@ -55,38 +57,46 @@ class Destination extends Component
} }
} }
public function stop(int $server_id) public function stop($serverId)
{ {
$server = Server::find($server_id); try {
StopApplicationOneServer::run($this->resource, $server); $server = Server::ownedByCurrentTeam()->findOrFail($serverId);
$this->refreshServers(); StopApplicationOneServer::run($this->resource, $server);
$this->refreshServers();
} catch (\Exception $e) {
return handleError($e, $this);
}
} }
public function redeploy(int $network_id, int $server_id) public function redeploy(int $network_id, int $server_id)
{ {
if ($this->resource->additional_servers->count() > 0 && str($this->resource->docker_registry_image_name)->isEmpty()) { try {
$this->dispatch('error', 'Failed to deploy.', 'Before deploying to multiple servers, you must first set a Docker image in the General tab.<br>More information here: <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/multiple-servers">documentation</a>'); if ($this->resource->additional_servers->count() > 0 && str($this->resource->docker_registry_image_name)->isEmpty()) {
$this->dispatch('error', 'Failed to deploy.', 'Before deploying to multiple servers, you must first set a Docker image in the General tab.<br>More information here: <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/multiple-servers">documentation</a>');
return; return;
}
$deployment_uuid = new Cuid2;
$server = Server::ownedByCurrentTeam()->findOrFail($server_id);
$destination = $server->standaloneDockers->where('id', $network_id)->firstOrFail();
queue_application_deployment(
deployment_uuid: $deployment_uuid,
application: $this->resource,
server: $server,
destination: $destination,
only_this_server: true,
no_questions_asked: true,
);
return redirect()->route('project.application.deployment.show', [
'project_uuid' => data_get($this->resource, 'environment.project.uuid'),
'application_uuid' => data_get($this->resource, 'uuid'),
'deployment_uuid' => $deployment_uuid,
'environment_name' => data_get($this->resource, 'environment.name'),
]);
} catch (\Exception $e) {
return handleError($e, $this);
} }
$deployment_uuid = new Cuid2;
$server = Server::find($server_id);
$destination = StandaloneDocker::find($network_id);
queue_application_deployment(
deployment_uuid: $deployment_uuid,
application: $this->resource,
server: $server,
destination: $destination,
only_this_server: true,
no_questions_asked: true,
);
return redirect()->route('project.application.deployment.show', [
'project_uuid' => data_get($this->resource, 'environment.project.uuid'),
'application_uuid' => data_get($this->resource, 'uuid'),
'deployment_uuid' => $deployment_uuid,
'environment_name' => data_get($this->resource, 'environment.name'),
]);
} }
public function promote(int $network_id, int $server_id) public function promote(int $network_id, int $server_id)
@@ -119,23 +129,27 @@ class Destination extends Component
public function removeServer(int $network_id, int $server_id, $password) public function removeServer(int $network_id, int $server_id, $password)
{ {
if (! data_get(InstanceSettings::get(), 'disable_two_step_confirmation')) { try {
if (! Hash::check($password, Auth::user()->password)) { if (! data_get(InstanceSettings::get(), 'disable_two_step_confirmation')) {
$this->addError('password', 'The provided password is incorrect.'); if (! Hash::check($password, Auth::user()->password)) {
$this->addError('password', 'The provided password is incorrect.');
return;
}
}
if ($this->resource->destination->server->id == $server_id && $this->resource->destination->id == $network_id) {
$this->dispatch('error', 'You cannot remove this destination server.', 'You are trying to remove the main server.');
return; return;
} }
$server = Server::ownedByCurrentTeam()->findOrFail($server_id);
StopApplicationOneServer::run($this->resource, $server);
$this->resource->additional_networks()->detach($network_id, ['server_id' => $server_id]);
$this->loadData();
ApplicationStatusChanged::dispatch(data_get($this->resource, 'environment.project.team.id'));
} catch (\Exception $e) {
return handleError($e, $this);
} }
if ($this->resource->destination->server->id == $server_id && $this->resource->destination->id == $network_id) {
$this->dispatch('error', 'You cannot remove this destination server.', 'You are trying to remove the main server.');
return;
}
$server = Server::find($server_id);
StopApplicationOneServer::run($this->resource, $server);
$this->resource->additional_networks()->detach($network_id, ['server_id' => $server_id]);
$this->loadData();
ApplicationStatusChanged::dispatch(data_get($this->resource, 'environment.project.team.id'));
} }
} }

View File

@@ -98,7 +98,7 @@
@elseif (request()->route()->getName() === 'project.application.source' && $application->git_based()) @elseif (request()->route()->getName() === 'project.application.source' && $application->git_based())
<livewire:project.application.source :application="$application" /> <livewire:project.application.source :application="$application" />
@elseif (request()->route()->getName() === 'project.application.servers') @elseif (request()->route()->getName() === 'project.application.servers')
<livewire:project.shared.destination :resource="$application" :servers="$servers" /> <livewire:project.shared.destination :resource="$application" />
@elseif (request()->route()->getName() === 'project.application.scheduled-tasks.show') @elseif (request()->route()->getName() === 'project.application.scheduled-tasks.show')
<livewire:project.shared.scheduled-task.all :resource="$application" /> <livewire:project.shared.scheduled-task.all :resource="$application" />
@elseif (request()->route()->getName() === 'project.application.webhooks') @elseif (request()->route()->getName() === 'project.application.webhooks')

View File

@@ -5,57 +5,45 @@
<h1>Configuration</h1> <h1>Configuration</h1>
<livewire:project.shared.configuration-checker :resource="$database" /> <livewire:project.shared.configuration-checker :resource="$database" />
<livewire:project.database.heading :database="$database" /> <livewire:project.database.heading :database="$database" />
<div x-data="{ activeTab: window.location.hash ? window.location.hash.substring(1) : 'general' }" class="flex flex-col h-full gap-8 pt-6 sm:flex-row"> <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"> <div class="flex flex-col items-start gap-2 min-w-fit">
<a class="menu-item" :class="activeTab === 'general' && 'menu-item-active'" <a class='menu-item' wire:current.exact="menu-item-active"
@click.prevent="activeTab = 'general'; href="{{ route('project.database.configuration', ['project_uuid' => $project->uuid, 'environment_name' => $environment->name, 'database_uuid' => $database->uuid]) }}"
window.location.hash = 'general'" wire:navigate>General</a>
href="#">General</a> <a class='menu-item' wire:current.exact="menu-item-active"
<a class="menu-item" :class="activeTab === 'environment-variables' && 'menu-item-active'" href="{{ route('project.database.environment-variables', ['project_uuid' => $project->uuid, 'environment_name' => $environment->name, 'database_uuid' => $database->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.database.servers', ['project_uuid' => $project->uuid, 'environment_name' => $environment->name, 'database_uuid' => $database->uuid]) }}"
<a class="menu-item" :class="activeTab === 'servers' && 'menu-item-active'" wire:navigate>Servers</a>
@click.prevent="activeTab = 'servers'; <a class='menu-item' wire:current.exact="menu-item-active"
window.location.hash = 'servers'" href="{{ route('project.database.persistent-storage', ['project_uuid' => $project->uuid, 'environment_name' => $environment->name, 'database_uuid' => $database->uuid]) }}"
href="#">Servers wire:navigate>Persistent Storage</a>
</a> <a class='menu-item' wire:current.exact="menu-item-active"
<a class="menu-item" :class="activeTab === 'storages' && 'menu-item-active'" href="{{ route('project.database.import-backups', ['project_uuid' => $project->uuid, 'environment_name' => $environment->name, 'database_uuid' => $database->uuid]) }}"
@click.prevent="activeTab = 'storages'; wire:navigate>Import Backups</a>
window.location.hash = 'storages'" <a class='menu-item' wire:current.exact="menu-item-active"
href="#">Storages href="{{ route('project.database.webhooks', ['project_uuid' => $project->uuid, 'environment_name' => $environment->name, 'database_uuid' => $database->uuid]) }}"
</a> wire:navigate>Webhooks</a>
<a class="menu-item" :class="activeTab === 'import' && 'menu-item-active'" <a class="menu-item" wire:current.exact="menu-item-active"
@click.prevent="activeTab = 'import'; href="{{ route('project.database.resource-limits', ['project_uuid' => $project->uuid, 'environment_name' => $environment->name, 'database_uuid' => $database->uuid]) }}"
window.location.hash = 'import'" href="#">Import wire:navigate>Resource Limits</a>
Backup
</a> <a class="menu-item" wire:current.exact="menu-item-active"
<a class="menu-item" :class="activeTab === 'webhooks' && 'menu-item-active'" href="{{ route('project.database.resource-operations', ['project_uuid' => $project->uuid, 'environment_name' => $environment->name, 'database_uuid' => $database->uuid]) }}"
@click.prevent="activeTab = 'webhooks'; window.location.hash = 'webhooks'" href="#">Webhooks wire:navigate>Resource Operations</a>
</a> <a class='menu-item' wire:current.exact="menu-item-active"
<a class="menu-item" :class="activeTab === 'resource-limits' && 'menu-item-active'" href="{{ route('project.database.metrics', ['project_uuid' => $project->uuid, 'environment_name' => $environment->name, 'database_uuid' => $database->uuid]) }}"
@click.prevent="activeTab = 'resource-limits'; wire:navigate>Metrics</a>
window.location.hash = 'resource-limits'" <a class='menu-item' wire:current.exact="menu-item-active"
href="#">Resource Limits href="{{ route('project.database.tags', ['project_uuid' => $project->uuid, 'environment_name' => $environment->name, 'database_uuid' => $database->uuid]) }}"
</a> wire:navigate>Tags</a>
<a class="menu-item" :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.database.danger', ['project_uuid' => $project->uuid, 'environment_name' => $environment->name, 'database_uuid' => $database->uuid]) }}"
href="#">Resource Operations wire:navigate>Danger Zone</a>
</a>
<a class="menu-item" :class="activeTab === 'metrics' && 'menu-item-active'"
@click.prevent="activeTab = 'metrics'; window.location.hash = 'metrics'" href="#">Metrics
</a>
<a class="menu-item" :class="activeTab === 'tags' && 'menu-item-active'"
@click.prevent="activeTab = 'tags'; window.location.hash = 'tags'" href="#">Tags
</a>
<a class="menu-item" :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 === 'general'" class="h-full"> @if (request()->route()->getName() === 'project.database.configuration')
@if ($database->type() === 'standalone-postgresql') @if ($database->type() === 'standalone-postgresql')
<livewire:project.database.postgresql.general :database="$database" /> <livewire:project.database.postgresql.general :database="$database" />
@elseif ($database->type() === 'standalone-redis') @elseif ($database->type() === 'standalone-redis')
@@ -73,37 +61,27 @@
@elseif ($database->type() === 'standalone-clickhouse') @elseif ($database->type() === 'standalone-clickhouse')
<livewire:project.database.clickhouse.general :database="$database" /> <livewire:project.database.clickhouse.general :database="$database" />
@endif @endif
</div> @elseif (request()->route()->getName() === 'project.database.environment-variables')
<div x-cloak x-show="activeTab === 'environment-variables'">
<livewire:project.shared.environment-variable.all :resource="$database" /> <livewire:project.shared.environment-variable.all :resource="$database" />
</div> @elseif (request()->route()->getName() === 'project.database.servers')
<div x-cloak x-show="activeTab === 'servers'">
<livewire:project.shared.destination :resource="$database" /> <livewire:project.shared.destination :resource="$database" />
</div> @elseif (request()->route()->getName() === 'project.database.persistent-storage')
<div x-cloak x-show="activeTab === 'storages'">
<livewire:project.service.storage :resource="$database" /> <livewire:project.service.storage :resource="$database" />
</div> @elseif (request()->route()->getName() === 'project.database.import-backups')
<div x-cloak x-show="activeTab === 'webhooks'">
<livewire:project.shared.webhooks :resource="$database" />
</div>
<div x-cloak x-show="activeTab === 'resource-limits'">
<livewire:project.shared.resource-limits :resource="$database" />
</div>
<div x-cloak x-show="activeTab === 'import'">
<livewire:project.database.import :resource="$database" /> <livewire:project.database.import :resource="$database" />
</div> @elseif (request()->route()->getName() === 'project.database.webhooks')
<div x-cloak x-show="activeTab === 'resource-operations'"> <livewire:project.shared.webhooks :resource="$database" />
@elseif (request()->route()->getName() === 'project.database.resource-limits')
<livewire:project.shared.resource-limits :resource="$database" />
@elseif (request()->route()->getName() === 'project.database.resource-operations')
<livewire:project.shared.resource-operations :resource="$database" /> <livewire:project.shared.resource-operations :resource="$database" />
</div> @elseif (request()->route()->getName() === 'project.database.metrics')
<div x-cloak x-show="activeTab === 'metrics'">
<livewire:project.shared.metrics :resource="$database" /> <livewire:project.shared.metrics :resource="$database" />
</div> @elseif (request()->route()->getName() === 'project.database.tags')
<div x-cloak x-show="activeTab === 'tags'"> <livewire:project.shared.tags :resource="$database" />
<livewire:project.shared.tags :resource="$database" lazy /> @elseif (request()->route()->getName() === 'project.database.danger')
</div>
<div x-cloak x-show="activeTab === 'danger'">
<livewire:project.shared.danger :resource="$database" /> <livewire:project.shared.danger :resource="$database" />
</div> @endif
</div> </div>
</div> </div>
</div> </div>

View File

@@ -62,17 +62,13 @@
<x-forms.button isError <x-forms.button isError
wire:click="stop('{{ data_get($destination, 'server.id') }}')">Stop</x-forms.button> wire:click="stop('{{ data_get($destination, 'server.id') }}')">Stop</x-forms.button>
@endif @endif
<x-modal-confirmation <x-modal-confirmation title="Confirm server removal?" isErrorButton buttonTitle="Remove Server"
title="Confirm server removal?"
isErrorButton
buttonTitle="Remove Server"
submitAction="removeServer({{ data_get($destination, 'id') }},{{ data_get($destination, 'server.id') }})" submitAction="removeServer({{ data_get($destination, 'id') }},{{ data_get($destination, 'server.id') }})"
:actions="['This will stop the all running applications on this server and remove it as a deployment destination.']" :actions="[
confirmationText="{{ data_get($destination, 'server.name') }}" 'This will stop the all running applications on this server and remove it as a deployment destination.',
]" confirmationText="{{ data_get($destination, 'server.name') }}"
confirmationLabel="Please confirm the execution of the actions by entering the Server Name below" confirmationLabel="Please confirm the execution of the actions by entering the Server Name below"
shortConfirmationLabel="Server Name" shortConfirmationLabel="Server Name" step3ButtonText="Permanently Remove Server" />
step3ButtonText="Permanently Remove Server"
/>
</div> </div>
</div> </div>
@endforeach @endforeach

View File

@@ -208,6 +208,17 @@ Route::middleware(['auth', 'verified'])->group(function () {
}); });
Route::prefix('project/{project_uuid}/{environment_name}/database/{database_uuid}')->group(function () { Route::prefix('project/{project_uuid}/{environment_name}/database/{database_uuid}')->group(function () {
Route::get('/', DatabaseConfiguration::class)->name('project.database.configuration'); Route::get('/', DatabaseConfiguration::class)->name('project.database.configuration');
Route::get('/environment-variables', DatabaseConfiguration::class)->name('project.database.environment-variables');
Route::get('/servers', DatabaseConfiguration::class)->name('project.database.servers');
Route::get('/import-backups', DatabaseConfiguration::class)->name('project.database.import-backups');
Route::get('/persistent-storage', DatabaseConfiguration::class)->name('project.database.persistent-storage');
Route::get('/webhooks', DatabaseConfiguration::class)->name('project.database.webhooks');
Route::get('/resource-limits', DatabaseConfiguration::class)->name('project.database.resource-limits');
Route::get('/resource-operations', DatabaseConfiguration::class)->name('project.database.resource-operations');
Route::get('/metrics', DatabaseConfiguration::class)->name('project.database.metrics');
Route::get('/tags', DatabaseConfiguration::class)->name('project.database.tags');
Route::get('/danger', DatabaseConfiguration::class)->name('project.database.danger');
Route::get('/logs', Logs::class)->name('project.database.logs'); Route::get('/logs', Logs::class)->name('project.database.logs');
Route::get('/terminal', ExecuteContainerCommand::class)->name('project.database.command'); Route::get('/terminal', ExecuteContainerCommand::class)->name('project.database.command');
Route::get('/backups', DatabaseBackupIndex::class)->name('project.database.backup.index'); Route::get('/backups', DatabaseBackupIndex::class)->name('project.database.backup.index');