فهرست منبع

Adapts Asset Info for SPA and improves CircleSpinner.

Christopher Leggett 5 سال پیش
والد
کامیت
28f3e947c8

+ 8 - 0
app/Asset.php

@@ -12,6 +12,14 @@ class Asset extends Model
     const CREATED_AT = 'created_date';
     const UPDATED_AT = 'modified_date';
 
+    public function getPcextraAttribute($value) {
+        return unserialize($value);
+    }
+
+    public function setPcextraAttribute($value) {
+        $this->attributes['pcextra'] = serialize($value);
+    }
+
     public function workOrders()
     {
         return $this->hasMany('App\WorkOrder');

+ 0 - 2
app/Events/AssetUpdated.php

@@ -16,7 +16,6 @@ class AssetUpdated implements ShouldBroadcast
     use Dispatchable, InteractsWithSockets, SerializesModels;
 
     public $data;
-    public $pcextra;
 
     /**
      * Create a new event instance.
@@ -26,7 +25,6 @@ class AssetUpdated implements ShouldBroadcast
     public function __construct($asset)
     {
         $this->data = $asset;
-        $this->pcextra = json_encode(unserialize($asset->pcextra));
     }
 
     /**

+ 1 - 1
app/Http/Controllers/Api/AssetsController.php

@@ -52,7 +52,7 @@ class AssetsController extends Controller
         $asset->pcmanu = $request->input('pcmanu');
         $asset->pcmake = $request->input('pcmake');
         $asset->pcnickname = $request->input('pcnickname');
-        $asset->pcextra = serialize($request->input('pcextra'));
+        $asset->pcextra = $request->input('pcextra');
         $asset->save();
         event(new \App\Events\AssetUpdated($asset));
         return response()->json($asset, 200);

+ 758 - 92
public/js/app.js

@@ -1897,6 +1897,140 @@ module.exports = {
 };
 
 
+/***/ }),
+
+/***/ "./node_modules/babel-loader/lib/index.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/AssetInfo.vue?vue&type=script&lang=js&":
+/*!********************************************************************************************************************************************************************!*\
+  !*** ./node_modules/babel-loader/lib??ref--4-0!./node_modules/vue-loader/lib??vue-loader-options!./resources/js/components/AssetInfo.vue?vue&type=script&lang=js& ***!
+  \********************************************************************************************************************************************************************/
+/*! exports provided: default */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony import */ var _components_AssetInfoEditModal_vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../components/AssetInfoEditModal.vue */ "./resources/js/components/AssetInfoEditModal.vue");
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+
+/* harmony default export */ __webpack_exports__["default"] = ({
+  components: {
+    AssetInfoEditModal: _components_AssetInfoEditModal_vue__WEBPACK_IMPORTED_MODULE_0__["default"]
+  },
+  props: ['asset'],
+  mounted: function mounted() {
+    var _this = this;
+
+    Echo.channel('asset.' + this.asset.pcid).listen('AssetUpdated', function (e) {
+      _this.asset = e.data;
+    });
+  }
+});
+
+/***/ }),
+
+/***/ "./node_modules/babel-loader/lib/index.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/AssetInfoEditModal.vue?vue&type=script&lang=js&":
+/*!*****************************************************************************************************************************************************************************!*\
+  !*** ./node_modules/babel-loader/lib??ref--4-0!./node_modules/vue-loader/lib??vue-loader-options!./resources/js/components/AssetInfoEditModal.vue?vue&type=script&lang=js& ***!
+  \*****************************************************************************************************************************************************************************/
+/*! exports provided: default */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony import */ var _components_Modal_vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../components/Modal.vue */ "./resources/js/components/Modal.vue");
+/* harmony import */ var _components_CircleSpinner_vue__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../components/CircleSpinner.vue */ "./resources/js/components/CircleSpinner.vue");
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+
+
+/* harmony default export */ __webpack_exports__["default"] = ({
+  components: {
+    Modal: _components_Modal_vue__WEBPACK_IMPORTED_MODULE_0__["default"],
+    CircleSpinner: _components_CircleSpinner_vue__WEBPACK_IMPORTED_MODULE_1__["default"]
+  },
+  props: ['populateWith', 'modalId'],
+  data: function data() {
+    return {
+      // Essentially makes a copy of the object. Otherwise
+      // We would have a reference to the exising object causing
+      // unwanted mutations in the parent component.
+      asset: JSON.parse(JSON.stringify(this.populateWith)),
+      assetSaving: false
+    };
+  },
+  methods: {
+    updateAsset: function updateAsset() {
+      var _this = this;
+
+      this.assetSaving = true;
+      axios.put("/api/assets/".concat(this.asset.pcid), this.asset).then(function (response) {
+        _this.assetSaving = false;
+        $("#".concat(_this.modalId)).modal('hide');
+      })["catch"](function (error) {
+        _this.assetSaving = false;
+      });
+    }
+  }
+});
+
 /***/ }),
 
 /***/ "./node_modules/babel-loader/lib/index.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/AutocompleteCustomDropdown.vue?vue&type=script&lang=js&":
@@ -2056,6 +2190,10 @@ __webpack_require__.r(__webpack_exports__);
     color: {
       type: String,
       "default": '#fff'
+    },
+    size: {
+      type: String,
+      "default": '10'
     }
   }
 });
@@ -2541,7 +2679,9 @@ __webpack_require__.r(__webpack_exports__);
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _components_WorkOrderInfo_vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../components/WorkOrderInfo.vue */ "./resources/js/components/WorkOrderInfo.vue");
-/* harmony import */ var _components_CircleSpinner_vue__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../components/CircleSpinner.vue */ "./resources/js/components/CircleSpinner.vue");
+/* harmony import */ var _components_AssetInfo_vue__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../components/AssetInfo.vue */ "./resources/js/components/AssetInfo.vue");
+/* harmony import */ var _components_CircleSpinner_vue__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../components/CircleSpinner.vue */ "./resources/js/components/CircleSpinner.vue");
+//
 //
 //
 //
