Skip to content

Commit

Permalink
Kevin yoo/hmp 198 data transfer no public globus (#3152)
Browse files Browse the repository at this point in the history
* remove console

* delete consoles

* bulk data design setup

* update padding to 16px all around

* Gobus access message

* bulk data transfer header

* globus access styling

* remove login button

* Links to external sites

* links styling

* icon styling and alignment

* Links alignment icons and styling

* fix order of bulk data transfer

* globus

* add email icon

* tooltip

* target black rel noopener noreferrer

* conditional logic for rendering files component

* delete SRA bioproject section

* icon size adjustment

* fix files rendering logix

* table of contents linked to section

* logic for rendering files section

* changelog

* Update CHANGELOG-hmp-198-data-transfer-no-public-globus.md

Co-authored-by: Nikolay Akhmetov <[email protected]>

* Update context/app/static/js/components/detailPage/BulkDataTransfer/BulkDataTransfer.jsx

Co-authored-by: John Conroy <[email protected]>

* Update context/app/static/js/components/detailPage/BulkDataTransfer/BulkDataTransfer.jsx

Co-authored-by: Nikolay Akhmetov <[email protected]>

* remove duplicate files, create loggedin component to follow convention

* correct name

* fix typo in text

* fix spacing and period placement in text

* styledanchortag

* remove tooltip for dbGaP study

* tooltip for blocus Access

* Update context/app/static/js/components/detailPage/BulkDataTransfer/NotLoggedIn/ProtectedData/DbGaP.jsx

Co-authored-by: John Conroy <[email protected]>

* Update context/app/static/js/pages/Dataset/Dataset.jsx

Co-authored-by: Nikolay Akhmetov <[email protected]>

* use python route for login

* outboundlink cleanup

* member login button styling

* get color from theme and abstract it into styled component

* remove unused typography from files, rename external link to link container

* apply theme spacing

* snake case

* remove unused code

* Links refactor

* remove comments

* componentize and eslint

* variable name

* add BlockIcon and clenaup

* refactor outboundLink

* fix updated import

* fix import

* refactor Links shared style

* update path

* remove unused style;

* refactor Links component

* Links component

* refactor components to parent level;

* Globus Link completed

* implement mui divider

* remove bulk data transfer from files section

* changelog update

* styling for globus link

* add formating util function and style table of contents

* logged in components set up

* remove unused components

* NoAccess component

* QA component and NoAccess refactor

* changelog update

* cleanup

* Add comment for context

* ...

* refactor for all scenarios

* conditional logic for loggedIn

* delete loggedIn directory

* delete Links component

* organize order of import files

* add comment

* change if else to switch statements

* fix build error

* cleanup;

* policies link

* remove globus access component

* Update CHANGELOG-hmp-198-data-transfer-no-public-globus.md

Co-authored-by: L Choy <[email protected]>

* update changelog

* outbound casing

* datatest id

* build fix testid update bulk-data-transfer

* conditionals readability

* fix conditional logic

* extract bulkdatatransfer

* refactor bulkDataTransferPanel

* Handle no DbGap links

* adjust publication page handling of files/bulkdatatransfer

* fix useSwr fetch call and Invalid state

* api call for globus link and globus support link

* refactor details context

* detailContext and filesContext usedetailcontext and usefilescontext refactor

* unit test for functions

* build fix

* test file fix

* remove unused file

* remove unused globus from files directory

* cleanup

* tooltip for data support

* tooltip fix

* build error fix

* unit test error

* update content for logged in panel

* cleanup

* tooltip hover over entire link

* build error fix

* tooltip fix

* Update CHANGELOG-hmp-198-data-transfer-no-public-globus.md

Co-authored-by: Nikolay Akhmetov <[email protected]>

* change block icon color to warning

* changelog update

* cleanup

* Update context/app/static/js/pages/Publication/Publication.jsx

Co-authored-by: Nikolay Akhmetov <[email protected]>

* Update context/app/static/js/pages/Publication/Publication.jsx

Co-authored-by: Nikolay Akhmetov <[email protected]>

* build error fix

* John conroy/fix globus support (#3179)

* Add prop to show icon in files conditional link

* Show tooltip on support globus links only

* Remove unused styles

* Fix dbGaP link styling

---------

Co-authored-by: John Conroy <[email protected]>

* Handle entity api failure for globus link (#3180)

Co-authored-by: John Conroy <[email protected]>

---------

Co-authored-by: Nikolay Akhmetov <[email protected]>
Co-authored-by: John Conroy <[email protected]>
Co-authored-by: L Choy <[email protected]>
Co-authored-by: John Conroy <[email protected]>
  • Loading branch information
5 people authored Jul 17, 2023
1 parent ef9fc08 commit e5210bc
Show file tree
Hide file tree
Showing 54 changed files with 1,039 additions and 371 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG-hmp-198-data-transfer-no-public-globus.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Create bulk data transfer section.
- Add links to Globus, dbGap study, and SRA Experiment for dbGaP datasets.
2 changes: 1 addition & 1 deletion context/.eslintrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ env:
plugins:
- react
- '@typescript-eslint'
- prettier
- import
- prettier
settings:
react:
version: detect
Expand Down
5 changes: 4 additions & 1 deletion context/app/routes_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,10 @@ def login():
log('7: 401')
abort(401)

additional_groups = {'Workspaces': current_app.config['WORKSPACES_GROUP_ID']}
additional_groups = {
'HuBMAP': current_app.config['GROUP_ID'],
'Workspaces': current_app.config['WORKSPACES_GROUP_ID']
}

session.update(
groups_token=groups_token,
Expand Down
3 changes: 3 additions & 0 deletions context/app/static/js/components/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,12 @@ pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/b

function App(props) {
const { flaskData, groupsToken, isAuthenticated, userEmail, workspacesToken, userGroups = [] } = props;

const { endpoints, globalAlertMd } = flaskData;
delete flaskData.endpoints;
delete flaskData.globalAlertMd;
const isWorkspacesUser = userGroups?.includes('Workspaces') || workspacesUsers.includes(userEmail);
const isHubmapUser = userGroups?.includes('HuBMAP');

return (
<Providers
Expand All @@ -45,6 +47,7 @@ function App(props) {
userEmail={userEmail}
workspacesToken={workspacesToken}
isWorkspacesUser={isWorkspacesUser}
isHubmapUser={isHubmapUser}
flaskData={flaskData}
>
<Header />
Expand Down
2 changes: 2 additions & 0 deletions context/app/static/js/components/Contexts.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ const FlaskDataContext = createContext({});
const AppContext = createContext({});

FlaskDataContext.displayName = 'FlaskDataContext';
AppContext.displayName = 'AppContext';

export { FlaskDataContext, AppContext };

export const useAppContext = () => useContext(AppContext);
export const useFlaskDataContext = () => useContext(FlaskDataContext);
4 changes: 3 additions & 1 deletion context/app/static/js/components/Providers.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,20 @@ function Providers({
children,
workspacesToken,
isWorkspacesUser,
isHubmapUser,
flaskData,
}) {
const appContext = useMemo(
() => ({
groupsToken,
workspacesToken,
isWorkspacesUser,
isHubmapUser,
isAuthenticated,
userEmail,
...endpoints,
}),
[groupsToken, workspacesToken, isWorkspacesUser, isAuthenticated, userEmail, endpoints],
[groupsToken, workspacesToken, isWorkspacesUser, isHubmapUser, isAuthenticated, userEmail, endpoints],
);

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ import TableRow from '@material-ui/core/TableRow';

import packageInfo from 'package';
import OutboundLink from 'js/shared-styles/Links/OutboundLink';
import { StyledExternalLinkIcon } from 'js/components/detailPage/files/GlobusLinkMessage/style';
import { HeaderCell } from 'js/shared-styles/tables';

import StatusIcon from './StatusIcon';
import { StyledExternalLinkIcon } from './style';
import { useGatewayStatus } from './hooks';

function buildServiceStatus(args) {
Expand Down
9 changes: 8 additions & 1 deletion context/app/static/js/components/ServiceStatusTable/style.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import styled from 'styled-components';
import LensIcon from '@material-ui/icons/LensRounded';

import { ExternalLinkIcon } from 'js/shared-styles/icons';

// Default font-size is too large, and causes vertical misalignment
// of text in this cell. 0.8rem works, but somewhat arbitrary.
// "vertical-align: sub" looks better than "baseline",
Expand All @@ -12,4 +14,9 @@ const ColoredStatusIcon = styled(LensIcon)`
vertical-align: sub;
`;

export { ColoredStatusIcon };
const StyledExternalLinkIcon = styled(ExternalLinkIcon)`
font-size: 1rem;
vertical-align: top;
`;

export { ColoredStatusIcon, StyledExternalLinkIcon };
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React, { useState, useMemo, useCallback } from 'react';

import SectionHeader from 'js/shared-styles/sections/SectionHeader';
import { DetailPageSection } from 'js/components/detailPage/style';
import { useDetailContext } from 'js/components/detailPage/context';
import { FilesContext } from 'js/components/detailPage/files/Files/context';
import FileBrowserDUA from './FileBrowserDUA';
import BulkDataTransferPanels from './BulkDataTransferPanels';
import { StyledContainer } from './style';

function BulkDataTransfer() {
const { mapped_data_access_level } = useDetailContext();
const localStorageKey = `has_agreed_to_${mapped_data_access_level}_DUA`;
const [hasAgreedToDUA, agreeToDUA] = useState(localStorage.getItem(localStorageKey));
const [isDialogOpen, setDialogOpen] = useState(false);
const [urlClickedBeforeDUA, setUrlClickedBeforeDUA] = useState('');

const handleDUAAgree = useCallback(() => {
agreeToDUA(true);
localStorage.setItem(localStorageKey, true);
setDialogOpen(false);
window.open(urlClickedBeforeDUA, '_blank');
}, [agreeToDUA, localStorageKey, setDialogOpen, urlClickedBeforeDUA]);

const handleDUAClose = useCallback(() => {
setDialogOpen(false);
}, []);

const openDUA = useCallback((linkUrl) => {
setDialogOpen(true);
setUrlClickedBeforeDUA(linkUrl);
}, []);

const filesContext = useMemo(() => ({ openDUA, hasAgreedToDUA }), [openDUA, hasAgreedToDUA]);

return (
<FilesContext.Provider value={filesContext}>
<DetailPageSection id="bulk-data-transfer" data-testid="bulk-data-transfer">
<SectionHeader>Bulk Data Transfer</SectionHeader>
<StyledContainer>
<BulkDataTransferPanels />
</StyledContainer>
</DetailPageSection>
<FileBrowserDUA
isOpen={isDialogOpen}
handleAgree={handleDUAAgree}
handleClose={handleDUAClose}
mapped_data_access_level={mapped_data_access_level}
/>
</FilesContext.Provider>
);
}

export default BulkDataTransfer;
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from 'react';
import InfoIcon from '@material-ui/icons/Info';

import { DetailSectionPaper } from 'js/shared-styles/surfaces';
import { SecondaryBackgroundTooltip } from 'js/shared-styles/tooltips';
import { Header, ContentText, GreenCheckCircleIcon, StyledBlockIcon } from './style';

const statusIcons = {
success: <GreenCheckCircleIcon fontSize="small" />,
error: <StyledBlockIcon color="error" fontSize="small" />,
};

function BulkDataTransferPanel({ title, status, tooltip, children, addOns }) {
return (
<DetailSectionPaper>
<Header variant="h5">
{title}
{status ? statusIcons[status] : null}
<SecondaryBackgroundTooltip title={tooltip}>
<InfoIcon fontSize="small" />
</SecondaryBackgroundTooltip>
</Header>
<ContentText variant="body2">{children}</ContentText>
{addOns}
</DetailSectionPaper>
);
}

export default BulkDataTransferPanel;
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from 'react';
import Paper from '@material-ui/core/Paper';

import { useFlaskDataContext } from 'js/components/Contexts';

import BulkDataTransferPanel from './BulkDataTransferPanel';
import Link from './Link';
import NoAccess from './NoAccess';
import { usePanelSet } from './usePanelSet';

function BulkDataTransferPanels() {
const {
entity: { dbgap_study_url, dbgap_sra_experiment_url },
} = useFlaskDataContext();

const panelsToUse = usePanelSet();

// Assign dynamic URL's to each type of link
const linkTitleUrlMap = {
dbGaP: dbgap_study_url,
'SRA Experiment': dbgap_sra_experiment_url,
};

if (panelsToUse.error) {
return <NoAccess>{panelsToUse.error}</NoAccess>;
}

return (
<>
{panelsToUse.panels.length > 0 &&
panelsToUse.panels.map((props) => <BulkDataTransferPanel {...props} key={props.title} />)}
{panelsToUse.links.length > 0 && (
<Paper>
{panelsToUse.links.map((link) =>
React.isValidElement(link) ? link : <Link {...link} key={link.key} url={linkTitleUrlMap[link.title]} />,
)}
</Paper>
)}
</>
);
}

export default BulkDataTransferPanels;
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import Button from '@material-ui/core/Button';
import Dialog from '@material-ui/core/Dialog';
import DialogActions from '@material-ui/core/DialogActions';
import DialogContent from '@material-ui/core/DialogContent';
import FormControlLabel from '@material-ui/core/FormControlLabel';
import Checkbox from '@material-ui/core/Checkbox';
import Typography from '@material-ui/core/Typography';

import OptDisabledButton from 'js/shared-styles/buttons/OptDisabledButton';
import OutboundLink from 'js/shared-styles/Links/OutboundLink';
import { getDUAText } from './utils';
import { ObliqueSpan, StyledHeader, StyledDiv } from './style';

function FileBrowserDUA({ isOpen, handleAgree, handleClose, mapped_data_access_level }) {
const [isChecked, check] = useState(false);

const { title, appropriateUse } = getDUAText(mapped_data_access_level);

return (
<Dialog
open={isOpen}
onClose={handleClose}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogContent>
<StyledDiv id="alert-dialog-description">
<StyledHeader id="alert-dialog-title" variant="h2" component="h1">
{'HuBMAP '} <ObliqueSpan>{`${title} Data`}</ObliqueSpan> {' Usage'}
</StyledHeader>

<StyledHeader variant="h4" component="h2">
Appropriate Use
</StyledHeader>
<Typography variant="body1">{appropriateUse}</Typography>

<StyledHeader variant="h4" component="h2">
Acknowledgement
</StyledHeader>
<Typography variant="body1">
Investigators using HuBMAP data in publications or presentations are requested to cite The Human Body at
Cellular Resolution: the NIH Human BioMolecular Atlas Program (doi:
<OutboundLink href="https://doi.org/10.1038/s41586-019-1629-x">10.1038/s41586-019-1629-x</OutboundLink>) and
to include an acknowledgement of HuBMAP. Suggested language for such an acknowledgment is: “The results here
are in whole or part based upon data generated by the NIH Human BioMolecular Atlas Program (HuBMAP):{' '}
<OutboundLink href="https://hubmapconsortium.org">https://hubmapconsortium.org</OutboundLink>
.”
</Typography>

<StyledHeader variant="h4" component="h2">
Data Sharing Policy
</StyledHeader>
<Typography variant="body1">
The HuBMAP Data Sharing Policy can be found at{' '}
<OutboundLink href="https://hubmapconsortium.org/policies/">
https://hubmapconsortium.org/policies/
</OutboundLink>
.
</Typography>
</StyledDiv>
<FormControlLabel
control={
<Checkbox
checked={isChecked}
onChange={() => {
check(!isChecked);
}}
/>
}
label="I have read and agree to the above data use guidelines."
/>
</DialogContent>
<DialogActions>
<Button onClick={handleClose} autoFocus>
Disagree
</Button>
<OptDisabledButton onClick={handleAgree} disabled={!isChecked}>
Agree
</OptDisabledButton>
</DialogActions>
</Dialog>
);
}

FileBrowserDUA.propTypes = {
isOpen: PropTypes.bool.isRequired,
handleAgree: PropTypes.func.isRequired,
handleClose: PropTypes.func.isRequired,
mapped_data_access_level: PropTypes.string.isRequired,
};

export default FileBrowserDUA;
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React from 'react';
import PropTypes from 'prop-types';

import OutboundLink from 'js/shared-styles/Links/OutboundLink';
import OutboundIconLink from 'js/shared-styles/Links/iconLinks/OutboundIconLink';

import { AlignedLink } from './style';

function getOutboundLinkComponent(hasIcon) {
if (hasIcon) {
return OutboundIconLink;
}
return OutboundLink;
}
function FilesConditionalLink({ hasAgreedToDUA, openDUA, href, children, hasIcon = false, ...rest }) {
const Link = getOutboundLinkComponent(hasIcon);

if (hasAgreedToDUA) {
return (
<Link href={href} {...rest}>
{children}
</Link>
);
}

return (
<AlignedLink
onClick={() => {
openDUA();
}}
component="button"
underline="none"
{...rest}
>
{children}
</AlignedLink>
);
}

FilesConditionalLink.propTypes = {
hasAgreedToDUA: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]),
openDUA: PropTypes.func.isRequired,
href: PropTypes.string.isRequired,
children: PropTypes.node.isRequired,
};

FilesConditionalLink.defaultProps = {
hasAgreedToDUA: null,
};

export default FilesConditionalLink;
Loading

0 comments on commit e5210bc

Please sign in to comment.