diff --git a/src/components/diagrams/diagram-utils.js b/src/components/diagrams/diagram-utils.js index fdee102ed9..7cda5895ce 100644 --- a/src/components/diagrams/diagram-utils.js +++ b/src/components/diagrams/diagram-utils.js @@ -5,6 +5,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +import { DiagramType } from './diagram-common'; + /** * SORTING FUNCTIONS */ @@ -38,6 +40,27 @@ const sortByIndex = (a, b, diagramStates) => { ); }; +/** + * Will build a distinctive identifier to differenciate between network area diagram instances + * @param diagramStates the diagrams array of the redux store + * @param depth the network area diagram's selected depth + * @param initNadWithGeoData config parameter specifying if the nad uses geographical data + * @returns {string} + */ +export const getNadIdentifier = (diagramStates, depth, initNadWithGeoData) => { + const result = + diagramStates + .filter((diagram) => diagram.svgType === DiagramType.NETWORK_AREA_DIAGRAM) + .map((diagram) => diagram.id) + .sort((a, b) => a.localeCompare(b)) + .join(',') + + 'depth' + + depth + + 'geo' + + initNadWithGeoData; + return result; +}; + /** * Create an array sorting function based on two values : first, the alignment, then, the index * @param diagramStates the diagrams array of the redux store diff --git a/src/components/diagrams/networkAreaDiagram/network-area-diagram-content.jsx b/src/components/diagrams/networkAreaDiagram/network-area-diagram-content.jsx index 44dbd8a299..0164b3f9fa 100644 --- a/src/components/diagrams/networkAreaDiagram/network-area-diagram-content.jsx +++ b/src/components/diagrams/networkAreaDiagram/network-area-diagram-content.jsx @@ -5,8 +5,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import React, { useLayoutEffect, useRef } from 'react'; -import { useSelector } from 'react-redux'; +import React, { useLayoutEffect, useRef, useMemo, useCallback } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; import PropTypes from 'prop-types'; import { RunningStatus } from '../../utils/running-status'; import { @@ -21,6 +21,9 @@ import LinearProgress from '@mui/material/LinearProgress'; import Box from '@mui/material/Box'; import { mergeSx } from '../../utils/functions'; import ComputingType from 'components/computing-status/computing-type'; +import { storeNetworkAreaDiagramNodeMovement } from '../../../redux/actions'; +import { PARAM_INIT_NAD_WITH_GEO_DATA } from '../../../utils/config-params.js'; +import { getNadIdentifier } from '../diagram-utils.js'; const dynamicCssRules = [ { @@ -118,10 +121,26 @@ const dynamicCssRules = [ function NetworkAreaDiagramContent(props) { const { diagramSizeSetter } = props; + const dispatch = useDispatch(); const svgRef = useRef(); const diagramViewerRef = useRef(); const currentNode = useSelector((state) => state.currentTreeNode); const loadFlowStatus = useSelector((state) => state.computingStatus[ComputingType.LOAD_FLOW]); + const nadNodeMovements = useSelector((state) => state.nadNodeMovements); + const diagramStates = useSelector((state) => state.diagramStates); + const networkAreaDiagramDepth = useSelector((state) => state.networkAreaDiagramDepth); + const initNadWithGeoData = useSelector((state) => state[PARAM_INIT_NAD_WITH_GEO_DATA]); + + const nadIdentifier = useMemo(() => { + return getNadIdentifier(diagramStates, networkAreaDiagramDepth, initNadWithGeoData); + }, [diagramStates, networkAreaDiagramDepth, initNadWithGeoData]); + + const onMoveNodeCallback = useCallback( + (equipmentId, nodeId, x, y, xOrig, yOrig) => { + dispatch(storeNetworkAreaDiagramNodeMovement(nadIdentifier, equipmentId, x, y)); + }, + [dispatch, nadIdentifier] + ); /** * DIAGRAM CONTENT BUILDING @@ -136,7 +155,7 @@ function NetworkAreaDiagramContent(props) { MIN_HEIGHT, MAX_WIDTH_NETWORK_AREA_DIAGRAM, MAX_HEIGHT_NETWORK_AREA_DIAGRAM, - null, + onMoveNodeCallback, null, null, true, @@ -148,7 +167,7 @@ function NetworkAreaDiagramContent(props) { diagramSizeSetter(props.diagramId, props.svgType, diagramViewer.getWidth(), diagramViewer.getHeight()); // If a previous diagram was loaded and the diagram's size remained the same, we keep - // the user's zoom and scoll state for the current render. + // the user's zoom and scroll state for the current render. if ( diagramViewerRef.current && diagramViewer.getWidth() === diagramViewerRef.current.getWidth() && @@ -157,9 +176,30 @@ function NetworkAreaDiagramContent(props) { diagramViewer.setViewBox(diagramViewerRef.current.getViewBox()); } + // Repositioning the previously moved nodes + if (!props.loadingState) { + const correspondingMovements = nadNodeMovements.filter( + (movement) => movement.nadIdentifier === nadIdentifier + ); + if (correspondingMovements.length > 0) { + correspondingMovements.forEach((movement) => { + diagramViewer.moveNodeToCoordonates(movement.equipmentId, movement.x, movement.y); + }); + } + } diagramViewerRef.current = diagramViewer; } - }, [props.diagramId, props.svgType, props.svg, currentNode, props.loadingState, diagramSizeSetter]); + }, [ + props.diagramId, + props.svgType, + props.svg, + currentNode, + props.loadingState, + diagramSizeSetter, + onMoveNodeCallback, + nadIdentifier, + nadNodeMovements, + ]); /** * RENDER diff --git a/src/redux/actions.ts b/src/redux/actions.ts index 3e867e2c16..c491b28e7c 100644 --- a/src/redux/actions.ts +++ b/src/redux/actions.ts @@ -905,6 +905,30 @@ export function decrementNetworkAreaDiagramDepth(): DecrementNetworkAreaDiagramD }; } +export const STORE_NETWORK_AREA_DIAGRAM_NODE_MOVEMENT = 'STORE_NETWORK_AREA_DIAGRAM_NODE_MOVEMENT'; +export type StoreNetworkAreaDiagramNodeMovementAction = Readonly< + Action +> & { + nadIdentifier: string; + equipmentId: string; + x: number; + y: number; +}; +export function storeNetworkAreaDiagramNodeMovement( + nadIdentifier: string, + equipmentId: string, + x: number, + y: number +): StoreNetworkAreaDiagramNodeMovementAction { + return { + type: STORE_NETWORK_AREA_DIAGRAM_NODE_MOVEMENT, + nadIdentifier: nadIdentifier, + equipmentId: equipmentId, + x: x, + y: y, + }; +} + export const NETWORK_AREA_DIAGRAM_NB_VOLTAGE_LEVELS = 'NETWORK_AREA_DIAGRAM_NB_VOLTAGE_LEVELS'; export type NetworkAreaDiagramNbVoltageLevelsAction = Readonly< Action diff --git a/src/redux/reducer.ts b/src/redux/reducer.ts index e8011b52b9..afa3739249 100644 --- a/src/redux/reducer.ts +++ b/src/redux/reducer.ts @@ -176,6 +176,8 @@ import { SpreadsheetFilterAction, STOP_DIAGRAM_BLINK, StopDiagramBlinkAction, + STORE_NETWORK_AREA_DIAGRAM_NODE_MOVEMENT, + StoreNetworkAreaDiagramNodeMovementAction, STUDY_UPDATED, StudyUpdatedAction, SUBSTATION_LAYOUT, @@ -380,6 +382,13 @@ export type DiagramState = { needsToBlink?: boolean; }; +export type NadNodeMovement = { + nadIdentifier: string; + equipmentId: string; + x: number; + y: number; +}; + export type SelectionForCopy = { sourceStudyUuid: UUID | null; nodeId: string | null; @@ -418,6 +427,7 @@ export interface AppState extends CommonStoreState { networkModificationTreeModel: NetworkModificationTreeModel | null; mapDataLoading: boolean; diagramStates: DiagramState[]; + nadNodeMovements: NadNodeMovement[]; fullScreenDiagram: null | { id: string; svgType?: DiagramType; @@ -538,6 +548,7 @@ const initialState: AppState = { isModificationsInProgress: false, studyDisplayMode: StudyDisplayMode.HYBRID, diagramStates: [], + nadNodeMovements: [], reloadMap: true, isMapEquipmentsInitialized: false, networkAreaDiagramDepth: 0, @@ -1368,6 +1379,27 @@ export const reducer = createReducer(initialState, (builder) => { } }); + builder.addCase( + STORE_NETWORK_AREA_DIAGRAM_NODE_MOVEMENT, + (state, action: StoreNetworkAreaDiagramNodeMovementAction) => { + const correspondingMovement: NadNodeMovement[] = state.nadNodeMovements.filter( + (movement) => + movement.nadIdentifier === action.nadIdentifier && movement.equipmentId === action.equipmentId + ); + if (correspondingMovement.length === 0) { + state.nadNodeMovements.push({ + nadIdentifier: action.nadIdentifier, + equipmentId: action.equipmentId, + x: action.x, + y: action.y, + }); + } else { + correspondingMovement[0].x = action.x; + correspondingMovement[0].y = action.y; + } + } + ); + builder.addCase( NETWORK_AREA_DIAGRAM_NB_VOLTAGE_LEVELS, (state, action: NetworkAreaDiagramNbVoltageLevelsAction) => {