import * as React from 'react'; import { action, computed, makeObservable } from 'mobx'; import { Observer, observer } from 'mobx-react'; import styles from './styles.module.scss'; import { ChartOption } from '../AddChartButton'; import _ from 'lodash'; import LabeledCheckbox from '../../../../shared/components/labeledCheckbox/LabeledCheckbox'; import { Column } from '../../../../shared/components/lazyMobXTable/LazyMobXTable'; import { getFrequencyStr } from '../../StudyViewUtils'; import LoadingIndicator from '../../../../shared/components/loadingIndicator/LoadingIndicator'; import MobxPromise from 'mobxpromise'; import { ChartDataCountSet } from '../../StudyViewUtils'; import FixedHeaderTable from '../../table/FixedHeaderTable'; import autobind from 'autobind-decorator'; import classnames from 'classnames'; import { EllipsisTextTooltip, DefaultTooltip, } from 'cbioportal-frontend-commons'; import { Omit } from '../../../../shared/lib/TypeScriptUtils'; import ifNotDefined from '../../../../shared/lib/ifNotDefined'; export type AddChartOption = Omit; export interface IAddChartByTypeProps { options: Omit[]; freqPromise?: MobxPromise; onAddAll: (keys: string[]) => void; onClearAll: (keys: string[]) => void; onToggleOption: (key: string) => void; optionsGivenInSortedOrder?: boolean; frequencyHeaderTooltip?: string; width?: number; firstColumnHeaderName?: string; hideControls?: boolean; shareCharts?: (chartIds: string[]) => void; deleteChart?: (chartId: string) => void; restoreChart?: (chartId: string) => void; markedForDeletion?: string[]; } class AddChartTableComponent extends FixedHeaderTable {} const NUM_ROWS_SHOWN = 15; @observer export default class AddChartByType extends React.Component< IAddChartByTypeProps, {} > { constructor(props: IAddChartByTypeProps) { super(props); makeObservable(this); } public static defaultProps = { firstColumnHeaderName: 'Name', hideControls: false, width: 400, }; @computed get options() { if (this.props.freqPromise?.isComplete) { const options = _.reduce( this.props.options, (acc, next) => { const disabled = this.props.freqPromise!.result![next.key] === 0; acc.push({ label: next.label, key: next.key, disabled: disabled, selected: next.selected, isSharedChart: next.isSharedChart, freq: disabled ? 0 : this.props.freqPromise!.result![next.key], }); return acc; }, [] as AddChartOption[] ); if (this.props.optionsGivenInSortedOrder) { return options; } else { return options.sort((a: AddChartOption, b: AddChartOption) => { return b.freq - a.freq || a.label.localeCompare(b.label); }); } } else { const options = this.props.options.map(o => Object.assign({ freq: 100 }, o) ); if (this.props.optionsGivenInSortedOrder) { return options; } else { return options.sort((a, b) => a.label.localeCompare(b.label)); } } } @autobind private onDeleteClick(option: AddChartOption) { this.props.deleteChart!(option.key); } @autobind private shareChart(option: AddChartOption) { this.props.shareCharts!([option.key]); } @autobind private onRestoreClick(option: AddChartOption) { this.props.restoreChart!(option.key); } @computed get columns() { const columns: Column[] = [ { name: this.props.firstColumnHeaderName!, render: (option: AddChartOption) => { return ( {() => (
this.onOptionChange(option) } >
)}
); }, filter: ( d: AddChartOption, f: string, filterStringUpper: string ) => d.label.toUpperCase().includes(filterStringUpper), sortBy: (d: AddChartOption) => d.label, // 250 for custom data tab width: this.props.width! - 80 - (this.props.shareCharts || this.props.deleteChart ? 70 : 0), defaultSortDirection: 'asc' as 'asc', }, ]; if (this.props.freqPromise) { columns.push({ name: 'Freq', tooltip: ( {ifNotDefined( this.props.frequencyHeaderTooltip, '% samples with data' )} ), render: (option: AddChartOption) => ( {this.props.freqPromise?.isComplete ? getFrequencyStr(option.freq) : ''} ), sortBy: (d: AddChartOption) => d.freq, defaultSortDirection: 'desc' as 'desc', width: 60, }); } if (this.props.shareCharts || this.props.deleteChart) { columns.push({ name: ' ', render: (option: AddChartOption) => { let content: JSX.Element = <>; if ( this.props.markedForDeletion && this.props.markedForDeletion.includes(option.key) ) { content = ( ); } else { content = ( <> {this.props.deleteChart && ( this.onDeleteClick(option) } style={{ marginRight: '5px' }} > )} {this.props.shareCharts && ( this.shareChart(option)} > )} ); } return (
{content}
); }, width: 70, }); } return columns; } @computed get tableHeight() { return this.options.length > NUM_ROWS_SHOWN ? NUM_ROWS_SHOWN * 25 : (this.options.length + 1) * 25; } @autobind getCurrentSelectedRows(): AddChartOption[] { return this.options.filter(option => option.selected); } @autobind getCurrentSelectedRowKeys() { return this.getCurrentSelectedRows().map(option => option.key); } @action.bound addAll(selectedOptions: AddChartOption[]) { this.props.onAddAll( _.filter(selectedOptions, option => !option.disabled).map( option => option.key ) ); } @action.bound removeAll(selectedOptions: AddChartOption[]) { this.props.onClearAll(selectedOptions.map(option => option.key)); } @action.bound onOptionChange(option: AddChartOption) { this.props.onToggleOption(option.key); } @action.bound shareSelected() { this.props.shareCharts!( this.props.options .filter(option => option.selected) .map(option => option.key) ); } @computed get extraButtons() { if (this.props.shareCharts) { return [ { content: <>Share selected, onClick: this.shareSelected, isDisabled: () => this.props.options.filter(option => option.selected) .length === 0, }, ]; } return []; } render() { return (
{(!this.props.freqPromise || this.props.freqPromise.isComplete) && ( !!data.isSharedChart} highlightedRowClassName={data => data.isSharedChart ? styles.sharedChart : '' } extraButtons={this.extraButtons} /> )} {this.props.freqPromise?.isPending && (

Calculating data availability...
)}
); } }