Skip to content
Open
8 changes: 7 additions & 1 deletion src/components/grid-layout/dialog/map-dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type { UUID } from 'node:crypto';
import { EquipmentType, LineFlowMode, NetworkVisualizationParameters, useStateBoolean } from '@gridsuite/commons-ui';
import { useDispatch, useSelector } from 'react-redux';
import { AppState } from 'redux/reducer';
import { resetMapEquipment, setMapDataLoading, setOpenMap, setReloadMapNeeded } from 'redux/actions';
import { resetMapEquipment, setMapDataLoading, setMapState, setOpenMap, setReloadMapNeeded } from 'redux/actions';
import NetworkMapPanel, { NetworkMapPanelRef } from 'components/network/network-map-panel';
import { Close } from '@mui/icons-material';
import { FormattedMessage } from 'react-intl';
Expand Down Expand Up @@ -61,6 +61,12 @@ export const MapDialog = (props: MapDialogProps) => {
return; // Do not close the map but only the drawing mode
}
}
if (networkMapPanelRef.current) {
const currentMapState = networkMapPanelRef.current.getCurrentMapState?.();
if (currentMapState) {
dispatch(setMapState(currentMapState));
}
}
dispatch(setOpenMap(false));
dispatch(resetMapEquipment());
dispatch(setMapDataLoading(false));
Expand Down
58 changes: 47 additions & 11 deletions src/components/network/network-map-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

import type { Writable } from 'type-fest';
import {
type Coordinate,
DRAW_EVENT,
Expand Down Expand Up @@ -57,7 +56,7 @@ import RunningStatus from 'components/utils/running-status';
import { useGetStudyImpacts } from 'hooks/use-get-study-impacts';
import { ROOT_NODE_LABEL } from '../../constants/node.constant';
import type { UUID } from 'node:crypto';
import { AppState } from 'redux/reducer';
import { AppState, MapState } from 'redux/reducer';
import { isReactFlowRootNodeData } from 'redux/utils';
import { isLoadflowResultNotification, isRootNetworksUpdatedNotification } from 'types/notification-types';
import { CurrentTreeNode } from 'components/graph/tree-node.type';
Expand Down Expand Up @@ -133,6 +132,7 @@ type NetworkMapPanelProps = {

export type NetworkMapPanelRef = {
leaveDrawingMode: () => void;
getCurrentMapState: () => MapState;
};

export const NetworkMapPanel = forwardRef<NetworkMapPanelRef, NetworkMapPanelProps>(
Expand Down Expand Up @@ -167,6 +167,7 @@ export const NetworkMapPanel = forwardRef<NetworkMapPanelRef, NetworkMapPanelPro
const isNetworkModificationTreeUpToDate = useSelector(
(state: AppState) => state.isNetworkModificationTreeModelUpToDate
);
const mapState = useSelector((state: AppState) => state.mapState);
const theme = useTheme();
const { snackInfo } = useSnackMessage();

Expand All @@ -183,7 +184,9 @@ export const NetworkMapPanel = forwardRef<NetworkMapPanelRef, NetworkMapPanelPro

const { snackError } = useSnackMessage();

const [filteredNominalVoltages, setFilteredNominalVoltages] = useState<number[]>();
const [filteredNominalVoltages, setFilteredNominalVoltages] = useState<number[]>(
mapState?.filteredNominalVoltages ?? []
);
const [geoData, setGeoData] = useState<GeoData>();
const geoDataRef = useRef<any>();

Expand Down Expand Up @@ -704,13 +707,21 @@ export const NetworkMapPanel = forwardRef<NetworkMapPanelRef, NetworkMapPanelPro
});
return Promise.all([updatedSubstations, updatedLines, updatedTieLines, updatedHvdcLines]).finally(
() => {
if (isFullReload) {
if (isFullReload && !mapState?.filteredNominalVoltages) {
// Only reset filters if no saved state exists
handleFilteredNominalVoltagesChange(mapEquipments.getNominalVoltages());
}
}
);
},
[currentNode, handleFilteredNominalVoltagesChange, currentRootNetworkUuid, mapEquipments, studyUuid]
[
currentNode,
handleFilteredNominalVoltagesChange,
currentRootNetworkUuid,
mapEquipments,
studyUuid,
mapState?.filteredNominalVoltages,
]
);

const updateMapEquipments = useCallback(
Expand Down Expand Up @@ -913,7 +924,8 @@ export const NetworkMapPanel = forwardRef<NetworkMapPanelRef, NetworkMapPanelPro
// we check if equipments are done initializing because they are checked to fetch accurate missing geo data
if (isRootNodeGeoDataLoaded && isMapEquipmentsInitialized && !isInitialized) {
// when root networks are changed, mapEquipments are recreated. when they are done recreating, the map is zoomed around the new network
if (mapEquipments) {
if (mapEquipments && !mapState?.filteredNominalVoltages) {
// Only initialize filters if no saved state exists
handleFilteredNominalVoltagesChange(mapEquipments.getNominalVoltages());
}
if (currentNodeRef.current && !isReactFlowRootNodeData(currentNodeRef.current)) {
Expand All @@ -932,6 +944,7 @@ export const NetworkMapPanel = forwardRef<NetworkMapPanelRef, NetworkMapPanelPro
isInitialized,
loadMissingGeoData,
dispatch,
mapState?.filteredNominalVoltages,
]);

// Reload geo data (if necessary) when we switch on full path
Expand Down Expand Up @@ -1017,12 +1030,28 @@ export const NetworkMapPanel = forwardRef<NetworkMapPanelRef, NetworkMapPanelPro
setShouldOpenSelectionCreationPanel(false);
}, [isInDrawingMode]);

