import * as React from 'react'; import _ from 'lodash'; import { observer } from 'mobx-react'; import LazyMobXTable, { Column, } from 'shared/components/lazyMobXTable/LazyMobXTable'; import { observable, makeObservable } from 'mobx'; import { Radio } from 'react-bootstrap'; import { DefaultTooltip } from 'cbioportal-frontend-commons'; import { getSortedData, getSortedFilteredData, SimpleGetterLazyMobXTableApplicationDataStore, } from '../../../shared/lib/ILazyMobXTableApplicationDataStore'; import { truncateGeneList } from './PathwayMapperHelpers'; export interface IPathwayMapperTable { name: string; score: number; genes: string[]; } export enum IPathwayMapperTableColumnType { NAME, SCORE, GENES, } interface IPathwayMapperTableProps { data: IPathwayMapperTable[]; selectedPathway: string; changePathway: (pathway: string) => void; onSelectedPathwayChange?: () => void; initialSortColumn?: string; columnsOverride?: { [columnEnum: number]: Partial; }; } type PathwayMapperTableColumn = Column; class PathwayMapperTableComponent extends LazyMobXTable {} export function findPageOfSelectedPathway( data: IPathwayMapperTable[], store: SimpleGetterLazyMobXTableApplicationDataStore, selectedPathway: string ): number { const sortedData = getSortedData( data, store.sortMetric, store.sortAscending ); const sortedFilteredData = getSortedFilteredData( sortedData, store.filterString, store.getFilter() ); const index = _.findIndex(sortedFilteredData, d => { return d.name === selectedPathway; }); return index >= 0 ? Math.floor(index / (store.itemsPerPage || 10)) : 0; } @observer export default class PathwayMapperTable extends React.Component< IPathwayMapperTableProps > { public static defaultProps = { columns: [ IPathwayMapperTableColumnType.NAME, IPathwayMapperTableColumnType.SCORE, IPathwayMapperTableColumnType.GENES, ], columnsOverride: {}, initialSortColumn: 'Score', }; @observable protected _columns: { [columnEnum: number]: PathwayMapperTableColumn; }; @observable.ref selectedPathway: string; constructor(props: IPathwayMapperTableProps) { super(props); makeObservable(this); this._columns = {}; this.generateColumns(); makeObservable(this); } generateColumns() { const lengthThreshold = 20; this._columns = {}; this._columns[IPathwayMapperTableColumnType.NAME] = { name: 'Pathway name', render: (d: IPathwayMapperTable) => { const pwName = d.name; const isPwNameShort = pwName.length < lengthThreshold; return ( { if (this.props.onSelectedPathwayChange) { this.props.onSelectedPathwayChange(); } this.props.changePathway(d.name); }} > {isPwNameShort ? pwName : pwName.substring(0, lengthThreshold) + '...'} ); }, tooltip: Pathway name, filter: ( d: IPathwayMapperTable, filterString: string, filterStringUpper: string ) => d.name.toUpperCase().includes(filterStringUpper), sortBy: (d: IPathwayMapperTable) => d.name, download: (d: IPathwayMapperTable) => d.name, ...this.props.columnsOverride![IPathwayMapperTableColumnType.NAME], }; this._columns[IPathwayMapperTableColumnType.SCORE] = { name: 'Score', render: (d: IPathwayMapperTable) => ( {d.score.toFixed(2)} ), tooltip: Score, filter: ( d: IPathwayMapperTable, filterString: string, filterStringUpper: string ) => (d.score + '').includes(filterStringUpper), sortBy: (d: IPathwayMapperTable) => d.score, download: (d: IPathwayMapperTable) => d.score + '', ...this.props.columnsOverride![IPathwayMapperTableColumnType.SCORE], }; this._columns[IPathwayMapperTableColumnType.GENES] = { name: 'Genes matched', render: (d: IPathwayMapperTable) => { const geneTextLength = d.genes.join(' ').length; return ( {truncateGeneList(d.genes, lengthThreshold)} ); }, tooltip: Genes matched, filter: ( d: IPathwayMapperTable, filterString: string, filterStringUpper: string ) => d.genes .join(' ') .toUpperCase() .includes(filterStringUpper), sortBy: (d: IPathwayMapperTable) => d.genes.length, download: (d: IPathwayMapperTable) => d.genes.toString(), ...this.props.columnsOverride![IPathwayMapperTableColumnType.GENES], }; } private dataStore = new SimpleGetterLazyMobXTableApplicationDataStore( () => this.props.data ); componentWillUpdate(nextProps: Readonly): void { // we need to know on which page the selected pathway will fall after Ranking option is updated. // there is a chance that selected pathway might be on another page than currently visible one. // therefore we need find the page number for the updated data and set data store page accordingly this.dataStore.page = findPageOfSelectedPathway( nextProps.data, this.dataStore, nextProps.selectedPathway ); } render() { const columns = _.sortBy(this._columns); return ( ); } }