diff --git a/app/Helpers/Helper.php b/app/Helpers/Helper.php index 89704242b..df498da8c 100644 --- a/app/Helpers/Helper.php +++ b/app/Helpers/Helper.php @@ -1092,6 +1092,15 @@ class Helper return $file_name; } + + /** + * Universal helper to show file size in human-readable formats + * + * @author A. Gianotto + * @since 5.0 + * + * @return string[] + */ public static function formatFilesizeUnits($bytes) { if ($bytes >= 1073741824) @@ -1121,30 +1130,56 @@ class Helper return $bytes; } + + /** + * This is weird but used by the side nav to determine which URL to point the user to + * + * @author A. Gianotto + * @since 5.0 + * + * @return string[] + */ public static function SettingUrls(){ $settings=['#','fields.index', 'statuslabels.index', 'models.index', 'categories.index', 'manufacturers.index', 'suppliers.index', 'departments.index', 'locations.index', 'companies.index', 'depreciations.index']; return $settings; } - public static function AgeFormat($date) { - $year = Carbon::parse($date) - ->diff(now())->y; - $month = Carbon::parse($date) - ->diff(now())->m; - $days = Carbon::parse($date) - ->diff(now())->d; - $age=''; - if ($year) { - $age .= $year.'y '; - } - if ($month) { - $age .= $month.'m '; - } - if ($days) { - $age .= $days.'d'; - } - return $age; + + /** + * Generic helper (largely used by livewire right now) that returns the font-awesome icon + * for the object type. + * + * @author A. Gianotto + * @since 6.1.0 + * + * @return string + */ + public static function iconTypeByItem($item) { + + switch ($item) { + case 'asset': + return 'fas fa-barcode'; + break; + case 'accessory': + return 'fas fa-keyboard'; + break; + case 'component': + return 'fas fa-hdd'; + break; + case 'consumable': + return 'fas fa-tint'; + break; + case 'license': + return 'far fa-save'; + break; + case 'location': + return 'fas fa-map-marker-alt'; + break; + case 'user': + return 'fas fa-user'; + break; + } } 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..31bbfcfbc --- /dev/null +++ b/app/Http/Livewire/Importer.php @@ -0,0 +1,322 @@ + 'required|string', + 'files.*.created_at' => 'required|string', + 'files.*.filesize' => 'required|integer', + 'activeFile' => 'Import', + 'activeFile.import_type' => 'string', + 'activeFile.field_map' => 'array', + 'activeFile.header_row' => 'array', + 'field_map' => 'array' + ]; + + public function generate_field_map() + { + \Log::debug("header row is: ".print_r($this->activeFile->header_row,true)); + \Log::debug("Field map is: ".print_r($this->field_map,true)); + $tmp = array_combine($this->activeFile->header_row, $this->field_map); + return json_encode(array_filter($tmp)); + } + + // all of these 'statics', alas, may have to change to something else to handle translations? + // I'm not sure. Maybe I use them to 'populate' the translations? TBH, I don't know yet. + 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' + ], + 'qty' => + [ + 'QTY', + 'Quantity' + ], + 'min_amt' => + [ + 'Min Amount', + 'Min QTY' + ], + 'next_audit_date' => + [ + 'Next Audit', + ], + + + ]; + + 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); + \Log::info("so, what's \$this->>field_map at?: " . print_r($this->field_map, true)); + // 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! + // Make *absolutely* sure that this key actually _exists_ in this import type - + // you can trigger this by importing accessories with a 'Warranty' column (which don't exist + // in "Accessories"!) + if (array_key_exists($key, $this->columnOptions[$new_import_type])) { + $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 boot() { // FIXME - delete or undelete. + ///////$this->activeFile = null; // I do *not* understand why I have to do this, but, well, whatever. + } + + + public function mount() + { + $this->authorize('import'); + $this->progress = -1; // '-1' means 'don't show the progressbar' + $this->progress_bar_class = 'progress-bar-warning'; + \Log::info("Hey, we are calling MOUNT (in the importer-file) !!!!!!!!"); //fcuk + $this->importTypes = [ + 'asset' => trans('general.assets'), + 'accessory' => trans('general.accessories'), + 'consumable' => trans('general.consumables'), + 'component' => trans('general.components'), + 'license' => trans('general.licenses'), + 'user' => trans('general.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); + } + if ($this->activeFile) { + $this->field_map = $this->activeFile->field_map ? array_values($this->activeFile->field_map) : []; + } + } + + public function selectFile($id) + { + \Log::info("TOGGLE EVENT FIRED!"); + \Log::error("The ID we are trying to find is AS FOLLOWS: ".$id); + $this->activeFile = Import::find($id); + $this->field_map = null; + foreach($this->activeFile->header_row as $element) { + if(isset($this->activeFile->field_map[$element])) { + $this->field_map[] = $this->activeFile->field_map[$element]; + } else { + $this->field_map[] = null; // re-inject the 'nulls' if a file was imported with some 'Do Not Import' settings + } + } + //$this->field_map = $this->activeFile->field_map ? array_values($this->activeFile->field_map) : []; // this is wrong + $this->file_id = $id; + $this->import_errors = null; + $this->statusText = null; + \Log::error("The import type we are about to try and load up is gonna be this: ".$this->activeFile->import_type); + + } + + public function destroy($id) + { + // TODO: why don't we just do File::find($id)? This seems dumb. + 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/Transformers/AssetsTransformer.php b/app/Http/Transformers/AssetsTransformer.php index 740e905d8..d431ec890 100644 --- a/app/Http/Transformers/AssetsTransformer.php +++ b/app/Http/Transformers/AssetsTransformer.php @@ -84,7 +84,7 @@ class AssetsTransformer 'next_audit_date' => Helper::getFormattedDateObject($asset->next_audit_date, 'date'), 'deleted_at' => Helper::getFormattedDateObject($asset->deleted_at, 'datetime'), 'purchase_date' => Helper::getFormattedDateObject($asset->purchase_date, 'date'), - 'age' => $asset->purchase_date ? Helper::AgeFormat($asset->purchase_date) : '', + 'age' => $asset->purchase_date ? $asset->purchase_date->diffForHumans() : '', 'last_checkout' => Helper::getFormattedDateObject($asset->last_checkout, 'datetime'), 'expected_checkin' => Helper::getFormattedDateObject($asset->expected_checkin, 'date'), 'purchase_cost' => Helper::formatCurrencyOutput($asset->purchase_cost), 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/public/js/build/app.js b/public/js/build/app.js index c9e1d08a1..3c65e5fa8 100644 --- a/public/js/build/app.js +++ b/public/js/build/app.js @@ -1,727 +1,6 @@ /******/ (() => { // webpackBootstrap /******/ var __webpack_modules__ = ({ -/***/ "./node_modules/babel-loader/lib/index.js??clonedRuleSet-5[0].rules[0].use[0]!./node_modules/vue-loader/lib/index.js??vue-loader-options!./resources/assets/js/components/alert.vue?vue&type=script&lang=js&": -/*!*******************************************************************************************************************************************************************************************************************!*\ - !*** ./node_modules/babel-loader/lib/index.js??clonedRuleSet-5[0].rules[0].use[0]!./node_modules/vue-loader/lib/index.js??vue-loader-options!./resources/assets/js/components/alert.vue?vue&type=script&lang=js& ***! - \*******************************************************************************************************************************************************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) -/* harmony export */ }); -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({ - /* - * The component's data. - */ - props: ['alertType', 'title'], - computed: { - alertClassName: function alertClassName() { - return 'alert-' + this.alertType; - } - }, - methods: { - hideEvent: function hideEvent() { - this.$emit('hide'); - } - } -}); - -/***/ }), - -/***/ "./node_modules/babel-loader/lib/index.js??clonedRuleSet-5[0].rules[0].use[0]!./node_modules/vue-loader/lib/index.js??vue-loader-options!./resources/assets/js/components/importer/importer-errors.vue?vue&type=script&lang=js&": -/*!**************************************************************************************************************************************************************************************************************************************!*\ - !*** ./node_modules/babel-loader/lib/index.js??clonedRuleSet-5[0].rules[0].use[0]!./node_modules/vue-loader/lib/index.js??vue-loader-options!./resources/assets/js/components/importer/importer-errors.vue?vue&type=script&lang=js& ***! - \**************************************************************************************************************************************************************************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) -/* harmony export */ }); -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({ - /* - * The component's data. - */ - props: ['errors'] -}); - -/***/ }), - -/***/ "./node_modules/babel-loader/lib/index.js??clonedRuleSet-5[0].rules[0].use[0]!./node_modules/vue-loader/lib/index.js??vue-loader-options!./resources/assets/js/components/importer/importer-file.vue?vue&type=script&lang=js&": -/*!************************************************************************************************************************************************************************************************************************************!*\ - !*** ./node_modules/babel-loader/lib/index.js??clonedRuleSet-5[0].rules[0].use[0]!./node_modules/vue-loader/lib/index.js??vue-loader-options!./resources/assets/js/components/importer/importer-file.vue?vue&type=script&lang=js& ***! - \************************************************************************************************************************************************************************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) -/* harmony export */ }); -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -var baseUrl = $('meta[name="baseUrl"]').attr('content'); -/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({ - props: ['file', 'customFields'], - data: function data() { - return { - activeFile: this.file, - processDetail: false, - statusText: null, - statusType: null, - options: { - importType: this.file.import_type, - update: false, - send_welcome: false, - run_backup: false, - importTypes: [{ - id: 'asset', - text: 'Assets' - }, { - id: 'accessory', - text: 'Accessories' - }, { - id: 'consumable', - text: 'Consumables' - }, { - id: 'component', - text: 'Components' - }, { - id: 'license', - text: 'Licenses' - }, { - id: 'user', - text: 'Users' - }], - statusText: null - }, - columnOptions: { - general: [{ - id: 'category', - text: 'Category' - }, { - id: 'company', - text: 'Company' - }, { - id: 'email', - text: 'Email' - }, { - id: 'item_name', - text: 'Item Name' - }, { - id: 'location', - text: 'Location' - }, { - id: 'maintained', - text: 'Maintained' - }, { - id: 'manufacturer', - text: 'Manufacturer' - }, { - id: 'order_number', - text: 'Order Number' - }, { - id: 'purchase_cost', - text: 'Purchase Cost' - }, { - id: 'purchase_date', - text: 'Purchase Date' - }, { - id: 'quantity', - text: 'Quantity' - }, { - id: 'requestable', - text: 'Requestable' - }, { - id: 'serial', - text: 'Serial Number' - }, { - id: 'supplier', - text: 'Supplier' - }, { - id: 'username', - text: 'Username' - }, { - id: 'department', - text: 'Department' - }], - accessories: [{ - id: 'model_number', - text: 'Model Number' - }, { - id: 'notes', - text: 'Notes' - }], - assets: [{ - id: 'asset_tag', - text: 'Asset Tag' - }, { - id: 'asset_model', - text: 'Model Name' - }, { - id: 'checkout_class', - text: 'Checkout Type' - }, { - id: 'checkout_location', - text: 'Checkout Location' - }, { - id: 'image', - text: 'Image Filename' - }, { - id: 'model_number', - text: 'Model Number' - }, { - id: 'asset_notes', - text: 'Asset Notes' - }, { - id: 'model_notes', - text: 'Model Notes' - }, { - id: 'full_name', - text: 'Full Name' - }, { - id: 'status', - text: 'Status' - }, { - id: 'warranty_months', - text: 'Warranty Months' - }, { - id: 'last_audit_date', - text: 'Last Audit Date' - }, { - id: 'next_audit_date', - text: 'Audit Date' - }, { - id: 'byod', - text: 'BYOD' - }], - consumables: [{ - id: 'item_no', - text: "Item Number" - }, { - id: 'model_number', - text: "Model Number" - }, { - id: 'min_amt', - text: "Minimum Quantity" - }, { - id: 'notes', - text: 'Notes' - }], - licenses: [{ - id: 'asset_tag', - text: 'Assigned To Asset' - }, { - id: 'expiration_date', - text: 'Expiration Date' - }, { - id: 'full_name', - text: 'Full Name' - }, { - id: 'license_email', - text: 'Licensed To Email' - }, { - id: 'license_name', - text: 'Licensed To Name' - }, { - id: 'notes', - text: 'Notes' - }, { - id: 'purchase_order', - text: 'Purchase Order' - }, { - id: 'reassignable', - text: 'Reassignable' - }, { - id: 'seats', - text: 'Seats' - }], - users: [{ - id: 'employee_num', - text: 'Employee Number' - }, { - id: 'first_name', - text: 'First Name' - }, { - id: 'jobtitle', - text: 'Job Title' - }, { - id: 'last_name', - text: 'Last Name' - }, { - id: 'phone_number', - text: 'Phone Number' - }, { - id: 'manager_first_name', - text: 'Manager First Name' - }, { - id: 'notes', - text: 'Notes' - }, { - id: 'manager_last_name', - text: 'Manager Last Name' - }, { - id: 'activated', - text: 'Activated' - }, { - id: 'address', - text: 'Address' - }, { - id: 'city', - text: 'City' - }, { - id: 'state', - text: 'State' - }, { - id: 'country', - text: 'Country' - }, { - id: 'zip', - text: 'ZIP' - }, { - id: 'remote', - text: 'Remote' - }, { - id: 'vip', - text: 'VIP' - }], - customFields: this.customFields - }, - columnMappings: this.file.field_map || {}, - activeColumn: null - }; - }, - created: function created() { - window.eventHub.$on('showDetails', this.toggleExtendedDisplay); - this.populateSelect2ActiveItems(); - }, - computed: { - columns: function columns() { - // function to sort objects by their display text. - function sorter(a, b) { - if (a.text < b.text) return -1; - if (a.text > b.text) return 1; - return 0; - } - - switch (this.options.importType) { - case 'asset': - return this.columnOptions.general.concat(this.columnOptions.assets).concat(this.columnOptions.customFields).sort(sorter); - - case 'accessory': - return this.columnOptions.general.concat(this.columnOptions.accessories).sort(sorter); - - case 'consumable': - console.log('Returned consumable'); - return this.columnOptions.general.concat(this.columnOptions.consumables).sort(sorter); - - case 'license': - return this.columnOptions.general.concat(this.columnOptions.licenses).sort(sorter); - - case 'user': - return this.columnOptions.general.concat(this.columnOptions.users).sort(sorter); - } - - return this.columnOptions.general; - }, - alertClass: function alertClass() { - if (this.statusType == 'success') { - return 'alert-success'; - } - - if (this.statusType == 'error') { - return 'alert-danger'; - } - - return 'alert-info'; - } - }, - watch: { - columns: function columns() { - this.populateSelect2ActiveItems(); - } - }, - methods: { - postSave: function postSave() { - var _this = this; - - console.log('saving'); - console.log(this.options.importType); - - if (!this.options.importType) { - this.statusType = 'error'; - this.statusText = "An import type is required... "; - return; - } - - this.statusType = 'pending'; - this.statusText = "Processing..."; - this.$http.post(baseUrl + 'api/v1/imports/process/' + this.file.id, { - 'import-update': this.options.update, - 'send-welcome': this.options.send_welcome, - 'import-type': this.options.importType, - 'run-backup': this.options.run_backup, - 'column-mappings': this.columnMappings - }).then(function (_ref) { - var body = _ref.body; - // Success - _this.statusType = "success"; - _this.statusText = "Success... Redirecting."; - window.location.href = body.messages.redirect_url; - }, function (_ref2) { - var body = _ref2.body; - - // Failure - if (body.status == 'import-errors') { - window.eventHub.$emit('importErrors', body.messages); - _this.statusType = 'error'; - _this.statusText = "Error"; - } else { - _this.$emit('alert', { - message: body.messages, - type: "danger", - visible: true - }); - } - - _this.displayImportModal = false; - }); - }, - populateSelect2ActiveItems: function populateSelect2ActiveItems() { - if (this.file.field_map == null) { - // Begin by populating the active selection in dropdowns with blank values. - for (var i = 0; i < this.file.header_row.length; i++) { - this.$set(this.columnMappings, this.file.header_row[i], null); - } // Then, for any values that have a likely match, we make that active. - - - for (var j = 0; j < this.columns.length; j++) { - var column = this.columns[j]; - var lower = this.file.header_row.map(function (value) { - return value.toLowerCase(); - }); - var index = lower.indexOf(column.text.toLowerCase()); - - if (index != -1) { - this.$set(this.columnMappings, this.file.header_row[index], column.id); - } - } - } - }, - toggleExtendedDisplay: function toggleExtendedDisplay(fileId) { - if (fileId == this.file.id) { - this.processDetail = !this.processDetail; - } - }, - updateModel: function updateModel(header, value) { - this.columnMappings[header] = value; - } - }, - components: { - select2: (__webpack_require__(/*! ../select2.vue */ "./resources/assets/js/components/select2.vue")["default"]) - } -}); - -/***/ }), - -/***/ "./node_modules/babel-loader/lib/index.js??clonedRuleSet-5[0].rules[0].use[0]!./node_modules/vue-loader/lib/index.js??vue-loader-options!./resources/assets/js/components/importer/importer.vue?vue&type=script&lang=js&": -/*!*******************************************************************************************************************************************************************************************************************************!*\ - !*** ./node_modules/babel-loader/lib/index.js??clonedRuleSet-5[0].rules[0].use[0]!./node_modules/vue-loader/lib/index.js??vue-loader-options!./resources/assets/js/components/importer/importer.vue?vue&type=script&lang=js& ***! - \*******************************************************************************************************************************************************************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) -/* harmony export */ }); -// -// -__webpack_require__(/*! blueimp-file-upload */ "./node_modules/blueimp-file-upload/js/jquery.fileupload.js"); - -var baseUrl = $('meta[name="baseUrl"]').attr('content'); -/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({ - /* - * The component's data. - */ - data: function data() { - return { - files: [], - displayImportModal: false, - activeFile: null, - alert: { - type: null, - message: null, - visible: false - }, - importErrors: null, - progress: { - currentClass: "progress-bar-warning", - currentPercent: "0", - statusText: '', - visible: false - }, - customFields: [] - }; - }, - mounted: function mounted() { - window.eventHub.$on('importErrors', this.updateImportErrors); - this.fetchFiles(); - this.fetchCustomFields(); - var vm = this; - $('#fileupload').fileupload({ - dataType: 'json', - done: function done(e, data) { - vm.progress.currentClass = "progress-bar-success"; - vm.progress.statusText = "Success!"; - vm.files = data.result.files.concat(vm.files); - console.log(data.result.header_row); - }, - add: function add(e, data) { - data.headers = { - "X-Requested-With": 'XMLHttpRequest', - "X-CSRF-TOKEN": Laravel.csrfToken - }; - data.process().done(function () { - data.submit(); - }); - vm.progress.visible = true; - }, - progress: function progress(e, data) { - var progress = parseInt((data.loaded / data.total * 100, 10)); - vm.progress.currentPercent = progress; - vm.progress.statusText = progress + '% Complete'; - }, - fail: function fail(e, data) { - vm.progress.currentClass = "progress-bar-danger"; // Display any errors returned from the $.ajax() - - vm.progress.statusText = data.jqXHR.responseJSON.messages; - } - }); - }, - methods: { - fetchFiles: function fetchFiles() { - var _this = this; - - this.$http.get(baseUrl + 'api/v1/imports').then(function (_ref) { - var data = _ref.data; - return _this.files = data; - }, // Success - //Fail - function (response) { - _this.alert.type = "danger"; - _this.alert.visible = true; - _this.alert.message = "Something went wrong fetching files..."; - }); - }, - fetchCustomFields: function fetchCustomFields() { - var _this2 = this; - - this.$http.get(baseUrl + 'api/v1/fields').then(function (_ref2) { - var data = _ref2.data; - data = data.rows; - data.forEach(function (item) { - _this2.customFields.push({ - 'id': item.db_column_name, - 'text': item.name - }); - }); - }); - }, - deleteFile: function deleteFile(file, key) { - var _this3 = this; - - this.$http["delete"](baseUrl + 'api/v1/imports/' + file.id).then( // Success, remove file from array. - function (response) { - _this3.files.splice(key, 1); - - _this3.alert.type = response.body.status; // A failed delete can still cause a 200 status code. - - _this3.alert.visible = true; - _this3.alert.message = response.body.messages; - }, function (response) { - // Fail - // this.files.splice(key, 1); - _this3.alert.type = "error"; - _this3.alert.visible = true; - _this3.alert.message = response.body.messages; - }); - }, - toggleEvent: function toggleEvent(fileId) { - window.eventHub.$emit('showDetails', fileId); - }, - updateAlert: function updateAlert(alert) { - this.alert = alert; - }, - updateImportErrors: function updateImportErrors(errors) { - this.importErrors = errors; - } - }, - computed: { - progressWidth: function progressWidth() { - return "width: " + this.progress.currentPercent * 10 + '%'; - } - }, - components: { - alert: (__webpack_require__(/*! ../alert.vue */ "./resources/assets/js/components/alert.vue")["default"]), - errors: (__webpack_require__(/*! ./importer-errors.vue */ "./resources/assets/js/components/importer/importer-errors.vue")["default"]), - importFile: (__webpack_require__(/*! ./importer-file.vue */ "./resources/assets/js/components/importer/importer-file.vue")["default"]) - } -}); - -/***/ }), - /***/ "./node_modules/babel-loader/lib/index.js??clonedRuleSet-5[0].rules[0].use[0]!./node_modules/vue-loader/lib/index.js??vue-loader-options!./resources/assets/js/components/passport/AuthorizedClients.vue?vue&type=script&lang=js&": /*!****************************************************************************************************************************************************************************************************************************************!*\ !*** ./node_modules/babel-loader/lib/index.js??clonedRuleSet-5[0].rules[0].use[0]!./node_modules/vue-loader/lib/index.js??vue-loader-options!./resources/assets/js/components/passport/AuthorizedClients.vue?vue&type=script&lang=js& ***! @@ -1530,64 +809,6 @@ function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" = /***/ }), -/***/ "./node_modules/babel-loader/lib/index.js??clonedRuleSet-5[0].rules[0].use[0]!./node_modules/vue-loader/lib/index.js??vue-loader-options!./resources/assets/js/components/select2.vue?vue&type=script&lang=js&": -/*!*********************************************************************************************************************************************************************************************************************!*\ - !*** ./node_modules/babel-loader/lib/index.js??clonedRuleSet-5[0].rules[0].use[0]!./node_modules/vue-loader/lib/index.js??vue-loader-options!./resources/assets/js/components/select2.vue?vue&type=script&lang=js& ***! - \*********************************************************************************************************************************************************************************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) -/* harmony export */ }); -// -// -// -// -// -// -// -// -// -// -// -// -// -//require('select2'); -/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({ - /* - * The component's data. - */ - props: ['options', 'value'], - mounted: function mounted() { - var vm = this; - $(this.$el).select2({ - data: this.options - }).on('change', function () { - vm.$emit('input', this.value); - }).val(this.value).trigger('change'); - }, - watch: { - value: function value(_value) { - $(this.$el).val(_value); - }, - options: function options(_options) { - var vm = this; - $(this.$el).select2('destroy').empty().select2({ - data: _options - }).on('change', function () { - vm.$emit('input', this.value); - }).val(this.value).trigger('change'); - }, - destroyed: function destroyed() { - $(this.$el).off().select2('destroy'); - } - } -}); - -/***/ }), - /***/ "./resources/assets/js/bootstrap.js": /*!******************************************!*\ !*** ./resources/assets/js/bootstrap.js ***! @@ -2209,6 +1430,56 @@ 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