@@ -2641,33 +2781,50 @@ __webpack_require__.r(__webpack_exports__);
 //
 
 
+
 /* harmony default export */ __webpack_exports__["default"] = ({
   components: {
     WorkOrderInfo: _components_WorkOrderInfo_vue__WEBPACK_IMPORTED_MODULE_0__["default"],
-    CircleSpinner: _components_CircleSpinner_vue__WEBPACK_IMPORTED_MODULE_1__["default"]
+    AssetInfo: _components_AssetInfo_vue__WEBPACK_IMPORTED_MODULE_1__["default"],
+    CircleSpinner: _components_CircleSpinner_vue__WEBPACK_IMPORTED_MODULE_2__["default"]
   },
   props: ['id'],
   data: function data() {
     return {
       workOrder: {},
+      asset: {},
       stores: {},
       woLoading: true,
+      assetLoading: true,
       storesLoading: true
     };
   },
   mounted: function mounted() {
     var _this = this;
 
+    // Get authentication info from current user from local storage
     var token = localStorage.getItem('jwt');
-    var user = localStorage.getItem('user');
+    var user = localStorage.getItem('user'); // Set some axios config options for Content-Type and Authentication.
+
     axios.defaults.headers.common['Content-Type'] = 'application/json';
-    axios.defaults.headers.common['Authorization'] = 'Bearer ' + token;
+    axios.defaults.headers.common['Authorization'] = 'Bearer ' + token; // Get WorkOrder from API
+
     axios.get('/api/workorders/' + this.id).then(function (response) {
       _this.workOrder = response.data;
       _this.woLoading = false;
     })["catch"](function (error) {
       console.log(error);
-    });
+    }); // Get Asset from API (will most likely be replaced with list of assets
+    // in the future. Current each WO can only have one but that is likely
+    // to change)
+
+    axios.get("/api/workorders/".concat(this.id, "/asset")).then(function (response) {
+      _this.asset = response.data;
+      _this.assetLoading = false;
+    })["catch"](function (error) {
+      console.log(error);
+    }); // Get list of stores from API
+
     axios.get('/api/stores/').then(function (response) {
       _this.stores = response.data;
       _this.storesLoading = false;
@@ -10174,7 +10331,7 @@ exports = module.exports = __webpack_require__(/*! ../../../node_modules/css-loa
 
 
 // module
-exports.push([module.i, "\n.loader[data-v-9a543b64],\n.loader[data-v-9a543b64]:after {\n  border-radius: 50%;\n  width: 10em;\n  height: 10em;\n}\n.loader[data-v-9a543b64] {\n  margin: 60px auto;\n  font-size: 10px;\n  position: relative;\n  text-indent: -9999em;\n  border-top: 1.1em solid rgba(255, 255, 255, 0.2);\n  border-right: 1.1em solid rgba(255, 255, 255, 0.2);\n  border-bottom: 1.1em solid rgba(255, 255, 255, 0.2);\n  border-left: 1.1em solid #663399;\n  transform: translateZ(0);\n  -webkit-animation: load8-data-v-9a543b64 1.1s infinite linear;\n  animation: load8-data-v-9a543b64 1.1s infinite linear;\n}\n@-webkit-keyframes load8-data-v-9a543b64 {\n0% {\n    transform: rotate(0deg);\n}\n100% {\n    transform: rotate(360deg);\n}\n}\n@keyframes load8-data-v-9a543b64 {\n0% {\n    transform: rotate(0deg);\n}\n100% {\n    transform: rotate(360deg);\n}\n}\n", ""]);
+exports.push([module.i, "\n.loader[data-v-9a543b64],\n.loader[data-v-9a543b64]:after {\n  border-radius: 50%;\n  width: 10em;\n  height: 10em;\n}\n.loader[data-v-9a543b64] {\n  margin: 0px auto;\n  position: relative;\n  text-indent: -9999em;\n  border-top: 1.1em solid rgba(255, 255, 255, 0.2);\n  border-right: 1.1em solid rgba(255, 255, 255, 0.2);\n  border-bottom: 1.1em solid rgba(255, 255, 255, 0.2);\n  transform: translateZ(0);\n  -webkit-animation: load8-data-v-9a543b64 1.1s infinite linear;\n  animation: load8-data-v-9a543b64 1.1s infinite linear;\n}\n@-webkit-keyframes load8-data-v-9a543b64 {\n0% {\n    transform: rotate(0deg);\n}\n100% {\n    transform: rotate(360deg);\n}\n}\n@keyframes load8-data-v-9a543b64 {\n0% {\n    transform: rotate(0deg);\n}\n100% {\n    transform: rotate(360deg);\n}\n}\n", ""]);
 
 // exports
 
@@ -49574,6 +49731,360 @@ exports.clearImmediate = (typeof self !== "undefined" && self.clearImmediate) ||
 
 /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../webpack/buildin/global.js */ "./node_modules/webpack/buildin/global.js")))
 
+/***/ }),
+
+/***/ "./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/AssetInfo.vue?vue&type=template&id=f949323a&":
+/*!************************************************************************************************************************************************************************************************************!*\
+  !*** ./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/vue-loader/lib??vue-loader-options!./resources/js/components/AssetInfo.vue?vue&type=template&id=f949323a& ***!
+  \************************************************************************************************************************************************************************************************************/
+/*! exports provided: render, staticRenderFns */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "render", function() { return render; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "staticRenderFns", function() { return staticRenderFns; });
+var render = function() {
+  var _vm = this
+  var _h = _vm.$createElement
+  var _c = _vm._self._c || _h
+  return _c(
+    "div",
+    [
+      _c("asset-info-edit-modal", {
+        attrs: {
+          "modal-id": "asset" + _vm.asset.pcid + "editModal",
+          "populate-with": _vm.asset
+        }
+      }),
+      _vm._v(" "),
+      _c("h4", { staticClass: "text-center" }, [
+        _vm._v(
+          _vm._s(this.asset.pcmanu) + " " + _vm._s(this.asset.pcmake) + " - "
+        ),
+        _c("small", { staticClass: "text-muted" }, [
+          _vm._v(_vm._s(this.asset.pcnickname))
+        ])
+      ]),
+      _vm._v(" "),
+      _c("p", [_vm._v("OS: " + _vm._s(this.asset.pcextra[2]))]),
+      _vm._v(" "),
+      _c("p", [_vm._v("S/N: " + _vm._s(this.asset.pcextra[104]))]),
+      _vm._v(" "),
+      _c("p", [_vm._v("CPU: " + _vm._s(this.asset.pcextra[101]))]),
+      _vm._v(" "),
+      _c("p", [_vm._v("RAM: " + _vm._s(this.asset.pcextra[100]))]),
+      _vm._v(" "),
+      _c("p", [_vm._v("Graphics: " + _vm._s(this.asset.pcextra[4]))]),
+      _vm._v(" "),
+      _c(
+        "button",
+        {
+          staticClass: "btn btn-primary",
+          attrs: {
+            type: "button",
+            "data-toggle": "modal",
+            "data-target": "#asset" + _vm.asset.pcid + "editModal"
+          }
+        },
+        [_vm._v("Edit")]
+      )
+    ],
+    1
+  )
+}
+var staticRenderFns = []
+render._withStripped = true
+
+
+
+/***/ }),
+
+/***/ "./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/AssetInfoEditModal.vue?vue&type=template&id=24c98bd0&":
+/*!*********************************************************************************************************************************************************************************************************************!*\
+  !*** ./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/vue-loader/lib??vue-loader-options!./resources/js/components/AssetInfoEditModal.vue?vue&type=template&id=24c98bd0& ***!
+  \*********************************************************************************************************************************************************************************************************************/
+/*! exports provided: render, staticRenderFns */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "render", function() { return render; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "staticRenderFns", function() { return staticRenderFns; });
+var render = function() {
+  var _vm = this
+  var _h = _vm.$createElement
+  var _c = _vm._self._c || _h
+  return _c(
+    "modal",
+    {
+      attrs: {
+        id: _vm.modalId,
+        tabindex: "-1",
+        role: "dialog",
+        "aria-labelledby": _vm.modalId + "Label"
+      }
+    },
+    [
+      _c(
+        "h5",
+        {
+          staticClass: "modal-title",
+          attrs: { slot: "header", id: _vm.modalId + "Label" },
+          slot: "header"
+        },
+        [_vm._v("\n        Edit Work Order Information\n    ")]
+      ),
+      _vm._v(" "),
+      _c("div", { attrs: { slot: "body" }, slot: "body" }, [
+        _c("div", { staticClass: "form-group" }, [
+          _c("label", { attrs: { for: "manufacturer" } }, [
+            _vm._v("Manufacturer")
+          ]),
+          _vm._v(" "),
+          _c("input", {
+            directives: [
+              {
+                name: "model",
+                rawName: "v-model",
+                value: _vm.asset.pcmanu,
+                expression: "asset.pcmanu"
+              }
+            ],
+            staticClass: "form-control",
+            attrs: { type: "text", name: "manufacturer", id: "manufacturer" },
+            domProps: { value: _vm.asset.pcmanu },
+            on: {
+              input: function($event) {
+                if ($event.target.composing) {
+                  return
+                }
+                _vm.$set(_vm.asset, "pcmanu", $event.target.value)
+              }
+            }
+          })
+        ]),
+        _vm._v(" "),
+        _c("div", { staticClass: "form-group" }, [
+          _c("label", { attrs: { for: "make" } }, [_vm._v("Make")]),
+          _vm._v(" "),
+          _c("input", {
+            directives: [
+              {
+                name: "model",
+                rawName: "v-model",
+                value: _vm.asset.pcmake,
+                expression: "asset.pcmake"
+              }
+            ],
+            staticClass: "form-control",
+            attrs: { type: "text", name: "make", id: "make" },
+            domProps: { value: _vm.asset.pcmake },
+            on: {
+              input: function($event) {
+                if ($event.target.composing) {
+                  return
+                }
+                _vm.$set(_vm.asset, "pcmake", $event.target.value)
+              }
+            }
+          })
+        ]),
+        _vm._v(" "),
+        _c("div", { staticClass: "form-group" }, [
+          _c("label", { attrs: { for: "nickname" } }, [_vm._v("Nickname")]),
+          _vm._v(" "),
+          _c("input", {
+            directives: [
+              {
+                name: "model",
+                rawName: "v-model",
+                value: _vm.asset.pcnickname,
+                expression: "asset.pcnickname"
+              }
+            ],
+            staticClass: "form-control",
+            attrs: { type: "text", name: "nickname", id: "nickname" },
+            domProps: { value: _vm.asset.pcnickname },
+            on: {
+              input: function($event) {
+                if ($event.target.composing) {
+                  return
+                }
+                _vm.$set(_vm.asset, "pcnickname", $event.target.value)
+              }
+            }
+          })
+        ]),
+        _vm._v(" "),
+        _c("div", { staticClass: "form-group" }, [
+          _c("label", { attrs: { for: "os" } }, [_vm._v("OS")]),
+          _vm._v(" "),
+          _c("input", {
+            directives: [
+              {
+                name: "model",
+                rawName: "v-model",
+                value: _vm.asset.pcextra[2],
+                expression: "asset.pcextra[2]"
+              }
+            ],
+            staticClass: "form-control",
+            attrs: { type: "text", name: "os", id: "os" },
+            domProps: { value: _vm.asset.pcextra[2] },
+            on: {
+              input: function($event) {
+                if ($event.target.composing) {
+                  return
+                }
+                _vm.$set(_vm.asset.pcextra, 2, $event.target.value)
+              }
+            }
+          })
+        ]),
+        _vm._v(" "),
+        _c("div", { staticClass: "form-group" }, [
+          _c("label", { attrs: { for: "serial" } }, [_vm._v("Serial Number")]),
+          _vm._v(" "),
+          _c("input", {
+            directives: [
+              {
+                name: "model",
+                rawName: "v-model",
+                value: _vm.asset.pcextra[104],
+                expression: "asset.pcextra[104]"
+              }
+            ],
+            staticClass: "form-control",
+            attrs: { type: "text", id: "serial", name: "serial" },
+            domProps: { value: _vm.asset.pcextra[104] },
+            on: {
+              input: function($event) {
+                if ($event.target.composing) {
+                  return
+                }
+                _vm.$set(_vm.asset.pcextra, 104, $event.target.value)
+              }
+            }
+          })
+        ]),
+        _vm._v(" "),
+        _c("div", { staticClass: "form-group" }, [
+          _c("label", { attrs: { for: "cpu" } }, [_vm._v("CPU")]),
+          _vm._v(" "),
+          _c("input", {
+            directives: [
+              {
+                name: "model",
+                rawName: "v-model",
+                value: _vm.asset.pcextra[101],
+                expression: "asset.pcextra[101]"
+              }
+            ],
+            staticClass: "form-control",
+            attrs: { type: "text", id: "cpu", name: "cpu" },
+            domProps: { value: _vm.asset.pcextra[101] },
+            on: {
+              input: function($event) {
+                if ($event.target.composing) {
+                  return
+                }
+                _vm.$set(_vm.asset.pcextra, 101, $event.target.value)
+              }
+            }
+          })
+        ]),
+        _vm._v(" "),
+        _c("div", { staticClass: "form-group" }, [
+          _c("label", { attrs: { for: "ram" } }, [_vm._v("RAM")]),
+          _vm._v(" "),
+          _c("input", {
+            directives: [
+              {
+                name: "model",
+                rawName: "v-model",
+                value: _vm.asset.pcextra[100],
+                expression: "asset.pcextra[100]"
+              }
+            ],
+            staticClass: "form-control",
+            attrs: { type: "text", name: "ram", id: "ram" },
+            domProps: { value: _vm.asset.pcextra[100] },
+            on: {
+              input: function($event) {
+                if ($event.target.composing) {
+                  return
+                }
+                _vm.$set(_vm.asset.pcextra, 100, $event.target.value)
+              }
+            }
+          })
+        ]),
+        _vm._v(" "),
+        _c("div", { staticClass: "form-group" }, [
+          _c("label", { attrs: { for: "graphics" } }, [_vm._v("Graphics")]),
+          _vm._v(" "),
+          _c("input", {
+            directives: [
+              {
+                name: "model",
+                rawName: "v-model",
+                value: _vm.asset.pcextra[4],
+                expression: "asset.pcextra[4]"
+              }
+            ],
+            staticClass: "form-control",
+            attrs: { type: "text", name: "graphics", id: "grapics" },
+            domProps: { value: _vm.asset.pcextra[4] },
+            on: {
+              input: function($event) {
+                if ($event.target.composing) {
+                  return
+                }
+                _vm.$set(_vm.asset.pcextra, 4, $event.target.value)
+              }
+            }
+          })
+        ])
+      ]),
+      _vm._v(" "),
+      _c("div", { attrs: { slot: "footer" }, slot: "footer" }, [
+        _c(
+          "button",
+          {
+            staticClass: "btn btn-secondary",
+            attrs: { type: "button", "data-dismiss": "modal" }
+          },
+          [_vm._v("Close")]
+        ),
+        _vm._v(" "),
+        _c(
+          "button",
+          {
+            staticClass: "btn btn-primary",
+            attrs: { type: "button" },
+            on: {
+              click: function($event) {
+                return _vm.updateAsset()
+              }
+            }
+          },
+          [
+            !_vm.assetSaving
+              ? _c("div", [_vm._v("Save")])
+              : _c("circle-spinner", { attrs: { size: 2 } })
+          ],
+          1
+        )
+      ])
+    ]
+  )
+}
+var staticRenderFns = []
+render._withStripped = true
+
+
+
 /***/ }),
 
 /***/ "./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/AutocompleteCustomDropdown.vue?vue&type=template&id=5fcc8b56&":
