From 69e6bda75b113cbf441500379a8ccdb226d0cb4c Mon Sep 17 00:00:00 2001 From: Thang PHAM Date: Fri, 15 May 2026 11:22:44 +0200 Subject: [PATCH] [FIX] Variation id in sensi result is not enriched with element names Signed-off-by: Thang PHAM --- .../study/sensitivity-analysis-utils.test.ts | 91 +++++++++++++++++++ .../study/sensitivity-analysis-utils.ts | 23 +++++ src/services/study/sensitivity-analysis.ts | 33 ++++++- 3 files changed, 144 insertions(+), 3 deletions(-) create mode 100644 src/services/study/sensitivity-analysis-utils.test.ts create mode 100644 src/services/study/sensitivity-analysis-utils.ts diff --git a/src/services/study/sensitivity-analysis-utils.test.ts b/src/services/study/sensitivity-analysis-utils.test.ts new file mode 100644 index 0000000000..631507bdd2 --- /dev/null +++ b/src/services/study/sensitivity-analysis-utils.test.ts @@ -0,0 +1,91 @@ +/** + * Copyright (c) 2026, 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 { extractUuidsFromVariationId, resolveForVariationId } from './sensitivity-analysis-utils'; + +describe('extractUuidsFromVarId', () => { + it('extracts a single UUID from a standard varId', () => { + const varId = '[1e34a601-fb40-4df1-8dc6-09aac5ef717e] (REGULAR)'; + expect(extractUuidsFromVariationId(varId)).toEqual(['1e34a601-fb40-4df1-8dc6-09aac5ef717e']); + }); + + it('extracts multiple comma-separated UUIDs', () => { + const varId = '[1e34a601-fb40-4df1-8dc6-09aac5ef717e, 2b45c702-ac51-4e20-9ed7-10bbd6af828f] (REGULAR)'; + expect(extractUuidsFromVariationId(varId)).toEqual([ + '1e34a601-fb40-4df1-8dc6-09aac5ef717e', + '2b45c702-ac51-4e20-9ed7-10bbd6af828f', + ]); + }); + + it('returns an empty array when no UUIDs are present', () => { + expect(extractUuidsFromVariationId('SomePlainText (REGULAR)')).toEqual([]); + }); + + it('returns an empty array for an empty string', () => { + expect(extractUuidsFromVariationId('')).toEqual([]); + }); + + it('extracts UUIDs regardless of surrounding text', () => { + const varId = 'prefix-1e34a601-fb40-4df1-8dc6-09aac5ef717e-suffix'; + expect(extractUuidsFromVariationId(varId)).toEqual(['1e34a601-fb40-4df1-8dc6-09aac5ef717e']); + }); + + it('handles three UUIDs', () => { + const varId = + '[aaaaaaaa-0000-0000-0000-000000000001, aaaaaaaa-0000-0000-0000-000000000002, aaaaaaaa-0000-0000-0000-000000000003] (CONTINGENCY)'; + expect(extractUuidsFromVariationId(varId)).toEqual([ + 'aaaaaaaa-0000-0000-0000-000000000001', + 'aaaaaaaa-0000-0000-0000-000000000002', + 'aaaaaaaa-0000-0000-0000-000000000003', + ]); + }); +}); + +describe('resolveVarId', () => { + it('replaces a single UUID with its name', () => { + const varId = '[1e34a601-fb40-4df1-8dc6-09aac5ef717e] (REGULAR)'; + const map = new Map([['1e34a601-fb40-4df1-8dc6-09aac5ef717e', 'FilterA']]); + expect(resolveForVariationId(varId, map)).toBe('[FilterA] (REGULAR)'); + }); + + it('replaces multiple comma-separated UUIDs with their names', () => { + const varId = '[1e34a601-fb40-4df1-8dc6-09aac5ef717e, 2b45c702-ac51-4e20-9ed7-10bbd6af828f] (REGULAR)'; + const map = new Map([ + ['1e34a601-fb40-4df1-8dc6-09aac5ef717e', 'FilterA'], + ['2b45c702-ac51-4e20-9ed7-10bbd6af828f', 'FilterB'], + ]); + expect(resolveForVariationId(varId, map)).toBe('[FilterA, FilterB] (REGULAR)'); + }); + + it('leaves unknown UUIDs as-is when not found in the map', () => { + const varId = '[1e34a601-fb40-4df1-8dc6-09aac5ef717e] (REGULAR)'; + const map = new Map(); + expect(resolveForVariationId(varId, map)).toBe('[1e34a601-fb40-4df1-8dc6-09aac5ef717e] (REGULAR)'); + }); + + it('replaces only known UUIDs and leaves unknown ones as-is', () => { + const varId = '[1e34a601-fb40-4df1-8dc6-09aac5ef717e, 2b45c702-ac51-4e20-9ed7-10bbd6af828f] (REGULAR)'; + const map = new Map([['1e34a601-fb40-4df1-8dc6-09aac5ef717e', 'FilterA']]); + expect(resolveForVariationId(varId, map)).toBe('[FilterA, 2b45c702-ac51-4e20-9ed7-10bbd6af828f] (REGULAR)'); + }); + + it('returns the original string unchanged when no UUIDs are present', () => { + const varId = 'SomePlainText (REGULAR)'; + const map = new Map([['1e34a601-fb40-4df1-8dc6-09aac5ef717e', 'FilterA']]); + expect(resolveForVariationId(varId, map)).toBe('SomePlainText (REGULAR)'); + }); + + it('handles an empty string', () => { + expect(resolveForVariationId('', new Map())).toBe(''); + }); + + it('preserves the suffix type (CONTINGENCY)', () => { + const varId = '[1e34a601-fb40-4df1-8dc6-09aac5ef717e] (CONTINGENCY)'; + const map = new Map([['1e34a601-fb40-4df1-8dc6-09aac5ef717e', 'MyFilter']]); + expect(resolveForVariationId(varId, map)).toBe('[MyFilter] (CONTINGENCY)'); + }); +}); diff --git a/src/services/study/sensitivity-analysis-utils.ts b/src/services/study/sensitivity-analysis-utils.ts new file mode 100644 index 0000000000..e28d66eeee --- /dev/null +++ b/src/services/study/sensitivity-analysis-utils.ts @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2026, 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/. + */ +const UUID_REGEX = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi; + +/** + * Extracts all unique UUIDs found inside a varId string in SensitivityOfTo like + * "[uuid1, uuid2] (REGULAR)" — finds all UUIDs inside brackets. + */ +export function extractUuidsFromVariationId(variationId: string): string[] { + return [...variationId.matchAll(UUID_REGEX)].map((match) => match[0]); +} + +/** + * Replaces all UUIDs in a varId string in SensitivityOfTo with the corresponding + * directory's element name from the provided map. UUIDs not found in the map are left as-is. + */ +export function resolveForVariationId(variationId: string, nameByUuid: Map): string { + return variationId.replace(UUID_REGEX, (uuid) => nameByUuid.get(uuid) ?? uuid); +} diff --git a/src/services/study/sensitivity-analysis.ts b/src/services/study/sensitivity-analysis.ts index b9c69073ee..ebfcd9d30c 100644 --- a/src/services/study/sensitivity-analysis.ts +++ b/src/services/study/sensitivity-analysis.ts @@ -6,16 +6,18 @@ */ import { getStudyUrlWithNodeUuidAndRootNetworkUuid } from './index'; -import { backendFetch, backendFetchJson, backendFetchText } from '@gridsuite/commons-ui'; +import { backendFetch, backendFetchJson, backendFetchText, fetchElementNames } from '@gridsuite/commons-ui'; import type { UUID } from 'node:crypto'; import { CsvConfig, SelectorFilterOptions, + Sensitivity, SensitivityResult, SensitivityResultFilterOptions, } from './sensitivity-analysis.type'; import { FilterConfig } from '../../types/custom-aggrid-types'; import { GlobalFilters } from 'components/results/common/global-filter/global-filter-types'; +import { extractUuidsFromVariationId, resolveForVariationId } from './sensitivity-analysis-utils'; export function startSensitivityAnalysis( studyUuid: UUID, @@ -58,7 +60,7 @@ export function fetchSensitivityAnalysisStatus(studyUuid: UUID, currentNodeUuid: return backendFetchText(url); } -export function fetchSensitivityAnalysisResult( +export async function fetchSensitivityAnalysisResult( studyUuid: UUID, currentNodeUuid: UUID, currentRootNetworkUuid: UUID, @@ -87,7 +89,32 @@ export function fetchSensitivityAnalysisResult( currentRootNetworkUuid )}/sensitivity-analysis/result?${urlSearchParams}`; console.debug(url); - return backendFetchJson(url); + const fetchedDto: SensitivityResult | null = await backendFetchJson(url); + + if (!fetchedDto) { + return null; + } + + // Collect all unique UUIDs across all sensitivities + const allUuids = new Set( + fetchedDto.sensitivities.flatMap((sensitivity: Sensitivity) => extractUuidsFromVariationId(sensitivity.varId)) + ); + + if (allUuids.size === 0) { + return fetchedDto; + } + + // Fetch names for all UUIDs in a single fetch + const nameByUuid = await fetchElementNames(allUuids); + + // Replace UUIDs with names in each sensitivity + return { + ...fetchedDto, + sensitivities: fetchedDto.sensitivities.map((sensitivity) => ({ + ...sensitivity, + varId: resolveForVariationId(sensitivity.varId, nameByUuid), + })), + }; } export function fetchSensitivityAnalysisFilterOptions(