UNPKG

@bigfishtv/cockpit

Version:

468 lines (418 loc) 16.7 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; }; /** * Table Utilities * @module Utilities/tableUtils */ import _get from 'lodash/get'; import moment from 'moment'; import * as SortTypes from '../constants/SortTypes'; import * as Conditions from '../constants/Conditions'; import { isNumeric, isString, isFunction } from './typeUtils'; import { titleCase } from './stringUtils'; import { getSchemaWithAssociations } from './formUtils'; import FixedDataTableCheckboxCell from '../components/table/cell/FixedDataTableCheckboxCell'; import FixedDataTableDateCell from '../components/table/cell/FixedDataTableDateCell'; import FixedDataTableHtmlCell from '../components/table/cell/FixedDataTableHtmlCell'; import FixedDataTableAssetCell from '../components/table/cell/FixedDataTableAssetCell'; import FixedDataTableDecimalCell from '../components/table/cell/FixedDataTableDecimalCell'; /** * Returns string swapping between ASC and DESC * @param {String} sortDir * @return {String} */ export function reverseSortDirection(sortDir) { return sortDir === SortTypes.DESC ? SortTypes.ASC : SortTypes.DESC; } /** * Returns a sort function that takes into account sort direction and type * @param {String} columnKey - key that will be in both objects to compare * @param {String} sortDirection - direction of sort either ASC or DESC * @param {String} [sortType=string] - sortType: string, numeric, boolean * @return {Function} - returns sort function */ export function sortByObjectKey(columnKey) { var sortDirection = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : SortTypes.ASC; var sortType = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'string'; return function (a, b) { var valA = _get(a, columnKey); var valB = _get(b, columnKey); var sortVal = 0; if (valA === null || valA === undefined) valA = sortType == 'string' ? '' : 0; if (valB === null || valB === undefined) valB = sortType == 'string' ? '' : 0; if (sortType == 'string') { valA = valA && typeof valA.toLowerCase == 'function' ? valA.toLowerCase() : valA; valB = valB && typeof valB.toLowerCase == 'function' ? valB.toLowerCase() : valB; sortVal = valA > valB ? 1 : valA < valB ? -1 : 0; } else if (sortType == 'numeric' || sortType == 'boolean') { sortVal = valB - valA > 0 ? -1 : valB - valA < 0 ? 1 : 0; } if (sortVal !== 0 && sortDirection === SortTypes.DESC) sortVal = sortVal * -1; return sortVal; }; } /** * Takes schema column, looks at type and resolves to javascript sort type * @param {Object} column * @param {String} column.type - e.g. integer, float, decimal, boolean * @return {string} */ export function getSortTypeFromColumn(column) { switch (column.type) { case 'integer': return 'numeric'; break; case 'float': return 'numeric'; break; case 'decimal': return 'numeric'; break; case 'boolean': return 'boolean'; break; } return 'string'; } /** * Takes schema column, looks at type and resolves to corresponding table cell component * @param {Object} column * @param {String} column.type - e.g. datetime, timestamp, boolean, text * @return {React.Component} - Returns react component, else null */ export function getCellComponentFromColumn(column) { switch (column.type) { case 'datetime': return FixedDataTableDateCell; break; case 'timestamp': return FixedDataTableDateCell; break; case 'boolean': return FixedDataTableCheckboxCell; break; case 'text': return FixedDataTableHtmlCell; break; case 'decimal': case 'float': return FixedDataTableDecimalCell; break; } switch (column.className) { case 'Tank.Assets': return FixedDataTableAssetCell; break; } return null; } /** * Generates default field attributes from a schema column * @param {Object} column * @param {String} column.type * @param {String} column.property * @return {Object} */ export function getFieldAttributesFromColumn(column) { var attributes = {}; switch (column.property) { case 'id': attributes = _extends({}, attributes, { width: 40, fixed: true }); break; } switch (column.type) { case 'json': attributes = _extends({}, attributes, { sortable: false }); break; } switch (column.className) { case 'Tank.Assets': attributes = _extends({}, attributes, { width: 80 }); break; } return attributes; } /** * Generates default table fields from schema * @param {Array} schema * @param {Function} componentResolver - precursor function to resolve component based on scema column * @param {Function} attributeModifier - precursor function to resolve additional field attributes based on scema column * @return {Array} - returns array of table fields */ export function getFieldsFromSchema() { var schema = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; var componentResolver = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () { return null; }; var attributeModifier = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : function () { return {}; }; return schema.map(function (column) { var sortType = getSortTypeFromColumn(column); var Cell = componentResolver(column) || getCellComponentFromColumn(column); var additionalAttributes = _extends({}, attributeModifier(column), getFieldAttributesFromColumn(column)); return _extends({ key: column.property, value: column.title || titleCase(column.property), resizable: true, sortable: true, schema: column, sortType: sortType, Cell: Cell }, additionalAttributes); }); } /** * Takes schema and assocations and adds 'belongsToMany' assocations to schema before returning result from 'getFieldsFromSchema' * @param {Array} schema * @param {Object[]} assocations * @param {String} assocations[].type - e.g. belongsTo, belongsToMany * @param {Function} componentResolver - precursor function to resolve component based on scema column * @param {Function} attributeModifier - precursor function to resolve additional field attributes based on scema column * @return {Array} - returns array of table fields */ export function getFieldsFromSchemaAndAssociations() { var schema = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; var associations = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; var componentResolver = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : function () { return null; }; var attributeModifier = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : function () { return {}; }; var newSchema = getSchemaWithAssociations(schema, associations); return normalizeFields(getFieldsFromSchema(newSchema, componentResolver, attributeModifier)); } /** * Takes a table fields and fixes any undefined variables in each one * @param {Object[]} fields * @param {String} fields[].sortType * @param {Boolean} fields[].resizable * @param {Boolean} fields[].sortable * @return {Array} */ export function normalizeFields(fields) { var order = 0; return fields.map(function (field) { if (typeof field.sortType == 'undefined') field.sortType = 'string'; if (typeof field.resizable == 'undefined') field.resizable = true; if (typeof field.sortable == 'undefined') field.sortable = true; if (typeof field.order == 'undefined') field.order = ++order; return field; }).sort(function (a, b) { return a.order < b.order ? -1 : a.order > b.order ? 1 : 0; }); } /** * Filters a data set by a query string, takes schemaTypes object to smartly skip columns of certain type * @param {Array} data * @param {String} queryString * @param {Object} schemaTypes - Keyed object containing schema column types, e.g. {id: 'numeric', title: 'string'} * @return {Array} - returns filtered data array */ export function filterDataByQuery() { var data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; var queryString = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''; var schemaTypes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; // first check if anything is being searched if (!queryString || queryString === '') return data; // filter all rows return data.filter(function (row) { var rowPassed = false; // map over field names for every row Object.keys(schemaTypes).map(function (columnName) { var rowValue = _get(row, columnName); // if a number has been searched for then allow for searching in numeric fields if (isNumeric(queryString) && schemaTypes[columnName] == 'numeric' && isNumeric(rowValue) && rowValue.toString().indexOf(queryString.toString()) >= 0) { rowPassed = true; // otherwise search for query string in all string-type columns } else if (schemaTypes[columnName] == 'string' && isString(rowValue) && rowValue.toLowerCase().indexOf(queryString.toLowerCase()) >= 0) { rowPassed = true; } }); return rowPassed; }); } /** * Takes data array, schema array and query string and smarly filters data using schema * @param {Array} data * @param {Array} schema * @param {String} queryString * @return {Array} - returns filtered data */ export function filterDataByQueryWithSchema() { var data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; var schema = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; var queryString = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : ''; // create an associative object for column name => content type var schemaTypes = {}; for (var _iterator = schema, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { var _ref; if (_isArray) { if (_i >= _iterator.length) break; _ref = _iterator[_i++]; } else { _i = _iterator.next(); if (_i.done) break; _ref = _i.value; } var column = _ref; schemaTypes[column.property] = getSortTypeFromColumn(column); } return filterDataByQuery(data, queryString, schemaTypes); } /** * Takes data array, table fields and query string and smarly filters data using table fields * @param {Array} data * @param {Array} fields * @param {String} queryString * @return {Array} - returns filtered data */ export function filterDataByQueryWithFields() { var data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; var fields = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; var queryString = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : ''; // create an associative object for column name => content type var schemaTypes = {}; for (var _iterator2 = fields, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) { var _ref2; if (_isArray2) { if (_i2 >= _iterator2.length) break; _ref2 = _iterator2[_i2++]; } else { _i2 = _iterator2.next(); if (_i2.done) break; _ref2 = _i2.value; } var column = _ref2; schemaTypes[column.key] = column.sortType; } return filterDataByQuery(data, queryString, schemaTypes); } /** * Takes data array and a keyed object of filters that correspond to keys in data array objects * @param {Array} data * @param {Object} filterset * @return {Array} - returns filtered data */ export function filterDataByFilterset() { var data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; var filterset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var condition = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : Conditions.OR; var properties = Object.keys(filterset); if (!properties.length) return data; return data.filter(function (row) { var passes = 0; for (var _iterator3 = properties, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) { var _ref3; if (_isArray3) { if (_i3 >= _iterator3.length) break; _ref3 = _iterator3[_i3++]; } else { _i3 = _iterator3.next(); if (_i3.done) break; _ref3 = _i3.value; } var property = _ref3; if (filterset[property] === null) { passes++; } else { var rowValue = _get(row, property, undefined); if (rowValue !== undefined) { if (isFunction(filterset[property]) && filterset[property](rowValue, row)) passes++;else if (rowValue === filterset[property]) passes++; } } } if (condition == Conditions.OR && passes > 0 || condition == Conditions.AND && passes === properties.length) return true; return false; }); } /** * Filters out data not within the date range. * * @param {Array} data * @param {String} property * @param {String|Date} fromDate * @param {String|Date} toDate * @return {Array} filtered data */ export function filterDataByDateRange(data, property, fromDate, toDate) { if (fromDate) { fromDate = moment(fromDate); data = data.filter(function (row) { var value = _get(row, property, undefined); return value && moment(value) >= fromDate; }); } if (toDate) { toDate = moment(toDate); data = data.filter(function (row) { var value = _get(row, property, undefined); return value && moment(value) <= toDate; }); } return data; } /** * Used for creating compact filterset rules * Returns a function that takes override values and calls createFilterset the default values, override values, and callback function * @param {Object} defaultValues Default filterset values * @param {Function} callback Typically 'handleFilterChange' passed in from AutoTableIndex * @return {Function} Returns function that takes override values */ export function createFiltersetGenerator() { var defaultValues = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var callback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {}; return function () { var values = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; return createFilterset(defaultValues, values, callback); }; } /** * Takes default values, override values and a callback function * Returns an empty function that calls the callback function with the combined values * @param {Object} defaultValues * @param {Object} values * @param {Function} callback Typically 'handleFilterChange' passed in from AutoTableIndex * @return {Function} Returns function that can be directly called in on onClick prop */ export function createFilterset() { var defaultValues = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var values = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var callback = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : function () {}; return function () { return callback(_extends({}, defaultValues, values)); }; } /** * Used for getting a currently selected filterset label based off rules provided * Note that the order in which the rules are provided is important as the loop short circuits as soon as a checker returns true * @param {Object} filterset Current filterset, typically provided by AutoTableIndex * @param {Object} rules Rules object where key is label and value is a checker function that should return a boolean * @param {String} defaultLabel Default label to return if no rules are matched * @return {String} */ export function getFiltersetLabel() { var filterset = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var rules = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var defaultLabel = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'All'; var filtersetLabel = defaultLabel; for (var _iterator4 = Object.entries(rules), _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) { var _ref4; if (_isArray4) { if (_i4 >= _iterator4.length) break; _ref4 = _iterator4[_i4++]; } else { _i4 = _iterator4.next(); if (_i4.done) break; _ref4 = _i4.value; } var _ref5 = _ref4, label = _ref5[0], checker = _ref5[1]; if (checker && checker(filterset)) { filtersetLabel = label; break; } } return filtersetLabel; }