Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
be347f8
add several limits with line catalog
EtienneLt Feb 16, 2026
38311a5
fix type-check
EtienneLt Feb 16, 2026
f4d9f65
Merge branch 'main' into add-limits-in-lines-catalog
EtienneLt Feb 16, 2026
2c96d97
try to fix
EtienneLt Feb 16, 2026
33a6dd6
try to fix 2
EtienneLt Feb 16, 2026
2d57035
try to fix 3
EtienneLt Feb 16, 2026
358ba67
fix underground lines
EtienneLt Feb 16, 2026
e067c5a
fix
EtienneLt Feb 17, 2026
9af52e1
fix
EtienneLt Feb 17, 2026
2459f31
Merge branch 'main' into add-limits-in-lines-catalog
EtienneLt Feb 17, 2026
6c36ed3
fix
EtienneLt Feb 17, 2026
06e5681
Merge branch 'main' into add-limits-in-lines-catalog
souissimai Feb 17, 2026
c26cceb
Merge branch 'main' into add-limits-in-lines-catalog
EtienneLt Feb 18, 2026
76ad76b
remove console.log
EtienneLt Feb 18, 2026
f4f28b4
add temporary limits names from metadata
EtienneLt Feb 18, 2026
497b940
fix
EtienneLt Feb 19, 2026
5b98c35
Merge branch 'main' into add-limits-in-lines-catalog
souissimai Feb 19, 2026
e37f083
Merge branch 'main' into add-limits-in-lines-catalog
Mathieu-Deharbe Feb 19, 2026
df75d1d
Merge branch 'main' into add-limits-in-lines-catalog
EtienneLt Feb 20, 2026
563cb20
Merge branch 'main' into add-limits-in-lines-catalog
EtienneLt Feb 20, 2026
499326c
review
EtienneLt Feb 20, 2026
d4b7cfc
Merge branch 'main' into add-limits-in-lines-catalog
Mathieu-Deharbe Feb 24, 2026
1f9d6af
review
EtienneLt Feb 25, 2026
1cf8f60
fix headers
EtienneLt Feb 26, 2026
e7b4d66
Merge branch 'main' into add-limits-in-lines-catalog
Mathieu-Deharbe Feb 26, 2026
efda1b2
Merge branch 'main' into add-limits-in-lines-catalog
Mathieu-Deharbe Feb 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 21 additions & 4 deletions src/components/dialogs/line-types-catalog/line-catalog.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,33 @@ export type ComputedLineCharacteristics = {
finalCurrentLimits: CurrentLimitsInfo[];
};

