Skip to content

Commit

Permalink
Disable possibility to add more than one study in a submission (merge…
Browse files Browse the repository at this point in the history
… commit)

Merge branch 'bugfix/allow-only-one-study' into 'main'
* fix and refactor with util function preventing multiple studies

* disable submitting multiple draft studies

* remove unused prop

* disable autosave for study drafts in case of submitted study

* rebase on main

* fix being able to add erroneously a draft study via alert

* disable study XML upload when existing study

* disable adding a study draft when already existing study

* Disable possibility to add more than one study in a submission

See merge request https://gitlab.ci.csc.fi/sds-dev/sd-submit/metadata-submitter-frontend/-/merge_requests/1030

Approved-by: Hang Le <[email protected]>
Co-authored-by: Liisa Lado-Villar <[email protected]>
Merged by Hang Le <[email protected]>
  • Loading branch information
Hang Le committed Dec 31, 2024
2 parents 71dc9a7 + b0d1ad1 commit a107a93
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,15 @@ import saveDraftHook from "../WizardHooks/WizardSaveDraftHook"
import WizardDraftSelections from "./WizardDraftSelections"

import { ResponseStatus } from "constants/responseStatus"
import { ObjectStatus } from "constants/wizardObject"
import { ObjectStatus, ObjectTypes } from "constants/wizardObject"
import { resetDraftStatus } from "features/draftStatusSlice"
import { updateStatus } from "features/statusMessageSlice"
import { setAlert, resetAlert } from "features/wizardAlertSlice"
import { resetCurrentObject } from "features/wizardCurrentObjectSlice"
import { useAppSelector, useAppDispatch } from "hooks"
import objectAPIService from "services/objectAPI"
import type { ObjectInsideSubmissionWithTags } from "types"
import { getStudyStatus } from "utils"

