Skip to content

Commit fa85a45

Browse files
author
Bas Leenknegt
committed
Force rerendering of study page filters when submitting
- Track submitted and queued filters in global stores - Submit queued filters when submitting or when changing submit mode - Keep global stores aligned using study view page store reaction
1 parent bc7ff6a commit fa85a45

File tree

7 files changed

+179
-101
lines changed

7 files changed

+179
-101
lines changed

src/pages/studyView/StudyViewPage.tsx

+16-28
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import { MSKTab, MSKTabs } from '../../shared/components/MSKTabs/MSKTabs';
55
import {
66
action,
77
computed,
8-
observable,
98
makeObservable,
9+
observable,
1010
runInAction,
1111
} from 'mobx';
1212
import {
@@ -24,6 +24,7 @@ import { ClinicalDataTab } from './tabs/ClinicalDataTab';
2424
import {
2525
DefaultTooltip,
2626
getBrowserWindow,
27+
onMobxPromise,
2728
remoteData,
2829
} from 'cbioportal-frontend-commons';
2930
import { PageLayout } from '../../shared/components/PageLayout/PageLayout';
@@ -38,7 +39,6 @@ import { Else, If, Then } from 'react-if';
3839
import CustomCaseSelection from './addChartButton/customCaseSelection/CustomCaseSelection';
3940
import { AppStore } from '../../AppStore';
4041
import ActionButtons from './studyPageHeader/ActionButtons';
41-
import { onMobxPromise } from 'cbioportal-frontend-commons';
4242
import {
4343
GACustomFieldsEnum,
4444
serializeEvent,
@@ -49,10 +49,10 @@ import classNames from 'classnames';
4949
import { getServerConfig, ServerConfigHelpers } from '../../config/config';
5050
import {
5151
AlterationMenuHeader,
52-
getButtonNameWithDownPointer,
5352
ChartMetaDataTypeEnum,
53+
getButtonNameWithDownPointer,
5454
} from './StudyViewUtils';
55-
import { Alert, Modal } from 'react-bootstrap';
55+
import { Modal } from 'react-bootstrap';
5656
import 'react-grid-layout/css/styles.css';
5757
import 'react-resizable/css/styles.css';
5858
import styles from './styles.module.scss';
@@ -74,10 +74,9 @@ import ErrorScreen from 'shared/components/errorScreen/ErrorScreen';
7474
import { CustomChartData } from 'shared/api/session-service/sessionServiceModels';
7575
import { HelpWidget } from 'shared/components/HelpWidget/HelpWidget';
7676
import { buildCBioPortalPageUrl } from 'shared/api/urls';
77-
import Tooltip from 'rc-tooltip';
7877
import { StudyViewContext } from 'pages/studyView/StudyViewContext';
79-
import StudyViewPageGearMenu from 'pages/studyView/menu/StudyViewPageGearMenu';
80-
import { QueuedFilterPillStore } from 'shared/components/PillTag/PillTag';
78+
import StudyViewPageSettingsMenu from 'pages/studyView/menu/StudyViewPageSettingsMenu';
79+
import { PillStore } from 'shared/components/PillTag/PillTag';
8180

8281
export interface IStudyViewPageProps {
8382
routing: any;
@@ -674,26 +673,11 @@ export default class StudyViewPage extends React.Component<
674673
'btn btn-sm btn-primary',
675674
styles.actionButtons
676675
)}
677-
onClick={() => {
678-
runInAction(() => {
679-
let hesitantPillStore = getBrowserWindow()
680-
.hesitantPillStore as QueuedFilterPillStore;
681-
_.forIn(
682-
hesitantPillStore,
683-
value => {
684-
const onDeleteCallback =
685-
value.onDeleteCallback;
686-
if (
687-
onDeleteCallback
688-
) {
689-
onDeleteCallback();
690-
}
691-
}
692-
);
693-
getBrowserWindow().hesitantPillStore = {};
694-
this.store.filters = this.store.filtersProx;
695-
});
696-
}}
676+
onClick={() =>
677+
runInAction(() =>
678+
this.submitHesitantFilters()
679+
)
680+
}
697681
>
698682
Submit ►
699683
</button>
@@ -1009,7 +993,7 @@ export default class StudyViewPage extends React.Component<
1009993
{ServerConfigHelpers.sessionServiceIsEnabled() &&
1010994
this.groupsButton}
1011995
</div>
1012-
<StudyViewPageGearMenu
996+
<StudyViewPageSettingsMenu
1013997
store={this.store}
1014998
/>
1015999
</div>
@@ -1021,6 +1005,10 @@ export default class StudyViewPage extends React.Component<
10211005
);
10221006
}
10231007

