Update the default firmware page

- Minor updates made to the general layout and styles
  - Changes to some page copy
  - Moves update firmware form to bottom of page
- Adds dynamic TFTP upload option
- Adds dynamic card layout for BMC and host firmwre
  - 2 cards for combined
  - 4 cards for separate
- Removes FirmwareSingleImage components that were used for IBM builds

Signed-off-by: Yoshie Muranaka <yoshiemuranaka@gmail.com>
Change-Id: Ib5465ecc30dd1505824bf41c82d33b7655d5e598
diff --git a/src/views/Configuration/Firmware/Firmware.vue b/src/views/Configuration/Firmware/Firmware.vue
index 5001702..e27c8a2 100644
--- a/src/views/Configuration/Firmware/Firmware.vue
+++ b/src/views/Configuration/Firmware/Firmware.vue
@@ -1,378 +1,93 @@
 <template>
   <b-container fluid="xl">
-    <page-title :description="$t('pageFirmware.pageDescription')" />
-    <b-row class="mb-4">
-      <b-col md="10" lg="12" xl="8" class="pr-xl-4">
-        <!-- Firmware on BMC -->
-        <page-section :section-title="$t('pageFirmware.firmwareOnBmc')">
-          <b-card-group deck>
-            <!-- Current FW -->
-            <b-card header-bg-variant="success">
-              <template #header>
-                <dl class="mb-0">
-                  <dt>{{ $t('pageFirmware.current') }}</dt>
-                  <dd class="mb-0">{{ bmcFirmwareCurrentVersion }}</dd>
-                </dl>
-              </template>
-              <dl class="my-0">
-                <dt>{{ $t('pageFirmware.state') }}:</dt>
-                <dd>{{ bmcFirmwareCurrentState }}</dd>
-              </dl>
-              <template #footer></template>
-            </b-card>
+    <page-title />
+    <alerts-server-power
+      v-if="isServerPowerOffRequired"
+      :is-host-off="isHostOff"
+    />
 
-            <!-- Backup FW -->
-            <b-card footer-class="p-0">
-              <template #header>
-                <dl class="mb-0">
-                  <dt>{{ $t('pageFirmware.backup') }}</dt>
-                  <dd class="mb-0">{{ bmcFirmwareBackupVersion }}</dd>
-                </dl>
-              </template>
-              <dl class="my-0">
-                <dt>{{ $t('pageFirmware.state') }}:</dt>
-                <dd>{{ bmcFirmwareBackupState }}</dd>
-              </dl>
-              <template #footer>
-                <b-btn
-                  v-b-modal.modal-reboot-backup-bmc
-                  :disabled="!bmcFirmwareBackupVersion"
-                  variant="link"
-                  size="sm"
-                >
-                  <icon-switch class="d-none d-sm-inline-block" />
-                  {{ $t('pageFirmware.makeCurrentVersion') }}</b-btn
-                >
-              </template>
-            </b-card>
-          </b-card-group>
-        </page-section>
+    <!-- Firmware cards -->
+    <b-row>
+      <b-col xl="10">
+        <!-- BMC Firmware -->
+        <bmc-cards :is-page-disabled="isPageDisabled" />
 
