import * as React from 'react'; import { observer } from 'mobx-react'; import _ from 'lodash'; import FixedHeaderTable, { IFixedHeaderTableProps } from '../FixedHeaderTable'; import { action, computed, observable, makeObservable } from 'mobx'; import autobind from 'autobind-decorator'; import { Column, SortDirection, } from '../../../../shared/components/lazyMobXTable/LazyMobXTable'; import { PatientTreatmentRow } from 'cbioportal-ts-api-client'; import { correctColumnWidth } from 'pages/studyView/StudyViewUtils'; import LabeledCheckbox from 'shared/components/labeledCheckbox/LabeledCheckbox'; import styles from 'pages/studyView/table/tables.module.scss'; import MobxPromise from 'mobxpromise'; import { stringListToIndexSet, stringListToSet, } from 'cbioportal-frontend-commons'; import ifNotDefined from 'shared/lib/ifNotDefined'; import { treatmentUniqueKey, TreatmentTableType, TreatmentGenericColumnHeader, TreatmentColumnCell, filterTreatmentCell, toNumericValue, } from './treatmentsTableUtil'; import { TreatmentsTable } from './AbstractTreatmentsTable'; import { MultiSelectionTableRow } from 'pages/studyView/table/MultiSelectionTable'; export enum PatientTreatmentsTableColumnKey { TREATMENT = 'Treatment', COUNT = '#', } export type PatientTreatmentsTableColumn = { columnKey: PatientTreatmentsTableColumnKey; columnWidthRatio?: number; }; export type PatientTreatmentsTableProps = { tableType: TreatmentTableType; promise: MobxPromise; width: number; height: number; filters: string[][]; onSubmitSelection: (value: string[][]) => void; onChangeSelectedRows: (rowsKeys: string[]) => void; extraButtons?: IFixedHeaderTableProps< MultiSelectionTableRow >['extraButtons']; selectedRowsKeys: string[]; selectedTreatments: string[]; defaultSortBy: PatientTreatmentsTableColumnKey; columns: PatientTreatmentsTableColumn[]; }; const DEFAULT_COLUMN_WIDTH_RATIO: { [key in PatientTreatmentsTableColumnKey]: number; } = { [PatientTreatmentsTableColumnKey.TREATMENT]: 0.8, [PatientTreatmentsTableColumnKey.COUNT]: 0.2, }; class MultiSelectionTableComponent extends FixedHeaderTable< PatientTreatmentRow > {} @observer export class PatientTreatmentsTable extends TreatmentsTable< PatientTreatmentsTableProps > { @observable protected sortBy: PatientTreatmentsTableColumnKey; public static defaultProps = { cancerGeneFilterEnabled: false, }; constructor(props: PatientTreatmentsTableProps) { super(props); makeObservable(this); this.sortBy = this.props.defaultSortBy; } createNubmerColumnCell( row: PatientTreatmentRow, cellMargin: number ): JSX.Element { return ( this.toggleSelectRow(treatmentUniqueKey(row))} labelProps={{ style: { display: 'flex', justifyContent: 'space-between', marginLeft: 0, marginRight: cellMargin, }, }} inputProps={{ className: styles.autoMarginCheckbox, }} > {row.count.toLocaleString()} ); } getDefaultColumnDefinition = ( columnKey: PatientTreatmentsTableColumnKey, columnWidth: number, cellMargin: number ) => { const defaults: { [key in PatientTreatmentsTableColumnKey]: Column< PatientTreatmentRow >; } = { [PatientTreatmentsTableColumnKey.TREATMENT]: { name: columnKey, headerRender: () => ( ), render: (data: PatientTreatmentRow) => ( ), sortBy: (data: PatientTreatmentRow) => data.treatment, defaultSortDirection: 'asc' as 'asc', filter: filterTreatmentCell, width: columnWidth, }, [PatientTreatmentsTableColumnKey.COUNT]: { tooltip: Number of patients treated, name: columnKey, headerRender: () => ( ), render: (data: PatientTreatmentRow) => this.createNubmerColumnCell(data, 28), sortBy: (data: PatientTreatmentRow) => data.count + toNumericValue(data.treatment), defaultSortDirection: 'desc' as 'desc', filter: filterTreatmentCell, width: columnWidth, }, }; return defaults[columnKey]; }; @computed get columnsWidth() { return _.reduce( this.props.columns, (acc, column) => { acc[column.columnKey] = correctColumnWidth( (column.columnWidthRatio ? column.columnWidthRatio : DEFAULT_COLUMN_WIDTH_RATIO[column.columnKey]) * this.props.width ); return acc; }, {} as { [key in PatientTreatmentsTableColumnKey]: number } ); } @computed get cellMargin() { return _.reduce( this.props.columns, (acc, column) => { acc[column.columnKey] = 0; return acc; }, {} as { [key in PatientTreatmentsTableColumnKey]: number } ); } @computed get tableData(): PatientTreatmentRow[] { return this.props.promise.result || []; } @computed get selectableTableData() { if (this.flattenedFilters.length === 0) { return this.tableData; } return _.filter( this.tableData, data => !this.flattenedFilters.includes(treatmentUniqueKey(data)) ); } @computed get preSelectedRows() { if (this.flattenedFilters.length === 0) { return []; } const order = stringListToIndexSet(this.flattenedFilters); return _.chain(this.tableData) .filter(data => this.flattenedFilters.includes(treatmentUniqueKey(data)) ) .sortBy(data => ifNotDefined( order[treatmentUniqueKey(data)], Number.POSITIVE_INFINITY ) ) .value(); } @computed get preSelectedRowsKeys() { return this.preSelectedRows.map(row => treatmentUniqueKey(row)); } @computed get tableColumns() { return this.props.columns.map(column => this.getDefaultColumnDefinition( column.columnKey, this.columnsWidth[column.columnKey], this.cellMargin[column.columnKey] ) ); } @action.bound afterSorting( sortBy: PatientTreatmentsTableColumnKey, sortDirection: SortDirection ) { this.sortBy = sortBy; this.sortDirection = sortDirection; } public render() { const tableId = `${this.props.tableType}-table`; return (
{this.props.promise.isComplete && ( )}
); } }