import * as React from 'react'; import { inject, observer } from 'mobx-react'; import GroupComparisonStore from './GroupComparisonStore'; import { MSKTab, MSKTabs } from '../../shared/components/MSKTabs/MSKTabs'; import { PageLayout } from '../../shared/components/PageLayout/PageLayout'; import Survival from './Survival'; import Overlap from './Overlap'; import MRNAEnrichments from './MRNAEnrichments'; import ProteinEnrichments from './ProteinEnrichments'; import { MakeMobxView } from '../../shared/components/MobxView'; import LoadingIndicator from '../../shared/components/loadingIndicator/LoadingIndicator'; import ErrorMessage from '../../shared/components/ErrorMessage'; import GroupSelector from './groupSelector/GroupSelector'; import { GENOMIC_ALTERATIONS_TAB_NAME, GroupComparisonTab, } from './GroupComparisonTabs'; import { StudyLink } from 'shared/components/StudyLink/StudyLink'; import { action, computed, IReactionDisposer, observable, reaction, makeObservable, } from 'mobx'; import autobind from 'autobind-decorator'; import { AppStore } from '../../AppStore'; import ClinicalData from './ClinicalData'; import ReactSelect from 'react-select'; import { trackEvent } from 'shared/lib/tracking'; import URL from 'url'; import GroupComparisonURLWrapper from './GroupComparisonURLWrapper'; import classnames from 'classnames'; import styles from './styles.module.scss'; import { OverlapStrategy } from '../../shared/lib/comparison/ComparisonStore'; import { buildCBioPortalPageUrl } from 'shared/api/urls'; import MethylationEnrichments from './MethylationEnrichments'; import GenericAssayEnrichments from './GenericAssayEnrichments'; import _ from 'lodash'; import AlterationEnrichments from './AlterationEnrichments'; import AlterationEnrichmentTypeSelector from '../../shared/lib/comparison/AlterationEnrichmentTypeSelector'; import { AlterationFilterMenuSection } from 'pages/groupComparison/GroupComparisonUtils'; import { getServerConfig } from 'config/config'; import { buildCustomTabs, prepareCustomTabConfigurations, } from 'shared/lib/customTabs/customTabHelpers'; import { getSortedGenericAssayTabSpecs } from 'shared/lib/GenericAssayUtils/GenericAssayCommonUtils'; import { HelpWidget } from 'shared/components/HelpWidget/HelpWidget'; import GroupComparisonPathwayMapper from './pathwayMapper/GroupComparisonPathwayMapper'; import GroupComparisonMutationsTab from './GroupComparisonMutationsTab'; export interface IGroupComparisonPageProps { routing: any; appStore: AppStore; } @inject('routing', 'appStore') @observer export default class GroupComparisonPage extends React.Component< IGroupComparisonPageProps, {} > { @observable.ref private store: GroupComparisonStore; private queryReaction: IReactionDisposer; private urlWrapper: GroupComparisonURLWrapper; constructor(props: IGroupComparisonPageProps) { super(props); makeObservable(this); this.urlWrapper = new GroupComparisonURLWrapper(props.routing); this.queryReaction = reaction( () => this.urlWrapper.query.comparisonId, sessionId => { if ( !props.routing.location.pathname.includes('/comparison') || !sessionId ) { return; } if (this.store) { this.store.destroy(); } this.store = new GroupComparisonStore( sessionId, this.props.appStore, this.urlWrapper ); (window as any).groupComparisonStore = this.store; }, { fireImmediately: true } ); (window as any).groupComparisonPage = this; } @computed get alterationEnrichmentTabName() { return GENOMIC_ALTERATIONS_TAB_NAME; } @computed get selectedGroupsKey() { // for components which should remount whenever selected groups change const selectedGroups = this.store._selectedGroups.result || []; return JSON.stringify(selectedGroups.map(g => g.uid)); } componentWillUnmount() { this.queryReaction && this.queryReaction(); this.store && this.store.destroy(); this.urlWrapper.destroy(); } @computed get customTabs() { return prepareCustomTabConfigurations( getServerConfig().custom_tabs, 'COMPARISON_PAGE' ); } readonly tabs = MakeMobxView({ await: () => [ this.store._activeGroupsNotOverlapRemoved, this.store.activeGroups, this.store.mutationEnrichmentProfiles, this.store.structuralVariantEnrichmentProfiles, this.store.copyNumberEnrichmentProfiles, this.store.mRNAEnrichmentProfiles, this.store.proteinEnrichmentProfiles, this.store.methylationEnrichmentProfiles, this.store.survivalClinicalDataExists, this.store.genericAssayEnrichmentProfilesGroupedByGenericAssayType, this.store.alterationsEnrichmentData, this.store.alterationsEnrichmentAnalysisGroups, this.store.genesSortedByMutationFrequency, ], render: () => { return ( } > {this.store.showSurvivalTab && ( )} {this.store.showAlterationsTab && ( {(getServerConfig().skin_show_settings_menu && ( )) || ( )} )} {this.store.showMutationsTab && ( Mutations{' '} Beta! } > {/* stacked lollipop plots for > 2 groups */} {/* {this.store.activeGroups.result!.map(g => { return (

{g.name}

); })} */}
)} {this.props.appStore.featureFlagStore.has( 'group_comparison_pathways' ) && ( )} {this.store.showMRNATab && ( )} {this.store.showProteinTab && ( )} {this.store.showMethylationTab && ( )} {this.store.showGenericAssayTab && getSortedGenericAssayTabSpecs( this.store .genericAssayEnrichmentProfilesGroupedByGenericAssayType .result ).map(genericAssayTabSpecs => { return ( ); })} {buildCustomTabs(this.customTabs)}
); }, renderPending: () => ( ), renderError: () => { return ; }, }); readonly studyLink = MakeMobxView({ await: () => [this.store.displayedStudies], render: () => { const studies = this.store.displayedStudies.result!; let studyHeader = ; switch (studies.length) { case 0: studyHeader = ; break; case 1: studyHeader = (

{studies[0].name}

); break; default: studyHeader = (

study.studyId) .join(','), })} target="_blank" > Multiple studies

); } let ret; if (this.store.sessionClinicalAttributeName) { ret = ( {studyHeader}Groups from{' '} {this.store.sessionClinicalAttributeName} ); } else { ret = studyHeader; } return ret; }, }); @action.bound public onOverlapStrategySelect(option: any) { trackEvent({ category: 'groupComparison', action: 'setOverlapStrategy', label: option.value, }); this.store.updateOverlapStrategy(option.value as OverlapStrategy); } readonly overlapStrategySelector = MakeMobxView({ await: () => [this.store.overlapComputations], render: () => { if ( !this.store.overlapComputations.result!.totalSampleOverlap && !this.store.overlapComputations.result!.totalPatientOverlap ) { return null; } else { const includeLabel = 'Include overlapping samples and patients'; const excludeLabel = 'Exclude overlapping samples and patients'; return (
{ if (option) { this.onOverlapStrategySelect(option); } }} options={[ { label: includeLabel, value: OverlapStrategy.INCLUDE, }, { label: excludeLabel, value: OverlapStrategy.EXCLUDE, }, ]} clearable={false} searchable={false} value={{ label: this.store.overlapStrategy === OverlapStrategy.EXCLUDE ? excludeLabel : includeLabel, value: this.store.overlapStrategy, }} />
); } }, }); @autobind private isGroupDeletable() { return ( this.store._originalGroups.isComplete && this.store._originalGroups.result!.length > 2 ); } render() { if (!this.store) { return null; } return (
{this.studyLink.component} {this.overlapStrategySelector.component}
{this.tabs.component}
); } }