Add loading image from external server

Signed-off-by: Mateusz Gapski <mateuszx.gapski@intel.com>
Change-Id: Ie9793b25fdee0f438d64aafe0978d75025800cb8
diff --git a/src/locales/en-US.json b/src/locales/en-US.json
index 85e2a3a..f3eb3e2 100644
--- a/src/locales/en-US.json
+++ b/src/locales/en-US.json
@@ -636,11 +636,21 @@
   },
   "pageVirtualMedia": {
     "configureConnection": "Configure Connection",
+    "defaultDeviceName": "Virtual media device",
+    "start": "Start",
+    "stop": "Stop",
     "virtualMediaSubTitleFirst": "Save image in a web browser",
     "virtualMediaSubTitleSecond": "Load image from external server",
-    "defaultDeviceName": "Virtual media device",
+    "modal": {
+      "password": "Password",
+      "serverUri": "External server URI",
+      "title": "Legacy mode configuration",
+      "username": "Username"
+    },
     "toast": {
+      "errorMounting": "Error mounting",
       "errorReadingFile": "Error reading file. Closing server.",
+      "errorUnmounting": "Error unmounting",
       "serverRunning": "Server running",
       "serverClosedSuccessfully": "Server closed successfully",
       "serverClosedWithErrors": "Server closed with errors"
diff --git a/src/store/modules/Control/VirtualMediaStore.js b/src/store/modules/Control/VirtualMediaStore.js
index e01cfce..13ef8ee 100644
--- a/src/store/modules/Control/VirtualMediaStore.js
+++ b/src/store/modules/Control/VirtualMediaStore.js
@@ -44,10 +44,12 @@
         .then(devices => api.all(devices.map(device => api.get(device))))
         .then(devices => {
           const deviceData = devices.map(device => {
+            const isActive = device.data?.Inserted === true ? true : false;
             return {
               id: device.data?.Id,
               transferProtocolType: device.data?.TransferProtocolType,
-              websocket: device.data?.Oem?.OpenBMC?.WebSocketEndpoint
+              websocket: device.data?.Oem?.OpenBMC?.WebSocketEndpoint,
+              isActive: isActive
             };
           });
           const proxyDevices = deviceData
@@ -55,8 +57,7 @@
             .map(device => {
               return {
                 ...device,
-                file: null,
-                isActive: false
+                file: null
               };
             });
           const legacyDevices = deviceData
@@ -64,7 +65,10 @@
             .map(device => {
               return {
                 ...device,
-                address: ''
+                serverUri: '',
+                username: '',
+                password: '',
+                isRW: false
               };
             });
           commit('setProxyDevicesData', proxyDevices);
@@ -73,6 +77,27 @@
         .catch(error => {
           console.log('Virtual Media:', error);
         });
+    },
+    async mountImage(_, { id, data }) {
+      return await api
+        .post(
+          `/redfish/v1/Managers/bmc/VirtualMedia/${id}/Actions/VirtualMedia.InsertMedia`,
+          data
+        )
+        .catch(error => {
+          console.log('Mount image:', error);
+          throw new Error();
+        });
+    },
+    async unmountImage(_, id) {
+      return await api
+        .post(
+          `/redfish/v1/Managers/bmc/VirtualMedia/${id}/Actions/VirtualMedia.EjectMedia`
+        )
+        .catch(error => {
+          console.log('Unmount image:', error);
+          throw new Error();
+        });
     }
   }
 };
diff --git a/src/views/Control/VirtualMedia/ModalConfigureConnection.vue b/src/views/Control/VirtualMedia/ModalConfigureConnection.vue
new file mode 100644
index 0000000..4401a04
--- /dev/null
+++ b/src/views/Control/VirtualMedia/ModalConfigureConnection.vue
@@ -0,0 +1,142 @@
+<template>
+  <b-modal
+    id="configure-connection"
+    ref="modal"
+    @ok="onOk"
+    @hidden="resetForm"
+    @show="initModal"
+  >
+    <template v-slot:modal-title>
+      {{ $t('pageVirtualMedia.modal.title') }}
+    </template>
+    <b-form>
+      <b-form-group
+        :label="$t('pageVirtualMedia.modal.serverUri')"
+        label-for="serverUri"
+      >
+        <b-form-input
+          id="serverUri"
+          v-model="form.serverUri"
+          type="text"
+          :state="getValidationState($v.form.serverUri)"
+          data-test-id="configureConnection-input-serverUri"
+          @input="$v.form.serverUri.$touch()"
+        />
+        <b-form-invalid-feedback role="alert">
+          <template v-if="!$v.form.serverUri.required">
+            {{ $t('global.form.fieldRequired') }}
+          </template>
+        </b-form-invalid-feedback>
+      </b-form-group>
+      <b-form-group
+        :label="$t('pageVirtualMedia.modal.username')"
+        label-for="username"
+      >
+        <b-form-input
+          id="username"
+          v-model="form.username"
+          type="text"
+          data-test-id="configureConnection-input-username"
+        />
+      </b-form-group>
+      <b-form-group
+        :label="$t('pageVirtualMedia.modal.password')"
+        label-for="password"
+      >
+        <b-form-input
+          id="password"
+          v-model="form.password"
+          type="password"
+          data-test-id="configureConnection-input-password"
+        />
+      </b-form-group>
+      <b-form-group>
+        <b-form-checkbox
+          v-model="form.isRW"
+          data-test-id="configureConnection-input-isRW"
+          name="check-button"
+        >
+          RW
+        </b-form-checkbox>
+      </b-form-group>
+    </b-form>
+    <template v-slot:modal-ok>
+      {{ $t('global.action.save') }}
+    </template>
+  </b-modal>
+</template>
+
+<script>
+import { required } from 'vuelidate/lib/validators';
+import VuelidateMixin from '../../../components/Mixins/VuelidateMixin.js';
+
+export default {
+  mixins: [VuelidateMixin],
+  props: {
+    connection: {
+      type: Object,
+      default: null,
+      validator: prop => {
+        console.log(prop);
+        return true;
+      }
+    }
+  },
+  data() {
+    return {
+      form: {
+        serverUri: null,
+        username: null,
+        password: null,
+        isRW: false
+      }
+    };
+  },
+  watch: {
+    connection: function(value) {
+      if (value === null) return;
+      Object.assign(this.form, value);
+    }
+  },
+  validations() {
+    return {
+      form: {
+        serverUri: {
+          required
+        }
+      }
+    };
+  },
+  methods: {
+    handleSubmit() {
+      this.$v.$touch();
+      if (this.$v.$invalid) return;
+      let connectionData = {};
+      Object.assign(connectionData, this.form);
+      this.$emit('ok', connectionData);
+      this.closeModal();
+    },
+    initModal() {
+      if (this.connection) {
+        Object.assign(this.form, this.connection);
+      }
+    },
+    closeModal() {
+      this.$nextTick(() => {
+        this.$refs.modal.hide();
+      });
+    },
+    resetForm() {
+      this.form.serverUri = null;
+      this.form.username = null;
+      this.form.password = null;
+      this.form.isRW = false;
+      this.$v.$reset();
+    },
+    onOk(bvModalEvt) {
+      bvModalEvt.preventDefault();
+      this.handleSubmit();
+    }
+  }
+};
+</script>
diff --git a/src/views/Control/VirtualMedia/VirtualMedia.vue b/src/views/Control/VirtualMedia/VirtualMedia.vue
index a9a575d..5460eb4 100644
--- a/src/views/Control/VirtualMedia/VirtualMedia.vue
+++ b/src/views/Control/VirtualMedia/VirtualMedia.vue
@@ -26,7 +26,7 @@
                 :disabled="!dev.file"
                 @click="startVM(dev)"
               >
-                {{ 'Start' }}
+                {{ $t('pageVirtualMedia.start') }}
               </b-button>
               <b-button
                 v-if="dev.isActive"
@@ -34,7 +34,7 @@
                 :disabled="!dev.file"
                 @click="stopVM(dev)"
               >
-                {{ 'Stop' }}
+                {{ $t('pageVirtualMedia.stop') }}
               </b-button>
             </b-col>
           </b-row>
@@ -57,17 +57,30 @@
                 :label-for="device.id"
                 label-class="bold"
               >
-                <b-button variant="primary" @click="configureConnection()">
+                <b-button
+                  variant="primary"
+                  :disabled="device.isActive"
+                  @click="configureConnection(device)"
+                >
                   {{ $t('pageVirtualMedia.configureConnection') }}
                 </b-button>
 
                 <b-button
+                  v-if="!device.isActive"
                   variant="primary"
                   class="float-right"
-                  :disabled="!device.address"
+                  :disabled="!device.serverUri"
                   @click="startLegacy(device)"
                 >
-                  {{ 'Start' }}
+                  {{ $t('pageVirtualMedia.start') }}
+                </b-button>
+                <b-button
+                  v-if="device.isActive"
+                  variant="primary"
+                  class="float-right"
+                  @click="stopLegacy(device)"
+                >
+                  {{ $t('pageVirtualMedia.stop') }}
                 </b-button>
               </b-form-group>
             </b-col>
@@ -75,6 +88,10 @@
         </page-section>
       </b-col>
     </b-row>
+    <modal-configure-connection
+      :connection="modalConfigureConnection"
+      @ok="saveConnection"
+    />
   </b-container>
 </template>
 
@@ -83,14 +100,16 @@
 import PageSection from '@/components/Global/PageSection';
 import BVToastMixin from '@/components/Mixins/BVToastMixin';
 import LoadingBarMixin from '@/components/Mixins/LoadingBarMixin';
+import ModalConfigureConnection from './ModalConfigureConnection';
 import NbdServer from '@/utilities/NBDServer';
 
 export default {
   name: 'VirtualMedia',
-  components: { PageTitle, PageSection },
+  components: { PageTitle, PageSection, ModalConfigureConnection },
   mixins: [BVToastMixin, LoadingBarMixin],
   data() {
     return {
+      modalConfigureConnection: null,
       loadImageFromExternalServer:
         process.env.VUE_APP_VIRTUAL_MEDIA_LIST_ENABLED === 'true' ? true : false
     };
@@ -142,11 +161,53 @@
     stopVM(device) {
       device.nbd.stop();
     },
-    startLegacy() {
-      console.log('starting legacy...');
+    startLegacy(connectionData) {
+      var data = {};
+      data.Image = connectionData.serverUri;
+      data.UserName = connectionData.username;
+      data.Password = connectionData.password;
+      data.WriteProtected = connectionData.isRW;
+      this.startLoader();
+      this.$store
+        .dispatch('virtualMedia/mountImage', {
+          id: connectionData.id,
+          data: data
+        })
+        .then(() => {
+          this.successToast(
+            this.$t('pageVirtualMedia.toast.serverClosedSuccessfully')
+          );
+          connectionData.isActive = true;
+        })
+        .catch(() => {
+          this.errorToast(this.$t('pageVirtualMedia.toast.errorMounting'));
+          this.isActive = false;
+        })
+        .finally(() => this.endLoader());
     },
-    configureConnection() {
-      this.warningToast('This option is unavialable. We are working on it.');
+    stopLegacy(connectionData) {
+      this.$store
+        .dispatch('virtualMedia/unmountImage', connectionData.id)
+        .then(() => {
+          this.successToast(
+            this.$t('pageVirtualMedia.toast.serverClosedSuccessfully')
+          );
+          connectionData.isActive = false;
+        })
+        .catch(() =>
+          this.errorToast(this.$t('pageVirtualMedia.toast.errorUnmounting'))
+        )
+        .finally(() => this.endLoader());
+    },
+    saveConnection(connectionData) {
+      this.modalConfigureConnection.serverUri = connectionData.serverUri;
+      this.modalConfigureConnection.username = connectionData.username;
+      this.modalConfigureConnection.password = connectionData.password;
+      this.modalConfigureConnection.isRW = connectionData.isRW;
+    },
+    configureConnection(connectionData) {
+      this.modalConfigureConnection = connectionData;
+      this.$bvModal.show('configure-connection');
     }
   }
 };