@@ -49687,7 +50198,17 @@ var render = function() {
   var _vm = this
   var _h = _vm.$createElement
   var _c = _vm._self._c || _h
-  return _c("div", { staticClass: "loader" }, [_vm._v("Loading...")])
+  return _c(
+    "div",
+    {
+      staticClass: "loader",
+      style: {
+        fontSize: _vm.size + "px",
+        borderLeft: "1.1em solid " + _vm.color
+      }
+    },
+    [_vm._v("Loading...")]
+  )
 }
 var staticRenderFns = []
 render._withStripped = true
@@ -50509,7 +51030,33 @@ var render = function() {
   var _c = _vm._self._c || _h
   return _c("div", { staticClass: "container-fluid" }, [
     _c("div", { staticClass: "row my-3" }, [
-      _vm._m(0),
+      _c("div", { staticClass: "col-lg-6" }, [
+        _c("div", { staticClass: "card h-100" }, [
+          _vm._m(0),
+          _vm._v(" "),
+          _c("div", { staticClass: "card-body" }, [
+            _c("div", { staticClass: "tab-content" }, [
+              _c(
+                "div",
+                {
+                  staticClass: "tab-pane active",
+                  attrs: {
+                    id: "assetinfo",
+                    role: "tabpanel",
+                    "aria-labelledby": "assetinfo-tab"
+                  }
+                },
+                [
+                  !_vm.assetLoading
+                    ? _c("asset-info", { attrs: { asset: _vm.asset } })
+                    : _c("circle-spinner", { attrs: { color: "#663399" } })
+                ],
+                1
+              )
+            ])
+          ])
+        ])
+      ]),
       _vm._v(" "),
       _c("div", { staticClass: "col-lg-6" }, [
         _c("div", { staticClass: "card h-100" }, [
@@ -50568,92 +51115,73 @@ var staticRenderFns = [
     var _vm = this
     var _h = _vm.$createElement
     var _c = _vm._self._c || _h
-    return _c("div", { staticClass: "col-lg-6" }, [
-      _c("div", { staticClass: "card h-100" }, [
-        _c("div", { staticClass: "card-header text-right" }, [
-          _c(
-            "button",
-            {
-              staticClass: "btn btn-default xs-toggle",
-              attrs: {
-                type: "button",
-                "data-toggle": "collapse",
-                "data-target": "#assetTab"
-              }
-            },
-            [
-              _c("span", { staticClass: "sr-only" }, [
-                _vm._v("Toggle Navigation")
-              ]),
-              _vm._v(" "),
-              _c("span", { staticClass: "icon-bar" }),
-              _vm._v(" "),
-              _c("span", { staticClass: "icon-bar" }),
-              _vm._v(" "),
-              _c("span", { staticClass: "icon-bar" })
-            ]
-          ),
+    return _c("div", { staticClass: "card-header text-right" }, [
+      _c(
+        "button",
+        {
+          staticClass: "btn btn-default xs-toggle",
+          attrs: {
+            type: "button",
+            "data-toggle": "collapse",
+            "data-target": "#assetTab"
+          }
+        },
+        [
+          _c("span", { staticClass: "sr-only" }, [_vm._v("Toggle Navigation")]),
           _vm._v(" "),
-          _c(
-            "ul",
-            {
-              staticClass:
-                "nav nav-pills card-header-pills nav-justified xs-collapse collapse",
-              attrs: { id: "assetTab", role: "tablist" }
-            },
-            [
-              _c("li", { staticClass: "nav-item" }, [
-                _c(
-                  "a",
-                  {
-                    staticClass: "nav-link active",
-                    attrs: {
-                      id: "assetinfo-tab",
-                      "data-toggle": "pill",
-                      href: "#assetinfo",
-                      role: "tab",
-                      "aria-controls": "assetinfo",
-                      "aria-selected": "true"
-                    }
-                  },
-                  [_vm._v("Hardware")]
-                )
-              ]),
-              _vm._v(" "),
-              _c("li", { staticClass: "nav-item" }, [
-                _c(
-                  "a",
-                  {
-                    staticClass: "nav-link",
-                    attrs: {
-                      id: "credentials-tab",
-                      "data-toggle": "pill",
-                      href: "#credentials",
-                      role: "tab",
-                      "aria-controls": "credentials",
-                      "aria-selected": "false"
-                    }
-                  },
-                  [_vm._v("Credentials")]
-                )
-              ])
-            ]
-          )
-        ]),
-        _vm._v(" "),
-        _c("div", { staticClass: "card-body" }, [
-          _c("div", { staticClass: "tab-content" }, [
-            _c("div", {
-              staticClass: "tab-pane active",
-              attrs: {
-                id: "assetinfo",
-                role: "tabpanel",
-                "aria-labelledby": "assetinfo-tab"
-              }
-            })
+          _c("span", { staticClass: "icon-bar" }),
+          _vm._v(" "),
+          _c("span", { staticClass: "icon-bar" }),
+          _vm._v(" "),
+          _c("span", { staticClass: "icon-bar" })
+        ]
+      ),
+      _vm._v(" "),
+      _c(
+        "ul",
+        {
+          staticClass:
+            "nav nav-pills card-header-pills nav-justified xs-collapse collapse",
+          attrs: { id: "assetTab", role: "tablist" }
+        },
+        [
+          _c("li", { staticClass: "nav-item" }, [
+            _c(
+              "a",
+              {
+                staticClass: "nav-link active",
+                attrs: {
+                  id: "assetinfo-tab",
+                  "data-toggle": "pill",
+                  href: "#assetinfo",
+                  role: "tab",
+                  "aria-controls": "assetinfo",
+                  "aria-selected": "true"
+                }
+              },
+              [_vm._v("Hardware")]
+            )
+          ]),
+          _vm._v(" "),
+          _c("li", { staticClass: "nav-item" }, [
+            _c(
+              "a",
+              {
+                staticClass: "nav-link",
+                attrs: {
+                  id: "credentials-tab",
+                  "data-toggle": "pill",
+                  href: "#credentials",
+                  role: "tab",
+                  "aria-controls": "credentials",
+                  "aria-selected": "false"
+                }
+              },
+              [_vm._v("Credentials")]
+            )
           ])
-        ])
-      ])
+        ]
+      )
     ])
   },
   function() {
@@ -65951,6 +66479,144 @@ window.Echo = new laravel_echo__WEBPACK_IMPORTED_MODULE_0__["default"]({
   disableStats: true
 });
 
+/***/ }),
+
+/***/ "./resources/js/components/AssetInfo.vue":
+/*!***********************************************!*\
+  !*** ./resources/js/components/AssetInfo.vue ***!
+  \***********************************************/
+/*! exports provided: default */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony import */ var _AssetInfo_vue_vue_type_template_id_f949323a___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./AssetInfo.vue?vue&type=template&id=f949323a& */ "./resources/js/components/AssetInfo.vue?vue&type=template&id=f949323a&");
+/* harmony import */ var _AssetInfo_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./AssetInfo.vue?vue&type=script&lang=js& */ "./resources/js/components/AssetInfo.vue?vue&type=script&lang=js&");
+/* empty/unused harmony star reexport *//* harmony import */ var _node_modules_vue_loader_lib_runtime_componentNormalizer_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../../node_modules/vue-loader/lib/runtime/componentNormalizer.js */ "./node_modules/vue-loader/lib/runtime/componentNormalizer.js");
+
+
+
+
+
+/* normalize component */
+
+var component = Object(_node_modules_vue_loader_lib_runtime_componentNormalizer_js__WEBPACK_IMPORTED_MODULE_2__["default"])(
+  _AssetInfo_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__["default"],
+  _AssetInfo_vue_vue_type_template_id_f949323a___WEBPACK_IMPORTED_MODULE_0__["render"],
+  _AssetInfo_vue_vue_type_template_id_f949323a___WEBPACK_IMPORTED_MODULE_0__["staticRenderFns"],
+  false,
+  null,
+  null,
+  null
+  
+)
+
+/* hot reload */
+if (false) { var api; }
+component.options.__file = "resources/js/components/AssetInfo.vue"
+/* harmony default export */ __webpack_exports__["default"] = (component.exports);
+
+/***/ }),
+
+/***/ "./resources/js/components/AssetInfo.vue?vue&type=script&lang=js&":
+/*!************************************************************************!*\
+  !*** ./resources/js/components/AssetInfo.vue?vue&type=script&lang=js& ***!
+  \************************************************************************/
+/*! exports provided: default */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony import */ var _node_modules_babel_loader_lib_index_js_ref_4_0_node_modules_vue_loader_lib_index_js_vue_loader_options_AssetInfo_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../../node_modules/babel-loader/lib??ref--4-0!../../../node_modules/vue-loader/lib??vue-loader-options!./AssetInfo.vue?vue&type=script&lang=js& */ "./node_modules/babel-loader/lib/index.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/AssetInfo.vue?vue&type=script&lang=js&");
+/* empty/unused harmony star reexport */ /* harmony default export */ __webpack_exports__["default"] = (_node_modules_babel_loader_lib_index_js_ref_4_0_node_modules_vue_loader_lib_index_js_vue_loader_options_AssetInfo_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_0__["default"]); 
+
+/***/ }),
+
+/***/ "./resources/js/components/AssetInfo.vue?vue&type=template&id=f949323a&":
+/*!******************************************************************************!*\
+  !*** ./resources/js/components/AssetInfo.vue?vue&type=template&id=f949323a& ***!
+  \******************************************************************************/
+/*! exports provided: render, staticRenderFns */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony import */ var _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_AssetInfo_vue_vue_type_template_id_f949323a___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../../node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!../../../node_modules/vue-loader/lib??vue-loader-options!./AssetInfo.vue?vue&type=template&id=f949323a& */ "./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/AssetInfo.vue?vue&type=template&id=f949323a&");
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "render", function() { return _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_AssetInfo_vue_vue_type_template_id_f949323a___WEBPACK_IMPORTED_MODULE_0__["render"]; });
+
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "staticRenderFns", function() { return _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_AssetInfo_vue_vue_type_template_id_f949323a___WEBPACK_IMPORTED_MODULE_0__["staticRenderFns"]; });
+
+
+
+/***/ }),
+
+/***/ "./resources/js/components/AssetInfoEditModal.vue":
+/*!********************************************************!*\
+  !*** ./resources/js/components/AssetInfoEditModal.vue ***!
+  \********************************************************/
+/*! exports provided: default */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony import */ var _AssetInfoEditModal_vue_vue_type_template_id_24c98bd0___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./AssetInfoEditModal.vue?vue&type=template&id=24c98bd0& */ "./resources/js/components/AssetInfoEditModal.vue?vue&type=template&id=24c98bd0&");
+/* harmony import */ var _AssetInfoEditModal_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./AssetInfoEditModal.vue?vue&type=script&lang=js& */ "./resources/js/components/AssetInfoEditModal.vue?vue&type=script&lang=js&");
+/* empty/unused harmony star reexport *//* harmony import */ var _node_modules_vue_loader_lib_runtime_componentNormalizer_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../../node_modules/vue-loader/lib/runtime/componentNormalizer.js */ "./node_modules/vue-loader/lib/runtime/componentNormalizer.js");
+
+
+
+
+
+/* normalize component */
+
+var component = Object(_node_modules_vue_loader_lib_runtime_componentNormalizer_js__WEBPACK_IMPORTED_MODULE_2__["default"])(
+  _AssetInfoEditModal_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__["default"],
+  _AssetInfoEditModal_vue_vue_type_template_id_24c98bd0___WEBPACK_IMPORTED_MODULE_0__["render"],
+  _AssetInfoEditModal_vue_vue_type_template_id_24c98bd0___WEBPACK_IMPORTED_MODULE_0__["staticRenderFns"],
+  false,
+  null,
+  null,
+  null
+  
+)
+
+/* hot reload */
+if (false) { var api; }
+component.options.__file = "resources/js/components/AssetInfoEditModal.vue"
+/* harmony default export */ __webpack_exports__["default"] = (component.exports);
+
+/***/ }),
+
+/***/ "./resources/js/components/AssetInfoEditModal.vue?vue&type=script&lang=js&":
+/*!*********************************************************************************!*\
+  !*** ./resources/js/components/AssetInfoEditModal.vue?vue&type=script&lang=js& ***!
+  \*********************************************************************************/
+/*! exports provided: default */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony import */ var _node_modules_babel_loader_lib_index_js_ref_4_0_node_modules_vue_loader_lib_index_js_vue_loader_options_AssetInfoEditModal_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../../node_modules/babel-loader/lib??ref--4-0!../../../node_modules/vue-loader/lib??vue-loader-options!./AssetInfoEditModal.vue?vue&type=script&lang=js& */ "./node_modules/babel-loader/lib/index.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/AssetInfoEditModal.vue?vue&type=script&lang=js&");
+/* empty/unused harmony star reexport */ /* harmony default export */ __webpack_exports__["default"] = (_node_modules_babel_loader_lib_index_js_ref_4_0_node_modules_vue_loader_lib_index_js_vue_loader_options_AssetInfoEditModal_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_0__["default"]); 
+
+/***/ }),
+
+/***/ "./resources/js/components/AssetInfoEditModal.vue?vue&type=template&id=24c98bd0&":
+/*!***************************************************************************************!*\
+  !*** ./resources/js/components/AssetInfoEditModal.vue?vue&type=template&id=24c98bd0& ***!
+  \***************************************************************************************/
+/*! exports provided: render, staticRenderFns */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony import */ var _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_AssetInfoEditModal_vue_vue_type_template_id_24c98bd0___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../../node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!../../../node_modules/vue-loader/lib??vue-loader-options!./AssetInfoEditModal.vue?vue&type=template&id=24c98bd0& */ "./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/AssetInfoEditModal.vue?vue&type=template&id=24c98bd0&");
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "render", function() { return _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_AssetInfoEditModal_vue_vue_type_template_id_24c98bd0___WEBPACK_IMPORTED_MODULE_0__["render"]; });
+
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "staticRenderFns", function() { return _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_AssetInfoEditModal_vue_vue_type_template_id_24c98bd0___WEBPACK_IMPORTED_MODULE_0__["staticRenderFns"]; });
+
+
+
 /***/ }),
 
 /***/ "./resources/js/components/AutocompleteCustomDropdown.vue":