const CustomDialog = styled(Dialog)(({ theme }) => ({
"& .MuiDialog-paper": {
Expand Down Expand Up @@ -112,6 +113,8 @@ const CancelFormDialog = ({
const [errorMessage, setErrorMessage] = useState("")
const dispatch = useAppDispatch()

const submittedStudy: boolean = getStudyStatus(submission.metadataObjects)

// Draft save logic
const saveDraft = async () => {
setError(false)
Expand Down Expand Up @@ -181,6 +184,7 @@ const CancelFormDialog = ({
saveDraft()
}}
color="primary"
disabled={submittedStudy && objectType === ObjectTypes.study}
>
{t("alerts.actions.saveDraft")}
</Button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ import type {
ObjectDisplayValues,
FormRef,
} from "types"
import { getObjectDisplayTitle, getAccessionIds, getNewUniqueFileTypes } from "utils"
import { getObjectDisplayTitle, getAccessionIds, getNewUniqueFileTypes, getStudyStatus } from "utils"
import { dereferenceSchema } from "utils/JSONSchemaUtils"

const StickyContainer = styled(Container)(({ theme }) => ({
Expand Down Expand Up @@ -143,6 +143,8 @@ const Form = styled("form")(({ theme }) => ({
}))

type CustomCardHeaderProps = {
updateStudy: boolean
updateStudyDraft: boolean
objectType: string
currentObject: ObjectDetails
onClickSaveDraft: () => Promise<void>
Expand All @@ -162,6 +164,8 @@ type FormContentProps = {
onSubmit: SubmitHandler<FieldValues>
objectType: string
submission: SubmissionDetailsWithId
updateStudy: boolean
updateStudyDraft: boolean
currentObject: ObjectDetails & { objectId: string; [key: string]: unknown }
closeDialog: () => void
formRef?: FormRef
Expand All @@ -172,6 +176,8 @@ type FormContentProps = {
*/
const CustomCardHeader = (props: CustomCardHeaderProps) => {
const {
updateStudy,
updateStudyDraft,
objectType,
currentObject,
refForm,
Expand Down Expand Up @@ -217,6 +223,7 @@ const CustomCardHeader = (props: CustomCardHeaderProps) => {
onClearForm={onClickClearForm}
onOpenXMLModal={onOpenXMLModal}
onDeleteForm={onDeleteForm}
existStudy={updateStudy}
/>
<ButtonGroup>
<Button
Expand All @@ -225,8 +232,9 @@ const CustomCardHeader = (props: CustomCardHeaderProps) => {
size="small"
onClick={onClickSaveDraft}
data-testid="form-draft"
disabled={updateStudy}
>
{currentObject?.status === ObjectStatus.draft
{updateStudyDraft || currentObject?.status === ObjectStatus.draft
? t("formActions.updateDraft")
: t("formActions.saveAsDraft")}
</Button>
Expand All @@ -238,8 +246,10 @@ const CustomCardHeader = (props: CustomCardHeaderProps) => {
onClick={onClickSubmit}
form={refForm}
data-testid="form-ready"
disabled={currentObject?.status === ObjectStatus.draft
&& updateStudy}
>
{currentObject?.status === ObjectStatus.submitted
{(updateStudy)
? t("formActions.update")
: t("formActions.markAsReady")}
</Button>
Expand All @@ -252,6 +262,9 @@ const CustomCardHeader = (props: CustomCardHeaderProps) => {
<WizardOptions
objectType={objectType}
onClearForm={onClickClearForm}
onOpenXMLModal={onOpenXMLModal}
onDeleteForm={onDeleteForm}
existStudy={updateStudy}
/>
<ButtonGroup>
<Button
Expand Down Expand Up @@ -329,6 +342,8 @@ const FormContent = ({
formSchema,
onSubmit,
objectType,
updateStudy,
updateStudyDraft,
submission,
currentObject,
closeDialog,
Expand Down Expand Up @@ -381,7 +396,6 @@ const FormContent = ({
resetTimer()
methods.reset({ undefined })
dispatch(setClearForm(true))
dispatch(resetDraftStatus())
}

// Check if the form is empty
Expand Down Expand Up @@ -484,7 +498,7 @@ const FormContent = ({
if (alert) resetTimer()

if (draftAutoSaveAllowed) {
handleSaveDraft()
if (!updateStudy) handleSaveDraft()
resetTimer()
}
}, [draftAutoSaveAllowed, alert])
Expand Down Expand Up @@ -571,7 +585,7 @@ const FormContent = ({
resetTimer()
const cleanedValues = getCleanedValues()

if (checkFormCleanedValuesEmpty(cleanedValues)) {
if ( !updateStudy && checkFormCleanedValuesEmpty(cleanedValues)) {
const handleSave = await saveDraftHook({
accessionId: currentObject.accessionId || currentObject.objectId,
objectType: objectType,
Expand Down Expand Up @@ -627,6 +641,8 @@ const FormContent = ({
return (
<FormProvider {...methods}>
<CustomCardHeader
updateStudy={updateStudy}
updateStudyDraft={updateStudyDraft}
objectType={objectType}
currentObject={currentObject}
refForm="hook-form"
Expand Down Expand Up @@ -666,6 +682,12 @@ const WizardFillObjectDetailsForm = (props: { closeDialog?: () => void; formRef?
const locale = useAppSelector(state => state.locale)
const openedXMLModal = useAppSelector(state => state.openedXMLModal)

const submittedStudy: boolean = getStudyStatus(submission.metadataObjects)
const submittedStudyDrafts: boolean = getStudyStatus(submission.drafts, "draft")

const updateStudy = submittedStudy && (objectType === ObjectTypes.study)
const updateStudyDraft = submittedStudyDrafts && (objectType === ObjectTypes.study)

// States that will update in useEffect()
const [states, setStates] = useState({
error: false,
Expand Down Expand Up @@ -797,15 +819,17 @@ const WizardFillObjectDetailsForm = (props: { closeDialog?: () => void; formRef?
}

// Either patch object or submit a new object
if (data.status === ObjectStatus.submitted) {
if (data.status === ObjectStatus.submitted || updateStudy) {
patchObject()
} else {
} else if (!updateStudy) {
submitObjectHook(data, submission.submissionId, objectType, dispatch)
.then(() => {
setSubmitting(false)
})
.catch(err => console.error(err))
}
} else {
setSubmitting(false)
}
}

if (states.isLoading) return <CircularProgress />
Expand All @@ -826,6 +850,8 @@ const WizardFillObjectDetailsForm = (props: { closeDialog?: () => void; formRef?
resolver={WizardAjvResolver(states.validationSchema, locale)}
onSubmit={onSubmit as SubmitHandler<FieldValues>}
objectType={objectType}
updateStudy={updateStudy}
updateStudyDraft={updateStudyDraft}
submission={submission}
currentObject={currentObject}
key={currentObject?.accessionId || submission.submissionId}
Expand Down
8 changes: 5 additions & 3 deletions src/components/SubmissionWizard/WizardForms/WizardOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ import { useTranslation } from "react-i18next"
type WizardOptionsProps = {
objectType: string,
onClearForm: () => void
onOpenXMLModal?: () => void
onDeleteForm?: () => void
onOpenXMLModal: () => void
onDeleteForm: () => void
existStudy: boolean
}

const WizardOptions: React.FC<WizardOptionsProps> = props => {
const { objectType, onClearForm, onOpenXMLModal, onDeleteForm } = props
const { objectType, onClearForm, onOpenXMLModal, onDeleteForm, existStudy } = props
const { t } = useTranslation()

const options = objectType !== "datacite"
Expand Down Expand Up @@ -74,6 +75,7 @@ const WizardOptions: React.FC<WizardOptionsProps> = props => {
<MenuItem
key={option}
selected={index === 0}
disabled={existStudy && index === 0}
onClick={e => handleClose(e, option)}
sx={{
p: "1.2rem",
Expand Down
8 changes: 8 additions & 0 deletions src/utils/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type {
FormDataFiles,
ObjectDisplayValues,
ObjectInsideSubmissionWithTags,
ObjectInsideSubmission,
} from "types"

export const getObjectDisplayTitle = (
Expand Down Expand Up @@ -137,3 +138,10 @@ export const getConvertedDate = (timestamp: number): string => {
// Check if it's a file or a subfolder (current path equals original file path)
export const isFile = (files: File[], path: string) =>
files.findIndex(file => file.path === path) > -1

// Check if submission contains studies
export const getStudyStatus = (submissionObjects: ObjectInsideSubmission[], typeDraft?: string) => {
if (typeDraft === "draft") {
return submissionObjects.filter(object => object.schema === "draft-study").length > 0
} else return submissionObjects.filter(object => object.schema === ObjectTypes.study).length > 0
}

0 comments on commit a107a93

Please sign in to comment.