Skip to content

Commit

Permalink
editor components
Browse files Browse the repository at this point in the history
  • Loading branch information
nreese committed Jun 6, 2017
1 parent d52bc31 commit bedfc97
Show file tree
Hide file tree
Showing 7 changed files with 311 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React, { Component, PropTypes } from 'react';
import Select from 'react-select';

export class FieldSelect extends Component {
constructor(props) {
super(props);

this.loadFields = this.loadFields.bind(this);
}

loadFields(input, callback) {
if (!this.props.indexPatternId || this.props.indexPatternId.length === 0) {
callback(null, { options: [] });
return;
}

this.props.getIndexPattern(this.props.indexPatternId).then(index => {
const fields = index.fields.filter(function (field) {
return field.aggregatable && ['number', 'boolean', 'date', 'ip', 'string'].includes(field.type);
}).sort((a, b) => {
if (a.name < b.name) return -1;
if (a.name > b.name) return 1;
return 0;
}).map(function (field) {
return { label: field.name, value: field.name };
});
//Setting complete=true means loadOptions will never be called again.
callback(null, { options: fields, complete: true });
});
}

render() {
if (!this.props.indexPatternId || this.props.indexPatternId.trim().length === 0) {
return null;
}

return (
<div className="kuiFieldGroup">
<div className="kuiFieldGroupSection">
<label>
Terms Field
</label>
</div>
<div className="kuiFieldGroupSection kuiFieldGroupSection--wide">
<Select.Async
placeholder="Select..."
value={this.props.value}
loadOptions={this.loadFields}
onChange={this.props.onChange}
resetValue={''}/>
</div>
</div>
);
}
}

