feat: introduce inline error messages in SamlConfiguration and RoleMappings forms

This commit is contained in:
kasia.oczkowska
2024-12-13 11:12:04 +00:00
parent 819f122106
commit e784215e3c
7 changed files with 314 additions and 174 deletions

View File

@@ -3,7 +3,7 @@ import LoadingButton from '@mui/lab/LoadingButton';
import Divider from '@mui/material/Divider';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import useEnqueueSnackbar from 'hooks/useEnqueueSnackbar';
import Alert from '@mui/material/Alert';
import { useMemo } from 'react';
import { yupResolver } from '@hookform/resolvers/yup';
import * as yup from 'yup';
@@ -13,6 +13,7 @@ import useFormatMessage from 'hooks/useFormatMessage';
import useAdminSamlAuthProviderRoleMappings from 'hooks/useAdminSamlAuthProviderRoleMappings';
import useAdminUpdateSamlAuthProviderRoleMappings from 'hooks/useAdminUpdateSamlAuthProviderRoleMappings';
import RoleMappingsFieldArray from './RoleMappingsFieldsArray';
import { getGeneralErrorMessage } from 'helpers/errors';
function generateFormRoleMappings(roleMappings) {
if (roleMappings?.length === 0) {
@@ -63,11 +64,11 @@ const getValidationSchema = (formatMessage) =>
function RoleMappings({ provider, providerLoading }) {
const formatMessage = useFormatMessage();
const enqueueSnackbar = useEnqueueSnackbar();
const {
mutateAsync: updateRoleMappings,
isPending: isUpdateRoleMappingsPending,
isSuccess: isUpdateRoleMappingsSuccess,
} = useAdminUpdateSamlAuthProviderRoleMappings(provider?.id);
const { data, isLoading: isAdminSamlAuthProviderRoleMappingsLoading } =
@@ -75,8 +76,9 @@ function RoleMappings({ provider, providerLoading }) {
adminSamlAuthProviderId: provider?.id,
});
const roleMappings = data?.data;
const fieldNames = ['remoteRoleName', 'roleId'];
const handleRoleMappingsUpdate = async (values) => {
const handleRoleMappingsUpdate = async (values, e, setError) => {
try {
if (provider?.id) {
await updateRoleMappings(
@@ -85,29 +87,31 @@ function RoleMappings({ provider, providerLoading }) {
remoteRoleName,
})),
);
enqueueSnackbar(formatMessage('roleMappingsForm.successfullySaved'), {
variant: 'success',
SnackbarProps: {
'data-test': 'snackbar-update-role-mappings-success',
},
});
}
} catch (error) {
const errors = Object.values(
error.response.data.errors || [['Failed while saving!']],
);
for (const [error] of errors) {
enqueueSnackbar(error, {
variant: 'error',
SnackbarProps: {
'data-test': 'snackbar-update-role-mappings-error',
},
const errors = error?.response?.data?.errors;
if (errors) {
Object.entries(errors).forEach(([fieldName, fieldErrors]) => {
if (fieldNames.includes(fieldName) && Array.isArray(fieldErrors)) {
setError(`root.${fieldName}`, {
type: 'fieldRequestError',
message: `${fieldName}: ${fieldErrors.join(', ')}`,
});
}
});
}
throw new Error('Failed while saving!');
const generalError = getGeneralErrorMessage({
error,
fallbackMessage: formatMessage('roleMappingsForm.error'),
});
if (generalError) {
setError('root.general', {
type: 'requestError',
message: generalError,
});
}
}
};
@@ -118,6 +122,17 @@ function RoleMappings({ provider, providerLoading }) {
[roleMappings],
);
const renderErrors = (errors) => {
const rootErrors = errors?.root;
if (rootErrors) {
return Object.values(rootErrors).map((error, index) => (
<Alert key={index} data-test="error-alert" severity="error">
{error.message}
</Alert>
));
}
};
if (
providerLoading ||
!provider?.id ||
@@ -140,27 +155,35 @@ function RoleMappings({ provider, providerLoading }) {
reValidateMode="onChange"
noValidate
automaticValidation={false}
>
<Stack direction="column" spacing={2}>
<RoleMappingsFieldArray />
<LoadingButton
type="submit"
variant="contained"
color="primary"
sx={{ boxShadow: 2 }}
loading={isUpdateRoleMappingsPending}
>
{formatMessage('roleMappingsForm.save')}
</LoadingButton>
</Stack>
</Form>
render={({ formState: { errors, isDirty } }) => (
<Stack direction="column" spacing={2}>
<RoleMappingsFieldArray />
{renderErrors(errors)}
{isUpdateRoleMappingsSuccess && !isDirty && (
<Alert data-test="success-alert" severity="success">
{formatMessage('roleMappingsForm.successfullySaved')}
</Alert>
)}
<LoadingButton
type="submit"
variant="contained"
color="primary"
sx={{ boxShadow: 2 }}
loading={isUpdateRoleMappingsPending}
disabled={!isDirty}
>
{formatMessage('roleMappingsForm.save')}
</LoadingButton>
</Stack>
)}
/>
</>
);
}
RoleMappings.propTypes = {
provider: PropTypes.shape({
id: PropTypes.oneOf([PropTypes.number, PropTypes.string]).isRequired,
id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
}),
providerLoading: PropTypes.bool,
};