diff --git a/src/components/parameters/short-circuit/columns-definition.ts b/src/components/parameters/short-circuit/columns-definition.ts new file mode 100644 index 00000000..b95fd81a --- /dev/null +++ b/src/components/parameters/short-circuit/columns-definition.ts @@ -0,0 +1,130 @@ +/** + * Copyright (c) 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 { ElementType, EquipmentType } from '../../../utils'; + +export const SHORT_CIRCUIT_ICC_MATERIAL_ACTIVE = 'active'; +export const SHORT_CIRCUIT_ICC_MATERIAL_TYPE = 'type'; +export const SHORT_CIRCUIT_ICC_MATERIAL_ALPHA = 'alpha'; +export const SHORT_CIRCUIT_ICC_MATERIAL_USMIN = 'usMin'; +export const SHORT_CIRCUIT_ICC_MATERIAL_USMAX = 'usMax'; +export const SHORT_CIRCUIT_ICC_MATERIAL_U0 = 'u0'; +export const SHORT_CIRCUIT_ICC_CLUSTER_ACTIVE = SHORT_CIRCUIT_ICC_MATERIAL_ACTIVE; +export const SHORT_CIRCUIT_ICC_CLUSTER_FILTERS = 'filters'; +export const SHORT_CIRCUIT_ICC_CLUSTER_TYPE = SHORT_CIRCUIT_ICC_MATERIAL_TYPE; +export const SHORT_CIRCUIT_ICC_CLUSTER_ALPHA = SHORT_CIRCUIT_ICC_MATERIAL_ALPHA; +export const SHORT_CIRCUIT_ICC_CLUSTER_USMIN = SHORT_CIRCUIT_ICC_MATERIAL_USMIN; +export const SHORT_CIRCUIT_ICC_CLUSTER_USMAX = SHORT_CIRCUIT_ICC_MATERIAL_USMAX; +export const SHORT_CIRCUIT_ICC_CLUSTER_U0 = SHORT_CIRCUIT_ICC_MATERIAL_U0; + +export interface IccCommonIColumnsDef { + label: React.ReactNode; + dataKey: string; + tooltip: React.ReactNode; + width?: string; +} + +export interface IccMaterialIColumnsDef extends IccCommonIColumnsDef {} +export interface IccClusterIColumnsDef extends IccCommonIColumnsDef { + equipmentTypes?: EquipmentType[]; + elementType?: string; + titleId?: string; + initialValue?: any; +} + +export const COLUMNS_DEFINITIONS_ICC_MATERIALS: IccMaterialIColumnsDef[] = [ + { + label: 'ShortCircuitIccActive', + dataKey: SHORT_CIRCUIT_ICC_MATERIAL_ACTIVE, + tooltip: 'ShortCircuitIccMaterialActiveTooltip', + width: '8%', + }, + { + label: 'ShortCircuitIccMaterialType', + dataKey: SHORT_CIRCUIT_ICC_MATERIAL_TYPE, + tooltip: 'ShortCircuitIccMaterialTypeTooltip', + }, + { + label: 'ShortCircuitIccAlpha', + dataKey: SHORT_CIRCUIT_ICC_MATERIAL_ALPHA, + tooltip: 'ShortCircuitIccAlphaTooltip', + width: '8%', + }, + { + label: 'ShortCircuitIccUsmin', + dataKey: SHORT_CIRCUIT_ICC_MATERIAL_USMIN, + tooltip: 'ShortCircuitIccUsminTooltip', + width: '8%', + }, + { + label: 'ShortCircuitIccUsmax', + dataKey: SHORT_CIRCUIT_ICC_MATERIAL_USMAX, + tooltip: 'ShortCircuitIccUsmaxTooltip', + width: '8%', + }, + { + label: 'ShortCircuitIccU0', + dataKey: SHORT_CIRCUIT_ICC_MATERIAL_U0, + tooltip: 'ShortCircuitIccU0Tooltip', + width: '8%', + }, +]; + +export const COLUMNS_DEFINITIONS_ICC_CLUSTERS: IccClusterIColumnsDef[] = [ + { + label: 'ShortCircuitIccActive', + dataKey: SHORT_CIRCUIT_ICC_CLUSTER_ACTIVE, + tooltip: 'ShortCircuitIccClusterActiveTooltip', + initialValue: false, + width: '8%', + }, + { + label: 'ShortCircuitIccClusterFilters', + dataKey: SHORT_CIRCUIT_ICC_CLUSTER_FILTERS, + tooltip: 'ShortCircuitIccClusterFiltersTooltip', + equipmentTypes: [EquipmentType.GENERATOR, EquipmentType.BATTERY], + elementType: ElementType.FILTER, + titleId: 'FiltersListsSelection', + initialValue: [], + }, + { + label: 'ShortCircuitIccClusterType', + dataKey: SHORT_CIRCUIT_ICC_CLUSTER_TYPE, + tooltip: 'ShortCircuitIccClusterTypeTooltip', + titleId: 'ShortCircuitIccClusterTypeListsSelection', + initialValue: [], + width: '15%', + }, + { + label: 'ShortCircuitIccAlpha', + dataKey: SHORT_CIRCUIT_ICC_CLUSTER_ALPHA, + tooltip: 'ShortCircuitIccAlphaTooltip', + initialValue: 1, + width: '8%', + }, + { + label: 'ShortCircuitIccUsmin', + dataKey: SHORT_CIRCUIT_ICC_CLUSTER_USMIN, + tooltip: 'ShortCircuitIccUsminTooltip', + initialValue: 0, + width: '8%', + }, + { + label: 'ShortCircuitIccUsmax', + dataKey: SHORT_CIRCUIT_ICC_CLUSTER_USMAX, + tooltip: 'ShortCircuitIccUsmaxTooltip', + initialValue: 100, + width: '8%', + }, + { + label: 'ShortCircuitIccU0', + dataKey: SHORT_CIRCUIT_ICC_CLUSTER_U0, + tooltip: 'ShortCircuitIccU0Tooltip', + initialValue: 100, + width: '8%', + }, +]; diff --git a/src/components/parameters/short-circuit/constants.ts b/src/components/parameters/short-circuit/constants.ts index acf455af..29277b18 100644 --- a/src/components/parameters/short-circuit/constants.ts +++ b/src/components/parameters/short-circuit/constants.ts @@ -31,6 +31,8 @@ export const SHORT_CIRCUIT_VOLTAGE_RANGES = 'voltageRanges'; export const SHORT_CIRCUIT_ONLY_STARTED_GENERATORS_IN_CALCULATION_CLUSTER = 'onlyStartedGeneratorsInCalculationCluster'; export const SHORT_CIRCUIT_MODEL_POWER_ELECTRONICS = 'modelPowerElectronics'; export const SHORT_CIRCUIT_POWER_ELECTRONICS_MATERIALS = 'powerElectronicsMaterials'; +export const SHORT_CIRCUIT_POWER_ELECTRONICS_CLUSTER = 'powerElectronicsCluster'; // TODO REMOVE WHEN fixed in powsybl +export const SHORT_CIRCUIT_POWER_ELECTRONICS_CLUSTERS = 'powerElectronicsClusters'; export const intlPredefinedParametersOptions = () => [ { diff --git a/src/components/parameters/short-circuit/short-circuit-fields.tsx b/src/components/parameters/short-circuit/short-circuit-fields.tsx index e411a763..b75e88cd 100644 --- a/src/components/parameters/short-circuit/short-circuit-fields.tsx +++ b/src/components/parameters/short-circuit/short-circuit-fields.tsx @@ -27,6 +27,7 @@ import { SHORT_CIRCUIT_WITH_NEUTRAL_POSITION, SHORT_CIRCUIT_WITH_SHUNT_COMPENSATORS, SHORT_CIRCUIT_WITH_VSC_CONVERTER_STATIONS, + SHORT_CIRCUIT_POWER_ELECTRONICS_CLUSTERS, } from './constants'; import { VoltageTable } from './short-circuit-voltage-table'; import GridItem from '../../grid/grid-item'; @@ -35,7 +36,8 @@ import { CheckboxInput, FieldLabel, MuiSelectInput, RadioInput, SwitchInput } fr import type { SxStyle } from '../../../utils/styles'; import { COMMON_PARAMETERS, SPECIFIC_PARAMETERS } from '../common'; import { ShortCircuitIccMaterialTable } from './short-circuit-icc-material-table'; -import { COLUMNS_DEFINITIONS_ICC_MATERIALS } from './short-circuit-icc-material-table-columns-definition'; +import { COLUMNS_DEFINITIONS_ICC_CLUSTERS, COLUMNS_DEFINITIONS_ICC_MATERIALS } from './columns-definition'; +import { ShortCircuitIccClusterTable } from './short-circuit-icc-cluster-table'; export interface ShortCircuitFieldsProps { resetAll: (predefinedParams: PredefinedParameters) => void; @@ -47,12 +49,26 @@ export enum Status { ERROR = 'ERROR', } -const columnsDef = COLUMNS_DEFINITIONS_ICC_MATERIALS.map((col) => ({ +const iccMaterialsColumnsDef = COLUMNS_DEFINITIONS_ICC_MATERIALS.map((col) => ({ ...col, label: , tooltip: , })); +const iccClustersColumnsDef = COLUMNS_DEFINITIONS_ICC_CLUSTERS.map((col) => ({ + ...col, + label: , + tooltip: , +})); + +function createRows() { + const rowData: { [key: string]: any } = {}; + iccClustersColumnsDef.forEach((column) => { + rowData[column.dataKey] = column.initialValue; + }); + return rowData; +} + export function ShortCircuitFields({ resetAll, isDeveloperMode = true }: Readonly) { const [status, setStatus] = useState(Status.SUCCESS); const watchInitialVoltageProfileMode = useWatch({ @@ -286,8 +302,12 @@ export function ShortCircuitFields({ resetAll, isDeveloperMode = true }: Readonl + )} diff --git a/src/components/parameters/short-circuit/short-circuit-icc-cluster-table-cell.tsx b/src/components/parameters/short-circuit/short-circuit-icc-cluster-table-cell.tsx new file mode 100644 index 00000000..2f3093fa --- /dev/null +++ b/src/components/parameters/short-circuit/short-circuit-icc-cluster-table-cell.tsx @@ -0,0 +1,60 @@ +/** + * Copyright (c) 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 { TableCell } from '@mui/material'; +import { DirectoryItemsInput, FloatInput, SelectInput, SwitchInput } from '../../inputs'; +import { + IccClusterIColumnsDef, + SHORT_CIRCUIT_ICC_CLUSTER_ACTIVE, + SHORT_CIRCUIT_ICC_CLUSTER_FILTERS, + SHORT_CIRCUIT_ICC_CLUSTER_TYPE, +} from './columns-definition'; + +export function ShortCircuitIccClusterTableCell({ + formName, + rowIndex, + column, + inputsDisabled, +}: Readonly<{ + formName: string; + rowIndex: number; + column: IccClusterIColumnsDef; + inputsDisabled?: boolean; +}>) { + return ( + + {column.dataKey === SHORT_CIRCUIT_ICC_CLUSTER_ACTIVE && ( + + )} + {column.dataKey === SHORT_CIRCUIT_ICC_CLUSTER_FILTERS && ( + + )} + {column.dataKey === SHORT_CIRCUIT_ICC_CLUSTER_TYPE && ( + + )} + {column.dataKey !== SHORT_CIRCUIT_ICC_CLUSTER_ACTIVE && + column.dataKey !== SHORT_CIRCUIT_ICC_CLUSTER_FILTERS && + column.dataKey !== SHORT_CIRCUIT_ICC_CLUSTER_TYPE && ( + + )} + + ); +} diff --git a/src/components/parameters/short-circuit/short-circuit-icc-cluster-table-row.tsx b/src/components/parameters/short-circuit/short-circuit-icc-cluster-table-row.tsx new file mode 100644 index 00000000..73ed7368 --- /dev/null +++ b/src/components/parameters/short-circuit/short-circuit-icc-cluster-table-row.tsx @@ -0,0 +1,55 @@ +/** + * Copyright (c) 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 { IconButton, TableCell, TableRow, Tooltip } from '@mui/material'; +import { Delete as DeleteIcon } from '@mui/icons-material'; +import { useWatch } from 'react-hook-form'; +import { useState } from 'react'; +import { FormattedMessage } from 'react-intl'; +import { IccClusterIColumnsDef, SHORT_CIRCUIT_ICC_CLUSTER_ACTIVE } from './columns-definition'; +import { ShortCircuitIccClusterTableCell } from './short-circuit-icc-cluster-table-cell'; + +interface ShortCircuitIccClusterTableRowProps { + formName: string; + columnsDefinition: IccClusterIColumnsDef[]; + index: number; + onDeleteButton: (index: number) => void; +} + +export function ShortCircuitIccClusterTableRow({ + formName, + columnsDefinition, + index, + onDeleteButton, +}: Readonly) { + const [isHover, setIsHover] = useState(false); + const watchRowActive = useWatch({ + name: `${formName}[${index}].${SHORT_CIRCUIT_ICC_CLUSTER_ACTIVE}`, + }); + + return ( + setIsHover(true)} onMouseLeave={() => setIsHover(false)}> + {columnsDefinition.map((column: IccClusterIColumnsDef) => ( + + ))} + + {isHover && ( + }> + onDeleteButton(index)}> + + + + )} + + + ); +} diff --git a/src/components/parameters/short-circuit/short-circuit-icc-cluster-table.tsx b/src/components/parameters/short-circuit/short-circuit-icc-cluster-table.tsx new file mode 100644 index 00000000..35087fea --- /dev/null +++ b/src/components/parameters/short-circuit/short-circuit-icc-cluster-table.tsx @@ -0,0 +1,105 @@ +/** + * Copyright (c) 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 { + IconButton, + Table, + TableBody, + TableCell, + TableContainer, + TableHead, + TableRow, + Theme, + Tooltip, +} from '@mui/material'; +import { AddCircle as AddCircleIcon } from '@mui/icons-material'; +import { useFieldArray } from 'react-hook-form'; +import { FormattedMessage } from 'react-intl'; +import { useCallback } from 'react'; +import { IccClusterIColumnsDef } from './columns-definition'; +import { ShortCircuitIccClusterTableRow } from './short-circuit-icc-cluster-table-row'; + +interface ShortCircuitIccClusterTableProps { + columnsDefinition: IccClusterIColumnsDef[]; + formName: string; + createRows: () => unknown; +} + +const styles = { + tableContainer: (theme: Theme) => ({ + width: '100%', + border: 'solid 0px rgba(0,0,0,0.1)', + marginBottom: theme.spacing(4), + }), + table: { + minWidth: '80em', + tableLayout: 'fixed', + }, +}; + +export function ShortCircuitIccClusterTable({ + formName, + columnsDefinition, + createRows, +}: Readonly) { + const { + fields: rows, + append, + remove, + } = useFieldArray({ + name: formName, + }); + + const handleAddRowsButton = useCallback(() => { + append(createRows()); + }, [append, createRows]); + + const handleDeleteButton = useCallback( + (index: number) => { + remove(index); + }, + [remove] + ); + + return ( + + + + + {columnsDefinition.map((column) => ( + + + {column.label} + + + ))} + + }> + + + + + + + + + + + {rows.map((row, index) => ( + + ))} + +
+
+ ); +} diff --git a/src/components/parameters/short-circuit/short-circuit-icc-material-table-cell.tsx b/src/components/parameters/short-circuit/short-circuit-icc-material-table-cell.tsx index 9fb1df2f..a8c04f6c 100644 --- a/src/components/parameters/short-circuit/short-circuit-icc-material-table-cell.tsx +++ b/src/components/parameters/short-circuit/short-circuit-icc-material-table-cell.tsx @@ -10,7 +10,7 @@ import { IccMaterialIColumnsDef, SHORT_CIRCUIT_ICC_MATERIAL_ACTIVE, SHORT_CIRCUIT_ICC_MATERIAL_TYPE, -} from './short-circuit-icc-material-table-columns-definition'; +} from './columns-definition'; export function ShortCircuitIccMaterialTableCell({ formName, @@ -24,9 +24,9 @@ export function ShortCircuitIccMaterialTableCell({ inputsDisabled?: boolean; }>) { return ( - + {column.dataKey === SHORT_CIRCUIT_ICC_MATERIAL_ACTIVE && ( - + )} {column.dataKey === SHORT_CIRCUIT_ICC_MATERIAL_TYPE && ( diff --git a/src/components/parameters/short-circuit/short-circuit-icc-material-table-columns-definition.ts b/src/components/parameters/short-circuit/short-circuit-icc-material-table-columns-definition.ts deleted file mode 100644 index 39e74796..00000000 --- a/src/components/parameters/short-circuit/short-circuit-icc-material-table-columns-definition.ts +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Copyright (c) 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/. - */ - -export const SHORT_CIRCUIT_ICC_MATERIAL_ACTIVE = 'active'; -export const SHORT_CIRCUIT_ICC_MATERIAL_TYPE = 'type'; -export const SHORT_CIRCUIT_ICC_MATERIAL_ALPHA = 'alpha'; -export const SHORT_CIRCUIT_ICC_MATERIAL_USMIN = 'usMin'; -export const SHORT_CIRCUIT_ICC_MATERIAL_USMAX = 'usMax'; -export const SHORT_CIRCUIT_ICC_MATERIAL_U0 = 'u0'; - -export interface IccMaterialIColumnsDef { - label: React.ReactNode; - dataKey: string; - tooltip: React.ReactNode; -} - -export const COLUMNS_DEFINITIONS_ICC_MATERIALS: IccMaterialIColumnsDef[] = [ - { - label: 'ShortCircuitIccMaterialActivate', - dataKey: SHORT_CIRCUIT_ICC_MATERIAL_ACTIVE, - tooltip: 'ShortCircuitIccMaterialActivateTooltip', - }, - { - label: 'ShortCircuitIccMaterialType', - dataKey: SHORT_CIRCUIT_ICC_MATERIAL_TYPE, - tooltip: 'ShortCircuitIccMaterialTypeTooltip', - }, - { - label: 'ShortCircuitIccMaterialAlpha', - dataKey: SHORT_CIRCUIT_ICC_MATERIAL_ALPHA, - tooltip: 'ShortCircuitIccMaterialAlphaTooltip', - }, - { - label: 'ShortCircuitIccMaterialUsmin', - dataKey: SHORT_CIRCUIT_ICC_MATERIAL_USMIN, - tooltip: 'ShortCircuitIccMaterialUsminTooltip', - }, - { - label: 'ShortCircuitIccMaterialUsmax', - dataKey: SHORT_CIRCUIT_ICC_MATERIAL_USMAX, - tooltip: 'ShortCircuitIccMaterialUsmaxTooltip', - }, - { - label: 'ShortCircuitIccMaterialU0', - dataKey: SHORT_CIRCUIT_ICC_MATERIAL_U0, - tooltip: 'ShortCircuitIccMaterialU0Tooltip', - }, -]; diff --git a/src/components/parameters/short-circuit/short-circuit-icc-material-table-row.tsx b/src/components/parameters/short-circuit/short-circuit-icc-material-table-row.tsx index 3950d3bf..43e4cebc 100644 --- a/src/components/parameters/short-circuit/short-circuit-icc-material-table-row.tsx +++ b/src/components/parameters/short-circuit/short-circuit-icc-material-table-row.tsx @@ -6,10 +6,7 @@ */ import { TableRow } from '@mui/material'; import { useWatch } from 'react-hook-form'; -import { - IccMaterialIColumnsDef, - SHORT_CIRCUIT_ICC_MATERIAL_ACTIVE, -} from './short-circuit-icc-material-table-columns-definition'; +import { IccMaterialIColumnsDef, SHORT_CIRCUIT_ICC_MATERIAL_ACTIVE } from './columns-definition'; import { ShortCircuitIccMaterialTableCell } from './short-circuit-icc-material-table-cell'; interface ShortCircuitIccMaterialTableRowProps { diff --git a/src/components/parameters/short-circuit/short-circuit-icc-material-table.tsx b/src/components/parameters/short-circuit/short-circuit-icc-material-table.tsx index d52e99f1..31a7c65c 100644 --- a/src/components/parameters/short-circuit/short-circuit-icc-material-table.tsx +++ b/src/components/parameters/short-circuit/short-circuit-icc-material-table.tsx @@ -5,48 +5,50 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Tooltip } from '@mui/material'; +import { Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Theme, Tooltip } from '@mui/material'; import { useFieldArray } from 'react-hook-form'; -import { IccMaterialIColumnsDef } from './short-circuit-icc-material-table-columns-definition'; +import { IccMaterialIColumnsDef } from './columns-definition'; import { ShortCircuitIccMaterialTableRow } from './short-circuit-icc-material-table-row'; interface ShortCircuitIccMaterialTableProps { columnsDefinition: IccMaterialIColumnsDef[]; - tableHeight: number; formName: string; } +const styles = { + tableContainer: (theme: Theme) => ({ + width: '100%', + border: 'solid 0px rgba(0,0,0,0.1)', + marginBottom: theme.spacing(4), + }), + table: { + minWidth: '80em', + tableLayout: 'fixed', + }, +}; + export function ShortCircuitIccMaterialTable({ formName, columnsDefinition, - tableHeight, }: Readonly) { const { fields: rows } = useFieldArray({ name: formName, }); return ( - - + +
{columnsDefinition.map((column) => ( - + {column.label} ))} + + {/* empty cell for alignment with delete button column in cluster table */} diff --git a/src/components/parameters/short-circuit/short-circuit-parameters-utils.ts b/src/components/parameters/short-circuit/short-circuit-parameters-utils.ts index ca5d1bd5..7b5134d6 100644 --- a/src/components/parameters/short-circuit/short-circuit-parameters-utils.ts +++ b/src/components/parameters/short-circuit/short-circuit-parameters-utils.ts @@ -8,6 +8,8 @@ import { InitialVoltage, SHORT_CIRCUIT_INITIAL_VOLTAGE_PROFILE_MODE, + SHORT_CIRCUIT_POWER_ELECTRONICS_CLUSTER, + SHORT_CIRCUIT_POWER_ELECTRONICS_CLUSTERS, SHORT_CIRCUIT_POWER_ELECTRONICS_MATERIALS, SHORT_CIRCUIT_WITH_FEEDER_RESULT, SHORT_CIRCUIT_WITH_LOADS, @@ -17,15 +19,22 @@ import { } from './constants'; import yup from '../../../utils/yupConfig'; import { COMMON_PARAMETERS, SPECIFIC_PARAMETERS } from '../common'; -import { type SpecificParameterInfos, type SpecificParametersValues } from '../../../utils'; +import { ID, snackWithFallback, type SpecificParameterInfos, type SpecificParametersValues } from '../../../utils'; -import type { PowerElectronicsMaterial } from './short-circuit-parameters.type'; +import { + FilterPOJO, + FormPowerElectronicsCluster, + type PowerElectronicsCluster, + type PowerElectronicsMaterial, +} from './short-circuit-parameters.type'; import { formatSpecificParameters, getAllSpecificParametersValues, getDefaultSpecificParamsValues, getSpecificParametersFormSchema, } from '../common/utils'; +import { NAME } from '../../inputs'; +import { SnackInputs } from '../../../hooks'; export const getCommonShortCircuitParametersFormSchema = () => { return yup.object().shape({ @@ -68,6 +77,32 @@ export const getSpecificShortCircuitParametersFormSchema = ( .required() : undefined; + const powerElectronicsClustersParam = specificParametersDescriptionForProvider?.find( + (specificParam) => specificParam.name === SHORT_CIRCUIT_POWER_ELECTRONICS_CLUSTER + ); + + const powerElectronicsClustersSchema = powerElectronicsClustersParam + ? yup + .array() + .of( + yup.object().shape({ + active: yup.boolean().required(), + alpha: yup.number().required(), + u0: yup.number().required(), + usMin: yup.number().required(), + usMax: yup.number().required(), + filters: yup.array().of( + yup.object().shape({ + [ID]: yup.string().required(), + [NAME]: yup.string().required(), + }) + ), + type: yup.string().oneOf(['WIND', 'SOLAR', 'HVDC']).required(), + }) + ) + .required() + : undefined; + // try to extract existing SPECIFIC_PARAMETERS fields from defaultSchema (if present) const existingSpecificSchema = (defaultSchema as any).fields?.[SPECIFIC_PARAMETERS] as | yup.ObjectSchema @@ -79,6 +114,9 @@ export const getSpecificShortCircuitParametersFormSchema = ( ...(powerElectronicsMaterialsSchema ? { [SHORT_CIRCUIT_POWER_ELECTRONICS_MATERIALS]: powerElectronicsMaterialsSchema } : {}), + ...(powerElectronicsClustersSchema + ? { [SHORT_CIRCUIT_POWER_ELECTRONICS_CLUSTERS]: powerElectronicsClustersSchema } + : {}), }; const overrideSchema = yup.object().shape({ @@ -89,18 +127,36 @@ export const getSpecificShortCircuitParametersFormSchema = ( return defaultSchema.concat(overrideSchema); }; -const parsepowerElectronicsMaterialsParamString = (paramString: string): PowerElectronicsMaterial[] => { +const parsePowerElectronicsMaterialsParamString = ( + paramString: string, + snackError: (message: SnackInputs) => void +): PowerElectronicsMaterial[] => { // Attempt to parse the string into an array of PowerElectronicsMaterial objects try { return JSON.parse(paramString); } catch (error) { console.error('Error parsing power electronics materials parameter string:', error); + snackWithFallback(snackError, error, { headerId: 'ShortCircuitPowerElectronicsMaterialsParamParsingError' }); + return []; + } +}; + +const parsePowerElectronicsClustersParamString = ( + paramString: string, + snackError: (message: SnackInputs) => void +): (PowerElectronicsCluster & { active: boolean })[] => { + // Attempt to parse the string into an array of PowerElectronicsCluster objects + try { + return JSON.parse(paramString); + } catch (error) { + snackWithFallback(snackError, error, { headerId: 'ShortCircuitPowerElectronicsClustersParamParsingError' }); return []; } }; export const getDefaultShortCircuitSpecificParamsValues = ( - specificParametersDescriptionForProvider: SpecificParameterInfos[] + specificParametersDescriptionForProvider: SpecificParameterInfos[], + snackError: (message: SnackInputs) => void ): SpecificParametersValues => { const defaultValues: SpecificParametersValues = getDefaultSpecificParamsValues( specificParametersDescriptionForProvider @@ -109,8 +165,9 @@ export const getDefaultShortCircuitSpecificParamsValues = ( (specificParam) => specificParam.name === SHORT_CIRCUIT_POWER_ELECTRONICS_MATERIALS ); if (powerElectronicsMaterialsParam) { - const electronicsMaterialsArray: PowerElectronicsMaterial[] = parsepowerElectronicsMaterialsParamString( - powerElectronicsMaterialsParam.defaultValue + const electronicsMaterialsArray: PowerElectronicsMaterial[] = parsePowerElectronicsMaterialsParamString( + powerElectronicsMaterialsParam.defaultValue, + snackError ); defaultValues[SHORT_CIRCUIT_POWER_ELECTRONICS_MATERIALS] = electronicsMaterialsArray.map((material) => ({ @@ -118,6 +175,12 @@ export const getDefaultShortCircuitSpecificParamsValues = ( active: false, })); } + const powerElectronicsClustersParam = specificParametersDescriptionForProvider.find( + (specificParam) => specificParam.name === SHORT_CIRCUIT_POWER_ELECTRONICS_CLUSTER + ); + if (powerElectronicsClustersParam) { + defaultValues[SHORT_CIRCUIT_POWER_ELECTRONICS_CLUSTERS] = []; // there is no default params for clusters for now + } return defaultValues; }; @@ -127,7 +190,9 @@ export const getShortCircuitSpecificParametersValues = ( ): SpecificParametersValues => { const powerElectronicsMaterialsParam: (PowerElectronicsMaterial & { active: boolean })[] = formData[SPECIFIC_PARAMETERS][SHORT_CIRCUIT_POWER_ELECTRONICS_MATERIALS]; - if (powerElectronicsMaterialsParam) { + const powerElectronicsClustersParam: (FormPowerElectronicsCluster & { active: boolean })[] = + formData[SPECIFIC_PARAMETERS][SHORT_CIRCUIT_POWER_ELECTRONICS_CLUSTERS]; + if (powerElectronicsMaterialsParam && powerElectronicsClustersParam) { // create pretty JSON return { ...getAllSpecificParametersValues(formData, _specificParametersValues), @@ -139,6 +204,17 @@ export const getShortCircuitSpecificParametersValues = ( return rest; }) ), + [SHORT_CIRCUIT_POWER_ELECTRONICS_CLUSTERS]: JSON.stringify( + powerElectronicsClustersParam.map((sParam) => { + const { filters, ...rest } = sParam; + const lightFilters = // keep only id and name in filters for backend + filters?.map((filter) => ({ + filterId: filter[ID], + filterName: filter.name, + })) ?? []; + return { ...rest, filters: lightFilters }; + }) + ), }; } return getAllSpecificParametersValues(formData, _specificParametersValues); @@ -146,22 +222,45 @@ export const getShortCircuitSpecificParametersValues = ( const formatElectronicsMaterialsParamString = ( defaultValues: PowerElectronicsMaterial[], - specificParamValue: string + specificParamValue: string, + snackError: (message: SnackInputs) => void ) => { - const electronicsMaterialsArrayInParams: PowerElectronicsMaterial[] = - parsepowerElectronicsMaterialsParamString(specificParamValue); + const electronicsMaterialsArrayInParams: PowerElectronicsMaterial[] = parsePowerElectronicsMaterialsParamString( + specificParamValue, + snackError + ); return defaultValues.map((material) => { const foundInParams = electronicsMaterialsArrayInParams.find((m) => m.type === material.type); return foundInParams ? { ...foundInParams, active: true } : { ...material, active: false }; }); }; +const formatElectronicsClustersParamString = ( + defaultValues: PowerElectronicsCluster[], + specificParamValue: string, + snackError: (message: SnackInputs) => void +) => { + const electronicsClustersArrayInParams: (PowerElectronicsCluster & { active: boolean })[] = + parsePowerElectronicsClustersParamString(specificParamValue, snackError); + return electronicsClustersArrayInParams.map((cluster) => { + const { filters, ...rest } = cluster; + return { + ...rest, + filters: filters.map((filter) => ({ + [ID]: filter.filterId, + [NAME]: filter.filterName, // from back to front -> {id: uuid, name: string} + })), + }; + }); +}; + export const formatShortCircuitSpecificParameters = ( specificParametersDescriptionForProvider: SpecificParameterInfos[], - specificParamsList: SpecificParametersValues + specificParamsList: SpecificParametersValues, + snackError: (message: SnackInputs) => void ): SpecificParametersValues => { if (!specificParamsList) { - return getDefaultShortCircuitSpecificParamsValues(specificParametersDescriptionForProvider); + return getDefaultShortCircuitSpecificParamsValues(specificParametersDescriptionForProvider, snackError); } // reuse generic formatter for specific params @@ -174,8 +273,11 @@ export const formatShortCircuitSpecificParameters = ( if (powerParam) { if (Object.hasOwn(specificParamsList, SHORT_CIRCUIT_POWER_ELECTRONICS_MATERIALS)) { formatted[SHORT_CIRCUIT_POWER_ELECTRONICS_MATERIALS] = formatElectronicsMaterialsParamString( - getDefaultShortCircuitSpecificParamsValues([powerParam])?.[SHORT_CIRCUIT_POWER_ELECTRONICS_MATERIALS], - specificParamsList[SHORT_CIRCUIT_POWER_ELECTRONICS_MATERIALS] as string + getDefaultShortCircuitSpecificParamsValues([powerParam], snackError)?.[ + SHORT_CIRCUIT_POWER_ELECTRONICS_MATERIALS + ], + specificParamsList[SHORT_CIRCUIT_POWER_ELECTRONICS_MATERIALS] as string, + snackError ); } else { formatted[SHORT_CIRCUIT_POWER_ELECTRONICS_MATERIALS] = getDefaultSpecificParamsValues([powerParam])?.[ @@ -183,5 +285,25 @@ export const formatShortCircuitSpecificParameters = ( ]; } } + + // handle special power-electronics-clusters case by overriding the generic result + const powerElectronicsClustersParam = specificParametersDescriptionForProvider.find( + (p) => p.name === SHORT_CIRCUIT_POWER_ELECTRONICS_CLUSTER + ); + if (powerElectronicsClustersParam) { + if (Object.hasOwn(specificParamsList, SHORT_CIRCUIT_POWER_ELECTRONICS_CLUSTERS)) { + formatted[SHORT_CIRCUIT_POWER_ELECTRONICS_CLUSTERS] = formatElectronicsClustersParamString( + getDefaultShortCircuitSpecificParamsValues([powerElectronicsClustersParam], snackError)?.[ + SHORT_CIRCUIT_POWER_ELECTRONICS_CLUSTERS + ], + specificParamsList[SHORT_CIRCUIT_POWER_ELECTRONICS_CLUSTERS] as string, + snackError + ); + } else { + formatted[SHORT_CIRCUIT_POWER_ELECTRONICS_CLUSTERS] = getDefaultSpecificParamsValues([ + powerElectronicsClustersParam, + ])?.[SHORT_CIRCUIT_POWER_ELECTRONICS_CLUSTERS]; + } + } return formatted; }; diff --git a/src/components/parameters/short-circuit/short-circuit-parameters.type.ts b/src/components/parameters/short-circuit/short-circuit-parameters.type.ts index fcbb664f..f7cde42b 100644 --- a/src/components/parameters/short-circuit/short-circuit-parameters.type.ts +++ b/src/components/parameters/short-circuit/short-circuit-parameters.type.ts @@ -4,7 +4,8 @@ * 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 { SpecificParametersPerProvider } from '../../../utils'; +import { UUID } from 'node:crypto'; +import { FilterIdentifier, SpecificParametersPerProvider } from '../../../utils'; import { InitialVoltage, PredefinedParameters } from './constants'; export interface VoltageRange { @@ -22,6 +23,26 @@ export interface PowerElectronicsMaterial { type: 'WIND' | 'SOLAR' | 'HVDC'; } +export type FilterPOJO = { + id: UUID; + name: string; +}; + +export interface FormPowerElectronicsCluster { + alpha: number; + u0: number; + usMin: number; + usMax: number; + filters: FilterPOJO[]; +} +export interface PowerElectronicsCluster { + alpha: number; + u0: number; + usMin: number; + usMax: number; + filters: FilterIdentifier[]; +} + export interface ShortCircuitParametersDto { withFeederResult: boolean; withLoads: boolean; diff --git a/src/components/parameters/short-circuit/use-short-circuit-parameters-form.ts b/src/components/parameters/short-circuit/use-short-circuit-parameters-form.ts index e6790877..48d9a676 100644 --- a/src/components/parameters/short-circuit/use-short-circuit-parameters-form.ts +++ b/src/components/parameters/short-circuit/use-short-circuit-parameters-form.ts @@ -78,9 +78,9 @@ export const useShortCircuitParametersForm = ({ const specificParametersDefaultValues = useMemo(() => { return { - ...getDefaultShortCircuitSpecificParamsValues(specificParametersDescriptionForProvider), + ...getDefaultShortCircuitSpecificParamsValues(specificParametersDescriptionForProvider, snackError), }; - }, [specificParametersDescriptionForProvider]); + }, [snackError, specificParametersDescriptionForProvider]); const formSchema = useMemo(() => { return yup @@ -205,13 +205,14 @@ export const useShortCircuitParametersForm = ({ [SPECIFIC_PARAMETERS]: { ...formatShortCircuitSpecificParameters( specificParametersDescriptionForProvider, - specificParamsListForCurrentProvider + specificParamsListForCurrentProvider, + snackError ), }, }; return values; }, - [provider, specificParametersDescriptionForProvider] + [provider, snackError, specificParametersDescriptionForProvider] ); const onValidationError = useCallback((_errors: FieldErrors) => { diff --git a/src/translations/en/parameters.ts b/src/translations/en/parameters.ts index 0a9b4165..30473e7e 100644 --- a/src/translations/en/parameters.ts +++ b/src/translations/en/parameters.ts @@ -121,18 +121,28 @@ export const parametersEn = { ShortCircuitStartedGeneratorsMode: 'Generators started', ShortCircuitPowerElectronicsSection: 'Modeling of power electronics connected equipment', ShortCircuitModelPowerElectronics: 'Consider following Icc characteristics', - ShortCircuitIccMaterialActivate: 'Activate', - ShortCircuitIccMaterialActivateTooltip: 'Activate or deactivate this material characteristic', + ShortCircuitIccActive: 'Activate', + ShortCircuitIccMaterialActiveTooltip: 'Activate or deactivate this material characteristic', ShortCircuitIccMaterialType: 'Material', ShortCircuitIccMaterialTypeTooltip: 'Type of power electronics equipment', - ShortCircuitIccMaterialAlpha: 'Alpha', - ShortCircuitIccMaterialAlphaTooltip: 'Exponent of the voltage dependency of the Icc', - ShortCircuitIccMaterialUsmin: 'Usmin (%)', - ShortCircuitIccMaterialUsminTooltip: 'Minimum voltage for the Icc calculation', - ShortCircuitIccMaterialUsmax: 'Usmax (%)', - ShortCircuitIccMaterialUsmaxTooltip: 'Maximum voltage for the Icc calculation', - ShortCircuitIccMaterialU0: 'U0 (%)', - ShortCircuitIccMaterialU0Tooltip: 'Voltage level at which the Icc is nominal', + ShortCircuitPowerElectronicsMaterialsParamParsingError: + 'An error occurred while parsing the power electronics materials parameters', + ShortCircuitIccClusterActiveTooltip: 'Activate or deactivate this cluster characteristic', + ShortCircuitIccClusterFilters: 'Filters', + ShortCircuitIccClusterFiltersTooltip: 'Select the filters to be included in this cluster', + ShortCircuitIccClusterType: 'Cluster type', + ShortCircuitIccClusterTypeTooltip: 'Select the types of equipment to be included in this cluster', + ShortCircuitIccClusterTypeListsSelection: 'Type', + ShortCircuitPowerElectronicsClustersParamParsingError: + 'An error occurred while parsing the power electronics clusters parameters', + ShortCircuitIccAlpha: 'Alpha', + ShortCircuitIccAlphaTooltip: 'Exponent of the voltage dependency of the Icc', + ShortCircuitIccUsmin: 'Usmin (%)', + ShortCircuitIccUsminTooltip: 'Minimum voltage for the Icc calculation', + ShortCircuitIccUsmax: 'Usmax (%)', + ShortCircuitIccUsmaxTooltip: 'Maximum voltage for the Icc calculation', + ShortCircuitIccU0: 'U0 (%)', + ShortCircuitIccU0Tooltip: 'Voltage level at which the Icc is nominal', ShortCircuitWindLabel: 'Wind', ShortCircuitSolarLabel: 'Solar', ShortCircuitHvdcLabel: 'HVDC', diff --git a/src/translations/fr/parameters.ts b/src/translations/fr/parameters.ts index 5abde27e..c3061bea 100644 --- a/src/translations/fr/parameters.ts +++ b/src/translations/fr/parameters.ts @@ -125,19 +125,29 @@ export const parametersFr = { ShortCircuitStartedGeneratorsMode: 'Démarrage des groupes', ShortCircuitPowerElectronicsSection: "Modélisation des équipements raccordés par de l'électronique de puissance", ShortCircuitModelPowerElectronics: "Prise en compte des caractéristiques d'Icc suivantes", - ShortCircuitIccMaterialActivate: 'Actif', - ShortCircuitIccMaterialActivateTooltip: + ShortCircuitIccActive: 'Actif', + ShortCircuitIccMaterialActiveTooltip: "Activer la modélisation des équipements raccordés par de l'électronique de puissance", ShortCircuitIccMaterialType: 'Matériel', ShortCircuitIccMaterialTypeTooltip: "Type d'équipement raccordé par de l'électronique de puissance", - ShortCircuitIccMaterialAlpha: 'Alpha', - ShortCircuitIccMaterialAlphaTooltip: 'Coefficient de pente de la caractéristique Icc', - ShortCircuitIccMaterialUsmin: 'Usmin (%)', - ShortCircuitIccMaterialUsminTooltip: 'Tension minimale pour le calcul de Icc', - ShortCircuitIccMaterialUsmax: 'Usmax (%)', - ShortCircuitIccMaterialUsmaxTooltip: 'Tension maximale pour le calcul de Icc', - ShortCircuitIccMaterialU0: 'U0 (%)', - ShortCircuitIccMaterialU0Tooltip: 'Tension de référence pour le calcul de Icc', + ShortCircuitPowerElectronicsMaterialsParamParsingError: + "Une erreur est survenue lors de l'analyse des paramètres des matériaux d'électronique de puissance", + ShortCircuitIccClusterActiveTooltip: "Activer la modélisation des clusters d'électronique de puissance", + ShortCircuitIccClusterFilters: 'Filtres', + ShortCircuitIccClusterFiltersTooltip: 'Filtres de sélection des clusters', + ShortCircuitIccClusterType: 'Type de cluster', + ShortCircuitIccClusterTypeTooltip: "Sélectionner les types d'équipements à inclure dans ce cluster", + ShortCircuitIccClusterTypeListsSelection: 'Type', + ShortCircuitPowerElectronicsClustersParamParsingError: + "Une erreur est survenue lors de l'analyse des paramètres des clusters d'électronique de puissance", + ShortCircuitIccAlpha: 'Alpha', + ShortCircuitIccAlphaTooltip: 'Coefficient de pente de la caractéristique Icc', + ShortCircuitIccUsmin: 'Usmin (%)', + ShortCircuitIccUsminTooltip: 'Tension minimale pour le calcul de Icc', + ShortCircuitIccUsmax: 'Usmax (%)', + ShortCircuitIccUsmaxTooltip: 'Tension maximale pour le calcul de Icc', + ShortCircuitIccU0: 'U0 (%)', + ShortCircuitIccU0Tooltip: 'Tension de référence pour le calcul de Icc', ShortCircuitWindLabel: 'Éolien', ShortCircuitSolarLabel: 'Solaire', ShortCircuitHvdcLabel: 'HVDC',