From a171a9861d828294083d020d12787b30ec0b7009 Mon Sep 17 00:00:00 2001 From: Andy Dufilie Date: Fri, 21 Apr 2017 15:59:59 -0400 Subject: [PATCH] Fix performance issue in cancer study selector --- .../components/query/CancerStudySelector.tsx | 142 +++++++++--------- .../components/query/studyList/StudyList.tsx | 48 ++++-- 2 files changed, 103 insertions(+), 87 deletions(-) diff --git a/src/shared/components/query/CancerStudySelector.tsx b/src/shared/components/query/CancerStudySelector.tsx index 83a00ae7040..43e43e3f32f 100644 --- a/src/shared/components/query/CancerStudySelector.tsx +++ b/src/shared/components/query/CancerStudySelector.tsx @@ -5,14 +5,13 @@ import {TypeOfCancer as CancerType, CancerStudy} from "../../api/generated/CBioP import {FlexCol, FlexRow} from "../flexbox/FlexBox"; import * as styles_any from './styles.module.scss'; import classNames from 'classnames'; -import LabeledCheckbox from "../labeledCheckbox/LabeledCheckbox"; import ReactSelect from 'react-select'; import StudyList from "./studyList/StudyList"; -import {observer} from "mobx-react"; +import {observer, Observer} from "mobx-react"; +import {expr} from 'mobx'; import memoize from "memoize-weak-decorator"; import {QueryStoreComponent} from "./QueryStore"; import SectionHeader from "../sectionHeader/SectionHeader"; -import StudyListLogic from "./StudyListLogic"; const styles = styles_any as { CancerStudySelector: string, @@ -70,19 +69,19 @@ export default class CancerStudySelector extends QueryStoreComponent { let cancerTypes = this.logic.cancerTypeListView.getChildCancerTypes(this.store.treeData.rootCancerType); return ( ); - } + }); - renderCancerTypeListItem = (cancerType:CancerType, arrayIndex:number) => - { - let numStudies = this.logic.cancerTypeListView.getDescendantCancerStudies(cancerType).length; + CancerTypeListItem = observer(({cancerType}: {cancerType:CancerType}) => { + let numStudies = expr(() => this.logic.cancerTypeListView.getDescendantCancerStudies(cancerType).length); let selected = _.includes(this.store.selectedCancerTypeIds, cancerType.cancerTypeId); let highlighted = this.logic.isHighlighted(cancerType); let liClassName = classNames({ @@ -91,12 +90,11 @@ export default class CancerStudySelector extends QueryStoreComponent this.logic.cancerTypeContainsSelectedStudies(cancerType)), }); return (
  • @@ -108,88 +106,84 @@ export default class CancerStudySelector extends QueryStoreComponent
  • ); - } - - renderStudyHeaderCheckbox = (shownStudies:CancerStudy[]) => - { - let selectedStudies = this.store.selectedStudyIds.map(studyId => this.store.treeData.map_studyId_cancerStudy.get(studyId) as CancerStudy); - let shownAndSelectedStudies = _.intersection(shownStudies, selectedStudies); - let checked = shownAndSelectedStudies.length > 0; - let indeterminate = checked && shownAndSelectedStudies.length != shownStudies.length; - return ( - ) => event.stopPropagation() - }} - onChange={event => { - let shownStudyIds = shownStudies.map(study => study.studyId); - this.handleStudiesCheckbox(event, shownStudyIds); - }} - /> - ); - } + }); render() { - let searchTextOptions = this.store.searchTextPresets; - if (this.store.searchText && searchTextOptions.indexOf(this.store.searchText) < 0) - searchTextOptions = [this.store.searchText].concat(searchTextOptions as string[]); - - let selectAllCheckboxProps = this.logic.mainView.getCheckboxProps(this.store.treeData.rootCancerType); - - let selectedCountClass = classNames({ - [styles.selectedCount]: true, - [styles.selectionsExist]: this.store.selectedStudyIds.length > 0 - }); - return ( Select Studies: {!!(!this.store.cancerTypes.isPending && !this.store.cancerStudies.isPending) && ( - { - if (this.store.selectedStudyIds.length) - this.store.showSelectedStudiesOnly = !this.store.showSelectedStudiesOnly; + + {() => { + let numSelectedStudies = expr(() => this.store.selectedStudyIds.length); + let selectedCountClass = classNames({ + [styles.selectedCount]: true, + [styles.selectionsExist]: numSelectedStudies > 0 + }); + return ( + { + if (numSelectedStudies) + this.store.showSelectedStudiesOnly = !this.store.showSelectedStudiesOnly; + }} + > + {numSelectedStudies} studies selected + ({this.store.selectedStudies_totalSampleCount} samples) + + ); }} - > - {this.store.selectedStudyIds.length} studies selected - ({this.store.selectedStudies_totalSampleCount} samples) - + )} - ({label: str, value: str}))} - placeholder='Search...' - noResultsText={false} - onCloseResetsInput={false} - onInputChange={(searchText:string) => { - this.store.searchText = searchText; - this.store.selectedCancerTypeIds = []; - }} - onChange={option => { - this.store.searchText = option ? option.value || '' : ''; - this.store.selectedCancerTypeIds = []; + + {() => { + let searchTextOptions = this.store.searchTextPresets; + if (this.store.searchText && searchTextOptions.indexOf(this.store.searchText) < 0) + searchTextOptions = [this.store.searchText].concat(searchTextOptions as string[]); + + return ( + ({label: str, value: str}))} + placeholder='Search...' + noResultsText={false} + onCloseResetsInput={false} + onInputChange={(searchText:string) => { + this.store.searchText = searchText; + this.store.selectedCancerTypeIds = []; + }} + onChange={option => { + this.store.searchText = option ? option.value || '' : ''; + this.store.selectedCancerTypeIds = []; + }} + /> + ); }} - /> + {!!(!this.store.forDownloadTab) && ( - this.logic.mainView.onCheck(this.store.treeData.rootCancerType, !selectAllCheckboxProps.checked)}> - {selectAllCheckboxProps.checked ? "Deselect all" : "Select all"} - + + {() => { + let selectAllChecked = expr(() => this.logic.mainView.getCheckboxProps(this.store.treeData.rootCancerType).checked); + return ( + this.logic.mainView.onCheck(this.store.treeData.rootCancerType, !selectAllChecked)}> + {selectAllChecked ? "Deselect all" : "Select all"} + + ); + }} + )}
    - {this.renderCancerTypeList()} +
    diff --git a/src/shared/components/query/studyList/StudyList.tsx b/src/shared/components/query/studyList/StudyList.tsx index 556bc5cdfe5..3213796f849 100644 --- a/src/shared/components/query/studyList/StudyList.tsx +++ b/src/shared/components/query/studyList/StudyList.tsx @@ -5,11 +5,12 @@ import classNames from 'classnames'; import FontAwesome from "react-fontawesome"; import LabeledCheckbox from "../../labeledCheckbox/LabeledCheckbox"; import {observer} from "mobx-react"; +import {computed} from "mobx"; import {getStudySummaryUrl, getPubMedUrl} from "../../../api/urls"; import {QueryStoreComponent} from "../QueryStore"; import DefaultTooltip from "../../DefaultTooltip"; -import StudyListLogic from "../StudyListLogic"; -import {cached} from 'mobxpromise'; +import StudyListLogic, {FilteredCancerTreeView} from "../StudyListLogic"; +import {CancerTreeNode} from "../CancerStudyTreeData"; const styles = { ...styles_any as { @@ -121,11 +122,8 @@ export default class StudyList extends QueryStoreComponent - this.view.onCheck(cancerType, (event.target as HTMLInputElement).checked)} - > - {indentArrow} + + {indentArrow} {cancerType.name} @@ -134,7 +132,7 @@ export default class StudyList extends QueryStoreComponent )} - + ); } @@ -172,14 +170,11 @@ export default class StudyList extends QueryStoreComponent { return ( - this.view.onCheck(study, (event.target as HTMLInputElement).checked)} - > + {study.name} - + ); } @@ -254,3 +249,30 @@ export default class StudyList extends QueryStoreComponent +{ + @computed.struct get checkboxProps() + { + return this.props.view.getCheckboxProps(this.props.node); + } + + render() + { + return ( + this.props.view.onCheck(this.props.node, (event.target as HTMLInputElement).checked)} + > + {this.props.children} + + ); + } +}