diff --git a/src/ui/components/table/ManagedTable.js b/src/ui/components/table/ManagedTable.js index 473f37524..602eeb6c3 100644 --- a/src/ui/components/table/ManagedTable.js +++ b/src/ui/components/table/ManagedTable.js @@ -116,6 +116,10 @@ export type ManagedTableProps = {| * Callback when sorting changes */ onSort?: (order: TableRowSortOrder) => void, + /** + * Table scroll horizontally, if needed + */ + horizontallyScrollable?: boolean, |}; type ManagedTableState = {| @@ -126,9 +130,10 @@ type ManagedTableState = {| shouldScrollToBottom: boolean, |}; -const Container = styled(FlexColumn)({ +const Container = styled(FlexColumn)(props => ({ + overflow: props.overflow ? 'scroll' : 'visible', flexGrow: 1, -}); +})); class ManagedTable extends React.Component< ManagedTableProps, @@ -318,8 +323,13 @@ class ManagedTable extends React.Component< ); }; - onColumnResize = (columnSizes: TableColumnSizes) => { - this.setState({columnSizes}); + onColumnResize = (id: string, width: number | string) => { + this.setState(({columnSizes}) => ({ + columnSizes: { + ...columnSizes, + [id]: width, + }, + })); }; scrollToBottom() { @@ -499,7 +509,13 @@ class ManagedTable extends React.Component< ); getRow = ({index, style}) => { - const {onAddFilter, multiline, zebra, rows} = this.props; + const { + onAddFilter, + multiline, + zebra, + rows, + horizontallyScrollable, + } = this.props; const {columnOrder, columnSizes, highlightedRows} = this.state; const columnKeys = columnOrder .map(k => (k.visible ? k.key : null)) @@ -520,16 +536,37 @@ class ManagedTable extends React.Component< style={style} onAddFilter={onAddFilter} zebra={zebra} + horizontallyScrollable={horizontallyScrollable} /> ); }; render() { - const {columns, rows, rowLineHeight, hideHeader} = this.props; + const { + columns, + rows, + rowLineHeight, + hideHeader, + horizontallyScrollable, + } = this.props; const {columnOrder, columnSizes} = this.state; + let computedWidth = 0; + if (horizontallyScrollable) { + for (const col in columnSizes) { + const width = columnSizes[col]; + if (isNaN(width)) { + // non-numeric columns with, can't caluclate + computedWidth = 0; + break; + } else { + computedWidth += parseInt(width, 10); + } + } + } + return ( - + {hideHeader !== true && ( )} @@ -560,7 +598,7 @@ class ManagedTable extends React.Component< DEFAULT_ROW_HEIGHT } ref={this.tableRef} - width={width} + width={Math.max(width, computedWidth)} estimatedItemSize={rowLineHeight || DEFAULT_ROW_HEIGHT} overscanCount={5} innerRef={this.scrollRef} diff --git a/src/ui/components/table/TableHead.js b/src/ui/components/table/TableHead.js index e05f30711..aab7d7d8d 100644 --- a/src/ui/components/table/TableHead.js +++ b/src/ui/components/table/TableHead.js @@ -43,7 +43,7 @@ const TableHeaderColumnContainer = styled('div')({ padding: '0 8px', }); -const TableHeadContainer = styled(FlexRow)({ +const TableHeadContainer = styled(FlexRow)(props => ({ borderBottom: `1px solid ${colors.sectionHeaderBorder}`, color: colors.light50, flexShrink: 0, @@ -53,7 +53,8 @@ const TableHeadContainer = styled(FlexRow)({ textAlign: 'left', top: 0, zIndex: 2, -}); + minWidth: props.horizontallyScrollable ? 'min-content' : 0, +})); const TableHeadColumnContainer = styled('div')(props => ({ position: 'relative', @@ -97,9 +98,17 @@ class TableHeadColumn extends PureComponent<{ onColumnResize: ?TableOnColumnResize, children?: React$Node, title?: string, + horizontallyScrollable?: boolean, }> { ref: HTMLElement; + componentDidMount() { + if (this.props.horizontallyScrollable) { + // measure initial width + this.onResize(this.ref.offsetWidth); + } + } + onClick = () => { const {id, onSort, sortOrder} = this.props; @@ -117,7 +126,7 @@ class TableHeadColumn extends PureComponent<{ }; onResize = (newWidth: number) => { - const {id, columnSizes, onColumnResize, width} = this.props; + const {id, onColumnResize, width} = this.props; if (!onColumnResize) { return; } @@ -143,10 +152,7 @@ class TableHeadColumn extends PureComponent<{ } } - onColumnResize({ - ...columnSizes, - [id]: normalizedWidth, - }); + onColumnResize(id, normalizedWidth); }; setRef = (ref: HTMLElement) => { @@ -191,6 +197,7 @@ export default class TableHead extends PureComponent<{ onSort: ?TableOnSort, columnSizes: TableColumnSizes, onColumnResize: ?TableOnColumnResize, + horizontallyScrollable?: boolean, }> { buildContextMenu = (): MenuTemplate => { const visibles = this.props.columnOrder @@ -237,6 +244,7 @@ export default class TableHead extends PureComponent<{ onColumnResize, onSort, sortOrder, + horizontallyScrollable, } = this.props; const elems = []; @@ -284,7 +292,8 @@ export default class TableHead extends PureComponent<{ onSort={onSort} columnSizes={columnSizes} onColumnResize={onColumnResize} - title={key}> + title={key} + horizontallyScrollable={horizontallyScrollable}> {col.value} {arrow} @@ -296,10 +305,11 @@ export default class TableHead extends PureComponent<{ lastResizable = isResizable; } - return ( - {elems} + + {elems} + ); } diff --git a/src/ui/components/table/types.js b/src/ui/components/table/types.js index d77c6333a..029818698 100644 --- a/src/ui/components/table/types.js +++ b/src/ui/components/table/types.js @@ -26,7 +26,7 @@ export type TableHighlightedRows = Array; export type TableColumnKeys = Array; -export type TableOnColumnResize = (sizes: TableColumnSizes) => void; +export type TableOnColumnResize = (id: string, size: number | string) => void; export type TableOnColumnOrder = (order: TableColumnOrder) => void; export type TableOnSort = (order: TableRowSortOrder) => void; export type TableOnHighlight = (