+ 82 - 0
resources/js/components/AssetInfoEditModal.vue

@@ -0,0 +1,82 @@
+<template>
+    <modal :id="modalId" tabindex="-1" role="dialog" :aria-labelledby="`${modalId}Label`">
+        <h5 slot="header" class="modal-title" :id="`${modalId}Label`">
+            Edit Work Order Information
+        </h5>
+        <div slot="body">
+            <div class="form-group">
+                <label for="manufacturer">Manufacturer</label>
+                <input type="text" name="manufacturer" id="manufacturer" class="form-control" v-model="asset.pcmanu">
+            </div>
+            <div class="form-group">
+                <label for="make">Make</label>
+                <input type="text" name="make" id="make" class="form-control" v-model="asset.pcmake">
+            </div>
+            <div class="form-group">
+                <label for="nickname">Nickname</label>
+                <input type="text" name="nickname" id="nickname" class="form-control" v-model="asset.pcnickname">
+            </div>
+            <div class="form-group">
+                <label for="os">OS</label>
+                <input type="text" name="os" id="os" class="form-control" v-model="asset.pcextra[2]">
+            </div>
+            <div class="form-group">
+                <label for="serial">Serial Number</label>
+                <input type="text" id="serial" name="serial" class="form-control" v-model="asset.pcextra[104]">
+            </div>
+            <div class="form-group">
+                <label for="cpu">CPU</label>
+                <input type="text" id="cpu" name="cpu" class="form-control" v-model="asset.pcextra[101]">
+            </div>
+            <div class="form-group">
+                <label for="ram">RAM</label>
+                <input type="text" name="ram" id="ram" class="form-control" v-model="asset.pcextra[100]">
+            </div>
+            <div class="form-group">
+                <label for="graphics">Graphics</label>
+                <input type="text" name="graphics" id="grapics" class="form-control" v-model="asset.pcextra[4]">
+            </div>
+        </div>
+
+        <div slot="footer">
+            <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
+            <button type="button" class="btn btn-primary" @click="updateAsset()">
+                <div v-if="!assetSaving">Save</div>
+                <circle-spinner v-else :size="2"></circle-spinner>
+            </button>
+        </div>
+    </modal>
+</template>
+<script>
+import Modal from '../components/Modal.vue'
+import CircleSpinner from '../components/CircleSpinner.vue'
+export default {
+    components: {
+        Modal,
+        CircleSpinner,
+    },
+    props: ['populateWith', 'modalId'],
+    data () {
+        return {
+            // Essentially makes a copy of the object. Otherwise
+            // We would have a reference to the exising object causing
+            // unwanted mutations in the parent component.
+            asset: JSON.parse(JSON.stringify(this.populateWith)),
+            assetSaving: false,
+        }
+    },
+    methods: {
+        updateAsset() {
+            this.assetSaving = true
+            axios.put(`/api/assets/${this.asset.pcid}`, this.asset)
+                    .then((response) => {
+                        this.assetSaving = false
+                        $(`#${this.modalId}`).modal('hide');
+                    })
+                    .catch((error) => {
+                        this.assetSaving = false
+                    });
+        }
+    }
+}
+</script>