-        <!-- Firmware on Host -->
-        <page-section :section-title="$t('pageFirmware.firmwareOnHost')">
-          <b-card-group deck>
-            <!-- Current FW -->
-            <b-card header-bg-variant="success">
-              <template #header>
-                <dl class="mb-0">
-                  <dt>{{ $t('pageFirmware.current') }}</dt>
-                  <dd class="mb-0">{{ hostFirmwareCurrentVersion }}</dd>
-                </dl>
-              </template>
-              <!-- State -->
-              <dl class="my-0">
-                <dt>{{ $t('pageFirmware.state') }}:</dt>
-                <dd>{{ hostFirmwareCurrentState }}</dd>
-              </dl>
-            </b-card>
-
-            <!-- Backup FW -->
-            <b-card>
-              <template #header>
-                <dl class="mb-0">
-                  <dt>{{ $t('pageFirmware.backup') }}</dt>
-                  <dd class="mb-0">{{ hostFirmwareBackupVersion }}</dd>
-                </dl>
-              </template>
-              <!-- State -->
-              <dl class="my-0">
-                <dt>{{ $t('pageFirmware.state') }}:</dt>
-                <dd>{{ hostFirmwareBackupState }}</dd>
-              </dl>
-            </b-card>
-          </b-card-group>
-        </page-section>
-      </b-col>
-
-      <!-- Update code -->
-      <b-col sm="8" xl="4" class="update-code pl-xl-4">
-        <page-section :section-title="$t('pageFirmware.updateCode')">
-          <b-form @submit.prevent="onSubmitUpload">
-            <b-form-group :label="$t('pageFirmware.form.uploadLocation')">
-              <b-form-radio v-model="isWorkstationSelected" :value="true">
-                {{ $t('pageFirmware.form.workstation') }}
-              </b-form-radio>
-              <b-form-radio v-model="isWorkstationSelected" :value="false">
-                {{ $t('pageFirmware.form.tftpServer') }}
-              </b-form-radio>
-            </b-form-group>
-
-            <!-- Workstation Upload -->
-            <template v-if="isWorkstationSelected">
-              <b-form-group :label="$t('pageFirmware.form.imageFile')">
-                <b-form-text id="image-file-help-block">
-                  {{ $t('pageFirmware.form.onlyTarFilesAccepted') }}
-                </b-form-text>
-                <form-file
-                  id="image-file"
-                  accept=".tar"
-                  :state="getValidationState($v.file)"
-                  aria-describedby="image-file-help-block"
-                  @input="onFileUpload($event)"
-                >
-                  <template #invalid>
-                    <b-form-invalid-feedback role="alert">
-                      {{ $t('global.form.required') }}
-                    </b-form-invalid-feedback>
-                  </template>
-                </form-file>
-              </b-form-group>
-            </template>
-
-            <!-- TFTP Server Upload -->
-            <template v-else>
-              <b-form-group
-                :label="$t('pageFirmware.form.tftpServerAddress')"
-                label-for="tftp-ip"
-              >
-                <b-form-text id="server-address-help-block">
-                  {{ $t('pageFirmware.form.tftpServerAddressHelper') }}
-                </b-form-text>
-                <b-form-input
-                  id="tftp-id"
-                  v-model="tftpIpAddress"
-                  type="text"
-                  :state="getValidationState($v.tftpIpAddress)"
-                  aria-describedby="server-address-help-block"
-                  @input="$v.tftpIpAddress.$touch()"
-                />
-                <b-form-invalid-feedback role="alert">
-                  {{ $t('global.form.fieldRequired') }}
-                </b-form-invalid-feedback>
-              </b-form-group>
-              <b-form-group
-                :label="$t('pageFirmware.form.imageFileName')"
-                label-for="tftp-file-name"
-              >
-                <b-form-input
-                  id="tftp-file-name"
-                  v-model="tftpFileName"
-                  type="text"
-                  :state="getValidationState($v.tftpFileName)"
-                  @input="$v.tftpFileName.$touch()"
-                />
-                <b-form-invalid-feedback role="alert">
-                  {{ $t('global.form.fieldRequired') }}
-                </b-form-invalid-feedback>
-              </b-form-group>
-            </template>
-
-            <!-- Info alert -->
-            <alert variant="info" class="mt-4 mb-5">
-              <p class="font-weight-bold mb-1">
-                {{ $t('pageFirmware.alert.updateProcess') }}
-              </p>
-              <p>{{ $t('pageFirmware.alert.updateProcessInfo') }}</p>
-            </alert>
-
-            <b-btn type="submit" variant="primary">
-              {{ $t('pageFirmware.form.uploadAndRebootBmcOrHost') }}
-            </b-btn>
-          </b-form>
-        </page-section>
+        <!-- Host Firmware -->
+        <host-cards v-if="!isSingleFileUploadEnabled" />
       </b-col>
     </b-row>
 
