mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 01:13:23 -04:00
Merge branch 'master' into fixed_scales
This commit is contained in:
commit
a5aca9d8c5
29 changed files with 789 additions and 330 deletions
|
@ -22,6 +22,13 @@ Please make sure you have signed the [Contributor License Agreement](http://www.
|
|||
```sh
|
||||
npm install -g grunt-cli bower
|
||||
```
|
||||
|
||||
- Clone the kibana repo and move into it
|
||||
|
||||
```sh
|
||||
git clone https://github.com/elastic/kibana.git kibana
|
||||
cd kibana
|
||||
```
|
||||
|
||||
- Install node and bower dependencies
|
||||
|
||||
|
|
|
@ -49,7 +49,8 @@
|
|||
"requirejs-text": "~2.0.10",
|
||||
"lodash-deep": "spenceralger/lodash-deep#compat",
|
||||
"marked": "~0.3.2",
|
||||
"numeral": "~1.5.3"
|
||||
"numeral": "~1.5.3",
|
||||
"leaflet-draw": "~0.2.4"
|
||||
},
|
||||
"devDependencies": {}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
= Kibana User Guide
|
||||
|
||||
:ref: http://www.elastic.co/guide/en/elasticsearch/reference/current
|
||||
:shield: https://www.elastic.co/guide/en/shield/current
|
||||
|
||||
include::introduction.asciidoc[]
|
||||
|
||||
|
|
|
@ -24,19 +24,26 @@ If you are using Shield to authenticate Elasticsearch users, you need to provide
|
|||
the Kibana server with credentials so it can access the `.kibana` index and monitor
|
||||
the cluster.
|
||||
|
||||
To configure credentials for the Kibana server, set the `kibana_elasticsearch_username` and
|
||||
`kibana_elasticsearch_password` properties in `kibana.yml`:
|
||||
To configure credentials for the Kibana server:
|
||||
|
||||
----
|
||||
# If your Elasticsearch is protected with basic auth:
|
||||
kibana_elasticsearch_username: kibana4
|
||||
kibana_elasticsearch_password: kibana4
|
||||
----
|
||||
|
||||
For information about assigning the Kibana server the necessary permissions in Shield,
|
||||
see https://www.elastic.co/guide/en/shield/current/_shield_with_kibana_4.html[Shield with Kibana 4]
|
||||
. Assign the `kibana4_server` role to a user in Shield. For more information, see
|
||||
{shield}/_shield_with_kibana_4.html[Configuring a Role for the Kibana 4 Server]
|
||||
in the Shield documentation.
|
||||
|
||||
. Set the `kibana_elasticsearch_username` and
|
||||
`kibana_elasticsearch_password` properties in `kibana.yml` to specify the credentials
|
||||
of the user you assigned the `kibana4_server`
|
||||
role:
|
||||
+
|
||||
[source,text]
|
||||
----
|
||||
kibana_elasticsearch_username: kibana4-user
|
||||
kibana_elasticsearch_password: kibana4-password
|
||||
----
|
||||
|
||||
Kibana 4 users also need access to the `.kibana` index so they can save and load searches, visualizations, and dashboards.
|
||||
For more information, see {shield}/_shield_with_kibana_4.html#kibana4-roles[Configuring Roles for Kibana 4 Users] in the Shield documentation.
|
||||
|
||||
[float]
|
||||
[[enabling-ssl]]
|
||||
=== Enabling SSL
|
||||
|
@ -45,6 +52,7 @@ sends to Elasticsearch.
|
|||
|
||||
To encrypt communications between the browser and the Kibana server, you configure the `ssl_key_file `and `ssl_cert_file` properties in `kibana.yml`:
|
||||
|
||||
[source,text]
|
||||
----
|
||||
# SSL for outgoing requests from the Kibana Server (PEM formatted)
|
||||
ssl_key_file: /path/to/your/server.key
|
||||
|
@ -58,12 +66,15 @@ the Kibana server and Elasticsearch are encrypted.
|
|||
To do this, you specify the HTTPS
|
||||
protocol when you configure the Elasticsearch URL in `kibana.yml`:
|
||||
|
||||
[source,text]
|
||||
----
|
||||
elasticsearch: "https://<your_elasticsearch_host>.com:9200"
|
||||
----
|
||||
|
||||
If you are using a self-signed certificate for Elasticsearch, set the `ca` property in
|
||||
`kibana.yml` to specify the location of the PEM file. Setting the `ca` property lets you leave the `verify_ssl` option enabled.
|
||||
|
||||
[source,text]
|
||||
----
|
||||
# If you need to provide a CA certificate for your Elasticsarech instance, put
|
||||
# the path of the pem file here.
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
define(function (require) {
|
||||
var decodeGeoHash = require('utils/decode_geo_hash');
|
||||
var _ = require('lodash');
|
||||
|
||||
function readRows(table, agg, index, chart) {
|
||||
var geoJson = chart.geoJson;
|
||||
|
@ -8,6 +9,7 @@ define(function (require) {
|
|||
props.length = table.rows.length;
|
||||
props.min = null;
|
||||
props.max = null;
|
||||
props.agg = agg;
|
||||
|
||||
table.rows.forEach(function (row) {
|
||||
var geohash = row[index.geo].value;
|
||||
|
|
|
@ -26,6 +26,7 @@ define(function (require) {
|
|||
Private(require('./mapExists')),
|
||||
Private(require('./mapMissing')),
|
||||
Private(require('./mapQueryString')),
|
||||
Private(require('./mapGeoBoundingBox')),
|
||||
Private(require('./mapScript')),
|
||||
Private(require('./mapDefault')) // ProTip: last one to get applied
|
||||
];
|
||||
|
|
21
src/kibana/components/filter_bar/lib/mapGeoBoundingBox.js
Normal file
21
src/kibana/components/filter_bar/lib/mapGeoBoundingBox.js
Normal file
|
@ -0,0 +1,21 @@
|
|||
define(function (require) {
|
||||
var _ = require('lodash');
|
||||
return function mapGeoBoundBoxProvider(Promise, courier) {
|
||||
return function (filter) {
|
||||
var key, value, topLeft, bottomRight, field;
|
||||
if (filter.geo_bounding_box) {
|
||||
return courier
|
||||
.indexPatterns
|
||||
.get(filter.meta.index).then(function (indexPattern) {
|
||||
key = _.keys(filter.geo_bounding_box)[0];
|
||||
field = indexPattern.fields.byName[key];
|
||||
topLeft = field.format.convert(filter.geo_bounding_box[field.name].top_left);
|
||||
bottomRight = field.format.convert(filter.geo_bounding_box[field.name].bottom_right);
|
||||
value = topLeft + ' to ' + bottomRight;
|
||||
return { key: key, value: value };
|
||||
});
|
||||
}
|
||||
return Promise.reject(filter);
|
||||
};
|
||||
};
|
||||
});
|
19
src/kibana/components/filter_bar/push_filter.js
Normal file
19
src/kibana/components/filter_bar/push_filter.js
Normal file
|
@ -0,0 +1,19 @@
|
|||
define(function (require) {
|
||||
var _ = require('lodash');
|
||||
|
||||
return function () {
|
||||
return function ($state) {
|
||||
if (!_.isObject($state)) throw new Error ('pushFilters requires a state object');
|
||||
return function (filter, negate, index) {
|
||||
// Hierarchical and tabular data set their aggConfigResult parameter
|
||||
// differently because of how the point is rewritten between the two. So
|
||||
// we need to check if the point.orig is set, if not use try the point.aggConfigResult
|
||||
var filters = _.clone($state.filters || []);
|
||||
var pendingFilter = { meta: { negate: negate, index: index }};
|
||||
_.extend(pendingFilter, filter);
|
||||
filters.push(pendingFilter);
|
||||
$state.filters = filters;
|
||||
};
|
||||
};
|
||||
};
|
||||
});
|
|
@ -1,46 +1,61 @@
|
|||
// Takes a hit, merges it with any stored/scripted fields, and with the metaFields
|
||||
// returns a flattened version
|
||||
define(function (require) {
|
||||
var _ = require('lodash');
|
||||
return function FlattenHitProvider(config, $rootScope) {
|
||||
|
||||
function flattenHit(indexPattern, hit) {
|
||||
var flat = {};
|
||||
var _ = require('lodash');
|
||||
|
||||
// recursively merge _source
|
||||
var fields = indexPattern.fields.byName;
|
||||
(function flatten(obj, keyPrefix) {
|
||||
keyPrefix = keyPrefix ? keyPrefix + '.' : '';
|
||||
_.forOwn(obj, function (val, key) {
|
||||
key = keyPrefix + key;
|
||||
var metaFields = config.get('metaFields');
|
||||
$rootScope.$on('change:config.metaFields', function () {
|
||||
metaFields = config.get('metaFields');
|
||||
});
|
||||
|
||||
if (flat[key] !== void 0) return;
|
||||
function flattenHit(indexPattern, hit) {
|
||||
var flat = {};
|
||||
|
||||
var hasValidMapping = (fields[key] && fields[key].type !== 'conflict');
|
||||
var isValue = !_.isPlainObject(val);
|
||||
// recursively merge _source
|
||||
var fields = indexPattern.fields.byName;
|
||||
(function flatten(obj, keyPrefix) {
|
||||
keyPrefix = keyPrefix ? keyPrefix + '.' : '';
|
||||
_.forOwn(obj, function (val, key) {
|
||||
key = keyPrefix + key;
|
||||
|
||||
if (hasValidMapping || isValue) {
|
||||
flat[key] = val;
|
||||
return;
|
||||
}
|
||||
if (flat[key] !== void 0) return;
|
||||
|
||||
flatten(val, key);
|
||||
var hasValidMapping = (fields[key] && fields[key].type !== 'conflict');
|
||||
var isValue = !_.isPlainObject(val);
|
||||
|
||||
if (hasValidMapping || isValue) {
|
||||
flat[key] = val;
|
||||
return;
|
||||
}
|
||||
|
||||
flatten(val, key);
|
||||
});
|
||||
}(hit._source));
|
||||
|
||||
// assign the meta fields
|
||||
_.each(metaFields, function (meta) {
|
||||
if (meta === '_source') return;
|
||||
flat[meta] = hit[meta];
|
||||
});
|
||||
}(hit._source));
|
||||
|
||||
// assign the meta fields
|
||||
_.each(indexPattern.metaFields, function (meta) {
|
||||
flat[meta] = hit[meta];
|
||||
});
|
||||
// unwrap computed fields
|
||||
_.forOwn(hit.fields, function (val, key) {
|
||||
if (key[0] === '_' && !_.contains(metaFields, key)) return;
|
||||
flat[key] = _.isArray(val) && val.length === 1 ? val[0] : val;
|
||||
});
|
||||
|
||||
// unwrap computed fields
|
||||
_.forOwn(hit.fields, function (val, key) {
|
||||
flat[key] = val[0];
|
||||
});
|
||||
return flat;
|
||||
}
|
||||
|
||||
return flat;
|
||||
}
|
||||
function cachedFlatten(indexPattern, hit) {
|
||||
return hit.$$_flattened || (hit.$$_flattened = flattenHit(indexPattern, hit));
|
||||
}
|
||||
|
||||
return function cachedFlatten(indexPattern, hit) {
|
||||
return hit.$$_flattened || (hit.$$_flattened = flattenHit(indexPattern, hit));
|
||||
cachedFlatten.uncached = flattenHit;
|
||||
|
||||
return cachedFlatten;
|
||||
};
|
||||
|
||||
});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
define(function (require) {
|
||||
return function IndexPatternFactory(Private, timefilter, configFile, Notifier, shortDotsFilter, config, Promise) {
|
||||
return function IndexPatternFactory(Private, timefilter, Notifier, config, Promise) {
|
||||
var _ = require('lodash');
|
||||
var angular = require('angular');
|
||||
var errors = require('errors');
|
||||
|
@ -9,8 +9,9 @@ define(function (require) {
|
|||
var fieldFormats = Private(require('components/index_patterns/_field_formats'));
|
||||
var intervals = Private(require('components/index_patterns/_intervals'));
|
||||
var fieldTypes = Private(require('components/index_patterns/_field_types'));
|
||||
var flattenHit = require('components/index_patterns/_flatten_hit');
|
||||
var flattenHit = Private(require('components/index_patterns/_flatten_hit'));
|
||||
var getComputedFields = require('components/index_patterns/_get_computed_fields');
|
||||
var shortDotsFilter = Private(require('filters/short_dots'));
|
||||
|
||||
|
||||
var DocSource = Private(require('components/courier/data_source/doc_source'));
|
||||
|
@ -42,7 +43,7 @@ define(function (require) {
|
|||
self.init = function () {
|
||||
// tell the docSource where to find the doc
|
||||
docSource
|
||||
.index(configFile.kibana_index)
|
||||
.index(config.file.kibana_index)
|
||||
.type(type)
|
||||
.id(self.id);
|
||||
|
||||
|
@ -274,12 +275,10 @@ define(function (require) {
|
|||
return '' + self.toJSON();
|
||||
};
|
||||
|
||||
self.metaFields = config.get('metaFields');
|
||||
self.flattenHit = _.partial(flattenHit, self);
|
||||
self.getComputedFields = getComputedFields.bind(self);
|
||||
|
||||
|
||||
}
|
||||
|
||||
return IndexPattern;
|
||||
};
|
||||
});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
define(function (require) {
|
||||
return function MapperService(Private, Promise, es, configFile, config) {
|
||||
return function MapperService(Private, Promise, es, config) {
|
||||
var _ = require('lodash');
|
||||
var moment = require('moment');
|
||||
|
||||
|
@ -33,7 +33,7 @@ define(function (require) {
|
|||
|
||||
if (!skipIndexPatternCache) {
|
||||
return es.get({
|
||||
index: configFile.kibana_index,
|
||||
index: config.file.kibana_index,
|
||||
type: 'index-pattern',
|
||||
id: id,
|
||||
_sourceInclude: ['fields']
|
||||
|
|
|
@ -13,13 +13,17 @@ define(function (require) {
|
|||
*/
|
||||
|
||||
function Dispatch(handler) {
|
||||
|
||||
var stockEvents = ['brush', 'click', 'hover', 'mouseup', 'mousedown', 'mouseover', 'mouseout'];
|
||||
var customEvents = _.deepGet(handler, 'vis.eventTypes.enabled');
|
||||
var eventTypes = customEvents ? stockEvents.concat(customEvents) : stockEvents;
|
||||
|
||||
if (!(this instanceof Dispatch)) {
|
||||
return new Dispatch(handler);
|
||||
}
|
||||
|
||||
this.handler = handler;
|
||||
this.dispatch = d3.dispatch('brush', 'click', 'hover', 'mouseup',
|
||||
'mousedown', 'mouseover', 'mouseout');
|
||||
this.dispatch = d3.dispatch.apply(this, eventTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -254,7 +254,7 @@ define(function (require) {
|
|||
|
||||
div = d3.select(this);
|
||||
width = parentWidth / n;
|
||||
height = $(this).height();
|
||||
height = $(this.parentElement).height();
|
||||
|
||||
self.validateWidthandHeight(width, height);
|
||||
|
||||
|
|
|
@ -148,7 +148,7 @@
|
|||
.x-axis-div-wrapper {
|
||||
.display(flex);
|
||||
.flex-direction(row);
|
||||
min-height: 15px;
|
||||
min-height: 20px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -108,6 +108,10 @@
|
|||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.leaflet-draw-tooltip {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* filter to desaturate mapquest tiles */
|
||||
|
||||
img.leaflet-tile {
|
||||
|
@ -116,4 +120,4 @@ img.leaflet-tile {
|
|||
|
||||
img.leaflet-tile.filters-off {
|
||||
.filter(none);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,9 @@ define(function (require) {
|
|||
var _ = require('lodash');
|
||||
var $ = require('jquery');
|
||||
var L = require('leaflet');
|
||||
require('leaflet-draw');
|
||||
|
||||
var Dispatch = Private(require('components/vislib/lib/dispatch'));
|
||||
var Chart = Private(require('components/vislib/visualizations/_chart'));
|
||||
var errors = require('errors');
|
||||
|
||||
|
@ -32,6 +34,8 @@ define(function (require) {
|
|||
// track the map objects
|
||||
this.maps = [];
|
||||
|
||||
this.events = new Dispatch(handler);
|
||||
|
||||
// add allmin and allmax to geoJson
|
||||
chartData.geoJson.properties.allmin = chartData.geoJson.properties.min;
|
||||
chartData.geoJson.properties.allmax = chartData.geoJson.properties.max;
|
||||
|
@ -76,6 +80,21 @@ define(function (require) {
|
|||
subdomains: '1234'
|
||||
});
|
||||
|
||||
|
||||
var drawOptions = {draw: {}};
|
||||
_.each(['polyline', 'polygon', 'circle', 'marker', 'rectangle'], function (drawShape) {
|
||||
if (!self.events.dispatch[drawShape]) {
|
||||
drawOptions.draw[drawShape] = false;
|
||||
} else {
|
||||
drawOptions.draw[drawShape] = {
|
||||
shapeOptions: {
|
||||
stroke: false,
|
||||
color: '#000'
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
var mapOptions = {
|
||||
minZoom: 1,
|
||||
maxZoom: 18,
|
||||
|
@ -85,11 +104,15 @@ define(function (require) {
|
|||
noWrap: true,
|
||||
maxBounds: worldBounds,
|
||||
scrollWheelZoom: false,
|
||||
fadeAnimation: false
|
||||
fadeAnimation: false,
|
||||
};
|
||||
|
||||
var map = L.map(div[0], mapOptions);
|
||||
|
||||
if (data.geoJson.features.length) {
|
||||
map.addControl(new L.Control.Draw(drawOptions));
|
||||
}
|
||||
|
||||
tileLayer.on('tileload', function () {
|
||||
self.saturateTiles();
|
||||
});
|
||||
|
@ -105,6 +128,29 @@ define(function (require) {
|
|||
mapCenter = self._attr.mapCenter = map.getCenter();
|
||||
});
|
||||
|
||||
map.on('draw:created', function (e) {
|
||||
var drawType = e.layerType;
|
||||
if (!self.events.dispatch[drawType]) return;
|
||||
|
||||
// TODO: Different drawTypes need differ info. Need a switch on the object creation
|
||||
var bounds = e.layer.getBounds();
|
||||
|
||||
self.events.dispatch[drawType]({
|
||||
e: e,
|
||||
data: self.chartData,
|
||||
bounds: {
|
||||
top_left: {
|
||||
lat: bounds.getNorthWest().lat,
|
||||
lon: bounds.getNorthWest().lng
|
||||
},
|
||||
bottom_right: {
|
||||
lat: bounds.getSouthEast().lat,
|
||||
lon: bounds.getSouthEast().lng
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// add label for splits
|
||||
if (mapData.properties.label) {
|
||||
self.addLabel(mapData.properties.label, map);
|
||||
|
|
|
@ -31,83 +31,77 @@ define(function (require) {
|
|||
*
|
||||
* @param {array[string|function|obj]} expressions - the list of expressions to $watch
|
||||
* @param {Function} fn - the callback function
|
||||
* @param {boolean} deep - should the watchers be created as deep watchers?
|
||||
* @return {undefined}
|
||||
* @return {Function} - an unwatch function, just like the return value of $watch
|
||||
*/
|
||||
$delegate.constructor.prototype.$watchMulti = function (expressions, fn, deep) {
|
||||
$delegate.constructor.prototype.$watchMulti = function (expressions, fn) {
|
||||
if (!_.isArray(expressions)) throw new TypeError('expected an array of expressions to watch');
|
||||
if (!_.isFunction(fn)) throw new TypeError('expected a function that is triggered on each watch');
|
||||
|
||||
var $scope = this;
|
||||
var fired = false;
|
||||
var queue = [];
|
||||
var vals = new Array(expressions.length);
|
||||
var prev = new Array(expressions.length);
|
||||
var fire = false;
|
||||
|
||||
function normalizeExpression(expr) {
|
||||
// first, register all of the multi-watchers
|
||||
var unwatchers = expressions.map(function (expr, i) {
|
||||
expr = normalizeExpression($scope, expr);
|
||||
if (!expr) return;
|
||||
|
||||
var norm = {
|
||||
fn: $scope.$watch,
|
||||
deep: false
|
||||
};
|
||||
|
||||
if (_.isFunction(expr)) return _.assign(norm, { get: expr });
|
||||
if (_.isObject(expr)) return _.assign(norm, expr);
|
||||
if (!_.isString(expr)) return;
|
||||
|
||||
if (expr.substr(0, 2) === '[]') {
|
||||
return _.assign(norm, {
|
||||
fn: $scope.$watchCollection,
|
||||
get: expr.substr(2)
|
||||
});
|
||||
}
|
||||
|
||||
if (expr.charAt(0) === '=') {
|
||||
return _.assign(norm, {
|
||||
deep: true,
|
||||
get: expr.substr(1)
|
||||
});
|
||||
}
|
||||
|
||||
return _.assign(norm, { get: expr });
|
||||
}
|
||||
|
||||
expressions.forEach(function (expr, i) {
|
||||
expr = normalizeExpression(expr);
|
||||
if (!expr) return;
|
||||
|
||||
queue.push(expr);
|
||||
expr.fn.call($scope, expr.get, function (newVal, oldVal) {
|
||||
return expr.fn.call($scope, expr.get, function (newVal, oldVal) {
|
||||
vals[i] = newVal;
|
||||
|
||||
if (queue) {
|
||||
prev[i] = oldVal;
|
||||
_.pull(queue, expr);
|
||||
if (queue.length > 0) return;
|
||||
queue = false;
|
||||
}
|
||||
|
||||
if (fired) return;
|
||||
fired = true;
|
||||
$scope.$evalAsync(function () {
|
||||
fired = false;
|
||||
|
||||
if (fn.length) {
|
||||
fn(vals.slice(0), prev.slice(0));
|
||||
} else {
|
||||
fn();
|
||||
}
|
||||
|
||||
for (var i = 0; i < vals.length; i++) {
|
||||
prev[i] = vals[i];
|
||||
}
|
||||
});
|
||||
prev[i] = oldVal;
|
||||
fire = true;
|
||||
}, expr.deep);
|
||||
});
|
||||
|
||||
// then, the watcher that checks to see if any of
|
||||
// the other watchers triggered this cycle
|
||||
var flip = false;
|
||||
unwatchers.push($scope.$watch(function () {
|
||||
if (fire) {
|
||||
fire = false;
|
||||
flip = !flip;
|
||||
}
|
||||
return flip;
|
||||
}, function () {
|
||||
fn(vals.slice(0), prev.slice(0));
|
||||
vals.forEach(function (v, i) {
|
||||
prev[i] = v;
|
||||
});
|
||||
}));
|
||||
|
||||
return _.partial(_.callEach, unwatchers);
|
||||
};
|
||||
|
||||
function normalizeExpression($scope, expr) {
|
||||
if (!expr) return;
|
||||
var norm = {
|
||||
fn: $scope.$watch,
|
||||
deep: false
|
||||
};
|
||||
|
||||
if (_.isFunction(expr)) return _.assign(norm, { get: expr });
|
||||
if (_.isObject(expr)) return _.assign(norm, expr);
|
||||
if (!_.isString(expr)) return;
|
||||
|
||||
if (expr.substr(0, 2) === '[]') {
|
||||
return _.assign(norm, {
|
||||
fn: $scope.$watchCollection,
|
||||
get: expr.substr(2)
|
||||
});
|
||||
}
|
||||
|
||||
if (expr.charAt(0) === '=') {
|
||||
return _.assign(norm, {
|
||||
deep: true,
|
||||
get: expr.substr(1)
|
||||
});
|
||||
}
|
||||
|
||||
return _.assign(norm, { get: expr });
|
||||
}
|
||||
|
||||
return $delegate;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,14 +3,21 @@
|
|||
// 'foo.bar.baz'.replace(/(.+?\.)/g,function(v) {return v[0]+'.';});
|
||||
define(function (require) {
|
||||
var _ = require('lodash');
|
||||
|
||||
require('modules')
|
||||
.get('kibana')
|
||||
.filter('shortDots', function (config) {
|
||||
return function (str) {
|
||||
if (!_.isString(str) || config.get('shortDots:enable') !== true) {
|
||||
return str;
|
||||
}
|
||||
return str.replace(/(.+?\.)/g, function (v) { return v[0] + '.'; });
|
||||
};
|
||||
.filter('shortDots', function (Private) {
|
||||
return Private(shortDotsFilterProvider);
|
||||
});
|
||||
});
|
||||
|
||||
function shortDotsFilterProvider(config) {
|
||||
return function (str) {
|
||||
if (!_.isString(str) || config.get('shortDots:enable') !== true) {
|
||||
return str;
|
||||
}
|
||||
return str.replace(/(.+?\.)/g, function (v) { return v[0] + '.'; });
|
||||
};
|
||||
}
|
||||
|
||||
return shortDotsFilterProvider;
|
||||
});
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
define(function (require) {
|
||||
return function TileMapVisType(Private) {
|
||||
return function TileMapVisType(Private, getAppState) {
|
||||
var VislibVisType = Private(require('plugins/vis_types/vislib/_vislib_vis_type'));
|
||||
var Schemas = Private(require('plugins/vis_types/_schemas'));
|
||||
var geoJsonConverter = Private(require('components/agg_response/geo_json/geo_json'));
|
||||
var _ = require('lodash');
|
||||
|
||||
return new VislibVisType({
|
||||
name: 'tile_map',
|
||||
|
@ -18,6 +19,20 @@ define(function (require) {
|
|||
mapTypes: ['Scaled Circle Markers', 'Shaded Circle Markers', 'Shaded Geohash Grid'],
|
||||
editor: require('text!plugins/vis_types/vislib/editors/tile_map.html')
|
||||
},
|
||||
listeners: {
|
||||
rectangle: function (event) {
|
||||
var agg = _.deepGet(event, 'data.geoJson.properties.agg');
|
||||
if (!agg) return;
|
||||
|
||||
var pushFilter = Private(require('components/filter_bar/push_filter'))(getAppState());
|
||||
var indexPatternName = agg.geo.vis.indexPattern.id;
|
||||
var field = agg.geo.fieldName();
|
||||
var filter = {geo_bounding_box: {}};
|
||||
filter.geo_bounding_box[field] = event.bounds;
|
||||
|
||||
pushFilter(filter, false, indexPatternName);
|
||||
}
|
||||
},
|
||||
responseConverter: geoJsonConverter,
|
||||
schemas: new Schemas([
|
||||
{
|
||||
|
|
|
@ -28,6 +28,7 @@ require.config({
|
|||
inflection: 'bower_components/inflection/lib/inflection',
|
||||
jquery: 'bower_components/jquery/dist/jquery',
|
||||
leaflet: 'bower_components/leaflet/dist/leaflet',
|
||||
'leaflet-draw': 'bower_components/leaflet-draw/dist/leaflet.draw',
|
||||
lodash_src: 'bower_components/lodash/dist/lodash',
|
||||
'lodash-deep': 'bower_components/lodash-deep/factory',
|
||||
moment: 'bower_components/moment/moment',
|
||||
|
@ -56,6 +57,9 @@ require.config({
|
|||
file_saver: {
|
||||
exports: 'saveAs'
|
||||
},
|
||||
'leaflet-draw': {
|
||||
deps: ['leaflet', 'css!bower_components/leaflet-draw/dist/leaflet.draw.css']
|
||||
},
|
||||
leaflet: {
|
||||
deps: ['css!bower_components/leaflet/dist/leaflet.css']
|
||||
},
|
||||
|
|
|
@ -3,7 +3,7 @@ define(function (require) {
|
|||
var StubIndexPattern = Private(require('test_utils/stub_index_pattern'));
|
||||
var fieldTypes = Private(require('components/index_patterns/_field_types'));
|
||||
var mockLogstashFields = Private(require('fixtures/logstash_fields'));
|
||||
var flattenHit = require('components/index_patterns/_flatten_hit');
|
||||
var flattenHit = Private(require('components/index_patterns/_flatten_hit'));
|
||||
var getComputedFields = require('components/index_patterns/_get_computed_fields');
|
||||
|
||||
var _ = require('lodash');
|
||||
|
@ -21,7 +21,6 @@ define(function (require) {
|
|||
|
||||
indexPattern.getComputedFields = _.bind(getComputedFields, indexPattern);
|
||||
indexPattern.flattenHit = _.partial(flattenHit, indexPattern);
|
||||
indexPattern.metaFields = ['_id', '_type', '_source'];
|
||||
indexPattern.id = 'logstash-*';
|
||||
|
||||
return indexPattern;
|
||||
|
|
|
@ -36,6 +36,11 @@
|
|||
ScreencastReporter: '../../node_modules/mocha-screencast-reporter/screencast-reporter'
|
||||
},
|
||||
shim: {
|
||||
angular_src: {
|
||||
deps: [
|
||||
'jquery'
|
||||
]
|
||||
},
|
||||
angular: {
|
||||
deps: [
|
||||
'jquery',
|
||||
|
|
62
test/unit/specs/components/filter_bar/mapGeoBoundingBox.js
Normal file
62
test/unit/specs/components/filter_bar/mapGeoBoundingBox.js
Normal file
|
@ -0,0 +1,62 @@
|
|||
define(function (require) {
|
||||
describe('Filter Bar Directive', function () {
|
||||
describe('mapGeoBoundingBox()', function () {
|
||||
var sinon = require('test_utils/auto_release_sinon');
|
||||
var mapGeoBoundingBox, $rootScope, indexPattern, getIndexPatternStub;
|
||||
beforeEach(module('kibana'));
|
||||
|
||||
beforeEach(function () {
|
||||
getIndexPatternStub = sinon.stub();
|
||||
module('kibana/courier', function ($provide) {
|
||||
$provide.service('courier', function () {
|
||||
var courier = { indexPatterns: { get: getIndexPatternStub } };
|
||||
return courier;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(inject(function (Private, _$rootScope_, Promise) {
|
||||
mapGeoBoundingBox = Private(require('components/filter_bar/lib/mapGeoBoundingBox'));
|
||||
$rootScope = _$rootScope_;
|
||||
indexPattern = Private(require('fixtures/stubbed_logstash_index_pattern'));
|
||||
getIndexPatternStub.returns(Promise.resolve(indexPattern));
|
||||
}));
|
||||
|
||||
it('should return the key and value for matching filters with bounds', function (done) {
|
||||
var filter = {
|
||||
meta: {
|
||||
index: 'logstash-*'
|
||||
},
|
||||
geo_bounding_box: {
|
||||
point: { // field name
|
||||
top_left: {
|
||||
lat: 5,
|
||||
lon: 10
|
||||
},
|
||||
bottom_right: {
|
||||
lat: 15,
|
||||
lon: 20
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
mapGeoBoundingBox(filter).then(function (result) {
|
||||
expect(result).to.have.property('key', 'point');
|
||||
expect(result).to.have.property('value', '{"lat":5,"lon":10} to {"lat":15,"lon":20}');
|
||||
done();
|
||||
});
|
||||
$rootScope.$apply();
|
||||
});
|
||||
|
||||
it('should return undefined for none matching', function (done) {
|
||||
var filter = { meta: { index: 'logstash-*' }, query: { query_string: { query: 'foo:bar' } } };
|
||||
mapGeoBoundingBox(filter).catch(function (result) {
|
||||
expect(result).to.be(filter);
|
||||
done();
|
||||
});
|
||||
$rootScope.$apply();
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
});
|
68
test/unit/specs/components/filter_bar/push_filter.js
Normal file
68
test/unit/specs/components/filter_bar/push_filter.js
Normal file
|
@ -0,0 +1,68 @@
|
|||
define(function (require) {
|
||||
describe('Filter Bar pushFilter()', function () {
|
||||
var _ = require('lodash');
|
||||
|
||||
var pushFilterFn;
|
||||
|
||||
beforeEach(module('kibana'));
|
||||
beforeEach(inject(function (Private, $injector) {
|
||||
pushFilterFn = Private(require('components/filter_bar/push_filter'));
|
||||
}));
|
||||
|
||||
it('is a function that returns a function', function () {
|
||||
expect(pushFilterFn).to.be.a(Function);
|
||||
expect(pushFilterFn({})).to.be.a(Function);
|
||||
});
|
||||
|
||||
it('throws an error if passed something besides an object', function () {
|
||||
expect(pushFilterFn).withArgs(true).to.throwError();
|
||||
});
|
||||
|
||||
describe('pushFilter($state)()', function () {
|
||||
var $state;
|
||||
var pushFilter;
|
||||
var filter;
|
||||
|
||||
beforeEach(inject(function (Private, $injector) {
|
||||
$state = {filters:[]};
|
||||
pushFilter = pushFilterFn($state);
|
||||
filter = {query: {query_string: {query: ''}}};
|
||||
}));
|
||||
|
||||
it('should create the filters property it needed', function () {
|
||||
var altState = {};
|
||||
pushFilterFn(altState)(filter);
|
||||
expect(altState.filters).to.be.an(Array);
|
||||
});
|
||||
|
||||
it('should replace the filters property instead of modifying it', function () {
|
||||
// If we push directly instead of using pushFilter a $watch('filters') does not trigger
|
||||
|
||||
var oldFilters;
|
||||
|
||||
oldFilters = $state.filters;
|
||||
$state.filters.push(filter);
|
||||
expect($state.filters).to.equal(oldFilters); // Same object
|
||||
|
||||
oldFilters = $state.filters;
|
||||
pushFilter(filter);
|
||||
expect($state.filters).to.not.equal(oldFilters); // New object!
|
||||
});
|
||||
|
||||
it('should add meta data to the filter', function () {
|
||||
pushFilter(filter, true, 'myIndex');
|
||||
expect($state.filters[0].meta).to.be.an(Object);
|
||||
|
||||
expect($state.filters[0].meta.negate).to.be(true);
|
||||
expect($state.filters[0].meta.index).to.be('myIndex');
|
||||
|
||||
pushFilter(filter, false, 'myIndex');
|
||||
expect($state.filters[1].meta.negate).to.be(false);
|
||||
});
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
});
|
|
@ -82,23 +82,48 @@ define(function (require) {
|
|||
]);
|
||||
});
|
||||
|
||||
it('does not pass args unless the function will use them', function () {
|
||||
var calls = 0;
|
||||
it('the current value is always up to date', function () {
|
||||
var count = 0;
|
||||
|
||||
$scope.one = 'a';
|
||||
$scope.two = 'b';
|
||||
$scope.three = 'c';
|
||||
$scope.$watchMulti([
|
||||
'one',
|
||||
'two',
|
||||
'three'
|
||||
], function () {
|
||||
calls++;
|
||||
expect(arguments).to.have.length(0);
|
||||
$scope.vals = [1, 0];
|
||||
$scope.$watchMulti([ 'vals[0]', 'vals[1]' ], function (cur, prev) {
|
||||
expect(cur).to.eql($scope.vals);
|
||||
count++;
|
||||
});
|
||||
$rootScope.$apply();
|
||||
|
||||
expect(calls).to.be(1);
|
||||
var $child = $scope.$new();
|
||||
$child.$watch('vals[0]', function (cur) {
|
||||
$child.vals[1] = cur;
|
||||
});
|
||||
|
||||
$rootScope.$apply();
|
||||
expect(count).to.be(2);
|
||||
});
|
||||
|
||||
it('returns a working unwatch function', function () {
|
||||
$scope.a = 0;
|
||||
$scope.b = 0;
|
||||
var triggers = 0;
|
||||
var unwatch = $scope.$watchMulti(['a', 'b'], function () { triggers++; });
|
||||
|
||||
// initial watch
|
||||
$scope.$apply();
|
||||
expect(triggers).to.be(1);
|
||||
|
||||
// prove that it triggers on chagne
|
||||
$scope.a++;
|
||||
$scope.$apply();
|
||||
expect(triggers).to.be(2);
|
||||
|
||||
// remove watchers
|
||||
expect($scope.$$watchers).to.not.eql([]);
|
||||
unwatch();
|
||||
expect($scope.$$watchers).to.eql([]);
|
||||
|
||||
// prove that it doesn't trigger anymore
|
||||
$scope.a++;
|
||||
$scope.$apply();
|
||||
expect(triggers).to.be(2);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,56 +1,67 @@
|
|||
define(function (require) {
|
||||
var _ = require('lodash');
|
||||
var flattenHit = require('components/index_patterns/_flatten_hit');
|
||||
|
||||
describe('IndexPattern#flattenHit()', function () {
|
||||
|
||||
var indexPattern = {
|
||||
fields: {
|
||||
byName: {
|
||||
'message': { type: 'string' },
|
||||
'geo.coordinates': { type: 'geo_point' },
|
||||
'geo.dest': { type: 'string' },
|
||||
'geo.src': { type: 'string' },
|
||||
'bytes': { type: 'number' },
|
||||
'@timestamp': { type: 'date' },
|
||||
'team': { type: 'nested' },
|
||||
'team.name': { type: 'string' },
|
||||
'team.role': { type: 'string' },
|
||||
'user': { type: 'conflict' },
|
||||
'user.name': { type: 'string' },
|
||||
'user.id': { type: 'conflict' },
|
||||
'delta': { type: 'number', scripted: true }
|
||||
var _ = require('lodash');
|
||||
|
||||
var flattenHit;
|
||||
var indexPattern;
|
||||
var config;
|
||||
var hit;
|
||||
var flat;
|
||||
|
||||
beforeEach(module('kibana'));
|
||||
beforeEach(inject(function (Private, $injector) {
|
||||
flattenHit = Private(require('components/index_patterns/_flatten_hit')).uncached;
|
||||
config = $injector.get('config');
|
||||
|
||||
indexPattern = {
|
||||
fields: {
|
||||
byName: {
|
||||
'message': { type: 'string' },
|
||||
'geo.coordinates': { type: 'geo_point' },
|
||||
'geo.dest': { type: 'string' },
|
||||
'geo.src': { type: 'string' },
|
||||
'bytes': { type: 'number' },
|
||||
'@timestamp': { type: 'date' },
|
||||
'team': { type: 'nested' },
|
||||
'team.name': { type: 'string' },
|
||||
'team.role': { type: 'string' },
|
||||
'user': { type: 'conflict' },
|
||||
'user.name': { type: 'string' },
|
||||
'user.id': { type: 'conflict' },
|
||||
'delta': { type: 'number', scripted: true }
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
var hit = {
|
||||
_source: {
|
||||
message: 'Hello World',
|
||||
geo: {
|
||||
coordinates: { lat: 33.4500, lon: 112.0667 },
|
||||
dest: 'US',
|
||||
src: 'IN'
|
||||
hit = {
|
||||
_source: {
|
||||
message: 'Hello World',
|
||||
geo: {
|
||||
coordinates: { lat: 33.4500, lon: 112.0667 },
|
||||
dest: 'US',
|
||||
src: 'IN'
|
||||
},
|
||||
bytes: 10039103,
|
||||
'@timestamp': (new Date()).toString(),
|
||||
tags: [{ text: 'foo' }, { text: 'bar' }],
|
||||
groups: ['loners'],
|
||||
noMapping: true,
|
||||
team: [
|
||||
{ name: 'foo', role: 'leader' },
|
||||
{ name: 'bar', role: 'follower' },
|
||||
{ name: 'baz', role: 'party boy' },
|
||||
],
|
||||
user: { name: 'smith', id: 123 }
|
||||
},
|
||||
bytes: 10039103,
|
||||
'@timestamp': (new Date()).toString(),
|
||||
tags: [{ text: 'foo' }, { text: 'bar' }],
|
||||
groups: ['loners'],
|
||||
noMapping: true,
|
||||
team: [
|
||||
{ name: 'foo', role: 'leader' },
|
||||
{ name: 'bar', role: 'follower' },
|
||||
{ name: 'baz', role: 'party boy' },
|
||||
],
|
||||
user: { name: 'smith', id: 123 }
|
||||
},
|
||||
fields: {
|
||||
delta: [42],
|
||||
random: [0.12345]
|
||||
}
|
||||
};
|
||||
fields: {
|
||||
delta: [42],
|
||||
random: [0.12345]
|
||||
}
|
||||
};
|
||||
|
||||
var flat = flattenHit(indexPattern, hit);
|
||||
flat = flattenHit(indexPattern, hit);
|
||||
}));
|
||||
|
||||
it('flattens keys as far down as the mapping goes', function () {
|
||||
expect(flat).to.have.property('geo.coordinates', hit._source.geo.coordinates);
|
||||
|
@ -94,5 +105,38 @@ define(function (require) {
|
|||
it('assumes that all fields are "computed fields"', function () {
|
||||
expect(flat).to.have.property('random', 0.12345);
|
||||
});
|
||||
|
||||
it('ignores fields that start with an _ and are not in the metaFields', function () {
|
||||
config.set('metaFields', ['_metaKey']);
|
||||
hit.fields._notMetaKey = [100];
|
||||
flat = flattenHit(indexPattern, hit);
|
||||
expect(flat).to.not.have.property('_notMetaKey');
|
||||
});
|
||||
|
||||
it('includes underscore-prefixed keys that are in the metaFields', function () {
|
||||
config.set('metaFields', ['_metaKey']);
|
||||
hit.fields._metaKey = [100];
|
||||
flat = flattenHit(indexPattern, hit);
|
||||
expect(flat).to.have.property('_metaKey', 100);
|
||||
});
|
||||
|
||||
it('adapts to changes in the metaFields', function () {
|
||||
hit.fields._metaKey = [100];
|
||||
|
||||
config.set('metaFields', ['_metaKey']);
|
||||
flat = flattenHit(indexPattern, hit);
|
||||
expect(flat).to.have.property('_metaKey', 100);
|
||||
|
||||
config.set('metaFields', []);
|
||||
flat = flattenHit(indexPattern, hit);
|
||||
expect(flat).to.not.have.property('_metaKey');
|
||||
});
|
||||
|
||||
it('handles fields that are not arrays, like _timestamp', function () {
|
||||
hit.fields._metaKey = 20000;
|
||||
config.set('metaFields', ['_metaKey']);
|
||||
flat = flattenHit(indexPattern, hit);
|
||||
expect(flat).to.have.property('_metaKey', 20000);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -9,91 +9,118 @@ define(function (require) {
|
|||
angular.module('DispatchClass', ['kibana']);
|
||||
|
||||
describe('VisLib Dispatch Class Test Suite', function () {
|
||||
var vis;
|
||||
|
||||
beforeEach(function () {
|
||||
module('AreaChartFactory');
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
inject(function (Private) {
|
||||
vis = Private(require('vislib_fixtures/_vis_fixture'))();
|
||||
require('css!components/vislib/styles/main');
|
||||
|
||||
vis.on('brush', _.noop);
|
||||
|
||||
vis.render(data);
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
function destroyVis(vis) {
|
||||
$(vis.el).remove();
|
||||
vis = null;
|
||||
});
|
||||
}
|
||||
|
||||
describe('addEvent method', function () {
|
||||
it('should return a function', function () {
|
||||
vis.handler.charts.forEach(function (chart) {
|
||||
var addEvent = chart.events.addEvent;
|
||||
expect(_.isFunction(addEvent('click', _.noop))).to.be(true);
|
||||
describe('Stock event handlers', function () {
|
||||
var vis;
|
||||
|
||||
beforeEach(function () {
|
||||
module('AreaChartFactory');
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
inject(function (Private) {
|
||||
vis = Private(require('vislib_fixtures/_vis_fixture'))();
|
||||
require('css!components/vislib/styles/main');
|
||||
|
||||
vis.on('brush', _.noop);
|
||||
|
||||
vis.render(data);
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
destroyVis(vis);
|
||||
});
|
||||
|
||||
describe('addEvent method', function () {
|
||||
it('should return a function', function () {
|
||||
vis.handler.charts.forEach(function (chart) {
|
||||
var addEvent = chart.events.addEvent;
|
||||
expect(_.isFunction(addEvent('click', _.noop))).to.be(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('addHoverEvent method', function () {
|
||||
it('should return a function', function () {
|
||||
vis.handler.charts.forEach(function (chart) {
|
||||
var hover = chart.events.addHoverEvent;
|
||||
|
||||
expect(_.isFunction(hover)).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('should attach a hover event', function () {
|
||||
vis.handler.charts.forEach(function (chart) {
|
||||
expect(_.isFunction(chart.events.dispatch.hover)).to.be(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('addClickEvent method', function () {
|
||||
it('should return a function', function () {
|
||||
vis.handler.charts.forEach(function (chart) {
|
||||
var click = chart.events.addClickEvent;
|
||||
|
||||
expect(_.isFunction(click)).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('should attach a click event', function () {
|
||||
vis.handler.charts.forEach(function (chart) {
|
||||
expect(_.isFunction(chart.events.dispatch.click)).to.be(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('addBrushEvent method', function () {
|
||||
it('should return a function', function () {
|
||||
vis.handler.charts.forEach(function (chart) {
|
||||
var brush = chart.events.addBrushEvent;
|
||||
|
||||
expect(_.isFunction(brush)).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('should attach a brush event', function () {
|
||||
vis.handler.charts.forEach(function (chart) {
|
||||
expect(_.isFunction(chart.events.dispatch.brush)).to.be(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('addMousePointer method', function () {
|
||||
it('should return a function', function () {
|
||||
vis.handler.charts.forEach(function (chart) {
|
||||
var pointer = chart.events.addMousePointer;
|
||||
|
||||
expect(_.isFunction(pointer)).to.be(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('addHoverEvent method', function () {
|
||||
it('should return a function', function () {
|
||||
vis.handler.charts.forEach(function (chart) {
|
||||
var hover = chart.events.addHoverEvent;
|
||||
describe('Custom event handlers', function () {
|
||||
it('should attach whatever gets passed on vis.on() to dispatch', function (done) {
|
||||
var vis;
|
||||
var chart;
|
||||
module('AreaChartFactory');
|
||||
inject(function (Private) {
|
||||
vis = Private(require('vislib_fixtures/_vis_fixture'))();
|
||||
vis.on('someEvent', _.noop);
|
||||
vis.render(data);
|
||||
|
||||
expect(_.isFunction(hover)).to.be(true);
|
||||
});
|
||||
});
|
||||
vis.handler.charts.forEach(function (chart) {
|
||||
expect(chart.events.dispatch.someEvent).to.be.a(Function);
|
||||
});
|
||||
|
||||
it('should attach a hover event', function () {
|
||||
vis.handler.charts.forEach(function (chart) {
|
||||
expect(_.isFunction(chart.events.dispatch.hover)).to.be(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('addClickEvent method', function () {
|
||||
it('should return a function', function () {
|
||||
vis.handler.charts.forEach(function (chart) {
|
||||
var click = chart.events.addClickEvent;
|
||||
|
||||
expect(_.isFunction(click)).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('should attach a click event', function () {
|
||||
vis.handler.charts.forEach(function (chart) {
|
||||
expect(_.isFunction(chart.events.dispatch.click)).to.be(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('addBrushEvent method', function () {
|
||||
it('should return a function', function () {
|
||||
vis.handler.charts.forEach(function (chart) {
|
||||
var brush = chart.events.addBrushEvent;
|
||||
|
||||
expect(_.isFunction(brush)).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('should attach a brush event', function () {
|
||||
vis.handler.charts.forEach(function (chart) {
|
||||
expect(_.isFunction(chart.events.dispatch.brush)).to.be(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('addMousePointer method', function () {
|
||||
it('should return a function', function () {
|
||||
vis.handler.charts.forEach(function (chart) {
|
||||
var pointer = chart.events.addMousePointer;
|
||||
|
||||
expect(_.isFunction(pointer)).to.be(true);
|
||||
destroyVis(vis);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -11,90 +11,169 @@ define(function (require) {
|
|||
require('vislib_fixtures/mock_data/geohash/_rows')
|
||||
];
|
||||
var names = ['geojson', 'columns', 'rows'];
|
||||
var mapTypes = ['Scaled Circle Markers', 'Shaded Circle Markers', 'Shaded Geohash Grid', 'Pins'];
|
||||
// TODO: Test the specific behavior of each these
|
||||
var mapTypes = ['Scaled Circle Markers', 'Shaded Circle Markers', 'Shaded Geohash Grid'];
|
||||
|
||||
angular.module('TileMapFactory', ['kibana']);
|
||||
|
||||
dataArray.forEach(function (data, i) {
|
||||
|
||||
mapTypes.forEach(function (type, j) {
|
||||
function bootstrapAndRender(data, type) {
|
||||
var vis;
|
||||
var visLibParams = {
|
||||
isDesaturated: true,
|
||||
type: 'tile_map',
|
||||
mapType: type
|
||||
};
|
||||
|
||||
describe('TileMap Test Suite for ' + mapTypes[j] + ' with ' + names[i] + ' data', function () {
|
||||
var vis;
|
||||
var visLibParams = {
|
||||
isDesaturated: true,
|
||||
type: 'tile_map',
|
||||
mapType: type
|
||||
};
|
||||
module('TileMapFactory');
|
||||
inject(function (Private) {
|
||||
vis = Private(require('vislib_fixtures/_vis_fixture'))(visLibParams);
|
||||
require('css!components/vislib/styles/main');
|
||||
vis.render(data);
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
module('TileMapFactory');
|
||||
});
|
||||
return vis;
|
||||
|
||||
beforeEach(function () {
|
||||
inject(function (Private) {
|
||||
vis = Private(require('vislib_fixtures/_vis_fixture'))(visLibParams);
|
||||
require('css!components/vislib/styles/main');
|
||||
vis.render(data);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
afterEach(function () {
|
||||
$(vis.el).remove();
|
||||
vis = null;
|
||||
});
|
||||
function destroyVis(vis) {
|
||||
$(vis.el).remove();
|
||||
vis = null;
|
||||
}
|
||||
|
||||
describe('draw method', function () {
|
||||
var leafletContainer;
|
||||
var isDrawn;
|
||||
describe('TileMap Tests', function () {
|
||||
describe('Rendering each types of tile map', function () {
|
||||
dataArray.forEach(function (data, i) {
|
||||
|
||||
it('should return a function', function () {
|
||||
vis.handler.charts.forEach(function (chart) {
|
||||
expect(_.isFunction(chart.draw())).to.be(true);
|
||||
mapTypes.forEach(function (type, j) {
|
||||
|
||||
describe('draw() ' + mapTypes[j] + ' with ' + names[i], function () {
|
||||
var vis;
|
||||
|
||||
beforeEach(function () {
|
||||
vis = bootstrapAndRender(data, type);
|
||||
});
|
||||
});
|
||||
|
||||
it('should draw a map', function () {
|
||||
leafletContainer = $(vis.el).find('.leaflet-container');
|
||||
isDrawn = (leafletContainer.length > 0);
|
||||
expect(isDrawn).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('geohashMinDistance method', function () {
|
||||
it('should return a number', function () {
|
||||
vis.handler.charts.forEach(function (chart) {
|
||||
var feature = chart.chartData.geoJson.features[0];
|
||||
expect(_.isNumber(chart.geohashMinDistance(feature))).to.be(true);
|
||||
afterEach(function () {
|
||||
destroyVis(vis);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('radiusScale method', function () {
|
||||
it('should return a number', function () {
|
||||
vis.handler.charts.forEach(function (chart) {
|
||||
var count = Math.random() * 50;
|
||||
var max = 50;
|
||||
var precision = 1;
|
||||
var feature = chart.chartData.geoJson.features[0];
|
||||
expect(_.isNumber(chart.radiusScale(count, max, feature))).to.be(true);
|
||||
it('should return a function', function () {
|
||||
vis.handler.charts.forEach(function (chart) {
|
||||
expect(chart.draw()).to.be.a(Function);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('quantizeColorScale method', function () {
|
||||
it('should return a hex color', function () {
|
||||
vis.handler.charts.forEach(function (chart) {
|
||||
var reds = ['#fed976', '#feb24c', '#fd8d3c', '#f03b20', '#bd0026'];
|
||||
var count = Math.random() * 300;
|
||||
var min = 0;
|
||||
var max = 300;
|
||||
expect(_.indexOf(reds, chart.quantizeColorScale(count, min, max))).to.not.be(-1);
|
||||
it('should create .leaflet-container as a by product of map rendering', function () {
|
||||
expect($(vis.el).find('.leaflet-container').length).to.be.above(0);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('Leaflet controls', function () {
|
||||
var vis;
|
||||
var leafletContainer;
|
||||
|
||||
beforeEach(function () {
|
||||
vis = bootstrapAndRender(dataArray[0], 'Scaled Circle Markers');
|
||||
leafletContainer = $(vis.el).find('.leaflet-container');
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
destroyVis(vis);
|
||||
});
|
||||
|
||||
it('should attach the zoom controls', function () {
|
||||
expect(leafletContainer.find('.leaflet-control-zoom-in').length).to.be(1);
|
||||
expect(leafletContainer.find('.leaflet-control-zoom-out').length).to.be(1);
|
||||
});
|
||||
|
||||
it('should attach the filter drawing button', function () {
|
||||
expect(leafletContainer.find('.leaflet-draw').length).to.be(1);
|
||||
});
|
||||
|
||||
it('should attach the crop button', function () {
|
||||
expect(leafletContainer.find('.leaflet-control-fit').length).to.be(1);
|
||||
});
|
||||
|
||||
it('should not attach the filter or crop buttons if no data is present', function () {
|
||||
var noData = {
|
||||
geoJson: {
|
||||
features: [],
|
||||
properties: {
|
||||
label: null,
|
||||
length: 30,
|
||||
min: 1,
|
||||
max: 608,
|
||||
precision: 1,
|
||||
allmin: 1,
|
||||
allmax: 608
|
||||
},
|
||||
hits: 20
|
||||
}
|
||||
};
|
||||
vis.render(noData);
|
||||
leafletContainer = $(vis.el).find('.leaflet-container');
|
||||
|
||||
expect(leafletContainer.find('.leaflet-control-fit').length).to.be(0);
|
||||
expect(leafletContainer.find('.leaflet-draw').length).to.be(0);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// Probably only neccesary to test one of these as we already know the the map will render
|
||||
|
||||
describe('Methods', function () {
|
||||
var vis;
|
||||
var leafletContainer;
|
||||
|
||||
beforeEach(function () {
|
||||
vis = bootstrapAndRender(dataArray[0], 'Scaled Circle Markers');
|
||||
leafletContainer = $(vis.el).find('.leaflet-container');
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
destroyVis(vis);
|
||||
});
|
||||
|
||||
describe('geohashMinDistance method', function () {
|
||||
it('should return a number', function () {
|
||||
vis.handler.charts.forEach(function (chart) {
|
||||
var feature = chart.chartData.geoJson.features[0];
|
||||
expect(_.isNumber(chart.geohashMinDistance(feature))).to.be(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('radiusScale method', function () {
|
||||
it('should return a number', function () {
|
||||
vis.handler.charts.forEach(function (chart) {
|
||||
var count = Math.random() * 50;
|
||||
var max = 50;
|
||||
var precision = 1;
|
||||
var feature = chart.chartData.geoJson.features[0];
|
||||
expect(_.isNumber(chart.radiusScale(count, max, feature))).to.be(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('quantizeColorScale method', function () {
|
||||
it('should return a hex color', function () {
|
||||
vis.handler.charts.forEach(function (chart) {
|
||||
var reds = ['#fed976', '#feb24c', '#fd8d3c', '#f03b20', '#bd0026'];
|
||||
var count = Math.random() * 300;
|
||||
var min = 0;
|
||||
var max = 300;
|
||||
expect(_.indexOf(reds, chart.quantizeColorScale(count, min, max))).to.not.be(-1);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
|
@ -4,7 +4,7 @@ define(function (require) {
|
|||
var sinon = require('sinon/sinon');
|
||||
var IndexedArray = require('utils/indexed_array/index');
|
||||
var fieldFormats = Private(require('components/index_patterns/_field_formats'));
|
||||
var flattenHit = require('components/index_patterns/_flatten_hit');
|
||||
var flattenHit = Private(require('components/index_patterns/_flatten_hit'));
|
||||
var getComputedFields = require('components/index_patterns/_get_computed_fields');
|
||||
|
||||
|
||||
|
@ -32,7 +32,6 @@ define(function (require) {
|
|||
this.toIndexList = _.constant([pattern]);
|
||||
this.getComputedFields = getComputedFields;
|
||||
this.flattenHit = _.partial(flattenHit, this);
|
||||
this.metaFields = ['_id', '_type', '_source'];
|
||||
}
|
||||
|
||||
return StubIndexPattern;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue