import React, {Component} from 'react'; import {Field as FormField} from "react-final-form"; import {Button, FormGroup, InputGroup, Intent, MenuItem, Switch, TextArea} from "@blueprintjs/core"; import {Select} from "@blueprintjs/select"; import {DateInput} from "@blueprintjs/datetime"; import {Entity, EntityFieldInfo, EntityRenderProps, LoadingQuery} from 'react-entity-plane'; import MaskedInput from 'react-text-mask'; import * as _ from "lodash"; import {fieldDefaults} from "../defaults/fieldDefaults"; import {getDisplayName} from "../page-templates/utils/getDisplayName"; import moment from 'moment'; import {EntityFieldType, FieldEnumValues, RelationEntityFieldInfo} from "react-entity-plane/src/types/fieldsInfo"; import {createNumberMask} from "text-mask-addons/dist/textMaskAddons"; import {D} from "../page-templates/utils/debug"; import EntityPicker from "./EntityPicker"; const d = D('Entity Field') export interface EntityFieldProps { entity: EntityRenderProps specificInfo: Partial inForm: boolean creating: boolean disabled: boolean } class EntityField extends Component { state = { dialogOpen: false } render() { const {specificInfo, ...rest} = this.props; const name = specificInfo.name; const baseInfo = this.props.entity.entityInfo.fields.find(fi => fi.name === name) let entityInfo = this.props.entity.entityInfo; if (baseInfo == null) { console.log(`[Entity View] Field ${name} is not defined on ${entityInfo.name}`); return null; } // TODO Generalize const matchingDefaults = fieldDefaults.filter(fd => { let match: (string | RegExp)[] = fd.match as any; if (!_.isArray(match)) match = [match] return match.some(m => _.isRegExp(m) ? m.test(name) : m === name) }).map(md => md.info); const field: EntityFieldInfo = _.defaultsDeep({}, specificInfo, baseInfo, ...matchingDefaults); const validation = (field || {} as any).validation || {} let mask = (field || {} as any).mask let hasMask = mask != null && mask.mask != null; const isBoolean = field.type === EntityFieldType.boolean; if (this.props.creating && field.create === false) return null; if (this.props.inForm) { let parse, format; if (field.type === EntityFieldType.number) { hasMask = true; // TODO Forcefully placed mask, place in defaults to allow custom masks let mask1 = createNumberMask({ prefix: '', suffix: '', // This will put the dollar sign at the end, with a space. includeThousandsSeparator: false, allowDecimal: true, }); mask = { mask: mask1 } parse = v => { if (v == null) return null; if (v === '') return null; d(`Parsing`, JSON.stringify(v), JSON.stringify(parseFloat(v)), JSON.stringify(parseInt(v))); // if(!_.isFinite(v)) return v; return parseFloat(v); } format = v => { //Currently using mask that already provides good format by default return v; } } let validate = (value, allValues) => { if (value == null) { if (field.required) return 'required'; return null; } if (validation.custom) return validation.custom(value, allValues); if (validation.maxLength && value.toString().length > validation.maxLength) return 'length exceeded'; if (validation.minLength && value.toString().length < validation.maxLength) return 'length not fulfilled'; if (validation.max && value > validation.max) return 'max not fulfilled'; if (validation.min && value < validation.min) return 'min not fulfilled'; if (validation.match && validation.match.test(value.toString())) return 'match not fulfilled'; if (field.type === EntityFieldType.number && !_.isFinite(parseFloat(value))) return 'number invalid'; return undefined; }; return {({input: formInput, meta}) => { let showInvalid = (meta.invalid && !this.props.creating) || (meta.invalid && (meta.touched || meta.submitError || meta.dirty)); let intent = (meta.error && showInvalid) ? Intent.DANGER : null; const renderFormGroup = (props, input) => { let maskIndicator = !mask ? undefined : '(Mask)'; let helperText = [field.help, meta.error].join(' '); let label = [field.label || field.name].join(' '); return {input} ; } let label = field.label || field.name; if (field.type === EntityFieldType.boolean) { return renderFormGroup(formInput, ) } if (field.type === EntityFieldType.textarea) { return renderFormGroup(formInput,