fix: prime group mapping state

This commit is contained in:
Ahmed Darrazi 2025-12-31 13:27:50 +01:00
parent 711e012827
commit 44b4a6adf0
2 changed files with 95 additions and 30 deletions

View File

@ -177,10 +177,15 @@ public static function getWizardSteps(): array
});
})
->reactive()
->afterStateUpdated(function (Set $set): void {
->afterStateUpdated(function (Set $set, Get $get): void {
$set('scope_mode', 'all');
$set('backup_item_ids', null);
$set('group_mapping', []);
$set('group_mapping', static::groupMappingPlaceholders(
backupSetId: $get('backup_set_id'),
scopeMode: 'all',
selectedItemIds: null,
tenant: Tenant::current(),
));
$set('is_dry_run', true);
$set('acknowledged_impact', false);
$set('tenant_confirm', null);
@ -204,8 +209,9 @@ public static function getWizardSteps(): array
])
->default('all')
->reactive()
->afterStateUpdated(function (Set $set, $state): void {
$set('group_mapping', []);
->afterStateUpdated(function (Set $set, Get $get, $state): void {
$backupSetId = $get('backup_set_id');
$tenant = Tenant::current();
$set('is_dry_run', true);
$set('acknowledged_impact', false);
$set('tenant_confirm', null);
@ -218,10 +224,17 @@ public static function getWizardSteps(): array
if ($state === 'all') {
$set('backup_item_ids', null);
$set('group_mapping', static::groupMappingPlaceholders(
backupSetId: $backupSetId,
scopeMode: 'all',
selectedItemIds: null,
tenant: $tenant,
));
return;
}
$set('group_mapping', []);
$set('backup_item_ids', []);
})
->required(),
@ -234,8 +247,18 @@ public static function getWizardSteps(): array
->optionsLimit(300)
->options(fn (Get $get) => static::restoreItemGroupedOptions($get('backup_set_id')))
->reactive()
->afterStateUpdated(function (Set $set): void {
$set('group_mapping', []);
->afterStateUpdated(function (Set $set, Get $get): void {
$backupSetId = $get('backup_set_id');
$selectedItemIds = $get('backup_item_ids');
$selectedItemIds = is_array($selectedItemIds) ? $selectedItemIds : null;
$tenant = Tenant::current();
$set('group_mapping', static::groupMappingPlaceholders(
backupSetId: $backupSetId,
scopeMode: 'selected',
selectedItemIds: $selectedItemIds,
tenant: $tenant,
));
$set('is_dry_run', true);
$set('acknowledged_impact', false);
$set('tenant_confirm', null);
@ -249,29 +272,29 @@ public static function getWizardSteps(): array
->visible(fn (Get $get): bool => $get('scope_mode') === 'selected')
->required(fn (Get $get): bool => $get('scope_mode') === 'selected')
->hintActions([
Actions\Action::make('select_all_backup_items')
->label('Select all')
->icon('heroicon-o-check')
->color('gray')
->visible(fn (Get $get): bool => filled($get('backup_set_id')) && $get('scope_mode') === 'selected')
->action(function (Get $get, Set $set): void {
$groupedOptions = static::restoreItemGroupedOptions($get('backup_set_id'));
Actions\Action::make('select_all_backup_items')
->label('Select all')
->icon('heroicon-o-check')
->color('gray')
->visible(fn (Get $get): bool => filled($get('backup_set_id')) && $get('scope_mode') === 'selected')
->action(function (Get $get, Set $set): void {
$groupedOptions = static::restoreItemGroupedOptions($get('backup_set_id'));
$allItemIds = [];
$allItemIds = [];
foreach ($groupedOptions as $options) {
$allItemIds = array_merge($allItemIds, array_keys($options));
}
foreach ($groupedOptions as $options) {
$allItemIds = array_merge($allItemIds, array_keys($options));
}
$set('backup_item_ids', array_values($allItemIds), shouldCallUpdatedHooks: true);
}),
Actions\Action::make('clear_backup_items')
->label('Clear')
->icon('heroicon-o-x-mark')
->color('gray')
->visible(fn (Get $get): bool => $get('scope_mode') === 'selected')
->action(fn (Set $set) => $set('backup_item_ids', [], shouldCallUpdatedHooks: true)),
])
$set('backup_item_ids', array_values($allItemIds), shouldCallUpdatedHooks: true);
}),
Actions\Action::make('clear_backup_items')
->label('Clear')
->icon('heroicon-o-x-mark')
->color('gray')
->visible(fn (Get $get): bool => $get('scope_mode') === 'selected')
->action(fn (Set $set) => $set('backup_item_ids', [], shouldCallUpdatedHooks: true)),
])
->helperText('Search by name or ID. Include foundations (scope tags, assignment filters) with policies to re-map IDs. Options are grouped by category, type, and platform.'),
Section::make('Group mapping')
->description('Some source groups do not exist in the target tenant. Map them or choose Skip.')
@ -1383,8 +1406,43 @@ private static function unresolvedGroups(?int $backupSetId, ?array $selectedItem
}
/**
* @param array<int>|null $selectedItemIds
* @return array<string, string|null>
*/
private static function groupMappingPlaceholders(?int $backupSetId, string $scopeMode, ?array $selectedItemIds, ?Tenant $tenant): array
{
if (! $tenant || ! $backupSetId) {
return [];
}
if ($scopeMode === 'selected' && ($selectedItemIds === null || $selectedItemIds === [])) {
return [];
}
$unresolved = static::unresolvedGroups(
backupSetId: $backupSetId,
selectedItemIds: $scopeMode === 'selected' ? $selectedItemIds : null,
tenant: $tenant,
);
$placeholders = [];
foreach ($unresolved as $group) {
$groupId = $group['id'] ?? null;
if (! is_string($groupId) || $groupId === '') {
continue;
}
$placeholders[$groupId] = null;
}
return $placeholders;
}
/**
* @return array<string, string>
*/
private static function normalizeGroupMapping(mixed $mapping): array
{
if ($mapping instanceof \Illuminate\Contracts\Support\Arrayable) {
@ -1449,7 +1507,7 @@ private static function normalizeGroupMapping(mixed $mapping): array
$result[$sourceGroupId] = null;
}
return $result;
return array_filter($result, static fn (?string $value): bool => is_string($value) && $value !== '');
}
/**

View File

@ -77,7 +77,7 @@
$user = User::factory()->create();
$this->actingAs($user);
Livewire::test(CreateRestoreRun::class)
$component = Livewire::test(CreateRestoreRun::class)
->fillForm([
'backup_set_id' => $backupSet->id,
])
@ -85,8 +85,15 @@
->fillForm([
'scope_mode' => 'selected',
'backup_item_ids' => [$backupItem->id],
])
->assertFormFieldVisible('group_mapping.source-group-1');
]);
$mapping = $component->get('data.group_mapping');
expect($mapping)->toBeArray();
expect(array_key_exists('source-group-1', $mapping))->toBeTrue();
expect($mapping['source-group-1'])->toBeNull();
$component->assertFormFieldVisible('group_mapping.source-group-1');
});
test('restore wizard persists group mapping selections', function () {