Skip to content

Commit

Permalink
feat(website): Make users accept ENA submission and warn of duplicati…
Browse files Browse the repository at this point in the history
…ons (#2276)

---------

Co-authored-by: Theo Sanderson <[email protected]>
  • Loading branch information
anna-parker and theosanderson authored Jul 10, 2024
1 parent 1383335 commit dbb1d5a
Show file tree
Hide file tree
Showing 8 changed files with 108 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,10 @@ Additionally, the column 'accession' is required and must match the accession of

const val SUBMIT_DESCRIPTION = """
Submit new data as multipart/form-data.
The user submits data on behalf of a group that they must be a member of.
The user submits data on behalf of a group that they must be a member of. After submission this data will be released
to INSDC, by using this endpoint the user confirms they have not and will not submit this data independently to INSDC
and they agree to Loculus handling the submission of this data to INSDC. Uploading this data independently to INSDC
may cause data duplication.
"""

const val REVISE_DESCRIPTION = """
Expand Down
5 changes: 2 additions & 3 deletions website/src/components/DataUseTerms/DataUseTermsSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ const DataUseTermsSelector: FC<DataUseTermsSelectorProps> = ({ dataUseTermsType,
</label>
<div className='text-xs pl-8 text-gray-500 pb-4'>
Anyone can use and share the data (though we believe researchers should exercise scientific
etiquette, including the importance of citation). Data will be released to the INSDC databases
shortly after submission.{' '}
etiquette, including the importance of citation).{' '}
<a href={routes.datauseTermsPage()} className='text-primary-600'>
Find out more
</a>
Expand All @@ -53,7 +52,7 @@ const DataUseTermsSelector: FC<DataUseTermsSelectorProps> = ({ dataUseTermsType,
Restricted
</label>
<div className='text-xs pl-8 text-gray-500 mb-4'>
Data will be restricted for a period of time. The sequences will be available but there will be
Data use will be restricted for a period of time. The sequences will be available but there will be
limitations on how they can be used by others.{' '}
<a href={routes.datauseTermsPage()} className='text-primary-600'>
Find out more
Expand Down
71 changes: 67 additions & 4 deletions website/src/components/Submission/DataUploadForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,13 @@ const DataUseTerms = ({
/>
)}
<div>
<h2 className='font-medium text-lg'>Terms of use</h2>
<p className='text-gray-500 text-sm'>Specify how your data can be used</p>
<h2 className='font-medium text-lg'>Data use terms</h2>
<p className='text-gray-500 text-sm'>Choose how your data can be used</p>
</div>
<div className=' grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6 col-span-2'>
<div className='sm:col-span-4 px-8'>
<label htmlFor='username' className='block text-sm font-medium leading-6 text-gray-900'>
Terms of use for these data
Terms of use for this data set
</label>
<div className='mt-2'>
<div className='mt-6 space-y-2'>
Expand All @@ -79,7 +79,7 @@ const DataUseTerms = ({
/>
{dataUseTermsType === restrictedDataUseTermsType && (
<div className='text-sm pl-6 text-gray-900 mb-4'>
Data will be restricted until <b>{restrictedUntil.toFormat('yyyy-MM-dd')}</b>.{' '}
Data use will be restricted until <b>{restrictedUntil.toFormat('yyyy-MM-dd')}</b>.{' '}
<button
className='border rounded px-2 py-1 '
onClick={() => setDateChangeModalOpen(true)}
Expand Down Expand Up @@ -281,6 +281,8 @@ const InnerDataUploadForm = ({
const [dataUseTermsType, setDataUseTermsType] = useState<DataUseTermsType>(openDataUseTermsType);
const [restrictedUntil, setRestrictedUntil] = useState<DateTime>(dateTimeInMonths(6));

const [agreedToINSDCUploadTerms, setAgreedToINSDCUploadTerms] = useState(false);

const isClient = useClientFlag();

const handleLoadExampleData = async () => {
Expand All @@ -298,6 +300,11 @@ const InnerDataUploadForm = ({
const handleSubmit = async (event: FormEvent) => {
event.preventDefault();

if (!agreedToINSDCUploadTerms) {
onError('Please tick the box agree that you will not independently submit these sequences to INSDC');
return;
}

if (!metadataFile) {
onError('Please select metadata file');
return;
Expand Down Expand Up @@ -402,6 +409,62 @@ const InnerDataUploadForm = ({
setRestrictedUntil={setRestrictedUntil}
/>
)}
<div className='grid sm:grid-cols-3 gap-x-16 pt-10'>
<div className=''>
<h2 className='font-medium text-lg'>Acknowledgement</h2>
<p className='text-gray-500 text-sm'>Acknowledge submission terms</p>
</div>
<div className='sm:col-span-2 grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6 col-span-2'>
<div className='sm:col-span-4 px-8'>
{dataUseTermsType === restrictedDataUseTermsType && (
<p className='block text-sm'>
Your data will be available on Pathoplexus, under the restricted use terms until{' '}
{restrictedUntil.toFormat('yyyy-MM-dd')}. After the restricted period your data will
additionally be made publicly available through the{' '}
<a href='https://www.insdc.org/' className='text-primary-600 hover:underline'>
INSDC
</a>{' '}
databases (ENA, DDBJ, NCBI).
</p>
)}
{dataUseTermsType === openDataUseTermsType && (
<p className='block text-sm'>
Your data will be available on Pathoplexus under the open use terms. It will
additionally be made publicly available through the{' '}
<a href='https://www.insdc.org/' className='text-primary-600 hover:underline'>
INSDC
</a>{' '}
databases (ENA, DDBJ, NCBI).
</p>
)}
<div className='mb-4 mt-3 py-5'>
<label className='flex items-center'>
<input
type='checkbox'
name='confirmation-INSDC-upload-terms'
className='mr-3 ml-1 h-5 w-5 rounded border-gray-300 text-blue focus:ring-blue'
checked={agreedToINSDCUploadTerms}
onChange={() => setAgreedToINSDCUploadTerms(!agreedToINSDCUploadTerms)}
/>
<div>
<p className='text-xs pl-4 text-gray-500'>
I confirm I have not and will not submit this data independently to INSDC,
to avoid data duplication. I agree to Loculus handling the submission of
this data to INSDC.{' '}
<a
href='/docs/concepts/insdc-submission'
className='text-primary-600 hover:underline'
>
Find out more.
</a>
</p>
</div>
</label>
</div>
</div>
</div>
</div>

<div className='flex items-center justify-end gap-x-6 pt-3'>
<button
name='submit'
Expand Down
26 changes: 26 additions & 0 deletions website/src/components/Submission/SubmissionForm.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ describe('SubmitForm', () => {
const { getByLabelText, getByText } = renderSubmissionForm();

await userEvent.upload(getByLabelText(/Metadata File/i), metadataFile);
await userEvent.click(
getByLabelText(/I confirm I have not and will not submit this data independently to INSDC/i),
);

const submitButton = getByText('Submit sequences');
await userEvent.click(submitButton);
Expand Down Expand Up @@ -110,11 +113,34 @@ describe('SubmitForm', () => {
await submitAndExpectErrorMessageContains(expectedErrorMessage);
});

test('should allow submission only after agreeing to terms of INSDC submission', async () => {
const { getByText, getByLabelText } = renderSubmissionForm();

const submitButton = getByText('Submit sequences');
await userEvent.click(submitButton);
await waitFor(() => {
expect(
getByText((text) =>
text.includes(
'Please tick the box agree that you will not independently submit these sequences to INSDC',
),
),
).toBeInTheDocument();
});

await userEvent.click(
getByLabelText(/I confirm I have not and will not submit this data independently to INSDC/i),
);
});

async function submitAndExpectErrorMessageContains(receivedUnexpectedMessageFromBackend: string) {
const { getByLabelText, getByText } = renderSubmissionForm();

await userEvent.upload(getByLabelText(/Metadata file/i), metadataFile);
await userEvent.upload(getByLabelText(/Sequence file/i), sequencesFile);
await userEvent.click(
getByLabelText(/I confirm I have not and will not submit this data independently to INSDC/i),
);

const submitButton = getByText('Submit sequences');
await userEvent.click(submitButton);
Expand Down
7 changes: 1 addition & 6 deletions website/src/components/User/GroupCreationForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,7 @@ const InnerGroupCreationForm: FC<GroupManagerProps> = ({ clientConfig, accessTok
<form onSubmit={handleCreateGroup}>
<div className='border-b border-gray-900/10 pb-12 '>
<p className='mt-1 text-sm leading-6 text-gray-600'>
Fill out following form to create a new submitting group.
</p>

<p className='mt-1 text-sm leading-6 text-red-600'>
Please note that the information you enter on this form will be publicly available on your group
page.
The information you enter on this form will be publicly available on your group page.
</p>

<div className='mt-5 grid grid-cols-1 gap-x-6 gap-y-4 sm:grid-cols-6'>
Expand Down
1 change: 1 addition & 0 deletions website/tests/pages/revise/revise.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export class RevisePage {
public async submitRevisedData(accessions: Accession[]) {
await this.setSequenceFile();
await this.setRevisedMetadataFile(accessions);
await this.page.getByText('I confirm I have not and will not submit this data independently to INSDC').click();
await this.page.getByRole('button', { name: 'Submit' }).click();
}

Expand Down
4 changes: 3 additions & 1 deletion website/tests/pages/submission/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ test.describe('The submit page', () => {

await Promise.all([submitPage.uploadSequenceData(), submitPage.uploadMetadata()]);

await submitPage.confirmationINSDCTerms.click();
await submitPage.submitButton.click();

await submitPage.page.waitForURL(`${baseUrl}${routes.userSequenceReviewPage(dummyOrganism.key, groupId)}`);
Expand All @@ -29,6 +30,7 @@ test.describe('The submit page', () => {

await Promise.all([submitPage.uploadCompressedSequenceData(), submitPage.uploadCompressedMetadata()]);

await submitPage.confirmationINSDCTerms.click();
await submitPage.submitButton.click();

await submitPage.page.waitForURL(`${baseUrl}${routes.userSequenceReviewPage(dummyOrganism.key, groupId)}`);
Expand All @@ -41,7 +43,7 @@ test.describe('The submit page', () => {

await Promise.all([submitPage.uploadSequenceData(), submitPage.uploadMetadata()]);
await submitPage.selectRestrictedDataUseTerms();

await submitPage.confirmationINSDCTerms.click();
await submitPage.submitButton.click();
await expect(submitPage.page.getByText('Response Sequence Headers')).toBeVisible();

Expand Down
4 changes: 4 additions & 0 deletions website/tests/pages/submission/submit.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,15 @@ import {

export class SubmitPage {
public readonly submitButton: Locator;
public readonly confirmationINSDCTerms: Locator;
public readonly dataUseTermsDropdown: Locator;
public readonly loginButton: Locator;

constructor(public readonly page: Page) {
this.submitButton = page.getByRole('button', { name: 'submit' });
this.confirmationINSDCTerms = page.getByText(
'I confirm I have not and will not submit this data independently to INSDC',
);
this.dataUseTermsDropdown = page.locator('#dataUseTermsDropdown');
this.loginButton = page.locator('a', { hasText: 'Login or register' });
}
Expand Down

0 comments on commit dbb1d5a

Please sign in to comment.