Skip to content

Commit

Permalink
Enable deletion of draft templates
Browse files Browse the repository at this point in the history
  • Loading branch information
saulipurhonen committed Oct 17, 2021
1 parent 92bd679 commit 11de60f
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 21 deletions.
33 changes: 32 additions & 1 deletion cypress/integration/draftTemplates.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ describe("draft selections and templates", function () {
cy.get("h1", { timeout: 10000 }).contains("Sample").should("be.visible")
cy.get("[data-testid='title']").should("have.value", "Sample draft title")
}),
it("should be able to select draft templates and reuse them when creating a new folder", () => {
it("should be able to select and delete draft templates and reuse them when creating a new folder", () => {
// Select drafts inside the dialog
cy.get("form").within(() => {
cy.get("input[type='checkbox']").first().check()
Expand All @@ -111,6 +111,37 @@ describe("draft selections and templates", function () {
// Check if the drafts have been saved as user's templates in Home page
cy.contains("Your Draft Templates", { timeout: 10000 }).should("be.visible")

const listAllSampleTemplates = () => {
cy.get("[data-testid='template-sample-item']")
.its("length")
.then(lengthOfSampleTemplates => {
if (lengthOfSampleTemplates >= 10) {
cy.get("[data-testid='form-template-sample']").within(() => {
cy.get("div[aria-haspopup='listbox']", { timeout: 10000 }).contains(10).click()
})
cy.get("li[role='option']").contains("All").click()
}
})
}

listAllSampleTemplates()

// Count sample templates, delete template and test that template count has decreased
cy.get("[data-testid='template-sample-item']")
.its("length")
.then(lengthOfSampleTemplates => {
cy.get("[data-testid='form-template-sample']").within(() => {
// Vertical menu button
cy.get("button").first().click()
})

cy.get("[data-testid='delete-template']").click()

listAllSampleTemplates()

cy.get("[data-testid='template-sample-item']").should("have.length", lengthOfSampleTemplates - 1)
})

// Select some drafts to reuse
cy.get("[data-testid='form-template-study']").within(() => {
cy.get("input").first().check()
Expand Down
77 changes: 77 additions & 0 deletions src/components/Home/UserDraftTemplateActions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
//@flow
import React, { useState } from "react"

import IconButton from "@material-ui/core/IconButton"
import Menu from "@material-ui/core/Menu"
import MenuItem from "@material-ui/core/MenuItem"
import MoreVertIcon from "@material-ui/icons/MoreVert"
import { useDispatch } from "react-redux"

import { WizardStatus } from "constants/wizardStatus"
import { deleteTemplateByAccessionId } from "features/userSlice"
import { updateStatus } from "features/wizardStatusMessageSlice"
import templateAPI from "services/templateAPI"

const UserDraftTemplateActions = (props: { item: { schema: string, accessionId: string } }): React$Element<any> => {
const { item } = props
const dispatch = useDispatch()
const [anchorEl, setAnchorEl] = useState(null)
const menuOpen = Boolean(anchorEl)

const handleMenuClick = event => {
setAnchorEl(event.currentTarget)
}

const handleCloseMenu = () => {
setAnchorEl(null)
}

const deleteTemplate = async (schema, accessionId) => {
const objectType = schema.split("template-")[1]

const response = await templateAPI.deleteTemplateByAccessionId(objectType, accessionId)

if (response.ok) {
dispatch(deleteTemplateByAccessionId(accessionId))
} else {
dispatch(
updateStatus({
successStatus: WizardStatus.error,
response: response,
errorPrefix: "Unable to delete template",
})
)
}
}

return (
<React.Fragment>
<IconButton
aria-label="more"
id={`template-more-button-${item.accessionId}`}
aria-controls="template-menu"
aria-expanded={menuOpen ? "true" : undefined}
aria-haspopup="true"
onClick={handleMenuClick}
>
<MoreVertIcon />
</IconButton>

<Menu
id="template-menu"
MenuListProps={{
"aria-labelledby": "template-more-button",
}}
anchorEl={anchorEl}
open={menuOpen}
onClose={handleCloseMenu}
>
<MenuItem onClick={() => deleteTemplate(item.schema, item.accessionId)} data-testid="delete-template">
Delete
</MenuItem>
</Menu>
</React.Fragment>
)
}

export default UserDraftTemplateActions
53 changes: 34 additions & 19 deletions src/components/Home/UserDraftTemplates.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import Collapse from "@material-ui/core/Collapse"
import FormControl from "@material-ui/core/FormControl"
import FormControlLabel from "@material-ui/core/FormControlLabel"
import FormLabel from "@material-ui/core/FormLabel"
import Grid from "@material-ui/core/Grid"
import ListItemText from "@material-ui/core/ListItemText"
import { makeStyles } from "@material-ui/core/styles"
import Typography from "@material-ui/core/Typography"
Expand All @@ -17,6 +18,8 @@ import KeyboardArrowUpIcon from "@material-ui/icons/KeyboardArrowUp"
import { useForm, FormProvider, useFormContext, Controller } from "react-hook-form"
import { useSelector, useDispatch } from "react-redux"

import UserDraftTemplateActions from "./UserDraftTemplateActions"

import { setTemplateAccessionIds } from "features/templatesSlice"
import { formatDisplayObjectType, getUserTemplates, getItemPrimaryText, Pagination } from "utils"

Expand Down Expand Up @@ -126,28 +129,40 @@ const UserDraftTemplates = (): React$Element<any> => {
.map(item => {
const { ref, ...rest } = register(item.accessionId)
return (
<FormControlLabel
<Grid
container
key={item.accessionId}
className={classes.formControlLabel}
control={
<Checkbox
checked={checkedItems.find(element => element === item.accessionId) !== undefined}
color="primary"
name={item.accessionId}
value={item.accessionId}
inputRef={ref}
{...rest}
/>
}
label={
<ListItemText
className={classes.listItemText}
primary={getItemPrimaryText(item)}
secondary={item.accessionId}
data-schema={item.schema}
data-testid={`${item.schema}-item`}
>
<Grid item xs>
<FormControlLabel
control={
<Checkbox
checked={
checkedItems.find(element => element === item.accessionId) !== undefined
}
color="primary"
name={item.accessionId}
value={item.accessionId}
inputRef={ref}
{...rest}
/>
}
label={
<ListItemText
className={classes.listItemText}
primary={getItemPrimaryText(item)}
secondary={item.accessionId}
data-schema={item.schema}
/>
}
/>
}
/>
</Grid>
<Grid item xs="auto">
<UserDraftTemplateActions item={item} />
</Grid>
</Grid>
)
})
}}
Expand Down
8 changes: 7 additions & 1 deletion src/features/userSlice.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//@flow
import { createSlice } from "@reduxjs/toolkit"
import _reject from "lodash/reject"

import userAPIService from "services/usersAPI"
import type { ObjectInsideFolderWithTags } from "types"
Expand All @@ -18,11 +19,16 @@ const userSlice: any = createSlice({
initialState,
reducers: {
setUser: (state, action) => action.payload,
deleteTemplateByAccessionId: (state, action) => {
state.templates = _reject(state.templates, template => {
return template.accessionId === action.payload
})
},
resetUser: () => initialState,
},
})

export const { setUser, resetUser } = userSlice.actions
export const { setUser, resetUser, deleteTemplateByAccessionId } = userSlice.actions
export default userSlice.reducer

export const fetchUserById =
Expand Down
5 changes: 5 additions & 0 deletions src/services/templateAPI.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@ const getTemplateByAccessionId = async (objectType: string, accessionId: string)
return await api.get(`/${objectType}/${accessionId}`)
}

const deleteTemplateByAccessionId = async (objectType: string, accessionId: string): Promise<any> => {
return await api.delete(`/${objectType}/${accessionId}`)
}

export default {
createTemplatesFromJSON,
getTemplateByAccessionId,
deleteTemplateByAccessionId,
}

0 comments on commit 11de60f

Please sign in to comment.