UNPKG

@bigfishtv/cockpit

Version:

245 lines (228 loc) 9.48 kB
/** * Form Utilities * @module Utilities/formUtils */ import React from 'react' import Switch from '../components/input/SwitchInput' import Checkbox from '../components/input/Checkbox' import Redactor from '../components/Redactor' import Textarea from '../components/input/TextareaInput' import NumberInput from '../components/input/NumberInput' import DateTimeInput from '../components/input/DateTimeInput' import AssetDropzoneInput from '../components/input/AssetDropzoneInput' const switchKeys = ['enabled', 'published', 'visible'] const protectedEditProperties = ['created', 'modified'] const AssetDropzoneInputMultiple = props => <AssetDropzoneInput {...props} multiple={true} extensions="*" type="file" /> /** * Takes schema column and returns appropriate Field input Component * @param {Array} associations - Array objects for associations * @param {Object} column - Oject for current column schema, contains keys: property, type, className * @param {String} column.property * @param {String} column.type * @param {String} column.className * @return {React.Component} - Returns React Component corresponding to column schema, otherwise returns undefined */ export function resolveFieldInputFromColumn(associations = [], column) { // We do this in case schema wasn't processed by getSchemaWithAssociations, e.g. if generated directly from AutoEdit const associationKeys = getAssociationKeyedClasses(associations) const association = column.property in associationKeys ? associations.filter(assoc => assoc.property == column.property)[0] : null if (association) { switch (association.className) { case 'Tank.Assets': if (association.type == 'belongsToMany') return AssetDropzoneInputMultiple return AssetDropzoneInput break } } if (column.type == 'boolean') { return switchKeys.indexOf(column.property) >= 0 ? Switch : Checkbox } if (column.type == 'text') { return Redactor } if (column.type == 'string' && column.length > 255) { return Textarea } if (column.type == 'datetime') { return DateTimeInput } if (column.type == 'decimal' || column.type == 'float' || column.type == 'integer') { const step = 1 / Math.pow(10, column.precision || 0) const min = column.unsigned ? 0 : undefined return props => <NumberInput {...props} step={step} min={min} /> } return undefined } /** * Takes associations and returns a keyed array of foreignKey: className * @param {Array} associations * @return {Object} */ export function getAssociationKeyedClasses(associations) { const associationKeys = {} for (let association of associations) associationKeys[association.property] = association.className return associationKeys } /** * Takes schema array and filters out typically uneditable things pertaining to table view e.g. _owner etc. * @param {Object[]} schema - Array of ojects for schema columns, contains keys: autoIncrement, default, property * @param {String} schema[].autoIncrement * @param {String} schema[].default * @param {String} schema[].property * @return {Object[]} - Returns filtered schema array */ export function filterOutProtectedSchema(schema, ignoreList = []) { return schema.filter(column => { return !(column.property.charAt(0) == '_') || ~ignoreList.indexOf(column.property) }) } /** * Takes schema array and filters out typically uneditable things pertaining to edit view e.g. auto incrementing columns, columns with default set to 'CURRENT_TIMESTAMP' etc. * @param {Object[]} schema - Array of ojects for schema columns, contains keys: autoIncrement, default, property * @param {String} schema[].autoIncrement * @param {String} schema[].default * @param {String} schema[].property * @return {Object[]} - Returns filtered schema array */ export function filterOutProtectedEditSchema(schema, protectedProperties = protectedEditProperties) { return filterOutProtectedSchema(schema).filter(column => { return !( column.autoIncrement || column.default == 'CURRENT_TIMESTAMP' || ~protectedProperties.indexOf(column.property) ) }) } /** * Takes associations and schema and filters out schema columns that are present in associations * @param {Object[]} associations Array of objects for associations * @param {String} associations[].className e.g. 'Model' * @param {String} associations[].foreignKey e.g. 'model_id' * @param {Object[]} schema Array of objects for schema columns * @param {String} schema[].property e.g. 'model_id' * @return {Object[]} Returns filtered schema */ export function removeAssocationsFromSchema(associations = [], schema) { const associationKeys = {} const associationSchemaKeys = {} for (let association of associations) { associationKeys[association.property] = association.className associationSchemaKeys[association.property] = association.schema ? association.schema.map(item => item.property) : null } return schema.filter( column => // automatically allow any field that's not linked to an association (or is a tank asset) !(column.property in associationKeys && associationKeys[column.property] != 'Tank.Assets') || // otherwise check if the field is an association, // and if the association has schema, // and that the schema has a title or name field (as this can be rendered by FixedDataTableTextCell) (column.property in associationKeys || (associationSchemaKeys[column.property] && (associationSchemaKeys[column.property].indexOf('title') >= 0 || associationSchemaKeys[column.property].indexOf('name') >= 0))) ) } /** * Takes schema array and panel object and filters the schema to only contain the properties defined in panel object * @param {Object[]} schema - Array of ojects for schema columns * @param {String} schema[].property * @param {Object} panel * @param {String[]} panel.properties * @return {Array} - Returns filtered schema array */ export function filterSchemaByPanel(schema, panel) { return schema.filter(column => (panel.properties || []).indexOf(column.property) >= 0) } /** * Takes schema array and array of panels and filters schema to exclude properties definied in panel objects * @param {Array} schema - Array of ojects for schema columns, contains keys: property * @param {String} schema[].property * @param {Object[]} panels - Array of panel objects, contains keys: title, properties * @param {String} panels[].title * @param {String[]} panels[].properties * @return {Array} - Returns filtered schema array */ export function filterSchemaExcludingPanels(schema, panels) { const excludeProperties = panels.reduce((acc, panel) => acc.concat(panel.properties), []) return schema.filter(column => excludeProperties.indexOf(column.property) < 0) } /** * Filters an array of objects by a key (default 'property') with an array of a regex rules * @param {Object[]} array Array to filter * @param {Array} patterns Array of regexes to match key against * @param {String} key (Optional) key to match against * @return {Object[]} Returns filtered array */ export function filterArrayByKeyPatterns(array, patterns, key = 'property') { return array.filter(column => { for (let pattern of patterns) { if (!!column[key].match(pattern)) return false } return true }) } /** * Takes schema and associations arrays and combines them into one schema, takes into account belongsToMany and belongsTo associations * @param {Object[]} schema - Array of ojects for schema columns, contains keys: property, title, type * @param {String} schema[].property * @param {String} schema[].title * @param {String} schema[].type * @param {Object[]} associations - Array of association objects to merge in with schema * @param {String} associations[].type - hasOne, belongsTo, belongsToMany * @param {String} associations[].foreignKey * @param {String} associations[].property * @param {String} associations[].title * @param {String} associations[].className * @return {Object[]} - Returns new schema array */ export function getSchemaWithAssociations(schema, associations) { const newSchema = [...schema] associations.map(association => { const schemaProperties = newSchema.map(column => column.property) if (schemaProperties.indexOf(association.property) < 0) { if (association.type == 'belongsToMany') { newSchema.push({ property: association.property, title: association.name, className: association.className, type: 'json', }) } else if (association.type == 'belongsTo') { newSchema.map(column => { if (association.foreignKey == column.property) { column.property = association.property column.title = association.name column.className = association.className } return column }) } else if (association.type == 'hasOne') { newSchema.push({ property: association.property, title: association.name, className: association.className, type: 'json', }) } else if (association.type == 'hasMany') { newSchema.push({ property: association.property, title: association.name, className: association.className, type: 'json', }) } } }) return newSchema } /** * Takes an array and maps it into a text, value object for select fields * @param {String[]} values * @return {Object[]} */ export function optionsList(values) { return values.map(value => ({ text: value, value })) }