@bigfishtv/cockpit
Version:
583 lines (525 loc) • 19.9 kB
JavaScript
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 };