Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DCJ-47] UI: Enable DAA Restriction in Data Library #2636

Draft
wants to merge 11 commits into
base: develop
Choose a base branch
from
102 changes: 102 additions & 0 deletions src/components/data_search/ApplyForAccess.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import React, {useEffect, useState} from 'react';
import {Button} from '@mui/material';
import {DAA} from '../../libs/ajax/DAA';
import {DAAUtils} from '../../utils/DAAUtils';
import {DAR} from '../../libs/ajax/DAR';
import {Storage} from '../../libs/storage';
import DatasetSelectionModal from './DatasetSelectionModal';


export default function ApplyForAccess(props) {

const { datasets, selectedDatasetKeys, history } = props;
const [showDatasetModal, setShowDatasetModal] = useState(false);
const [allowableTermSelections, setAllowableTermSelections] = useState([]);
const [openTermSelections, setOpenTermSelections] = useState([]);
const [externalTermSelections, setExternalTermSelections] = useState([]);
const [unselectableTermSelections, setUnselectableTermSelections] = useState([]);

useEffect(() => {
const init = async () => {
// Logical cases:
// 1. If the user has access to all datasets - go straight to apply
// 2. If the user has access to some datasets show the partially selected datasets modal
// 3. If the user requests access to Open or External Access datasets, show the partially selected datasets modal
// 4. If the user has no access to any datasets, show custom message in modal
const allDAAs = await DAA.getDaas();
const selectedDatasetIds = selectedDatasetKeys.map((id) => parseInt(id.replace('dataset-', '')));
const selectedTerms = datasets.filter(d => selectedDatasetIds.includes(d.datasetId));
const user = Storage.getCurrentUser();
const userLibraryCardDAAIds = user.libraryCards.flatMap(lc => lc.daaIds);
const userDAAs = allDAAs.filter(daa => userLibraryCardDAAIds.includes(daa.daaId));

// Ensure that the dataset's DAC is one of the DACs that match any of the DACs in the user's list of DAAs
let allowable = [];
let open = [];
let external = [];
let unAllowable = [];
selectedTerms.forEach(term => {
if (term.accessManagement === 'open') {
open.push(term);
} else if (term.accessManagement === 'external') {
external.push(term);
} else {
const selectedTermDacId = term.dac?.dacId;
const matchingDatasetDAA = userDAAs.filter(daa => {
const daaDacIds = daa.dacs?.map(dac => dac.dacId);
return daaDacIds?.includes(selectedTermDacId);
});
if (matchingDatasetDAA.length > 0) {
allowable.push(term);
} else {
unAllowable.push(term);
}
}
});
setAllowableTermSelections(allowable);
setOpenTermSelections(open);
setExternalTermSelections(external);
setUnselectableTermSelections(unAllowable);
};
init();
}, [datasets, selectedDatasetKeys]);

const preCheckApply = async () => {
const selectedDatasetIds = selectedDatasetKeys.map((id) => parseInt(id.replace('dataset-', '')));
const selectedTerms = datasets.filter(d => selectedDatasetIds.includes(d.datasetId));
if (allowableTermSelections.length === selectedTerms.length) {
// Go straight to Apply for Access:
await applyForAccess();
} else {
// Some combination of partially allowed, open, external, or no available terms are selected
setShowDatasetModal(true);
}
};

const applyForAccess = async () => {
const draftDatasetIds = allowableTermSelections.map((d) => d.datasetId);
const darDraft = await DAR.postDarDraft({ datasetId: draftDatasetIds });
history.push(`/dar_application/${darDraft.referenceId}`);
};

return (
<>
<Button variant="contained" onClick={() => DAAUtils.isEnabled() ? preCheckApply() : applyForAccess()} sx={{ transform: 'scale(1.5)' }} >
Apply for Access
</Button>
{
showDatasetModal &&
<DatasetSelectionModal
showModal={showDatasetModal}
onCloseRequest={()=>setShowDatasetModal(false)}
onApply={applyForAccess}
datasets={datasets}
allowableTermSelections={allowableTermSelections}
openTermSelections={openTermSelections}
externalTermSelections={externalTermSelections}
unselectableTermSelections={unselectableTermSelections}
/>
}
</>
);
}
17 changes: 6 additions & 11 deletions src/components/data_search/DatasetSearchTable.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import CollapsibleTable from '../CollapsibleTable';
import TableHeaderSection from '../TableHeaderSection';
import DatasetExportButton from './DatasetExportButton';
import { DataSet } from '../../libs/ajax/DataSet';
import { DAR } from '../../libs/ajax/DAR';
import eventList from '../../libs/events';
import { Config } from '../../libs/config';
import DatasetFilterList from './DatasetFilterList';
Expand All @@ -17,7 +16,7 @@ import { Styles } from '../../libs/theme';
import { TerraDataRepo } from '../../libs/ajax/TerraDataRepo';
import isEqual from 'lodash/isEqual';
import TranslatedDulModal from '../modals/TranslatedDulModal';

import ApplyForAccess from './ApplyForAccess';

