From 9083930947704bb1eac2d62b8f2e9763bf6bc941 Mon Sep 17 00:00:00 2001 From: Matthew Bargar Date: Wed, 9 Mar 2016 18:13:54 -0500 Subject: [PATCH 1/6] Implements a pattern checker directive for use in the Add Data UI --- src/plugins/elasticsearch/index.js | 1 + .../add_data_steps/install_filebeat_step.html | 2 + .../add_data_steps/install_filebeat_step.js | 1 + .../kibana/public/settings/styles/main.less | 7 ++- .../pattern_checker/pattern_checker.html | 5 ++ .../public/pattern_checker/pattern_checker.js | 56 +++++++++++++++++++ .../pattern_checker/pattern_checker.less | 3 + 7 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 src/ui/public/pattern_checker/pattern_checker.html create mode 100644 src/ui/public/pattern_checker/pattern_checker.js create mode 100644 src/ui/public/pattern_checker/pattern_checker.less diff --git a/src/plugins/elasticsearch/index.js b/src/plugins/elasticsearch/index.js index c60f56f88b6df..da18eddf5349b 100644 --- a/src/plugins/elasticsearch/index.js +++ b/src/plugins/elasticsearch/index.js @@ -54,6 +54,7 @@ module.exports = function ({ Plugin }) { createProxy(server, 'POST', '/{index}/_field_stats'); createProxy(server, 'POST', '/_msearch'); createProxy(server, 'POST', '/_search/scroll'); + createProxy(server, 'POST', '/{index}/_count'); function noBulkCheck({ path }, reply) { if (/\/_bulk/.test(path)) { diff --git a/src/plugins/kibana/public/settings/sections/indices/add_data_steps/install_filebeat_step.html b/src/plugins/kibana/public/settings/sections/indices/add_data_steps/install_filebeat_step.html index cd1d483adc849..99b807009bfa7 100644 --- a/src/plugins/kibana/public/settings/sections/indices/add_data_steps/install_filebeat_step.html +++ b/src/plugins/kibana/public/settings/sections/indices/add_data_steps/install_filebeat_step.html @@ -44,4 +44,6 @@

Follow these instructions to install Filebeat

) + + diff --git a/src/plugins/kibana/public/settings/sections/indices/add_data_steps/install_filebeat_step.js b/src/plugins/kibana/public/settings/sections/indices/add_data_steps/install_filebeat_step.js index b6f4c3664a220..88282f7469d10 100644 --- a/src/plugins/kibana/public/settings/sections/indices/add_data_steps/install_filebeat_step.js +++ b/src/plugins/kibana/public/settings/sections/indices/add_data_steps/install_filebeat_step.js @@ -1,5 +1,6 @@ import modules from 'ui/modules'; import template from 'plugins/kibana/settings/sections/indices/add_data_steps/install_filebeat_step.html'; +import 'ui/pattern_checker'; import { patternToIngest } from '../../../../../common/lib/convert_pattern_and_ingest_name'; modules.get('apps/settings') diff --git a/src/plugins/kibana/public/settings/styles/main.less b/src/plugins/kibana/public/settings/styles/main.less index 3bd4e4208b698..5e7a47025d565 100644 --- a/src/plugins/kibana/public/settings/styles/main.less +++ b/src/plugins/kibana/public/settings/styles/main.less @@ -191,6 +191,12 @@ kbn-settings-indices { .time-and-pattern > div {} } +filebeat-wizard { + .nav-buttons { + float: right; + } +} + .wizard-step-headings{ margin-top: 1em; @@ -237,4 +243,3 @@ kbn-settings-indices { height: 250px; } } - diff --git a/src/ui/public/pattern_checker/pattern_checker.html b/src/ui/public/pattern_checker/pattern_checker.html new file mode 100644 index 0000000000000..ffd71b0c49d66 --- /dev/null +++ b/src/ui/public/pattern_checker/pattern_checker.html @@ -0,0 +1,5 @@ +
+ + + {{checker.validationResults}} +
diff --git a/src/ui/public/pattern_checker/pattern_checker.js b/src/ui/public/pattern_checker/pattern_checker.js new file mode 100644 index 0000000000000..b18cb5ce6a10e --- /dev/null +++ b/src/ui/public/pattern_checker/pattern_checker.js @@ -0,0 +1,56 @@ +import uiModules from 'ui/modules'; +import template from './pattern_checker.html'; +import './pattern_checker.less'; + +const module = uiModules.get('kibana'); + +module.directive('patternChecker', function () { + return { + restrict: 'E', + template: template, + controllerAs: 'checker', + bindToController: true, + scope: { + pattern: '=', + buttonLabel: '=' + }, + controller: function (es, Notifier, $scope, $timeout) { + let validationTimeout; + this.isValidating = false; + + var notify = new Notifier({ + location: 'Add Data' + }); + + this.toggleValidation = () => { + if (!this.isValidating) { + this.isValidating = true; + this.validateInstall(); + } + else { + $timeout.cancel(validationTimeout); + this.isValidating = false; + this.validationResults = ''; + } + }; + + this.validateInstall = () => { + es.count({ + index: this.pattern + }) + .then( + (response) => { + this.validationResults = `Querying ${this.pattern}... ${response.count} results`; + }, + (error) => { + notify.fatal(error); + } + ) + .then(() => { + validationTimeout = $timeout(this.validateInstall, 5000); + }); + }; + } + }; +}); + diff --git a/src/ui/public/pattern_checker/pattern_checker.less b/src/ui/public/pattern_checker/pattern_checker.less new file mode 100644 index 0000000000000..a7037ee5cf17b --- /dev/null +++ b/src/ui/public/pattern_checker/pattern_checker.less @@ -0,0 +1,3 @@ +pattern-checker .spinner { + padding: 0 1em; +} From 43e7eb0ce2261e766006c970c38b1398f55baadb Mon Sep 17 00:00:00 2001 From: Matthew Bargar Date: Mon, 14 Mar 2016 13:17:29 -0400 Subject: [PATCH 2/6] Cancel timeout on scope --- src/ui/public/pattern_checker/pattern_checker.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ui/public/pattern_checker/pattern_checker.js b/src/ui/public/pattern_checker/pattern_checker.js index b18cb5ce6a10e..f97664b557040 100644 --- a/src/ui/public/pattern_checker/pattern_checker.js +++ b/src/ui/public/pattern_checker/pattern_checker.js @@ -50,6 +50,10 @@ module.directive('patternChecker', function () { validationTimeout = $timeout(this.validateInstall, 5000); }); }; + + $scope.$on('$destroy', () => { + $timeout.cancel(validationTimeout); + }); } }; }); From 7931f1ac35629251952baef8d4f0e11b20f73920 Mon Sep 17 00:00:00 2001 From: Matthew Bargar Date: Mon, 14 Mar 2016 13:52:09 -0400 Subject: [PATCH 3/6] Remove user control of pattern polling and add some explanation to the filebeat installation instructions --- .../add_data_steps/install_filebeat_step.html | 9 ++++++--- .../kibana/public/settings/styles/main.less | 4 ++++ .../public/pattern_checker/pattern_checker.html | 7 ++----- src/ui/public/pattern_checker/pattern_checker.js | 16 +++------------- 4 files changed, 15 insertions(+), 21 deletions(-) diff --git a/src/plugins/kibana/public/settings/sections/indices/add_data_steps/install_filebeat_step.html b/src/plugins/kibana/public/settings/sections/indices/add_data_steps/install_filebeat_step.html index 99b807009bfa7..6b7fd16b89b15 100644 --- a/src/plugins/kibana/public/settings/sections/indices/add_data_steps/install_filebeat_step.html +++ b/src/plugins/kibana/public/settings/sections/indices/add_data_steps/install_filebeat_step.html @@ -3,7 +3,7 @@

