Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgraded react-mutation-mapper version to 0.3.0 #2706

Merged
merged 2 commits into from
Nov 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 2 additions & 3 deletions end-to-end-test/remote/specs/core/results.logic.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,11 @@ describe('single study query', function() {
$('a.tabAnchor_mutations').waitForExist(10000);
$('a.tabAnchor_mutations').click();

$('[data-test="germlineMutationRate"]').waitForExist(60000);
var text = browser.getText('[data-test="germlineMutationRate"]')
$('[data-test="mutation-rate-summary"]').waitForExist(60000);
var text = browser.getText('[data-test="mutation-rate-summary"]');
// check germline mutation rate
assert(text.search('8.2%') > -1);
// check somatic mutation
var text = browser.getText('[data-test="somaticMutationRate"]')
assert(text.search('3.5%') > -1);

});
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@
"react-markdown": "^3.4.1",
"react-mfb": "^0.6.0",
"react-motion": "^0.4.7",
"react-mutation-mapper": "^0.2.6",
"react-mutation-mapper": "^0.3.0",
"react-overlays": "0.7.4",
"react-portal": "^4.2.0",
"react-rangeslider": "^2.1.0",
Expand Down
83 changes: 40 additions & 43 deletions src/pages/resultsView/mutation/MutationRateSummary.tsx
Original file line number Diff line number Diff line change
@@ -1,45 +1,28 @@
import * as React from 'react';
import {DataFilter} from "react-mutation-mapper";
import {MolecularProfile, Mutation, SampleIdentifier} from "shared/api/generated/CBioPortalAPI";
import {germlineMutationRate, somaticMutationRate} from "shared/lib/MutationUtils";
import {computed} from "mobx";
import {MobxPromise} from "mobxpromise";
import {observer} from "mobx-react";
import DefaultTooltip from "public-lib/components/defaultTooltip/DefaultTooltip";

import MutationStatusSelector from "./MutationStatusSelector";

export interface IMutationRateSummaryProps {
mutations: Mutation[];
hugoGeneSymbol: string;
samples: SampleIdentifier[];
germlineConsentedSamples: MobxPromise<SampleIdentifier[]>;
molecularProfileIdToMolecularProfile:MobxPromise<{[molecularProfileId:string]:MolecularProfile}>;
mutationStatusFilter?: DataFilter<string>;
onMutationStatusSelect?: (selectedOptionIds: string[], allValuesSelected?: boolean) => void;
}

@observer
export default class MutationRateSummary extends React.Component<IMutationRateSummaryProps, {}>
{
public somaticMutationFrequency(): JSX.Element
{
let rate = 0;

if (this.props.samples.length > 0) {
rate = somaticMutationRate(this.props.hugoGeneSymbol, this.props.mutations, this.props.molecularProfileIdToMolecularProfile.result!, this.props.samples);
}

return (
<div data-test="somaticMutationRate">
<label>Somatic Mutation Frequency:</label>
{rate.toFixed(1)}%

<DefaultTooltip
placement="right"
overlay={(<span>{'Percentage of samples with a somatic mutation in ' + this.props.hugoGeneSymbol}</span>)}
>
<i className="fa fa-info-circle" style={{'marginLeft':5}}></i>
</DefaultTooltip>
</div>
);
}

public germlineMutationFrequency(): JSX.Element
@computed
public get germlineMutationRate()
{
let samples: SampleIdentifier[]|undefined;

Expand All @@ -56,28 +39,42 @@ export default class MutationRateSummary extends React.Component<IMutationRateSu
) ? this.props.germlineConsentedSamples.result : this.props.samples;
}

const gmr = samples ? germlineMutationRate(this.props.hugoGeneSymbol, this.props.mutations, this.props.molecularProfileIdToMolecularProfile.result!, samples) : 0;
return samples ? germlineMutationRate(this.props.hugoGeneSymbol,
this.props.mutations,
this.props.molecularProfileIdToMolecularProfile.result!,
samples): 0;
}

return (
<div data-test='germlineMutationRate' className={(gmr > 0) ? '' : 'invisible' }>
<label>Germline Mutation Frequency:</label>
{(gmr > 0) ? `${gmr.toFixed(1)}%` : '--'}
<DefaultTooltip
placement="right"
overlay={(<span>{'Percentage of samples with a germline mutation in ' + this.props.hugoGeneSymbol}</span>)}
>
<i className="fa fa-info-circle" style={{'marginLeft':5}}></i>
</DefaultTooltip>
</div>
);
@computed
public get somaticMutationRate()
{
return this.props.samples.length > 0 ? somaticMutationRate(this.props.hugoGeneSymbol,
this.props.mutations,
this.props.molecularProfileIdToMolecularProfile.result!,
this.props.samples): 0;
}

render() {
render()
{
return (
<div>
{this.somaticMutationFrequency()}
{this.germlineMutationFrequency()}
</div>
<span data-test="mutation-rate-summary">
<MutationStatusSelector
filter={this.props.mutationStatusFilter}
onSelect={this.props.onMutationStatusSelect}
rates={{
"Germline": this.germlineMutationRate,
"Somatic": this.somaticMutationRate
}}
somaticContent={{
title: "Somatic Mutation Frequency",
description: `Percentage of samples with a somatic mutation in ${this.props.hugoGeneSymbol}`
}}
germlineContent={this.germlineMutationRate > 0 ? {
title: "Germline Mutation Frequency",
description: `Percentage of samples with a germline mutation in ${this.props.hugoGeneSymbol}`
}: undefined}
/>
</span>
);
}
}
101 changes: 101 additions & 0 deletions src/pages/resultsView/mutation/MutationStatusSelector.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import {computed} from "mobx";
import {observer} from "mobx-react";
import * as React from 'react';
import {
BadgeLabel,
formatPercentValue,
MUTATION_STATUS_BADGE_STYLE_OVERRIDE,
MutationStatusBadgeSelector,
MutationStatusBadgeSelectorProps
} from "react-mutation-mapper";

