Mailspring/packages/client-app/src/components/scenario-editor-row.jsx
2017-07-16 14:01:20 -07:00

186 lines
5 KiB
JavaScript

import React from 'react';
import Rx from 'rx-lite';
import {Flexbox} from 'nylas-component-kit';
import {Template} from './scenario-editor-models';
const SOURCE_SELECT_NULL = 'NULL';
class SourceSelect extends React.Component {
static displayName = 'SourceSelect';
static propTypes = {
value: React.PropTypes.string,
onChange: React.PropTypes.func.isRequired,
options: React.PropTypes.oneOfType([
React.PropTypes.object,
React.PropTypes.array,
]).isRequired,
};
constructor(props) {
super(props);
this.state = {
options: [],
};
}
componentDidMount() {
this._setupValuesSubscription()
}
componentWillReceiveProps(nextProps) {
this._setupValuesSubscription(nextProps);
}
componentWillUnmount() {
if (this._subscription) { this._subscription.dispose(); }
this._subscription = null;
}
_setupValuesSubscription(props = this.props) {
if (this._subscription) { this._subscription.dispose(); }
this._subscription = null;
if (props.options instanceof Rx.Observable) {
this._subscription = props.options.subscribe((options) =>
this.setState({options})
)
} else {
this.setState({options: props.options});
}
}
_onChange = (event) => {
this.props.onChange({target: {
value: event.target.value === SOURCE_SELECT_NULL ? null : event.target.value,
}});
}
render() {
// The React <select> component won't select the correct option if the value
// is null or undefined - it just leaves the selection whatever it was in the
// previous render. To work around this, we coerce null/undefined to SOURCE_SELECT_NULL.
return (
<select value={this.props.value || SOURCE_SELECT_NULL} onChange={this._onChange}>
<option key={SOURCE_SELECT_NULL} value={SOURCE_SELECT_NULL} />
{this.state.options.map(({value, name}) =>
<option key={value} value={value}>{name}</option>
)}
</select>
);
}
}
export default class ScenarioEditorRow extends React.Component {
static displayName = 'ScenarioEditorRow';
static propTypes = {
instance: React.PropTypes.object.isRequired,
removable: React.PropTypes.bool,
templates: React.PropTypes.array.isRequired,
onChange: React.PropTypes.func,
onInsert: React.PropTypes.func,
onRemove: React.PropTypes.func,
};
_onChangeValue = (event) => {
const instance = JSON.parse(JSON.stringify(this.props.instance));
instance.value = event.target.value
this.props.onChange(instance)
}
_onChangeComparator = (event) => {
const instance = JSON.parse(JSON.stringify(this.props.instance));
instance.comparatorKey = event.target.value
this.props.onChange(instance);
}
_onChangeTemplate = (event) => {
const instance = JSON.parse(JSON.stringify(this.props.instance));
const newTemplate = this.props.templates.find(t => t.key === event.target.value);
this.props.onChange(newTemplate.coerceInstance(instance));
}
_renderTemplateSelect() {
const options = this.props.templates.map(({key, name}) =>
<option value={key} key={key}>{name}</option>
);
return (
<select
value={this.props.instance.templateKey}
onChange={this._onChangeTemplate}
>
{options}
</select>
);
}
_renderComparator(template) {
const options = Object.keys(template.comparators).map(key =>
<option key={key} value={key}>{template.comparators[key].name}</option>
);
if (options.length === 0) {
return false;
}
return (
<select
value={this.props.instance.comparatorKey}
onChange={this._onChangeComparator}
>
{options}
</select>
);
}
_renderValue(template) {
if (template.type === Template.Type.Enum) {
return (
<SourceSelect
value={this.props.instance.value}
onChange={this._onChangeValue}
options={template.values}
/>
);
}
if (template.type === Template.Type.String) {
return (
<input
type="text"
value={this.props.instance.value}
onChange={this._onChangeValue}
/>
);
}
return false;
}
_renderActions() {
return (
<div className="actions">
{ this.props.removable && <div className="btn" onClick={this.props.onRemove}>&minus;</div> }
<div className="btn" onClick={this.props.onInsert}>+</div>
</div>
);
}
render() {
const template = this.props.templates.find(t => t.key === this.props.instance.templateKey);
if (!template) {
return (
<span> Could not find template for instance key: {this.props.instance.templateKey}</span>
);
}
return (
<Flexbox direction="row" className="well-row">
<span>
{this._renderTemplateSelect(template)}
{this._renderComparator(template)}
<span>{template.valueLabel}</span>
{this._renderValue(template)}
</span>
<div style={{flex: 1}} />
{this._renderActions()}
</Flexbox>
);
}
}