Ver código fonte

Adapts credentials for SPA.

Christopher Leggett 5 anos atrás
pai
commit
b49bfa2ccb

+ 5 - 0
app/Http/Controllers/Api/AssetsController.php

@@ -40,6 +40,11 @@ class AssetsController extends Controller
         //
     }
 
+    public function credentials(Asset $asset) {
+        $credentials = $asset->credentials->sortByDesc('creddate')->values();
+        return response()->json($credentials, 200);
+    }
+
     /**
      * Update the specified resource in storage.
      *

+ 1032 - 9
public/js/app.js

@@ -2200,6 +2200,332 @@ __webpack_require__.r(__webpack_exports__);
 
 /***/ }),
 
+/***/ "./node_modules/babel-loader/lib/index.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/Credential.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/Credential.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_CredentialFormModal_vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../components/CredentialFormModal.vue */ "./resources/js/components/CredentialFormModal.vue");
+/* harmony import */ var _components_Modal_vue__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../components/Modal.vue */ "./resources/js/components/Modal.vue");
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+
+
+/* harmony default export */ __webpack_exports__["default"] = ({
+  components: {
+    CredentialFormModal: _components_CredentialFormModal_vue__WEBPACK_IMPORTED_MODULE_0__["default"],
+    Modal: _components_Modal_vue__WEBPACK_IMPORTED_MODULE_1__["default"]
+  },
+  props: ['credential', 'descriptions'],
+  data: function data() {
+    return {
+      data: this.credential,
+      creddescList: this.descriptions
+    };
+  },
+  mounted: function mounted() {
+    var _this = this;
+
+    Echo.channel('credential.' + this.data.credid).listen('CredentialUpdated', function (e) {
+      _this.data = e.credential;
+    });
+  },
+  methods: {
+    deleteCredential: function deleteCredential() {
+      var _this2 = this;
+
+      axios["delete"]('/api/credentials/' + this.data.credid, this.data).then(function (response) {
+        $('#credential' + _this2.data.credid + 'deleteModal').modal('hide');
+      })["catch"](function (error) {
+        console.error(error);
+      });
+    }
+  }
+});
+
+/***/ }),
+
+/***/ "./node_modules/babel-loader/lib/index.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/CredentialFormModal.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/CredentialFormModal.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_AutocompleteCustomDropdown_vue__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../components/AutocompleteCustomDropdown.vue */ "./resources/js/components/AutocompleteCustomDropdown.vue");
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+
+
+/* harmony default export */ __webpack_exports__["default"] = ({
+  components: {
+    AutocompleteCustomDropdown: _components_AutocompleteCustomDropdown_vue__WEBPACK_IMPORTED_MODULE_1__["default"],
+    Modal: _components_Modal_vue__WEBPACK_IMPORTED_MODULE_0__["default"]
+  },
+  props: {
+    populateWith: {
+      type: Object,
+      "default": function _default() {
+        return {
+          creddesc: null,
+          creduser: null,
+          credpass: null,
+          groupid: null,
+          pcid: null,
+          credtype: null
+        };
+      }
+    },
+    modalId: {
+      type: String,
+      required: true
+    },
+    descriptions: {
+      type: Object,
+      required: true
+    },
+    create: {
+      type: Boolean
+    },
+    pcid: {
+      type: Number
+    },
+    groupid: {
+      type: Number
+    }
+  },
+  data: function data() {
+    return {
+      data: JSON.parse(JSON.stringify(this.populateWith)),
+      creddesc: {},
+      id: this.modalId,
+      errors: []
+    };
+  },
+  mounted: function mounted() {
+    this.creddesc = {
+      'id': this.data.credtype,
+      'name': this.data.creddesc
+    };
+  },
+  methods: {
+    rndStr: function rndStr(len) {
+      var text = "";
+      var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%";
+
+      for (var i = 0; i < len; i++) {
+        text += chars.charAt(Math.floor(Math.random() * chars.length));
+      }
+
+      return text;
+    },
+    getRandomPassword: function getRandomPassword(id) {
+      this.data.credpass = this.rndStr(16);
+    },
+    updateCredential: function updateCredential() {
+      var _this = this;
+
+      if (this.creddesc.id === "custom") {
+        this.data.credtype = 1;
+        this.data.creddesc = this.creddesc.name;
+      } else {
+        this.data.credtype = this.creddesc.id;
+        this.data.creddesc = this.creddesc.name;
+      }
+
+      if (this.create) {
+        if (this.pcid) {
+          this.data.pcid = this.pcid;
+        }
+
+        if (this.groupid) {
+          this.data.groupid = this.groupid;
+        }
+
+        axios.post('/api/credentials/', this.data).then(function (response) {
+          $('#' + _this.id).modal('hide');
+        });
+      } else {
+        axios.put('/api/credentials/' + this.data.credid, this.data).then(function (response) {
+          $('#' + _this.id).modal('hide');
+        })["catch"](function (error) {
+          console.error(error);
+        });
+      }
+    }
+  }
+});
+
+/***/ }),
+
+/***/ "./node_modules/babel-loader/lib/index.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/CredentialList.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/CredentialList.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_Credential_vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../components/Credential.vue */ "./resources/js/components/Credential.vue");
+/* harmony import */ var _components_CredentialFormModal_vue__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../components/CredentialFormModal.vue */ "./resources/js/components/CredentialFormModal.vue");
+//
+//
+//
+//
+//
+//
+//
+//
+//
+
+
+/* harmony default export */ __webpack_exports__["default"] = ({
+  components: {
+    Credential: _components_Credential_vue__WEBPACK_IMPORTED_MODULE_0__["default"],
+    CredentialFormModal: _components_CredentialFormModal_vue__WEBPACK_IMPORTED_MODULE_1__["default"]
+  },
+  props: {
+    credentials: {
+      type: Array,
+      required: true
+    },
+    descriptions: {
+      type: Array,
+      required: true
+    },
+    pcid: {
+      type: Number
+    },
+    groupid: {
+      type: Number
+    }
+  },
+  computed: {
+    creddescList: function creddescList() {
+      var list = {};
+      this.descriptions.map(function (val) {
+        list[val.creddescid] = val.credtitle;
+      });
+      return list;
+    }
+  },
+  methods: {
+    deleteCred: function deleteCred(index) {
+      this.credentials.splice(index, 1);
+    }
+  },
+  mounted: function mounted() {
+    var _this = this;
+
+    if (this.pcid) {
+      Echo.channel('credlist.pcid.' + this.pcid).listen('CredentialDeleted', function (e) {
+        var deletedCred = e.credential;
+
+        var index = _this.credentials.findIndex(function (credential) {
+          return credential.credid === deletedCred['credid'];
+        });
+
+        $('#credential' + deletedCred['credid'] + 'deleteModal').modal('hide');
+
+        _this.deleteCred(index);
+      }).listen('CredentialAdded', function (e) {
+        _this.credentials.unshift(e.credential);
+      });
+    }
+
+    if (this.groupid) {
+      Echo.channel('credlist.groupid.' + this.groupid).listen('CredentialDeleted', function (e) {
+        var deletedCred = e.credential;
+
+        var index = _this.credentials.findIndex(function (credential) {
+          return credential.groupid === deletedCred['groupid'];
+        });
+
+        $('#credential' + deletedCred['credid'] + 'deleteModal').modal('hide');
+
+        _this.deleteCred(index);
+      }).listen('CredentialAdded', function (e) {
+        _this.credentials.unshift(e.credential);
+      });
+    }
+  }
+});
+
+/***/ }),
+
 /***/ "./node_modules/babel-loader/lib/index.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/WoInfoEditModal.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/WoInfoEditModal.vue?vue&type=script&lang=js& ***!