FieldSelect.propTypes = {
getIndexPattern: PropTypes.func.isRequired,
indexPatternId: PropTypes.string,
onChange: PropTypes.func.isRequired,
value: PropTypes.string
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React, { Component, PropTypes } from 'react';
import Select from 'react-select';

export class IndexPatternSelect extends Component {
constructor(props) {
super(props);

this.loadOptions = this.loadOptions.bind(this);
}

loadOptions(input, callback) {
this.props.getIndexPatternIds().then(ids => {
const options = ids.map(id => {
return { label: id, value: id };
});
//Setting complete=true means loadOptions will never be called again.
callback(null, { options: options, complete: true });
});
}

render() {
return (
<div className="kuiFieldGroup">
<div className="kuiFieldGroupSection">
<label>
Index Pattern
</label>
</div>
<div className="kuiFieldGroupSection kuiFieldGroupSection--wide">
<Select.Async
placeholder="Select..."
value={this.props.value}
loadOptions={this.loadOptions}
onChange={this.props.onChange}
resetValue={''}/>
</div>
</div>
);
}
}

IndexPatternSelect.propTypes = {
getIndexPatternIds: PropTypes.func.isRequired,
onChange: PropTypes.func.isRequired,
value: PropTypes.string
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React, { Component } from 'react';
import Select from 'react-select';

export class TermsVis extends Component {
constructor(props) {
super(props);

this.handleOnChange = this.handleOnChange.bind(this);
}

handleOnChange(control, evt) {
if (evt) {
this.props.setFilter(control.field, evt.value, control.indexPattern);
} else {
this.props.removeFilter(control.field, control.indexPattern);
}
}

render() {
return (
<div className="vertical-layout">
{this.props.controls.map((control, index) =>
<div key={index} className="terms-field">
<span>{control.label}</span>
<Select
className="terms-select"
placeholder="Select..."
value={control.selected}
options={control.terms}
onChange={this.handleOnChange.bind(null, control)}/>
</div>
)}
</div>
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import React, { Component } from 'react';
import { IndexPatternSelect } from './index_pattern_select';
import { FieldSelect } from './field_select';
import {
KuiButton,
KuiButtonIcon,
} from 'ui_framework/components';
import { addField, newField, removeField, setField } from '../lib/editor_utils';

export class TermsVisEditor extends Component {
constructor(props) {
super(props);

this.handleFieldNameChange = this.handleFieldNameChange.bind(this);
this.handleLabelChange = this.handleLabelChange.bind(this);
this.handleIndexPatternChange = this.handleIndexPatternChange.bind(this);
this.handleRemoveField = this.handleRemoveField.bind(this);
this.handleAddField = this.handleAddField.bind(this);
}

shouldComponentUpdate() {
console.log('shouldComponentUpdate');
}

componentWillReceiveProps(newProps) {
console.log('newProps', newProps);
}

handleLabelChange(fieldIndex, evt) {
const updatedField = this.props.visParams.fields[fieldIndex];
updatedField.label = evt.target.value;
this.props.setVisParam('fields', setField(this.props.visParams.fields, fieldIndex, updatedField));
}

handleIndexPatternChange(fieldIndex, evt) {
const updatedField = this.props.visParams.fields[fieldIndex];
updatedField.indexPattern = evt.value;
updatedField.fieldName = '';
this.props.setVisParam('fields', setField(this.props.visParams.fields, fieldIndex, updatedField));
}

handleFieldNameChange(fieldIndex, evt) {
const updatedField = this.props.visParams.fields[fieldIndex];
updatedField.fieldName = evt.value;
this.props.setVisParam('fields', setField(this.props.visParams.fields, fieldIndex, updatedField));
}

handleRemoveField(fieldIndex) {
this.props.setVisParam('fields', removeField(this.props.visParams.fields, fieldIndex));
}

handleAddField() {
this.props.setVisParam('fields', addField(this.props.visParams.fields, newField()));
}

renderFields() {
return this.props.visParams.fields.map((field, index) => {
return (
<div key={index} className="field-section">
<div className="kuiFieldGroup">
<div className="kuiFieldGroupSection">
<label>
Label
</label>
</div>
<div className="kuiFieldGroupSection">
<input
className="kuiTextInput"
type="text"
value={field.label}
onChange={this.handleLabelChange.bind(null, index)} />
</div>
<button
className="kuiButton kuiButton--danger kuiButton--small"
onClick={this.handleRemoveField.bind(null, index)}>
<span className="kuiIcon fa-trash"></span>
</button>
</div>

<IndexPatternSelect
value={field.indexPattern}
onChange={this.handleIndexPatternChange.bind(null, index)}
getIndexPatternIds={this.props.getIndexPatternIds} />

<FieldSelect
value={field.fieldName}
indexPatternId={field.indexPattern}
onChange={this.handleFieldNameChange.bind(null, index)}
getIndexPattern={this.props.getIndexPattern} />
</div>
);
});
}

render() {
return (
<div>
<div>
{this.props.count}
</div>
{this.renderFields()}

<KuiButton
type="primary"
icon={<KuiButtonIcon type="create" />}
onClick={this.handleAddField}
>
Add
</KuiButton>
</div>
);
}
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,46 @@
import React from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import { VisController } from './vis_controller';
import { TermsVisEditor } from './components/terms_vis_editor';

class EditorController {
constructor(el) {
constructor(el, vis) {
this.el = el;
this.vis = vis;
this.editorDiv = document.createElement('div');
this.visDiv = document.createElement('div');
this.el.appendChild(this.editorDiv);
this.el.appendChild(this.visDiv);
this.visualization = new VisController(this.visDiv);
}

render(vis, visData) {
render(visData) {
let count = 0;
const setVisParam = (paramName, paramValue) => {
this.vis.params[paramName] = paramValue;
//this.vis.updateState();
count++;
console.log('count', count);
};
const getIndexPatternIds = () => {
return this.vis.API.indexPatterns.getIds();
};
const getIndexPattern = (indexPatternId) => {
return this.vis.API.indexPatterns.get(indexPatternId);
};
return new Promise(resolve => {
console.log('rendering editor');
this.editorDiv.innerHTML = 'my editor';
render(
<TermsVisEditor
visParams={this.vis.params}
count={count}
setVisParam={setVisParam}
getIndexPatternIds={getIndexPatternIds}
getIndexPattern={getIndexPattern}
/>,
this.el
);
// we probably want to render the visualization as well ?
this.visualization.render(vis, visData).then(() => {
this.visualization.render(this.vis, visData).then(() => {
resolve('when done rendering');
});
});
Expand All @@ -26,6 +51,7 @@ class EditorController {
}

destroy() {
unmountComponentAtNode(this.el);
this.visualization.destroy();
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
export const setField = (fields, fieldIndex, field) => [
...fields.slice(0, fieldIndex),
field,
...fields.slice(fieldIndex + 1)
];

export const addField = (fields, field) => [...fields, field];

export const removeField = (fields, fieldIndex) => [
...fields.slice(0, fieldIndex),
...fields.slice(fieldIndex + 1)
];

export const newField = () => ({
indexPattern: '',
fieldName: '',
label: '',
size: 5,
order: 'desc'
});
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import './terms_vis.less';
import 'react-select/dist/react-select.css';
import { CATEGORY } from 'ui/vis/vis_category';
import { VisFactoryProvider } from 'ui/vis/vis_factory';
import { VisTypesRegistryProvider } from 'ui/registry/vis_types';
import { VisController } from './vis_controller';
import { EditorController } from './editor_controller';
import { newField } from './lib/editor_utils';

function TermsVisProvider(Private) {
const VisFactory = Private(VisFactoryProvider);
Expand All @@ -18,8 +20,7 @@ function TermsVisProvider(Private) {
visualization: VisController,
visConfig: {
defaults: {
// add default parameters
fontSize: '50'
fields: [newField()]
},
},
editor: EditorController,
Expand Down

0 comments on commit bedfc97

Please sign in to comment.