diff --git a/src/globalStyles/global.scss b/src/globalStyles/global.scss index 89ab63895df..4aa10bff97c 100755 --- a/src/globalStyles/global.scss +++ b/src/globalStyles/global.scss @@ -254,6 +254,10 @@ th.reactable-header-sort-asc:after { } } +.comparisonMutationMapperTabs { + height: 0; +} + .mainTabs { > .nav { @extend .portalWidth; diff --git a/src/pages/groupComparison/GroupComparisonMutationsTab.tsx b/src/pages/groupComparison/GroupComparisonMutationsTab.tsx index 3089c09585b..ecef7f91cef 100644 --- a/src/pages/groupComparison/GroupComparisonMutationsTab.tsx +++ b/src/pages/groupComparison/GroupComparisonMutationsTab.tsx @@ -14,6 +14,7 @@ import ErrorMessage from 'shared/components/ErrorMessage'; import { LollipopGeneSelector } from './LollipopGeneSelector'; import GroupComparisonMutationsTabPlot from './GroupComparisonMutationsTabPlot'; import OverlapExclusionIndicator from './OverlapExclusionIndicator'; +import { MSKTab, MSKTabs } from 'shared/components/MSKTabs/MSKTabs'; interface IGroupComparisonMutationsTabProps { store: GroupComparisonStore; @@ -24,8 +25,39 @@ export default class GroupComparisonMutationsTab extends React.Component< IGroupComparisonMutationsTabProps, {} > { + @observable public geneTab: string | undefined; constructor(props: IGroupComparisonMutationsTabProps) { super(props); + makeObservable(this); + } + + @action.bound + protected handleGeneChange(id: string | undefined) { + this.geneTab = id; + this.props.store.setSelectedMutationMapperGene(id); + } + + @computed get tabs() { + return this.props.store.genesWithMaxFrequency.map(g => ( + + )); + } + + @computed get activeTabId(): string | undefined { + let activeTabId; + if (this.geneTab) { + activeTabId = this.geneTab; + } else if (this.props.store.userSelectedMutationMapperGene) { + activeTabId = this.props.store.userSelectedMutationMapperGene; + } else { + activeTabId = this.props.store.activeMutationMapperGene! + .hugoGeneSymbol; + } + return activeTabId; } readonly tabUI = MakeMobxView({ @@ -45,14 +77,29 @@ export default class GroupComparisonMutationsTab extends React.Component< ); } + return ( <> - {!this.props.store.userSelectedMutationMapperGene && ( + {/* {!this.props.store.userSelectedMutationMapperGene ? ( +
+
+ Gene with highest frequency is displayed by + default. Gene can be changed in the dropdown + below. +
+
+ The top 10 genes with highest frequency are + shown below the dropdown and can be selected by + clicking on their respective tabs. +
+
+ ) : (
- Gene with highest frequency is displayed by default. - Gene can be changed in the dropdown below. + The top 10 genes with highest frequency are shown + below the dropdown and can be selected by clicking + on their respective tabs.
- )} + )} */} +
+
+ Highest Frequency: +
+ + this.handleGeneChange(id) + } + className="pillTabs comparisonMutationMapperTabs" + tabButtonStyle="pills" + defaultTabId={false} + > + {this.tabs} + +
{ if ( @@ -92,9 +93,12 @@ export default class GroupComparisonMutationsTabPlot extends React.Component< return ( <>

- {_(this.props.store.mutationsByGroup.result!) - .keys() - .join(' vs ')} + {this.props.store.activeMutationMapperGene + ?.hugoGeneSymbol + + ' mutations: ' + + _(this.props.store.mutationsByGroup.result!) + .keys() + .join(' vs ')}

); } else { - return null; + if ( + Object.values( + this.props.store.coverageInformation.result!.samples + ).some(s => !_.isEmpty(s.allGenes) || !_.isEmpty(s.byGene)) + ) { + return ( +
+ Selected gene has no mutations for profiled samples. +
+ ); + } else { + return ( +
+ Selected gene has no mutations due to no profiled + samples. +
+ ); + } } }, renderPending: () => ( diff --git a/src/pages/groupComparison/GroupComparisonStore.ts b/src/pages/groupComparison/GroupComparisonStore.ts index f2c96ba9728..c013d1ddd35 100644 --- a/src/pages/groupComparison/GroupComparisonStore.ts +++ b/src/pages/groupComparison/GroupComparisonStore.ts @@ -51,7 +51,7 @@ import { FeatureFlagEnum } from 'shared/featureFlags'; export default class GroupComparisonStore extends ComparisonStore { @observable private sessionId: string; - @observable private _userSelectedMutationMapperGene: string; + @observable private _userSelectedMutationMapperGene: string | undefined; constructor( sessionId: string, @@ -452,13 +452,8 @@ export default class GroupComparisonStore extends ComparisonStore { } @action.bound - public setSelectedMutationMapperGene(gene: Gene) { - this._userSelectedMutationMapperGene = gene.hugoGeneSymbol; - } - - @action.bound - public clearSelectedMutationMapperGene() { - this._userSelectedMutationMapperGene = ''; + public setSelectedMutationMapperGene(gene: string | undefined) { + this._userSelectedMutationMapperGene = gene; } @autobind diff --git a/src/pages/groupComparison/LollipopGeneSelector.tsx b/src/pages/groupComparison/LollipopGeneSelector.tsx index de76cc1b397..00979723f9a 100644 --- a/src/pages/groupComparison/LollipopGeneSelector.tsx +++ b/src/pages/groupComparison/LollipopGeneSelector.tsx @@ -8,58 +8,59 @@ import GroupComparisonStore from './GroupComparisonStore'; interface ILollipopGeneSelectorProps { store: GroupComparisonStore; genes: Gene[]; + handleGeneChange: (id?: string) => void; } -export const LollipopGeneSelector: React.FC = ({ - store, - genes, -}: ILollipopGeneSelectorProps) => { - const loadOptions = (inputText: string, callback: any) => { - if (!inputText) { - callback([]); - } - const stringCompare = (item: any) => - item.hugoGeneSymbol.startsWith(inputText.toUpperCase()); - const options = genes; - callback( - options - .filter(stringCompare) - .slice(0, 200) - .map(g => ({ - label: g.hugoGeneSymbol, - value: g, - })) - ); - }; +export const LollipopGeneSelector: React.FC = observer( + ({ store, genes, handleGeneChange }: ILollipopGeneSelectorProps) => { + const loadOptions = (inputText: string, callback: any) => { + if (!inputText) { + callback([]); + } + const stringCompare = (item: any) => + item.hugoGeneSymbol.startsWith(inputText.toUpperCase()); + const options = genes; + callback( + options + .filter(stringCompare) + .slice(0, 200) + .map(g => ({ + label: g.hugoGeneSymbol, + value: g, + })) + ); + }; - return ( -
- { - if (option) { - store.setSelectedMutationMapperGene(option.value); - } else { - store.clearSelectedMutationMapperGene(); + return ( +
+ { + if (option) { + handleGeneChange(option.value.hugoGeneSymbol); + } else { + handleGeneChange(undefined); + } + }} + isClearable={true} + isSearchable={true} + defaultOptions={genes.slice(0, 200).map(gene => ({ + label: gene.hugoGeneSymbol, + value: gene, + }))} + value={ + store.userSelectedMutationMapperGene + ? { + label: store.userSelectedMutationMapperGene, + value: store.activeMutationMapperGene, + } + : null } - }} - isClearable={true} - isSearchable={true} - defaultOptions={genes.slice(0, 200).map(gene => ({ - label: gene.hugoGeneSymbol, - value: gene, - }))} - value={{ - label: store.activeMutationMapperGene!.hugoGeneSymbol, - value: store.activeMutationMapperGene, - }} - placeholder={ - store.activeMutationMapperGene!.hugoGeneSymbol || - 'Select a gene' - } - loadOptions={loadOptions} - cacheOptions={true} - /> -
- ); -}; + placeholder={'Search genes'} + loadOptions={loadOptions} + cacheOptions={true} + /> +
+ ); + } +); diff --git a/src/shared/components/MSKTabs/MSKTabs.tsx b/src/shared/components/MSKTabs/MSKTabs.tsx index ad468bfcd94..762d94b870f 100644 --- a/src/shared/components/MSKTabs/MSKTabs.tsx +++ b/src/shared/components/MSKTabs/MSKTabs.tsx @@ -117,6 +117,7 @@ interface IMSKTabsProps { contentWindowExtra?: JSX.Element; hrefRoot?: string; onMount?: () => void; + defaultTabId?: string | Boolean; } @observer @@ -218,9 +219,11 @@ export class MSKTabs extends React.Component { ) { return this.props.activeTabId; } else { - return (toArrayedChildren[0] as React.ReactElement< - IMSKTabProps - >).props.id; + return this.props.defaultTabId === false + ? undefined + : (toArrayedChildren[0] as React.ReactElement< + IMSKTabProps + >).props.id; } })(); @@ -287,7 +290,7 @@ export class MSKTabs extends React.Component { protected navTabs( children: React.ReactElement[], - effectiveActiveTab: string + effectiveActiveTab: string | undefined ) { // restart the tab refs before each tab rendering this.tabRefs = []; @@ -349,7 +352,7 @@ export class MSKTabs extends React.Component { protected tabPages( children: React.ReactElement[], - effectiveActiveTab: string + effectiveActiveTab: string | undefined ): JSX.Element[][] { const pages: JSX.Element[][] = [[]]; let currentPage = 1;