Skip to content

Commit

Permalink
[DUOS-2714] Add external access to data submission form (#2359)
Browse files Browse the repository at this point in the history
  • Loading branch information
fboulnois authored Oct 31, 2023
1 parent 6784bb6 commit f8b1abf
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 47 deletions.
7 changes: 3 additions & 4 deletions src/pages/data_submission/DataAccessGovernance.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,8 @@ export const DataAccessGovernance = (props) => {
const prefillConsentGroups = useCallback(async () => {
var consentGroups = await Promise.all(datasets?.map(async (dataset, idx) => {
const dataUse = await normalizeDataUse(dataset?.dataUse);
// DAC is required if openAccess is false
const openAccess = extract('Open Access', dataset);
const dac = openAccess ? undefined : await DAC.get(dataset?.dacId);
const accessManagement = extract('Access Management', dataset);
const dac = 'dacId' in dataset ? await DAC.get(dataset.dacId) : undefined;

return {
consentGroup: {
Expand All @@ -130,7 +129,7 @@ export const DataAccessGovernance = (props) => {
hmb: dataUse.hmbResearch,
diseaseSpecificUse: dataUse.diseaseRestrictions,
poa: dataUse.populationOriginsAncestry,
openAccess: openAccess,
accessManagement: accessManagement,
otherPrimary: dataUse.other,

// secondary
Expand Down
2 changes: 1 addition & 1 deletion src/pages/data_submission/RegistrationValidation.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ const updateValidation = (existingValidation, validationError) => {
};
}
// if the field is required and empty, we shouldn't also error on, e.g., that it isn't a date format
if (existingValidation.failed.includes('required') || validationError === 'required') {
if ((existingValidation.failed && existingValidation.failed.includes('required')) || validationError === 'required') {
return {
valid: false,
failed: ['required']
Expand Down
8 changes: 6 additions & 2 deletions src/pages/data_submission/consent_group/ConsentGroupErrors.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ const invalidFormatError = (format) => {
export const computeConsentGroupValidationErrors = (consentGroup, datasetNames = []) => {
const validation = {};

if (isNil(selectedPrimaryGroup(consentGroup))) {
if (isNil(consentGroup.accessManagement)) {
validation.accessManagement = requiredError;
}

if (isNil(selectedPrimaryGroup(consentGroup)) && consentGroup.accessManagement !== 'open') {
validation.primaryConsent = requiredError;
}

Expand Down Expand Up @@ -61,7 +65,7 @@ export const computeConsentGroupValidationErrors = (consentGroup, datasetNames =
validation.otherPrimary = requiredError;
}

if (isNil(consentGroup.dataAccessCommitteeId) && consentGroup.openAccess !== true) {
if (isNil(consentGroup.dataAccessCommitteeId) && consentGroup.accessManagement === 'controlled') {
validation.dataAccessCommitteeId = requiredError;
}

Expand Down
4 changes: 3 additions & 1 deletion src/pages/data_submission/consent_group/ConsentGroupForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@ export const ConsentGroupForm = (props) => {
datasetId: curConsentGroup.datasetId || null,
consentGroupName: curConsentGroup.consentGroupName || '',

// access management is one of: "controlled", "open", "external"
accessManagement: curConsentGroup.accessManagement || undefined, // string

// primary:
generalResearchUse: curConsentGroup.generalResearchUse || undefined,
hmb: curConsentGroup.hmb || undefined,
diseaseSpecificUse: curConsentGroup.diseaseSpecificUse || undefined, // string
poa: curConsentGroup.poa || undefined,
openAccess: curConsentGroup.openAccess || undefined,
otherPrimary: curConsentGroup.otherPrimary || undefined, // string

// secondary:
Expand Down
112 changes: 73 additions & 39 deletions src/pages/data_submission/consent_group/EditConsentGroup.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ export const selectedPrimaryGroup = (consentGroup) => {
return 'diseaseSpecificUse';
} else if (!isNil(consentGroup.poa) && consentGroup.poa) {
return 'poa';
} else if (!isNil(consentGroup.openAccess) && consentGroup.openAccess) {
return 'openAccess';
} else if (!isNil(consentGroup.otherPrimary) && isString(consentGroup.otherPrimary)) {
return 'otherPrimary';
}
Expand Down Expand Up @@ -75,7 +73,7 @@ export const EditConsentGroup = (props) => {
setConsentGroup((cg) => {
const consentGroup = cloneDeep(cg);

updates.forEach(({key, value}) => {
updates.forEach(({ key, value }) => {
consentGroup[key] = value;
});

Expand All @@ -91,7 +89,6 @@ export const EditConsentGroup = (props) => {
hmb: false,
diseaseSpecificUse: undefined,
poa: false,
openAccess: false,
otherPrimary: undefined,
},
...{
Expand Down Expand Up @@ -119,8 +116,62 @@ export const EditConsentGroup = (props) => {
onValidationChange,
}),

// primary
// controlled, open and external access
div({}, [
h(FormField, {
title: 'Data Access Management',
description: 'Select a data access management strategy',
id: idx + '_accessManagement_controlled',
name: 'accessManagement',
value: 'controlled',
type: FormFieldTypes.RADIOBUTTON,
toggleText: 'Controlled Access (managed by a DAC in DUOS)',
disabled: disableFields,
defaultValue: consentGroup.accessManagement,
onChange,
validation: validation.accessManagement,
onValidationChange: ({ validation }) => {
onValidationChange({ key: 'accessManagement', validation });
},
}),

h(FormField, {
id: idx + '_accessManagement_open',
name: 'accessManagement',
value: 'open',
type: FormFieldTypes.RADIOBUTTON,
toggleText: 'Open Access (does not need DAC approval)',
disabled: disableFields,
defaultValue: consentGroup.accessManagement,
onChange: ({ key, value }) => {
onPrimaryChange({ key, value });
},
validation: validation.accessManagement,
onValidationChange: ({ validation }) => {
onValidationChange({ key: 'accessManagement', validation });
},
}),

h(FormField, {
id: idx + '_accessManagement_external',
name: 'accessManagement',
value: 'external',
type: FormFieldTypes.RADIOBUTTON,
toggleText: 'External Access (managed by a DAC external to DUOS)',
disabled: disableFields,
defaultValue: consentGroup.accessManagement,
onChange,
validation: validation.accessManagement,
onValidationChange: ({ validation }) => {
onValidationChange({ key: 'accessManagement', validation });
},
}),
]),

// primary
div({
isRendered: consentGroup.accessManagement !== 'open',
}, [
h(FormField, {
title: 'Primary Data Use Terms*',
description: 'Please select one of the following data use permissions for your dataset',
Expand Down Expand Up @@ -229,23 +280,6 @@ export const EditConsentGroup = (props) => {
},
}),

h(FormField, {
type: FormFieldTypes.RADIOBUTTON,
id: idx + '_primaryConsent_openAccess',
name: 'primaryConsent',
value: 'openAccess',
toggleText: 'No Restrictions (Open Access Data)',
disabled: disableFields,
defaultValue: selectedPrimaryGroup(consentGroup),
onChange: ({ value }) => {
onPrimaryChange({ key: value, value: true });
},
validation: validation.primaryConsent,
onValidationChange: ({ validation }) => {
onValidationChange({ key: 'primaryConsent', validation });
},
}),

h(FormField, {
type: FormFieldTypes.RADIOBUTTON,
id: idx + '_primaryConsent_otherPrimary',
Expand Down Expand Up @@ -284,7 +318,7 @@ export const EditConsentGroup = (props) => {

// secondary
div({
isRendered: consentGroup.openAccess !== true,
isRendered: consentGroup.accessManagement !== 'open',
}, [
h(FormField, {
title: 'Secondary Data Use Terms',
Expand Down Expand Up @@ -460,10 +494,10 @@ export const EditConsentGroup = (props) => {

// data access committee
h(FormField, {
isRendered: consentGroup.openAccess !== true,
isRendered: consentGroup.accessManagement === 'controlled',
id: idx + 'dataAccessCommitteeId',
name: 'dataAccessCommitteeId',
title: 'Data Access Committee',
title: 'Data Access Committee (DAC)',
description: 'Please select which DAC should govern requests for this dataset',
type: FormFieldTypes.SELECT,
selectOptions: dacs.map((dac) => {
Expand All @@ -472,7 +506,7 @@ export const EditConsentGroup = (props) => {
onChange: ({ key, value }) => {
onChange({ key, value: value?.dacId });
},
validators: [FormValidators.REQUIRED],
validators: consentGroup.accessManagement === 'controlled' ? [FormValidators.REQUIRED] : undefined,
validation: validation.dataAccessCommitteeId,
disabled: disableFields,
defaultValue: dacs.map((dac) => {
Expand All @@ -483,17 +517,17 @@ export const EditConsentGroup = (props) => {
]),

// location
div({style:{ display: 'flex', flexDirection:'row', justifyContent: 'space-between' }}, [
div({ style: { display: 'flex', flexDirection: 'row', justifyContent: 'space-between' } }, [
h(FormFieldTitle, {
required: true,
title: 'Data Location',
description: 'Please provide the location of your data resource for this consent group',
}),
]),
div({className: 'flex flex-row'}, [
div({ className: 'flex flex-row' }, [
h(FormField, {
style: { width: '50%' },
id: idx+'_dataLocation',
id: idx + '_dataLocation',
name: 'dataLocation',
type: FormFieldTypes.SELECT,
selectOptions: [
Expand All @@ -504,22 +538,22 @@ export const EditConsentGroup = (props) => {
],
placeholder: 'Data Location(s)',
defaultValue: consentGroup.dataLocation,
onChange: ({key, value, isValid}) => {
onChange: ({ key, value, isValid }) => {

if (value === 'Not Determined') {
// if not determined, clear url field as well.
// must do in one batch call, otherwise react gets confused.
onBatchChange({ key, value }, {key: 'url', value: undefined});
onBatchChange({ key, value }, { key: 'url', value: undefined });
} else {
onChange({key, value, isValid});
onChange({ key, value, isValid });
}
},
validation: validation.dataLocation,
onValidationChange,
}),
h(FormField, {
style: { width: '50%', paddingLeft: '1.5%' },
id: idx+'_url',
id: idx + '_url',
name: 'url',
validators: [FormValidators.URL],
disabled: consentGroup.dataLocation === 'Not Determined',
Expand All @@ -532,7 +566,7 @@ export const EditConsentGroup = (props) => {
}),
]),
h(FormTable, {
id: idx+'_fileTypes',
id: idx + '_fileTypes',
name: 'fileTypes',
formFields: [
{
Expand Down Expand Up @@ -573,22 +607,22 @@ export const EditConsentGroup = (props) => {
}),
]),

div({style:{ display: 'flex', flexDirection:'row', justifyContent: 'flex-start', alignItems: 'flex-end', marginRight: '30px' }}, [
div({ style: { display: 'flex', flexDirection: 'row', justifyContent: 'flex-start', alignItems: 'flex-end', marginRight: '30px' } }, [
h(FormField, {
type: FormFieldTypes.FILE,
title: 'NIH Institutional Certification',
description: 'If an Institutional Certification for this consent group exists, please upload it here',
id: idx+'_nihInstituionalCertificationFile',
id: idx + '_nihInstituionalCertificationFile',
name: 'nihInstituionalCertificationFile',
hideTextBar: true,
hideInput: true,
}),
h(FormField, {
style: {margin: '11px'},
style: { margin: '11px' },
type: FormFieldTypes.FILE,
id: idx+'_fileInputSection',
id: idx + '_fileInputSection',
defaultValue: nihInstitutionalCertificationFile,
onChange: ({value}) => setNihInstitutionalCertificationFile(value),
onChange: ({ value }) => setNihInstitutionalCertificationFile(value),
hideTextBar: true,
}),
]),
Expand Down

0 comments on commit f8b1abf

Please sign in to comment.