const getCurrentMapState = useCallback((): MapState => {
const currentMapState = networkMapRef.current?.getCurrentViewState();

const center: [number, number] = [
currentMapState?.center.lng ?? INITIAL_POSITION[0],
currentMapState?.center.lat ?? INITIAL_POSITION[1],
];

return {
zoom: currentMapState?.zoom ?? INITIAL_ZOOM,
center,
filteredNominalVoltages: filteredNominalVoltages,
};
}, [filteredNominalVoltages]);

useImperativeHandle(
ref,
() => ({
leaveDrawingMode,
getCurrentMapState,
}),
[leaveDrawingMode]
[leaveDrawingMode, getCurrentMapState]
);

const handleDrawingModeChange = useCallback(
Expand Down Expand Up @@ -1121,8 +1150,9 @@ export const NetworkMapPanel = forwardRef<NetworkMapPanelRef, NetworkMapPanelPro
filteredNominalVoltages={filteredNominalVoltages}
labelsZoomThreshold={LABELS_ZOOM_THRESHOLD}
arrowsZoomThreshold={ARROWS_ZOOM_THRESHOLD}
initialPosition={INITIAL_POSITION as Writable<typeof INITIAL_POSITION>}
initialZoom={INITIAL_ZOOM}
// Use saved state for initial position and zoom
initialPosition={mapState?.center}
initialZoom={mapState?.zoom}
lineFullPath={lineFullPath}
lineParallelPath={lineParallelPath}
lineFlowMode={lineFlowMode}
Expand Down Expand Up @@ -1222,11 +1252,17 @@ export const NetworkMapPanel = forwardRef<NetworkMapPanelRef, NetworkMapPanelPro
if (
nominalVoltagesFromMapEquipments !== undefined &&
nominalVoltagesFromMapEquipments.length > 0 &&
filteredNominalVoltages === undefined
filteredNominalVoltages.length === 0 &&
!mapState?.filteredNominalVoltages // Only initialize if no saved map state exists
) {
handleFilteredNominalVoltagesChange(nominalVoltagesFromMapEquipments);
}
}, [filteredNominalVoltages, handleFilteredNominalVoltagesChange, nominalVoltagesFromMapEquipments]);
}, [
filteredNominalVoltages,
handleFilteredNominalVoltagesChange,
nominalVoltagesFromMapEquipments,
mapState?.filteredNominalVoltages,
]);

function renderNominalVoltageFilter() {
return (
Expand Down
13 changes: 13 additions & 0 deletions src/redux/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import type {
ComputingStatusParameters,
DiagramGridLayoutConfig,
GlobalFilterSpreadsheetState,
MapState,
NodeSelectionForCopy,
OneBusShortCircuitAnalysisDiagram,
SpreadsheetFilterState,
Expand Down Expand Up @@ -1550,3 +1551,15 @@ export function updateNodeAliases(nodeAliases: NodeAlias[]): UpdateNodeAliasesAc
nodeAliases,
};
}

export const SET_MAP_STATE = 'SET_MAP_STATE';
export type SetMapStateAction = Readonly<Action<typeof SET_MAP_STATE>> & {
mapState: Partial<MapState>;
};

export function setMapState(mapState: Partial<MapState>): SetMapStateAction {
return {
type: SET_MAP_STATE,
mapState,
};
}
17 changes: 17 additions & 0 deletions src/redux/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,8 @@ import {
type UpdateTableDefinitionAction,
USE_NAME,
type UseNameAction,
SetMapStateAction,
SET_MAP_STATE,
} from './actions';
import {
getLocalStorageComputedLanguage,
Expand Down Expand Up @@ -560,6 +562,12 @@ export interface DiagramGridLayoutConfig {

export type LogsPaginationState = Record<string, LogsPaginationConfig>;

export interface MapState {
zoom?: number;
center?: [number, number];
filteredNominalVoltages?: number[];
}

export interface AppState extends CommonStoreState, AppConfigState {
signInCallbackError: Error | null;
authenticationRouterError: AuthenticationRouterErrorState | null;
Expand Down Expand Up @@ -651,6 +659,7 @@ export interface AppState extends CommonStoreState, AppConfigState {
toggleOptions: StudyDisplayMode[];
highlightedModificationUuid: UUID | null;
mapOpen: boolean;
mapState: MapState;
}

export type LogsFilterState = Record<string, FilterConfig[]>;
Expand Down Expand Up @@ -776,6 +785,7 @@ const initialState: AppState = {
freezeMapUpdates: false,
isMapEquipmentsInitialized: false,
networkAreaDiagramDepth: 0,
mapState: {},
spreadsheetNetwork: { ...initialSpreadsheetNetworkState },
globalFilterSpreadsheetState: {},
spreadsheetOptionalLoadingParameters: {
Expand Down Expand Up @@ -1977,6 +1987,13 @@ export const reducer = createReducer(initialState, (builder) => {
builder.addCase(UPDATE_NODE_ALIASES, (state, action: UpdateNodeAliasesAction) => {
state.nodeAliases = action.nodeAliases;
});

builder.addCase(SET_MAP_STATE, (state, action: SetMapStateAction) => {
state.mapState = {
...state.mapState,
...action.mapState,
};
});
});

function updateSubstationAfterVLDeletion(
Expand Down
Loading