mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
Merge pull request #5 from spenceralger/application_boot
Application boot
This commit is contained in:
commit
c385df2eb9
22 changed files with 779 additions and 347 deletions
|
@ -27,6 +27,6 @@ define(function () {
|
|||
* The default ES index to use for storing Kibana specific object
|
||||
* such as stored dashboards
|
||||
*/
|
||||
kibanaIndex: 'kibana-int'
|
||||
kibanaIndex: 'kibana4-int'
|
||||
};
|
||||
});
|
|
@ -9,8 +9,9 @@ define(function (require) {
|
|||
var DocSource = require('courier/data_source/doc');
|
||||
var SearchSource = require('courier/data_source/search');
|
||||
var HastyRefresh = require('courier/errors').HastyRefresh;
|
||||
var nextTick = require('utils/next_tick');
|
||||
|
||||
var Mapper = require('courier/mapper.js');
|
||||
var Mapper = require('courier/mapper');
|
||||
|
||||
// map constructors to type keywords
|
||||
var sourceTypes = {
|
||||
|
@ -31,6 +32,7 @@ define(function (require) {
|
|||
courier._refs.search,
|
||||
function (err) {
|
||||
if (err) return courier._error(err);
|
||||
courier._activeSearchRequest = null;
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -38,10 +40,7 @@ define(function (require) {
|
|||
// then fetch the onces that are not
|
||||
doc: function (courier) {
|
||||
DocSource.validate(courier, courier._refs.doc, function (err, invalid) {
|
||||
if (err) {
|
||||
courier.stop();
|
||||
return courier.emit('error', err);
|
||||
}
|
||||
if (err) return courier._error(err);
|
||||
|
||||
// if all of the docs are up to date we don't need to do anything else
|
||||
if (invalid.length === 0) return;
|
||||
|
@ -56,8 +55,9 @@ define(function (require) {
|
|||
// default config values
|
||||
var defaults = {
|
||||
fetchInterval: 30000,
|
||||
docInterval: 2500,
|
||||
internalIndex: 'kibana4-int'
|
||||
docInterval: 1500,
|
||||
internalIndex: 'kibana4-int',
|
||||
mapperCacheType: 'mappings'
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -66,12 +66,13 @@ define(function (require) {
|
|||
* search:
|
||||
* - inherits filters, and other query properties
|
||||
* - automatically emit results on a set interval
|
||||
*
|
||||
* doc:
|
||||
* - tracks doc versions
|
||||
* - emits same results event when the doc is updated
|
||||
* - helps seperate versions of kibana running on the same machine stay in sync
|
||||
* - (NI) tracks version and uses it when new versions of a doc are reindexed
|
||||
* - (NI) helps deal with conflicts
|
||||
* - tracks version and uses it to verify that updates are safe to make
|
||||
* - emits conflict event when that happens
|
||||
*
|
||||
* @param {object} config
|
||||
* @param {Client} config.client - The elasticsearch.js client to use for querying. Should be
|
||||
|
@ -104,7 +105,10 @@ define(function (require) {
|
|||
this._onInterval = {};
|
||||
|
||||
// make the mapper accessable
|
||||
this._mapper = new Mapper(this);
|
||||
this._mapper = new Mapper(this, {
|
||||
cacheIndex: config.internalIndex,
|
||||
cacheType: config.mapperCacheType
|
||||
});
|
||||
|
||||
_.each(sourceTypes, function (fn, type) {
|
||||
var courier = this;
|
||||
|
@ -121,7 +125,7 @@ define(function (require) {
|
|||
|
||||
// store a quick "bound" method for triggering
|
||||
this._onInterval[type] = function () {
|
||||
if (courier._refs[type].length) onFetch[type](courier);
|
||||
courier.fetch(type);
|
||||
courier._schedule(type);
|
||||
};
|
||||
|
||||
|
@ -151,7 +155,7 @@ define(function (require) {
|
|||
|
||||
// is the courier currently running?
|
||||
Courier.prototype.running = function () {
|
||||
return !!this._fetchTimer;
|
||||
return !!_.size(this._timer);
|
||||
};
|
||||
|
||||
// stop the courier from fetching more results
|
||||
|
@ -170,11 +174,18 @@ define(function (require) {
|
|||
}, this);
|
||||
};
|
||||
|
||||
// force a fetch of all datasources right now
|
||||
Courier.prototype.fetch = function () {
|
||||
_.forOwn(onFetch, function (fn, type) {
|
||||
if (this._refs[type].length) fn(this);
|
||||
}, this);
|
||||
// force a fetch of all datasources right now, optionally filter by type
|
||||
Courier.prototype.fetch = function (onlyType) {
|
||||
var courier = this;
|
||||
nextTick(function () {
|
||||
_.forOwn(onFetch, function (fn, type) {
|
||||
if (onlyType && onlyType !== type) return;
|
||||
if (courier._refs[type].length) fn(courier);
|
||||
courier._refs[type].forEach(function (ref) {
|
||||
ref.fetchCount ++;
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// data source factory
|
||||
|
@ -187,6 +198,7 @@ define(function (require) {
|
|||
return new Constructor(this, initialState);
|
||||
};
|
||||
|
||||
|
||||
/*****
|
||||
* PRIVATE API
|
||||
*****/
|
||||
|
@ -212,7 +224,8 @@ define(function (require) {
|
|||
var refs = this._refs[source._getType()];
|
||||
if (!_.find(refs, { source: source })) {
|
||||
refs.push({
|
||||
source: source
|
||||
source: source,
|
||||
fetchCount: 0
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -235,7 +248,8 @@ define(function (require) {
|
|||
|
||||
// properly clear scheduled fetches
|
||||
Courier.prototype._clearScheduled = function (type) {
|
||||
this._timer[type] = clearTimeout(this._timer[type]);
|
||||
clearTimeout(this._timer[type]);
|
||||
delete this._timer[type];
|
||||
};
|
||||
|
||||
// alert the courior that a doc has been updated
|
||||
|
@ -246,18 +260,15 @@ define(function (require) {
|
|||
_.each(this._refs.doc, function (ref) {
|
||||
var state = ref.source._state;
|
||||
if (
|
||||
state === updated
|
||||
|| (
|
||||
state.id === updated.id
|
||||
&& state.type === updated.type
|
||||
&& state.index === updated.index
|
||||
)
|
||||
state.id === updated.id
|
||||
&& state.type === updated.type
|
||||
&& state.index === updated.index
|
||||
) {
|
||||
delete ref.version;
|
||||
}
|
||||
});
|
||||
|
||||
onFetch.doc(this);
|
||||
this.fetch('doc');
|
||||
};
|
||||
|
||||
return Courier;
|
||||
|
|
|
@ -45,6 +45,11 @@ define(function (require) {
|
|||
return courier.createSource(this._getType()).inherits(this);
|
||||
};
|
||||
|
||||
this.courier = function (newCourier) {
|
||||
courier = this._courier = newCourier;
|
||||
return this;
|
||||
};
|
||||
|
||||
// get/set internal state values
|
||||
this._methods.forEach(function (name) {
|
||||
this[name] = function (val) {
|
||||
|
@ -96,6 +101,50 @@ define(function (require) {
|
|||
return JSON.stringify(this.toJSON());
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the $scope for a datasource, when a datasource is bound
|
||||
* to a scope, it's event listeners will be wrapped in a call to that
|
||||
* scope's $apply method (safely).
|
||||
*
|
||||
* This also binds the DataSource to the lifetime of the scope: when the scope
|
||||
* is destroyed, the datasource is closed
|
||||
*
|
||||
* @param {AngularScope} $scope - the scope where the event emitter "occurs",
|
||||
* helps angular determine where to start checking for changes
|
||||
* @return {this} - chainable
|
||||
*/
|
||||
DataSource.prototype.$scope = function ($scope) {
|
||||
var emitter = this;
|
||||
|
||||
if (emitter._emitter$scope) {
|
||||
emitter._emitter$scope = $scope;
|
||||
return this;
|
||||
}
|
||||
|
||||
emitter._emitter$scope = $scope;
|
||||
var origOn = emitter.on;
|
||||
|
||||
emitter.on = function (event, listener) {
|
||||
var wrapped = function () {
|
||||
var args = arguments;
|
||||
// always use the stored ref so that it can be updated if needed
|
||||
var $scope = emitter._emitter$scope;
|
||||
$scope[$scope.$$phase ? '$eval' : '$apply'](function () {
|
||||
listener.apply(emitter, args);
|
||||
});
|
||||
};
|
||||
wrapped.listener = listener;
|
||||
return origOn.call(emitter, event, wrapped);
|
||||
};
|
||||
|
||||
emitter.on.restore = function () {
|
||||
delete emitter._emitter$scope;
|
||||
emitter.on = origOn;
|
||||
};
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/*****
|
||||
* PRIVATE API
|
||||
*****/
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
define(function (require) {
|
||||
var DataSource = require('courier/data_source/data_source');
|
||||
var inherits = require('utils/inherits');
|
||||
var nextTick = require('utils/next_tick');
|
||||
var errors = require('courier/errors');
|
||||
var listenerCount = require('utils/event_emitter').listenerCount;
|
||||
var _ = require('lodash');
|
||||
|
@ -23,7 +24,7 @@ define(function (require) {
|
|||
DocSource.fetch = function (courier, refs, cb) {
|
||||
var client = courier._getClient();
|
||||
var allRefs = [];
|
||||
var body = {
|
||||
var getBody = {
|
||||
docs: []
|
||||
};
|
||||
|
||||
|
@ -32,25 +33,30 @@ define(function (require) {
|
|||
if (source._getType() !== 'doc') return;
|
||||
|
||||
allRefs.push(ref);
|
||||
body.docs.push(source._flatten());
|
||||
getBody.docs.push(source._flatten());
|
||||
});
|
||||
|
||||
return client.mget({ body: body }, function (err, resp) {
|
||||
if (err) return cb(err);
|
||||
return client.mget({ body: getBody })
|
||||
.then(function (resp) {
|
||||
_.each(resp.docs, function (resp, i) {
|
||||
var ref = allRefs[i];
|
||||
var source = ref.source;
|
||||
|
||||
_.each(resp.docs, function (resp, i) {
|
||||
var ref = allRefs[i];
|
||||
var source = ref.source;
|
||||
if (resp.error) return source._error(new errors.DocFetchFailure(resp));
|
||||
if (resp.found) {
|
||||
if (ref.version === resp._version) return; // no change
|
||||
ref.version = resp._version;
|
||||
source._storeVersion(resp._version);
|
||||
} else {
|
||||
ref.version = void 0;
|
||||
source._clearVersion();
|
||||
}
|
||||
source.emit('results', resp);
|
||||
});
|
||||
|
||||
if (resp.error) return source._error(new errors.DocFetchFailure(resp));
|
||||
if (ref.version === resp._version) return; // no change
|
||||
ref.version = resp._version;
|
||||
source._storeVersion(resp._version);
|
||||
source.emit('results', resp);
|
||||
});
|
||||
|
||||
cb(err, resp);
|
||||
});
|
||||
cb(void 0, resp);
|
||||
})
|
||||
.catch(cb);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -63,11 +69,10 @@ define(function (require) {
|
|||
DocSource.validate = function (courier, refs, cb) {
|
||||
var invalid = _.filter(refs, function (ref) {
|
||||
var storedVersion = ref.source._getVersion();
|
||||
if (ref.version !== storedVersion) return true;
|
||||
});
|
||||
setTimeout(function () {
|
||||
cb(void 0, invalid);
|
||||
/* jshint eqeqeq: false */
|
||||
return (!ref.fetchCount || ref.version != storedVersion);
|
||||
});
|
||||
nextTick(cb, void 0, invalid);
|
||||
};
|
||||
|
||||
/*****
|
||||
|
@ -102,6 +107,7 @@ define(function (require) {
|
|||
id: state.id,
|
||||
type: state.type,
|
||||
index: state.index,
|
||||
version: source._getVersion(),
|
||||
body: {
|
||||
doc: fields
|
||||
}
|
||||
|
@ -129,7 +135,6 @@ define(function (require) {
|
|||
id: state.id,
|
||||
type: state.type,
|
||||
index: state.index,
|
||||
version: source._getVersion(),
|
||||
body: body,
|
||||
ignore: [409]
|
||||
}, function (err, resp) {
|
||||
|
@ -201,8 +206,8 @@ define(function (require) {
|
|||
* @return {number} - the version number, or NaN
|
||||
*/
|
||||
DocSource.prototype._getVersion = function () {
|
||||
var id = this._versionKey();
|
||||
return _.parseInt(localStorage.getItem(id));
|
||||
var v = localStorage.getItem(this._versionKey());
|
||||
return v ? _.parseInt(v) : void 0;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -212,8 +217,17 @@ define(function (require) {
|
|||
*/
|
||||
DocSource.prototype._storeVersion = function (version) {
|
||||
var id = this._versionKey();
|
||||
localStorage.setItem(id, version);
|
||||
if (version) {
|
||||
localStorage.setItem(id, version);
|
||||
} else {
|
||||
localStorage.removeItem(id);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Clears the stored version for a DocSource
|
||||
*/
|
||||
DocSource.prototype._clearVersion = DocSource.prototype._storeVersion;
|
||||
|
||||
return DocSource;
|
||||
});
|
|
@ -1,62 +1,101 @@
|
|||
define(function (require) {
|
||||
var listenerCount = require('utils/event_emitter').listenerCount;
|
||||
var _ = require('lodash');
|
||||
var errors = {};
|
||||
var inherits = require('utils/inherits');
|
||||
|
||||
// caused by a refresh attempting to start before the prevous is done
|
||||
function HastyRefresh() {
|
||||
this.name = 'HastyRefresh';
|
||||
this.message = 'Courier attempted to start a query before the previous had finished.';
|
||||
var canStack = (function () {
|
||||
var err = new Error();
|
||||
return !!err.stack;
|
||||
}());
|
||||
|
||||
// abstract error class
|
||||
function CourierError(msg, constructor) {
|
||||
this.message = msg;
|
||||
|
||||
Error.call(this, this.message);
|
||||
if (Error.captureStackTrace) {
|
||||
Error.captureStackTrace(this, constructor || CourierError);
|
||||
} else if (canStack) {
|
||||
this.stack = (new Error()).stack;
|
||||
} else {
|
||||
this.stack = '';
|
||||
}
|
||||
}
|
||||
HastyRefresh.prototype = new Error();
|
||||
HastyRefresh.prototype.constructor = HastyRefresh;
|
||||
errors.HastyRefresh = HastyRefresh;
|
||||
errors.CourierError = CourierError;
|
||||
inherits(CourierError, Error);
|
||||
|
||||
// a non-critical cache write to elasticseach failed
|
||||
function CacheWriteFailure() {
|
||||
this.name = 'CacheWriteFailure';
|
||||
this.message = 'A Elasticsearch cache write has failed.';
|
||||
}
|
||||
CacheWriteFailure.prototype = new Error();
|
||||
CacheWriteFailure.prototype.constructor = CacheWriteFailure;
|
||||
errors.CacheWriteFailure = CacheWriteFailure;
|
||||
/**
|
||||
* HastyRefresh error class
|
||||
* @param {String} [msg] - An error message that will probably end up in a log.
|
||||
*/
|
||||
errors.HastyRefresh = function HastyRefresh() {
|
||||
CourierError.call(this,
|
||||
'Courier attempted to start a query before the previous had finished.',
|
||||
errors.HastyRefresh);
|
||||
};
|
||||
inherits(errors.HastyRefresh, CourierError);
|
||||
|
||||
// when a field mapping is requested for an unknown field
|
||||
function FieldNotFoundInCache(name) {
|
||||
this.name = 'FieldNotFoundInCache';
|
||||
this.message = 'The ' + name + ' field was not found in the cached mappings';
|
||||
}
|
||||
FieldNotFoundInCache.prototype = new Error();
|
||||
FieldNotFoundInCache.prototype.constructor = FieldNotFoundInCache;
|
||||
errors.FieldNotFoundInCache = FieldNotFoundInCache;
|
||||
|
||||
// where there is an error getting a doc
|
||||
function DocFetchFailure(resp) {
|
||||
this.name = 'DocFetchFailure';
|
||||
/**
|
||||
* DocFetchFailure Error - where there is an error getting a doc
|
||||
* @param {String} [msg] - An error message that will probably end up in a log.
|
||||
*/
|
||||
errors.DocFetchFailure = function DocFetchFailure(resp) {
|
||||
CourierError.call(this,
|
||||
'Failed to get the doc: ' + JSON.stringify(resp),
|
||||
errors.DocFetchFailure);
|
||||
|
||||
this.resp = resp;
|
||||
this.message = 'Failed to get the doc: ' + JSON.stringify(resp);
|
||||
}
|
||||
DocFetchFailure.prototype = new Error();
|
||||
DocFetchFailure.prototype.constructor = DocFetchFailure;
|
||||
errors.DocFetchFailure = DocFetchFailure;
|
||||
};
|
||||
inherits(errors.DocFetchFailure, CourierError);
|
||||
|
||||
|
||||
/**
|
||||
* Connection Error
|
||||
* @param {String} [msg] - An error message that will probably end up in a log.
|
||||
*/
|
||||
errors.VersionConflict = function VersionConflict(resp) {
|
||||
CourierError.call(this,
|
||||
'Failed to store document changes do to a version conflict.',
|
||||
errors.VersionConflict);
|
||||
|
||||
// there was a conflict storing a doc
|
||||
function VersionConflict(resp) {
|
||||
this.name = 'VersionConflict';
|
||||
this.resp = resp;
|
||||
this.message = 'Failed to store document changes due to a version conflict.';
|
||||
}
|
||||
VersionConflict.prototype = new Error();
|
||||
VersionConflict.prototype.constructor = VersionConflict;
|
||||
errors.VersionConflict = VersionConflict;
|
||||
};
|
||||
inherits(errors.VersionConflict, CourierError);
|
||||
|
||||
// there was a conflict storing a doc
|
||||
function MappingConflict(field) {
|
||||
this.name = 'MappingConflict';
|
||||
this.message = 'Field ' + field + ' is defined as at least two different types in indices matching the pattern';
|
||||
}
|
||||
MappingConflict.prototype = new Error();
|
||||
MappingConflict.prototype.constructor = MappingConflict;
|
||||
errors.MappingConflict = MappingConflict;
|
||||
|
||||
/**
|
||||
* there was a conflict storing a doc
|
||||
* @param {String} field - the fields which contains the conflict
|
||||
*/
|
||||
errors.MappingConflict = function MappingConflict(field) {
|
||||
CourierError.call(this,
|
||||
'Field ' + field + ' is defined as at least two different types in indices matching the pattern',
|
||||
errors.MappingConflict);
|
||||
};
|
||||
inherits(errors.MappingConflict, CourierError);
|
||||
|
||||
/**
|
||||
* a non-critical cache write to elasticseach failed
|
||||
*/
|
||||
errors.CacheWriteFailure = function CacheWriteFailure() {
|
||||
CourierError.call(this,
|
||||
'A Elasticsearch cache write has failed.',
|
||||
errors.CacheWriteFailure);
|
||||
};
|
||||
inherits(errors.CacheWriteFailure, CourierError);
|
||||
|
||||
/**
|
||||
* when a field mapping is requested for an unknown field
|
||||
* @param {String} name - the field name
|
||||
*/
|
||||
errors.FieldNotFoundInCache = function FieldNotFoundInCache(name) {
|
||||
CourierError.call(this,
|
||||
'The ' + name + ' field was not found in the cached mappings',
|
||||
errors.FieldNotFoundInCache);
|
||||
};
|
||||
inherits(errors.FieldNotFoundInCache, CourierError);
|
||||
|
||||
return errors;
|
||||
});
|
|
@ -1,6 +1,7 @@
|
|||
define(function (require) {
|
||||
var _ = require('lodash');
|
||||
var Error = require('courier/errors');
|
||||
var nextTick = require('utils/next_tick');
|
||||
|
||||
/**
|
||||
* - Resolves index patterns
|
||||
|
@ -9,7 +10,7 @@ define(function (require) {
|
|||
*
|
||||
* @class Mapper
|
||||
*/
|
||||
function Mapper(courier) {
|
||||
function Mapper(courier, config) {
|
||||
|
||||
var client = courier._getClient();
|
||||
|
||||
|
@ -23,11 +24,6 @@ define(function (require) {
|
|||
// Save a reference to this
|
||||
var self = this;
|
||||
|
||||
// STUB Until we have another way to get the config object.
|
||||
var config = {
|
||||
index: 'kibana4-int'
|
||||
};
|
||||
|
||||
// Store mappings we've already loaded from Elasticsearch
|
||||
var mappings = {};
|
||||
|
||||
|
@ -39,7 +35,7 @@ define(function (require) {
|
|||
this.getFields = function (dataSource, callback) {
|
||||
if (self.getFieldsFromObject(dataSource)) {
|
||||
// If we already have the fields in our object, use that.
|
||||
setTimeout(callback(undefined, self.getFieldsFromObject(dataSource)), 0);
|
||||
nextTick(callback, void 0, self.getFieldsFromObject(dataSource));
|
||||
} else {
|
||||
// Otherwise, try to get fields from Elasticsearch cache
|
||||
self.getFieldsFromCache(dataSource, function (err, fields) {
|
||||
|
@ -72,7 +68,7 @@ define(function (require) {
|
|||
*/
|
||||
this.getFieldMapping = function (dataSource, field, callback) {
|
||||
self.getFields(dataSource, function (err, fields) {
|
||||
if (_.isUndefined(fields[field])) return courier._error(new Error.FieldNotFoundInCache());
|
||||
if (_.isUndefined(fields[field])) return courier._error(new Error.FieldNotFoundInCache(field));
|
||||
callback(err, fields[field]);
|
||||
});
|
||||
};
|
||||
|
@ -86,7 +82,7 @@ define(function (require) {
|
|||
this.getFieldsMapping = function (dataSource, fields, callback) {
|
||||
self.getFields(dataSource, function (err, fields) {
|
||||
var _mapping = _.object(_.map(fields, function (field) {
|
||||
if (_.isUndefined(fields[field])) return courier._error(new Error.FieldNotFoundInCache());
|
||||
if (_.isUndefined(fields[field])) return courier._error(new Error.FieldNotFoundInCache(field));
|
||||
return [field, fields[field]];
|
||||
}));
|
||||
callback(err, _mapping);
|
||||
|
@ -109,8 +105,8 @@ define(function (require) {
|
|||
*/
|
||||
this.getFieldsFromCache = function (dataSource, callback) {
|
||||
var params = {
|
||||
index: config.index,
|
||||
type: 'mapping',
|
||||
index: config.cacheIndex,
|
||||
type: config.cacheType,
|
||||
id: dataSource._state.index,
|
||||
};
|
||||
|
||||
|
@ -161,10 +157,10 @@ define(function (require) {
|
|||
*/
|
||||
var cacheFieldsToElasticsearch = function (config, index, fields, callback) {
|
||||
client.index({
|
||||
index : config.index,
|
||||
type: 'mapping',
|
||||
id : index,
|
||||
body : fields
|
||||
index: config.cacheIndex,
|
||||
type: config.cacheType,
|
||||
id: index,
|
||||
body: fields
|
||||
}, callback);
|
||||
};
|
||||
|
||||
|
@ -188,9 +184,9 @@ define(function (require) {
|
|||
delete mappings[dataSource._state.index];
|
||||
}
|
||||
client.delete({
|
||||
index : config.index,
|
||||
type: 'mapping',
|
||||
id : dataSource._state.index
|
||||
index: config.cacheIndex,
|
||||
type: config.cacheType,
|
||||
id: dataSource._state.index
|
||||
}, callback);
|
||||
};
|
||||
|
||||
|
|
1
src/courier/tests/config.html
Normal file
1
src/courier/tests/config.html
Normal file
|
@ -0,0 +1 @@
|
|||
<config-test></config-test>
|
114
src/courier/tests/directives.js
Normal file
114
src/courier/tests/directives.js
Normal file
|
@ -0,0 +1,114 @@
|
|||
define(function (require) {
|
||||
var angular = require('angular');
|
||||
|
||||
angular
|
||||
.module('kibana/directives')
|
||||
.directive('configTest', function () {
|
||||
return {
|
||||
restrict: 'E',
|
||||
template: 'My favorite number is {{favoriteNum}} <button ng-click="click()">New Favorite</button>',
|
||||
controller: function ($scope, config) {
|
||||
config.$bind($scope, 'favoriteNum', {
|
||||
default: 0
|
||||
});
|
||||
|
||||
$scope.click = function () {
|
||||
$scope.favoriteNum++;
|
||||
};
|
||||
}
|
||||
};
|
||||
})
|
||||
.directive('courierTest', function () {
|
||||
return {
|
||||
restrict: 'E',
|
||||
scope: {
|
||||
type: '@'
|
||||
},
|
||||
template: '<strong style="float:left">{{count}} : </strong><pre>{{json}}</pre>',
|
||||
controller: function ($scope, courier) {
|
||||
$scope.count = 0;
|
||||
var source = courier.rootSearchSource.extend()
|
||||
.type($scope.type)
|
||||
.source({
|
||||
include: 'country'
|
||||
})
|
||||
.$scope($scope)
|
||||
.on('results', function (resp) {
|
||||
$scope.count ++;
|
||||
$scope.json = JSON.stringify(resp.hits, null, ' ');
|
||||
});
|
||||
}
|
||||
};
|
||||
})
|
||||
.directive('courierDocTest', function () {
|
||||
return {
|
||||
restrict: 'E',
|
||||
scope: {
|
||||
id: '@',
|
||||
type: '@',
|
||||
index: '@'
|
||||
},
|
||||
template: '<strong style="float:left">{{count}} : <button ng-click="click()">reindex</button> : </strong><pre>{{json}}</pre>',
|
||||
controller: function (courier, $scope) {
|
||||
$scope.count = 0;
|
||||
var currentSource;
|
||||
$scope.click = function () {
|
||||
if (currentSource) {
|
||||
source.doIndex(currentSource);
|
||||
}
|
||||
};
|
||||
var source = courier.createSource('doc')
|
||||
.id($scope.id)
|
||||
.type($scope.type)
|
||||
.index($scope.index)
|
||||
.$scope($scope)
|
||||
.on('results', function (doc) {
|
||||
currentSource = doc._source;
|
||||
$scope.count ++;
|
||||
$scope.json = JSON.stringify(doc, null, ' ');
|
||||
});
|
||||
}
|
||||
};
|
||||
})
|
||||
.directive('mappingTest', function () {
|
||||
return {
|
||||
restrict: 'E',
|
||||
scope: {
|
||||
type: '@',
|
||||
fields: '@'
|
||||
},
|
||||
template: 'Mappings:<br><div ng-repeat="(name,mapping) in mappedFields">{{name}} = {{mapping.type}}</div><hr>' +
|
||||
'<strong style="float:left">{{count}} : </strong><pre>{{json}}</pre>',
|
||||
controller: function ($rootScope, $scope, courier) {
|
||||
$scope.count = 0;
|
||||
$scope.mappedFields = {};
|
||||
|
||||
var source = courier.rootSearchSource.extend()
|
||||
.index('logstash-*')
|
||||
.type($scope.type)
|
||||
.source({
|
||||
include: 'geo'
|
||||
})
|
||||
.$scope($scope)
|
||||
.on('results', function (resp) {
|
||||
$scope.count ++;
|
||||
$scope.json = JSON.stringify(resp.hits, null, ' ');
|
||||
});
|
||||
|
||||
var fields = $scope.fields.split(',');
|
||||
|
||||
fields.forEach(function (field) {
|
||||
courier._mapper.getFieldMapping(source, field, function (err, mapping) {
|
||||
$scope.$apply(function () {
|
||||
$scope.mappedFields[field] = mapping;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
courier._mapper.getFields(source, function (err, response, status) {
|
||||
console.log(response);
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
1
src/courier/tests/mapper.html
Normal file
1
src/courier/tests/mapper.html
Normal file
|
@ -0,0 +1 @@
|
|||
<mapping-test type="apache" fields="extension,response,request"></mapping-test>
|
|
@ -12,7 +12,7 @@
|
|||
<script>require(['main'], function () {});</script>
|
||||
</head>
|
||||
<body>
|
||||
<div ng-controller="Kibana">
|
||||
<div ng-controller="kibana">
|
||||
<div ng-view></div>
|
||||
</div>
|
||||
</body>
|
||||
|
|
15
src/kibana/constants/base.js
Normal file
15
src/kibana/constants/base.js
Normal file
|
@ -0,0 +1,15 @@
|
|||
define(function (require) {
|
||||
var angular = require('angular');
|
||||
|
||||
/**
|
||||
* broke this out so that it could be loaded before the application is
|
||||
*/
|
||||
angular.module('kibana/constants')
|
||||
// This stores the Kibana revision number, @REV@ is replaced by grunt.
|
||||
.constant('kbnVersion', '@REV@')
|
||||
|
||||
// Use this for cache busting partials
|
||||
.constant('cacheBust', 'cache-bust=' + Date.now())
|
||||
|
||||
;
|
||||
});
|
|
@ -1,93 +1,20 @@
|
|||
define(function (require) {
|
||||
var angular = require('angular');
|
||||
var _ = require('lodash');
|
||||
var $ = require('jquery');
|
||||
|
||||
angular.module('kibana/controllers')
|
||||
.controller('Kibana', function (courier, $scope, $rootScope) {
|
||||
$rootScope.dataSource = courier.createSource('search')
|
||||
.index('_all')
|
||||
.size(5);
|
||||
require('services/config');
|
||||
require('services/courier');
|
||||
|
||||
// this should be triggered from within the controlling application
|
||||
setTimeout(_.bindKey(courier, 'start'), 15);
|
||||
});
|
||||
angular
|
||||
.module('kibana/controllers')
|
||||
.controller('kibana', function ($scope, courier) {
|
||||
setTimeout(function () {
|
||||
courier.start();
|
||||
}, 15);
|
||||
|
||||
angular.module('kibana/directives')
|
||||
.directive('courierTest', function () {
|
||||
return {
|
||||
restrict: 'E',
|
||||
scope: {
|
||||
type: '@',
|
||||
fields: '@'
|
||||
},
|
||||
template: 'Mappings:<br><div ng-repeat="(name,mapping) in mappedFields">{{name}} = {{mapping.type}}</div><hr>' +
|
||||
'<strong style="float:left">{{count}} : </strong><pre>{{json}}</pre>',
|
||||
controller: function ($rootScope, $scope, courier) {
|
||||
$scope.count = 0;
|
||||
$scope.mappedFields = {};
|
||||
|
||||
var source = $rootScope.dataSource.extend()
|
||||
.index('logstash-*')
|
||||
.type($scope.type)
|
||||
.source({
|
||||
include: 'geo'
|
||||
})
|
||||
.on('results', function (resp) {
|
||||
$scope.count ++;
|
||||
$scope.json = JSON.stringify(resp.hits, null, ' ');
|
||||
});
|
||||
|
||||
var fields = $scope.fields.split(',');
|
||||
|
||||
|
||||
_.each(fields, function (field) {
|
||||
courier._mapper.getFieldMapping(source, field, function (err, mapping) {
|
||||
$scope.mappedFields[field] = mapping;
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
courier._mapper.getFields(source, function (err, response, status) {
|
||||
console.log(response);
|
||||
});
|
||||
|
||||
$scope.$watch('type', source.type);
|
||||
}
|
||||
};
|
||||
})
|
||||
.directive('courierDocTest', function () {
|
||||
return {
|
||||
restrict: 'E',
|
||||
scope: {
|
||||
id: '@',
|
||||
type: '@',
|
||||
index: '@'
|
||||
},
|
||||
template: '<strong style="float:left">{{count}} : <button ng-click="click()">reindex</button> : </strong>' +
|
||||
'<pre>{{json}} BEER</pre>',
|
||||
controller: function (courier, $scope) {
|
||||
$scope.count = 0;
|
||||
|
||||
console.log(courier);
|
||||
|
||||
var currentSource;
|
||||
$scope.click = function () {
|
||||
if (currentSource) {
|
||||
source.update(currentSource);
|
||||
}
|
||||
};
|
||||
|
||||
var source = courier.createSource('doc')
|
||||
.id($scope.id)
|
||||
.type($scope.type)
|
||||
.index($scope.index)
|
||||
.on('results', function (doc) {
|
||||
currentSource = doc._source;
|
||||
$scope.count ++;
|
||||
$scope.json = JSON.stringify(doc, null, ' ');
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
$scope.$on('$routeChangeSuccess', function () {
|
||||
if (courier.running()) courier.fetch();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -7,90 +7,72 @@ define(function (require) {
|
|||
var $ = require('jquery');
|
||||
var _ = require('lodash');
|
||||
var scopedRequire = require('require');
|
||||
var enableAsyncModules = require('utils/async_modules');
|
||||
var setup = require('./setup');
|
||||
|
||||
require('elasticsearch');
|
||||
require('angular-route');
|
||||
|
||||
// keep a reference to each module defined before boot, so that
|
||||
// after boot it can define new features. Also serves as a flag.
|
||||
var preBootModules = [];
|
||||
|
||||
// the functions needed to register different
|
||||
// features defined after boot
|
||||
var registerFns = {};
|
||||
var app = angular.module('kibana', []);
|
||||
enableAsyncModules(app);
|
||||
|
||||
var dependencies = [
|
||||
'elasticsearch',
|
||||
'ngRoute',
|
||||
'kibana',
|
||||
'ngRoute'
|
||||
'kibana/controllers',
|
||||
'kibana/directives',
|
||||
'kibana/factories',
|
||||
'kibana/services',
|
||||
'kibana/filters',
|
||||
'kibana/constants'
|
||||
];
|
||||
|
||||
_('controllers directives factories services filters'.split(' '))
|
||||
.map(function (type) { return 'kibana/' + type; })
|
||||
.each(function (name) {
|
||||
preBootModules.push(angular.module(name, []));
|
||||
dependencies.push(name);
|
||||
});
|
||||
function isScope(obj) {
|
||||
return obj && obj.$evalAsync && obj.$watch;
|
||||
}
|
||||
|
||||
var app = angular.module('kibana', dependencies);
|
||||
|
||||
// This stores the Kibana revision number, @REV@ is replaced by grunt.
|
||||
app.constant('kbnVersion', '@REV@');
|
||||
|
||||
// Use this for cache busting partials
|
||||
app.constant('cacheBust', 'cache-bust=' + Date.now());
|
||||
|
||||
/**
|
||||
* Modules that need to register components within the application after
|
||||
* bootstrapping is complete need to pass themselves to this method.
|
||||
*
|
||||
* @param {object} module - The Angular module
|
||||
* @return {object} module
|
||||
*/
|
||||
app.useModule = function (module) {
|
||||
if (preBootModules) {
|
||||
preBootModules.push(module);
|
||||
} else {
|
||||
_.extend(module, registerFns);
|
||||
dependencies.forEach(function (name) {
|
||||
if (name.indexOf('kibana/') === 0) {
|
||||
app.useModule(angular.module(name, []));
|
||||
}
|
||||
return module;
|
||||
};
|
||||
|
||||
app.config(function ($routeProvider, $controllerProvider, $compileProvider, $filterProvider, $provide) {
|
||||
$routeProvider
|
||||
.when('/courier-test', {
|
||||
templateUrl: 'courier/test.html',
|
||||
})
|
||||
.otherwise({
|
||||
redirectTo: 'courier-test'
|
||||
});
|
||||
|
||||
// this is how the internet told me to dynamically add modules :/
|
||||
registerFns.controller = $controllerProvider.register;
|
||||
registerFns.directive = $compileProvider.directive;
|
||||
registerFns.factory = $provide.factory;
|
||||
registerFns.service = $provide.service;
|
||||
registerFns.filter = $filterProvider.register;
|
||||
});
|
||||
|
||||
// load the core components
|
||||
require([
|
||||
'services/courier',
|
||||
'services/es',
|
||||
'services/config',
|
||||
'controllers/kibana'
|
||||
], function () {
|
||||
app.requires = dependencies;
|
||||
|
||||
// bootstrap the app
|
||||
$(function () {
|
||||
angular
|
||||
.bootstrap(document, dependencies)
|
||||
.invoke(function ($rootScope) {
|
||||
_.each(preBootModules, function (module) {
|
||||
_.extend(module, registerFns);
|
||||
});
|
||||
preBootModules = false;
|
||||
});
|
||||
app.config(function ($routeProvider) {
|
||||
$routeProvider
|
||||
.when('/', {
|
||||
templateUrl: 'kibana/partials/index.html'
|
||||
})
|
||||
.when('/config-test', {
|
||||
templateUrl: 'courier/tests/config.html',
|
||||
})
|
||||
.when('/mapper-test', {
|
||||
templateUrl: 'courier/tests/mapper.html',
|
||||
})
|
||||
.when('/courier-test', {
|
||||
templateUrl: 'courier/tests/index.html',
|
||||
})
|
||||
.otherwise({
|
||||
redirectTo: '/'
|
||||
});
|
||||
});
|
||||
|
||||
setup(app, function (err) {
|
||||
if (err) throw err;
|
||||
|
||||
// load the elasticsearch service
|
||||
require([
|
||||
'courier/tests/directives',
|
||||
'controllers/kibana',
|
||||
'constants/base'
|
||||
], function () {
|
||||
// bootstrap the app
|
||||
$(function () {
|
||||
angular
|
||||
.bootstrap(document, dependencies);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
5
src/kibana/partials/index.html
Normal file
5
src/kibana/partials/index.html
Normal file
|
@ -0,0 +1,5 @@
|
|||
<ul>
|
||||
<li><a ng-href="#/courier-test">Courier Test</a></li>
|
||||
<li><a ng-href="#/config-test">Config Test</a></li>
|
||||
<li><a ng-href="#/mapper-test">Mapper Test</a></li>
|
||||
</ul>
|
|
@ -16,6 +16,7 @@
|
|||
var bowerComponents = [
|
||||
'angular',
|
||||
'angular-route',
|
||||
['async', 'lib/async'],
|
||||
'd3',
|
||||
['elasticsearch', 'elasticsearch.angular'],
|
||||
'jquery',
|
||||
|
|
|
@ -1,89 +1,149 @@
|
|||
define(function (require) {
|
||||
var angular = require('angular');
|
||||
var configFile = require('../../config');
|
||||
var _ = require('lodash');
|
||||
var configFile = require('../../config');
|
||||
var nextTick = require('utils/next_tick');
|
||||
|
||||
require('services/courier');
|
||||
|
||||
var module = angular.module('kibana/services');
|
||||
module.service('config', function ($q, es, courier) {
|
||||
// share doc and val cache between apps
|
||||
var doc;
|
||||
var vals = {};
|
||||
|
||||
var app = angular.module('kibana');
|
||||
var config = {};
|
||||
module.service('config', function ($q, $rootScope, courier, kbnVersion) {
|
||||
var watchers = {};
|
||||
var unwatchers = [];
|
||||
|
||||
function watch(key, onChange) {
|
||||
// probably a horrible idea
|
||||
if (!watchers[key]) watchers[key] = [];
|
||||
watchers[key].push(onChange);
|
||||
if (!doc) {
|
||||
doc = courier.createSource('doc')
|
||||
.index(configFile.kibanaIndex)
|
||||
.type('config')
|
||||
.id(kbnVersion);
|
||||
} else {
|
||||
// clean up after previous app
|
||||
doc
|
||||
.removeAllListeners('results')
|
||||
.courier(courier);
|
||||
}
|
||||
|
||||
function change(key, val) {
|
||||
if (config[key] !== val) {
|
||||
var oldVal = config[key];
|
||||
config[key] = val;
|
||||
if (watchers[key]) {
|
||||
watchers[key].forEach(function (watcher) {
|
||||
watcher(val, oldVal);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getDoc() {
|
||||
var defer = $q.promise();
|
||||
|
||||
courier.get({
|
||||
index: config.kibanaIndex,
|
||||
type: 'config',
|
||||
id: app.constant('kbnVersion')
|
||||
}, function fetchDoc(err, doc) {
|
||||
_.assign(config, doc);
|
||||
defer.resolve();
|
||||
}, function onDocUpdate(doc) {
|
||||
_.forOwn(doc, function (val, key) {
|
||||
change(key, val);
|
||||
});
|
||||
doc.on('results', function (resp) {
|
||||
if (!resp.found) return; // init should ensure it exists
|
||||
_.forOwn(resp._source, function (val, key) {
|
||||
if (vals[key] !== val) _change(key, val);
|
||||
});
|
||||
});
|
||||
|
||||
/******
|
||||
* PUBLIC API
|
||||
******/
|
||||
|
||||
function init() {
|
||||
var defer = $q.defer();
|
||||
courier.fetch();
|
||||
doc.on('results', function completeInit(resp) {
|
||||
// ONLY ACT IF !resp.found
|
||||
if (!resp.found) {
|
||||
console.log('creating empty config doc');
|
||||
doc.doIndex({});
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('fetched config doc');
|
||||
doc.removeListener('results', completeInit);
|
||||
defer.resolve();
|
||||
});
|
||||
return defer.promise;
|
||||
}
|
||||
|
||||
return {
|
||||
get: function (key) {
|
||||
return config[key];
|
||||
},
|
||||
set: function (key, val) {
|
||||
// sets a value in the config
|
||||
// the es doc must be updated successfully for the update to reflect in the get api.
|
||||
|
||||
if (key === 'elasticsearch' || key === 'kibanaIndex') {
|
||||
return $q.reject(new Error('These values must be updated in the config.js file.'));
|
||||
}
|
||||
function get(key) {
|
||||
return vals[key];
|
||||
}
|
||||
|
||||
function set(key, val) {
|
||||
// sets a value in the config
|
||||
// the es doc must be updated successfully for the update to reflect in the get api.
|
||||
if (vals[key] === val) {
|
||||
var defer = $q.defer();
|
||||
|
||||
if (config[key] === val) {
|
||||
defer.resolve();
|
||||
return defer.promise;
|
||||
}
|
||||
|
||||
var body = {};
|
||||
body[key] = val;
|
||||
courier.update({
|
||||
index: config.kibanaIndex,
|
||||
type: 'config',
|
||||
id: app.constant('kbnVersion'),
|
||||
body: body
|
||||
}, function (err) {
|
||||
if (err) return defer.reject(err);
|
||||
|
||||
change(key, val);
|
||||
defer.resolve();
|
||||
});
|
||||
|
||||
defer.resolve(true);
|
||||
return defer.promise;
|
||||
},
|
||||
$watch: watch,
|
||||
init: getDoc
|
||||
};
|
||||
}
|
||||
|
||||
var update = {};
|
||||
update[key] = val;
|
||||
|
||||
return doc.doUpdate(update)
|
||||
.then(function () {
|
||||
_change(key, val);
|
||||
return true;
|
||||
})
|
||||
.catch(function (err) {
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
function $watch(key, onChange) {
|
||||
// probably a horrible idea
|
||||
if (!watchers[key]) watchers[key] = [];
|
||||
watchers[key].push(onChange);
|
||||
_notify(onChange, vals[key]);
|
||||
}
|
||||
|
||||
function $bindToScope($scope, key, opts) {
|
||||
$watch(key, function (val) {
|
||||
if (opts && val === void 0) val = opts['default'];
|
||||
$scope[key] = val;
|
||||
});
|
||||
|
||||
var first = true;
|
||||
unwatchers.push($scope.$watch(key, function (newVal) {
|
||||
if (first) return first = false;
|
||||
set(key, newVal);
|
||||
}));
|
||||
}
|
||||
|
||||
function close() {
|
||||
watchers = null;
|
||||
unwatchers.forEach(function (unwatcher) {
|
||||
unwatcher();
|
||||
});
|
||||
}
|
||||
|
||||
// expose public API on the instance
|
||||
this.init = init;
|
||||
this.close = close;
|
||||
this.get = get;
|
||||
this.set = set;
|
||||
this.$bind = $bindToScope;
|
||||
this.$watch = $watch;
|
||||
|
||||
/*******
|
||||
* PRIVATE API
|
||||
*******/
|
||||
|
||||
function _change(key, val) {
|
||||
_notify(watchers[key], val, vals[key]);
|
||||
vals[key] = val;
|
||||
console.log(key, 'is now', val);
|
||||
}
|
||||
|
||||
function _notify(fns, cur, prev) {
|
||||
if ($rootScope.$$phase) {
|
||||
// reschedule
|
||||
nextTick(_notify, fns, cur, prev);
|
||||
return;
|
||||
}
|
||||
|
||||
var isArr = _.isArray(fns);
|
||||
if (!fns || (isArr && !fns.length)) return;
|
||||
|
||||
$rootScope.$apply(function () {
|
||||
if (!isArr) return fns(cur, prev);
|
||||
|
||||
fns.forEach(function (onChange) {
|
||||
onChange(cur, prev);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
|
@ -3,25 +3,31 @@ define(function (require) {
|
|||
var Courier = require('courier/courier');
|
||||
var DocSource = require('courier/data_source/doc');
|
||||
var errors = require('courier/errors');
|
||||
var configFile = require('../../config');
|
||||
|
||||
require('services/promises');
|
||||
require('services/es');
|
||||
|
||||
var courier; // share the courier amoungst all of the apps
|
||||
angular.module('kibana/services')
|
||||
.service('courier', function (es, promises) {
|
||||
if (courier) return courier;
|
||||
|
||||
promises.playNice(DocSource.prototype, [
|
||||
'doUpdate',
|
||||
'doIndex'
|
||||
]);
|
||||
|
||||
var courier = new Courier({
|
||||
courier = new Courier({
|
||||
fetchInterval: 15000,
|
||||
client: es,
|
||||
promises: promises
|
||||
internalIndex: configFile.kibanaIndex
|
||||
});
|
||||
|
||||
courier.errors = errors;
|
||||
|
||||
courier.rootSearchSource = courier.createSource('search');
|
||||
|
||||
return courier;
|
||||
});
|
||||
});
|
|
@ -1,8 +1,16 @@
|
|||
define(function (require) {
|
||||
var angular = require('angular');
|
||||
var configFile = require('../../config');
|
||||
|
||||
var module = angular.module('kibana/services');
|
||||
module.service('es', function (esFactory) {
|
||||
return esFactory();
|
||||
});
|
||||
var es; // share the client amoungst all apps
|
||||
require('angular')
|
||||
.module('kibana/services')
|
||||
.service('es', function (esFactory, $q) {
|
||||
if (es) return es;
|
||||
|
||||
es = esFactory({
|
||||
host: configFile.elasticsearch
|
||||
});
|
||||
|
||||
return es;
|
||||
});
|
||||
});
|
101
src/kibana/setup.js
Normal file
101
src/kibana/setup.js
Normal file
|
@ -0,0 +1,101 @@
|
|||
define(function (require) {
|
||||
var angular = require('angular');
|
||||
var async = require('async');
|
||||
var $ = require('jquery');
|
||||
var configFile = require('../config');
|
||||
var nextTick = require('utils/next_tick');
|
||||
|
||||
/**
|
||||
* Setup the kibana application, ensuring that the kibanaIndex exists,
|
||||
* and perform any migration of data that is required.
|
||||
*
|
||||
* @param {Module} app - The Kibana module
|
||||
* @param {function} done - callback
|
||||
*/
|
||||
return function SetupApp(app, done) {
|
||||
// load angular deps
|
||||
require([
|
||||
'elasticsearch',
|
||||
'services/es',
|
||||
'services/config',
|
||||
'constants/base'
|
||||
], function () {
|
||||
$(function () {
|
||||
|
||||
var setup = angular.module('setup', [
|
||||
'elasticsearch',
|
||||
'kibana/services',
|
||||
'kibana/constants'
|
||||
]);
|
||||
var appEl = document.createElement('div');
|
||||
var kibanaIndexExists;
|
||||
|
||||
setup.run(function (es, config) {
|
||||
// init the setup module
|
||||
async.series([
|
||||
async.apply(checkForKibanaIndex, es),
|
||||
async.apply(createKibanaIndex, es),
|
||||
async.apply(checkForCurrentConfigDoc, es),
|
||||
async.apply(initConfig, config)
|
||||
], function (err) {
|
||||
// ready to go, remove the appEl, close services and boot be done
|
||||
appEl.remove();
|
||||
console.log('booting application');
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
angular.bootstrap(appEl, ['setup']);
|
||||
|
||||
function checkForKibanaIndex(es, done) {
|
||||
console.log('look for kibana index');
|
||||
es.indices.exists({
|
||||
index: configFile.kibanaIndex
|
||||
}, function (err, exists) {
|
||||
console.log('kibana index does', (exists ? '' : 'not ') + 'exist');
|
||||
kibanaIndexExists = exists;
|
||||
return done(err);
|
||||
});
|
||||
}
|
||||
|
||||
// create the index if it doens't exist already
|
||||
function createKibanaIndex(es, done) {
|
||||
if (kibanaIndexExists) return done();
|
||||
console.log('creating kibana index');
|
||||
es.indices.create({
|
||||
index: configFile.kibanaIndex,
|
||||
body: {
|
||||
settings: {
|
||||
mappings: {
|
||||
mappings: {
|
||||
_source: {
|
||||
enabled: false
|
||||
},
|
||||
properties: {
|
||||
type: {
|
||||
type: 'string',
|
||||
index: 'not_analyzed'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, done);
|
||||
}
|
||||
|
||||
// if the index is brand new, no need to see if it is out of data
|
||||
function checkForCurrentConfigDoc(es, done) {
|
||||
if (!kibanaIndexExists) return done();
|
||||
console.log('checking if migration is necessary: not implemented');
|
||||
nextTick(done);
|
||||
}
|
||||
|
||||
function initConfig(config, done) {
|
||||
console.log('initializing config service');
|
||||
config.init().then(function () { done(); }, done);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
});
|
58
src/kibana/utils/async_modules.js
Normal file
58
src/kibana/utils/async_modules.js
Normal file
|
@ -0,0 +1,58 @@
|
|||
define(function (require) {
|
||||
var _ = require('lodash');
|
||||
|
||||
/* TODO: this will probably fail to work when we have multiple apps.
|
||||
* Might need to propogate registrations to multiple providers
|
||||
*/
|
||||
function enable(app) {
|
||||
// keep a reference to each module defined before boot, so that
|
||||
// after boot it can define new features. Also serves as a flag.
|
||||
var preBootModules = [];
|
||||
|
||||
// the functions needed to register different
|
||||
// features defined after boot
|
||||
var registerFns = {};
|
||||
|
||||
app.config(function ($controllerProvider, $compileProvider, $filterProvider, $provide) {
|
||||
// this is how the internet told me to dynamically add modules :/
|
||||
registerFns = {
|
||||
controller: $controllerProvider.register,
|
||||
directive: $compileProvider.directive,
|
||||
factory: $provide.factory,
|
||||
service: $provide.service,
|
||||
constant: $provide.constant,
|
||||
value: $provide.value,
|
||||
filter: $filterProvider.register
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* Modules that need to register components within the application after
|
||||
* bootstrapping is complete need to pass themselves to this method.
|
||||
*
|
||||
* @param {object} module - The Angular module
|
||||
* @return {object} module
|
||||
*/
|
||||
app.useModule = function (module) {
|
||||
if (preBootModules) {
|
||||
preBootModules.push(module);
|
||||
} else {
|
||||
_.extend(module, registerFns);
|
||||
}
|
||||
return module;
|
||||
};
|
||||
|
||||
/**
|
||||
* Called after app is bootrapped to enable asyncModules
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
app.run(function () {
|
||||
_.each(preBootModules, function (module) {
|
||||
_.extend(module, registerFns);
|
||||
});
|
||||
preBootModules = false;
|
||||
});
|
||||
}
|
||||
|
||||
return enable;
|
||||
});
|
44
src/kibana/utils/next_tick.js
Normal file
44
src/kibana/utils/next_tick.js
Normal file
|
@ -0,0 +1,44 @@
|
|||
define(function () {
|
||||
|
||||
var canSetImmediate = typeof window !== 'undefined' && window.setImmediate;
|
||||
var canPost = typeof window !== 'undefined' && window.postMessage && window.addEventListener
|
||||
;
|
||||
|
||||
if (canSetImmediate) {
|
||||
return function (f) { return window.setImmediate(f); };
|
||||
}
|
||||
|
||||
if (canPost) {
|
||||
var queue = [];
|
||||
window.addEventListener('message', function (ev) {
|
||||
if (ev.source === window && ev.data === 'process-tick') {
|
||||
ev.stopPropagation();
|
||||
if (queue.length > 0) {
|
||||
var fn = queue.shift();
|
||||
if (typeof fn === 'function') {
|
||||
fn();
|
||||
} else {
|
||||
// partial args were supplied
|
||||
var args = fn;
|
||||
fn = args.shift();
|
||||
fn.apply(null, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, true);
|
||||
|
||||
return function nextTick(fn) {
|
||||
if (arguments.length > 1) {
|
||||
queue.push([fn].concat([].slice.call(arguments, 1)));
|
||||
} else {
|
||||
queue.push(fn);
|
||||
}
|
||||
window.postMessage('process-tick', '*');
|
||||
};
|
||||
}
|
||||
|
||||
return function nextTick(fn) {
|
||||
setTimeout(fn, 0);
|
||||
};
|
||||
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue