diff --git a/database/migrations/2019_04_26_000000_create_excel_uploads_table.php b/database/migrations/2019_04_26_000000_create_excel_uploads_table.php index 21005e3..93e5f9d 100644 --- a/database/migrations/2019_04_26_000000_create_excel_uploads_table.php +++ b/database/migrations/2019_04_26_000000_create_excel_uploads_table.php @@ -19,6 +19,7 @@ public function up() $table->string('resource'); $table->string('disk')->nullable(); $table->string('path')->nullable(); + $table->string('stats')->nullable(); $table->string('filename'); $table->timestamps(); }); diff --git a/dist/js/tool.js b/dist/js/tool.js index 523884c..0fe2368 100644 --- a/dist/js/tool.js +++ b/dist/js/tool.js @@ -394,6 +394,10 @@ function _asyncToGenerator(fn) { return function () { var self = this, args = ar // // // +// +// +// +// /* harmony default export */ __webpack_exports__["default"] = ({ props: ['upload'], data: function data() { @@ -406,7 +410,8 @@ function _asyncToGenerator(fn) { return function () { var self = this, args = ar mapping: {}, importing: false, errors: [], - errorMessage: null + errorMessage: null, + loading: true }; }, mounted: function () { @@ -431,6 +436,7 @@ function _asyncToGenerator(fn) { return function () { var self = this, args = ar headings = _ref$data.headings; totalRows = _ref$data.totalRows; fields = _ref$data.fields; + this.loading = false; this.rows = rows; this.fields = fields; this.headings = headings; @@ -439,8 +445,22 @@ function _asyncToGenerator(fn) { return function () { var self = this, args = ar this.headings.map(function (value, key) { _this.mapping[key] = ''; }); + this.fields.forEach(function (field_config) { + var field = field_config.attribute, + heading_index = _this.headings.indexOf(field); + + if (heading_index < 0) { + return; + } + + var heading = _this.headings[heading_index]; + + if (heading === field) { + _this.$set(_this.mapping, heading_index, field); + } + }); - case 14: + case 16: case "end": return _context.stop(); } @@ -11714,154 +11734,175 @@ var render = function() { _c("heading", { staticClass: "mb-6" }, [_vm._v("Import")]), _vm._v(" "), _c("card", { staticClass: "flex flex-col" }, [ - _c("div", { staticClass: "p-8" }, [ - _c("h2", { staticClass: "pb-4" }, [_vm._v("Preview")]), - _vm._v(" "), - _c("p", { staticClass: "pb-4" }, [ - _vm._v("\n We were able to discover "), - _c("b", [_vm._v(_vm._s(_vm.columnCount))]), - _vm._v(" column(s) and "), - _c("b", [_vm._v(_vm._s(_vm.rowCount))]), - _vm._v("\n row(s) in your data.\n ") - ]), - _vm._v(" "), - _c("p", { staticClass: "pb-4" }, [ - _vm._v( - "\n Match up the headings from the file to the appropriate fields of the resource.\n " - ) - ]), - _vm._v(" "), - _vm.errorMessage - ? _c( - "div", - { - staticClass: - "bg-danger-light border border-danger-dark text-danger-dark px-4 py-3 rounded relative", - attrs: { role: "alert" } - }, - [ - _c("div", { staticClass: "font-bold mb-4" }, [ - _vm._v(_vm._s(_vm.errorMessage)) - ]), - _vm._v(" "), - _vm.errors.length > 0 - ? _c( - "ul", - { staticClass: "pl-6" }, - _vm._l(_vm.errors, function(error) { - return _c("li", { key: error.row }, [ - _vm._v( - "\n " + - _vm._s( - _vm.__("Error on row :row.", { - row: error.row - }) - ) + - " " + - _vm._s(error.message) + - "\n " - ) - ]) - }), - 0 - ) - : _vm._e() - ] - ) - : _vm._e() - ]), - _vm._v(" "), - _c("table", { staticClass: "table w-full" }, [ - _c("thead", [ + _c( + "div", + { staticClass: "p-8" }, + [ + _c("h2", { staticClass: "pb-4" }, [_vm._v("Preview")]), + _vm._v(" "), _c( - "tr", - _vm._l(_vm.headings, function(heading) { - return _c("th", [_vm._v(_vm._s(heading))]) - }), - 0 - ) - ]), - _vm._v(" "), - _c( - "tbody", - [ + "loading-view", + { attrs: { loading: _vm.loading || _vm.importing } }, + [ + _c("p", { staticClass: "pb-4" }, [ + _vm._v("\n We were able to discover "), + _c("b", [_vm._v(_vm._s(_vm.columnCount))]), + _vm._v(" column(s) and "), + _c("b", [_vm._v(_vm._s(_vm.rowCount))]), + _vm._v( + "\n row(s) in your data.\n " + ) + ]), + _vm._v(" "), + _c("p", { staticClass: "pb-4" }, [ + _vm._v( + "\n Match up the headings from the file to the appropriate fields of the resource.\n " + ) + ]) + ] + ), + _vm._v(" "), + _vm.errorMessage + ? _c( + "div", + { + staticClass: + "bg-danger-light border border-danger-dark text-danger-dark px-4 py-3 rounded relative", + attrs: { role: "alert" } + }, + [ + _c("div", { staticClass: "font-bold mb-4" }, [ + _vm._v(_vm._s(_vm.errorMessage)) + ]), + _vm._v(" "), + _vm.errors.length > 0 + ? _c( + "ul", + { staticClass: "pl-6" }, + _vm._l(_vm.errors, function(error) { + return _c("li", { key: error.row }, [ + _vm._v( + "\n " + + _vm._s( + _vm.__("Error on row :row.", { + row: error.row + }) + ) + + " " + + _vm._s(error.message) + + "\n " + ) + ]) + }), + 0 + ) + : _vm._e() + ] + ) + : _vm._e() + ], + 1 + ), + _vm._v(" "), + _c("div", { staticClass: "w-full overflow-x-scroll" }, [ + _c("table", { staticClass: "table" }, [ + _c("thead", [ _c( "tr", - _vm._l(_vm.headings, function(heading, headingIndex) { - return _c( - "td", - { key: headingIndex, staticClass: "text-center" }, - [ - _c( - "select", - { - directives: [ - { - name: "model", - rawName: "v-model", - value: _vm.mapping[headingIndex], - expression: "mapping[headingIndex]" - } - ], - staticClass: "w-full form-control form-select", - on: { - change: function($event) { - var $$selectedVal = Array.prototype.filter - .call($event.target.options, function(o) { - return o.selected - }) - .map(function(o) { - var val = "_value" in o ? o._value : o.value - return val - }) - _vm.$set( - _vm.mapping, - headingIndex, - $event.target.multiple - ? $$selectedVal - : $$selectedVal[0] - ) - } - } - }, - [ - _c("option", { attrs: { value: "" } }, [ - _vm._v( - "- " + _vm._s(_vm.__("Ignore this column")) + " -" - ) - ]), - _vm._v(" "), - _vm._l(_vm.fields, function(field) { - return _c( - "option", - { - key: field.attribute, - domProps: { value: field.attribute } - }, - [_vm._v(_vm._s(field.name))] - ) - }) - ], - 2 - ) - ] - ) + _vm._l(_vm.headings, function(heading) { + return _c("th", [_vm._v(_vm._s(heading))]) }), 0 - ), - _vm._v(" "), - _vm._l(_vm.rows, function(row) { - return _c( + ) + ]), + _vm._v(" "), + _c( + "tbody", + [ + _c( "tr", - _vm._l(row, function(col, index) { - return _c("td", { key: index }, [_vm._v(_vm._s(col))]) + _vm._l(_vm.headings, function(heading, headingIndex) { + return _c( + "td", + { + key: headingIndex, + staticClass: "text-center", + staticStyle: { "min-width": "225px" } + }, + [ + _c( + "select", + { + directives: [ + { + name: "model", + rawName: "v-model", + value: _vm.mapping[headingIndex], + expression: "mapping[headingIndex]" + } + ], + staticClass: "w-full form-control form-select", + on: { + change: function($event) { + var $$selectedVal = Array.prototype.filter + .call($event.target.options, function(o) { + return o.selected + }) + .map(function(o) { + var val = "_value" in o ? o._value : o.value + return val + }) + _vm.$set( + _vm.mapping, + headingIndex, + $event.target.multiple + ? $$selectedVal + : $$selectedVal[0] + ) + } + } + }, + [ + _c("option", { attrs: { value: "" } }, [ + _vm._v( + "- " + + _vm._s(_vm.__("Ignore this column")) + + " -" + ) + ]), + _vm._v(" "), + _vm._l(_vm.fields, function(field) { + return _c( + "option", + { + key: field.attribute, + domProps: { value: field.attribute } + }, + [_vm._v(_vm._s(field.name))] + ) + }) + ], + 2 + ) + ] + ) }), 0 - ) - }) - ], - 2 - ) + ), + _vm._v(" "), + _vm._l(_vm.rows, function(row) { + return _c( + "tr", + _vm._l(row, function(col, index) { + return _c("td", { key: index }, [_vm._v(_vm._s(col))]) + }), + 0 + ) + }) + ], + 2 + ) + ]) ]), _vm._v(" "), _c("div", { staticClass: "bg-30 flex px-8 py-4" }, [ @@ -12389,7 +12430,7 @@ Nova.booting(function (Vue, router) { /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { -module.exports = __webpack_require__(/*! /Users/patrick/Sites/laravel-nova/maatwebsite/laravel-nova-excel/resources/js/tool.js */"./resources/js/tool.js"); +module.exports = __webpack_require__(/*! /Users/simonhamp/Projects/Composer/Laravel-Nova-Excel/resources/js/tool.js */"./resources/js/tool.js"); /***/ }) diff --git a/resources/js/components/Preview.vue b/resources/js/components/Preview.vue index e73f57c..e6a77fa 100644 --- a/resources/js/components/Preview.vue +++ b/resources/js/components/Preview.vue @@ -5,13 +5,15 @@

Preview

-

- We were able to discover {{ columnCount }} column(s) and {{ rowCount }} - row(s) in your data. -

-

- Match up the headings from the file to the appropriate fields of the resource. -

+ +

+ We were able to discover {{ columnCount }} column(s) and {{ rowCount }} + row(s) in your data. +

+

+ Match up the headings from the file to the appropriate fields of the resource. +

+
- - - - - - - - - - - - - - -
{{ heading }}
- -
{{ col }}
+
+ + + + + + + + + + + + + + +
{{ heading }}
+ +
{{ col }}
+
@@ -70,12 +74,14 @@ importing: false, errors: [], errorMessage: null, + loading: true, } }, async mounted() { let {data: {rows, headings, totalRows, fields}} = await window.Nova.request() .get(`/nova-vendor/maatwebsite/laravel-nova-excel/uploads/${this.upload}/preview`); + this.loading = false; this.rows = rows; this.fields = fields; this.headings = headings; @@ -84,7 +90,22 @@ this.headings.map((value, key) => { this.mapping[key] = ''; - }) + }); + + this.fields.forEach((field_config) => { + let field = field_config.attribute, + heading_index = this.headings.indexOf(field); + + if (heading_index < 0) { + return; + } + + let heading = this.headings[heading_index]; + + if (heading === field) { + this.$set(this.mapping, heading_index, field); + } + }); }, methods: { async importRows() { @@ -108,4 +129,4 @@ } }, } - \ No newline at end of file + diff --git a/src/Http/Controllers/UploadsPreviewsController.php b/src/Http/Controllers/UploadsPreviewsController.php index b2d62a9..bf9bff5 100644 --- a/src/Http/Controllers/UploadsPreviewsController.php +++ b/src/Http/Controllers/UploadsPreviewsController.php @@ -22,11 +22,13 @@ public function show(Upload $upload, NovaRequest $request, Importer $importer) { $import = new PreviewImport($upload, $request); - $importer->import( - $import, - $upload->path, - $upload->disk - ); + if (!$upload->stats) { + $importer->import( + $import, + $upload->path, + $upload->disk + ); + } return $import; } diff --git a/src/Imports/PreviewImport.php b/src/Imports/PreviewImport.php index 3fd2059..d0cc88e 100644 --- a/src/Imports/PreviewImport.php +++ b/src/Imports/PreviewImport.php @@ -88,12 +88,18 @@ public function registerEvents(): array */ public function toResponse($request) { - return new JsonResponse([ - 'rows' => $this->rows, - 'headings' => $this->headings, - 'totalRows' => $this->totalRows, - 'fields' => $this->resource()->creationFields($this->request), - ]); + if (!$this->upload->stats) { + $this->upload->stats = [ + 'rows' => $this->rows, + 'headings' => $this->headings, + 'totalRows' => $this->totalRows, + 'fields' => $this->resource()->creationFields($this->request), + ]; + + $this->upload->update(); + } + + return new JsonResponse($this->upload->stats); } /** diff --git a/src/Models/Upload.php b/src/Models/Upload.php index 0e41c2c..c88f816 100644 --- a/src/Models/Upload.php +++ b/src/Models/Upload.php @@ -37,6 +37,13 @@ class Upload extends Model 'path', ]; + /** + * @var array + */ + protected $casts = [ + 'stats' => 'array', + ]; + /** * @param UploadedFile $file * @param User $user