From af093eea6e1ccc485c007fc8601c81b3b9fe637a Mon Sep 17 00:00:00 2001 From: Aditya Tripathi Date: Fri, 11 Sep 2026 08:00:02 +0000 Subject: [PATCH] feat(service): reopen the live deployment log after closing it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- app/Livewire/Project/Service/Heading.php | 39 +++++++++++++++++++ .../components/deploying-indicator.blade.php | 19 +++++++++ .../project/service/heading.blade.php | 14 +++++-- 3 files changed, 68 insertions(+), 4 deletions(-) create mode 100644 resources/views/components/deploying-indicator.blade.php diff --git a/app/Livewire/Project/Service/Heading.php b/app/Livewire/Project/Service/Heading.php index d692a71546..33fce9f079 100644 --- a/app/Livewire/Project/Service/Heading.php +++ b/app/Livewire/Project/Service/Heading.php @@ -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) { diff --git a/resources/views/components/deploying-indicator.blade.php b/resources/views/components/deploying-indicator.blade.php new file mode 100644 index 0000000000..e18543234e --- /dev/null +++ b/resources/views/components/deploying-indicator.blade.php @@ -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. --}} + diff --git a/resources/views/livewire/project/service/heading.blade.php b/resources/views/livewire/project/service/heading.blade.php index 820163ddb1..29b9523092 100644 --- a/resources/views/livewire/project/service/heading.blade.php +++ b/resources/views/livewire/project/service/heading.blade.php @@ -75,6 +75,9 @@
+ @if ($isDeploymentProgress) + + @endif
@if ($selectedResource) @@ -173,6 +176,9 @@
+ @if ($isDeploymentProgress) + + @endif @if ($service->isDeployable)
@@ -303,8 +309,8 @@ const isDeploymentProgress = await $wire.$call('checkDeployments'); if (isDeploymentProgress) { - $wire.$dispatch('error', - 'There is a deployment in progress.

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.

You can force deploy from the Actions menu.'); + // A deploy is already running: reopen its live log instead of erroring. + $wire.$call('reopenDeployment'); return; }