Skip to content

Commit

Permalink
Merge pull request #1982 from w33ble/scripted-fields
Browse files Browse the repository at this point in the history
Scripted fields in index pattern
  • Loading branch information
spenceralger committed Nov 20, 2014
2 parents 202e587 + 18d2ea3 commit d399422
Show file tree
Hide file tree
Showing 13 changed files with 236 additions and 191 deletions.
3 changes: 2 additions & 1 deletion src/kibana/components/agg_types/buckets/terms.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ define(function (require) {
},
params: [
{
name: 'field'
name: 'field',
scriptable: true
},
{
name: 'size',
Expand Down
4 changes: 2 additions & 2 deletions src/kibana/components/agg_types/controls/field.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
ng-options="
field as field.name group by field.type for field in aggConfig.vis.indexPattern.fields.raw
| fieldType: aggParam.filterFieldTypes
| filter: { indexed:true }
| orderBy:['type','name']
| filter: { indexed: true }
| orderBy: ['type', 'name']
">
</select>
</div>
2 changes: 1 addition & 1 deletion src/kibana/components/agg_types/param_types/field.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ define(function (require) {
}

FieldAggParam.prototype.editor = editorHtml;
FieldAggParam.prototype.scriptable = false;
FieldAggParam.prototype.filterFieldTypes = '*';


/**
* Called to serialize values for saving an aggConfig object
*
Expand Down
36 changes: 16 additions & 20 deletions src/kibana/components/courier/courier.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,25 @@ define(function (require) {
require('modules').get('kibana/courier')
.service('courier', function ($rootScope, Private, Promise, indexPatterns) {
function Courier() {
var courier = this;
var self = this;

var DocSource = Private(require('components/courier/data_source/doc_source'));
var SearchSource = Private(require('components/courier/data_source/search_source'));

var pendingRequests = Private(require('components/courier/_pending_requests'));

var docLooper = courier.docLooper = Private(require('components/courier/looper/doc'));
var searchLooper = courier.searchLooper = Private(require('components/courier/looper/search'));
var docLooper = self.docLooper = Private(require('components/courier/looper/doc'));
var searchLooper = self.searchLooper = Private(require('components/courier/looper/search'));

// expose some internal modules
courier.setRootSearchSource = Private(require('components/courier/data_source/_root_search_source')).set;
self.setRootSearchSource = Private(require('components/courier/data_source/_root_search_source')).set;

courier.SavedObject = Private(require('components/courier/saved_object/saved_object'));
courier.indexPatterns = indexPatterns;
courier.redirectWhenMissing = Private(require('components/courier/_redirect_when_missing'));
self.SavedObject = Private(require('components/courier/saved_object/saved_object'));
self.indexPatterns = indexPatterns;
self.redirectWhenMissing = Private(require('components/courier/_redirect_when_missing'));

courier.DocSource = DocSource;
courier.SearchSource = SearchSource;
self.DocSource = DocSource;
self.SearchSource = SearchSource;

var HastyRefresh = errors.HastyRefresh;
var Abort = errors.Abort;
Expand All @@ -36,7 +36,7 @@ define(function (require) {
*
* @chainable
*/
courier.fetchInterval = function (ms) {
self.fetchInterval = function (ms) {
searchLooper.ms(ms);
return this;
};
Expand All @@ -45,7 +45,7 @@ define(function (require) {
* Start fetching search requests on an interval
* @chainable
*/
courier.start = function () {
self.start = function () {
searchLooper.start();
return this;
};
Expand All @@ -55,7 +55,7 @@ define(function (require) {
* a promise that resembles the success of the fetch completing,
* individual errors are routed to their respective requests.
*/
courier.fetch = function () {
self.fetch = function () {
return searchLooper.run();
};

Expand All @@ -66,7 +66,7 @@ define(function (require) {
*
* @return {boolean}
*/
courier.started = function () {
self.started = function () {
return searchLooper.started();
};

Expand All @@ -77,7 +77,7 @@ define(function (require) {
*
* @chainable
*/
courier.stop = function () {
self.stop = function () {
searchLooper.stop();
return this;
};
Expand All @@ -88,7 +88,7 @@ define(function (require) {
*
* @param {string} type - the type of Source to create
*/
courier.createSource = function (type) {
self.createSource = function (type) {
switch (type) {
case 'doc':
return new DocSource();
Expand All @@ -97,15 +97,11 @@ define(function (require) {
}
};

courier.getFieldsFor = function (indexish) {
return courier.indexPatterns.getFieldsFor(indexish);
};

/**
* Abort all pending requests
* @return {[type]} [description]
*/
courier.close = function () {
self.close = function () {
searchLooper.stop();
docLooper.stop();

Expand Down
5 changes: 2 additions & 3 deletions src/kibana/components/courier/data_source/doc_source.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,15 @@ define(function (require) {
var VersionConflict = errors.VersionConflict;
var RequestFailure = errors.RequestFailure;

_(DocSource).inherits(SourceAbstract);
function DocSource(initialState) {
SourceAbstract.call(this, initialState);
DocSource.Super.call(this, initialState);

// move onResults over to onUpdate, because that makes more sense
this.onUpdate = this.onResults;
this.onResults = void 0;
}

inherits(DocSource, SourceAbstract);

/*****
* PUBLIC API
*****/
Expand Down
82 changes: 41 additions & 41 deletions src/kibana/components/courier/saved_object/saved_object.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ define(function (require) {
if (!_.isObject(config)) config = {};

// save an easy reference to this
var obj = this;
var self = this;

/************
* Initialize config vars
Expand All @@ -39,10 +39,10 @@ define(function (require) {
var customInit = config.init || _.noop;

// optional search source which this object configures
obj.searchSource = config.searchSource && new SearchSource();
self.searchSource = config.searchSource && new SearchSource();

// the id of the document
obj.id = config.id || void 0;
self.id = config.id || void 0;

/**
* Asynchronously initialize this object - will only run
Expand All @@ -51,15 +51,15 @@ define(function (require) {
* @return {Promise}
* @resolved {SavedObject}
*/
obj.init = _.once(function () {
self.init = _.once(function () {
// ensure that the type is defined
if (!type) throw new Error('You must define a type name to use SavedObject objects.');

// tell the docSource where to find the doc
docSource
.index(configFile.kibanaIndex)
.type(type)
.id(obj.id);
.id(self.id);

// check that the mapping for this type is defined
return mappingSetup.isDefined(type)
Expand All @@ -81,56 +81,56 @@ define(function (require) {
})
.then(function () {
// If there is not id, then there is no document to fetch from elasticsearch
if (!obj.id) {
if (!self.id) {
// just assign the defaults and be done
_.assign(obj, defaults);
_.assign(self, defaults);
return hydrateIndexPattern().then(function () {
return afterESResp.call(obj);
return afterESResp.call(self);
});
}

// fetch the object from ES
return docSource.fetch()
.then(function applyESResp(resp) {

obj._source = _.cloneDeep(resp._source);
self._source = _.cloneDeep(resp._source);

if (!resp.found) throw new errors.SavedObjectNotFound(type, obj.id);
if (!resp.found) throw new errors.SavedObjectNotFound(type, self.id);

var meta = resp._source.kibanaSavedObjectMeta || {};
delete resp._source.kibanaSavedObjectMeta;

if (!config.indexPattern && obj._source.indexPattern) {
config.indexPattern = obj._source.indexPattern;
delete obj._source.indexPattern;
if (!config.indexPattern && self._source.indexPattern) {
config.indexPattern = self._source.indexPattern;
delete self._source.indexPattern;
}

// assign the defaults to the response
_.defaults(obj._source, defaults);
_.defaults(self._source, defaults);

// transform the source using _deserializers
_.forOwn(mapping, function ittr(fieldMapping, fieldName) {
if (fieldMapping._deserialize) {
obj._source[fieldName] = fieldMapping._deserialize(obj._source[fieldName], resp, fieldName, fieldMapping);
self._source[fieldName] = fieldMapping._deserialize(self._source[fieldName], resp, fieldName, fieldMapping);
}
});

// Give obj all of the values in _source.fields
_.assign(obj, obj._source);
_.assign(self, self._source);

return Promise.try(function () {
// if we have a searchSource, set it's state based on the searchSourceJSON field
if (obj.searchSource) {
if (self.searchSource) {
var state = {};
try {
state = JSON.parse(meta.searchSourceJSON);
} catch (e) {}
obj.searchSource.set(state);
self.searchSource.set(state);
}
})
.then(hydrateIndexPattern)
.then(function () {
return Promise.cast(afterESResp.call(obj, resp));
return Promise.cast(afterESResp.call(self, resp));
})
.then(function () {
// Any time obj is updated, re-call applyESResp
Expand All @@ -139,11 +139,11 @@ define(function (require) {
});
})
.then(function () {
return customInit.call(obj);
return customInit.call(self);
})
.then(function () {
// return our obj as the result of init()
return obj;
return self;
});
});

Expand All @@ -155,12 +155,12 @@ define(function (require) {
*/
function hydrateIndexPattern() {
return Promise.try(function () {
if (obj.searchSource) {
if (self.searchSource) {

var index = config.indexPattern || obj.searchSource.getOwn('index');
var index = config.indexPattern || self.searchSource.getOwn('index');
if (!index) return;
if (config.clearSavedIndexPattern) {
obj.searchSource.set('index', undefined);
self.searchSource.set('index', undefined);
return;
}

Expand All @@ -169,7 +169,7 @@ define(function (require) {
}

return Promise.resolve(index).then(function (indexPattern) {
obj.searchSource.set('index', indexPattern);
self.searchSource.set('index', indexPattern);
});
}
});
Expand All @@ -182,38 +182,38 @@ define(function (require) {
* @return {Promise}
* @resolved {String} - The id of the doc
*/
obj.save = function () {
self.save = function () {
var body = {};

_.forOwn(mapping, function (fieldMapping, fieldName) {
if (obj[fieldName] != null) {
if (self[fieldName] != null) {
body[fieldName] = (fieldMapping._serialize)
? fieldMapping._serialize(obj[fieldName])
: obj[fieldName];
? fieldMapping._serialize(self[fieldName])
: self[fieldName];
}
});

if (obj.searchSource) {
if (self.searchSource) {
body.kibanaSavedObjectMeta = {
searchSourceJSON: JSON.stringify(_.omit(obj.searchSource.toJSON(), ['sort', 'size']))
searchSourceJSON: JSON.stringify(_.omit(self.searchSource.toJSON(), ['sort', 'size']))
};
}


// Slugify the object id
obj.id = slugifyId(obj.id);
self.id = slugifyId(self.id);

// ensure that the docSource has the current obj.id
docSource.id(obj.id);
// ensure that the docSource has the current self.id
docSource.id(self.id);

// index the document
return obj.saveSource(body);
return self.saveSource(body);
};

obj.saveSource = function (source) {
self.saveSource = function (source) {
return docSource.doIndex(source)
.then(function (id) {
obj.id = id;
self.id = id;
})
.then(function () {
return es.indices.refresh({
Expand All @@ -222,7 +222,7 @@ define(function (require) {
})
.then(function () {
// ensure that the object has the potentially new id
return obj.id;
return self.id;
});
};

Expand All @@ -231,16 +231,16 @@ define(function (require) {
*
* @return {undefined}
*/
obj.destroy = function () {
self.destroy = function () {
docSource.cancelPending();
if (obj.searchSource) obj.searchSource.cancelPending();
if (self.searchSource) self.searchSource.cancelPending();
};

/**
* Delete this object from Elasticsearch
* @return {promise}
*/
obj.delete = function () {
self.delete = function () {
return es.delete({
index: configFile.kibanaIndex,
type: type,
Expand Down
2 changes: 1 addition & 1 deletion src/kibana/components/index_patterns/_field_formats.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
/* markdown
### Formatting a value
To format a response value, you need to get ahold of the field list, which is usually available at `indexPattern.fields`. When the indexPattern is not available, call `courier.getFieldsFor`. Each field object has a `format` property*, which is an object detailed in [_field_formats.js](https://github.com/elasticsearch/kibana4/blob/master/src/kibana/components/index_patterns/_field_formats.js).
To format a response value, you need to get ahold of the field list, which is usually available at `indexPattern.fields`. Each field object has a `format` property*, which is an object detailed in [_field_formats.js](https://github.com/elasticsearch/kibana4/blob/master/src/kibana/components/index_patterns/_field_formats.js).
Once you have the field that a response value came from, pass the value to `field.format.convert(value)` and a formatted string representation of the field will be returned.
Expand Down
Loading

0 comments on commit d399422

Please sign in to comment.