From ae77d625bbc4e03301fd1b2714e55c62408007d2 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Wed, 10 May 2017 12:49:15 -0600 Subject: [PATCH 01/17] terms_vis plugin skeleton --- .../control_visualizations/index.js | 12 +++++++++ .../control_visualizations/package.json | 4 +++ .../public/terms_vis/editor.html | 3 +++ .../public/terms_vis/vis.html | 3 +++ .../public/terms_vis/vis.js | 26 +++++++++++++++++++ .../public/terms_vis/vis.less | 8 ++++++ .../public/terms_vis/vis_controller.js | 6 +++++ .../kibana/public/visualize/wizard/wizard.js | 1 + src/ui/public/vis/vis_type.js | 1 + 9 files changed, 64 insertions(+) create mode 100644 src/core_plugins/control_visualizations/index.js create mode 100644 src/core_plugins/control_visualizations/package.json create mode 100644 src/core_plugins/control_visualizations/public/terms_vis/editor.html create mode 100644 src/core_plugins/control_visualizations/public/terms_vis/vis.html create mode 100644 src/core_plugins/control_visualizations/public/terms_vis/vis.js create mode 100644 src/core_plugins/control_visualizations/public/terms_vis/vis.less create mode 100644 src/core_plugins/control_visualizations/public/terms_vis/vis_controller.js diff --git a/src/core_plugins/control_visualizations/index.js b/src/core_plugins/control_visualizations/index.js new file mode 100644 index 0000000000000..e7ff3dbb7c461 --- /dev/null +++ b/src/core_plugins/control_visualizations/index.js @@ -0,0 +1,12 @@ +export default function (kibana) { + + return new kibana.Plugin({ + require: ['kibana','elasticsearch'], + + uiExports: { + visTypes: [ + 'plugins/control_visualizations/terms_vis/vis.js' + ] + } + }); +} \ No newline at end of file diff --git a/src/core_plugins/control_visualizations/package.json b/src/core_plugins/control_visualizations/package.json new file mode 100644 index 0000000000000..179a67c6e3299 --- /dev/null +++ b/src/core_plugins/control_visualizations/package.json @@ -0,0 +1,4 @@ +{ + "name": "terms", + "version": "kibana" +} diff --git a/src/core_plugins/control_visualizations/public/terms_vis/editor.html b/src/core_plugins/control_visualizations/public/terms_vis/editor.html new file mode 100644 index 0000000000000..6355823aafaed --- /dev/null +++ b/src/core_plugins/control_visualizations/public/terms_vis/editor.html @@ -0,0 +1,3 @@ +
+ options +
diff --git a/src/core_plugins/control_visualizations/public/terms_vis/vis.html b/src/core_plugins/control_visualizations/public/terms_vis/vis.html new file mode 100644 index 0000000000000..c1e47676a4f29 --- /dev/null +++ b/src/core_plugins/control_visualizations/public/terms_vis/vis.html @@ -0,0 +1,3 @@ +
+ Visualization goes here +
diff --git a/src/core_plugins/control_visualizations/public/terms_vis/vis.js b/src/core_plugins/control_visualizations/public/terms_vis/vis.js new file mode 100644 index 0000000000000..e3e0d74404343 --- /dev/null +++ b/src/core_plugins/control_visualizations/public/terms_vis/vis.js @@ -0,0 +1,26 @@ +import './vis.less'; +import './vis_controller'; +import { VisVisTypeProvider } from 'ui/vis/vis_type'; +import { TemplateVisTypeProvider } from 'ui/template_vis_type/template_vis_type'; +import { VisTypesRegistryProvider } from 'ui/registry/vis_types'; +VisTypesRegistryProvider.register(TermsProvider); + +export default function TermsProvider(Private) { + const VisType = Private(VisVisTypeProvider); + const TemplateVisType = Private(TemplateVisTypeProvider); + + return new TemplateVisType({ + name: 'terms', + title: 'Terms', + implementsRenderComplete: true, + description: 'Terms filter control', + category: VisType.CATEGORY.CONTROL, + template: require('./vis.html'), + params: { + editor: require('./editor.html'), + defaults: { + } + }, + requiresSearch: false + }); +} \ No newline at end of file diff --git a/src/core_plugins/control_visualizations/public/terms_vis/vis.less b/src/core_plugins/control_visualizations/public/terms_vis/vis.less new file mode 100644 index 0000000000000..379f6550830c5 --- /dev/null +++ b/src/core_plugins/control_visualizations/public/terms_vis/vis.less @@ -0,0 +1,8 @@ +.terms-vis { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + overflow: hidden; +} \ No newline at end of file diff --git a/src/core_plugins/control_visualizations/public/terms_vis/vis_controller.js b/src/core_plugins/control_visualizations/public/terms_vis/vis_controller.js new file mode 100644 index 0000000000000..ab4793657cf45 --- /dev/null +++ b/src/core_plugins/control_visualizations/public/terms_vis/vis_controller.js @@ -0,0 +1,6 @@ +import { uiModules } from 'ui/modules'; + +const module = uiModules.get('kibana/terms_vis', ['kibana']); +module.controller('KbnTermsController', function () { + +}); diff --git a/src/core_plugins/kibana/public/visualize/wizard/wizard.js b/src/core_plugins/kibana/public/visualize/wizard/wizard.js index 776b1174b53ca..db1bd175ccb23 100644 --- a/src/core_plugins/kibana/public/visualize/wizard/wizard.js +++ b/src/core_plugins/kibana/public/visualize/wizard/wizard.js @@ -37,6 +37,7 @@ module.controller('VisualizeWizardStep1', function ($scope, $route, kbnUrl, time const visTypeCategoryToHumanReadableMap = { [VisType.CATEGORY.BASIC]: 'Basic Charts', + [VisType.CATEGORY.CONTROL]: 'Dashboard Controls', [VisType.CATEGORY.DATA]: 'Data', [VisType.CATEGORY.GRAPHIC]: 'Graphic', [VisType.CATEGORY.MAP]: 'Maps', diff --git a/src/ui/public/vis/vis_type.js b/src/ui/public/vis/vis_type.js index 102edf340def9..167e9930e3283 100644 --- a/src/ui/public/vis/vis_type.js +++ b/src/ui/public/vis/vis_type.js @@ -37,6 +37,7 @@ export function VisVisTypeProvider(Private) { VisType.CATEGORY = { BASIC: 'basic', + CONTROL: 'control', DATA: 'data', MAP: 'map', OTHER: 'other', From 1981d496e34fc4490a6dcff07a0894d5dd6d4574 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Wed, 10 May 2017 13:10:29 -0600 Subject: [PATCH 02/17] fix plugin register path --- src/core_plugins/control_visualizations/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core_plugins/control_visualizations/index.js b/src/core_plugins/control_visualizations/index.js index e7ff3dbb7c461..353ce4fd1780e 100644 --- a/src/core_plugins/control_visualizations/index.js +++ b/src/core_plugins/control_visualizations/index.js @@ -5,7 +5,7 @@ export default function (kibana) { uiExports: { visTypes: [ - 'plugins/control_visualizations/terms_vis/vis.js' + 'plugins/terms/terms_vis/vis' ] } }); From 6e23bb11baedc410642992f3cda00adc67bd91f8 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Wed, 10 May 2017 13:55:34 -0600 Subject: [PATCH 03/17] react hello world --- .../public/terms_vis/components/terms_vis.js | 9 +++++++++ .../control_visualizations/public/terms_vis/vis.html | 2 +- .../public/terms_vis/vis_controller.js | 5 ++++- 3 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis.js diff --git a/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis.js b/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis.js new file mode 100644 index 0000000000000..ab0cf9205bebc --- /dev/null +++ b/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis.js @@ -0,0 +1,9 @@ +import React, { Component } from 'react'; + +export class TermsVis extends Component { + render() { + return ( +

Terms Visualization

+ ); + } +} \ No newline at end of file diff --git a/src/core_plugins/control_visualizations/public/terms_vis/vis.html b/src/core_plugins/control_visualizations/public/terms_vis/vis.html index c1e47676a4f29..666f95f077f95 100644 --- a/src/core_plugins/control_visualizations/public/terms_vis/vis.html +++ b/src/core_plugins/control_visualizations/public/terms_vis/vis.html @@ -1,3 +1,3 @@
- Visualization goes here +
diff --git a/src/core_plugins/control_visualizations/public/terms_vis/vis_controller.js b/src/core_plugins/control_visualizations/public/terms_vis/vis_controller.js index ab4793657cf45..446b8c07e52af 100644 --- a/src/core_plugins/control_visualizations/public/terms_vis/vis_controller.js +++ b/src/core_plugins/control_visualizations/public/terms_vis/vis_controller.js @@ -1,6 +1,9 @@ import { uiModules } from 'ui/modules'; +import { TermsVis } from './components/terms_vis'; -const module = uiModules.get('kibana/terms_vis', ['kibana']); +const module = uiModules.get('kibana/terms_vis', ['kibana', 'react']); module.controller('KbnTermsController', function () { }); + +module.value('TermsVis', TermsVis); \ No newline at end of file From 86d0024929b0f26936092d6ce7cb812e2498c798 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Thu, 11 May 2017 11:19:19 -0600 Subject: [PATCH 04/17] react - use callback to update angular scope --- .../public/terms_vis/components/terms_vis.js | 2 +- .../terms_vis/components/terms_vis_editor.js | 31 +++++++++++++++++++ .../public/terms_vis/editor.html | 6 ++-- .../public/terms_vis/editor_controller.js | 14 +++++++++ .../public/terms_vis/vis.html | 2 +- .../public/terms_vis/vis.js | 2 ++ .../public/terms_vis/vis_controller.js | 10 +++++- 7 files changed, 61 insertions(+), 6 deletions(-) create mode 100644 src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis_editor.js create mode 100644 src/core_plugins/control_visualizations/public/terms_vis/editor_controller.js diff --git a/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis.js b/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis.js index ab0cf9205bebc..6ad31841d6578 100644 --- a/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis.js +++ b/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis.js @@ -3,7 +3,7 @@ import React, { Component } from 'react'; export class TermsVis extends Component { render() { return ( -

Terms Visualization

+

{this.props.visParams.label}

); } } \ No newline at end of file diff --git a/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis_editor.js b/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis_editor.js new file mode 100644 index 0000000000000..dbb71db8f191f --- /dev/null +++ b/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis_editor.js @@ -0,0 +1,31 @@ +import React, { Component } from 'react'; + +export class TermsVisEditor extends Component { + constructor(props) { + super(props); + + this.handleLabelChange = this.handleLabelChange.bind(this); + } + handleLabelChange(evt) { + this.props.setVisParam('label', evt.target.value); + } + render() { + return ( +
+
+ +
+ +
+ +
+
+ ); + } +} \ No newline at end of file diff --git a/src/core_plugins/control_visualizations/public/terms_vis/editor.html b/src/core_plugins/control_visualizations/public/terms_vis/editor.html index 6355823aafaed..52640678fd7f3 100644 --- a/src/core_plugins/control_visualizations/public/terms_vis/editor.html +++ b/src/core_plugins/control_visualizations/public/terms_vis/editor.html @@ -1,3 +1,3 @@ -
- options -
+
+ +
\ No newline at end of file diff --git a/src/core_plugins/control_visualizations/public/terms_vis/editor_controller.js b/src/core_plugins/control_visualizations/public/terms_vis/editor_controller.js new file mode 100644 index 0000000000000..e4e9e172ba653 --- /dev/null +++ b/src/core_plugins/control_visualizations/public/terms_vis/editor_controller.js @@ -0,0 +1,14 @@ +import { uiModules } from 'ui/modules'; +import { TermsVisEditor } from './components/terms_vis_editor'; + +const module = uiModules.get('kibana/terms_vis', ['kibana', 'react']); +module.controller('KbnTermsEditorController', function ($scope) { + $scope.reactProps = { + visParams: $scope.vis.params, + setVisParam: function (paramName, paramValue) { + $scope.vis.params[paramName] = paramValue; + } + }; +}); + +module.value('TermsVisEditor', TermsVisEditor); \ No newline at end of file diff --git a/src/core_plugins/control_visualizations/public/terms_vis/vis.html b/src/core_plugins/control_visualizations/public/terms_vis/vis.html index 666f95f077f95..88000748484b8 100644 --- a/src/core_plugins/control_visualizations/public/terms_vis/vis.html +++ b/src/core_plugins/control_visualizations/public/terms_vis/vis.html @@ -1,3 +1,3 @@
- +
diff --git a/src/core_plugins/control_visualizations/public/terms_vis/vis.js b/src/core_plugins/control_visualizations/public/terms_vis/vis.js index e3e0d74404343..899e982325484 100644 --- a/src/core_plugins/control_visualizations/public/terms_vis/vis.js +++ b/src/core_plugins/control_visualizations/public/terms_vis/vis.js @@ -1,5 +1,6 @@ import './vis.less'; import './vis_controller'; +import './editor_controller'; import { VisVisTypeProvider } from 'ui/vis/vis_type'; import { TemplateVisTypeProvider } from 'ui/template_vis_type/template_vis_type'; import { VisTypesRegistryProvider } from 'ui/registry/vis_types'; @@ -19,6 +20,7 @@ export default function TermsProvider(Private) { params: { editor: require('./editor.html'), defaults: { + label: `terms` } }, requiresSearch: false diff --git a/src/core_plugins/control_visualizations/public/terms_vis/vis_controller.js b/src/core_plugins/control_visualizations/public/terms_vis/vis_controller.js index 446b8c07e52af..52bf6a2af60e4 100644 --- a/src/core_plugins/control_visualizations/public/terms_vis/vis_controller.js +++ b/src/core_plugins/control_visualizations/public/terms_vis/vis_controller.js @@ -2,8 +2,16 @@ import { uiModules } from 'ui/modules'; import { TermsVis } from './components/terms_vis'; const module = uiModules.get('kibana/terms_vis', ['kibana', 'react']); -module.controller('KbnTermsController', function () { +module.controller('KbnTermsController', function ($scope) { + $scope.reactProps = { + visParams: $scope.vis.params + }; + $scope.$watch('vis.params', function (visParams, oldParams) { + if (visParams !== oldParams) { + $scope.reactProps.visParams = visParams; + } + }); }); module.value('TermsVis', TermsVis); \ No newline at end of file From 86c7f4d5fc7749b7d2150af12c4646a9e6c40205 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Thu, 11 May 2017 14:23:27 -0600 Subject: [PATCH 05/17] allow list of fields --- .../public/terms_vis/components/terms_vis.js | 8 +- .../terms_vis/components/terms_vis_editor.js | 76 +++++++++++++++---- .../public/terms_vis/vis.js | 4 +- 3 files changed, 71 insertions(+), 17 deletions(-) diff --git a/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis.js b/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis.js index 6ad31841d6578..5ce8e508d2710 100644 --- a/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis.js +++ b/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis.js @@ -3,7 +3,13 @@ import React, { Component } from 'react'; export class TermsVis extends Component { render() { return ( -

{this.props.visParams.label}

+
+ {this.props.visParams.fields.map((field, index) => +
+

{field.label}

+
+ )} +
); } } \ No newline at end of file diff --git a/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis_editor.js b/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis_editor.js index dbb71db8f191f..89147fb09eff7 100644 --- a/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis_editor.js +++ b/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis_editor.js @@ -1,30 +1,76 @@ import React, { Component } from 'react'; +import { + KuiButton, + KuiButtonIcon, +} from 'ui_framework/components'; export class TermsVisEditor extends Component { constructor(props) { super(props); this.handleLabelChange = this.handleLabelChange.bind(this); + this.addField = this.addField.bind(this); } - handleLabelChange(evt) { - this.props.setVisParam('label', evt.target.value); + + handleLabelChange(fieldIndex, evt) { + const updatedField = this.props.visParams.fields[fieldIndex]; + updatedField.label = evt.target.value; + const updatedFields = [ + ...this.props.visParams.fields.slice(0, fieldIndex), + updatedField, + ...this.props.visParams.fields.slice(fieldIndex + 1) + ]; + this.props.setVisParam('fields', updatedFields); + } + + addField() { + const newField = { + label: '' + }; + const updatedFields = [ + ...this.props.visParams.fields, + newField + ]; + this.props.setVisParam('fields', updatedFields); } + + renderFields() { + return this.props.visParams.fields.map((field, index) => { + return ( +
+
+
+ +
+ +
+ +
+
+
+ ); + }); + } + render() { return ( -
-
- -
+
-
- -
+ {this.renderFields()} + + } + onClick={this.addField} + > + Add +
); } diff --git a/src/core_plugins/control_visualizations/public/terms_vis/vis.js b/src/core_plugins/control_visualizations/public/terms_vis/vis.js index 899e982325484..eefbcf5c28157 100644 --- a/src/core_plugins/control_visualizations/public/terms_vis/vis.js +++ b/src/core_plugins/control_visualizations/public/terms_vis/vis.js @@ -20,7 +20,9 @@ export default function TermsProvider(Private) { params: { editor: require('./editor.html'), defaults: { - label: `terms` + fields: [{ + label: '' + }] } }, requiresSearch: false From 545d8cb724196a50adb63d59f82ae9f221720e57 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Fri, 12 May 2017 08:29:46 -0600 Subject: [PATCH 06/17] add index pattern select --- .../components/index_pattern_select.js | 36 +++++++++++++++++++ .../public/terms_vis/components/terms_vis.js | 3 +- .../terms_vis/components/terms_vis_editor.js | 31 ++++++++++++++-- .../public/terms_vis/editor_controller.js | 10 ++++-- 4 files changed, 74 insertions(+), 6 deletions(-) create mode 100644 src/core_plugins/control_visualizations/public/terms_vis/components/index_pattern_select.js diff --git a/src/core_plugins/control_visualizations/public/terms_vis/components/index_pattern_select.js b/src/core_plugins/control_visualizations/public/terms_vis/components/index_pattern_select.js new file mode 100644 index 0000000000000..ea5f59f1ef744 --- /dev/null +++ b/src/core_plugins/control_visualizations/public/terms_vis/components/index_pattern_select.js @@ -0,0 +1,36 @@ +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 => { + this.cachedOptions = ids.map(id => { + return { label: id, value: id }; + }); + //Setting complete=true means loadOptions will never be called again. + callback(null, { options: this.cachedOptions, complete: true }); + }); + } + + render() { + return ( + + ); + } +} + +IndexPatternSelect.propTypes = { + getIndexPatternIds: PropTypes.func.isRequired, + onChange: PropTypes.func.isRequired, + value: PropTypes.string +}; diff --git a/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis.js b/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis.js index 5ce8e508d2710..e89f393e04d96 100644 --- a/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis.js +++ b/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis.js @@ -7,9 +7,10 @@ export class TermsVis extends Component { {this.props.visParams.fields.map((field, index) =>

{field.label}

+ {field.indexPattern}
)}
); } -} \ No newline at end of file +} diff --git a/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis_editor.js b/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis_editor.js index 89147fb09eff7..080694554bfbb 100644 --- a/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis_editor.js +++ b/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis_editor.js @@ -1,4 +1,5 @@ import React, { Component } from 'react'; +import { IndexPatternSelect } from './index_pattern_select'; import { KuiButton, KuiButtonIcon, @@ -9,6 +10,7 @@ export class TermsVisEditor extends Component { super(props); this.handleLabelChange = this.handleLabelChange.bind(this); + this.handleIndexPatternChange = this.handleIndexPatternChange.bind(this); this.addField = this.addField.bind(this); } @@ -23,8 +25,20 @@ export class TermsVisEditor extends Component { this.props.setVisParam('fields', updatedFields); } + handleIndexPatternChange(fieldIndex, evt) { + const updatedField = this.props.visParams.fields[fieldIndex]; + updatedField.indexPattern = evt.value; + const updatedFields = [ + ...this.props.visParams.fields.slice(0, fieldIndex), + updatedField, + ...this.props.visParams.fields.slice(fieldIndex + 1) + ]; + this.props.setVisParam('fields', updatedFields); + } + addField() { const newField = { + indexPattern: '', label: '' }; const updatedFields = [ @@ -41,10 +55,23 @@ export class TermsVisEditor extends Component {
+
+ +
+
+
+
+ +
); } -} \ No newline at end of file +} diff --git a/src/core_plugins/control_visualizations/public/terms_vis/editor_controller.js b/src/core_plugins/control_visualizations/public/terms_vis/editor_controller.js index e4e9e172ba653..c046d64e76ca4 100644 --- a/src/core_plugins/control_visualizations/public/terms_vis/editor_controller.js +++ b/src/core_plugins/control_visualizations/public/terms_vis/editor_controller.js @@ -2,13 +2,17 @@ import { uiModules } from 'ui/modules'; import { TermsVisEditor } from './components/terms_vis_editor'; const module = uiModules.get('kibana/terms_vis', ['kibana', 'react']); -module.controller('KbnTermsEditorController', function ($scope) { +module.controller('KbnTermsEditorController', ($scope, indexPatterns) => { $scope.reactProps = { + indexPatterns: indexPatterns, visParams: $scope.vis.params, - setVisParam: function (paramName, paramValue) { + setVisParam: (paramName, paramValue) => { $scope.vis.params[paramName] = paramValue; + }, + getIndexPatternIds: () => { + return indexPatterns.getIds(); } }; }); -module.value('TermsVisEditor', TermsVisEditor); \ No newline at end of file +module.value('TermsVisEditor', TermsVisEditor); From 40f679680e9fbc80aca8ddb27b5460df7dc56c74 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Mon, 15 May 2017 10:09:04 -0600 Subject: [PATCH 07/17] FieldSelect input --- .../terms_vis/components/field_select.js | 61 +++++++++++++++++++ .../components/index_pattern_select.js | 23 ++++--- .../public/terms_vis/components/terms_vis.js | 3 +- .../terms_vis/components/terms_vis_editor.js | 40 +++++++----- .../public/terms_vis/editor_controller.js | 3 + .../public/terms_vis/vis.js | 7 ++- 6 files changed, 113 insertions(+), 24 deletions(-) create mode 100644 src/core_plugins/control_visualizations/public/terms_vis/components/field_select.js diff --git a/src/core_plugins/control_visualizations/public/terms_vis/components/field_select.js b/src/core_plugins/control_visualizations/public/terms_vis/components/field_select.js new file mode 100644 index 0000000000000..7f01659cfc609 --- /dev/null +++ b/src/core_plugins/control_visualizations/public/terms_vis/components/field_select.js @@ -0,0 +1,61 @@ +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.type === 'string'; + }).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 ( +
+
+ +
+
+ +
+
+ ); + } +} + +FieldSelect.propTypes = { + getIndexPattern: PropTypes.func.isRequired, + indexPatternId: PropTypes.string, + onChange: PropTypes.func.isRequired, + value: PropTypes.string +}; diff --git a/src/core_plugins/control_visualizations/public/terms_vis/components/index_pattern_select.js b/src/core_plugins/control_visualizations/public/terms_vis/components/index_pattern_select.js index ea5f59f1ef744..338a6e046f25a 100644 --- a/src/core_plugins/control_visualizations/public/terms_vis/components/index_pattern_select.js +++ b/src/core_plugins/control_visualizations/public/terms_vis/components/index_pattern_select.js @@ -10,21 +10,30 @@ export class IndexPatternSelect extends Component { loadOptions(input, callback) { this.props.getIndexPatternIds().then(ids => { - this.cachedOptions = ids.map(id => { + const options = ids.map(id => { return { label: id, value: id }; }); //Setting complete=true means loadOptions will never be called again. - callback(null, { options: this.cachedOptions, complete: true }); + callback(null, { options: options, complete: true }); }); } render() { return ( - +
+
+ +
+
+ +
+
); } } diff --git a/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis.js b/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis.js index e89f393e04d96..d14923f841fb1 100644 --- a/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis.js +++ b/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis.js @@ -7,7 +7,8 @@ export class TermsVis extends Component { {this.props.visParams.fields.map((field, index) =>

{field.label}

- {field.indexPattern} +
{field.indexPattern}
+
{field.fieldName}
)}
diff --git a/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis_editor.js b/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis_editor.js index 080694554bfbb..438eaada1f233 100644 --- a/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis_editor.js +++ b/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis_editor.js @@ -1,5 +1,6 @@ import React, { Component } from 'react'; import { IndexPatternSelect } from './index_pattern_select'; +import { FieldSelect } from './field_select'; import { KuiButton, KuiButtonIcon, @@ -9,6 +10,7 @@ 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.addField = this.addField.bind(this); @@ -28,6 +30,18 @@ export class TermsVisEditor extends Component { handleIndexPatternChange(fieldIndex, evt) { const updatedField = this.props.visParams.fields[fieldIndex]; updatedField.indexPattern = evt.value; + updatedField.fieldName = ''; + const updatedFields = [ + ...this.props.visParams.fields.slice(0, fieldIndex), + updatedField, + ...this.props.visParams.fields.slice(fieldIndex + 1) + ]; + this.props.setVisParam('fields', updatedFields); + } + + handleFieldNameChange(fieldIndex, evt) { + const updatedField = this.props.visParams.fields[fieldIndex]; + updatedField.fieldName = evt.value; const updatedFields = [ ...this.props.visParams.fields.slice(0, fieldIndex), updatedField, @@ -39,6 +53,7 @@ export class TermsVisEditor extends Component { addField() { const newField = { indexPattern: '', + fieldName: '', label: '' }; const updatedFields = [ @@ -52,20 +67,6 @@ export class TermsVisEditor extends Component { return this.props.visParams.fields.map((field, index) => { return (
-
-
- -
-
- -
-
-
+ + + +
); }); diff --git a/src/core_plugins/control_visualizations/public/terms_vis/editor_controller.js b/src/core_plugins/control_visualizations/public/terms_vis/editor_controller.js index c046d64e76ca4..91119d1da8135 100644 --- a/src/core_plugins/control_visualizations/public/terms_vis/editor_controller.js +++ b/src/core_plugins/control_visualizations/public/terms_vis/editor_controller.js @@ -11,6 +11,9 @@ module.controller('KbnTermsEditorController', ($scope, indexPatterns) => { }, getIndexPatternIds: () => { return indexPatterns.getIds(); + }, + getIndexPattern: (indexPatternId) => { + return indexPatterns.get(indexPatternId); } }; }); diff --git a/src/core_plugins/control_visualizations/public/terms_vis/vis.js b/src/core_plugins/control_visualizations/public/terms_vis/vis.js index eefbcf5c28157..43229f741f06e 100644 --- a/src/core_plugins/control_visualizations/public/terms_vis/vis.js +++ b/src/core_plugins/control_visualizations/public/terms_vis/vis.js @@ -1,6 +1,7 @@ -import './vis.less'; import './vis_controller'; import './editor_controller'; +import 'react-select/dist/react-select.css'; +import './vis.less'; import { VisVisTypeProvider } from 'ui/vis/vis_type'; import { TemplateVisTypeProvider } from 'ui/template_vis_type/template_vis_type'; import { VisTypesRegistryProvider } from 'ui/registry/vis_types'; @@ -21,10 +22,12 @@ export default function TermsProvider(Private) { editor: require('./editor.html'), defaults: { fields: [{ + indexPattern: '', + fieldName: '', label: '' }] } }, requiresSearch: false }); -} \ No newline at end of file +} From 24f96986c52834deb61f7130b47444da02a6ae74 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Mon, 15 May 2017 11:13:20 -0600 Subject: [PATCH 08/17] move editor state logic to seperate file --- .../terms_vis/components/terms_vis_editor.js | 33 +++---------------- .../public/terms_vis/lib/editor_utils.js | 14 ++++++++ .../public/terms_vis/vis.js | 7 ++-- 3 files changed, 21 insertions(+), 33 deletions(-) create mode 100644 src/core_plugins/control_visualizations/public/terms_vis/lib/editor_utils.js diff --git a/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis_editor.js b/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis_editor.js index 438eaada1f233..ddea960829dea 100644 --- a/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis_editor.js +++ b/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis_editor.js @@ -5,6 +5,7 @@ import { KuiButton, KuiButtonIcon, } from 'ui_framework/components'; +import { addField, newField, setField } from '../lib/editor_utils'; export class TermsVisEditor extends Component { constructor(props) { @@ -19,48 +20,24 @@ export class TermsVisEditor extends Component { handleLabelChange(fieldIndex, evt) { const updatedField = this.props.visParams.fields[fieldIndex]; updatedField.label = evt.target.value; - const updatedFields = [ - ...this.props.visParams.fields.slice(0, fieldIndex), - updatedField, - ...this.props.visParams.fields.slice(fieldIndex + 1) - ]; - this.props.setVisParam('fields', updatedFields); + 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 = ''; - const updatedFields = [ - ...this.props.visParams.fields.slice(0, fieldIndex), - updatedField, - ...this.props.visParams.fields.slice(fieldIndex + 1) - ]; - this.props.setVisParam('fields', updatedFields); + 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; - const updatedFields = [ - ...this.props.visParams.fields.slice(0, fieldIndex), - updatedField, - ...this.props.visParams.fields.slice(fieldIndex + 1) - ]; - this.props.setVisParam('fields', updatedFields); + this.props.setVisParam('fields', setField(this.props.visParams.fields, fieldIndex, updatedField)); } addField() { - const newField = { - indexPattern: '', - fieldName: '', - label: '' - }; - const updatedFields = [ - ...this.props.visParams.fields, - newField - ]; - this.props.setVisParam('fields', updatedFields); + this.props.setVisParam('fields', addField(this.props.visParams.fields, newField())); } renderFields() { diff --git a/src/core_plugins/control_visualizations/public/terms_vis/lib/editor_utils.js b/src/core_plugins/control_visualizations/public/terms_vis/lib/editor_utils.js new file mode 100644 index 0000000000000..f915cf34d9c8d --- /dev/null +++ b/src/core_plugins/control_visualizations/public/terms_vis/lib/editor_utils.js @@ -0,0 +1,14 @@ +export const setField = (fields, fieldIndex, field) => [ + ...fields.slice(0, fieldIndex), + field, + ...fields.slice(fieldIndex + 1) +]; + +export const addField = (fields, field) => [...fields, field]; + +export const newField = () => ({ + indexPattern: '', + fieldName: '', + label: '' +}); + diff --git a/src/core_plugins/control_visualizations/public/terms_vis/vis.js b/src/core_plugins/control_visualizations/public/terms_vis/vis.js index 43229f741f06e..a2eb693bd6d30 100644 --- a/src/core_plugins/control_visualizations/public/terms_vis/vis.js +++ b/src/core_plugins/control_visualizations/public/terms_vis/vis.js @@ -5,6 +5,7 @@ import './vis.less'; import { VisVisTypeProvider } from 'ui/vis/vis_type'; import { TemplateVisTypeProvider } from 'ui/template_vis_type/template_vis_type'; import { VisTypesRegistryProvider } from 'ui/registry/vis_types'; +import { newField } from './lib/editor_utils'; VisTypesRegistryProvider.register(TermsProvider); export default function TermsProvider(Private) { @@ -21,11 +22,7 @@ export default function TermsProvider(Private) { params: { editor: require('./editor.html'), defaults: { - fields: [{ - indexPattern: '', - fieldName: '', - label: '' - }] + fields: [newField()] } }, requiresSearch: false From 6a2ba47a2e5b4c4be5ef42919eba4cc60ebcd043 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Mon, 15 May 2017 11:43:06 -0600 Subject: [PATCH 09/17] remove field button --- .../terms_vis/components/terms_vis_editor.js | 18 ++++++++++++++---- .../public/terms_vis/lib/editor_utils.js | 5 +++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis_editor.js b/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis_editor.js index ddea960829dea..13fe085918425 100644 --- a/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis_editor.js +++ b/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis_editor.js @@ -5,7 +5,7 @@ import { KuiButton, KuiButtonIcon, } from 'ui_framework/components'; -import { addField, newField, setField } from '../lib/editor_utils'; +import { addField, newField, removeField, setField } from '../lib/editor_utils'; export class TermsVisEditor extends Component { constructor(props) { @@ -14,7 +14,8 @@ export class TermsVisEditor extends Component { this.handleFieldNameChange = this.handleFieldNameChange.bind(this); this.handleLabelChange = this.handleLabelChange.bind(this); this.handleIndexPatternChange = this.handleIndexPatternChange.bind(this); - this.addField = this.addField.bind(this); + this.handleRemoveField = this.handleRemoveField.bind(this); + this.handleAddField = this.handleAddField.bind(this); } handleLabelChange(fieldIndex, evt) { @@ -36,7 +37,11 @@ export class TermsVisEditor extends Component { this.props.setVisParam('fields', setField(this.props.visParams.fields, fieldIndex, updatedField)); } - addField() { + handleRemoveField(fieldIndex) { + this.props.setVisParam('fields', removeField(this.props.visParams.fields, fieldIndex)); + } + + handleAddField() { this.props.setVisParam('fields', addField(this.props.visParams.fields, newField())); } @@ -57,6 +62,11 @@ export class TermsVisEditor extends Component { value={field.label} onChange={this.handleLabelChange.bind(null, index)} />
+ } - onClick={this.addField} + onClick={this.handleAddField} > Add diff --git a/src/core_plugins/control_visualizations/public/terms_vis/lib/editor_utils.js b/src/core_plugins/control_visualizations/public/terms_vis/lib/editor_utils.js index f915cf34d9c8d..a33f68c571066 100644 --- a/src/core_plugins/control_visualizations/public/terms_vis/lib/editor_utils.js +++ b/src/core_plugins/control_visualizations/public/terms_vis/lib/editor_utils.js @@ -6,6 +6,11 @@ export const setField = (fields, fieldIndex, field) => [ 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: '', From cddf481b0886a87478903543adf47ebb1201c91b Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Mon, 15 May 2017 15:48:09 -0600 Subject: [PATCH 10/17] msearch terms first take --- .../public/terms_vis/vis_controller.js | 33 ++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/src/core_plugins/control_visualizations/public/terms_vis/vis_controller.js b/src/core_plugins/control_visualizations/public/terms_vis/vis_controller.js index 52bf6a2af60e4..1451b4520543b 100644 --- a/src/core_plugins/control_visualizations/public/terms_vis/vis_controller.js +++ b/src/core_plugins/control_visualizations/public/terms_vis/vis_controller.js @@ -1,17 +1,42 @@ import { uiModules } from 'ui/modules'; import { TermsVis } from './components/terms_vis'; +import { FetchProvider } from 'ui/courier/fetch/fetch'; +import { SearchSourceProvider } from 'ui/courier/data_source/search_source'; const module = uiModules.get('kibana/terms_vis', ['kibana', 'react']); -module.controller('KbnTermsController', function ($scope) { +module.controller('KbnTermsController', function ($scope, indexPatterns, Private, Promise) { + const fetch = Private(FetchProvider); + const SearchSource = Private(SearchSourceProvider); + $scope.reactProps = { visParams: $scope.vis.params }; $scope.$watch('vis.params', function (visParams, oldParams) { - if (visParams !== oldParams) { - $scope.reactProps.visParams = visParams; + if (visParams === oldParams) { + return; } + + $scope.reactProps.visParams = visParams; + + const createRequestPromises = $scope.vis.params.fields.map(async (field) => { + const indexPattern = await indexPatterns.get(field.indexPattern); + const searchSource = new SearchSource(); + searchSource.inherits(false); //Do not filter by time so can not inherit from rootSearchSource + searchSource.size(0); + searchSource.index(indexPattern); + + const defer = Promise.defer(); + defer.promise.then(function (resp) { + console.log('resp', resp); + }); + + return searchSource._createRequest(defer); + }); + Promise.all(createRequestPromises).then(requests => { + fetch.these(requests); + }); }); }); -module.value('TermsVis', TermsVis); \ No newline at end of file +module.value('TermsVis', TermsVis); From 4a538565554d2b07967a6a3b22fb9f8935158f13 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Tue, 16 May 2017 09:03:20 -0600 Subject: [PATCH 11/17] add terms agg to request --- .../terms_vis/components/field_select.js | 2 +- .../public/terms_vis/vis_controller.js | 25 +++++++++++++------ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/core_plugins/control_visualizations/public/terms_vis/components/field_select.js b/src/core_plugins/control_visualizations/public/terms_vis/components/field_select.js index 7f01659cfc609..ad2720bb25140 100644 --- a/src/core_plugins/control_visualizations/public/terms_vis/components/field_select.js +++ b/src/core_plugins/control_visualizations/public/terms_vis/components/field_select.js @@ -16,7 +16,7 @@ export class FieldSelect extends Component { this.props.getIndexPattern(this.props.indexPatternId).then(index => { const fields = index.fields.filter(function (field) { - return field.type === 'string'; + return field.aggregatable && field.type === 'string'; }).sort((a, b) => { if (a.name < b.name) return -1; if (a.name > b.name) return 1; diff --git a/src/core_plugins/control_visualizations/public/terms_vis/vis_controller.js b/src/core_plugins/control_visualizations/public/terms_vis/vis_controller.js index 1451b4520543b..bb6b027bc4a12 100644 --- a/src/core_plugins/control_visualizations/public/terms_vis/vis_controller.js +++ b/src/core_plugins/control_visualizations/public/terms_vis/vis_controller.js @@ -8,15 +8,23 @@ module.controller('KbnTermsController', function ($scope, indexPatterns, Private const fetch = Private(FetchProvider); const SearchSource = Private(SearchSourceProvider); + const termsAgg = (fieldName, size, direction) => ({ + 'termsAgg': { + 'terms': { + 'field': fieldName, + 'size': size, + 'order': { + '_count': direction + } + } + } + }); + $scope.reactProps = { visParams: $scope.vis.params }; - $scope.$watch('vis.params', function (visParams, oldParams) { - if (visParams === oldParams) { - return; - } - + $scope.$watch('vis.params', function (visParams) { $scope.reactProps.visParams = visParams; const createRequestPromises = $scope.vis.params.fields.map(async (field) => { @@ -25,12 +33,15 @@ module.controller('KbnTermsController', function ($scope, indexPatterns, Private searchSource.inherits(false); //Do not filter by time so can not inherit from rootSearchSource searchSource.size(0); searchSource.index(indexPattern); + searchSource.aggs(termsAgg(field.fieldName, 5, 'desc')); const defer = Promise.defer(); defer.promise.then(function (resp) { - console.log('resp', resp); + const terms = resp.aggregations.termsAgg.buckets.map((bucket) => { + return bucket.key; + }); + console.log('terms', terms); }); - return searchSource._createRequest(defer); }); Promise.all(createRequestPromises).then(requests => { From 8b5ed899e28483cb7593a354f114f0d4ec9fe29e Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Tue, 16 May 2017 13:21:13 -0600 Subject: [PATCH 12/17] build phrase filter when control changes --- .../public/terms_vis/components/terms_vis.js | 22 ++++++++-- .../public/terms_vis/vis_controller.js | 43 ++++++++++++++++--- 2 files changed, 55 insertions(+), 10 deletions(-) diff --git a/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis.js b/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis.js index d14923f841fb1..2ac1d63ed01a7 100644 --- a/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis.js +++ b/src/core_plugins/control_visualizations/public/terms_vis/components/terms_vis.js @@ -1,14 +1,28 @@ 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) { + this.props.setFilter(control.field, evt.value, control.indexPattern); + } + render() { return (
- {this.props.visParams.fields.map((field, index) => + {this.props.controls.map((control, index) =>
-

{field.label}

-
{field.indexPattern}
-
{field.fieldName}
+ {control.label} + { return ( -
+