|
| 1 | +/* |
| 2 | + * Copyright (c) 2025, RTE (http://www.rte-france.com) |
| 3 | + * This Source Code Form is subject to the terms of the Mozilla Public |
| 4 | + * License, v. 2.0. If a copy of the MPL was not distributed with this |
| 5 | + * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
| 6 | + */ |
| 7 | + |
| 8 | +import { useCallback } from 'react'; |
| 9 | +import type { UUID } from 'crypto'; |
| 10 | +import { DeletedEquipment, isStudyNotification, type NetworkImpactsInfos } from '../../../types/notification-types'; |
| 11 | +import { isSpreadsheetEquipmentType, SpreadsheetEquipmentType } from '../types/spreadsheet.type'; |
| 12 | +import { |
| 13 | + deleteEquipments, |
| 14 | + type EquipmentToDelete, |
| 15 | + resetEquipments, |
| 16 | + resetEquipmentsByTypes, |
| 17 | + updateEquipments, |
| 18 | +} from '../../../redux/actions'; |
| 19 | +import { fetchAllEquipments } from '../../../services/study/network-map'; |
| 20 | +import { useDispatch, useSelector } from 'react-redux'; |
| 21 | +import { AppState } from 'redux/reducer'; |
| 22 | +import { NotificationsUrlKeys, useNotificationsListener } from '@gridsuite/commons-ui'; |
| 23 | +import { NodeAlias } from '../types/node-alias.type'; |
| 24 | +import { useSpreadsheetNodes } from './use-spreadsheet-nodes'; |
| 25 | + |
| 26 | +const SPREADSHEET_EQUIPMENTS_LISTENER_ID = 'spreadsheet-equipments-listener'; |
| 27 | + |
| 28 | +export function useUpdateEquipmentsOnNotification(nodeAliases: NodeAlias[] | undefined) { |
| 29 | + const dispatch = useDispatch(); |
| 30 | + const allEquipments = useSelector((state: AppState) => state.spreadsheetNetwork); |
| 31 | + const studyUuid = useSelector((state: AppState) => state.studyUuid); |
| 32 | + const currentRootNetworkUuid = useSelector((state: AppState) => state.currentRootNetworkUuid); |
| 33 | + |
| 34 | + const { builtNodesIds } = useSpreadsheetNodes(nodeAliases); |
| 35 | + |
| 36 | + const updateEquipmentsLocal = useCallback( |
| 37 | + ( |
| 38 | + nodeUuid: UUID, |
| 39 | + impactedSubstationsIds: UUID[], |
| 40 | + deletedEquipments: DeletedEquipment[], |
| 41 | + impactedElementTypes: string[] |
| 42 | + ) => { |
| 43 | + // Handle updates and resets based on impacted element types |
| 44 | + if (impactedElementTypes.length > 0) { |
| 45 | + if (impactedElementTypes.includes(SpreadsheetEquipmentType.SUBSTATION)) { |
| 46 | + dispatch(resetEquipments()); |
| 47 | + return; |
| 48 | + } |
| 49 | + const impactedSpreadsheetEquipmentsTypes = impactedElementTypes.filter((type) => |
| 50 | + Object.keys(allEquipments).includes(type) |
| 51 | + ); |
| 52 | + if (impactedSpreadsheetEquipmentsTypes.length > 0) { |
| 53 | + dispatch( |
| 54 | + resetEquipmentsByTypes(impactedSpreadsheetEquipmentsTypes.filter(isSpreadsheetEquipmentType)) |
| 55 | + ); |
| 56 | + } |
| 57 | + } |
| 58 | + |
| 59 | + if (impactedSubstationsIds.length > 0 && studyUuid && currentRootNetworkUuid) { |
| 60 | + fetchAllEquipments(studyUuid, nodeUuid, currentRootNetworkUuid, impactedSubstationsIds).then( |
| 61 | + (values) => { |
| 62 | + dispatch(updateEquipments(values, nodeUuid)); |
| 63 | + } |
| 64 | + ); |
| 65 | + } |
| 66 | + |
| 67 | + if (deletedEquipments.length > 0) { |
| 68 | + const equipmentsToDelete = deletedEquipments |
| 69 | + .filter(({ equipmentType, equipmentId }) => equipmentType && equipmentId) |
| 70 | + .map(({ equipmentType, equipmentId }) => { |
| 71 | + console.info( |
| 72 | + 'removing equipment with id=', |
| 73 | + equipmentId, |
| 74 | + ' and type=', |
| 75 | + equipmentType, |
| 76 | + ' from the network' |
| 77 | + ); |
| 78 | + return { equipmentType, equipmentId }; |
| 79 | + }); |
| 80 | + |
| 81 | + if (equipmentsToDelete.length > 0) { |
| 82 | + const equipmentsToDeleteArray = equipmentsToDelete |
| 83 | + .filter((e) => isSpreadsheetEquipmentType(e.equipmentType)) |
| 84 | + .map<EquipmentToDelete>((equipment) => ({ |
| 85 | + equipmentType: equipment.equipmentType as unknown as SpreadsheetEquipmentType, |
| 86 | + equipmentId: equipment.equipmentId, |
| 87 | + })); |
| 88 | + dispatch(deleteEquipments(equipmentsToDeleteArray, nodeUuid)); |
| 89 | + } |
| 90 | + } |
| 91 | + }, |
| 92 | + [studyUuid, currentRootNetworkUuid, dispatch, allEquipments] |
| 93 | + ); |
| 94 | + |
| 95 | + const listenerUpdateEquipmentsLocal = useCallback( |
| 96 | + (event: MessageEvent) => { |
| 97 | + const eventData = JSON.parse(event.data); |
| 98 | + if (isStudyNotification(eventData)) { |
| 99 | + const eventStudyUuid = eventData.headers.studyUuid; |
| 100 | + const eventNodeUuid = eventData.headers.node; |
| 101 | + const eventRootNetworkUuid = eventData.headers.rootNetworkUuid; |
| 102 | + if ( |
| 103 | + studyUuid === eventStudyUuid && |
| 104 | + currentRootNetworkUuid === eventRootNetworkUuid && |
| 105 | + builtNodesIds.has(eventNodeUuid) |
| 106 | + ) { |
| 107 | + const payload = JSON.parse(eventData.payload) as NetworkImpactsInfos; |
| 108 | + console.log(`notif impacts: ${JSON.stringify(payload)}`); |
| 109 | + const impactedSubstationsIds = payload.impactedSubstationsIds; |
| 110 | + const deletedEquipments = payload.deletedEquipments; |
| 111 | + const impactedElementTypes = payload.impactedElementTypes ?? []; |
| 112 | + updateEquipmentsLocal( |
| 113 | + eventNodeUuid, |
| 114 | + impactedSubstationsIds, |
| 115 | + deletedEquipments, |
| 116 | + impactedElementTypes |
| 117 | + ); |
| 118 | + } |
| 119 | + } |
| 120 | + }, |
| 121 | + [builtNodesIds, currentRootNetworkUuid, studyUuid, updateEquipmentsLocal] |
| 122 | + ); |
| 123 | + |
| 124 | + useNotificationsListener(NotificationsUrlKeys.STUDY, { |
| 125 | + listenerCallbackMessage: listenerUpdateEquipmentsLocal, |
| 126 | + propsId: SPREADSHEET_EQUIPMENTS_LISTENER_ID, |
| 127 | + }); |
| 128 | +} |
0 commit comments