Show total and filtered number of items in a table

 -The total number of items and the filtered items will be shown in the
   EventLogs, Sensors and HardwareStatus table.

Signed-off-by: Sukanya Pandey <sukapan1@in.ibm.com>
Change-Id: I0ee6410bf675038a350a71a02ec076f9e8baf004
diff --git a/src/components/Global/TableCellCount.vue b/src/components/Global/TableCellCount.vue
new file mode 100644
index 0000000..4f44ec2
--- /dev/null
+++ b/src/components/Global/TableCellCount.vue
@@ -0,0 +1,35 @@
+<template>
+  <div class="mt-2 d-flex flex-column justify-content-end">
+    <p v-if="!filterActive">
+      {{ $t('global.table.items', { count: totalNumberOfCells }) }}
+    </p>
+    <p v-else>
+      {{
+        $t('global.table.selectedItems', {
+          count: totalNumberOfCells,
+          filterCount: filteredItemsCount
+        })
+      }}
+    </p>
+  </div>
+</template>
+
+<script>
+export default {
+  props: {
+    filteredItemsCount: {
+      type: Number,
+      required: true
+    },
+    totalNumberOfCells: {
+      type: Number,
+      required: true
+    }
+  },
+  computed: {
+    filterActive() {
+      return this.filteredItemsCount !== this.totalNumberOfCells;
+    }
+  }
+};
+</script>
diff --git a/src/locales/en-US.json b/src/locales/en-US.json
index f3eb3e2..54f726a 100644
--- a/src/locales/en-US.json
+++ b/src/locales/en-US.json
@@ -63,7 +63,9 @@
       "emptyMessage": "No items available",
       "emptySearchMessage": "No items match the search query",
       "fromDate": "From date",
+      "items": "%{count} items",
       "itemsPerPage": "Items per page",
+      "selectedItems":"%{filterCount} of %{count} items",
       "toDate": "To date",
       "viewAll": "View all"
     }
diff --git a/src/views/Health/EventLogs/EventLogs.vue b/src/views/Health/EventLogs/EventLogs.vue
index dcede59..e7d4895 100644
--- a/src/views/Health/EventLogs/EventLogs.vue
+++ b/src/views/Health/EventLogs/EventLogs.vue
@@ -2,18 +2,19 @@
   <b-container fluid="xl">
     <page-title />
     <b-row class="mb-3">
-      <b-col
-        sm="8"
-        md="7"
-        xl="4"
-        class="mb-2 mb-xl-0 d-flex flex-column justify-content-end"
-      >
+      <b-col sm="7" xl="4" class="d-flex flex-column justify-content-end">
         <search
           :placeholder="$t('pageEventLogs.table.searchLogs')"
           @changeSearch="onChangeSearchInput"
         />
       </b-col>
-      <b-col sm="8" md="7" xl="5" offset-xl="3">
+      <b-col sm="3" class="d-flex flex-column justify-content-end">
+        <table-cell-count
+          :filtered-items-count="filteredRows"
+          :total-number-of-cells="allLogs.length"
+        ></table-cell-count>
+      </b-col>
+      <b-col sm="8" md="7" xl="5">
         <table-date-filter @change="onChangeDateTimeFilter" />
       </b-col>
     </b-row>
@@ -57,6 +58,7 @@
           :per-page="perPage"
           :current-page="currentPage"
           :filter="searchFilter"
+          @filtered="onFiltered"
           @row-selected="onRowSelected($event, filteredLogs.length)"
         >
           <!-- Checkbox column -->
@@ -145,6 +147,7 @@
 import PageTitle from '@/components/Global/PageTitle';
 import StatusIcon from '@/components/Global/StatusIcon';
 import Search from '@/components/Global/Search';
+import TableCellCount from '@/components/Global/TableCellCount';
 import TableDateFilter from '@/components/Global/TableDateFilter';
 import TableFilter from '@/components/Global/TableFilter';
 import TableRowAction from '@/components/Global/TableRowAction';
@@ -166,6 +169,7 @@
     PageTitle,
     Search,
     StatusIcon,
+    TableCellCount,
     TableFilter,
     TableRowAction,
     TableToolbar,
@@ -235,10 +239,16 @@
       ],
       filterStartDate: null,
       filterEndDate: null,
