Merge branch 'master' of github.com:elastic/kibana into apps/home

This commit is contained in:
Spencer Alger 2015-07-09 20:18:26 -07:00
commit e809f4b718
9 changed files with 391 additions and 54 deletions

View file

@ -35,10 +35,6 @@ module.exports = function (grunt) {
'<%= src %>/**/*.js',
'<%= unitTestDir %>/**/*.js',
'!<%= unitTestDir %>/specs/vislib/fixture/**/*'
],
lessFiles: [
'<%= src %>/**/*.less',
'!<%= src %>/**/_*.less'
]
};

View file

@ -17,6 +17,7 @@
"angular-bootstrap": "0.10.0",
"angular-elastic": "2.4.2",
"angular-mocks": "1.2.28",
"angular-nvd3": "https://github.com/krispo/angular-nvd3.git#1.0.0-beta",
"angular-route": "1.2.28",
"angular-ui-ace": "0.2.3",
"bluebird": "~2.9.27",
@ -34,7 +35,10 @@
"ng-clip": "0.2.6",
"marked": "0.3.3",
"numeral": "1.5.3",
"nvd3": "1.7.1",
"leaflet-draw": "0.2.4"
},
"devDependencies": {}
"resolutions": {
"d3": "3.5.5"
}
}

View file

@ -0,0 +1,3 @@
{
"extends": "../../../../../.jshintrc.browser"
}

View file

@ -0,0 +1,229 @@
define(function (require) {
var angular = require('angular');
var $ = require('jquery');
var _ = require('lodash');
var moment = require('moment');
var numeral = require('numeral');
require('nvd3_directives');
// Make sure we don't have to deal with statuses by hand
function getStatus(plugin) {
var statusMap = {
green: {
label: 'success',
msg: 'Ready',
idx: 1
},
yellow: {
label: 'warning',
msg: 'S.N.A.F.U.',
idx: 2
},
red: {
label: 'danger',
msg: 'Danger Will Robinson! Danger!',
idx: 3
},
loading: {
label: 'info',
msg: 'Loading...',
idx: 0
}
};
if (!_.isObject(plugin) || _.isUndefined(plugin)) {
plugin = {state: plugin};
}
return statusMap[plugin.state];
}
function getLabel(plugin) { return getStatus(plugin).label; }
// Turns thisIsASentence to
// This Is A Sentence
function niceName(name) {
return name
.split(/(?=[A-Z])/)
.map(function (word) { return word[0].toUpperCase() + _.rest(word).join(''); })
.join(' ');
}
function formatNumber(num, which) {
var format = '0.00';
var postfix = '';
switch (which) {
case 'time':
return moment(num).format('HH:mm:ss');
case 'byte':
format += 'b';
break;
case 'ms':
postfix = 'ms';
break;
}
return numeral(num).format(format) + postfix;
}
function numberType(key) {
var byteMetrics = ['heapTotal', 'heapUsed', 'rss'];
var msMetrics = ['delay', 'responseTimeAvg', 'responseTimeMax'];
var preciseMetric = ['requests', 'load'];
if ( byteMetrics.indexOf(key) > -1 ) {
return 'byte';
} else if (msMetrics.indexOf(key) > -1 ) {
return 'ms';
} else {
return 'precise';
}
}
var makeChartOptions = _.memoize(function (type) {
return {
chart: {
type: 'lineChart',
height: 200,
showLegend: false,
showXAxis: false,
showYAxis: false,
useInteractiveGuideline: true,
tooltips: true,
pointSize: 0,
color: ['#444', '#777', '#aaa'],
margin: {
top: 10,
left: 0,
right: 0,
bottom: 20
},
xAxis: { tickFormat: function (d) { return formatNumber(d, 'time'); } },
yAxis: { tickFormat: function (d) { return formatNumber(d, type); }, },
y: function (d) { return d.y; },
x: function (d) { return d.x; }
}
};
});
// The Kibana App
require('modules')
.get('KibanaStatusApp', ['nvd3'])
.controller('StatusPage', function ($scope, $http, $window, $timeout) {
// the object representing all of the elements the ui touches
$scope.ui = {
// show the system status by going through all of the plugins,
// and making sure they're green.
systemStatus: (function () {
// for convenience
function getIdx(plugin) { return getStatus(plugin).idx; }
return function () {
var currentStatus = 'loading';
var currentIdx = getIdx(currentStatus);
// FIXME eh, not too thrilled about this.
var status = _.reduce($scope.ui.plugins, function (curr, plugin, key) {
var pluginIdx = getIdx(plugin);
if (pluginIdx > currentIdx) {
// set the current status
currentStatus = plugin.state;
currentIdx = getIdx(plugin);
}
return currentStatus;
}, 'loading');
// give the ui the label for colors and such
return getStatus(status);
};
}()),
charts: {},
plugins: []
};
var windowHasFocus = true;
angular.element($window).bind({
blur: function () { windowHasFocus = false; },
focus: function () {
windowHasFocus = true;
getAppStatus();
}
});
function getAppStatus() {
// go ahead and get the info you want
$http
.get('/status/health')
.success(function (data) {
// Assign the propper variables to the scope and change them as necessary
// setup The charts
// wrap the metrics data and append the average
$scope.ui.charts = _.mapValues(data.metrics, function (metric, name) {
// Metric Values format
// metric: [[xValue, yValue], ...]
// LoadMetric:
// metric: [[xValue, [yValue, yValue2, yValue3]], ...]
// return [
// {type: 'line', key: name, yAxis: 1, values: [{x: xValue, y: yValue}, ...]},
// {type: 'line', key: name, yAxis: 1, values: [{x: xValue, y: yValue1}, ...]},
// {type: 'line', key: name, yAxis: 1, values: [{x: xValue, y: yValue2}, ...]}]
//
// Go through all of the metric values and split the values out.
// returns an array of all of the averages
var metricList = [];
var metricNumberType = numberType(name);
// convert the [x,y] into {x: x, y: y}
metric.forEach(function (vector) {
vector = _.flatten(vector);
var x = vector.shift();
vector.forEach(function (yValue, idx) {
if (!metricList[idx]) {
metricList[idx] = {
key: name + idx,
values: []
};
}
// unshift to make sure they're in the correct order
metricList[idx].values.unshift({x: x, y: yValue});
});
});
var average = metricList.map(function (data) {
var uglySum = data.values.reduce(function (sumSoFar, vector) {
return sumSoFar + vector.y;
}, 0);
return formatNumber(uglySum / data.values.length, metricNumberType);
});
var options = makeChartOptions(metricNumberType);
return { data: metricList, average: average, niceName: niceName(name), options: options };
});
// give the plugins their proper name so CSS classes can be properply applied
$scope.ui.plugins = _.mapValues(data.status, function (plugin) {
plugin.uiStatus = getLabel(plugin);
return plugin;
});
if (windowHasFocus) {
// go ahead and get another status in 5 seconds
$timeout(getAppStatus, 5000);
}
})
.error(function () {
window.alert('Something went terribly wrong while making the request!!! Perhaps your server is down?');
});
}
// Start it all up
getAppStatus();
});
return {
init: function () {
$(function () {
angular.bootstrap(window.document, ['nvd3', 'KibanaStatusApp']);
});
}
};
});