export type CurrentLimitsInfo = {
export type CurrentLimitHeader = {
limitSetName: string;
permanentLimit: number;
temporaryLimitValue: number;
temporaryLimitAcceptableDuration: number;
temporaryLimitName: string;
};

export type CurrentLimitsInfo = CurrentLimitHeader & {
temporaryLimits: TemporaryLimitsInfo[];
area: string;
temperature: string;
};

export type LimitSelectedRowData = CurrentLimitHeader & TemporaryLimitSelectedRowData;

export type TemporaryLimitSelectedRowData = Record<string, number | string>;

export type AreaTemperatureShapeFactorInfo = {
area: string | null;
temperature: string | null;
shapeFactor: number | null;
};

export type TemporaryLimitsInfo = {
limitValue: number;
acceptableDuration: number;
name: string;
};

export const CATEGORIES_TABS = {
AERIAL: { id: 0, name: 'AERIAL' },
UNDERGROUND: { id: 1, name: 'UNDERGROUND' },
Expand Down
171 changes: 121 additions & 50 deletions src/components/dialogs/line-types-catalog/line-type-segment-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,19 @@
CustomAGGrid,
DefaultCellRenderer,
ExpandableInput,
fetchStudyMetadata,
type MuiStyles,
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 {
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';
Expand All @@ -65,6 +71,7 @@
const { snackError } = useSnackMessage();
const intl = useIntl();
const [currentLimitResult, setCurrentLimitResult] = useState<CurrentLimitsInfo[]>([]);
const [limitsColumnDefs, setLimitsColumnDefs] = useState<ColDef[]>([]);

// Fetches the lineTypes catalog on startup
useEffect(() => {
Expand Down Expand Up @@ -104,12 +111,10 @@
);

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(() => {
Expand Down Expand Up @@ -141,54 +146,65 @@

const keepMostConstrainingLimits = useCallback(() => {
const segments: SegmentFormData[] = getValues(SEGMENTS);
const computedLimits = new Map<string, CurrentLimitsInfo>();
const mostContrainingLimits = new Map<string, CurrentLimitsInfo>();
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;
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) {
computedLimit?.temporaryLimits.push(temporaryLimit);
} else if (temporaryLimit.limitValue === null) {
foundTemporaryLimit.limitValue = temporaryLimit.limitValue;
} else {
let temporaryLimitValue = Math.min(
computedLimit.temporaryLimitValue,
limit.temporaryLimitValue
foundTemporaryLimit.limitValue = Math.min(
foundTemporaryLimit.limitValue,
temporaryLimit.limitValue
);
if (temporaryLimitValue === limit.temporaryLimitValue) {
computedLimit.temporaryLimitValue = limit.temporaryLimitValue;
computedLimit.temporaryLimitAcceptableDuration =
limit.temporaryLimitAcceptableDuration;
computedLimit.temporaryLimitName = limit.temporaryLimitName;
}
}
}
});
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, structuredClone(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: AreaTemperatureShapeFactorInfo) => {
getLineTypeWithLimits(
selectedLine.id,
selectedAreaAndTemperature2LineTypeData?.area,
selectedAreaAndTemperature2LineTypeData?.temperature,
selectedAreaAndTemperature2LineTypeData?.shapeFactor
)
.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,
Expand All @@ -198,6 +214,7 @@
openCatalogDialogIndex,
updateSegmentLimitsValues,
keepMostConstrainingLimits,
snackError,
]
);

Expand Down Expand Up @@ -277,8 +294,8 @@
[]
);

const limitsColumnDefs = useMemo((): ColDef[] => {
return [
useMemo((): void => {
let base: ColDef[] = [
{
headerName: intl.formatMessage({ id: 'lineTypes.currentLimits.limitSet' }),
field: 'limitSetName',
Expand All @@ -290,13 +307,67 @@
field: 'permanentLimit',
cellRenderer: DefaultCellRenderer,
},
{
headerName: intl.formatMessage({ id: 'lineTypes.currentLimits.Temporary' }),
field: 'temporaryLimitValue',
cellRenderer: DefaultCellRenderer,
},
];
}, [intl]);
let limitNamesSet = new Set<string>();
currentLimitResult.forEach((limit) => {
limit.temporaryLimits?.forEach((temporaryLimit) => {
limitNamesSet.add(temporaryLimit.name);
});
});
fetchStudyMetadata().then((studyMetadata) => {
manageHeader(base, limitNamesSet, studyMetadata?.temporaryLimitsNamesForCatalog);

Check failure on line 318 in src/components/dialogs/line-types-catalog/line-type-segment-form.tsx

View workflow job for this annotation

GitHub Actions / build / build

Property 'temporaryLimitsNamesForCatalog' does not exist on type 'StudyMetadata'.
});
}, [intl, currentLimitResult]);

const manageHeader = (base: ColDef[], limitNamesSet: Set<string>, 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 finalDataArray: LimitSelectedRowData[] = [];
currentLimitResult.forEach((currentLimit) => {
const limitData: LimitSelectedRowData = {
limitSetName: currentLimit.limitSetName,
permanentLimit: currentLimit.permanentLimit,
};
currentLimit.temporaryLimits.forEach((temporaryLimit) => {
limitData[temporaryLimit.name] = temporaryLimit.limitValue;
});
finalDataArray.push(limitData);
});
return finalDataArray;
}, [currentLimitResult]);

return (
<>
Expand Down Expand Up @@ -331,7 +402,7 @@
<GridSection title="lineTypes.currentLimits.limitSets" customStyle={styles.h3} />
<Grid container sx={{ height: '100%' }} direction="column">
<CustomAGGrid
rowData={currentLimitResult}
rowData={rowData}
defaultColDef={limitsDefaultColDef}
columnDefs={limitsColumnDefs}
domLayout="autoHeight"
Expand Down
Loading
Loading