Skip to content

Commit

Permalink
Add somatic/germline gene page (#1181)
Browse files Browse the repository at this point in the history
- Update gene info section 
- Add external link icon
- Add InfoTile & GeneOriginTabs
- Add genomic indicators
- Add germline core proxy config


---------

Co-authored-by: John Konecny <[email protected]>
  • Loading branch information
zhx828 and jfkonecn authored Oct 25, 2024
1 parent 1b362f3 commit 067dcd3
Show file tree
Hide file tree
Showing 95 changed files with 3,176 additions and 419 deletions.
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'
}
>
<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

0 comments on commit 067dcd3

Please sign in to comment.