3
0
mirror of https://github.com/snipe/snipe-it.git synced 2026-08-18 11:15:42 +00:00

Fixed #19450 - added unmatched headers back to importer

This commit is contained in:
snipe
2026-08-13 10:38:02 +01:00
parent d85c4feddb
commit fee72c57de
2 changed files with 54 additions and 15 deletions

View File

@ -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))
<div class="form-group col-md-12" wire:key="header-row-{{ $index }}">
<label for="field_map.{{ $index }}" class="col-md-3 control-label text-right">{{ $header }}</label>

View File

@ -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();