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 @@