-    <!-- Modals -->
-    <modal-upload @ok="uploadFirmware" />
-    <modal-reboot-backup-bmc
-      :current="bmcFirmwareCurrentVersion || '--'"
-      :backup="bmcFirmwareBackupVersion || '--'"
-      @ok="switchBmcFirmware"
-    />
+    <!-- Update firmware-->
+    <page-section
+      :section-title="$t('pageFirmware.sectionTitleUpdateFirmware')"
+    >
+      <b-row>
+        <b-col sm="8" md="6" xl="4">
+          <!-- Update form -->
+          <form-update
+            :is-host-off="isHostOff"
+            :is-page-disabled="isPageDisabled"
+          />
+        </b-col>
+      </b-row>
+    </page-section>
   </b-container>
 </template>
 
 <script>
-import { requiredIf } from 'vuelidate/lib/validators';
-import { mapGetters } from 'vuex';
-import IconSwitch from '@carbon/icons-vue/es/arrows--horizontal/20';
-
+import AlertsServerPower from './FirmwareAlertServerPower';
+import BmcCards from './FirmwareCardsBmc';
+import FormUpdate from './FirmwareFormUpdate';
+import HostCards from './FirmwareCardsHost';
 import PageSection from '@/components/Global/PageSection';
 import PageTitle from '@/components/Global/PageTitle';
-import Alert from '@/components/Global/Alert';
-import ModalUpload from './FirmwareModalUpload';
-import ModalRebootBackupBmc from './FirmwareModalRebootBackupBmc';
-import FormFile from '@/components/Global/FormFile';
 
-import VuelidateMixin from '@/components/Mixins/VuelidateMixin.js';
 import LoadingBarMixin, { loading } from '@/components/Mixins/LoadingBarMixin';
