mirror of
https://github.com/coollabsio/coolify.git
synced 2026-09-26 09:20:54 -04:00
feat(service): reopen the live deployment log after closing it
The deploy/start log lived in a fire-and-forget dialog; closing it left the deploy running server-side with no way back, and re-clicking Deploy only errored 'deployment in progress'. - Track the running activity id in the service heading (refreshed on the 10s poll, on broadcasts, and instantly when a deploy starts) - Add reopenDeployment(): re-attach the activity monitor to the running deploy and reopen the dialog - Show a persistent 'Deploying… View log' indicator (mobile status row + desktop action HUD) that reopens the live log - Clicking Deploy/Restart while a deploy runs now reopens the log instead of throwing an error - New reusable x-deploying-indicator component
This commit is contained in:
@@ -27,6 +27,8 @@ class Heading extends Component
|
||||
|
||||
public $isDeploymentProgress = false;
|
||||
|
||||
public $runningActivityId = null;
|
||||
|
||||
public $docker_cleanup = true;
|
||||
|
||||
public $title = 'Configuration';
|
||||
@@ -35,6 +37,8 @@ class Heading extends Component
|
||||
{
|
||||
$this->authorizeService('view');
|
||||
|
||||
$this->checkDeployments();
|
||||
|
||||
if (str($this->service->status)->contains('running') && is_null($this->service->config_hash)) {
|
||||
$this->service->isConfigurationChanged(true);
|
||||
$this->dispatch('configurationChanged');
|
||||
@@ -57,6 +61,8 @@ class Heading extends Component
|
||||
{
|
||||
$this->authorizeService('view');
|
||||
|
||||
$this->checkDeployments();
|
||||
|
||||
if ($this->service->server->isFunctional()) {
|
||||
GetContainersStatus::dispatch($this->service->server);
|
||||
} else {
|
||||
@@ -101,22 +107,46 @@ class Heading extends Component
|
||||
$status = data_get($activity, 'properties.status');
|
||||
if ($status === ProcessStatus::QUEUED->value || $status === ProcessStatus::IN_PROGRESS->value) {
|
||||
$this->isDeploymentProgress = true;
|
||||
$this->runningActivityId = $activity->id;
|
||||
} else {
|
||||
$this->isDeploymentProgress = false;
|
||||
$this->runningActivityId = null;
|
||||
}
|
||||
} catch (\Throwable) {
|
||||
$this->isDeploymentProgress = false;
|
||||
$this->runningActivityId = null;
|
||||
}
|
||||
|
||||
return $this->isDeploymentProgress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-attach the live log dialog to a deployment that is already running.
|
||||
* Used by the "Deploying…" indicator and when Deploy/Restart is clicked
|
||||
* while a deployment is in progress, so the running log reappears instead
|
||||
* of a dead-end error.
|
||||
*/
|
||||
public function reopenDeployment()
|
||||
{
|
||||
$this->authorizeService('view');
|
||||
|
||||
$this->checkDeployments();
|
||||
|
||||
if ($this->isDeploymentProgress && $this->runningActivityId) {
|
||||
$this->dispatch('activityMonitor', $this->runningActivityId);
|
||||
$this->js("window.dispatchEvent(new CustomEvent('startservice'))");
|
||||
} else {
|
||||
$this->dispatch('info', 'No deployment is currently running.');
|
||||
}
|
||||
}
|
||||
|
||||
public function start()
|
||||
{
|
||||
try {
|
||||
$this->authorizeService('deploy');
|
||||
$activity = StartService::run($this->service, pullLatestImages: true);
|
||||
$this->auditServiceAction('ui.service.started');
|
||||
$this->markDeploymentRunning($activity->id);
|
||||
$this->js("window.dispatchEvent(new CustomEvent('startservice'))");
|
||||
$this->dispatch('activityMonitor', $activity->id);
|
||||
} catch (\Throwable $e) {
|
||||
@@ -138,6 +168,7 @@ class Heading extends Component
|
||||
$activity->save();
|
||||
}
|
||||
$activity = StartService::run($this->service, pullLatestImages: true, stopBeforeStart: true);
|
||||
$this->markDeploymentRunning($activity->id);
|
||||
$this->js("window.dispatchEvent(new CustomEvent('startservice'))");
|
||||
$this->dispatch('activityMonitor', $activity->id);
|
||||
} catch (\Throwable $e) {
|
||||
@@ -145,6 +176,12 @@ class Heading extends Component
|
||||
}
|
||||
}
|
||||
|
||||
private function markDeploymentRunning($activityId): void
|
||||
{
|
||||
$this->isDeploymentProgress = true;
|
||||
$this->runningActivityId = $activityId;
|
||||
}
|
||||
|
||||
public function stop()
|
||||
{
|
||||
try {
|
||||
@@ -168,6 +205,7 @@ class Heading extends Component
|
||||
}
|
||||
$activity = StartService::run($this->service, stopBeforeStart: true);
|
||||
$this->auditServiceAction('ui.service.restarted');
|
||||
$this->markDeploymentRunning($activity->id);
|
||||
$this->js("window.dispatchEvent(new CustomEvent('startservice'))");
|
||||
$this->dispatch('activityMonitor', $activity->id);
|
||||
} catch (\Throwable $e) {
|
||||
@@ -210,6 +248,7 @@ class Heading extends Component
|
||||
}
|
||||
$activity = StartService::run($this->service, pullLatestImages: true, stopBeforeStart: true);
|
||||
$this->auditServiceAction('ui.service.restarted');
|
||||
$this->markDeploymentRunning($activity->id);
|
||||
$this->js("window.dispatchEvent(new CustomEvent('startservice'))");
|
||||
$this->dispatch('activityMonitor', $activity->id);
|
||||
} catch (\Throwable $e) {
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
@props([
|
||||
'action' => 'reopenDeployment',
|
||||
'label' => 'Deploying',
|
||||
])
|
||||
|
||||
{{-- Persistent affordance shown while a deploy/start is running. Re-opens the
|
||||
live log dialog (the process runs server-side even after the modal closes).
|
||||
Uses the Alpine $wire magic (not wire:click) so it also works when the
|
||||
button is teleported to the desktop action HUD, outside the Livewire root. --}}
|
||||
<button type="button" x-on:click="$wire.{{ $action }}()"
|
||||
{{ $attributes->class('inline-flex shrink-0 items-center gap-1.5 rounded-md px-2 py-1 text-[11px] font-medium ring-1 transition-colors bg-coollabs/10 text-coollabs ring-coollabs/25 hover:bg-coollabs/15 dark:bg-warning/15 dark:text-warning dark:ring-warning/25 dark:hover:bg-warning/20') }}
|
||||
title="View the running deployment log">
|
||||
<svg class="size-3 animate-spin" viewBox="0 0 24 24" fill="none" aria-hidden="true">
|
||||
<circle cx="12" cy="12" r="9" stroke="currentColor" stroke-width="2.5" opacity="0.25" />
|
||||
<path d="M21 12a9 9 0 0 0-9-9" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" />
|
||||
</svg>
|
||||
<span>{{ $label }}…</span>
|
||||
<span class="opacity-70">View log</span>
|
||||
</button>
|
||||
@@ -75,6 +75,9 @@
|
||||
<div class="relative flex w-full min-w-0 items-center gap-2">
|
||||
<x-status-summary :status="$service->status" title="Service status" container-name="Containers" />
|
||||
<x-services.links :service="$service" compact />
|
||||
@if ($isDeploymentProgress)
|
||||
<x-deploying-indicator />
|
||||
@endif
|
||||
</div>
|
||||
<div class="flex w-full flex-wrap gap-1">
|
||||
@if ($selectedResource)
|
||||
@@ -173,6 +176,9 @@
|
||||
<div
|
||||
class="resource-heading-navbar application-heading-actions flex w-auto min-w-0 items-center justify-end gap-1 overflow-visible">
|
||||
<div class="resource-heading-actions flex shrink-0 items-center gap-0.5">
|
||||
@if ($isDeploymentProgress)
|
||||
<x-deploying-indicator class="mr-1" />
|
||||
@endif
|
||||
@if ($service->isDeployable)
|
||||
<div class="resource-heading-menus shrink-0">
|
||||
<x-services.links :service="$service" />
|
||||
@@ -303,8 +309,8 @@
|
||||
const isDeploymentProgress = await $wire.$call('checkDeployments');
|
||||
|
||||
if (isDeploymentProgress) {
|
||||
$wire.$dispatch('error',
|
||||
'There is a deployment in progress.<br><br>You can force deploy from the Actions menu.');
|
||||
// A deploy is already running: reopen its live log instead of erroring.
|
||||
$wire.$call('reopenDeployment');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -317,8 +323,8 @@
|
||||
const isDeploymentProgress = await $wire.$call('checkDeployments');
|
||||
|
||||
if (isDeploymentProgress) {
|
||||
$wire.$dispatch('error',
|
||||
'There is a deployment in progress.<br><br>You can force deploy from the Actions menu.');
|
||||
// A deploy is already running: reopen its live log instead of erroring.
|
||||
$wire.$call('reopenDeployment');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user