-      searchFilter: null
+      searchFilter: null,
+      searchTotalFilteredRows: 0
     };
   },
   computed: {
+    filteredRows() {
+      return this.searchFilter
+        ? this.searchTotalFilteredRows
+        : this.filteredLogs.length;
+    },
     allLogs() {
       return this.$store.getters['eventLog/allEvents'].map(event => {
         return {
@@ -346,6 +356,9 @@
     onChangeSearchInput(searchValue) {
       this.searchFilter = searchValue;
     },
+    onFiltered(filteredItems) {
+      this.searchTotalFilteredRows = filteredItems.length;
+    },
     // Create export file name based on date
     exportFileNameByDate() {
       let date = new Date();
diff --git a/src/views/Health/HardwareStatus/HardwareStatusTableDimmSlot.vue b/src/views/Health/HardwareStatus/HardwareStatusTableDimmSlot.vue
index 4fd077b..97116ca 100644
--- a/src/views/Health/HardwareStatus/HardwareStatusTableDimmSlot.vue
+++ b/src/views/Health/HardwareStatus/HardwareStatusTableDimmSlot.vue
@@ -4,6 +4,12 @@
       <b-col sm="6" md="5" xl="4">
         <search @changeSearch="onChangeSearchInput" />
       </b-col>
+      <b-col sm="6" md="3" xl="2">
+        <table-cell-count
+          :filtered-items-count="filteredRows"
+          :total-number-of-cells="dimms.length"
+        ></table-cell-count>
+      </b-col>
     </b-row>
     <b-table
       sort-icon-left
@@ -18,6 +24,7 @@
       :filter="searchFilter"
       :empty-text="$t('global.table.emptyMessage')"
       :empty-filtered-text="$t('global.table.emptySearchMessage')"
+      @filtered="onFiltered"
     >
       <!-- Expand chevron icon -->
       <template v-slot:cell(expandRow)="row">
@@ -58,12 +65,14 @@
 import IconChevron from '@carbon/icons-vue/es/chevron--down/20';
 
 import StatusIcon from '@/components/Global/StatusIcon';
+import TableCellCount from '@/components/Global/TableCellCount';
+
 import TableDataFormatterMixin from '@/components/Mixins/TableDataFormatterMixin';
 import TableSortMixin from '@/components/Mixins/TableSortMixin';
 import Search from '@/components/Global/Search';
 
 export default {
-  components: { IconChevron, PageSection, StatusIcon, Search },
+  components: { IconChevron, PageSection, StatusIcon, Search, TableCellCount },
   mixins: [TableDataFormatterMixin, TableSortMixin],
   data() {
     return {
@@ -99,10 +108,16 @@
           sortable: true
         }
       ],
-      searchFilter: null
+      searchFilter: null,
+      searchTotalFilteredRows: 0
     };
   },
   computed: {
+    filteredRows() {
+      return this.searchFilter
+        ? this.searchTotalFilteredRows
+        : this.dimms.length;
+    },
     dimms() {
       return this.$store.getters['memory/dimms'];
     }
@@ -121,6 +136,9 @@
     },
     onChangeSearchInput(searchValue) {
       this.searchFilter = searchValue;
+    },
+    onFiltered(filteredItems) {
+      this.searchTotalFilteredRows = filteredItems.length;
     }
   }
 };
diff --git a/src/views/Health/HardwareStatus/HardwareStatusTableFans.vue b/src/views/Health/HardwareStatus/HardwareStatusTableFans.vue
index c2fd7bf..0b6e1a3 100644
--- a/src/views/Health/HardwareStatus/HardwareStatusTableFans.vue
+++ b/src/views/Health/HardwareStatus/HardwareStatusTableFans.vue
@@ -4,6 +4,12 @@
       <b-col sm="6" md="5" xl="4">
         <search @changeSearch="onChangeSearchInput" />
       </b-col>
+      <b-col sm="6" md="3" xl="2">
+        <table-cell-count
+          :filtered-items-count="filteredRows"
+          :total-number-of-cells="fans.length"
+        ></table-cell-count>
+      </b-col>
     </b-row>
     <b-table
       sort-icon-left
@@ -18,6 +24,7 @@
       :filter="searchFilter"
       :empty-text="$t('global.table.emptyMessage')"
       :empty-filtered-text="$t('global.table.emptySearchMessage')"
+      @filtered="onFiltered"
     >
       <!-- Expand chevron icon -->
       <template v-slot:cell(expandRow)="row">
@@ -56,6 +63,7 @@
 <script>
 import PageSection from '@/components/Global/PageSection';
 import IconChevron from '@carbon/icons-vue/es/chevron--down/20';
+import TableCellCount from '@/components/Global/TableCellCount';
 
 import StatusIcon from '@/components/Global/StatusIcon';
 import TableDataFormatterMixin from '@/components/Mixins/TableDataFormatterMixin';
@@ -63,7 +71,7 @@
 import Search from '@/components/Global/Search';
 
 export default {
-  components: { IconChevron, PageSection, StatusIcon, Search },
+  components: { IconChevron, PageSection, StatusIcon, Search, TableCellCount },
   mixins: [TableDataFormatterMixin, TableSortMixin],
   data() {
     return {
@@ -99,10 +107,16 @@
           sortable: true
         }
       ],
-      searchFilter: null
+      searchFilter: null,
+      searchTotalFilteredRows: 0
     };
   },
   computed: {
+    filteredRows() {
+      return this.searchFilter
+        ? this.searchTotalFilteredRows
+        : this.fans.length;
+    },
     fans() {
       return this.$store.getters['fan/fans'];
     }
@@ -121,6 +135,9 @@
     },
     onChangeSearchInput(searchValue) {
       this.searchFilter = searchValue;
+    },
+    onFiltered(filteredItems) {
+      this.searchTotalFilteredRows = filteredItems.length;
     }
   }
 };