const studyTableHeader = [
'Study Name',
Expand Down Expand Up @@ -245,12 +244,6 @@ export const DatasetSearchTable = (props) => {
setExportableDatasets({});
};

const applyForAccess = async () => {
const draftDatasets = selected.map((id) => parseInt(id.replace('dataset-', '')));
const darDraft = await DAR.postDarDraft({ datasetId: draftDatasets });
history.push(`/dar_application/${darDraft.referenceId}`);
};

const clearSearchRef = () => {
searchRef.current.value = '';
filterHandler(null, datasets, '', '');
Expand Down Expand Up @@ -472,9 +465,11 @@ export const DatasetSearchTable = (props) => {
<Box sx={{ display: 'flex', flexDirection: 'row', justifyContent: 'flex-end', padding: '2em 4em' }}>
{
!isEmpty(datasets) &&
<Button variant="contained" onClick={applyForAccess} sx={{ transform: 'scale(1.5)' }} >
Apply for Access
</Button>
<ApplyForAccess
history={history}
datasets={datasets}
selectedDatasetKeys={selected}>
</ApplyForAccess>
}
</Box>
</Box>
Expand Down
104 changes: 104 additions & 0 deletions src/components/data_search/DatasetSelectionModal.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import React, { useEffect } from 'react';
import {
Dialog, DialogTitle, DialogContent, DialogActions, Button
} from '@mui/material';

const listStyle = {
listStyle: 'none',
padding: '0',
fontSize:'1rem'
};

function FormattedDatasets({ datasets }) {
return (
<div style={{border: '0.5px solid #cccccc', borderRadius: '10px', overflow: 'auto', maxHeight: '150px'}}>
<ul key='dulUnorderedList' style={{...listStyle, border: '0.5px solid #cccccc', borderRadius: '10px', padding: '10px'}} id="txt_translatedRestrictions" className="row no-margin translated-restriction">
{datasets.map((dataset) => {
const displayName = dataset.datasetName.length > 50
? `${dataset.datasetName.substring(0, 50)}...`
: dataset.datasetName;
return <li key={dataset.dataSetId} className="translated-restriction"
style={{display: 'grid', gridTemplateColumns: '1fr 3.5fr'}}>
<span style={{fontWeight: 'bold'}}>{dataset.datasetIdentifier}</span>
<span style={{wordWrap: 'break-word'}}>{displayName}</span>
</li>;
})}
</ul>
</div>
);
}

export default function DatasetSelectionModal(props) {
const { showModal, onCloseRequest, onApply, allowableTermSelections, openTermSelections, externalTermSelections, unselectableTermSelections } = props;

useEffect(() => {
// console.log('allowableTermSelections:', allowableTermSelections);
// console.log('openTermSelections:', openTermSelections);
// console.log('externalTermSelections:', externalTermSelections);
// console.log('unselectableTermSelections:', unselectableTermSelections);
}, [allowableTermSelections, openTermSelections, unselectableTermSelections]);

const closeHandler = () => {
onCloseRequest();
};

return (
<Dialog
open={showModal}
onClose={closeHandler}
aria-labelledby='Datasets available for Data Access Request'
aria-describedby='Dialog Description'
sx={{ transform: 'scale(1.2)'}}
PaperProps={{
style: {
maxWidth: '500px',
width: '100%'
},
}}
fullWidth
>
<DialogTitle id='dialog-title'>
<span style={{ fontFamily: 'Montserrat', fontWeight: 600, fontSize: '2.0rem', color:'#1E1E1E'}}>Datasets available for Data Access Request</span>
</DialogTitle>
<DialogContent id='dialog-content'>
{(allowableTermSelections.length > 0) &&
<div>
<div style={{fontFamily: 'Montserrat', fontSize: '1.2rem', paddingBottom: '15px'}}>Based on your credentials
you can fill out a Data Access Request form for these dataset(s):
</div>
<FormattedDatasets datasets={allowableTermSelections}/>
</div>
}
{(unselectableTermSelections.length > 0) &&
<div>
<div style={{fontFamily: 'Montserrat', fontSize: '1.2rem', paddingBottom: '15px'}}>The requested datasets
require that your Signing Official issues you a Library Card before proceeding.
</div>
<FormattedDatasets datasets={unselectableTermSelections}/>
</div>
}
{(openTermSelections.length > 0) &&
<div>
<div style={{fontFamily: 'Montserrat', fontSize: '1.2rem', paddingBottom: '15px'}}>The following datasets
are Open Access and do not require a Data Access Request.
</div>
<FormattedDatasets datasets={openTermSelections}/>
</div>
}
{(externalTermSelections.length > 0) &&
<div>
<div style={{fontFamily: 'Montserrat', fontSize: '1.2rem', paddingBottom: '15px'}}>The following datasets
are External Access and do not require a Data Access Request.
</div>
<FormattedDatasets datasets={externalTermSelections}/>
</div>
}
</DialogContent>
<DialogActions id="dialog-footer">
<Button onClick={closeHandler} style={{fontSize: '1.1rem'}}>Cancel</Button>
{(allowableTermSelections.length > 0) &&
<Button onClick={() => onApply()} variant="contained" style={{fontSize: '1.1rem'}}>Apply</Button>}
</DialogActions>
</Dialog>
);
}
Loading