From be347f82e39f0e23512fe6fd3b4f1e441b97818e Mon Sep 17 00:00:00 2001 From: Etienne LESOT Date: Mon, 16 Feb 2026 08:50:31 +0100 Subject: [PATCH 01/15] add several limits with line catalog Signed-off-by: Etienne LESOT --- .../line-types-catalog/line-catalog.type.ts | 15 +- .../line-type-segment-form.tsx | 140 +++++++++++------- .../line-types-catalog-selector-dialog.tsx | 25 ++-- .../line-types-catalog/segment-utils.ts | 16 +- .../line/creation/line-creation-dialog.tsx | 19 ++- src/components/utils/field-constants.ts | 2 +- src/services/network-modification.ts | 11 +- 7 files changed, 152 insertions(+), 76 deletions(-) diff --git a/src/components/dialogs/line-types-catalog/line-catalog.type.ts b/src/components/dialogs/line-types-catalog/line-catalog.type.ts index 2fd2a4c5cc..aa7ddae40a 100644 --- a/src/components/dialogs/line-types-catalog/line-catalog.type.ts +++ b/src/components/dialogs/line-types-catalog/line-catalog.type.ts @@ -40,13 +40,22 @@ export type ComputedLineCharacteristics = { export type CurrentLimitsInfo = { limitSetName: string; permanentLimit: number; - temporaryLimitValue: number; - temporaryLimitAcceptableDuration: number; - temporaryLimitName: string; + temporaryLimits: TemporaryLimitsInfo[]; area: string; temperature: string; }; +export type AreaAndTemperatureInfo = { + area: string | null; + temperature: string | null; +}; + +export type TemporaryLimitsInfo = { + limitValue: number; + acceptableDuration: number; + name: string; +}; + export const CATEGORIES_TABS = { AERIAL: { id: 0, name: 'AERIAL' }, UNDERGROUND: { id: 1, name: 'UNDERGROUND' }, diff --git a/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx b/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx index 0fff828477..c167ea0939 100644 --- a/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx +++ b/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx @@ -36,9 +36,9 @@ import { snackWithFallback, useSnackMessage, } from '@gridsuite/commons-ui'; -import { getLineTypesCatalog } from '../../../services/network-modification'; +import { getLineTypesCatalog, getLineTypeWithLimits } from '../../../services/network-modification'; import GridItem from '../commons/grid-item'; -import { CurrentLimitsInfo, LineTypeInfo } from './line-catalog.type'; +import { CurrentLimitsInfo, AreaAndTemperatureInfo, LineTypeInfo } from './line-catalog.type'; import { emptyLineSegment, SegmentFormData } from './segment-utils'; import { ColDef } from 'ag-grid-community'; import GridSection from '../commons/grid-section'; @@ -104,12 +104,10 @@ export const LineTypeSegmentForm = () => { ); const updateSegmentLimitsValues = useCallback( - (index: number) => { - const typeId = getValues(`${SEGMENTS}.${index}.${SEGMENT_TYPE_ID}`); - const entryFromCatalog = lineTypesCatalog?.find((entry) => entry.id === typeId); - setValue(`${SEGMENTS}.${index}.${SEGMENT_CURRENT_LIMITS}`, entryFromCatalog?.limitsForLineType); + (index: number, limitInfo: CurrentLimitsInfo[]) => { + setValue(`${SEGMENTS}.${index}.${SEGMENT_CURRENT_LIMITS}`, limitInfo); }, - [getValues, setValue, lineTypesCatalog] + [setValue] ); const updateTotals = useCallback(() => { @@ -141,54 +139,69 @@ export const LineTypeSegmentForm = () => { const keepMostConstrainingLimits = useCallback(() => { const segments: SegmentFormData[] = getValues(SEGMENTS); - const computedLimits = new Map(); + const mostContrainingLimits = new Map(); segments.forEach((segment) => { segment[SEGMENT_CURRENT_LIMITS]?.forEach((limit: CurrentLimitsInfo) => { - if (computedLimits.has(limit.limitSetName)) { - let computedLimit: CurrentLimitsInfo | undefined = computedLimits.get(limit.limitSetName); - if (computedLimit !== undefined) { - if (limit?.temporaryLimitValue != null) { - if (computedLimit.temporaryLimitValue == null) { - computedLimit.temporaryLimitValue = limit.temporaryLimitValue; - computedLimit.temporaryLimitName = limit.temporaryLimitName; - computedLimit.temporaryLimitAcceptableDuration = limit.temporaryLimitAcceptableDuration; - } else { - let temporaryLimitValue = Math.min( - computedLimit.temporaryLimitValue, - limit.temporaryLimitValue - ); - if (temporaryLimitValue === limit.temporaryLimitValue) { - computedLimit.temporaryLimitValue = limit.temporaryLimitValue; - computedLimit.temporaryLimitAcceptableDuration = - limit.temporaryLimitAcceptableDuration; - computedLimit.temporaryLimitName = limit.temporaryLimitName; + if (mostContrainingLimits.has(limit.limitSetName)) { + let computedLimit: CurrentLimitsInfo | undefined = mostContrainingLimits.get(limit.limitSetName); + if (computedLimit !== undefined && computedLimit.temporaryLimits !== null) { + limit.temporaryLimits.forEach((temporaryLimit) => { + const foundTemporaryLimit = computedLimit?.temporaryLimits.find( + (temporaryLimitData) => temporaryLimitData.name === temporaryLimit.name + ); + if (foundTemporaryLimit !== undefined) { + if (temporaryLimit.limitValue !== null) { + foundTemporaryLimit.limitValue = Math.min( + foundTemporaryLimit.limitValue, + temporaryLimit.limitValue + ); + } else { + foundTemporaryLimit.limitValue = temporaryLimit.limitValue; } + } else { + computedLimit?.temporaryLimits.push(Object.assign({}, temporaryLimit)); } - } + }); computedLimit.permanentLimit = Math.min(computedLimit.permanentLimit, limit.permanentLimit); } } else { - computedLimits.set(limit.limitSetName, limit); + // need deep copy else segment[SEGMENT_CURRENT_LIMITS] will be modified with computedLimit + mostContrainingLimits.set(limit.limitSetName, JSON.parse(JSON.stringify(limit))); } }); }); - setCurrentLimitResult(Array.from(computedLimits.values())); - setValue(FINAL_CURRENT_LIMITS, Array.from(computedLimits.values())); + setCurrentLimitResult(Array.from(mostContrainingLimits.values())); + setValue(FINAL_CURRENT_LIMITS, Array.from(mostContrainingLimits.values())); }, [getValues, setValue, setCurrentLimitResult]); const onSelectCatalogLine = useCallback( - (selectedLine: LineTypeInfo) => { - if (selectedLine && openCatalogDialogIndex !== null) { - const selectedType = selectedLine.type ?? ''; - const selectedTypeId = selectedLine.id ?? ''; - setValue(`${SEGMENTS}.${openCatalogDialogIndex}.${SEGMENT_TYPE_VALUE}`, selectedType); - setValue(`${SEGMENTS}.${openCatalogDialogIndex}.${SEGMENT_TYPE_ID}`, selectedTypeId); - clearErrors(`${SEGMENTS}.${openCatalogDialogIndex}.${SEGMENT_TYPE_VALUE}`); - updateSegmentValues(openCatalogDialogIndex); - updateSegmentLimitsValues(openCatalogDialogIndex); - updateTotals(); - keepMostConstrainingLimits(); - } + ( + selectedLine: LineTypeInfo, + selectedAreaAndTemperature2LineTypeData: { area: string | null; temperature: string | null } + ) => { + getLineTypeWithLimits( + selectedLine.id, + selectedAreaAndTemperature2LineTypeData?.area, + selectedAreaAndTemperature2LineTypeData?.temperature + ) + .then((lineTypeWithLimits) => { + if (lineTypeWithLimits && openCatalogDialogIndex !== null) { + const selectedType = lineTypeWithLimits.type ?? ''; + const selectedTypeId = lineTypeWithLimits.id ?? ''; + setValue(`${SEGMENTS}.${openCatalogDialogIndex}.${SEGMENT_TYPE_VALUE}`, selectedType); + setValue(`${SEGMENTS}.${openCatalogDialogIndex}.${SEGMENT_TYPE_ID}`, selectedTypeId); + clearErrors(`${SEGMENTS}.${openCatalogDialogIndex}.${SEGMENT_TYPE_VALUE}`); + updateSegmentValues(openCatalogDialogIndex); + updateSegmentLimitsValues(openCatalogDialogIndex, lineTypeWithLimits.limitsForLineType); + updateTotals(); + keepMostConstrainingLimits(); + } + }) + .catch((error) => + snackWithFallback(snackError, error, { + headerId: 'LineTypesCatalogFetchingError', + }) + ); }, [ updateSegmentValues, @@ -278,7 +291,7 @@ export const LineTypeSegmentForm = () => { ); const limitsColumnDefs = useMemo((): ColDef[] => { - return [ + let base: ColDef[] = [ { headerName: intl.formatMessage({ id: 'lineTypes.currentLimits.limitSet' }), field: 'limitSetName', @@ -290,13 +303,40 @@ export const LineTypeSegmentForm = () => { field: 'permanentLimit', cellRenderer: DefaultCellRenderer, }, - { - headerName: intl.formatMessage({ id: 'lineTypes.currentLimits.Temporary' }), - field: 'temporaryLimitValue', - cellRenderer: DefaultCellRenderer, - }, ]; - }, [intl]); + let limitNamesSet = new Set(); + currentLimitResult.forEach((limit) => { + limit.temporaryLimits?.forEach((temporaryLimit) => { + limitNamesSet.add(temporaryLimit.name); + }); + }); + let i = 0; + limitNamesSet.forEach((limitName) => { + base.push({ + headerName: `${limitName}`, + field: 'temporaryLimit' + i, + cellRenderer: DefaultCellRenderer, + }); + i++; + }); + return base; + }, [intl, currentLimitResult]); + + const rowData = useMemo(() => { + const testArray: any[] = []; + currentLimitResult.forEach((currentLimit) => { + let test: any = {}; + test['limitSetName'] = currentLimit.limitSetName; + test['permanentLimit'] = currentLimit.permanentLimit; + let c = 0; + currentLimit.temporaryLimits?.forEach((temporaryLimit) => { + test['temporaryLimit' + c] = temporaryLimit.limitValue; + c++; + }); + testArray.push(test); + }); + return testArray; + }, [currentLimitResult]); return ( <> @@ -331,7 +371,7 @@ export const LineTypeSegmentForm = () => { ; export type LineTypesCatalogSelectorDialogProps = { - onSelectLine: (selectedLine: LineTypeInfo) => void; + onSelectLine: (selectedLine: LineTypeInfo, selectedAreaAndTemperature: AreaAndTemperatureInfo) => void; preselectedRowId: string; rowData: LineTypeInfo[]; onClose: () => void; @@ -109,7 +109,7 @@ export default function LineTypesCatalogSelectorDialog({ const { setValue, getValues } = formMethods; const handleSelectedAerial = useCallback( - (selectedAerialRow: LineTypeInfo) => { + (selectedAerialRow: LineTypeInfo): AreaAndTemperatureInfo => { const selectedArea = getValues(AERIAL_AREAS); const selectedTemperature = getValues(AERIAL_TEMPERATURES); @@ -119,15 +119,15 @@ export default function LineTypesCatalogSelectorDialog({ ); selectedAerialRow.limitsForLineType = filteredLimits ? filteredLimits : []; } + return { area: selectedArea.id, temperature: selectedTemperature.id }; }, [getValues, areasOptions?.length, aerialTemperatures?.length] ); const handleSelectedUnderground = useCallback( - (selectedUndergroundRow: LineTypeInfo) => { + (selectedUndergroundRow: LineTypeInfo): AreaAndTemperatureInfo => { const selectedArea = getValues(UNDERGROUND_AREAS); const selectedShapeFactor = getValues(UNDERGROUND_SHAPE_FACTORS); - const areaId = selectedArea?.id; const shapeFactorId = selectedShapeFactor?.id; @@ -148,18 +148,19 @@ export default function LineTypesCatalogSelectorDialog({ selectedUndergroundRow.limitsForLineType = []; } } + return { area: selectedArea.id, temperature: null }; }, [getValues, areasOptions] ); const onSubmit = useCallback(() => { + let selectedAreaAndTemperature: AreaAndTemperatureInfo = { area: null, temperature: null }; if (selectedRow?.category === CATEGORIES_TABS.AERIAL.name) { - handleSelectedAerial(selectedRow); + selectedAreaAndTemperature = handleSelectedAerial(selectedRow); } else if (selectedRow?.category === CATEGORIES_TABS.UNDERGROUND.name) { - handleSelectedUnderground(selectedRow); + selectedAreaAndTemperature = handleSelectedUnderground(selectedRow); } - - selectedRow && onSelectLine?.(selectedRow); + selectedRow && onSelectLine?.(selectedRow, selectedAreaAndTemperature); }, [selectedRow, handleSelectedAerial, handleSelectedUnderground, onSelectLine]); const createOptionsFromAreas = (limitsData?: CurrentLimitsInfo[]) => { @@ -191,7 +192,7 @@ export default function LineTypesCatalogSelectorDialog({ const handleSelectedRowData = useCallback( async (selectedData: LineTypeInfo) => { try { - const lineTypeWithLimits = await getLineTypeWithLimits(selectedData.id); + const lineTypeWithLimits = await getLineTypeWithAreaAndTemperature(selectedData.id); selectedData.limitsForLineType = lineTypeWithLimits.limitsForLineType; selectedData.shapeFactors = lineTypeWithLimits.shapeFactors; setSelectedRow(selectedData); diff --git a/src/components/dialogs/line-types-catalog/segment-utils.ts b/src/components/dialogs/line-types-catalog/segment-utils.ts index cf1e551986..87baa30ba6 100644 --- a/src/components/dialogs/line-types-catalog/segment-utils.ts +++ b/src/components/dialogs/line-types-catalog/segment-utils.ts @@ -7,6 +7,7 @@ import { LIMIT_SET_NAME, + LIMIT_VALUE, PERMANENT_LIMIT, SEGMENT_CURRENT_LIMITS, SEGMENT_DISTANCE_VALUE, @@ -15,7 +16,9 @@ import { SEGMENT_SUSCEPTANCE, SEGMENT_TYPE_ID, SEGMENT_TYPE_VALUE, - TEMPORARY_LIMIT, + TEMPORARY_LIMIT_DURATION, + TEMPORARY_LIMIT_NAME, + TEMPORARY_LIMITS, } from 'components/utils/field-constants'; import yup from '../../utils/yup-config'; @@ -36,7 +39,16 @@ export const SegmentSchema = yup.object().shape({ yup.object().shape({ [LIMIT_SET_NAME]: yup.string().required(), [PERMANENT_LIMIT]: yup.number().required(), - [TEMPORARY_LIMIT]: yup.number().nullable(), + [TEMPORARY_LIMITS]: yup + .array() + .of( + yup.object().shape({ + [LIMIT_VALUE]: yup.number().required(), + [TEMPORARY_LIMIT_DURATION]: yup.number().required(), + [TEMPORARY_LIMIT_NAME]: yup.string().required(), + }) + ) + .nullable(), }) ), }); diff --git a/src/components/dialogs/network-modifications/line/creation/line-creation-dialog.tsx b/src/components/dialogs/network-modifications/line/creation/line-creation-dialog.tsx index 446a0b6cca..76b269b668 100644 --- a/src/components/dialogs/network-modifications/line/creation/line-creation-dialog.tsx +++ b/src/components/dialogs/network-modifications/line/creation/line-creation-dialog.tsx @@ -92,7 +92,10 @@ import { LineCreationInfos } from '../../../../../services/network-modification- import { LineModificationFormSchema } from '../modification/line-modification-type'; import { ComputedLineCharacteristics, CurrentLimitsInfo } from '../../../line-types-catalog/line-catalog.type'; import { LineCreationFormSchema, LineFormInfos } from './line-creation-type'; -import { OperationalLimitsGroupFormSchema } from '../../../limits/operational-limits-groups-types'; +import { + OperationalLimitsGroupFormSchema, + TemporaryLimitFormSchema, +} from '../../../limits/operational-limits-groups-types'; import { NetworkModificationDialogProps } from '../../../../graph/menus/network-modifications/network-modification-menu.type'; const emptyFormData: any = { @@ -281,14 +284,14 @@ const LineCreationDialog = ({ }); const finalLimits: OperationalLimitsGroupFormSchema[] = []; data[FINAL_CURRENT_LIMITS].forEach((item: CurrentLimitsInfo) => { - const temporaryLimitsList = []; - if (item.temporaryLimitValue) { + const temporaryLimitsList: TemporaryLimitFormSchema[] = []; + item.temporaryLimits.forEach((temporaryLimit) => { temporaryLimitsList.push({ - name: item.temporaryLimitName, - acceptableDuration: item.temporaryLimitAcceptableDuration, - value: item.temporaryLimitValue, + name: temporaryLimit.name, + acceptableDuration: temporaryLimit.acceptableDuration, + value: temporaryLimit.limitValue, }); - } + }); finalLimits.push({ id: item.limitSetName + APPLICABILITY.EQUIPMENT.id, name: item.limitSetName, @@ -300,6 +303,8 @@ const LineCreationDialog = ({ }, }); }); + console.log('test'); + console.log(finalLimits); setValue(`${LIMITS}.${OPERATIONAL_LIMITS_GROUPS}`, finalLimits); }; diff --git a/src/components/utils/field-constants.ts b/src/components/utils/field-constants.ts index 7b8b3cc804..73bbc5731d 100644 --- a/src/components/utils/field-constants.ts +++ b/src/components/utils/field-constants.ts @@ -212,7 +212,7 @@ export const B2 = 'b2'; export const LIMITS = 'limits'; export const TAB_HEADER = 'tabHeader'; export const LIMIT_SET_NAME = 'limitSetName'; -export const TEMPORARY_LIMIT = 'temporaryLimit'; +export const LIMIT_VALUE = 'limitValue'; export const TEMPORARY_LIMITS = 'temporaryLimits'; export const TEMPORARY_LIMIT_NAME = 'name'; export const TEMPORARY_LIMIT_DURATION = 'acceptableDuration'; diff --git a/src/services/network-modification.ts b/src/services/network-modification.ts index cc8ba5c7cd..24306e151c 100644 --- a/src/services/network-modification.ts +++ b/src/services/network-modification.ts @@ -16,7 +16,16 @@ export function getLineTypesCatalog(): Promise { return backendFetchJson(url); } -export function getLineTypeWithLimits(id: string): Promise { +export function getLineTypeWithAreaAndTemperature(id: string): Promise { const url = `${PREFIX_NETWORK_MODIFICATION_QUERIES}/v1/network-modifications/catalog/line_types/${id}`; return backendFetchJson(url); } + +export function getLineTypeWithLimits( + id: string, + area: string | null, + temperature: string | null +): Promise { + const url = `${PREFIX_NETWORK_MODIFICATION_QUERIES}/v1/network-modifications/catalog/line_types/${id}/area/${area}/temperature/${temperature}`; + return backendFetchJson(url); +} From 38311a5bfd74769aba224f01d569aa0a49d7fd36 Mon Sep 17 00:00:00 2001 From: Etienne LESOT Date: Mon, 16 Feb 2026 09:04:48 +0100 Subject: [PATCH 02/15] fix type-check Signed-off-by: Etienne LESOT --- .../dialogs/line-types-catalog/line-type-segment-form.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx b/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx index c167ea0939..ac1aecda67 100644 --- a/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx +++ b/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx @@ -38,7 +38,7 @@ import { } from '@gridsuite/commons-ui'; import { getLineTypesCatalog, getLineTypeWithLimits } from '../../../services/network-modification'; import GridItem from '../commons/grid-item'; -import { CurrentLimitsInfo, AreaAndTemperatureInfo, LineTypeInfo } from './line-catalog.type'; +import { CurrentLimitsInfo, LineTypeInfo } from './line-catalog.type'; import { emptyLineSegment, SegmentFormData } from './segment-utils'; import { ColDef } from 'ag-grid-community'; import GridSection from '../commons/grid-section'; @@ -159,7 +159,7 @@ export const LineTypeSegmentForm = () => { foundTemporaryLimit.limitValue = temporaryLimit.limitValue; } } else { - computedLimit?.temporaryLimits.push(Object.assign({}, temporaryLimit)); + computedLimit?.temporaryLimits.push(temporaryLimit); } }); computedLimit.permanentLimit = Math.min(computedLimit.permanentLimit, limit.permanentLimit); @@ -211,6 +211,7 @@ export const LineTypeSegmentForm = () => { openCatalogDialogIndex, updateSegmentLimitsValues, keepMostConstrainingLimits, + snackError, ] ); From 2c96d97b5aa436c2946ee24059383532f0f261e3 Mon Sep 17 00:00:00 2001 From: Etienne LESOT Date: Mon, 16 Feb 2026 10:32:12 +0100 Subject: [PATCH 03/15] try to fix Signed-off-by: Etienne LESOT --- .../line-types-catalog/line-types-catalog-selector-dialog.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/dialogs/line-types-catalog/line-types-catalog-selector-dialog.tsx b/src/components/dialogs/line-types-catalog/line-types-catalog-selector-dialog.tsx index cf8ee747e0..7c5c35c8b4 100644 --- a/src/components/dialogs/line-types-catalog/line-types-catalog-selector-dialog.tsx +++ b/src/components/dialogs/line-types-catalog/line-types-catalog-selector-dialog.tsx @@ -119,7 +119,7 @@ export default function LineTypesCatalogSelectorDialog({ ); selectedAerialRow.limitsForLineType = filteredLimits ? filteredLimits : []; } - return { area: selectedArea.id, temperature: selectedTemperature.id }; + return { area: selectedArea?.id, temperature: selectedTemperature?.id } as AreaAndTemperatureInfo; }, [getValues, areasOptions?.length, aerialTemperatures?.length] ); @@ -148,7 +148,7 @@ export default function LineTypesCatalogSelectorDialog({ selectedUndergroundRow.limitsForLineType = []; } } - return { area: selectedArea.id, temperature: null }; + return { area: selectedArea?.id, temperature: null } as AreaAndTemperatureInfo; }, [getValues, areasOptions] ); From 33a6dd62a38ebd357500dbba83e7c3f7840eb156 Mon Sep 17 00:00:00 2001 From: Etienne LESOT Date: Mon, 16 Feb 2026 10:47:22 +0100 Subject: [PATCH 04/15] try to fix 2 Signed-off-by: Etienne LESOT --- .../line-types-catalog/line-type-segment-form.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx b/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx index ac1aecda67..d932b61a99 100644 --- a/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx +++ b/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx @@ -149,24 +149,24 @@ export const LineTypeSegmentForm = () => { const foundTemporaryLimit = computedLimit?.temporaryLimits.find( (temporaryLimitData) => temporaryLimitData.name === temporaryLimit.name ); - if (foundTemporaryLimit !== undefined) { - if (temporaryLimit.limitValue !== null) { + if (foundTemporaryLimit === undefined) { + computedLimit?.temporaryLimits.push(temporaryLimit); + } else { + if (temporaryLimit.limitValue === null) { + foundTemporaryLimit.limitValue = temporaryLimit.limitValue; + } else { foundTemporaryLimit.limitValue = Math.min( foundTemporaryLimit.limitValue, temporaryLimit.limitValue ); - } else { - foundTemporaryLimit.limitValue = temporaryLimit.limitValue; } - } else { - computedLimit?.temporaryLimits.push(temporaryLimit); } }); computedLimit.permanentLimit = Math.min(computedLimit.permanentLimit, limit.permanentLimit); } } else { // need deep copy else segment[SEGMENT_CURRENT_LIMITS] will be modified with computedLimit - mostContrainingLimits.set(limit.limitSetName, JSON.parse(JSON.stringify(limit))); + mostContrainingLimits.set(limit.limitSetName, structuredClone(limit)); } }); }); From 2d5703584d6969b34f08d47aeb55421e50df2787 Mon Sep 17 00:00:00 2001 From: Etienne LESOT Date: Mon, 16 Feb 2026 10:54:47 +0100 Subject: [PATCH 05/15] try to fix 3 Signed-off-by: Etienne LESOT --- .../line-types-catalog/line-type-segment-form.tsx | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx b/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx index d932b61a99..c8b4d8b442 100644 --- a/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx +++ b/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx @@ -151,15 +151,13 @@ export const LineTypeSegmentForm = () => { ); if (foundTemporaryLimit === undefined) { computedLimit?.temporaryLimits.push(temporaryLimit); + } else if (temporaryLimit.limitValue === null) { + foundTemporaryLimit.limitValue = temporaryLimit.limitValue; } else { - if (temporaryLimit.limitValue === null) { - foundTemporaryLimit.limitValue = temporaryLimit.limitValue; - } else { - foundTemporaryLimit.limitValue = Math.min( - foundTemporaryLimit.limitValue, - temporaryLimit.limitValue - ); - } + foundTemporaryLimit.limitValue = Math.min( + foundTemporaryLimit.limitValue, + temporaryLimit.limitValue + ); } }); computedLimit.permanentLimit = Math.min(computedLimit.permanentLimit, limit.permanentLimit); From 358ba67a2c60da096935bda6b9882cb6c548166a Mon Sep 17 00:00:00 2001 From: Etienne LESOT Date: Mon, 16 Feb 2026 16:55:15 +0100 Subject: [PATCH 06/15] fix underground lines Signed-off-by: Etienne LESOT --- .../line-types-catalog/line-catalog.type.ts | 3 +- .../line-type-segment-form.tsx | 7 ++-- .../line-types-catalog-selector-dialog.tsx | 39 ++++--------------- src/services/network-modification.ts | 22 +++++++++-- 4 files changed, 32 insertions(+), 39 deletions(-) diff --git a/src/components/dialogs/line-types-catalog/line-catalog.type.ts b/src/components/dialogs/line-types-catalog/line-catalog.type.ts index aa7ddae40a..1eac2c5cba 100644 --- a/src/components/dialogs/line-types-catalog/line-catalog.type.ts +++ b/src/components/dialogs/line-types-catalog/line-catalog.type.ts @@ -45,9 +45,10 @@ export type CurrentLimitsInfo = { temperature: string; }; -export type AreaAndTemperatureInfo = { +export type AreaTemperatureShapeFactorInfo = { area: string | null; temperature: string | null; + shapeFactor: number | null; }; export type TemporaryLimitsInfo = { diff --git a/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx b/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx index c8b4d8b442..39114853b2 100644 --- a/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx +++ b/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx @@ -38,7 +38,7 @@ import { } from '@gridsuite/commons-ui'; import { getLineTypesCatalog, getLineTypeWithLimits } from '../../../services/network-modification'; import GridItem from '../commons/grid-item'; -import { CurrentLimitsInfo, LineTypeInfo } from './line-catalog.type'; +import { AreaTemperatureShapeFactorInfo, CurrentLimitsInfo, LineTypeInfo } from './line-catalog.type'; import { emptyLineSegment, SegmentFormData } from './segment-utils'; import { ColDef } from 'ag-grid-community'; import GridSection from '../commons/grid-section'; @@ -175,12 +175,13 @@ export const LineTypeSegmentForm = () => { const onSelectCatalogLine = useCallback( ( selectedLine: LineTypeInfo, - selectedAreaAndTemperature2LineTypeData: { area: string | null; temperature: string | null } + selectedAreaAndTemperature2LineTypeData: AreaTemperatureShapeFactorInfo ) => { getLineTypeWithLimits( selectedLine.id, selectedAreaAndTemperature2LineTypeData?.area, - selectedAreaAndTemperature2LineTypeData?.temperature + selectedAreaAndTemperature2LineTypeData?.temperature, + selectedAreaAndTemperature2LineTypeData?.shapeFactor ) .then((lineTypeWithLimits) => { if (lineTypeWithLimits && openCatalogDialogIndex !== null) { diff --git a/src/components/dialogs/line-types-catalog/line-types-catalog-selector-dialog.tsx b/src/components/dialogs/line-types-catalog/line-types-catalog-selector-dialog.tsx index 7c5c35c8b4..723511d17d 100644 --- a/src/components/dialogs/line-types-catalog/line-types-catalog-selector-dialog.tsx +++ b/src/components/dialogs/line-types-catalog/line-types-catalog-selector-dialog.tsx @@ -8,7 +8,7 @@ import { useCallback, useRef, useState } from 'react'; import { CustomFormProvider, DeepNullable, Option, snackWithFallback, useSnackMessage } from '@gridsuite/commons-ui'; import { AgGridReact } from 'ag-grid-react'; -import { CATEGORIES_TABS, CurrentLimitsInfo, LineTypeInfo, AreaAndTemperatureInfo } from './line-catalog.type'; +import { CATEGORIES_TABS, CurrentLimitsInfo, LineTypeInfo, AreaTemperatureShapeFactorInfo } from './line-catalog.type'; import { AERIAL_AREAS, AERIAL_TEMPERATURES, @@ -82,7 +82,7 @@ const emptyFormData = { export type LineTypesCatalogSelectorDialogSchemaForm = yup.InferType; export type LineTypesCatalogSelectorDialogProps = { - onSelectLine: (selectedLine: LineTypeInfo, selectedAreaAndTemperature: AreaAndTemperatureInfo) => void; + onSelectLine: (selectedLine: LineTypeInfo, selectedAreaAndTemperature: AreaTemperatureShapeFactorInfo) => void; preselectedRowId: string; rowData: LineTypeInfo[]; onClose: () => void; @@ -109,52 +109,27 @@ export default function LineTypesCatalogSelectorDialog({ const { setValue, getValues } = formMethods; const handleSelectedAerial = useCallback( - (selectedAerialRow: LineTypeInfo): AreaAndTemperatureInfo => { + (selectedAerialRow: LineTypeInfo): AreaTemperatureShapeFactorInfo => { const selectedArea = getValues(AERIAL_AREAS); const selectedTemperature = getValues(AERIAL_TEMPERATURES); - - if (areasOptions?.length > 0 && aerialTemperatures?.length > 0) { - const filteredLimits = selectedAerialRow?.limitsForLineType?.filter( - (limit) => limit?.area === selectedArea?.id && limit?.temperature === selectedTemperature?.id - ); - selectedAerialRow.limitsForLineType = filteredLimits ? filteredLimits : []; - } - return { area: selectedArea?.id, temperature: selectedTemperature?.id } as AreaAndTemperatureInfo; + return { area: selectedArea?.id, temperature: selectedTemperature?.id } as AreaTemperatureShapeFactorInfo; }, [getValues, areasOptions?.length, aerialTemperatures?.length] ); const handleSelectedUnderground = useCallback( - (selectedUndergroundRow: LineTypeInfo): AreaAndTemperatureInfo => { + (selectedUndergroundRow: LineTypeInfo): AreaTemperatureShapeFactorInfo => { const selectedArea = getValues(UNDERGROUND_AREAS); const selectedShapeFactor = getValues(UNDERGROUND_SHAPE_FACTORS); const areaId = selectedArea?.id; const shapeFactorId = selectedShapeFactor?.id; - - if (areasOptions.length > 0 && areaId && shapeFactorId) { - const filteredLimits = selectedUndergroundRow?.limitsForLineType?.filter( - (limit) => limit?.area === areaId - ); - - if (filteredLimits) { - const shapeFactorValue = parseFloat(shapeFactorId); - if (!isNaN(shapeFactorValue) && shapeFactorValue !== 0) { - filteredLimits.forEach((limit) => { - limit.permanentLimit = Math.floor(limit.permanentLimit / shapeFactorValue); - }); - selectedUndergroundRow.limitsForLineType = filteredLimits; - } - } else { - selectedUndergroundRow.limitsForLineType = []; - } - } - return { area: selectedArea?.id, temperature: null } as AreaAndTemperatureInfo; + return { area: areaId, shapeFactor: shapeFactorId } as AreaTemperatureShapeFactorInfo; }, [getValues, areasOptions] ); const onSubmit = useCallback(() => { - let selectedAreaAndTemperature: AreaAndTemperatureInfo = { area: null, temperature: null }; + let selectedAreaAndTemperature: AreaTemperatureShapeFactorInfo = { area: null, temperature: null }; if (selectedRow?.category === CATEGORIES_TABS.AERIAL.name) { selectedAreaAndTemperature = handleSelectedAerial(selectedRow); } else if (selectedRow?.category === CATEGORIES_TABS.UNDERGROUND.name) { diff --git a/src/services/network-modification.ts b/src/services/network-modification.ts index 24306e151c..ab2504c75d 100644 --- a/src/services/network-modification.ts +++ b/src/services/network-modification.ts @@ -24,8 +24,24 @@ export function getLineTypeWithAreaAndTemperature(id: string): Promise { - const url = `${PREFIX_NETWORK_MODIFICATION_QUERIES}/v1/network-modifications/catalog/line_types/${id}/area/${area}/temperature/${temperature}`; - return backendFetchJson(url); + let urlSearchParams = new URLSearchParams(); + if (area !== null && area !== undefined) { + urlSearchParams.append('area', area); + } + if (temperature !== null && temperature !== undefined) { + urlSearchParams.append('temperature', temperature); + } + if (shapeFactor !== null && shapeFactor !== undefined) { + urlSearchParams.append('shapeFactor', shapeFactor.toString()); + } + const url = `${PREFIX_NETWORK_MODIFICATION_QUERIES}/v1/network-modifications/catalog/line_types/${id}/withLimits?` + urlSearchParams.toString(); + return backendFetchJson(url, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + }); } From e067c5a58391281bbdf5edd898a706c0861c9764 Mon Sep 17 00:00:00 2001 From: Etienne LESOT Date: Tue, 17 Feb 2026 10:58:00 +0100 Subject: [PATCH 07/15] fix Signed-off-by: Etienne LESOT --- .../line-type-segment-form.tsx | 5 +-- .../line-types-catalog-selector-dialog.tsx | 40 ++++++++----------- src/services/network-modification.ts | 4 +- 3 files changed, 21 insertions(+), 28 deletions(-) diff --git a/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx b/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx index 39114853b2..57278c65de 100644 --- a/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx +++ b/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx @@ -173,10 +173,7 @@ export const LineTypeSegmentForm = () => { }, [getValues, setValue, setCurrentLimitResult]); const onSelectCatalogLine = useCallback( - ( - selectedLine: LineTypeInfo, - selectedAreaAndTemperature2LineTypeData: AreaTemperatureShapeFactorInfo - ) => { + (selectedLine: LineTypeInfo, selectedAreaAndTemperature2LineTypeData: AreaTemperatureShapeFactorInfo) => { getLineTypeWithLimits( selectedLine.id, selectedAreaAndTemperature2LineTypeData?.area, diff --git a/src/components/dialogs/line-types-catalog/line-types-catalog-selector-dialog.tsx b/src/components/dialogs/line-types-catalog/line-types-catalog-selector-dialog.tsx index 723511d17d..7d4922ef7b 100644 --- a/src/components/dialogs/line-types-catalog/line-types-catalog-selector-dialog.tsx +++ b/src/components/dialogs/line-types-catalog/line-types-catalog-selector-dialog.tsx @@ -8,7 +8,7 @@ import { useCallback, useRef, useState } from 'react'; import { CustomFormProvider, DeepNullable, Option, snackWithFallback, useSnackMessage } from '@gridsuite/commons-ui'; import { AgGridReact } from 'ag-grid-react'; -import { CATEGORIES_TABS, CurrentLimitsInfo, LineTypeInfo, AreaTemperatureShapeFactorInfo } from './line-catalog.type'; +import { AreaTemperatureShapeFactorInfo, CATEGORIES_TABS, CurrentLimitsInfo, LineTypeInfo } from './line-catalog.type'; import { AERIAL_AREAS, AERIAL_TEMPERATURES, @@ -108,35 +108,29 @@ export default function LineTypesCatalogSelectorDialog({ }); const { setValue, getValues } = formMethods; - const handleSelectedAerial = useCallback( - (selectedAerialRow: LineTypeInfo): AreaTemperatureShapeFactorInfo => { - const selectedArea = getValues(AERIAL_AREAS); - const selectedTemperature = getValues(AERIAL_TEMPERATURES); - return { area: selectedArea?.id, temperature: selectedTemperature?.id } as AreaTemperatureShapeFactorInfo; - }, - [getValues, areasOptions?.length, aerialTemperatures?.length] - ); + const handleSelectedAerial = useCallback((): AreaTemperatureShapeFactorInfo => { + const selectedArea = getValues(AERIAL_AREAS); + const selectedTemperature = getValues(AERIAL_TEMPERATURES); + return { area: selectedArea?.id, temperature: selectedTemperature?.id } as AreaTemperatureShapeFactorInfo; + }, [getValues]); - const handleSelectedUnderground = useCallback( - (selectedUndergroundRow: LineTypeInfo): AreaTemperatureShapeFactorInfo => { - const selectedArea = getValues(UNDERGROUND_AREAS); - const selectedShapeFactor = getValues(UNDERGROUND_SHAPE_FACTORS); - const areaId = selectedArea?.id; - const shapeFactorId = selectedShapeFactor?.id; - return { area: areaId, shapeFactor: shapeFactorId } as AreaTemperatureShapeFactorInfo; - }, - [getValues, areasOptions] - ); + const handleSelectedUnderground = useCallback((): AreaTemperatureShapeFactorInfo => { + const selectedArea = getValues(UNDERGROUND_AREAS); + const selectedShapeFactor = getValues(UNDERGROUND_SHAPE_FACTORS); + const areaId = selectedArea?.id; + const shapeFactorId = selectedShapeFactor?.id; + return { area: areaId, shapeFactor: shapeFactorId } as AreaTemperatureShapeFactorInfo; + }, [getValues]); const onSubmit = useCallback(() => { - let selectedAreaAndTemperature: AreaTemperatureShapeFactorInfo = { area: null, temperature: null }; + let selectedAreaAndTemperature = { area: null, temperature: null } as AreaTemperatureShapeFactorInfo; if (selectedRow?.category === CATEGORIES_TABS.AERIAL.name) { - selectedAreaAndTemperature = handleSelectedAerial(selectedRow); + selectedAreaAndTemperature = handleSelectedAerial(); } else if (selectedRow?.category === CATEGORIES_TABS.UNDERGROUND.name) { - selectedAreaAndTemperature = handleSelectedUnderground(selectedRow); + selectedAreaAndTemperature = handleSelectedUnderground(); } selectedRow && onSelectLine?.(selectedRow, selectedAreaAndTemperature); - }, [selectedRow, handleSelectedAerial, handleSelectedUnderground, onSelectLine]); + }, [selectedRow, onSelectLine]); const createOptionsFromAreas = (limitsData?: CurrentLimitsInfo[]) => { if (!limitsData?.length) { diff --git a/src/services/network-modification.ts b/src/services/network-modification.ts index ab2504c75d..8ac71d738a 100644 --- a/src/services/network-modification.ts +++ b/src/services/network-modification.ts @@ -37,7 +37,9 @@ export function getLineTypeWithLimits( if (shapeFactor !== null && shapeFactor !== undefined) { urlSearchParams.append('shapeFactor', shapeFactor.toString()); } - const url = `${PREFIX_NETWORK_MODIFICATION_QUERIES}/v1/network-modifications/catalog/line_types/${id}/withLimits?` + urlSearchParams.toString(); + const url = + `${PREFIX_NETWORK_MODIFICATION_QUERIES}/v1/network-modifications/catalog/line_types/${id}/withLimits?` + + urlSearchParams.toString(); return backendFetchJson(url, { method: 'GET', headers: { From 9af52e1cdfbe51d1f43f1bbbe6c025900f8e93a2 Mon Sep 17 00:00:00 2001 From: Etienne LESOT Date: Tue, 17 Feb 2026 11:02:22 +0100 Subject: [PATCH 08/15] fix Signed-off-by: Etienne LESOT --- .../line-types-catalog-selector-dialog.tsx | 2 +- tsconfig.json | 9 ++++- vite.config.ts | 33 +++++-------------- 3 files changed, 17 insertions(+), 27 deletions(-) diff --git a/src/components/dialogs/line-types-catalog/line-types-catalog-selector-dialog.tsx b/src/components/dialogs/line-types-catalog/line-types-catalog-selector-dialog.tsx index 7d4922ef7b..2576c71d25 100644 --- a/src/components/dialogs/line-types-catalog/line-types-catalog-selector-dialog.tsx +++ b/src/components/dialogs/line-types-catalog/line-types-catalog-selector-dialog.tsx @@ -130,7 +130,7 @@ export default function LineTypesCatalogSelectorDialog({ selectedAreaAndTemperature = handleSelectedUnderground(); } selectedRow && onSelectLine?.(selectedRow, selectedAreaAndTemperature); - }, [selectedRow, onSelectLine]); + }, [selectedRow, handleSelectedUnderground, handleSelectedAerial, onSelectLine]); const createOptionsFromAreas = (limitsData?: CurrentLimitsInfo[]) => { if (!limitsData?.length) { diff --git a/tsconfig.json b/tsconfig.json index 8acf660004..9c3ffce3ff 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,7 +15,14 @@ "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, - "jsx": "react-jsx" + "jsx": "react-jsx", + "compilerOptions": { + "baseUrl": "src", + "paths": { + "@gridsuite/commons-ui": ["../../commons-ui/src"], + "@gridsuite/commons-ui/*": ["../../commons-ui/src/*"] + } + } }, "include": [ "src", diff --git a/vite.config.ts b/vite.config.ts index a5a2fce97b..814a2e5faf 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -7,9 +7,9 @@ import react from '@vitejs/plugin-react'; import { CommonServerOptions, defineConfig } from 'vite'; -import checker from 'vite-plugin-checker'; import svgr from 'vite-plugin-svgr'; import tsconfigPaths from 'vite-tsconfig-paths'; +import path from 'node:path'; const serverSettings: CommonServerOptions = { port: 3004, @@ -29,30 +29,6 @@ const serverSettings: CommonServerOptions = { export default defineConfig((_config) => ({ plugins: [ react(), - checker({ - // TypeScript checking - typescript: true, - - // ESLint checking - eslint: { - useFlatConfig: true, - lintCommand: 'eslint . --max-warnings 0', - dev: { - logLevel: ['error', 'warning'], - }, - watchPath: './src', - }, - - overlay: false, // Disable overlay in browser - - // Show errors in terminal - terminal: true, - - // Disable during build because vite-plugin-checker runs checks in a parallel worker, - // which doesn't block the build if linting or type checking fails. To ensure build - // failure on errors, we use the 'prebuild' script instead (runs before 'npm run build'). - enableBuild: false, - }), svgr(), // works on every import with the pattern "**/*.svg?react" tsconfigPaths(), // to resolve absolute path via tsconfig cf https://stackoverflow.com/a/68250175/5092999 ], @@ -62,4 +38,11 @@ export default defineConfig((_config) => ({ build: { outDir: 'build', }, + resolve: { + alias: { + '@gridsuite/commons-ui': path.resolve(__dirname, '../commons-ui/src'), + }, + // If the overrides from npm does not work, you can also tell to vite that you want only one React + dedupe: ['react', 'react-dom'], + }, })); From 6c36ed3214254a6c9e3e180763f0d25e18304441 Mon Sep 17 00:00:00 2001 From: Etienne LESOT Date: Tue, 17 Feb 2026 11:08:37 +0100 Subject: [PATCH 09/15] fix Signed-off-by: Etienne LESOT --- tsconfig.json | 9 +-------- vite.config.ts | 33 +++++++++++++++++++++++++-------- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/tsconfig.json b/tsconfig.json index 9c3ffce3ff..8acf660004 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,14 +15,7 @@ "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, - "jsx": "react-jsx", - "compilerOptions": { - "baseUrl": "src", - "paths": { - "@gridsuite/commons-ui": ["../../commons-ui/src"], - "@gridsuite/commons-ui/*": ["../../commons-ui/src/*"] - } - } + "jsx": "react-jsx" }, "include": [ "src", diff --git a/vite.config.ts b/vite.config.ts index 814a2e5faf..a5a2fce97b 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -7,9 +7,9 @@ import react from '@vitejs/plugin-react'; import { CommonServerOptions, defineConfig } from 'vite'; +import checker from 'vite-plugin-checker'; import svgr from 'vite-plugin-svgr'; import tsconfigPaths from 'vite-tsconfig-paths'; -import path from 'node:path'; const serverSettings: CommonServerOptions = { port: 3004, @@ -29,6 +29,30 @@ const serverSettings: CommonServerOptions = { export default defineConfig((_config) => ({ plugins: [ react(), + checker({ + // TypeScript checking + typescript: true, + + // ESLint checking + eslint: { + useFlatConfig: true, + lintCommand: 'eslint . --max-warnings 0', + dev: { + logLevel: ['error', 'warning'], + }, + watchPath: './src', + }, + + overlay: false, // Disable overlay in browser + + // Show errors in terminal + terminal: true, + + // Disable during build because vite-plugin-checker runs checks in a parallel worker, + // which doesn't block the build if linting or type checking fails. To ensure build + // failure on errors, we use the 'prebuild' script instead (runs before 'npm run build'). + enableBuild: false, + }), svgr(), // works on every import with the pattern "**/*.svg?react" tsconfigPaths(), // to resolve absolute path via tsconfig cf https://stackoverflow.com/a/68250175/5092999 ], @@ -38,11 +62,4 @@ export default defineConfig((_config) => ({ build: { outDir: 'build', }, - resolve: { - alias: { - '@gridsuite/commons-ui': path.resolve(__dirname, '../commons-ui/src'), - }, - // If the overrides from npm does not work, you can also tell to vite that you want only one React - dedupe: ['react', 'react-dom'], - }, })); From 76ad76b3d7d8f36cc534aea27ab77ee998da3f77 Mon Sep 17 00:00:00 2001 From: Etienne LESOT Date: Wed, 18 Feb 2026 14:25:44 +0100 Subject: [PATCH 10/15] remove console.log Signed-off-by: Etienne LESOT --- .../line/creation/line-creation-dialog.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/dialogs/network-modifications/line/creation/line-creation-dialog.tsx b/src/components/dialogs/network-modifications/line/creation/line-creation-dialog.tsx index 76b269b668..5899dc71b1 100644 --- a/src/components/dialogs/network-modifications/line/creation/line-creation-dialog.tsx +++ b/src/components/dialogs/network-modifications/line/creation/line-creation-dialog.tsx @@ -303,8 +303,6 @@ const LineCreationDialog = ({ }, }); }); - console.log('test'); - console.log(finalLimits); setValue(`${LIMITS}.${OPERATIONAL_LIMITS_GROUPS}`, finalLimits); }; From f4f28b4953fbd17ce60a5bb4f5900f644c3592dc Mon Sep 17 00:00:00 2001 From: Etienne LESOT Date: Wed, 18 Feb 2026 16:53:59 +0100 Subject: [PATCH 11/15] add temporary limits names from metadata Signed-off-by: Etienne LESOT --- .../line-type-segment-form.tsx | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx b/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx index 57278c65de..3e1b2058ba 100644 --- a/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx +++ b/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx @@ -32,6 +32,7 @@ import { CustomAGGrid, DefaultCellRenderer, ExpandableInput, + fetchStudyMetadata, type MuiStyles, snackWithFallback, useSnackMessage, @@ -65,6 +66,7 @@ export const LineTypeSegmentForm = () => { const { snackError } = useSnackMessage(); const intl = useIntl(); const [currentLimitResult, setCurrentLimitResult] = useState([]); + const [limitsColumnDefs, setLimitsColumnDefs] = useState([]); // Fetches the lineTypes catalog on startup useEffect(() => { @@ -287,7 +289,7 @@ export const LineTypeSegmentForm = () => { [] ); - const limitsColumnDefs = useMemo((): ColDef[] => { + useMemo((): void => { let base: ColDef[] = [ { headerName: intl.formatMessage({ id: 'lineTypes.currentLimits.limitSet' }), @@ -307,30 +309,31 @@ export const LineTypeSegmentForm = () => { limitNamesSet.add(temporaryLimit.name); }); }); - let i = 0; - limitNamesSet.forEach((limitName) => { - base.push({ - headerName: `${limitName}`, - field: 'temporaryLimit' + i, - cellRenderer: DefaultCellRenderer, + fetchStudyMetadata().then((studyMetadata) => { + // metadata order makes order of temporary limits columns + studyMetadata?.temporaryLimitsNamesForCatalog.forEach((limitName) => { + if (limitNamesSet.has(limitName)) { + base.push({ + headerName: `${limitName} [A]`, + field: limitName, + cellRenderer: DefaultCellRenderer, + }); + } }); - i++; + setLimitsColumnDefs(base); }); - return base; }, [intl, currentLimitResult]); const rowData = useMemo(() => { const testArray: any[] = []; currentLimitResult.forEach((currentLimit) => { - let test: any = {}; - test['limitSetName'] = currentLimit.limitSetName; - test['permanentLimit'] = currentLimit.permanentLimit; - let c = 0; - currentLimit.temporaryLimits?.forEach((temporaryLimit) => { - test['temporaryLimit' + c] = temporaryLimit.limitValue; - c++; - }); - testArray.push(test); + let limitData: any = {}; + limitData['limitSetName'] = currentLimit.limitSetName; + limitData['permanentLimit'] = currentLimit.permanentLimit; + currentLimit.temporaryLimits.forEach((temporaryLimit) => { + limitData[temporaryLimit.name] = temporaryLimit.limitValue; + }); + testArray.push(limitData); }); return testArray; }, [currentLimitResult]); From 497b940e41e4143555e01a943e9a058379ddc8b0 Mon Sep 17 00:00:00 2001 From: Etienne LESOT Date: Thu, 19 Feb 2026 08:32:48 +0100 Subject: [PATCH 12/15] fix Signed-off-by: Etienne LESOT --- .../dialogs/line-types-catalog/line-type-segment-form.tsx | 6 +++--- src/services/network-modification.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx b/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx index 3e1b2058ba..01a59b4163 100644 --- a/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx +++ b/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx @@ -289,7 +289,7 @@ export const LineTypeSegmentForm = () => { [] ); - useMemo((): void => { + useMemo((): void => { let base: ColDef[] = [ { headerName: intl.formatMessage({ id: 'lineTypes.currentLimits.limitSet' }), @@ -331,8 +331,8 @@ export const LineTypeSegmentForm = () => { limitData['limitSetName'] = currentLimit.limitSetName; limitData['permanentLimit'] = currentLimit.permanentLimit; currentLimit.temporaryLimits.forEach((temporaryLimit) => { - limitData[temporaryLimit.name] = temporaryLimit.limitValue; - }); + limitData[temporaryLimit.name] = temporaryLimit.limitValue; + }); testArray.push(limitData); }); return testArray; diff --git a/src/services/network-modification.ts b/src/services/network-modification.ts index 8ac71d738a..ecca551d31 100644 --- a/src/services/network-modification.ts +++ b/src/services/network-modification.ts @@ -38,7 +38,7 @@ export function getLineTypeWithLimits( urlSearchParams.append('shapeFactor', shapeFactor.toString()); } const url = - `${PREFIX_NETWORK_MODIFICATION_QUERIES}/v1/network-modifications/catalog/line_types/${id}/withLimits?` + + `${PREFIX_NETWORK_MODIFICATION_QUERIES}/v1/network-modifications/catalog/line_types/${id}/with-limits?` + urlSearchParams.toString(); return backendFetchJson(url, { method: 'GET', From 499326c5338a95bb5a0a0b1c767956f61fb6197c Mon Sep 17 00:00:00 2001 From: Etienne LESOT Date: Fri, 20 Feb 2026 13:05:06 +0100 Subject: [PATCH 13/15] review Signed-off-by: Etienne LESOT --- .../line-types-catalog/line-catalog.type.ts | 9 ++++- .../line-type-segment-form.tsx | 36 +++++++++++-------- src/services/network-modification.ts | 6 ++-- 3 files changed, 33 insertions(+), 18 deletions(-) diff --git a/src/components/dialogs/line-types-catalog/line-catalog.type.ts b/src/components/dialogs/line-types-catalog/line-catalog.type.ts index 1eac2c5cba..254cd33e82 100644 --- a/src/components/dialogs/line-types-catalog/line-catalog.type.ts +++ b/src/components/dialogs/line-types-catalog/line-catalog.type.ts @@ -37,14 +37,21 @@ export type ComputedLineCharacteristics = { finalCurrentLimits: CurrentLimitsInfo[]; }; -export type CurrentLimitsInfo = { +export type CurrentLimitHeader = { limitSetName: string; permanentLimit: number; +} + +export type CurrentLimitsInfo = CurrentLimitHeader & { temporaryLimits: TemporaryLimitsInfo[]; area: string; temperature: string; }; +export type LimitSelectedRowData = CurrentLimitHeader & TemporaryLimitSelectedRowData; + +export type TemporaryLimitSelectedRowData = Record + export type AreaTemperatureShapeFactorInfo = { area: string | null; temperature: string | null; diff --git a/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx b/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx index 01a59b4163..caf79bfba9 100644 --- a/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx +++ b/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx @@ -39,7 +39,12 @@ import { } from '@gridsuite/commons-ui'; import { getLineTypesCatalog, getLineTypeWithLimits } from '../../../services/network-modification'; import GridItem from '../commons/grid-item'; -import { AreaTemperatureShapeFactorInfo, CurrentLimitsInfo, LineTypeInfo } from './line-catalog.type'; +import { + AreaTemperatureShapeFactorInfo, + CurrentLimitsInfo, + LimitSelectedRowData, + LineTypeInfo, +} from './line-catalog.type'; import { emptyLineSegment, SegmentFormData } from './segment-utils'; import { ColDef } from 'ag-grid-community'; import GridSection from '../commons/grid-section'; @@ -311,25 +316,28 @@ export const LineTypeSegmentForm = () => { }); fetchStudyMetadata().then((studyMetadata) => { // metadata order makes order of temporary limits columns - studyMetadata?.temporaryLimitsNamesForCatalog.forEach((limitName) => { - if (limitNamesSet.has(limitName)) { - base.push({ - headerName: `${limitName} [A]`, - field: limitName, - cellRenderer: DefaultCellRenderer, - }); - } - }); + if (studyMetadata?.temporaryLimitsNamesForCatalog) { + studyMetadata?.temporaryLimitsNamesForCatalog.forEach((limitName) => { + if (limitNamesSet.has(limitName)) { + base.push({ + headerName: `${limitName} [A]`, + field: limitName, + cellRenderer: DefaultCellRenderer, + }); + } + }); + } setLimitsColumnDefs(base); }); }, [intl, currentLimitResult]); const rowData = useMemo(() => { - const testArray: any[] = []; + const testArray: LimitSelectedRowData[] = []; currentLimitResult.forEach((currentLimit) => { - let limitData: any = {}; - limitData['limitSetName'] = currentLimit.limitSetName; - limitData['permanentLimit'] = currentLimit.permanentLimit; + const limitData: LimitSelectedRowData = { + limitSetName: currentLimit.limitSetName, + permanentLimit: currentLimit.permanentLimit, + }; currentLimit.temporaryLimits.forEach((temporaryLimit) => { limitData[temporaryLimit.name] = temporaryLimit.limitValue; }); diff --git a/src/services/network-modification.ts b/src/services/network-modification.ts index ecca551d31..996b8c4c1d 100644 --- a/src/services/network-modification.ts +++ b/src/services/network-modification.ts @@ -28,13 +28,13 @@ export function getLineTypeWithLimits( shapeFactor: number | null ): Promise { let urlSearchParams = new URLSearchParams(); - if (area !== null && area !== undefined) { + if (area != null) { urlSearchParams.append('area', area); } - if (temperature !== null && temperature !== undefined) { + if (temperature != null) { urlSearchParams.append('temperature', temperature); } - if (shapeFactor !== null && shapeFactor !== undefined) { + if (shapeFactor != null) { urlSearchParams.append('shapeFactor', shapeFactor.toString()); } const url = From 1f9d6af67ec803fb57e40032eb59def661946946 Mon Sep 17 00:00:00 2001 From: Etienne LESOT Date: Wed, 25 Feb 2026 14:46:51 +0100 Subject: [PATCH 14/15] review Signed-off-by: Etienne LESOT --- src/components/dialogs/line-types-catalog/line-catalog.type.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/dialogs/line-types-catalog/line-catalog.type.ts b/src/components/dialogs/line-types-catalog/line-catalog.type.ts index 254cd33e82..80e524dcc8 100644 --- a/src/components/dialogs/line-types-catalog/line-catalog.type.ts +++ b/src/components/dialogs/line-types-catalog/line-catalog.type.ts @@ -50,7 +50,7 @@ export type CurrentLimitsInfo = CurrentLimitHeader & { export type LimitSelectedRowData = CurrentLimitHeader & TemporaryLimitSelectedRowData; -export type TemporaryLimitSelectedRowData = Record +export type TemporaryLimitSelectedRowData = Record; export type AreaTemperatureShapeFactorInfo = { area: string | null; From 1cf8f60d249b0b5e0edd945772ac807d314d0f8c Mon Sep 17 00:00:00 2001 From: Etienne LESOT Date: Thu, 26 Feb 2026 08:43:52 +0100 Subject: [PATCH 15/15] fix headers Signed-off-by: Etienne LESOT --- .../line-types-catalog/line-catalog.type.ts | 2 +- .../line-type-segment-form.tsx | 55 +++++++++++++------ 2 files changed, 40 insertions(+), 17 deletions(-) diff --git a/src/components/dialogs/line-types-catalog/line-catalog.type.ts b/src/components/dialogs/line-types-catalog/line-catalog.type.ts index 80e524dcc8..632e083539 100644 --- a/src/components/dialogs/line-types-catalog/line-catalog.type.ts +++ b/src/components/dialogs/line-types-catalog/line-catalog.type.ts @@ -40,7 +40,7 @@ export type ComputedLineCharacteristics = { export type CurrentLimitHeader = { limitSetName: string; permanentLimit: number; -} +}; export type CurrentLimitsInfo = CurrentLimitHeader & { temporaryLimits: TemporaryLimitsInfo[]; diff --git a/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx b/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx index caf79bfba9..160c2e528f 100644 --- a/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx +++ b/src/components/dialogs/line-types-catalog/line-type-segment-form.tsx @@ -315,24 +315,47 @@ export const LineTypeSegmentForm = () => { }); }); fetchStudyMetadata().then((studyMetadata) => { - // metadata order makes order of temporary limits columns - if (studyMetadata?.temporaryLimitsNamesForCatalog) { - studyMetadata?.temporaryLimitsNamesForCatalog.forEach((limitName) => { - if (limitNamesSet.has(limitName)) { - base.push({ - headerName: `${limitName} [A]`, - field: limitName, - cellRenderer: DefaultCellRenderer, - }); - } - }); - } - setLimitsColumnDefs(base); + manageHeader(base, limitNamesSet, studyMetadata?.temporaryLimitsNamesForCatalog); }); }, [intl, currentLimitResult]); + const manageHeader = (base: ColDef[], limitNamesSet: Set, temporaryLimitsNamesForCatalog?: string[]) => { + // metadata order makes order of temporary limits columns + if (temporaryLimitsNamesForCatalog) { + temporaryLimitsNamesForCatalog.forEach((limitName) => { + if (limitNamesSet.has(limitName)) { + base.push({ + headerName: `${limitName} [A]`, + field: limitName, + cellRenderer: DefaultCellRenderer, + }); + } + }); + // limits that are in catalog and not in metadata are added at the end + limitNamesSet.forEach((limitName) => { + if (!temporaryLimitsNamesForCatalog.includes(limitName)) { + base.push({ + headerName: `${limitName} [A]`, + field: limitName, + cellRenderer: DefaultCellRenderer, + }); + } + }); + } else { + // no metadata, all limits are added (no order) + limitNamesSet.forEach((limitName) => { + base.push({ + headerName: `${limitName} [A]`, + field: limitName, + cellRenderer: DefaultCellRenderer, + }); + }); + } + setLimitsColumnDefs(base); + }; + const rowData = useMemo(() => { - const testArray: LimitSelectedRowData[] = []; + const finalDataArray: LimitSelectedRowData[] = []; currentLimitResult.forEach((currentLimit) => { const limitData: LimitSelectedRowData = { limitSetName: currentLimit.limitSetName, @@ -341,9 +364,9 @@ export const LineTypeSegmentForm = () => { currentLimit.temporaryLimits.forEach((temporaryLimit) => { limitData[temporaryLimit.name] = temporaryLimit.limitValue; }); - testArray.push(limitData); + finalDataArray.push(limitData); }); - return testArray; + return finalDataArray; }, [currentLimitResult]); return (