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

Add somatic/germline gene page #1181

Merged
merged 21 commits into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
"@types/react-select": "^3.0.21",
"@types/react-spinkit": "^3.0.5",
"@types/reactstrap": "^8.0.4",
"@types/resize-observer-browser": "^0.1.11",
"@types/webpack-env": "1.15.2",
"@typescript-eslint/eslint-plugin": "2.29.0",
"@typescript-eslint/parser": "2.29.0",
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified screenshot-test/__baseline_snapshots__/Gene Page with Login-snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified screenshot-test/__baseline_snapshots__/Login Page-snap.png
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public class ApplicationProperties {
private String name;
private String baseUrl = "";
private String apiProxyUrl;
private String apiProxyGermlineUrl;
private SlackProperties slack;
private ProjectProfile profile;
private Boolean sitemapEnabled;
Expand Down Expand Up @@ -62,6 +63,14 @@ public void setApiProxyUrl(String apiProxyUrl) {
this.apiProxyUrl = apiProxyUrl;
}

public String getApiProxyGermlineUrl() {
return apiProxyGermlineUrl;
}

public void setApiProxyGermlineUrl(String apiProxyGermlineUrl) {
this.apiProxyGermlineUrl = apiProxyGermlineUrl;
}

public SlackProperties getSlack() { return slack; }

public void setSlack( SlackProperties slack ) { this.slack = slack; }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package org.mskcc.cbio.oncokb.service;

import org.apache.commons.lang3.StringUtils;
import org.mskcc.cbio.oncokb.config.application.ApplicationProperties;
import org.mskcc.cbio.oncokb.security.SecurityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -27,7 +29,13 @@ public class ApiProxyService {

public URI prepareURI(HttpServletRequest request) throws URISyntaxException {
String queryString = request.getQueryString();
return new URI(applicationProperties.getApiProxyUrl() + request.getRequestURI() + (queryString == null ? "" : "?" + queryString));
String defaultApiProxyUrl = applicationProperties.getApiProxyUrl();
String germlineParam = request.getParameter("germline");
if (germlineParam != null && Boolean.TRUE.equals(Boolean.parseBoolean(germlineParam))
&& SecurityUtils.isAuthenticated() && StringUtils.isNotEmpty(applicationProperties.getApiProxyGermlineUrl())) {
defaultApiProxyUrl = applicationProperties.getApiProxyGermlineUrl();
}
return new URI(defaultApiProxyUrl + request.getRequestURI() + (queryString == null ? "" : "?" + queryString));
}

public URI prepareURI(String apiRequest) throws URISyntaxException {
Expand Down
23 changes: 12 additions & 11 deletions src/main/webapp/app/Main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ import * as React from 'react';
import Footer from './components/Footer';
import Header from './components/Header';
import { observer } from 'mobx-react';
import AppRouts from 'app/routes/routes';
import AppRoutes from 'app/routes/routes';
import { isAuthorized } from 'app/shared/auth/AuthUtils';
import { Container, Row, Col, Modal, Button } from 'react-bootstrap';
import { Stores } from 'app/App';
import { Prompt, withRouter } from 'react-router';
import {
Expand All @@ -19,6 +18,7 @@ import { FeedbackModal } from './components/feedback/FeedbackModal';
import { FdaModal } from 'app/components/fdaModal/FdaModal';
import { Location } from 'history';
import autobind from 'autobind-decorator';
import PageContainer from 'app/components/PageContainer';

export type IMainPage = Stores;

Expand Down Expand Up @@ -104,15 +104,16 @@ class Main extends React.Component<IMainPage> {
routing={this.props.routing}
appStore={this.props.appStore}
/>
<div className={'view-wrapper'}>
<Container fluid={!this.props.windowStore.isXLscreen}>
<AppRouts
authenticationStore={this.props.authenticationStore}
appStore={this.props.appStore}
routing={this.props.routing}
/>
</Container>
</div>
<PageContainer
routing={this.props.routing}
windowStore={this.props.windowStore}
>
<AppRoutes
authenticationStore={this.props.authenticationStore}
appStore={this.props.appStore}
routing={this.props.routing}
/>
</PageContainer>
<FeedbackModal
showModal={this.props.appStore.showFeedbackFormModal}
feedback={this.feedbackAnnotation}
Expand Down
4 changes: 2 additions & 2 deletions src/main/webapp/app/components/Footer.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@
}

.footerAList > a {
color: white;
line-height: 1rem;
border-right: 0.5px solid #fff;
padding: 0 5px;
padding: 0 0.5rem;

&:last-child {
border: 0;
Expand Down
35 changes: 13 additions & 22 deletions src/main/webapp/app/components/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,28 +32,19 @@ class Footer extends React.Component<{ lastDataUpdate: string }> {
<div className={'mb-2'}>
<CitationText highlightLinkout={true} boldLinkout />
</div>
<div className={classnames(styles.footerAList, 'mb-2')}>
<a
href="https://www.mskcc.org"
target="_blank"
rel="noopener noreferrer"
>
MSK <ExternalLinkIcon />
</a>
<a
href="https://www.mskcc.org/research-areas/programs-centers/molecular-oncology"
target="_blank"
rel="noopener noreferrer"
>
CMO <ExternalLinkIcon />
</a>
<a
href="https://www.cbioportal.org"
target="_blank"
rel="noopener noreferrer"
>
cBioPortal <ExternalLinkIcon />
</a>
<div
className={classnames(
styles.footerAList,
'mb-2 d-flex justify-content-center'
)}
>
<ExternalLinkIcon link="https://www.mskcc.org">MSK</ExternalLinkIcon>
<ExternalLinkIcon link="https://www.mskcc.org/research-areas/programs-centers/molecular-oncology">
CMO
</ExternalLinkIcon>
<ExternalLinkIcon link="https://www.cbioportal.org">
cBioPortal
</ExternalLinkIcon>
<OncoTreeLink />
</div>
</>
Expand Down
43 changes: 36 additions & 7 deletions src/main/webapp/app/components/PageContainer.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,44 @@
import React from 'react';
import React, { FunctionComponent } from 'react';
import { Col, Row } from 'react-bootstrap';
import WindowStore from 'app/store/WindowStore';
import { RouterStore } from 'mobx-react-router';
import { PAGE_ROUTE } from 'app/config/constants';
import { GENETIC_TYPE } from 'app/components/geneticTypeTabs/GeneticTypeTabs';
import { parseGenePagePath } from 'app/shared/utils/UrlUtils';

const Container: FunctionComponent<{
inGenePage: boolean;
}> = props => {
if (props.inGenePage) {
return <div>{props.children}</div>;
} else {
return (
<Row className={`justify-content-center`}>
<Col md={11}>{props.children}</Col>
</Row>
);
}
};
const PageContainer: React.FunctionComponent<{
className?: string;
routing: RouterStore;
windowStore: WindowStore;
}> = props => {
const genePagePath = parseGenePagePath(props.routing.location.pathname);
const inGenePage = genePagePath.geneticType !== undefined;
return (
<Row className={`justify-content-center ${props.className}`}>
<Col xl={10} lg={11}>
{props.children}
</Col>
</Row>
<div className={'view-wrapper'}>
<div
className={
inGenePage
? ''
: props.windowStore.isXLscreen
? 'container'
: 'container-fluid'
}
Comment on lines +32 to +36
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would CSS media queries would this be simpler than using Javascript?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. Didn't look into, inherited from the original.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For public website, we haven't really used the @media to manage the layout. I would stick to the classname for now.

>
<Container inGenePage={inGenePage}>{props.children}</Container>
</div>
</div>
);
};
export default PageContainer;
47 changes: 47 additions & 0 deletions src/main/webapp/app/components/geneticTypeTabs/GeneticTypeTabs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React, { FunctionComponent, useState } from 'react';
import styles from './genetic-type-tabs.module.scss';
import classnames from 'classnames';
import { RouterStore } from 'mobx-react-router';

export enum GENETIC_TYPE {
SOMATIC = 'somatic',
GERMLINE = 'germline',
}

const GeneticTypeTabs: FunctionComponent<{
routing: RouterStore;
hugoSymbol: string;
geneticType?: GENETIC_TYPE;
onChange: (status: string) => void;
}> = props => {
const [selected, setSelected] = useState<GENETIC_TYPE>(
props.geneticType || GENETIC_TYPE.SOMATIC
);

const ontoggle = (status: GENETIC_TYPE) => {
setSelected(status);
props.onChange(status);
};

return (
<div className={styles.tabs}>
{[GENETIC_TYPE.SOMATIC, GENETIC_TYPE.GERMLINE].map((geneOrigin, idx) => (
<div
key={idx}
style={{ width: '50%' }}
className={
selected === geneOrigin
? classnames(styles.tab, styles.selectedTab, 'font-bold')
: classnames(styles.tab, styles.unselectedTab)
}
onClick={() => ontoggle(geneOrigin)}
>
{geneOrigin.substring(0, 1).toUpperCase()}
{geneOrigin.toLowerCase().slice(1)}
</div>
))}
</div>
);
};

export default GeneticTypeTabs;
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
@import '../../variables';

.tabs {
display: flex;
margin: 1.5rem 0 0 0;
}

.tab {
text-align: center;
padding: 0.75rem 0;
border: 1px solid $oncokb-darker-blue;
cursor: pointer;
}

.tab:first-child {
border-left: 0;
border-top-right-radius: 3px;
}

.tab:last-child {
border-right: 0;
border-top-left-radius: 3px;
}

.selectedTab {
padding-top: 0.5rem;
border-width: 3px 1px 0 1px;
}

.unselectedTab {
background-color: $inactive;
border-width: 0 0 1px 0;
}
25 changes: 25 additions & 0 deletions src/main/webapp/app/components/geneticTypeTag/GeneticTypeTag.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React, { FunctionComponent } from 'react';
import { GENETIC_TYPE } from 'app/components/geneticTypeTabs/GeneticTypeTabs';
import classnames from 'classnames';
import styles from './genetic-type-tag.module.scss';
import { capitalize } from 'cbioportal-frontend-commons';

const GeneticTypeTag: FunctionComponent<{
geneticType: GENETIC_TYPE;
className?: string;
}> = props => {
return (
<span
className={classnames(
props.className,
props.geneticType === GENETIC_TYPE.GERMLINE
? styles.germlineTag
: styles.somaticTag
)}
>
{capitalize(props.geneticType)}
</span>
);
};

export default GeneticTypeTag;
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
@import '../../variables';

.geneticTypeTag {
font-weight: 500 !important;
font-family: "Gotham Book";
display: inline-flex;
padding: 0 var(--radius-8, 8px);
justify-content: center;
align-items: center;
gap: var(--radius-8, 8px);
border-radius: 56px;
}

.germlineTag {
@extend .geneticTypeTag;
color: $primary;
border: var(--radius-2, 2px) solid var(--Color-11, $primary);
background: #F0F5FF;
}

.somaticTag {
@extend .geneticTypeTag;
color: #FFFFFF;
background: $primary;
}
52 changes: 52 additions & 0 deletions src/main/webapp/app/components/infoTile/InfoTile.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React, { CSSProperties } from 'react';
import styles from './info-tile.module.scss';
import { COLOR_GREY } from 'app/config/theme';
import classnames from 'classnames';

export type Category = {
title: string;
content?: JSX.Element | string;
className?: string;
};
export type InfoTile = {
title: string;
categories: Category[];
className?: string;
};

const Category: React.FunctionComponent<Category> = props => {
const isNa = props.content === undefined || props.content === null;
const isText = isNa || typeof props.content === 'string';
const style: CSSProperties = { height: '3rem' };
if (isText) {
style.fontSize = '1.5rem';
style.fontFamily = 'Gotham Bold';
}
return (
<div className={classnames(props.className, 'flex-grow-1')}>
<div style={{ color: COLOR_GREY }} className={'mb-1'}>
{props.title}
</div>
<div className={classnames('d-flex align-items-center')} style={style}>
{props.content}
</div>
</div>
);
};

const InfoTile: React.FunctionComponent<InfoTile> = props => {
return props.categories.length > 0 ? (
<div className={classnames(styles.tile, 'mr-2', props.className)}>
<div className={'h6 font-bold mb-2'}>{props.title}</div>
<div className={'d-flex'}>
{props.categories.map((category, idx) => (
<Category key={idx} {...category} className={styles.category} />
))}
</div>
</div>
) : (
<></>
);
};

export default InfoTile;
Loading
Loading