IA update: Update health section

This is the second update to information architecture changes and
has the following changes:

- Health section is updated to hardware status section
- Hardware status page is updated to inventory and LEDs page
- Route for sensors page has been updated

Signed-off-by: Sandeepa Singh <sandeepa.singh@ibm.com>
Change-Id: Ia1ba3a15a243a00f59a2ec646132436eb355a999
diff --git a/src/store/modules/HardwareStatus/BmcStore.js b/src/store/modules/HardwareStatus/BmcStore.js
new file mode 100644
index 0000000..f58dc63
--- /dev/null
+++ b/src/store/modules/HardwareStatus/BmcStore.js
@@ -0,0 +1,79 @@
+import api from '@/store/api';
+import i18n from '@/i18n';
+
+const BmcStore = {
+  namespaced: true,
+  state: {
+    bmc: null,
+  },
+  getters: {
+    bmc: (state) => state.bmc,
+  },
+  mutations: {
+    setBmcInfo: (state, data) => {
+      const bmc = {};
+      bmc.dateTime = new Date(data.DateTime);
+      bmc.description = data.Description;
+      bmc.firmwareVersion = data.FirmwareVersion;
+      bmc.graphicalConsoleConnectTypes =
+        data.GraphicalConsole.ConnectTypesSupported;
+      bmc.graphicalConsoleEnabled = data.GraphicalConsole.ServiceEnabled;
+      bmc.graphicalConsoleMaxSessions =
+        data.GraphicalConsole.MaxConcurrentSessions;
+      bmc.health = data.Status.Health;
+      bmc.healthRollup = data.Status.HealthRollup;
+      bmc.id = data.Id;
+      bmc.lastResetTime = new Date(data.LastResetTime);
+      bmc.identifyLed = data.LocationIndicatorActive;
+      bmc.locationNumber = data.LocationNumber;
+      bmc.manufacturer = data.manufacturer;
+      bmc.managerType = data.ManagerType;
+      bmc.model = data.Model;
+      bmc.name = data.Name;
+      bmc.partNumber = data.PartNumber;
+      bmc.powerState = data.PowerState;
+      bmc.serialConsoleConnectTypes = data.SerialConsole.ConnectTypesSupported;
+      bmc.serialConsoleEnabled = data.SerialConsole.ServiceEnabled;
+      bmc.serialConsoleMaxSessions = data.SerialConsole.MaxConcurrentSessions;
+      bmc.serialNumber = data.SerialNumber;
+      bmc.serviceEntryPointUuid = data.ServiceEntryPointUUID;
+      bmc.sparePartNumber = data.SparePartNumber;
+      bmc.statusState = data.Status.State;
+      bmc.uuid = data.UUID;
+      bmc.uri = data['@odata.id'];
+      state.bmc = bmc;
+    },
+  },
+  actions: {
+    async getBmcInfo({ commit }) {
+      return await api
+        .get('/redfish/v1/Managers/bmc')
+        .then(({ data }) => commit('setBmcInfo', data))
+        .catch((error) => console.log(error));
+    },
+    async updateIdentifyLedValue({ dispatch }, led) {
+      const uri = led.uri;
+      const updatedIdentifyLedValue = {
+        LocationIndicatorActive: led.identifyLed,
+      };
+      return await api
+        .patch(uri, updatedIdentifyLedValue)
+        .then(() => dispatch('getBmcInfo'))
+        .catch((error) => {
+          dispatch('getBmcInfo');
+          console.log('error', error);
+          if (led.identifyLed) {
+            throw new Error(
+              i18n.t('pageInventory.toast.errorEnableIdentifyLed')
+            );
+          } else {
+            throw new Error(
+              i18n.t('pageInventory.toast.errorDisableIdentifyLed')
+            );
+          }
+        });
+    },
+  },
+};
+
+export default BmcStore;
diff --git a/src/store/modules/HardwareStatus/ChassisStore.js b/src/store/modules/HardwareStatus/ChassisStore.js
new file mode 100644
index 0000000..b5edef5
--- /dev/null
+++ b/src/store/modules/HardwareStatus/ChassisStore.js
@@ -0,0 +1,89 @@
+import api from '@/store/api';
+import i18n from '@/i18n';
+
+const ChassisStore = {
+  namespaced: true,
+  state: {
+    chassis: [],
+  },
+  getters: {
+    chassis: (state) => state.chassis,
+  },
+  mutations: {
+    setChassisInfo: (state, data) => {
+      state.chassis = data.map((chassis) => {
+        const {
+          Id,
+          Status = {},
+          PartNumber,
+          SerialNumber,
+          ChassisType,
+          Manufacturer,
+          PowerState,
+          LocationIndicatorActive,
+          AssetTag,
+          MaxPowerWatts,
+          MinPowerWatts,
+          Name,
+        } = chassis;
+
+        return {
+          id: Id,
+          health: Status.Health,
+          partNumber: PartNumber,
+          serialNumber: SerialNumber,
+          chassisType: ChassisType,
+          manufacturer: Manufacturer,
+          powerState: PowerState,
+          statusState: Status.State,
+          healthRollup: Status.HealthRollup,
+          assetTag: AssetTag,
+          maxPowerWatts: MaxPowerWatts,
+          minPowerWatts: MinPowerWatts,
+          name: Name,
+          identifyLed: LocationIndicatorActive,
+          uri: chassis['@odata.id'],
+        };
+      });
+    },
+  },
+  actions: {
+    async getChassisInfo({ commit }) {
+      return await api
+        .get('/redfish/v1/Chassis')
+        .then(({ data: { Members = [] } }) =>
+          Members.map((member) => api.get(member['@odata.id']))
+        )
+        .then((promises) => api.all(promises))
+        .then((response) => {
+          const data = response.map(({ data }) => data);
+          commit('setChassisInfo', data);
+        })
+        .catch((error) => console.log(error));
+    },
+    async updateIdentifyLedValue({ dispatch }, led) {
+      const uri = led.uri;
+      const updatedIdentifyLedValue = {
+        LocationIndicatorActive: led.identifyLed,
+      };
+      return await api
+        .patch(uri, updatedIdentifyLedValue)
+        .then(() => dispatch('getChassisInfo'))
+        .catch((error) => {
+          dispatch('getChassisInfo');
+          console.log('error', error);
+          if (led.identifyLed) {
+            throw new Error(
+              i18n.t('pageInventory.toast.errorEnableIdentifyLed')
+            );
+          } else {
+            throw new Error(
+              i18n.t('pageInventory.toast.errorDisableIdentifyLed')
+            );
+          }
+        });
+    },
+  },
+};
+
+export default ChassisStore;
diff --git a/src/store/modules/HardwareStatus/FanStore.js b/src/store/modules/HardwareStatus/FanStore.js
new file mode 100644
index 0000000..fca1f32
--- /dev/null
+++ b/src/store/modules/HardwareStatus/FanStore.js
@@ -0,0 +1,50 @@
+import api from '@/store/api';
+
+const FanStore = {
+  namespaced: true,
+  state: {
+    fans: [],
+  },
+  getters: {
+    fans: (state) => state.fans,
+  },
+  mutations: {
+    setFanInfo: (state, data) => {
+      state.fans = data.map((fan) => {
+        const {
+          IndicatorLED,
+          Location,
+          MemberId,
+          Name,
+          Reading,
+          ReadingUnits,
+          Status = {},
+          PartNumber,
+          SerialNumber,
+        } = fan;
+        return {
+          id: MemberId,
+          health: Status.Health,
+          partNumber: PartNumber,
+          serialNumber: SerialNumber,
+          healthRollup: Status.HealthRollup,
+          identifyLed: IndicatorLED,
+          locationNumber: Location,
+          name: Name,
+          speed: Reading + ' ' + ReadingUnits,
+          statusState: Status.State,
+        };
+      });
+    },
+  },
+  actions: {
+    async getFanInfo({ commit }) {
+      return await api
+        .get('/redfish/v1/Chassis/chassis/Thermal')
+        .then(({ data: { Fans = [] } }) => commit('setFanInfo', Fans))
+        .catch((error) => console.log(error));
+    },
+  },
+};
+
+export default FanStore;
diff --git a/src/store/modules/HardwareStatus/MemoryStore.js b/src/store/modules/HardwareStatus/MemoryStore.js
new file mode 100644
index 0000000..cd2478d
--- /dev/null
+++ b/src/store/modules/HardwareStatus/MemoryStore.js
@@ -0,0 +1,39 @@
+import api from '@/store/api';
+
+const MemoryStore = {
+  namespaced: true,
+  state: {
+    dimms: [],
+  },
+  getters: {
+    dimms: (state) => state.dimms,
+  },
+  mutations: {
+    setMemoryInfo: (state, data) => {
+      state.dimms = data.map(({ data }) => {
+        const { Id, Status = {}, PartNumber, SerialNumber } = data;
+        return {
+          id: Id,
+          health: Status.Health,
+          partNumber: PartNumber,
+          serialNumber: SerialNumber,
+          statusState: Status.State,
+        };
+      });
+    },
+  },
+  actions: {
+    async getDimms({ commit }) {
+      return await api
+        .get('/redfish/v1/Systems/system/Memory')
+        .then(({ data: { Members } }) => {
+          const promises = Members.map((item) => api.get(item['@odata.id']));
+          return api.all(promises);
+        })
+        .then((response) => commit('setMemoryInfo', response))
+        .catch((error) => console.log(error));
+    },
+  },
+};
+
+export default MemoryStore;
diff --git a/src/store/modules/HardwareStatus/PowerSupplyStore.js b/src/store/modules/HardwareStatus/PowerSupplyStore.js
new file mode 100644
index 0000000..f7be280
--- /dev/null
+++ b/src/store/modules/HardwareStatus/PowerSupplyStore.js
@@ -0,0 +1,78 @@
+import api from '@/store/api';
+
+const PowerSupplyStore = {
+  namespaced: true,
+  state: {
+    powerSupplies: [],
+  },
+  getters: {
+    powerSupplies: (state) => state.powerSupplies,
+  },
+  mutations: {
+    setPowerSupply: (state, data) => {
+      state.powerSupplies = data.map((powerSupply) => {
+        const {
+          EfficiencyPercent,
+          FirmwareVersion,
+          LocationIndicatorActive,
+          MemberId,
+          Manufacturer,
+          Model,
+          Name,
+          PartNumber,
+          PowerInputWatts,
+          SerialNumber,
+          SparePartNumber,
+          Status = {},
+        } = powerSupply;
+        return {
+          id: MemberId,
+          health: Status.Health,
+          partNumber: PartNumber,
+          serialNumber: SerialNumber,
+          efficiencyPercent: EfficiencyPercent,
+          firmwareVersion: FirmwareVersion,
+          identifyLed: LocationIndicatorActive,
+          manufacturer: Manufacturer,
+          model: Model,
+          powerInputWatts: PowerInputWatts,
+          name: Name,
+          sparePartNumber: SparePartNumber,
+          statusState: Status.State,
+        };
+      });
+    },
+  },
+  actions: {
+    async getChassisCollection() {
+      return await api
+        .get('/redfish/v1/Chassis')
+        .then(({ data: { Members } }) =>
+          Members.map((member) => member['@odata.id'])
+        )
+        .catch((error) => console.log(error));
+    },
+    async getAllPowerSupplies({ dispatch, commit }) {
+      const collection = await dispatch('getChassisCollection');
+      if (!collection) return;
+      return await api
+        .all(collection.map((chassis) => dispatch('getChassisPower', chassis)))
+        .then((supplies) => {
+          let suppliesList = [];
+          supplies.forEach(
+            (supply) => (suppliesList = [...suppliesList, ...supply])
+          );
+          commit('setPowerSupply', suppliesList);
+        })
+        .catch((error) => console.log(error));
+    },
+    async getChassisPower(_, id) {
+      return await api
+        .get(`${id}/Power`)
+        .then(({ data: { PowerSupplies } }) => PowerSupplies || [])
+        .catch((error) => console.log(error));
+    },
+  },
+};
+
+export default PowerSupplyStore;
diff --git a/src/store/modules/HardwareStatus/ProcessorStore.js b/src/store/modules/HardwareStatus/ProcessorStore.js
new file mode 100644
index 0000000..c7cbbee
--- /dev/null
+++ b/src/store/modules/HardwareStatus/ProcessorStore.js
@@ -0,0 +1,104 @@
+import api from '@/store/api';
+import i18n from '@/i18n';
+
+const ProcessorStore = {
+  namespaced: true,
+  state: {
+    processors: [],
+  },
+  getters: {
+    processors: (state) => state.processors,
+  },
+  mutations: {
+    setProcessorsInfo: (state, data) => {
+      state.processors = data.map((processor) => {
+        const {
+          Id,
+          Status = {},
+          PartNumber,
+          SerialNumber,
+          SparePartNumber,
+          InstructionSet,
+          Manufacturer,
+          Model,
+          Name,
+          ProcessorArchitecture,
+          ProcessorType,
+          Version,
+          AssetTag,
+          MinSpeedMHz,
+          MaxSpeedMHz,
+          TotalCores,
+          TotalThreads,
+          LocationNumber,
+          LocationIndicatorActive,
+        } = processor;
+        return {
+          id: Id,
+          health: Status.Health,
+          healthRollup: Status.HealthRollup,
+          partNumber: PartNumber,
+          sparePartNumber: SparePartNumber,
+          serialNumber: SerialNumber,
+          statusState: Status.State,
+          instructionSet: InstructionSet,
+          manufacturer: Manufacturer,
+          model: Model,
+          name: Name,
+          processorArchitecture: ProcessorArchitecture,
+          processorType: ProcessorType,
+          version: Version,
+          assetTag: AssetTag,
+          minSpeedMHz: MinSpeedMHz,
+          maxSpeedMHz: MaxSpeedMHz,
+          totalCores: TotalCores,
+          totalThreads: TotalThreads,
+          locationNumber: LocationNumber,
+          identifyLed: LocationIndicatorActive,
+          uri: processor['@odata.id'],
+        };
+      });
+    },
+  },
+  actions: {
+    async getProcessorsInfo({ commit }) {
+      return await api
+        .get('/redfish/v1/Systems/system/Processors')
+        .then(({ data: { Members = [] } }) =>
+          Members.map((member) => api.get(member['@odata.id']))
+        )
+        .then((promises) => api.all(promises))
+        .then((response) => {
+          const data = response.map(({ data }) => data);
+          commit('setProcessorsInfo', data);
+        })
+        .catch((error) => console.log(error));
+    },
+    // Waiting for the following to be merged to test the Identify Led:
+    // https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/37045
+    async updateIdentifyLedValue({ dispatch }, led) {
+      const uri = led.uri;
+      const updatedIdentifyLedValue = {
+        LocationIndicatorActive: led.identifyLed,
+      };
+      return await api
+        .patch(uri, updatedIdentifyLedValue)
+        .then(() => dispatch('getProcessorsInfo'))
+        .catch((error) => {
+          dispatch('getProcessorsInfo');
+          console.log('error', error);
+          if (led.identifyLed) {
+            throw new Error(
+              i18n.t('pageInventory.toast.errorEnableIdentifyLed')
+            );
+          } else {
+            throw new Error(
+              i18n.t('pageInventory.toast.errorDisableIdentifyLed')
+            );
+          }
+        });
+    },
+  },
+};
+
+export default ProcessorStore;
diff --git a/src/store/modules/HardwareStatus/SensorsStore.js b/src/store/modules/HardwareStatus/SensorsStore.js
new file mode 100644
index 0000000..0af2a95
--- /dev/null
+++ b/src/store/modules/HardwareStatus/SensorsStore.js
@@ -0,0 +1,123 @@
+import api from '@/store/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: {
+    async getAllSensors({ dispatch }) {
+      const collection = await dispatch('getChassisCollection');
+      if (!collection) return;
+      const promises = collection.reduce((acc, id) => {
+        acc.push(dispatch('getSensors', id));
+        acc.push(dispatch('getThermalSensors', id));
+        acc.push(dispatch('getPowerSensors', id));
+        return acc;
+      }, []);
+      return await api.all(promises);
+    },
+    async getChassisCollection() {
+      return await api
+        .get('/redfish/v1/Chassis')
+        .then(({ data: { Members } }) =>
+          Members.map((member) => member['@odata.id'])
+        )
+        .catch((error) => console.log(error));
+    },
+    async getSensors({ commit }, id) {
+      const sensors = await api
+        .get(`${id}/Sensors`)
+        .then((response) => response.data.Members)
+        .catch((error) => console.log(error));
+      if (!sensors) return;
+      const promises = sensors.map((sensor) => {
+        return api.get(sensor['@odata.id']).catch((error) => {
+          console.log(error);
+          return error;
+        });
+      });
+      return await 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);
+        })
+      );
+    },
+    async getThermalSensors({ commit }, id) {
+      return await api
+        .get(`${id}/Thermal`)
+        .then(({ data: { Fans = [], Temperatures = [] } }) => {
+          const sensorData = [];
+          Fans.forEach((sensor) => {
+            sensorData.push({
+              name: sensor.Name,
+              status: sensor.Status.Health,
+              currentValue: sensor.Reading,
+              lowerCaution: sensor.LowerThresholdNonCritical,
+              upperCaution: sensor.UpperThresholdNonCritical,
+              lowerCritical: sensor.LowerThresholdCritical,
+              upperCritical: sensor.UpperThresholdCritical,
+              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));
+    },
+    async getPowerSensors({ commit }, id) {
+      return await 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;
diff --git a/src/store/modules/HardwareStatus/ServerLedStore.js b/src/store/modules/HardwareStatus/ServerLedStore.js
new file mode 100644
index 0000000..a8903e2
--- /dev/null
+++ b/src/store/modules/HardwareStatus/ServerLedStore.js
@@ -0,0 +1,55 @@
+import api from '@/store/api';
+import i18n from '@/i18n';
+
+const ServerLedStore = {
+  namespaced: true,
+  state: {
+    indicatorLedActiveState: false,
+  },
+  getters: {
+    getIndicatorLedActiveState: (state) => state.indicatorLedActiveState,
+  },
+  mutations: {
+    setIndicatorLedActiveState(state, indicatorLedActiveState) {
+      state.indicatorLedActiveState = indicatorLedActiveState;
+    },
+  },
+  actions: {
+    async getIndicatorLedActiveState({ commit }) {
+      return await api
+        .get('/redfish/v1/Systems/system')
+        .then((response) => {
+          commit(
+            'setIndicatorLedActiveState',
+            response.data.LocationIndicatorActive
+          );
+        })
+        .catch((error) => console.log(error));
+    },
+    async saveIndicatorLedActiveState({ commit }, payload) {
+      commit('setIndicatorLedActiveState', payload);
+      return await api
+        .patch('/redfish/v1/Systems/system', {
+          LocationIndicatorActive: payload,
+        })
+        .then(() => {
+          if (payload) {
+            return i18n.t('pageServerLed.toast.successServerLedOn');
+          } else {
+            return i18n.t('pageServerLed.toast.successServerLedOff');
+          }
+        })
+        .catch((error) => {
+          console.log(error);
+          commit('setIndicatorLedActiveState', !payload);
+          if (payload) {
+            throw new Error(i18n.t('pageServerLed.toast.errorServerLedOn'));
+          } else {
+            throw new Error(i18n.t('pageServerLed.toast.errorServerLedOff'));
+          }
+        });
+    },
+  },
+};
+
+export default ServerLedStore;
diff --git a/src/store/modules/HardwareStatus/SystemStore.js b/src/store/modules/HardwareStatus/SystemStore.js
new file mode 100644
index 0000000..55f3754
--- /dev/null
+++ b/src/store/modules/HardwareStatus/SystemStore.js
@@ -0,0 +1,72 @@
+import api from '@/store/api';
+import i18n from '@/i18n';
+
+const SystemStore = {
+  namespaced: true,
+  state: {
+    systems: [],
+  },
+  getters: {
+    systems: (state) => state.systems,
+  },
+  mutations: {
+    setSystemInfo: (state, data) => {
+      const system = {};
+      system.assetTag = data.AssetTag;
+      system.description = data.Description;
+      system.firmwareVersion = data.BiosVersion;
+      system.hardwareType = data.Name;
+      system.health = data.Status.Health;
+      system.id = data.Id;
+      system.locationIndicatorActive = data.LocationIndicatorActive;
+      system.locationNumber = data.LocationNumber;
+      system.manufacturer = data.Manufacturer;
+      system.memorySummaryHealth = data.MemorySummary.Status.Health;
+      system.memorySummaryHealthRollup = data.MemorySummary.Status.HealthRollup;
+      system.memorySummaryState = data.MemorySummary.Status.State;
+      system.model = data.Model;
+      system.processorSummaryCount = data.ProcessorSummary.Count;
+      system.processorSummaryHealth = data.ProcessorSummary.Status.Health;
+      system.processorSummaryHealthRoll =
+        data.ProcessorSummary.Status.HealthRollup;
+      system.processorSummaryState = data.ProcessorSummary.Status.State;
+      system.powerState = data.PowerState;
+      system.serialNumber = data.SerialNumber;
+      system.healthRollup = data.Status.HealthRollup;
+      system.subModel = data.SubModel;
+      system.statusState = data.Status.State;
+      system.systemType = data.SystemType;
+      state.systems = [system];
+    },
+  },
+  actions: {
+    async getSystem({ commit }) {
+      return await api
+        .get('/redfish/v1/Systems/system')
+        .then(({ data }) => commit('setSystemInfo', data))
+        .catch((error) => console.log(error));
+    },
+    changeIdentifyLedState({ dispatch }, ledState) {
+      api
+        .patch('/redfish/v1/Systems/system', {
+          LocationIndicatorActive: ledState,
+        })
+        .then(() => dispatch('getSystem'))
+        .catch((error) => {
+          dispatch('getSystem');
+          console.log('error', error);
+          if (ledState) {
+            throw new Error(
+              i18n.t('pageHardwareStatus.toast.errorEnableIdentifyLed')
+            );
+          } else {
+            throw new Error(
+              i18n.t('pageHardwareStatus.toast.errorDisableIdentifyLed')
+            );
+          }
+        });
+    },
+  },
+};
+
+export default SystemStore;