Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
74c351f
draft get /profiles ok
dbraquart Mar 21, 2024
4b8af24
add/remove profile ok, update with pbs
dbraquart Mar 24, 2024
0ff936d
set/reset profile to user
dbraquart Mar 24, 2024
69d2ab5
add validity column
dbraquart Mar 25, 2024
6c16bd8
Merge remote-tracking branch 'origin/main' into dbraquart/add-user-pr…
dbraquart Mar 25, 2024
8af82cf
add validity in form
dbraquart Mar 25, 2024
aacbb37
sounds ok
dbraquart Mar 26, 2024
1d10392
move some files
dbraquart Mar 26, 2024
c0f0db9
clean code
dbraquart Mar 26, 2024
8b3f798
change parameters translations
dbraquart Mar 27, 2024
a3ec558
dont use potentially xtra long message in snackbar
dbraquart Mar 27, 2024
60b7501
add scrollbar for profiles select
dbraquart Mar 27, 2024
57e9261
validity renderer with images
dbraquart Mar 27, 2024
c0af5ab
use tsx for profile-modification
dbraquart Mar 28, 2024
26d940e
fix typo
dbraquart Mar 28, 2024
83134d4
rev remark: rename validity into allParametersLinksValid
dbraquart Apr 2, 2024
0219e7d
rev remark: avoid getPath called twice (unmount ProfileModificationForm)
dbraquart Apr 2, 2024
f3ace58
Merge commit 'c23d298e24f59f9a76dcddd7f2dc9226fb422d5e' into dbraquar…
dbraquart Apr 3, 2024
439d3af
use ElementType from commons-ui after merge
dbraquart Apr 3, 2024
6ce6d50
Merge remote-tracking branch 'origin/main' into dbraquart/add-user-pr…
dbraquart Apr 5, 2024
f2402b5
update after merge
dbraquart Apr 5, 2024
732ba9f
rev remarks: minor changes
dbraquart Apr 5, 2024
e07438a
rev remarks: use mui icons rather than png
dbraquart Apr 5, 2024
dda8869
rev remarks: change post/put on /profiles
dbraquart Apr 8, 2024
8d2aabe
PO remarks: use RadioButtonUnchecked
dbraquart Apr 8, 2024
6a02b50
rm warnings
dbraquart Apr 8, 2024
0a63c60
rev remarks: minor changes
dbraquart Apr 12, 2024
4f4f7fd
rev remarks: create ParameterDisplay
dbraquart Apr 12, 2024
87faaaa
rev remarks: add ProfilesTable
dbraquart Apr 15, 2024
be9bcd6
rev remarks: add ProfileDialog
dbraquart Apr 15, 2024
f6ab5c6
create common/PaperForm
dbraquart Apr 15, 2024
55a8d4b
add missing catch+snackbar
dbraquart Apr 16, 2024
8e1cebd
rev remarks: move and rename
dbraquart Apr 16, 2024
b46e64b
add fetchProfilesWithoutValidityCheck
dbraquart Apr 17, 2024
2aec306
rev remarks: use 422 error in case of integrity violation
dbraquart Apr 17, 2024
7583960
rev remarks: minor remarks, renaming, etc
dbraquart Apr 17, 2024
db9da66
rev remarks: last change
dbraquart Apr 17, 2024
d6b8eac
clean code
dbraquart Apr 17, 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
16 changes: 15 additions & 1 deletion src/components/App/app-top-bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
useState,
} from 'react';
import { capitalize, Tab, Tabs, useTheme } from '@mui/material';
import { PeopleAlt } from '@mui/icons-material';
import { ManageAccounts, PeopleAlt } from '@mui/icons-material';
import { logout, TopBar } from '@gridsuite/commons-ui';
import { useParameterState } from '../parameters';
import {
Expand Down Expand Up @@ -47,6 +47,20 @@ const tabs = new Map<MainPaths, ReactElement>([
))}
/>,
],
[
MainPaths.profiles,
<Tab
icon={<ManageAccounts />}
label={<FormattedMessage id="appBar.tabs.profiles" />}
href={`/${MainPaths.profiles}`}
value={MainPaths.profiles}
key={`tab-${MainPaths.profiles}`}
iconPosition="start"
LinkComponent={forwardRef((props, ref) => (
<NavLink ref={ref} to={props.href} {...props} />
))}
/>,
],
]);

