parent
5952632816
commit
a9803f335f
|
@ -95,15 +95,6 @@
|
||||||
}
|
}
|
||||||
&-form {
|
&-form {
|
||||||
&-field {
|
&-field {
|
||||||
&-error {
|
|
||||||
input,
|
|
||||||
select {
|
|
||||||
border-color: rgb(220, 0, 0);
|
|
||||||
&:focus {
|
|
||||||
border-color: rgb(220, 0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
min-height: $input-height;
|
min-height: $input-height;
|
||||||
padding: 1px 0;
|
padding: 1px 0;
|
||||||
@extend %clearfix;
|
@extend %clearfix;
|
||||||
|
@ -131,3 +122,13 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form-field-error {
|
||||||
|
input,
|
||||||
|
select {
|
||||||
|
border-color: rgb(220, 0, 0);
|
||||||
|
&:focus {
|
||||||
|
border-color: rgb(220, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -106,5 +106,10 @@ export default [
|
||||||
field: 'max',
|
field: 'max',
|
||||||
title: 'Maximum value',
|
title: 'Maximum value',
|
||||||
type: 'number'
|
type: 'number'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'valueDescriptions',
|
||||||
|
title: 'Value descriptions',
|
||||||
|
type: 'map'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
|
@ -2,9 +2,10 @@ import React, { Component } from 'react';
|
||||||
|
|
||||||
export default class Field extends Component {
|
export default class Field extends Component {
|
||||||
render() {
|
render() {
|
||||||
const { title, htmlFor, children } = this.props;
|
const { title, htmlFor, children, valid } = this.props;
|
||||||
|
const errorCls = valid === false ? ' form-field-error' : '';
|
||||||
return (
|
return (
|
||||||
<div className="form-field form-field--small">
|
<div className={ `form-field form-field--small${errorCls}` }>
|
||||||
<label htmlFor={htmlFor}>{title}</label>
|
<label htmlFor={htmlFor}>{title}</label>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import Field from './Field';
|
||||||
|
|
||||||
|
export default class MapField extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
fieldSpec: PropTypes.any,
|
||||||
|
signal: PropTypes.any,
|
||||||
|
isExpanded: PropTypes.any,
|
||||||
|
signalEdited: PropTypes.any,
|
||||||
|
updateField: PropTypes.any,
|
||||||
|
valid: PropTypes.any,
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
valid: true,
|
||||||
|
mapString: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
this.onChange = this.onChange.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.componentDidUpdate({}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps) {
|
||||||
|
if (prevProps.isExpanded !== this.props.isExpanded) {
|
||||||
|
const entryPairs = Array.from(this.props.signalEdited.entries());
|
||||||
|
const mapString = entryPairs.reduce((str, [value, desc]) => `${str + value} "${desc}" `, '').trim();
|
||||||
|
this.setState({ mapString });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onChange(ev) {
|
||||||
|
const mapString = ev.target.value;
|
||||||
|
this.setState({ mapString });
|
||||||
|
|
||||||
|
if ((mapString.split('"').length - 1) % 2 !== 0) {
|
||||||
|
this.setState({ valid: false });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let splitted = Array.from(mapString.matchAll(/[^\s"]+|"([^"]*)"/g));
|
||||||
|
if (splitted.length % 2 !== 0) {
|
||||||
|
this.setState({ valid: false });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
splitted = splitted.map(([match, group]) => group || match);
|
||||||
|
const res = new Map();
|
||||||
|
for (let i = 0; i < splitted.length; i += 2) {
|
||||||
|
res.set(splitted[i], splitted[i+1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({ valid: true });
|
||||||
|
this.props.updateField(this.props.fieldSpec, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { fieldSpec, signal, isExpanded } = this.props;
|
||||||
|
|
||||||
|
const htmlFor = `${signal.name}_${fieldSpec.field}`;
|
||||||
|
let valueCol;
|
||||||
|
|
||||||
|
if (isExpanded) {
|
||||||
|
valueCol = <input id={htmlFor} type="text" value={this.state.mapString} onChange={this.onChange} />;
|
||||||
|
} else {
|
||||||
|
valueCol = <span>{signal[fieldSpec.field]}</span>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Field title={typeof fieldSpec.title === 'function' ? fieldSpec.title(signal) : fieldSpec.title}
|
||||||
|
htmlFor={htmlFor} valid={this.props.valid && this.state.valid}>
|
||||||
|
{valueCol}
|
||||||
|
</Field>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,7 +6,8 @@ export default ({
|
||||||
signal,
|
signal,
|
||||||
isExpanded,
|
isExpanded,
|
||||||
signalEdited,
|
signalEdited,
|
||||||
updateField
|
updateField,
|
||||||
|
valid
|
||||||
}) => {
|
}) => {
|
||||||
const { field, title } = fieldSpec;
|
const { field, title } = fieldSpec;
|
||||||
const htmlFor = `${signal.name}_${field}`;
|
const htmlFor = `${signal.name}_${field}`;
|
||||||
|
@ -36,6 +37,7 @@ export default ({
|
||||||
<Field
|
<Field
|
||||||
title={typeof title === 'function' ? title(signal) : title}
|
title={typeof title === 'function' ? title(signal) : title}
|
||||||
htmlFor={htmlFor}
|
htmlFor={htmlFor}
|
||||||
|
valid={valid}
|
||||||
>
|
>
|
||||||
{valueCol}
|
{valueCol}
|
||||||
</Field>
|
</Field>
|
||||||
|
|
|
@ -8,7 +8,8 @@ export default ({
|
||||||
signal,
|
signal,
|
||||||
isExpanded,
|
isExpanded,
|
||||||
signalEdited,
|
signalEdited,
|
||||||
updateField
|
updateField,
|
||||||
|
valid
|
||||||
}) => {
|
}) => {
|
||||||
let valueCol;
|
let valueCol;
|
||||||
const { field, title } = fieldSpec;
|
const { field, title } = fieldSpec;
|
||||||
|
@ -41,6 +42,7 @@ export default ({
|
||||||
<Field
|
<Field
|
||||||
title={typeof title === 'function' ? title(signal) : title}
|
title={typeof title === 'function' ? title(signal) : title}
|
||||||
htmlFor={htmlFor}
|
htmlFor={htmlFor}
|
||||||
|
valid={valid}
|
||||||
>
|
>
|
||||||
{valueCol}
|
{valueCol}
|
||||||
</Field>
|
</Field>
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import cx from 'classnames';
|
|
||||||
|
|
||||||
import FIELDS from './FIELDS';
|
import FIELDS from './FIELDS';
|
||||||
import NumberField from './NumberField';
|
import NumberField from './NumberField';
|
||||||
import StringField from './StringField';
|
import StringField from './StringField';
|
||||||
import OptionField from './OptionField';
|
import OptionField from './OptionField';
|
||||||
|
import MapField from './MapField';
|
||||||
|
|
||||||
const FieldMap = {
|
const FieldMap = {
|
||||||
number: NumberField,
|
number: NumberField,
|
||||||
option: OptionField,
|
option: OptionField,
|
||||||
string: StringField
|
string: StringField,
|
||||||
|
map: MapField,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ({
|
export default ({
|
||||||
|
@ -23,15 +24,16 @@ export default ({
|
||||||
<div className="signals-legend-entry-form">
|
<div className="signals-legend-entry-form">
|
||||||
{FIELDS.map((field) => {
|
{FIELDS.map((field) => {
|
||||||
const Node = FieldMap[field.type];
|
const Node = FieldMap[field.type];
|
||||||
const errorClass = fieldError === field.field ? 'signals-legend-entry-form-field-error' : null;
|
const valid = fieldError !== field.field;
|
||||||
return (
|
return (
|
||||||
<div className={cx("signals-legend-entry-form-field", errorClass)} key={field.field}>
|
<div className="signals-legend-entry-form-field" key={field.field}>
|
||||||
<Node
|
<Node
|
||||||
fieldSpec={field}
|
fieldSpec={field}
|
||||||
signal={signal}
|
signal={signal}
|
||||||
isExpanded={isExpanded}
|
isExpanded={isExpanded}
|
||||||
signalEdited={getSignalEdited(field.field)}
|
signalEdited={getSignalEdited(field.field)}
|
||||||
updateField={update}
|
updateField={update}
|
||||||
|
valid={valid}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -6,7 +6,8 @@ export default ({
|
||||||
signal,
|
signal,
|
||||||
isExpanded,
|
isExpanded,
|
||||||
signalEdited,
|
signalEdited,
|
||||||
updateField
|
updateField,
|
||||||
|
valid
|
||||||
}) => {
|
}) => {
|
||||||
const { field, title } = fieldSpec;
|
const { field, title } = fieldSpec;
|
||||||
const htmlFor = `${signal.name}_${field}`;
|
const htmlFor = `${signal.name}_${field}`;
|
||||||
|
@ -30,6 +31,7 @@ export default ({
|
||||||
<Field
|
<Field
|
||||||
title={typeof title === 'function' ? title(signal) : title}
|
title={typeof title === 'function' ? title(signal) : title}
|
||||||
htmlFor={htmlFor}
|
htmlFor={htmlFor}
|
||||||
|
valid={valid}
|
||||||
>
|
>
|
||||||
{valueCol}
|
{valueCol}
|
||||||
</Field>
|
</Field>
|
||||||
|
|
Loading…
Reference in New Issue