+ 6 - 4
resources/js/components/CircleSpinner.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="loader">Loading...</div>
+  <div class="loader" :style="{fontSize: size + 'px', borderLeft: '1.1em solid ' + color}">Loading...</div>
 </template>
 
 <script>
@@ -10,6 +10,10 @@
       color: {
         type: String,
         default: '#fff'
+      },
+      size: {
+        type: String,
+        default: '10'
       }
     },
   }
@@ -23,14 +27,12 @@
   height: 10em;
 }
 .loader {
-  margin: 60px auto;
-  font-size: 10px;
+  margin: 0px auto;
   position: relative;
   text-indent: -9999em;
   border-top: 1.1em solid rgba(255, 255, 255, 0.2);
   border-right: 1.1em solid rgba(255, 255, 255, 0.2);
   border-bottom: 1.1em solid rgba(255, 255, 255, 0.2);
-  border-left: 1.1em solid #663399;
   -webkit-transform: translateZ(0);
   -ms-transform: translateZ(0);
   transform: translateZ(0);

+ 14 - 69
resources/js/components/assetinfo.vue

@@ -1,83 +1,28 @@
 <template>
     <div>
-        <modal id="asseteditModal" tabindex="-1" role="dialog" aria-labelledby="asseteditModalLabel">
-            <h5 slot="header" class="modal-title" id="asseteditModalLabel">
-                Edit Work Order Information
-            </h5>
-            <div slot="body">
-                <div class="form-group">
-                    <label for="manufacturer">Manufacturer</label>
-                    <input type="text" name="manufacturer" id="manufacturer" class="form-control" v-model.lazy="data.pcmanu">
-                </div>
-                <div class="form-group">
-                    <label for="make">Make</label>
-                    <input type="text" name="make" id="make" class="form-control" v-model.lazy="data.pcmake">
-                </div>
-                <div class="form-group">
-                    <label for="nickname">Nickname</label>
-                    <input type="text" name="nickname" id="nickname" class="form-control" v-model.lazy="data.pcnickname">
-                </div>
-                <div class="form-group">
-                    <label for="os">OS</label>
-                    <input type="text" name="os" id="os" class="form-control" v-model.lazy="pcextra[2]">
-                </div>
-                <div class="form-group">
-                    <label for="serial">Serial Number</label>
-                    <input type="text" id="serial" name="serial" class="form-control" v-model.lazy="pcextra[104]">
-                </div>
-                <div class="form-group">
-                    <label for="cpu">CPU</label>
-                    <input type="text" id="cpu" name="cpu" class="form-control" v-model.lazy="pcextra[101]">
-                </div>
-                <div class="form-group">
-                    <label for="ram">RAM</label>
-                    <input type="text" name="ram" id="ram" class="form-control" v-model.lazy="pcextra[100]">
-                </div>
-                <div class="form-group">
-                    <label for="graphics">Graphics</label>
-                    <input type="text" name="graphics" id="grapics" class="form-control" v-model.lazy="pcextra[4]">
-                </div>
-            </div>
+        <asset-info-edit-modal :modal-id="`asset${asset.pcid}editModal`" :populate-with="asset"></asset-info-edit-modal>
+        <h4 class="text-center">{{ this.asset.pcmanu }} {{ this.asset.pcmake }} - <small class="text-muted">{{this.asset.pcnickname}}</small></h4>
+        <p>OS: {{this.asset.pcextra[2]}}</p>
+        <p>S/N: {{ this.asset.pcextra[104] }}</p>
+        <p>CPU: {{ this.asset.pcextra[101]}}</p>
+        <p>RAM: {{ this.asset.pcextra[100] }}</p>
+        <p>Graphics: {{this.asset.pcextra[4]}}</p>
 
-            <div slot="footer">
-                <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
-                <button type="button" class="btn btn-primary" @click="updateAsset()">Save</button>
-            </div>
-        </modal>
-        <h4 class="text-center">{{ this.data.pcmanu }} {{ this.data.pcmake }} - <small class="text-muted">{{this.data.pcnickname}}</small></h4>
-        <p>OS: {{this.pcextra[2]}}</p>
-        <p>S/N: {{ this.pcextra[104] }}</p>
-        <p>CPU: {{ this.pcextra[101]}}</p>
-        <p>RAM: {{ this.pcextra[100] }}</p>
-        <p>Graphics: {{this.pcextra[4]}}</p>
-
-        <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#asseteditModal">Edit</button>
+        <button type="button" class="btn btn-primary" data-toggle="modal" :data-target="`#asset${asset.pcid}editModal`">Edit</button>
     </div>
 </template>
 <script>
+import AssetInfoEditModal from '../components/AssetInfoEditModal.vue'
 export default {
-    props: ['asset', 'pcextraStart'],
-    data() {
-        return {
-            data: JSON.parse(this.asset),
-            pcextra: JSON.parse(this.pcextraStart),
-        }
+    components: {
+        AssetInfoEditModal,
     },
+    props: ['asset'],
     mounted() {
-        Echo.channel('asset.'+this.data.pcid)
+        Echo.channel('asset.'+this.asset.pcid)
                 .listen('AssetUpdated', (e) => {
-                this.data = e.data;
-                this.pcextra = JSON.parse(e.pcextra);
+                this.asset = e.data;
             });
     },
-    methods: {
-        updateAsset() {
-            this.data.pcextra = this.pcextra;
-            axios.put('/api/assets/' + this.data.pcid, this.data)
-                    .then((response) => {})
-                    .catch((error) => {});
-                $('#asseteditModal').modal('hide');
-        }
-    }
 }
 </script>

+ 20 - 1
resources/js/views/WorkOrder.vue

@@ -27,7 +27,8 @@
                     <div class="card-body">
                         <div class="tab-content">
                             <div class="tab-pane active" id="assetinfo" role="tabpanel" aria-labelledby="assetinfo-tab">
-                                <!-- <assetinfo asset="{{$asset}}"></assetinfo> -->
+                                <asset-info v-if="!assetLoading" :asset="asset"></asset-info>
+                                <circle-spinner v-else :color="'#663399'"></circle-spinner>
                             </div>
                             <!-- @if($workOrder->asset->group !== null)
                             <div class="tab-pane" id="group" role="tabpanel" aria-labelledby="group-tab">
@@ -97,28 +98,35 @@
 </template>
 <script>
 import WorkOrderInfo from '../components/WorkOrderInfo.vue'
+import AssetInfo from '../components/AssetInfo.vue'
 import CircleSpinner from '../components/CircleSpinner.vue'
 export default {
     components: {
         WorkOrderInfo,
+        AssetInfo,
         CircleSpinner,
     },
     props: ['id'],
     data () {
         return {
             workOrder: {},
+            asset: {},
             stores: {},
             woLoading: true,
+            assetLoading: true,
             storesLoading: true,
         }
     },
     mounted () {
+        // Get authentication info from current user from local storage
         let token = localStorage.getItem('jwt')
         let user = localStorage.getItem('user')
 
+        // Set some axios config options for Content-Type and Authentication.
         axios.defaults.headers.common['Content-Type'] = 'application/json'
         axios.defaults.headers.common['Authorization'] = 'Bearer ' + token
 
+        // Get WorkOrder from API
         axios.get('/api/workorders/'+this.id).then(response => {
             this.workOrder = response.data
             this.woLoading = false
@@ -126,6 +134,17 @@ export default {
             console.log(error)
         })
 
+        // Get Asset from API (will most likely be replaced with list of assets
+        // in the future. Current each WO can only have one but that is likely
+        // to change)
+        axios.get(`/api/workorders/${this.id}/asset`).then(response => {
+            this.asset = response.data
+            this.assetLoading = false
+        }).catch(error => {
+            console.log(error)
+        })
+
+        // Get list of stores from API
         axios.get('/api/stores/').then(response => {
             this.stores = response.data
             this.storesLoading = false

+ 1 - 1
routes/api.php

@@ -23,7 +23,7 @@ Route::middleware('auth:api')->get('/user', function (Request $request) {
 Route::middleware('auth:api')->group( function() {
     Route::get('/users/{user}/workorders', 'Api\UsersController@workOrders');
 
-    Route::get('/workorders/{workOrder}/assets');
+    Route::get('/workorders/{workOrder}/asset', 'Api\WorkOrdersController@asset');
     Route::get('/workorders/{workOrder}', 'Api\WorkOrdersController@show');
     Route::put('/workorders/{workOrder}', 'Api\WorkOrdersController@update');