diff --git a/src/views/Health/HardwareStatus/HardwareStatusTablePowerSupplies.vue b/src/views/Health/HardwareStatus/HardwareStatusTablePowerSupplies.vue
index 2ad4a28..77a1e3c 100644
--- a/src/views/Health/HardwareStatus/HardwareStatusTablePowerSupplies.vue
+++ b/src/views/Health/HardwareStatus/HardwareStatusTablePowerSupplies.vue
@@ -4,6 +4,12 @@
       <b-col sm="6" md="5" xl="4">
         <search @changeSearch="onChangeSearchInput" />
       </b-col>
+      <b-col sm="6" md="3" xl="2">
+        <table-cell-count
+          :filtered-items-count="filteredRows"
+          :total-number-of-cells="powerSupplies.length"
+        ></table-cell-count>
+      </b-col>
     </b-row>
     <b-table
       sort-icon-left
@@ -18,6 +24,7 @@
       :filter="searchFilter"
       :empty-text="$t('global.table.emptyMessage')"
       :empty-filtered-text="$t('global.table.emptySearchMessage')"
+      @filtered="onFiltered"
     >
       <!-- Expand chevron icon -->
       <template v-slot:cell(expandRow)="row">
@@ -81,12 +88,13 @@
 import IconChevron from '@carbon/icons-vue/es/chevron--down/20';
 
 import StatusIcon from '@/components/Global/StatusIcon';
+import TableCellCount from '@/components/Global/TableCellCount';
 import TableDataFormatterMixin from '@/components/Mixins/TableDataFormatterMixin';
 import TableSortMixin from '@/components/Mixins/TableSortMixin';
 import Search from '@/components/Global/Search';
 
 export default {
-  components: { IconChevron, PageSection, StatusIcon, Search },
+  components: { IconChevron, PageSection, StatusIcon, Search, TableCellCount },
   mixins: [TableDataFormatterMixin, TableSortMixin],
   data() {
     return {
@@ -122,10 +130,16 @@
           sortable: true
         }
       ],
-      searchFilter: null
+      searchFilter: null,
+      searchTotalFilteredRows: 0
     };
   },
   computed: {
+    filteredRows() {
+      return this.searchFilter
+        ? this.searchTotalFilteredRows
+        : this.powerSupplies.length;
+    },
     powerSupplies() {
       return this.$store.getters['powerSupply/powerSupplies'];
     }
@@ -144,6 +158,9 @@
     },
     onChangeSearchInput(searchValue) {
       this.searchFilter = searchValue;
+    },
+    onFiltered(filteredItems) {
+      this.searchTotalFilteredRows = filteredItems.length;
     }
   }
 };
diff --git a/src/views/Health/HardwareStatus/HardwareStatusTableProcessors.vue b/src/views/Health/HardwareStatus/HardwareStatusTableProcessors.vue
index fc6c17f..6ab1343 100644
--- a/src/views/Health/HardwareStatus/HardwareStatusTableProcessors.vue
+++ b/src/views/Health/HardwareStatus/HardwareStatusTableProcessors.vue
@@ -5,6 +5,12 @@
       <b-col sm="6" md="5" xl="4">
         <search @changeSearch="onChangeSearchInput" />
       </b-col>
+      <b-col sm="6" md="3" xl="2">
+        <table-cell-count
+          :filtered-items-count="filteredRows"
+          :total-number-of-cells="processors.length"
+        ></table-cell-count>
+      </b-col>
     </b-row>
     <b-table
       sort-icon-left
