-
Notifications
You must be signed in to change notification settings - Fork 8.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ingest UI Pattern Review Screen #5892
Changes from 15 commits
7dbef2f
d4aff77
27e402b
e5ff5ce
027e807
da6183c
5fcb4cb
a47fc05
3bad81d
9e4362b
4df54be
b94631b
d13a6ca
7ae9d3a
3f02157
41e7303
3d94e1a
d769ebf
11fe9aa
caa7a0f
6dd73b3
00ff3d7
0111071
bd45e77
ac0974b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,28 @@ | ||
<h2>Pattern review step</h2> | ||
<div class="wizard-step-title"> | ||
<h3>Review the index pattern</h3> | ||
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 iw we got it wrong! | ||
</div> | ||
|
||
<div> | ||
Docs: {{sampleDocs}} | ||
<div class="pattern-review"> | ||
<input ng-model="indexPattern.id" class="pattern-input"/> | ||
<label> | ||
<input ng-model="isTimeBased" type="checkbox"/> | ||
time based | ||
</label> | ||
<label ng-if="isTimeBased" class="time-field-input"> | ||
Time Field | ||
<select ng-model="indexPattern.timeFieldName" name="time_field_name"> | ||
<option ng-repeat="field in dateFields" value="{{field}}"> | ||
{{field}} | ||
</option> | ||
</select> | ||
</label> | ||
</div> | ||
|
||
<button ng-click="indexPattern = {id: 'logstash-*', title: 'myFirstIndexPattern'}">Create an index pattern</button> | ||
<div> | ||
<paginated-table | ||
columns="columns" | ||
rows="rows"> | ||
</paginated-table> | ||
</div> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,70 @@ | ||
var modules = require('ui/modules'); | ||
var template = require('plugins/kibana/settings/sections/indices/directives/pattern_review_step.html'); | ||
var _ = require('lodash'); | ||
var editFieldTypeHTML = require('plugins/kibana/settings/sections/indices/partials/_edit_field_type.html'); | ||
|
||
var 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] | ||
}; | ||
|
||
var 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; | ||
} | ||
|
||
let fieldName = dateFields[0]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Might be cleaner to do const fieldname = _.includes(dateFields, '@timestamp') ? '@timestamp' : dateFields[0]; ? |
||
if (_.includes(dateFields, '@timestamp')) { | ||
fieldName = '@timestamp'; | ||
} | ||
|
||
return fieldName; | ||
} | ||
|
||
modules.get('apps/settings') | ||
.directive('patternReviewStep', function () { | ||
|
@@ -9,6 +74,76 @@ modules.get('apps/settings') | |
sampleDocs: '=', | ||
indexPattern: '=', | ||
pipeline: '=' | ||
}, | ||
controller: function ($scope, Private) { | ||
$scope.sampleDocs = testData; | ||
$scope.pipeline = testPipeline; | ||
|
||
if (_.isUndefined($scope.indexPattern)) { | ||
$scope.indexPattern = {}; | ||
} | ||
|
||
const knownFieldTypes = {}; | ||
$scope.dateFields = []; | ||
$scope.pipeline.forEach(function (processor) { | ||
if (processor.geoip) { | ||
let field = processor.geoip.target_field || 'geoip'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of declaring the variable let field;
$scope.pipeline.forEach(function (processor) {
if (processor.geoip) {
field = ...
}
if (processor.date) {
field = ...
}
}); |
||
knownFieldTypes[field] = 'geo_point'; | ||
} | ||
if (processor.date) { | ||
let field = processor.date.target_field || '@timestamp'; | ||
knownFieldTypes[field] = 'date'; | ||
$scope.dateFields.push(field); | ||
} | ||
}); | ||
|
||
_.defaults($scope.indexPattern, { | ||
id: 'filebeat-*', | ||
title: 'filebeat-*', | ||
timeFieldName: pickDefaultTimeFieldName($scope.dateFields), | ||
fields: _.map($scope.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}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does the team use ES6 shorthand? return {type, name: key}; |
||
}) | ||
}); | ||
|
||
$scope.isTimeBased = !!$scope.indexPattern.timeFieldName; | ||
|
||
$scope.$watch('indexPattern.id', function (value) { | ||
$scope.indexPattern.title = value; | ||
}); | ||
$scope.$watch('isTimeBased', function (value) { | ||
if (value) { | ||
$scope.indexPattern.timeFieldName = pickDefaultTimeFieldName($scope.dateFields); | ||
} | ||
else { | ||
delete $scope.indexPattern.timeFieldName; | ||
} | ||
}); | ||
$scope.$watch('indexPattern.fields', (fields) => { | ||
$scope.dateFields = _.map(_.filter(fields, {type: 'date'}), 'name'); | ||
}, true); | ||
|
||
$scope.columns = [ | ||
{title: 'Field'}, | ||
{title: 'Type'}, | ||
{title: 'Example', sortable: false} | ||
]; | ||
|
||
$scope.rows = _.map($scope.indexPattern.fields, (field) => { | ||
const sampleValue = $scope.sampleDocs[field.name]; | ||
return [ | ||
field.name, | ||
{ | ||
markup: editFieldTypeHTML, | ||
scope: _.assign($scope.$new(), {field: field, knownFieldTypes: knownFieldTypes}) | ||
}, | ||
typeof sampleValue === 'object' ? JSON.stringify(sampleValue) : sampleValue | ||
]; | ||
}); | ||
} | ||
}; | ||
}); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<select ng-if="knownFieldTypes[field.name] !== 'geo_point'" name="field_type" ng-model="field.type"> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. could geo_point be a string? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not 100% sure I understand the question, are you asking if a geo_point field could be of type string in the elasticsearch mappings? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, or on the flip side I see I can convert bytes to geo_point for example. How are the rules defined for which options are available? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So the geoip processor is a special case, because its target field must be classified as a geo_point type in the index template and index pattern. That's why I'm doing a special check here for any geoip processors and then preventing any changes to that target field's type. Other than that, the user can change anything they want. For instance, they might have lat/lon coordinates in their data which they could create their own geo_point field out of without using the geoip processor. In that case they'd need to manually update the type of that field to geo_point. |
||
<option value="string">string</option> | ||
<option value="number">number</option> | ||
<option value="boolean">boolean</option> | ||
<option value="date">date</option> | ||
<option value="geo_point">geo_point</option> | ||
<option value="geo_shape">geo_shape</option> | ||
<option value="ip">ip</option> | ||
</select> | ||
|
||
<span ng-if="knownFieldTypes[field.name] === 'geo_point'"> | ||
geo_point | ||
</span> |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -204,3 +204,18 @@ kbn-settings-indices { | |
} | ||
} | ||
} | ||
|
||
.wizard-step-title { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not worried about this yet, but eventually it may make these styles easier to edit if they're split into their own file There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, these will probably get moved out when I try to do some refactoring when creating additional wizards. |
||
padding-bottom: 1em; | ||
} | ||
|
||
.pattern-review { | ||
.time-field-input { | ||
padding-left: 1em; | ||
} | ||
|
||
.pattern-input { | ||
width: 300px; | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
iw we got it wrong
-->if we got it wrong
?