@bigfishtv/cockpit
Version:
383 lines (330 loc) • 14 kB
JavaScript
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 };