Skip to content

Commit

Permalink
Merge branch 'dev' into BHBC-914
Browse files Browse the repository at this point in the history
  • Loading branch information
NickPhura authored Apr 13, 2021
2 parents 685309c + f8911e7 commit f87ec79
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 61 deletions.
2 changes: 1 addition & 1 deletion api/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ app.use(function (req: any, res: any, next: any) {
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Authorization, responseType');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE, HEAD');
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Cache-Control', 'max-age=4');
res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');

next();
});
Expand Down
138 changes: 83 additions & 55 deletions app/src/components/attachments/AttachmentsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { getFormattedDate } from 'utils/Utils';
import { DATE_FORMAT } from 'constants/dateFormats';
import { useBiohubApi } from 'hooks/useBioHubApi';
import { IGetProjectAttachment } from 'interfaces/useProjectApi.interface';
import YesNoDialog from 'components/dialog/YesNoDialog';

const useStyles = makeStyles({
table: {
Expand All @@ -44,6 +45,13 @@ const AttachmentsList: React.FC<IAttachmentsListProps> = (props) => {

const [rowsPerPage, setRowsPerPage] = useState(10);
const [page, setPage] = useState(0);
const [showDeleteModal, setShowDeleteModal] = useState(false);
const [attachmentToDelete, setAttachmentToDelete] = useState<IGetProjectAttachment>({
id: (null as unknown) as number,
fileName: (null as unknown) as string,
lastModified: (null as unknown) as string,
size: (null as unknown) as number
});

const handleChangePage = (event: unknown, newPage: number) => {
setPage(newPage);
Expand All @@ -54,9 +62,13 @@ const AttachmentsList: React.FC<IAttachmentsListProps> = (props) => {
setPage(0);
};

const deleteAttachment = async (attachment: any) => {
const deleteAttachment = async () => {
if (!attachmentToDelete || !attachmentToDelete.id) {
return;
}

try {
const response = await biohubApi.project.deleteProjectAttachment(props.projectId, attachment.id);
const response = await biohubApi.project.deleteProjectAttachment(props.projectId, attachmentToDelete.id);

if (!response) {
return;
Expand All @@ -83,61 +95,77 @@ const AttachmentsList: React.FC<IAttachmentsListProps> = (props) => {
};

return (
<Paper>
<TableContainer>
<Table className={classes.table} aria-label="attachments-list-table">
<TableHead>
<TableRow>
<TableCell className={classes.heading}>Name</TableCell>
<TableCell className={classes.heading}>Last Modified</TableCell>
<TableCell className={classes.heading}>File Size</TableCell>
<TableCell></TableCell>
</TableRow>
</TableHead>
<TableBody>
{props.attachmentsList.length > 0 &&
props.attachmentsList.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage).map((row, index) => (
<TableRow key={row.fileName}>
<TableCell component="th" scope="row">
<Link underline="always" component="button" variant="body2" onClick={() => viewFileContents(row)}>
{row.fileName}
</Link>
</TableCell>
<TableCell>{getFormattedDate(DATE_FORMAT.ShortDateFormatMonthFirst, row.lastModified)}</TableCell>
<TableCell>{row.size / 1000000} MB</TableCell>
<TableCell align="right" className={clsx(index === 0 && classes.tableCellBorderTop)}>
<IconButton
color="primary"
aria-label="delete-attachment"
data-testid="delete-attachment"
onClick={() => deleteAttachment(row)}>
<Icon path={mdiTrashCanOutline} size={1} />
</IconButton>
</TableCell>
</TableRow>
))}
{!props.attachmentsList.length && (
<>
<YesNoDialog
dialogTitle="Delete Attachment"
dialogText="Are you sure you want to delete the selected attachment?"
open={showDeleteModal}
onClose={() => setShowDeleteModal(false)}
onNo={() => setShowDeleteModal(false)}
onYes={() => {
setShowDeleteModal(false);
deleteAttachment();
}}
/>
<Paper>
<TableContainer>
<Table className={classes.table} aria-label="attachments-list-table">
<TableHead>
<TableRow>
<TableCell colSpan={3} align="center">
No Attachments
</TableCell>
<TableCell className={classes.heading}>Name</TableCell>
<TableCell className={classes.heading}>Last Modified</TableCell>
<TableCell className={classes.heading}>File Size</TableCell>
<TableCell></TableCell>
</TableRow>
)}
</TableBody>
</Table>
</TableContainer>
{props.attachmentsList.length > 0 && (
<TablePagination
rowsPerPageOptions={[5, 10, 15, 20]}
component="div"
count={props.attachmentsList.length}
rowsPerPage={rowsPerPage}
page={page}
onChangePage={handleChangePage}
onChangeRowsPerPage={handleChangeRowsPerPage}
/>
)}
</Paper>
</TableHead>
<TableBody>
{props.attachmentsList.length > 0 &&
props.attachmentsList.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage).map((row, index) => (
<TableRow key={row.fileName}>
<TableCell component="th" scope="row">
<Link underline="always" component="button" variant="body2" onClick={() => viewFileContents(row)}>
{row.fileName}
</Link>
</TableCell>
<TableCell>{getFormattedDate(DATE_FORMAT.ShortDateFormatMonthFirst, row.lastModified)}</TableCell>
<TableCell>{row.size / 1000000} MB</TableCell>
<TableCell align="right" className={clsx(index === 0 && classes.tableCellBorderTop)}>
<IconButton
color="primary"
aria-label="delete-attachment"
data-testid="delete-attachment"
onClick={() => {
setAttachmentToDelete(row);
setShowDeleteModal(true);
}}>
<Icon path={mdiTrashCanOutline} size={1} />
</IconButton>
</TableCell>
</TableRow>
))}
{!props.attachmentsList.length && (
<TableRow>
<TableCell colSpan={3} align="center">
No Attachments
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</TableContainer>
{props.attachmentsList.length > 0 && (
<TablePagination
rowsPerPageOptions={[5, 10, 15, 20]}
component="div"
count={props.attachmentsList.length}
rowsPerPage={rowsPerPage}
page={page}
onChangePage={handleChangePage}
onChangeRowsPerPage={handleChangeRowsPerPage}
/>
)}
</Paper>
</>
);
};

Expand Down
90 changes: 89 additions & 1 deletion app/src/features/projects/view/ProjectAttachments.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ describe('ProjectAttachments', () => {
]
});

const { queryByText, getByTestId } = render(
const { queryByText, getByTestId, getByText } = render(
<Router history={history}>
<ProjectAttachments projectForViewData={getProjectForViewResponse} />
</Router>
Expand All @@ -116,8 +116,96 @@ describe('ProjectAttachments', () => {

fireEvent.click(getByTestId('delete-attachment'));

await waitFor(() => {
expect(queryByText('Delete Attachment')).toBeInTheDocument();
});

fireEvent.click(getByText('Yes'));

await waitFor(() => {
expect(queryByText('filename.test')).toBeNull();
});
});

it('does not delete an attachment from the attachments when user selects no from dialog', async () => {
mockBiohubApi().project.deleteProjectAttachment.mockResolvedValue(1);
mockBiohubApi().project.getProjectAttachments.mockResolvedValue({
attachmentsList: [
{
id: 1,
fileName: 'filename.test',
lastModified: '2021-04-09 11:53:53',
size: 3028
}
]
});

const { queryByText, getByTestId, getByText } = render(
<Router history={history}>
<ProjectAttachments projectForViewData={getProjectForViewResponse} />
</Router>
);

await waitFor(() => {
expect(queryByText('filename.test')).toBeInTheDocument();
});

mockBiohubApi().project.getProjectAttachments.mockResolvedValue({
attachmentsList: []
});

fireEvent.click(getByTestId('delete-attachment'));

await waitFor(() => {
expect(queryByText('Delete Attachment')).toBeInTheDocument();
});

fireEvent.click(getByText('No'));

await waitFor(() => {
expect(queryByText('filename.test')).toBeInTheDocument();
});
});

it('does not delete an attachment from the attachments when user clicks outside the dialog', async () => {
mockBiohubApi().project.deleteProjectAttachment.mockResolvedValue(1);
mockBiohubApi().project.getProjectAttachments.mockResolvedValue({
attachmentsList: [
{
id: 1,
fileName: 'filename.test',
lastModified: '2021-04-09 11:53:53',
size: 3028
}
]
});

const { queryByText, getByTestId, getAllByRole } = render(
<Router history={history}>
<ProjectAttachments projectForViewData={getProjectForViewResponse} />
</Router>
);

await waitFor(() => {
expect(queryByText('filename.test')).toBeInTheDocument();
});

mockBiohubApi().project.getProjectAttachments.mockResolvedValue({
attachmentsList: []
});

fireEvent.click(getByTestId('delete-attachment'));

await waitFor(() => {
expect(queryByText('Delete Attachment')).toBeInTheDocument();
});

// Get the backdrop, then get the firstChild because this is where the event listener is attached
//@ts-ignore
fireEvent.click(getAllByRole('presentation')[0].firstChild);

await waitFor(() => {
expect(queryByText('filename.test')).toBeInTheDocument();
});
});
});
7 changes: 3 additions & 4 deletions app/src/features/projects/view/ProjectAttachments.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ const ProjectAttachments: React.FC<IProjectAttachmentsProps> = () => {

useEffect(() => {
getAttachments(false);
}, [getAttachments]);
// eslint-disable-next-line
}, []);

return (
<>
Expand All @@ -76,9 +77,7 @@ const ProjectAttachments: React.FC<IProjectAttachmentsProps> = () => {
</Box>
</Box>
<Box mb={3}>
<Box p={3}>
<AttachmentsList projectId={projectId} attachmentsList={attachmentsList} getAttachments={getAttachments} />
</Box>
<AttachmentsList projectId={projectId} attachmentsList={attachmentsList} getAttachments={getAttachments} />
</Box>
</>
);
Expand Down
1 change: 1 addition & 0 deletions app/src/interfaces/useProjectApi.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { IProjectSpeciesForm } from 'features/projects/components/ProjectSpecies
import { Feature } from 'geojson';

export interface IGetProjectAttachment {
id: number;
fileName: string;
lastModified: string;
size: number;
Expand Down

0 comments on commit f87ec79

Please sign in to comment.