@bigfishtv/cockpit
Version:
245 lines (228 loc) • 9.48 kB
JavaScript
/**
* 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 }))
}