diff --git a/src/components/app-wrapper.jsx b/src/components/app-wrapper.jsx index aaa8ce6eaf..79b5f0419a 100644 --- a/src/components/app-wrapper.jsx +++ b/src/components/app-wrapper.jsx @@ -5,7 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { useMemo } from 'react'; +import { useMemo, useEffect } from 'react'; import App from './app'; import { createTheme, @@ -72,7 +72,7 @@ import { } from '@gridsuite/commons-ui'; import { IntlProvider } from 'react-intl'; import { BrowserRouter } from 'react-router'; -import { Provider, useSelector } from 'react-redux'; +import { Provider, useSelector, useDispatch } from 'react-redux'; import messages_en from '../translations/en.json'; import messages_fr from '../translations/fr.json'; import messages_plugins from '../plugins/translations'; @@ -102,6 +102,9 @@ import useNotificationsUrlGenerator from 'hooks/use-notifications-url-generator' import { AllCommunityModule, ModuleRegistry, provideGlobalGridOptions } from 'ag-grid-community'; import { lightThemeCssVars } from '../styles/light-theme-css-vars'; import { darkThemeCssVars } from '../styles/dark-theme-css-vars'; +import { getVoltageLevelsCssVars } from 'utils/colors'; +import { fetchBaseVoltagesConfig } from '../services/utils'; +import { setBaseVoltagesConfig } from '../redux/actions'; // Register all community features (migration to V33) ModuleRegistry.registerModules([AllCommunityModule]); @@ -448,9 +451,27 @@ const basename = new URL(document.querySelector('base').href).pathname; const AppWrapperWithRedux = () => { const computedLanguage = useSelector((state) => state.computedLanguage); const theme = useSelector((state) => state[PARAM_THEME]); + const baseVoltagesConfig = useSelector((state) => state.baseVoltagesConfig); const themeCompiled = useMemo(() => getMuiTheme(theme, computedLanguage), [computedLanguage, theme]); - const rootCssVars = theme === LIGHT_THEME ? lightThemeCssVars : darkThemeCssVars; + const dispatch = useDispatch(); + + useEffect(() => { + fetchBaseVoltagesConfig().then((appMetadataBaseVoltagesConfig) => { + dispatch(setBaseVoltagesConfig(appMetadataBaseVoltagesConfig)); + }); + }, [dispatch]); + + const rootCssVars = useMemo(() => { + const themeVars = theme === LIGHT_THEME ? lightThemeCssVars : darkThemeCssVars; + if (!baseVoltagesConfig || baseVoltagesConfig.length === 0) { + return themeVars; + } + return { + ...themeVars, + ...getVoltageLevelsCssVars(baseVoltagesConfig, theme), + }; + }, [baseVoltagesConfig, theme]); const urlMapper = useNotificationsUrlGenerator(); diff --git a/src/components/grid-layout/hooks/use-diagram-model.ts b/src/components/grid-layout/hooks/use-diagram-model.ts index 1a5562a36d..5df8f1e452 100644 --- a/src/components/grid-layout/hooks/use-diagram-model.ts +++ b/src/components/grid-layout/hooks/use-diagram-model.ts @@ -28,11 +28,22 @@ import { BUILD_STATUS, SLD_DISPLAY_MODE } from 'components/network/constants'; import { useDiagramParamsInitialization } from './use-diagram-params-initialization'; import { useIntl } from 'react-intl'; import { useDiagramTitle } from './use-diagram-title'; -import { useSnackMessage } from '@gridsuite/commons-ui'; +import { BaseVoltageConfig, useSnackMessage } from '@gridsuite/commons-ui'; import { NodeType } from 'components/graph/tree-node.type'; import { isThereTooManyOpenedNadDiagrams, mergePositions } from '../cards/diagrams/diagram-utils'; import { DiagramMetadata } from '@powsybl/network-viewer'; +interface BaseVoltages { + name: string; + minValue: number; + maxValue: number; + profile: string; +} +interface BaseVoltagesConfigInfos { + baseVoltages: BaseVoltages[]; + defaultProfile: string; +} + type UseDiagramModelProps = { diagramTypes: DiagramType[]; onAddDiagram: (diagram: Diagram) => void; @@ -55,6 +66,7 @@ export const useDiagramModel = ({ diagramTypes, onAddDiagram, onDiagramAlreadyEx const networkVisuParams = useSelector((state: AppState) => state.networkVisualizationsParameters); const paramUseName = useSelector((state: AppState) => state[PARAM_USE_NAME]); const language = useSelector((state: AppState) => state[PARAM_LANGUAGE]); + const baseVoltagesConfig = useSelector((state: AppState) => state.baseVoltagesConfig); const getDiagramTitle = useDiagramTitle(); const [diagrams, setDiagrams] = useState>({}); @@ -286,6 +298,21 @@ export const useDiagramModel = ({ diagramTypes, onAddDiagram, onDiagramAlreadyEx }); }, []); + const getBaseVoltagesConfigInfos = useCallback((): BaseVoltagesConfigInfos | undefined => { + if (!baseVoltagesConfig) { + return; + } + return { + baseVoltages: baseVoltagesConfig.map((vl: BaseVoltageConfig) => ({ + name: vl.name, + minValue: vl.minValue, + maxValue: vl.maxValue, + profile: 'Default', + })), + defaultProfile: 'Default', + }; + }, [baseVoltagesConfig]); + const fetchDiagramSvg = useCallback( (diagram: Diagram) => { // make url from type @@ -304,6 +331,7 @@ export const useDiagramModel = ({ diagramTypes, onAddDiagram, onDiagramAlreadyEx positions: diagram.positions, nadPositionsGenerationMode: networkVisuParams.networkAreaDiagramParameters.nadPositionsGenerationMode, + baseVoltagesConfigInfos: getBaseVoltagesConfigInfos(), }; fetchOptions = { method: 'POST', @@ -311,6 +339,14 @@ export const useDiagramModel = ({ diagramTypes, onAddDiagram, onDiagramAlreadyEx body: JSON.stringify(nadRequestInfos), }; } + if (diagram.type === DiagramType.SUBSTATION || diagram.type === DiagramType.VOLTAGE_LEVEL) { + const sldRequestInfos = { baseVoltagesConfigInfos: getBaseVoltagesConfigInfos() }; + fetchOptions = { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(sldRequestInfos), + }; + } setLoadingDiagrams((loadingDiagrams) => { if (loadingDiagrams.includes(diagram.diagramUuid)) { @@ -337,6 +373,7 @@ export const useDiagramModel = ({ diagramTypes, onAddDiagram, onDiagramAlreadyEx [ getUrl, networkVisuParams.networkAreaDiagramParameters.nadPositionsGenerationMode, + getBaseVoltagesConfigInfos, handleFetchSuccess, handleFetchError, handleFetchFinally, diff --git a/src/components/network/constants.ts b/src/components/network/constants.ts index e7caf770a9..77f9ba6b1d 100644 --- a/src/components/network/constants.ts +++ b/src/components/network/constants.ts @@ -210,22 +210,3 @@ export const REGULATING_TERMINAL_TYPES = [ export const NUMBER = 'number'; export const ENUM = 'enum'; export const BOOLEAN = 'boolean'; - -export interface VoltageLevelInterval { - name: string; - vlValue: number; - minValue: number; - maxValue: number; -} - -export const BASE_VOLTAGES: VoltageLevelInterval[] = [ - { name: 'vl300to500', vlValue: 400, minValue: 300, maxValue: Infinity }, - { name: 'vl180to300', vlValue: 225, minValue: 180, maxValue: 300 }, - { name: 'vl120to180', vlValue: 150, minValue: 120, maxValue: 180 }, - { name: 'vl70to120', vlValue: 90, minValue: 70, maxValue: 120 }, - { name: 'vl50to70', vlValue: 63, minValue: 50, maxValue: 70 }, - { name: 'vl30to50', vlValue: 45, minValue: 30, maxValue: 50 }, - { name: 'vl0to30', vlValue: 20, minValue: 0, maxValue: 30 }, -]; - -export const MAX_VOLTAGE = 500; diff --git a/src/components/network/network-map-panel.tsx b/src/components/network/network-map-panel.tsx index f8cab0c071..f1f0d6df51 100644 --- a/src/components/network/network-map-panel.tsx +++ b/src/components/network/network-map-panel.tsx @@ -164,6 +164,7 @@ export const NetworkMapPanel = forwardRef state.isNetworkModificationTreeModelUpToDate ); + const baseVoltagesConfig = useSelector((state: AppState) => state.baseVoltagesConfig) ?? []; const theme = useTheme(); const { snackInfo } = useSnackMessage(); @@ -1184,7 +1185,9 @@ export const NetworkMapPanel = forwardRef + getNominalVoltageColor(baseVoltagesConfig, voltageValue) + } /> {mapEquipments && mapEquipments?.substations?.length > 0 && renderNominalVoltageFilter()} {renderSearchEquipment()} diff --git a/src/components/network/nominal-voltage-filter.tsx b/src/components/network/nominal-voltage-filter.tsx index bb00dafc13..a4e88e2ac1 100644 --- a/src/components/network/nominal-voltage-filter.tsx +++ b/src/components/network/nominal-voltage-filter.tsx @@ -9,8 +9,9 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; import { Button, Checkbox, List, ListItem, ListItemButton, ListItemText, Paper, Tooltip } from '@mui/material'; import { FormattedMessage } from 'react-intl'; import { type MuiStyles } from '@gridsuite/commons-ui'; -import { BASE_VOLTAGES, MAX_VOLTAGE, VoltageLevelInterval } from './constants'; -import { getNominalVoltageIntervalName } from './utils/nominal-voltage-filter-utils'; +import { MAX_VOLTAGE } from 'utils/constants'; +import { useSelector } from 'react-redux'; +import { AppState } from 'redux/reducer'; const styles = { nominalVoltageZone: { @@ -40,34 +41,61 @@ const styles = { }, } as const satisfies MuiStyles; +interface VoltageLevelInterval { + name: string; + minValue: number; + maxValue: number; + label: string; +} +type VoltageLevelValuesInterval = VoltageLevelInterval & { + vlListValues: number[]; + isChecked: boolean; +}; + export type NominalVoltageFilterProps = { nominalVoltages: number[]; filteredNominalVoltages: number[]; onChange: (filteredNominalVoltages: number[]) => void; }; -type VoltageLevelValuesInterval = VoltageLevelInterval & { - vlListValues: number[]; - isChecked: boolean; -}; - export default function NominalVoltageFilter({ nominalVoltages, filteredNominalVoltages, onChange, }: Readonly) { + const baseVoltagesConfigIntervals = useSelector( + (state: AppState) => + state.baseVoltagesConfig?.map(({ name, minValue, maxValue, label }) => ({ + name, + minValue, + maxValue, + label, + })) ?? [] + ); const [voltageLevelIntervals, setVoltageLevelIntervals] = useState( - BASE_VOLTAGES.map((interval) => ({ ...interval, vlListValues: [], isChecked: true })) + baseVoltagesConfigIntervals.map((interval) => ({ ...interval, vlListValues: [], isChecked: true })) ); + + const getNominalVoltageIntervalName = useCallback( + (voltageValue: number) => { + for (let interval of baseVoltagesConfigIntervals) { + if (voltageValue >= interval.minValue && voltageValue < interval.maxValue) { + return interval.name; + } + } + }, + [baseVoltagesConfigIntervals] + ); + useEffect(() => { - const newIntervals = BASE_VOLTAGES.map((interval) => { + const newIntervals = baseVoltagesConfigIntervals.map((interval) => { const vlListValues = nominalVoltages.filter( (vnom) => getNominalVoltageIntervalName(vnom) === interval.name ); return { ...interval, vlListValues, isChecked: true }; }); setVoltageLevelIntervals(newIntervals); - }, [nominalVoltages]); + }, [baseVoltagesConfigIntervals, getNominalVoltageIntervalName, nominalVoltages]); const handleToggle = useCallback( (interval: VoltageLevelValuesInterval) => { @@ -134,7 +162,7 @@ export default function NominalVoltageFilter({ diff --git a/src/components/network/utils/nominal-voltage-filter-utils.tsx b/src/components/network/utils/nominal-voltage-filter-utils.tsx deleted file mode 100644 index 19c34301ab..0000000000 --- a/src/components/network/utils/nominal-voltage-filter-utils.tsx +++ /dev/null @@ -1,15 +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/. - */ -import { BASE_VOLTAGES } from '../constants'; - -export const getNominalVoltageIntervalName = (voltageValue: number): string | undefined => { - for (let interval of BASE_VOLTAGES) { - if (voltageValue >= interval.minValue && voltageValue < interval.maxValue) { - return interval.name; - } - } -}; diff --git a/src/components/voltage-level-choice.jsx b/src/components/voltage-level-choice.jsx index 81f5ad3f71..1121088a7e 100644 --- a/src/components/voltage-level-choice.jsx +++ b/src/components/voltage-level-choice.jsx @@ -14,6 +14,7 @@ import Typography from '@mui/material/Typography'; import { getNominalVoltageColor } from '../utils/colors'; import { useNameOrId } from './utils/equipmentInfosHandler'; import { Box } from '@mui/material'; +import { useSelector } from 'react-redux'; const styles = { menu: { @@ -48,6 +49,7 @@ const voltageLevelComparator = (vl1, vl2) => { const VoltageLevelChoice = ({ handleClose, onClickHandler, substation, position }) => { const { getNameOrId } = useNameOrId(); + const baseVoltagesConfig = useSelector((state) => state.baseVoltagesConfig); return ( @@ -64,7 +66,7 @@ const VoltageLevelChoice = ({ handleClose, onClickHandler, substation, position > {substation !== undefined && substation.voltageLevels.sort(voltageLevelComparator).map((voltageLevel) => { - let color = getNominalVoltageColor(voltageLevel.nominalV); + let color = getNominalVoltageColor(baseVoltagesConfig, voltageLevel.nominalV); let colorString = 'rgb(' + color[0].toString() + ',' + color[1].toString() + ',' + color[2].toString() + ')'; diff --git a/src/redux/actions.ts b/src/redux/actions.ts index 935d3ccd69..a6aec03ce8 100644 --- a/src/redux/actions.ts +++ b/src/redux/actions.ts @@ -15,6 +15,7 @@ import { } from '../utils/config-params'; import type { Action } from 'redux'; import { + BaseVoltageConfig, ComputingType, type GsLang, type GsLangUser, @@ -152,6 +153,7 @@ export type AppActions = | ReorderTableDefinitionsAction | RenameTableDefinitionAction | SetAppTabIndexAction + | SetBaseVoltagesConfigAction | AttemptLeaveParametersTabAction | ConfirmLeaveParametersTabAction | CancelLeaveParametersTabAction @@ -180,6 +182,18 @@ export function setAppTabIndex(tabIndex: number): SetAppTabIndexAction { }; } +export const SET_BASE_VOLTAGES_CONFIG = 'SET_BASE_VOLTAGES_CONFIG'; +export type SetBaseVoltagesConfigAction = Readonly> & { + baseVoltagesConfig: BaseVoltageConfig[]; +}; + +export function setBaseVoltagesConfig(baseVoltagesConfig: BaseVoltageConfig[]): SetBaseVoltagesConfigAction { + return { + type: SET_BASE_VOLTAGES_CONFIG, + baseVoltagesConfig, + }; +} + export const ATTEMPT_LEAVE_PARAMETERS_TAB = 'ATTEMPT_LEAVE_PARAMETERS_TAB'; export type AttemptLeaveParametersTabAction = Readonly> & { targetTabIndex: number; diff --git a/src/redux/reducer.ts b/src/redux/reducer.ts index 1cad9fbf7d..5075b9d313 100644 --- a/src/redux/reducer.ts +++ b/src/redux/reducer.ts @@ -10,6 +10,7 @@ import { type AuthenticationActions, type AuthenticationRouterErrorAction, type AuthenticationRouterErrorState, + BaseVoltageConfig, type CommonStoreState, ComputingType, type GsLang, @@ -168,6 +169,7 @@ import { SET_ACTIVE_SPREADSHEET_TAB, SET_ADDED_SPREADSHEET_TAB, SET_APP_TAB_INDEX, + SET_BASE_VOLTAGES_CONFIG, SET_CALCULATION_SELECTIONS, SET_COMPUTATION_STARTING, SET_COMPUTING_STATUS, @@ -219,6 +221,7 @@ import { PCCMIN_ANALYSIS_RESULT_PAGINATION, type PccminAnalysisResultFilterAction, PccminAnalysisResultPaginationAction, + SetBaseVoltagesConfigAction, SPREADSHEET_FILTER, type SpreadsheetFilterAction, STATEESTIMATION_RESULT_FILTER, @@ -583,6 +586,7 @@ export interface AppState extends CommonStoreState, AppConfigState { authenticationRouterError: AuthenticationRouterErrorState | null; showAuthenticationRouterLogin: boolean; appTabIndex: number; + baseVoltagesConfig: BaseVoltageConfig[] | undefined; attemptedLeaveParametersTabIndex: number | null; isDirtyComputationParameters: boolean; studyUpdated: StudyUpdated; @@ -758,6 +762,7 @@ const initialTablesState: TablesState = { const initialState: AppState = { syncEnabled: false, appTabIndex: 0, + baseVoltagesConfig: undefined, attemptedLeaveParametersTabIndex: null, isDirtyComputationParameters: false, studyUuid: null, @@ -999,6 +1004,10 @@ export const reducer = createReducer(initialState, (builder) => { state.appTabIndex = action.tabIndex; }); + builder.addCase(SET_BASE_VOLTAGES_CONFIG, (state, action: SetBaseVoltagesConfigAction) => { + state.baseVoltagesConfig = action.baseVoltagesConfig; + }); + builder.addCase(ATTEMPT_LEAVE_PARAMETERS_TAB, (state, action: AttemptLeaveParametersTabAction) => { state.attemptedLeaveParametersTabIndex = action.targetTabIndex; }); diff --git a/src/services/utils.ts b/src/services/utils.ts index 9b0228054e..8ac38f41b3 100644 --- a/src/services/utils.ts +++ b/src/services/utils.ts @@ -4,7 +4,7 @@ * 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 { catchErrorHandler, fetchStudyMetadata, StudyMetadata } from '@gridsuite/commons-ui'; +import { BaseVoltageConfig, catchErrorHandler, fetchStudyMetadata, StudyMetadata } from '@gridsuite/commons-ui'; import { getUserToken } from '../redux/user-store'; export const FetchStatus = { @@ -82,6 +82,22 @@ export const fetchDefaultParametersValues = () => { return defaultValues; }); }; + +export async function fetchBaseVoltagesConfig(): Promise { + console.info('fetching base voltages configuration from apps-metadata file'); + const emptyConfig: BaseVoltageConfig[] = []; + return fetchStudyMetadata() + .then((studyMetadata) => { + return studyMetadata?.baseVoltagesConfig ?? emptyConfig; + }) + .catch((error: unknown) => { + catchErrorHandler(error, (message) => { + console.error(`fetching error (${message}), then empty config will be used.`); + }); + return emptyConfig; + }); +} + export const getQueryParamsList = (params: string[] | number[] | null | undefined, paramName: string) => { if (params != null && Array.isArray(params) && params.length > 0) { const urlSearchParams = new URLSearchParams(); diff --git a/src/styles/dark-theme-css-vars.ts b/src/styles/dark-theme-css-vars.ts index a7159b3783..ae760fd492 100644 --- a/src/styles/dark-theme-css-vars.ts +++ b/src/styles/dark-theme-css-vars.ts @@ -18,214 +18,4 @@ export const darkThemeCssVars = { '.nad-textnode-highlight': { backgroundColor: '#32373bd9', // same displayed color as #6c6c6c20 but with 0.85 opacity }, - '.sld-vl0to30, .nad-vl0to30': { - '--vl-color': '#CCC93A', - }, - '.sld-vl0to30.sld-bus-1, .nad-vl0to30.nad-bus-1': { - '--vl-color': '#5E835C', - }, - '.sld-vl0to30.sld-bus-2, .nad-vl0to30.nad-bus-2': { - '--vl-color': '#B1B46C', - }, - '.sld-vl0to30.sld-bus-3, .nad-vl0to30.nad-bus-3': { - '--vl-color': '#A156AA', - }, - '.sld-vl0to30.sld-bus-4, .nad-vl0to30.nad-bus-4': { - '--vl-color': '#CB3DDD', - }, - '.sld-vl0to30.sld-bus-5, .nad-vl0to30.nad-bus-5': { - '--vl-color': '#AC8AC2', - }, - '.sld-vl0to30.sld-bus-6, .nad-vl0to30.nad-bus-6': { - '--vl-color': '#734097', - }, - '.sld-vl0to30.sld-bus-7, .nad-vl0to30.nad-bus-7': { - '--vl-color': '#BCADCC', - }, - '.sld-vl0to30.sld-bus-8, .nad-vl0to30.nad-bus-8': { - '--vl-color': '#A246E0', - }, - '.sld-vl0to30.sld-bus-9, .nad-vl0to30.nad-bus-9': { - '--vl-color': '#C38CEB', - }, - '.sld-vl30to50, .nad-vl30to50': { - '--vl-color': '#EA8E9B', - }, - '.sld-vl30to50.sld-bus-1, .nad-vl30to50.nad-bus-1': { - '--vl-color': '#A43857', - }, - '.sld-vl30to50.sld-bus-2, .nad-vl30to50.nad-bus-2': { - '--vl-color': '#CEAAB0', - }, - '.sld-vl30to50.sld-bus-3, .nad-vl30to50.nad-bus-3': { - '--vl-color': '#459C63', - }, - '.sld-vl30to50.sld-bus-4, .nad-vl30to50.nad-bus-4': { - '--vl-color': '#00E266', - }, - '.sld-vl30to50.sld-bus-5, .nad-vl30to50.nad-bus-5': { - '--vl-color': '#A7B368', - }, - '.sld-vl30to50.sld-bus-6, .nad-vl30to50.nad-bus-6': { - '--vl-color': '#3F7340', - }, - '.sld-vl30to50.sld-bus-7, .nad-vl30to50.nad-bus-7': { - '--vl-color': '#C2CB92', - }, - '.sld-vl30to50.sld-bus-8, .nad-vl30to50.nad-bus-8': { - '--vl-color': '#218B21', - }, - '.sld-vl30to50.sld-bus-9, .nad-vl30to50.nad-bus-9': { - '--vl-color': '#58D058', - }, - '.sld-vl50to70, .nad-vl50to70': { - '--vl-color': '#D47DFF', - }, - '.sld-vl50to70.sld-bus-1, .nad-vl50to70.nad-bus-1': { - '--vl-color': '#C230D2', - }, - '.sld-vl50to70.sld-bus-2, .nad-vl50to70.nad-bus-2': { - '--vl-color': '#AB94BF', - }, - '.sld-vl50to70.sld-bus-3, .nad-vl50to70.nad-bus-3': { - '--vl-color': '#1F7620', - }, - '.sld-vl50to70.sld-bus-4, .nad-vl50to70.nad-bus-4': { - '--vl-color': '#C5ED3B', - }, - '.sld-vl50to70.sld-bus-5, .nad-vl50to70.nad-bus-5': { - '--vl-color': '#A7B368', - }, - '.sld-vl50to70.sld-bus-6, .nad-vl50to70.nad-bus-6': { - '--vl-color': '#697046', - }, - '.sld-vl50to70.sld-bus-7, .nad-vl50to70.nad-bus-7': { - '--vl-color': '#E1E444', - }, - '.sld-vl50to70.sld-bus-8, .nad-vl50to70.nad-bus-8': { - '--vl-color': '#AAAE50', - }, - '.sld-vl50to70.sld-bus-9, .nad-vl50to70.nad-bus-9': { - '--vl-color': '#D4D486', - }, - '.sld-vl70to120, .nad-vl70to120': { - '--vl-color': '#FF6100', - }, - '.sld-vl70to120.sld-bus-1, .nad-vl70to120.nad-bus-1': { - '--vl-color': '#B27153', - }, - '.sld-vl70to120.sld-bus-2, .nad-vl70to120.nad-bus-2': { - '--vl-color': '#C6A68B', - }, - '.sld-vl70to120.sld-bus-3, .nad-vl70to120.nad-bus-3': { - '--vl-color': '#25699D', - }, - '.sld-vl70to120.sld-bus-4, .nad-vl70to120.nad-bus-4': { - '--vl-color': '#0057F9', - }, - '.sld-vl70to120.sld-bus-5, .nad-vl70to120.nad-bus-5': { - '--vl-color': '#74AFEA', - }, - '.sld-vl70to120.sld-bus-6, .nad-vl70to120.nad-bus-6': { - '--vl-color': '#44679C', - }, - '.sld-vl70to120.sld-bus-7, .nad-vl70to120.nad-bus-7': { - '--vl-color': '#458BE8', - }, - '.sld-vl70to120.sld-bus-8, .nad-vl70to120.nad-bus-8': { - '--vl-color': '#2862AE', - }, - '.sld-vl70to120.sld-bus-9, .nad-vl70to120.nad-bus-9': { - '--vl-color': '#B0D4FE', - }, - '.sld-vl120to180, .nad-vl120to180': { - '--vl-color': '#29AFB0', - }, - '.sld-vl120to180.sld-bus-1, .nad-vl120to180.nad-bus-1': { - '--vl-color': '#336B6F', - }, - '.sld-vl120to180.sld-bus-2, .nad-vl120to180.nad-bus-2': { - '--vl-color': '#84C6CC', - }, - '.sld-vl120to180.sld-bus-3, .nad-vl120to180.nad-bus-3': { - '--vl-color': '#BA133C', - }, - '.sld-vl120to180.sld-bus-4, .nad-vl120to180.nad-bus-4': { - '--vl-color': '#FF8290', - }, - '.sld-vl120to180.sld-bus-5, .nad-vl120to180.nad-bus-5': { - '--vl-color': '#DAA8AD', - }, - '.sld-vl120to180.sld-bus-6, .nad-vl120to180.nad-bus-6': { - '--vl-color': '#97353A', - }, - '.sld-vl120to180.sld-bus-7, .nad-vl120to180.nad-bus-7': { - '--vl-color': '#EABCBD', - }, - '.sld-vl120to180.sld-bus-8, .nad-vl120to180.nad-bus-8': { - '--vl-color': '#EA2E33', - }, - '.sld-vl120to180.sld-bus-9, .nad-vl120to180.nad-bus-9': { - '--vl-color': '#EA6E72', - }, - '.sld-vl180to300, .nad-vl180to300': { - '--vl-color': '#00FF50', - }, - '.sld-vl180to300.sld-bus-1, .nad-vl180to300.nad-bus-1': { - '--vl-color': '#42954B', - }, - '.sld-vl180to300.sld-bus-2, .nad-vl180to300.nad-bus-2': { - '--vl-color': '#A7B27E', - }, - '.sld-vl180to300.sld-bus-3, .nad-vl180to300.nad-bus-3': { - '--vl-color': '#F57F17', - }, - '.sld-vl180to300.sld-bus-4, .nad-vl180to300.nad-bus-4': { - '--vl-color': '#A3715C', - }, - '.sld-vl180to300.sld-bus-5, .nad-vl180to300.nad-bus-5': { - '--vl-color': '#DBAB9D', - }, - '.sld-vl180to300.sld-bus-6, .nad-vl180to300.nad-bus-6': { - '--vl-color': '#885239', - }, - '.sld-vl180to300.sld-bus-7, .nad-vl180to300.nad-bus-7': { - '--vl-color': '#B39572', - }, - '.sld-vl180to300.sld-bus-8, .nad-vl180to300.nad-bus-8': { - '--vl-color': '#C94119', - }, - '.sld-vl180to300.sld-bus-9, .nad-vl180to300.nad-bus-9': { - '--vl-color': '#EABC45', - }, - '.sld-vl300to500, .nad-vl300to500': { - '--vl-color': '#FF0007', - }, - '.sld-vl300to500.sld-bus-1, .nad-vl300to500.nad-bus-1': { - '--vl-color': '#DD6484', - }, - '.sld-vl300to500.sld-bus-2, .nad-vl300to500.nad-bus-2': { - '--vl-color': '#FFBCBE', - }, - '.sld-vl300to500.sld-bus-3, .nad-vl300to500.nad-bus-3': { - '--vl-color': '#25699D', - }, - '.sld-vl300to500.sld-bus-4, .nad-vl300to500.nad-bus-4': { - '--vl-color': '#0057F9', - }, - '.sld-vl300to500.sld-bus-5, .nad-vl300to500.nad-bus-5': { - '--vl-color': '#74AFEA', - }, - '.sld-vl300to500.sld-bus-6, .nad-vl300to500.nad-bus-6': { - '--vl-color': '#44679C', - }, - '.sld-vl300to500.sld-bus-7, .nad-vl300to500.nad-bus-7': { - '--vl-color': '#458BE8', - }, - '.sld-vl300to500.sld-bus-8, .nad-vl300to500.nad-bus-8': { - '--vl-color': '#2862AE', - }, - '.sld-vl300to500.sld-bus-9, .nad-vl300to500.nad-bus-9': { - '--vl-color': '#B0D4FE', - }, }; diff --git a/src/styles/light-theme-css-vars.ts b/src/styles/light-theme-css-vars.ts index 9c3a96d364..9b1468401e 100644 --- a/src/styles/light-theme-css-vars.ts +++ b/src/styles/light-theme-css-vars.ts @@ -21,214 +21,4 @@ export const lightThemeCssVars = { '.nad-textnode-highlight': { backgroundColor: '#f0f0f0cc', // same displayed color as #9c9c9c20 but with 0.8 opacity }, - '.sld-vl0to30, .nad-vl0to30': { - '--vl-color': '#ABAE28', - }, - '.sld-vl0to30.sld-bus-1, .nad-vl0to30.nad-bus-1': { - '--vl-color': '#69701B', - }, - '.sld-vl0to30.sld-bus-2, .nad-vl0to30.nad-bus-2': { - '--vl-color': '#D8D20A', - }, - '.sld-vl0to30.sld-bus-3, .nad-vl0to30.nad-bus-3': { - '--vl-color': '#A156AA', - }, - '.sld-vl0to30.sld-bus-4, .nad-vl0to30.nad-bus-4': { - '--vl-color': '#CB3DDD', - }, - '.sld-vl0to30.sld-bus-5, .nad-vl0to30.nad-bus-5': { - '--vl-color': '#A684BC', - }, - '.sld-vl0to30.sld-bus-6, .nad-vl0to30.nad-bus-6': { - '--vl-color': '#62188B', - }, - '.sld-vl0to30.sld-bus-7, .nad-vl0to30.nad-bus-7': { - '--vl-color': '#885CA8', - }, - '.sld-vl0to30.sld-bus-8, .nad-vl0to30.nad-bus-8': { - '--vl-color': '#A020F0', - }, - '.sld-vl0to30.sld-bus-9, .nad-vl0to30.nad-bus-9': { - '--vl-color': '#CC80FF', - }, - '.sld-vl30to50, .nad-vl30to50': { - '--vl-color': '#FF8290', - }, - '.sld-vl30to50.sld-bus-1, .nad-vl30to50.nad-bus-1': { - '--vl-color': '#E7173E', - }, - '.sld-vl30to50.sld-bus-2, .nad-vl30to50.nad-bus-2': { - '--vl-color': '#DAA8AD', - }, - '.sld-vl30to50.sld-bus-3, .nad-vl30to50.nad-bus-3': { - '--vl-color': '#459C63', - }, - '.sld-vl30to50.sld-bus-4, .nad-vl30to50.nad-bus-4': { - '--vl-color': '#00E266', - }, - '.sld-vl30to50.sld-bus-5, .nad-vl30to50.nad-bus-5': { - '--vl-color': '#A7B368', - }, - '.sld-vl30to50.sld-bus-6, .nad-vl30to50.nad-bus-6': { - '--vl-color': '#1A4D1B', - }, - '.sld-vl30to50.sld-bus-7, .nad-vl30to50.nad-bus-7': { - '--vl-color': '#C2CB92', - }, - '.sld-vl30to50.sld-bus-8, .nad-vl30to50.nad-bus-8': { - '--vl-color': '#218B21', - }, - '.sld-vl30to50.sld-bus-9, .nad-vl30to50.nad-bus-9': { - '--vl-color': '#58D058', - }, - '.sld-vl50to70, .nad-vl50to70': { - '--vl-color': '#A020F0', - }, - '.sld-vl50to70.sld-bus-1, .nad-vl50to70.nad-bus-1': { - '--vl-color': '#62188B', - }, - '.sld-vl50to70.sld-bus-2, .nad-vl50to70.nad-bus-2': { - '--vl-color': '#AC8AC2', - }, - '.sld-vl50to70.sld-bus-3, .nad-vl50to70.nad-bus-3': { - '--vl-color': '#1F7620', - }, - '.sld-vl50to70.sld-bus-4, .nad-vl50to70.nad-bus-4': { - '--vl-color': '#C5ED3B', - }, - '.sld-vl50to70.sld-bus-5, .nad-vl50to70.nad-bus-5': { - '--vl-color': '#A7B368', - }, - '.sld-vl50to70.sld-bus-6, .nad-vl50to70.nad-bus-6': { - '--vl-color': '#55591B', - }, - '.sld-vl50to70.sld-bus-7, .nad-vl50to70.nad-bus-7': { - '--vl-color': '#E5E845', - }, - '.sld-vl50to70.sld-bus-8, .nad-vl50to70.nad-bus-8': { - '--vl-color': '#ABAE28', - }, - '.sld-vl50to70.sld-bus-9, .nad-vl50to70.nad-bus-9': { - '--vl-color': '#DAD971', - }, - '.sld-vl70to120, .nad-vl70to120': { - '--vl-color': '#FF9D00', - }, - '.sld-vl70to120.sld-bus-1, .nad-vl70to120.nad-bus-1': { - '--vl-color': '#7E3109', - }, - '.sld-vl70to120.sld-bus-2, .nad-vl70to120.nad-bus-2': { - '--vl-color': '#C50', - }, - '.sld-vl70to120.sld-bus-3, .nad-vl70to120.nad-bus-3': { - '--vl-color': '#25699D', - }, - '.sld-vl70to120.sld-bus-4, .nad-vl70to120.nad-bus-4': { - '--vl-color': '#0057F9', - }, - '.sld-vl70to120.sld-bus-5, .nad-vl70to120.nad-bus-5': { - '--vl-color': '#74AFEA', - }, - '.sld-vl70to120.sld-bus-6, .nad-vl70to120.nad-bus-6': { - '--vl-color': '#1B3459', - }, - '.sld-vl70to120.sld-bus-7, .nad-vl70to120.nad-bus-7': { - '--vl-color': '#458BE8', - }, - '.sld-vl70to120.sld-bus-8, .nad-vl70to120.nad-bus-8': { - '--vl-color': '#2862AE', - }, - '.sld-vl70to120.sld-bus-9, .nad-vl70to120.nad-bus-9': { - '--vl-color': '#B0D4FE', - }, - '.sld-vl120to180, .nad-vl120to180': { - '--vl-color': '#00AFAE', - }, - '.sld-vl120to180.sld-bus-1, .nad-vl120to180.nad-bus-1': { - '--vl-color': '#0A6365', - }, - '.sld-vl120to180.sld-bus-2, .nad-vl120to180.nad-bus-2': { - '--vl-color': '#79CED4', - }, - '.sld-vl120to180.sld-bus-3, .nad-vl120to180.nad-bus-3': { - '--vl-color': '#A30E32', - }, - '.sld-vl120to180.sld-bus-4, .nad-vl120to180.nad-bus-4': { - '--vl-color': '#FF8290', - }, - '.sld-vl120to180.sld-bus-5, .nad-vl120to180.nad-bus-5': { - '--vl-color': '#DAA8AD', - }, - '.sld-vl120to180.sld-bus-6, .nad-vl120to180.nad-bus-6': { - '--vl-color': '#C30D33', - }, - '.sld-vl120to180.sld-bus-7, .nad-vl120to180.nad-bus-7': { - '--vl-color': '#E3BEC0', - }, - '.sld-vl120to180.sld-bus-8, .nad-vl120to180.nad-bus-8': { - '--vl-color': '#FF8290', - }, - '.sld-vl120to180.sld-bus-9, .nad-vl120to180.nad-bus-9': { - '--vl-color': '#FFCCD0', - }, - '.sld-vl180to300, .nad-vl180to300': { - '--vl-color': '#32B532', - }, - '.sld-vl180to300.sld-bus-1, .nad-vl180to300.nad-bus-1': { - '--vl-color': '#1E5D1F', - }, - '.sld-vl180to300.sld-bus-2, .nad-vl180to300.nad-bus-2': { - '--vl-color': '#A7B368', - }, - '.sld-vl180to300.sld-bus-3, .nad-vl180to300.nad-bus-3': { - '--vl-color': '#E47400', - }, - '.sld-vl180to300.sld-bus-4, .nad-vl180to300.nad-bus-4': { - '--vl-color': '#6B3A26', - }, - '.sld-vl180to300.sld-bus-5, .nad-vl180to300.nad-bus-5': { - '--vl-color': '#D69A88', - }, - '.sld-vl180to300.sld-bus-6, .nad-vl180to300.nad-bus-6': { - '--vl-color': '#7E3109', - }, - '.sld-vl180to300.sld-bus-7, .nad-vl180to300.nad-bus-7': { - '--vl-color': '#B78B58', - }, - '.sld-vl180to300.sld-bus-8, .nad-vl180to300.nad-bus-8': { - '--vl-color': '#C94119', - }, - '.sld-vl180to300.sld-bus-9, .nad-vl180to300.nad-bus-9': { - '--vl-color': '#FFC019', - }, - '.sld-vl300to500, .nad-vl300to500': { - '--vl-color': '#F00', - }, - '.sld-vl300to500.sld-bus-1, .nad-vl300to500.nad-bus-1': { - '--vl-color': '#920A0A', - }, - '.sld-vl300to500.sld-bus-2, .nad-vl300to500.nad-bus-2': { - '--vl-color': '#FF9494', - }, - '.sld-vl300to500.sld-bus-3, .nad-vl300to500.nad-bus-3': { - '--vl-color': '#25699D', - }, - '.sld-vl300to500.sld-bus-4, .nad-vl300to500.nad-bus-4': { - '--vl-color': '#0057F9', - }, - '.sld-vl300to500.sld-bus-5, .nad-vl300to500.nad-bus-5': { - '--vl-color': '#74AFEA', - }, - '.sld-vl300to500.sld-bus-6, .nad-vl300to500.nad-bus-6': { - '--vl-color': '#1B3459', - }, - '.sld-vl300to500.sld-bus-7, .nad-vl300to500.nad-bus-7': { - '--vl-color': '#458BE8', - }, - '.sld-vl300to500.sld-bus-8, .nad-vl300to500.nad-bus-8': { - '--vl-color': '#2862AE', - }, - '.sld-vl300to500.sld-bus-9, .nad-vl300to500.nad-bus-9': { - '--vl-color': '#B0D4FE', - }, }; diff --git a/src/utils/colors.ts b/src/utils/colors.ts index 00a26dee14..0092130286 100644 --- a/src/utils/colors.ts +++ b/src/utils/colors.ts @@ -5,22 +5,58 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -export function getNominalVoltageColor(nominalVoltage: number): number[] { - if (nominalVoltage >= 300) { - return [255, 0, 0]; - } else if (nominalVoltage >= 180 && nominalVoltage < 300) { - return [34, 139, 34]; - } else if (nominalVoltage >= 120 && nominalVoltage < 180) { - return [1, 175, 175]; - } else if (nominalVoltage >= 70 && nominalVoltage < 120) { - return [204, 85, 0]; - } else if (nominalVoltage >= 50 && nominalVoltage < 70) { - return [160, 32, 240]; - } else if (nominalVoltage >= 30 && nominalVoltage < 50) { - return [255, 130, 144]; - } else { - return [171, 175, 40]; - } +import { BaseVoltageConfig, LIGHT_THEME } from '@gridsuite/commons-ui'; + +export const MAX_VOLTAGE = 500; + +function parseRGB(stringRGB: string): number[] | undefined { + return stringRGB + .match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/) + ?.slice(1) + .map(Number); } +export const getNominalVoltageIntervalByVoltageValue = ( + baseVoltages: BaseVoltageConfig[], + voltageValue: number +): BaseVoltageConfig | undefined => { + for (let interval of baseVoltages) { + if (voltageValue >= interval.minValue && voltageValue < interval.maxValue) { + return interval; + } + } +}; + +export const getNominalVoltageColor = (baseVoltages: BaseVoltageConfig[], voltageValue: number): number[] => { + const color = getNominalVoltageIntervalByVoltageValue(baseVoltages, voltageValue)?.mapColor; + return (color ? parseRGB(color) : [0, 0, 0]) ?? [0, 0, 0]; +}; + +export const getVoltageLevelsCssVars = ( + baseVoltages: BaseVoltageConfig[], + theme: string +): Record> => { + const css: Record> = {}; + + for (const interval of baseVoltages) { + const className = `.sld-${interval.name}, .nad-${interval.name}`; + + const themeColors = + theme === LIGHT_THEME + ? interval.sldAndNadColors.lightThemeColors + : interval.sldAndNadColors.darkThemeColors; + css[className] = { '--vl-color': themeColors.default }; + + for (let i = 1; i <= 9; i++) { + const key = `bus-${i}`; + const color = themeColors[key]; + if (!color) continue; + + const selector = `.sld-${interval.name}.sld-${key}, .nad-${interval.name}.nad-${key}`; + css[selector] = { '--vl-color': color }; + } + } + return css; +}; + export const INVALID_LOADFLOW_OPACITY = 0.2; diff --git a/src/utils/constants.ts b/src/utils/constants.ts new file mode 100644 index 0000000000..5f7d747ad5 --- /dev/null +++ b/src/utils/constants.ts @@ -0,0 +1,8 @@ +/** + * 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 MAX_VOLTAGE = 500;