Adding property validators

This commit is contained in:
Jesús Espino 2021-04-08 12:40:55 +02:00
parent b7a14ac838
commit 6383d79ecf
4 changed files with 51 additions and 5 deletions

View file

@ -29,6 +29,24 @@ const PropertyValueElement = (props:Props): JSX.Element => {
const displayValue = OctoUtils.propertyDisplayValue(card, propertyValue, propertyTemplate) const displayValue = OctoUtils.propertyDisplayValue(card, propertyValue, propertyTemplate)
const finalDisplayValue = displayValue || emptyDisplayValue const finalDisplayValue = displayValue || emptyDisplayValue
const validateProp = (propType: string, val: string): boolean => {
if (val === '') {
return true
}
switch (propType) {
case 'number':
return !isNaN(parseInt(val, 10))
case 'email': {
const emailRegexp = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
return emailRegexp.test(val.toLowerCase())
}
case 'text':
return true
default:
return false
}
}
if (propertyTemplate.type === 'select') { if (propertyTemplate.type === 'select') {
let propertyColorCssClassName = '' let propertyColorCssClassName = ''
const cardPropertyValue = propertyTemplate.options.find((o) => o.id === propertyValue) const cardPropertyValue = propertyTemplate.options.find((o) => o.id === propertyValue)
@ -85,6 +103,7 @@ const PropertyValueElement = (props:Props): JSX.Element => {
onChange={setValue} onChange={setValue}
onSave={() => mutator.changePropertyValue(card, propertyTemplate.id, value)} onSave={() => mutator.changePropertyValue(card, propertyTemplate.id, value)}
onCancel={() => setValue(propertyValue)} onCancel={() => setValue(propertyValue)}
validator={(value) => validateProp(propertyTemplate.type, value)}
/> />
) )
} }

View file

@ -8,6 +8,7 @@
--button-bg: 22, 109, 204; --button-bg: 22, 109, 204;
--link-color: 35, 137, 215; --link-color: 35, 137, 215;
--link-visited-color: #551a8b; --link-visited-color: #551a8b;
--error-color: #ffa9a9;
// Label Colors // Label Colors
--prop-default: #fff; --prop-default: #fff;

View file

@ -3,6 +3,7 @@
border: 0; border: 0;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
border: 1px solid transparent;
&.active { &.active {
min-width: 100px; min-width: 100px;
} }
@ -10,4 +11,8 @@
color: rgba(var(--body-color), 0.4); color: rgba(var(--body-color), 0.4);
opacity: 1; opacity: 1;
} }
&.error {
border: 1px solid var(--error-color);
border-radius: var(--default-rad);
}
} }

View file

@ -12,6 +12,7 @@ type Props = {
saveOnEsc?: boolean saveOnEsc?: boolean
readonly?: boolean readonly?: boolean
validator?: (value: string) => boolean
onCancel?: () => void onCancel?: () => void
onSave?: (saveType: 'onEnter'|'onEsc'|'onBlur') => void onSave?: (saveType: 'onEnter'|'onEsc'|'onBlur') => void
} }
@ -24,6 +25,22 @@ export default class Editable extends React.Component<Props> {
return true return true
} }
save = (saveType: 'onEnter'|'onEsc'|'onBlur'): void => {
if (this.props.validator && !this.props.validator(this.props.value || '')) {
return
}
if (!this.props.onSave) {
return
}
if (saveType === 'onBlur' && !this.saveOnBlur) {
return
}
if (saveType === 'onEsc' && !this.props.saveOnEsc) {
return
}
this.props.onSave(saveType)
}
public focus(selectAll = false): void { public focus(selectAll = false): void {
if (this.elementRef.current) { if (this.elementRef.current) {
const valueLength = this.elementRef.current.value.length const valueLength = this.elementRef.current.value.length
@ -44,30 +61,34 @@ export default class Editable extends React.Component<Props> {
public render(): JSX.Element { public render(): JSX.Element {
const {value, onChange, className, placeholderText} = this.props const {value, onChange, className, placeholderText} = this.props
let error = false
if (this.props.validator) {
error = !this.props.validator(value || '')
}
return ( return (
<input <input
ref={this.elementRef} ref={this.elementRef}
className={'Editable ' + className} className={'Editable ' + (error ? 'error ' : '') + className}
placeholder={placeholderText} placeholder={placeholderText}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => { onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
onChange(e.target.value) onChange(e.target.value)
}} }}
value={value} value={value}
title={value} title={value}
onBlur={() => this.saveOnBlur && this.props.onSave && this.props.onSave('onBlur')} onBlur={() => this.save('onBlur')}
onKeyDown={(e: React.KeyboardEvent<HTMLInputElement>): void => { onKeyDown={(e: React.KeyboardEvent<HTMLInputElement>): void => {
if (e.keyCode === 27 && !(e.metaKey || e.ctrlKey) && !e.shiftKey && !e.altKey) { // ESC if (e.keyCode === 27 && !(e.metaKey || e.ctrlKey) && !e.shiftKey && !e.altKey) { // ESC
e.stopPropagation() e.stopPropagation()
if (this.props.saveOnEsc) { if (this.props.saveOnEsc) {
this.props.onSave?.('onEsc') this.save('onEsc')
} else { } else {
this.props.onCancel?.() this.props.onCancel?.()
} }
this.blur() this.blur()
} else if (e.keyCode === 13 && !(e.metaKey || e.ctrlKey) && !e.shiftKey && !e.altKey) { // Return } else if (e.keyCode === 13 && !(e.metaKey || e.ctrlKey) && !e.shiftKey && !e.altKey) { // Return
e.stopPropagation() e.stopPropagation()
this.props.onSave?.('onEnter') this.save('onEnter')
this.blur() this.blur()
} }
}} }}