diff --git a/src/components/dialogs/commons/criteria-based/criteria-based-form.js b/src/components/dialogs/commons/criteria-based/criteria-based-form.js
index 5a2fdacc0..731d7a770 100644
--- a/src/components/dialogs/commons/criteria-based/criteria-based-form.js
+++ b/src/components/dialogs/commons/criteria-based/criteria-based-form.js
@@ -42,6 +42,7 @@ const CriteriaBasedForm = ({ equipments, defaultValues }) => {
shouldOpenPopup={openConfirmationPopup}
resetOnConfirmation={handleResetOnConfirmation}
message={'changeTypeMessage'}
+ validateButtonLabel={'button.changeType'}
/>
);
diff --git a/src/components/dialogs/delete-dialog.js b/src/components/dialogs/delete-dialog.js
index 9770e2d1f..58c1c2331 100644
--- a/src/components/dialogs/delete-dialog.js
+++ b/src/components/dialogs/delete-dialog.js
@@ -82,7 +82,6 @@ const DeleteDialog = ({
itemName: (
),
diff --git a/src/components/dialogs/filter/expert/expert-filter-constants.ts b/src/components/dialogs/filter/expert/expert-filter-constants.ts
index 5f13d2ee7..f7c0da1b6 100644
--- a/src/components/dialogs/filter/expert/expert-filter-constants.ts
+++ b/src/components/dialogs/filter/expert/expert-filter-constants.ts
@@ -38,6 +38,10 @@ export const EXPERT_FILTER_EQUIPMENTS = {
id: 'SHUNT_COMPENSATOR',
label: 'ShuntCompensators',
},
+ LINE: {
+ id: 'LINE',
+ label: 'Lines',
+ },
};
export const ENERGY_SOURCE_OPTIONS = [
@@ -292,6 +296,90 @@ export const FIELDS_OPTIONS = {
dataType: DataType.NUMBER,
inputType: 'number',
},
+ CONNECTED_1: {
+ name: FieldType.CONNECTED_1,
+ label: 'terminal1Connected',
+ dataType: DataType.BOOLEAN,
+ valueEditorType: 'switch',
+ },
+ CONNECTED_2: {
+ name: FieldType.CONNECTED_2,
+ label: 'terminal2Connected',
+ dataType: DataType.BOOLEAN,
+ valueEditorType: 'switch',
+ },
+ VOLTAGE_LEVEL_ID_1: {
+ name: FieldType.VOLTAGE_LEVEL_ID_1,
+ label: 'voltageLevelId1',
+ dataType: DataType.STRING,
+ },
+ VOLTAGE_LEVEL_ID_2: {
+ name: FieldType.VOLTAGE_LEVEL_ID_2,
+ label: 'voltageLevelId2',
+ dataType: DataType.STRING,
+ },
+ NOMINAL_VOLTAGE_1: {
+ name: FieldType.NOMINAL_VOLTAGE_1,
+ label: 'nominalVoltage1Or',
+ dataType: DataType.NUMBER,
+ inputType: 'number',
+ },
+ NOMINAL_VOLTAGE_2: {
+ name: FieldType.NOMINAL_VOLTAGE_2,
+ label: 'nominalVoltage2Ex',
+ dataType: DataType.NUMBER,
+ inputType: 'number',
+ },
+ COUNTRY_1: {
+ name: FieldType.COUNTRY_1,
+ label: 'country1',
+ dataType: DataType.ENUM,
+ valueEditorType: 'select',
+ defaultValue: 'AF',
+ },
+ COUNTRY_2: {
+ name: FieldType.COUNTRY_2,
+ label: 'country2',
+ dataType: DataType.ENUM,
+ valueEditorType: 'select',
+ defaultValue: 'AF',
+ },
+ SERIE_RESISTANCE: {
+ name: FieldType.SERIE_RESISTANCE,
+ label: 'seriesResistance',
+ dataType: DataType.NUMBER,
+ inputType: 'number',
+ },
+ SERIE_REACTANCE: {
+ name: FieldType.SERIE_REACTANCE,
+ label: 'seriesReactance',
+ dataType: DataType.NUMBER,
+ inputType: 'number',
+ },
+ SHUNT_CONDUCTANCE_1: {
+ name: FieldType.SHUNT_CONDUCTANCE_1,
+ label: 'shuntConductance1',
+ dataType: DataType.NUMBER,
+ inputType: 'number',
+ },
+ SHUNT_CONDUCTANCE_2: {
+ name: FieldType.SHUNT_CONDUCTANCE_2,
+ label: 'shuntConductance2',
+ dataType: DataType.NUMBER,
+ inputType: 'number',
+ },
+ SHUNT_SUSCEPTANCE_1: {
+ name: FieldType.SHUNT_SUSCEPTANCE_1,
+ label: 'shuntSusceptance1',
+ dataType: DataType.NUMBER,
+ inputType: 'number',
+ },
+ SHUNT_SUSCEPTANCE_2: {
+ name: FieldType.SHUNT_SUSCEPTANCE_2,
+ label: 'shuntSusceptance2',
+ dataType: DataType.NUMBER,
+ inputType: 'number',
+ },
};
export const fields: Record = {
@@ -323,6 +411,7 @@ export const fields: Record = {
FIELDS_OPTIONS.COUNTRY,
FIELDS_OPTIONS.P0,
FIELDS_OPTIONS.Q0,
+ FIELDS_OPTIONS.CONNECTED,
],
SHUNT_COMPENSATOR: [
FIELDS_OPTIONS.ID,
@@ -364,4 +453,22 @@ export const fields: Record = {
FIELDS_OPTIONS.NAME,
FIELDS_OPTIONS.COUNTRY,
],
+ LINE: [
+ FIELDS_OPTIONS.ID,
+ FIELDS_OPTIONS.NAME,
+ FIELDS_OPTIONS.CONNECTED_1,
+ FIELDS_OPTIONS.CONNECTED_2,
+ FIELDS_OPTIONS.VOLTAGE_LEVEL_ID_1,
+ FIELDS_OPTIONS.VOLTAGE_LEVEL_ID_2,
+ FIELDS_OPTIONS.NOMINAL_VOLTAGE_1,
+ FIELDS_OPTIONS.NOMINAL_VOLTAGE_2,
+ FIELDS_OPTIONS.COUNTRY_1,
+ FIELDS_OPTIONS.COUNTRY_2,
+ FIELDS_OPTIONS.SERIE_RESISTANCE,
+ FIELDS_OPTIONS.SERIE_REACTANCE,
+ FIELDS_OPTIONS.SHUNT_CONDUCTANCE_1,
+ FIELDS_OPTIONS.SHUNT_CONDUCTANCE_2,
+ FIELDS_OPTIONS.SHUNT_SUSCEPTANCE_1,
+ FIELDS_OPTIONS.SHUNT_SUSCEPTANCE_2,
+ ],
};
diff --git a/src/components/dialogs/filter/expert/expert-filter-form.tsx b/src/components/dialogs/filter/expert/expert-filter-form.tsx
index 0b4b0cf8b..a99c1fa97 100644
--- a/src/components/dialogs/filter/expert/expert-filter-form.tsx
+++ b/src/components/dialogs/filter/expert/expert-filter-form.tsx
@@ -138,6 +138,7 @@ function ExpertFilterForm() {
shouldOpenPopup={openConfirmationPopup}
resetOnConfirmation={handleResetOnConfirmation}
message={'changeTypeMessage'}
+ validateButtonLabel={'button.changeType'}
/>
{watchEquipmentType &&
diff --git a/src/components/dialogs/filter/expert/expert-filter-utils.ts b/src/components/dialogs/filter/expert/expert-filter-utils.ts
index 383184ca0..b483f7857 100644
--- a/src/components/dialogs/filter/expert/expert-filter-utils.ts
+++ b/src/components/dialogs/filter/expert/expert-filter-utils.ts
@@ -32,10 +32,18 @@ import {
RuleGroupTypeExport,
RuleTypeExport,
} from './expert-filter.type';
+import { microUnitToUnit, unitToMicroUnit } from 'utils/conversion-utils';
type CustomRuleType = RuleType & { dataType: DataType };
type CustomRuleGroupType = RuleGroupType & { dataType: DataType };
+const microUnits = [
+ FieldType.SHUNT_CONDUCTANCE_1,
+ FieldType.SHUNT_CONDUCTANCE_2,
+ FieldType.SHUNT_SUSCEPTANCE_1,
+ FieldType.SHUNT_SUSCEPTANCE_2,
+];
+
const getDataType = (fieldName: string) => {
const field = Object.values(FIELDS_OPTIONS).find(
(field) => field.name === fieldName
@@ -93,6 +101,17 @@ export const getOperators = (fieldName: string, intl: IntlShape) => {
return defaultOperators;
};
+function changeValueUnit(value: any, field: FieldType) {
+ if (microUnits.includes(field)) {
+ if (!Array.isArray(value)) {
+ return microUnitToUnit(value);
+ } else {
+ return value.map((a: number) => microUnitToUnit(a));
+ }
+ }
+ return value;
+}
+
export function exportExpertRules(
query: CustomRuleGroupType
): RuleGroupTypeExport {
@@ -105,9 +124,11 @@ export function exportExpertRules(
)?.customName as OperatorType,
value:
!isValueAnArray && rule.operator !== OperatorType.EXISTS
- ? rule.value
+ ? changeValueUnit(rule.value, rule.field as FieldType)
: undefined,
- values: isValueAnArray ? rule.value : undefined,
+ values: isValueAnArray
+ ? changeValueUnit(rule.value, rule.field as FieldType)
+ : undefined,
dataType: getDataType(rule.field) as DataType,
};
}
@@ -141,12 +162,19 @@ export function importExpertRules(
if (rule.dataType === DataType.NUMBER) {
return rule.values
.map((value) => parseFloat(value as string))
+ .map((numberValue) => {
+ return microUnits.includes(rule.field)
+ ? unitToMicroUnit(numberValue)!
+ : numberValue;
+ })
.sort((a, b) => a - b);
} else {
return rule.values.sort();
}
} else {
- return rule.value;
+ return microUnits.includes(rule.field)
+ ? unitToMicroUnit(parseFloat(rule.value as string))
+ : rule.value;
}
}
diff --git a/src/components/dialogs/filter/expert/expert-filter.type.ts b/src/components/dialogs/filter/expert/expert-filter.type.ts
index 932727386..4eb4d4502 100644
--- a/src/components/dialogs/filter/expert/expert-filter.type.ts
+++ b/src/components/dialogs/filter/expert/expert-filter.type.ts
@@ -56,6 +56,20 @@ export enum FieldType {
SWITCHED_ON_Q_AT_NOMINAL_V = 'SWITCHED_ON_Q_AT_NOMINAL_V',
MAX_SUSCEPTANCE = 'MAX_SUSCEPTANCE',
SWITCHED_ON_SUSCEPTANCE = 'SWITCHED_ON_SUSCEPTANCE',
+ CONNECTED_1 = 'CONNECTED_1',
+ CONNECTED_2 = 'CONNECTED_2',
+ VOLTAGE_LEVEL_ID_1 = 'VOLTAGE_LEVEL_ID_1',
+ VOLTAGE_LEVEL_ID_2 = 'VOLTAGE_LEVEL_ID_2',
+ NOMINAL_VOLTAGE_1 = 'NOMINAL_VOLTAGE_1',
+ NOMINAL_VOLTAGE_2 = 'NOMINAL_VOLTAGE_2',
+ COUNTRY_1 = 'COUNTRY_1',
+ COUNTRY_2 = 'COUNTRY_2',
+ SERIE_RESISTANCE = 'SERIE_RESISTANCE',
+ SERIE_REACTANCE = 'SERIE_REACTANCE',
+ SHUNT_CONDUCTANCE_1 = 'SHUNT_CONDUCTANCE_1',
+ SHUNT_CONDUCTANCE_2 = 'SHUNT_CONDUCTANCE_2',
+ SHUNT_SUSCEPTANCE_1 = 'SHUNT_SUSCEPTANCE_1',
+ SHUNT_SUSCEPTANCE_2 = 'SHUNT_SUSCEPTANCE_2',
}
export enum DataType {
diff --git a/src/components/dialogs/filter/explicit-naming/explicit-naming-filter-form.tsx b/src/components/dialogs/filter/explicit-naming/explicit-naming-filter-form.tsx
index 4eb18a3cb..92cab306a 100644
--- a/src/components/dialogs/filter/explicit-naming/explicit-naming-filter-form.tsx
+++ b/src/components/dialogs/filter/explicit-naming/explicit-naming-filter-form.tsx
@@ -185,6 +185,7 @@ function ExplicitNamingFilterForm() {
shouldOpenPopup={openConfirmationPopup}
resetOnConfirmation={handleResetOnConfirmation}
message={'changeTypeMessage'}
+ validateButtonLabel={'button.changeType'}
/>
{watchEquipmentType && (
diff --git a/src/components/dialogs/replace-with-script-dialog.js b/src/components/dialogs/replace-with-script-dialog.js
index 251c3dbd4..04d7ae6a4 100644
--- a/src/components/dialogs/replace-with-script-dialog.js
+++ b/src/components/dialogs/replace-with-script-dialog.js
@@ -51,7 +51,7 @@ const ReplaceWithScriptDialog = ({ id, open, onClose, onClick, title }) => {
diff --git a/src/components/utils/popup-confirmation-dialog.js b/src/components/utils/popup-confirmation-dialog.js
index b97ca56de..238321972 100644
--- a/src/components/utils/popup-confirmation-dialog.js
+++ b/src/components/utils/popup-confirmation-dialog.js
@@ -17,6 +17,7 @@ import { CancelButton } from '@gridsuite/commons-ui';
const PopupConfirmationDialog = ({
message,
+ validateButtonLabel,
openConfirmationPopup,
setOpenConfirmationPopup,
handlePopupConfirmation,
@@ -37,11 +38,15 @@ const PopupConfirmationDialog = ({
setOpenConfirmationPopup(false)} />
);
};
+PopupConfirmationDialog.defaultProps = {
+ validateButtonLabel: undefined,
+};
+
export default PopupConfirmationDialog;
diff --git a/src/components/utils/rhf-inputs/select-inputs/input-with-popup-confirmation.js b/src/components/utils/rhf-inputs/select-inputs/input-with-popup-confirmation.js
index 7dd3b20ab..904d88bcb 100644
--- a/src/components/utils/rhf-inputs/select-inputs/input-with-popup-confirmation.js
+++ b/src/components/utils/rhf-inputs/select-inputs/input-with-popup-confirmation.js
@@ -8,6 +8,7 @@ const InputWithPopupConfirmation = ({
shouldOpenPopup, // condition to open popup confirmation
resetOnConfirmation, // function to reset values in your form on confirmation,
message,
+ validateButtonLabel,
...props
}) => {
const [newValue, setNewValue] = useState(null);
@@ -47,9 +48,14 @@ const InputWithPopupConfirmation = ({
openConfirmationPopup={openPopup}
setOpenConfirmationPopup={setOpenPopup}
handlePopupConfirmation={handlePopupConfirmation}
+ validateButtonLabel={validateButtonLabel}
/>
>
);
};
+InputWithPopupConfirmation.defaultProps = {
+ validateButtonLabel: undefined,
+};
+
export default InputWithPopupConfirmation;
diff --git a/src/components/utils/rqb-inputs/combinator-selector.tsx b/src/components/utils/rqb-inputs/combinator-selector.tsx
index 742a819d9..999a361c6 100644
--- a/src/components/utils/rqb-inputs/combinator-selector.tsx
+++ b/src/components/utils/rqb-inputs/combinator-selector.tsx
@@ -23,6 +23,7 @@ const CombinatorSelector = (props: CombinatorSelectorProps) => {
<>
{
// No value needed for this operator
return null;
}
- if (props.field === FieldType.COUNTRY) {
+ if (
+ [FieldType.COUNTRY, FieldType.COUNTRY_1, FieldType.COUNTRY_2].includes(
+ props.field as FieldType
+ )
+ ) {
return ;
}
if (
diff --git a/src/translations/en.json b/src/translations/en.json
index 58801b614..0fa372bad 100644
--- a/src/translations/en.json
+++ b/src/translations/en.json
@@ -1,4 +1,7 @@
{
+ "button.replace": "Replace",
+ "button.changeType": "Change",
+ "button.changeOperator": "Change",
"close": "Close",
"parameters": "Parameters",
"paramsChangingError": "An error occured when changing the parameters",
@@ -63,11 +66,11 @@
"confirmDirectoryDialog": "Confirm",
"insertNewDirectoryDialogTitle": "Create folder",
"insertNewRootDirectoryDialogTitle": "Create root folder",
- "deleteDirectoryDialogMessage": "Are you sure you want to delete the {itemName} folder and the items it contains ?",
- "deleteMultipleDirectoriesDialogMessage": "Are you sure you want to delete those {itemsCount} folders and the items they contains ?",
- "deleteItemDialogMessage": "Are you sure you want to delete {itemName} ?",
- "deleteMultipleItemsDialogMessage": "Are you sure you want to delete those {itemsCount} items ?",
- "deleteItemDialogTitle": "Delete {itemName}",
+ "deleteDirectoryDialogMessage": "The {itemName} folder and the items it contains will be deleted.",
+ "deleteMultipleDirectoriesDialogMessage": "{itemsCount} folders and the items they contain will be deleted.",
+ "deleteItemDialogMessage": "{itemName} will be deleted.",
+ "deleteMultipleItemsDialogMessage": "{itemsCount} items will be deleted.",
+ "deleteItemDialogTitle": "Delete\u00a0{itemName}",
"deleteMultipleItemsDialogTitle": "Delete {itemsCount} items",
"renameDirectoryDialogTitle": "Rename the folder",
"accessRights": "Access rights",
@@ -110,7 +113,7 @@
"equipmentID": "Equipment ID",
"equipments": "Equipments",
"nominalVoltage": "Nominal voltage",
- "alertBeforeReplaceWithScript": "Do you really want to replace this list with a Groovy script ?{br}{br}This action cannot be reversed",
+ "alertBeforeReplaceWithScript": "This list will be replaced by a Groovy script.{br}This action is irreversible.",
"replaceList": "Replace list",
"copyToScriptList": "Copy to script",
"copyToScript": "Copy to script",
@@ -153,6 +156,20 @@
"nominalVoltage1": "Nominal Voltage 1",
"nominalVoltage2": "Nominal Voltage 2",
"nominalVoltage3": "Nominal Voltage 3",
+ "nominalVoltage1Or": "Nominal Voltage 1",
+ "nominalVoltage2Ex": "Nominal Voltage 2",
+ "voltageLevelId1": "Voltage level ID 1",
+ "voltageLevelId2": "Voltage level ID 2",
+ "terminal1Connected": "Connected 1",
+ "terminal2Connected": "Connected 2",
+ "country1": "Country 1",
+ "country2": "Country 2",
+ "seriesResistance": "Series resistance (Ω)",
+ "seriesReactance": "Series reactance (Ω)",
+ "shuntConductance1": "Shunt conductance 1 (μS)",
+ "shuntSusceptance1": "Shunt susceptance 1 (μS)",
+ "shuntConductance2": "Shunt conductance 2 (μS)",
+ "shuntSusceptance2": "Shunt susceptance 2 (μS)",
"cannotRetrieveContingencyList": "Could not retrieve contingency list: ",
"cannotRetrieveFilter": "Could not retrieve filter: ",
"FreePropsCrit": "By properties filtering",
@@ -186,8 +203,8 @@
"serverConnectionFailed": "Failed to connect to server. Please retry later.",
"invalidFormatOrName": "Imported file name or format invalid",
"parameterLoadingProblem": "problem of loading parameters",
- "changeOperatorMessage": "Do you want to change the operator? The new operator will be applied to all the rules already created in the group.",
- "changeTypeMessage": "Do you want to change the type? Previous configuration will be erased",
+ "changeOperatorMessage": "The operator will be changed and will be applied to all the rules already created in the group.",
+ "changeTypeMessage": "The type will be changed and previous configuration will be erased.",
"keepCSVDataMessage": "Do you want to replace or add the new data to the current list ?",
"add": "Add",
"replace": "Replace",
diff --git a/src/translations/fr.json b/src/translations/fr.json
index c83ad4f28..d4bb2d736 100644
--- a/src/translations/fr.json
+++ b/src/translations/fr.json
@@ -1,4 +1,7 @@
{
+ "button.replace": "Remplacer",
+ "button.changeType": "Modifier",
+ "button.changeOperator": "Modifier",
"close": "Fermer",
"parameters": "Paramètres",
"paramsChangingError": "Une erreur est survenue lors de la modification des paramètres",
@@ -63,11 +66,11 @@
"renameFolder": "Renommer",
"insertNewDirectoryDialogTitle": "Créer un dossier",
"insertNewRootDirectoryDialogTitle": "Créer un dossier racine",
- "deleteDirectoryDialogMessage": "Êtes-vous sûr(e) de vouloir supprimer le dossier {itemName} ainsi que les éléments qu'il contient ?",
- "deleteMultipleDirectoriesDialogMessage": "Êtes-vous sûr(e) de vouloir supprimer ces dossiers ainsi que les éléments qu'ils contiennent ?",
- "deleteItemDialogMessage": "Êtes-vous sûr(e) de vouloir supprimer {itemName} ?",
- "deleteMultipleItemsDialogMessage": "Êtes-vous sûr(e) de vouloir supprimer ces {itemsCount} éléments ?",
- "deleteItemDialogTitle": "Supprimer {itemName}",
+ "deleteDirectoryDialogMessage": "Le dossier {itemName} ainsi que les éléments qu'il contient va être supprimé.",
+ "deleteMultipleDirectoriesDialogMessage": "{itemsCount} dossiers ainsi que les éléments qu'ils contiennent vont être supprimés.",
+ "deleteItemDialogMessage": "{itemName} va être supprimé.",
+ "deleteMultipleItemsDialogMessage": "{itemsCount} éléments vont être supprimés.",
+ "deleteItemDialogTitle": "Supprimer\u00a0{itemName}",
"deleteMultipleItemsDialogTitle": "Supprimer {itemsCount} éléments",
"renameDirectoryDialogTitle": "Renommer le dossier",
"accessRights": "Droits d'accès",
@@ -110,7 +113,7 @@
"equipmentID": "ID d'ouvrage",
"equipments": "Ouvrages",
"nominalVoltage": "Tension nominale",
- "alertBeforeReplaceWithScript": "Voulez-vous vraiment remplacer cette liste par un script Groovy ?{br}{br}Cette action est irréversible",
+ "alertBeforeReplaceWithScript": "Cette liste sera remplacée par un script Groovy.{br}Cette action est irréversible.",
"replaceList": "Remplacer la liste",
"copyToScriptList": "Copier vers script",
"copyToScript": "Copier dans un script",
@@ -153,6 +156,20 @@
"nominalVoltage1": "Tension nominale 1",
"nominalVoltage2": "Tension nominale 2",
"nominalVoltage3": "Tension nominale 3",
+ "nominalVoltage1Or": "Tension nominale Or",
+ "nominalVoltage2Ex": "Tension nominale Ex",
+ "voltageLevelId1": "ID Poste Or",
+ "voltageLevelId2": "ID Poste Ex",
+ "terminal1Connected": "Connecté Or",
+ "terminal2Connected": "Connecté Ex",
+ "country1": "Pays Or",
+ "country2": "Pays Ex",
+ "seriesResistance": "Résistance série (Ω)",
+ "seriesReactance": "Réactance série (Ω)",
+ "shuntConductance1": "Conductance parallèle Or (μS)",
+ "shuntSusceptance1": "Susceptance parallèle Or (μS)",
+ "shuntConductance2": "Conductance parallèle Ex (μS)",
+ "shuntSusceptance2": "Susceptance parallèle Ex (μS)",
"cannotRetrieveContingencyList": "Erreur d'accès à la liste d'aléas : ",
"cannotRetrieveFilter": "Erreur d'accès au filtre : ",
"FreePropsCrit": "Filtrage par propriétés",
@@ -186,8 +203,8 @@
"serverConnectionFailed": "Échec de connexion avec le serveur. Veuillez réessayer ultérieurement",
"invalidFormatOrName": "Format ou nom du fichier importé non valide",
"parameterLoadingProblem": "Problème de chargement des paramètres",
- "changeOperatorMessage": "Voulez-vous changer l'opérateur ? Le nouvel opérateur s'appliquera sur toutes les règles déjà créées dans le groupe.",
- "changeTypeMessage": "Voulez-vous changer le type ? La précédente configuration sera perdue",
+ "changeOperatorMessage": "L'opérateur sera modifié et s'appliquera sur toutes les règles déjà créées dans le groupe.",
+ "changeTypeMessage": "Le type sera modifié et la précédente configuration sera perdue.",
"keepCSVDataMessage": "Voulez-vous remplacer la liste existante ou y ajouter les nouvelles données ?",
"add": "Ajouter",
"replace": "Remplacer",
diff --git a/src/utils/conversion-utils.ts b/src/utils/conversion-utils.ts
new file mode 100644
index 000000000..cb23fb97c
--- /dev/null
+++ b/src/utils/conversion-utils.ts
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 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/.
+ */
+
+export const GRIDSUITE_DEFAULT_PRECISION: number = 13;
+
+export const roundToPrecision = (num: number, precision: number) =>
+ Number(num.toPrecision(precision));
+
+export const roundToDefaultPrecision = (num: number) =>
+ roundToPrecision(num, GRIDSUITE_DEFAULT_PRECISION);
+
+export function isBlankOrEmpty(value: unknown) {
+ if (value === undefined || value === null) {
+ return true;
+ }
+ if (typeof value === 'string') {
+ return /^\s*$/.test(value);
+ }
+ return false;
+}
+
+export const unitToMicroUnit = (num: number) =>
+ isBlankOrEmpty(num) ? undefined : roundToDefaultPrecision(num * 1e6);
+
+export const microUnitToUnit = (num: number) =>
+ isBlankOrEmpty(num) ? undefined : roundToDefaultPrecision(num / 1e6);