Merge branch 'feature/ingest' into ingest/pipelineIngestAPI

This commit is contained in:
Matthew Bargar 2016-02-04 20:25:39 -05:00
commit 0e707fe72d
50 changed files with 698 additions and 126 deletions

View file

@ -60,11 +60,11 @@ define(function (require) {
}; };
$scope.toggleDisplay = function (field) { $scope.toggleDisplay = function (field) {
// inheritted param to fieldChooser // This is inherited from fieldChooser
$scope.toggle(field.name); $scope.toggle(field.name);
if (field.display) $scope.increaseFieldCounter(field); if (field.display) $scope.increaseFieldCounter(field);
// we are now displaying the field, kill it's details // we are now displaying the field, kill its details
if (field.details) { if (field.details) {
$scope.toggleDetails(field); $scope.toggleDetails(field);
} }

View file

@ -16,7 +16,7 @@
<!-- Settings editors --> <!-- Settings editors -->
<form <form
name="forms.configEdit" name="forms.configEdit"
ng-if="conf.editting" ng-if="conf.editing"
ng-submit="save(conf)" ng-submit="save(conf)"
role="form"> role="form">
@ -65,7 +65,7 @@
</form> </form>
<!-- Setting display formats --> <!-- Setting display formats -->
<span ng-if="!conf.editting" data-test-subj="currentValue"> <span ng-if="!conf.editing" data-test-subj="currentValue">
<span ng-show="(conf.normal || conf.json || conf.select)">{{conf.value || conf.defVal}}</span> <span ng-show="(conf.normal || conf.json || conf.select)">{{conf.value || conf.defVal}}</span>
<span ng-show="conf.array">{{(conf.value || conf.defVal).join(', ')}}</span> <span ng-show="conf.array">{{(conf.value || conf.defVal).join(', ')}}</span>
<span ng-show="conf.bool">{{conf.value === undefined ? conf.defVal : conf.value}}</span> <span ng-show="conf.bool">{{conf.value === undefined ? conf.defVal : conf.value}}</span>
@ -74,7 +74,7 @@
</td> </td>
<td class="actions"> <td class="actions">
<button <button
ng-if="!conf.editting" ng-if="!conf.editing"
ng-click="edit(conf)" ng-click="edit(conf)"
class="btn btn-default" class="btn btn-default"
ng-disabled="conf.tooComplex" ng-disabled="conf.tooComplex"
@ -85,7 +85,7 @@
</button> </button>
<button <button
ng-if="conf.editting" ng-if="conf.editing"
ng-click="save(conf)" ng-click="save(conf)"
class="btn btn-success" class="btn btn-success"
ng-disabled="conf.loading || conf.tooComplex || forms.configEdit.$invalid" ng-disabled="conf.loading || conf.tooComplex || forms.configEdit.$invalid"
@ -97,7 +97,7 @@
</button> </button>
<button <button
ng-if="!conf.editting" ng-if="!conf.editing"
ng-click="clear(conf)" ng-click="clear(conf)"
ng-hide="conf.value === undefined" ng-hide="conf.value === undefined"
class="btn btn-danger" class="btn btn-danger"
@ -108,7 +108,7 @@
</button> </button>
<button <button
ng-if="conf.editting" ng-if="conf.editing"
ng-click="cancelEdit(conf)" ng-click="cancelEdit(conf)"
class="btn btn-default" class="btn btn-default"
aria-label="Cancel edit" aria-label="Cancel edit"

View file

@ -22,12 +22,12 @@ define(function (require) {
// To allow passing form validation state back // To allow passing form validation state back
$scope.forms = {}; $scope.forms = {};
// setup loading flag, run async op, then clear loading and editting flag (just in case) // setup loading flag, run async op, then clear loading and editing flag (just in case)
var loading = function (conf, fn) { var loading = function (conf, fn) {
conf.loading = true; conf.loading = true;
fn() fn()
.finally(function () { .finally(function () {
conf.loading = conf.editting = false; conf.loading = conf.editing = false;
}) })
.catch(notify.fatal); .catch(notify.fatal);
}; };
@ -41,7 +41,7 @@ define(function (require) {
$scope.edit = function (conf) { $scope.edit = function (conf) {
conf.unsavedValue = conf.value == null ? conf.defVal : conf.value; conf.unsavedValue = conf.value == null ? conf.defVal : conf.value;
$scope.configs.forEach(function (c) { $scope.configs.forEach(function (c) {
c.editting = (c === conf); c.editing = (c === conf);
}); });
}; };
@ -56,7 +56,7 @@ define(function (require) {
}; };
$scope.cancelEdit = function (conf) { $scope.cancelEdit = function (conf) {
conf.editting = false; conf.editing = false;
}; };
$scope.clear = function (conf) { $scope.clear = function (conf) {

View file

@ -167,6 +167,7 @@
</div> </div>
<button <button
data-test-subj="submitCreateIndexPatternFromExistingForm"
ng-disabled="form.$invalid || index.fetchFieldsError" ng-disabled="form.$invalid || index.fetchFieldsError"
ng-class="index.fetchFieldsError ? 'btn-default' : 'btn-success'" ng-class="index.fetchFieldsError ? 'btn-default' : 'btn-success'"
type="submit" type="submit"

View file

@ -7,7 +7,7 @@ define(function (require) {
require('ui/directives/auto_select_if_only_one'); require('ui/directives/auto_select_if_only_one');
require('ui/routes') require('ui/routes')
.when('/settings/indices/', { .when('/settings/indices/create/existing', {
template: require('plugins/kibana/settings/sections/indices/_create.html') template: require('plugins/kibana/settings/sections/indices/_create.html')
}); });
@ -70,7 +70,7 @@ define(function (require) {
config.set('defaultIndex', indexPattern.id); config.set('defaultIndex', indexPattern.id);
} }
indexPatterns.cache.clear(indexPattern.id); indexPatterns.cache.clear(indexPattern.id);
kbnUrl.change('/settings/indices/' + indexPattern.id); kbnUrl.change('/settings/indices/edit/' + indexPattern.id);
}); });
} }
}); });

