diff --git a/src/components/Composables/useTableSelectableComposable.js b/src/components/Composables/useTableSelectableComposable.js index 6568e5ed27..22c0d78520 100644 --- a/src/components/Composables/useTableSelectableComposable.js +++ b/src/components/Composables/useTableSelectableComposable.js @@ -33,6 +33,26 @@ const useTableSelectableComposable = () => { } } }; + + const toggleSelectRowById = (tableRef, rowIndex, rowSelected, row) => { + if (tableRef && rowIndex !== undefined) { + if (!rowSelected) { + // Find the index of the object to remove + const indexToRemove = selectedRowsList.value.findIndex( + (item) => item.id === row.id, + ); + + // Check if the object exists in the array + if (indexToRemove !== -1) { + tableRef.unselectRow(rowIndex); + // Remove the object from the array + selectedRowsList.value.splice(indexToRemove, 1); + } + } else { + tableRef.selectRow(rowIndex); + } + } + }; const onRowSelected = (selectedRows, totalRowsCount) => { if (selectedRows && totalRowsCount !== undefined) { @@ -65,6 +85,7 @@ const useTableSelectableComposable = () => { return { clearSelectedRows, toggleSelectRow, + toggleSelectRowById, onRowSelected, onChangeHeaderCheckbox, selectedRowsList, @@ -73,4 +94,4 @@ const useTableSelectableComposable = () => { }; }; -export default useTableSelectableComposable; +export default useTableSelectableComposable; \ No newline at end of file diff --git a/src/locales/en-US.json b/src/locales/en-US.json index 4f30a5bd52..72df4c6154 100644 --- a/src/locales/en-US.json +++ b/src/locales/en-US.json @@ -496,6 +496,7 @@ }, "pageDeconfigurationRecords": { "additionalDataUri": "Download additional data", + "alertPowerOff": "Deconfiguration records can be deleted only when the system is powered off.", "clearAll": "Clear all records", "fatal": "Fatal", "manual": "Manual", @@ -517,7 +518,7 @@ "confirmMessage": "Clearing all deconfiguration records will attempt to reconfigure all hardware in the selected node(s). These changes will take effect on the next boot.", "deleteAllMessage": "Are you sure you want to delete all records? This action cannot be undone.", "deleteAllTitle": "Delete all records", - "deleteMessage": "Are you sure you want to delete %{count} records? This action cannot be undone. | Are you sure you want to delete %{count} records? This action cannot be undone.", + "deleteMessage": "Are you sure you want to delete %{count} record? This action cannot be undone. | Are you sure you want to delete %{count} records? This action cannot be undone.", "deleteTitle": "Delete record | Delete records", "goBack": "Go back", "continue": "Continue" diff --git a/src/router/routes.js b/src/router/routes.js index a28d07e953..410de8f9db 100644 --- a/src/router/routes.js +++ b/src/router/routes.js @@ -30,6 +30,7 @@ import HardwareDeconfiguration from '../views/Settings/HardwareDeconfiguration/H import HostConsole from '@/views/Operations/HostConsole'; import HostConsoleConsole from '@/views/Operations/HostConsole/HostConsoleConsole.vue'; import CapacityOnDemand from '../views/ResourceManagement/CapacityOnDemand/CapacityOnDemand.vue'; +import DeconfigurationRecords from '../views/Logs/DeconfigurationRecords/DeconfigurationRecords.vue'; const roles = { administrator: 'Administrator', @@ -188,6 +189,14 @@ export const routes = [ title: i18n.global.t('appPageTitle.hostConsole'), }, }, + { + path: '/logs/deconfiguration-records', + name: 'deconfiguration-records', + component: DeconfigurationRecords, + meta: { + title: i18n.global.t('appPageTitle.deconfigurationRecords'), + }, + }, { path: '/settings/power-restore-policy', name: 'power-restore-policy', diff --git a/src/store/index.js b/src/store/index.js index 43b746bdb5..fbe106dbcb 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -30,6 +30,7 @@ import CertificatesStore from './modules/SecurityAndAccess/CertificatesStore'; import UserManagementStore from './modules/SecurityAndAccess/UserManagementStore'; import PcieTopologyStore from './modules/HardwareStatus/PcieTopologyStore.js'; import HardwareDeconfigurationStore from './modules/Settings/HardwareDeconfigurationStore'; +import DeconfigurationRecordsStore from './modules/Logs/DeconfigurationRecordsStore.js'; // ... (export use other stores) export { EventLogStore, @@ -63,4 +64,5 @@ export { UserManagementStore, PcieTopologyStore, HardwareDeconfigurationStore, + DeconfigurationRecordsStore }; diff --git a/src/store/modules/Logs/DeconfigurationRecordsStore.js b/src/store/modules/Logs/DeconfigurationRecordsStore.js index ddea41f9a0..bfb7e07414 100644 --- a/src/store/modules/Logs/DeconfigurationRecordsStore.js +++ b/src/store/modules/Logs/DeconfigurationRecordsStore.js @@ -1,29 +1,23 @@ import api from '@/store/api'; import i18n from '@/i18n'; +import { defineStore } from 'pinia'; -const DeconfigurationRecordsStore = { - namespaced: true, - state: { +export const DeconfigurationRecordsStore = defineStore('deconfigurationRecordsStore', { + state: () => ({ deconfigRecords: [], - }, + }), getters: { - deconfigRecords: (state) => state.deconfigRecords, - }, - mutations: { - setDeconfigurationRecordInfo: (state, deconfigRecords) => - (state.deconfigRecords = deconfigRecords), + deconfigRecordsGetter: (state) => state.deconfigRecords, }, actions: { - async getDeconfigurationRecordInfo({ commit }) { + async getDeconfigurationRecordInfo() { return await api .get('/redfish/v1/Systems/system/LogServices/HardwareIsolation/Entries') .then(async ({ data: { Members = [] } = {} }) => { const allMembers = await api.all( Members.map(async (member) => { const arrayNumber = Number( - member?.Links?.OriginOfCondition?.['@odata.id'] - .split('/') - .pop(), + member?.Links?.OriginOfCondition?.['@odata.id'].split('/').pop() ); const uri = member?.Links?.OriginOfCondition?.['@odata.id'] .split('/SubProcessors') @@ -44,16 +38,15 @@ const DeconfigurationRecordsStore = { } }); return member; - }), + }) ); const deconfigRecords = await api.all( allMembers.map(async (log) => { const { Id, - Severity, + MessageArgs, Created, - Message, Name, AdditionalDataURI, AdditionalData = AdditionalDataURI @@ -72,7 +65,7 @@ const DeconfigurationRecordsStore = { return { additionalDataUri: AdditionalDataURI, date: new Date(Created), - description: Message, + description: MessageArgs[1], filterByStatus: AdditionalData?.Resolved ? 'Resolved' : 'Unresolved', @@ -82,35 +75,31 @@ const DeconfigurationRecordsStore = { srcDetails: AdditionalData?.EventId, status: AdditionalData?.Resolved, //true or false uri: log['@odata.id'], - severity: Severity, + severity: MessageArgs[0], location: LocationCode, eventID: eventId, + isSelected: false, + toggleDetails: false, }; - }), + }) ); - commit('setDeconfigurationRecordInfo', deconfigRecords); + this.deconfigRecords = deconfigRecords; }) .catch((error) => console.log(error)); }, - async clearAllEntries({ dispatch }, data) { + async clearAllEntries(data) { return await api .post( - '/redfish/v1/Systems/system/LogServices/HardwareIsolation/Actions/LogService.ClearLog', + '/redfish/v1/Systems/system/LogServices/HardwareIsolation/Actions/LogService.ClearLog' ) - .then(() => dispatch('getDeconfigurationRecordInfo')) + .then(() => this.getDeconfigurationRecordInfo()) .then(() => - i18n.tc( - 'pageDeconfigurationRecords.toast.successDelete', - data.length, - ), + i18n.tc('pageDeconfigurationRecords.toast.successDelete', data.length) ) .catch((error) => { console.log(error); throw new Error( - i18n.tc( - 'pageDeconfigurationRecords.toast.errorDelete', - data.length, - ), + i18n.global.t('pageDeconfigurationRecords.toast.errorDelete', data.length) ); }); }, @@ -131,7 +120,7 @@ const DeconfigurationRecordsStore = { const element = document.createElement('a'); element.setAttribute( 'href', - `data:text/plain;charset=utf-8,${encodeURIComponent(pelJsonInfo)}`, + `data:text/plain;charset=utf-8,${encodeURIComponent(pelJsonInfo)}` ); element.setAttribute('download', fileName); element.style.display = 'none'; @@ -141,10 +130,10 @@ const DeconfigurationRecordsStore = { }) .then(() => { const message = [ - i18n.t('pageDeconfigurationRecords.toast.successStartDownload'), + i18n.global.t('pageDeconfigurationRecords.toast.successStartDownload'), { - title: i18n.t( - 'pageDeconfigurationRecords.toast.successStartDownloadTitle', + title: i18n.global.t( + 'pageDeconfigurationRecords.toast.successStartDownloadTitle' ), }, ]; @@ -154,11 +143,26 @@ const DeconfigurationRecordsStore = { .catch((error) => { console.log(error); throw new Error( - i18n.t('pageDeconfigurationRecords.toast.errorStartDownload'), + i18n.global.t('pageDeconfigurationRecords.toast.errorStartDownload') + ); + }); + }, + async deleteRecords(uris = []) { + const promises = uris.map((uri) => api.delete(uri)); + return await api + .all(promises) + .then(() => this.getDeconfigurationRecordInfo()) + .then(() => + i18n.global.t('pageDeconfigurationRecords.toast.successDelete', uris.length) + ) + .catch((error) => { + console.log(error); + throw new Error( + i18n.global.t('pageDeconfigurationRecords.toast.errorDelete', uris.length) ); }); }, }, -}; +}); export default DeconfigurationRecordsStore; diff --git a/src/views/Logs/DeconfigurationRecords/DeconfigurationRecords.vue b/src/views/Logs/DeconfigurationRecords/DeconfigurationRecords.vue index f57280f67a..520e0dfc72 100644 --- a/src/views/Logs/DeconfigurationRecords/DeconfigurationRecords.vue +++ b/src/views/Logs/DeconfigurationRecords/DeconfigurationRecords.vue @@ -1,5 +1,5 @@ - +