@@ -2691,6 +3017,8 @@ __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_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");
+/* harmony import */ var _components_CredentialList_vue__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../components/CredentialList.vue */ "./resources/js/components/CredentialList.vue");
+//
 //
 //
 //
@@ -2792,11 +3120,13 @@ __webpack_require__.r(__webpack_exports__);
 
 
 
+
 /* harmony default export */ __webpack_exports__["default"] = ({
   components: {
     WorkOrderInfo: _components_WorkOrderInfo_vue__WEBPACK_IMPORTED_MODULE_0__["default"],
     AssetInfo: _components_AssetInfo_vue__WEBPACK_IMPORTED_MODULE_1__["default"],
-    CircleSpinner: _components_CircleSpinner_vue__WEBPACK_IMPORTED_MODULE_2__["default"]
+    CircleSpinner: _components_CircleSpinner_vue__WEBPACK_IMPORTED_MODULE_2__["default"],
+    CredentialList: _components_CredentialList_vue__WEBPACK_IMPORTED_MODULE_3__["default"]
   },
   props: ['id'],
   data: function data() {
@@ -2804,9 +3134,13 @@ __webpack_require__.r(__webpack_exports__);
       workOrder: {},
       asset: {},
       stores: {},
+      credentials: {},
+      credentialDescriptions: {},
       woLoading: true,
       assetLoading: true,
-      storesLoading: true
+      storesLoading: true,
+      credentialsLoading: true,
+      credentialDescriptionsLoading: true
     };
   },
   mounted: function mounted() {
@@ -2824,20 +3158,36 @@ __webpack_require__.r(__webpack_exports__);
       _this.woLoading = 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;
+    })["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
+      _this.assetLoading = false; // Get Credentials for this asset. May be relocated to be part of asset
+      // Component when WOs can have more than one asset.
 
-    axios.get('/api/stores/').then(function (response) {
-      _this.stores = response.data;
-      _this.storesLoading = false;
+      axios.get("/api/assets/".concat(_this.asset.pcid, "/credentials")).then(function (response) {
+        _this.credentials = response.data;
+        _this.credentialsLoading = false;
+      })["catch"](function (error) {
+        console.log(error);
+      }); // Get default list of Credential Descriptions. May be relocated along with
+      // the above.
+
+      axios.get('/api/credentials/descriptions').then(function (response) {
+        _this.credentialDescriptions = response.data;
+        _this.credentialDescriptionsLoading = false;
+      })["catch"](function (error) {
+        console.log(error);
+      });
     })["catch"](function (error) {
       console.log(error);
     });
@@ -50225,6 +50575,448 @@ render._withStripped = true
 
 
 
+/***/ }),
+
+/***/ "./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/Credential.vue?vue&type=template&id=58b8dcfc&":
+/*!*************************************************************************************************************************************************************************************************************!*\
+  !*** ./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/vue-loader/lib??vue-loader-options!./resources/js/components/Credential.vue?vue&type=template&id=58b8dcfc& ***!
+  \*************************************************************************************************************************************************************************************************************/
+/*! 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",
+    { staticClass: "bg-lightgray m-1 p-2 border rounded container-fluid" },
+    [
+      _c("credential-form-modal", {
+        attrs: {
+          descriptions: _vm.creddescList,
+          "modal-id": "credential" + this.data.credid + "editModal",
+          populateWith: this.data
+        }
+      }),
+      _vm._v(" "),
+      _c(
+        "modal",
+        {
+          attrs: {
+            id: "credential" + this.data.credid + "deleteModal",
+            tabindex: "-1"
+          }
+        },
+        [
+          _c(
+            "h5",
+            {
+              staticClass: "modal-title",
+              attrs: {
+                slot: "header",
+                id: "credential" + this.data.credid + "deleteModalLabel"
+              },
+              slot: "header"
+            },
+            [_vm._v("\r\n            Delete Credential\r\n        ")]
+          ),
+          _vm._v(" "),
+          _c("div", { attrs: { slot: "body" }, slot: "body" }, [
+            _vm._v("\r\n            Are you sure?\r\n        ")
+          ]),
+          _vm._v(" "),
+          _c("div", { attrs: { slot: "footer" }, slot: "footer" }, [
+            _c(
+              "button",
+              {
+                staticClass: "btn btn-secondary",
+                attrs: { type: "button", "data-dismiss": "modal" }
+              },
+              [_vm._v("Cancel")]
+            ),
+            _vm._v(" "),
+            _c(
+              "button",
+              {
+                staticClass: "btn btn-danger",
+                attrs: { type: "button" },
+                on: {
+                  click: function($event) {
+                    return _vm.deleteCredential()
+                  }
+                }
+              },
+              [_vm._v("Confirm")]
+            )
+          ])
+        ]
+      ),
+      _vm._v(" "),
+      _c("div", { staticClass: "row no-gutters" }, [
+        _c("div", { staticClass: "h5 col-3 text-left" }, [
+          _vm._v(_vm._s(this.data.creddesc))
+        ]),
+        _vm._v(" "),
+        _c("div", { staticClass: "col-9 text-right" }, [
+          _vm._v(_vm._s(this.data.creddate))
+        ])
+      ]),
+      _vm._v(" "),
+      _c("div", { staticClass: "row" }, [
+        _c("div", { staticClass: "col-lg-9" }, [
+          _c("div", [
+            _vm._m(0),
+            _vm._v(" "),
+            _c("input", {
+              staticClass: "border-0 credential",
+              attrs: {
+                type: "text",
+                id: "username" + this.data.credid,
+                readonly: ""
+              },
+              domProps: { value: this.data.creduser }
+            }),
+            _vm._v(" "),
+            _c(
+              "button",
+              {
+                staticClass: "btn-clip btn btn-sm btn-primary rounded-pill",
+                attrs: {
+                  id: "btn-username" + this.data.credid,
+                  "data-clipboard-target": "#username" + this.data.credid
+                }
+              },
+              [_c("i", { staticClass: "far fa-clone" })]
+            )
+          ]),
+          _vm._v(" "),
+          _c("div", [
+            _vm._m(1),
+            _vm._v(" "),
+            _c("input", {
+              staticClass: "border-0 credential",
+              attrs: {
+                type: "text",
+                id: "password" + this.data.credid,
+                readonly: ""
+              },
+              domProps: { value: this.data.credpass }
+            }),
+            _vm._v(" "),
+            _c(
+              "button",
+              {
+                staticClass: "btn-clip btn btn-sm btn-primary rounded-pill",
+                attrs: {
+                  id: "btn-password" + this.data.credid,
+                  "data-clipboard-target": "#password" + this.data.credid
+                }
+              },
+              [_c("i", { staticClass: "far fa-clone" })]
+            )
+          ])
+        ]),
+        _vm._v(" "),
+        _c(
+          "div",
+          {
+            staticClass: "btn-group col-lg-2 align-self-end w-25 w-lg-auto",
+            attrs: { role: "group", "aria-label": "Edit and Delete" }
+          },
+          [
+            _c(
+              "button",
+              {
+                staticClass: "btn btn-sm btn-secondary p-lg-1",
+                attrs: {
+                  type: "button",
+                  "data-toggle": "modal",
+                  "data-target": "#credential" + this.data.credid + "editModal"
+                }
+              },
+              [_c("i", { staticClass: "fas fa-fw fa-edit" })]
+            ),
+            _vm._v(" "),
+            _c(
+              "button",
+              {
+                staticClass: "btn btn-sm btn-danger p-lg-1",
+                attrs: {
+                  type: "button",
+                  "data-toggle": "modal",
+                  "data-target":
+                    "#credential" + this.data.credid + "deleteModal"
+                }
+              },
+              [_c("i", { staticClass: "fas fa-fw fa-trash-alt" })]
+            )
+          ]
+        )
+      ])
+    ],
+    1
+  )
+}
+var staticRenderFns = [
+  function() {
+    var _vm = this
+    var _h = _vm.$createElement
+    var _c = _vm._self._c || _h
+    return _c("label", { attrs: { for: "username" } }, [
+      _c("i", { staticClass: "fas fa-fw fa-user" })
+    ])
+  },
+  function() {
+    var _vm = this
+    var _h = _vm.$createElement
+    var _c = _vm._self._c || _h
+    return _c("label", { attrs: { for: "password" } }, [
+      _c("i", { staticClass: "fas fa-fw fa-key" })
+    ])
+  }
+]
+render._withStripped = true
+
+
+
+/***/ }),
+
+/***/ "./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/CredentialFormModal.vue?vue&type=template&id=3cdb3697&":
+/*!**********************************************************************************************************************************************************************************************************************!*\
+  !*** ./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/vue-loader/lib??vue-loader-options!./resources/js/components/CredentialFormModal.vue?vue&type=template&id=3cdb3697& ***!
+  \**********************************************************************************************************************************************************************************************************************/
+/*! 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.id,
+        tabindex: "-1",
+        role: "dialog",
+        "aria-labelledby": _vm.id + "Label"
+      }
+    },
+    [
+      _c(
+        "h5",
+        {
+          staticClass: "modal-title",
+          attrs: { slot: "header", id: _vm.id + "Label" },
+          slot: "header"
+        },
+        [_vm._v("\n        Edit Credential\n    ")]
+      ),
+      _vm._v(" "),
+      _c("div", { attrs: { slot: "body" }, slot: "body" }, [
+        _c(
+          "div",
+          { staticClass: "form" },
+          [
+            _c("autocomplete-custom-dropdown", {
+              attrs: {
+                options: _vm.descriptions,
+                value: _vm.creddesc,
+                "allow-custom": true
+              },
+              model: {
+                value: _vm.creddesc,
+                callback: function($$v) {
+                  _vm.creddesc = $$v
+                },
+                expression: "creddesc"
+              }
+            })
+          ],
+          1
+        ),
+        _vm._v(" "),
+        _c("div", { staticClass: "form-group" }, [
+          _c("label", { attrs: { for: "newusername" } }, [_vm._v("Username")]),
+          _vm._v(" "),
+          _c("input", {
+            directives: [
+              {
+                name: "model",
+                rawName: "v-model",
+                value: _vm.data.creduser,
+                expression: "data.creduser"
+              }
+            ],
+            staticClass: "form-control credential",
+            attrs: {
+              type: "text",
+              name: "newusername" + _vm.data.credid,
+              id: "newusername" + _vm.data.credid
+            },
+            domProps: { value: _vm.data.creduser },
+            on: {
+              input: function($event) {
+                if ($event.target.composing) {
+                  return
+                }
+                _vm.$set(_vm.data, "creduser", $event.target.value)
+              }
+            }
+          })
+        ]),
+        _vm._v(" "),
+        _c("div", { staticClass: "form-group" }, [
+          _c("label", { attrs: { for: "newpassword" } }, [_vm._v("Password")]),
+          _vm._v(" "),
+          _c("input", {
+            directives: [
+              {
+                name: "model",
+                rawName: "v-model",
+                value: _vm.data.credpass,
+                expression: "data.credpass"
+              }
+            ],
+            staticClass: "form-control credential",
+            attrs: {
+              type: "text",
+              name: "newpassword" + _vm.data.credid,
+              id: "newpassword" + _vm.data.credid
+            },
+            domProps: { value: _vm.data.credpass },
+            on: {
+              input: function($event) {
+                if ($event.target.composing) {
+                  return
+                }
+                _vm.$set(_vm.data, "credpass", $event.target.value)
+              }
+            }
+          }),
+          _vm._v(" "),
+          _c(
+            "button",
+            {
+              staticClass: "btn btn-secondary",
+              attrs: { type: "button" },
+              on: {
+                click: function($event) {
+                  return _vm.getRandomPassword(_vm.data.credid)
+                }
+              }
+            },
+            [_vm._v("Generate Random")]
+          )
+        ]),
+        _vm._v(" "),
+        _c("div", { staticClass: "form-group" })
+      ]),
+      _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.updateCredential()
+              }
+            }
+          },
+          [_vm._v("Save")]
+        )
+      ])
+    ]
+  )
+}
+var staticRenderFns = []
+render._withStripped = true
+
+
+
+/***/ }),
+
+/***/ "./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/CredentialList.vue?vue&type=template&id=7264bb80&":
+/*!*****************************************************************************************************************************************************************************************************************!*\
+  !*** ./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/vue-loader/lib??vue-loader-options!./resources/js/components/CredentialList.vue?vue&type=template&id=7264bb80& ***!
+  \*****************************************************************************************************************************************************************************************************************/
+/*! 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("credential-form-modal", {
+        attrs: {
+          "modal-id": "newCredentialModal",
+          descriptions: _vm.creddescList,
+          create: true,
+          pcid: _vm.pcid
+        }
+      }),
+      _vm._v(" "),
+      _c(
+        "button",
+        {
+          staticClass: "btn btn-primary",
+          attrs: {
+            type: "button",
+            "data-toggle": "modal",
+            "data-target": "#newCredentialModal"
+          }
+        },
+        [_vm._v("New Credential")]
+      ),
+      _vm._v(" "),
+      _vm._l(_vm.credentials, function(credential) {
+        return _c(
+          "div",
+          { key: credential.credid },
+          [
+            _c("credential", {
+              attrs: { credential: credential, descriptions: _vm.creddescList }
+            })
+          ],
+          1
+        )
+      })
+    ],
+    2
+  )
+}
+var staticRenderFns = []
+render._withStripped = true
+
+
+
 /***/ }),
 
 /***/ "./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/Modal.vue?vue&type=template&id=53ab54d2&":