View file

@ -0,0 +1,23 @@
require.config({
baseUrl: '/',
paths: {
angular: '/bower_components/angular/angular',
css: '/bower_components/require-css/css',
d3: '/bower_components/d3/d3',
jquery: '/bower_components/jquery/dist/jquery',
lodash: '/utils/lodash-mixins/index',
lodash_src: '/bower_components/lodash/lodash',
moment: '/bower_components/moment/moment',
nvd3: '/bower_components/nvd3/build/nv.d3',
nvd3_directives: '/bower_components/angular-nvd3/dist/angular-nvd3',
numeral: '/bower_components/numeral/numeral'
},
shim: {
angular: {
deps: ['jquery'],
exports: 'angular'
},
nvd3: ['css!bower_components/nvd3/build/nv.d3.css', 'd3'],
nvd3_directives: ['angular', 'nvd3']
}
});

View file

@ -0,0 +1,115 @@
.section {
margin-bottom:15px;
}
.system_status_wrapper {
border:1px solid #0a8e03;
border-radius:5px;
overflow:hidden;
.title {
color:#ffffff;
height:50px;
line-height:50px;
background-color:#0a8e03;
margin:0 0 10px 0;
padding:0 15px;
background:-moz-linear-gradient(left,#0a8e03 0%,#96f501 100%);
background:-webkit-gradient(linear,left top,right top,color-stop(0%,#0a8e03),color-stop(100%,#96f501));
background:-webkit-linear-gradient(left,#0a8e03 0%,#96f501 100%);
background:-o-linear-gradient(left,#0a8e03 0%,#96f501 100%);
background:-ms-linear-gradient(left,#0a8e03 0%,#96f501 100%);
background:linear-gradient(to right,#0a8e03 0%,#96f501 100%);
filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#0a8e03',endColorstr='#96f501',GradientType=1);
}
}
.system_status_wrapper.system_status_danger {
border-color:#da1e04;
.title {
border-color:#da1e04;
background:#da1e04;
background:-moz-linear-gradient(left,#da1e04 0%,#ff730f 100%);
background:-webkit-gradient(linear,left top,right top,color-stop(0%,#da1e04),color-stop(100%,#ff730f));
background:-webkit-linear-gradient(left,#da1e04 0%,#ff730f 100%);
background:-o-linear-gradient(left,#da1e04 0%,#ff730f 100%);
background:-ms-linear-gradient(left,#da1e04 0%,#ff730f 100%);
background:linear-gradient(to right,#da1e04 0%,#ff730f 100%);
filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#da1e04',endColorstr='#ff730f',GradientType=1);
}
}
.system_status_wrapper.system_status_warning {
border-color:#fdee00;
.title {
border-color:#fdee00;
background:#fdee00;
background:-moz-linear-gradient(left,#fdee00 0%,#c16f00 100%);
background:-webkit-gradient(linear,left top,right top,color-stop(0%,#fdee00),color-stop(100%,#c16f00));
background:-webkit-linear-gradient(left,#fdee00 0%,#c16f00 100%);
background:-o-linear-gradient(left,#fdee00 0%,#c16f00 100%);
background:-ms-linear-gradient(left,#fdee00 0%,#c16f00 100%);
background:linear-gradient(to right,#fdee00 0%,#c16f00 100%);
filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdee00',endColorstr='#c16f00',GradientType=1);
}
}
#plugin_table {
margin:0 15px 15px 15px;
.plugin_row {
height:30px;
line-height:30px;
+ .plugin_row {
border-top:1px solid #ebebeb;
}
}
.plugin_table_header {
font-size:10px;
color:#a9a9a9;
height:25px;
line-height:25px;
}
.plugin_state {
border-left:1px solid #ebebeb;
padding:0;
padding-left:15px;
}
.plugin_table_plugin {
color:#608b32;
}
.plugin_key {
font-weight:bold;
padding:0px 5px;
}
.plugin_status_danger {
color:#da1e04;
}
}
.status_chart_wrapper {
border-top:1px solid #ebebeb;
border-left:1px solid #ebebeb;
.average {
font-size: 42px;
line-height:45px;
margin-top:0;
font-weight:bold;
}
.title {
margin:0 0 5px 0;
text-transform:capitalize;
}
}
#chart_cont {
margin-top:35px;
}
.status_chart_wrapper:nth-child(2), .status_chart_wrapper:nth-child(3) {
border-top:0 none transparent;
}
.status_chart_wrapper:first-child {
border-top:0 none transparent;
border-left:0 none transparent;
}
.status_chart_wrapper:nth-child(3n + 1) {
border-left:0 none transparent;
}
.status_chart_wrapper:nth-child(n + 4) {
padding-top:20px;
}
.nv-axis.nv-x .tick line {
display:none;
}

View file

@ -32,7 +32,11 @@ define(function (require) {
* @returns {D3.Selection|D3.Transition.Transition} DOM element with chart titles
*/
ChartTitle.prototype.render = function () {
return d3.select(this.el).selectAll('.chart-title').call(this.draw());
var el = d3.select(this.el).select('.chart-title').node();
var width = el ? el.clientWidth : 0;
var height = el ? el.clientHeight : 0;
return d3.select(this.el).selectAll('.chart-title').call(this.draw(width, height));
};
/**
@ -89,33 +93,21 @@ define(function (require) {
* @method draw
* @returns {Function} Appends chart titles to a D3 selection
*/
ChartTitle.prototype.draw = function () {
ChartTitle.prototype.draw = function (width, height) {
var self = this;
return function (selection) {
selection.each(function () {
var div = d3.select(this);
var dataType = this.parentNode.__data__.rows ? 'rows' : 'columns';
var width = $(this).width();
var height = $(this).height();
var size = dataType === 'rows' ? height : width;
var txtHtOffset = 11;
self.validateWidthandHeight(width, height);
div.append('svg')
.attr('width', function () {
if (dataType === 'rows') {
return height;
}
return width;
})
.attr('height', function () {
if (dataType === 'rows') {
return width;
}
return height;
})
.attr('width', width)
.attr('height', height)
.append('text')
.attr('transform', function () {
if (dataType === 'rows') {

View file

@ -4,6 +4,7 @@ module.exports = function (grunt) {
licenses: [
'MIT',
'MIT*',
'MIT License',
'MIT/X11',
'new BSD, and MIT',
'BSD',
@ -20,9 +21,11 @@ module.exports = function (grunt) {
'Apache2',
'Apache-2.0',
'Apache, Version 2.0',
'Apache License, v2.0',
'ISC',
'WTFPL',
'Public-Domain'
'Public-Domain',
'UNLICENSE'
],
overrides: {
'assert-plus@0.1.5': ['MIT'],
@ -36,7 +39,10 @@ module.exports = function (grunt) {
'cycle@1.0.3': ['Public-Domain'],
'pkginfo@0.2.3': ['MIT'],
'uglify-js@2.2.5': ['BSD'],
'amdefine@0.1.1': ['BSD-3-Clause', 'MIT']
'amdefine@0.1.1': ['BSD-3-Clause', 'MIT'],
'flatten@0.0.1': ['MIT'],
'color-name@1.0.0': ['UNLICENSE'],
'css-color-names@0.0.1': ['MIT']
}
}
};

View file

@ -1,31 +0,0 @@
module.exports = function (grunt) {
var config = {
less: {
files: [
'src/**/*.less'
],
tasks: ['less:dev']
},
jade: {
files: [
'<%= unitTestDir %>/index.jade'
],
tasks: ['jade:test']
},
clientside_jade: {
files: [
'<%= testUtilsDir %>/istanbul_reporter/report.clientside.jade'
],
tasks: ['jade:clientside']
}
};
if (grunt.option('no-test-watcher')) {
// unset the test watcher
delete config.test;
}
return config;
};