feat(resources): add cross-server resource migration (dev-only) (#11165)

This commit is contained in:
Andras Bacsai
2026-08-07 23:01:31 +02:00
committed by GitHub
parent d83ba627cd
commit c15e3b35fd
15 changed files with 1354 additions and 7 deletions
@@ -6,6 +6,7 @@ use App\Actions\Database\StartDatabase;
use App\Actions\Database\StopDatabase;
use App\Actions\Service\StartService;
use App\Actions\Service\StopService;
use App\Actions\Shared\MigrateResourceToDestination;
use App\Jobs\VolumeCloneJob;
use App\Models\Application;
use App\Models\Environment;
@@ -19,6 +20,7 @@ use App\Models\StandaloneMysql;
use App\Models\StandalonePostgresql;
use App\Models\StandaloneRedis;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Validation\ValidationException;
use Livewire\Component;
class ResourceOperations extends Component
@@ -39,6 +41,8 @@ class ResourceOperations extends Component
public bool $cloneVolumeData = false;
public bool $migrateVolumeData = true;
public function mount()
{
$parameters = get_route_parameters();
@@ -55,6 +59,11 @@ class ResourceOperations extends Component
$this->cloneVolumeData = $value;
}
public function toggleVolumeMigration(bool $value): void
{
$this->migrateVolumeData = $value;
}
public function cloneTo($destination_uuid, $environment_id = null)
{
try {
@@ -417,6 +426,64 @@ class ResourceOperations extends Component
}
}
public function migrateTo(string $destination_uuid)
{
try {
$this->authorize('update', $this->resource);
$new_destination = find_resource_destination_for_current_team($destination_uuid);
if (! $new_destination) {
return $this->addError('destination_id', 'Destination not found.');
}
$result = MigrateResourceToDestination::run(
$this->resource,
$new_destination,
$this->migrateVolumeData,
);
$this->dispatch('success', $result['message']);
$this->resource->loadMissing('environment.project');
$projectUuid = $this->projectUuid ?? $this->resource->environment?->project?->uuid;
$environmentUuid = $this->environmentUuid ?? $this->resource->environment?->uuid;
if (! $projectUuid || ! $environmentUuid) {
return null;
}
if ($this->resource->type() === 'application') {
$route = route('project.application.configuration', [
'project_uuid' => $projectUuid,
'environment_uuid' => $environmentUuid,
'application_uuid' => $this->resource->uuid,
]).'#resource-operations';
} elseif (str($this->resource->type())->startsWith('standalone-')) {
$route = route('project.database.configuration', [
'project_uuid' => $projectUuid,
'environment_uuid' => $environmentUuid,
'database_uuid' => $this->resource->uuid,
]).'#resource-operations';
} elseif ($this->resource->type() === 'service') {
$route = route('project.service.configuration', [
'project_uuid' => $projectUuid,
'environment_uuid' => $environmentUuid,
'service_uuid' => $this->resource->uuid,
]).'#resource-operations';
} else {
return null;
}
return redirect()->to($route);
} catch (ValidationException $e) {
$message = collect($e->errors())->flatten()->first() ?? $e->getMessage();
return $this->addError('destination_id', $message);
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function render()
{
return view('livewire.project.shared.resource-operations');