const AppTopBar: FunctionComponent = () => {
Expand Down
23 changes: 23 additions & 0 deletions src/pages/common/paper-form.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* 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 } from 'react';
import { Paper, PaperProps } from '@mui/material';

/*
* <Paper> is defined in <Dialog> without generics, which default to `PaperProps => PaperProps<'div'>`,
* so we must trick typescript check with a cast
*/
const PaperForm: FunctionComponent<
PaperProps<'form'> & { untypedProps?: PaperProps }
> = (props, context) => {
const { untypedProps, ...formProps } = props;
const othersProps = untypedProps as PaperProps<'form'>; //trust me ts
return <Paper component="form" {...formProps} {...(othersProps ?? {})} />;
};

export default PaperForm;
1 change: 1 addition & 0 deletions src/pages/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
*/

export * from './users';
export * from './profiles';
132 changes: 132 additions & 0 deletions src/pages/profiles/add-profile-dialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/**
* 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, RefObject, useCallback } from 'react';
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
InputAdornment,
TextField,
} from '@mui/material';
import { FormattedMessage } from 'react-intl';
import { Controller, useForm } from 'react-hook-form';
import { ManageAccounts } from '@mui/icons-material';
import { UserAdminSrv, UserProfile } from '../../services';
import { useSnackMessage } from '@gridsuite/commons-ui';
import { GridTableRef } from '../../components/Grid';
import PaperForm from '../common/paper-form';

export interface AddProfileDialogProps {
gridRef: RefObject<GridTableRef<UserProfile>>;
open: boolean;
setOpen: (open: boolean) => void;
}

const AddProfileDialog: FunctionComponent<AddProfileDialogProps> = (props) => {
const { snackError } = useSnackMessage();

const { handleSubmit, control, reset, clearErrors } = useForm<{
name: string;
}>({
defaultValues: { name: '' }, //need default not undefined value for html input, else react error at runtime
});

const addProfile = useCallback(
(name: string) => {
const profileData: UserProfile = {
name: name,
};
UserAdminSrv.addProfile(profileData)
.catch((error) =>
snackError({
messageTxt: error.message,
headerId: 'profiles.table.error.add',
})
)
.then(() => props.gridRef?.current?.context?.refresh?.());
},
[props.gridRef, snackError]
);

const handleClose = useCallback(() => {
props.setOpen(false);
reset();
clearErrors();
}, [clearErrors, props, reset]);

const onSubmit = useCallback(
(data: { name: string }) => {
addProfile(data.name.trim());
handleClose();
},
[addProfile, handleClose]
);

return (
<Dialog
open={props.open}
onClose={handleClose}
PaperComponent={(props) => (
<PaperForm
untypedProps={props}
onSubmit={handleSubmit(onSubmit)}
/>
)}
>
<DialogTitle>
<FormattedMessage id="profiles.form.title" />
</DialogTitle>
<DialogContent>
<DialogContentText>
<FormattedMessage id="profiles.form.content" />
</DialogContentText>
<Controller
name="name"
control={control}
rules={{ required: true, minLength: 1 }}
render={({ field, fieldState, formState }) => (
<TextField
{...field}
autoFocus
required
margin="dense"
label={
<FormattedMessage id="profiles.form.field.profilename.label" />
}
type="text"
fullWidth
variant="standard"
inputMode="text"
InputProps={{
startAdornment: (
<InputAdornment position="start">
<ManageAccounts />
</InputAdornment>
),
}}
error={fieldState?.invalid}
helperText={fieldState?.error?.message}
/>
)}
/>
</DialogContent>
<DialogActions>
<Button onClick={handleClose}>
<FormattedMessage id="cancel" />
</Button>
<Button type="submit">
<FormattedMessage id="ok" />
</Button>
</DialogActions>
</Dialog>
);
};
export default AddProfileDialog;
8 changes: 8 additions & 0 deletions src/pages/profiles/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* 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 { default as Profiles } from './profiles-page';
120 changes: 120 additions & 0 deletions src/pages/profiles/modification/custom-mui-dialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/**
* 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/.
*/

