Merge branch 'add/yAxisFormatter' into fieldFormatting

This commit is contained in:
Spencer Alger 2015-04-28 14:17:05 -07:00
commit 8d3d6d51e8
35 changed files with 573 additions and 181 deletions

View file

@ -3,7 +3,7 @@ define(function (require) {
var _ = require('lodash');
var moment = require('moment');
var BucketAggType = Private(require('components/agg_types/buckets/_bucket_agg_type'));
var defaultPrecision = 3;
var defaultPrecision = 2;
function getPrecision(precision) {
var maxPrecision = _.parseInt(config.get('visualization:tileMap:maxPrecision'));

View file

@ -19,7 +19,7 @@ define(function (require) {
var angular = require('angular');
var _ = require('lodash');
var defaults = require('components/config/defaults');
var defaults = Private(require('components/config/defaults'));
var DelayedUpdater = Private(require('components/config/_delayed_updater'));
var vals = Private(require('components/config/_vals'));

View file

@ -1,109 +1,122 @@
define(function () {
return {
'query:queryString:options': {
value: '{ "analyze_wildcard": true }',
description: 'Options for the lucene query string parser',
type: 'json'
},
'dateFormat': {
value: 'MMMM Do YYYY, HH:mm:ss.SSS',
description: 'When displaying a pretty formatted date, use this format',
},
'dateFormat:scaled': {
type: 'json',
value:
'[\n' +
' ["", "hh:mm:ss.SSS"],\n' +
' ["PT1S", "HH:mm:ss"],\n' +
' ["PT1M", "HH:mm"],\n' +
' ["PT1H",\n' +
' "YYYY-MM-DD HH:mm"],\n' +
' ["P1DT", "YYYY-MM-DD"],\n' +
' ["P1YT", "YYYY"]\n' +
']',
description: 'Values that define the format used in situations where timebased' +
' data is rendered in order, and formatted timestamps should adapt to the' +
' interval between measurements. Keys are ISO 8601 intervals:' +
' http://en.wikipedia.org/wiki/ISO_8601#Time_intervals'
},
'defaultIndex': {
value: null,
description: 'The index to access if no index is set',
},
'metaFields': {
value: ['_source', '_id', '_type', '_index'],
description: 'Fields that exist outside of _source to merge into our document when displaying it',
},
'discover:sampleSize': {
value: 500,
description: 'The number of rows to show in the table',
},
'fields:popularLimit': {
value: 10,
description: 'The top N most popular fields to show',
},
'histogram:barTarget': {
value: 50,
description: 'Attempt to generate around this many bar when using "auto" interval in date histograms',
},
'histogram:maxBars': {
value: 100,
description: 'Never show more than this many bar in date histograms, scale values if needed',
},
'visualization:tileMap:maxPrecision': {
value: 7,
description: 'The maximum geoHash precision displayed on tile maps: 7 is high, 10 is very high, ' +
'12 is the max. Explanation of cell dimensions: http://www.elastic.co/guide/en/elasticsearch/reference/current/' +
'search-aggregations-bucket-geohashgrid-aggregation.html#_cell_dimensions_at_the_equator',
},
'csv:separator': {
value: ',',
description: 'Separate exported values with this string',
},
'csv:quoteValues': {
value: true,
description: 'Should values be quoted in csv exports?',
},
'history:limit': {
value: 10,
description: 'In fields that have history (e.g. query inputs), show this many recent values',
},
'shortDots:enable': {
value: false,
description: 'Shorten long fields, for example, instead of foo.bar.baz, show f.b.baz',
},
'truncate:maxHeight': {
value: 115,
description: 'The maximum height that a cell in a table should occupy. Set to 0 to disable truncation.'
},
'format:defaultTypeMap': {
type: 'json',
value: [
'{',
' "ip": "ip",',
' "date": "date",',
' "number": "number",',
' "_default_": "string"',
'}',
].join('\n'),
description: 'Map of the format name to use by default for each field type. ' +
'"_default_" is used if the field type is not mentioned explicitly.'
},
'format:number:defaultPattern': {
type: 'string',
value: '0,0.[000]'
},
'format:bytes:defaultPattern': {
type: 'string',
value: '0,0.[000]b'
},
'format:percent:defaultPattern': {
type: 'string',
value: '0,0.[000]%'
},
'format:currency:defaultPattern': {
type: 'string',
value: '($0,0.[00])'
}
define(function (require) {
return function () {
var _ = require('lodash');
return {
'query:queryString:options': {
value: '{ "analyze_wildcard": true }',
description: 'Options for the lucene query string parser',
type: 'json'
},
'dateFormat': {
value: 'MMMM Do YYYY, HH:mm:ss.SSS',
description: 'When displaying a pretty formatted date, use this format',
},
'dateFormat:scaled': {
type: 'json',
value:
'[\n' +
' ["", "hh:mm:ss.SSS"],\n' +
' ["PT1S", "HH:mm:ss"],\n' +
' ["PT1M", "HH:mm"],\n' +
' ["PT1H",\n' +
' "YYYY-MM-DD HH:mm"],\n' +
' ["P1DT", "YYYY-MM-DD"],\n' +
' ["P1YT", "YYYY"]\n' +
']',
description: 'Values that define the format used in situations where timebased' +
' data is rendered in order, and formatted timestamps should adapt to the' +
' interval between measurements. Keys are ISO 8601 intervals:' +
' http://en.wikipedia.org/wiki/ISO_8601#Time_intervals'
},
'defaultIndex': {
value: null,
description: 'The index to access if no index is set',
},
'metaFields': {
value: ['_source', '_id', '_type', '_index'],
description: 'Fields that exist outside of _source to merge into our document when displaying it',
},
'discover:sampleSize': {
value: 500,
description: 'The number of rows to show in the table',
},
'fields:popularLimit': {
value: 10,
description: 'The top N most popular fields to show',
},
'format:numberPrecision': {
value: 3,
description: 'Round numbers to this many decimal places',
},
'histogram:barTarget': {
value: 50,
description: 'Attempt to generate around this many bar when using "auto" interval in date histograms',
},
'histogram:maxBars': {
value: 100,
description: 'Never show more than this many bar in date histograms, scale values if needed',
},
'visualization:tileMap:maxPrecision': {
value: 7,
description: 'The maximum geoHash precision displayed on tile maps: 7 is high, 10 is very high, ' +
'12 is the max. Explanation of cell dimensions: http://www.elastic.co/guide/en/elasticsearch/reference/current/' +
'search-aggregations-bucket-geohashgrid-aggregation.html#_cell_dimensions_at_the_equator',
},
'csv:separator': {
value: ',',
description: 'Separate exported values with this string',
},
'csv:quoteValues': {
value: true,
description: 'Should values be quoted in csv exports?',
},
'history:limit': {
value: 10,
description: 'In fields that have history (e.g. query inputs), show this many recent values',
},
'shortDots:enable': {
value: false,
description: 'Shorten long fields, for example, instead of foo.bar.baz, show f.b.baz',
},
'truncate:maxHeight': {
value: 115,
description: 'The maximum height that a cell in a table should occupy. Set to 0 to disable truncation.'
},
'indexPattern:fieldMapping:lookBack': {
value: 5,
description: 'For index patterns containing timestamps in their names, look for this many recent matching ' +
'patterns from which to query the field mapping.'
},
'format:defaultTypeMap': {
type: 'json',
value: [
'{',
' "ip": "ip",',
' "date": "date",',
' "number": "number",',
' "_default_": "string"',
'}',
].join('\n'),
description: 'Map of the format name to use by default for each field type. ' +
'"_default_" is used if the field type is not mentioned explicitly.'
},
'format:number:defaultPattern': {
type: 'string',
value: '0,0.[000]'
},
'format:bytes:defaultPattern': {
type: 'string',
value: '0,0.[000]b'
},
'format:percent:defaultPattern': {
type: 'string',
value: '0,0.[000]%'
},
'format:currency:defaultPattern': {
type: 'string',
value: '($0,0.[00])'
}
};
};
});

View file

@ -1,5 +1,5 @@
define(function (require) {
return function MapperService(Private, Promise, es, configFile) {
return function MapperService(Private, Promise, es, configFile, config) {
var _ = require('lodash');
var moment = require('moment');
@ -51,7 +51,7 @@ define(function (require) {
promise = self.getIndicesForIndexPattern(indexPattern)
.then(function (existing) {
if (existing.matches.length === 0) throw new IndexPatternMissingIndices();
return existing.matches.slice(-5); // Grab the most recent 5
return existing.matches.slice(-config.get('indexPattern:fieldMapping:lookBack')); // Grab the most recent
});
}

View file

@ -45,7 +45,8 @@ define(function (require) {
if (self.shouldAutoReload(next, prev)) {
var appState = getAppState();
appState.destroy();
if (appState) appState.destroy();
reloading = $rootScope.$on('$locationChangeSuccess', function () {
// call the "unlisten" function returned by $on
reloading();

View file

@ -102,6 +102,14 @@ define(function (require) {
}
};
Vis.prototype.hasSchemaAgg = function (schemaName, aggTypeName) {
var aggs = this.aggs.bySchemaName[schemaName] || [];
return aggs.some(function (agg) {
if (!agg.type || !agg.type.name) return false;
return agg.type.name === aggTypeName;
});
};
return Vis;
};
});

View file

@ -265,18 +265,9 @@ define(function (require) {
* @param thing {String} Data object key
* @returns {*} Data object value
*/
Data.prototype.get = function (thing) {
var data;
if (this.data.rows) {
data = this.data.rows;
} else if (this.data.columns) {
data = this.data.columns;
} else {
data = [this.data];
}
return _.pluck(data, thing)[0];
Data.prototype.get = function (thing, def) {
var source = (this.data.rows || this.data.columns || [this.data])[0];
return _.get(source, thing, def);
};
/**

View file

@ -19,7 +19,7 @@ define(function (require) {
this.handler = handler;
this.dispatch = d3.dispatch('brush', 'click', 'hover', 'mouseup',
'mousedown', 'mouseover', 'mouseout');
'mousedown', 'mouseover', 'mouseout', 'mapZoomEnd');
}
/**

View file

@ -27,6 +27,9 @@ define(function (require) {
data = new Data(vis.data, vis._attr);
}
var isPercentage = (vis._attr.mode === 'percentage');
var tickFormat = isPercentage ? d3.format('%') : data.get('yAxisFormatter', d3.format('n'));
return new Handler(vis, {
data: data,
legend: new Legend(vis, vis.el, data.labels, data.color, vis._attr),
@ -45,7 +48,8 @@ define(function (require) {
el : vis.el,
yMin : data.getYMin(),
yMax : data.getYMax(),
_attr: vis._attr
_attr: vis._attr,
tickFormat: tickFormat
})
});
};

View file

@ -138,14 +138,14 @@ define(function (require) {
// legend
legendDiv.selectAll('li')
.filter(function (d) {
return this.getAttribute('data-label') !== label;
return this.getAttribute('data-label') !== label.toString();
})
.classed('blur_shape', true);
// all data-label attribute
charts.selectAll('[data-label]')
.filter(function (d) {
return this.getAttribute('data-label') !== label;
return this.getAttribute('data-label') !== label.toString();
})
.classed('blur_shape', true);

View file

@ -18,6 +18,7 @@ define(function (require) {
this.el = args.el;
this.yMin = args.yMin;
this.yMax = args.yMax;
this.tickFormat = args.tickFormat;
this._attr = args._attr || {};
}
@ -103,20 +104,6 @@ define(function (require) {
.nice();
};
/**
* By default, d3.format('s') returns billion values
* with a `G` instead of a `B`. @method formatAxisLabel returns
* billion values with a B instead of a G. Else, it defaults
* to the d3.format('s') value.
*
* @method formatAxisLabel
* @param d {Number}
* @returns {*}
*/
YAxis.prototype.formatAxisLabel = function (d) {
return numeral(d).format('0.[0]a');
};
/**
* Creates the d3 y axis function
*
@ -126,16 +113,6 @@ define(function (require) {
*/
YAxis.prototype.getYAxis = function (height) {
var yScale = this.getYScale(height);
var isPercentage = (this._attr.mode === 'percentage');
var tickFormat;
if (isPercentage) {
tickFormat = d3.format('%');
} else if (this.yMax <= 100 && this.yMin >= -100 && !isPercentage) {
tickFormat = d3.format('n');
} else {
tickFormat = this.formatAxisLabel;
}
// y scale should never be `NaN`
if (!yScale || _.isNaN(yScale)) {
@ -145,7 +122,7 @@ define(function (require) {
// Create the d3 yAxis function
this.yAxis = d3.svg.axis()
.scale(yScale)
.tickFormat(tickFormat)
.tickFormat(this.tickFormat)
.ticks(this.tickScale(height))
.orient('left');

View file

@ -4,6 +4,7 @@ define(function (require) {
var $ = require('jquery');
var PointSeriesChart = Private(require('components/vislib/visualizations/_point_series_chart'));
var TimeMarker = Private(require('components/vislib/visualizations/time_marker'));
var errors = require('errors');
require('css!components/vislib/styles/main');
@ -266,6 +267,9 @@ define(function (require) {
var yScale = this.handler.yAxis.yScale;
var minWidth = 20;
var minHeight = 20;
var addTimeMarker = this._attr.addTimeMarker;
var times = this._attr.times || [];
var timeMarker;
var div;
var svg;
var width;
@ -283,6 +287,10 @@ define(function (require) {
width = elWidth;
height = elHeight - margin.top - margin.bottom;
if (addTimeMarker) {
timeMarker = new TimeMarker(times, xScale, height);
}
if (width < minWidth || height < minHeight) {
throw new errors.ContainerTooSmall();
}
@ -333,6 +341,10 @@ define(function (require) {
.style('stroke', '#ddd')
.style('stroke-width', 1);
if (addTimeMarker) {
timeMarker.render(svg);
}
return svg;
});
};

View file

@ -5,6 +5,7 @@ define(function (require) {
var moment = require('moment');
var PointSeriesChart = Private(require('components/vislib/visualizations/_point_series_chart'));
var TimeMarker = Private(require('components/vislib/visualizations/time_marker'));
var errors = require('errors');
require('css!components/vislib/styles/main');
@ -269,8 +270,12 @@ define(function (require) {
var elHeight = this._attr.height = $elem.height();
var yMin = this.handler.yAxis.yMin;
var yScale = this.handler.yAxis.yScale;
var xScale = this.handler.xAxis.xScale;
var minWidth = 20;
var minHeight = 20;
var addTimeMarker = this._attr.addTimeMarker;
var times = this._attr.times || [];
var timeMarker;
var div;
var svg;
var width;
@ -285,6 +290,10 @@ define(function (require) {
width = elWidth;
height = elHeight - margin.top - margin.bottom;
if (addTimeMarker) {
timeMarker = new TimeMarker(times, xScale, height);
}
if (width < minWidth || height < minHeight) {
throw new errors.ContainerTooSmall();
}
@ -325,6 +334,10 @@ define(function (require) {
.style('stroke-width', 1);
}
if (addTimeMarker) {
timeMarker.render(svg);
}
return svg;
});
};

View file

@ -5,6 +5,7 @@ define(function (require) {
var errors = require('errors');
var PointSeriesChart = Private(require('components/vislib/visualizations/_point_series_chart'));
var TimeMarker = Private(require('components/vislib/visualizations/time_marker'));
require('css!components/vislib/styles/main');
/**
@ -258,10 +259,14 @@ define(function (require) {
var elHeight = this._attr.height = $elem.height();
var yMin = this.handler.yAxis.yMin;
var yScale = this.handler.yAxis.yScale;
var xScale = this.handler.xAxis.xScale;
var minWidth = 20;
var minHeight = 20;
var startLineX = 0;
var lineStrokeWidth = 1;
var addTimeMarker = this._attr.addTimeMarker;
var times = this._attr.times || [];
var timeMarker;
var div;
var svg;
var width;
@ -288,6 +293,10 @@ define(function (require) {
width = elWidth - margin.left - margin.right;
height = elHeight - margin.top - margin.bottom;
if (addTimeMarker) {
timeMarker = new TimeMarker(times, xScale, height);
}
if (width < minWidth || height < minHeight) {
throw new errors.ContainerTooSmall();
}
@ -331,6 +340,10 @@ define(function (require) {
.style('stroke', '#ddd')
.style('stroke-width', lineStrokeWidth);
if (addTimeMarker) {
timeMarker.render(svg);
}
return svg;
});
};

View file

@ -105,6 +105,14 @@ define(function (require) {
mapCenter = self._attr.mapCenter = map.getCenter();
});
map.on('zoomend', function (e) {
var mapInfo = {
zoom: map.getZoom(),
zoomPct: map.getZoom() / 18
};
self.events.dispatch.mapZoomEnd(mapInfo);
});
// add label for splits
if (mapData.properties.label) {
self.addLabel(mapData.properties.label, map);
@ -134,6 +142,14 @@ define(function (require) {
};
};
TileMap.prototype.addZoomEndEvent = function (element) {
var events = this.events;
var zoomend = events.addMapZoomEndEvent();
var attachedEvents = element.call(zoomend);
return attachedEvents;
};
/**
* zoom map to fit all features in featureLayer
*

View file

@ -0,0 +1,74 @@
define(function (require) {
var datemath = require('utils/datemath');
return function TimeMarkerFactory(d3) {
function TimeMarker(times, xScale, height) {
if (!(this instanceof TimeMarker)) {
return new TimeMarker(times, xScale, height);
}
var currentTimeArr = [{
'time': new Date().getTime(),
'class': 'time-marker',
'color': '#c80000',
'opacity': 0.3,
'width': 2
}];
this.xScale = xScale;
this.height = height;
this.times = (times.length) ? times.map(function (d) {
return {
'time': datemath.parse(d.time),
'class': d.class || 'time-marker',
'color': d.color || '#c80000',
'opacity': d.opacity || 0.3,
'width': d.width || 2
};
}) : currentTimeArr;
}
TimeMarker.prototype._isTimeBasedChart = function (selection) {
var data = selection.data();
return data.every(function (datum) {
return (datum.ordered && datum.ordered.date);
});
};
TimeMarker.prototype.render = function (selection) {
var self = this;
// return if not time based chart
if (!self._isTimeBasedChart(selection)) return;
selection.each(function () {
d3.select(this).selectAll('time-marker')
.data(self.times)
.enter().append('line')
.attr('class', function (d) {
return d.class;
})
.attr('pointer-events', 'none')
.attr('stroke', function (d) {
return d.color;
})
.attr('stroke-width', function (d) {
return d.width;
})
.attr('stroke-opacity', function (d) {
return d.opacity;
})
.attr('x1', function (d) {
return self.xScale(d.time);
})
.attr('x2', function (d) {
return self.xScale(d.time);
})
.attr('y1', self.height)
.attr('y2', self.xScale.range()[0]);
});
};
return TimeMarker;
};
});

View file

@ -479,6 +479,7 @@ define(function (require) {
type: 'histogram',
params: {
addLegend: false,
addTimeMarker: true
},
listeners: {
click: function (e) {

View file

@ -1,6 +1,5 @@
define(function (require) {
var _ = require('lodash');
var configDefaults = require('components/config/defaults');
require('components/elastic_textarea');
require('modules').get('apps/settings')
@ -14,6 +13,7 @@ define(function (require) {
configs: '='
},
link: function ($scope) {
var configDefaults = Private(require('components/config/defaults'));
var notify = new Notifier();
var keyCodes = {
ESC: 27

View file

@ -1,6 +1,5 @@
define(function (require) {
var _ = require('lodash');
var configDefaults = require('components/config/defaults');
var getValType = require('plugins/settings/sections/advanced/lib/get_val_type');
@ -16,6 +15,7 @@ define(function (require) {
return {
restrict: 'E',
link: function ($scope) {
var configDefaults = Private(require('components/config/defaults'));
var keyCodes = {
ESC: 27
};
@ -70,4 +70,4 @@ define(function (require) {
display: 'Advanced',
url: '#/settings/advanced'
};
});
});

View file

@ -17,4 +17,10 @@
Scale Y-Axis to Data Bounds
</label>
</div>
<div class="vis-option-item" ng-show="vis.hasSchemaAgg('segment', 'date_histogram')">
<label>
<input type="checkbox" ng-model="vis.params.addTimeMarker" ng-checked="vis.params.addTimeMarker">
Current time marker
</label>
</div>
</div>

View file

@ -20,7 +20,9 @@ define(function (require) {
scale: 'linear',
mode: 'stacked',
interpolate: 'linear',
defaultYExtents: false
defaultYExtents: false,
times: [],
addTimeMarker: false
},
scales: ['linear', 'log', 'square root'],
modes: ['stacked', 'overlap', 'percentage', 'wiggle', 'silhouette'],

View file

@ -11,9 +11,25 @@
</div>
<div class="vis-option-item">
</br>
<label>
<input type="checkbox" value="{{isDesaturated}}" ng-model="vis.params.isDesaturated" name="isDesaturated" ng-checked="vis.params.isDesaturated">
<input type="checkbox"
name="autoPrecision"
value="{{autoPrecision}}"
ng-model="vis.params.autoPrecision"
ng-checked="vis.params.autoPrecision">
Change geoHash precision on map zoom
</label>
</div>
<div class="vis-option-item">
<label>
<input type="checkbox"
name="isDesaturated"
value="{{isDesaturated}}"
ng-model="vis.params.isDesaturated"
ng-checked="vis.params.isDesaturated">
Desaturate map tiles
</label>
</div>
</div>

View file

@ -16,7 +16,9 @@ define(function (require) {
addLegend: true,
scale: 'linear',
mode: 'stacked',
defaultYExtents: false
defaultYExtents: false,
times: [],
addTimeMarker: false
},
scales: ['linear', 'log', 'square root'],
modes: ['stacked', 'percentage', 'grouped'],

View file

@ -20,7 +20,9 @@ define(function (require) {
drawLinesBetweenPoints: true,
radiusRatio: 9,
scale: 'linear',
defaultYExtents: false
defaultYExtents: false,
times: [],
addTimeMarker: false
},
scales: ['linear', 'log', 'square root'],
editor: require('text!plugins/vis_types/vislib/editors/line.html')

View file

@ -13,7 +13,8 @@ define(function (require) {
params: {
defaults: {
mapType: 'Scaled Circle Markers',
isDesaturated: true
isDesaturated: true,
autoPrecision: true
},
mapTypes: ['Scaled Circle Markers', 'Shaded Circle Markers', 'Shaded Geohash Grid'],
editor: require('text!plugins/vis_types/vislib/editors/tile_map.html')

View file

@ -50,7 +50,7 @@ define(function (require) {
'kibana/notify',
'kibana/courier'
])
.controller('VisEditor', function ($scope, $route, timefilter, AppState, $location, kbnUrl, $timeout, courier, Private, Promise) {
.controller('VisEditor', function ($scope, $route, timefilter, AppState, $location, kbnUrl, $timeout, courier, Private, Promise, config) {
var _ = require('lodash');
var angular = require('angular');
@ -125,6 +125,16 @@ define(function (require) {
editableVis.listeners.click = vis.listeners.click = filterBarClickHandler($state);
editableVis.listeners.brush = vis.listeners.brush = brushEvent;
editableVis.listeners.mapZoomEnd = vis.listeners.mapZoomEnd = function (event) {
if (!vis.params.autoPrecision) return;
var geoHash = _.find(vis.aggs, function (agg) {
return agg.type.name === 'geohash_grid';
});
geoHash.params.precision = autoPrecision(event.zoom, config.get('visualization:tileMap:maxPrecision'));
$scope.fetch();
};
// track state of editable vis vs. "actual" vis
$scope.stageEditableVis = transferVisState(editableVis, vis, true);
@ -288,6 +298,10 @@ define(function (require) {
};
}
function autoPrecision(zoom, limit) {
return Math.min(Math.round(0.02 * Math.pow(zoom, 2) + 0.24 * zoom + 0.723), limit);
}
init();
});
});

View file

@ -262,11 +262,18 @@ define(function (require) {
},
/**
* Shortcut for the simple version of _.deepGet
* Shortcut for the simple version of _.deepGet with support for default
* values added
*
* @param {obj} any - the value to read from
* @param {string|array} path - the location of the value to return as
* a dot-notated string or array of keys.
* @param {any} def - when the value is null or undefined return this instead
* @return {any}
*/
get: function (obj, path) {
return _.deepGet(obj, path);
get: function (obj, path, def) {
var val = _.deepGet(obj, path);
return (val == null && def != null) ? def : val;
},
/**

View file

@ -10,7 +10,7 @@ define(function (require) {
'=' : '-equal-'
};
_.each(trans, function (val, key) {
var regex = new RegExp(key);
var regex = new RegExp(key, 'g');
id = id.replace(regex, val);
});
id = id.replace(/[\s]+/g, '-');

View file

@ -16,6 +16,17 @@ function checkPath(path) {
}
}
// Set defaults for config file stuff
kibana.port = kibana.port || 5601;
kibana.host = kibana.host || '0.0.0.0';
kibana.elasticsearch_url = kibana.elasticsearch_url || 'http://localhost:9200';
kibana.maxSockets = kibana.maxSockets || Infinity;
kibana.log_file = kibana.log_file || null;
kibana.request_timeout = kibana.startup_timeout == null ? 0 : kibana.request_timeout;
kibana.ping_timeout = kibana.ping_timeout == null ? kibana.request_timeout : kibana.ping_timeout;
kibana.startup_timeout = kibana.startup_timeout == null ? 5000 : kibana.startup_timeout;
// Check if the local public folder is present. This means we are running in
// the NPM module. If it's not there then we are running in the git root.
var public_folder = path.resolve(__dirname, '..', 'public');
@ -33,13 +44,10 @@ try {
packagePath = path.resolve(__dirname, '..', '..', '..', 'package.json');
}
var requestTimeout = kibana.request_timeout || 0;
var pingTimeout = kibana.ping_timeout == null ? requestTimeout : kibana.ping_timeout;
var config = module.exports = {
port : kibana.port || 5601,
host : kibana.host || '0.0.0.0',
elasticsearch : kibana.elasticsearch_url || 'http://localhost:9200',
port : kibana.port,
host : kibana.host,
elasticsearch : kibana.elasticsearch_url,
root : path.normalize(path.join(__dirname, '..')),
quiet : false,
public_folder : public_folder,
@ -49,10 +57,10 @@ var config = module.exports = {
package : require(packagePath),
htpasswd : htpasswdPath,
buildNum : '@@buildNum',
maxSockets : kibana.maxSockets || Infinity,
log_file : kibana.log_file || null,
request_timeout : requestTimeout,
ping_timeout : pingTimeout
maxSockets : kibana.maxSockets,
log_file : kibana.log_file,
request_timeout : kibana.request_timeout,
ping_timeout : kibana.ping_timeout
};
config.plugins = listPlugins(config);

View file

@ -45,6 +45,9 @@ request_timeout: 300000
# Set to 0 to disable.
shard_timeout: 0
# Time in milliseconds to wait for Elasticsearch at Kibana startup before retrying
# startup_timeout: 5000
# Set to false to have a complete disregard for the validity of the SSL
# certificate.
verify_ssl: true

View file

@ -6,7 +6,7 @@ var logger = require('./logger');
var config = require('../config');
function waitForPong() {
return client.ping()
return client.ping({requestTimeout: config.kibana.startup_timeout})
.catch(function (err) {
if (!(err instanceof NoConnections)) throw err;

View file

@ -0,0 +1,74 @@
define(function (require) {
describe('config component', function () {
var $scope;
var config;
var defaults;
var configFile;
beforeEach(module('kibana'));
beforeEach(inject(function ($injector, Private) {
config = $injector.get('config');
$scope = $injector.get('$rootScope');
configFile = $injector.get('configFile');
defaults = Private(require('components/config/defaults'));
}));
it('exposes the configFile', function () {
expect(config.file).to.be(configFile);
});
describe('#get', function () {
it('gives access to config values', function () {
expect(config.get('dateFormat')).to.be.a('string');
});
it('reads from the defaults', function () {
var initial = config.get('dateFormat');
var newDefault = initial + '- new';
defaults.dateFormat.value = newDefault;
expect(config.get('dateFormat')).to.be(newDefault);
});
});
describe('#set', function () {
it('stores a value in the config val set', function () {
var initial = config.get('dateFormat');
config.set('dateFormat', 'notaformat');
expect(config.get('dateFormat')).to.be('notaformat');
});
});
describe('#$bind', function () {
it('binds a config key to a $scope property', function () {
var dateFormat = config.get('dateFormat');
config.$bind($scope, 'dateFormat');
expect($scope).to.have.property('dateFormat', dateFormat);
});
it('alows overriding the property name', function () {
var dateFormat = config.get('dateFormat');
config.$bind($scope, 'dateFormat', 'defaultDateFormat');
expect($scope).to.not.have.property('dateFormat');
expect($scope).to.have.property('defaultDateFormat', dateFormat);
});
it('keeps the property up to date', function () {
var dateFormat = config.get('dateFormat');
var newDateFormat = dateFormat + ' NEW NEW NEW!';
config.$bind($scope, 'dateFormat');
expect($scope).to.have.property('dateFormat', dateFormat);
config.set('dateFormat', newDateFormat);
expect($scope).to.have.property('dateFormat', newDateFormat);
});
});
});
});

View file

@ -16,7 +16,11 @@ define(function (require) {
['test / ^test', 'test-slash-^test'],
['test ? test', 'test-questionmark-test'],
['test = test', 'test-equal-test'],
['test & test', 'test-ampersand-test']
['test & test', 'test-ampersand-test'],
['test/test/test', 'test-slash-test-slash-test'],
['test?test?test', 'test-questionmark-test-questionmark-test'],
['test&test&test', 'test-ampersand-test-ampersand-test'],
['test=test=test', 'test-equal-test-equal-test']
];
_.each(fixtures, function (fixture) {

View file

@ -5,17 +5,20 @@ define(function (require) {
var slices = require('vislib_fixtures/mock_data/histogram/_slices');
var stackedSeries = require('vislib_fixtures/mock_data/date_histogram/_stacked_series');
var histogramSlices = require('vislib_fixtures/mock_data/histogram/_slices');
var dataArray = [
stackedSeries,
slices,
histogramSlices,
stackedSeries,
stackedSeries,
stackedSeries
];
var chartTypes = [
'histogram',
'pie',
'pie',
'area',
'line'
];
@ -24,7 +27,7 @@ define(function (require) {
histogram: '.chart rect',
pie: '.chart path',
area: '.chart path',
line: '.chart circle',
line: '.chart circle'
};
angular.module('LegendFactory', ['kibana']);

View file

@ -0,0 +1,127 @@
define(function (require) {
var angular = require('angular');
var _ = require('lodash');
var $ = require('jquery');
var fixtures = require('fixtures/fake_hierarchical_data');
var series = require('vislib_fixtures/mock_data/date_histogram/_series');
var terms = require('vislib_fixtures/mock_data/terms/_columns');
angular.module('TimeMarkerFactory', ['kibana']);
describe('VisLib Time Marker Test Suite', function () {
var height = 50;
var color = '#ff0000';
var opacity = 0.5;
var width = 3;
var customClass = 'custom-time-marker';
var dateMathTimes = ['now-1m', 'now-5m', 'now-15m'];
var myTimes = dateMathTimes.map(function (dateMathString) {
return {
time: dateMathString,
class: customClass,
color: color,
opacity: opacity,
width: width
};
});
var getExtent = function (dataArray, func) {
return func(dataArray, function (obj) {
return func(obj.values, function (d) {
return d.x;
});
});
};
var times = [];
var TimeMarker;
var defaultMarker;
var customMarker;
var selection;
var xScale;
var minDomain;
var maxDomain;
var domain;
beforeEach(function () {
module('TimeMarkerFactory');
});
beforeEach(function () {
inject(function (d3, Private) {
TimeMarker = Private(require('components/vislib/visualizations/time_marker'));
minDomain = getExtent(series.series, d3.min);
maxDomain = getExtent(series.series, d3.max);
domain = [minDomain, maxDomain];
xScale = d3.time.scale().domain(domain).range([0, 500]);
defaultMarker = new TimeMarker(times, xScale, height);
customMarker = new TimeMarker(myTimes, xScale, height);
selection = d3.select('body').append('div').attr('class', 'marker');
selection.datum(series);
});
});
afterEach(function () {
selection.remove('*');
selection = null;
defaultMarker = null;
});
describe('_isTimeBaseChart method', function () {
var boolean;
var newSelection;
it('should return true when data is time based', function () {
boolean = defaultMarker._isTimeBasedChart(selection);
expect(boolean).to.be(true);
});
it('should return false when data is not time based', function () {
newSelection = selection.datum(terms);
boolean = defaultMarker._isTimeBasedChart(newSelection);
expect(boolean).to.be(false);
});
});
describe('render method', function () {
var lineArray;
beforeEach(function () {
defaultMarker.render(selection);
customMarker.render(selection);
lineArray = document.getElementsByClassName('custom-time-marker');
});
it('should render the default line', function () {
expect(!!$('line.time-marker').length).to.be(true);
});
it('should render the custom (user defined) lines', function () {
expect($('line.custom-time-marker').length).to.be(myTimes.length);
});
it('should set the class', function () {
Array.prototype.forEach.call(lineArray, function (line) {
expect(line.getAttribute('class')).to.be(customClass);
});
});
it('should set the stroke', function () {
Array.prototype.forEach.call(lineArray, function (line) {
expect(line.getAttribute('stroke')).to.be(color);
});
});
it('should set the stroke-opacity', function () {
Array.prototype.forEach.call(lineArray, function (line) {
expect(+line.getAttribute('stroke-opacity')).to.be(opacity);
});
});
it('should set the stroke-width', function () {
Array.prototype.forEach.call(lineArray, function (line) {
expect(+line.getAttribute('stroke-width')).to.be(width);
});
});
});
});
});