Skip to content

Commit

Permalink
update csv import error dialog
Browse files Browse the repository at this point in the history
  • Loading branch information
mauberti-bc committed Jan 8, 2025
1 parent fb14aa8 commit 0cbf589
Show file tree
Hide file tree
Showing 9 changed files with 113 additions and 146 deletions.
6 changes: 3 additions & 3 deletions api/src/utils/csv-utils/csv-config-validation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ describe('csv-config-validation', () => {
errors: [
{
error: 'A required column is missing',
solution: `Add all required columns to the file.`,
solution: `Add the ALIAS column to the file.`,
header: 'ALIAS',
values: ['ALIAS', 'ALIAS_2'],
cell: null,
Expand Down Expand Up @@ -159,7 +159,7 @@ describe('csv-config-validation', () => {
{
row: 1,
error: 'A required column is missing',
solution: `Add all required columns to the file.`,
solution: `Add the ALIAS column to the file.`,
header: 'ALIAS',
values: ['ALIAS'],
cell: null
Expand Down Expand Up @@ -189,7 +189,7 @@ describe('csv-config-validation', () => {
{
row: 1,
error: 'An unknown column is included in the file',
solution: `Remove extra columns from the file.`,
solution: `Remove the UNKNOWN_HEADER column from the file.`,
header: 'UNKNOWN_HEADER',
cell: null,
values: null
Expand Down
4 changes: 2 additions & 2 deletions api/src/utils/csv-utils/csv-config-validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ export const validateCSVHeaders = (worksheet: WorkSheet, config: CSVConfig): CSV
if (!headerConfig.optional && !worksheetHasStaticHeader) {
csvErrors.push({
error: 'A required column is missing',
solution: `Add all required columns to the file.`,
solution: `Add the ${staticHeader} column to the file.`,
values: [staticHeader, ...config.staticHeadersConfig[staticHeader].aliases],
header: staticHeader,
cell: null,
Expand All @@ -113,7 +113,7 @@ export const validateCSVHeaders = (worksheet: WorkSheet, config: CSVConfig): CSV
for (const unknownHeader of configUtils.worksheetDynamicHeaders) {
csvErrors.push({
error: 'An unknown column is included in the file',
solution: `Remove extra columns from the file.`,
solution: `Remove the ${unknownHeader} column from the file.`,
values: null,
header: unknownHeader,
cell: null,
Expand Down
13 changes: 10 additions & 3 deletions app/src/components/alert/AlertBar.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import Alert, { AlertProps } from '@mui/material/Alert';
import AlertTitle from '@mui/material/AlertTitle';
import Typography from '@mui/material/Typography';

interface IAlertBarProps extends AlertProps {
severity: 'error' | 'warning' | 'info' | 'success';
variant: 'filled' | 'outlined' | 'standard';
title: string;
text: string | JSX.Element;
ornament?: JSX.Element;
}

/**
Expand All @@ -15,7 +17,7 @@ interface IAlertBarProps extends AlertProps {
* @returns
*/
const AlertBar = (props: IAlertBarProps) => {
const { severity, variant, title, text, ...alertProps } = props;
const { severity, variant, title, text, ornament, ...alertProps } = props;

const defaultProps = {
severity: 'success',
Expand All @@ -30,8 +32,13 @@ const AlertBar = (props: IAlertBarProps) => {
{...alertProps}
variant={variant}
severity={severity}
sx={{ flex: '1 1 auto', ...alertProps.sx }}>
<AlertTitle>{title}</AlertTitle>
sx={{ flex: '1 1 auto', '& .MuiAlert-message': { flex: '1 1 auto' }, ...alertProps.sx }}>
<AlertTitle sx={{ justifyContent: 'space-between', display: 'flex', alignItems: 'center', flex: '1 1 auto' }}>
{title}
<Typography component="span" variant="body2">
{ornament}
</Typography>
</AlertTitle>
{text}
</Alert>
);
Expand Down
17 changes: 10 additions & 7 deletions app/src/components/csv/CSVDropzoneSection.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { Box } from '@mui/material';
import { Box, Typography } from '@mui/material';
import Button from '@mui/material/Button';
import { CSVErrorsTableContainer } from 'components/csv/CSVErrorsTableContainer';
import HorizontalSplitFormComponent from 'components/fields/HorizontalSplitFormComponent';
import { PropsWithChildren } from 'react';
import { CSVError } from 'utils/csv-utils';
import { CSVErrorsContainer } from './CSVErrorsTableContainer';

interface CSVDropzoneSectionProps {
title: string;
Expand All @@ -21,9 +20,10 @@ interface CSVDropzoneSectionProps {
*/
export const CSVDropzoneSection = (props: PropsWithChildren<CSVDropzoneSectionProps>) => {
return (
<HorizontalSplitFormComponent title={props.title} summary={props.summary}>
<>
<Box sx={{ display: 'flex', flexDirection: 'column' }} gap={2}>
<Box sx={{ display: 'flex', ml: 'auto' }}>
<Box sx={{ display: 'flex', justifyContent: 'space-between' }}>
<Typography variant="h3">{props.title}</Typography>
<Button
sx={{ textTransform: 'none', fontWeight: 'regular' }}
variant="outlined"
Expand All @@ -32,9 +32,12 @@ export const CSVDropzoneSection = (props: PropsWithChildren<CSVDropzoneSectionPr
Download Template
</Button>
</Box>
<Typography color="textSecondary" variant="body2">
{props.summary}
</Typography>
{props.children}
{props.errors.length > 0 ? <CSVErrorsTableContainer errors={props.errors} /> : null}
{props.errors.length > 0 ? <CSVErrorsContainer errors={props.errors} /> : null}
</Box>
</HorizontalSplitFormComponent>
</>
);
};
67 changes: 67 additions & 0 deletions app/src/components/csv/CSVErrors.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import AlertBar from 'components/alert/AlertBar';
import { useMemo } from 'react';
import { CSVError } from 'utils/csv-utils';
import { v4 } from 'uuid';

interface CSVErrorsProps {
errors: CSVError[];
}

/**
* Returns a stack of CSV errors with information about solutions
*
* @param {CSVErrorsProps} props
* @returns {*}
*/
export const CSVErrors = (props: CSVErrorsProps) => {
const rows: (CSVError & { id: string })[] = useMemo(() => {
return props.errors.map((error) => {
return {
id: v4(),
...error
};
});
}, [props.errors]);

return (
<Stack gap={1}>
{rows.map((error) => {
return (
<AlertBar
key={error.id}
severity="error"
variant="standard"
title={error.error}
text={
<Stack gap={1}>
<Typography variant="body2">{error.solution}</Typography>
<Stack gap={3} flexDirection="row">
<Stack>
<Typography variant="body2" fontWeight={700}>
Row
</Typography>
<Typography variant="body2">{error.row}</Typography>
</Stack>
<Stack>
<Typography variant="body2" fontWeight={700}>
Column
</Typography>
<Typography variant="body2">{error.header}</Typography>
</Stack>
<Stack>
<Typography variant="body2" fontWeight={700}>
Value
</Typography>
<Typography variant="body2">{error.cell}</Typography>
</Stack>
</Stack>
</Stack>
}
/>
);
})}
</Stack>
);
};
99 changes: 0 additions & 99 deletions app/src/components/csv/CSVErrorsTable.tsx

This file was deleted.

29 changes: 11 additions & 18 deletions app/src/components/csv/CSVErrorsTableContainer.tsx
Original file line number Diff line number Diff line change
@@ -1,47 +1,40 @@
import { Divider, Paper, Toolbar, Typography } from '@mui/material';
import { Toolbar, Typography } from '@mui/material';
import { Box, Stack } from '@mui/system';
import { ReactElement } from 'react';
import { CSVError } from 'utils/csv-utils';
import { CSVErrorsTable } from './CSVErrorsTable';
import { CSVErrors } from './CSVErrors';

interface CSVErrorsTableContainerProps {
interface CSVErrorsContainerProps {
errors: CSVError[];
title?: ReactElement;
}

/**
* Renders a CSV errors table with toolbar.
*
* @param {CSVErrorsTableContainerProps} props
* @returns {*} {JSX.Element}
* @param {CSVErrorsContainerProps} props
* @returns {*}
*/
export const CSVErrorsTableContainer = (props: CSVErrorsTableContainerProps) => {
export const CSVErrorsContainer = (props: CSVErrorsContainerProps) => {
return (
<Paper component={Stack} flexDirection="column" flex="1 1 auto" height="100%">
<Toolbar
disableGutters
sx={{
pl: 2,
pr: 3
}}>
<Stack flexDirection="column" flex="1 1 auto" height="100%">
<Toolbar disableGutters>
{props.title ?? (
<Typography
sx={{
flexGrow: '1',
fontSize: '1.125rem',
fontWeight: 700
}}>
CSV Errors Detected &zwnj;
Errors &zwnj;
<Typography sx={{ fontWeight: '400' }} component="span" variant="inherit" color="textSecondary">
({props.errors.length})
</Typography>
</Typography>
)}
</Toolbar>
<Divider />
<Box width="100%" height="100%">
<CSVErrorsTable errors={props.errors} />
<CSVErrors errors={props.errors} />
</Box>
</Paper>
</Stack>
);
};
20 changes: 8 additions & 12 deletions app/src/components/csv/CSVSingleImportDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import LoadingButton from '@mui/lab/LoadingButton/LoadingButton';
import { Box, Dialog, DialogActions, DialogContent, Divider, Typography, useMediaQuery, useTheme } from '@mui/material';
import { Box, Dialog, DialogActions, DialogContent, Divider, useMediaQuery, useTheme } from '@mui/material';
import { AxiosProgressEvent } from 'axios';
import { UploadFileStatus } from 'components/file-upload/FileUploadItem';
import { FileUploadSingleItem } from 'components/file-upload/FileUploadSingleItem';
Expand Down Expand Up @@ -90,24 +90,20 @@ export const CSVSingleImportDialog = (props: CSVSingleImportDialogProps) => {
// Wait for the complete status to be rendered + 500ms before closing the dialog
await waitForRenderCycle(500);

// Show a success snackbar message
dialogContext.setSnackbar({
open: true,
snackbarAutoCloseMs: 2000,
snackbarMessage: 'Successfully imported telemetry'
});

handleClose();
} catch (err) {
if (err instanceof Error) {
setError(err);
}

setUploadStatus(UploadFileStatus.FAILED);
} finally {
// Show a success snackbar message
dialogContext.setSnackbar({
open: true,
snackbarAutoCloseMs: 2000,
snackbarMessage: (
<Typography variant="body2" component="div">
{uploadStatus === UploadFileStatus.FAILED ? 'CSV failed to import' : 'CSV imported'}
</Typography>
)
});
}
};

Expand Down
Loading

0 comments on commit 0cbf589

Please sign in to comment.