diff --git a/src/components/grid-layout/cards/map/map-card.tsx b/src/components/grid-layout/cards/map/map-card.tsx index 2fa8aac8af..6a49e23e88 100644 --- a/src/components/grid-layout/cards/map/map-card.tsx +++ b/src/components/grid-layout/cards/map/map-card.tsx @@ -4,20 +4,18 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { Box, Dialog, Fab, Theme, useTheme } from '@mui/material'; -import { forwardRef, MouseEventHandler, Ref, TouchEventHandler, useCallback, useRef, useState } from 'react'; -import CustomCardHeader from '../custom-card-header'; +import { Box, Dialog, Fab, Theme } from '@mui/material'; +import { useCallback, useRef } from 'react'; import { UUID } from 'crypto'; -import AlertCustomMessageNode from 'components/utils/alert-custom-message-node'; -import { EquipmentType, LineFlowMode, mergeSx, useStateBoolean } from '@gridsuite/commons-ui'; +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 WorldSvg from 'images/world.svg?react'; import NetworkMapPanel, { NetworkMapPanelRef } from 'components/network/network-map-panel'; import { cardStyles } from '../card-styles'; import { Close } from '@mui/icons-material'; -import { FormattedMessage, useIntl } from 'react-intl'; +import { FormattedMessage } from 'react-intl'; +import { CurrentTreeNode } from 'components/graph/tree-node.type'; const styles = { closeButton: (theme: Theme) => ({ @@ -27,61 +25,32 @@ const styles = { }), }; -interface ReactGridLayoutCustomChildComponentProps { - style?: React.CSSProperties; - className?: string; - onMouseDown?: MouseEventHandler; - onMouseUp?: MouseEventHandler; - onTouchEnd?: TouchEventHandler; - children?: React.ReactNode; -} - -interface MapCardProps extends ReactGridLayoutCustomChildComponentProps { +interface MapCardProps { studyUuid: UUID; onClose: () => void; errorMessage?: string; showInSpreadsheet: (equipment: { equipmentId: string | null; equipmentType: EquipmentType | null }) => void; onOpenNetworkAreaDiagram: (elementId?: string) => void; - key: string; // Required for React Grid Layout to identify the component + currentRootNetworkUuid: UUID; + networkVisuParams: NetworkVisualizationParameters; + currentNode: CurrentTreeNode; } -export const MapCard = forwardRef((props: MapCardProps, ref: Ref) => { +export const MapCard = (props: MapCardProps) => { const { studyUuid, onClose, - errorMessage, + currentRootNetworkUuid, + networkVisuParams, showInSpreadsheet, onOpenNetworkAreaDiagram, - ...reactGridLayoutCustomChildComponentProps + currentNode, } = props; - const { style, children, ...otherProps } = reactGridLayoutCustomChildComponentProps; - const [isHover, setIsHover] = useState(false); - const intl = useIntl(); - - const handleMouseEnter = () => { - setIsHover(true); - }; - const handleMouseLeave = () => { - setIsHover(false); - }; const dispatch = useDispatch(); - const theme = useTheme(); const mapOpen = useSelector((state: AppState) => state.mapOpen); - const currentNode = useSelector((state: AppState) => state.currentTreeNode); - const currentRootNetworkUuid = useSelector((state: AppState) => state.currentRootNetworkUuid); - const networkVisuParams = useSelector((state: AppState) => state.networkVisualizationsParameters); - const clickable = !errorMessage; - - const handleOpenMap = useCallback(() => { - dispatch(resetMapEquipment()); - dispatch(setMapDataLoading(false)); - dispatch(setReloadMapNeeded(true)); - dispatch(setOpenMap(true)); - }, [dispatch]); - const isInDrawingMode = useStateBoolean(false); const networkMapPanelRef = useRef(null); @@ -97,77 +66,44 @@ export const MapCard = forwardRef((props: MapCardProps, ref: Ref dispatch(resetMapEquipment()); dispatch(setMapDataLoading(false)); dispatch(setReloadMapNeeded(true)); + onClose(); }, - [dispatch, isInDrawingMode] + [dispatch, isInDrawingMode, onClose] ); - if (!studyUuid || !currentNode || !currentRootNetworkUuid || !networkVisuParams) { - return ( - - - - {/* Empty container to keep the layout */} - - ); - } - return ( - - - {errorMessage && } - - + + + + + + { + handleCloseMap(); + showInSpreadsheet(eq); }} - fill={clickable && isHover ? theme.palette.grey[800] : theme.palette.grey[500]} - onClick={ - clickable - ? (e) => { - e.stopPropagation(); - handleOpenMap(); - } - : undefined - } - onMouseEnter={handleMouseEnter} - onMouseLeave={handleMouseLeave} + onOpenNetworkAreaDiagram={onOpenNetworkAreaDiagram} + onPolygonChanged={() => {}} + isInDrawingMode={isInDrawingMode} /> - - - - - - { - handleCloseMap(); - showInSpreadsheet(eq); - }} - onOpenNetworkAreaDiagram={onOpenNetworkAreaDiagram} - onPolygonChanged={() => {}} - isInDrawingMode={isInDrawingMode} - /> - - - {children} + ); -}); +}; export default MapCard; diff --git a/src/components/grid-layout/diagram-grid-layout.types.ts b/src/components/grid-layout/diagram-grid-layout.types.ts index 3c72da57d0..27e6dbdf18 100644 --- a/src/components/grid-layout/diagram-grid-layout.types.ts +++ b/src/components/grid-layout/diagram-grid-layout.types.ts @@ -6,7 +6,6 @@ */ import { DiagramParams, DiagramParamsDto } from 'components/grid-layout/cards/diagrams/diagram.type'; -import { UUID } from 'crypto'; import { Layout } from 'react-grid-layout'; export type DiagramLayoutParam = DiagramParams & { @@ -17,12 +16,7 @@ export interface DiagramGridLayout { diagramLayouts: DiagramLayoutParam[]; } -type MapDTO = { - diagramUuid: UUID; - type: 'map'; -}; - -export type DiagramLayoutDto = (DiagramParamsDto | MapDTO) & { +export type DiagramLayoutDto = DiagramParamsDto & { diagramPositions: Record>; }; diff --git a/src/components/grid-layout/grid-layout-panel.tsx b/src/components/grid-layout/grid-layout-panel.tsx index ff051ea1af..f45b10b2c7 100644 --- a/src/components/grid-layout/grid-layout-panel.tsx +++ b/src/components/grid-layout/grid-layout-panel.tsx @@ -5,7 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { useCallback, useState, useRef } from 'react'; +import { useCallback, useState, useRef, useMemo } from 'react'; import { Layout, Layouts, ItemCallback, Responsive, WidthProvider } from 'react-grid-layout'; import { useDiagramModel } from './hooks/use-diagram-model'; import { Diagram, DiagramParams, DiagramType } from './cards/diagrams/diagram.type'; @@ -22,6 +22,9 @@ import { BLINK_LENGTH_MS } from './cards/custom-card-header'; import CustomResizeHandle from './custom-resize-handle'; import { useSaveDiagramLayout } from './hooks/use-save-diagram-layout'; import { isThereTooManyOpenedNadDiagrams } from './cards/diagrams/diagram-utils'; +import { resetMapEquipment, setMapDataLoading, setOpenMap, setReloadMapNeeded } from 'redux/actions'; +import { useDispatch, useSelector } from 'react-redux'; +import { AppState } from 'redux/reducer'; const styles = { container: { @@ -159,8 +162,14 @@ function GridLayoutPanel({ studyUuid, showInSpreadsheet, showGrid, visible }: Re const responsiveGridLayoutRef = useRef(null); const currentBreakpointRef = useRef('lg'); const lastModifiedBreakpointRef = useRef('lg'); // Track the last modified breakpoint + const [isMapOpen, setIsMapOpen] = useState(false); + const dispatch = useDispatch(); + const currentNode = useSelector((state: AppState) => state.currentTreeNode); - const { snackInfo } = useSnackMessage(); + const currentRootNetworkUuid = useSelector((state: AppState) => state.currentRootNetworkUuid); + const networkVisuParams = useSelector((state: AppState) => state.networkVisualizationsParameters); + + const { snackInfo, snackError } = useSnackMessage(); // Blinking diagrams management const stopDiagramBlinking = useCallback((diagramUuid: UUID) => { @@ -181,12 +190,6 @@ function GridLayoutPanel({ studyUuid, showInSpreadsheet, showGrid, visible }: Re ); // Grid operations - const isMapCardAdded = () => { - return Object.values(layouts).some((breakpointLayouts) => - breakpointLayouts.some((layout) => layout.i === 'MapCard') - ); - }; - const addLayoutItem = useCallback((diagram: Diagram) => { lastModifiedBreakpointRef.current = currentBreakpointRef.current; setLayouts((currentLayouts) => createLayoutItem(diagram.diagramUuid, currentLayouts)); @@ -206,13 +209,25 @@ function GridLayoutPanel({ studyUuid, showInSpreadsheet, showGrid, visible }: Re }); }, []); - const onAddMapCard = useCallback(() => { - setLayouts((currentLayouts) => createLayoutItem('MapCard', currentLayouts)); - }, []); + const loadingMapError = useMemo(() => { + return !currentNode || !currentRootNetworkUuid; + }, [currentNode, currentRootNetworkUuid]); - const handleRemoveMapCard = useCallback(() => { - removeLayoutItem('MapCard'); - }, [removeLayoutItem]); + const onOpenMap = useCallback(() => { + if (loadingMapError) { + snackError({ messageId: 'MapCardNotAvailable' }); + return; + } + dispatch(resetMapEquipment()); + dispatch(setMapDataLoading(false)); + dispatch(setReloadMapNeeded(true)); + dispatch(setOpenMap(true)); + setIsMapOpen(true); + }, [dispatch, loadingMapError, snackError]); + + const handleCloseMap = useCallback(() => { + setIsMapOpen(false); + }, []); const { diagrams, @@ -425,14 +440,13 @@ function GridLayoutPanel({ studyUuid, showInSpreadsheet, showGrid, visible }: Re // Debounce the layout save function to avoid excessive calls const debouncedGridLayoutSave = useDebounce(handleGridLayoutSave, 300); - return ( ); })} - {isMapCardAdded() && ( - - )} + {isMapOpen && currentRootNetworkUuid && currentNode && ( + + )} ); } diff --git a/src/components/grid-layout/hooks/use-save-diagram-layout.ts b/src/components/grid-layout/hooks/use-save-diagram-layout.ts index 3e1489d590..37ae198ba2 100644 --- a/src/components/grid-layout/hooks/use-save-diagram-layout.ts +++ b/src/components/grid-layout/hooks/use-save-diagram-layout.ts @@ -15,7 +15,6 @@ import { DiagramGridLayoutDto, DiagramLayoutDto } from 'components/grid-layout/d import { MAX_INT32 } from 'services/utils'; import { saveDiagramGridLayout } from 'services/study/study-config'; import { useSnackMessage } from '@gridsuite/commons-ui'; -import { v4 } from 'uuid'; interface UseSaveDiagramLayoutProps { layouts: Layouts; @@ -64,14 +63,6 @@ const frontendToBackendDiagramGridLayout = (diagram: DiagramGridLayoutConfig): D } }); - // get the map from gridLayoutById - const transformedMapDTO: DiagramLayoutDto = { - diagramUuid: v4() as UUID, - type: 'map', - diagramPositions: gridLayoutById['MapCard'], - }; - diagramLayouts.push(transformedMapDTO); - return { diagramLayouts: diagramLayouts, }; diff --git a/src/hooks/use-diagram-grid-layout.ts b/src/hooks/use-diagram-grid-layout.ts index 4f2d74bb12..4adbd655f9 100644 --- a/src/hooks/use-diagram-grid-layout.ts +++ b/src/hooks/use-diagram-grid-layout.ts @@ -42,14 +42,14 @@ const decodeInfinity = (value: number) => { const backendToFrontendGridLayout = (diagramGridLayout: DiagramGridLayoutDto): DiagramGridLayoutConfig => { const gridLayoutResult: Layouts = {}; - for (const { diagramUuid, type, diagramPositions } of diagramGridLayout.diagramLayouts) { + for (const { diagramUuid, diagramPositions } of diagramGridLayout.diagramLayouts) { for (const [layoutKey, layoutValues] of Object.entries(diagramPositions)) { if (!gridLayoutResult[layoutKey]) { gridLayoutResult[layoutKey] = []; } gridLayoutResult[layoutKey].push({ ...layoutValues, - i: type === 'map' ? 'MapCard' : diagramUuid, + i: diagramUuid, x: decodeInfinity(layoutValues.x), y: decodeInfinity(layoutValues.y), }); @@ -58,24 +58,22 @@ const backendToFrontendGridLayout = (diagramGridLayout: DiagramGridLayoutDto): D return { gridLayouts: gridLayoutResult, - params: diagramGridLayout.diagramLayouts - .filter((layout) => layout.type !== 'map') - .map((layout) => { - if (layout.type === DiagramType.NETWORK_AREA_DIAGRAM) { - return { - type: layout.type, - diagramUuid: layout.diagramUuid, - nadConfigUuid: layout.originalNadConfigUuid, - initializationNadConfigUuid: layout.currentNadConfigUuid, - filterUuid: layout.filterUuid, - name: layout.name, - voltageLevelIds: [], - voltageLevelToExpandIds: [], - voltageLevelToOmitIds: [], - positions: [], - }; - } - return layout; - }), + params: diagramGridLayout.diagramLayouts.map((layout) => { + if (layout.type === DiagramType.NETWORK_AREA_DIAGRAM) { + return { + type: layout.type, + diagramUuid: layout.diagramUuid, + nadConfigUuid: layout.originalNadConfigUuid, + initializationNadConfigUuid: layout.currentNadConfigUuid, + filterUuid: layout.filterUuid, + name: layout.name, + voltageLevelIds: [], + voltageLevelToExpandIds: [], + voltageLevelToOmitIds: [], + positions: [], + }; + } + return layout; + }), }; }; diff --git a/src/images/world.svg b/src/images/world.svg deleted file mode 100644 index 2026fb7521..0000000000 --- a/src/images/world.svg +++ /dev/null @@ -1,977 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -