Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Visualize composite modifications #538

Merged
merged 26 commits into from
Nov 13, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
208daf7
visualize
Mathieu-Deharbe Oct 8, 2024
79600b0
better css list and scroll system
Mathieu-Deharbe Oct 9, 2024
0f08acd
better display of the network modification label
Mathieu-Deharbe Oct 9, 2024
75e8df4
respect spaces and strong anchors
Mathieu-Deharbe Oct 9, 2024
86831c6
correct localisation imports
Mathieu-Deharbe Oct 10, 2024
5cca28c
Merge branch 'main' into visualize-composite-modifications
Mathieu-Deharbe Oct 21, 2024
8be793a
post conflict solving in commons-ui
Mathieu-Deharbe Oct 21, 2024
0982dfa
Merge branch 'main' into visualize-composite-modifications
Mathieu-Deharbe Oct 24, 2024
19b39f1
post auto review
Mathieu-Deharbe Oct 24, 2024
a3b92e0
allows to change composite modification name
Mathieu-Deharbe Oct 24, 2024
00b9ff9
change url
Mathieu-Deharbe Oct 24, 2024
62703c9
prettier
Mathieu-Deharbe Oct 24, 2024
9a373bc
Merge branch 'main' into visualize-composite-modifications
Mathieu-Deharbe Oct 30, 2024
e212512
adapt to the new eslint standard
Mathieu-Deharbe Oct 30, 2024
dd6c719
corrections post Ghazwa review
Mathieu-Deharbe Oct 30, 2024
14107da
some renaming
Mathieu-Deharbe Oct 30, 2024
f263799
Merge branch 'main' into visualize-composite-modifications
Mathieu-Deharbe Oct 31, 2024
ab6cad7
handle null case
Mathieu-Deharbe Oct 31, 2024
68d5494
better test syntax
Mathieu-Deharbe Oct 31, 2024
ca1f475
Merge branch 'main' into visualize-composite-modifications
Mathieu-Deharbe Oct 31, 2024
618d372
updated endpoint
Mathieu-Deharbe Oct 31, 2024
0e06eeb
corrects getModificationLabel
Mathieu-Deharbe Oct 31, 2024
2ae94b8
Merge branch 'main' into visualize-composite-modifications
Mathieu-Deharbe Nov 6, 2024
cd382e5
revert MODIFICATION localization
Mathieu-Deharbe Nov 6, 2024
3a62a60
Merge branch 'main' into visualize-composite-modifications
Mathieu-Deharbe Nov 12, 2024
068a7c1
Merge branch 'main' into visualize-composite-modifications
Mathieu-Deharbe Nov 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/components/app-wrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ import {
LIGHT_THEME,
loginEn,
loginFr,
networkModificationsLocaleEn,
networkModificationsLocaleFr,
multipleSelectionDialogEn,
multipleSelectionDialogFr,
SnackbarProvider,
Expand All @@ -53,8 +55,6 @@ import { BrowserRouter } from 'react-router-dom';
import { Provider, useSelector } from 'react-redux';
import messages_en from '../translations/en.json';
import messages_fr from '../translations/fr.json';
import network_modification_locale_en from '../translations/dynamic/network-modifications-locale-en';
import network_modification_locale_fr from '../translations/dynamic/network-modifications-locale-fr';
import messages_plugins from '../plugins/translations';
import aggrid_locale_fr from '../translations/external/aggrid-locale-fr';
import backend_locale_fr from '../translations/external/backend-locale-fr';
Expand Down Expand Up @@ -185,7 +185,7 @@ function getMuiTheme(theme: GsTheme, locale: GsLangUser) {
const messages: Record<GsLangUser, IntlConfig['messages']> = {
en: {
...messages_en,
...network_modification_locale_en,
...networkModificationsLocaleEn,
...loginEn,
...topBarEn,
...tableEn,
Expand All @@ -207,7 +207,7 @@ const messages: Record<GsLangUser, IntlConfig['messages']> = {
},
fr: {
...messages_fr,
...network_modification_locale_fr,
...networkModificationsLocaleFr,
...loginFr,
...topBarFr,
...tableFr,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
/**
* 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/.
*/
import { FunctionComponent, SyntheticEvent, useEffect, useState } from 'react';
import { useParameterState } from '../../use-parameters-dialog';
import { PARAM_LANGUAGE } from '../../../../utils/config-params';
import {
CustomMuiDialog,
FieldConstants,
NetworkModificationMetadata,
NO_SELECTION_FOR_COPY,
unscrollableDialogStyles,
useModificationLabelComputer,
useSnackMessage,
yupConfig as yup,
} from '@gridsuite/commons-ui';
import { useForm } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers/yup';
import { getCompositeModificationContent, saveCompositeModification } from '../../../../utils/rest-api';
import CompositeModificationEditionForm from './composite-modification-edition-form';
import { List, ListItem } from '@mui/material';
import { useIntl } from 'react-intl';
import Divider from '@mui/material/Divider';
import Box from '@mui/material/Box';
import { setSelectionForCopy } from '../../../../redux/actions';
import { useDispatch, useSelector } from 'react-redux';
import { AppState } from '../../../../redux/reducer';

const schema = yup.object().shape({
[FieldConstants.NAME]: yup.string().trim().required('nameEmpty'),
});

const emptyFormData = (name?: string) => ({
[FieldConstants.NAME]: name,
});

interface FormData {
[FieldConstants.NAME]: string;
}

interface CompositeModificationEditionDialogProps {
compositeModificationId: string;
open: boolean;
onClose: (event?: SyntheticEvent) => void;
titleId: string;
name: string;
broadcastChannel: BroadcastChannel;
}

export const CompositeModificationEditionDialog: FunctionComponent<CompositeModificationEditionDialogProps> = ({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only Edition ? it could be just CompositeModificationDialog

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. It should be enough, at least for now. And I am tired of those huge names.

compositeModificationId,
open,
onClose,
titleId,
name,
broadcastChannel,
}: Readonly<CompositeModificationEditionDialogProps>) => {
const intl = useIntl();
const [languageLocal] = useParameterState(PARAM_LANGUAGE);
const [isFetching, setIsFetching] = useState(!!compositeModificationId);
const { snackError } = useSnackMessage();
const selectionForCopy = useSelector((state: AppState) => state.selectionForCopy);
const [modifications, setModifications] = useState<NetworkModificationMetadata[]>([]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useState<NetworkCompositeModificationMetadata[]>([]);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually no : those are the "metadata" from regular network modifications, not from composite network modification.

const dispatch = useDispatch();

const methods = useForm<FormData>({
defaultValues: emptyFormData(name),
resolver: yupResolver(schema),
});

const { computeLabel } = useModificationLabelComputer();
const getModificationLabel = (modif: NetworkModificationMetadata) => {
if (!modif) {
return null;
}
return intl.formatMessage(
{ id: 'network_modifications.' + modif.type },
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

network_modifications.${modif.type}

Copy link
Contributor Author

@Mathieu-Deharbe Mathieu-Deharbe Oct 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes done. eslint is forcing me to do it now anyway !

{
...modif,
...computeLabel(modif),
}
);
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const labelData = {
        ...modif,
        ...computeLabel(modif),
    };

    return intl.formatMessage(
        { id: `network_modifications.${modif.type}` },
        labelData
    );
    };


const renderNetworkModificationsList = () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

render.. could be improved, it doesn't clearly convey what the function does
maybe (generate or create)NetworkModificationsList or something else

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just a copy paste. Maybe the original author used "render" because it contains jsx anchor code ?
Anyway I prefer generate so ok.

return (
<>
{modifications && (
<List sx={unscrollableDialogStyles.scrollableContent}>
{modifications.map((modification: NetworkModificationMetadata) => (
<>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are missing keys.
<React.Fragment key={imodification.uuid}> ?
And remove it from ListItem ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and then you have to remove the key from the ListItem as the React.Fragment managing the key

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, done.

<ListItem key={modification.uuid}>
<Box>{getModificationLabel(modification)}</Box>
</ListItem>
<Divider component="li" />
</>
))}
</List>
)}
</>
);
};

useEffect(() => {
setIsFetching(true);
getCompositeModificationContent(compositeModificationId)
.then((response) => {
if (response) {
setModifications(response);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setCompositeModifications(response);
don't forget to update the [modifications, setModifications] = useState
modifications is too generic

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can change this to setNetworkModifications if you want, but those are not composite modifications.

}
})
.catch((error) => {
snackError({
messageTxt: error.message,
headerId: 'cannotRetrieveCompositeModification',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RetrieveCompositeModificationError ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK done.

});
})
.finally(() => setIsFetching(false));
}, [compositeModificationId, name, snackError]);

const closeAndClear = (event?: SyntheticEvent) => {
onClose(event);
};

const onSubmit = (formData: FormData) => {
saveCompositeModification(compositeModificationId, formData[FieldConstants.NAME])
.then(() => {
if (selectionForCopy.sourceItemUuid === compositeModificationId) {
dispatch(setSelectionForCopy(NO_SELECTION_FOR_COPY));
broadcastChannel.postMessage({
NO_SELECTION_FOR_COPY,
});
}
closeAndClear();
})
.catch((errorMessage) => {
snackError({
messageTxt: errorMessage,
headerId: 'contingencyListEditingError',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

contingencyListEditingError ?
it is copy paste forgetten

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops ! Well seen thank you. Done.

headerValues: { name },
});
});
};

return (
<CustomMuiDialog
open={open}
onClose={closeAndClear}
titleId={titleId}
onSave={onSubmit}
removeOptional={true}
isDataFetching={isFetching}
language={languageLocal}
formSchema={schema}
formMethods={methods}
unscrollableFullHeight
>
{!isFetching && (
<Box sx={unscrollableDialogStyles.unscrollableContainer}>
<CompositeModificationEditionForm />
{renderNetworkModificationsList()}
</Box>
)}
</CustomMuiDialog>
);
};
Mathieu-Deharbe marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* 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/.
*/

import { UniqueNameInput, ElementType, FieldConstants } from '@gridsuite/commons-ui';
import { elementExists } from 'utils/rest-api';
import { useSelector } from 'react-redux';
import { AppState } from 'redux/reducer';
import Box from '@mui/material/Box';

const CompositeModificationEditionForm = () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CompositeModificationForm ?

const activeDirectory = useSelector((state: AppState) => state.activeDirectory);
return (
<Box>
<UniqueNameInput
name={FieldConstants.NAME}
label={'nameProperty'}
elementType={ElementType.MODIFICATION}
activeDirectory={activeDirectory}
elementExists={elementExists}
/>
</Box>
);
};

export default CompositeModificationEditionForm;
29 changes: 28 additions & 1 deletion src/components/directory-content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { FormattedMessage, useIntl } from 'react-intl';
import * as constants from '../utils/UIconstants';
import CircularProgress from '@mui/material/CircularProgress';

import { ContingencyListType, FilterType } from '../utils/elementType';
import { ContingencyListType, FilterType, NetworkModificationType } from '../utils/elementType';
import {
CriteriaBasedFilterEditionDialog,
DescriptionModificationDialog,
Expand Down Expand Up @@ -54,6 +54,7 @@ import AddIcon from '@mui/icons-material/Add';
import { AppState } from '../redux/reducer';
import { AgGridReact } from 'ag-grid-react';
import { SelectionForCopy } from '@gridsuite/commons-ui/dist/components/filter/filter.type';
import CompositeModificationEditionDialog from './dialogs/network-modification/composite-modification/composite-modification-edition-dialog';

const circularProgressSize = '70px';

Expand Down Expand Up @@ -209,6 +210,14 @@ const DirectoryContent = () => {
};
const [currentExplicitNamingFilterId, setCurrentExplicitNamingFilterId] = useState(null);

const handleCloseCompositeModificationDialog = () => {
setOpenDialog(constants.DialogsId.NONE);
setCurrentNetworkModificationId(null);
setActiveElement(null);
setElementName('');
};
const [currentNetworkModificationId, setCurrentNetworkModificationId] = useState(null);

/**
* Filters dialog: window status value to edit Expert filters
*/
Expand Down Expand Up @@ -392,6 +401,12 @@ const DirectoryContent = () => {
setOpenDialog(subtype);
}
break;
case ElementType.MODIFICATION:
if (subtype === NetworkModificationType.COMPOSITE.id) {
setCurrentNetworkModificationId(event.data.elementUuid);
setOpenDialog(subtype);
}
break;
default:
break;
}
Expand Down Expand Up @@ -529,6 +544,18 @@ const DirectoryContent = () => {
// TODO openDialog should also be aware of the dialog's type, not only its subtype, because
// if/when two different dialogs have the same subtype, this function will display the wrong dialog.
switch (openDialog) {
case NetworkModificationType.COMPOSITE.id:
return (
<CompositeModificationEditionDialog
open={true}
titleId={'compositeModification'}
// @ts-expect-error TODO: manage null case(s) here
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in a very simple and straightforward way. If it ever happens it will cause a regular error during the fetch.

I didn't change the other TODOs on the same subject that are in the same switch.

compositeModificationId={currentNetworkModificationId}
onClose={handleCloseCompositeModificationDialog}
name={name}
broadcastChannel={broadcastChannel}
/>
);
case ContingencyListType.CRITERIA_BASED.id:
return (
<CriteriaBasedEditionDialog
Expand Down
45 changes: 0 additions & 45 deletions src/translations/dynamic/network-modifications-locale-en.ts

This file was deleted.

45 changes: 0 additions & 45 deletions src/translations/dynamic/network-modifications-locale-fr.ts

This file was deleted.

Loading
Loading