diff --git a/src/components/spreadsheet-view/add-spreadsheet/add-spreadsheet-button.tsx b/src/components/spreadsheet-view/add-spreadsheet/add-spreadsheet-button.tsx index 0736e96d68..e2a831419c 100644 --- a/src/components/spreadsheet-view/add-spreadsheet/add-spreadsheet-button.tsx +++ b/src/components/spreadsheet-view/add-spreadsheet/add-spreadsheet-button.tsx @@ -5,22 +5,23 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { FC, MouseEvent, useCallback, useState } from 'react'; -import { Button, Menu, MenuItem, Theme, Tooltip } from '@mui/material'; +import { useCallback, useState } from 'react'; +import { Button, type ButtonProps, Menu, MenuItem, Theme, Tooltip } from '@mui/material'; import AddIcon from '@mui/icons-material/Add'; -import { useStateBoolean, UseStateBooleanReturn } from '@gridsuite/commons-ui'; +import { useStateBoolean } from '@gridsuite/commons-ui'; import { FormattedMessage } from 'react-intl'; import { SpreadsheetTabDefinition } from '../types/spreadsheet.type'; import { ResetNodeAliasCallback } from '../hooks/use-node-aliases'; import AddEmptySpreadsheetDialog from './dialogs/add-empty-spreadsheet-dialog'; import AddSpreadsheetFromModelDialog from './dialogs/add-spreadsheet-from-model-dialog'; import AddSpreadsheetsFromCollectionDialog from './dialogs/add-spreadsheets-from-collection-dialog'; +import type { DialogComponent } from './types'; -interface AddSpreadsheetButtonProps { +export type AddSpreadsheetButtonProps = { disabled: boolean; resetTabIndex: (newTablesDefinitions: SpreadsheetTabDefinition[]) => void; resetNodeAliases: ResetNodeAliasCallback; -} +}; const styles = { addButton: (theme: Theme) => ({ @@ -29,12 +30,6 @@ const styles = { }), }; -type DialogComponent = FC<{ - open: UseStateBooleanReturn; - resetTabIndex: (newTablesDefinitions: SpreadsheetTabDefinition[]) => void; - resetNodeAliases: ResetNodeAliasCallback; -}>; - export interface SpreadsheetOption { id: string; label: string; @@ -44,7 +39,7 @@ export interface SpreadsheetOption { /** * Constants for spreadsheet creation options with associated dialog components */ -const NEW_SPREADSHEET_CREATION_OPTIONS: Record = { +const NEW_SPREADSHEET_CREATION_OPTIONS = { EMPTY: { id: 'EMPTY', label: 'spreadsheet/create_new_spreadsheet/empty_spreadsheet_option', @@ -60,20 +55,23 @@ const NEW_SPREADSHEET_CREATION_OPTIONS: Record = { label: 'spreadsheet/create_new_spreadsheet/apply_collection_option', dialog: AddSpreadsheetsFromCollectionDialog, }, -}; +} as const satisfies Record; -const AddSpreadsheetButton: React.FC = ({ disabled, resetTabIndex, resetNodeAliases }) => { +export default function AddSpreadsheetButton({ + disabled, + resetTabIndex, + resetNodeAliases, +}: Readonly) { const [anchorEl, setAnchorEl] = useState(null); const dialogOpen = useStateBoolean(false); const [selectedOption, setSelectedOption] = useState(); - const handleClick = useCallback((event: MouseEvent) => { - setAnchorEl(event.currentTarget); - }, []); + const handleClick = useCallback>( + (event) => setAnchorEl(event.currentTarget), + [] + ); - const handleClose = useCallback(() => { - setAnchorEl(null); - }, []); + const handleClose = useCallback(() => setAnchorEl(null), []); const handleMenuItemClick = useCallback( (option: SpreadsheetOption) => { @@ -102,12 +100,9 @@ const AddSpreadsheetButton: React.FC = ({ disabled, r ))} - {SelectedDialog && ( )} ); -}; - -export default AddSpreadsheetButton; +} diff --git a/src/components/spreadsheet-view/add-spreadsheet/dialogs/add-empty-spreadsheet-dialog.tsx b/src/components/spreadsheet-view/add-spreadsheet/dialogs/add-empty-spreadsheet-dialog.tsx index 957a076d05..133cce9311 100644 --- a/src/components/spreadsheet-view/add-spreadsheet/dialogs/add-empty-spreadsheet-dialog.tsx +++ b/src/components/spreadsheet-view/add-spreadsheet/dialogs/add-empty-spreadsheet-dialog.tsx @@ -7,14 +7,7 @@ import { useCallback, useEffect, useMemo } from 'react'; import { Grid } from '@mui/material'; -import { - CustomFormProvider, - EquipmentType, - SelectInput, - TextInput, - UseStateBooleanReturn, - useSnackMessage, -} from '@gridsuite/commons-ui'; +import { CustomFormProvider, SelectInput, TextInput, useSnackMessage } from '@gridsuite/commons-ui'; import { useForm } from 'react-hook-form'; import { yupResolver } from '@hookform/resolvers/yup'; import { useDispatch, useSelector } from 'react-redux'; @@ -22,50 +15,38 @@ import { EQUIPMENT_TYPE_FIELD } from 'components/utils/field-constants'; import { AppState } from 'redux/reducer'; import { UUID } from 'crypto'; import { dialogStyles } from '../styles/styles'; -import { ModificationDialog } from 'components/dialogs/commons/modificationDialog'; -import { getEmptySpreadsheetFormSchema, initialEmptySpreadsheetForm, SPREADSHEET_NAME } from './add-spreadsheet-form'; +import { ModificationDialog, type ModificationDialogProps } from 'components/dialogs/commons/modificationDialog'; +import { + type EmptySpreadsheetForm, + getEmptySpreadsheetFormSchema, + initialEmptySpreadsheetForm, + SPREADSHEET_NAME, +} from './add-spreadsheet-form'; import { addNewSpreadsheet } from './add-spreadsheet-utils'; import { COLUMN_TYPES } from 'components/custom-aggrid/custom-aggrid-header.type'; -import { ColumnDefinitionDto } from '../../types/spreadsheet.type'; +import { ColumnDefinitionDto, SpreadsheetEquipmentType } from '../../types/spreadsheet.type'; import { v4 as uuid4 } from 'uuid'; +import type { DialogComponentProps } from '../types'; -interface AddEmptySpreadsheetDialogProps { - open: UseStateBooleanReturn; -} +export type AddEmptySpreadsheetDialogProps = Pick; -const TABLES_TYPES = [ - EquipmentType.SUBSTATION, - EquipmentType.VOLTAGE_LEVEL, - EquipmentType.LINE, - EquipmentType.TWO_WINDINGS_TRANSFORMER, - EquipmentType.THREE_WINDINGS_TRANSFORMER, - EquipmentType.GENERATOR, - EquipmentType.LOAD, - EquipmentType.SHUNT_COMPENSATOR, - EquipmentType.STATIC_VAR_COMPENSATOR, - EquipmentType.BATTERY, - EquipmentType.HVDC_LINE, - EquipmentType.LCC_CONVERTER_STATION, - EquipmentType.VSC_CONVERTER_STATION, - EquipmentType.TIE_LINE, - EquipmentType.DANGLING_LINE, - EquipmentType.BUS, - EquipmentType.BUSBAR_SECTION, -]; +const TABLES_OPTIONS = Object.values(SpreadsheetEquipmentType).map( + (elementType) => ({ id: elementType, label: elementType }) as const +); -const DEFAULT_ID_COLUMN: ColumnDefinitionDto = { +const DEFAULT_ID_COLUMN = { uuid: uuid4() as UUID, name: 'ID', id: 'id', type: COLUMN_TYPES.TEXT, formula: 'id', visible: true, -}; +} as const satisfies ColumnDefinitionDto; /** * Dialog for creating an empty spreadsheet */ -export default function AddEmptySpreadsheetDialog({ open, ...dialogProps }: Readonly) { +export default function AddEmptySpreadsheetDialog({ open }: Readonly) { const dispatch = useDispatch(); const { snackError } = useSnackMessage(); const studyUuid = useSelector((state: AppState) => state.studyUuid); @@ -88,21 +69,17 @@ export default function AddEmptySpreadsheetDialog({ open, ...dialogProps }: Read reset(initialEmptySpreadsheetForm); }, [open.value, reset]); - const onSubmit = useCallback( - (formData: any) => { + const onSubmit = useCallback['onSave']>( + (formData) => { if (!studyUuid) { return; } - const tabIndex = tablesDefinitions.length; - const tabName = formData[SPREADSHEET_NAME]; - const equipmentType = formData.equipmentType; - addNewSpreadsheet({ studyUuid, columns: [DEFAULT_ID_COLUMN], - sheetType: equipmentType, - tabIndex, - tabName, + sheetType: formData.equipmentType, + tabIndex: tablesDefinitions.length, + tabName: formData[SPREADSHEET_NAME], spreadsheetsCollectionUuid: spreadsheetsCollectionUuid as UUID, dispatch, snackError, @@ -119,9 +96,8 @@ export default function AddEmptySpreadsheetDialog({ open, ...dialogProps }: Read open={open.value} onClose={open.setFalse} onSave={onSubmit} - onClear={() => null} + onClear={() => {}} PaperProps={{ sx: dialogStyles.dialogContent }} - {...dialogProps} > @@ -133,10 +109,7 @@ export default function AddEmptySpreadsheetDialog({ open, ...dialogProps }: Read ({ - id: elementType, - label: elementType, - }))} + options={TABLES_OPTIONS} name={EQUIPMENT_TYPE_FIELD} label="spreadsheet/create_new_spreadsheet/element_type" size="small" diff --git a/src/components/spreadsheet-view/add-spreadsheet/dialogs/add-spreadsheet-form.ts b/src/components/spreadsheet-view/add-spreadsheet/dialogs/add-spreadsheet-form.ts index 1041103d2a..52c4ddaa29 100644 --- a/src/components/spreadsheet-view/add-spreadsheet/dialogs/add-spreadsheet-form.ts +++ b/src/components/spreadsheet-view/add-spreadsheet/dialogs/add-spreadsheet-form.ts @@ -7,6 +7,7 @@ import { EQUIPMENT_TYPE_FIELD, ID, NAME } from 'components/utils/field-constants'; import yup from '../../../utils/yup-config'; +import { SpreadsheetEquipmentType } from '../../types/spreadsheet.type'; export const SPREADSHEET_NAME = 'spreadsheetName'; export const SPREADSHEET_MODEL = 'spreadsheetModel'; @@ -15,13 +16,14 @@ export const SPREADSHEET_COLLECTION_IMPORT_MODE = 'spreadsheetCollectionMode'; export const initialEmptySpreadsheetForm: EmptySpreadsheetForm = { [SPREADSHEET_NAME]: '', + //@ts-expect-error TS2418: Type of computed property's value is '', which is not assignable to type NonNullable [EQUIPMENT_TYPE_FIELD]: '', -}; +} as const; export const initialSpreadsheetFromModelForm: SpreadsheetFromModelForm = { [SPREADSHEET_NAME]: '', [SPREADSHEET_MODEL]: [], -}; +} as const; export enum SpreadsheetCollectionImportMode { REPLACE = 'REPLACE', @@ -33,28 +35,28 @@ export const initialSpreadsheetCollectionForm: SpreadsheetCollectionForm = { [SPREADSHEET_COLLECTION_IMPORT_MODE]: SpreadsheetCollectionImportMode.REPLACE, }; -export const getEmptySpreadsheetFormSchema = (tablesNames: string[]) => { +function schemaSpreadsheetName(tablesNames: string[]) { + return yup + .string() + .required() + .max(60, 'spreadsheet/spreadsheet_name_le_60') + .test( + 'unique', + 'spreadsheet/create_new_spreadsheet/spreadsheet_name_already_exists', + (value) => !tablesNames.includes(value || '') + ); +} + +export function getEmptySpreadsheetFormSchema(tablesNames: string[]) { return yup.object().shape({ - [SPREADSHEET_NAME]: yup - .string() - .required() - .max(60, 'spreadsheet/spreadsheet_name_le_60') - .test('unique', 'spreadsheet/create_new_spreadsheet/spreadsheet_name_already_exists', (value) => { - return !tablesNames.includes(value || ''); - }), - [EQUIPMENT_TYPE_FIELD]: yup.string().required(), + [SPREADSHEET_NAME]: schemaSpreadsheetName(tablesNames), + [EQUIPMENT_TYPE_FIELD]: yup.string().oneOf(Object.values(SpreadsheetEquipmentType)).required(), }); -}; +} -export const getSpreadsheetFromModelFormSchema = (tablesNames: string[]) => { +export function getSpreadsheetFromModelFormSchema(tablesNames: string[]) { return yup.object().shape({ - [SPREADSHEET_NAME]: yup - .string() - .required() - .max(60, 'spreadsheet/spreadsheet_name_le_60') - .test('unique', 'spreadsheet/create_new_spreadsheet/spreadsheet_name_already_exists', (value) => { - return !tablesNames.includes(value || ''); - }), + [SPREADSHEET_NAME]: schemaSpreadsheetName(tablesNames), [SPREADSHEET_MODEL]: yup .array() .of( @@ -67,7 +69,7 @@ export const getSpreadsheetFromModelFormSchema = (tablesNames: string[]) => { .min(1, 'spreadsheet/create_new_spreadsheet/must_select_spreadsheet_model') .max(1, 'spreadsheet/create_new_spreadsheet/must_select_only_one_spreadsheet_model'), }); -}; +} export const getSpreadsheetCollectionFormSchema = () => { return yup.object().shape({ diff --git a/src/components/spreadsheet-view/add-spreadsheet/dialogs/add-spreadsheet-from-model-dialog.tsx b/src/components/spreadsheet-view/add-spreadsheet/dialogs/add-spreadsheet-from-model-dialog.tsx index a155fd71eb..f1e4bf9a4f 100644 --- a/src/components/spreadsheet-view/add-spreadsheet/dialogs/add-spreadsheet-from-model-dialog.tsx +++ b/src/components/spreadsheet-view/add-spreadsheet/dialogs/add-spreadsheet-from-model-dialog.tsx @@ -12,7 +12,6 @@ import { DirectoryItemsInput, ElementType, TextInput, - UseStateBooleanReturn, useSnackMessage, } from '@gridsuite/commons-ui'; import { useForm, useWatch } from 'react-hook-form'; @@ -20,22 +19,19 @@ import { yupResolver } from '@hookform/resolvers/yup'; import { useDispatch, useSelector } from 'react-redux'; import { AppState } from 'redux/reducer'; import { - SPREADSHEET_MODEL, - SPREADSHEET_NAME, getSpreadsheetFromModelFormSchema, initialSpreadsheetFromModelForm, + SPREADSHEET_MODEL, + SPREADSHEET_NAME, } from './add-spreadsheet-form'; import { addNewSpreadsheet } from './add-spreadsheet-utils'; import { getSpreadsheetModel } from 'services/study-config'; import { UUID } from 'crypto'; import { ModificationDialog } from 'components/dialogs/commons/modificationDialog'; import { dialogStyles } from '../styles/styles'; -import { ResetNodeAliasCallback } from '../../hooks/use-node-aliases'; +import type { DialogComponentProps } from '../types'; -interface AddSpreadsheetFromModelDialogProps { - open: UseStateBooleanReturn; - resetNodeAliases: ResetNodeAliasCallback; -} +export type AddSpreadsheetFromModelDialogProps = Pick; /** * Dialog for creating a spreadsheet from an existing model @@ -43,7 +39,6 @@ interface AddSpreadsheetFromModelDialogProps { export default function AddSpreadsheetFromModelDialog({ open, resetNodeAliases, - ...dialogProps }: Readonly) { const dispatch = useDispatch(); const { snackError } = useSnackMessage(); @@ -126,7 +121,6 @@ export default function AddSpreadsheetFromModelDialog({ onSave={onSubmit} onClear={() => null} PaperProps={{ sx: dialogStyles.dialogContent }} - {...dialogProps} > diff --git a/src/components/spreadsheet-view/add-spreadsheet/dialogs/add-spreadsheets-from-collection-dialog.tsx b/src/components/spreadsheet-view/add-spreadsheet/dialogs/add-spreadsheets-from-collection-dialog.tsx index 0d4a4496c0..fad81b1ab5 100644 --- a/src/components/spreadsheet-view/add-spreadsheet/dialogs/add-spreadsheets-from-collection-dialog.tsx +++ b/src/components/spreadsheet-view/add-spreadsheet/dialogs/add-spreadsheets-from-collection-dialog.tsx @@ -13,7 +13,6 @@ import { ElementType, PopupConfirmationDialog, RadioInput, - UseStateBooleanReturn, useSnackMessage, } from '@gridsuite/commons-ui'; import { useForm } from 'react-hook-form'; @@ -26,8 +25,7 @@ import { initTableDefinitions } from 'redux/actions'; import { UUID } from 'crypto'; import { ModificationDialog } from 'components/dialogs/commons/modificationDialog'; import { dialogStyles } from '../styles/styles'; -import { SpreadsheetCollectionDto, SpreadsheetTabDefinition } from 'components/spreadsheet-view/types/spreadsheet.type'; -import { ResetNodeAliasCallback } from 'components/spreadsheet-view/hooks/use-node-aliases'; +import { SpreadsheetCollectionDto } from 'components/spreadsheet-view/types/spreadsheet.type'; import { getSpreadsheetCollectionFormSchema, initialSpreadsheetCollectionForm, @@ -37,12 +35,7 @@ import { SpreadsheetCollectionImportMode, } from './add-spreadsheet-form'; import { processSpreadsheetsCollectionData } from './add-spreadsheet-utils'; - -interface AddSpreadsheetsFromCollectionDialogProps { - open: UseStateBooleanReturn; - resetTabIndex: (newTablesDefinitions: SpreadsheetTabDefinition[]) => void; - resetNodeAliases: ResetNodeAliasCallback; -} +import type { DialogComponentProps } from '../types'; /** * Dialog for importing a spreadsheet collection @@ -51,8 +44,7 @@ export default function AddSpreadsheetsFromCollectionDialog({ open, resetTabIndex, resetNodeAliases, - ...dialogProps -}: Readonly) { +}: Readonly) { const dispatch = useDispatch(); const intl = useIntl(); const { snackError } = useSnackMessage(); @@ -153,7 +145,6 @@ export default function AddSpreadsheetsFromCollectionDialog({ onSave={onSubmit} onClear={() => null} PaperProps={{ sx: dialogStyles.dialogContent }} - {...dialogProps} > {updateModeSelectionField} diff --git a/src/components/spreadsheet-view/add-spreadsheet/styles/styles.ts b/src/components/spreadsheet-view/add-spreadsheet/styles/styles.ts index 0f6a7a1ffe..bb1660bd7f 100644 --- a/src/components/spreadsheet-view/add-spreadsheet/styles/styles.ts +++ b/src/components/spreadsheet-view/add-spreadsheet/styles/styles.ts @@ -12,9 +12,6 @@ import { SxProps, Theme } from '@mui/material'; */ export const dialogStyles = { dialogContent: { - width: '45%', - height: '30%', - maxWidth: 'none', - margin: 'auto', + minWidth: '45%', }, } as const satisfies Record>; diff --git a/src/components/spreadsheet-view/add-spreadsheet/types.d.ts b/src/components/spreadsheet-view/add-spreadsheet/types.d.ts new file mode 100644 index 0000000000..e091a6d852 --- /dev/null +++ b/src/components/spreadsheet-view/add-spreadsheet/types.d.ts @@ -0,0 +1,19 @@ +/* + * Copyright © 2025, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * 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 type { ComponentType } from 'react'; +import type { UseStateBooleanReturn } from '@gridsuite/commons-ui'; +import type { SpreadsheetTabDefinition } from '../types/spreadsheet.type'; +import type { ResetNodeAliasCallback } from '../hooks/use-node-aliases'; + +export type DialogComponentProps = { + open: UseStateBooleanReturn; + resetTabIndex: (newTablesDefinitions: SpreadsheetTabDefinition[]) => void; + resetNodeAliases: ResetNodeAliasCallback; +}; + +export type DialogComponent = ComponentType; diff --git a/src/components/spreadsheet-view/hooks/use-fetch-equipment.ts b/src/components/spreadsheet-view/hooks/use-fetch-equipment.ts index d4134f46e5..388a9fbfdd 100644 --- a/src/components/spreadsheet-view/hooks/use-fetch-equipment.ts +++ b/src/components/spreadsheet-view/hooks/use-fetch-equipment.ts @@ -6,104 +6,48 @@ */ import { useCallback } from 'react'; -import { EquipmentFetcher, SpreadsheetEquipmentsByNodes, SpreadsheetEquipmentType } from '../types/spreadsheet.type'; -import { UUID } from 'crypto'; +import { type SpreadsheetEquipmentsByNodes, type SpreadsheetEquipmentType } from '../types/spreadsheet.type'; +import type { UUID } from 'crypto'; import { useDispatch, useSelector } from 'react-redux'; -import { AppState } from '../../../redux/reducer'; +import { type AppState } from '../../../redux/reducer'; import { loadEquipments } from '../../../redux/actions'; import { useSnackMessage } from '@gridsuite/commons-ui'; -import { EQUIPMENT_TYPES } from '../../utils/equipment-types'; -import { - fetchBatteries, - fetchBusbarSections, - fetchBuses, - fetchDanglingLines, - fetchGenerators, - fetchHvdcLines, - fetchLccConverterStations, - fetchLines, - fetchLoads, - fetchShuntCompensators, - fetchStaticVarCompensators, - fetchSubstations, - fetchThreeWindingsTransformers, - fetchTieLines, - fetchTwoWindingsTransformers, - fetchVoltageLevels, - fetchVscConverterStations, -} from '../../../services/study/network'; +import { fetchNetworkElementsInfos } from '../../../services/study/network'; import { mapSpreadsheetEquipments } from '../../../utils/spreadsheet-equipments-mapper'; +import { EQUIPMENT_INFOS_TYPES } from '../../utils/equipment-types'; -const getFetcher = (equipmentType: SpreadsheetEquipmentType): EquipmentFetcher => { - switch (equipmentType) { - case EQUIPMENT_TYPES.SUBSTATION: - return fetchSubstations; - case EQUIPMENT_TYPES.VOLTAGE_LEVEL: - return fetchVoltageLevels; - case EQUIPMENT_TYPES.LINE: - return fetchLines; - case EQUIPMENT_TYPES.TIE_LINE: - return fetchTieLines; - case EQUIPMENT_TYPES.TWO_WINDINGS_TRANSFORMER: - return fetchTwoWindingsTransformers; - case EQUIPMENT_TYPES.THREE_WINDINGS_TRANSFORMER: - return fetchThreeWindingsTransformers; - case EQUIPMENT_TYPES.HVDC_LINE: - return fetchHvdcLines; - case EQUIPMENT_TYPES.GENERATOR: - return fetchGenerators; - case EQUIPMENT_TYPES.BATTERY: - return fetchBatteries; - case EQUIPMENT_TYPES.LOAD: - return fetchLoads; - case EQUIPMENT_TYPES.SHUNT_COMPENSATOR: - return fetchShuntCompensators; - case EQUIPMENT_TYPES.DANGLING_LINE: - return fetchDanglingLines; - case EQUIPMENT_TYPES.STATIC_VAR_COMPENSATOR: - return fetchStaticVarCompensators; - case EQUIPMENT_TYPES.VSC_CONVERTER_STATION: - return fetchVscConverterStations; - case EQUIPMENT_TYPES.LCC_CONVERTER_STATION: - return fetchLccConverterStations; - case EQUIPMENT_TYPES.BUS: - return fetchBuses; - case EQUIPMENT_TYPES.BUSBAR_SECTION: - return fetchBusbarSections; - } -}; - -export const useFetchEquipment = (type: SpreadsheetEquipmentType) => { +export function useFetchEquipment(type: SpreadsheetEquipmentType) { const dispatch = useDispatch(); const { snackError } = useSnackMessage(); const studyUuid = useSelector((state: AppState) => state.studyUuid); - const mapEquipments = useCallback( - (fetchedEquipments: any) => { - //Format the equipments data to set calculated fields, so that the edition validation is consistent with the displayed data - return mapSpreadsheetEquipments(type, fetchedEquipments); - }, - [type] - ); - const fetchNodesEquipmentData = useCallback( - (nodeIds: Set, currentNodeUuid: UUID, currentRootNetworkUuid: UUID, onFetchingDone?: () => void) => { + (nodeIds: Set, currentNodeUuid: UUID, currentRootNetworkUuid: UUID, onFetchingDone?: () => void) => { if (studyUuid && currentNodeUuid && currentRootNetworkUuid) { - let fetcherPromises: Promise[] = []; - let spreadsheetEquipmentsByNodes: SpreadsheetEquipmentsByNodes = { + const fetcherPromises: ReturnType[] = []; + const spreadsheetEquipmentsByNodes: SpreadsheetEquipmentsByNodes = { nodesId: [], equipmentsByNodeId: {}, }; nodeIds.forEach((nodeId) => { - const promise = getFetcher(type)(studyUuid, nodeId as UUID, currentRootNetworkUuid, []); + const promise = fetchNetworkElementsInfos( + studyUuid, + nodeId, + currentRootNetworkUuid, + [], + type, + EQUIPMENT_INFOS_TYPES.TAB.type + ); fetcherPromises.push(promise); promise .then((results) => { - let fetchedEquipments = results.flat(); spreadsheetEquipmentsByNodes.nodesId.push(nodeId); - fetchedEquipments = mapEquipments(fetchedEquipments); - spreadsheetEquipmentsByNodes.equipmentsByNodeId[nodeId] = fetchedEquipments; + // Format the equipments data to set calculated fields so that the edition validation is consistent with the displayed data + spreadsheetEquipmentsByNodes.equipmentsByNodeId[nodeId] = mapSpreadsheetEquipments( + type, + results + ); }) .catch((err) => { console.error( @@ -131,8 +75,8 @@ export const useFetchEquipment = (type: SpreadsheetEquipmentType) => { }); } }, - [dispatch, mapEquipments, snackError, studyUuid, type] + [dispatch, snackError, studyUuid, type] ); return { fetchNodesEquipmentData }; -}; +} diff --git a/src/components/spreadsheet-view/spreadsheet/spreadsheet-content/hooks/use-equipment-modification.tsx b/src/components/spreadsheet-view/spreadsheet/spreadsheet-content/hooks/use-equipment-modification.tsx index 708d243cbc..678544021b 100644 --- a/src/components/spreadsheet-view/spreadsheet/spreadsheet-content/hooks/use-equipment-modification.tsx +++ b/src/components/spreadsheet-view/spreadsheet/spreadsheet-content/hooks/use-equipment-modification.tsx @@ -14,74 +14,59 @@ import ShuntCompensatorModificationDialog from 'components/dialogs/network-modif import SubstationModificationDialog from 'components/dialogs/network-modifications/substation/modification/substation-modification-dialog'; import TwoWindingsTransformerModificationDialog from 'components/dialogs/network-modifications/two-windings-transformer/modification/two-windings-transformer-modification-dialog'; import VoltageLevelModificationDialog from 'components/dialogs/network-modifications/voltage-level/modification/voltage-level-modification-dialog'; -import { useCallback, useMemo, useState } from 'react'; +import { type FunctionComponent, type ReactElement, useCallback, useMemo, useState } from 'react'; import { useSelector } from 'react-redux'; -import { AppState } from 'redux/reducer'; -import { SpreadsheetEquipmentType } from '../../../types/spreadsheet.type'; -import { EQUIPMENT_TYPES } from 'components/utils/equipment-types'; +import { type AppState } from 'redux/reducer'; +import { type EditableEquipmentType, SpreadsheetEquipmentType } from '../../../types/spreadsheet.type'; -interface UseEquipmentModificationProps { +export type UseEquipmentModificationProps = { equipmentType: SpreadsheetEquipmentType; -} - -type EditableEquipmentType = Exclude< - SpreadsheetEquipmentType, - | EQUIPMENT_TYPES.TIE_LINE - | EQUIPMENT_TYPES.THREE_WINDINGS_TRANSFORMER - | EQUIPMENT_TYPES.BUS - | EQUIPMENT_TYPES.BUSBAR_SECTION - | EQUIPMENT_TYPES.DANGLING_LINE - | EQUIPMENT_TYPES.STATIC_VAR_COMPENSATOR - | EQUIPMENT_TYPES.VSC_CONVERTER_STATION - | EQUIPMENT_TYPES.LCC_CONVERTER_STATION - | EQUIPMENT_TYPES.HVDC_LINE ->; +}; -const EQUIPMENT_DIALOG_MAPPING: Record> = { - [EQUIPMENT_TYPES.SUBSTATION]: SubstationModificationDialog, - [EQUIPMENT_TYPES.VOLTAGE_LEVEL]: VoltageLevelModificationDialog, - [EQUIPMENT_TYPES.LINE]: LineModificationDialog, - [EQUIPMENT_TYPES.TWO_WINDINGS_TRANSFORMER]: TwoWindingsTransformerModificationDialog, - [EQUIPMENT_TYPES.GENERATOR]: GeneratorModificationDialog, - [EQUIPMENT_TYPES.LOAD]: LoadModificationDialog, - [EQUIPMENT_TYPES.BATTERY]: BatteryModificationDialog, - [EQUIPMENT_TYPES.SHUNT_COMPENSATOR]: ShuntCompensatorModificationDialog, +const EQUIPMENT_DIALOG_MAPPING: Readonly>> = { + [SpreadsheetEquipmentType.SUBSTATION]: SubstationModificationDialog, + [SpreadsheetEquipmentType.VOLTAGE_LEVEL]: VoltageLevelModificationDialog, + [SpreadsheetEquipmentType.LINE]: LineModificationDialog, + [SpreadsheetEquipmentType.TWO_WINDINGS_TRANSFORMER]: TwoWindingsTransformerModificationDialog, + [SpreadsheetEquipmentType.GENERATOR]: GeneratorModificationDialog, + [SpreadsheetEquipmentType.LOAD]: LoadModificationDialog, + [SpreadsheetEquipmentType.BATTERY]: BatteryModificationDialog, + [SpreadsheetEquipmentType.SHUNT_COMPENSATOR]: ShuntCompensatorModificationDialog, }; -export const useEquipmentModification = ({ equipmentType }: UseEquipmentModificationProps) => { - const [modificationDialog, setModificationDialog] = useState(null); +function isEditableEquipmentType(type: SpreadsheetEquipmentType): type is EditableEquipmentType { + return type in EQUIPMENT_DIALOG_MAPPING; +} + +export function useEquipmentModification({ equipmentType }: Readonly) { + const [modificationDialog, setModificationDialog] = useState(null); const currentNode = useSelector((state: AppState) => state.currentTreeNode); const currentRootNetworkUuid = useSelector((state: AppState) => state.currentRootNetworkUuid); const studyUuid = useSelector((state: AppState) => state.studyUuid); const createDialogWithProps = useCallback( - (Dialog: React.FC, equipmentId: string) => { - return ( - setModificationDialog(null)} - currentNode={currentNode} - studyUuid={studyUuid} - currentRootNetworkUuid={currentRootNetworkUuid} - editData={undefined} - isUpdate={false} - editDataFetchStatus={FetchStatus.IDLE} - defaultIdValue={equipmentId} - /> - ); - }, + (Dialog: FunctionComponent, equipmentId: string) => ( + setModificationDialog(null)} + currentNode={currentNode} + studyUuid={studyUuid} + currentRootNetworkUuid={currentRootNetworkUuid} + editData={undefined} + isUpdate={false} + editDataFetchStatus={FetchStatus.IDLE} + defaultIdValue={equipmentId} + /> + ), [currentNode, studyUuid, currentRootNetworkUuid] ); const getDialogForEquipment = useCallback( (equipmentId: string) => { - const DialogComponent = EQUIPMENT_DIALOG_MAPPING[equipmentType as EditableEquipmentType]; - - if (!DialogComponent) { + if (!isEditableEquipmentType(equipmentType)) { return null; } - - return createDialogWithProps(DialogComponent, equipmentId); + return createDialogWithProps(EQUIPMENT_DIALOG_MAPPING[equipmentType], equipmentId); }, [createDialogWithProps, equipmentType] ); @@ -93,10 +78,7 @@ export const useEquipmentModification = ({ equipmentType }: UseEquipmentModifica [getDialogForEquipment] ); - const isModificationDialogForEquipmentType = useMemo(() => { - const DialogComponent = EQUIPMENT_DIALOG_MAPPING[equipmentType as EditableEquipmentType]; - return DialogComponent !== undefined; - }, [equipmentType]); + const isModificationDialogForEquipmentType = useMemo(() => isEditableEquipmentType(equipmentType), [equipmentType]); return { modificationDialog, handleOpenModificationDialog, isModificationDialogForEquipmentType }; -}; +} diff --git a/src/components/spreadsheet-view/spreadsheet/spreadsheet-content/hooks/use-spreadsheet-equipments.ts b/src/components/spreadsheet-view/spreadsheet/spreadsheet-content/hooks/use-spreadsheet-equipments.ts index e5b10869df..f52c7645d5 100644 --- a/src/components/spreadsheet-view/spreadsheet/spreadsheet-content/hooks/use-spreadsheet-equipments.ts +++ b/src/components/spreadsheet-view/spreadsheet/spreadsheet-content/hooks/use-spreadsheet-equipments.ts @@ -5,70 +5,30 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { type Identifiable, NotificationsUrlKeys, useNotificationsListener } from '@gridsuite/commons-ui'; +import { NotificationsUrlKeys, useNotificationsListener } from '@gridsuite/commons-ui'; import type { UUID } from 'crypto'; import { useCallback, useEffect, useMemo, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { deleteEquipments, - EquipmentToDelete, + type EquipmentToDelete, removeNodeData, resetEquipments, resetEquipmentsByTypes, updateEquipments, + type UpdateEquipmentsAction, } from 'redux/actions'; -import { type AppState, EquipmentUpdateType } from 'redux/reducer'; -import type { SpreadsheetEquipmentType } from '../../../types/spreadsheet.type'; +import { type AppState } from 'redux/reducer'; +import { isSpreadsheetEquipmentType, SpreadsheetEquipmentType } from '../../../types/spreadsheet.type'; import { fetchAllEquipments } from 'services/study/network-map'; import type { NodeAlias } from '../../../types/node-alias.type'; import { isStatusBuilt } from '../../../../graph/util/model-functions'; import { useFetchEquipment } from '../../../hooks/use-fetch-equipment'; -import { isStudyNotification } from 'types/notification-types'; +import { type DeletedEquipment, isStudyNotification, type NetworkImpactsInfos } from 'types/notification-types'; import { NodeType } from '../../../../graph/tree-node.type'; import { validAlias } from '../../../hooks/use-node-aliases'; -import { EQUIPMENT_TYPES } from 'components/utils/equipment-types'; import { fetchNetworkElementInfos } from 'services/study/network'; - -const getEquipmentUpdateTypeFromType = (type: SpreadsheetEquipmentType) => { - switch (type) { - case 'SUBSTATION': - return EquipmentUpdateType.SUBSTATIONS; - case 'VOLTAGE_LEVEL': - return EquipmentUpdateType.VOLTAGE_LEVELS; - case 'TIE_LINE': - return EquipmentUpdateType.TIE_LINES; - case 'LINE': - return EquipmentUpdateType.LINES; - case 'TWO_WINDINGS_TRANSFORMER': - return EquipmentUpdateType.TWO_WINDINGS_TRANSFORMERS; - case 'THREE_WINDINGS_TRANSFORMER': - return EquipmentUpdateType.THREE_WINDINGS_TRANSFORMERS; - case 'HVDC_LINE': - return EquipmentUpdateType.HVDC_LINES; - case 'BUS': - return EquipmentUpdateType.BUSES; - case 'BUSBAR_SECTION': - return EquipmentUpdateType.BUSBAR_SECTIONS; - case 'GENERATOR': - return EquipmentUpdateType.GENERATORS; - case 'BATTERY': - return EquipmentUpdateType.BATTERIES; - case 'LOAD': - return EquipmentUpdateType.LOADS; - case 'SHUNT_COMPENSATOR': - return EquipmentUpdateType.SHUNT_COMPENSATORS; - case 'DANGLING_LINE': - return EquipmentUpdateType.DANGLING_LINES; - case 'STATIC_VAR_COMPENSATOR': - return EquipmentUpdateType.STATIC_VAR_COMPENSATORS; - case 'VSC_CONVERTER_STATION': - return EquipmentUpdateType.VSC_CONVERTER_STATIONS; - case 'LCC_CONVERTER_STATION': - return EquipmentUpdateType.LCC_CONVERTER_STATIONS; - default: - return; - } -}; +import { EQUIPMENT_INFOS_TYPES } from '../../../../utils/equipment-types'; export const useSpreadsheetEquipments = ( type: SpreadsheetEquipmentType, @@ -87,10 +47,8 @@ export const useSpreadsheetEquipments = ( const currentRootNetworkUuid = useSelector((state: AppState) => state.currentRootNetworkUuid); const currentNode = useSelector((state: AppState) => state.currentTreeNode); const treeNodes = useSelector((state: AppState) => state.networkModificationTreeModel?.treeNodes); - const [builtAliasedNodesIds, setBuiltAliasedNodesIds] = useState(); - + const [builtAliasedNodesIds, setBuiltAliasedNodesIds] = useState([]); const [isFetching, setIsFetching] = useState(false); - const { fetchNodesEquipmentData } = useFetchEquipment(type); // effect to keep builtAliasedNodesIds up-to-date (when we add/remove an alias or build/unbuild an aliased node) @@ -103,76 +61,66 @@ export const useSpreadsheetEquipments = ( .filter((nodeAlias) => validAlias(nodeAlias)) .map((nodeAlias) => nodeAlias.id); if (aliasedNodesIds.length > 0) { - treeNodes?.forEach((treeNode) => { - if ( - aliasedNodesIds.includes(treeNode.id) && - (treeNode.type === NodeType.ROOT || isStatusBuilt(treeNode.data.globalBuildStatus)) - ) { - computedIds.push(treeNode.id); - } - }); + computedIds = + treeNodes + ?.filter( + (treeNode) => + aliasedNodesIds.includes(treeNode.id) && + (treeNode.type === NodeType.ROOT || isStatusBuilt(treeNode.data.globalBuildStatus)) + ) + .map((treeNode) => treeNode.id) ?? []; } + computedIds.sort((a, b) => a.localeCompare(b)); // Because of treeNodes: update the state only on real values changes (to avoid multiple effects for the watchers) - setBuiltAliasedNodesIds((prevState) => { - const currentIds = prevState; - currentIds?.sort((a, b) => a.localeCompare(b)); - computedIds.sort((a, b) => a.localeCompare(b)); - if (JSON.stringify(currentIds) !== JSON.stringify(computedIds)) { - return computedIds; - } - return prevState; - }); + setBuiltAliasedNodesIds((prevState) => + JSON.stringify(prevState) !== JSON.stringify(computedIds) ? computedIds : prevState + ); }, [nodeAliases, treeNodes]); const nodesIdToFetch = useMemo(() => { - let nodesIdToFetch = new Set(); - if (!equipments || !builtAliasedNodesIds) { + const nodesIdToFetch = new Set(); + if (!equipments.nodesId || !builtAliasedNodesIds || !currentNode?.id) { return nodesIdToFetch; } - // We check if we have the data for the currentNode and if we don't we save the fact that we need to fetch it - if (equipments.nodesId.find((nodeId) => nodeId === currentNode?.id) === undefined) { - nodesIdToFetch.add(currentNode?.id as string); + // We check if we have the data for the currentNode and if we don't, we save the fact that we need to fetch it + if (equipments.nodesId.find((nodeId) => nodeId === currentNode.id) === undefined) { + nodesIdToFetch.add(currentNode.id); } // Then we do the same for the other nodes we need the data of (the ones defined in aliases) - builtAliasedNodesIds.forEach((builtAliasNodeId) => { + for (const builtAliasNodeId of builtAliasedNodesIds) { if (equipments.nodesId.find((nodeId) => nodeId === builtAliasNodeId) === undefined) { nodesIdToFetch.add(builtAliasNodeId); } - }); + } return nodesIdToFetch; - }, [currentNode?.id, equipments, builtAliasedNodesIds]); + }, [currentNode?.id, equipments.nodesId, builtAliasedNodesIds]); // effect to unload equipment data when we remove an alias or unbuild an aliased node useEffect(() => { - if (!equipments || !builtAliasedNodesIds) { + if (!equipments || !builtAliasedNodesIds.length || !currentNode?.id) { return; } - const currentNodeId = currentNode?.id as UUID; - let unwantedFetchedNodes = new Set(); - unwantedFetchedNodes = new Set([...unwantedFetchedNodes, ...equipments.nodesId]); + const currentNodeId = currentNode.id; + const unwantedFetchedNodes = new Set(equipments.nodesId); const usedNodesId = new Set(builtAliasedNodesIds); usedNodesId.add(currentNodeId); usedNodesId.forEach((nodeId) => unwantedFetchedNodes.delete(nodeId)); if (unwantedFetchedNodes.size !== 0) { dispatch(removeNodeData(Array.from(unwantedFetchedNodes))); } - }, [builtAliasedNodesIds, currentNode, dispatch, equipments]); + }, [builtAliasedNodesIds, currentNode?.id, dispatch, equipments]); - const updateEquipmentsLocal = useCallback( - ( - impactedSubstationsIds: string[], - deletedEquipments: { equipmentType: string; equipmentId: string }[], - impactedElementTypes: string[] - ) => { + const deleteEquipmentsLocal = useCallback( + (impactedSubstationsIds: UUID[], deletedEquipments: DeletedEquipment[], impactedElementTypes: string[]) => { if (!type) { return; } // updating data related to impacted elements - const nodeId = currentNode?.id as UUID; + const nodeId = currentNode?.id as UUID; //TODO maybe do nothing if no current node? // Handle updates and resets based on impacted element types if (impactedElementTypes.length > 0) { - if (impactedElementTypes.includes(EQUIPMENT_TYPES.SUBSTATION)) { + if (impactedElementTypes.includes(SpreadsheetEquipmentType.SUBSTATION)) { dispatch(resetEquipments()); return; } @@ -180,15 +128,17 @@ export const useSpreadsheetEquipments = ( Object.keys(allEquipments).includes(type) ); if (impactedSpreadsheetEquipmentsTypes.length > 0) { - dispatch(resetEquipmentsByTypes(impactedSpreadsheetEquipmentsTypes as SpreadsheetEquipmentType[])); + dispatch( + resetEquipmentsByTypes(impactedSpreadsheetEquipmentsTypes.filter(isSpreadsheetEquipmentType)) + ); } } if (impactedSubstationsIds.length > 0 && studyUuid && currentRootNetworkUuid && currentNode?.id) { // The formatting of the fetched equipments is done in the reducer if ( - type === EQUIPMENT_TYPES.SUBSTATION || - type === EQUIPMENT_TYPES.VOLTAGE_LEVEL || + type === SpreadsheetEquipmentType.SUBSTATION || + type === SpreadsheetEquipmentType.VOLTAGE_LEVEL || !equipmentToUpdateId ) { // we must fetch data for all equipments, as substation data (country) and voltage level data(nominalV) @@ -201,22 +151,50 @@ export const useSpreadsheetEquipments = ( ); } else { // here, we can fetch only the data for the modified equipment - fetchNetworkElementInfos( - studyUuid, - nodeId, - currentRootNetworkUuid, - type, - 'TAB', - equipmentToUpdateId, - false - ).then((value: Identifiable) => { - highlightUpdatedEquipment(); - const updateType = getEquipmentUpdateTypeFromType(type); - if (updateType) { - const equipmentsToUpdate: Partial> = { - [updateType]: [value], - }; - dispatch(updateEquipments(equipmentsToUpdate, nodeId)); + const promises = [ + fetchNetworkElementInfos( + studyUuid, + nodeId, + currentRootNetworkUuid, + type, + EQUIPMENT_INFOS_TYPES.TAB.type, + equipmentToUpdateId, + false + ), + ]; + if ( + type === SpreadsheetEquipmentType.LINE || + type === SpreadsheetEquipmentType.TWO_WINDINGS_TRANSFORMER + ) { + promises.push( + fetchNetworkElementInfos( + studyUuid, + nodeId, + currentRootNetworkUuid, + SpreadsheetEquipmentType.BRANCH, + EQUIPMENT_INFOS_TYPES.TAB.type, + equipmentToUpdateId, + false + ) + ); + } + Promise.allSettled(promises).then((results) => { + const updates: UpdateEquipmentsAction['equipments'] = {}; + if (results[0].status === 'rejected') { + //TODO show snackbar error? + } else { + updates[type] = results[0].value; + } + if (results.length > 1) { + if (results[1].status === 'rejected') { + //TODO show snackbar error? + } else { + updates[SpreadsheetEquipmentType.BRANCH] = results[1].value; + } + } + if (Object.keys(updates).length > 1) { + highlightUpdatedEquipment(); + dispatch(updateEquipments(updates, nodeId)); } }); } @@ -236,11 +214,12 @@ export const useSpreadsheetEquipments = ( }); if (equipmentsToDelete.length > 0) { - const equipmentsToDeleteArray: EquipmentToDelete[] = equipmentsToDelete.map((equipment) => ({ - equipmentType: equipment.equipmentType as SpreadsheetEquipmentType, - equipmentId: equipment.equipmentId, - nodeId: nodeId, - })); + const equipmentsToDeleteArray = equipmentsToDelete + .filter((e) => isSpreadsheetEquipmentType(e.equipmentType)) + .map((equipment) => ({ + equipmentType: equipment.equipmentType as unknown as SpreadsheetEquipmentType, + equipmentId: equipment.equipmentId, + })); dispatch(deleteEquipments(equipmentsToDeleteArray, nodeId)); } } @@ -269,25 +248,18 @@ export const useSpreadsheetEquipments = ( currentNode?.id === eventNodeUuid && currentRootNetworkUuid === eventRootNetworkUuid ) { - // @ts-ignore const payload = JSON.parse(eventData.payload) as NetworkImpactsInfos; const impactedSubstationsIds = payload.impactedSubstationsIds; const deletedEquipments = payload.deletedEquipments; const impactedElementTypes = payload.impactedElementTypes ?? []; - updateEquipmentsLocal(impactedSubstationsIds, deletedEquipments, impactedElementTypes); + deleteEquipmentsLocal(impactedSubstationsIds, deletedEquipments, impactedElementTypes); } } }, - [currentNode?.id, currentRootNetworkUuid, studyUuid, updateEquipmentsLocal] + [currentNode?.id, currentRootNetworkUuid, studyUuid, deleteEquipmentsLocal] ); - useNotificationsListener(NotificationsUrlKeys.STUDY, { - listenerCallbackMessage: listenerUpdateEquipmentsLocal, - }); - - const onFetchingDone = () => { - setIsFetching(false); - }; + useNotificationsListener(NotificationsUrlKeys.STUDY, { listenerCallbackMessage: listenerUpdateEquipmentsLocal }); // Note: take care about the dependencies because any execution here implies equipment loading (large fetches). // For example, we have 3 currentNode properties in deps rather than currentNode object itself. @@ -301,7 +273,7 @@ export const useSpreadsheetEquipments = ( (currentNode?.type === NodeType.ROOT || isStatusBuilt(currentNode?.data.globalBuildStatus)) ) { setIsFetching(true); - fetchNodesEquipmentData(nodesIdToFetch, currentNode.id, currentRootNetworkUuid, onFetchingDone); + fetchNodesEquipmentData(nodesIdToFetch, currentNode.id, currentRootNetworkUuid, () => setIsFetching(false)); } }, [ active, diff --git a/src/components/spreadsheet-view/spreadsheet/spreadsheet-content/hooks/use-spreadsheet-gs-filter.ts b/src/components/spreadsheet-view/spreadsheet/spreadsheet-content/hooks/use-spreadsheet-gs-filter.ts index 7ec7d5651e..c955d674c9 100644 --- a/src/components/spreadsheet-view/spreadsheet/spreadsheet-content/hooks/use-spreadsheet-gs-filter.ts +++ b/src/components/spreadsheet-view/spreadsheet/spreadsheet-content/hooks/use-spreadsheet-gs-filter.ts @@ -5,16 +5,16 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { RefObject, useCallback, useEffect, useState } from 'react'; -import { FilterChangedEvent, IRowNode } from 'ag-grid-community'; -import { UUID } from 'crypto'; +import { type RefObject, useCallback, useEffect, useState } from 'react'; +import { type FilterChangedEvent, type IRowNode } from 'ag-grid-community'; +import type { UUID } from 'crypto'; import { useSelector } from 'react-redux'; -import { AppState } from '../../../../../redux/reducer'; +import { type AppState } from '../../../../../redux/reducer'; import { evaluateFilters, evaluateJsonFilter } from '../../../../../services/study/filter'; import { buildExpertFilter } from '../../../../dialogs/parameters/dynamicsimulation/curve/dialog/curve-selector-utils'; import { SpreadsheetEquipmentType } from '../../../types/spreadsheet.type'; -import { GlobalFilter } from '../../../../results/common/global-filter/global-filter-types'; -import { AgGridReact } from 'ag-grid-react'; +import type { GlobalFilter } from '../../../../results/common/global-filter/global-filter-types'; +import { type AgGridReact } from 'ag-grid-react'; import { ROW_INDEX_COLUMN_ID } from '../../../constants'; export const refreshSpreadsheetAfterFilterChanged = (event: FilterChangedEvent) => { @@ -89,6 +89,7 @@ export const useSpreadsheetGlobalFilter = ( } const computedFilter = buildExpertFilter( + //@ts-expect-error TODO: what to do with BRANCH type? equipmentType, undefined, countries, diff --git a/src/components/spreadsheet-view/spreadsheet/spreadsheet-content/spreadsheet-content.tsx b/src/components/spreadsheet-view/spreadsheet/spreadsheet-content/spreadsheet-content.tsx index 8c765d22e5..cb4751489f 100644 --- a/src/components/spreadsheet-view/spreadsheet/spreadsheet-content/spreadsheet-content.tsx +++ b/src/components/spreadsheet-view/spreadsheet/spreadsheet-content/spreadsheet-content.tsx @@ -5,17 +5,17 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import { memo, type RefObject, useCallback, useEffect, useMemo, useState } from 'react'; import { useSpreadsheetEquipments } from './hooks/use-spreadsheet-equipments'; import { EquipmentTable } from './equipment-table'; -import { Identifiable } from '@gridsuite/commons-ui'; -import { CustomColDef } from 'components/custom-aggrid/custom-aggrid-filters/custom-aggrid-filter.type'; -import { SpreadsheetTabDefinition } from '../../types/spreadsheet.type'; -import { CurrentTreeNode } from 'components/graph/tree-node.type'; -import { AgGridReact } from 'ag-grid-react'; -import { Alert, Box, Theme } from '@mui/material'; +import { type Identifiable } from '@gridsuite/commons-ui'; +import { type CustomColDef } from 'components/custom-aggrid/custom-aggrid-filters/custom-aggrid-filter.type'; +import { SpreadsheetEquipmentType, type SpreadsheetTabDefinition } from '../../types/spreadsheet.type'; +import { type CurrentTreeNode } from 'components/graph/tree-node.type'; +import { type AgGridReact } from 'ag-grid-react'; +import { Alert, Box, type Theme } from '@mui/material'; import { useEquipmentModification } from './hooks/use-equipment-modification'; -import { NodeAlias } from '../../types/node-alias.type'; +import { type NodeAlias } from '../../types/node-alias.type'; import { FormattedMessage } from 'react-intl'; import { useSpreadsheetGlobalFilter } from './hooks/use-spreadsheet-gs-filter'; import { useFilterSelector } from 'hooks/use-filter-selector'; @@ -23,7 +23,6 @@ import { FilterType } from 'types/custom-aggrid-types'; import { updateFilters } from 'components/custom-aggrid/custom-aggrid-filters/utils/aggrid-filters-utils'; import { useGridCalculations } from 'components/spreadsheet-view/spreadsheet/spreadsheet-content/hooks/use-grid-calculations'; import { useColumnManagement } from './hooks/use-column-management'; -import { EQUIPMENT_TYPES } from 'components/utils/equipment-types'; import { DiagramType } from 'components/diagrams/diagram.type'; import { type FirstDataRenderedEvent } from 'ag-grid-community'; @@ -49,7 +48,7 @@ interface RecursiveIdentifiable extends Identifiable { } interface SpreadsheetContentProps { - gridRef: React.RefObject; + gridRef: RefObject; currentNode: CurrentTreeNode; tableDefinition: SpreadsheetTabDefinition; columns: CustomColDef[]; @@ -62,7 +61,7 @@ interface SpreadsheetContentProps { active: boolean; } -export const SpreadsheetContent = React.memo( +export const SpreadsheetContent = memo( ({ gridRef, currentNode, @@ -211,7 +210,7 @@ export const SpreadsheetContent = React.memo( const handleOpenDiagram = useCallback( (equipmentId: string) => { const diagramType = - tableDefinition?.type === EQUIPMENT_TYPES.SUBSTATION + tableDefinition?.type === SpreadsheetEquipmentType.SUBSTATION ? DiagramType.SUBSTATION : DiagramType.VOLTAGE_LEVEL; openDiagram?.(equipmentId, diagramType); diff --git a/src/components/spreadsheet-view/spreadsheet/spreadsheet-toolbar/global-filter/spreadsheet-global-filter.tsx b/src/components/spreadsheet-view/spreadsheet/spreadsheet-toolbar/global-filter/spreadsheet-global-filter.tsx index 0f55debe83..ab31cc4b57 100644 --- a/src/components/spreadsheet-view/spreadsheet/spreadsheet-toolbar/global-filter/spreadsheet-global-filter.tsx +++ b/src/components/spreadsheet-view/spreadsheet/spreadsheet-toolbar/global-filter/spreadsheet-global-filter.tsx @@ -9,10 +9,10 @@ import type { UUID } from 'crypto'; import { useCallback, useEffect, useMemo } from 'react'; import { debounce } from '@mui/material'; import { useDispatch, useSelector } from 'react-redux'; -import { SpreadsheetTabDefinition } from '../../../types/spreadsheet.type'; -import { AppState } from '../../../../../redux/reducer'; +import { SpreadsheetEquipmentType, type SpreadsheetTabDefinition } from '../../../types/spreadsheet.type'; +import { type AppState } from '../../../../../redux/reducer'; import { setGlobalFiltersToSpreadsheetConfig } from 'services/study/study-config'; -import { GlobalFilter } from '../../../../results/common/global-filter/global-filter-types'; +import type { GlobalFilter } from '../../../../results/common/global-filter/global-filter-types'; import { FilterType } from '../../../../results/common/utils'; import GlobalFilterSelector from '../../../../results/common/global-filter/global-filter-selector'; import { EQUIPMENT_TYPES } from '@powsybl/network-viewer'; @@ -32,7 +32,7 @@ export default function SpreadsheetGlobalFilter({ tableDefinition }: Readonly { if (!studyUuid) { @@ -52,13 +52,14 @@ export default function SpreadsheetGlobalFilter({ tableDefinition }: Readonly { - if (tableDefinition.type === EQUIPMENT_TYPES.SUBSTATION) { - return [...countriesFilter, ...propertiesFilter]; - } else { - return [...voltageLevelsFilter, ...countriesFilter, ...propertiesFilter]; - } - }, [countriesFilter, propertiesFilter, tableDefinition.type, voltageLevelsFilter]); + const filters = useMemo( + () => [ + ...(tableDefinition.type === SpreadsheetEquipmentType.SUBSTATION ? voltageLevelsFilter : []), + ...countriesFilter, + ...propertiesFilter, + ], + [countriesFilter, propertiesFilter, tableDefinition.type, voltageLevelsFilter] + ); useEffect(() => { if (globalFilterSpreadsheetState) { @@ -73,7 +74,7 @@ export default function SpreadsheetGlobalFilter({ tableDefinition }: Readonly { if (currentNode?.id && currentRootNetworkUuid && nodesToReload?.length) { - const nodesIdsToReload = new Set(nodesToReload.map((n) => n.id as string)); + const nodesIdsToReload = new Set(nodesToReload.map((n) => n.id).filter(notUndefined)); fetchNodesEquipmentData(nodesIdsToReload, currentNode.id, currentRootNetworkUuid); } }, [currentNode?.id, currentRootNetworkUuid, fetchNodesEquipmentData, nodesToReload]); diff --git a/src/components/spreadsheet-view/spreadsheet/spreadsheet-toolbar/save/save-spreadsheet-button.tsx b/src/components/spreadsheet-view/spreadsheet/spreadsheet-toolbar/save/save-spreadsheet-button.tsx index 095f2c6802..9ccf3092a1 100644 --- a/src/components/spreadsheet-view/spreadsheet/spreadsheet-toolbar/save/save-spreadsheet-button.tsx +++ b/src/components/spreadsheet-view/spreadsheet/spreadsheet-toolbar/save/save-spreadsheet-button.tsx @@ -5,20 +5,20 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { useState, MouseEvent, useCallback, useMemo, RefObject } from 'react'; +import { type MouseEvent, type RefObject, useCallback, useMemo, useState } from 'react'; import { Button, Menu, MenuItem } from '@mui/material'; import { FormattedMessage } from 'react-intl'; import SaveIcon from '@mui/icons-material/Save'; import SaveSpreadsheetDialog from './save-spreadsheet-dialog'; -import { useCsvExport, useStateBoolean, FILTER_EQUIPMENTS } from '@gridsuite/commons-ui'; -import { NodeAlias } from '../../../types/node-alias.type'; +import { EquipmentType, FILTER_EQUIPMENTS, useCsvExport, useStateBoolean } from '@gridsuite/commons-ui'; +import type { NodeAlias } from '../../../types/node-alias.type'; import { ROW_INDEX_COLUMN_ID } from '../../../constants'; -import { SpreadsheetTabDefinition } from '../../../types/spreadsheet.type'; -import { AgGridReact } from 'ag-grid-react'; -import { ColDef } from 'ag-grid-community'; +import { SpreadsheetEquipmentType, type SpreadsheetTabDefinition } from '../../../types/spreadsheet.type'; +import type { AgGridReact } from 'ag-grid-react'; +import type { ColDef } from 'ag-grid-community'; import { spreadsheetStyles } from '../../../spreadsheet.style'; import { useSelector } from 'react-redux'; -import { AppState } from '../../../../../redux/reducer'; +import type { AppState } from '../../../../../redux/reducer'; import SaveNamingFilterDialog from './save-naming-filter-dialog'; enum SpreadsheetSaveOptionId { @@ -57,15 +57,10 @@ export default function SaveSpreadsheetButton({ const { downloadCSVData } = useCsvExport(); const language = useSelector((state: AppState) => state.computedLanguage); - const handleClick = useCallback((event: MouseEvent) => { - setAnchorEl(event.currentTarget); - }, []); + const handleClick = useCallback((event: MouseEvent) => setAnchorEl(event.currentTarget), []); + const handleClose = useCallback(() => setAnchorEl(null), []); - const handleClose = useCallback(() => { - setAnchorEl(null); - }, []); - - const spreadsheetOptions = useMemo( + const spreadsheetOptions = useMemo>( () => ({ [SpreadsheetSaveOptionId.SAVE_MODEL]: { id: SpreadsheetSaveOptionId.SAVE_MODEL, @@ -76,16 +71,14 @@ export default function SaveSpreadsheetButton({ id: SpreadsheetSaveOptionId.EXPORT_CSV, label: 'spreadsheet/save/options/csv', action: () => { - // Filter out the rowIndex column and the hidden columns before exporting to CSV - const columnsForExport = columns.filter((col) => col.colId !== ROW_INDEX_COLUMN_ID && !col.hide); - const exportDataAsCsv = gridRef.current?.api.exportDataAsCsv; if (!exportDataAsCsv) { console.error('Export API is not available.'); return; } downloadCSVData({ - columns: columnsForExport, + // Filter out the rowIndex column and the hidden columns before exporting to CSV + columns: columns.filter((col) => col.colId !== ROW_INDEX_COLUMN_ID && !col.hide), tableName: tableDefinition.name, language: language, exportDataAsCsv, @@ -97,7 +90,12 @@ export default function SaveSpreadsheetButton({ id: SpreadsheetSaveOptionId.SAVE_FILTER, label: 'spreadsheet/save/options/filter', action: saveFilterDialogOpen.setTrue, - disabled: dataSize === 0 || !FILTER_EQUIPMENTS[tableDefinition.type], + disabled: + dataSize === 0 || + (tableDefinition.type === SpreadsheetEquipmentType.BRANCH + ? !FILTER_EQUIPMENTS[EquipmentType.LINE] || + !FILTER_EQUIPMENTS[EquipmentType.TWO_WINDINGS_TRANSFORMER] + : !FILTER_EQUIPMENTS[tableDefinition.type as unknown as EquipmentType]), }, }), [ @@ -121,17 +119,6 @@ export default function SaveSpreadsheetButton({ [spreadsheetOptions, handleClose] ); - const renderMenuItem = useCallback( - (option: SpreadsheetSaveOption) => { - return ( - handleMenuItemClick(option.id)} disabled={option?.disabled}> - - - ); - }, - [handleMenuItemClick] - ); - return ( <> - {Object.values(spreadsheetOptions).map(renderMenuItem)} + {Object.values(spreadsheetOptions).map((option) => ( + handleMenuItemClick(option.id)} + disabled={option?.disabled} + > + + + ))} Promise; +export enum SpreadsheetEquipmentType { + BATTERY = 'BATTERY', + BRANCH = 'BRANCH', // LINE + TWO_WINDINGS_TRANSFORMER + BUS = 'BUS', + BUSBAR_SECTION = 'BUSBAR_SECTION', + DANGLING_LINE = 'DANGLING_LINE', + GENERATOR = 'GENERATOR', + HVDC_LINE = 'HVDC_LINE', + LCC_CONVERTER_STATION = 'LCC_CONVERTER_STATION', + LINE = 'LINE', + LOAD = 'LOAD', + SHUNT_COMPENSATOR = 'SHUNT_COMPENSATOR', + STATIC_VAR_COMPENSATOR = 'STATIC_VAR_COMPENSATOR', + SUBSTATION = 'SUBSTATION', + THREE_WINDINGS_TRANSFORMER = 'THREE_WINDINGS_TRANSFORMER', + TIE_LINE = 'TIE_LINE', + TWO_WINDINGS_TRANSFORMER = 'TWO_WINDINGS_TRANSFORMER', + VOLTAGE_LEVEL = 'VOLTAGE_LEVEL', + VSC_CONVERTER_STATION = 'VSC_CONVERTER_STATION', +} + +export function isSpreadsheetEquipmentType(type: string): type is SpreadsheetEquipmentType { + return type in SpreadsheetEquipmentType; +} -export type SpreadsheetEquipmentType = Exclude< - EQUIPMENT_TYPES, - | EQUIPMENT_TYPES.HVDC_CONVERTER_STATION - | EQUIPMENT_TYPES.SWITCH - | EQUIPMENT_TYPES.BREAKER - | EQUIPMENT_TYPES.DISCONNECTOR ->; +export type EditableEquipmentType = + | SpreadsheetEquipmentType.SUBSTATION + | SpreadsheetEquipmentType.VOLTAGE_LEVEL + | SpreadsheetEquipmentType.LINE + | SpreadsheetEquipmentType.TWO_WINDINGS_TRANSFORMER + | SpreadsheetEquipmentType.GENERATOR + | SpreadsheetEquipmentType.LOAD + | SpreadsheetEquipmentType.BATTERY + | SpreadsheetEquipmentType.SHUNT_COMPENSATOR; export interface SpreadsheetTabDefinition { uuid: UUID; @@ -62,8 +81,8 @@ export type ColumnStateDto = { }; export type SpreadsheetEquipmentsByNodes = { - nodesId: string[]; - equipmentsByNodeId: Record; + nodesId: UUID[]; + equipmentsByNodeId: Record; }; export type SpreadsheetConfig = { diff --git a/src/components/utils/ts-utils.ts b/src/components/utils/ts-utils.ts index 32724b9b66..22926c9ded 100644 --- a/src/components/utils/ts-utils.ts +++ b/src/components/utils/ts-utils.ts @@ -8,3 +8,11 @@ export type Nullable = { [K in keyof T]: T[K] | null }; export type DeepNullable = { [K in keyof T]: DeepNullable | null; }; + +export function notUndefined(value: T | undefined): value is T { + return value !== undefined; +} + +export function notNull(value: T | null): value is T { + return value !== null; +} diff --git a/src/hooks/use-get-study-impacts.ts b/src/hooks/use-get-study-impacts.ts index bd7c5f4a4e..ac0f3578ed 100644 --- a/src/hooks/use-get-study-impacts.ts +++ b/src/hooks/use-get-study-impacts.ts @@ -59,10 +59,7 @@ export const useGetStudyImpacts = (): StudyImpactsWithReset => { impactedSubstationsIds: substationsIds, deletedEquipments, impactedElementTypes, - } = JSON.parse( - // @ts-ignore - eventData.payload - ) as NetworkImpactsInfos; + } = JSON.parse(eventData.payload) as NetworkImpactsInfos; if (impactedElementTypes?.length > 0) { setImpactedElementTypes(impactedElementTypes); diff --git a/src/redux/actions.ts b/src/redux/actions.ts index 91fadd39a8..d83cfc613a 100644 --- a/src/redux/actions.ts +++ b/src/redux/actions.ts @@ -13,33 +13,32 @@ import { PARAM_USE_NAME, PARAMS_LOADED, } from '../utils/config-params'; -import { Action } from 'redux'; +import type { Action } from 'redux'; import { - GsLang, - GsLangUser, - GsTheme, - Identifiable, - NetworkVisualizationParameters, ComputingType, + type GsLang, + type GsLangUser, + type GsTheme, + type Identifiable, + type NetworkVisualizationParameters, } from '@gridsuite/commons-ui'; -import { UUID } from 'crypto'; +import type { UUID } from 'crypto'; import type { UnknownArray } from 'type-fest'; -import NetworkModificationTreeModel from '../components/graph/network-modification-tree-model'; +import type NetworkModificationTreeModel from '../components/graph/network-modification-tree-model'; import type { MapHvdcLine, MapLine, MapSubstation, MapTieLine } from '@powsybl/network-viewer'; import type { AppState, - EquipmentUpdateType, + ComputingStatusParameters, + DiagramGridLayoutConfig, GlobalFilterSpreadsheetState, NodeSelectionForCopy, OneBusShortCircuitAnalysisDiagram, SpreadsheetFilterState, TableSortKeysType, - ComputingStatusParameters, - DiagramGridLayoutConfig, } from './reducer'; -import { RunningStatus } from '../components/utils/running-status'; -import { IOptionalService } from '../components/utils/optional-services'; -import { GlobalFilter } from '../components/results/common/global-filter/global-filter-types'; +import type { RunningStatus } from '../components/utils/running-status'; +import type { IOptionalService } from '../components/utils/optional-services'; +import type { GlobalFilter } from '../components/results/common/global-filter/global-filter-types'; import { DYNAMIC_SIMULATION_RESULT_STORE_FIELD, LOADFLOW_RESULT_STORE_FIELD, @@ -54,15 +53,15 @@ import { StudyDisplayMode } from '../components/network-modification.type'; import { CurrentTreeNode, NetworkModificationNodeData, RootNodeData } from '../components/graph/tree-node.type'; import type GSMapEquipments from 'components/network/gs-map-equipments'; import { - SpreadsheetEquipmentsByNodes, - ColumnDefinition, + type ColumnDefinition, + type SpreadsheetEquipmentsByNodes, SpreadsheetEquipmentType, - SpreadsheetTabDefinition, + type SpreadsheetTabDefinition, } from '../components/spreadsheet-view/types/spreadsheet.type'; import { FilterConfig, SortConfig } from '../types/custom-aggrid-types'; import type { DiagramType } from '../components/diagrams/diagram.type'; -import { RootNetworkMetadata } from 'components/graph/menus/network-modifications/network-modification-menu.type'; -import { NodeInsertModes, RootNetworkIndexationStatus, StudyUpdateEventData } from 'types/notification-types'; +import type { RootNetworkMetadata } from 'components/graph/menus/network-modifications/network-modification-menu.type'; +import type { NodeInsertModes, RootNetworkIndexationStatus, StudyUpdateEventData } from 'types/notification-types'; export type TableValue = { uuid: UUID; @@ -225,13 +224,13 @@ export function removeEquipmentData(equipmentType: SpreadsheetEquipmentType): Re export const UPDATE_EQUIPMENTS = 'UPDATE_EQUIPMENTS'; export type UpdateEquipmentsAction = Readonly> & { - equipments: Partial>; + equipments: Partial>; nodeId: UUID; }; export function updateEquipments( - equipments: Partial>, - nodeId: UUID + equipments: UpdateEquipmentsAction['equipments'], + nodeId: UpdateEquipmentsAction['nodeId'] ): UpdateEquipmentsAction { return { type: UPDATE_EQUIPMENTS, @@ -676,11 +675,11 @@ export function setModificationsDrawerOpen(): SetModificationsDrawerOpenAction { } export const SET_TOGGLE_OPTIONS = 'SET_TOGGLE_OPTIONS'; -export type setToggleOptionsAction = Readonly> & { +export type SetToggleOptionsAction = Readonly> & { toggleOptions: StudyDisplayMode[]; }; -export function setToggleOptions(toggleOptions: StudyDisplayMode[]): setToggleOptionsAction { +export function setToggleOptions(toggleOptions: StudyDisplayMode[]): SetToggleOptionsAction { return { type: SET_TOGGLE_OPTIONS, toggleOptions: toggleOptions, diff --git a/src/redux/reducer.ts b/src/redux/reducer.ts index 9b84f62b25..0703d02ea5 100644 --- a/src/redux/reducer.ts +++ b/src/redux/reducer.ts @@ -5,29 +5,29 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { createReducer, Draft } from '@reduxjs/toolkit'; +import { createReducer, type Draft } from '@reduxjs/toolkit'; import { - AuthenticationActions, - AuthenticationRouterErrorAction, - AuthenticationRouterErrorState, - CommonStoreState, - GsLang, - GsLangUser, - GsTheme, - Identifiable, + type AuthenticationActions, + type AuthenticationRouterErrorAction, + type AuthenticationRouterErrorState, + type CommonStoreState, + ComputingType, + type GsLang, + type GsLangUser, + type GsTheme, + type Identifiable, LOGOUT_ERROR, - LogoutErrorAction, + type LogoutErrorAction, + type NetworkVisualizationParameters, RESET_AUTHENTICATION_ROUTER_ERROR, SHOW_AUTH_INFO_LOGIN, - ShowAuthenticationRouterLoginAction, + type ShowAuthenticationRouterLoginAction, UNAUTHORIZED_USER_INFO, - UnauthorizedUserAction, + type UnauthorizedUserAction, USER, USER_VALIDATION_ERROR, - UserAction, - UserValidationErrorAction, - NetworkVisualizationParameters, - ComputingType, + type UserAction, + type UserValidationErrorAction, } from '@gridsuite/commons-ui'; import { EQUIPMENT_TYPES } from 'components/utils/equipment-types'; import { @@ -35,172 +35,172 @@ import { ADD_NOTIFICATION, ADD_SORT_FOR_NEW_SPREADSHEET, ADD_TO_RECENT_GLOBAL_FILTERS, - AddFilterForNewSpreadsheetAction, - AddNotificationAction, - AddSortForNewSpreadsheetAction, - AddToRecentGlobalFiltersAction, - AppActions, + type AddFilterForNewSpreadsheetAction, + type AddNotificationAction, + type AddSortForNewSpreadsheetAction, + type AddToRecentGlobalFiltersAction, + type AppActions, ATTEMPT_LEAVE_PARAMETERS_TAB, - AttemptLeaveParametersTabAction, + type AttemptLeaveParametersTabAction, CANCEL_LEAVE_PARAMETERS_TAB, CENTER_ON_SUBSTATION, - CenterOnSubstationAction, + type CenterOnSubstationAction, CLOSE_STUDY, - CloseStudyAction, + type CloseStudyAction, CONFIRM_LEAVE_PARAMETERS_TAB, CURRENT_ROOT_NETWORK_UUID, CURRENT_TREE_NODE, - CurrentRootNetworkUuidAction, - CurrentTreeNodeAction, + type CurrentRootNetworkUuidAction, + type CurrentTreeNodeAction, DELETE_EQUIPMENTS, - DeleteEquipmentsAction, + DELETED_OR_RENAMED_NODES, + type DeletedOrRenamedNodesAction, + type DeleteEquipmentsAction, DYNAMIC_SIMULATION_RESULT_FILTER, - DynamicSimulationResultFilterAction, + type DynamicSimulationResultFilterAction, ENABLE_DEVELOPER_MODE, - EnableDeveloperModeAction, + type EnableDeveloperModeAction, FAVORITE_CONTINGENCY_LISTS, - FavoriteContingencyListsAction, + type FavoriteContingencyListsAction, INIT_TABLE_DEFINITIONS, - InitTableDefinitionsAction, + type InitTableDefinitionsAction, LOAD_EQUIPMENTS, LOAD_NETWORK_MODIFICATION_TREE_SUCCESS, - LoadEquipmentsAction, + type LoadEquipmentsAction, LOADFLOW_RESULT_FILTER, - LoadflowResultFilterAction, - LoadNetworkModificationTreeSuccessAction, + type LoadflowResultFilterAction, + type LoadNetworkModificationTreeSuccessAction, LOGS_FILTER, - LogsFilterAction, + type LogsFilterAction, MAP_DATA_LOADING, MAP_EQUIPMENTS_CREATED, MAP_EQUIPMENTS_INITIALIZED, - MapDataLoadingAction, - MapEquipmentsCreatedAction, - MapEquipmentsInitializedAction, + type MapDataLoadingAction, + type MapEquipmentsCreatedAction, + type MapEquipmentsInitializedAction, NETWORK_MODIFICATION_HANDLE_SUBTREE, NETWORK_MODIFICATION_TREE_NODE_ADDED, NETWORK_MODIFICATION_TREE_NODE_MOVED, NETWORK_MODIFICATION_TREE_NODES_REMOVED, NETWORK_MODIFICATION_TREE_NODES_REORDER, NETWORK_MODIFICATION_TREE_NODES_UPDATED, - NetworkModificationHandleSubtreeAction, - NetworkModificationTreeNodeAddedAction, - NetworkModificationTreeNodeMovedAction, - NetworkModificationTreeNodesRemovedAction, - NetworkModificationTreeNodesReorderAction, - NetworkModificationTreeNodesUpdatedAction, + type NetworkModificationHandleSubtreeAction, + type NetworkModificationTreeNodeAddedAction, + type NetworkModificationTreeNodeMovedAction, + type NetworkModificationTreeNodesRemovedAction, + type NetworkModificationTreeNodesReorderAction, + type NetworkModificationTreeNodesUpdatedAction, NODE_SELECTION_FOR_COPY, - NodeSelectionForCopyAction, + type NodeSelectionForCopyAction, OPEN_DIAGRAM, OPEN_NAD_LIST, OPEN_STUDY, - OpenDiagramAction, - OpenNadListAction, - OpenStudyAction, + type OpenDiagramAction, + type OpenNadListAction, + type OpenStudyAction, + type ParameterizedComputingType, REMOVE_COLUMN_DEFINITION, + REMOVE_EQUIPMENT_DATA, REMOVE_FROM_RECENT_GLOBAL_FILTERS, REMOVE_NODE_DATA, REMOVE_NOTIFICATION_BY_NODE, REMOVE_TABLE_DEFINITION, - RemoveColumnDefinitionAction, - RemoveFromRecentGlobalFiltersAction, - RemoveNodeDataAction, - RemoveNotificationByNodeAction, - RemoveTableDefinitionAction, + type RemoveColumnDefinitionAction, + type RemoveEquipmentDataAction, + type RemoveFromRecentGlobalFiltersAction, + type RemoveNodeDataAction, + type RemoveNotificationByNodeAction, + type RemoveTableDefinitionAction, RENAME_TABLE_DEFINITION, - RenameTableDefinitionAction, + type RenameTableDefinitionAction, REORDER_TABLE_DEFINITIONS, - ReorderTableDefinitionsAction, + type ReorderTableDefinitionsAction, RESET_ALL_SPREADSHEET_GS_FILTERS, + RESET_DIAGRAM_EVENT, RESET_EQUIPMENTS, RESET_EQUIPMENTS_BY_TYPES, RESET_EQUIPMENTS_POST_COMPUTATION, RESET_LOGS_FILTER, RESET_MAP_EQUIPMENTS, - ResetAllSpreadsheetGlobalFiltersAction, - ResetEquipmentsAction, - ResetEquipmentsByTypesAction, - ResetEquipmentsPostComputationAction, - ResetLogsFilterAction, - ResetMapEquipmentsAction, + type ResetAllSpreadsheetGlobalFiltersAction, + type ResetDiagramEventAction, + type ResetEquipmentsAction, + type ResetEquipmentsByTypesAction, + type ResetEquipmentsPostComputationAction, + type ResetLogsFilterAction, + type ResetMapEquipmentsAction, SAVE_SPREADSHEET_GS_FILTER, - SaveSpreadSheetGlobalFilterAction, + type SaveSpreadSheetGlobalFilterAction, SECURITY_ANALYSIS_RESULT_FILTER, - SecurityAnalysisResultFilterAction, + type SecurityAnalysisResultFilterAction, SELECT_COMPUTED_LANGUAGE, SELECT_LANGUAGE, SELECT_THEME, - SelectComputedLanguageAction, - SelectLanguageAction, - SelectThemeAction, + type SelectComputedLanguageAction, + type SelectLanguageAction, + type SelectThemeAction, SENSITIVITY_ANALYSIS_RESULT_FILTER, - SensitivityAnalysisResultFilterAction, + type SensitivityAnalysisResultFilterAction, SET_APP_TAB_INDEX, SET_CALCULATION_SELECTIONS, SET_COMPUTATION_STARTING, SET_COMPUTING_STATUS, + SET_COMPUTING_STATUS_INFOS, + SET_DIAGRAM_GRID_LAYOUT, SET_LAST_COMPLETED_COMPUTATION, SET_MODIFICATIONS_DRAWER_OPEN, SET_MODIFICATIONS_IN_PROGRESS, + SET_MONO_ROOT_STUDY, SET_ONE_BUS_SHORTCIRCUIT_ANALYSIS_DIAGRAM, + SET_OPEN_MAP, SET_OPTIONAL_SERVICES, SET_PARAMS_LOADED, - SET_ROOT_NETWORKS, SET_RELOAD_MAP_NEEDED, - SET_STUDY_DISPLAY_MODE, SET_ROOT_NETWORK_INDEXATION_STATUS, - SetAppTabIndexAction, - SetCalculationSelectionsAction, - SetComputationStartingAction, - SetComputingStatusAction, - SetLastCompletedComputationAction, - SetModificationsDrawerOpenAction, - SetModificationsInProgressAction, - SetOneBusShortcircuitAnalysisDiagramAction, - SetOptionalServicesAction, - SetParamsLoadedAction, - SetRootNetworksAction, - SetReloadMapNeededAction, - SetStudyDisplayModeAction, - SetRootNetworkIndexationStatusAction, + SET_ROOT_NETWORKS, + SET_STUDY_DISPLAY_MODE, + SET_TOGGLE_OPTIONS, + type SetAppTabIndexAction, + type SetCalculationSelectionsAction, + type SetComputationStartingAction, + type SetComputingStatusAction, + type SetComputingStatusParametersAction, + type SetDiagramGridLayoutAction, + type SetLastCompletedComputationAction, + type SetModificationsDrawerOpenAction, + type SetModificationsInProgressAction, + type SetMonoRootStudyAction, + type SetOneBusShortcircuitAnalysisDiagramAction, + type SetOpenMapAction, + type SetOptionalServicesAction, + type SetParamsLoadedAction, + type SetReloadMapNeededAction, + type SetRootNetworkIndexationStatusAction, + type SetRootNetworksAction, + type SetStudyDisplayModeAction, + type SetToggleOptionsAction, SHORTCIRCUIT_ANALYSIS_RESULT_FILTER, - ShortcircuitAnalysisResultFilterAction, + type ShortcircuitAnalysisResultFilterAction, SPREADSHEET_FILTER, - SpreadsheetFilterAction, + type SpreadsheetFilterAction, STATEESTIMATION_RESULT_FILTER, - StateEstimationResultFilterAction, + type StateEstimationResultFilterAction, STUDY_UPDATED, - StudyUpdatedAction, + type StudyUpdatedAction, TABLE_SORT, - TableSortAction, + type TableSortAction, UPDATE_COLUMNS_DEFINITION, UPDATE_EQUIPMENTS, UPDATE_NETWORK_VISUALIZATION_PARAMETERS, + UPDATE_TABLE_COLUMNS, UPDATE_TABLE_DEFINITION, - UpdateColumnsDefinitionsAction, - UpdateEquipmentsAction, - UpdateNetworkVisualizationParametersAction, - UpdateTableDefinitionAction, + type UpdateColumnsDefinitionsAction, + type UpdateEquipmentsAction, + type UpdateNetworkVisualizationParametersAction, + type UpdateTableColumnsAction, + type UpdateTableDefinitionAction, USE_NAME, - UseNameAction, - DELETED_OR_RENAMED_NODES, - DeletedOrRenamedNodesAction, - REMOVE_EQUIPMENT_DATA, - RemoveEquipmentDataAction, - UPDATE_TABLE_COLUMNS, - UpdateTableColumnsAction, - SET_MONO_ROOT_STUDY, - SetMonoRootStudyAction, - RESET_DIAGRAM_EVENT, - ResetDiagramEventAction, - SET_COMPUTING_STATUS_INFOS, - SetComputingStatusParametersAction, - ParameterizedComputingType, - SET_DIAGRAM_GRID_LAYOUT, - SetDiagramGridLayoutAction, - SET_TOGGLE_OPTIONS, - setToggleOptionsAction, - SET_OPEN_MAP, - SetOpenMapAction, + type UseNameAction, } from './actions'; import { getLocalStorageComputedLanguage, @@ -224,7 +224,11 @@ import { import NetworkModificationTreeModel from '../components/graph/network-modification-tree-model'; import { getAllChildren, getNetworkModificationNode } from 'components/graph/util/model-functions'; import { RunningStatus } from 'components/utils/running-status'; -import { IOptionalService, OptionalServicesNames, OptionalServicesStatus } from '../components/utils/optional-services'; +import { + type IOptionalService, + OptionalServicesNames, + OptionalServicesStatus, +} from '../components/utils/optional-services'; import { ALL_BUSES, DYNAMIC_SIMULATION_RESULT_SORT_STORE, @@ -259,33 +263,33 @@ import { TABLE_SORT_STORE, TIMELINE, } from '../utils/store-sort-filter-fields'; -import { UUID } from 'crypto'; -import { GlobalFilter } from '../components/results/common/global-filter/global-filter-types'; -import type { ValueOf } from 'type-fest'; +import type { UUID } from 'crypto'; +import type { GlobalFilter } from '../components/results/common/global-filter/global-filter-types'; +import type { Entries, ValueOf } from 'type-fest'; import { CopyType, StudyDisplayMode } from '../components/network-modification.type'; import { CurrentTreeNode, - NetworkModificationNodeInfos, NetworkModificationNodeData, + NetworkModificationNodeInfos, NetworkModificationNodeType, RootNodeData, } from '../components/graph/tree-node.type'; import { COMPUTING_AND_NETWORK_MODIFICATION_TYPE } from '../utils/report/report.constant'; -import GSMapEquipments from 'components/network/gs-map-equipments'; +import type GSMapEquipments from 'components/network/gs-map-equipments'; import { - ColumnDefinition, - SpreadsheetEquipmentsByNodes, + type ColumnDefinition, + type SpreadsheetEquipmentsByNodes, SpreadsheetEquipmentType, - SpreadsheetTabDefinition, + type SpreadsheetTabDefinition, } from '../components/spreadsheet-view/types/spreadsheet.type'; import { FilterConfig, SortConfig, SortWay } from '../types/custom-aggrid-types'; import { DiagramParams, DiagramType } from '../components/diagrams/diagram.type'; import { RootNetworkMetadata } from 'components/graph/menus/network-modifications/network-modification-menu.type'; import { CalculationType } from 'components/spreadsheet-view/types/calculation.type'; -import { NodeInsertModes, RootNetworkIndexationStatus, StudyUpdateNotification } from 'types/notification-types'; +import { NodeInsertModes, RootNetworkIndexationStatus, type StudyUpdateNotification } from 'types/notification-types'; import { mapSpreadsheetEquipments } from '../utils/spreadsheet-equipments-mapper'; import { Layouts } from 'react-grid-layout'; -import { DiagramConfigPosition } from '../services/explore'; +import { type DiagramConfigPosition } from '../services/explore'; // Redux state export type StudyUpdated = { @@ -534,27 +538,27 @@ const emptySpreadsheetEquipmentsByNodes: SpreadsheetEquipmentsByNodes = { export type SpreadsheetNetworkState = Record; const initialSpreadsheetNetworkState: SpreadsheetNetworkState = { - [EQUIPMENT_TYPES.SUBSTATION]: emptySpreadsheetEquipmentsByNodes, - [EQUIPMENT_TYPES.VOLTAGE_LEVEL]: emptySpreadsheetEquipmentsByNodes, - [EQUIPMENT_TYPES.LINE]: emptySpreadsheetEquipmentsByNodes, - [EQUIPMENT_TYPES.TWO_WINDINGS_TRANSFORMER]: emptySpreadsheetEquipmentsByNodes, - [EQUIPMENT_TYPES.THREE_WINDINGS_TRANSFORMER]: emptySpreadsheetEquipmentsByNodes, - [EQUIPMENT_TYPES.GENERATOR]: emptySpreadsheetEquipmentsByNodes, - [EQUIPMENT_TYPES.LOAD]: emptySpreadsheetEquipmentsByNodes, - [EQUIPMENT_TYPES.BATTERY]: emptySpreadsheetEquipmentsByNodes, - [EQUIPMENT_TYPES.DANGLING_LINE]: emptySpreadsheetEquipmentsByNodes, - [EQUIPMENT_TYPES.TIE_LINE]: emptySpreadsheetEquipmentsByNodes, - [EQUIPMENT_TYPES.HVDC_LINE]: emptySpreadsheetEquipmentsByNodes, - [EQUIPMENT_TYPES.LCC_CONVERTER_STATION]: emptySpreadsheetEquipmentsByNodes, - [EQUIPMENT_TYPES.VSC_CONVERTER_STATION]: emptySpreadsheetEquipmentsByNodes, - [EQUIPMENT_TYPES.SHUNT_COMPENSATOR]: emptySpreadsheetEquipmentsByNodes, - [EQUIPMENT_TYPES.STATIC_VAR_COMPENSATOR]: emptySpreadsheetEquipmentsByNodes, - [EQUIPMENT_TYPES.BUS]: emptySpreadsheetEquipmentsByNodes, - [EQUIPMENT_TYPES.BUSBAR_SECTION]: emptySpreadsheetEquipmentsByNodes, + [SpreadsheetEquipmentType.BATTERY]: emptySpreadsheetEquipmentsByNodes, + [SpreadsheetEquipmentType.BRANCH]: emptySpreadsheetEquipmentsByNodes, + [SpreadsheetEquipmentType.BUS]: emptySpreadsheetEquipmentsByNodes, + [SpreadsheetEquipmentType.BUSBAR_SECTION]: emptySpreadsheetEquipmentsByNodes, + [SpreadsheetEquipmentType.DANGLING_LINE]: emptySpreadsheetEquipmentsByNodes, + [SpreadsheetEquipmentType.GENERATOR]: emptySpreadsheetEquipmentsByNodes, + [SpreadsheetEquipmentType.HVDC_LINE]: emptySpreadsheetEquipmentsByNodes, + [SpreadsheetEquipmentType.LCC_CONVERTER_STATION]: emptySpreadsheetEquipmentsByNodes, + [SpreadsheetEquipmentType.LINE]: emptySpreadsheetEquipmentsByNodes, + [SpreadsheetEquipmentType.LOAD]: emptySpreadsheetEquipmentsByNodes, + [SpreadsheetEquipmentType.SHUNT_COMPENSATOR]: emptySpreadsheetEquipmentsByNodes, + [SpreadsheetEquipmentType.STATIC_VAR_COMPENSATOR]: emptySpreadsheetEquipmentsByNodes, + [SpreadsheetEquipmentType.SUBSTATION]: emptySpreadsheetEquipmentsByNodes, + [SpreadsheetEquipmentType.THREE_WINDINGS_TRANSFORMER]: emptySpreadsheetEquipmentsByNodes, + [SpreadsheetEquipmentType.TIE_LINE]: emptySpreadsheetEquipmentsByNodes, + [SpreadsheetEquipmentType.TWO_WINDINGS_TRANSFORMER]: emptySpreadsheetEquipmentsByNodes, + [SpreadsheetEquipmentType.VOLTAGE_LEVEL]: emptySpreadsheetEquipmentsByNodes, + [SpreadsheetEquipmentType.VSC_CONVERTER_STATION]: emptySpreadsheetEquipmentsByNodes, }; export type GlobalFilterSpreadsheetState = Record; -const initialGlobalFilterSpreadsheet: GlobalFilterSpreadsheetState = {}; interface TablesState { uuid: UUID | null; @@ -611,7 +615,7 @@ const initialState: AppState = { isMapEquipmentsInitialized: false, networkAreaDiagramDepth: 0, spreadsheetNetwork: { ...initialSpreadsheetNetworkState }, - globalFilterSpreadsheetState: initialGlobalFilterSpreadsheet, + globalFilterSpreadsheetState: {}, diagramGridLayout: { gridLayouts: {}, params: [], @@ -1173,7 +1177,7 @@ export const reducer = createReducer(initialState, (builder) => { } }); - builder.addCase(SET_TOGGLE_OPTIONS, (state, action: setToggleOptionsAction) => { + builder.addCase(SET_TOGGLE_OPTIONS, (state, action: SetToggleOptionsAction) => { state.toggleOptions = action.toggleOptions; if (state.studyUuid) { saveLocalStorageToggleOptions(state.studyUuid, state.toggleOptions); @@ -1278,7 +1282,11 @@ export const reducer = createReducer(initialState, (builder) => { }); builder.addCase(LOAD_EQUIPMENTS, (state, action: LoadEquipmentsAction) => { - Object.entries(action.spreadsheetEquipmentByNodes.equipmentsByNodeId).forEach(([nodeId, equipments]) => { + ( + Object.entries(action.spreadsheetEquipmentByNodes.equipmentsByNodeId) as Entries< + LoadEquipmentsAction['spreadsheetEquipmentByNodes']['equipmentsByNodeId'] + > + ).forEach(([nodeId, equipments]) => { state.spreadsheetNetwork[action.equipmentType].equipmentsByNodeId[nodeId] = equipments; }); //to remove duplicate @@ -1323,31 +1331,23 @@ export const reducer = createReducer(initialState, (builder) => { builder.addCase(UPDATE_EQUIPMENTS, (state, action: UpdateEquipmentsAction) => { // for now, this action receives an object containing all equipments from a substation - // it will be modified when the notifications received after a network modification will be more precise - const updatedEquipments = action.equipments; - - // equipmentType : type of equipment updated - // equipments : list of updated equipments of type - for (const [updateType, equipments] of Object.entries(updatedEquipments) as [ - EquipmentUpdateType, + // it will be modified when the notifications received after a network modification are more precise + // equipmentType: type of equipment updated + // equipments: list of updated equipments of type + for (const [equipmentType, equipments] of Object.entries(action.equipments) as [ + SpreadsheetEquipmentType, Identifiable[], ][]) { - const equipmentType = getEquipmentTypeFromUpdateType(updateType); const currentEquipment: Identifiable[] | undefined = - // @ts-expect-error TODO manage undefined value case state.spreadsheetNetwork[equipmentType]?.equipmentsByNodeId[action.nodeId]; // Format the updated equipments to match the table format - const formattedEquipments = mapSpreadsheetEquipments( - // @ts-expect-error TODO manage undefined value case - equipmentType, - equipments - ); + const formattedEquipments = mapSpreadsheetEquipments(equipmentType, equipments); // if the equipments are not loaded into the store yet, we don't have to update them - if (currentEquipment != null) { + if (currentEquipment !== undefined) { //since substations data contains voltage level ones, they have to be treated separately - if (equipmentType === EQUIPMENT_TYPES.SUBSTATION) { + if (equipmentType === SpreadsheetEquipmentType.SUBSTATION) { const [updatedSubstations, updatedVoltageLevels] = updateSubstationsAndVoltageLevels( state.spreadsheetNetwork[EQUIPMENT_TYPES.SUBSTATION].equipmentsByNodeId[ action.nodeId @@ -1365,7 +1365,6 @@ export const reducer = createReducer(initialState, (builder) => { updatedVoltageLevels; } } else { - // @ts-expect-error TODO manage undefined value case state.spreadsheetNetwork[equipmentType].equipmentsByNodeId[action.nodeId] = updateEquipments( currentEquipment, formattedEquipments @@ -1381,13 +1380,13 @@ export const reducer = createReducer(initialState, (builder) => { state.spreadsheetNetwork[equipmentToDeleteType]?.equipmentsByNodeId[action.nodeId]; if (currentEquipments !== undefined) { // in case of voltage level deletion, we need to update the linked substation which contains a list of its voltage levels - if (equipmentToDeleteType === EQUIPMENT_TYPES.VOLTAGE_LEVEL) { - const currentSubstations = state.spreadsheetNetwork[EQUIPMENT_TYPES.SUBSTATION].equipmentsByNodeId[ - action.nodeId - ] as Substation[] | null; + if (equipmentToDeleteType === SpreadsheetEquipmentType.VOLTAGE_LEVEL) { + const currentSubstations = state.spreadsheetNetwork[SpreadsheetEquipmentType.SUBSTATION] + .equipmentsByNodeId[action.nodeId] as Substation[] | null; if (currentSubstations != null) { - state.spreadsheetNetwork[EQUIPMENT_TYPES.SUBSTATION].equipmentsByNodeId[action.nodeId] = - updateSubstationAfterVLDeletion(currentSubstations, equipmentToDeleteId); + state.spreadsheetNetwork[SpreadsheetEquipmentType.SUBSTATION].equipmentsByNodeId[ + action.nodeId + ] = updateSubstationAfterVLDeletion(currentSubstations, equipmentToDeleteId); } } @@ -1620,67 +1619,6 @@ function updateSubstationAfterVLDeletion(currentSubstations: Substation[], VLToD return currentSubstations; } -export enum EquipmentUpdateType { - LINES = 'lines', - TIE_LINES = 'tieLines', - TWO_WINDINGS_TRANSFORMERS = 'twoWindingsTransformers', - THREE_WINDINGS_TRANSFORMERS = 'threeWindingsTransformers', - GENERATORS = 'generators', - LOADS = 'loads', - BATTERIES = 'batteries', - DANGLING_LINES = 'danglingLines', - HVDC_LINES = 'hvdcLines', - LCC_CONVERTER_STATIONS = 'lccConverterStations', - VSC_CONVERTER_STATIONS = 'vscConverterStations', - SHUNT_COMPENSATORS = 'shuntCompensators', - STATIC_VAR_COMPENSATORS = 'staticVarCompensators', - VOLTAGE_LEVELS = 'voltageLevels', - SUBSTATIONS = 'substations', - BUSES = 'buses', - BUSBAR_SECTIONS = 'busbarSections', -} - -function getEquipmentTypeFromUpdateType(updateType: EquipmentUpdateType): EQUIPMENT_TYPES | undefined { - switch (updateType) { - case 'lines': - return EQUIPMENT_TYPES.LINE; - case 'tieLines': - return EQUIPMENT_TYPES.TIE_LINE; - case 'twoWindingsTransformers': - return EQUIPMENT_TYPES.TWO_WINDINGS_TRANSFORMER; - case 'threeWindingsTransformers': - return EQUIPMENT_TYPES.THREE_WINDINGS_TRANSFORMER; - case 'generators': - return EQUIPMENT_TYPES.GENERATOR; - case 'loads': - return EQUIPMENT_TYPES.LOAD; - case 'batteries': - return EQUIPMENT_TYPES.BATTERY; - case 'danglingLines': - return EQUIPMENT_TYPES.DANGLING_LINE; - case 'hvdcLines': - return EQUIPMENT_TYPES.HVDC_LINE; - case 'lccConverterStations': - return EQUIPMENT_TYPES.LCC_CONVERTER_STATION; - case 'vscConverterStations': - return EQUIPMENT_TYPES.VSC_CONVERTER_STATION; - case 'shuntCompensators': - return EQUIPMENT_TYPES.SHUNT_COMPENSATOR; - case 'staticVarCompensators': - return EQUIPMENT_TYPES.STATIC_VAR_COMPENSATOR; - case 'voltageLevels': - return EQUIPMENT_TYPES.VOLTAGE_LEVEL; - case 'substations': - return EQUIPMENT_TYPES.SUBSTATION; - case 'buses': - return EQUIPMENT_TYPES.BUS; - case 'busbarSections': - return EQUIPMENT_TYPES.BUSBAR_SECTION; - default: - return; - } -} - function deleteEquipment(currentEquipments: Identifiable[], equipmentToDeleteId: string) { const equipmentToDeleteIndex = currentEquipments.findIndex((eq) => eq.id === equipmentToDeleteId); if (equipmentToDeleteIndex >= 0) { diff --git a/src/services/study/network.ts b/src/services/study/network.ts index 6fc5d0bac8..73a935d37c 100644 --- a/src/services/study/network.ts +++ b/src/services/study/network.ts @@ -12,6 +12,7 @@ import { getStudyUrlWithNodeUuidAndRootNetworkUuid, PREFIX_STUDY_QUERIES, safeEn import { EQUIPMENT_INFOS_TYPES, EQUIPMENT_TYPES, type VoltageLevel } from '../../components/utils/equipment-types'; import { backendFetch, backendFetchJson, backendFetchText, getQueryParamsList, getUrlWithToken } from '../utils'; import { SwitchInfos } from './network-map.type'; +import type { SpreadsheetEquipmentType } from '../../components/spreadsheet-view/types/spreadsheet.type'; interface VoltageLevelSingleLineDiagram { studyUuid: UUID; @@ -234,7 +235,7 @@ export function fetchNetworkElementInfos( studyUuid: string | undefined | null, currentNodeUuid: UUID | undefined, currentRootNetworkUuid: string | undefined | null, - elementType: EquipmentType | ExtendedEquipmentType | EQUIPMENT_TYPES, + elementType: EquipmentType | ExtendedEquipmentType | EQUIPMENT_TYPES | SpreadsheetEquipmentType, infoType: string, elementId: string, inUpstreamBuiltParentNode: boolean @@ -332,54 +333,6 @@ export function fetchHvdcLinesMapInfos( ); } -export function fetchSubstations( - studyUuid: UUID, - currentNodeUuid: UUID, - currentRootNetworkUuid: UUID, - substationsIds?: string[] -) { - return fetchNetworkElementsInfos( - studyUuid, - currentNodeUuid, - currentRootNetworkUuid, - substationsIds, - EQUIPMENT_TYPES.SUBSTATION, - EQUIPMENT_INFOS_TYPES.TAB.type - ); -} - -export function fetchLines( - studyUuid: UUID, - currentNodeUuid: UUID, - currentRootNetworkUuid: UUID, - substationsIds?: string[] -) { - return fetchNetworkElementsInfos( - studyUuid, - currentNodeUuid, - currentRootNetworkUuid, - substationsIds, - EQUIPMENT_TYPES.LINE, - EQUIPMENT_INFOS_TYPES.TAB.type - ); -} - -export function fetchVoltageLevels( - studyUuid: UUID, - currentNodeUuid: UUID, - currentRootNetworkUuid: UUID, - substationsIds?: string[] -) { - return fetchNetworkElementsInfos( - studyUuid, - currentNodeUuid, - currentRootNetworkUuid, - substationsIds, - EQUIPMENT_TYPES.VOLTAGE_LEVEL, - EQUIPMENT_INFOS_TYPES.TAB.type - ); -} - export function fetchVoltageLevelsListInfos( studyUuid: UUID, currentNodeUuid: UUID, @@ -414,230 +367,6 @@ export function fetchVoltageLevelsMapInfos( ); } -export function fetchTwoWindingsTransformers( - studyUuid: UUID, - currentNodeUuid: UUID, - currentRootNetworkUuid: UUID, - substationsIds?: string[] -) { - return fetchNetworkElementsInfos( - studyUuid, - currentNodeUuid, - currentRootNetworkUuid, - substationsIds, - EQUIPMENT_TYPES.TWO_WINDINGS_TRANSFORMER, - EQUIPMENT_INFOS_TYPES.TAB.type - ); -} - -export function fetchThreeWindingsTransformers( - studyUuid: UUID, - currentNodeUuid: UUID, - currentRootNetworkUuid: UUID, - substationsIds?: string[] -) { - return fetchNetworkElementsInfos( - studyUuid, - currentNodeUuid, - currentRootNetworkUuid, - substationsIds, - EQUIPMENT_TYPES.THREE_WINDINGS_TRANSFORMER, - EQUIPMENT_INFOS_TYPES.TAB.type - ); -} - -export function fetchGenerators( - studyUuid: UUID, - currentNodeUuid: UUID, - currentRootNetworkUuid: UUID, - substationsIds?: string[] -) { - return fetchNetworkElementsInfos( - studyUuid, - currentNodeUuid, - currentRootNetworkUuid, - substationsIds, - EQUIPMENT_TYPES.GENERATOR, - EQUIPMENT_INFOS_TYPES.TAB.type - ); -} - -export function fetchLoads( - studyUuid: UUID, - currentNodeUuid: UUID, - currentRootNetworkUuid: UUID, - substationsIds?: string[] -) { - return fetchNetworkElementsInfos( - studyUuid, - currentNodeUuid, - currentRootNetworkUuid, - substationsIds, - EQUIPMENT_TYPES.LOAD, - EQUIPMENT_INFOS_TYPES.TAB.type - ); -} - -export function fetchDanglingLines( - studyUuid: UUID, - currentNodeUuid: UUID, - currentRootNetworkUuid: UUID, - substationsIds?: string[] -) { - return fetchNetworkElementsInfos( - studyUuid, - currentNodeUuid, - currentRootNetworkUuid, - substationsIds, - EQUIPMENT_TYPES.DANGLING_LINE, - EQUIPMENT_INFOS_TYPES.TAB.type - ); -} - -export function fetchBatteries( - studyUuid: UUID, - currentNodeUuid: UUID, - currentRootNetworkUuid: UUID, - substationsIds?: string[] -) { - return fetchNetworkElementsInfos( - studyUuid, - currentNodeUuid, - currentRootNetworkUuid, - substationsIds, - EQUIPMENT_TYPES.BATTERY, - EQUIPMENT_INFOS_TYPES.TAB.type - ); -} - -export function fetchHvdcLines( - studyUuid: UUID, - currentNodeUuid: UUID, - currentRootNetworkUuid: UUID, - substationsIds?: string[] -) { - return fetchNetworkElementsInfos( - studyUuid, - currentNodeUuid, - currentRootNetworkUuid, - substationsIds, - EQUIPMENT_TYPES.HVDC_LINE, - EQUIPMENT_INFOS_TYPES.TAB.type - ); -} - -export function fetchLccConverterStations( - studyUuid: UUID, - currentNodeUuid: UUID, - currentRootNetworkUuid: UUID, - substationsIds?: string[] -) { - return fetchNetworkElementsInfos( - studyUuid, - currentNodeUuid, - currentRootNetworkUuid, - substationsIds, - EQUIPMENT_TYPES.LCC_CONVERTER_STATION, - EQUIPMENT_INFOS_TYPES.TAB.type - ); -} - -export function fetchVscConverterStations( - studyUuid: UUID, - currentNodeUuid: UUID, - currentRootNetworkUuid: UUID, - substationsIds?: string[] -) { - return fetchNetworkElementsInfos( - studyUuid, - currentNodeUuid, - currentRootNetworkUuid, - substationsIds, - EQUIPMENT_TYPES.VSC_CONVERTER_STATION, - EQUIPMENT_INFOS_TYPES.TAB.type - ); -} - -export function fetchShuntCompensators( - studyUuid: UUID, - currentNodeUuid: UUID, - currentRootNetworkUuid: UUID, - substationsIds?: string[] -) { - return fetchNetworkElementsInfos( - studyUuid, - currentNodeUuid, - currentRootNetworkUuid, - substationsIds, - EQUIPMENT_TYPES.SHUNT_COMPENSATOR, - EQUIPMENT_INFOS_TYPES.TAB.type - ); -} - -export function fetchStaticVarCompensators( - studyUuid: UUID, - currentNodeUuid: UUID, - currentRootNetworkUuid: UUID, - substationsIds?: string[] -) { - return fetchNetworkElementsInfos( - studyUuid, - currentNodeUuid, - currentRootNetworkUuid, - substationsIds, - EQUIPMENT_TYPES.STATIC_VAR_COMPENSATOR, - EQUIPMENT_INFOS_TYPES.TAB.type - ); -} - -export function fetchBuses( - studyUuid: UUID, - currentNodeUuid: UUID, - currentRootNetworkUuid: UUID, - substationsIds?: string[] -) { - return fetchNetworkElementsInfos( - studyUuid, - currentNodeUuid, - currentRootNetworkUuid, - substationsIds, - EQUIPMENT_TYPES.BUS, - EQUIPMENT_INFOS_TYPES.TAB.type - ); -} - -export function fetchBusbarSections( - studyUuid: UUID, - currentNodeUuid: UUID, - currentRootNetworkUuid: UUID, - substationsIds?: string[] -) { - return fetchNetworkElementsInfos( - studyUuid, - currentNodeUuid, - currentRootNetworkUuid, - substationsIds, - EQUIPMENT_TYPES.BUSBAR_SECTION, - EQUIPMENT_INFOS_TYPES.TAB.type - ); -} - -export function fetchTieLines( - studyUuid: UUID, - currentNodeUuid: UUID, - currentRootNetworkUuid: UUID, - substationsIds?: string[] -) { - return fetchNetworkElementsInfos( - studyUuid, - currentNodeUuid, - currentRootNetworkUuid, - substationsIds, - EQUIPMENT_TYPES.TIE_LINE, - EQUIPMENT_INFOS_TYPES.TAB.type - ); -} - export const fetchNetworkExistence = (studyUuid: UUID, rootNetworkUuid: UUID) => { const fetchNetworkExistenceUrl = `${PREFIX_STUDY_QUERIES}/v1/studies/${studyUuid}/root-networks/${rootNetworkUuid}/network`; diff --git a/src/translations/en.json b/src/translations/en.json index 06769b8093..8758b8588c 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -560,6 +560,7 @@ "Type": "Type", "SUBSTATION": "Substation", "VOLTAGE_LEVEL": "Voltage Level", + "BRANCH": "Branch", "LINE": "Line", "TIE_LINE": "Tie line", "SWITCH": "Switch", diff --git a/src/translations/fr.json b/src/translations/fr.json index 9ad2abbace..f63d4907a2 100644 --- a/src/translations/fr.json +++ b/src/translations/fr.json @@ -557,6 +557,7 @@ "Type": "Type", "SUBSTATION": "Site", "VOLTAGE_LEVEL": "Poste", + "BRANCH": "Quadripôle", "LINE": "Ligne", "TIE_LINE": "Ligne d'interconnexion", "SWITCH": "disjoncteur", diff --git a/src/types/notification-types.ts b/src/types/notification-types.ts index 8a32c043fb..ce2f21f366 100644 --- a/src/types/notification-types.ts +++ b/src/types/notification-types.ts @@ -4,9 +4,9 @@ * 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 { EQUIPMENT_TYPES as NetworkViewerEquipmentType } from '@powsybl/network-viewer'; -import { ComputingType } from '@gridsuite/commons-ui'; -import { UUID } from 'crypto'; +import type { EQUIPMENT_TYPES as NetworkViewerEquipmentType } from '@powsybl/network-viewer'; +import type { ComputingType } from '@gridsuite/commons-ui'; +import type { UUID } from 'crypto'; export enum NotificationType { // Study status @@ -540,7 +540,8 @@ interface CommonStudyEventData { export interface StudyEventData { headers: StudyEventDataHeaders; - payload: NetworkImpactsInfos; + /** @see NetworkImpactsInfos */ + payload: string; } export interface ComputationParametersUpdatedEventData { @@ -585,7 +586,8 @@ export interface MetadataUpdatedEventData { export interface StudyAlertEventData { headers: StudyAlertEventDataHeaders; - payload: StudyAlert; + /** @see StudyAlert */ + payload: string; } export interface NodeCreatedEventData { @@ -640,7 +642,8 @@ export interface SubtreeCreatedEventData { export interface NodesColumnPositionsChangedEventData { headers: NodesColumnPositionsChangedEventDataHeaders; - payload: UUID[]; + /** JSON of {@link UUID}[] */ + payload: string; } export interface ModificationsCreationInProgressEventData extends CommonStudyEventData { @@ -1137,6 +1140,7 @@ export interface StudyUpdatedEventDataHeader { */ export interface StudyUpdatedEventData { headers: StudyUpdatedEventDataHeader; - payload: NetworkImpactsInfos; + /** @see NetworkImpactsInfos */ + payload: string; } /******************* TO REMOVE LATER ****************/ diff --git a/src/utils/spreadsheet-equipments-mapper.ts b/src/utils/spreadsheet-equipments-mapper.ts index 25c0c24477..23f0dbc4eb 100644 --- a/src/utils/spreadsheet-equipments-mapper.ts +++ b/src/utils/spreadsheet-equipments-mapper.ts @@ -17,8 +17,8 @@ import { getComputedPhaseTapChangerRegulationMode, getPhaseTapRegulationSideId, } from 'components/dialogs/network-modifications/two-windings-transformer/tap-changer-pane/phase-tap-changer-pane/phase-tap-changer-pane-utils'; -import { EQUIPMENT_TYPES } from 'components/utils/equipment-types'; -import { Identifiable } from '@gridsuite/commons-ui'; +import { type Identifiable } from '@gridsuite/commons-ui'; +import { SpreadsheetEquipmentType } from '../components/spreadsheet-view/types/spreadsheet.type'; /* * This function is used to format the data of the table to be able to display it in the table @@ -72,12 +72,7 @@ const mapPhaseTapChanger = (twt: any) => { }; }; -const mapTwtDataForTable = (twt: any) => { - let formattedTwt = mapRatioTapChanger(twt); - formattedTwt = mapPhaseTapChanger(formattedTwt); - - return formattedTwt; -}; +const mapTwtDataForTable = (twt: any) => mapPhaseTapChanger(mapRatioTapChanger(twt)); const mapGeneratorDataForTable = (generator: any) => { const formattedGenerator = { ...generator }; @@ -102,24 +97,26 @@ const mapShuntCompensatorDataForTable = (shuntCompensator: any) => { return formattedCompensator; }; -const mapSpreadsheetEquipment = (equipmentType: EQUIPMENT_TYPES, equipment: Identifiable) => { +const mapSpreadsheetEquipment = (equipmentType: SpreadsheetEquipmentType, equipment: Identifiable) => { switch (equipmentType) { - case EQUIPMENT_TYPES.TWO_WINDINGS_TRANSFORMER: + case SpreadsheetEquipmentType.TWO_WINDINGS_TRANSFORMER: + case SpreadsheetEquipmentType.BRANCH: // can do it because mappers test if field present before modifying return mapTwtDataForTable(equipment); - case EQUIPMENT_TYPES.GENERATOR: + case SpreadsheetEquipmentType.GENERATOR: return mapGeneratorDataForTable(equipment); - case EQUIPMENT_TYPES.SHUNT_COMPENSATOR: + case SpreadsheetEquipmentType.SHUNT_COMPENSATOR: return mapShuntCompensatorDataForTable(equipment); default: return equipment; } }; -export const mapSpreadsheetEquipments = (equipmentType: EQUIPMENT_TYPES, equipments: Identifiable[]) => { +export const mapSpreadsheetEquipments = ( + equipmentType: SpreadsheetEquipmentType, + equipments: Identifiable[] //TODO + `| null | undefined` +) => { if (equipments && equipments?.length > 0) { - return equipments.map((equipment) => { - return mapSpreadsheetEquipment(equipmentType, equipment); - }); + return equipments.map((equipment) => mapSpreadsheetEquipment(equipmentType, equipment)); } return equipments; };