From d02d3ff007de54bb6a866c9cdc2db0050187ccd9 Mon Sep 17 00:00:00 2001 From: Sandeepa Singh Date: Wed, 1 Sep 2021 18:57:32 +0530 Subject: [PATCH] Add SNMP alerts page and test hooks (#8) * Add SNMP alerts page and test hooks This page will be included in the Settings section of the primary navigation. The user will be able to delete and add alert destination. Signed-off-by: Sandeepa Singh --- .../AppNavigation/AppNavigationMixin.js | 5 + src/env/components/AppNavigation/ibm.js | 5 + src/env/router/ibm.js | 9 + src/locales/en-US.json | 30 +- src/router/routes.js | 9 + src/store/index.js | 3 +- src/store/modules/Settings/SnmpAlertsStore.js | 116 ++++++++ .../SnmpAlerts/ModalAddDestination.vue | 142 +++++++++ src/views/Settings/SnmpAlerts/SnmpAlerts.vue | 272 ++++++++++++++++++ src/views/Settings/SnmpAlerts/index.js | 2 + .../__snapshots__/AppNavigation.spec.js.snap | 18 ++ 11 files changed, 609 insertions(+), 2 deletions(-) create mode 100644 src/store/modules/Settings/SnmpAlertsStore.js create mode 100644 src/views/Settings/SnmpAlerts/ModalAddDestination.vue create mode 100644 src/views/Settings/SnmpAlerts/SnmpAlerts.vue create mode 100644 src/views/Settings/SnmpAlerts/index.js diff --git a/src/components/AppNavigation/AppNavigationMixin.js b/src/components/AppNavigation/AppNavigationMixin.js index edeabc52f4..ad9af89914 100644 --- a/src/components/AppNavigation/AppNavigationMixin.js +++ b/src/components/AppNavigation/AppNavigationMixin.js @@ -123,6 +123,11 @@ const AppNavigationMixin = { label: this.$t('appNavigation.powerRestorePolicy'), route: '/settings/power-restore-policy', }, + { + id: 'snmp-alerts', + label: this.$t('appNavigation.snmpAlerts'), + route: '/settings/snmp-alerts', + }, ], }, { diff --git a/src/env/components/AppNavigation/ibm.js b/src/env/components/AppNavigation/ibm.js index 32f5c9f47c..233c3f7565 100644 --- a/src/env/components/AppNavigation/ibm.js +++ b/src/env/components/AppNavigation/ibm.js @@ -118,6 +118,11 @@ const AppNavigationMixin = { label: this.$t('appNavigation.powerRestorePolicy'), route: '/settings/power-restore-policy', }, + { + id: 'snmp-alerts', + label: this.$t('appNavigation.snmpAlerts'), + route: '/settings/snmp-alerts', + }, ], }, { diff --git a/src/env/router/ibm.js b/src/env/router/ibm.js index c6ac61f79d..2eacbdca89 100644 --- a/src/env/router/ibm.js +++ b/src/env/router/ibm.js @@ -25,6 +25,7 @@ import SerialOverLanConsole from '@/views/Operations/SerialOverLan/SerialOverLan import ServerPowerOperations from '@/views/Operations/ServerPowerOperations'; import Certificates from '@/views/SecurityAndAccess/Certificates'; import Power from '@/views/ResourceManagement/Power'; +import SnmpAlerts from '@/views/Settings/SnmpAlerts'; import i18n from '@/i18n'; // Custom components @@ -206,6 +207,14 @@ const routes = [ title: i18n.t('appPageTitle.powerRestorePolicy'), }, }, + { + path: '/settings/snmp-alerts', + name: 'snmp-alerts', + component: SnmpAlerts, + meta: { + title: i18n.t('appPageTitle.snmpAlerts'), + }, + }, { path: '/resource-management/power', name: 'power', diff --git a/src/locales/en-US.json b/src/locales/en-US.json index afe886dcf2..1edc03c77a 100644 --- a/src/locales/en-US.json +++ b/src/locales/en-US.json @@ -126,6 +126,7 @@ "serverPowerOperations": "@:appPageTitle.serverPowerOperations", "certificates": "@:appPageTitle.certificates", "virtualMedia": "@:appPageTitle.virtualMedia", + "snmpAlerts": "@:appPageTitle.snmpAlerts", "power": "@:appPageTitle.power" }, "appPageTitle": { @@ -154,7 +155,8 @@ "serialOverLan": "Serial over LAN (SOL) console", "serverPowerOperations": "Server power operations", "certificates": "Certificates", - "virtualMedia": "Virtual media" + "virtualMedia": "Virtual media", + "snmpAlerts":"SNMP Alerts" }, "pageChangePassword": { "changePassword": "Change password", @@ -806,6 +808,32 @@ "successSaveSettings": "Successfully saved settings." } }, + "pageSnmpAlerts": { + "addDestination": "Add destination", + "deleteDestination": "Delete destination | Delete destinations", + "pageDescription": "Set the Simple Network Management Protocol (SNMP) traps with an IP address and a port.", + "modal": { + "addSnmpDestinationTitle": "Add SNMP alert destination", + "batchDeleteConfirmMessage": "Are you sure you want to delete the SNMP alert destination? This action cannot be undone. | Are you sure you want to delete %{count} SNMP alert destinations? This action cannot be undone.", + "deleteConfirmMessage": "Are you sure you want to delete the SNMP alert destination? This action cannot be undone.", + "deleteSnmpDestinationTitle": "Delete SNMP alert destination | Delete SNMP alert destinations", + "ipaddress": "IP Address", + "port": "Port" + }, + "table": { + "ipaddress": "IP Address", + "port": "Port" + }, + "toast": { + "errorAddDestination":"Error in adding SNMP alert destination", + "errorBatchDelete": "Error in deleting SNMP alert destination. | Error in deleting SNMP alert destinations.", + "errorDeleteDestination": "Error deleting SNMP alert destination.", + "errorLoadSnmpDetails": "Error loading SNMP alert details.", + "successAddDestination":"Successfully added SNMP alert destination.", + "successBatchDelete": "Successfully deleted SNMP alert destination. | Successfully deleted %{count} SNMP alert destinations.", + "successDeleteDestination": "Successfully deleted SNMP alert destination." + } + }, "pageCertificates": { "addNewCertificate": "Add new certificate", "caCertificate": "CA Certificate", diff --git a/src/router/routes.js b/src/router/routes.js index b99aac5166..48c3f42c4a 100644 --- a/src/router/routes.js +++ b/src/router/routes.js @@ -28,6 +28,7 @@ import ServerPowerOperations from '@/views/Operations/ServerPowerOperations'; import Certificates from '@/views/SecurityAndAccess/Certificates'; import VirtualMedia from '@/views/Operations/VirtualMedia'; import Power from '@/views/ResourceManagement/Power'; +import SnmpAlerts from '@/views/Settings/SnmpAlerts'; import i18n from '@/i18n'; const routes = [ @@ -182,6 +183,14 @@ const routes = [ title: i18n.t('appPageTitle.dateTime'), }, }, + { + path: '/settings/snmp-alerts', + name: 'snmp-alerts', + component: SnmpAlerts, + meta: { + title: i18n.t('appPageTitle.snmpAlerts'), + }, + }, { path: '/operations/factory-reset', name: 'factory-reset', diff --git a/src/store/index.js b/src/store/index.js index d7c1b22d03..3f9cf17904 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -27,7 +27,7 @@ import AssemblyStore from './modules/HardwareStatus/AssemblyStore'; import PostCodeLogsStore from './modules/Logs/PostCodeLogsStore'; import PoliciesStore from './modules/SecurityAndAccess/PoliciesStore'; import FactoryResetStore from './modules/Operations/FactoryResetStore'; - +import SnmpAlertsStore from './modules/Settings/SnmpAlertsStore'; import WebSocketPlugin from './plugins/WebSocketPlugin'; import DateTimeStore from './modules/Settings/DateTimeStore'; import VirtualMediaStore from './modules/Operations/VirtualMediaStore'; @@ -55,6 +55,7 @@ export default new Vuex.Store({ eventLog: EventLogStore, sensors: SensorsStore, serverLed: ServerLedStore, + snmpAlerts: SnmpAlertsStore, certificates: CertificatesStore, system: SystemStore, memory: MemoryStore, diff --git a/src/store/modules/Settings/SnmpAlertsStore.js b/src/store/modules/Settings/SnmpAlertsStore.js new file mode 100644 index 0000000000..17b91dfa36 --- /dev/null +++ b/src/store/modules/Settings/SnmpAlertsStore.js @@ -0,0 +1,116 @@ +import api, { getResponseCount } from '@/store/api'; +import i18n from '@/i18n'; +const SnmpAlertsStore = { + namespaced: true, + state: { + allSnmpDetails: [], + }, + getters: { + allSnmpDetails(state) { + return state.allSnmpDetails; + }, + }, + mutations: { + setSnmpDetails(state, allSnmpDetails) { + state.allSnmpDetails = allSnmpDetails; + }, + }, + actions: { + async getSnmpAlertUrl() { + return await api + .get('/redfish/v1/') + .then((response) => api.get(response.data.EventService['@odata.id'])) + .then((response) => api.get(response.data.Subscriptions['@odata.id'])) + .then((response) => response.data['@odata.id']) + .catch((error) => console.log('Error', error)); + }, + async getSnmpDetails({ commit, dispatch }) { + const snmpAlertUrl = await dispatch('getSnmpAlertUrl'); + return await api + .get(snmpAlertUrl) + .then((response) => + response.data.Members.map((user) => user['@odata.id']) + ) + .then((userIds) => api.all(userIds.map((user) => api.get(user)))) + .then((users) => { + const snmpDetailsData = users.map((user) => user.data); + commit('setSnmpDetails', snmpDetailsData); + }) + .catch((error) => { + console.log(error); + const message = i18n.t('pageSnmpAlerts.toast.errorLoadSnmpDetails'); + throw new Error(message); + }); + }, + async deleteDestination({ dispatch }, id) { + const snmpAlertUrl = await dispatch('getSnmpAlertUrl'); + return await api + .delete(`${snmpAlertUrl}/${id}`) + .then(() => dispatch('getSnmpDetails')) + .then(() => + i18n.t('pageSnmpAlerts.toast.successDeleteDestination', { + id, + }) + ) + .catch((error) => { + console.log(error); + const message = i18n.t( + 'pageSnmpAlerts.toast.errorDeleteDestination', + { + id, + } + ); + throw new Error(message); + }); + }, + async deleteMultipleDestinations({ dispatch }, destination) { + const snmpAlertUrl = await dispatch('getSnmpAlertUrl'); + const promises = destination.map(({ id }) => { + return api.delete(`${snmpAlertUrl}/${id}`).catch((error) => { + console.log(error); + return error; + }); + }); + return await api + .all(promises) + .then((response) => { + dispatch('getSnmpDetails'); + return response; + }) + .then( + api.spread((...responses) => { + const { successCount, errorCount } = getResponseCount(responses); + let toastMessages = []; + if (successCount) { + const message = i18n.tc( + 'pageSnmpAlerts.toast.successBatchDelete', + successCount + ); + toastMessages.push({ type: 'success', message }); + } + if (errorCount) { + const message = i18n.tc( + 'pageSnmpAlerts.toast.errorBatchDelete', + errorCount + ); + toastMessages.push({ type: 'error', message }); + } + return toastMessages; + }) + ); + }, + async addDestination({ dispatch }, { data }) { + const snmpAlertUrl = await dispatch('getSnmpAlertUrl'); + return await api + .post(snmpAlertUrl, data) + .then(() => dispatch('getSnmpDetails')) + .then(() => i18n.t('pageSnmpAlerts.toast.successAddDestination')) + .catch((error) => { + console.log(error); + const message = i18n.t('pageSnmpAlerts.toast.errorAddDestination'); + throw new Error(message); + }); + }, + }, +}; +export default SnmpAlertsStore; diff --git a/src/views/Settings/SnmpAlerts/ModalAddDestination.vue b/src/views/Settings/SnmpAlerts/ModalAddDestination.vue new file mode 100644 index 0000000000..1d14117809 --- /dev/null +++ b/src/views/Settings/SnmpAlerts/ModalAddDestination.vue @@ -0,0 +1,142 @@ + + diff --git a/src/views/Settings/SnmpAlerts/SnmpAlerts.vue b/src/views/Settings/SnmpAlerts/SnmpAlerts.vue new file mode 100644 index 0000000000..08b3c114e1 --- /dev/null +++ b/src/views/Settings/SnmpAlerts/SnmpAlerts.vue @@ -0,0 +1,272 @@ + + diff --git a/src/views/Settings/SnmpAlerts/index.js b/src/views/Settings/SnmpAlerts/index.js new file mode 100644 index 0000000000..f27ed4aa46 --- /dev/null +++ b/src/views/Settings/SnmpAlerts/index.js @@ -0,0 +1,2 @@ +import SnmpAlerts from './SnmpAlerts.vue'; +export default SnmpAlerts; diff --git a/tests/unit/__snapshots__/AppNavigation.spec.js.snap b/tests/unit/__snapshots__/AppNavigation.spec.js.snap index 37609d3992..e25f9c16ed 100644 --- a/tests/unit/__snapshots__/AppNavigation.spec.js.snap +++ b/tests/unit/__snapshots__/AppNavigation.spec.js.snap @@ -453,6 +453,15 @@ exports[`AppNavigation.vue should render correctly 1`] = ` appNavigation.powerRestorePolicy + + + appNavigation.snmpAlerts + + @@ -1114,6 +1123,15 @@ exports[`AppNavigation.vue should render with nav-container open 1`] = ` appNavigation.powerRestorePolicy + + + appNavigation.snmpAlerts + +