Follow these instructions to install Filebeat

Now that you've got a fresh pipeline and index pattern, let's throw some data at it! -
+
  1. Install Filebeat on all servers on which you want to tail logs ( @@ -43,7 +43,10 @@

    Follow these instructions to install Filebeat

    instructions
    )
  2. +
  3. Verify your filebeat installation below. We'll poll your new index pattern for documents and let you know when + they show up. If you'd like to skip this step, simply click Done now. +
- -
+ + diff --git a/src/plugins/kibana/public/settings/styles/main.less b/src/plugins/kibana/public/settings/styles/main.less index 5e7a47025d565..29622353a87d0 100644 --- a/src/plugins/kibana/public/settings/styles/main.less +++ b/src/plugins/kibana/public/settings/styles/main.less @@ -243,3 +243,7 @@ filebeat-wizard { height: 250px; } } + +.install-filebeat { + padding-bottom: 1em; +} diff --git a/src/ui/public/pattern_checker/pattern_checker.html b/src/ui/public/pattern_checker/pattern_checker.html index ffd71b0c49d66..0bc586cde8aa2 100644 --- a/src/ui/public/pattern_checker/pattern_checker.html +++ b/src/ui/public/pattern_checker/pattern_checker.html @@ -1,5 +1,2 @@ -
- - - {{checker.validationResults}} -
+ +{{checker.validationResults}} diff --git a/src/ui/public/pattern_checker/pattern_checker.js b/src/ui/public/pattern_checker/pattern_checker.js index f97664b557040..23db84e756b53 100644 --- a/src/ui/public/pattern_checker/pattern_checker.js +++ b/src/ui/public/pattern_checker/pattern_checker.js @@ -16,24 +16,11 @@ module.directive('patternChecker', function () { }, controller: function (es, Notifier, $scope, $timeout) { let validationTimeout; - this.isValidating = false; var notify = new Notifier({ location: 'Add Data' }); - this.toggleValidation = () => { - if (!this.isValidating) { - this.isValidating = true; - this.validateInstall(); - } - else { - $timeout.cancel(validationTimeout); - this.isValidating = false; - this.validationResults = ''; - } - }; - this.validateInstall = () => { es.count({ index: this.pattern @@ -41,6 +28,7 @@ module.directive('patternChecker', function () { .then( (response) => { this.validationResults = `Querying ${this.pattern}... ${response.count} results`; + this.isValidated = !!response.count; }, (error) => { notify.fatal(error); @@ -54,6 +42,8 @@ module.directive('patternChecker', function () { $scope.$on('$destroy', () => { $timeout.cancel(validationTimeout); }); + + this.validateInstall(); } }; }); From c450934d8f4a24006c2903408ad2ab66ae235692 Mon Sep 17 00:00:00 2001 From: Matthew Bargar Date: Wed, 16 Mar 2016 17:19:50 -0400 Subject: [PATCH 4/6] Use the new count API in place of the elasticsearch proxy --- src/plugins/elasticsearch/index.js | 1 - .../add_data_steps/install_filebeat_step.html | 2 +- .../pattern_checker/pattern_checker.html | 2 +- .../public/pattern_checker/pattern_checker.js | 19 +++++++++++-------- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/plugins/elasticsearch/index.js b/src/plugins/elasticsearch/index.js index da18eddf5349b..c60f56f88b6df 100644 --- a/src/plugins/elasticsearch/index.js +++ b/src/plugins/elasticsearch/index.js @@ -54,7 +54,6 @@ module.exports = function ({ Plugin }) { createProxy(server, 'POST', '/{index}/_field_stats'); createProxy(server, 'POST', '/_msearch'); createProxy(server, 'POST', '/_search/scroll'); - createProxy(server, 'POST', '/{index}/_count'); function noBulkCheck({ path }, reply) { if (/\/_bulk/.test(path)) { diff --git a/src/plugins/kibana/public/settings/sections/indices/add_data_steps/install_filebeat_step.html b/src/plugins/kibana/public/settings/sections/indices/add_data_steps/install_filebeat_step.html index 6b7fd16b89b15..0fdf818251d5f 100644 --- a/src/plugins/kibana/public/settings/sections/indices/add_data_steps/install_filebeat_step.html +++ b/src/plugins/kibana/public/settings/sections/indices/add_data_steps/install_filebeat_step.html @@ -49,4 +49,4 @@

Follow these instructions to install Filebeat

- + diff --git a/src/ui/public/pattern_checker/pattern_checker.html b/src/ui/public/pattern_checker/pattern_checker.html index 0bc586cde8aa2..ba9d627f62c1d 100644 --- a/src/ui/public/pattern_checker/pattern_checker.html +++ b/src/ui/public/pattern_checker/pattern_checker.html @@ -1,2 +1,2 @@ -{{checker.validationResults}} +Querying {{checker.pattern}}... {{checker.resultCount}} results diff --git a/src/ui/public/pattern_checker/pattern_checker.js b/src/ui/public/pattern_checker/pattern_checker.js index 23db84e756b53..39a0d06a15e78 100644 --- a/src/ui/public/pattern_checker/pattern_checker.js +++ b/src/ui/public/pattern_checker/pattern_checker.js @@ -1,6 +1,7 @@ import uiModules from 'ui/modules'; import template from './pattern_checker.html'; import './pattern_checker.less'; +import chrome from 'ui/chrome'; const module = uiModules.get('kibana'); @@ -11,10 +12,9 @@ module.directive('patternChecker', function () { controllerAs: 'checker', bindToController: true, scope: { - pattern: '=', - buttonLabel: '=' + pattern: '=' }, - controller: function (es, Notifier, $scope, $timeout) { + controller: function (Notifier, $scope, $timeout, $http) { let validationTimeout; var notify = new Notifier({ @@ -22,16 +22,19 @@ module.directive('patternChecker', function () { }); this.validateInstall = () => { - es.count({ - index: this.pattern - }) + $http.post(chrome.addBasePath(`/api/kibana/${this.pattern}/_count`)) .then( (response) => { - this.validationResults = `Querying ${this.pattern}... ${response.count} results`; + this.resultCount = response.count; this.isValidated = !!response.count; }, (error) => { - notify.fatal(error); + if (error.status === 404) { + this.resultCount = 0; + } + else { + notify.fatal(error); + } } ) .then(() => { From f83c4fdbffea1517561f0690a94277accdae6970 Mon Sep 17 00:00:00 2001 From: Matthew Bargar Date: Fri, 18 Mar 2016 16:52:42 -0400 Subject: [PATCH 5/6] Fix incorrect property access --- src/ui/public/pattern_checker/pattern_checker.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/public/pattern_checker/pattern_checker.js b/src/ui/public/pattern_checker/pattern_checker.js index 39a0d06a15e78..d9e81db6f3167 100644 --- a/src/ui/public/pattern_checker/pattern_checker.js +++ b/src/ui/public/pattern_checker/pattern_checker.js @@ -25,8 +25,8 @@ module.directive('patternChecker', function () { $http.post(chrome.addBasePath(`/api/kibana/${this.pattern}/_count`)) .then( (response) => { - this.resultCount = response.count; - this.isValidated = !!response.count; + this.resultCount = response.data.count; + this.isValidated = !!response.data.count; }, (error) => { if (error.status === 404) { From 615560f0db5ee18dfec4c4ff7c1b09b3ceb13e03 Mon Sep 17 00:00:00 2001 From: Matthew Bargar Date: Mon, 21 Mar 2016 13:36:15 -0400 Subject: [PATCH 6/6] Added tests for patternChecker directive --- .../__tests__/pattern_checker.js | 95 +++++++++++++++++++ .../public/pattern_checker/pattern_checker.js | 1 - 2 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 src/ui/public/pattern_checker/__tests__/pattern_checker.js diff --git a/src/ui/public/pattern_checker/__tests__/pattern_checker.js b/src/ui/public/pattern_checker/__tests__/pattern_checker.js new file mode 100644 index 0000000000000..0432c623cb6f8 --- /dev/null +++ b/src/ui/public/pattern_checker/__tests__/pattern_checker.js @@ -0,0 +1,95 @@ +import ngMock from 'ng_mock'; +import expect from 'expect.js'; +import _ from 'lodash'; +import sinon from 'auto-release-sinon'; + +describe('pattern checker', function () { + let $httpBackend; + let $compile; + let $rootScope; + let apiResponse; + let $timeout; + const notifyFatalStub = sinon.stub(); + + beforeEach(ngMock.module('kibana')); + + beforeEach(ngMock.module(function ($provide) { + notifyFatalStub.reset(); + + $provide.value('Notifier', function () { + this.fatal = notifyFatalStub; + }); + })); + + beforeEach(ngMock.inject(function ($injector, Private) { + $httpBackend = $injector.get('$httpBackend'); + $compile = $injector.get('$compile'); + $rootScope = $injector.get('$rootScope'); + $timeout = $injector.get('$timeout'); + + apiResponse = $httpBackend.when('POST', /\/api\/kibana\/.*\/_count/); + })); + + it('should display the number of documents in a given index pattern', function () { + apiResponse.respond(200, {count: 1}); + + const element = $compile('')($rootScope); + + $httpBackend.flush(); + $rootScope.$digest(); + expect(_.contains(element.html(), `1 results`)).to.be.ok(); + }); + + it('should poll the api for changes to the document count and update the ui', function () { + apiResponse.respond(200, {count: 1}); + + const element = $compile('')($rootScope); + + $httpBackend.flush(); + $rootScope.$digest(); + expect(_.contains(element.html(), `1 results`)).to.be.ok(); + + apiResponse.respond(200, {count: 2}); + $timeout.flush(); + $httpBackend.flush(); + $rootScope.$digest(); + expect(_.contains(element.html(), `2 results`)).to.be.ok(); + }); + + it('should display 0 results when API responds with 404', function () { + apiResponse.respond(404); + + const element = $compile('')($rootScope); + + $httpBackend.flush(); + $rootScope.$digest(); + expect(_.contains(element.html(), `0 results`)).to.be.ok(); + }); + + it('should throw a fatal notificaiton for any error other than a 404', function () { + apiResponse.respond(500, 'Bad things happened'); + + const element = $compile('')($rootScope); + + $httpBackend.flush(); + $rootScope.$digest(); + + expect(notifyFatalStub.called).to.be.ok(); + }); + + it('should stop polling when the scope is destroyed', function () { + apiResponse.respond(200, {count: 1}); + + const element = $compile('')($rootScope); + const scope = element.scope(); + + $httpBackend.flush(); + $rootScope.$digest(); + expect(_.contains(element.html(), `1 results`)).to.be.ok(); + + scope.$destroy(); + $timeout.flush(); + $httpBackend.verifyNoOutstandingRequest(); + }); + +}); diff --git a/src/ui/public/pattern_checker/pattern_checker.js b/src/ui/public/pattern_checker/pattern_checker.js index d9e81db6f3167..5ac8834d8a8e8 100644 --- a/src/ui/public/pattern_checker/pattern_checker.js +++ b/src/ui/public/pattern_checker/pattern_checker.js @@ -26,7 +26,6 @@ module.directive('patternChecker', function () { .then( (response) => { this.resultCount = response.data.count; - this.isValidated = !!response.data.count; }, (error) => { if (error.status === 404) {