@@ -51073,6 +51865,30 @@ var render = function() {
                     : _c("circle-spinner", { attrs: { color: "#663399" } })
                 ],
                 1
+              ),
+              _vm._v(" "),
+              _c(
+                "div",
+                {
+                  staticClass: "tab-pane",
+                  attrs: {
+                    id: "credentials",
+                    role: "tabpanel",
+                    "aria-labelledby": "credentials-tab"
+                  }
+                },
+                [
+                  !_vm.credentialsLoading && !_vm.credentialDescriptionsLoading
+                    ? _c("credential-list", {
+                        attrs: {
+                          credentials: _vm.credentials,
+                          descriptions: _vm.credentialDescriptions,
+                          pcid: _vm.asset.pcid
+                        }
+                      })
+                    : _c("circle-spinner", { attrs: { color: "#663399" } })
+                ],
+                1
               )
             ])
           ])
@@ -66795,6 +67611,213 @@ __webpack_require__.r(__webpack_exports__);
 
 
 
+/***/ }),
+
+/***/ "./resources/js/components/Credential.vue":
+/*!************************************************!*\
+  !*** ./resources/js/components/Credential.vue ***!
+  \************************************************/
+/*! exports provided: default */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony import */ var _Credential_vue_vue_type_template_id_58b8dcfc___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Credential.vue?vue&type=template&id=58b8dcfc& */ "./resources/js/components/Credential.vue?vue&type=template&id=58b8dcfc&");
+/* harmony import */ var _Credential_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./Credential.vue?vue&type=script&lang=js& */ "./resources/js/components/Credential.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"])(
+  _Credential_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__["default"],
+  _Credential_vue_vue_type_template_id_58b8dcfc___WEBPACK_IMPORTED_MODULE_0__["render"],
+  _Credential_vue_vue_type_template_id_58b8dcfc___WEBPACK_IMPORTED_MODULE_0__["staticRenderFns"],
+  false,
+  null,
+  null,
+  null
+  
+)
+
+/* hot reload */
+if (false) { var api; }
+component.options.__file = "resources/js/components/Credential.vue"
+/* harmony default export */ __webpack_exports__["default"] = (component.exports);
+
+/***/ }),
+
+/***/ "./resources/js/components/Credential.vue?vue&type=script&lang=js&":
+/*!*************************************************************************!*\
+  !*** ./resources/js/components/Credential.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_Credential_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!./Credential.vue?vue&type=script&lang=js& */ "./node_modules/babel-loader/lib/index.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/Credential.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_Credential_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_0__["default"]); 
+
+/***/ }),
+
+/***/ "./resources/js/components/Credential.vue?vue&type=template&id=58b8dcfc&":
+/*!*******************************************************************************!*\
+  !*** ./resources/js/components/Credential.vue?vue&type=template&id=58b8dcfc& ***!
+  \*******************************************************************************/
+/*! 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_Credential_vue_vue_type_template_id_58b8dcfc___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!./Credential.vue?vue&type=template&id=58b8dcfc& */ "./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/Credential.vue?vue&type=template&id=58b8dcfc&");
+/* 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_Credential_vue_vue_type_template_id_58b8dcfc___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_Credential_vue_vue_type_template_id_58b8dcfc___WEBPACK_IMPORTED_MODULE_0__["staticRenderFns"]; });
+
+
+
+/***/ }),
+
+/***/ "./resources/js/components/CredentialFormModal.vue":
+/*!*********************************************************!*\
+  !*** ./resources/js/components/CredentialFormModal.vue ***!
+  \*********************************************************/
+/*! exports provided: default */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony import */ var _CredentialFormModal_vue_vue_type_template_id_3cdb3697___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./CredentialFormModal.vue?vue&type=template&id=3cdb3697& */ "./resources/js/components/CredentialFormModal.vue?vue&type=template&id=3cdb3697&");
+/* harmony import */ var _CredentialFormModal_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./CredentialFormModal.vue?vue&type=script&lang=js& */ "./resources/js/components/CredentialFormModal.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"])(
+  _CredentialFormModal_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__["default"],
+  _CredentialFormModal_vue_vue_type_template_id_3cdb3697___WEBPACK_IMPORTED_MODULE_0__["render"],
+  _CredentialFormModal_vue_vue_type_template_id_3cdb3697___WEBPACK_IMPORTED_MODULE_0__["staticRenderFns"],
+  false,
+  null,
+  null,
+  null
+  
+)
+
+/* hot reload */
+if (false) { var api; }
+component.options.__file = "resources/js/components/CredentialFormModal.vue"
+/* harmony default export */ __webpack_exports__["default"] = (component.exports);
+
+/***/ }),
+
+/***/ "./resources/js/components/CredentialFormModal.vue?vue&type=script&lang=js&":
+/*!**********************************************************************************!*\
+  !*** ./resources/js/components/CredentialFormModal.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_CredentialFormModal_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!./CredentialFormModal.vue?vue&type=script&lang=js& */ "./node_modules/babel-loader/lib/index.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/CredentialFormModal.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_CredentialFormModal_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_0__["default"]); 
+
+/***/ }),
+
+/***/ "./resources/js/components/CredentialFormModal.vue?vue&type=template&id=3cdb3697&":
+/*!****************************************************************************************!*\
+  !*** ./resources/js/components/CredentialFormModal.vue?vue&type=template&id=3cdb3697& ***!
+  \****************************************************************************************/
+/*! 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_CredentialFormModal_vue_vue_type_template_id_3cdb3697___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!./CredentialFormModal.vue?vue&type=template&id=3cdb3697& */ "./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/CredentialFormModal.vue?vue&type=template&id=3cdb3697&");
+/* 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_CredentialFormModal_vue_vue_type_template_id_3cdb3697___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_CredentialFormModal_vue_vue_type_template_id_3cdb3697___WEBPACK_IMPORTED_MODULE_0__["staticRenderFns"]; });
+
+
+
+/***/ }),
+
+/***/ "./resources/js/components/CredentialList.vue":
+/*!****************************************************!*\
+  !*** ./resources/js/components/CredentialList.vue ***!
+  \****************************************************/
+/*! exports provided: default */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony import */ var _CredentialList_vue_vue_type_template_id_7264bb80___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./CredentialList.vue?vue&type=template&id=7264bb80& */ "./resources/js/components/CredentialList.vue?vue&type=template&id=7264bb80&");
+/* harmony import */ var _CredentialList_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./CredentialList.vue?vue&type=script&lang=js& */ "./resources/js/components/CredentialList.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"])(
+  _CredentialList_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__["default"],
+  _CredentialList_vue_vue_type_template_id_7264bb80___WEBPACK_IMPORTED_MODULE_0__["render"],
+  _CredentialList_vue_vue_type_template_id_7264bb80___WEBPACK_IMPORTED_MODULE_0__["staticRenderFns"],
+  false,
+  null,
+  null,
+  null
+  
+)
+
+/* hot reload */
+if (false) { var api; }
+component.options.__file = "resources/js/components/CredentialList.vue"
+/* harmony default export */ __webpack_exports__["default"] = (component.exports);
+
+/***/ }),
+
+/***/ "./resources/js/components/CredentialList.vue?vue&type=script&lang=js&":
+/*!*****************************************************************************!*\
+  !*** ./resources/js/components/CredentialList.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_CredentialList_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!./CredentialList.vue?vue&type=script&lang=js& */ "./node_modules/babel-loader/lib/index.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/CredentialList.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_CredentialList_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_0__["default"]); 
+
+/***/ }),
+
+/***/ "./resources/js/components/CredentialList.vue?vue&type=template&id=7264bb80&":
+/*!***********************************************************************************!*\
+  !*** ./resources/js/components/CredentialList.vue?vue&type=template&id=7264bb80& ***!
+  \***********************************************************************************/
+/*! 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_CredentialList_vue_vue_type_template_id_7264bb80___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!./CredentialList.vue?vue&type=template&id=7264bb80& */ "./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/CredentialList.vue?vue&type=template&id=7264bb80&");
+/* 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_CredentialList_vue_vue_type_template_id_7264bb80___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_CredentialList_vue_vue_type_template_id_7264bb80___WEBPACK_IMPORTED_MODULE_0__["staticRenderFns"]; });
+
+
+
 /***/ }),
 
 /***/ "./resources/js/components/Modal.vue":

