diff --git a/src/components/dialogs/csv-import-filter-creation-dialog.js b/src/components/dialogs/csv-import-filter-creation-dialog.js index 6ac393578..f181510bc 100644 --- a/src/components/dialogs/csv-import-filter-creation-dialog.js +++ b/src/components/dialogs/csv-import-filter-creation-dialog.js @@ -19,7 +19,7 @@ import Alert from '@mui/material/Alert'; import PropTypes from 'prop-types'; import { DialogContentText } from '@mui/material'; import { ElementType } from '../../utils/elementType'; -import { Generator, Load } from '../../utils/equipment-types'; +import { EquipmentType } from '../../utils/equipment-types'; import { CancelButton } from '@gridsuite/commons-ui'; const CsvImportFilterCreationDialog = ({ @@ -41,8 +41,8 @@ const CsvImportFilterCreationDialog = ({ // TODO This is temporary : should be refactored to remove the business logic. if (formType === ElementType.FILTER) { if ( - equipmentType === Generator.type || - equipmentType === Load.type + equipmentType === EquipmentType.GENERATOR || + equipmentType === EquipmentType.LOAD ) { return [ intl.formatMessage({ id: 'equipmentID' }), diff --git a/src/components/dialogs/filter/criteria-based/filter-free-properties.tsx b/src/components/dialogs/filter/criteria-based/filter-free-properties.tsx index f1408926f..6d48c4236 100644 --- a/src/components/dialogs/filter/criteria-based/filter-free-properties.tsx +++ b/src/components/dialogs/filter/criteria-based/filter-free-properties.tsx @@ -13,7 +13,7 @@ import { } from 'components/utils/field-constants'; import { useFieldArray, useWatch } from 'react-hook-form'; import { FormattedMessage } from 'react-intl'; -import { Hvdc, Line } from 'utils/equipment-types'; +import { EquipmentType } from 'utils/equipment-types'; import { FreePropertiesTypes } from './filter-properties'; import FilterProperty, { PROPERTY_NAME, @@ -37,8 +37,8 @@ function FilterFreeProperties({ name: EQUIPMENT_TYPE, }); const isForLineOrHvdcLineSubstation = - (watchEquipmentType === Line.type || - watchEquipmentType === Hvdc.type) && + (watchEquipmentType === EquipmentType.LINE || + watchEquipmentType === EquipmentType.HVDC_LINE) && freePropertiesType === FreePropertiesTypes.SUBSTATION_FILTER_PROPERTIES; const fieldName = `${CRITERIA_BASED}.${freePropertiesType}`; diff --git a/src/components/dialogs/filter/criteria-based/filter-properties.tsx b/src/components/dialogs/filter/criteria-based/filter-properties.tsx index cc56cd9e2..9f02fe964 100644 --- a/src/components/dialogs/filter/criteria-based/filter-properties.tsx +++ b/src/components/dialogs/filter/criteria-based/filter-properties.tsx @@ -1,16 +1,9 @@ -import { useSnackMessage } from '@gridsuite/commons-ui'; import Grid from '@mui/material/Grid'; -import { useEffect, useState } from 'react'; +import { useEffect, useMemo } from 'react'; import { useWatch } from 'react-hook-form'; import { FormattedMessage } from 'react-intl'; -import { fetchAppsAndUrls } from 'utils/rest-api'; import { FilterType } from '../../../../utils/elementType'; -import { - Hvdc, - Line, - Load, - Substation, -} from '../../../../utils/equipment-types'; +import { EquipmentType } from '../../../../utils/equipment-types'; import { areArrayElementsUnique } from '../../../../utils/functions'; import { EQUIPMENT_TYPE, FILTER_TYPE } from '../../../utils/field-constants'; import yup from '../../../utils/yup-config'; @@ -21,27 +14,13 @@ import { PROPERTY_VALUES_1, PROPERTY_VALUES_2, } from './filter-property'; +import { usePredefinedProperties } from '../../../../hooks/predefined-properties-hook'; export enum FreePropertiesTypes { SUBSTATION_FILTER_PROPERTIES = 'substationFreeProperties', FREE_FILTER_PROPERTIES = 'freeProperties', } -function fetchPredefinedProperties() { - return fetchAppsAndUrls().then((res) => { - const studyMetadata = res.find( - (metadata: any) => metadata.name === 'Study' - ); - if (!studyMetadata) { - return Promise.reject( - 'Study entry could not be found in metadatas' - ); - } - - return studyMetadata?.predefinedEquipmentProperties?.substation; - }); -} - function propertyValuesTest( values: (string | undefined)[] | undefined, context: yup.TestContext, @@ -56,7 +35,8 @@ function propertyValuesTest( } const equipmentType = rootLevelForm.value[EQUIPMENT_TYPE]; const isForLineOrHvdcLine = - equipmentType === Line.type || equipmentType === Hvdc.type; + equipmentType === EquipmentType.LINE || + equipmentType === EquipmentType.HVDC_LINE; if (doublePropertyValues) { return isForLineOrHvdcLine ? values?.length! > 0 : true; } else { @@ -152,24 +132,39 @@ export const filterPropertiesYupSchema = { }; function FilterProperties() { - const watchEquipmentType = useWatch({ + const watchEquipmentType: EquipmentType = useWatch({ name: EQUIPMENT_TYPE, }); - const isForSubstation = watchEquipmentType === Substation.type; - const isForLoad = watchEquipmentType === Load.type; - const [fieldProps, setFieldProps] = useState({}); + const [equipmentPredefinedProps, setEquipmentType] = + usePredefinedProperties(watchEquipmentType); + const [substationPredefinedProps, setSubstationType] = + usePredefinedProperties(null); - const { snackError } = useSnackMessage(); + const displayEquipmentProperties = useMemo(() => { + return ( + watchEquipmentType === EquipmentType.SUBSTATION || + watchEquipmentType === EquipmentType.LOAD + ); + }, [watchEquipmentType]); + + const displaySubstationProperties = useMemo(() => { + return ( + watchEquipmentType !== EquipmentType.SUBSTATION && + watchEquipmentType !== null + ); + }, [watchEquipmentType]); useEffect(() => { - fetchPredefinedProperties() - .then((p) => setFieldProps(p)) - .catch((error) => { - snackError({ - messageTxt: error.message ?? error, - }); - }); - }, [snackError]); + if (displayEquipmentProperties) { + setEquipmentType(watchEquipmentType); + } + }, [displayEquipmentProperties, watchEquipmentType, setEquipmentType]); + + useEffect(() => { + if (displaySubstationProperties) { + setSubstationType(EquipmentType.SUBSTATION); + } + }, [displaySubstationProperties, setSubstationType]); return ( watchEquipmentType && ( @@ -178,20 +173,20 @@ function FilterProperties() { {(txt) =>

{txt}

}
- {(isForSubstation || isForLoad) && ( + {displayEquipmentProperties && ( )} - {!isForSubstation && ( + {displaySubstationProperties && ( )} diff --git a/src/components/dialogs/filter/explicit-naming/explicit-naming-filter-form.tsx b/src/components/dialogs/filter/explicit-naming/explicit-naming-filter-form.tsx index c34d35ca8..39e32b1d3 100644 --- a/src/components/dialogs/filter/explicit-naming/explicit-naming-filter-form.tsx +++ b/src/components/dialogs/filter/explicit-naming/explicit-naming-filter-form.tsx @@ -20,7 +20,7 @@ import { FILTER_EQUIPMENTS } from '../../commons/criteria-based/criteria-based-u import Grid from '@mui/material/Grid'; import { SelectInput, useSnackMessage } from '@gridsuite/commons-ui'; import { ValueParserParams } from 'ag-grid-community'; -import { Generator, Load } from '../../../../utils/equipment-types'; +import { EquipmentType } from '../../../../utils/equipment-types'; import { ElementType, FilterType } from '../../../../utils/elementType'; import { NumericEditor } from '../../../utils/rhf-inputs/ag-grid-table-rhf/cell-editors/numericEditor'; import { toFloatOrNullValue } from '../../../utils/dialog-utils'; @@ -80,7 +80,10 @@ export const explicitNamingFilterSchema = { }; function isGeneratorOrLoad(equipmentType: string): boolean { - return equipmentType === Generator.type || equipmentType === Load.type; + return ( + equipmentType === EquipmentType.GENERATOR || + equipmentType === EquipmentType.LOAD + ); } interface FilterTableRow { @@ -111,6 +114,7 @@ export interface FilterForExplicitConversionProps { id: UUID; equipmentType: String; } + interface ExplicitNamingFilterFormProps { sourceFilterForExplicitNamingConversion?: FilterForExplicitConversionProps; } diff --git a/src/components/dialogs/filter/filters-utils.js b/src/components/dialogs/filter/filters-utils.js index dcdb33f81..346ee5f47 100644 --- a/src/components/dialogs/filter/filters-utils.js +++ b/src/components/dialogs/filter/filters-utils.js @@ -8,7 +8,7 @@ import { createFilter, saveFilter } from '../../../utils/rest-api'; import { FilterType } from '../../../utils/elementType'; import { frontToBackTweak } from './criteria-based/criteria-based-filter-utils'; import { DESCRIPTION, EQUIPMENT_ID, NAME } from '../../utils/field-constants'; -import { Generator, Load } from '../../../utils/equipment-types'; +import { EquipmentType } from '../../../utils/equipment-types'; import { DISTRIBUTION_KEY } from './explicit-naming/explicit-naming-filter-form'; import { exportExpertRules } from './expert/expert-filter-utils'; @@ -26,7 +26,8 @@ export const saveExplicitNamingFilter = ( // we remove unnecessary fields from the table let cleanedTableValues; const isGeneratorOrLoad = - equipmentType === Generator.type || equipmentType === Load.type; + equipmentType === EquipmentType.GENERATOR || + equipmentType === EquipmentType.LOAD; if (isGeneratorOrLoad) { cleanedTableValues = tableValues.map((row) => ({ [EQUIPMENT_ID]: row[EQUIPMENT_ID], diff --git a/src/components/utils/rqb-inputs/value-editor.tsx b/src/components/utils/rqb-inputs/value-editor.tsx index baef28e2a..5607bc34e 100644 --- a/src/components/utils/rqb-inputs/value-editor.tsx +++ b/src/components/utils/rqb-inputs/value-editor.tsx @@ -20,7 +20,7 @@ import ElementValueEditor from './element-value-editor'; import { ElementType, FilterType } from '../../../utils/elementType'; import { EQUIPMENT_TYPE, FILTER_UUID } from '../field-constants'; import { useFormContext } from 'react-hook-form'; -import { VoltageLevel } from '../../../utils/equipment-types'; +import { EquipmentType } from '../../../utils/equipment-types'; const styles = { noArrows: { @@ -52,7 +52,7 @@ const ValueEditor = (props: ValueEditorProps) => { props.field === FieldType.VOLTAGE_LEVEL_ID_1 || props.field === FieldType.VOLTAGE_LEVEL_ID_2) && value?.specificMetadata?.equipmentType === - VoltageLevel.type)) + EquipmentType.VOLTAGE_LEVEL)) ); } return true; @@ -87,7 +87,7 @@ const ValueEditor = (props: ValueEditorProps) => { props.field === FieldType.VOLTAGE_LEVEL_ID_1 || props.field === FieldType.VOLTAGE_LEVEL_ID_2 ) { - equipmentTypes = [VoltageLevel.type]; + equipmentTypes = [EquipmentType.VOLTAGE_LEVEL]; } else if (props.field === FieldType.ID) { equipmentTypes = [getValues(EQUIPMENT_TYPE)]; } diff --git a/src/hooks/predefined-properties-hook.ts b/src/hooks/predefined-properties-hook.ts new file mode 100644 index 000000000..38c6589fd --- /dev/null +++ b/src/hooks/predefined-properties-hook.ts @@ -0,0 +1,79 @@ +/** + * Copyright (c) 2024, 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 { Dispatch, SetStateAction, useEffect, useState } from 'react'; +import { useSnackMessage } from '@gridsuite/commons-ui'; +import { mapEquipmentTypeForPredefinedProperties } from '../utils/equipment-types-for-predefined-properties-mapper'; +import { fetchAppsAndUrls } from '../utils/rest-api'; +import { EquipmentType } from '../utils/equipment-types'; + +export type PredefinedProperties = { + [propertyName: string]: string[]; +}; + +interface Metadata { + name: string; + url: string; + appColor: string; + hiddenInAppsMenu: boolean; + resources: unknown; +} + +interface StudyMetadata extends Metadata { + name: 'Study'; + predefinedEquipmentProperties: { + [networkElementType: string]: PredefinedProperties; + }; +} + +const isStudyMetadata = (metadata: Metadata): metadata is StudyMetadata => { + return metadata.name === 'Study'; +}; + +const fetchPredefinedProperties = async ( + equipmentType: EquipmentType +): Promise => { + const networkEquipmentType = + mapEquipmentTypeForPredefinedProperties(equipmentType); + if (networkEquipmentType === undefined) { + return Promise.resolve(undefined); + } + const res = await fetchAppsAndUrls(); + const studyMetadata = res.filter(isStudyMetadata); + if (!studyMetadata) { + return Promise.reject('Study entry could not be found in metadata'); + } + return studyMetadata[0].predefinedEquipmentProperties?.[ + networkEquipmentType + ]; +}; + +export const usePredefinedProperties = ( + initialType: EquipmentType | null +): [PredefinedProperties, Dispatch>] => { + const [type, setType] = useState(initialType); + const [equipmentPredefinedProps, setEquipmentPredefinedProps] = + useState({}); + const { snackError } = useSnackMessage(); + + useEffect(() => { + if (type !== null) { + fetchPredefinedProperties(type) + .then((p) => { + if (p !== undefined) { + setEquipmentPredefinedProps(p); + } + }) + .catch((error) => { + snackError({ + messageTxt: error.message ?? error, + }); + }); + } + }, [type, setEquipmentPredefinedProps, snackError]); + + return [equipmentPredefinedProps, setType]; +}; diff --git a/src/utils/equipment-types-for-predefined-properties-mapper.ts b/src/utils/equipment-types-for-predefined-properties-mapper.ts new file mode 100644 index 000000000..c9c260831 --- /dev/null +++ b/src/utils/equipment-types-for-predefined-properties-mapper.ts @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2024, 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 { EquipmentType } from './equipment-types'; + +export const mapEquipmentTypeForPredefinedProperties = ( + type: EquipmentType +): string | undefined => { + switch (type) { + case EquipmentType.SUBSTATION: + return 'substation'; + case EquipmentType.LOAD: + return 'load'; + case EquipmentType.GENERATOR: + return 'generator'; + case EquipmentType.LINE: + return 'line'; + case EquipmentType.TWO_WINDING_TRANSFORMER: + return 'twt'; + case EquipmentType.BATTERY: + return 'battery'; + case EquipmentType.SHUNT_COMPENSATOR: + return 'shuntCompensator'; + case EquipmentType.VOLTAGE_LEVEL: + return 'voltageLevel'; + case EquipmentType.BUSBAR_SECTION: + case EquipmentType.DANGLING_LINE: + case EquipmentType.HVDC_LINE: + case EquipmentType.LCC_CONVERTER_STATION: + case EquipmentType.THREE_WINDINGS_TRANSFORMER: + case EquipmentType.STATIC_VAR_COMPENSATOR: + case EquipmentType.VSC_CONVERTER_STATION: + return undefined; + } +}; diff --git a/src/utils/equipment-types.js b/src/utils/equipment-types.js deleted file mode 100644 index 245201908..000000000 --- a/src/utils/equipment-types.js +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Copyright (c) 2021, 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/. - */ - -export const Line = { label: 'Lines', type: 'LINE' }; -export const Generator = { label: 'Generators', type: 'GENERATOR' }; -export const Load = { label: 'Loads', type: 'LOAD' }; -export const Battery = { label: 'Batteries', type: 'BATTERY' }; -export const SVC = { - label: 'StaticVarCompensators', - type: 'STATIC_VAR_COMPENSATOR', -}; -export const DanglingLine = { label: 'DanglingLines', type: 'DANGLING_LINE' }; -export const LCC = { - label: 'LccConverterStations', - type: 'LCC_CONVERTER_STATION', -}; -export const VSC = { - label: 'VscConverterStations', - type: 'VSC_CONVERTER_STATION', -}; -export const Hvdc = { label: 'HvdcLines', type: 'HVDC_LINE' }; -export const BusBar = { label: 'BusBarSections', type: 'BUSBAR_SECTION' }; -export const TwoWindingTransfo = { - label: 'TwoWindingsTransformers', - type: 'TWO_WINDINGS_TRANSFORMER', -}; -export const ThreeWindingTransfo = { - label: 'ThreeWindingsTransformers', - type: 'THREE_WINDINGS_TRANSFORMER', -}; -export const ShuntCompensator = { - label: 'ShuntCompensators', - type: 'SHUNT_COMPENSATOR', -}; -export const VoltageLevel = { - label: 'VoltageLevels', - type: 'VOLTAGE_LEVEL', -}; -export const Substation = { - label: 'Substations', - type: 'SUBSTATION', -}; diff --git a/src/utils/equipment-types.ts b/src/utils/equipment-types.ts new file mode 100644 index 000000000..42be6598f --- /dev/null +++ b/src/utils/equipment-types.ts @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2021, 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/. + */ + +export enum EquipmentType { + SUBSTATION = 'SUBSTATION', + LOAD = 'LOAD', + GENERATOR = 'GENERATOR', + LINE = 'LINE', + TWO_WINDING_TRANSFORMER = 'TWO_WINDINGS_TRANSFORMER', + BATTERY = 'BATTERY', + SHUNT_COMPENSATOR = 'SHUNT_COMPENSATOR', + VOLTAGE_LEVEL = 'VOLTAGE_LEVEL', + BUSBAR_SECTION = 'BUSBAR_SECTION', + DANGLING_LINE = 'DANGLING_LINE', + HVDC_LINE = 'HVDC_LINE', + LCC_CONVERTER_STATION = 'LCC_CONVERTER_STATION', + THREE_WINDINGS_TRANSFORMER = 'THREE_WINDINGS_TRANSFORMER', + STATIC_VAR_COMPENSATOR = 'STATIC_VAR_COMPENSATOR', + VSC_CONVERTER_STATION = 'VSC_CONVERTER_STATION', +}