From fee72c57de353d61eb9295c5666a2ba841ada57a Mon Sep 17 00:00:00 2001 From: snipe Date: Thu, 13 Aug 2026 10:38:02 +0100 Subject: [PATCH] Fixed #19450 - added unmatched headers back to importer --- resources/views/livewire/importer.blade.php | 29 ++++++++------- tests/Feature/Livewire/ImporterTest.php | 40 +++++++++++++++++++++ 2 files changed, 54 insertions(+), 15 deletions(-) diff --git a/resources/views/livewire/importer.blade.php b/resources/views/livewire/importer.blade.php index 930cd432db..43b795af1a 100644 --- a/resources/views/livewire/importer.blade.php +++ b/resources/views/livewire/importer.blade.php @@ -513,23 +513,22 @@ @if (! empty($headerRow)) @foreach ($headerRow as $index => $header) @php - // Skip CSV columns that the auto-map - // couldn't bind to any target for the - // current import type — those come - // through as PHP null. Rows the USER - // set to "Do not import" come through - // as empty string (Livewire binds the - // select's value="" as ""), so those - // stay visible and the user can change - // their mind. Previously used empty() - // here, which conflated the two and - // made "Do not import" rows disappear - // from the wizard with no way to bring - // them back short of restarting the - // import (#19450). + // Render every CSV header, whether or + // not the auto-map bound it to a target. + // Auto-unmapped columns come through + // with $currentMapping = null and render + // with the "Do not import" placeholder + // selected; the user can pick a target + // from the dropdown if they want to. An + // earlier iteration of the wizard hid + // unmapped columns to keep the mapping + // step focused, but reporter feedback + // (swift2512 / Dewi4nt on #19450) was + // that people want to see every column + // so they can hand-map anything the + // auto-matcher missed. $currentMapping = $field_map[$index] ?? null; @endphp - @continue(is_null($currentMapping))
diff --git a/tests/Feature/Livewire/ImporterTest.php b/tests/Feature/Livewire/ImporterTest.php index 942f82828f..93914429f0 100644 --- a/tests/Feature/Livewire/ImporterTest.php +++ b/tests/Feature/Livewire/ImporterTest.php @@ -456,6 +456,46 @@ class ImporterTest extends TestCase ->assertSet('statusType', 'error'); } + public function test_mapping_step_renders_every_csv_header_even_when_auto_map_finds_no_match(): void + { + // Reporter feedback on #19450 (swift2512 / Dewi4nt): the wizard + // was silently omitting CSV columns whose headers didn't hit an + // auto-match or an alias, which left users with no way to + // hand-map them. Every header should show up in the mapping list + // - matched ones with the target pre-selected, unmatched ones + // defaulting to "Do not import" (rendered as an empty-value + // option) with the dropdown available. + Storage::fake(); + $user = User::factory()->canImport()->create(); + + $import = Import::factory()->create([ + 'created_by' => $user->id, + 'header_row' => ['Asset Tag', 'lorem ipsum column'], + 'first_row' => ['ASSET-001', 'whatever'], + 'import_type' => 'asset', + ]); + $this->writeFakeImportFile($import, "Asset Tag,lorem ipsum column\nASSET-001,whatever\n"); + + $component = Livewire::actingAs($user) + ->test(Importer::class) + ->call('selectFile', $import->id) + ->set('typeOfImport', 'asset'); + + // Both header positions are represented in field_map. Index 0 is + // the auto-matched target key, index 1 is null (auto-unmapped - + // the user picks from the dropdown in the UI). + $fieldMap = $component->get('field_map'); + $this->assertCount(2, $fieldMap, 'field_map should hold one entry per CSV header, matched or not.'); + $this->assertSame('asset_tag', $fieldMap[0]); + $this->assertNull($fieldMap[1]); + + // The unmapped header's raw text is rendered in the mapping list. + $component->call('nextStep') + ->assertSet('wizardStep', 2) + ->assertSee('lorem ipsum column') + ->assertSee('Asset Tag'); + } + public function test_next_step_from_mapping_advances_when_required_fields_are_mapped(): void { $user = User::factory()->canImport()->create();