diff --git a/src/Routes.jsx b/src/Routes.jsx index 2456bc979..219c8411f 100644 --- a/src/Routes.jsx +++ b/src/Routes.jsx @@ -38,7 +38,6 @@ import TermsOfServiceAcceptance from './pages/TermsOfServiceAcceptance'; import {HealthCheck} from './pages/HealthCheck'; import DataSubmissionForm from './pages/data_submission/DataSubmissionForm'; import {ensureSoHasDaaAcknowledgement} from './components/SigningOfficialDaaAgreementWrapper'; -import CustomDatasetCatalog from './pages/dac_dataset_catalog/CustomDatasetCatalog'; import {AnVILDMSPolicyInfo, NIHDMSPolicyInfo} from './pages/DMSPolicyInfo'; import {checkEnv, envGroups} from './utils/EnvironmentUtils'; import { DatasetUpdateForm } from './pages/DatasetUpdateForm'; @@ -101,7 +100,6 @@ const Routes = (props) => ( - {checkEnv(envGroups.NON_STAGING) && } diff --git a/src/images/broad_logo.png b/src/images/broad_logo.png deleted file mode 100644 index bb612994f..000000000 Binary files a/src/images/broad_logo.png and /dev/null differ diff --git a/src/images/sample_dac_logo.png b/src/images/sample_dac_logo.png deleted file mode 100644 index fc1e63732..000000000 Binary files a/src/images/sample_dac_logo.png and /dev/null differ diff --git a/src/libs/utils.js b/src/libs/utils.js index 704db3ee5..6bc891eb5 100644 --- a/src/libs/utils.js +++ b/src/libs/utils.js @@ -625,18 +625,6 @@ export const searchOnFilteredList = (searchTerms, originalList, filterFn, setFil setFilteredList(searchList); }; -export const getBooleanFromEventHtmlDataValue = (e) => { - if (!isNil(e)) { - if (!isNil(e.target)) { - const dataValue = e.target.getAttribute('data-value'); - if (!isNil(dataValue)) { - return dataValue.toLowerCase() === 'true'; - } - } - } - return false; -}; - export const hasDataSubmitterRole = (user) => { const roles = get('roles')(user); const dsRole = find({'roleId': 8})(roles); diff --git a/src/pages/DatasetCatalog.jsx b/src/pages/DatasetCatalog.jsx deleted file mode 100644 index 7d89deced..000000000 --- a/src/pages/DatasetCatalog.jsx +++ /dev/null @@ -1,777 +0,0 @@ -import {filter, find, flow, getOr, includes, isEmpty, isNil, isNull, map, isFunction} from 'lodash/fp'; -import React, {Fragment, useEffect, useState, useCallback } from 'react'; -import ReactTooltip from 'react-tooltip'; -import {ConfirmationDialog} from '../components/ConfirmationDialog'; -import TranslatedDulModal from '../components/modals/TranslatedDulModal'; -import {PageHeading} from '../components/PageHeading'; -import {PaginatorBar} from '../components/PaginatorBar'; -import {SearchBox} from '../components/SearchBox'; -import { DataSet } from '../libs/ajax/DataSet'; -import { DAR } from '../libs/ajax/DAR'; -import { DAC } from '../libs/ajax/DAC'; -import {Storage} from '../libs/storage'; -import {Theme} from '../libs/theme'; -import {getBooleanFromEventHtmlDataValue, USER_ROLES} from '../libs/utils'; -import {DataUseTranslation} from '../libs/dataUseTranslation'; -import {spinnerService} from '../libs/spinner-service'; -import { ArrowDropUp, ArrowDropDown } from '@mui/icons-material'; -import DuosLogo from '../images/duos-network-logo.svg'; -import style from './DatasetCatalog.module.css'; - -const tableBody = { - ...Theme.textTableBody, - padding: '8px 5px 8px 5px' -}; - -const canApplyForDataset = (dataset) => { - return !isNil(dataset.dacId) && dataset.dacApproval; -}; - -const extractDatasetProp = (propertyName, dataset) => { - const property = find({ propertyName })(dataset.properties); - return property?.propertyValue; -}; - -const isVisible = (dataset) => { - const openAccess = extractDatasetProp('Open Access', dataset); - const publicDataset = extractDatasetProp('Public Visibility', dataset); - const publicStudy = !isNil(dataset.study?.publicVisibility) ? dataset.study?.publicVisibility : true; - - const open = !isNil(openAccess) ? openAccess : false; - const dacApproved = (!isNil(dataset.dacApproval) && dataset.dacApproval); - const publiclyVisible = !isNil(publicDataset) ? publicDataset : publicStudy; - - return open || (dacApproved && publiclyVisible); -}; - -export default function DatasetCatalog(props) { - - const { - customDacDatasetPage - } = props; - - const isCustomDacDatasetPage = !isNil(customDacDatasetPage); - const color = isCustomDacDatasetPage ? customDacDatasetPage.colorKey : 'dataset'; - const dacFilter = customDacDatasetPage?.dacFilter; - - // Data states - const [currentUser, setCurrentUser] = useState({}); - const [datasetList, setDatasetList] = useState([]); - const [sort, setSort] = useState({ field: 'datasetIdentifier', dir: 1 }); - const [numDatasetsSelected, setNumDatasetsSelected] = useState(0); - const [selectedDatasets, setSelectedDatasets] = useState([]); - const [datasetsOnPage, setDatasetsOnPage] = useState([]); - - // Selection States - const [currentPageAllDatasets, setCurrentPageAllDatasets] = useState(1); - const [currentPageOnlySelected, setCurrentPageOnlySelected] = useState(1); - - const [useCustomFilter, setUseCustomFilter] = useState(isFunction(dacFilter)); - - const [dataUse, setDataUse] = useState(); - const [errorMessage, setErrorMessage] = useState(); - const [errorTitle, setErrorTitle] = useState(); - const [pageSize, setPageSize] = useState(10); - const [searchDulText, setSearchDulText] = useState(); - const [selectedDatasetId, setSelectedDatasetId] = useState(); - - // Modal States - const [showDatasetDelete, setShowDatasetDelete] = useState(false); - const [showDatasetEdit, setShowDatasetEdit] = useState(false); - const [showTranslatedDULModal, setShowTranslatedDULModal] = useState(false); - - const [filterToOnlySelected, setFilterToOnlySelected] = useState(false); - - - const applyDatasetSort = useCallback((sortParams, datasets) => { - const sortedList = datasets.sort((a, b) => { - const aVal = a[sortParams.field] || findPropertyValue(a, sortParams.field); - const bVal = b[sortParams.field] || findPropertyValue(b, sortParams.field); - return aVal.localeCompare(bVal, 'en', {numeric: true}) * sortParams.dir; - }); - setSort(sortParams); - setDatasetList(sortedList); - }, []); - - const getDatasets = useCallback(async () => { - let datasets = await DataSet.getDatasets(); - let localDacs = await getDacs(); - datasets = map((row, index) => { - row.checked = false; - row.ix = index; - row.dbGapLink = - getOr('')('propertyValue')(find({propertyName: 'url'})(row.properties)); - // Extracting these fields to make sorting easier - row['Dataset ID'] = row.datasetIdentifier; - row['Data Access Committee'] = findDacName(localDacs, row); - row['Disease Studied'] = findPropertyValue(row, 'Phenotype/Indication'); - row['Principal Investigator (PI)'] = row.study?.piName || findPropertyValue(row, 'Principal Investigator(PI)'); - row['# of Participants'] = findPropertyValue(row, '# of participants'); - row['Data Custodian'] = findPropertyValue(row, 'Data Depositor'); - return row; - })(datasets); - applyDatasetSort(sort, datasets); - }, [applyDatasetSort, sort]); - - useEffect(() => { - const selected = datasetList.filter((ds) => ds.checked); - - setNumDatasetsSelected(selected.length); - setSelectedDatasets(selected); - }, [datasetList]); - - useEffect(() => { - - const numPages = Math.ceil(selectedDatasets.length / pageSize); - // if we're past the last page, then - // go to the last page. - if (currentPageOnlySelected > numPages && numPages != 0) { - setCurrentPageOnlySelected(numPages); - } - }, [selectedDatasets, pageSize, currentPageOnlySelected]); - - // Initialize page data - useEffect( () => { - const init = async() => { - setCurrentUser(Storage.getCurrentUser()); - await getDatasets(); - ReactTooltip.rebuild(); - }; - init(); - }, [getDatasets]); - - useEffect( () => { - const doEnrichment = async() => { - spinnerService.showAll(); - const theCurrentPage = filterToOnlySelected ? currentPageOnlySelected : currentPageAllDatasets; - const searchTable = (query) => (row) => { - if (query) { - let text = JSON.stringify(row); - return text.toLowerCase().includes(query.toLowerCase()); - } - return true; - }; - const visibleDatasets = filterToOnlySelected ? selectedDatasets : datasetList; - const results = ( - visibleDatasets - .filter(searchTable(searchDulText)) - .filter((row) => { - return (useCustomFilter ? dacFilter(row) : true); - }) - .slice((theCurrentPage - 1) * pageSize, theCurrentPage * pageSize)); - await Promise.all(results.map(async (dataset) => { - - if (isNil(dataset.codeList)) { - if (!dataset.dataUse || isEmpty(dataset.dataUse)) { - dataset.codeList = 'None'; - } else { - const translations = await DataUseTranslation.translateDataUseRestrictions(dataset.dataUse); - const codes = []; - translations.map((restriction) => { - codes.push(restriction.alternateLabel || restriction.code); - }); - dataset.codeList = codes.join(', '); - } - } - })); - setDatasetsOnPage(results); - spinnerService.hideAll(); - }; - doEnrichment(); - - }, [searchDulText, pageSize, selectedDatasets, datasetList, filterToOnlySelected, currentPageOnlySelected, currentPageAllDatasets, dacFilter, useCustomFilter]); - - const getDacs = async () => { - let dacs = await DAC.list(false); - dacs = dacs.map(dac => { - return {id: dac.dacId, name: dac.name}; - }); - return dacs; - }; - - const currentPage = () => { - return (filterToOnlySelected ? currentPageOnlySelected : currentPageAllDatasets); - }; - - - const exportToRequest = async () => { - let datasets = []; - let datasetIdList = []; - selectedDatasets - .forEach(dataset => { - datasets.push({ - key: dataset.dataSetId, - value: dataset.dataSetId, - label: dataset.name, - concatenation: dataset.name, - }); - datasetIdList.push(dataset.dataSetId); - }); - const darBody = { - userId: Storage.getCurrentUser().userId, - datasets: datasets, - datasetId: datasetIdList - }; - const formData = await DAR.postDarDraft(darBody); - const referenceId = formData.referenceId; - props.history.push({ pathname: '/dar_application/' + referenceId }); - }; - - const openTranslatedDUL = async (dataUse) => { - const translations = await DataUseTranslation.translateDataUseRestrictions(dataUse); - setDataUse(translations); - setShowTranslatedDULModal(true); - }; - - const openDelete = (datasetId) => () => { - setShowDatasetDelete(true); - setSelectedDatasetId(datasetId); - }; - - const openEdit = (datasetId) => () => { - setShowDatasetEdit(true); - setSelectedDatasetId(datasetId); - }; - - const dialogHandlerDelete = async (e) => { - const answer = getBooleanFromEventHtmlDataValue(e); - if (answer) { - DataSet.deleteDataset(selectedDatasetId).then(() => { - getDatasets(); - setShowDatasetDelete(false); - }).catch(() => { - setShowDatasetDelete(true); - setErrorMessage('Please try again later.'); - setErrorTitle('Something went wrong'); - }); - } else { - setShowDatasetDelete(false); - setErrorMessage(undefined); - setErrorTitle(undefined); - } - }; - - const dialogHandlerEdit = async (e) => { - const answer = getBooleanFromEventHtmlDataValue(e); - if (answer) { - setShowDatasetEdit(false); - props.history.push({ pathname: `dataset_registration/${selectedDatasetId}` }); - } else { - setShowDatasetEdit(false); - setErrorMessage(undefined); - setErrorTitle(undefined); - } - }; - - const download = () => { - const listDownload = selectedDatasets; - let dataSetsId = []; - listDownload.forEach(dataset => { - dataSetsId.push(dataset.dataSetId); - }); - DataSet.downloadDataSets(dataSetsId, 'datasets.tsv'); - }; - - const handlePageChange = (page) => { - if (filterToOnlySelected) { - setCurrentPageOnlySelected(page); - } else { - setCurrentPageAllDatasets(page); - } - }; - - const handleSizeChange = (size) => { - setPageSize(size); - handlePageChange(1); - }; - - const handleSearchDul = (query) => { - setSearchDulText(query); - }; - - const searchTable = (query) => (row) => { - if (query) { - let text = JSON.stringify(row); - return text.toLowerCase().includes(query.toLowerCase()); - } - return true; - }; - - - const allOnPageSelected = () => { - - const filteredList = datasetsOnPage.filter(canApplyForDataset); - - return filteredList.length > 0 && filteredList.every((row) => { - return row.checked; - }); - }; - - const selectAllOnPage = (e) => { - const checked = isNil(e.target.checked) ? false : e.target.checked; - - const datasetIdsToCheck = datasetsOnPage.map((row) => { - return row.dataSetId; - }); - - const modifiedDatasetList = map((row) => { - if (canApplyForDataset(row)) { - if (datasetIdsToCheck.includes(row.dataSetId)) { - row.checked = checked; - } - } - - return row; - })(datasetList); - - // Update state - setDatasetList(modifiedDatasetList); - }; - - const checkSingleRow = (dataset) => (e) => { - const checked = isNil(e.target.checked) ? false : e.target.checked; - const selectedDatasets = map(row => { - if (row.dataSetId === dataset.dataSetId) { - if (canApplyForDataset(row)) { - row.checked = checked; - } - } - return row; - })(datasetList); - - // Update state - setDatasetList(selectedDatasets); - }; - - const unapprovedStyle = (dataset) => { - if (!isVisible(dataset)) { - return {cursor: 'default', opacity: '50%'}; - } - return {}; - }; - - const findPropertyValue = (dataSet, propName, defaultVal) => { - const defaultValue = isNil(defaultVal) ? '' : defaultVal; - return getOr(defaultValue)('propertyValue')(find({ propertyName: propName })(dataSet.properties)); - }; - - const findDacName = (dacs, dataSet) => { - return getOr('')('name')(find({ id: dataSet.dacId })(dacs)); - }; - - const getLinkDisplay = (dataSet, trIndex) => { - try { - const url = new URL(dataSet.dbGapLink); - return ( - - Link - - ); - } catch (e) { - return --; - } - }; - - const getSortDisplay = ({ field, label }) => { - return ( -
{ - let newSort = - sort.field === field - ? { field, dir: sort.dir * -1 } - : { field, dir: 1 }; - applyDatasetSort(newSort, datasetList); - }} - > - {label ? label : field} -
- - -
-
- ); - }; - - const isEditDatasetEnabled = (dataset) => { - // Study editing is not currently supported through existing edit page. - if (!isNull(getOr(null)('study.studyId')(dataset))) { - return false; - } - if (currentUser.isAdmin) { - return true; - } - // Chairpersons can only edit datasets they have direct access to via their DACs - if (currentUser.isChairPerson) { - return flow( - filter({name: USER_ROLES.chairperson}), - map('dacId'), - includes(dataset.dacId) - )(currentUser.roles); - } - return false; - }; - - const visibleDatasets = () => { - return (filterToOnlySelected ? selectedDatasets : datasetList); - }; - - return ( - -
-
-
- - {isCustomDacDatasetPage && ( -
- -
- )} -
-
-
- - {isCustomDacDatasetPage && ( -
- { - setUseCustomFilter(!useCustomFilter); - setCurrentPageOnlySelected(1); - setCurrentPageAllDatasets(1); - }} - /> - -
- )} -
- { - (currentUser.isAdmin || currentUser.isChairPerson) && ( - - ) - } -
-
-
-
-
- - -
-
-
-
-
- { - setFilterToOnlySelected(!filterToOnlySelected); - }} - /> - -
- -
- - - - - )} - - - - - - - - - - - - - - - - {!isNil(visibleDatasets()) && !isEmpty(visibleDatasets()) && datasetsOnPage.map((dataset, trIndex) => ( - - - - {(currentUser.isAdmin || currentUser.isChairPerson) && ( - - )} - - - - - - - - - - - - - - - ))} - -
- {(currentUser.isAdmin || currentUser.isChairPerson) && ( - Actions{getSortDisplay({ field: 'datasetIdentifier', label: 'Dataset ID' })}{getSortDisplay({ field: 'Dataset Name' })}{getSortDisplay({ field: 'Data Access Committee' })}Data SourceData Use Terms{getSortDisplay({ field: 'Data Type' })}{getSortDisplay({ field: 'Disease Studied' })}{getSortDisplay({ field: 'Principal Investigator (PI)' })}{getSortDisplay({ field: '# of Participants' })}{getSortDisplay({ field: 'Description' })}{getSortDisplay({ field: 'Species' })}{getSortDisplay({ field: 'Data Custodian' })}
-
- {!isNil(dataset.dacId) && ( - <> - -
-
- - - {dataset['Dataset ID']} - - {dataset.name} - - {dataset['Data Access Committee']} - - {getLinkDisplay(dataset, trIndex)} - - openTranslatedDUL(dataset.dataUse)} - className={!isVisible(dataset) ? style['dataset-disabled'] : 'enabled'} - > - {dataset.codeList} - - - {findPropertyValue(dataset, 'Data Type')} - - {dataset['Disease Studied']} - - {dataset['Principal Investigator (PI)']} - - {dataset['# of Participants']} - - {findPropertyValue(dataset, 'Description')} - - {findPropertyValue(dataset, 'Species')} - - {dataset['Data Custodian']} -
-
-
- -
-
-
- { (currentUser.isAdmin || currentUser.isChairPerson || currentUser.isMember || currentUser.isSigningOfficial) && ( - - )} -
-
- {currentUser.isResearcher && ( -
- -
- )} -
- {showTranslatedDULModal && ( - setShowTranslatedDULModal(false)} - /> - )} - dialogHandlerDelete }} - > -
Are you sure you want to delete this Dataset?
-
- dialogHandlerEdit }} - > -
Are you sure you want to edit this Dataset?
-
- - -
- - ); -} diff --git a/src/pages/DatasetCatalog.module.css b/src/pages/DatasetCatalog.module.css deleted file mode 100644 index b6ece3687..000000000 --- a/src/pages/DatasetCatalog.module.css +++ /dev/null @@ -1,112 +0,0 @@ -.first-child { - position: absolute; - margin-left: -40px; -} - -.checkbox { - margin-top: 0; - display: inline; -} - -.checkbox label { - padding-top: 1px; -} - -.checkbox[disabled] .regular-checkbox { - cursor: not-allowed !important; - opacity: 0.65; -} - -.checkbox[disabled] .regular-checkbox:before { - background-color: #eee; - border: 1px solid #ccc; -} - -.regular-checkbox { - cursor: pointer; - position: relative; - padding-left: 25px !important; - margin-right: 15px; - margin-bottom: 15px; - font-size: 13px; -} - -.regular-checkbox.normal { - font-weight: normal; - font-size: 15px; - color: #777777; -} - -.regular-checkbox:before { - content: ""; - width: 18px; - height: 18px; - margin-right: 10px; - position: absolute; - left: 0; - background-color: #ffffff; - border-radius: 3px; -} - -.form-control, .regular-checkbox:before { - border: 1px solid #999999; -} - -.cell-size { - white-space: nowrap; - overflow: hidden; - width: 1%; -} - -.cell-size p { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - max-width: 400px!important; -} - -.table-scroll { - overflow-x: scroll; - margin: 0 25px 5px 60px; - overflow-y: visible; -} - -.table-scroll-admin { - overflow-x: scroll; - margin: 0 25px 5px 60px !important; - overflow-y: visible; -} - -.table-scroll-admin thead, .table-scroll thead { - padding: 0 10px 0 10px; -} - -.display-inline-block { - display: inline-block !important; -} - -.dataset-actions { - display: inline !important; - margin: 0; - padding-right: 10px; -} - -.dataset-actions a { - display: inline !important; - margin: 0 5px 0 0; -} - -.dataset-actions a:hover span { - color: #2FA4E7 !important; -} - -.dataset-actions a .glyphicon { - text-shadow: 1px 1px 0 #ffffff !important; - padding: 0; - vertical-align: bottom; - font-size: 1.15em; -} - -.dataset-disabled, .dataset-disabled p, .dataset-disabled a { - color: #cccccc !important; -} diff --git a/src/pages/dac_dataset_catalog/CustomDatasetCatalog.css b/src/pages/dac_dataset_catalog/CustomDatasetCatalog.css deleted file mode 100644 index bbbbf4fc2..000000000 --- a/src/pages/dac_dataset_catalog/CustomDatasetCatalog.css +++ /dev/null @@ -1,31 +0,0 @@ -/** -Add colors for each page variant that you include. The color key is an option of each variant - -// Text color for title -.[colorKey]-color { - color: <> !important; -} - -// Button color -.[colorKey]-background { - background: <> !important; -} -**/ - -/* Sample color scheme */ -.sample-color { - color: #ff0000 !important; -} - -.sample-background { - background: #ff0000 !important; -} - -/* Broad color scheme */ -.broad-color { - color: #0948B7 !important; -} - -.broad-background { - background: #0948B7 !important; -} \ No newline at end of file diff --git a/src/pages/dac_dataset_catalog/CustomDatasetCatalog.jsx b/src/pages/dac_dataset_catalog/CustomDatasetCatalog.jsx deleted file mode 100644 index 808c91731..000000000 --- a/src/pages/dac_dataset_catalog/CustomDatasetCatalog.jsx +++ /dev/null @@ -1,64 +0,0 @@ -import React from 'react'; -import _ from 'lodash'; -import '../DatasetCatalog'; -import SampleLogoIcon from '../../images/sample_dac_logo.png'; -import BroadLogoIcon from '../../images/broad_logo.png'; -import NotFound from '../NotFound'; -import DatasetCatalog from '../DatasetCatalog'; -import './CustomDatasetCatalog.css'; - - -/** - * Variants can be added and must include the following: - * path: the last element of the path that will identify this catalog variant - * icon: an icon for the catalog variant. It should have as close to a 4x1 ratio as possible - * dacName: the name of the DAC that this catalog is for - * dacFilter: filter method to get the datasets to show on the catalog by default. Return true to include - * the referenced dataset. The callback takes: - * dataset: the datataset to evaluate. The content of the dataset may vary, as a result to see what - * fields are available, open the developer console and go to the sample page. The datasets will - * echoed to the console in dev or local mode - * colorKey: the key of the color scheme for the catalog. See the CustomDatasetCatalog.css file for - * instructions on how to use the colorKey - */ -const variants = (env) => [ - { - path: 'sample', - icon: SampleLogoIcon, - dacName: 'Sample', - dacFilter: (dataset) => { - // eslint-disable-next-line no-console - (_.indexOf(['local', 'dev'], env) > -1) && console.log(dataset); - return dataset['Data Access Committee'] === 'Demo Dac New'; - }, - colorKey: 'sample' - }, - { - path: 'broad', - icon: BroadLogoIcon, - dacName: 'Broad', - dacFilter: (dataset) => dataset.dacId === 4, - colorKey: 'broad' - }, -]; - -export const CustomDatasetCatalog = (props) => { - const { history, match: { params: { variant } }, env } = props; - - const resolvedVariants = variants(env); - const findVariant = (variant) => _.find(resolvedVariants, v => v.path === variant); - - const variantDef = findVariant(variant); - if (_.isEmpty(variantDef)) { - return ; - } - - return ( - - ); -}; - -export default CustomDatasetCatalog; \ No newline at end of file