Skip to content

Commit 744cee9

Browse files
gblaihBryan Lai
and
Bryan Lai
authored
Oncoprint track selection: allow bulk submission of Oncoprint tracks (#4780)
* add submit button in tracks menu to add toggled tracks * move buttom to bottom of menu and add functionality to other tabs * change button name to update tracks * fix bug with tracks having value Mixed * fix tests and update tracks button now closes tracks menu --------- Co-authored-by: Bryan Lai <laib1@mskcc.org>
1 parent 100f4b9 commit 744cee9

File tree

5 files changed

+107
-29
lines changed

5 files changed

+107
-29
lines changed

end-to-end-test/remote/specs/core/resultsOncoprintColorConfig.spec.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,14 @@ describe('oncoprint colors', () => {
3535
getElementByTestHandle('add-chart-option-mutation-spectrum')
3636
.$('label')
3737
.click();
38+
getElementByTestHandle('update-tracks').waitForDisplayed();
39+
getElementByTestHandle('update-tracks').click();
3840
waitForOncoprint(ONCOPRINT_TIMEOUT);
3941

4042
// check that mutation spectrum is added to the oncoprint
4143
let legendText = getTextInOncoprintLegend();
4244
assert(legendText.indexOf('Mutation spectrum') > -1);
4345

44-
$tracksDropdown.waitForDisplayed();
45-
$tracksDropdown.click();
46-
4746
var trackOptionsElts = getNthOncoprintTrackOptionsElements(5);
4847
// open menu
4948
$(trackOptionsElts.button_selector).click();

src/pages/resultsView/oncoprint/TracksMenu.tsx

Lines changed: 80 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,18 @@ export default class TracksMenu extends React.Component<IAddTrackProps, {}> {
6565
string
6666
>({}, { deep: true });
6767

68+
private tracksDropdown: CustomDropdown;
69+
6870
constructor(props: IAddTrackProps) {
6971
super(props);
7072
makeObservable(this);
7173
}
7274

75+
@autobind
76+
private tracksDropdownRef(dropdown: CustomDropdown) {
77+
this.tracksDropdown = dropdown;
78+
}
79+
7380
@action.bound
7481
private updateTabId(newId: Tab) {
7582
this.tabId = newId;
@@ -288,6 +295,9 @@ export default class TracksMenu extends React.Component<IAddTrackProps, {}> {
288295
clinicalAttributeIds.map(id => new ClinicalTrackConfig(id))
289296
)
290297
);
298+
this.props.handlers.onChangeToggledClinicalTracks!(
299+
this.getSelectedClinicalAttributes()
300+
);
291301
}
292302

293303
@action.bound
@@ -299,30 +309,64 @@ export default class TracksMenu extends React.Component<IAddTrackProps, {}> {
299309
'stableId'
300310
)
301311
);
312+
this.props.handlers.onChangeToggledClinicalTracks!(
313+
this.getSelectedClinicalAttributes()
314+
);
315+
}
316+
317+
@action.bound
318+
private submit() {
319+
this.props.handlers.onChangeSelectedClinicalTracks!(
320+
this.props.state.toggledClinicalTracks!
321+
);
322+
this.tracksDropdown.hide();
302323
}
303324

304325
@action.bound
305326
private toggleClinicalTrack(clinicalAttributeId: string) {
306-
const toggled = toggleIncluded(
307-
new ClinicalTrackConfig(clinicalAttributeId),
308-
this.getSelectedClinicalAttributes(),
309-
track => track.stableId === clinicalAttributeId
327+
this.props.handlers.onChangeToggledClinicalTracks!(
328+
toggleIncluded(
329+
new ClinicalTrackConfig(clinicalAttributeId),
330+
this.props.state.toggledClinicalTracks!,
331+
track => track.stableId === clinicalAttributeId
332+
)
333+
);
334+
}
335+
336+
@computed get showSubmit() {
337+
return (
338+
_.xorBy(
339+
this.getSelectedClinicalAttributes(),
340+
this.props.state.toggledClinicalTracks!,
341+
'stableId'
342+
).length !== 0
310343
);
311-
this.props.handlers.onChangeSelectedClinicalTracks!(toggled);
312344
}
313345

314346
readonly addClinicalTracksMenu = MakeMobxView({
315347
await: () => [this.trackOptionsByType],
316348
render: () => (
317-
<AddChartByType
318-
options={this.trackOptionsByType.result!.clinical}
319-
freqPromise={this.clinicalAttributeIdToAvailableFrequency}
320-
onAddAll={this.addAll}
321-
onClearAll={this.clear}
322-
onToggleOption={this.toggleClinicalTrack}
323-
optionsGivenInSortedOrder={true}
324-
width={this.dropdownWidth}
325-
/>
349+
<>
350+
<AddChartByType
351+
options={this.trackOptionsByType.result!.clinical}
352+
freqPromise={this.clinicalAttributeIdToAvailableFrequency}
353+
onAddAll={this.addAll}
354+
onClearAll={this.clear}
355+
onToggleOption={this.toggleClinicalTrack}
356+
optionsGivenInSortedOrder={true}
357+
width={this.dropdownWidth}
358+
/>
359+
{this.showSubmit && (
360+
<button
361+
className="btn btn-primary btn-sm"
362+
data-test="update-tracks"
363+
style={{ marginTop: '10px', marginBottom: '0px' }}
364+
onClick={this.submit}
365+
>
366+
{'Update tracks'}
367+
</button>
368+
)}
369+
</>
326370
),
327371
renderPending: () => <LoadingIndicator isLoading={true} small={true} />,
328372
showLastRenderWhenPending: true,
@@ -349,6 +393,16 @@ export default class TracksMenu extends React.Component<IAddTrackProps, {}> {
349393
frequencyHeaderTooltip="% samples in group"
350394
width={this.dropdownWidth}
351395
/>
396+
{this.showSubmit && (
397+
<button
398+
className="btn btn-primary btn-sm"
399+
data-test="update-tracks"
400+
style={{ marginTop: '10px', marginBottom: '0px' }}
401+
onClick={this.submit}
402+
>
403+
{'Update tracks'}
404+
</button>
405+
)}
352406
</>
353407
),
354408
renderPending: () => <LoadingIndicator isLoading={true} small={true} />,
@@ -376,6 +430,16 @@ export default class TracksMenu extends React.Component<IAddTrackProps, {}> {
376430
frequencyHeaderTooltip="% samples in group"
377431
width={this.dropdownWidth}
378432
/>
433+
{this.showSubmit && (
434+
<button
435+
className="btn btn-primary btn-sm"
436+
data-test="update-tracks"
437+
style={{ marginTop: '10px', marginBottom: '0px' }}
438+
onClick={this.submit}
439+
>
440+
{'Update tracks'}
441+
</button>
442+
)}
379443
</>
380444
),
381445
renderPending: () => <LoadingIndicator isLoading={true} small={true} />,
@@ -392,7 +456,7 @@ export default class TracksMenu extends React.Component<IAddTrackProps, {}> {
392456
selected:
393457
option.key in
394458
_.keyBy(
395-
this.getSelectedClinicalAttributes().map(
459+
this.props.state.toggledClinicalTracks!.map(
396460
a => a.stableId
397461
)
398462
),
@@ -677,6 +741,7 @@ export default class TracksMenu extends React.Component<IAddTrackProps, {}> {
677741
id="addTracksDropdown"
678742
className="oncoprintAddTracksDropdown"
679743
styles={{ minWidth: MIN_DROPDOWN_WIDTH, width: 'auto' }}
744+
ref={this.tracksDropdownRef}
680745
>
681746
<div
682747
style={{

src/shared/components/oncoprint/ResultsViewOncoprint.tsx

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -165,11 +165,7 @@ export function getClinicalTrackColor(
165165
let valueIndex = _.indexOf(track.countsCategoryLabels, value);
166166
return track.countsCategoryFills[valueIndex];
167167
} else if (track.datatype === 'string' && track.category_to_color) {
168-
if (
169-
(track.label === 'Sample Type' ||
170-
track.label === 'Sample type id') &&
171-
value === 'Mixed'
172-
) {
168+
if (value === 'Mixed') {
173169
return track.category_to_color[value] || [48, 97, 194, 1];
174170
}
175171
return track.category_to_color[value];
@@ -306,6 +302,8 @@ export default class ResultsViewOncoprint extends React.Component<
306302

307303
@observable renderingComplete = false;
308304

305+
@observable toggledClinicalTracks: ClinicalTrackConfig[];
306+
309307
private heatmapGeneInputValueUpdater: IReactionDisposer;
310308

311309
private molecularProfileIdToTrackGroupIndex: {
@@ -508,6 +506,13 @@ export default class ResultsViewOncoprint extends React.Component<
508506
get selectedClinicalAttributeSpecInits(): ClinicalTrackConfigMap {
509507
return self.selectedClinicalTrackConfig;
510508
},
509+
get toggledClinicalTracks(): ClinicalTrackConfig[] {
510+
if (!self.toggledClinicalTracks) {
511+
return _.values(self.selectedClinicalTrackConfig);
512+
} else {
513+
return self.toggledClinicalTracks;
514+
}
515+
},
511516
get selectedColumnType() {
512517
return self.oncoprintAnalysisCaseType;
513518
},
@@ -859,6 +864,11 @@ export default class ResultsViewOncoprint extends React.Component<
859864
});
860865
},
861866
onChangeSelectedClinicalTracks: this.setSessionClinicalTracks,
867+
onChangeToggledClinicalTracks: (
868+
clinicalTracks: ClinicalTrackConfig[]
869+
) => {
870+
this.toggledClinicalTracks = clinicalTracks;
871+
},
862872
onChangeHeatmapGeneInputValue: action((s: string) => {
863873
this.heatmapGeneInputValue = s;
864874
this.heatmapGeneInputValueUpdater(); // stop updating heatmap input if user has typed
@@ -1313,6 +1323,10 @@ export default class ResultsViewOncoprint extends React.Component<
13131323
...session.userSettings,
13141324
clinicallist: _.values(json),
13151325
};
1326+
this.controlsHandlers.onChangeToggledClinicalTracks &&
1327+
this.controlsHandlers.onChangeToggledClinicalTracks(
1328+
_.values(json)
1329+
);
13161330
}
13171331
}
13181332

@@ -1892,11 +1906,7 @@ export default class ResultsViewOncoprint extends React.Component<
18921906
_.indexOf(MUTATION_SPECTRUM_CATEGORIES, value)
18931907
];
18941908
} else if (this.selectedClinicalTrack.datatype === 'string') {
1895-
if (
1896-
(this.selectedClinicalTrack.label === 'Sample Type' ||
1897-
this.selectedClinicalTrack.label === 'Sample type id') &&
1898-
value === 'Mixed'
1899-
) {
1909+
if (value === 'Mixed') {
19001910
return [48, 97, 194, 1];
19011911
} else {
19021912
return hexToRGBA(

src/shared/components/oncoprint/controls/CustomDropdown.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export default class CustomDropdown extends React.Component<
4848
@observable private open: boolean = false;
4949

5050
private toggle: () => void;
51-
private hide: () => void;
51+
public hide: () => void;
5252

5353
constructor(props: ButtonProps) {
5454
super(props);

src/shared/components/oncoprint/controls/OncoprintControls.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ export interface IOncoprintControlsHandlers
7474
onChangeSelectedClinicalTracks?: (
7575
trackConfigs: ClinicalTrackConfig[]
7676
) => void;
77+
onChangeToggledClinicalTracks?: (
78+
trackConfigs: ClinicalTrackConfig[]
79+
) => void;
7780
onClickAddGenesToHeatmap?: () => void;
7881
onSelectGenericAssayProfile?: (molecularProfileId: string) => void;
7982
onClickAddGenericAssays?: (info: GenericAssayTrackInfo[]) => void;
@@ -110,6 +113,7 @@ export interface IOncoprintControlsState
110113
[clinicalAttributeId: string]: number;
111114
}>;
112115
selectedClinicalAttributeSpecInits?: ClinicalTrackConfigMap;
116+
toggledClinicalTracks?: ClinicalTrackConfig[];
113117
heatmapProfilesPromise?: MobxPromise<MolecularProfile[]>;
114118
genericAssayEntitiesGroupedByGenericAssayTypePromise?: MobxPromise<{
115119
[genericAssayType: string]: GenericAssayMeta[];

0 commit comments

Comments
 (0)