From 828dda9b187684902710bb11621eca27bf0c6eec Mon Sep 17 00:00:00 2001 From: Derick Montague Date: Mon, 28 Jun 2021 15:52:22 -0500 Subject: IA update: Add logs and update overview icon This is the first patchset of the information architecture changes. These changes are the result of several months of design research with users to improve the existing information architecture (IA). More information can we found in the Github story. This patchset will add a Logs section and move event logs and dumps from the Health section to the new Logs section. It will also update the icon used for the Overview page. Github story: https://github.com/openbmc/webui-vue/issues/56 Testing: 1. IBM build: - Logs contained Event logs and dumps - Both pages rendered when clicking link 2. Intel build - Logs contained Event logs only - Logs page rendered when clicking link 3. Tested default build - Logs contained Event logs only - Logs page rendered when clicking link Signed-off-by: Derick Montague Change-Id: I4621837202cf5ad3469d6ea460d9a5bdc79c8816 --- src/components/AppHeader/AppHeader.vue | 2 +- src/components/AppNavigation/AppNavigationMixin.js | 21 +- src/env/components/AppNavigation/ibm.js | 23 +- src/env/components/AppNavigation/intel.js | 21 +- src/env/router/ibm.js | 8 +- src/env/router/intel.js | 4 +- src/env/store/ibm.js | 2 +- src/locales/en-US.json | 1 + src/router/routes.js | 4 +- src/store/index.js | 2 +- src/store/modules/Health/DumpsStore.js | 117 ---- src/store/modules/Health/EventLogStore.js | 222 -------- src/store/modules/Logs/DumpsStore.js | 117 ++++ src/store/modules/Logs/EventLogStore.js | 222 ++++++++ src/views/Health/Dumps/Dumps.vue | 337 ------------ src/views/Health/Dumps/DumpsForm.vue | 95 ---- src/views/Health/Dumps/DumpsModalConfirmation.vue | 75 --- src/views/Health/Dumps/index.js | 2 - src/views/Health/EventLogs/EventLogs.vue | 597 --------------------- src/views/Health/EventLogs/index.js | 2 - src/views/Logs/Dumps/Dumps.vue | 337 ++++++++++++ src/views/Logs/Dumps/DumpsForm.vue | 95 ++++ src/views/Logs/Dumps/DumpsModalConfirmation.vue | 75 +++ src/views/Logs/Dumps/index.js | 2 + src/views/Logs/EventLogs/EventLogs.vue | 597 +++++++++++++++++++++ src/views/Logs/EventLogs/index.js | 2 + src/views/Overview/OverviewEvents.vue | 2 +- tests/unit/__snapshots__/AppHeader.spec.js.snap | 2 +- .../unit/__snapshots__/AppNavigation.spec.js.snap | 182 ++++++- 29 files changed, 1667 insertions(+), 1501 deletions(-) delete mode 100644 src/store/modules/Health/DumpsStore.js delete mode 100644 src/store/modules/Health/EventLogStore.js create mode 100644 src/store/modules/Logs/DumpsStore.js create mode 100644 src/store/modules/Logs/EventLogStore.js delete mode 100644 src/views/Health/Dumps/Dumps.vue delete mode 100644 src/views/Health/Dumps/DumpsForm.vue delete mode 100644 src/views/Health/Dumps/DumpsModalConfirmation.vue delete mode 100644 src/views/Health/Dumps/index.js delete mode 100644 src/views/Health/EventLogs/EventLogs.vue delete mode 100644 src/views/Health/EventLogs/index.js create mode 100644 src/views/Logs/Dumps/Dumps.vue create mode 100644 src/views/Logs/Dumps/DumpsForm.vue create mode 100644 src/views/Logs/Dumps/DumpsModalConfirmation.vue create mode 100644 src/views/Logs/Dumps/index.js create mode 100644 src/views/Logs/EventLogs/EventLogs.vue create mode 100644 src/views/Logs/EventLogs/index.js diff --git a/src/components/AppHeader/AppHeader.vue b/src/components/AppHeader/AppHeader.vue index f7989d2e..df6acbf7 100644 --- a/src/components/AppHeader/AppHeader.vue +++ b/src/components/AppHeader/AppHeader.vue @@ -49,7 +49,7 @@ diff --git a/src/components/AppNavigation/AppNavigationMixin.js b/src/components/AppNavigation/AppNavigationMixin.js index f9ba0776..42552da5 100644 --- a/src/components/AppNavigation/AppNavigationMixin.js +++ b/src/components/AppNavigation/AppNavigationMixin.js @@ -1,4 +1,5 @@ -import IconAnalytics from '@carbon/icons-vue/es/analytics/16'; +import IconDashboard from '@carbon/icons-vue/es/dashboard/16'; +import IconTextLinkAnalysis from '@carbon/icons-vue/es/text-link--analysis/16'; import IconDataCheck from '@carbon/icons-vue/es/data--check/16'; import IconSettingsAdjust from '@carbon/icons-vue/es/settings--adjust/16'; import IconSettings from '@carbon/icons-vue/es/settings/16'; @@ -7,7 +8,8 @@ import IconChevronUp from '@carbon/icons-vue/es/chevron--up/16'; const AppNavigationMixin = { components: { - iconOverview: IconAnalytics, + iconOverview: IconDashboard, + iconLogs: IconTextLinkAnalysis, iconHealth: IconDataCheck, iconControl: IconSettingsAdjust, iconConfiguration: IconSettings, @@ -24,15 +26,22 @@ const AppNavigationMixin = { icon: 'iconOverview', }, { - id: 'health', - label: this.$t('appNavigation.health'), - icon: 'iconHealth', + id: 'logs', + label: this.$t('appNavigation.logs'), + icon: 'iconLogs', children: [ { id: 'event-logs', label: this.$t('appNavigation.eventLogs'), - route: '/health/event-logs', + route: '/logs/event-logs', }, + ], + }, + { + id: 'health', + label: this.$t('appNavigation.health'), + icon: 'iconHealth', + children: [ { id: 'hardware-status', label: this.$t('appNavigation.hardwareStatus'), diff --git a/src/env/components/AppNavigation/ibm.js b/src/env/components/AppNavigation/ibm.js index b8186a44..8792ccc8 100644 --- a/src/env/components/AppNavigation/ibm.js +++ b/src/env/components/AppNavigation/ibm.js @@ -1,4 +1,5 @@ -import IconAnalytics from '@carbon/icons-vue/es/analytics/16'; +import IconDashboard from '@carbon/icons-vue/es/dashboard/16'; +import IconTextLinkAnalysis from '@carbon/icons-vue/es/text-link--analysis/16'; import IconDataCheck from '@carbon/icons-vue/es/data--check/16'; import IconSettingsAdjust from '@carbon/icons-vue/es/settings--adjust/16'; import IconSettings from '@carbon/icons-vue/es/settings/16'; @@ -7,7 +8,8 @@ import IconChevronUp from '@carbon/icons-vue/es/chevron--up/16'; const AppNavigationMixin = { components: { - iconOverview: IconAnalytics, + iconOverview: IconDashboard, + iconLogs: IconTextLinkAnalysis, iconHealth: IconDataCheck, iconControl: IconSettingsAdjust, iconConfiguration: IconSettings, @@ -24,20 +26,27 @@ const AppNavigationMixin = { icon: 'iconOverview', }, { - id: 'health', - label: this.$t('appNavigation.health'), - icon: 'iconHealth', + id: 'logs', + label: this.$t('appNavigation.logs'), + icon: 'iconLogs', children: [ { id: 'dumps', label: this.$t('appNavigation.dumps'), - route: '/health/dumps', + route: '/logs/dumps', }, { id: 'event-logs', label: this.$t('appNavigation.eventLogs'), - route: '/health/event-logs', + route: '/logs/event-logs', }, + ], + }, + { + id: 'health', + label: this.$t('appNavigation.health'), + icon: 'iconHealth', + children: [ { id: 'hardware-status', label: this.$t('appNavigation.hardwareStatus'), diff --git a/src/env/components/AppNavigation/intel.js b/src/env/components/AppNavigation/intel.js index 7144487b..9c3591f5 100644 --- a/src/env/components/AppNavigation/intel.js +++ b/src/env/components/AppNavigation/intel.js @@ -1,4 +1,5 @@ -import IconAnalytics from '@carbon/icons-vue/es/analytics/16'; +import IconDashboard from '@carbon/icons-vue/es/dashboard/16'; +import IconTextLinkAnalysis from '@carbon/icons-vue/es/text-link--analysis/16'; import IconDataCheck from '@carbon/icons-vue/es/data--check/16'; import IconSettingsAdjust from '@carbon/icons-vue/es/settings--adjust/16'; import IconSettings from '@carbon/icons-vue/es/settings/16'; @@ -7,7 +8,8 @@ import IconChevronUp from '@carbon/icons-vue/es/chevron--up/16'; const AppNavigationMixin = { components: { - iconOverview: IconAnalytics, + iconOverview: IconDashboard, + iconLogs: IconTextLinkAnalysis, iconHealth: IconDataCheck, iconControl: IconSettingsAdjust, iconConfiguration: IconSettings, @@ -24,15 +26,22 @@ const AppNavigationMixin = { icon: 'iconOverview', }, { - id: 'health', - label: this.$t('appNavigation.health'), - icon: 'iconHealth', + id: 'logs', + label: this.$t('appNavigation.logs'), + icon: 'iconLogs', children: [ { id: 'event-logs', label: this.$t('appNavigation.eventLogs'), - route: '/health/event-logs', + route: '/logs/event-logs', }, + ], + }, + { + id: 'health', + label: this.$t('appNavigation.health'), + icon: 'iconHealth', + children: [ { id: 'hardware-status', label: this.$t('appNavigation.hardwareStatus'), diff --git a/src/env/router/ibm.js b/src/env/router/ibm.js index 91b70a70..8b94cf78 100644 --- a/src/env/router/ibm.js +++ b/src/env/router/ibm.js @@ -3,7 +3,7 @@ import ChangePassword from '@/views/ChangePassword'; import ClientSessions from '@/views/AccessControl/ClientSessions'; import ConsoleLayout from '@/layouts/ConsoleLayout.vue'; import DateTimeSettings from '@/views/Configuration/DateTimeSettings'; -import EventLogs from '@/views/Health/EventLogs'; +import EventLogs from '@/views/Logs/EventLogs'; import FactoryReset from '@/views/Control/FactoryReset'; import Firmware from '@/views/Configuration/Firmware'; import HardwareStatus from '@/views/Health/HardwareStatus'; @@ -29,7 +29,7 @@ import SslCertificates from '@/views/AccessControl/SslCertificates'; import i18n from '@/i18n'; // Custom components -import Dumps from '@/views/Health/Dumps'; +import Dumps from '@/views/Logs/Dumps'; const routes = [ { @@ -96,7 +96,7 @@ const routes = [ }, }, { - path: '/health/dumps', + path: '/logs/dumps', name: 'dumps', component: Dumps, meta: { @@ -104,7 +104,7 @@ const routes = [ }, }, { - path: '/health/event-logs', + path: '/logs/event-logs', name: 'event-logs', component: EventLogs, meta: { diff --git a/src/env/router/intel.js b/src/env/router/intel.js index 53f6154e..3e3349d0 100644 --- a/src/env/router/intel.js +++ b/src/env/router/intel.js @@ -3,7 +3,7 @@ import ChangePassword from '@/views/ChangePassword'; import ClientSessions from '@/views/AccessControl/ClientSessions'; import ConsoleLayout from '@/layouts/ConsoleLayout.vue'; import DateTimeSettings from '@/views/Configuration/DateTimeSettings'; -import EventLogs from '@/views/Health/EventLogs'; +import EventLogs from '@/views/Logs/EventLogs'; import Firmware from '@/views/Configuration/Firmware'; import HardwareStatus from '@/views/Health/HardwareStatus'; import Kvm from '@/views/Control/Kvm'; @@ -100,7 +100,7 @@ const routes = [ }, }, { - path: '/health/event-logs', + path: '/logs/event-logs', name: 'event-logs', component: EventLogs, meta: { diff --git a/src/env/store/ibm.js b/src/env/store/ibm.js index ff20b9cf..787f8975 100644 --- a/src/env/store/ibm.js +++ b/src/env/store/ibm.js @@ -1,5 +1,5 @@ import store from '@/store'; -import DumpsStore from '@/store/modules/Health/DumpsStore'; +import DumpsStore from '@/store/modules/Logs/DumpsStore'; store.unregisterModule('virtualMedia'); diff --git a/src/locales/en-US.json b/src/locales/en-US.json index eccd302a..a5fd8202 100644 --- a/src/locales/en-US.json +++ b/src/locales/en-US.json @@ -111,6 +111,7 @@ "health": "Health", "kvm": "@:appPageTitle.kvm", "ldap": "@:appPageTitle.ldap", + "logs": "Logs", "localUserManagement": "@:appPageTitle.localUserManagement", "managePowerUsage": "@:appPageTitle.managePowerUsage", "networkSettings": "@:appPageTitle.networkSettings", diff --git a/src/router/routes.js b/src/router/routes.js index 7501073a..1c5d57b1 100644 --- a/src/router/routes.js +++ b/src/router/routes.js @@ -2,7 +2,7 @@ import AppLayout from '@/layouts/AppLayout.vue'; import ChangePassword from '@/views/ChangePassword'; import ConsoleLayout from '@/layouts/ConsoleLayout.vue'; import DateTimeSettings from '@/views/Configuration/DateTimeSettings'; -import EventLogs from '@/views/Health/EventLogs'; +import EventLogs from '@/views/Logs/EventLogs'; import FactoryReset from '@/views/Control/FactoryReset'; import Firmware from '@/views/Configuration/Firmware'; import HardwareStatus from '@/views/Health/HardwareStatus'; @@ -104,7 +104,7 @@ const routes = [ }, }, { - path: '/health/event-logs', + path: '/logs/event-logs', name: 'event-logs', component: EventLogs, meta: { diff --git a/src/store/index.js b/src/store/index.js index 29dfe4fc..5aba4663 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -13,7 +13,7 @@ import ControlStore from './modules/Control/ControlStore'; import PowerControlStore from './modules/Control/PowerControlStore'; import PowerPolicyStore from './modules/Control/PowerPolicyStore'; import NetworkSettingStore from './modules/Configuration/NetworkSettingsStore'; -import EventLogStore from './modules/Health/EventLogStore'; +import EventLogStore from './modules/Logs/EventLogStore'; import SensorsStore from './modules/Health/SensorsStore'; import ServerLedStore from './modules/Control/ServerLedStore'; import SystemStore from './modules/Health/SystemStore'; diff --git a/src/store/modules/Health/DumpsStore.js b/src/store/modules/Health/DumpsStore.js deleted file mode 100644 index 3b91354b..00000000 --- a/src/store/modules/Health/DumpsStore.js +++ /dev/null @@ -1,117 +0,0 @@ -import api, { getResponseCount } from '@/store/api'; -import i18n from '@/i18n'; - -const DumpsStore = { - namespaced: true, - state: { - bmcDumps: [], - }, - getters: { - bmcDumps: (state) => state.bmcDumps, - }, - mutations: { - setBmcDumps: (state, dumps) => { - state.bmcDumps = dumps.map((dump) => ({ - data: dump.AdditionalDataURI, - dateTime: new Date(dump.Created), - dumpType: dump.Name, - id: dump.Id, - location: dump['@odata.id'], - size: dump.AdditionalDataSizeBytes, - })); - }, - }, - actions: { - async getBmcDumps({ commit }) { - return await api - .get('/redfish/v1/Managers/bmc/LogServices/Dump/Entries') - .then(({ data = {} }) => commit('setBmcDumps', data.Members || [])) - .catch((error) => console.log(error)); - }, - async createBmcDump() { - return await api - .post( - '/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData', - { - DiagnosticDataType: 'Manager', - OEMDiagnosticDataType: '', - } - ) - .catch((error) => { - console.log(error); - throw new Error(i18n.t('pageDumps.toast.errorStartBmcDump')); - }); - }, - async createSystemDump() { - return await api - .post( - '/redfish/v1/Systems/system/LogServices/Dump/Actions/LogService.CollectDiagnosticData', - { - DiagnosticDataType: 'OEM', - OEMDiagnosticDataType: 'System', - } - ) - .catch((error) => { - console.log(error); - throw new Error(i18n.t('pageDumps.toast.errorStartSystemDump')); - }); - }, - async deleteDumps({ dispatch }, dumps) { - const promises = dumps.map(({ location }) => - api.delete(location).catch((error) => { - console.log(error); - return error; - }) - ); - return await api - .all(promises) - .then((response) => { - dispatch('getBmcDumps'); - return response; - }) - .then( - api.spread((...responses) => { - const { successCount, errorCount } = getResponseCount(responses); - const toastMessages = []; - - if (successCount) { - const message = i18n.tc( - 'pageDumps.toast.successDeleteDump', - successCount - ); - toastMessages.push({ type: 'success', message }); - } - - if (errorCount) { - const message = i18n.tc( - 'pageDumps.toast.errorDeleteDump', - errorCount - ); - toastMessages.push({ type: 'error', message }); - } - - return toastMessages; - }) - ); - }, - async deleteAllDumps({ commit, state }) { - const totalDumpCount = state.bmcDumps.length; - return await api - .post( - '/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.ClearLog' - ) - .then(() => { - commit('setBmcDumps', []); - return i18n.tc('pageDumps.toast.successDeleteDump', totalDumpCount); - }) - .catch((error) => { - console.log(error); - throw new Error( - i18n.tc('pageDumps.toast.errorDeleteDump', totalDumpCount) - ); - }); - }, - }, -}; - -export default DumpsStore; diff --git a/src/store/modules/Health/EventLogStore.js b/src/store/modules/Health/EventLogStore.js deleted file mode 100644 index c9bd82fd..00000000 --- a/src/store/modules/Health/EventLogStore.js +++ /dev/null @@ -1,222 +0,0 @@ -import api, { getResponseCount } from '@/store/api'; -import i18n from '@/i18n'; - -const getHealthStatus = (events, loadedEvents) => { - let status = loadedEvents ? 'OK' : ''; - for (const event of events) { - if (event.severity === 'Warning') { - status = 'Warning'; - } - if (event.severity === 'Critical') { - status = 'Critical'; - break; - } - } - return status; -}; - -// TODO: High priority events should also check if Log -// is resolved when the property is available in Redfish -const getHighPriorityEvents = (events) => - events.filter(({ severity }) => severity === 'Critical'); - -const EventLogStore = { - namespaced: true, - state: { - allEvents: [], - loadedEvents: false, - }, - getters: { - allEvents: (state) => state.allEvents, - highPriorityEvents: (state) => getHighPriorityEvents(state.allEvents), - healthStatus: (state) => - getHealthStatus(state.allEvents, state.loadedEvents), - }, - mutations: { - setAllEvents: (state, allEvents) => ( - (state.allEvents = allEvents), (state.loadedEvents = true) - ), - }, - actions: { - async getEventLogData({ commit }) { - return await api - .get('/redfish/v1/Systems/system/LogServices/EventLog/Entries') - .then(({ data: { Members = [] } = {} }) => { - const eventLogs = Members.map((log) => { - const { - Id, - Severity, - Created, - EntryType, - Message, - Name, - Modified, - Resolved, - AdditionalDataURI, - } = log; - return { - id: Id, - severity: Severity, - date: new Date(Created), - type: EntryType, - description: Message, - name: Name, - modifiedDate: new Date(Modified), - uri: log['@odata.id'], - filterByStatus: Resolved ? 'Resolved' : 'Unresolved', - status: Resolved, //true or false - additionalDataUri: AdditionalDataURI, - }; - }); - commit('setAllEvents', eventLogs); - }) - .catch((error) => { - console.log('Event Log Data:', error); - }); - }, - async deleteAllEventLogs({ dispatch }, data) { - return await api - .post( - '/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog' - ) - .then(() => dispatch('getEventLogData')) - .then(() => i18n.tc('pageEventLogs.toast.successDelete', data.length)) - .catch((error) => { - console.log(error); - throw new Error( - i18n.tc('pageEventLogs.toast.errorDelete', data.length) - ); - }); - }, - async deleteEventLogs({ dispatch }, uris = []) { - const promises = uris.map((uri) => - api.delete(uri).catch((error) => { - console.log(error); - return error; - }) - ); - return await api - .all(promises) - .then((response) => { - dispatch('getEventLogData'); - return response; - }) - .then( - api.spread((...responses) => { - const { successCount, errorCount } = getResponseCount(responses); - const toastMessages = []; - - if (successCount) { - const message = i18n.tc( - 'pageEventLogs.toast.successDelete', - successCount - ); - toastMessages.push({ type: 'success', message }); - } - - if (errorCount) { - const message = i18n.tc( - 'pageEventLogs.toast.errorDelete', - errorCount - ); - toastMessages.push({ type: 'error', message }); - } - - return toastMessages; - }) - ); - }, - async resolveEventLogs({ dispatch }, logs) { - const promises = logs.map((log) => - api.patch(log.uri, { Resolved: true }).catch((error) => { - console.log(error); - return error; - }) - ); - return await api - .all(promises) - .then((response) => { - dispatch('getEventLogData'); - return response; - }) - .then( - api.spread((...responses) => { - const { successCount, errorCount } = getResponseCount(responses); - const toastMessages = []; - if (successCount) { - const message = i18n.tc( - 'pageEventLogs.toast.successResolveLogs', - successCount - ); - toastMessages.push({ type: 'success', message }); - } - if (errorCount) { - const message = i18n.tc( - 'pageEventLogs.toast.errorResolveLogs', - errorCount - ); - toastMessages.push({ type: 'error', message }); - } - return toastMessages; - }) - ); - }, - async unresolveEventLogs({ dispatch }, logs) { - const promises = logs.map((log) => - api.patch(log.uri, { Resolved: false }).catch((error) => { - console.log(error); - return error; - }) - ); - return await api - .all(promises) - .then((response) => { - dispatch('getEventLogData'); - return response; - }) - .then( - api.spread((...responses) => { - const { successCount, errorCount } = getResponseCount(responses); - const toastMessages = []; - if (successCount) { - const message = i18n.tc( - 'pageEventLogs.toast.successUnresolveLogs', - successCount - ); - toastMessages.push({ type: 'success', message }); - } - if (errorCount) { - const message = i18n.tc( - 'pageEventLogs.toast.errorUnresolveLogs', - errorCount - ); - toastMessages.push({ type: 'error', message }); - } - return toastMessages; - }) - ); - }, - // Single log entry - async updateEventLogStatus({ dispatch }, log) { - const updatedEventLogStatus = log.status; - return await api - .patch(log.uri, { Resolved: updatedEventLogStatus }) - .then(() => { - dispatch('getEventLogData'); - }) - .then(() => { - if (log.status) { - return i18n.tc('pageEventLogs.toast.successResolveLogs', 1); - } else { - return i18n.tc('pageEventLogs.toast.successUnresolveLogs', 1); - } - }) - .catch((error) => { - console.log(error); - throw new Error(i18n.t('pageEventLogs.toast.errorLogStatusUpdate')); - }); - }, - }, -}; - -export default EventLogStore; diff --git a/src/store/modules/Logs/DumpsStore.js b/src/store/modules/Logs/DumpsStore.js new file mode 100644 index 00000000..3b91354b --- /dev/null +++ b/src/store/modules/Logs/DumpsStore.js @@ -0,0 +1,117 @@ +import api, { getResponseCount } from '@/store/api'; +import i18n from '@/i18n'; + +const DumpsStore = { + namespaced: true, + state: { + bmcDumps: [], + }, + getters: { + bmcDumps: (state) => state.bmcDumps, + }, + mutations: { + setBmcDumps: (state, dumps) => { + state.bmcDumps = dumps.map((dump) => ({ + data: dump.AdditionalDataURI, + dateTime: new Date(dump.Created), + dumpType: dump.Name, + id: dump.Id, + location: dump['@odata.id'], + size: dump.AdditionalDataSizeBytes, + })); + }, + }, + actions: { + async getBmcDumps({ commit }) { + return await api + .get('/redfish/v1/Managers/bmc/LogServices/Dump/Entries') + .then(({ data = {} }) => commit('setBmcDumps', data.Members || [])) + .catch((error) => console.log(error)); + }, + async createBmcDump() { + return await api + .post( + '/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData', + { + DiagnosticDataType: 'Manager', + OEMDiagnosticDataType: '', + } + ) + .catch((error) => { + console.log(error); + throw new Error(i18n.t('pageDumps.toast.errorStartBmcDump')); + }); + }, + async createSystemDump() { + return await api + .post( + '/redfish/v1/Systems/system/LogServices/Dump/Actions/LogService.CollectDiagnosticData', + { + DiagnosticDataType: 'OEM', + OEMDiagnosticDataType: 'System', + } + ) + .catch((error) => { + console.log(error); + throw new Error(i18n.t('pageDumps.toast.errorStartSystemDump')); + }); + }, + async deleteDumps({ dispatch }, dumps) { + const promises = dumps.map(({ location }) => + api.delete(location).catch((error) => { + console.log(error); + return error; + }) + ); + return await api + .all(promises) + .then((response) => { + dispatch('getBmcDumps'); + return response; + }) + .then( + api.spread((...responses) => { + const { successCount, errorCount } = getResponseCount(responses); + const toastMessages = []; + + if (successCount) { + const message = i18n.tc( + 'pageDumps.toast.successDeleteDump', + successCount + ); + toastMessages.push({ type: 'success', message }); + } + + if (errorCount) { + const message = i18n.tc( + 'pageDumps.toast.errorDeleteDump', + errorCount + ); + toastMessages.push({ type: 'error', message }); + } + + return toastMessages; + }) + ); + }, + async deleteAllDumps({ commit, state }) { + const totalDumpCount = state.bmcDumps.length; + return await api + .post( + '/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.ClearLog' + ) + .then(() => { + commit('setBmcDumps', []); + return i18n.tc('pageDumps.toast.successDeleteDump', totalDumpCount); + }) + .catch((error) => { + console.log(error); + throw new Error( + i18n.tc('pageDumps.toast.errorDeleteDump', totalDumpCount) + ); + }); + }, + }, +}; + +export default DumpsStore; diff --git a/src/store/modules/Logs/EventLogStore.js b/src/store/modules/Logs/EventLogStore.js new file mode 100644 index 00000000..c9bd82fd --- /dev/null +++ b/src/store/modules/Logs/EventLogStore.js @@ -0,0 +1,222 @@ +import api, { getResponseCount } from '@/store/api'; +import i18n from '@/i18n'; + +const getHealthStatus = (events, loadedEvents) => { + let status = loadedEvents ? 'OK' : ''; + for (const event of events) { + if (event.severity === 'Warning') { + status = 'Warning'; + } + if (event.severity === 'Critical') { + status = 'Critical'; + break; + } + } + return status; +}; + +// TODO: High priority events should also check if Log +// is resolved when the property is available in Redfish +const getHighPriorityEvents = (events) => + events.filter(({ severity }) => severity === 'Critical'); + +const EventLogStore = { + namespaced: true, + state: { + allEvents: [], + loadedEvents: false, + }, + getters: { + allEvents: (state) => state.allEvents, + highPriorityEvents: (state) => getHighPriorityEvents(state.allEvents), + healthStatus: (state) => + getHealthStatus(state.allEvents, state.loadedEvents), + }, + mutations: { + setAllEvents: (state, allEvents) => ( + (state.allEvents = allEvents), (state.loadedEvents = true) + ), + }, + actions: { + async getEventLogData({ commit }) { + return await api + .get('/redfish/v1/Systems/system/LogServices/EventLog/Entries') + .then(({ data: { Members = [] } = {} }) => { + const eventLogs = Members.map((log) => { + const { + Id, + Severity, + Created, + EntryType, + Message, + Name, + Modified, + Resolved, + AdditionalDataURI, + } = log; + return { + id: Id, + severity: Severity, + date: new Date(Created), + type: EntryType, + description: Message, + name: Name, + modifiedDate: new Date(Modified), + uri: log['@odata.id'], + filterByStatus: Resolved ? 'Resolved' : 'Unresolved', + status: Resolved, //true or false + additionalDataUri: AdditionalDataURI, + }; + }); + commit('setAllEvents', eventLogs); + }) + .catch((error) => { + console.log('Event Log Data:', error); + }); + }, + async deleteAllEventLogs({ dispatch }, data) { + return await api + .post( + '/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog' + ) + .then(() => dispatch('getEventLogData')) + .then(() => i18n.tc('pageEventLogs.toast.successDelete', data.length)) + .catch((error) => { + console.log(error); + throw new Error( + i18n.tc('pageEventLogs.toast.errorDelete', data.length) + ); + }); + }, + async deleteEventLogs({ dispatch }, uris = []) { + const promises = uris.map((uri) => + api.delete(uri).catch((error) => { + console.log(error); + return error; + }) + ); + return await api + .all(promises) + .then((response) => { + dispatch('getEventLogData'); + return response; + }) + .then( + api.spread((...responses) => { + const { successCount, errorCount } = getResponseCount(responses); + const toastMessages = []; + + if (successCount) { + const message = i18n.tc( + 'pageEventLogs.toast.successDelete', + successCount + ); + toastMessages.push({ type: 'success', message }); + } + + if (errorCount) { + const message = i18n.tc( + 'pageEventLogs.toast.errorDelete', + errorCount + ); + toastMessages.push({ type: 'error', message }); + } + + return toastMessages; + }) + ); + }, + async resolveEventLogs({ dispatch }, logs) { + const promises = logs.map((log) => + api.patch(log.uri, { Resolved: true }).catch((error) => { + console.log(error); + return error; + }) + ); + return await api + .all(promises) + .then((response) => { + dispatch('getEventLogData'); + return response; + }) + .then( + api.spread((...responses) => { + const { successCount, errorCount } = getResponseCount(responses); + const toastMessages = []; + if (successCount) { + const message = i18n.tc( + 'pageEventLogs.toast.successResolveLogs', + successCount + ); + toastMessages.push({ type: 'success', message }); + } + if (errorCount) { + const message = i18n.tc( + 'pageEventLogs.toast.errorResolveLogs', + errorCount + ); + toastMessages.push({ type: 'error', message }); + } + return toastMessages; + }) + ); + }, + async unresolveEventLogs({ dispatch }, logs) { + const promises = logs.map((log) => + api.patch(log.uri, { Resolved: false }).catch((error) => { + console.log(error); + return error; + }) + ); + return await api + .all(promises) + .then((response) => { + dispatch('getEventLogData'); + return response; + }) + .then( + api.spread((...responses) => { + const { successCount, errorCount } = getResponseCount(responses); + const toastMessages = []; + if (successCount) { + const message = i18n.tc( + 'pageEventLogs.toast.successUnresolveLogs', + successCount + ); + toastMessages.push({ type: 'success', message }); + } + if (errorCount) { + const message = i18n.tc( + 'pageEventLogs.toast.errorUnresolveLogs', + errorCount + ); + toastMessages.push({ type: 'error', message }); + } + return toastMessages; + }) + ); + }, + // Single log entry + async updateEventLogStatus({ dispatch }, log) { + const updatedEventLogStatus = log.status; + return await api + .patch(log.uri, { Resolved: updatedEventLogStatus }) + .then(() => { + dispatch('getEventLogData'); + }) + .then(() => { + if (log.status) { + return i18n.tc('pageEventLogs.toast.successResolveLogs', 1); + } else { + return i18n.tc('pageEventLogs.toast.successUnresolveLogs', 1); + } + }) + .catch((error) => { + console.log(error); + throw new Error(i18n.t('pageEventLogs.toast.errorLogStatusUpdate')); + }); + }, + }, +}; + +export default EventLogStore; diff --git a/src/views/Health/Dumps/Dumps.vue b/src/views/Health/Dumps/Dumps.vue deleted file mode 100644 index 4538b305..00000000 --- a/src/views/Health/Dumps/Dumps.vue +++ /dev/null @@ -1,337 +0,0 @@ - - - diff --git a/src/views/Health/Dumps/DumpsForm.vue b/src/views/Health/Dumps/DumpsForm.vue deleted file mode 100644 index 02ec1864..00000000 --- a/src/views/Health/Dumps/DumpsForm.vue +++ /dev/null @@ -1,95 +0,0 @@ - - - diff --git a/src/views/Health/Dumps/DumpsModalConfirmation.vue b/src/views/Health/Dumps/DumpsModalConfirmation.vue deleted file mode 100644 index f8e20cfd..00000000 --- a/src/views/Health/Dumps/DumpsModalConfirmation.vue +++ /dev/null @@ -1,75 +0,0 @@ - - - diff --git a/src/views/Health/Dumps/index.js b/src/views/Health/Dumps/index.js deleted file mode 100644 index 65525fb0..00000000 --- a/src/views/Health/Dumps/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import Dumps from './Dumps.vue'; -export default Dumps; diff --git a/src/views/Health/EventLogs/EventLogs.vue b/src/views/Health/EventLogs/EventLogs.vue deleted file mode 100644 index fa3f43cb..00000000 --- a/src/views/Health/EventLogs/EventLogs.vue +++ /dev/null @@ -1,597 +0,0 @@ - - - diff --git a/src/views/Health/EventLogs/index.js b/src/views/Health/EventLogs/index.js deleted file mode 100644 index 521efde4..00000000 --- a/src/views/Health/EventLogs/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import EventLogs from './EventLogs.vue'; -export default EventLogs; diff --git a/src/views/Logs/Dumps/Dumps.vue b/src/views/Logs/Dumps/Dumps.vue new file mode 100644 index 00000000..4538b305 --- /dev/null +++ b/src/views/Logs/Dumps/Dumps.vue @@ -0,0 +1,337 @@ + + + diff --git a/src/views/Logs/Dumps/DumpsForm.vue b/src/views/Logs/Dumps/DumpsForm.vue new file mode 100644 index 00000000..02ec1864 --- /dev/null +++ b/src/views/Logs/Dumps/DumpsForm.vue @@ -0,0 +1,95 @@ + + + diff --git a/src/views/Logs/Dumps/DumpsModalConfirmation.vue b/src/views/Logs/Dumps/DumpsModalConfirmation.vue new file mode 100644 index 00000000..f8e20cfd --- /dev/null +++ b/src/views/Logs/Dumps/DumpsModalConfirmation.vue @@ -0,0 +1,75 @@ + + + diff --git a/src/views/Logs/Dumps/index.js b/src/views/Logs/Dumps/index.js new file mode 100644 index 00000000..65525fb0 --- /dev/null +++ b/src/views/Logs/Dumps/index.js @@ -0,0 +1,2 @@ +import Dumps from './Dumps.vue'; +export default Dumps; diff --git a/src/views/Logs/EventLogs/EventLogs.vue b/src/views/Logs/EventLogs/EventLogs.vue new file mode 100644 index 00000000..fa3f43cb --- /dev/null +++ b/src/views/Logs/EventLogs/EventLogs.vue @@ -0,0 +1,597 @@ + + + diff --git a/src/views/Logs/EventLogs/index.js b/src/views/Logs/EventLogs/index.js new file mode 100644 index 00000000..521efde4 --- /dev/null +++ b/src/views/Logs/EventLogs/index.js @@ -0,0 +1,2 @@ +import EventLogs from './EventLogs.vue'; +export default EventLogs; diff --git a/src/views/Overview/OverviewEvents.vue b/src/views/Overview/OverviewEvents.vue index 885db07c..b8f876ac 100644 --- a/src/views/Overview/OverviewEvents.vue +++ b/src/views/Overview/OverviewEvents.vue @@ -2,7 +2,7 @@
diff --git a/tests/unit/__snapshots__/AppHeader.spec.js.snap b/tests/unit/__snapshots__/AppHeader.spec.js.snap index 02d99b16..b472bcbc 100644 --- a/tests/unit/__snapshots__/AppHeader.spec.js.snap +++ b/tests/unit/__snapshots__/AppHeader.spec.js.snap @@ -68,7 +68,7 @@ exports[`AppHeader.vue should render correctly 1`] = ` > @@ -43,6 +43,84 @@ exports[`AppNavigation.vue should render correctly 1`] = ` + +