diff --git a/packages/react-mutation-mapper/src/component/filter/ProteinImpactTypeBadgeSelector.tsx b/packages/react-mutation-mapper/src/component/filter/ProteinImpactTypeBadgeSelector.tsx index 4140a38c3c7..97b7ccb2a61 100644 --- a/packages/react-mutation-mapper/src/component/filter/ProteinImpactTypeBadgeSelector.tsx +++ b/packages/react-mutation-mapper/src/component/filter/ProteinImpactTypeBadgeSelector.tsx @@ -66,7 +66,7 @@ export class ProteinImpactTypeBadgeSelector< public static defaultProps: Partial = { colors: DEFAULT_PROTEIN_IMPACT_TYPE_COLORS, alignColumns: true, - unselectOthersWhenAllSelected: true, + unselectOthersWhenAllSelected: false, numberOfColumnsPerRow: 2, }; diff --git a/packages/react-mutation-mapper/src/index.tsx b/packages/react-mutation-mapper/src/index.tsx index 423eb5f2e75..f65297fce0b 100644 --- a/packages/react-mutation-mapper/src/index.tsx +++ b/packages/react-mutation-mapper/src/index.tsx @@ -152,7 +152,6 @@ export { SequenceSpec } from './model/SequenceSpec'; export * from './util/DataFetcherUtils'; export * from './util/FilterUtils'; -export * from 'cbioportal-utils'; export { MUTATION_TYPE_PRIORITY, mutationTypeSort, @@ -163,6 +162,7 @@ export { defaultOncoKbFilter, groupOncoKbIndicatorDataByMutations, } from './util/OncoKbUtils'; +export * from './util/SelectorUtils'; export * from './util/TrackUtils'; export { default as DefaultMutationMapperDataFetcher } from './store/DefaultMutationMapperDataFetcher'; diff --git a/src/pages/patientView/structuralVariant/column/AnnotationColumnFormatter.tsx b/src/pages/patientView/structuralVariant/column/AnnotationColumnFormatter.tsx index 0a6d6d9e0a0..493160ff673 100644 --- a/src/pages/patientView/structuralVariant/column/AnnotationColumnFormatter.tsx +++ b/src/pages/patientView/structuralVariant/column/AnnotationColumnFormatter.tsx @@ -7,7 +7,6 @@ import { IAnnotation, USE_DEFAULT_PUBLIC_INSTANCE_FOR_ONCOKB, oncoKbAnnotationSortValue, - calculateOncoKbAvailableDataType, } from 'react-mutation-mapper'; import { CancerStudy, StructuralVariant } from 'cbioportal-ts-api-client'; import { IAnnotationColumnProps } from 'shared/components/mutationTable/column/AnnotationColumnFormatter'; @@ -17,6 +16,7 @@ import { IOncoKbData, generateQueryStructuralVariantId, OncoKbCardDataType, + calculateOncoKbAvailableDataType, } from 'cbioportal-utils'; export default class AnnotationColumnFormatter { diff --git a/src/pages/resultsView/mutation/DriverAnnotationProteinImpactTypeBadgeSelector.tsx b/src/pages/resultsView/mutation/DriverAnnotationProteinImpactTypeBadgeSelector.tsx index afd08e1f49c..2812f435fc7 100644 --- a/src/pages/resultsView/mutation/DriverAnnotationProteinImpactTypeBadgeSelector.tsx +++ b/src/pages/resultsView/mutation/DriverAnnotationProteinImpactTypeBadgeSelector.tsx @@ -3,8 +3,11 @@ import { ProteinImpactTypeBadgeSelectorProps, DEFAULT_PROTEIN_IMPACT_TYPE_COLORS, BadgeSelector, + getAllOptionValues, + getSelectedOptionValues, getProteinImpactTypeOptionLabel, getProteinImpactTypeBadgeLabel, + DataFilter, } from 'react-mutation-mapper'; import * as React from 'react'; import { @@ -20,7 +23,7 @@ import { } from 'cbioportal-frontend-commons'; import _ from 'lodash'; import { observer } from 'mobx-react'; -import { action, makeObservable, observable } from 'mobx'; +import { action, computed, makeObservable, observable } from 'mobx'; import './mutations.scss'; import styles from './badgeSelector.module.scss'; @@ -51,6 +54,32 @@ export interface IDriverAnnotationProteinImpactTypeBadgeSelectorProps allValuesSelected?: boolean ) => void; onClickSettingMenu?: (visible: boolean) => void; + annotatedProteinImpactTypeFilter?: DataFilter; +} + +function findSelectedDriverVsVus( + type: DriverVsVusType, + selectedOption: string[], + alreadySelectedValues: { value: string }[], + allTypes: ProteinImpactType[] +): string[] { + let toSelect: string[] = []; + + // If "type" is selected then also select all of corresponding mutation types + if (selectedOption.includes(type)) { + toSelect = allTypes; + } + // If "type" is not selected, decide whether we unselect all mutations corresponding to that type as well + else { + // if selected mutation types already includes ALL of the mutations corresponding to the given type + // then it means "type" is just UNSELECTED, + // we should not add "type" mutations back in the selected in that case + if (alreadySelectedValues.length !== allTypes.length) { + toSelect = alreadySelectedValues.map(v => v.value); + } + } + + return toSelect; } @observer @@ -62,18 +91,59 @@ export default class DriverAnnotationProteinImpactTypeBadgeSelector extends Prot makeObservable(this); } - @observable selectedDriverVsVusValues: string[] = [ - DriverVsVusType.DRIVER, - DriverVsVusType.VUS, - ]; @observable settingMenuVisible = false; + @computed get selectedMutationTypeValues() { + return getSelectedOptionValues( + getAllOptionValues(this.options), + this.props.filter + ); + } + + @computed get selectedDriverMutationTypeValues() { + return this.selectedMutationTypeValues.filter(v => + (PUTATIVE_DRIVER_TYPE as string[]).includes(v.value) + ); + } + + @computed get selectedVUSMutationTypeValues() { + return this.selectedMutationTypeValues.filter(v => + (UNKNOWN_SIGNIFICANCE_TYPE as string[]).includes(v.value) + ); + } + + @computed get selectedDriverVsVusValues() { + if (this.props.annotatedProteinImpactTypeFilter) { + // If all driver(vus) mutation types are selected, select "Driver"("VUS") button + let driverVsVusValues = []; + if ( + _.intersection( + this.props.annotatedProteinImpactTypeFilter.values, + PUTATIVE_DRIVER_TYPE + ).length === PUTATIVE_DRIVER_TYPE.length + ) { + driverVsVusValues.push(DriverVsVusType.DRIVER); + } + if ( + _.intersection( + this.props.annotatedProteinImpactTypeFilter.values, + UNKNOWN_SIGNIFICANCE_TYPE + ).length === UNKNOWN_SIGNIFICANCE_TYPE.length + ) { + driverVsVusValues.push(DriverVsVusType.VUS); + } + return driverVsVusValues; + } else { + return [DriverVsVusType.DRIVER, DriverVsVusType.VUS]; + } + } + public static defaultProps: Partial< IDriverAnnotationProteinImpactTypeBadgeSelectorProps > = { colors: DEFAULT_PROTEIN_IMPACT_TYPE_COLORS, alignColumns: true, - unselectOthersWhenAllSelected: true, + unselectOthersWhenAllSelected: false, numberOfColumnsPerRow: 2, }; @@ -198,42 +268,25 @@ export default class DriverAnnotationProteinImpactTypeBadgeSelector extends Prot selectedOption: string[], allValuesSelected: boolean ) { - let selected: string[] = []; - // If select "Driver" or "VUS", then also select corresponding mutation types - _.forEach(selectedOption, option => { - if (option === DriverVsVusType.DRIVER) { - selected = _.union(selected, PUTATIVE_DRIVER_TYPE); - } - if (option === DriverVsVusType.VUS) { - selected = _.union(selected, UNKNOWN_SIGNIFICANCE_TYPE); - } - }); - this.props.onSelect && this.props.onSelect(selected, allValuesSelected); - this.selectedDriverVsVusValues = selectedOption; - } + const selectedDriver = findSelectedDriverVsVus( + DriverVsVusType.DRIVER, + selectedOption, + this.selectedDriverMutationTypeValues, + PUTATIVE_DRIVER_TYPE + ); + + const selectedVus = findSelectedDriverVsVus( + DriverVsVusType.VUS, + selectedOption, + this.selectedVUSMutationTypeValues, + UNKNOWN_SIGNIFICANCE_TYPE + ); - @action.bound - protected onMutationTypeSelect( - selectedOption: string[], - allValuesSelected: boolean - ) { - // If all driver(vus) mutation types are selected, select "Driver"("VUS") button - let updatedDriverVsVusValues = []; - if ( - _.intersection(selectedOption, PUTATIVE_DRIVER_TYPE).length === - PUTATIVE_DRIVER_TYPE.length - ) { - updatedDriverVsVusValues.push(DriverVsVusType.DRIVER); - } - if ( - _.intersection(selectedOption, UNKNOWN_SIGNIFICANCE_TYPE).length === - UNKNOWN_SIGNIFICANCE_TYPE.length - ) { - updatedDriverVsVusValues.push(DriverVsVusType.VUS); - } - this.selectedDriverVsVusValues = updatedDriverVsVusValues; this.props.onSelect && - this.props.onSelect(selectedOption, allValuesSelected); + this.props.onSelect( + selectedDriver.concat(selectedVus), + allValuesSelected + ); } @action.bound @@ -263,7 +316,7 @@ export default class DriverAnnotationProteinImpactTypeBadgeSelector extends Prot getOptionLabel={getProteinImpactTypeOptionLabel} getBadgeLabel={getProteinImpactTypeBadgeLabel} {...this.props} - onSelect={this.onMutationTypeSelect} + onSelect={this.props.onSelect} /> ); diff --git a/src/shared/components/mutationMapper/MutationMapper.tsx b/src/shared/components/mutationMapper/MutationMapper.tsx index a00f569c75c..33683bfb698 100644 --- a/src/shared/components/mutationMapper/MutationMapper.tsx +++ b/src/shared/components/mutationMapper/MutationMapper.tsx @@ -333,6 +333,12 @@ export default class MutationMapper< return findProteinImpactTypeFilter(this.store.dataStore.dataFilters); } + @computed get annotatedProteinImpactTypeFilter() { + return this.store.dataStore.dataFilters.find( + filter => filter.type === ANNOTATED_PROTEIN_IMPACT_FILTER_TYPE + ); + } + /** * Overriding the parent method to have a customized filter panel. */ @@ -350,6 +356,9 @@ export default class MutationMapper< counts={this.mutationCountsByProteinImpactType} onSelect={this.onProteinImpactTypeSelect} onClickSettingMenu={this.props.onClickSettingMenu} + annotatedProteinImpactTypeFilter={ + this.annotatedProteinImpactTypeFilter + } /> ) : (