UNPKG

@bigfishtv/cockpit

Version:

383 lines (330 loc) 14 kB
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; }; var _class, _temp, _initialiseProps; 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 PropTypes from 'prop-types'; import React, { Component } from 'react'; import deepEqual from 'deep-equal'; import keyCode from 'keycode'; import _isEqual from 'lodash/isEqual'; import _debounce from 'lodash/debounce'; import { formatDate } from '../../utils/timeUtils'; import { getDataHash } from '../../utils/lifecycleUtils'; import { sortByObjectKey, getFieldsFromSchemaAndAssociations, normalizeFields } from '../../utils/tableUtils'; import { isCtrlKeyPressed, isShiftKeyPressed } from '../../utils/selectKeyUtils'; import * as SortTypes from '../../constants/SortTypes'; import FixedDataTable from './FixedDataTable'; import FixedDataTableCheckboxSelectCell from './cell/FixedDataTableCheckboxSelectCell'; import FixedDataTableCheckboxSelectHeaderCell from './cell/FixedDataTableCheckboxSelectHeaderCell'; var dateTimeFormat = 'YYYY-MM-DDTHH:mm:ssZ'; var _defaultProps = { uncontrolled: false, allowSelection: true, multiselect: true, stickySelect: false, data: [], selectedIds: [], checkboxSelection: false, tableWidth: 600, tableHeight: 500, fixedWidth: false, fixedHeight: false, cellWidth: 180, rowHeight: 42, negativeHeight: 167, associations: [], defaultSortField: 'modified', defaultSortDirection: SortTypes.DESC, componentResolver: function componentResolver() { return null; }, attributeModifier: function attributeModifier() { return {}; }, onSelectionChange: function onSelectionChange() { return console.warn('[TableView] no onSelectionChange prop provided'); }, onSelect: function onSelect() { return console.warn('[TableView] no onSelect prop provided'); }, onSortChange: function onSortChange(key, direction, type) {} /* { key: 'enabled', value: ' ', width: 30, Cell: FixedDataTableStatusCell, }, */ /** * */ };var TableView = (_temp = _class = function (_Component) { _inherits(TableView, _Component); function TableView(props) { _classCallCheck(this, TableView); var _this = _possibleConstructorReturn(this, _Component.call(this, props)); _initialiseProps.call(_this); _this.lastSelectedId = null; _this.lastSelectedList = []; _this.handleResize = _debounce(_this.handleResize, 200); _this.fieldsHash = getDataHash(_this.getTableFields(props)); var columnKey = localStorage[_this.fieldsHash + '_sortField'] || props.defaultSortField; var sortDirection = localStorage[_this.fieldsHash + '_sortDirection'] || props.defaultSortDirection; var data = (props.data || []).sort(sortByObjectKey(columnKey, sortDirection)); _this.state = { inited: false, data: data, preSortedData: props.data, selectedIds: props.selectedIds, tableWidth: props.tableWidth, tableHeight: props.tableHeight, columnKey: columnKey, sortDirection: sortDirection }; return _this; } TableView.prototype.getTableFields = function getTableFields() { var props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.props; var tableFields = []; if (props.schema instanceof Array && props.schema.length) tableFields = getFieldsFromSchemaAndAssociations(props.schema, props.associations, props.componentResolver, props.attributeModifier);else if (props.fields instanceof Array && props.fields.length) tableFields = normalizeFields(props.fields); if (props.checkboxSelection) { tableFields = [{ fixed: true, resizable: false, order: -999, width: 28, Cell: FixedDataTableCheckboxSelectCell, HeaderCell: FixedDataTableCheckboxSelectHeaderCell }].concat(tableFields); } return tableFields; }; TableView.prototype.componentDidUpdate = function componentDidUpdate() { localStorage[this.fieldsHash + '_sortField'] = this.state.columnKey; localStorage[this.fieldsHash + '_sortDirection'] = this.state.sortDirection; }; TableView.prototype.componentDidMount = function componentDidMount() { window.addEventListener('resize', this.handleResize); window.addEventListener('keydown', this.handleKeyDown); this.handleResize(); }; TableView.prototype.componentWillUnmount = function componentWillUnmount() { window.removeEventListener('resize', this.handleResize); window.removeEventListener('keydown', this.handleKeyDown); }; TableView.prototype.componentWillReceiveProps = function componentWillReceiveProps(nextProps) { var _this2 = this; Object.keys(nextProps).map(function (key) { if (key == 'data') { if (!deepEqual(_this2.state.preSortedData, nextProps.data)) { var data = _this2.sortData(nextProps.data.map(function (item) { // this is temporary because dummy data had weird date format, won't break when changed to real data but should be removed if ('modified' in item) item.modified = formatDate(item.modified, dateTimeFormat); if ('created' in item) item.created = formatDate(item.created, dateTimeFormat); return item; })); _this2.setState({ data: data, preSortedData: nextProps.data }); } // if prop key is in state then update it in state } else if (key in _this2.state && nextProps[key] != _defaultProps[key] && !_isEqual(nextProps[key], _this2.state[key])) { var _this2$setState; _this2.setState((_this2$setState = {}, _this2$setState[key] = nextProps[key], _this2$setState)); } }); }; TableView.prototype.handleSelectAll = function handleSelectAll() { var data = this.state.data; var selectedIds = data.map(function (row) { return row.id; }); this.lastSelectedList = selectedIds.slice(); if (!this.props.uncontrolled) { this.props.onSelectionChange(selectedIds); } else { this.setState({ selectedIds: selectedIds }); } }; TableView.prototype.handleDeselectAll = function handleDeselectAll() { this.lastSelectedList = []; var selectedIds = []; if (!this.props.uncontrolled) { this.props.onSelectionChange(selectedIds); } else { this.setState({ selectedIds: selectedIds }); } }; TableView.prototype.sortData = function sortData(data) { var _state = this.state, columnKey = _state.columnKey, sortDirection = _state.sortDirection; return data.sort(sortByObjectKey(columnKey, sortDirection)); }; TableView.prototype.render = function render() { var _state2 = this.state, inited = _state2.inited, data = _state2.data, selectedIds = _state2.selectedIds, tableWidth = _state2.tableWidth, tableHeight = _state2.tableHeight, columnKey = _state2.columnKey, sortDirection = _state2.sortDirection; var _props = this.props, cellWidth = _props.cellWidth, rowHeight = _props.rowHeight; var tableFields = this.getTableFields(); return React.createElement( 'div', { ref: 'tableContainer', style: !inited ? { opacity: 0 } : {} }, React.createElement(FixedDataTable, _extends({}, this.props, { uncontrolled: false, data: data, fields: tableFields, selectedIds: selectedIds, tableWidth: tableWidth, tableHeight: tableHeight, cellWidth: cellWidth, rowHeight: rowHeight, columnKey: columnKey, sortDirection: sortDirection, onSelect: this.handleSelect, onSelected: this.handleSelected, onSortChange: this.onSortChange, onSelectionChange: this.props.onSelectionChange })) ); }; return TableView; }(Component), _class.defaultProps = _defaultProps, _class.propTypes = { /** Array of objects representing table rows */ data: PropTypes.arrayOf(PropTypes.object), /** Array of objects representing table columns/schema */ fields: PropTypes.arrayOf(PropTypes.object), /** array of table schema passed in from backend */ schema: PropTypes.array, /** array of entity assocations passed in from backend */ assocations: PropTypes.array, /** Array of selected row ids */ selectedIds: PropTypes.arrayOf(PropTypes.number), /** Whether or not component should control its own sorting */ uncontrolled: PropTypes.bool, /** Whether or not to inject a checkbox column to control selection state */ checkboxSelection: PropTypes.bool, tableWidth: PropTypes.number, tableHeight: PropTypes.number, fixedHeight: PropTypes.bool, fixedWidth: PropTypes.bool, cellWidth: PropTypes.number, rowHeight: PropTypes.number, headerHeight: PropTypes.number, /** column key to sort by, can even be nested e.g. 'collection.title' */ defaultSortField: PropTypes.string, defaultSortDirections: PropTypes.oneOf([SortTypes.ASC, SortTypes.DESC]), /** On row(s) selection change */ onSelectionChange: PropTypes.func, /** On row double click */ onSelect: PropTypes.func, /** Component to replace default HeaderCell -- invisibly passed into FixedDataTable */ HeaderCell: PropTypes.func, /** Component to replace default table cell component -- invisibly passed into FixedDataTable */ DefaultCell: PropTypes.func }, _initialiseProps = function _initialiseProps() { var _this3 = this; this.handleResize = function () { var tableContainer = _this3.refs.tableContainer; if (!tableContainer) return; var boundingRect = tableContainer.getBoundingClientRect(); var _props2 = _this3.props, negativeHeight = _props2.negativeHeight, fixedHeight = _props2.fixedHeight, tableHeight = _props2.tableHeight, fixedWidth = _props2.fixedWidth, tableWidth = _props2.tableWidth; // shortcut logic so we not constantly setting state when not needed if (_this3.state.inited && fixedWidth && fixedHeight) return; _this3.setState({ inited: true, tableWidth: fixedWidth ? tableWidth : boundingRect.width, tableHeight: fixedHeight ? tableHeight : window.innerHeight - negativeHeight }); }; this.handleKeyDown = function (event) { var data = _this3.state.data; if (!data.length) return; var key = keyCode(event); var activeElement = document.activeElement; if (!activeElement || activeElement.nodeName !== 'INPUT' && activeElement.nodeName !== 'TEXTAREA') { if (key === 'up') { event.preventDefault(); var index = _this3.lastSelectedId === null ? data.length - 1 : data.reduce(function (value, row, i) { return row.id === _this3.lastSelectedId ? i - 1 : value; }, null); _this3.handleSelect(data[index <= 0 ? 0 : index]); } else if (key === 'down') { event.preventDefault(); var _index = _this3.lastSelectedId === null ? 0 : data.reduce(function (value, row, i) { return row.id === _this3.lastSelectedId ? i + 1 : value; }, null); _this3.handleSelect(data[_index >= data.length - 1 ? data.length - 1 : _index]); } else if (key == 'esc') { event.preventDefault(); _this3.handleDeselectAll(); } else if (key == 'a' && isCtrlKeyPressed()) { event.preventDefault(); _this3.handleSelectAll(); } } }; this.handleSelect = function (row) { var _props3 = _this3.props, multiselect = _props3.multiselect, allowSelection = _props3.allowSelection, stickySelect = _props3.stickySelect, checkboxSelection = _props3.checkboxSelection; if (!allowSelection) return; var selectedIds = _this3.state.selectedIds; if (!multiselect || !checkboxSelection && !isCtrlKeyPressed() && !isShiftKeyPressed()) { selectedIds = selectedIds.length === 1 && selectedIds[0] === row.id && !stickySelect ? [] : [row.id]; } else if (isShiftKeyPressed()) { var data = _this3.state.data; var lastIndex = data.indexOf(data.filter(function (item) { return item.id === _this3.lastSelectedId; })[0]); var nextIndex = data.indexOf(data.filter(function (item) { return item.id === row.id; })[0]); var lower = Math.min(lastIndex, nextIndex); var upper = Math.max(lastIndex, nextIndex); selectedIds = [].concat(_this3.lastSelectedList, data.filter(function (item, i) { return i >= lower && i <= upper; }).map(function (item) { return item.id; })); } else if (isCtrlKeyPressed() || checkboxSelection) { selectedIds = selectedIds.indexOf(row.id) >= 0 ? selectedIds.filter(function (id) { return id !== row.id; }) : [].concat(selectedIds, [row.id]); } // remove any duplicate ids selectedIds = selectedIds.filter(function (val, i) { return selectedIds.indexOf(val) === i; }); _this3.lastSelectedId = row.id; _this3.lastSelectedList = selectedIds.slice(); if (!_this3.props.uncontrolled) { _this3.props.onSelectionChange(selectedIds); } else { _this3.setState({ selectedIds: selectedIds }); } }; this.handleSelected = function (row) { _this3.props.onSelect(row); }; this.onSortChange = function (columnKey, sortDirection, sortType) { var data = [].concat(_this3.state.data).sort(sortByObjectKey(columnKey, sortDirection, sortType)); _this3.props.onSortChange(columnKey, sortDirection, sortType); _this3.setState({ data: data, columnKey: columnKey, sortDirection: sortDirection }); }; }, _temp); export { TableView as default };