diff --git a/.env b/.env
index fab96a8..bcbdc28 100644
--- a/.env
+++ b/.env
@@ -4,8 +4,8 @@ REACT_APP_NAME=GridDynaApp
EXTEND_ESLINT=true
-REACT_APP_API_PREFIX=api
-REACT_APP_GATEWAY_PREFIX=/gateway
-REACT_APP_URI=/dynamic-mapping-server
REACT_APP_WS_GATEWAY=ws/gateway
-REACT_APP_STUDY_URI=/study-server
+REACT_APP_API_GATEWAY=api/gateway
+
+REACT_APP_API_PREFIX=api/gateway
+REACT_APP_DYNAMAP_SVC=dynamic-mapping
diff --git a/.env.development b/.env.development
index 86192d9..8f03c67 100644
--- a/.env.development
+++ b/.env.development
@@ -2,8 +2,8 @@ REACT_APP_USE_AUTHENTICATION=false
REACT_APP_NAME=GridDynaApp
-REACT_APP_API_PREFIX=api
-REACT_APP_GATEWAY_PREFIX=/gateway
-REACT_APP_URI=/dynamic-mapping-server
REACT_APP_WS_GATEWAY=ws/gateway
-REACT_APP_STUDY_URI=/study-server
+REACT_APP_API_GATEWAY=api/gateway
+
+REACT_APP_API_PREFIX=api
+REACT_APP_DYNAMAP_SVC=dynamic-mapping-server
diff --git a/package-lock.json b/package-lock.json
index c06aea0..1e80af4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,7 +11,7 @@
"dependencies": {
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.5",
- "@gridsuite/commons-ui": "0.63.4",
+ "@gridsuite/commons-ui": "file:../commons-ui/gridsuite-commons-ui-0.63.4.tgz",
"@hookform/resolvers": "^3.3.4",
"@mui/icons-material": "^5.15.14",
"@mui/lab": "5.0.0-alpha.169",
@@ -2750,8 +2750,9 @@
},
"node_modules/@gridsuite/commons-ui": {
"version": "0.63.4",
- "resolved": "https://registry.npmjs.org/@gridsuite/commons-ui/-/commons-ui-0.63.4.tgz",
- "integrity": "sha512-0o0pfC8uySLLaEJSdur4/K54jnV9TResXwBI7JD51mfCNq1woXkzlBWmpDi7ruLwGIvGSF/8SR9Tw0F60Eovjw==",
+ "resolved": "file:../commons-ui/gridsuite-commons-ui-0.63.4.tgz",
+ "integrity": "sha512-3vvFWa40RY81G57P5H8zUUbAhUwcd1ayB1NWWZnHRvizq+0woRcw9qiy+bTdnt0mA7qznq9a5+IMcQU2bOPQPw==",
+ "license": "MPL-2.0",
"dependencies": {
"@react-querybuilder/dnd": "^7.2.0",
"@react-querybuilder/material": "^7.2.0",
@@ -2767,6 +2768,7 @@
"react-dnd-html5-backend": "^16.0.1",
"react-querybuilder": "^7.2.0",
"react-virtualized": "^9.22.5",
+ "type-fest": "^4.21.0",
"uuid": "^9.0.1"
},
"engines": {
@@ -2792,6 +2794,7 @@
"react-intl": "^6.6.4",
"react-papaparse": "^4.1.0",
"react-router-dom": "^6.22.3",
+ "reconnecting-websocket": "^4.4.0",
"yup": "^1.4.0"
}
},
@@ -2803,6 +2806,17 @@
"node": ">=6"
}
},
+ "node_modules/@gridsuite/commons-ui/node_modules/type-fest": {
+ "version": "4.23.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.23.0.tgz",
+ "integrity": "sha512-ZiBujro2ohr5+Z/hZWHESLz3g08BBdrdLMieYFULJO+tWc437sn8kQsWLJoZErY8alNhxre9K4p3GURAG11n+w==",
+ "engines": {
+ "node": ">=16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/@hookform/resolvers": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-3.3.4.tgz",
@@ -16565,6 +16579,12 @@
"node": ">=8.10.0"
}
},
+ "node_modules/reconnecting-websocket": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/reconnecting-websocket/-/reconnecting-websocket-4.4.0.tgz",
+ "integrity": "sha512-D2E33ceRPga0NvTDhJmphEgJ7FUYF0v4lr1ki0csq06OdlxKfugGzN0dSkxM/NfqCxYELK4KcaTOUOjTV6Dcng==",
+ "peer": true
+ },
"node_modules/recursive-readdir": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz",
diff --git a/package.json b/package.json
index 03840c2..66ec855 100644
--- a/package.json
+++ b/package.json
@@ -7,7 +7,7 @@
"dependencies": {
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.5",
- "@gridsuite/commons-ui": "0.63.4",
+ "@gridsuite/commons-ui": "file:../commons-ui/gridsuite-commons-ui-0.63.4.tgz",
"@hookform/resolvers": "^3.3.4",
"@mui/icons-material": "^5.15.14",
"@mui/lab": "5.0.0-alpha.169",
diff --git a/src/components/2-molecules/Header.jsx b/src/components/2-molecules/Header.jsx
index b9c5c10..51d35db 100644
--- a/src/components/2-molecules/Header.jsx
+++ b/src/components/2-molecules/Header.jsx
@@ -9,9 +9,8 @@ import { Grid, Tooltip, Typography } from '@mui/material';
import { AddIconButton, AttachButton, SaveButton } from '../1-atoms/buttons/';
import React from 'react';
import PropTypes from 'prop-types';
-
+import { mergeSx } from '@gridsuite/commons-ui';
import { styles } from './HeaderStyles';
-import { mergeSx } from 'utils/functions';
const outdatedLabel = 'Generated elements are outdated, re-generate them to delete this warning';
diff --git a/src/components/2-molecules/SetGroupSelect.tsx b/src/components/2-molecules/SetGroupSelect.tsx
index ebee5d3..00650aa 100644
--- a/src/components/2-molecules/SetGroupSelect.tsx
+++ b/src/components/2-molecules/SetGroupSelect.tsx
@@ -6,13 +6,13 @@
*/
import { Checkbox, Grid, Typography } from '@mui/material';
+import { mergeSx } from '@gridsuite/commons-ui';
import Select from '../1-atoms/Select';
import { styles } from './SetGroupSelectStyle';
import React, { useEffect, useState } from 'react';
import { SetType } from '../../constants/models';
import { EditButton } from '../1-atoms/buttons';
import { Group, Model } from '../../redux/types/model.type';
-import { mergeSx } from 'utils/functions';
const setLabel = 'and use parameters group';
const editGroupLabel = 'Edit the parameters group and/or the parameters sets';
@@ -92,7 +92,11 @@ const SetGroupSelect = (props: SetGroupSelectProps) => {
{`${setLabel} :`}
-
+
{
const {
diff --git a/src/components/3-organisms/Filter.jsx b/src/components/3-organisms/Filter.jsx
index 62f7c88..6536a57 100644
--- a/src/components/3-organisms/Filter.jsx
+++ b/src/components/3-organisms/Filter.jsx
@@ -8,11 +8,10 @@
import React, { useMemo } from 'react';
import PropTypes from 'prop-types';
import { Box, Grid, Tooltip, Typography } from '@mui/material';
-import { CustomReactQueryBuilder, EXPERT_FILTER_FIELDS, EXPERT_FILTER_QUERY } from '@gridsuite/commons-ui';
+import { CustomReactQueryBuilder, EXPERT_FILTER_FIELDS, EXPERT_FILTER_QUERY, mergeSx } from '@gridsuite/commons-ui';
import { useIntl } from 'react-intl';
import { AddIconButton, DeleteButton } from '../1-atoms/buttons';
import { styles } from './FilterStyle';
-import { mergeSx } from '../../utils/functions';
import InfoIcon from '@mui/icons-material/Info';
const filterLabel = 'Where:';
diff --git a/src/components/3-organisms/Rule.jsx b/src/components/3-organisms/Rule.jsx
index c9bd84e..5786b9e 100644
--- a/src/components/3-organisms/Rule.jsx
+++ b/src/components/3-organisms/Rule.jsx
@@ -7,12 +7,12 @@
import React from 'react';
import PropTypes from 'prop-types';
+import { mergeSx } from '@gridsuite/commons-ui';
import { CopyButton, DeleteButton } from '../1-atoms/buttons';
import { Grid, Paper, Typography } from '@mui/material';
import { styles } from './RuleStyle';
import ModelSelect from '../2-molecules/ModelSelect';
import SetGroupSelect from '../2-molecules/SetGroupSelect';
-import { mergeSx } from 'utils/functions';
const equipmentLabel = 'Each';
const deleteRuleLabel = 'Delete model';
diff --git a/src/components/3-organisms/SetEditor.jsx b/src/components/3-organisms/SetEditor.jsx
index 659db2e..99baf57 100644
--- a/src/components/3-organisms/SetEditor.jsx
+++ b/src/components/3-organisms/SetEditor.jsx
@@ -10,7 +10,7 @@ import PropTypes from 'prop-types';
import { ParameterOrigin, ParameterType } from '../../constants/models';
import { Box, Grid, TextField, Tooltip, Typography } from '@mui/material';
import InfoIcon from '@mui/icons-material/Info';
-import * as _ from 'lodash';
+import { cloneDeep } from 'lodash';
import { isParameterValueValid } from '../../utils/parameters';
const infoTypeLabel = 'This parameter is of type ';
@@ -38,7 +38,7 @@ const SetEditor = (props) => {
filteredDefinitions.find((definition) => definition.name === parameterChanged).type === ParameterType.DOUBLE
? newValue.replace(',', '.')
: newValue;
- const updatedSet = _.cloneDeep(set);
+ const updatedSet = cloneDeep(set);
updatedSet.parameters.find((parameter) => parameter.name === parameterChanged).value = newValueToUse;
saveSet(updatedSet);
};
@@ -46,7 +46,7 @@ const SetEditor = (props) => {
return (
{set.name}
- {_.cloneDeep(filteredDefinitions)
+ {cloneDeep(filteredDefinitions)
.sort((a, b) => valueOrigin(a.origin) - valueOrigin(b.origin))
.map((definition) => {
const correspondingParameter = set.parameters.find((param) => param.name === definition.name);
diff --git a/src/components/3-organisms/automaton/AutomatonProperties.tsx b/src/components/3-organisms/automaton/AutomatonProperties.tsx
index 9089173..0fa41da 100644
--- a/src/components/3-organisms/automaton/AutomatonProperties.tsx
+++ b/src/components/3-organisms/automaton/AutomatonProperties.tsx
@@ -10,7 +10,7 @@ import { Divider, Grid, Typography } from '@mui/material';
import Autocomplete from '../../1-atoms/Autocomplete';
import { styles } from './AutomatonPropertiesStyle';
import { getPossibleOptionsForProperty } from '../../../utils/automata';
-import * as _ from 'lodash';
+import { isArray, join, map, split, trim } from 'lodash';
import { Automaton } from '../../../redux/types/mapping.type';
import { AutomationDefinition } from '../../../redux/types/model.type';
import { EquipmentValues } from '../../../redux/types/network.type';
@@ -39,7 +39,7 @@ const AutomatonProperties = ({
propertyType
)(
// convert an array to a string content with VALUE_DELIMITER
- _.isArray(propertyValue) ? _.join(propertyValue, VALUE_DELIMITER) : propertyValue
+ isArray(propertyValue) ? join(propertyValue, VALUE_DELIMITER) : propertyValue
);
},
[onChangeProperty]
@@ -53,7 +53,7 @@ const AutomatonProperties = ({
// convert a string content with VALUE_DELIMITER to an array
const propertyValue = propertyDefinition.multiple
- ? _.map(_.split(property?.value, VALUE_DELIMITER), _.trim)
+ ? map(split(property?.value, VALUE_DELIMITER), trim)
: property?.value ?? '';
const options =
diff --git a/src/components/3-organisms/hooks/useSetSearch.js b/src/components/3-organisms/hooks/useSetSearch.js
index 0ed04b9..f2e0bff 100644
--- a/src/components/3-organisms/hooks/useSetSearch.js
+++ b/src/components/3-organisms/hooks/useSetSearch.js
@@ -13,7 +13,7 @@ import {
makeGetSearchSets,
ModelSlice,
} from '../../../redux/slices/Model';
-import _ from 'lodash';
+import { cloneDeep, find, forEach, reduce } from 'lodash';
import { useDispatch } from 'react-redux';
export default function useSetSearch(currentGroup, currentSet) {
@@ -49,13 +49,13 @@ export default function useSetSearch(currentGroup, currentSet) {
}
const updatedSets = isAll
- ? _.reduce(currentGroup?.sets, (acc, set) => [...acc, _.cloneDeep(set)], [])
- : [_.cloneDeep(currentSet)];
+ ? reduce(currentGroup?.sets, (acc, set) => [...acc, cloneDeep(set)], [])
+ : [cloneDeep(currentSet)];
// fill with values in the provided sets
- _.forEach(updatedSets, (updatedSet) => {
- _.forEach(updatedSet?.parameters, (parameter) => {
- const templateParameter = _.find(set?.parameters, (elem) => elem.name === parameter.name);
+ forEach(updatedSets, (updatedSet) => {
+ forEach(updatedSet?.parameters, (parameter) => {
+ const templateParameter = find(set?.parameters, (elem) => elem.name === parameter.name);
templateParameter && (parameter.value = templateParameter?.value);
});
});
diff --git a/src/components/app.js b/src/components/app.js
index 4c9db0e..3568522 100644
--- a/src/components/app.js
+++ b/src/components/app.js
@@ -10,23 +10,22 @@ import { useDispatch, useSelector } from 'react-redux';
import { Navigate, Route, Routes, useLocation, useMatch, useNavigate } from 'react-router-dom';
import { Box, CssBaseline } from '@mui/material';
import { createTheme, StyledEngineProvider, ThemeProvider } from '@mui/material/styles';
-import { LIGHT_THEME } from '../redux/slices/Theme';
import {
AuthenticationRouter,
CardErrorBoundary,
getPreLoginPath,
initializeAuthenticationDev,
initializeAuthenticationProd,
+ LIGHT_THEME,
logout,
TopBar,
} from '@gridsuite/commons-ui';
import { FormattedMessage } from 'react-intl';
import { ReactComponent as PowsyblLogo } from '../images/powsybl_logo.svg';
import AppPackage from '../../package.json';
-import { fetchAppsAndUrls, fetchIdpSettings, fetchValidateUser, fetchVersion } from '../utils/rest-api';
-import { getServersInfos } from '../rest/studyAPI';
import { UserSlice } from '../redux/slices/User';
import RootContainer from '../containers/RootContainer';
+import { appLocalSrv, appsMetadataSrv, studySrv, userAdminSrv } from '../services';
const lightTheme = createTheme({
palette: {
@@ -65,6 +64,8 @@ const App = () => {
const navigate = useNavigate();
+ const onLogoClick = useCallback(() => navigate('/', { replace: true }), [navigate]);
+
const dispatch = useDispatch();
const authenticationDispatch = useCallback(
@@ -72,6 +73,11 @@ const App = () => {
[dispatch]
);
+ const onLogoutClick = useCallback(
+ () => logout(authenticationDispatch, userManager.instance),
+ [authenticationDispatch, userManager.instance]
+ );
+
const location = useLocation();
// Can't use lazy initializer because useMatch is a hook
@@ -97,8 +103,8 @@ const App = () => {
? initializeAuthenticationProd(
authenticationDispatch,
initialMatchSilentRenewCallbackUrl != null,
- fetchIdpSettings,
- fetchValidateUser,
+ appLocalSrv.fetchIdpSettings,
+ userAdminSrv.fetchValidateUser,
initialMatchSigninCallbackUrl != null
)
: initializeAuthenticationDev(
@@ -120,12 +126,18 @@ const App = () => {
useEffect(() => {
if (user !== null) {
- fetchAppsAndUrls().then((res) => {
+ appsMetadataSrv.fetchAppsMetadata().then((res) => {
setAppsAndUrls(res);
});
}
}, [user]);
+ const additionalModulesFetcher = useCallback(() => studySrv.getServersInfos('dyna'), []);
+ const globalVersionFetcher = useCallback(
+ () => appsMetadataSrv.fetchVersion().then((res) => res?.deployVersion),
+ []
+ );
+
return (
@@ -137,12 +149,12 @@ const App = () => {
appLogo={}
appVersion={AppPackage.version}
appLicense={AppPackage.license}
- onLogoClick={() => navigate('/', { replace: true })}
- onLogoutClick={() => logout(authenticationDispatch, userManager.instance)}
+ onLogoClick={onLogoClick}
+ onLogoutClick={onLogoutClick}
user={user}
appsAndUrls={appsAndUrls}
- globalVersionPromise={() => fetchVersion().then((res) => res?.deployVersion)}
- additionalModulesPromise={getServersInfos}
+ globalVersionPromise={globalVersionFetcher}
+ additionalModulesPromise={additionalModulesFetcher}
/>
{user !== null ? (
diff --git a/src/hooks/react-hook-form/form/useDataUpdate.ts b/src/hooks/react-hook-form/form/useDataUpdate.ts
index 774d785..b8f8e31 100644
--- a/src/hooks/react-hook-form/form/useDataUpdate.ts
+++ b/src/hooks/react-hook-form/form/useDataUpdate.ts
@@ -7,7 +7,7 @@
import { useEffect } from 'react';
import { FieldErrors, FieldValues, UseFormReturn } from 'react-hook-form';
import { usePrevious } from '@gridsuite/commons-ui';
-import _ from 'lodash';
+import { isEqual } from 'lodash';
const useDataUpdate = (
formApi: UseFormReturn,
@@ -18,7 +18,7 @@ const useDataUpdate = (
const prevFormData = usePrevious(formData);
useEffect(() => {
- if (!_.isEqual(prevFormData, formData)) {
+ if (!isEqual(prevFormData, formData)) {
formApi.handleSubmit(onValid, onInvalid)();
}
}, [formApi, onValid, onInvalid, formData, prevFormData]);
diff --git a/src/react-app-env.d.ts b/src/react-app-env.d.ts
index 7b288b8..49bf58a 100644
--- a/src/react-app-env.d.ts
+++ b/src/react-app-env.d.ts
@@ -6,3 +6,13 @@
*/
///
+
+namespace NodeJS {
+ interface ProcessEnv {
+ REACT_APP_API_GATEWAY: string;
+ REACT_APP_WS_GATEWAY: string;
+
+ REACT_APP_API_PREFIX: string;
+ REACT_APP_DYNAMAP_SVC: string;
+ }
+}
diff --git a/src/redux/local-storage.js b/src/redux/local-storage.js
deleted file mode 100644
index 309296e..0000000
--- a/src/redux/local-storage.js
+++ /dev/null
@@ -1,18 +0,0 @@
-/**
- * Copyright (c) 2020, 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 { DARK_THEME } from './slices/Theme';
-
-const LOCAL_STORAGE_THEME_KEY = process.env.REACT_APP_NAME + '_THEME';
-
-export const getLocalStorageTheme = () => {
- return localStorage.getItem(LOCAL_STORAGE_THEME_KEY) || DARK_THEME;
-};
-
-export const saveLocalStorageTheme = (theme) => {
- localStorage.setItem(LOCAL_STORAGE_THEME_KEY, theme);
-};
diff --git a/src/redux/slices/Mapping.js b/src/redux/slices/Mapping.js
index bdbdaa0..fa48718 100644
--- a/src/redux/slices/Mapping.js
+++ b/src/redux/slices/Mapping.js
@@ -6,10 +6,8 @@
*/
import { createAsyncThunk, createSelector, createSlice } from '@reduxjs/toolkit';
-import * as mappingsAPI from '../../rest/mappingsAPI';
-import * as _ from 'lodash';
+import { cloneDeep, isEmpty, isEqual } from 'lodash';
import RequestStatus from '../../constants/RequestStatus';
-import * as networkAPI from '../../rest/networkAPI';
import { AutomatonFamily } from '../../constants/automatonDefinition';
import { RuleEquipmentTypes } from '../../constants/equipmentType';
import {
@@ -23,6 +21,7 @@ import {
import { v4 as uuid4 } from 'uuid';
import { enrichIdRqbQuery } from '../../utils/rqb-utils';
import { assignArray } from '../../utils/functions';
+import { dynamicMappingSrv } from '../../services';
const initialState = {
mappings: [],
@@ -59,7 +58,7 @@ export const DEFAULT_NAME = 'default';
const ruleMatcher = (rule1) => (rule2) => rule1?.id === rule2?.id;
const transformMapping = (receivedMapping) => {
- const mapping = _.cloneDeep(receivedMapping);
+ const mapping = cloneDeep(receivedMapping);
mapping.rules = mapping.rules.map((rule) => {
rule['type'] = rule.equipmentType;
delete rule.equipmentType;
@@ -215,7 +214,7 @@ const checkFilterValidity = (filter, isLast) => {
// only last rule allows empty filter
return !!isLast;
}
- const isQueryExist = !_.isEmpty(filter.rules);
+ const isQueryExist = !isEmpty(filter.rules);
const isQueryValid = isQueryExist && rqbQuerySchemaValidator(yup.object()).isValidSync(filter.rules);
return isQueryValid;
};
@@ -380,7 +379,7 @@ export const isModified = createSelector(
const foundMapping = savedMappings.find((mapping) => mapping.name === activeName);
function ignoreInternalProperties(rule) {
- const ruleToTest = _.cloneDeep(rule);
+ const ruleToTest = cloneDeep(rule);
delete ruleToTest.matches; // ignore matches which is used for matched equipment ids
delete ruleToTest.filterDirty; // ignore the derived field
@@ -397,9 +396,9 @@ export const isModified = createSelector(
}
return !(
- _.isEqual(activeRules.map(ignoreInternalProperties), foundMapping.rules.map(ignoreInternalProperties)) &&
- _.isEqual(activeAutomata, foundMapping.automata) &&
- _.isEqual(controlledParameters, foundMapping.controlledParameters)
+ isEqual(activeRules.map(ignoreInternalProperties), foundMapping.rules.map(ignoreInternalProperties)) &&
+ isEqual(activeAutomata, foundMapping.automata) &&
+ isEqual(controlledParameters, foundMapping.controlledParameters)
);
}
);
@@ -433,7 +432,7 @@ export const postMapping = createAsyncThunk('mappings/post', async (name, { getS
: state?.mappings.rules;
const augmentedRules = rules.map((rule) => {
- let augmentedRule = _.cloneDeep(rule);
+ let augmentedRule = cloneDeep(rule);
augmentedRule.equipmentType = rule.type.toUpperCase();
if (augmentedRule.filter) {
@@ -469,27 +468,33 @@ export const postMapping = createAsyncThunk('mappings/post', async (name, { getS
? state?.mappings.mappings.find((mapping) => mapping.name === name)?.controlledParameters
: state?.mappings.controlledParameters;
- return await mappingsAPI.postMapping(mappingName, augmentedRules, formattedAutomata, controlledParameters, token);
+ return await dynamicMappingSrv.postMapping(
+ mappingName,
+ augmentedRules,
+ formattedAutomata,
+ controlledParameters,
+ token
+ );
});
export const getMappings = createAsyncThunk('mappings/get', async (_arg, { getState }) => {
const token = getState()?.user.user?.id_token;
- return await mappingsAPI.getMappings(token);
+ return await dynamicMappingSrv.getMappings(token);
});
export const deleteMapping = createAsyncThunk('mappings/delete', async (mappingName, { getState }) => {
const token = getState()?.user.user?.id_token;
- return await mappingsAPI.deleteMapping(mappingName, token);
+ return await dynamicMappingSrv.deleteMapping(mappingName, token);
});
export const renameMapping = createAsyncThunk('mappings/rename', async ({ nameToReplace, newName }, { getState }) => {
const token = getState()?.user.user?.id_token;
- return await mappingsAPI.renameMapping(nameToReplace, newName, token);
+ return await dynamicMappingSrv.renameMapping(nameToReplace, newName, token);
});
export const copyMapping = createAsyncThunk('mappings/copy', async ({ originalName, copyName }, { getState }) => {
const token = getState()?.user.user?.id_token;
- return await mappingsAPI.copyMapping(originalName, copyName, token);
+ return await dynamicMappingSrv.copyMapping(originalName, copyName, token);
});
export const getNetworkMatchesFromRule = createAsyncThunk('mappings/matchNetwork', async (ruleIndex, { getState }) => {
@@ -503,7 +508,7 @@ export const getNetworkMatchesFromRule = createAsyncThunk('mappings/matchNetwork
equipmentType: foundRule.type,
filter: augmentFilter(foundRule.filter, foundRule.type),
};
- return await networkAPI.getNetworkMatchesFromRule(networkId, ruleToMatch, token);
+ return await dynamicMappingSrv.getNetworkMatchesFromRule(networkId, ruleToMatch, token);
});
// daisy-chain action creators
@@ -556,7 +561,7 @@ const reducers = {
},
// Rule
addRule: (state) => {
- const newRule = _.cloneDeep(DEFAULT_RULE);
+ const newRule = cloneDeep(DEFAULT_RULE);
// provide an id for new rule
newRule.id = uuid4();
newRule.type = state.filteredRuleType;
@@ -580,7 +585,7 @@ const reducers = {
},
copyRule: (state, action) => {
const { index } = action.payload;
- const ruleToCopy = _.cloneDeep(filterRulesByType(state.rules, state.filteredRuleType)[index]);
+ const ruleToCopy = cloneDeep(filterRulesByType(state.rules, state.filteredRuleType)[index]);
// force reset rule with new id
ruleToCopy.id = uuid4();
@@ -634,7 +639,7 @@ const reducers = {
},
// Automaton
addAutomaton: (state) => {
- const newAutomaton = _.cloneDeep(DEFAULT_AUTOMATON);
+ const newAutomaton = cloneDeep(DEFAULT_AUTOMATON);
newAutomaton.family = state.filteredAutomatonFamily;
state.automata.push(newAutomaton);
},
@@ -677,9 +682,7 @@ const reducers = {
},
copyAutomaton: (state, action) => {
const { index } = action.payload;
- const automatonToCopy = _.cloneDeep(
- filterAutomataByFamily(state.automata, state.filteredAutomatonFamily)[index]
- );
+ const automatonToCopy = cloneDeep(filterAutomataByFamily(state.automata, state.filteredAutomatonFamily)[index]);
state.automata.push(automatonToCopy);
},
// Mappings
diff --git a/src/redux/slices/Model.js b/src/redux/slices/Model.js
index 037520e..c50fac7 100644
--- a/src/redux/slices/Model.js
+++ b/src/redux/slices/Model.js
@@ -6,10 +6,10 @@
*/
import { createAsyncThunk, createSelector, createSlice } from '@reduxjs/toolkit';
-import * as modelsAPI from '../../rest/modelsAPI';
import RequestStatus from '../../constants/RequestStatus';
-import * as _ from 'lodash';
+import { cloneDeep, findIndex, forEach, uniqBy } from 'lodash';
import { SetType } from '../../constants/models';
+import { dynamicMappingSrv } from '../../services';
const DEFAULT_GROUP = {
name: '',
@@ -65,12 +65,12 @@ export const makeGetSearchSets = () =>
export const getModels = createAsyncThunk('models/get', async (_arg, { getState }) => {
const token = getState()?.user.user?.id_token;
- return await modelsAPI.getModels(token);
+ return await dynamicMappingSrv.getModels(token);
});
export const getModelDefinitions = createAsyncThunk('models/definitions', async (modelName, { getState }) => {
const token = getState()?.user.user?.id_token;
- return await modelsAPI.getModelDefinitions(modelName, token);
+ return await dynamicMappingSrv.getModelDefinitions(modelName, token);
});
export const getModelSets = createAsyncThunk(
@@ -78,7 +78,7 @@ export const getModelSets = createAsyncThunk(
async ({ modelName, groupName, groupType }, { getState }) => {
if (groupName) {
const token = getState()?.user.user?.id_token;
- return await modelsAPI.getModelSets(
+ return await dynamicMappingSrv.getModelSets(
modelName,
groupName,
groupType !== '' ? groupType : SetType.FIXED,
@@ -95,7 +95,7 @@ export const getSearchedModelSets = createAsyncThunk(
async ({ modelName, groupName, groupType }, { getState }) => {
if (groupName) {
const token = getState()?.user.user?.id_token;
- return await modelsAPI.getModelSets(modelName, groupName, groupType ?? '', token);
+ return await dynamicMappingSrv.getModelSets(modelName, groupName, groupType ?? '', token);
} else {
return [];
}
@@ -105,14 +105,14 @@ export const getSearchedModelSets = createAsyncThunk(
export const postModelSetsGroup = createAsyncThunk('models/post', async (strict, { getState }) => {
const token = getState()?.user.user?.id_token;
const setGroup = getState()?.models.currentGroup;
- return await modelsAPI.postModelSetsGroup(setGroup, strict, token);
+ return await dynamicMappingSrv.postModelSetsGroup(setGroup, strict, token);
});
export const getAutomatonDefinitions = createAsyncThunk(
'models/automaton/get/definitions',
async (_arg, { getState }) => {
const token = getState()?.user.user?.id_token;
- return await modelsAPI.getAutomatonDefinitions(token);
+ return await dynamicMappingSrv.getAutomatonDefinitions(token);
}
);
@@ -130,7 +130,7 @@ const reducers = {
},
changeGroup: (state, action) => {
const { group, originalGroup, modelName, isAbsolute, matches } = action.payload;
- const currentGroup = _.cloneDeep(group);
+ const currentGroup = cloneDeep(group);
const definitions = state.parameterDefinitions;
currentGroup.modelName = modelName;
if (originalGroup) {
@@ -148,7 +148,7 @@ const reducers = {
const newSets = matches
.filter(
(match) =>
- _.findIndex(
+ findIndex(
currentGroup.sets,
(set) => set.name === matchingSetName(match, currentGroup.type)
) === -1
@@ -189,7 +189,7 @@ const reducers = {
addOrModifySet: (state, action) => {
const newSets = action.payload;
- _.forEach(Array.isArray(newSets) ? newSets : [newSets], (newSet) => {
+ forEach(Array.isArray(newSets) ? newSets : [newSets], (newSet) => {
const setIndex = state.currentGroup.sets.findIndex((setToTest) => setToTest.name === newSet.name);
if (setIndex === -1) {
state.currentGroup.sets.push(newSet);
@@ -215,13 +215,13 @@ const extraReducers = (builder) => {
builder.addCase(getModelSets.fulfilled, (state, action) => {
const receivedSets = action.payload;
- state.currentGroup.sets = _.uniqBy(receivedSets.concat(state.currentGroup.sets), 'name');
+ state.currentGroup.sets = uniqBy(receivedSets.concat(state.currentGroup.sets), 'name');
state.status = RequestStatus.SUCCESS;
});
builder.addCase(getSearchedModelSets.fulfilled, (state, action) => {
const candidateSets = action.payload;
- state.currentGroup.searchSets = _.uniqBy(candidateSets, 'name');
+ state.currentGroup.searchSets = uniqBy(candidateSets, 'name');
state.status = RequestStatus.SUCCESS;
});
builder.addCase(postModelSetsGroup.fulfilled, (state, action) => {
diff --git a/src/redux/slices/Network.js b/src/redux/slices/Network.js
index f1e7081..a191fa2 100644
--- a/src/redux/slices/Network.js
+++ b/src/redux/slices/Network.js
@@ -7,9 +7,9 @@
import { createAsyncThunk, createSelector, createSlice } from '@reduxjs/toolkit';
import RequestStatus from '../../constants/RequestStatus';
-import * as networkAPI from '../../rest/networkAPI';
import { createParameterSelector } from '../selectorUtil';
import { PropertyType } from '../../constants/equipmentType';
+import { dynamicMappingSrv } from '../../services';
const initialState = {
propertyValues: [],
@@ -52,20 +52,20 @@ export const getCurrentNetworkObj = createSelector(
export const getPropertyValuesFromFile = createAsyncThunk('network/getValuesFromFile', async (file, { getState }) => {
const token = getState()?.user.user?.id_token;
- return await networkAPI.getPropertyValuesFromFile(file, token);
+ return await dynamicMappingSrv.getPropertyValuesFromFile(file, token);
});
export const getPropertyValuesFromNetworkId = createAsyncThunk(
'network/getValuesFromId',
async (networkId, { getState }) => {
const token = getState()?.user.user?.id_token;
- return await networkAPI.getPropertyValuesFromId(networkId, token);
+ return await dynamicMappingSrv.getPropertyValuesFromId(networkId, token);
}
);
export const getNetworkNames = createAsyncThunk('network/getNetworks', async (_args, { getState }) => {
const token = getState()?.user.user?.id_token;
- return await networkAPI.getNetworksName(token);
+ return await dynamicMappingSrv.getNetworksName(token);
});
const reducers = {
diff --git a/src/redux/slices/Theme.js b/src/redux/slices/Theme.js
deleted file mode 100644
index dea1976..0000000
--- a/src/redux/slices/Theme.js
+++ /dev/null
@@ -1,38 +0,0 @@
-/**
- * Copyright (c) 2021, 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 { createSlice } from '@reduxjs/toolkit';
-import { getLocalStorageTheme, saveLocalStorageTheme } from '../local-storage';
-
-export const SELECT_THEME = 'SELECT_THEME';
-export const DARK_THEME = 'Dark';
-export const LIGHT_THEME = 'Light';
-
-export function selectTheme(theme) {
- return { type: SELECT_THEME, theme: theme };
-}
-
-const initialState = getLocalStorageTheme();
-
-// Selectors
-
-// Reducers
-
-const reducers = {
- selectTheme: (state, action) => {
- state = action.payload;
- saveLocalStorageTheme(state.theme);
- },
-};
-
-export const ThemeSlice = createSlice({
- name: 'Theme',
- initialState,
- reducers,
-});
-
-export const ThemeReducer = ThemeSlice.reducer;
diff --git a/src/redux/slices/Theme.ts b/src/redux/slices/Theme.ts
new file mode 100644
index 0000000..1c3f3f0
--- /dev/null
+++ b/src/redux/slices/Theme.ts
@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2021, 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 { Action, createSlice, PayloadAction, SliceCaseReducers } from '@reduxjs/toolkit';
+import { getLocalStorageTheme, GsTheme, saveLocalStorageTheme } from '@gridsuite/commons-ui';
+
+export const SELECT_THEME = 'SELECT_THEME';
+type SelectThemeAction = Action & {
+ theme: GsTheme;
+};
+export function selectTheme(theme: GsTheme) {
+ return { type: SELECT_THEME, theme: theme };
+}
+
+export type ThemeState = {
+ theme: GsTheme;
+};
+
+const initialState: ThemeState = {
+ theme: getLocalStorageTheme(process.env.REACT_APP_NAME!),
+};
+
+// Selectors
+
+// Reducers
+
+const reducers: SliceCaseReducers = {
+ selectTheme: (state, action: PayloadAction) => {
+ state = action.payload;
+ saveLocalStorageTheme(process.env.REACT_APP_NAME!, state.theme);
+ },
+};
+
+export const ThemeSlice = createSlice({
+ name: 'Theme',
+ initialState,
+ reducers,
+});
+
+export const ThemeReducer = ThemeSlice.reducer;
diff --git a/src/redux/slices/User.ts b/src/redux/slices/User.ts
index 9f14e93..32314ee 100644
--- a/src/redux/slices/User.ts
+++ b/src/redux/slices/User.ts
@@ -6,9 +6,10 @@
*/
import { createSlice, PayloadAction, SliceCaseReducers } from '@reduxjs/toolkit';
+import { User } from 'oidc-client';
import {
+ AuthenticationRouterErrorAction,
AuthenticationRouterErrorState,
- CommonStoreState,
LOGOUT_ERROR,
LogoutErrorAction,
RESET_AUTHENTICATION_ROUTER_ERROR,
@@ -23,16 +24,16 @@ import {
UserAction,
UserValidationErrorAction,
} from '@gridsuite/commons-ui';
-import { AuthenticationRouterErrorAction } from '@gridsuite/commons-ui/dist/redux/authActions';
-export type UserState = CommonStoreState & {
+export type UserState = {
+ user: User | undefined;
signInCallbackError: Error | null;
authenticationRouterError: AuthenticationRouterErrorState | null;
showAuthenticationRouterLogin: boolean;
};
const initialState: UserState = {
- user: null,
+ user: undefined,
signInCallbackError: null,
authenticationRouterError: null,
showAuthenticationRouterLogin: false,
diff --git a/src/redux/store.ts b/src/redux/store.ts
index 83f2453..301cd34 100644
--- a/src/redux/store.ts
+++ b/src/redux/store.ts
@@ -5,11 +5,12 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
import { configureStore } from '@reduxjs/toolkit';
-import { setCommonStore } from '@gridsuite/commons-ui';
+import { initCommonServices } from '@gridsuite/commons-ui';
import { reducer } from './reducer';
export const store = configureStore({ reducer });
export type AppDispatch = typeof store.dispatch;
-setCommonStore({
- getState: () => store.getState().user,
-});
+
+export function getUser() {
+ return store.getState().user?.user;
+}
diff --git a/src/rest/mappingsAPI.js b/src/rest/mappingsAPI.js
deleted file mode 100644
index 9773417..0000000
--- a/src/rest/mappingsAPI.js
+++ /dev/null
@@ -1,94 +0,0 @@
-/**
- * Copyright (c) 2021, 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 { backendFetchJson, backendFetchText } from '../utils/rest-api';
-
-const API_URL =
- process.env.REACT_APP_API_PREFIX +
- (process.env.REACT_APP_USE_AUTHENTICATION === 'true'
- ? process.env.REACT_APP_GATEWAY_PREFIX + '/dynamic-mapping'
- : process.env.REACT_APP_URI) +
- '/mappings';
-
-export function postMapping(mappingName, rules, automata, controlledParameters, token) {
- return backendFetchJson(
- `${API_URL}/${mappingName}`,
- {
- method: 'POST',
- headers: {
- Accept: 'application/json',
- 'Content-Type': 'application/json',
- },
- cache: 'default',
- body: JSON.stringify({
- name: mappingName,
- rules,
- automata,
- controlledParameters,
- }),
- },
- token
- );
-}
-
-export function getMappings(token) {
- return backendFetchJson(
- `${API_URL}/`,
- {
- headers: {
- Accept: 'application/json',
- 'Content-Type': 'application/json',
- },
- cache: 'default',
- },
- token
- );
-}
-
-export function deleteMapping(mappingName, token) {
- return backendFetchText(
- `${API_URL}/${mappingName}`,
- {
- method: 'DELETE',
- headers: {
- Accept: 'application/json',
- 'Content-Type': 'application/json',
- },
- cache: 'default',
- },
- token
- );
-}
-
-export async function renameMapping(nameToReplace, newName, token) {
- return backendFetchJson(
- `${API_URL}/rename/${nameToReplace}/to/${newName}`,
- {
- method: 'POST',
- headers: {
- Accept: 'application/json',
- 'Content-Type': 'application/json',
- },
- cache: 'default',
- },
- token
- );
-}
-
-export async function copyMapping(originalName, copyName, token) {
- return backendFetchJson(
- `${API_URL}/copy/${originalName}/to/${copyName}`,
- {
- method: 'POST',
- headers: {
- Accept: 'application/json',
- 'Content-Type': 'application/json',
- },
- cache: 'default',
- },
- token
- );
-}
diff --git a/src/rest/modelsAPI.js b/src/rest/modelsAPI.js
deleted file mode 100644
index 0a60401..0000000
--- a/src/rest/modelsAPI.js
+++ /dev/null
@@ -1,86 +0,0 @@
-/**
- * Copyright (c) 2021, 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 { backendFetchJson } from '../utils/rest-api';
-
-const API_URL =
- process.env.REACT_APP_API_PREFIX +
- (process.env.REACT_APP_USE_AUTHENTICATION === 'true'
- ? process.env.REACT_APP_GATEWAY_PREFIX + '/dynamic-mapping'
- : process.env.REACT_APP_URI) +
- '/models';
-
-export function getModels(token) {
- return backendFetchJson(
- `${API_URL}/`,
- {
- headers: {
- Accept: 'application/json',
- 'Content-Type': 'application/json',
- },
- cache: 'default',
- },
- token
- );
-}
-
-export function getModelDefinitions(modelName, token) {
- return backendFetchJson(
- `${API_URL}/${modelName}/parameters/definitions`,
- {
- headers: {
- Accept: 'application/json',
- 'Content-Type': 'application/json',
- },
- cache: 'default',
- },
- token
- );
-}
-
-export function getModelSets(modelName, groupName, groupType, token) {
- return backendFetchJson(
- `${API_URL}/${modelName}/parameters/sets/${groupName}/${groupType}`,
- {
- headers: {
- Accept: 'application/json',
- 'Content-Type': 'application/json',
- },
- cache: 'default',
- },
- token
- );
-}
-
-export function postModelSetsGroup(setGroup, strict, token) {
- return backendFetchJson(
- `${API_URL}/${setGroup.modelName}/parameters/sets${strict ? '/strict' : ''}`,
- {
- method: 'POST',
- headers: {
- Accept: 'application/json',
- 'Content-Type': 'application/json',
- },
- cache: 'default',
- body: JSON.stringify(setGroup),
- },
- token
- );
-}
-
-export function getAutomatonDefinitions(token) {
- return backendFetchJson(
- `${API_URL}/automaton-definitions`,
- {
- headers: {
- Accept: 'application/json',
- 'Content-Type': 'application/json',
- },
- cache: 'default',
- },
- token
- );
-}
diff --git a/src/rest/networkAPI.js b/src/rest/networkAPI.js
deleted file mode 100644
index 2894f04..0000000
--- a/src/rest/networkAPI.js
+++ /dev/null
@@ -1,76 +0,0 @@
-/**
- * Copyright (c) 2021, 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 { backendFetchJson } from '../utils/rest-api';
-
-const API_URL =
- process.env.REACT_APP_API_PREFIX +
- (process.env.REACT_APP_USE_AUTHENTICATION === 'true'
- ? process.env.REACT_APP_GATEWAY_PREFIX + '/dynamic-mapping'
- : process.env.REACT_APP_URI) +
- '/network';
-
-export function getPropertyValuesFromFile(networkFile, token) {
- const formData = new FormData();
- formData.append('file', networkFile);
-
- return backendFetchJson(
- `${API_URL}/new`,
- {
- method: 'POST',
- headers: {
- Accept: 'application/json',
- },
- cache: 'default',
- body: formData,
- },
- token
- );
-}
-
-export function getPropertyValuesFromId(networkId, token) {
- return backendFetchJson(
- `${API_URL}/${networkId}/values`,
- {
- headers: {
- Accept: 'application/json',
- 'Content-Type': 'application/json',
- },
- cache: 'default',
- },
- token
- );
-}
-
-export function getNetworksName(token) {
- return backendFetchJson(
- `${API_URL}/`,
- {
- headers: {
- Accept: 'application/json',
- 'Content-Type': 'application/json',
- },
- cache: 'default',
- },
- token
- );
-}
-
-export function getNetworkMatchesFromRule(networkId, ruleToMatch, token) {
- return backendFetchJson(
- `${API_URL}/${networkId}/matches/rule`,
- {
- method: 'POST',
- headers: {
- Accept: 'application/json',
- 'Content-Type': 'application/json',
- },
- cache: 'default',
- body: JSON.stringify(ruleToMatch),
- },
- token
- );
-}
diff --git a/src/rest/studyAPI.js b/src/rest/studyAPI.js
deleted file mode 100644
index 9d62af3..0000000
--- a/src/rest/studyAPI.js
+++ /dev/null
@@ -1,30 +0,0 @@
-/**
- * Copyright (c) 2023, 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 { backendFetchJson } from '../utils/rest-api';
-
-const API_URL =
- process.env.REACT_APP_API_PREFIX +
- (process.env.REACT_APP_USE_AUTHENTICATION === 'true'
- ? process.env.REACT_APP_GATEWAY_PREFIX + '/study/v1'
- : process.env.REACT_APP_STUDY_URI + '/v1');
-
-export function getServersInfos(token) {
- return backendFetchJson(
- `${API_URL}/servers/about?view=dyna`,
- {
- headers: {
- Accept: 'application/json',
- 'Content-Type': 'application/json',
- },
- cache: 'default',
- },
- token
- ).catch((reason) => {
- console.error('Error while fetching the servers infos : ' + reason);
- return reason;
- });
-}
diff --git a/src/services/app-local.ts b/src/services/app-local.ts
new file mode 100644
index 0000000..d983687
--- /dev/null
+++ b/src/services/app-local.ts
@@ -0,0 +1,20 @@
+/*
+ * Copyright © 2024, 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 { AppLocalComSvc, Env } from '@gridsuite/commons-ui';
+
+export type EnvJson = Env & typeof import('../../public/env.json');
+
+export default class AppLocalSvc extends AppLocalComSvc {
+ public constructor() {
+ super();
+ }
+
+ public async fetchEnv() {
+ return (await super.fetchEnv()) as EnvJson;
+ }
+}
diff --git a/src/services/dynamic-mapping.ts b/src/services/dynamic-mapping.ts
new file mode 100644
index 0000000..1e27101
--- /dev/null
+++ b/src/services/dynamic-mapping.ts
@@ -0,0 +1,100 @@
+/*
+ * Copyright © 2024, 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 { ApiService } from '@gridsuite/commons-ui';
+import { getUser } from '../redux/store';
+import { UUID } from 'crypto';
+
+export default class DynamicMappingSvc extends ApiService {
+ public constructor() {
+ super(
+ getUser,
+ process.env.REACT_APP_DYNAMAP_SVC,
+ // If you want to use user-admin-server in dev mode you must avoid passing through gateway
+ // and use the user-admin-server directly. SetupProxy should allow this.
+ // @ts-expect-error url type incompatibility
+ process.env.REACT_APP_API_PREFIX
+ );
+ }
+
+ public async postMapping(mappingName: string, rules: unknown, automata: unknown, controlledParameters: boolean) {
+ return this.backendSendFetchJson(
+ `${this.getPrefix(1)}/mappings/${mappingName}`,
+ 'POST',
+ JSON.stringify({
+ name: mappingName,
+ rules,
+ automata,
+ controlledParameters,
+ })
+ );
+ }
+
+ public async getMappings() {
+ return this.backendFetchJson(`${this.getPrefix(1)}/mappings/`);
+ }
+
+ public async deleteMapping(mappingName: string) {
+ return this.backendFetchText(`${this.getPrefix(1)}/mappings/${mappingName}`, 'DELETE');
+ }
+
+ public async renameMapping(nameToReplace: string, newName: string) {
+ return this.backendFetchJson(`${this.getPrefix(1)}/mappings/rename/${nameToReplace}/to/${newName}`, 'POST');
+ }
+
+ public async copyMapping(originalName: string, copyName: string) {
+ return await this.backendFetchJson(`${this.getPrefix(1)}/mappings/copy/${originalName}/to/${copyName}`, 'POST');
+ }
+
+ public async getPropertyValuesFromFile(networkFile: string | Blob) {
+ const formData = new FormData();
+ formData.append('file', networkFile);
+ return this.backendSendFetchJson(`${this.getPrefix(1)}/network/new`, 'POST', formData);
+ }
+
+ public async getPropertyValuesFromId(networkId: UUID) {
+ return this.backendFetchJson(`${this.getPrefix(1)}/network/${networkId}/values`);
+ }
+
+ public async getNetworksName() {
+ return this.backendFetchJson(`${this.getPrefix(1)}/network/`);
+ }
+
+ public async getNetworkMatchesFromRule(networkId: UUID, ruleToMatch: unknown) {
+ return this.backendSendFetchJson(
+ `${this.getPrefix(1)}/network/${networkId}/matches/rule`,
+ 'POST',
+ JSON.stringify(ruleToMatch)
+ );
+ }
+
+ public async getModels() {
+ return this.backendFetchJson(`${this.getPrefix(1)}/models/`);
+ }
+
+ public async getModelDefinitions(modelName: string) {
+ return this.backendFetchJson(`${this.getPrefix(1)}/models/${modelName}/parameters/definitions`);
+ }
+
+ public async getModelSets(modelName: string, groupName: string, groupType: unknown) {
+ return this.backendFetchJson(
+ `${this.getPrefix(1)}/models/${modelName}/parameters/sets/${groupName}/${groupType}`
+ );
+ }
+
+ public async postModelSetsGroup(setGroup: any, strict: boolean) {
+ return this.backendSendFetchJson(
+ `${this.getPrefix(1)}/models/${setGroup.modelName}/parameters/sets${strict ? '/strict' : ''}`,
+ 'POST',
+ JSON.stringify(setGroup)
+ );
+ }
+
+ public async getAutomatonDefinitions() {
+ return this.backendFetchJson(`${this.getPrefix(1)}/models/automaton-definitions`);
+ }
+}
diff --git a/src/services/index.ts b/src/services/index.ts
new file mode 100644
index 0000000..bf79cda
--- /dev/null
+++ b/src/services/index.ts
@@ -0,0 +1,65 @@
+/*
+ * Copyright © 2024, 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 { getUser } from '../redux/store';
+import {
+ AppsMetadataComSvc,
+ ConfigComSvc,
+ ConfigNotificationComSvc,
+ DirectoryComSvc,
+ ExploreComSvc,
+ setCommonServices,
+ StudyComSvc,
+ UserAdminComSvc,
+} from '@gridsuite/commons-ui';
+import AppLocalSvc from './app-local';
+import DynamicMappingSvc from './dynamic-mapping';
+
+export type { EnvJson } from './app-local';
+
+// If you want to use user-admin-server in dev mode you must avoid passing through gateway
+// and use the user-admin-server directly. SetupProxy should allow this.
+
+export const appLocalSrv = new AppLocalSvc(),
+ appsMetadataSrv = new AppsMetadataComSvc(appLocalSrv),
+ configSrv = new ConfigComSvc(
+ process.env.REACT_APP_NAME!,
+ getUser,
+ // @ts-expect-error url type incompatibility
+ process.env.REACT_APP_API_GATEWAY
+ ),
+ configNotificationSrv = new ConfigNotificationComSvc(
+ getUser,
+ // @ts-expect-error url type incompatibility
+ process.env.REACT_APP_WS_GATEWAY
+ ),
+ directorySrv = new DirectoryComSvc(
+ getUser,
+ // @ts-expect-error url type incompatibility
+ process.env.REACT_APP_API_GATEWAY
+ ),
+ // @ts-expect-error url type incompatibility
+ exploreSrv = new ExploreComSvc(getUser, process.env.REACT_APP_API_GATEWAY),
+ // @ts-expect-error url type incompatibility
+ studySrv = new StudyComSvc(getUser, process.env.REACT_APP_API_PREFIX),
+ userAdminSrv = new UserAdminComSvc(
+ getUser,
+ // @ts-expect-error url type incompatibility
+ process.env.REACT_APP_API_GATEWAY
+ ),
+ dynamicMappingSrv = new DynamicMappingSvc();
+
+setCommonServices(
+ appLocalSrv,
+ appsMetadataSrv,
+ configSrv,
+ configNotificationSrv,
+ directorySrv,
+ exploreSrv,
+ studySrv,
+ userAdminSrv
+);
diff --git a/src/setupProxy.js b/src/setupProxy.js
index c757b6b..30d0f94 100644
--- a/src/setupProxy.js
+++ b/src/setupProxy.js
@@ -24,8 +24,8 @@ module.exports = function (app) {
})
);
app.use(
- createProxyMiddleware('http://localhost:5001/api/study-server', {
- pathRewrite: { '^/api/study-server/': '/' },
+ createProxyMiddleware('http://localhost:5001/api/study', {
+ pathRewrite: { '^/api/study/': '/' },
})
);
};
diff --git a/src/utils/composition.js b/src/utils/composition.js
deleted file mode 100644
index 34e0afa..0000000
--- a/src/utils/composition.js
+++ /dev/null
@@ -1,86 +0,0 @@
-/**
- * Copyright (c) 2021, 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 function convertCompositionStringToArray(compositionString) {
- // Transform parentheses into arrays
- const step1 = compositionString
- .split(/([()])/)
- .map((x) => x.trim())
- .join(' ')
- .replace(/\)\s\)/g, '))')
- .replace(/\(/g, '[')
- .replace(/\)\s/g, '], ')
- .replace(/\)/g, ']');
-
- // Wrap whole string in an array
- const step2 = '[' + step1 + ']';
-
- // Replace whitespace separators with commas and escape values
- const step3 = step2
- .replace(/[^[\],\s]+/g, '"$&"')
- .replace(/" /g, '", ')
- .replace(/,[\s]+]/g, ']');
-
- // Parse as a JSON array
- const compositionArray = JSON.parse(step3);
-
- // Wrap Single filters in a group
- return compositionArray.map((element) => {
- if (!Array.isArray(element) && element !== '||' && element !== '&&') {
- return [element];
- }
- return element;
- });
-}
-
-export function convertCompositionArrayToString(compositionArray) {
- const compositionStringArray = compositionArray.map((element) => {
- if (Array.isArray(element)) {
- if (element.length === 1) {
- return element[0];
- } else {
- return `(${convertCompositionArrayToString(element)})`;
- }
- }
- return element;
- });
- return compositionStringArray.join(' ');
-}
-
-export const checkCompositionArrayValidity = (compositionArray, isInner = false) => {
- let arrayOperation;
- return compositionArray
- .map((compositionElement, index) => {
- if (index % 2 === 0) {
- if (Array.isArray(compositionElement)) {
- return checkCompositionArrayValidity(compositionElement, true);
- }
- return /filter\d+\b/.test(compositionElement);
- }
- if (index === 1) {
- arrayOperation = compositionElement;
- }
- return /(&&|\|\|)/.test(compositionElement) && (!isInner || compositionElement === arrayOperation);
- })
- .reduce((acc, element) => acc && element);
-};
-
-export function getMaxDepthParentheses(logicString) {
- let count = 0;
- let maxCount = 0;
- Array.from(logicString).forEach((char) => {
- if (char === '(') {
- count++;
- } else if (char === ')') {
- count--;
- }
- if (count > maxCount) {
- maxCount = count;
- }
- });
- return maxCount;
-}
diff --git a/src/utils/functions.js b/src/utils/functions.ts
similarity index 67%
rename from src/utils/functions.js
rename to src/utils/functions.ts
index 5b6a4a7..90b401f 100644
--- a/src/utils/functions.js
+++ b/src/utils/functions.ts
@@ -5,13 +5,14 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-import _ from 'lodash';
+import { pick } from 'lodash';
-export const mergeSx = (...allSx) => allSx.flat();
+type GetMatcher = (target: T) => Parameters['find']>[0];
+type PickProps = Array;
/**
* Copy properties from corresponding objects in a source array to objects in a target array.
- * It returns the target array that contain modified objects
+ * It returns the target array that contains modified objects
*
* @param targetArray the target array to copy to inside objects
* @param sourceArray the source array from which to copy properties of objects
@@ -19,13 +20,18 @@ export const mergeSx = (...allSx) => allSx.flat();
* @param props properties names to copy, specified individually or in array
* @return the target array
*/
-export const assignArray = (targetArray, sourceArray, matcher, ...props) => {
+export function assignArray(
+ targetArray: T[],
+ sourceArray: T[],
+ matcher: GetMatcher,
+ ...props: PickProps
+) {
targetArray?.forEach((targetObj) => {
const matcherOfTarget = matcher(targetObj);
const sourceObj = sourceArray?.find(matcherOfTarget);
- const pickObj = _.pick(sourceObj, props);
+ const pickObj = pick(sourceObj, props);
Object.assign(targetObj, pickObj);
});
return targetArray;
-};
+}
diff --git a/src/utils/properties.js b/src/utils/properties.js
deleted file mode 100644
index 0f9a140..0000000
--- a/src/utils/properties.js
+++ /dev/null
@@ -1,20 +0,0 @@
-/**
- * Copyright (c) 2021, 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 { EquipmentProperties } from '../constants/equipmentDefinition';
-
-export function getProperty(equipmentType, propertyName) {
- return EquipmentProperties[equipmentType].find((property) => property.name === propertyName);
-}
-
-export function getValuesOption(property) {
- //TODO Intl
- return property?.values?.map((value) => ({
- label: value,
- value,
- }));
-}
diff --git a/src/utils/rest-api.js b/src/utils/rest-api.js
deleted file mode 100644
index 1c367dd..0000000
--- a/src/utils/rest-api.js
+++ /dev/null
@@ -1,135 +0,0 @@
-/**
- * Copyright (c) 2020, 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 { store } from '../redux/store';
-const PREFIX_USER_ADMIN_SERVER_QUERIES =
- process.env.REACT_APP_API_PREFIX + process.env.REACT_APP_GATEWAY_PREFIX + '/user-admin';
-
-// If you want to use user-admin-server in dev mode you must avoid passing through gateway
-// and use the user-admin-server directly. SetupProxy should allow this.
-// const PREFIX_USER_ADMIN_SERVER_QUERIES =
-// process.env.REACT_APP_API_PREFIX +
-// (process.env.REACT_APP_USE_AUTHENTICATION === 'true'
-// ? process.env.REACT_APP_API_GATEWAY + '/user-admin'
-// : process.env.REACT_APP_USER_ADMIN_URI);
-
-function getToken() {
- const state = store.getState();
- return state.user.id_token;
-}
-
-function parseError(text) {
- try {
- return JSON.parse(text);
- } catch (err) {
- return null;
- }
-}
-
-function handleError(response) {
- return response.text().then((text) => {
- const errorName = 'HttpResponseError : ';
- let error;
- const errorJson = parseError(text);
- if (errorJson && errorJson.status && errorJson.error && errorJson.message) {
- error = new Error(
- errorName + errorJson.status + ' ' + errorJson.error + ', message : ' + errorJson.message
- );
- error.status = errorJson.status;
- } else {
- error = new Error(errorName + response.status + ' ' + response.statusText);
- error.status = response.status;
- }
- throw error;
- });
-}
-
-function prepareRequest(init, token) {
- if (!(typeof init == 'undefined' || typeof init == 'object')) {
- throw new TypeError('Argument 2 of backendFetch is not an object' + typeof init);
- }
- const initCopy = Object.assign({}, init);
- initCopy.headers = new Headers(initCopy.headers || {});
- const tokenCopy = token ? token : getToken();
- initCopy.headers.append('Authorization', 'Bearer ' + tokenCopy);
- return initCopy;
-}
-
-function safeFetch(url, initCopy) {
- return fetch(url, initCopy).then((response) => (response.ok ? response : handleError(response)));
-}
-
-export function backendFetch(url, init, token) {
- const initCopy = prepareRequest(init, token);
- return safeFetch(url, initCopy);
-}
-
-export function backendFetchText(url, init, token) {
- const initCopy = prepareRequest(init, token);
- return safeFetch(url, initCopy).then((safeResponse) => safeResponse.text());
-}
-
-export function backendFetchJson(url, init, token) {
- const initCopy = prepareRequest(init, token);
- return safeFetch(url, initCopy).then((safeResponse) => safeResponse.json());
-}
-
-export function fetchValidateUser(user) {
- const sub = user?.profile?.sub;
- if (!sub) {
- return Promise.reject(new Error('Error : Fetching access for missing user.profile.sub : ' + user));
- }
-
- console.info(`Fetching access for user...`);
- const CheckAccessUrl = PREFIX_USER_ADMIN_SERVER_QUERIES + `/v1/users/${sub}`;
- console.debug(CheckAccessUrl);
-
- return backendFetch(
- CheckAccessUrl,
- {
- method: 'head',
- },
- user?.id_token
- )
- .then((response) => {
- //if the response is ok, the responseCode will be either 200 or 204 otherwise it's a Http error and it will be caught
- return response.status === 200;
- })
- .catch((error) => {
- if (error.status === 403) {
- return false;
- } else {
- throw error;
- }
- });
-}
-
-function fetchEnv() {
- return fetch('env.json').then((res) => res.json());
-}
-
-export function fetchIdpSettings() {
- return fetch('idpSettings.json').then((res) => res.json());
-}
-
-export function fetchAppsAndUrls() {
- console.info(`Fetching apps and urls...`);
- return fetchEnv()
- .then((env) => fetch(env.appsMetadataServerUrl + '/apps-metadata.json'))
- .then((response) => response.json());
-}
-
-export function fetchVersion() {
- console.info(`Fetching global metadata...`);
- return fetchEnv()
- .then((env) => fetch(env.appsMetadataServerUrl + '/version.json'))
- .then((response) => response.json())
- .catch((reason) => {
- console.error('Error while fetching the version : ' + reason);
- return reason;
- });
-}