Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Importer front-end improvements (minimum mapping, no dupes) #16114

Draft
wants to merge 1 commit into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 113 additions & 4 deletions app/Livewire/Importer.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use App\Models\CustomField;
use App\Models\Import;
use App\Models\Setting;
use Illuminate\Support\Facades\Storage;
use Livewire\Attributes\Computed;
use Livewire\Component;
Expand All @@ -30,6 +31,8 @@ class Importer extends Component
public $send_welcome;
public $run_backup;
public $field_map; // we need a separate variable for the field-mapping, because the keys in the normal array are too complicated for Livewire to understand
public $mapping_errors = []; // helps keep track of duplicate mappings
public $enough_data_to_import = false;

// Make these variables public - we set the properties in the constructor so we can localize them (versus the old static arrays)
public $accessories_fields;
Expand Down Expand Up @@ -118,6 +121,7 @@ private function getColumns($type)
public function updatingTypeOfImport($type)
{

\Log::error("UPDATING TYPE OF IMPORT!!!!!! to: $type");
// go through each header, find a matching field to try and map it to.
foreach ($this->headerRow as $i => $header) {
// do we have something mapped already?
Expand Down Expand Up @@ -159,6 +163,107 @@ public function updatingTypeOfImport($type)
}
}

public function updatedFieldMap($value, $index)
{
\Log::error("Updated (past tense!) THE FIELD MAP! HERE's...something? $index - the value it's changing to is: $value");
//check first if you've tried to map two different things to the same field.
$already_mapped = [];
foreach ($this->field_map as $i => $mapping) {
if (!$mapping) {
//'Do Not Import' *can* be reused
continue;
}
if (array_key_exists($mapping, $already_mapped)) {
$this->mapping_errors[$i] = true;
} else {
$already_mapped[$mapping] = true;
}
}

//finally, check to see if you have enough to import this type of file
$this->enough_data_to_import = $this->check_minimum_mappings($already_mapped);
}

