diff --git a/app/Http/Controllers/ImportsController.php b/app/Http/Controllers/ImportsController.php deleted file mode 100644 index 5c2ca6175..000000000 --- a/app/Http/Controllers/ImportsController.php +++ /dev/null @@ -1,22 +0,0 @@ -authorize('import'); - $imports = (new ImportsTransformer)->transformImports(Import::latest()->get()); - - return view('importer/import')->with('imports', $imports); - } -} diff --git a/app/Http/Livewire/Importer.php b/app/Http/Livewire/Importer.php new file mode 100644 index 000000000..237ebe550 --- /dev/null +++ b/app/Http/Livewire/Importer.php @@ -0,0 +1,104 @@ + 'required|string', + 'files.*.created_at' => 'required|string', + 'files.*.filesize' => 'required|integer' + ]; + + protected $listeners = [ + 'hideDetails' => 'hideDetails', + 'importError' => 'importError', + 'alert' => 'alert' + ]; // TODO - try using the 'short' form of this? + + public function mount() + { + $this->authorize('import'); + $this->progress = -1; // '-1' means 'don't show the progressbar' + $this->progress_bar_class = 'progress-bar-warning'; + } + + public function hideMessages() + { + $this->message=''; + } + + public function importError($errors) + { + \Log::debug("Errors fired!!!!"); + \Log::debug(" Here they are...".print_r($errors,true)); + $this->import_errors = $errors; + } + + public function alert($obj) + { + \Log::debug("Alert object received: ".print_r($obj,true)); + $this->message = $obj; + $this->message_type = "danger"; + } + + public function toggleEvent($id) + { + $this->processDetails = Import::find($id); + } + + public function hideDetails() + { + $this->processDetails = null; + } + + public function destroy($id) + { + foreach($this->files as $file) { + \Log::debug("File id is: ".$file->id); + if($id == $file->id) { + if(Storage::delete('private_uploads/imports/'.$file->file_path)) { + $file->delete(); + + $this->message = trans('admin/hardware/message.import.file_delete_success'); + $this->message_type = 'success'; + return; + } else { + $this->message = trans('admin/hardware/message.import.file_delete_error'); + $this->message_type = 'danger'; + } + } + } + } + + public function render() + { + $this->files = Import::orderBy('id','desc')->get(); //HACK - slows down renders. + return view('livewire.importer') + ->extends('layouts.default') + ->section('content'); + } +} diff --git a/app/Http/Livewire/ImporterFile.php b/app/Http/Livewire/ImporterFile.php new file mode 100644 index 000000000..e67f37f49 --- /dev/null +++ b/app/Http/Livewire/ImporterFile.php @@ -0,0 +1,221 @@ + 'string', + 'activeFile.field_map' => 'array', + 'activeFile.header_row' => 'array', + 'field_map' => 'array' + ]; + + + public function generate_field_map() + { + $tmp = array_combine($this->activeFile->header_row, $this->field_map); + return json_encode(array_filter($tmp)); + } + + static $general = [ + 'category' => 'Category', + 'company' => 'Company', + 'email' => 'Email', + 'item_name' => 'Item Name', + 'location' => 'Location', + 'maintained' => 'Maintained', + 'manufacturer' => 'Manufacturer', + 'notes' => 'Notes', + 'order_number' => 'Order Number', + 'purchase_cost' => 'Purchase Cost', + 'purchase_date' => 'Purchase Date', + 'quantity' => 'Quantity', + 'requestable' => 'Requestable', + 'serial' => 'Serial Number', + 'supplier' => 'Supplier', + 'username' => 'Username', + 'department' => 'Department', + ]; + + static $accessories = [ + 'model_number' => 'Model Number', + ]; + + static $assets = [ + 'asset_tag' => 'Asset Tag', + 'asset_model' => 'Model Name', + 'byod' => 'BYOD', + 'checkout_class' => 'Checkout Type', + 'checkout_location' => 'Checkout Location', + 'image' => 'Image Filename', + 'model_number' => 'Model Number', + 'full_name' => 'Full Name', + 'status' => 'Status', + 'warranty_months' => 'Warranty Months', + ]; + + static $consumables = [ + 'item_no' => "Item Number", + 'model_number' => "Model Number", + 'min_amt' => "Minimum Quantity", + ]; + + static $licenses = [ + 'asset_tag' => 'Assigned To Asset', + 'expiration_date' => 'Expiration Date', + 'full_name' => 'Full Name', + 'license_email' => 'Licensed To Email', + 'license_name' => 'Licensed To Name', + 'purchase_order' => 'Purchase Order', + 'reassignable' => 'Reassignable', + 'seats' => 'Seats', + ]; + + static $users = [ + 'employee_num' => 'Employee Number', + 'first_name' => 'First Name', + 'jobtitle' => 'Job Title', + 'last_name' => 'Last Name', + 'phone_number' => 'Phone Number', + 'manager_first_name' => 'Manager First Name', + 'manager_last_name' => 'Manager Last Name', + 'activated' => 'Activated', + 'address' => 'Address', + 'city' => 'City', + 'state' => 'State', + 'country' => 'Country', + 'vip' => 'VIP' + ]; + + //array of "real fieldnames" to a list of aliases for that field + static $aliases = [ + 'model_number' => ['model', 'model no','model no.','model number', 'model num', 'model num.'], + 'warranty_months' => ['Warranty', 'Warranty Months'] + ]; + + private function getColumns($type) + { + switch($type) { + case 'asset': + $results = self::$general + self::$assets; + break; + case 'accessory': + $results = self::$general + self::$accessories; + break; + case 'consumable': + $results = self::$general + self::$consumables; + break; + case 'license': + $results = self::$general + self::$licenses; + break; + case 'user': + $results = self::$general + self::$users; + break; + default: + $results = self::$general; + } + asort($results, SORT_FLAG_CASE|SORT_STRING); + if($type == "asset") { + // add Custom Fields after a horizontal line + $results['-'] = "———".trans('admin/custom_fields/general.custom_fields')."———’"; + foreach(CustomField::orderBy('name')->get() AS $field) { + $results[$field->db_column_name()] = $field->name; + } + } + return $results; + } + + public function updating($name, $new_import_type) + { + if ($name == "activeFile.import_type") { + \Log::info("WE ARE CHANGING THE import_type!!!!! TO: ".$new_import_type); + // go through each header, find a matching field to try and map it to. + foreach($this->activeFile->header_row as $i => $header) { + // do we have something mapped already? + if (array_key_exists($i, $this->field_map)) { + // yes, we do. Is it valid for this type of import? + // (e.g. the import type might have been changed...?) + if (array_key_exists($this->field_map[$i], $this->columnOptions[$new_import_type])) { + //yes, this key *is* valid. Continue on to the next field. + continue; + } else { + //no, this key is *INVALID* for this import type. Better set it to null + // and we'll hope that the aliases or something else picks it up. + $this->field_map[$i] = null; // fingers crossed! But it's not likely, tbh. + } // TODO - strictly speaking, this isn't necessary here I don't think. + } + // first, check for exact matches + foreach ($this->columnOptions[$new_import_type] AS $value => $text) { + if (strcasecmp($text, $header) === 0) { // case-INSENSITIVe on purpose! + $this->field_map[$i] = $value; + continue 2; //don't bother with the alias check, go to the next header + } + } + // if you got here, we didn't find a match. Try the aliases + foreach(self::$aliases as $key => $alias_values) { + foreach($alias_values as $alias_value) { + if (strcasecmp($alias_value,$header) === 0) { // aLsO CaSe-INSENSitiVE! + $this->field_map[$i] = $key; + continue 3; // bust out of both of these loops; as well as the surrounding one - e.g. move on to the next header + } + } + } + // and if you got here, we got nothing. Let's recommend 'null' + $this->field_map[$i] = null; // Booooo :( + } + } + } + + public function mount() + { + $this->importTypes = [ + 'asset' => 'Assets', // TODO - translate! + 'accessory' => 'Accessories', + 'consumable' => 'Consumables', + 'component' => 'Components', + 'license' => 'Licenses', + 'user' => 'Users' + ]; + + $this->columnOptions[''] = $this->getColumns(''); //blank mode? I don't know what this is supposed to mean + foreach($this->importTypes AS $type => $name) { + $this->columnOptions[$type] = $this->getColumns($type); + } + $this->field_map = $this->activeFile->field_map ? array_values($this->activeFile->field_map): []; + } + + public function postSave() + { + if (!$this->activeFile->import_type) { + Log::error("didn't find an import type :("); + $this->statusType ='error'; + $this->statusText = "An import type is required... "; // TODO - translate me! + return false; + } + $this->statusType = 'pending'; + $this->statusText = "Processing..."; + + } + + public function render() + { + return view('livewire.importer-file'); + } +} diff --git a/app/Models/CustomField.php b/app/Models/CustomField.php index 83fa93ec5..fcab5b25f 100644 --- a/app/Models/CustomField.php +++ b/app/Models/CustomField.php @@ -238,7 +238,7 @@ class CustomField extends Model * * @author [A. Gianotto] [] * @since [v3.0] - * @return \Illuminate\Database\Eloquent\Relations\Relation + * @return string */ public function db_column_name() { diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 90520738d..d5b10bde3 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -39,7 +39,7 @@ class RouteServiceProvider extends ServiceProvider { Route::group([ 'middleware' => 'web', - 'namespace' => $this->namespace, +// 'namespace' => $this->namespace, //okay, I don't know what this means, but somehow this might be a problem for us? ], function ($router) { require base_path('routes/web/hardware.php'); require base_path('routes/web/models.php'); @@ -65,7 +65,7 @@ class RouteServiceProvider extends ServiceProvider { Route::group([ 'middleware' => 'auth:api', - 'namespace' => $this->namespace, +// 'namespace' => $this->namespace, // this might also be a problem? I don't really know :/ 'prefix' => 'api', ], function ($router) { require base_path('routes/api.php'); diff --git a/resources/assets/js/components/alert.vue b/resources/assets/js/components/alert.vue deleted file mode 100644 index 1a2033465..000000000 --- a/resources/assets/js/components/alert.vue +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - diff --git a/resources/assets/js/components/importer/importer-errors.vue b/resources/assets/js/components/importer/importer-errors.vue deleted file mode 100644 index adc6841d4..000000000 --- a/resources/assets/js/components/importer/importer-errors.vue +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - diff --git a/resources/assets/js/components/importer/importer-file.vue b/resources/assets/js/components/importer/importer-file.vue deleted file mode 100644 index 8541f7c58..000000000 --- a/resources/assets/js/components/importer/importer-file.vue +++ /dev/null @@ -1,327 +0,0 @@ - - - diff --git a/resources/assets/js/components/importer/importer.vue b/resources/assets/js/components/importer/importer.vue deleted file mode 100644 index 474f8f145..000000000 --- a/resources/assets/js/components/importer/importer.vue +++ /dev/null @@ -1,130 +0,0 @@ - - - diff --git a/resources/assets/js/snipeit.js b/resources/assets/js/snipeit.js index 6d5340c80..95fb26865 100755 --- a/resources/assets/js/snipeit.js +++ b/resources/assets/js/snipeit.js @@ -605,3 +605,54 @@ function htmlEntities(str) { }; })(jQuery); + +/** + * Universal Livewire Select2 and iCheck integration + * + * How to use: + * + * 1. Set the class of your select2 elements to 'livewire-select2' and your icheck elements to 'livewire-icheck' (as appropriate). + * (For iCheck, you may still need to apply the other iCheck classes like 'minimal' or 'iCheck') + * 2. Name your element to match a property in your Livewire component + * 3. Add an attribute called 'data-livewire-component' that points to $_instance->id (via `{{ }}` if you're in a blade, + * or just $_instance->id if not). + * 4. For iCheck, you need to wrap the 'checkbox' element with wire:ignore - perhaps in the