Skip to content

Commit 69ef8b6

Browse files
authored
Fix : Homogenize diagram opening behavior (#3141)
Signed-off-by: Ayoub LABIDI <[email protected]>
1 parent 08faaae commit 69ef8b6

14 files changed

+124
-42
lines changed

src/components/diagrams/diagram-common.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ export const MAX_WIDTH_SUBSTATION = 1200;
2020
export const MAX_HEIGHT_SUBSTATION = 700;
2121
export const MAX_WIDTH_NETWORK_AREA_DIAGRAM = 1200;
2222
export const MAX_HEIGHT_NETWORK_AREA_DIAGRAM = 650;
23-
export const MAX_NUMBER_OF_NAD_DIAGRAMS = 3;
2423

2524
// Array of zoom levels used to determine level-of-detail rendering by applying in the network-viewer the
2625
// corresponding css class 'nad-zoom-{level}' to the NAD's SVG.

src/components/diagrams/diagram-grid-header.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,13 @@ const styles = {
3737
interface DiagramGridHeaderProps {
3838
onLoad: (elementUuid: UUID, elementType: ElementType, elementName: string) => void;
3939
onSearch: (element: EquipmentInfos) => void;
40+
onOpenNetworkAreaDiagram?: (elementId?: string) => void;
4041
onLayoutSave: () => void;
4142
onMap?: () => void;
4243
}
4344

4445
export const DiagramGridHeader = (props: DiagramGridHeaderProps) => {
45-
const { onLoad, onSearch, onMap, onLayoutSave } = props;
46+
const { onLoad, onSearch, onOpenNetworkAreaDiagram, onMap, onLayoutSave } = props;
4647

4748
const intl = useIntl();
4849

@@ -102,6 +103,7 @@ export const DiagramGridHeader = (props: DiagramGridHeaderProps) => {
102103
{!mapOpen && (
103104
<TopBarEquipmentSearchDialog
104105
showVoltageLevelDiagram={onSearch}
106+
onOpenNetworkAreaDiagram={onOpenNetworkAreaDiagram}
105107
isDialogSearchOpen={isDialogSearchOpen}
106108
setIsDialogSearchOpen={setIsDialogSearchOpen}
107109
disablCenterSubstation={true}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
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 { UUID } from 'crypto';
9+
import { Diagram, DiagramType } from './diagram.type';
10+
11+
export const MAX_NUMBER_OF_NAD_DIAGRAMS = 3;
12+
13+
export const countOpenedNadDiagrams = (diagrams: Record<UUID, Diagram>) => {
14+
return Object.values(diagrams).filter((diagram) => diagram?.type === DiagramType.NETWORK_AREA_DIAGRAM).length;
15+
};

src/components/diagrams/diagram-grid-layout.tsx

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { Layout, Layouts, Responsive, WidthProvider } from 'react-grid-layout';
1010
import { useDiagramModel } from './hooks/use-diagram-model';
1111
import { Diagram, DiagramParams, DiagramType } from './diagram.type';
1212
import { Box, useTheme } from '@mui/material';
13-
import { ElementType, EquipmentInfos, EquipmentType, useDebounce } from '@gridsuite/commons-ui';
13+
import { ElementType, EquipmentInfos, EquipmentType, useDebounce, useSnackMessage } from '@gridsuite/commons-ui';
1414
import { UUID } from 'crypto';
1515
import { useDiagramsGridLayoutInitialization } from './hooks/use-diagrams-grid-layout-initialization';
1616
import { v4 } from 'uuid';
@@ -21,6 +21,7 @@ import MapCard from './map-card';
2121
import { BLINK_LENGTH_MS } from './card-header';
2222
import CustomResizeHandle from './custom-resize-handle';
2323
import { useSaveDiagramLayout } from './hooks/use-save-diagram-layout';
24+
import { countOpenedNadDiagrams, MAX_NUMBER_OF_NAD_DIAGRAMS } from './diagram-grid-layout-utils';
2425

2526
const styles = {
2627
container: {
@@ -147,16 +148,19 @@ const initialLayouts: Layouts = generateInitialLayouts();
147148
interface DiagramGridLayoutProps {
148149
studyUuid: UUID;
149150
showInSpreadsheet: (equipment: { equipmentId: string | null; equipmentType: EquipmentType | null }) => void;
151+
showGrid: () => void;
150152
visible: boolean;
151153
}
152154

153-
function DiagramGridLayout({ studyUuid, showInSpreadsheet, visible }: Readonly<DiagramGridLayoutProps>) {
155+
function DiagramGridLayout({ studyUuid, showInSpreadsheet, showGrid, visible }: Readonly<DiagramGridLayoutProps>) {
154156
const theme = useTheme();
155157
const [layouts, setLayouts] = useState<Layouts>(initialLayouts);
156158
const [blinkingDiagrams, setBlinkingDiagrams] = useState<UUID[]>([]);
157159
const currentBreakpointRef = useRef<string>('lg');
158160
const lastModifiedBreakpointRef = useRef<string>('lg'); // Track the last modified breakpoint
159161

162+
const { snackInfo } = useSnackMessage();
163+
160164
// Blinking diagrams management
161165
const stopDiagramBlinking = useCallback((diagramUuid: UUID) => {
162166
setBlinkingDiagrams((old_blinking_diagrams) => old_blinking_diagrams.filter((uuid) => uuid !== diagramUuid));
@@ -253,10 +257,11 @@ function DiagramGridLayout({ studyUuid, showInSpreadsheet, visible }: Readonly<D
253257
}
254258

255259
if (diagram) {
260+
showGrid();
256261
createDiagram(diagram);
257262
}
258263
},
259-
[createDiagram]
264+
[createDiagram, showGrid]
260265
);
261266

262267
const handleLoadNad = useCallback(
@@ -380,6 +385,21 @@ function DiagramGridLayout({ studyUuid, showInSpreadsheet, visible }: Readonly<D
380385
}, []);
381386
useDiagramsGridLayoutInitialization({ onLoadDiagramLayout });
382387

388+
const onOpenNetworkAreaDiagram = useCallback(
389+
(elementId?: string) => {
390+
if (countOpenedNadDiagrams(diagrams) < MAX_NUMBER_OF_NAD_DIAGRAMS) {
391+
if (!elementId) {
392+
return;
393+
}
394+
snackInfo({
395+
messageId: 'NADOpenedInTheGrid',
396+
messageValues: { elementId: elementId },
397+
});
398+
}
399+
},
400+
[diagrams, snackInfo]
401+
);
402+
383403
const handleGridLayoutSave = useSaveDiagramLayout({ layouts, diagrams });
384404

385405
// Debounce the layout save function to avoid excessive calls
@@ -390,6 +410,7 @@ function DiagramGridLayout({ studyUuid, showInSpreadsheet, visible }: Readonly<D
390410
<DiagramGridHeader
391411
onLoad={handleLoadNad}
392412
onSearch={showVoltageLevelDiagram}
413+
onOpenNetworkAreaDiagram={showGrid}
393414
onMap={!isMapCardAdded() ? onAddMapCard : undefined}
394415
onLayoutSave={debouncedGridLayoutSave}
395416
/>
@@ -451,6 +472,7 @@ function DiagramGridLayout({ studyUuid, showInSpreadsheet, visible }: Readonly<D
451472
onClose={handleRemoveMapCard}
452473
errorMessage={globalError}
453474
showInSpreadsheet={showInSpreadsheet}
475+
onOpenNetworkAreaDiagram={onOpenNetworkAreaDiagram}
454476
/>
455477
)}
456478
</ResponsiveGridLayout>

src/components/diagrams/hooks/use-diagram-model.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,10 @@ import { useIntl } from 'react-intl';
2929
import { useDiagramTitle } from './use-diagram-title';
3030
import { useSnackMessage } from '@gridsuite/commons-ui';
3131
import { NodeType } from 'components/graph/tree-node.type';
32-
import { DiagramAdditionalMetadata, MAX_NUMBER_OF_NAD_DIAGRAMS } from '../diagram-common';
32+
import { DiagramAdditionalMetadata } from '../diagram-common';
3333
import { mergePositions } from '../diagram-utils';
3434
import { DiagramMetadata } from '@powsybl/network-viewer';
35+
import { countOpenedNadDiagrams, MAX_NUMBER_OF_NAD_DIAGRAMS } from '../diagram-grid-layout-utils';
3536

3637
type UseDiagramModelProps = {
3738
diagramTypes: DiagramType[];
@@ -354,10 +355,6 @@ export const useDiagramModel = ({ diagramTypes, onAddDiagram, onDiagramAlreadyEx
354355
[diagrams]
355356
);
356357

357-
const countOpenedNadDiagrams = (diagrams: Record<UUID, Diagram>) => {
358-
return Object.values(diagrams).filter((diagram) => diagram?.type === DiagramType.NETWORK_AREA_DIAGRAM).length;
359-
};
360-
361358
const createDiagram = useCallback(
362359
(diagramParams: DiagramParams) => {
363360
if (

src/components/diagrams/map-card.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,19 @@ interface MapCardProps extends ReactGridLayoutCustomChildComponentProps {
4141
onClose: () => void;
4242
errorMessage?: string;
4343
showInSpreadsheet: (equipment: { equipmentId: string | null; equipmentType: EquipmentType | null }) => void;
44+
onOpenNetworkAreaDiagram: (elementId?: string) => void;
4445
key: string; // Required for React Grid Layout to identify the component
4546
}
4647

4748
export const MapCard = forwardRef((props: MapCardProps, ref: Ref<HTMLDivElement>) => {
48-
const { studyUuid, onClose, errorMessage, showInSpreadsheet, ...reactGridLayoutCustomChildComponentProps } = props;
49+
const {
50+
studyUuid,
51+
onClose,
52+
errorMessage,
53+
showInSpreadsheet,
54+
onOpenNetworkAreaDiagram,
55+
...reactGridLayoutCustomChildComponentProps
56+
} = props;
4957
const { style, children, ...otherProps } = reactGridLayoutCustomChildComponentProps;
5058
const [isHover, setIsHover] = useState(false);
5159
const intl = useIntl();
@@ -132,13 +140,13 @@ export const MapCard = forwardRef((props: MapCardProps, ref: Ref<HTMLDivElement>
132140
lineFullPath={networkVisuParams.mapParameters.lineFullPath}
133141
lineParallelPath={networkVisuParams.mapParameters.lineParallelPath}
134142
lineFlowMode={networkVisuParams.mapParameters.lineFlowMode as LineFlowMode}
135-
openVoltageLevel={() => {}}
136143
currentNode={currentNode}
137144
currentRootNetworkUuid={currentRootNetworkUuid}
138145
showInSpreadsheet={(eq) => {
139146
handleCloseMap();
140147
showInSpreadsheet(eq);
141148
}}
149+
onOpenNetworkAreaDiagram={onOpenNetworkAreaDiagram}
142150
onPolygonChanged={() => {}}
143151
onElementCreated={handleCloseMap}
144152
></NetworkMapTab>

src/components/map-viewer.jsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,14 @@ const styles = {
2828
panelContent: { display: 'flex', flexGrow: 1, height: '100%' },
2929
};
3030

31-
const MapViewer = ({ studyUuid, currentRootNetworkUuid, tableEquipment, onTableEquipementChanged, onChangeTab }) => {
31+
const MapViewer = ({
32+
studyUuid,
33+
currentRootNetworkUuid,
34+
tableEquipment,
35+
onTableEquipementChanged,
36+
onChangeTab,
37+
showGrid,
38+
}) => {
3239
const theme = useTheme();
3340
const studyDisplayMode = useSelector((state) => state.studyDisplayMode);
3441
const isNetworkModificationTreeModelUpToDate = useSelector((state) => state.isNetworkModificationTreeModelUpToDate);
@@ -149,6 +156,7 @@ const MapViewer = ({ studyUuid, currentRootNetworkUuid, tableEquipment, onTableE
149156
studyUuid={studyUuid}
150157
visible={state.visibility.grid}
151158
showInSpreadsheet={showInSpreadsheet}
159+
showGrid={showGrid}
152160
/>
153161
</Box>
154162
</Panel>

src/components/network/network-map-tab.tsx

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ import { AppState } from 'redux/reducer';
6565
import { isReactFlowRootNodeData } from 'redux/utils';
6666
import { isLoadflowResultNotification, isRootNetworksUpdatedNotification } from 'types/notification-types';
6767
import { CurrentTreeNode } from 'components/graph/tree-node.type';
68-
import { FormattedMessage } from 'react-intl';
68+
import { FormattedMessage, useIntl } from 'react-intl';
6969
import { Search } from '@mui/icons-material';
7070
import { TopBarEquipmentSearchDialog } from 'components/top-bar-equipment-seach-dialog/top-bar-equipment-search-dialog';
7171
import { DiagramType } from 'components/diagrams/diagram.type';
@@ -129,7 +129,7 @@ type NetworkMapTabProps = {
129129
lineFullPath: boolean;
130130
lineParallelPath: boolean;
131131
lineFlowMode: LineFlowMode;
132-
openVoltageLevel: (idVoltageLevel: string) => void;
132+
onOpenNetworkAreaDiagram: (elementId?: string) => void;
133133
showInSpreadsheet: (equipment: { equipmentType: EquipmentType; equipmentId: string }) => void;
134134
onPolygonChanged: (polygoneFeature: any) => void;
135135
onElementCreated?: () => void;
@@ -146,7 +146,7 @@ export const NetworkMapTab = ({
146146
lineParallelPath,
147147
lineFlowMode,
148148
/* callbacks */
149-
openVoltageLevel,
149+
onOpenNetworkAreaDiagram,
150150
showInSpreadsheet,
151151
onPolygonChanged,
152152
onElementCreated,
@@ -188,6 +188,7 @@ export const NetworkMapTab = ({
188188

189189
const lineFullPathRef = useRef<boolean>();
190190
const [isDialogSearchOpen, setIsDialogSearchOpen] = useState(false);
191+
const intl = useIntl();
191192

192193
/*
193194
This Set stores the geo data that are collected from the server AFTER the initialization.
@@ -1059,14 +1060,25 @@ export const NetworkMapTab = ({
10591060
leaveDrawingMode();
10601061
}, [leaveDrawingMode, onElementCreated]);
10611062

1063+
const openSLDInTheGrid = useCallback(
1064+
(equipmentId: string, diagramType: DiagramType) => {
1065+
dispatch(openDiagram(equipmentId, diagramType));
1066+
snackInfo({
1067+
messageId: 'SLDOpenedInTheGrid',
1068+
messageValues: { diagramType: intl.formatMessage({ id: diagramType }), equipmentId },
1069+
});
1070+
},
1071+
[dispatch, intl, snackInfo]
1072+
);
1073+
10621074
const handleOpenVoltageLevel = useCallback(
10631075
(vlId: string) => {
10641076
// don't open the sld if the drawing mode is activated
10651077
if (!isInDrawingMode) {
1066-
openVoltageLevel(vlId);
1078+
openSLDInTheGrid(vlId, DiagramType.VOLTAGE_LEVEL);
10671079
}
10681080
},
1069-
[isInDrawingMode, openVoltageLevel]
1081+
[isInDrawingMode, openSLDInTheGrid]
10701082
);
10711083

10721084
const getHvdcExtendedEquipmentType = (hvdcType: string): ExtendedEquipmentType | null => {
@@ -1253,13 +1265,9 @@ export const NetworkMapTab = ({
12531265
return;
12541266
}
12551267
const diagramType = isSubstation ? DiagramType.SUBSTATION : DiagramType.VOLTAGE_LEVEL;
1256-
dispatch(openDiagram(id, diagramType));
1257-
snackInfo({
1258-
messageId: 'NetworkEquipmentSearchLabelInfo',
1259-
messageValues: { equipmentId: id },
1260-
});
1268+
openSLDInTheGrid(id, diagramType);
12611269
},
1262-
[dispatch, snackInfo]
1270+
[openSLDInTheGrid]
12631271
);
12641272

12651273
return (
@@ -1278,6 +1286,7 @@ export const NetworkMapTab = ({
12781286
{studyUuid && (
12791287
<TopBarEquipmentSearchDialog
12801288
showVoltageLevelDiagram={showVoltageLevelDiagram}
1289+
onOpenNetworkAreaDiagram={onOpenNetworkAreaDiagram}
12811290
isDialogSearchOpen={isDialogSearchOpen}
12821291
setIsDialogSearchOpen={setIsDialogSearchOpen}
12831292
/>

src/components/study-pane.jsx

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@ import MapViewer from './map-viewer';
1818
import { StudyView } from './utils/utils';
1919
import { DiagramType } from './diagrams/diagram.type';
2020
import HorizontalToolbar from './horizontal-toolbar';
21-
import { openDiagram } from '../redux/actions.js';
22-
import { useDispatch } from 'react-redux';
21+
import { openDiagram, setToggleOptions } from '../redux/actions.js';
22+
import { useDispatch, useSelector } from 'react-redux';
23+
import { StudyDisplayMode } from './network-modification.type';
2324

2425
const styles = {
2526
tabsContainer: (theme) => {
@@ -54,22 +55,32 @@ const StudyPane = ({
5455
onChangeTab,
5556
...props
5657
}) => {
58+
const toggleOptions = useSelector((state) => state.toggleOptions);
5759
const dispatch = useDispatch();
5860
const [tableEquipment, setTableEquipment] = useState({
5961
id: null,
6062
type: null,
6163
});
6264

6365
const disabled = !isNodeBuilt(currentNode);
66+
const showGrid = useCallback(() => {
67+
// switch to tree view
68+
onChangeTab(0);
69+
// toggle diagram grid layout
70+
if (!toggleOptions.includes(StudyDisplayMode.DIAGRAM_GRID_LAYOUT)) {
71+
dispatch(setToggleOptions([...toggleOptions, StudyDisplayMode.DIAGRAM_GRID_LAYOUT]));
72+
}
73+
}, [dispatch, onChangeTab, toggleOptions]);
74+
6475
const openVoltageLevelDiagram = useCallback(
6576
(equipmentId, diagramType = DiagramType.VOLTAGE_LEVEL) => {
6677
// TODO code factorization for displaying a VL via a hook
6778
if (equipmentId) {
68-
onChangeTab(0); // switch to map view
79+
showGrid();
6980
dispatch(openDiagram(equipmentId, diagramType));
7081
}
7182
},
72-
[dispatch, onChangeTab]
83+
[dispatch, showGrid]
7384
);
7485

7586
const unsetTableEquipment = useCallback(() => {
@@ -95,6 +106,7 @@ const StudyPane = ({
95106
tableEquipment={tableEquipment}
96107
onTableEquipementChanged={handleTableEquipmentChanged}
97108
onChangeTab={onChangeTab}
109+
showGrid={showGrid}
98110
></MapViewer>
99111
</div>
100112
{/* using a key in these TabPanelLazy because we can change the nodeUuid in this component */}

src/components/top-bar-equipment-seach-dialog/custom-suffix-renderer.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@ import { DiagramType } from '../diagrams/diagram.type';
1919
interface CustomSuffixRendererProps extends TagRendererProps {
2020
onClose?: () => void;
2121
disablCenterSubstation: boolean;
22+
onOpenNetworkAreaDiagram?: (elementId?: string) => void;
2223
}
2324

2425
export const CustomSuffixRenderer: FunctionComponent<CustomSuffixRendererProps> = ({
2526
element,
2627
onClose,
2728
disablCenterSubstation,
29+
onOpenNetworkAreaDiagram,
2830
...tagRendererProps
2931
}) => {
3032
const dispatch = useDispatch<AppDispatch>();
@@ -64,8 +66,9 @@ export const CustomSuffixRenderer: FunctionComponent<CustomSuffixRendererProps>
6466
dispatch(openDiagram(element.id, DiagramType.NETWORK_AREA_DIAGRAM));
6567
onClose?.();
6668
e.stopPropagation();
69+
onOpenNetworkAreaDiagram?.(element.id);
6770
},
68-
[dispatch, element.id, onClose]
71+
[dispatch, element.id, onClose, onOpenNetworkAreaDiagram]
6972
);
7073

7174
if (

0 commit comments

Comments
 (0)