diff --git a/src/plugins/kibana/public/settings/sections/indices/add_data_steps/pattern_review_step.html b/src/plugins/kibana/public/settings/sections/indices/add_data_steps/pattern_review_step.html index 25b713bd7fd30e..5a8735d7b3ea80 100644 --- a/src/plugins/kibana/public/settings/sections/indices/add_data_steps/pattern_review_step.html +++ b/src/plugins/kibana/public/settings/sections/indices/add_data_steps/pattern_review_step.html @@ -1,7 +1,32 @@ -

Pattern review step

+
+

Review the index pattern

+ Here we'll define how and where to store your parsed events. We've made some intellient guesses for you, but most + fields can be changed if we got it wrong! +
-
- Docs: {{sampleDocs}} +
+
+ + +
+ + +
- +
+ + +
diff --git a/src/plugins/kibana/public/settings/sections/indices/add_data_steps/pattern_review_step.js b/src/plugins/kibana/public/settings/sections/indices/add_data_steps/pattern_review_step.js index 240e97a036a5ea..be7a220636edf4 100644 --- a/src/plugins/kibana/public/settings/sections/indices/add_data_steps/pattern_review_step.js +++ b/src/plugins/kibana/public/settings/sections/indices/add_data_steps/pattern_review_step.js @@ -1,5 +1,65 @@ -var modules = require('ui/modules'); -var template = require('plugins/kibana/settings/sections/indices/add_data_steps/pattern_review_step.html'); +const modules = require('ui/modules'); +const template = require('plugins/kibana/settings/sections/indices/add_data_steps/pattern_review_step.html'); +const _ = require('lodash'); +const editFieldTypeHTML = require('plugins/kibana/settings/sections/indices/partials/_edit_field_type.html'); + +const testData = { + message: '11/24/2015 ip=1.1.1.1 bytes=1234', + clientip: '1.1.1.1', + bytes: 1234, + geoip: { + lat: 37.3894, + lon: 122.0819 + }, + location: { + lat: 37.3894, + lon: 122.0819 + }, + '@timestamp': '2015-11-24T00:00:00.000Z', + otherdate: '2015-11-24T00:00:00.000Z', + codes: [1, 2, 3, 4] +}; + +const testPipeline = [ + { + grok: { + match_field: 'message', + match_pattern: 'foo' + } + }, + { + geoip: { + source_field: 'ip' + } + }, + { + geoip: { + source_field: 'ip', + target_field: 'location' + } + }, + { + date: { + match_field: 'initialDate', + match_formats: ['dd/MM/yyyy hh:mm:ss'] + } + }, + { + date: { + match_field: 'initialDate', + match_formats: ['dd/MM/yyyy hh:mm:ss'], + target_field: 'otherdate' + } + } +]; + +function pickDefaultTimeFieldName(dateFields) { + if (_.isEmpty(dateFields)) { + return undefined; + } + + return _.includes(dateFields, '@timestamp') ? '@timestamp' : dateFields[0]; +} modules.get('apps/settings') .directive('patternReviewStep', function () { @@ -9,6 +69,83 @@ modules.get('apps/settings') sampleDocs: '=', indexPattern: '=', pipeline: '=' + }, + controllerAs: 'reviewStep', + bindToController: true, + controller: function ($scope, Private) { + this.sampleDocs = testData; + this.pipeline = testPipeline; + + if (_.isUndefined(this.indexPattern)) { + this.indexPattern = {}; + } + + const knownFieldTypes = {}; + this.dateFields = []; + this.pipeline.forEach((processor) => { + if (processor.geoip) { + const field = processor.geoip.target_field || 'geoip'; + knownFieldTypes[field] = 'geo_point'; + } + else if (processor.date) { + const field = processor.date.target_field || '@timestamp'; + knownFieldTypes[field] = 'date'; + this.dateFields.push(field); + } + }); + + _.defaults(this.indexPattern, { + id: 'filebeat-*', + title: 'filebeat-*', + timeFieldName: pickDefaultTimeFieldName(this.dateFields), + fields: _.map(this.sampleDocs, (value, key) => { + let type = knownFieldTypes[key] || typeof value; + if (type === 'object' && _.isArray(value) && !_.isEmpty(value)) { + type = typeof value[0]; + } + return {name: key, type: type}; + }) + }); + + this.isTimeBased = !!this.indexPattern.timeFieldName; + + $scope.$watch('reviewStep.indexPattern.id', (value) => { + this.indexPattern.title = value; + }); + $scope.$watch('reviewStep.isTimeBased', (value) => { + if (value) { + this.indexPattern.timeFieldName = pickDefaultTimeFieldName(this.dateFields); + } + else { + delete this.indexPattern.timeFieldName; + } + }); + $scope.$watch('reviewStep.indexPattern.fields', (fields) => { + this.dateFields = _.map(_.filter(fields, {type: 'date'}), 'name'); + }, true); + + const buildRows = () => { + this.rows = _.map(this.indexPattern.fields, (field) => { + const sampleValue = this.sampleDocs[field.name]; + return [ + _.escape(field.name), + { + markup: editFieldTypeHTML, + scope: _.assign($scope.$new(), {field: field, knownFieldTypes: knownFieldTypes, buildRows: buildRows}), + value: field.type + }, + typeof sampleValue === 'object' ? _.escape(JSON.stringify(sampleValue)) : _.escape(sampleValue) + ]; + }); + }; + + this.columns = [ + {title: 'Field'}, + {title: 'Type'}, + {title: 'Example', sortable: false} + ]; + + buildRows(); } }; }); diff --git a/src/plugins/kibana/public/settings/sections/indices/filebeat/directives/filebeat_wizard.html b/src/plugins/kibana/public/settings/sections/indices/filebeat/directives/filebeat_wizard.html index 094cbeecdfe6a4..7fc03086509c51 100644 --- a/src/plugins/kibana/public/settings/sections/indices/filebeat/directives/filebeat_wizard.html +++ b/src/plugins/kibana/public/settings/sections/indices/filebeat/directives/filebeat_wizard.html @@ -59,7 +59,10 @@

Tail a File

diff --git a/src/plugins/kibana/public/settings/sections/indices/partials/_edit_field_type.html b/src/plugins/kibana/public/settings/sections/indices/partials/_edit_field_type.html new file mode 100644 index 00000000000000..b80ded8219f116 --- /dev/null +++ b/src/plugins/kibana/public/settings/sections/indices/partials/_edit_field_type.html @@ -0,0 +1,13 @@ + + + + geo_point + diff --git a/src/plugins/kibana/public/settings/styles/main.less b/src/plugins/kibana/public/settings/styles/main.less index 451f492c9ac1dc..7cf4bbc16a0b06 100644 --- a/src/plugins/kibana/public/settings/styles/main.less +++ b/src/plugins/kibana/public/settings/styles/main.less @@ -216,9 +216,21 @@ kbn-settings-indices { padding-bottom: 1em; } +.pattern-review { + .time-field-input { + padding-left: 1em; + margin-bottom: 0; + } + + .pattern-input { + width: 300px; + } +} + .paste-samples { textarea { width: 100%; height: 250px; } } +