+ 6 - 0
resources/js/components/credential-form-modal.vue → resources/js/components/CredentialFormModal.vue

@@ -25,7 +25,13 @@
     </modal>
 </template>
 <script>
+import Modal from '../components/Modal.vue'
+import AutocompleteCustomDropdown from '../components/AutocompleteCustomDropdown.vue'
 export default {
+    components: {
+        AutocompleteCustomDropdown,
+        Modal,
+    },
     props: {
         populateWith: {
             type: Object,

+ 7 - 6
resources/js/components/credential-list.vue → resources/js/components/CredentialList.vue

@@ -8,9 +8,15 @@
     </div>
 </template>
 <script>
+import Credential from '../components/Credential.vue'
+import CredentialFormModal from '../components/CredentialFormModal.vue'
 export default {
+    components: {
+        Credential,
+        CredentialFormModal,
+    },
     props: {
-        credentialList: {
+        credentials: {
             type: Array,
             required: true
         },
@@ -25,11 +31,6 @@ export default {
             type: Number
         }
     },
-    data () {
-        return {
-            credentials: this.credentialList
-        }
-    },
     computed : {
         creddescList: function () {
             let list = {}

+ 6 - 0
resources/js/components/credential.vue

@@ -42,7 +42,13 @@
 </div>
 </template>
 <script>
+import CredentialFormModal from '../components/CredentialFormModal.vue'
+import Modal from '../components/Modal.vue'
 export default {
+    components: {
+        CredentialFormModal,
+        Modal,
+    },
     props: ['credential', 'descriptions'],
     data() {
         return {

+ 35 - 10
resources/js/views/WorkOrder.vue

@@ -34,10 +34,11 @@
                             <div class="tab-pane" id="group" role="tabpanel" aria-labelledby="group-tab">
                                 Name: {{$workOrder->asset->group->pcgroupname}}
                             </div>
-                            @endif
+                            @endif -->
                             <div class="tab-pane" id="credentials" role="tabpanel" aria-labelledby="credentials-tab">
-                                <credential-list :credential-list="{{$workOrder->asset->credentials->sortByDesc('creddate')->values()}}" :descriptions="{{App\CredDesc::all()}}" :pcid="{{$workOrder->asset->pcid}}"></credential-list>
-                            </div> -->
+                                <credential-list v-if="!credentialsLoading && !credentialDescriptionsLoading" :credentials="credentials" :descriptions="credentialDescriptions" :pcid="asset.pcid"></credential-list>
+                                <circle-spinner v-else color="#663399"></circle-spinner>
+                            </div>
                         </div>
                     </div>
                 </div>
@@ -100,11 +101,13 @@
 import WorkOrderInfo from '../components/WorkOrderInfo.vue'
 import AssetInfo from '../components/AssetInfo.vue'
 import CircleSpinner from '../components/CircleSpinner.vue'
+import CredentialList from '../components/CredentialList.vue'
 export default {
     components: {
         WorkOrderInfo,
         AssetInfo,
         CircleSpinner,
+        CredentialList,
     },
     props: ['id'],
     data () {
@@ -112,9 +115,13 @@ export default {
             workOrder: {},
             asset: {},
             stores: {},
+            credentials: {},
+            credentialDescriptions: {},
             woLoading: true,
             assetLoading: true,
             storesLoading: true,
+            credentialsLoading: true,
+            credentialDescriptionsLoading: true,
         }
     },
     mounted () {
@@ -134,20 +141,38 @@ export default {
             console.log(error)
         })
 
+        // Get list of stores from API
+        axios.get('/api/stores/').then(response => {
+            this.stores = response.data
+            this.storesLoading = false
+        }).catch(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/${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
+            // Get Credentials for this asset. May be relocated to be part of asset
+            // Component when WOs can have more than one asset.
+            axios.get(`/api/assets/${this.asset.pcid}/credentials`).then (response => {
+                this.credentials = response.data
+                this.credentialsLoading = false
+            }).catch(error => {
+                console.log(error)
+            })
+
+            // Get default list of Credential Descriptions. May be relocated along with
+            // the above.
+            axios.get('/api/credentials/descriptions').then(response => {
+                this.credentialDescriptions = response.data
+                this.credentialDescriptionsLoading = false
+            }).catch(error => {
+                console.log(error)
+            })
         }).catch(error => {
             console.log(error)
         })

+ 2 - 2
routes/api.php

@@ -30,6 +30,7 @@ Route::middleware('auth:api')->group( function() {
     Route::post('/workorders/notes', 'Api\WorkOrderNotesController@store');
     Route::put('/workorders/notes/{workOrderNote}', 'Api\WorkOrderNotesController@update');
 
+    Route::get('/assets/{asset}/credentials', 'Api\AssetsController@credentials');
     Route::put('/assets/{asset}', 'Api\AssetsController@update');
 
     Route::get('/stores', 'Api\StoresController@index');
@@ -38,7 +39,6 @@ Route::middleware('auth:api')->group( function() {
     Route::post('/credentials', 'Api\CredentialsController@store');
     Route::put('/credentials/{credential}', 'Api\CredentialsController@update');
     Route::delete('/credentials/{credential}', 'Api\CredentialsController@destroy');
-
-    Route::get('credtypes', 'Api\CredDescController@index');
+    Route::get('credentials/descriptions', 'Api\CredDescController@index');
 
 });