1008+
submitHesitantFilters() {
1009+
this.store.filterSubmitTime = performance.now();
1010+
}
1011+
10241012
private readonly body = MakeMobxView({
10251013
await: () => [
10261014
this.store.unknownQueriedIds,

src/pages/studyView/StudyViewPageStore.ts

+38
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ import {
172172
} from '../../shared/api/urls';
173173
import {
174174
DataType as DownloadDataType,
175+
getBrowserWindow,
175176
onMobxPromise,
176177
pluralize,
177178
remoteData,
@@ -263,6 +264,7 @@ import { PageType } from 'shared/userSession/PageType';
263264
import client from 'shared/api/cbioportalClientInstance';
264265
import { FeatureFlagEnum } from 'shared/featureFlags';
265266
import intersect from 'fast_array_intersect';
267+
import { PillStore } from 'shared/components/PillTag/PillTag';
266268

267269
type ChartUniqueKey = string;
268270
type ResourceId = string;
@@ -403,6 +405,16 @@ export class StudyViewPageStore
403405
@observable chartsBinMethod: { [chartKey: string]: BinMethodOption } = {};
404406
chartsBinsGeneratorConfigs = observable.map<string, BinsGeneratorConfig>();
405407

408+
@observable filterSubmitTime: number = performance.now();
409+
410+
/**
411+
* Force remount of filters when filters are submitted of submit mode changes
412+
*/
413+
@computed
414+
public get filtersRemountKey() {
415+
return `${this.hesitateUpdate}${this.filterSubmitTime}`;
416+
}
417+
406418
private getDataBinFilterSet(uniqueKey: string) {
407419
if (this.isGenericAssayChart(uniqueKey)) {
408420
return this._genericAssayDataBinFilterSet;
@@ -467,6 +479,32 @@ export class StudyViewPageStore
467479
)
468480
);
469481

482+
/**
483+
* Submit filters when submit mode changes
484+
* or when user clicks submit button
485+
*/
486+
this.reactionDisposers.push(
487+
reaction(
488+
() => [this.hesitateUpdate, this.filterSubmitTime],
489+
() => {
490+
const browserWindow = getBrowserWindow();
491+
const hesitantPillStore = browserWindow.hesitantPillStore as PillStore;
492+
const submittedPillStore = browserWindow.submittedPillStore as PillStore;
493+
_.forIn(hesitantPillStore, (value, key) => {
494+
const onDeleteCallback = value.onDeleteCallback;
495+
if (onDeleteCallback) {
496+
onDeleteCallback();
497+
delete submittedPillStore[key];
498+
} else {
499+
submittedPillStore[key] = value;
500+
}
501+
});
502+
browserWindow.hesitantPillStore = {};
503+
this.filters = this.filtersProx;
504+
}
505+
)
506+
);
507+
470508
this.reactionDisposers.push(
471509
reaction(
472510
() => [this.filtersProx, this.hesitateUpdate],

src/pages/studyView/UserSelections.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ import {
4040
getSampleIdentifiers,
4141
StudyViewComparisonGroup,
4242
} from '../groupComparison/GroupComparisonUtils';
43-
import { DefaultTooltip } from 'cbioportal-frontend-commons';
43+
import { DefaultTooltip, getBrowserWindow } from 'cbioportal-frontend-commons';
4444
import {
4545
OredPatientTreatmentFilters,
4646
OredSampleTreatmentFilters,
@@ -97,6 +97,7 @@ export default class UserSelections extends React.Component<
9797
super(props);
9898
makeObservable(this);
9999
}
100+
100101
@computed
101102
get showFilters() {
102103
//return isFiltered(this.props.filter)

src/pages/studyView/menu/StudyViewPageGearMenu.tsx src/pages/studyView/menu/AutosubmitToggle.tsx

+5-52
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,17 @@
1-
import { StudyViewPageStore } from 'pages/studyView/StudyViewPageStore';
1+
import { observer } from 'mobx-react';
22
import * as React from 'react';
3-
import { computed, makeObservable, observable } from 'mobx';
43
import classNames from 'classnames';
54
import styles from 'pages/studyView/styles.module.scss';
6-
import { DefaultTooltip } from 'cbioportal-frontend-commons';
7-
import { observer } from 'mobx-react';
85
import Tooltip from 'rc-tooltip';
96

10-
interface IStudyViewPageGearMenuProps {
7+
import { StudyViewPageStore } from 'pages/studyView/StudyViewPageStore';
8+
export type IAutosubmitToggleProps = {
119
store: StudyViewPageStore;
12-
}
13-
14-
@observer
15-
export default class StudyViewPageGearMenu extends React.Component<
16-
IStudyViewPageGearMenuProps,
17-
{}
18-
> {
19-
constructor(props: Readonly<IStudyViewPageGearMenuProps>) {
20-
super(props);
21-
makeObservable(this);
22-
}
23-
24-
@observable visible = false;
25-
26-
@computed get menu() {
27-
return (
28-
<div>
29-
<AutosubmitToggle store={this.props.store} />
30-
</div>
31-
);
32-
}
33-
34-
render() {
35-
return (
36-
<div className={classNames(styles.studyViewPageGearMenu)}>
37-
<DefaultTooltip
38-
trigger={'click'}
39-
placement="bottom"
40-
overlay={this.menu}
41-
visible={this.visible}
42-
onVisibleChange={visible => {
43-
this.visible = !!visible;
44-
}}
45-
>
46-
<button
47-
className={classNames('btn', 'btn-sm', 'btn-primary', {
48-
active: this.visible,
49-
})}
50-
>
51-
<i className="fa fa-cog" />
52-
</button>
53-
</DefaultTooltip>
54-
</div>
55-
);
56-
}
57-
}
10+
};
5811

5912
@observer
6013
export class AutosubmitToggle extends React.Component<
61-
IStudyViewPageGearMenuProps,
14+
IAutosubmitToggleProps,
6215
{}
6316
> {
6417
render() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { StudyViewPageStore } from 'pages/studyView/StudyViewPageStore';
2+
import * as React from 'react';
3+
import { computed, makeObservable, observable } from 'mobx';
4+
import classNames from 'classnames';
5+
import styles from 'pages/studyView/styles.module.scss';
6+
import { DefaultTooltip } from 'cbioportal-frontend-commons';
7+
import { observer } from 'mobx-react';
8+
import { AutosubmitToggle } from 'pages/studyView/menu/AutosubmitToggle';
9+
10+
export interface IStudyViewPageSettingsMenuProps {
11+
store: StudyViewPageStore;
12+
}
13+
14+
@observer
15+
export default class StudyViewPageSettingsMenu extends React.Component<
16+
IStudyViewPageSettingsMenuProps,
17+
{}
18+
> {
19+
constructor(props: Readonly<IStudyViewPageSettingsMenuProps>) {
20+
super(props);
21+
makeObservable(this);
22+
}
23+
24+
@observable visible = false;
25+
26+
@computed get menu() {
27+
return (
28+
<div>
29+
<AutosubmitToggle store={this.props.store} />
30+
</div>
31+
);
32+
}
33+
34+
render() {
35+
return (
36+
<div className={classNames(styles.studyViewPageGearMenu)}>
37+
<DefaultTooltip
38+
trigger={'click'}
39+
placement="bottom"
40+
overlay={this.menu}
41+
visible={this.visible}
42+
onVisibleChange={visible => {
43+
this.visible = !!visible;
44+
}}
45+
>
46+
<button
47+
className={classNames('btn', 'btn-sm', 'btn-primary', {
48+
active: this.visible,
49+
})}
50+
>
51+
<i className="fa fa-cog" />
52+
</button>
53+
</DefaultTooltip>
54+
</div>
55+
);
56+
}
57+
}

src/pages/studyView/studyPageHeader/StudyPageHeader.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ export default class StudyPageHeader extends React.Component<
5656

5757
{this.props.store.clinicalAttributeIdToDataType.isComplete && (
5858
<UserSelections
59+
key={this.props.store.filtersRemountKey}
5960
store={this.props.store}
6061
filter={this.props.store.userSelections}
6162
comparisonGroupSelection={

0 commit comments

Comments
 (0)