import * as React from 'react'; import _ from 'lodash'; import $ from 'jquery'; import URL from 'url'; import { inject, observer } from 'mobx-react'; import { action, computed, observable, runInAction, makeObservable, autorun, } from 'mobx'; import { ResultsViewPageStore } from './ResultsViewPageStore'; import CancerSummaryContainer from 'pages/resultsView/cancerSummary/CancerSummaryContainer'; import Mutations from './mutation/Mutations'; import MutualExclusivityTab from './mutualExclusivity/MutualExclusivityTab'; import DownloadTab from './download/DownloadTab'; import { getServerConfig, ServerConfigHelpers } from 'config/config'; import CNSegments from './cnSegments/CNSegments'; import './styles.scss'; import ResultsViewOncoprint from 'shared/components/oncoprint/ResultsViewOncoprint'; import QuerySummary from './querySummary/QuerySummary'; import PlotsTab from './plots/PlotsTab'; import { MSKTab, MSKTabs } from '../../shared/components/MSKTabs/MSKTabs'; import { PageLayout } from '../../shared/components/PageLayout/PageLayout'; import autobind from 'autobind-decorator'; import { ITabConfiguration } from '../../shared/model/ITabConfiguration'; import { getBrowserWindow, remoteData } from 'cbioportal-frontend-commons'; import CoExpressionTab from './coExpression/CoExpressionTab'; import Helmet from 'react-helmet'; import { parseConfigDisabledTabs, ResultsViewTab, } from './ResultsViewPageHelpers'; import { buildResultsViewPageTitle, doesQueryHaveCNSegmentData, } from './ResultsViewPageStoreUtils'; import { AppStore } from '../../AppStore'; import { trackQuery } from '../../shared/lib/tracking'; import QueryAndDownloadTabs from 'shared/components/query/QueryAndDownloadTabs'; import ExtendedRouterStore from 'shared/lib/ExtendedRouterStore'; import GeneSymbolValidationError from 'shared/components/query/GeneSymbolValidationError'; import ResultsViewURLWrapper, { USER_SETTINGS_QUERY_PARAM, } from 'pages/resultsView/ResultsViewURLWrapper'; import setWindowVariable from 'shared/lib/setWindowVariable'; import LoadingIndicator from 'shared/components/loadingIndicator/LoadingIndicator'; import { onMobxPromise } from 'cbioportal-frontend-commons'; import { createQueryStore } from 'shared/lib/createQueryStore'; import { handleLegacySubmission, handlePostedSubmission, } from 'shared/lib/redirectHelpers'; import ComparisonTab from './comparison/ComparisonTab'; import OQLTextArea, { GeneBoxType, } from 'shared/components/GeneSelectionBox/OQLTextArea'; import browser from 'bowser'; import { QueryStore } from '../../shared/components/query/QueryStore'; import UserMessager, { IUserMessage, } from 'shared/components/userMessager/UserMessage'; import { HelpWidget } from 'shared/components/HelpWidget/HelpWidget'; import { buildCustomTabs, prepareCustomTabConfigurations, } from 'shared/lib/customTabs/customTabHelpers'; import { buildCBioPortalPageUrl } from 'shared/api/urls'; import { AppContext } from 'cbioportal-frontend-commons'; import PathWayMapperContainer from 'pages/resultsView/pathwayMapper/PathWayMapperContainer'; export function initStore( appStore: AppStore, urlWrapper: ResultsViewURLWrapper ) { const resultsViewPageStore = new ResultsViewPageStore(appStore, urlWrapper); setWindowVariable('resultsViewPageStore', resultsViewPageStore); autorun(() => { if ( resultsViewPageStore.studyIds.isComplete && resultsViewPageStore.oqlText ) { trackQuery( resultsViewPageStore.studyIds.result!, resultsViewPageStore.oqlText, resultsViewPageStore.hugoGeneSymbols, resultsViewPageStore.queriedVirtualStudies.result!.length > 0 ); } }); return resultsViewPageStore; } function addOnBecomeVisibleListener(callback: () => void) { $('#oncoprint-result-tab').click(callback); } export interface IResultsViewPageProps { params: any; // from react router } @observer export default class ResultsViewPage extends React.Component< IResultsViewPageProps, {} > { private resultsViewPageStore: ResultsViewPageStore; private urlWrapper: ResultsViewURLWrapper; @observable.ref quickOQLQueryStore: QueryStore | null = null; @observable showTabs = true; constructor(props: IResultsViewPageProps) { super(props); makeObservable(this); this.urlWrapper = new ResultsViewURLWrapper(this.routing); handleLegacySubmission(this.urlWrapper); handlePostedSubmission(this.urlWrapper); setWindowVariable('urlWrapper', this.urlWrapper); if (this.urlWrapper.hasSessionId) { onMobxPromise(this.urlWrapper.remoteSessionData, () => { this.resultsViewPageStore = initStore( this.appStore, this.urlWrapper ); }); } else { this.resultsViewPageStore = initStore( this.appStore, this.urlWrapper ); } } // this is temporary to allow us to // get rid of @inject, which is conflicting // with react context // ultimately should be replaced with react context private get appStore(): AppStore { return getBrowserWindow().globalStores.appStore as AppStore; } private get routing(): ExtendedRouterStore { return getBrowserWindow().globalStores.routing as ExtendedRouterStore; } componentDidMount() { // Remove bookmark user settings query param after initialization const newParams = _.clone(this.routing.query); newParams[USER_SETTINGS_QUERY_PARAM] = undefined; this.routing.updateRoute(newParams); } componentWillUnmount() { this.resultsViewPageStore.destroy(); this.urlWrapper.destroy(); } @computed private get tabs() { const store = this.resultsViewPageStore; const tabMap: ITabConfiguration[] = [ { id: ResultsViewTab.ONCOPRINT, getTab: () => { return ( ); }, }, { id: ResultsViewTab.CANCER_TYPES_SUMMARY, getTab: () => { return ( ); }, }, { id: ResultsViewTab.MUTUAL_EXCLUSIVITY, getTab: () => { return ( ); }, hide: () => { // we are using the size of isSampleAlteredMap as a proxy for the number of things we have to compare return ( !this.resultsViewPageStore.isSampleAlteredMap .isComplete || _.size( this.resultsViewPageStore.isSampleAlteredMap.result ) < 2 ); }, }, { id: ResultsViewTab.PLOTS, getTab: () => { return ( ); }, }, { id: ResultsViewTab.MUTATIONS, getTab: () => { return ( ); }, }, { id: ResultsViewTab.COEXPRESSION, hide: () => { if ( !this.resultsViewPageStore.isThereDataForCoExpressionTab .isComplete || !this.resultsViewPageStore.studies.isComplete ) { return true; } else { const tooManyStudies = this.resultsViewPageStore.studies.result!.length > 1; const noData = !this.resultsViewPageStore .isThereDataForCoExpressionTab.result; return tooManyStudies || noData; } }, getTab: () => { return ( ); }, }, { id: ResultsViewTab.COMPARISON, hide: () => { return this.resultsViewPageStore.survivalClinicalDataExists .isPending; }, getTab: () => { const text = this.resultsViewPageStore .survivalClinicalDataExists.result ? 'Comparison/Survival' : 'Comparison'; return ( ); }, }, { id: ResultsViewTab.CN_SEGMENTS, hide: () => { return ( !this.resultsViewPageStore.studies.isComplete || !this.resultsViewPageStore.genes.isComplete || !this.resultsViewPageStore.referenceGenes.isComplete || !doesQueryHaveCNSegmentData( this.resultsViewPageStore.samples.result ) ); }, getTab: () => { return ( ); }, }, { id: ResultsViewTab.NETWORK, hide: () => { return true; }, getTab: () => { return (
The Network tab has been retired. For similar functionality, please visit{' '} http://www.pathwaycommons.org/pcviz/
); }, }, { id: ResultsViewTab.PATHWAYS, hide: () => browser.name === 'Internet Explorer' || (!getServerConfig().show_pathway_mapper && !getServerConfig().show_ndex) || !this.resultsViewPageStore.studies.isComplete, getTab: () => { const showPathwaysTab = store.filteredSequencedSampleKeysByGene.isComplete && store.oqlFilteredCaseAggregatedDataByOQLLine .isComplete && store.genes.isComplete && store.samples.isComplete && store.patients.isComplete && store.coverageInformation.isComplete && store.filteredSequencedSampleKeysByGene.isComplete && store.filteredSequencedPatientKeysByGene.isComplete && store.selectedMolecularProfiles.isComplete && store.oqlFilteredCaseAggregatedDataByUnflattenedOQLLine .isComplete; return ( {showPathwaysTab ? ( ) : ( )} ); }, }, ]; if (this.context.showDownloadControls === true) { tabMap.push({ id: ResultsViewTab.DOWNLOAD, getTab: () => { return ( ); }, }); } let filteredTabs = tabMap .filter(this.evaluateTabInclusion) .map(tab => tab.getTab()); filteredTabs.push(...buildCustomTabs(this.customTabs)); return filteredTabs; } @computed get customTabs() { return prepareCustomTabConfigurations( getServerConfig().custom_tabs, 'RESULTS_PAGE' ); } @autobind public evaluateTabInclusion(tab: ITabConfiguration) { const excludedTabs = getServerConfig().disabled_tabs || ''; const isExcludedInList = parseConfigDisabledTabs(excludedTabs).includes( tab.id ); const isRoutedTo = this.resultsViewPageStore.tabId === tab.id; const isExcluded = tab.hide ? tab.hide() : false; // we show no matter what if its routed to return isRoutedTo || (!isExcludedInList && !isExcluded); } @computed get quickOQLSubmitButton() { if (this.quickOQLQueryStore) { return ( <>   ); } } @computed get showOQLEditor() { return !!this.quickOQLQueryStore; } set showOQLEditor(s: boolean) { if (s) { this.quickOQLQueryStore = createQueryStore( this.urlWrapper.query, this.urlWrapper, false ); } else { this.quickOQLQueryStore = null; } } @action.bound handleQuickOQLSubmission() { this.quickOQLQueryStore!.submit(); this.showOQLEditor = false; } @action.bound toggleOQLEditor() { this.showOQLEditor = !this.showOQLEditor; } @autobind private getTabHref(tabId: string) { return URL.format({ pathname: buildCBioPortalPageUrl(`./results/${tabId}`), query: this.routing.query, hash: this.routing.location.hash, }); } readonly userMessages = remoteData({ await: () => [ this.resultsViewPageStore.expressionProfiles, this.resultsViewPageStore.studies, ], invoke: () => { // TODO: make this configurable from outside app return Promise.resolve([]); }, }); @computed get pageContent() { if ( this.resultsViewPageStore.hugoGeneSymbols.length === 0 || this.resultsViewPageStore.invalidStudyIds.result.length > 0 ) { return (
createQueryStore( this.urlWrapper.query, this.urlWrapper ) } />
); } else { // we don't show the result tabs if we don't have valid query const tabsReady = this.showTabs && !this.resultsViewPageStore.genesInvalid && !this.resultsViewPageStore.queryExceedsLimit && this.resultsViewPageStore.customDriverAnnotationReport .isComplete; return ( <> {// if query invalid(we only check gene count * sample count < 1,000,000 for now), return error page this.resultsViewPageStore.queryExceedsLimit && (
)} {this.userMessages.isComplete && this.userMessages.result.length > 0 && ( )} {(this.resultsViewPageStore.studies.isPending || (!tabsReady && !this.resultsViewPageStore.queryFormVisible)) && ( )} {this.resultsViewPageStore.studies.isComplete && ( <> {buildResultsViewPageTitle( this.resultsViewPageStore .hugoGeneSymbols, this.resultsViewPageStore.studies.result )}
{ runInAction(() => { this.showTabs = visible; this.showOQLEditor = false; }); }} onToggleOQLEditUIVisibility={ this.toggleOQLEditor } /> {this.showOQLEditor && (
{ this.quickOQLQueryStore!.geneQuery = args[2]; }} location={GeneBoxType.DEFAULT} submitButton={ this.quickOQLSubmitButton } error={ this.quickOQLQueryStore! .submitError } messages={ this.quickOQLQueryStore! .oqlMessages } />
)}
{tabsReady && ( this.resultsViewPageStore.handleTabChange( id ) } className="mainTabs" hrefRoot={buildCBioPortalPageUrl( 'results' )} contentWindowExtra={ } > {this.tabs} )}
)} ); } } public render() { if ( this.urlWrapper.isTemporarySessionPendingSave || this.urlWrapper.isLoadingSession || !this.resultsViewPageStore.studies.isComplete ) { return ( ); } // if we don't have a tabId, we need figure out // which tab should be default based upon // characteristics of study (handled in tabId getter) if ( this.resultsViewPageStore.studies.isComplete && !this.resultsViewPageStore.tabId ) { // we have to use timeout in order to // circumvent restriction on updating state // inside of render setTimeout(() => { this.resultsViewPageStore.handleTabChange( this.resultsViewPageStore.tabId, true ); }); return null; } else { return ( {this.pageContent} ); } } } ResultsViewPage.contextType = AppContext;