UNPKG

@bigfishtv/cockpit

Version:

583 lines (525 loc) 19.9 kB
var _class, _temp; var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { AutoSizer, MultiGrid } from 'react-virtualized'; import throttle from 'lodash/throttle'; import _get from 'lodash/get'; import cn from 'classnames'; import { isFunction, isArray, isObject } from '../../utils/typeUtils'; import { isCtrlKeyPressed, isShiftKeyPressed } from '../../utils/selectKeyUtils'; import Button from '../button/Button'; import Checkbox from '../input/Checkbox'; import DefaultResultsFooter from './ResultsFooter'; import { multisort, sortProperty } from '../../utils/sortUtils'; import Icon from '../Icon'; export var DefaultHeaderCell = function (_Component) { _inherits(DefaultHeaderCell, _Component); function DefaultHeaderCell(props) { _classCallCheck(this, DefaultHeaderCell); var _this = _possibleConstructorReturn(this, _Component.call(this, props)); _this.handleMouseMove = _this.handleMouseMove.bind(_this); _this.handleMouseUp = _this.handleMouseUp.bind(_this); _this.triggerResize = throttle(_this.triggerResize, 1000 / 30); _this.clientX = 0; _this.originalWidth = props.style.width; _this.state = { resizing: false, startX: 0 }; return _this; } DefaultHeaderCell.prototype.componentDidMount = function componentDidMount() { document.addEventListener('mousemove', this.handleMouseMove); document.addEventListener('mouseup', this.handleMouseUp); }; DefaultHeaderCell.prototype.componentWillUnmount = function componentWillUnmount() { document.removeEventListener('mousemove', this.handleMouseMove); document.removeEventListener('mouseup', this.handleMouseUp); }; DefaultHeaderCell.prototype.handleMouseMove = function handleMouseMove(event) { if (this.state.resizing) { this.clientX = event.clientX; this.triggerResize(); } }; DefaultHeaderCell.prototype.triggerResize = function triggerResize() { this.props.onResize(this.originalWidth + (this.clientX - this.state.startX)); }; DefaultHeaderCell.prototype.handleMouseUp = function handleMouseUp() { if (this.state.resizing) this.setState({ resizing: false }); }; DefaultHeaderCell.prototype.handleResizeStart = function handleResizeStart(event) { event.preventDefault(); this.originalWidth = this.props.style.width; this.setState({ resizing: true, startX: event.clientX }); }; DefaultHeaderCell.prototype.render = function render() { var _this2 = this; var _props = this.props, style = _props.style, field = _props.field, onClick = _props.onClick, select = _props.select, sort = _props.sort, direction = _props.direction, hover = _props.hover; return React.createElement( 'div', { style: style, className: cn('data-header-cell', { hover: hover }) }, React.createElement( 'a', { onClick: onClick }, isFunction(field.text) ? field.text(this.props) : React.createElement( 'strong', null, field.text, ' ' ), !field.unsortable && select === sort && React.createElement( 'span', null, React.createElement(Icon, { name: direction === 'DESC' ? 'chevron-down' : 'chevron-up', size: 16 }) ) ), React.createElement('div', { className: 'data-header-cell-resize', onMouseDown: function onMouseDown(e) { return _this2.handleResizeStart(e); } }) ); }; return DefaultHeaderCell; }(Component); export var DefaultContentCell = function DefaultContentCell(props) { var style = props.style, field = props.field, row = props.row, hover = props.hover, selected = props.selected, onClick = props.onClick, onDoubleClick = props.onDoubleClick, onMouseOver = props.onMouseOver, onMouseOut = props.onMouseOut, rowIndex = props.rowIndex; var value = _get(row, field.value, null); if (value !== null && field.valueMapper) value = field.valueMapper(value, props); if (isArray(value)) value = '[' + value.length + '] Items';else if (isObject(value) && !value.hasOwnProperty('$$typeof')) value = '[Object]'; return React.createElement( 'div', { style: _extends({}, style), className: cn('data-cell', 'truncate', { hover: hover, selected: selected }, rowIndex % 2 && 'data-cell-alt'), onClick: onClick, onDoubleClick: onDoubleClick, onMouseOver: onMouseOver, onMouseOut: onMouseOut, onMouseDown: function onMouseDown(e) { return e.preventDefault(); } }, value ); }; export function validateFields(fields) { fields = fields.map(function (field, i) { return _extends({ fixed: false, order: i }, field); }); fields.sort(multisort([sortProperty('fixed', 'desc'), sortProperty('order')])); return fields; } var DataTable = (_temp = _class = function (_Component2) { _inherits(DataTable, _Component2); function DataTable(props) { _classCallCheck(this, DataTable); var _this3 = _possibleConstructorReturn(this, _Component2.call(this, props)); _this3.cellRenderer = _this3.cellRenderer.bind(_this3); var fields = validateFields(props.fields); if (props.checkboxSelection) fields.unshift({ unsortable: true, fixed: true, width: 35, value: 'id', text: function text(props) { return React.createElement(Checkbox, { value: props.selectAll || props.selectAllGlobal, onChange: function onChange() { return props.onSelectAll(); } }); }, valueMapper: function valueMapper(value, props) { return React.createElement(Checkbox, { value: props.selected || false, onChange: function onChange() { return props.onSelect(); } }); } }); _this3.state = { fields: fields, columnWidths: fields.map(function (_ref) { var width = _ref.width; return width || props.defaultColumnWidth; }), selectedIds: props.selectedIds, selectedData: props.selectedData, selectAllGlobal: props.selectAllGlobal, rowHoverIndex: null, columnHoverIndex: null }; return _this3; } DataTable.prototype.componentDidUpdate = function componentDidUpdate(prevProps) { if (!this.state.selectAllGlobal && this.state.selectedIds.length > 0 && this.props.params != prevProps.params) { this.handleDeselectAll(); } }; DataTable.prototype.getFieldSelect = function getFieldSelect(field) { return field.select || (this.props.model ? this.props.model + '.' + field.value : field.value); }; DataTable.prototype.handleHeaderColumnClick = function handleHeaderColumnClick(field) { if (field.unsortable) return; var params = this.props.params; var sort = params.sort, direction = params.direction; if (!sort) sort = this.getFieldSelect({ value: 'id' }); if (!direction) direction = 'ASC'; var newSort = this.getFieldSelect(field); if (newSort == sort) direction = direction == 'ASC' ? 'DESC' : 'ASC'; this.props.onParamsChange({ direction: direction, sort: newSort }); // this.onParamChange({ ...params, sort: newSort, direction }) }; DataTable.prototype.handleSelectAll = function handleSelectAll() { var data = this.props.data; var selectAllGlobal = this.state.selectAllGlobal; if (selectAllGlobal) { this.setState({ selectedIds: [], selectedData: [], selectAllGlobal: false }); this.props.onSelectGlobalChange && this.props.onSelectGlobalChange(false); this.props.onSelectionChange && this.props.onSelectionChange([], []); } else if (this.state.selectedIds.length > 0 && data.length === this.state.selectedIds.length) { this.setState({ selectedIds: [], selectedData: [], selectAllGlobal: false }); this.props.onSelectionChange && this.props.onSelectionChange([], []); } else { var selectedIds = data.map(function (_ref2) { var id = _ref2.id; return id; }); this.setState({ selectedIds: selectedIds, selectedData: [], selectAllGlobal: false }); this.props.onSelectionChange && this.props.onSelectionChange(selectedIds, data); } }; DataTable.prototype.handleSelectAllGlobal = function handleSelectAllGlobal() { this.setState({ selectAllGlobal: true, selectedIds: [], selectedData: [] }); this.props.onSelectGlobalChange && this.props.onSelectGlobalChange(true); this.props.onSelectionChange && this.props.onSelectionChange([], []); }; DataTable.prototype.handleDeselectAll = function handleDeselectAll() { this.setState({ selectAllGlobal: false, selectedIds: [], selectedData: [] }); this.props.onSelectGlobalChange && this.props.onSelectGlobalChange(false); this.props.onSelectionChange && this.props.onSelectionChange([], []); }; DataTable.prototype.handleRowClick = function handleRowClick(index) { var _props2 = this.props, checkboxSelection = _props2.checkboxSelection, data = _props2.data; var row = data[index]; var _state = this.state, selectedIds = _state.selectedIds, selectAllGlobal = _state.selectAllGlobal; if (isShiftKeyPressed()) { if (selectAllGlobal) { selectAllGlobal = false; selectedIds = data.map(function (_ref3) { var id = _ref3.id; return id; }).filter(function (v, i) { return i > index; }); } else if (selectedIds.length === 0) { selectedIndexes = [index]; } else { var lowerIndex = Math.min(index, this.lastIndex); var upperIndex = Math.max(index, this.lastIndex); selectedIds = data.filter(function (v, i) { return i >= lowerIndex && i <= upperIndex; }).map(function (_ref4) { var id = _ref4.id; return id; }); } } else if (isCtrlKeyPressed() || checkboxSelection) { if (selectAllGlobal) { selectAllGlobal = false; selectedIds = data.map(function (_ref5) { var id = _ref5.id; return id; }); } selectedIds = ~selectedIds.indexOf(row.id) ? selectedIds.filter(function (id) { return id !== row.id; }) : [].concat(selectedIds, [row.id]); } else { if (selectAllGlobal) selectAllGlobal = false; selectedIds = selectedIds.length === 1 && selectedIds[0] == row.id ? [] : [row.id]; } if (selectAllGlobal !== this.state.selectAllGlobal) { this.props.onSelectGlobalChange && this.props.onSelectGlobalChange(selectAllGlobal); } var selectedData = selectAllGlobal ? [] : data.filter(function (_ref6) { var id = _ref6.id; return ~selectedIds.indexOf(id); }); this.lastIndex = index; this.setState({ selectedIds: selectedIds, selectAllGlobal: selectAllGlobal, selectedData: selectedData }); this.props.onSelectionChange && this.props.onSelectionChange(selectedIds, selectedData); }; DataTable.prototype.handleRowDoubleClick = function handleRowDoubleClick(row) { this.props.onRowSelected && this.props.onRowSelected(row); }; DataTable.prototype.handleColumnResize = function handleColumnResize(columnIndex, width) { var columnWidths = [].concat(this.state.columnWidths); columnWidths[columnIndex] = Math.max(width, 20); this.setState({ columnWidths: columnWidths }); if (this.grid) this.grid.recomputeGridSize(); }; DataTable.prototype.cellRenderer = function cellRenderer(_ref7) { var _this4 = this; var columnIndex = _ref7.columnIndex, rowIndex = _ref7.rowIndex, key = _ref7.key, isVisible = _ref7.isVisible, isScrolling = _ref7.isScrolling, style = _ref7.style; var field = this.state.fields[columnIndex]; var _props3 = this.props, checkboxSelection = _props3.checkboxSelection, data = _props3.data, columnHighlight = _props3.columnHighlight, rowHighlight = _props3.rowHighlight; var _state2 = this.state, selectedIds = _state2.selectedIds, selectAllGlobal = _state2.selectAllGlobal, columnHoverIndex = _state2.columnHoverIndex, rowHoverIndex = _state2.rowHoverIndex; var selectAll = selectedIds.length > 0 && selectedIds.length === data.length; if (rowIndex === 0) { var HeaderCell = this.props.HeaderCell; var cellProps = { style: style, isVisible: isVisible, isScrolling: isScrolling, field: field, columnIndex: columnIndex, selectAll: selectAll, selectAllGlobal: selectAllGlobal, select: this.getFieldSelect(field), sort: this.props.params.sort || this.getFieldSelect({ value: 'id' }), direction: this.props.params.direction || 'ASC', onClick: function onClick() { return _this4.handleHeaderColumnClick(field); }, onSelectAll: function onSelectAll() { return _this4.handleSelectAll(); }, onResize: function onResize(width) { return _this4.handleColumnResize(columnIndex, width); } }; return React.createElement(HeaderCell, _extends({ key: key }, cellProps)); } else { var row = data[rowIndex - 1]; if (row || checkboxSelection && columnIndex === 0) { var ContentCell = this.props.ContentCell; var _cellProps = { style: style, isVisible: isVisible, isScrolling: isScrolling, field: field, row: row, rowIndex: rowIndex, columnIndex: columnIndex, selected: selectAllGlobal || ~selectedIds.indexOf(row.id), hover: columnHighlight && columnHoverIndex == columnIndex || rowHighlight && rowHoverIndex == rowIndex, onClick: checkboxSelection ? function () {} : function () { return _this4.handleRowClick(rowIndex - 1); }, onSelect: function onSelect() { return _this4.handleRowClick(rowIndex - 1); }, onDoubleClick: function onDoubleClick() { return _this4.handleRowDoubleClick(row); }, onMouseOver: function onMouseOver() { return _this4.setState({ columnHoverIndex: columnIndex, rowHoverIndex: rowIndex }); } }; return React.createElement(ContentCell, _extends({ key: key }, _cellProps)); } else { return React.createElement('div', null); } } }; DataTable.prototype.getColumnWidth = function getColumnWidth(index) { if (this.isLastColumn(index)) { var shortfall = this.calculateLastColumnShortfall(); if (shortfall) { return this.state.columnWidths[index] + shortfall; } } return this.state.columnWidths[index] || this.props.defaultColumnWidth; }; DataTable.prototype.isLastColumn = function isLastColumn(index) { return index == this.state.fields.length - 1; }; DataTable.prototype.calculateLastColumnShortfall = function calculateLastColumnShortfall() { var shortfall = this._width; for (var i = 0; i < this.state.fields.length; i++) { shortfall -= this.state.columnWidths[i]; } if (shortfall > 0) { return shortfall; } return 0; }; DataTable.prototype.render = function render() { var _this5 = this; var _props4 = this.props, defaultRowHeight = _props4.defaultRowHeight, data = _props4.data, pagination = _props4.pagination, ResultsFooter = _props4.ResultsFooter; var _state3 = this.state, selectedIds = _state3.selectedIds, fields = _state3.fields, selectAllGlobal = _state3.selectAllGlobal; var fixedColumnCount = fields.reduce(function (count, field) { return count + (field.fixed ? 1 : 0); }, 0); return React.createElement( 'div', { className: 'flex-1-0-auto flex flex-column data-table-container' }, selectedIds.length > 0 && selectedIds.length == data.length && React.createElement( 'div', { className: 'flex-none data-message-row' }, 'All ', data.length, ' items on this page are selected.', ' ', React.createElement(Button, { text: 'Select all ' + pagination.count, size: 'xsmall margin-left-xsmall', style: 'tertiary', onClick: function onClick() { return _this5.handleSelectAllGlobal(); } }) ), selectAllGlobal && React.createElement( 'div', { className: 'flex-none data-message-row' }, 'All ', React.createElement( 'strong', null, pagination.count ), ' items are selected.', React.createElement(Button, { text: 'Deselect all', size: 'xsmall margin-left-xsmall', style: 'tertiary', onClick: function onClick() { return _this5.handleSelectAll(); } }) ), React.createElement( 'div', { className: 'flex-1-0-auto', style: { position: 'relative' } }, React.createElement( AutoSizer, null, function (_ref8) { var width = _ref8.width, height = _ref8.height; _this5._lastWidth = _this5._width; _this5._width = width; return React.createElement(MultiGrid, { ref: function ref(_ref11) { _this5.grid = _ref11; if (_this5.grid && _this5._lastWidth != width) { _this5.grid.recomputeGridSize(); } }, fixedColumnCount: fixedColumnCount, enableFixedColumnScroll: true, classNameTopRightGrid: 'data-table-top-right', classNameBottomLeftGrid: 'data-table-bottom-left', fixedRowCount: 1, width: width, height: height, cellRenderer: _this5.cellRenderer, columnCount: fields.length, columnWidth: function columnWidth(_ref9) { var index = _ref9.index; return _this5.getColumnWidth(index); }, rowHeight: function rowHeight(_ref10) { var index = _ref10.index; return index === 0 ? 35 : isFunction(defaultRowHeight) ? defaultRowHeight({ index: index }) : defaultRowHeight; }, rowCount: data.length + 1, overscanRowCount: 5 }); } ) ), ResultsFooter && React.createElement( 'div', { className: 'flex-none data-footer-row' }, React.createElement(ResultsFooter, { pagination: pagination, loading: this.props.loading }) ) ); }; return DataTable; }(Component), _class.propTypes = { data: PropTypes.array.isRequired, fields: PropTypes.array.isRequired, pagination: PropTypes.shape({ count: PropTypes.number.isRequired, current_page: PropTypes.number.isRequired, page_count: PropTypes.number.isRequired, has_next_page: PropTypes.bool, has_prev_page: PropTypes.bool, limit: PropTypes.number }), onSelectionChange: PropTypes.func, onSelectGlobalChange: PropTypes.func, onParamsChange: PropTypes.func.isRequired, rowHighlight: PropTypes.bool, columnHighlight: PropTypes.bool, loading: PropTypes.bool, defaultRowHeight: PropTypes.oneOfType([PropTypes.number, PropTypes.func]), selectAllGlobal: PropTypes.bool, selectedIds: PropTypes.arrayOf(PropTypes.number), selectedData: PropTypes.arrayOf(PropTypes.object) }, _class.defaultProps = { fields: [], data: [], pagination: { count: 0, current_page: 0, page_count: 1, has_next_page: false, has_prev_page: false, limit: 50 }, checkboxSelection: false, defaultColumnWidth: 150, defaultRowHeight: 35, selectAllGlobal: false, selectedIds: [], selectedData: [], rowHighlight: true, columnHighlight: false, loading: false, HeaderCell: DefaultHeaderCell, ContentCell: DefaultContentCell, ResultsFooter: DefaultResultsFooter }, _temp); export { DataTable as default };