Add Sensors page

- Update api calls to use Redfish
- Add column sort to name and status columns
- Set default table sort to status column
- Added lodash package

Github story: https://github.com/openbmc/webui-vue/issues/4

Signed-off-by: Yoshie Muranaka <yoshiemuranaka@gmail.com>
Change-Id: Ic6e76107475fbf5fb34deb01a4de4a4a9ccfeabf
diff --git a/src/store/index.js b/src/store/index.js
index 2721699..08ada05 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -11,6 +11,7 @@
 import PowerControlStore from './modules/Control/PowerControlStore';
 import NetworkSettingStore from './modules/Configuration/NetworkSettingsStore';
 import EventLogStore from './modules/Health/EventLogStore';
+import SensorsStore from './modules/Health/SensorsStore';
 
 import WebSocketPlugin from './plugins/WebSocketPlugin';
 
@@ -30,7 +31,8 @@
     controls: ControlStore,
     powerControl: PowerControlStore,
     networkSettings: NetworkSettingStore,
-    eventLog: EventLogStore
+    eventLog: EventLogStore,
+    sensors: SensorsStore
   },
   plugins: [WebSocketPlugin]
 });
diff --git a/src/store/modules/Health/SensorsStore.js b/src/store/modules/Health/SensorsStore.js
new file mode 100644
index 0000000..5da1515
--- /dev/null
+++ b/src/store/modules/Health/SensorsStore.js
@@ -0,0 +1,113 @@
+import api from '../../api';
+import { uniqBy } from 'lodash';
+
+const SensorsStore = {
+  namespaced: true,
+  state: {
+    sensors: []
+  },
+  getters: {
+    sensors: state => state.sensors
+  },
+  mutations: {
+    setSensors: (state, sensors) => {
+      state.sensors = uniqBy([...state.sensors, ...sensors], 'name');
+    }
+  },
+  actions: {
+    getAllSensors({ dispatch }) {
+      dispatch('getChassisCollection').then(collection => {
+        collection.forEach(item => {
+          dispatch('getSensors', item);
+          dispatch('getThermalSensors', item);
+          dispatch('getPowerSensors', item);
+        });
+      });
+    },
+    getChassisCollection() {
+      return api
+        .get('/redfish/v1/Chassis')
+        .then(({ data: { Members } }) =>
+          Members.map(member => member['@odata.id'])
+        )
+        .catch(error => console.log(error));
+    },
+    getSensors({ commit }, id) {
+      api
+        .get(`${id}/Sensors`)
+        .then(({ data: { Members = [] } }) => {
+          const promises = Members.map(sensor => api.get(sensor['@odata.id']));
+          api.all(promises).then(
+            api.spread((...responses) => {
+              const sensorData = responses.map(({ data }) => {
+                return {
+                  name: data.Name,
+                  status: data.Status.Health,
+                  currentValue: data.Reading,
+                  lowerCaution: data.Thresholds.LowerCaution.Reading,
+                  upperCaution: data.Thresholds.UpperCaution.Reading,
+                  lowerCritical: data.Thresholds.LowerCritical.Reading,
+                  upperCritical: data.Thresholds.UpperCritical.Reading,
+                  units: data.ReadingUnits
+                };
+              });
+              commit('setSensors', sensorData);
+            })
+          );
+        })
+        .catch(error => console.log(error));
+    },
+    getThermalSensors({ commit }, id) {
+      api
+        .get(`${id}/Thermal`)
+        .then(({ data: { Fans = [], Temperatures = [] } }) => {
+          const sensorData = [];
+          Fans.forEach(sensor => {
+            sensorData.push({
+              // TODO: add upper/lower threshold
+              name: sensor.Name,
+              status: sensor.Status.Health,
+              currentValue: sensor.Reading,
+              units: sensor.ReadingUnits
+            });
+          });
+          Temperatures.forEach(sensor => {
+            sensorData.push({
+              name: sensor.Name,
+              status: sensor.Status.Health,
+              currentValue: sensor.ReadingCelsius,
+              lowerCaution: sensor.LowerThresholdNonCritical,
+              upperCaution: sensor.UpperThresholdNonCritical,
+              lowerCritical: sensor.LowerThresholdCritical,
+              upperCritical: sensor.UpperThresholdCritical,
+              units: '℃'
+            });
+          });
+          commit('setSensors', sensorData);
+        })
+        .catch(error => console.log(error));
+    },
+    getPowerSensors({ commit }, id) {
+      api
+        .get(`${id}/Power`)
+        .then(({ data: { Voltages = [] } }) => {
+          const sensorData = Voltages.map(sensor => {
+            return {
+              name: sensor.Name,
+              status: sensor.Status.Health,
+              currentValue: sensor.ReadingVolts,
+              lowerCaution: sensor.LowerThresholdNonCritical,
+              upperCaution: sensor.UpperThresholdNonCritical,
+              lowerCritical: sensor.LowerThresholdCritical,
+              upperCritical: sensor.UpperThresholdCritical,
+              units: 'Volts'
+            };
+          });
+          commit('setSensors', sensorData);
+        })
+        .catch(error => console.log(error));
+    }
+  }
+};
+
+export default SensorsStore;