import DefaultTooltip from "public-lib/components/defaultTooltip/DefaultTooltip";


export function getFilterOptionLabel(content: {title: string, description?: string}): JSX.Element | string
{
if (content.description) {
return (
<span>
{content.title}
<DefaultTooltip
placement="right"
overlay={
<span>{content.description}</span>
}
>
<i className="fa fa-info-circle" style={{marginLeft: "0.2rem"}} />
</DefaultTooltip>
</span>
);
}
else {
return content.title;
}
}

type MutationStatusSelectorProps = MutationStatusBadgeSelectorProps & {
somaticContent: {title: string, description?: string};
germlineContent?: {title: string, description?: string};
};

@observer
export default class MutationStatusSelector extends React.Component<MutationStatusSelectorProps, {}>
{
@computed
private get mutationStatusFilterOptions()
{
const options = [
{
value: "Somatic",
label: getFilterOptionLabel(this.props.somaticContent),
badgeStyleOverride: MUTATION_STATUS_BADGE_STYLE_OVERRIDE,
badgeStyleSelectedOverride: MUTATION_STATUS_BADGE_STYLE_OVERRIDE
}
];

if (this.props.germlineContent)
{
options.push({
value: "Germline",
label: getFilterOptionLabel(this.props.germlineContent),
badgeStyleOverride: MUTATION_STATUS_BADGE_STYLE_OVERRIDE,
badgeStyleSelectedOverride: MUTATION_STATUS_BADGE_STYLE_OVERRIDE
});
}

return options;
}

private get somaticInfo()
{
return this.props.rates ? (
<BadgeLabel
label={getFilterOptionLabel(this.props.somaticContent)}
badgeContent={`${formatPercentValue(this.props.rates["Somatic"])}%`}
badgeStyleOverride={this.mutationStatusFilterOptions[0].badgeStyleOverride}
/>
): null;
}

private get germlinePlaceholder() {
return <div data-test='germlineMutationRate' className="invisible">%</div>
}

public render()
{
// Render the actual selector only if germline content exists.
// Otherwise just display the somatic info without a filter option.
return this.props.germlineContent === undefined ? (
<React.Fragment>
{this.somaticInfo}
{this.germlinePlaceholder}
</React.Fragment>
): (
<MutationStatusBadgeSelector
badgeSelectorOptions={this.mutationStatusFilterOptions}
{...this.props}
/>
);
}
}
26 changes: 24 additions & 2 deletions src/pages/resultsView/mutation/ResultsViewMutationMapper.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import autobind from "autobind-decorator";
import * as React from 'react';
import {DataFilterType, onFilterOptionSelect} from "react-mutation-mapper";
import {observer} from "mobx-react";
import {computed} from "mobx";
import {action, computed} from "mobx";

import {EnsemblTranscript} from "public-lib/api/generated/GenomeNexusAPI";
import DiscreteCNACache from "shared/cache/DiscreteCNACache";
Expand All @@ -11,11 +13,14 @@ import GenomeNexusMyVariantInfoCache from "shared/cache/GenomeNexusMyVariantInfo
import {
IMutationMapperProps, default as MutationMapper
} from "shared/components/mutationMapper/MutationMapper";
import {
MUTATION_STATUS_FILTER_ID
} from "shared/components/mutationMapper/MutationMapperDataStore";

import MutationRateSummary from "pages/resultsView/mutation/MutationRateSummary";
import ResultsViewMutationMapperStore from "pages/resultsView/mutation/ResultsViewMutationMapperStore";
import ResultsViewMutationTable from "pages/resultsView/mutation/ResultsViewMutationTable";
import {getMobxPromiseGroupStatus} from "../../../shared/lib/getMobxPromiseGroupStatus";
import {getMobxPromiseGroupStatus} from "shared/lib/getMobxPromiseGroupStatus";

export interface IResultsViewMutationMapperProps extends IMutationMapperProps
{
Expand All @@ -34,6 +39,10 @@ export default class ResultsViewMutationMapper extends MutationMapper<IResultsVi
super(props);
}

@computed get mutationStatusFilter() {
return this.store.dataStore.dataFilters.find(f => f.id === MUTATION_STATUS_FILTER_ID);
}

@computed get mutationRateSummary():JSX.Element|null {
// TODO we should not be even calculating mskImpactGermlineConsentedPatientIds for studies other than msk impact
if (this.props.store.germlineConsentedSamples &&
Expand All @@ -47,6 +56,8 @@ export default class ResultsViewMutationMapper extends MutationMapper<IResultsVi
mutations={this.props.store.mutationData.result}
samples={this.props.store.samples.result!}
germlineConsentedSamples={this.props.store.germlineConsentedSamples}
onMutationStatusSelect={this.onMutationStatusSelect}
mutationStatusFilter={this.mutationStatusFilter}
/>
);
} else {
Expand Down Expand Up @@ -112,4 +123,15 @@ export default class ResultsViewMutationMapper extends MutationMapper<IResultsVi
</span>
);
}

@autobind
@action
protected onMutationStatusSelect(selectedMutationStatusIds: string[], allValuesSelected: boolean)
{
onFilterOptionSelect(selectedMutationStatusIds,
allValuesSelected,
this.store.dataStore,
DataFilterType.MUTATION_STATUS,
MUTATION_STATUS_FILTER_ID);
}
}