Merge pull request #4842 from peaklabs-dev/docker-cleanup-executions-ui

feat: Docker cleanup execution UI and some UI improvements
This commit is contained in:
Andras Bacsai
2025-01-16 21:42:02 +01:00
committed by GitHub
30 changed files with 894 additions and 331 deletions

View File

@@ -117,29 +117,6 @@ class BackupExecutions extends Component
return null;
}
public function getServerTimezone()
{
$server = $this->server();
if (! $server) {
return 'UTC';
}
return $server->settings->server_timezone;
}
public function formatDateInServerTimezone($date)
{
$serverTimezone = $this->getServerTimezone();
$dateObj = new \DateTime($date);
try {
$dateObj->setTimezone(new \DateTimeZone($serverTimezone));
} catch (\Exception) {
$dateObj->setTimezone(new \DateTimeZone('UTC'));
}
return $dateObj->format('Y-m-d H:i:s T');
}
public function render()
{
return view('livewire.project.database.backup-executions', [

View File

@@ -141,17 +141,4 @@ class Executions extends Component
return $lines->count() > ($this->currentPage * $this->logsPerPage);
}
public function formatDateInServerTimezone($date)
{
$serverTimezone = $this->serverTimezone;
$dateObj = new \DateTime($date);
try {
$dateObj->setTimezone(new \DateTimeZone($serverTimezone));
} catch (\Exception) {
$dateObj->setTimezone(new \DateTimeZone('UTC'));
}
return $dateObj->format('Y-m-d H:i:s T');
}
}

View File

@@ -2,7 +2,6 @@
namespace App\Livewire\Server;
use App\Jobs\DockerCleanupJob;
use App\Models\Server;
use Livewire\Attributes\Validate;
use Livewire\Component;
@@ -19,21 +18,6 @@ class Advanced extends Component
#[Validate(['integer', 'min:1', 'max:99'])]
public int $serverDiskUsageNotificationThreshold = 50;
#[Validate(['string', 'required'])]
public string $dockerCleanupFrequency = '*/10 * * * *';
#[Validate(['integer', 'min:1', 'max:99'])]
public int $dockerCleanupThreshold = 10;
#[Validate('boolean')]
public bool $forceDockerCleanup = false;
#[Validate('boolean')]
public bool $deleteUnusedVolumes = false;
#[Validate('boolean')]
public bool $deleteUnusedNetworks = false;
#[Validate(['integer', 'min:1'])]
public int $concurrentBuilds = 1;
@@ -47,7 +31,7 @@ class Advanced extends Component
$this->parameters = get_route_parameters();
$this->syncData();
} catch (\Throwable) {
return redirect()->route('server.show');
return redirect()->route('server.index');
}
}
@@ -57,23 +41,13 @@ class Advanced extends Component
$this->validate();
$this->server->settings->concurrent_builds = $this->concurrentBuilds;
$this->server->settings->dynamic_timeout = $this->dynamicTimeout;
$this->server->settings->force_docker_cleanup = $this->forceDockerCleanup;
$this->server->settings->docker_cleanup_frequency = $this->dockerCleanupFrequency;
$this->server->settings->docker_cleanup_threshold = $this->dockerCleanupThreshold;
$this->server->settings->server_disk_usage_notification_threshold = $this->serverDiskUsageNotificationThreshold;
$this->server->settings->delete_unused_volumes = $this->deleteUnusedVolumes;
$this->server->settings->delete_unused_networks = $this->deleteUnusedNetworks;
$this->server->settings->server_disk_usage_check_frequency = $this->serverDiskUsageCheckFrequency;
$this->server->settings->save();
} else {
$this->concurrentBuilds = $this->server->settings->concurrent_builds;
$this->dynamicTimeout = $this->server->settings->dynamic_timeout;
$this->forceDockerCleanup = $this->server->settings->force_docker_cleanup;
$this->dockerCleanupFrequency = $this->server->settings->docker_cleanup_frequency;
$this->dockerCleanupThreshold = $this->server->settings->docker_cleanup_threshold;
$this->serverDiskUsageNotificationThreshold = $this->server->settings->server_disk_usage_notification_threshold;
$this->deleteUnusedVolumes = $this->server->settings->delete_unused_volumes;
$this->deleteUnusedNetworks = $this->server->settings->delete_unused_networks;
$this->serverDiskUsageCheckFrequency = $this->server->settings->server_disk_usage_check_frequency;
}
}
@@ -88,23 +62,9 @@ class Advanced extends Component
}
}
public function manualCleanup()
{
try {
DockerCleanupJob::dispatch($this->server, true);
$this->dispatch('success', 'Manual cleanup job started. Depending on the amount of data, this might take a while.');
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function submit()
{
try {
if (! validate_cron_expression($this->dockerCleanupFrequency)) {
$this->dockerCleanupFrequency = $this->server->settings->getOriginal('docker_cleanup_frequency');
throw new \Exception('Invalid Cron / Human expression for Docker Cleanup Frequency.');
}
if (! validate_cron_expression($this->serverDiskUsageCheckFrequency)) {
$this->serverDiskUsageCheckFrequency = $this->server->settings->getOriginal('server_disk_usage_check_frequency');
throw new \Exception('Invalid Cron / Human expression for Disk Usage Check Frequency.');

View File

@@ -0,0 +1,99 @@
<?php
namespace App\Livewire\Server;
use App\Jobs\DockerCleanupJob;
use App\Models\Server;
use Livewire\Attributes\Validate;
use Livewire\Component;
class DockerCleanup extends Component
{
public Server $server;
public array $parameters = [];
#[Validate(['string', 'required'])]
public string $dockerCleanupFrequency = '*/10 * * * *';
#[Validate(['integer', 'min:1', 'max:99'])]
public int $dockerCleanupThreshold = 10;
#[Validate('boolean')]
public bool $forceDockerCleanup = false;
#[Validate('boolean')]
public bool $deleteUnusedVolumes = false;
#[Validate('boolean')]
public bool $deleteUnusedNetworks = false;
public function mount(string $server_uuid)
{
try {
$this->server = Server::ownedByCurrentTeam()->whereUuid($server_uuid)->firstOrFail();
$this->parameters = get_route_parameters();
$this->syncData();
} catch (\Throwable) {
return redirect()->route('server.index');
}
}
public function syncData(bool $toModel = false)
{
if ($toModel) {
$this->validate();
$this->server->settings->force_docker_cleanup = $this->forceDockerCleanup;
$this->server->settings->docker_cleanup_frequency = $this->dockerCleanupFrequency;
$this->server->settings->docker_cleanup_threshold = $this->dockerCleanupThreshold;
$this->server->settings->delete_unused_volumes = $this->deleteUnusedVolumes;
$this->server->settings->delete_unused_networks = $this->deleteUnusedNetworks;
$this->server->settings->save();
} else {
$this->forceDockerCleanup = $this->server->settings->force_docker_cleanup;
$this->dockerCleanupFrequency = $this->server->settings->docker_cleanup_frequency;
$this->dockerCleanupThreshold = $this->server->settings->docker_cleanup_threshold;
$this->deleteUnusedVolumes = $this->server->settings->delete_unused_volumes;
$this->deleteUnusedNetworks = $this->server->settings->delete_unused_networks;
}
}
public function instantSave()
{
try {
$this->syncData(true);
$this->dispatch('success', 'Server updated.');
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function manualCleanup()
{
try {
DockerCleanupJob::dispatch($this->server, true);
$this->dispatch('success', 'Manual cleanup job started. Depending on the amount of data, this might take a while.');
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function submit()
{
try {
if (! validate_cron_expression($this->dockerCleanupFrequency)) {
$this->dockerCleanupFrequency = $this->server->settings->getOriginal('docker_cleanup_frequency');
throw new \Exception('Invalid Cron / Human expression for Docker Cleanup Frequency.');
}
$this->syncData(true);
$this->dispatch('success', 'Server updated.');
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function render()
{
return view('livewire.server.docker-cleanup');
}
}

View File

@@ -0,0 +1,132 @@
<?php
namespace App\Livewire\Server;
use App\Models\DockerCleanupExecution;
use App\Models\Server;
use Illuminate\Support\Collection;
use Livewire\Component;
class DockerCleanupExecutions extends Component
{
public Server $server;
public Collection $executions;
public ?int $selectedKey = null;
public $selectedExecution = null;
public bool $isPollingActive = false;
public $currentPage = 1;
public $logsPerPage = 100;
public function getListeners()
{
$teamId = auth()->user()->currentTeam()->id;
return [
"echo-private:team.{$teamId},DockerCleanupDone" => 'refreshExecutions',
];
}
public function mount(Server $server)
{
$this->server = $server;
$this->refreshExecutions();
}
public function refreshExecutions(): void
{
$this->executions = $this->server->dockerCleanupExecutions()
->orderBy('created_at', 'desc')
->take(20)
->get();
if ($this->selectedKey) {
$this->selectedExecution = DockerCleanupExecution::find($this->selectedKey);
if ($this->selectedExecution && $this->selectedExecution->status !== 'running') {
$this->isPollingActive = false;
}
}
}
public function selectExecution($key): void
{
if ($key == $this->selectedKey) {
$this->selectedKey = null;
$this->selectedExecution = null;
$this->currentPage = 1;
$this->isPollingActive = false;
return;
}
$this->selectedKey = $key;
$this->selectedExecution = DockerCleanupExecution::find($key);
$this->currentPage = 1;
if ($this->selectedExecution && $this->selectedExecution->status === 'running') {
$this->isPollingActive = true;
}
}
public function polling()
{
if ($this->selectedExecution && $this->isPollingActive) {
$this->selectedExecution->refresh();
if ($this->selectedExecution->status !== 'running') {
$this->isPollingActive = false;
}
}
$this->refreshExecutions();
}
public function loadMoreLogs()
{
$this->currentPage++;
}
public function getLogLinesProperty()
{
if (! $this->selectedExecution) {
return collect();
}
if (! $this->selectedExecution->message) {
return collect(['Waiting for execution output...']);
}
$lines = collect(explode("\n", $this->selectedExecution->message));
return $lines->take($this->currentPage * $this->logsPerPage);
}
public function downloadLogs(int $executionId)
{
$execution = $this->executions->firstWhere('id', $executionId);
if (! $execution) {
return;
}
return response()->streamDownload(function () use ($execution) {
echo $execution->message;
}, "docker-cleanup-{$execution->uuid}.log");
}
public function hasMoreLogs()
{
if (! $this->selectedExecution || ! $this->selectedExecution->message) {
return false;
}
$lines = collect(explode("\n", $this->selectedExecution->message));
return $lines->count() > ($this->currentPage * $this->logsPerPage);
}
public function render()
{
return view('livewire.server.docker-cleanup-executions');
}
}