-import BVToastMixin from '@/components/Mixins/BVToastMixin';
 
 export default {
-  name: 'Firmware',
+  name: 'FirmwareSingleImage',
   components: {
-    Alert,
-    IconSwitch,
-    ModalRebootBackupBmc,
-    ModalUpload,
+    AlertsServerPower,
+    BmcCards,
+    FormUpdate,
+    HostCards,
     PageSection,
     PageTitle,
-    FormFile,
   },
-  mixins: [BVToastMixin, LoadingBarMixin, VuelidateMixin],
+  mixins: [LoadingBarMixin],
   beforeRouteLeave(to, from, next) {
     this.hideLoader();
-    this.clearRebootTimeout();
     next();
   },
   data() {
     return {
-      isWorkstationSelected: true,
-      file: null,
-      tftpIpAddress: null,
-      tftpFileName: null,
-      timeoutId: null,
-      loading: loading,
+      loading,
+      isServerPowerOffRequired:
+        process.env.VUE_APP_SERVER_OFF_REQUIRED === 'true',
     };
   },
   computed: {
-    ...mapGetters('firmware', [
-      'bmcFirmwareCurrentVersion',
-      'bmcFirmwareCurrentState',
-      'bmcFirmwareBackupVersion',
-      'bmcFirmwareBackupState',
-      'hostFirmwareCurrentVersion',
-      'hostFirmwareCurrentState',
-      'hostFirmwareBackupVersion',
-      'hostFirmwareBackupState',
-    ]),
-  },
-  watch: {
-    isWorkstationSelected: function () {
-      this.$v.$reset();
-      this.file = null;
-      this.tftpIpAddress = null;
-      this.tftpFileName = null;
+    hostStatus() {
+      return this.$store.getters['global/hostStatus'];
+    },
+    isHostOff() {
+      return this.hostStatus === 'off' ? true : false;
+    },
+    isSingleFileUploadEnabled() {
+      return this.$store.getters['firmware/isSingleFileUploadEnabled'];
+    },
+    isPageDisabled() {
+      if (this.isServerPowerOffRequired) {
+        return !this.isHostOff || this.loading || this.isOperationInProgress;
+      }
+      return this.loading || this.isOperationInProgress;
     },
   },
   created() {
     this.startLoader();
-    this.$store.dispatch('firmware/getUpdateServiceApplyTime');
     this.$store
       .dispatch('firmware/getFirmwareInformation')
       .finally(() => this.endLoader());
   },
-  validations() {
-    return {
-      file: {
-        required: requiredIf(function () {
-          return this.isWorkstationSelected;
-        }),
-      },
-      tftpIpAddress: {
-        required: requiredIf(function () {
-          return !this.isWorkstationSelected;
-        }),
-      },
-      tftpFileName: {
-        required: requiredIf(function () {
-          return !this.isWorkstationSelected;
-        }),
-      },
-    };
-  },
-  methods: {
-    onFileUpload(file) {
-      this.file = file;
-      this.$v.file.$touch();
-    },
-    uploadFirmware() {
-      const startTime = this.$options.filters.formatTime(new Date());
-      this.setRebootTimeout(360000); //6 minute timeout
-      this.infoToast(
-        this.$t('pageFirmware.toast.infoUploadStartTimeMessage', { startTime }),
-        { title: this.$t('pageFirmware.toast.infoUploadStartTimeTitle') }
-      );
-      if (this.isWorkstationSelected) {
-        this.dispatchWorkstationUpload();
-      } else {
-        this.dispatchTftpUpload();
-      }
-    },
-    dispatchWorkstationUpload() {
-      this.$store
-        .dispatch('firmware/uploadFirmware', this.file)
-        .then((success) =>
-          this.infoToast(success, {
-            title: this.$t('pageFirmware.toast.successUploadTitle'),
-          })
-        )
-        .catch(({ message }) => {
-          this.errorToast(message);
-          this.clearRebootTimeout();
-        });
-    },
-    dispatchTftpUpload() {
-      const data = {
-        address: this.tftpIpAddress,
-        filename: this.tftpFileName,
-      };
-      this.$store
-        .dispatch('firmware/uploadFirmwareTFTP', data)
-        .then((success) =>
-          this.infoToast(success, {
-            title: this.$t('pageFirmware.toast.successUploadTitle'),
-          })
-        )
-        .catch(({ message }) => {
-          this.errorToast(message);
-          this.clearRebootTimeout();
-        });
-    },
-    switchBmcFirmware() {
-      this.setRebootTimeout();
-      this.$store
-        .dispatch('firmware/switchBmcFirmware')
-        .then((success) =>
-          this.infoToast(success, { title: this.$t('global.status.success') })
-        )
-        .catch(({ message }) => {
-          this.errorToast(message);
-          this.clearRebootTimeout();
-        });
-    },
-    setRebootTimeout(timeoutMs = 60000) {
-      // Set a timeout to disable page interactions while
-      // an upload or BMC reboot is in progress
-      this.startLoader();
-      this.timeoutId = setTimeout(() => {
-        this.endLoader();
-        this.infoToast(
-          this.$t('pageFirmware.toast.infoRefreshApplicationMessage'),
-          {
-            title: this.$t('pageFirmware.toast.infoRefreshApplicationTitle'),
-            refreshAction: true,
-          }
-        );
-      }, timeoutMs);
-    },
-    clearRebootTimeout() {
-      if (this.timeoutId) {
-        clearTimeout(this.timeoutId);
-        this.endLoader();
-      }
-    },
-    onSubmitUpload() {
-      this.$v.$touch();
-      if (this.$v.$invalid) return;
-      this.$bvModal.show('modal-upload');
-    },
-  },
 };
 </script>
-
-<style lang="scss" scoped>
-.update-code {
-  border-left: none;
-  @include media-breakpoint-up(xl) {
-    border-left: 1px solid gray('300');
-  }
-}
-.card-footer {
-  height: 40px;
-}
-.card-body {
-  padding: 0.75rem 1.25rem;
-}
-</style>