Create LoadingBar component

Create loading bar component to indicate when page data
is 'loading'. Not every component view will need to show the
loading bar (eg Reboot BMC).
The LoadingBarMixin can be imported per component as needed.

Signed-off-by: Yoshie Muranaka <yoshiemuranaka@gmail.com>
Change-Id: I6735be37bc0a81f5bb2b7c93fb31a0e0ef9b40d1
diff --git a/src/components/AppHeader/AppHeader.vue b/src/components/AppHeader/AppHeader.vue
index 114d6c9..d937293 100644
--- a/src/components/AppHeader/AppHeader.vue
+++ b/src/components/AppHeader/AppHeader.vue
@@ -52,6 +52,7 @@
         </b-navbar-nav>
       </b-navbar>
     </header>
+    <loading-bar />
   </div>
 </template>
 
@@ -61,10 +62,18 @@
 import IconMenu from '@carbon/icons-vue/es/menu/20';
 import IconRenew from '@carbon/icons-vue/es/renew/20';
 import StatusIcon from '../Global/StatusIcon';
+import LoadingBar from '../Global/LoadingBar';
 
 export default {
   name: 'AppHeader',
-  components: { IconAvatar, IconClose, IconMenu, IconRenew, StatusIcon },
+  components: {
+    IconAvatar,
+    IconClose,
+    IconMenu,
+    IconRenew,
+    StatusIcon,
+    LoadingBar
+  },
   data() {
     return {
       isNavigationOpen: false
diff --git a/src/components/Global/LoadingBar.vue b/src/components/Global/LoadingBar.vue
new file mode 100644
index 0000000..1d8d68a
--- /dev/null
+++ b/src/components/Global/LoadingBar.vue
@@ -0,0 +1,85 @@
+<template>
+  <transition name="fade">
+    <b-progress
+      v-if="!isLoadingComplete"
+      :value="loadingIndicatorValue"
+      height="0.4rem"
+    />
+  </transition>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      loadingIndicatorValue: 0,
+      isLoadingComplete: false,
+      loadingIntervalId: null,
+      timeoutId: null
+    };
+  },
+  created() {
+    this.$root.$on('loader::start', () => {
+      this.startLoadingInterval();
+    });
+    this.$root.$on('loader::end', () => {
+      this.endLoadingInterval();
+    });
+    this.$root.$on('loader::hide', () => {
+      this.hideLoadingBar();
+    });
+  },
+  methods: {
+    startLoadingInterval() {
+      this.clearLoadingInterval();
+      this.clearTimeout();
+      this.loadingIndicatorValue = 0;
+      this.isLoadingComplete = false;
+      this.loadingIntervalId = setInterval(() => {
+        this.loadingIndicatorValue += 1;
+        if (this.loadingIndicatorValue > 100) this.clearLoadingInterval();
+      }, 100);
+    },
+    endLoadingInterval() {
+      this.clearLoadingInterval();
+      this.clearTimeout();
+      this.loadingIndicatorValue = 100;
+      this.timeoutId = setTimeout(() => {
+        // Let animation complete before hiding
+        // the loading bar
+        this.isLoadingComplete = true;
+      }, 1000);
+    },
+    hideLoadingBar() {
+      this.clearLoadingInterval();
+      this.clearTimeout();
+      this.loadingIndicatorValue = 0;
+      this.isLoadingComplete = true;
+    },
+    clearLoadingInterval() {
+      if (this.loadingIntervalId) clearInterval(this.loadingIntervalId);
+      this.loadingIntervalId = null;
+    },
+    clearTimeout() {
+      if (this.timeoutId) clearTimeout(this.timeoutId);
+      this.timeoutId = null;
+    }
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+.progress {
+  position: absolute;
+  left: 0;
+  right: 0;
+  bottom: -0.4rem;
+  opacity: 1;
+  transition: opacity $duration--moderate-01 $standard-easing--productive;
+
+  &.fade-enter,
+  &.fade-leave-to {
+    opacity: 0;
+  }
+}
+</style>
diff --git a/src/components/Mixins/LoadingBarMixin.js b/src/components/Mixins/LoadingBarMixin.js
new file mode 100644
index 0000000..111b40d
--- /dev/null
+++ b/src/components/Mixins/LoadingBarMixin.js
@@ -0,0 +1,15 @@
+const LoadingBarMixin = {
+  methods: {
+    startLoader() {
+      this.$root.$emit('loader::start');
+    },
+    endLoader() {
+      this.$root.$emit('loader::end');
+    },
+    hideLoader() {
+      this.$root.$emit('loader::hide');
+    }
+  }
+};
+
+export default LoadingBarMixin;
diff --git a/src/main.js b/src/main.js
index b59afd9..d9f1e78 100644
--- a/src/main.js
+++ b/src/main.js
@@ -24,6 +24,7 @@
   ModalPlugin,
   NavbarPlugin,
   NavPlugin,
+  ProgressPlugin,
   TablePlugin,
   ToastPlugin,
   TooltipPlugin
@@ -91,6 +92,7 @@
 Vue.use(ModalPlugin);
 Vue.use(NavbarPlugin);
 Vue.use(NavPlugin);
+Vue.use(ProgressPlugin);
 Vue.use(TablePlugin);
 Vue.use(ToastPlugin);
 Vue.use(TooltipPlugin);