From aa18c4882350875a8f1069e0e1530f34f132d797 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Wed, 26 Nov 2025 10:43:07 +0100 Subject: [PATCH] fix: resolve uncloseable database restore modal on MariaDB import (#7335) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the "Snapshot missing on Livewire component" error that occurs when toggling the "Backup includes all databases" checkbox during MariaDB database import operations. Root Cause: - ActivityMonitor component was initialized without proper lifecycle hooks - When parent Import component re-rendered (via checkbox toggle), the ActivityMonitor's Livewire snapshot became stale - Missing null checks caused errors when querying with undefined activityId - No state cleanup when slide-over closed, causing issues on subsequent opens Changes: - Add updatedActivityId() lifecycle hook to ActivityMonitor for proper hydration - Add defensive null check in hydrateActivity() to prevent query errors - Track activityId in Import component for state management - Add slideOverClosed event dispatch in slide-over component - Add event listener in Import component to reset activityId on close Testing: - Manually verify checkbox toggle doesn't trigger popup - Verify actual restore operations work correctly - Test both file-based and S3-based restore methods - Ensure X button properly closes the modal - Verify no console errors or Livewire warnings 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- app/Livewire/ActivityMonitor.php | 17 ++++++++++++++++- app/Livewire/Project/Database/Import.php | 14 ++++++++++++++ resources/views/components/slide-over.blade.php | 8 +++++++- 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/app/Livewire/ActivityMonitor.php b/app/Livewire/ActivityMonitor.php index d01b55afb..bc310e715 100644 --- a/app/Livewire/ActivityMonitor.php +++ b/app/Livewire/ActivityMonitor.php @@ -10,7 +10,7 @@ class ActivityMonitor extends Component { public ?string $header = null; - public $activityId; + public $activityId = null; public $eventToDispatch = 'activityFinished'; @@ -49,9 +49,24 @@ public function newMonitorActivity($activityId, $eventToDispatch = 'activityFini public function hydrateActivity() { + if ($this->activityId === null) { + $this->activity = null; + + return; + } + $this->activity = Activity::find($this->activityId); } + public function updatedActivityId($value) + { + if ($value) { + $this->hydrateActivity(); + $this->isPollingActive = true; + self::$eventDispatched = false; + } + } + public function polling() { $this->hydrateActivity(); diff --git a/app/Livewire/Project/Database/Import.php b/app/Livewire/Project/Database/Import.php index fd191e587..26feb1a5e 100644 --- a/app/Livewire/Project/Database/Import.php +++ b/app/Livewire/Project/Database/Import.php @@ -133,6 +133,8 @@ private function validateServerPath(string $path): bool public string $customLocation = ''; + public ?int $activityId = null; + public string $postgresqlRestoreCommand = 'pg_restore -U $POSTGRES_USER -d $POSTGRES_DB'; public string $mysqlRestoreCommand = 'mysql -u $MYSQL_USER -p$MYSQL_PASSWORD $MYSQL_DATABASE'; @@ -156,9 +158,15 @@ public function getListeners() return [ "echo-private:user.{$userId},DatabaseStatusChanged" => '$refresh', + 'slideOverClosed' => 'resetActivityId', ]; } + public function resetActivityId() + { + $this->activityId = null; + } + public function mount() { $this->parameters = get_route_parameters(); @@ -327,6 +335,9 @@ public function runImport() 'serverId' => $this->server->id, ]); + // Track the activity ID + $this->activityId = $activity->id; + // Dispatch activity to the monitor and open slide-over $this->dispatch('activityMonitor', $activity->id); $this->dispatch('databaserestore'); @@ -548,6 +559,9 @@ public function restoreFromS3() 'serverId' => $this->server->id, ]); + // Track the activity ID + $this->activityId = $activity->id; + // Dispatch activity to the monitor and open slide-over $this->dispatch('activityMonitor', $activity->id); $this->dispatch('databaserestore'); diff --git a/resources/views/components/slide-over.blade.php b/resources/views/components/slide-over.blade.php index 3cb8ec3ab..13769c7b6 100644 --- a/resources/views/components/slide-over.blade.php +++ b/resources/views/components/slide-over.blade.php @@ -1,7 +1,13 @@ @props(['closeWithX' => false, 'fullScreen' => false])
merge(['class' => 'relative w-auto h-auto']) }}> +}" +x-init="$watch('slideOverOpen', value => { + if (!value) { + $dispatch('slideOverClosed') + } +})" +{{ $attributes->merge(['class' => 'relative w-auto h-auto']) }}> {{ $slot }}