private function check_minimum_mappings($already_mapped)
{
/*****************************
* TODO (maybe more than that) -
* should we shrink this into some kind of language?
* When we allow for an 'update' - should we insist on getting *any* column so we
* can guarantee an update?
* If we're *not* doing an update, should we have a fuller list?
* And, again, is there a better way of doing this other than 'code'? I'm still not sure
* (Also, I hate the '@' signs everywhere, it's gross :/)
*******************************/
switch ($this->typeOfImport) {
case 'asset':
if ($this->update) {
//on *update* you need asset_tag, and something to update
return @$already_mapped['asset_tag'] && count($already_mapped) > 1;
} else {
//model is required on create.
if (!@$already_mapped['asset_model']) {
return false;
}

//on *create* we need either an asset tag, or we need autoincrement
return (Setting::getSetting()->auto_increment_assets || @$already_mapped['asset_tag']);
}
case 'user':
if ($this->update) {
//a username + one other field is a valid update.
if (@$already_mapped['username'] && count($already_mapped) > 1) {
return true;
}
//or, a full_name and one other field will do
if (@$already_mapped['full_name'] && count($already_mapped) > 1) {
return true;
}
//but just a first name isn't enough to update users - you don't have enough to import
return false;
} else {
// to create a new user in the importer, having any *one* of these things is enough to guess
// the rest (!)
return @$already_mapped['full_name'] || @$already_mapped['username'] || @$already_mapped['first_name'];
}
case 'accessory':
if ($this->update) {
return @$already_mapped['name'] && count($already_mapped) > 1;
} else {
return @$already_mapped['name'] && @$already_mapped['category'] && @$already_mapped['qty'];
}
case 'consumable':
// PHPStorm complains that this 'branch' is a dupe of accessory, and it kinda is,
// but it may not *always* be, so let's keep this as its own thing for now
if ($this->update) {
return @$already_mapped['name'] && count($already_mapped) > 1;
} else {
return @$already_mapped['name'] && @$already_mapped['category'] && @$already_mapped['qty'];
}
case 'component':
//similarly here for 'component'
if ($this->update) {
return (@$already_mapped['name'] && count($already_mapped) > 1);
} else {
return @$already_mapped['name'] && @$already_mapped['category'] && @$already_mapped['qty'];
}
case 'license':
if ($this->update) {
return @$already_mapped['name'] && count($already_mapped) > 1;
} else {
return @$already_mapped['name'] && @$already_mapped['seats'] && @$already_mapped['category'];
}
case 'location':
// Weird - this one is the only one where the update is _stricter_ than the insert!
if ($this->update) {
return @$already_mapped['name'] && count($already_mapped) > 1;
} else {
return @$already_mapped['name'];
}
}
return true; //go with a conservative option here, we can tighten this up later

}
public function mount()
{
$this->authorize('import');
Expand All @@ -179,7 +284,7 @@ public function mount()
$this->accessories_fields = [
'company' => trans('general.company'),
'location' => trans('general.location'),
'quantity' => trans('general.qty'),
'quantity' => trans('general.quantity'),
'item_name' => trans('general.item_name_var', ['item' => trans('general.accessory')]),
'model_number' => trans('general.model_no'),
'notes' => trans('general.notes'),
Expand Down Expand Up @@ -240,7 +345,7 @@ public function mount()
$this->consumables_fields = [
'company' => trans('general.company'),
'location' => trans('general.location'),
'quantity' => trans('general.qty'),
'quantity' => trans('general.quantity'),
'item_name' => trans('general.item_name_var', ['item' => trans('general.consumable')]),
'model_number' => trans('general.model_no'),
'notes' => trans('general.notes'),
Expand All @@ -258,7 +363,7 @@ public function mount()
$this->components_fields = [
'company' => trans('general.company'),
'location' => trans('general.location'),
'quantity' => trans('general.qty'),
'quantity' => trans('general.quantity'),
'item_name' => trans('general.item_name_var', ['item' => trans('general.component')]),
'model_number' => trans('general.model_no'),
'notes' => trans('general.notes'),
Expand Down Expand Up @@ -475,7 +580,7 @@ public function mount()
'Warranty',
'Warranty Months'
],
'qty' =>
'quantity' =>
[
'QTY',
'Quantity'
Expand Down Expand Up @@ -534,6 +639,8 @@ public function mount()
foreach ($this->importTypes as $type => $name) {
$this->columnOptions[$type] = $this->getColumns($type);
}

$this->mapping_errors = [];
}

public function selectFile($id)
Expand Down Expand Up @@ -563,6 +670,8 @@ public function selectFile($id)
$this->file_id = $id;
$this->import_errors = null;
$this->statusText = null;
$this->mapping_errors = [];
$this->updatedFieldMap("x", -1); //force trigger the duplicate-fieldmapping (and minimum fieldmapping) code

}

Expand Down
18 changes: 14 additions & 4 deletions resources/views/livewire/importer.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ class="col-md-12 table table-striped snipe-table">
<hr style="border-top: 1px solid lightgray">
</div>
<div class="form-group col-md-12">
<div class="col-md-3 text-right">
<div class="col-md-2 text-right">
<strong>{{ trans('general.csv_header_field') }}</strong>
</div>
<div class="col-md-4">
Expand All @@ -228,6 +228,9 @@ class="col-md-12 table table-striped snipe-table">
<div class="col-md-5">
<strong>{{ trans('general.sample_value') }}</strong>
</div>
<div class="col-md-1">
<strong>Status</strong> {{-- FIXME - TRANSLATE ME! --}}
</div>
</div><!-- /div row -->

@if(! empty($headerRow))
Expand All @@ -236,9 +239,9 @@ class="col-md-12 table table-striped snipe-table">

<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>
<label for="field_map.{{ $index }}"
class="col-md-2 control-label text-right">{{ $header }}</label>
<div class="col-md-4">

{{ Form::select('field_map.'.$index, $columnOptions[$typeOfImport], @$field_map[$index],
[
'class' => 'mappings livewire-select2',
Expand All @@ -254,6 +257,11 @@ class="col-md-12 table table-striped snipe-table">
<div class="col-md-5">
<p class="form-control-static">{{ str_limit($this->activeFile->first_row[$index], 50, '...') }}</p>
</div>
<div class="col-md-1">
@if(array_key_exists($index, $mapping_errors))
BAD MAPPING
@endif
</div>
@else
@php
$statusText = trans('help.empty_file');
Expand All @@ -271,7 +279,9 @@ class="col-md-12 table table-striped snipe-table">
<a href="#" wire:click.prevent="$set('activeFileId',null)">{{ trans('general.cancel') }}</a>
</div>
<div class="col-md-9">
<button type="submit" class="btn btn-primary col-md-5" id="import">{{ trans('admin/hardware/message.import.import_button') }}</button>
<button type="submit"
class="btn btn-primary col-md-5"
{{ $enough_data_to_import ? '' : ' disabled="disabled"' }} id="import">{{ trans('admin/hardware/message.import.import_button') }}</button>
<br><br>
</div>
</div>
Expand Down
Loading