@@ -17,6 +23,7 @@
       :filter="searchFilter"
       :empty-text="$t('global.table.emptyMessage')"
       :empty-filtered-text="$t('global.table.emptySearchMessage')"
+      @filtered="onFiltered"
     >
       <!-- Expand button -->
       <template v-slot:cell(expandRow)="row">
@@ -87,13 +94,14 @@
 import PageSection from '@/components/Global/PageSection';
 import IconChevron from '@carbon/icons-vue/es/chevron--down/20';
 import StatusIcon from '@/components/Global/StatusIcon';
+import TableCellCount from '@/components/Global/TableCellCount';
 
 import TableSortMixin from '@/components/Mixins/TableSortMixin';
 import TableDataFormatterMixin from '@/components/Mixins/TableDataFormatterMixin';
 import Search from '@/components/Global/Search';
 
 export default {
-  components: { PageSection, IconChevron, StatusIcon, Search },
+  components: { PageSection, IconChevron, TableCellCount, StatusIcon, Search },
   mixins: [TableDataFormatterMixin, TableSortMixin],
   data() {
     return {
@@ -129,10 +137,16 @@
           sortable: true
         }
       ],
-      searchFilter: null
+      searchFilter: null,
+      searchTotalFilteredRows: 0
     };
   },
   computed: {
+    filteredRows() {
+      return this.searchFilter
+        ? this.searchTotalFilteredRows
+        : this.processors.length;
+    },
     processors() {
       return this.$store.getters['processors/processors'];
     }
@@ -146,6 +160,9 @@
   methods: {
     onChangeSearchInput(searchValue) {
       this.searchFilter = searchValue;
+    },
+    onFiltered(filteredItems) {
+      this.searchTotalFilteredRows = filteredItems.length;
     }
   }
 };
diff --git a/src/views/Health/Sensors/Sensors.vue b/src/views/Health/Sensors/Sensors.vue
index 6acabd9..3915ff2 100644
--- a/src/views/Health/Sensors/Sensors.vue
+++ b/src/views/Health/Sensors/Sensors.vue
@@ -2,13 +2,19 @@
   <b-container fluid="xl">
     <page-title />
     <b-row>
-      <b-col md="5" xl="4">
+      <b-col sm="6" md="5" xl="4">
         <search
           :placeholder="$t('pageSensors.searchForSensors')"
           @changeSearch="onChangeSearchInput"
         />
       </b-col>
-      <b-col md="7" xl="8" class="text-right">
+      <b-col sm="3" md="3" xl="2">
+        <table-cell-count
+          :filtered-items-count="filteredRows"
+          :total-number-of-cells="allSensors.length"
+        ></table-cell-count>
+      </b-col>
+      <b-col sm="3" md="4" xl="6" class="text-right">
         <table-filter :filters="tableFilters" @filterChange="onFilterChange" />
       </b-col>
     </b-row>
@@ -44,6 +50,7 @@
           :filter="searchFilter"
           :empty-text="$t('global.table.emptyMessage')"
           :empty-filtered-text="$t('global.table.emptySearchMessage')"
+          @filtered="onFiltered"
           @row-selected="onRowSelected($event, filteredSensors.length)"
         >
           <!-- Checkbox column -->
@@ -93,6 +100,7 @@
 import TableFilter from '@/components/Global/TableFilter';
 import TableToolbar from '@/components/Global/TableToolbar';
 import TableToolbarExport from '@/components/Global/TableToolbarExport';
+import TableCellCount from '@/components/Global/TableCellCount';
 
 import BVTableSelectableMixin from '@/components/Mixins/BVTableSelectableMixin';
 import LoadingBarMixin from '@/components/Mixins/LoadingBarMixin';
@@ -106,6 +114,7 @@
     PageTitle,
     Search,
     StatusIcon,
+    TableCellCount,
     TableFilter,
     TableToolbar,
     TableToolbarExport
@@ -170,13 +179,19 @@
         }
       ],
       activeFilters: [],
-      searchFilter: null
+      searchFilter: null,
+      searchTotalFilteredRows: 0
     };
   },
   computed: {
     allSensors() {
       return this.$store.getters['sensors/sensors'];
     },
+    filteredRows() {
+      return this.searchFilter
+        ? this.searchTotalFilteredRows
+        : this.filteredSensors.length;
+    },
     filteredSensors() {
       return this.getFilteredTableData(this.allSensors, this.activeFilters);
     }
@@ -202,6 +217,9 @@
     },
     onChangeSearchInput(event) {
       this.searchFilter = event;
+    },
+    onFiltered(filteredItems) {
+      this.searchTotalFilteredRows = filteredItems.length;
     }
   }
 };