View file

@ -1,6 +1,6 @@
<kbn-settings-app section="indices"> <kbn-settings-app section="indices">
<kbn-settings-indices> <kbn-settings-indices>
<div ng-controller="settingsIndicesEdit"> <div ng-controller="settingsIndicesEdit" data-test-subj="editIndexPattern">
<div class="page-header"> <div class="page-header">
<kbn-settings-index-header <kbn-settings-index-header
index-pattern="indexPattern" index-pattern="indexPattern"

View file

@ -5,7 +5,7 @@ define(function (require) {
require('plugins/kibana/settings/sections/indices/_index_header'); require('plugins/kibana/settings/sections/indices/_index_header');
require('ui/routes') require('ui/routes')
.when('/settings/indices/:indexPatternId', { .when('/settings/indices/edit/:indexPatternId', {
template: require('plugins/kibana/settings/sections/indices/_edit.html'), template: require('plugins/kibana/settings/sections/indices/_edit.html'),
resolve: { resolve: {
indexPattern: function ($route, courier) { indexPattern: function ($route, courier) {

View file

@ -3,9 +3,9 @@ define(function (require) {
require('plugins/kibana/settings/sections/indices/_index_header'); require('plugins/kibana/settings/sections/indices/_index_header');
require('ui/routes') require('ui/routes')
.when('/settings/indices/:indexPatternId/field/:fieldName', { mode: 'edit' }) .when('/settings/indices/edit/:indexPatternId/field/:fieldName', { mode: 'edit' })
.when('/settings/indices/:indexPatternId/create-field/', { mode: 'create' }) .when('/settings/indices/edit/:indexPatternId/create-field/', { mode: 'create' })
.defaults(/settings\/indices\/[^\/]+\/(field|create-field)(\/|$)/, { .defaults(/settings\/indices\/edit\/[^\/]+\/(field|create-field)(\/|$)/, {
template: require('plugins/kibana/settings/sections/indices/_field_editor.html'), template: require('plugins/kibana/settings/sections/indices/_field_editor.html'),
resolve: { resolve: {
indexPattern: function ($route, courier) { indexPattern: function ($route, courier) {

View file

@ -18,7 +18,7 @@ define(function (require) {
link: function ($scope) { link: function ($scope) {
var dateScripts = require('plugins/kibana/settings/sections/indices/_date_scripts'); var dateScripts = require('plugins/kibana/settings/sections/indices/_date_scripts');
var fieldCreatorPath = '/settings/indices/{{ indexPattern }}/scriptedField'; var fieldCreatorPath = '/settings/indices/edit/{{ indexPattern }}/scriptedField';
var fieldEditorPath = fieldCreatorPath + '/{{ fieldName }}'; var fieldEditorPath = fieldCreatorPath + '/{{ fieldName }}';
$scope.perPage = 25; $scope.perPage = 25;

View file

@ -0,0 +1,34 @@
<div class="wizard-step-title">
<h3>Follow these instructions to install Filebeat</h3>
Now that you've got a fresh pipeline and index pattern, let's throw some data at it!
</div>
<div>
<ol>
<li>Install Filebeat on all servers on which you want to tail logs
(<a target="_blank" href="https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-getting-started.html#filebeat-installation">
instructions
</a>)
</li>
<li>
Point Filebeat at the log files you want to tail
(<a target="_blank" href="https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-getting-started.html#filebeat-configuration">
instructions
</a>)
</li>
<li>Configure Filebeat on each server to send data to your Elasticsearch instances
(<a target="_blank" href="https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-configuration-details.html#elasticsearch-output">
instructions
</a>)
</li>
<li>Set the index name in filebeat.yml based on the index pattern you configured in the previous step. The Filebeat
config takes a base index name and automatically rotates the target index by appending "-{date}" to the end, so if
your pattern was "foo-*" you would make the index name "foo" in filebeat.yml.
</li>
<li>Run Filebeat on each server
(<a target="_blank" href="https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-getting-started.html#_running_filebeat">
instructions
</a>)
</li>
</ol>
</div>

View file

@ -0,0 +1,16 @@
import modules from 'ui/modules';
import template from 'plugins/kibana/settings/sections/indices/add_data_steps/install_filebeat_step.html';
modules.get('apps/settings')
.directive('installFilebeatStep', function () {
return {
template: template,
scope: {
results: '='
},
controller: function ($scope) {
var results = $scope.results;
}
};
});

View file

@ -0,0 +1,13 @@
<div class="wizard-step-title">
<h3>Provide some sample logs</h3>
Paste in one or more lines from the file you intend to tail. We'll use these samples in the following steps to help
you build an ingest pipeline and configure a Kibana index pattern. Log lines can be raw strings or
formatted as JSON. If your logs are raw strings but you intend to use
<a target="_window" href="https://www.elastic.co/guide/en/beats/filebeat/current/exported-fields.html">Filebeat's metadata</a>,
you'll want to paste the JSON as it will come out of Filebeat.
</div>
<div class="paste-samples">
<textarea ng-model="pasteStep.rawSamples" placeholder="Paste your sample log lines here, separated by a newline"></textarea>
</div>

View file

@ -0,0 +1,37 @@
import modules from 'ui/modules';
import template from 'plugins/kibana/settings/sections/indices/add_data_steps/paste_samples_step.html';
import _ from 'lodash';
modules.get('apps/settings')
.directive('pasteSamplesStep', function () {
return {
template: template,
scope: {
samples: '=',
rawSamples: '='
},
bindToController: true,
controllerAs: 'pasteStep',
controller: function ($scope) {
if (_.isUndefined(this.rawSamples)) {
this.rawSamples = '';
}
$scope.$watch('pasteStep.rawSamples', (newValue) => {
const splitRawSamples = newValue.split('\n');
try {
this.samples = _.map(splitRawSamples, (sample) => {
return JSON.parse(sample);
});
}
catch (error) {
this.samples = _.map(splitRawSamples, (sample) => {
return {message: sample};
});
}
});
}
};
});

View file

@ -0,0 +1,32 @@
<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 if we got it wrong!
</div>
<div class="pattern-review">
<div>
<label>Index name or pattern</label>
<kbn-info info="Patterns allow you to define dynamic index names using * as a wildcard. Example: filebeat-*"></kbn-info>
</div>
<input ng-model="reviewStep.indexPattern.id" class="pattern-input"/>
<label>
<input ng-model="reviewStep.isTimeBased" type="checkbox"/>
time based
</label>
<label ng-if="reviewStep.isTimeBased" class="time-field-input">
Time Field
<select ng-model="reviewStep.indexPattern.timeFieldName" name="time_field_name">
<option ng-repeat="field in reviewStep.dateFields" value="{{field}}">
{{field}}
</option>
</select>
</label>
</div>
<div>
<paginated-table
columns="reviewStep.columns"
rows="reviewStep.rows">
</paginated-table>
</div>

View file

@ -0,0 +1,152 @@
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 () {
return {
template: template,
scope: {
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();
}
};
});

View file

@ -0,0 +1,7 @@
<h2>Build pipeline step</h2>
<div>
Logs: {{samples}}
</div>
<button ng-click="sampleDocs = {results: {os: 'osx'}}; pipeline = {processor: 'I processor'};">Build a pipeline</button>

View file

@ -0,0 +1,15 @@
var modules = require('ui/modules');
var template = require('plugins/kibana/settings/sections/indices/add_data_steps/pipeline_step.html');
modules.get('apps/settings')
.directive('pipelineStep', function () {
return {
template: template,
scope: {
samples: '=',
sampleDocs: '=',
pipeline: '='
}
};
});

View file

@ -0,0 +1,38 @@
<div class="col-md-2 sidebar-container">
<div class="sidebar-list">
<div class="sidebar-list-header">
<h5>
Index Patterns&nbsp;
<a
ng-if="showAddNew"
href="#/settings/indices"
class="btn btn-primary btn-xs"
aria-label="Add New">
<span class="sr-only">Add New</span>
<i aria-hidden="true" class="fa fa-plus"></i> Add New
</a>
</h5>
</div>
<ul class="list-unstyled">
<li
ng-if="!defaultIndex"
class="sidebar-item">
<div class="sidebar-item-title full-title">
<span class="label label-warning">Warning</span> No default index pattern. You must select or create one to continue.
</div>
</li>
<li
ng-repeat="pattern in indexPatternList | orderBy:['-default','id'] track by pattern.id "
class="sidebar-item">
<a href="{{::pattern.url}}">
<div class="{{::pattern.class}}">
<i aria-hidden="true" ng-if="pattern.default" class="fa fa-star"></i>
<span ng-bind="::pattern.id"></span>
</div>
</a>
</li>
</ul>
</div>
</div>
<div class="col-md-10" ng-transclude></div>

View file

@ -0,0 +1,28 @@
// wrapper directive, which sets some global stuff up like the left nav
require('ui/modules').get('apps/settings')
.directive('kbnSettingsIndices', function ($route, config, kbnUrl) {
return {
restrict: 'E',
transclude: true,
template: require('plugins/kibana/settings/sections/indices/directives/kbn_settings_indices.html'),
link: function ($scope) {
$scope.showAddNew = !/^\/settings\/indices$/.test($route.current.$$route.originalPath);
$scope.editingId = $route.current.params.indexPatternId;
config.$bind($scope, 'defaultIndex');
$scope.$watch('defaultIndex', function () {
var ids = $route.current.locals.indexPatternIds;
$scope.indexPatternList = ids.map(function (id) {
return {
id: id,
url: kbnUrl.eval('#/settings/indices/edit/{{id}}', {id: id}),
class: 'sidebar-item-title ' + ($scope.editingId === id ? 'active' : ''),
default: $scope.defaultIndex === id
};
});
});
$scope.$emit('application.load');
}
};
});

View file

@ -0,0 +1,78 @@
<div>
<div class="page-header">
<h1>Tail a File</h1>
Let's send some log data to Elasticsearch.
</div>
</div>
<div>
<div class="wizard-step-headings" ng-class="{complete: wizard.complete}">
<span ng-class="{active: wizard.currentStep === 0}"
class="wizard-step-heading"
ng-click="wizard.setCurrentStep(0)">
1. Paste
</span>
<span ng-class="{active: wizard.currentStep === 1, aheadActive: wizard.currentStep < 1}"
class="wizard-step-heading"
ng-click="wizard.currentStep < 1 || wizard.setCurrentStep(1)">
2. Parse
</span>
<span ng-class="{active: wizard.currentStep === 2, aheadActive: wizard.currentStep < 2}"
class="wizard-step-heading"
ng-click="wizard.currentStep < 2 || wizard.setCurrentStep(2)">
3. Review
</span>
<span ng-class="{active: wizard.currentStep === 3, aheadActive: wizard.currentStep < 3}"
class="wizard-step-heading"
ng-click="wizard.currentStep < 3 || wizard.setCurrentStep(3)">
4. Install Filebeat
</span>
</div>
<div ng-switch="wizard.currentStep">
<div ng-switch-when="0">
<paste-samples-step samples="wizard.stepResults.samples" raw-samples="wizard.stepResults.rawSamples"></paste-samples-step>
<div class="nav-buttons">
<button ng-disabled="!wizard.stepResults.samples" ng-click="wizard.nextStep()">Next</button>
</div>
</div>
<div ng-switch-when="1">
<pipeline-step
samples="wizard.stepResults.samples"
pipeline="wizard.stepResults.pipeline"
sample-docs="wizard.stepResults.sampleDocs">
</pipeline-step>
<div class="nav-buttons">
<button ng-click="wizard.prevStep()">Prev</button>
<button ng-disabled="!wizard.stepResults.pipeline || !wizard.stepResults.sampleDocs" ng-click="wizard.nextStep()">Next</button>
</div>
</div>
<div ng-switch-when="2">
<pattern-review-step
index-pattern="wizard.stepResults.indexPattern"
sample-docs="wizard.stepResults.sampleDocs"
pipeline="wizard.stepResults.pipeline">
</pattern-review-step>
<div class="nav-buttons">
<button ng-click="wizard.prevStep()">Prev</button>
<button ng-disabled="!wizard.stepResults.indexPattern || !wizard.stepResults.indexPattern.id"
ng-click="wizard.nextStep()">
Save
</button>
</div>
</div>
<div ng-switch-when="3">
<install-filebeat-step results="wizard.stepResults"></install-filebeat-step>
<div class="nav-buttons">
Click Done to go explore your data
<button ng-click="wizard.nextStep()">Done</button>
</div>
</div>
</div>
</div>

View file

@ -0,0 +1,78 @@
var modules = require('ui/modules');
var template = require('plugins/kibana/settings/sections/indices/filebeat/directives/filebeat_wizard.html');
require('plugins/kibana/settings/sections/indices/add_data_steps/pattern_review_step');
require('plugins/kibana/settings/sections/indices/add_data_steps/paste_samples_step');
require('plugins/kibana/settings/sections/indices/add_data_steps/pipeline_step');
require('plugins/kibana/settings/sections/indices/add_data_steps/install_filebeat_step');
// wrapper directive, which sets up the breadcrumb for all filebeat steps
modules.get('apps/settings')
.directive('filebeatWizard', function () {
return {
restrict: 'E',
template: template,
scope: {},
bindToController: true,
controllerAs: 'wizard',
controller: function ($scope, AppState, safeConfirm, kbnUrl) {
var $state = this.state = new AppState();
var totalSteps = 4;
this.stepResults = {};
this.setCurrentStep = (step) => {
if (!this.complete) {
$state.currentStep = step;
$state.save();
}
};
this.setCurrentStep(0);
this.nextStep = () => {
if ($state.currentStep + 1 < totalSteps) {
this.setCurrentStep($state.currentStep + 1);
}
else if ($state.currentStep + 1 === totalSteps) {
kbnUrl.change('/discover');
}
};
this.prevStep = () => {
if ($state.currentStep > 0) {
this.setCurrentStep($state.currentStep - 1);
}
};
$scope.$watch('wizard.state.currentStep', (newValue, oldValue) => {
if (this.complete) {
$state.currentStep = totalSteps - 1;
$state.save();
return;
}
if (newValue + 1 === totalSteps) {
this.complete = true;
}
if (newValue < oldValue) {
return safeConfirm('Going back will reset any changes you\'ve made to this step, do you want to continue?')
.then(
() => {
if ($state.currentStep < 1) {
delete this.stepResults.pipeline;
}
if ($state.currentStep < 2) {
delete this.stepResults.indexPattern;
}
this.currentStep = newValue;
},
() => {
$state.currentStep = oldValue;
$state.save();
}
);
}
else {
this.currentStep = newValue;
}
});
}
};
});

View file

@ -0,0 +1,5 @@
<kbn-settings-app section="indices">
<kbn-settings-indices>
<filebeat-wizard />
</kbn-settings-indices>
</kbn-settings-app>

View file

@ -0,0 +1,8 @@
var routes = require('ui/routes');
var template = require('plugins/kibana/settings/sections/indices/filebeat/index.html');
require('plugins/kibana/settings/sections/indices/filebeat/directives/filebeat_wizard');
routes.when('/settings/indices/create/filebeat', {
template: template
});

View file

@ -1,38 +1,25 @@
<div class="col-md-2 sidebar-container"> <kbn-settings-app section="indices">
<div class="sidebar-list"> <kbn-settings-indices>
<div class="sidebar-list-header"> <div data-test-subj="addData">
<h5> <div class="page-header">
Index Patterns&nbsp; <h1>Add Data</h1>
<a Before we can get to the fun stuff, we'll have to get some data into your Elasticsearch cluster.
ng-if="edittingId" Pick the option that best suits your use case below, and we'll guide you through the process!
href="#/settings/indices" </div>
class="btn btn-primary btn-xs"
aria-label="Add New">
<span class="sr-only">Add New</span>
<i aria-hidden="true" class="fa fa-plus"></i> Add New
</a>
</h5>
</div>
<ul class="list-unstyled">
<li
ng-if="!defaultIndex"
class="sidebar-item">
<div class="sidebar-item-title full-title">
<span class="label label-warning">Warning</span> No default index pattern. You must select or create one to continue.
</div>
</li>
<li
ng-repeat="pattern in indexPatternList | orderBy:['-default','id'] track by pattern.id "
class="sidebar-item">
<a href="{{::pattern.url}}">
<div class="{{::pattern.class}}">
<i aria-hidden="true" ng-if="pattern.default" class="fa fa-star"></i>
<span ng-bind="::pattern.id"></span>
</div>
</a>
</li>
</ul>
</div>
</div>
<div class="col-md-10" ng-transclude></div> <h4>
<a href="#/settings/indices/create/existing" data-test-subj="existingIndices">Existing Indices</a>
</h4>
<div>
Pick this option if you already have data in Elasticsearch.
</div>
<h4>
<a href="#/settings/indices/create/filebeat">Tail a File</a>
</h4>
<div>
Pick this option if you have log file data you'd like to send to Elasticsearch.
</div>
</div>
</kbn-settings-indices>
</kbn-settings-app>

View file

@ -1,7 +1,9 @@
define(function (require) { define(function (require) {
var _ = require('lodash'); var _ = require('lodash');
require('plugins/kibana/settings/sections/indices/directives/kbn_settings_indices');
require('plugins/kibana/settings/sections/indices/_create'); require('plugins/kibana/settings/sections/indices/_create');
require('plugins/kibana/settings/sections/indices/filebeat/index');
require('plugins/kibana/settings/sections/indices/_edit'); require('plugins/kibana/settings/sections/indices/_edit');
require('plugins/kibana/settings/sections/indices/_field_editor'); require('plugins/kibana/settings/sections/indices/_field_editor');
@ -15,37 +17,14 @@ define(function (require) {
} }
}); });
// wrapper directive, which sets some global stuff up like the left nav require('ui/routes')
require('ui/modules').get('apps/settings') .when('/settings/indices', {
.directive('kbnSettingsIndices', function ($route, config, kbnUrl) { template: require('plugins/kibana/settings/sections/indices/index.html')
return { });
restrict: 'E',
transclude: true,
template: require('plugins/kibana/settings/sections/indices/index.html'),
link: function ($scope) {
$scope.edittingId = $route.current.params.indexPatternId;
config.$bind($scope, 'defaultIndex');
$scope.$watch('defaultIndex', function () {
var ids = $route.current.locals.indexPatternIds;
$scope.indexPatternList = ids.map(function (id) {
return {
id: id,
url: kbnUrl.eval('#/settings/indices/{{id}}', {id: id}),
class: 'sidebar-item-title ' + ($scope.edittingId === id ? 'active' : ''),
default: $scope.defaultIndex === id
};
});
});
$scope.$emit('application.load');
}
};
});
return { return {
name: 'indices', name: 'indices',
display: 'Indices', display: 'Indices',
url: '#/settings/indices', url: '#/settings/indices'
}; };
}); });

View file

@ -0,0 +1,13 @@
<select ng-if="knownFieldTypes[field.name] !== 'geo_point'" name="field_type" ng-model="field.type" ng-change="buildRows()">
<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>

View file

@ -186,3 +186,51 @@ kbn-settings-indices {
.kbn-settings-indices-create { .kbn-settings-indices-create {
.time-and-pattern > div {} .time-and-pattern > div {}
} }
.wizard-step-headings{
margin-top: 1em;
.wizard-step-heading {
font-size: 1.5em;
padding-right: 1.5em;
&.active {
cursor: default;
font-weight: bold;
}
&.aheadActive {
cursor: default;
font-weight: 300;
}
}
&.complete {
.wizard-step-heading:not(.active) {
color: #dddddd;
cursor: default;
}
}
}
.wizard-step-title {
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;
}
}

View file

@ -69,7 +69,7 @@ define(function (require) {
} }
Field.prototype.routes = { Field.prototype.routes = {
edit: '/settings/indices/{{indexPattern.id}}/field/{{name}}' edit: '/settings/indices/edit/{{indexPattern.id}}/field/{{name}}'
}; };
return Field; return Field;

View file

@ -314,10 +314,10 @@ define(function (require) {
} }
IndexPattern.prototype.routes = { IndexPattern.prototype.routes = {
edit: '/settings/indices/{{id}}', edit: '/settings/indices/edit/{{id}}',
addField: '/settings/indices/{{id}}/create-field', addField: '/settings/indices/edit/{{id}}/create-field',
indexedFields: '/settings/indices/{{id}}?_a=(tab:indexedFields)', indexedFields: '/settings/indices/edit/{{id}}?_a=(tab:indexedFields)',
scriptedFields: '/settings/indices/{{id}}?_a=(tab:scriptedFields)' scriptedFields: '/settings/indices/edit/{{id}}?_a=(tab:scriptedFields)'
}; };
return IndexPattern; return IndexPattern;

View file

@ -23,7 +23,7 @@ define(function (require) {
self.fetch(); self.fetch();
}), }),
// begining of full route update, new app will be initialized before // beginning of full route update, new app will be initialized before
// $routeChangeSuccess or $routeChangeError // $routeChangeSuccess or $routeChangeError
$rootScope.$on('$routeChangeStart', function () { $rootScope.$on('$routeChangeStart', function () {
if (self._persistAcrossApps) { if (self._persistAcrossApps) {
@ -136,8 +136,8 @@ define(function (require) {
* @returns {void} * @returns {void}
*/ */
State.prototype.destroy = function () { State.prototype.destroy = function () {
this.off(); // removes all listners this.off(); // removes all listeners
this._cleanUpListeners(); // Removes the $routeUpdate listner this._cleanUpListeners(); // Removes the $routeUpdate listener
}; };
State.prototype.setDefaults = function (defaults) { State.prototype.setDefaults = function (defaults) {

View file

@ -88,9 +88,9 @@ define(function (require) {
/** /**
* Return the current bounds, if we have any. * Return the current bounds, if we have any.
* *
* THIS DOES NOT CLONE THE BOUNDS, so editting them * THIS DOES NOT CLONE THE BOUNDS, so editing them
* may have unexpected side-effects. Always * may have unexpected side-effects. Always
* call bounds.min.clone() before editting * call bounds.min.clone() before editing
* *
* @return {object|undefined} - If bounds are not defined, this * @return {object|undefined} - If bounds are not defined, this
* returns undefined, else it returns the bounds * returns undefined, else it returns the bounds

View file

@ -32,7 +32,7 @@ define(function (require) {
}) })
.then(function (navigateTo) { .then(function (navigateTo) {
common.debug('navigateTo'); common.debug('navigateTo');
return settingsPage.navigateTo(); return settingsPage.navigateTo().then(settingsPage.clickExistingIndicesAddDataLink);
}) })
.then(function () { .then(function () {
common.debug('createIndexPattern'); common.debug('createIndexPattern');

View file

@ -28,7 +28,7 @@ define(function (require) {
}) })
.then(function (navigateTo) { .then(function (navigateTo) {
common.debug('navigateTo'); common.debug('navigateTo');
return settingsPage.navigateTo(); return settingsPage.navigateTo().then(settingsPage.clickExistingIndicesAddDataLink);
}) })
.then(function () { .then(function () {
common.debug('createIndexPattern'); common.debug('createIndexPattern');

View file

@ -28,7 +28,7 @@ define(function (require) {
}) })
.then(function (navigateTo) { .then(function (navigateTo) {
common.debug('navigateTo'); common.debug('navigateTo');
return settingsPage.navigateTo(); return settingsPage.navigateTo().then(settingsPage.clickExistingIndicesAddDataLink);
}) })
.then(function () { .then(function () {
common.debug('createIndexPattern'); common.debug('createIndexPattern');

View file

@ -37,7 +37,7 @@ define(function (require) {
}) })
.then(function (navigateTo) { .then(function (navigateTo) {
common.debug('navigateTo'); common.debug('navigateTo');
return settingsPage.navigateTo(); return settingsPage.navigateTo().then(settingsPage.clickExistingIndicesAddDataLink);
}) })
.then(function () { .then(function () {
common.debug('createIndexPattern'); common.debug('createIndexPattern');

View file

@ -14,7 +14,7 @@ define(function (require) {
return scenarioManager.reload('emptyKibana') return scenarioManager.reload('emptyKibana')
.then(function () { .then(function () {
return settingsPage.navigateTo(); return settingsPage.navigateTo().then(settingsPage.clickExistingIndicesAddDataLink);
}); });
}); });

View file

@ -16,7 +16,7 @@ define(function (require) {
bdd.beforeEach(function () { bdd.beforeEach(function () {
return scenarioManager.reload('emptyKibana') return scenarioManager.reload('emptyKibana')
.then(function () { .then(function () {
return settingsPage.navigateTo(); return settingsPage.navigateTo().then(settingsPage.clickExistingIndicesAddDataLink);
}); });
}); });

View file

@ -16,7 +16,7 @@ define(function (require) {
return scenarioManager.reload('emptyKibana') return scenarioManager.reload('emptyKibana')
.then(function () { .then(function () {
return settingsPage.navigateTo(); return settingsPage.navigateTo().then(settingsPage.clickExistingIndicesAddDataLink);
}); });
}); });
@ -81,9 +81,9 @@ define(function (require) {
}); });
}); });
bdd.it('should return to index pattern creation page', function returnToPage() { bdd.it('should return to the add data landing page', function returnToPage() {
return common.tryForTime(5000, function () { return common.tryForTime(5000, function () {
return settingsPage.getCreateButton(); return common.findTestSubject('addData');
}) })
.catch(common.handleError(this)); .catch(common.handleError(this));
}); });

View file

@ -16,7 +16,7 @@ define(function (require) {
return scenarioManager.reload('emptyKibana') return scenarioManager.reload('emptyKibana')
.then(function () { .then(function () {
return settingsPage.navigateTo(); return settingsPage.navigateTo().then(settingsPage.clickExistingIndicesAddDataLink);
}); });
}); });
@ -25,7 +25,7 @@ define(function (require) {
}); });
bdd.afterEach(function ae() { bdd.afterEach(function ae() {
return settingsPage.removeIndexPattern(); return settingsPage.removeIndexPattern().then(settingsPage.clickExistingIndicesAddDataLink);
}); });
bdd.describe('change popularity', function indexPatternCreation() { bdd.describe('change popularity', function indexPatternCreation() {

View file

@ -38,7 +38,7 @@ define(function (require) {
columns.forEach(function (col) { columns.forEach(function (col) {
bdd.describe('sort by heading - ' + col.heading, function indexPatternCreation() { bdd.describe('sort by heading - ' + col.heading, function indexPatternCreation() {
bdd.before(function () { bdd.before(function () {
return settingsPage.navigateTo(); return settingsPage.navigateTo().then(settingsPage.clickExistingIndicesAddDataLink);
}); });
bdd.beforeEach(function () { bdd.beforeEach(function () {
@ -46,7 +46,7 @@ define(function (require) {
}); });
bdd.afterEach(function () { bdd.afterEach(function () {
return settingsPage.removeIndexPattern(); return settingsPage.removeIndexPattern().then(settingsPage.clickExistingIndicesAddDataLink);
}); });
bdd.it('should sort ascending', function pageHeader() { bdd.it('should sort ascending', function pageHeader() {
@ -84,6 +84,7 @@ define(function (require) {
bdd.before(function () { bdd.before(function () {
return settingsPage.navigateTo() return settingsPage.navigateTo()
.then(settingsPage.clickExistingIndicesAddDataLink)
.then(function () { .then(function () {
return settingsPage.createIndexPattern(); return settingsPage.createIndexPattern();
}); });

View file

@ -14,7 +14,7 @@ define(function (require) {
return scenarioManager.reload('emptyKibana') return scenarioManager.reload('emptyKibana')
.then(function () { .then(function () {
return settingsPage.navigateTo(); return settingsPage.navigateTo().then(settingsPage.clickExistingIndicesAddDataLink);
}); });
}); });

View file

@ -31,7 +31,7 @@ define(function (require) {
return scenarioManager.reload('emptyKibana') return scenarioManager.reload('emptyKibana')
.then(function () { .then(function () {
common.debug('navigateTo'); common.debug('navigateTo');
return settingsPage.navigateTo(); return settingsPage.navigateTo().then(settingsPage.clickExistingIndicesAddDataLink);
}) })
.then(function () { .then(function () {
common.debug('createIndexPattern'); common.debug('createIndexPattern');

View file

@ -18,7 +18,7 @@ define(function (require) {
return scenarioManager.reload('emptyKibana') return scenarioManager.reload('emptyKibana')
.then(function () { .then(function () {
common.debug('navigateTo'); common.debug('navigateTo');
return settingsPage.navigateTo(); return settingsPage.navigateTo().then(settingsPage.clickExistingIndicesAddDataLink);
}) })
.then(function () { .then(function () {
common.debug('createIndexPattern'); common.debug('createIndexPattern');

View file

@ -31,7 +31,7 @@ define(function (require) {
return scenarioManager.reload('emptyKibana') return scenarioManager.reload('emptyKibana')
.then(function () { .then(function () {
common.debug('navigateTo'); common.debug('navigateTo');
return settingsPage.navigateTo(); return settingsPage.navigateTo().then(settingsPage.clickExistingIndicesAddDataLink);
}) })
.then(function () { .then(function () {
common.debug('createIndexPattern'); common.debug('createIndexPattern');

View file

@ -28,7 +28,7 @@ define(function (require) {
return scenarioManager.reload('emptyKibana') return scenarioManager.reload('emptyKibana')
.then(function () { .then(function () {
common.debug('navigateTo'); common.debug('navigateTo');
return settingsPage.navigateTo(); return settingsPage.navigateTo().then(settingsPage.clickExistingIndicesAddDataLink);
}) })
.then(function () { .then(function () {
common.debug('createIndexPattern'); common.debug('createIndexPattern');

View file

@ -34,7 +34,7 @@ define(function (require) {
return scenarioManager.reload('emptyKibana') return scenarioManager.reload('emptyKibana')
.then(function () { .then(function () {
common.debug('navigateTo'); common.debug('navigateTo');
return settingsPage.navigateTo(); return settingsPage.navigateTo().then(settingsPage.clickExistingIndicesAddDataLink);
}) })
.then(function () { .then(function () {
common.debug('createIndexPattern'); common.debug('createIndexPattern');

View file

@ -28,7 +28,7 @@ define(function (require) {
return scenarioManager.reload('emptyKibana') return scenarioManager.reload('emptyKibana')
.then(function () { .then(function () {
common.debug('navigateTo'); common.debug('navigateTo');
return settingsPage.navigateTo(); return settingsPage.navigateTo().then(settingsPage.clickExistingIndicesAddDataLink);
}) })
.then(function () { .then(function () {
common.debug('createIndexPattern'); common.debug('createIndexPattern');

View file

@ -30,7 +30,7 @@ define(function (require) {
return scenarioManager.reload('emptyKibana') return scenarioManager.reload('emptyKibana')
.then(function () { .then(function () {
common.debug('navigateTo'); common.debug('navigateTo');
return settingsPage.navigateTo(); return settingsPage.navigateTo().then(settingsPage.clickExistingIndicesAddDataLink);
}) })
.then(function () { .then(function () {
common.debug('createIndexPattern'); common.debug('createIndexPattern');

View file

@ -30,7 +30,7 @@ define(function (require) {
return scenarioManager.reload('emptyKibana') return scenarioManager.reload('emptyKibana')
.then(function () { .then(function () {
common.debug('navigateTo'); common.debug('navigateTo');
return settingsPage.navigateTo(); return settingsPage.navigateTo().then(settingsPage.clickExistingIndicesAddDataLink);
}) })
.then(function () { .then(function () {
common.debug('createIndexPattern'); common.debug('createIndexPattern');

View file

@ -20,6 +20,10 @@ define(function (require) {
return common.findTestSubject('settingsNav advanced').click(); return common.findTestSubject('settingsNav advanced').click();
}, },
clickExistingIndicesAddDataLink: function () {
return common.findTestSubject('addData existingIndices').click();
},
setAdvancedSettings: function setAdvancedSettings(propertyName, propertyValue) { setAdvancedSettings: function setAdvancedSettings(propertyName, propertyValue) {
var self = this; var self = this;
return common.findTestSubject('advancedSetting&' + propertyName + ' editButton') return common.findTestSubject('advancedSetting&' + propertyName + ' editButton')
@ -126,13 +130,11 @@ define(function (require) {
}, },
getCreateButton: function () { getCreateButton: function () {
return this.remote.setFindTimeout(defaultTimeout) return common.findTestSubject('submitCreateIndexPatternFromExistingForm');
.findByCssSelector('.btn');
}, },
clickCreateButton: function () { clickCreateButton: function () {
return this.remote.setFindTimeout(defaultTimeout) return common.findTestSubject('submitCreateIndexPatternFromExistingForm').click();
.findByCssSelector('.btn').click();
}, },
clickDefaultIndexButton: function () { clickDefaultIndexButton: function () {
@ -305,17 +307,17 @@ define(function (require) {
return common.tryForTime(defaultTimeout, function () { return common.tryForTime(defaultTimeout, function () {
return self.selectTimeFieldOption('@timestamp') return self.selectTimeFieldOption('@timestamp')
.then(function () { .then(function () {
return self.getCreateButton().click(); return self.clickCreateButton();
}); });
}) })
.then(function () { .then(function () {
return common.tryForTime(defaultTimeout, function () { return common.tryForTime(defaultTimeout, function () {
return self.remote.getCurrentUrl() return common.findTestSubject('editIndexPattern')
.then(function (currentUrl) { .then(function (editPatternContainer) {
if (!currentUrl.match(/indices\/.+\?/)) { if (!editPatternContainer) {
throw new Error('Index pattern not created'); throw new Error('Index pattern not created');
} else { } else {
common.debug('Index pattern created: ' + currentUrl); common.debug('Index pattern created');
} }
}); });
}); });