// TODO: this file is going to be available soon in commons-ui

import { FunctionComponent } from 'react';
import { FieldErrors, FormProvider } from 'react-hook-form';
import { FormattedMessage } from 'react-intl';
import {
DialogActions,
DialogContent,
Grid,
LinearProgress,
Dialog,
DialogTitle,
} from '@mui/material';
import { CancelButton, SubmitButton } from '@gridsuite/commons-ui';

interface ICustomMuiDialog {
open: boolean;
formSchema: any;
formMethods: any;
onClose: (event: React.MouseEvent) => void;
onSave: (data: any) => void;
onValidationError?: (errors: FieldErrors) => void;
titleId: string;
disabledSave?: boolean;
removeOptional?: boolean;
onCancel?: () => void;
children: React.ReactNode;
isDataFetching?: boolean;
}

const styles = {
dialogPaper: {
'.MuiDialog-paper': {
width: 'auto',
minWidth: '800px',
margin: 'auto',
},
},
};

const CustomMuiDialog: FunctionComponent<ICustomMuiDialog> = ({
open,
formSchema,
formMethods,
onClose,
onSave,
isDataFetching = false,
onValidationError,
titleId,
disabledSave,
removeOptional = false,
onCancel,
children,
}) => {
const { handleSubmit } = formMethods;

const handleCancel = (event: React.MouseEvent) => {
onCancel && onCancel();
onClose(event);
};

const handleClose = (event: React.MouseEvent, reason?: string) => {
if (reason === 'backdropClick' && onCancel) {
onCancel();
}
onClose(event);
};

const handleValidate = (data: any) => {
onSave(data);
onClose(data);
};

const handleValidationError = (errors: FieldErrors) => {
onValidationError && onValidationError(errors);
};

return (
<FormProvider
validationSchema={formSchema}
{...formMethods}
removeOptional={removeOptional}
>
<Dialog
sx={styles.dialogPaper}
open={open}
onClose={handleClose}
fullWidth
>
{isDataFetching && <LinearProgress />}
<DialogTitle>
<Grid item xs={11}>
<FormattedMessage id={titleId} />
</Grid>
</DialogTitle>
<DialogContent>{children}</DialogContent>
<DialogActions>
<CancelButton onClick={handleCancel} />
<SubmitButton
variant="outlined"
disabled={disabledSave}
onClick={handleSubmit(
handleValidate,
handleValidationError
)}
/>
</DialogActions>
</Dialog>
</FormProvider>
);
};

export default CustomMuiDialog;
50 changes: 50 additions & 0 deletions src/pages/profiles/modification/linked-path-display.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* 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 { Typography, useTheme } from '@mui/material';
import { useIntl } from 'react-intl';
import { FunctionComponent } from 'react';

export interface LinkedPathDisplayProps {
nameKey: string;
value?: string;
linkValidity?: boolean;
}

const LinkedPathDisplay: FunctionComponent<LinkedPathDisplayProps> = (
props
) => {
const intl = useIntl();
const theme = useTheme();

return (
<Typography
sx={{
fontWeight: 'bold',
color:
props.linkValidity === false
? theme.palette.error.main
: undefined,
}}
>
{intl.formatMessage({
id: props.nameKey,
}) +
' : ' +
(props.value
? props.value
: intl.formatMessage({
id:
props.linkValidity === false
? 'linked.path.display.invalidLink'
: 'linked.path.display.noLink',
}))}
</Typography>
);
};

export default LinkedPathDisplay;
Loading