Skip to content

Commit

Permalink
Save Column Visibility & Add "Reset Columns" Button (#3846)
Browse files Browse the repository at this point in the history
Fixes cBioPortal/cbioportal#8521, 3.1 Store user settings and 3.2 Add "reset to default" button based on app configuration in cBioPortal/cbioportal#8711, points 3 & 4 in cBioPortal/cbioportal#8716.

Changes:

Remembers active column selection when switching genes in Results View Mutation Table
Adds "Reset Columns" button which resets the visible columns back to their initial configuration (i.e., according to the visible attribute in the column definition). Note, this button is only shown when the current column selection is different from the default configuration. (Feedback on its design is appreciated.)
Fixes bug in cbioportal-frontend-commons where user-selection was prevented when passing columnVisibility prop to LazyMobXTable
  • Loading branch information
Rajat-Sirohi committed Jul 23, 2021
1 parent 0115b34 commit 3a990bc
Show file tree
Hide file tree
Showing 12 changed files with 97 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ describe('ColumnVisibilityResolver', () => {
});

describe('resolveColumnVisibility', () => {
it('relies only on custom column visibility contents when provided', () => {
it('properly overrides even custom column visibility when provided', () => {
const customColumnVisibility = {
'1st': false,
'2nd': true,
Expand Down Expand Up @@ -84,8 +84,8 @@ describe('ColumnVisibilityResolver', () => {

assert.deepEqual(
getVisibleColumnIds(colVis),
['2nd', '5th'],
'only 2nd and 5th columns should be visible'
['1st', '2nd', '3rd', '4th', '5th'],
'all columns should be visible'
);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,13 @@ export function resolveColumnVisibility(
): { [columnId: string]: boolean } {
let colVis: { [columnId: string]: boolean };

// if a custom columnVisibility object is provided use that one
if (columnVisibility) {
colVis = { ...columnVisibility };
colVis = {
// if a custom columnVisibility object is provided use that one
...columnVisibility,
// if exists override with the state from the latest user selection
...(columnVisibilityOverride || {}),
};
} else {
colVis = {
// resolve visibility by column definition
Expand Down
12 changes: 5 additions & 7 deletions src/pages/resultsView/ResultsViewPageStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3502,13 +3502,11 @@ export class ResultsViewPageStore {
this.mutations.isComplete &&
this.mutationsByGene.isComplete
) {
return this.mutationMapperStoreByGeneWithDriverKey[
this.getGeneWithDriverKey(gene)
]
? this.mutationMapperStoreByGeneWithDriverKey[
this.getGeneWithDriverKey(gene)
]
: this.createMutationMapperStoreForSelectedGene(gene);
return (
this.mutationMapperStoreByGeneWithDriverKey[
this.getGeneWithDriverKey(gene)
] || this.createMutationMapperStoreForSelectedGene(gene)
);
}
return undefined;
}
Expand Down
17 changes: 16 additions & 1 deletion src/pages/resultsView/mutation/AddColumns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ export default class AddColumns extends React.Component<IAddColumnsProps, {}> {
render() {
const haveMutationsOptions = this.mutationsOptions.length > 0;
const haveClinicalOptions = this.clinicalOptions.length > 0;
const showTabs = haveMutationsOptions || haveClinicalOptions;

return (
<div style={{ float: 'right' }}>
Expand All @@ -237,7 +238,7 @@ export default class AddColumns extends React.Component<IAddColumnsProps, {}> {
flexDirection: 'column',
}}
>
{(haveMutationsOptions || haveClinicalOptions) && (
{showTabs && (
<MSKTabs
activeTabId={this.tabId}
onTabClick={this.updateTabId}
Expand All @@ -264,6 +265,20 @@ export default class AddColumns extends React.Component<IAddColumnsProps, {}> {
)}
</MSKTabs>
)}
{showTabs && this.props.showResetColumnsButton && (
<button
style={{
position: 'absolute',
top: 11,
right: 12,
zIndex: 2,
}}
className="btn btn-primary btn-xs"
onClick={this.props.resetColumnVisibility}
>
Reset columns
</button>
)}
</div>
</CustomDropdown>
</div>
Expand Down
6 changes: 6 additions & 0 deletions src/pages/resultsView/mutation/Mutations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,12 @@ export default class Mutations extends React.Component<
trackVisibility={
this.userSelectionStore.trackVisibility
}
columnVisibility={
this.userSelectionStore.columnVisibility
}
storeColumnVisibility={
this.userSelectionStore.storeColumnVisibility
}
discreteCNACache={this.props.store.discreteCNACache}
pubMedCache={this.props.store.pubMedCache}
cancerTypeCache={this.props.store.cancerTypeCache}
Expand Down
2 changes: 2 additions & 0 deletions src/pages/resultsView/mutation/ResultsViewMutationMapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ export default class ResultsViewMutationMapper extends MutationMapper<
}
isCanonicalTranscript={this.props.store.isCanonicalTranscript}
selectedTranscriptId={this.props.store.activeTranscript.result}
columnVisibility={this.props.columnVisibility}
storeColumnVisibility={this.props.storeColumnVisibility}
sampleIdToClinicalDataMap={
this.props.store.clinicalDataGroupedBySampleMap
}
Expand Down
6 changes: 6 additions & 0 deletions src/pages/resultsView/mutation/ResultsViewMutationTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@ export default class ResultsViewMutationTable extends MutationTable<
columnVisibilityControlsProps.columnVisibility
}
onColumnToggled={columnVisibilityControlsProps.onColumnToggled}
resetColumnVisibility={
columnVisibilityControlsProps.resetColumnVisibility
}
showResetColumnsButton={
columnVisibilityControlsProps.showResetColumnsButton
}
clinicalAttributes={
this.props.mutationsTabClinicalAttributes.result!
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export interface IColumnVisibilityControlsProps {
columnId: string,
columnVisibility?: IColumnVisibilityDef[]
) => void;
resetColumnVisibility?: () => void;
showResetColumnsButton?: boolean;
customDropdown?: (props: IColumnVisibilityControlsProps) => JSX.Element;
}

Expand Down
29 changes: 27 additions & 2 deletions src/shared/components/lazyMobXTable/LazyMobXTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,9 @@ type LazyMobXTableProps<T> = {
showColumnVisibility?: boolean;
columnVisibilityProps?: IColumnVisibilityControlsProps;
columnVisibility?: { [columnId: string]: boolean };
storeColumnVisibility?: (columnVisibility: {
[columnId: string]: boolean;
}) => void;
pageToHighlight?: boolean;
showCountHeader?: boolean;
onRowClick?: (d: T) => void;
Expand Down Expand Up @@ -271,6 +274,7 @@ export class LazyMobXTableStore<T> {
@observable private onRowMouseLeave: ((d: T) => void) | undefined;

// this observable is intended to always refer to props.columnVisibility
// except possibly once "Reset columns" has been clicked
@observable private _columnVisibility:
| { [columnId: string]: boolean }
| undefined;
Expand Down Expand Up @@ -339,6 +343,13 @@ export class LazyMobXTableStore<T> {
return resolveColumnVisibilityByColumnDefinition(this.columns);
}

@computed public get showResetColumnsButton() {
return (
JSON.stringify(this.columnVisibility) !==
JSON.stringify(this.columnVisibilityByColumnDefinition)
);
}

@computed public get downloadData() {
const tableDownloadData: string[][] = [];

Expand Down Expand Up @@ -383,8 +394,7 @@ export class LazyMobXTableStore<T> {

@computed get sortColumnObject(): Column<T> | undefined {
return this.columns.find(
(col: Column<T>) =>
this.isVisible(col) && col.name === this.sortColumn
(col: Column<T>) => col.name === this.sortColumn
);
}

Expand Down Expand Up @@ -735,6 +745,12 @@ export class LazyMobXTableStore<T> {
}
}

@action.bound
resetColumnVisibility() {
this._columnVisibility = undefined;
this._columnVisibilityOverride = undefined;
}

public isVisible(column: Column<T>): boolean {
const index = column.hasOwnProperty('id') ? column.id! : column.name;
return this.columnVisibility[index] || false;
Expand Down Expand Up @@ -896,6 +912,9 @@ export default class LazyMobXTable<T> extends React.Component<
componentWillUnmount() {
this.filterInputReaction();
this.pageToHighlightReaction();
if (this.props.storeColumnVisibility) {
this.props.storeColumnVisibility(this.store.columnVisibility);
}
}

@action componentWillReceiveProps(nextProps: LazyMobXTableProps<T>) {
Expand Down Expand Up @@ -1020,6 +1039,12 @@ export default class LazyMobXTable<T> extends React.Component<
className="pull-right"
columnVisibility={this.store.colVisProp}
onColumnToggled={this.handlers.visibilityToggle}
resetColumnVisibility={
this.store.resetColumnVisibility
}
showResetColumnsButton={
this.store.showResetColumnsButton
}
{...this.props.columnVisibilityProps}
/>
) : (
Expand Down
4 changes: 4 additions & 0 deletions src/shared/components/mutationMapper/MutationMapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ export interface IMutationMapperProps {
store: MutationMapperStore;
isPutativeDriver?: (mutation: Partial<AnnotatedMutation>) => boolean;
trackVisibility?: TrackVisibility;
columnVisibility?: { [columnId: string]: boolean };
storeColumnVisibility?: (columnVisibility: {
[columnId: string]: boolean;
}) => void;
showPlotYMaxSlider?: boolean;
showPlotLegendToggle?: boolean;
showPlotDownloadControls?: boolean;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,29 @@
import { observable, makeObservable } from 'mobx';
import { action, observable, makeObservable } from 'mobx';
import {
initDefaultTrackVisibility,
TrackVisibility,
} from 'react-mutation-mapper';

export default class MutationMapperUserSelectionStore {
@observable trackVisibility: TrackVisibility;
@observable columnVisibility: {
[columnId: string]: boolean;
};

constructor() {
makeObservable(this);
this.trackVisibility = initDefaultTrackVisibility();
}

@action.bound
public storeColumnVisibility(columnVisibility: {
[columnId: string]: boolean;
}) {
if (
JSON.stringify(this.columnVisibility) !==
JSON.stringify(columnVisibility)
) {
this.columnVisibility = columnVisibility;
}
}
}
4 changes: 4 additions & 0 deletions src/shared/components/mutationTable/MutationTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@ export interface IMutationTableProps {
selectedTranscriptId?: string;
columnVisibility?: { [columnId: string]: boolean };
columnVisibilityProps?: IColumnVisibilityControlsProps;
storeColumnVisibility?: (columnVisibility: {
[columnId: string]: boolean;
}) => void;
onRowClick?: (d: Mutation[]) => void;
onRowMouseEnter?: (d: Mutation[]) => void;
onRowMouseLeave?: (d: Mutation[]) => void;
Expand Down Expand Up @@ -1248,6 +1251,7 @@ export default class MutationTable<
showCountHeader={this.props.showCountHeader}
columnVisibility={this.props.columnVisibility}
columnVisibilityProps={this.props.columnVisibilityProps}
storeColumnVisibility={this.props.storeColumnVisibility}
onRowClick={this.props.onRowClick}
onRowMouseEnter={this.props.onRowMouseEnter}
onRowMouseLeave={this.props.onRowMouseLeave}
Expand Down

0 comments on commit 3a990bc

Please sign in to comment.