Commit a3c8b095 by Zachary Tong

Merge remote-tracking branch 'upstream/master'

parents 1dcf9d65 06b196f6
...@@ -646,7 +646,7 @@ button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding- ...@@ -646,7 +646,7 @@ button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-
.nav>.disabled>a{color:#4d4d4d;} .nav>.disabled>a{color:#4d4d4d;}
.nav>.disabled>a:hover,.nav>.disabled>a:focus{text-decoration:none;background-color:transparent;cursor:default;} .nav>.disabled>a:hover,.nav>.disabled>a:focus{text-decoration:none;background-color:transparent;cursor:default;}
.navbar{overflow:visible;margin-bottom:20px;*position:relative;*z-index:2;} .navbar{overflow:visible;margin-bottom:20px;*position:relative;*z-index:2;}
.navbar-inner{min-height:40px;padding-left:20px;padding-right:20px;background-color:#2e2e2e;background-image:-moz-linear-gradient(top, #333333, #262626);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#262626));background-image:-webkit-linear-gradient(top, #333333, #262626);background-image:-o-linear-gradient(top, #333333, #262626);background-image:linear-gradient(to bottom, #333333, #262626);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff333333', endColorstr='#ff262626', GradientType=0);border:1px solid #080808;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 4px rgba(0, 0, 0, 0.065);-moz-box-shadow:0 1px 4px rgba(0, 0, 0, 0.065);box-shadow:0 1px 4px rgba(0, 0, 0, 0.065);*zoom:1;}.navbar-inner:before,.navbar-inner:after{display:table;content:"";line-height:0;} .navbar-inner{min-height:40px;padding-left:20px;padding-right:20px;background-color:#2e2e2e;background-image:-moz-linear-gradient(top, #404040, #262626);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#404040), to(#262626));background-image:-webkit-linear-gradient(top, #404040, #262626);background-image:-o-linear-gradient(top, #404040, #262626);background-image:linear-gradient(to bottom, #404040, #262626);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff404040', endColorstr='#ff262626', GradientType=0);border:1px solid #080808;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 4px rgba(0, 0, 0, 0.065);-moz-box-shadow:0 1px 4px rgba(0, 0, 0, 0.065);box-shadow:0 1px 4px rgba(0, 0, 0, 0.065);*zoom:1;}.navbar-inner:before,.navbar-inner:after{display:table;content:"";line-height:0;}
.navbar-inner:after{clear:both;} .navbar-inner:after{clear:both;}
.navbar .container{width:auto;} .navbar .container{width:auto;}
.nav-collapse.collapse{height:auto;overflow:visible;} .nav-collapse.collapse{height:auto;overflow:visible;}
......
...@@ -6,6 +6,50 @@ ...@@ -6,6 +6,50 @@
color: #000; color: #000;
} }
.kibana-row {
margin-left: 15px;
margin-bottom: 15px;
}
.navbar .brand {
color: #eee;
}
.navbar-inner {
border-width: 0 0 0px;
}
.row-close {
color: #bbb;
position: absolute;
font-size: 9pt;
font-weight: 200;
padding-left: 35px;
padding-top:0px;
}
.row-open {
text-align: right;
color: #bbb;
margin-top:30px;
position: absolute;
font-size: 13pt;
font-weight: 200;
-moz-transform-origin: 40px;
-ms-transform-origin: 40px;
-o-transform-origin: 40px;
-webkit-transform-origin: 40px;
transform-origin: 40px;
transform: rotate(-90deg);
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);
-webkit-transform: rotate(-90deg);
-moz-transform: rotate(-90deg);
}
.row-open i {
font-size: 10pt;
}
.odd { .odd {
background-color: #f9f9f9; background-color: #f9f9f9;
} }
...@@ -96,3 +140,8 @@ ...@@ -96,3 +140,8 @@
} }
.typeahead { z-index: 1051; } .typeahead { z-index: 1051; }
.navbar-inner {
padding-left: 0px;
padding-right: 0px;
}
\ No newline at end of file
/*! elastic.js - v1.0.0 - 2013-01-15 /*! elastic.js - v1.0.0 - 2013-03-05
* https://github.com/fullscale/elastic.js * https://github.com/fullscale/elastic.js
* Copyright (c) 2013 FullScale Labs, LLC; Licensed MIT */ * Copyright (c) 2013 FullScale Labs, LLC; Licensed MIT */
/*jshint browser:true */ /*jshint browser:true */
/*global angular:true */ /*global angular:true */
/*jshint es5:true */
'use strict'; 'use strict';
/* /*
...@@ -26,8 +27,8 @@ angular.module('elasticjs.service', []) ...@@ -26,8 +27,8 @@ angular.module('elasticjs.service', [])
(successcb || angular.noop)(response.data); (successcb || angular.noop)(response.data);
return response.data; return response.data;
}, function (response) { }, function (response) {
(errorcb || angular.noop)(undefined); (errorcb || angular.noop)(response.data);
return undefined; return response.data;
}); });
}; };
......
/*! elastic.js - v1.0.0 - 2013-01-15 /*! elastic.js - v1.0.0 - 2013-03-05
* https://github.com/fullscale/elastic.js * https://github.com/fullscale/elastic.js
* Copyright (c) 2013 FullScale Labs, LLC; Licensed MIT */ * Copyright (c) 2013 FullScale Labs, LLC; Licensed MIT */
"use strict";angular.module("elasticjs.service",[]).factory("ejsResource",["$http",function(e){return function(t){var n=window.ejs||{},r=function(e,t,n){return e.then(function(e){return(t||angular.noop)(e.data),e.data},function(e){return(n||angular.noop)(undefined),undefined})};return t==null&&(t=""),n.client={server:function(e){return e==null?t:(t=e,this)},post:function(n,i,s,o){return n=t+n,r(e.post(n,i),s,o)},get:function(n,i,s,o){return n=t+n,r(e.get(n,i),s,o)},put:function(n,i,s,o){return n=t+n,r(e.put(n,i),s,o)},del:function(n,i,s,o){return n=t+n,r(e.delete(n,i),s,o)},head:function(n,r,i,s){return n=t+n,e.head(n,r).then(function(e){return(i||angular.noop)(e.headers()),e.headers()},function(e){return(s||angular.noop)(undefined),undefined})}},n}}]); "use strict";angular.module("elasticjs.service",[]).factory("ejsResource",["$http",function(e){return function(t){var n=window.ejs||{},r=function(e,t,n){return e.then(function(e){return(t||angular.noop)(e.data),e.data},function(e){return(n||angular.noop)(undefined),undefined})};return t==null&&(t=""),n.client={server:function(e){return e==null?t:(t=e,this)},post:function(n,i,s,o){return n=t+n,r(e.post(n,i),s,o)},get:function(n,i,s,o){return n=t+n,r(e.get(n,i),s,o)},put:function(n,i,s,o){return n=t+n,r(e.put(n,i),s,o)},del:function(n,i,s,o){return n=t+n,r(e.delete(n,i),s,o)},head:function(n,r,i,s){return n=t+n,e.head(n,r).then(function(e){return(i||angular.noop)(e.headers()),e.headers()},function(e){return(s||angular.noop)(undefined),undefined})}},n}}]);
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -36,13 +36,13 @@ ...@@ -36,13 +36,13 @@
<div class="navbar navbar-static-top"> <div class="navbar navbar-static-top">
<div class="navbar-inner"> <div class="navbar-inner">
<div class="container-fluid"> <div class="container-fluid">
<p class="navbar-text pull-right"><small>Kibana 3 Preview</small></p> <p class="navbar-text pull-right"><small><strong>Kibana 3</strong> <small>milestone 1</small></small></p>
<span class="brand">{{dashboards.title}}</span> <span class="brand">{{dashboards.title}}</span>
<div class="brand"><i class='icon-edit pointer' ng-show='dashboards.editable' bs-modal="'partials/dasheditor.html'"></i></div> <div class="brand"><i class='icon-edit pointer' ng-show='dashboards.editable' bs-modal="'partials/dasheditor.html'"></i></div>
</div> </div>
</div> </div>
</div> </div>
<div class="container-fluid"> <div class="container-fluid main">
<div class="row-fluid"> <div class="row-fluid">
<div ng-view></div> <div ng-view></div>
</div> </div>
......
...@@ -27,7 +27,7 @@ var labjs = $LAB ...@@ -27,7 +27,7 @@ var labjs = $LAB
.script("common/lib/angular-strap.min.js") .script("common/lib/angular-strap.min.js")
.script("common/lib/angular-sanitize.min.js") .script("common/lib/angular-sanitize.min.js")
.script("common/lib/elastic.min.js") .script("common/lib/elastic.min.js")
.script("common/lib/elastic-angular-client.min.js") .script("common/lib/elastic-angular-client.js")
.script("common/lib/dateformat.js") .script("common/lib/dateformat.js")
.script("common/lib/date.js") .script("common/lib/date.js")
.script("common/lib/datepicker.js") .script("common/lib/datepicker.js")
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
'use strict'; 'use strict';
angular.module('kibana.controllers', []) angular.module('kibana.controllers', [])
.controller('DashCtrl', function($scope, $rootScope, $http, $timeout, ejsResource, eventBus) { .controller('DashCtrl', function($scope, $rootScope, $http, $timeout, ejsResource, eventBus, fields) {
var _d = { var _d = {
title: "", title: "",
...@@ -14,7 +14,11 @@ angular.module('kibana.controllers', []) ...@@ -14,7 +14,11 @@ angular.module('kibana.controllers', [])
$scope.init = function() { $scope.init = function() {
$scope.config = config; $scope.config = config;
// Make underscore.js available to views
$scope._ = _; $scope._ = _;
// Provide a global list of all see fields
$scope.fields = fields
$scope.reset_row(); $scope.reset_row();
$scope.clear_all_alerts(); $scope.clear_all_alerts();
...@@ -44,6 +48,10 @@ angular.module('kibana.controllers', []) ...@@ -44,6 +48,10 @@ angular.module('kibana.controllers', [])
}; };
}; };
$scope.row_style = function(row) {
return { 'min-height': row.collapse ? '5px' : row.height }
}
$scope.alert = function(title,text,severity,timeout) { $scope.alert = function(title,text,severity,timeout) {
var alert = { var alert = {
title: title, title: title,
...@@ -70,6 +78,12 @@ angular.module('kibana.controllers', []) ...@@ -70,6 +78,12 @@ angular.module('kibana.controllers', [])
return 'panels/'+type+'/editor.html'; return 'panels/'+type+'/editor.html';
} }
// This is whoafully incomplete, but will do for now
$scope.parse_error = function(data) {
var _error = data.match("nested: (.*?);")
return _.isNull(_error) ? data : _error[1];
}
$scope.init(); $scope.init();
}) })
...@@ -86,7 +100,7 @@ angular.module('kibana.controllers', []) ...@@ -86,7 +100,7 @@ angular.module('kibana.controllers', [])
_.defaults($scope.row,_d) _.defaults($scope.row,_d)
$scope.init = function(){ $scope.init = function() {
$scope.reset_panel(); $scope.reset_panel();
} }
...@@ -94,13 +108,14 @@ angular.module('kibana.controllers', []) ...@@ -94,13 +108,14 @@ angular.module('kibana.controllers', [])
row.collapse = row.collapse ? false : true; row.collapse = row.collapse ? false : true;
if (!row.collapse) { if (!row.collapse) {
$timeout(function() { $timeout(function() {
$scope.send_render(); $scope.$broadcast('render')
}); });
} }
} }
$scope.send_render = function() { // This can be overridden by individual panel
$scope.$broadcast('render'); $scope.close_edit = function() {
$scope.$broadcast('render')
} }
$scope.add_panel = function(row,panel) { $scope.add_panel = function(row,panel) {
...@@ -109,11 +124,11 @@ angular.module('kibana.controllers', []) ...@@ -109,11 +124,11 @@ angular.module('kibana.controllers', [])
$scope.reset_panel = function() { $scope.reset_panel = function() {
$scope.panel = { $scope.panel = {
loading: false, loading : false,
error: false, error : false,
span: 3, span : 3,
editable: true, editable: true,
group: ['default'], group : ['default'],
}; };
}; };
......
...@@ -68,6 +68,21 @@ angular.module('kibana.services', []) ...@@ -68,6 +68,21 @@ angular.module('kibana.services', [])
} }
}) })
/* Service: fields
Provides a global list of all seen fields for use in editor panels
*/
.factory('fields', function($rootScope) {
var fields = {
list : []
}
$rootScope.$on('fields', function(event,f) {
fields.list = _.union(f.data.all,fields.list)
})
return fields;
})
.service('timer', function($timeout) { .service('timer', function($timeout) {
// This service really just tracks a list of $timeout promises to give us a // This service really just tracks a list of $timeout promises to give us a
// method for cancelling them all when we need to // method for cancelling them all when we need to
......
...@@ -187,8 +187,9 @@ angular.module('kibana.dashcontrol', []) ...@@ -187,8 +187,9 @@ angular.module('kibana.dashcontrol', [])
var results = request.query( var results = request.query(
$scope.ejs.QueryStringQuery(query || '*') $scope.ejs.QueryStringQuery(query || '*')
).size($scope.panel.elasticsearch_size).doSearch(); ).size($scope.panel.elasticsearch_size).doSearch();
results.then(function(results) { results.then(function(results) {
if(_.isUndefined(results)) { if(_.isUndefined(results.hits)) {
return; return;
} }
$scope.panel.error = false; $scope.panel.error = false;
......
<div class="row-fluid" ng-controller='histogram'> <div ng-controller='histogram'>
<div class="row-fluid">
<div class="span3"> <div class="span3">
<form style="margin-bottom: 0px"> <form style="margin-bottom: 0px">
<h6>Label</h6> <h6>Label</h6>
...@@ -14,8 +15,8 @@ ...@@ -14,8 +15,8 @@
</div> </div>
<div class="span1"> <div class="span1">
</div> </div>
</div> </div>
<div class="row-fluid" ng-repeat="q in panel.query"> <div class="row-fluid" ng-repeat="q in panel.query">
<div class="span3"> <div class="span3">
<form style="margin-bottom: 0px"> <form style="margin-bottom: 0px">
<input type="text" style="width:70%" ng-model="q.label"> <input type="text" style="width:70%" ng-model="q.label">
...@@ -30,16 +31,26 @@ ...@@ -30,16 +31,26 @@
<div class="span1"> <div class="span1">
<i class="icon-remove pointer" ng-click="remove_query(q)"></i> <i class="icon-remove pointer" ng-click="remove_query(q)"></i>
</div> </div>
</div>
<div class="row-fluid">
<div class="span3">
<label class="small">Chart Options</label>
<select ng-change="$emit('render')" multiple style="width:95%" ng-model="panel.show" ng-options="f for f in ['bars','points','stack','lines','legend','x-axis','y-axis']"></select>
</div> </div>
<div class="span3"> <h5>Chart Options</h5>
<label class="small">Line Fill (1 - 10)</label> <div class="row-fluid" style="margin-bottom:10px;">
<input ng-change="$emit('render')" type="number" class="input-mini" ng-model="panel.fill"> <div class="span1"> <label class="small">Bars</label><input ng-change="$emit('render')" type="checkbox" ng-model="panel.bars" ng-checked="panel.bars"></div>
<div class="span1"> <label class="small">Lines</label><input ng-change="$emit('render')" type="checkbox" ng-model="panel.lines" ng-checked="panel.lines"></div>
<div class="span1"> <label class="small">Points</label><input ng-change="$emit('render')" type="checkbox" ng-model="panel.points" ng-checked="panel.points"></div>
<div class="span1"> <label class="small">Stack</label><input ng-change="$emit('render')" type="checkbox" ng-model="panel.stack" ng-checked="panel.stack"></div>
<div class="span1"> <label class="small">Legend</label><input ng-change="$emit('render')" type="checkbox" ng-model="panel.legend" ng-checked="panel.legend"></div>
<div class="span1"> <label class="small">xAxis</label><input ng-change="$emit('render')" type="checkbox" ng-model="panel['x-axis']" ng-checked="panel['x-axis']"></div>
<div class="span1"> <label class="small">yAxis</label><input ng-change="$emit('render')" type="checkbox" ng-model="panel['y-axis']" ng-checked="panel['y-axis']"></div>
<div class="span2" ng-show="panel.lines">
<label class="small">Line Fill</label>
<select ng-change="$emit('render')" class="input-mini" ng-model="panel.fill" ng-options="f for f in [0,1,2,3,4,5,6,7,8,9,10]"></select>
</div> </div>
<div class="span2" ng-show="panel.lines">
<label class="small">Line Width</label>
<select ng-change="$emit('render')" class="input-mini" ng-model="panel.linewidth" ng-options="f for f in [0,1,2,3,4,5,6,7,8,9,10]"></select>
</div>
</div>
<div class="row-fluid">
<div class="span3"> <div class="span3">
<label class="small">Time correction</label> <label class="small">Time correction</label>
<select ng-change="$emit('render')" ng-model="panel.timezone" class='input-small' ng-options="f for f in ['browser','utc']"></select> <select ng-change="$emit('render')" ng-model="panel.timezone" class='input-small' ng-options="f for f in ['browser','utc']"></select>
...@@ -47,9 +58,9 @@ ...@@ -47,9 +58,9 @@
<div class="span2"> <div class="span2">
<label class="small">Zoom Links</label><input type="checkbox" ng-model="panel.zoomlinks" ng-checked="panel.zoomlinks"> <label class="small">Zoom Links</label><input type="checkbox" ng-model="panel.zoomlinks" ng-checked="panel.zoomlinks">
</div> </div>
</div> </div>
<h5>Panel Spy</h5> <h5>Panel Spy</h5>
<div class="row-fluid"> <div class="row-fluid">
<div class="span2"> <div class="span2">
<label class="small">Spyable</label><input type="checkbox" ng-model="panel.spyable" ng-checked="panel.spyable"> <label class="small">Spyable</label><input type="checkbox" ng-model="panel.spyable" ng-checked="panel.spyable">
</div> </div>
...@@ -58,4 +69,5 @@ ...@@ -58,4 +69,5 @@
be accessed by clicking the <i class='icon-eye-open'></i> in the top right be accessed by clicking the <i class='icon-eye-open'></i> in the top right
of the panel. of the panel.
</div> </div>
</div>
</div> </div>
...@@ -2,15 +2,16 @@ ...@@ -2,15 +2,16 @@
<span ng-show="panel.spyable" style="position:absolute;right:0px;top:0px" class='panelextra pointer'> <span ng-show="panel.spyable" style="position:absolute;right:0px;top:0px" class='panelextra pointer'>
<i bs-modal="'partials/modal.html'" class="icon-eye-open"></i> <i bs-modal="'partials/modal.html'" class="icon-eye-open"></i>
</span> </span>
<center ng-show='panel.zoomlinks && data'> <div>
<span ng-show='panel.zoomlinks && data'>
<a class='small' ng-click='zoom(0.5)'><i class='icon-zoom-in'></i> Zoom In</a> <a class='small' ng-click='zoom(0.5)'><i class='icon-zoom-in'></i> Zoom In</a>
<a class='small' ng-click='zoom(2)'><i class='icon-zoom-out'></i> Zoom Out</a> <a class='small' ng-click='zoom(2)'><i class='icon-zoom-out'></i> Zoom Out</a>
</center> </span> |
<div> <span ng-show="panel.legend" ng-repeat='series in plot.getData()' style='display:inline-block;padding-right:5px'>
<span ng-repeat='series in legend' style='display:inline-block;padding-right:5px'> <div style="display:inline-block;background:{{series.color}};height:10px;width:10px;border-radius:5px;"></div>
<div style="display:inline-block;background:{{series.color}};height:10px;width:10px"></div>
<div class='small' style='display:inline-block'>{{series.label}} ({{series.hits}})</div> <div class='small' style='display:inline-block'>{{series.label}} ({{series.hits}})</div>
</span><span class="small"> per <strong>{{panel.interval}}</strong> | (<strong>{{hits}}</strong> total)</span> </span><span class="small"> per <strong>{{panel.interval}}</strong> | (<strong>{{hits}}</strong> total)</span>
</div> </div>
<div histogram params="{{panel}}" style="height:{{panel.height || row.height}};position:relative"></div> <center><img ng-show='panel.loading && _.isUndefined(data)' src="common/img/load_big.gif"></center>
<div histogram-chart params="{{panel}}" style="height:{{panel.height || row.height}};position:relative"></div>
</kibana-panel> </kibana-panel>
\ No newline at end of file
...@@ -3,19 +3,28 @@ angular.module('kibana.histogram', []) ...@@ -3,19 +3,28 @@ angular.module('kibana.histogram', [])
// Set and populate defaults // Set and populate defaults
var _d = { var _d = {
group : "default",
query : [ {query: "*", label:"Query"} ], query : [ {query: "*", label:"Query"} ],
interval : secondsToHms(calculate_interval($scope.from,$scope.to,40,0)/1000), interval : secondsToHms(calculate_interval($scope.from,$scope.to,40,0)/1000),
show : ['bars','y-axis','x-axis','legend'],
fill : 3, fill : 3,
linewidth : 3,
timezone : 'browser', // browser, utc or a standard timezone timezone : 'browser', // browser, utc or a standard timezone
spyable : true, spyable : true,
zoomlinks : true, zoomlinks : true,
group : "default", bars : true,
stack : true,
points : false,
lines : false,
legend : true,
'x-axis' : true,
'y-axis' : true,
} }
_.defaults($scope.panel,_d) _.defaults($scope.panel,_d)
$scope.init = function() { $scope.init = function() {
eventBus.register($scope,'time', function(event,time){$scope.set_time(time)}); eventBus.register($scope,'time', function(event,time){$scope.set_time(time)});
// Consider eliminating the check for array, this should always be an array
eventBus.register($scope,'query', function(event, query) { eventBus.register($scope,'query', function(event, query) {
if(_.isArray(query)) { if(_.isArray(query)) {
$scope.panel.query = _.map(query,function(q) { $scope.panel.query = _.map(query,function(q) {
...@@ -26,6 +35,7 @@ angular.module('kibana.histogram', []) ...@@ -26,6 +35,7 @@ angular.module('kibana.histogram', [])
} }
$scope.get_data(); $scope.get_data();
}); });
// Now that we're all setup, request the time from our group if we don't // Now that we're all setup, request the time from our group if we don't
// have it yet // have it yet
if(_.isUndefined($scope.time)) if(_.isUndefined($scope.time))
...@@ -48,13 +58,13 @@ angular.module('kibana.histogram', []) ...@@ -48,13 +58,13 @@ angular.module('kibana.histogram', [])
} }
$scope.get_data = function(segment,query_id) { $scope.get_data = function(segment,query_id) {
delete $scope.panel.error
// Make sure we have everything for the request to complete // Make sure we have everything for the request to complete
if(_.isUndefined($scope.panel.index) || _.isUndefined($scope.time)) if(_.isUndefined($scope.panel.index) || _.isUndefined($scope.time))
return return
var _segment = _.isUndefined(segment) ? 0 : segment
$scope.panel.loading = true; $scope.panel.loading = true;
var _segment = _.isUndefined(segment) ? 0 : segment
var request = $scope.ejs.Request().indices($scope.panel.index[_segment]); var request = $scope.ejs.Request().indices($scope.panel.index[_segment]);
// Build the question part of the query // Build the question part of the query
...@@ -68,7 +78,7 @@ angular.module('kibana.histogram', []) ...@@ -68,7 +78,7 @@ angular.module('kibana.histogram', [])
) )
}); });
// Build the facet part // Build the facet part, injecting the query in as a facet filter
_.each(queries, function(v) { _.each(queries, function(v) {
request = request request = request
.facet($scope.ejs.DateHistogramFacet("chart"+_.indexOf(queries,v)) .facet($scope.ejs.DateHistogramFacet("chart"+_.indexOf(queries,v))
...@@ -78,6 +88,7 @@ angular.module('kibana.histogram', []) ...@@ -78,6 +88,7 @@ angular.module('kibana.histogram', [])
).size(0) ).size(0)
}) })
// Populate the inspector panel
$scope.populate_modal(request); $scope.populate_modal(request);
// Then run it // Then run it
...@@ -92,16 +103,17 @@ angular.module('kibana.histogram', []) ...@@ -92,16 +103,17 @@ angular.module('kibana.histogram', [])
query_id = $scope.query_id = new Date().getTime(); query_id = $scope.query_id = new Date().getTime();
} }
// Check for error and abort if found
if(!(_.isUndefined(results.error))) {
$scope.panel.error = $scope.parse_error(results.error);
return;
}
// Make sure we're still on the same query
if($scope.query_id === query_id) { if($scope.query_id === query_id) {
var i = 0; var i = 0;
_.each(results.facets, function(v, k) { _.each(results.facets, function(v, k) {
// If this isn't a date histogram it must be a QueryFacet, get the
// count and return
if(v._type !== 'date_histogram') {
//$scope.hits += v.count;
return
}
// Null values at each end of the time range ensure we see entire range // Null values at each end of the time range ensure we see entire range
if(_.isUndefined($scope.data[i]) || _segment == 0) { if(_.isUndefined($scope.data[i]) || _segment == 0) {
...@@ -116,14 +128,14 @@ angular.module('kibana.histogram', []) ...@@ -116,14 +128,14 @@ angular.module('kibana.histogram', [])
var segment_data = []; var segment_data = [];
_.each(v.entries, function(v, k) { _.each(v.entries, function(v, k) {
segment_data.push([v['time'],v['count']]) segment_data.push([v['time'],v['count']])
hits += v['count']; hits += v['count']; // The series level hits counter
$scope.hits += v['count']; $scope.hits += v['count']; // Entire dataset level hits counter
}); });
data.splice.apply(data,[1,0].concat(segment_data)) data.splice.apply(data,[1,0].concat(segment_data)) // Join histogram data
// Create the flot series // Create the flot series object
var series = { var series = {
data: { data: {
label: $scope.panel.query[i].label || "query"+(parseInt(i)+1), label: $scope.panel.query[i].label || "query"+(parseInt(i)+1),
...@@ -140,8 +152,10 @@ angular.module('kibana.histogram', []) ...@@ -140,8 +152,10 @@ angular.module('kibana.histogram', [])
i++; i++;
}); });
eventBus.broadcast($scope.$id,$scope.panel.group,'hits',$scope.hits) // Tell the histogram directive to render.
$scope.$emit('render') $scope.$emit('render')
// If we still have segments left, get them
if(_segment < $scope.panel.index.length-1) { if(_segment < $scope.panel.index.length-1) {
$scope.get_data(_segment+1,query_id) $scope.get_data(_segment+1,query_id)
} }
...@@ -176,15 +190,13 @@ angular.module('kibana.histogram', []) ...@@ -176,15 +190,13 @@ angular.module('kibana.histogram', [])
} }
}) })
.directive('histogram', function(eventBus) { .directive('histogramChart', function(eventBus) {
return { return {
restrict: 'A', restrict: 'A',
link: function(scope, elem, attrs, ctrl) { link: function(scope, elem, attrs, ctrl) {
var height = scope.panel.height || scope.row.height; var height = scope.panel.height || scope.row.height;
elem.html('<center><img src="common/img/load_big.gif"></center>')
// Receive render events // Receive render events
scope.$on('render',function(){ scope.$on('render',function(){
render_panel(); render_panel();
...@@ -197,19 +209,6 @@ angular.module('kibana.histogram', []) ...@@ -197,19 +209,6 @@ angular.module('kibana.histogram', [])
// Function for rendering panel // Function for rendering panel
function render_panel() { function render_panel() {
// Determine format
var show = _.isUndefined(scope.panel.show) ? {
bars: true, lines: false, points: false
} : {
lines: _.indexOf(scope.panel.show,'lines') < 0 ? false : true,
bars: _.indexOf(scope.panel.show,'bars') < 0 ? false : true,
points: _.indexOf(scope.panel.show,'points') < 0 ? false : true,
stack: _.indexOf(scope.panel.show,'stack') < 0 ? null : true,
legend: _.indexOf(scope.panel.show,'legend') < 0 ? false : true,
'x-axis': _.indexOf(scope.panel.show,'x-axis') < 0 ? false : true,
'y-axis': _.indexOf(scope.panel.show,'y-axis') < 0 ? false : true,
}
// Set barwidth based on specified interval // Set barwidth based on specified interval
var barwidth = interval_to_seconds(scope.panel.interval)*1000 var barwidth = interval_to_seconds(scope.panel.interval)*1000
...@@ -221,31 +220,36 @@ angular.module('kibana.histogram', []) ...@@ -221,31 +220,36 @@ angular.module('kibana.histogram', [])
// Populate element. Note that jvectormap appends, does not replace. // Populate element. Note that jvectormap appends, does not replace.
scripts.wait(function(){ scripts.wait(function(){
var stack = scope.panel.stack ? true : null;
// Populate element // Populate element
try { try {
var plot = $.plot(elem, scope.data, { scope.plot = $.plot(elem, scope.data, {
legend: { legend: { show: false },
show: false,
},
series: { series: {
stack: show.stack, stack: stack,
lines: { show: show.lines, fill: scope.panel.fill/10 }, lines: {
bars: { show: show.bars, fill: 1, barWidth: barwidth/1.8 }, show: scope.panel.lines,
points: { show: show.points, fill: 1, fillColor: false}, fill: scope.panel.fill/10,
lineWidth: scope.panel.linewidth,
steps: false
},
bars: { show: scope.panel.bars, fill: 1, barWidth: barwidth/1.8 },
points: { show: scope.panel.points, fill: 1, fillColor: false, radius: 5},
shadowSize: 1 shadowSize: 1
}, },
yaxis: { show: show['y-axis'], min: 0, color: "#000" }, yaxis: { show: scope.panel['y-axis'], min: 0, color: "#000" },
xaxis: { xaxis: {
timezone: scope.panel.timezone, timezone: scope.panel.timezone,
show: show['x-axis'], show: scope.panel['x-axis'],
mode: "time", mode: "time",
timeformat: time_format(scope.panel.interval), timeformat: time_format(scope.panel.interval),
label: "Datetime", label: "Datetime",
color: "#000", color: "#000",
}, },
selection: { selection: {
mode: "x" mode: "x",
color: '#666'
}, },
grid: { grid: {
backgroundColor: '#fff', backgroundColor: '#fff',
...@@ -254,12 +258,13 @@ angular.module('kibana.histogram', []) ...@@ -254,12 +258,13 @@ angular.module('kibana.histogram', [])
color: "#eee", color: "#eee",
hoverable: true, hoverable: true,
}, },
colors: ['#EB6841','#00A0B0','#6A4A3C','#EDC951','#CC333F'] colors: ['#86B22D',
}) '#BF6730',
'#1D7373',
scope.legend = []; '#BFB930',
_.each(plot.getData(),function(series) { '#BF3030',
scope.legend.push(_.pick(series,'label','color','hits')) '#77207D'
]
}) })
// Work around for missing legend at initialization // Work around for missing legend at initialization
...@@ -288,23 +293,25 @@ angular.module('kibana.histogram', []) ...@@ -288,23 +293,25 @@ angular.module('kibana.histogram', [])
var tooltip = $('#pie-tooltip').length ? var tooltip = $('#pie-tooltip').length ?
$('#pie-tooltip') : $('<div id="pie-tooltip"></div>'); $('#pie-tooltip') : $('<div id="pie-tooltip"></div>');
//var tooltip = $('#pie-tooltip') //var tooltip = $('#pie-tooltip')
tooltip.text(contents).css({ tooltip.html(contents).css({
position: 'absolute', position: 'absolute',
top : y + 5, top : y + 5,
left : x + 5, left : x + 5,
color : "#FFF", color : "#000",
border : '1px solid #FFF', border : '2px solid #000',
padding : '2px', padding : '10px',
'font-size': '8pt', 'font-size': '11pt',
'background-color': '#000', 'font-weight' : 200,
'background-color': '#FFF',
'border-radius': '10px',
}).appendTo("body"); }).appendTo("body");
} }
elem.bind("plothover", function (event, pos, item) { elem.bind("plothover", function (event, pos, item) {
if (item) { if (item) {
var percent = parseFloat(item.series.percent).toFixed(1) + "%";
tt(pos.pageX, pos.pageY, tt(pos.pageX, pos.pageY,
item.datapoint[1].toFixed(1) + " @ " + "<div style='vertical-align:middle;display:inline-block;background:"+item.series.color+";height:15px;width:15px;border-radius:10px;'></div> "+
item.datapoint[1].toFixed(0) + " @ " +
new Date(item.datapoint[0]).format('mm/dd HH:MM:ss')); new Date(item.datapoint[0]).format('mm/dd HH:MM:ss'));
} else { } else {
$("#pie-tooltip").remove(); $("#pie-tooltip").remove();
......
<div class="row-fluid" ng-controller="hits"> <div ng-controller="hits">
<div class="row-fluid">
<div class="span2 "><label class="small">Font Size</label>
<select class="input-mini" ng-model="panel.style['font-size']" ng-options="f for f in ['7pt','8pt','9pt','10pt','12pt','14pt','16pt','18pt','20pt','24pt','28pt','32pt','36pt','42pt','48pt','52pt','60pt','72pt']"></select></span>
</div>
<div class="span2"> <div class="span2">
<label class="small">Run Query</label><input type="checkbox" ng-model="panel.run_query" ng-checked="panel.run_query"> <label class="small">Aggregate</label><input type="checkbox" ng-model="panel.aggregate" ng-checked="panel.aggregate">
</div> </div>
<div class="span9" ng-show='!panel.run_query'> <div class="span3" ng-show="!panel.aggregate"><label class="small">Counter Style</label>
With query running disabled, this panel receives its hit count from a histogram panel. If multiple queries are running this <strong>will show the total of all queries</strong>. <select class="input-small" ng-model="panel.arrangement" ng-options="f for f in ['none','horizontal','vertical']"></select></span>
</div> </div>
<div class="span9" ng-show='panel.run_query'> <div class="span2" ng-show="!panel.aggregate">
This shows a simple count of how many records match your filtered query. If multiple queries are sent from a single panel the <strong>first query will be displayed</strong> <label class="small">Chart</label><input type="checkbox" ng-model="panel.chart" ng-checked="panel.chart">
</div> </div>
</div> </div>
<div class="row-fluid"> <div class="row-fluid">
<div class="span9" ng-show='panel.run_query'> <div class="span3">
<form class="input-append"> <form style="margin-bottom: 0px">
<h6>Query</h6> <label class="small">Label</label>
<input type="text" style="width:85%" ng-model="panel.query"> <input type="text" placeholder="New Label" style="width:70%" ng-model="newlabel">
<button class="btn" ng-click="get_data();"><i class="icon-search"></i></button> </form>
</div>
<div class="span8">
<form class="input-append" style="margin-bottom: 0px">
<label class="small">Query</label>
<input type="text" placeholder="New Query" style="width:80%" ng-model="newquery">
<button class="btn" ng-click="add_query(newlabel,newquery);newlabel='';newquery=''"><i class="icon-plus"></i></button>
</form> </form>
</div> </div>
<div class="span3"><h6>Font Size</h6> <div class="span1">
<select class="input-small" ng-model="panel.style['font-size']" ng-options="f for f in ['6pt','7pt','8pt','10pt','12pt','14pt','16pt','18pt','20pt','24pt','28pt','32pt','36pt','42pt','48pt','52pt','60pt','72pt']"></select></span> </div>
</div>
<div class="row-fluid" ng-repeat="q in panel.query">
<div class="span3">
<form style="margin-bottom: 0px">
<input type="text" style="width:70%" ng-model="q.label">
</form>
</div>
<div class="span8">
<form class="input-append" style="margin-bottom: 0px">
<input type="text" style="width:80%" ng-model="q.query">
<button class="btn" ng-click="get_data()"><i class="icon-search"></i></button>
</form>
</div>
<div class="span1">
<i class="icon-remove pointer" ng-click="remove_query(q)"></i>
</div>
</div> </div>
</div>
<kibana-panel ng-controller='hits' ng-init="init()"> <kibana-panel ng-controller='hits' ng-init="init()">
<p ng-style="panel.style">&#8805 {{hits}}</p> <div ng-show="panel.counters">
<p ng-style="panel.style" ng-show="panel.aggregate">{{hits}}</p>
<table ng-style="panel.style" ng-show="!panel.aggregate && panel.arrangement == 'vertical'">
<tr style="line-height:{{panel.style['font-size']}}" ng-repeat="query in plot.getData()">
<td ng-show="panel.chart" style="background:{{query.color}};width:{{panel.style['font-size']}}"></td> <td style="padding-right:10px;padding-left:10px;">{{query.label}}</td><td>{{query.hits}}</td>
</tr>
</table>
<div ng-style="panel.style" ng-show="!panel.aggregate && panel.arrangement == 'horizontal'" ng-repeat="query in plot.getData()" style="float:left;padding-left: 10px;">
<span ng-show='panel.chart'><div style="display:inline-block;border-radius:{{panel.style['font-size']}};background:{{query.color}};height:{{panel.style['font-size']}};width:{{panel.style['font-size']}}"></div></span> {{query.label}} ({{query.hits}}) <span ng-show="!$last">|</span>
</div><br>
</div><div style="clear:both"></div>
<div ng-show='panel.chart && !panel.aggregate ' hits-chart params="{{panel}}" style="height:{{panel.height || row.height}};position:relative"></div>
</kibana-panel> </kibana-panel>
\ No newline at end of file
...@@ -5,58 +5,117 @@ angular.module('kibana.hits', []) ...@@ -5,58 +5,117 @@ angular.module('kibana.hits', [])
var _d = { var _d = {
query : "*", query : "*",
group : "default", group : "default",
style : { "font-size": '36pt', "font-weight": "bold" }, style : { "font-size": '10pt'},
run_query : false aggregate : true,
arrangement : 'vertical',
chart : true,
counters: true,
count_pos: 'above'
} }
_.defaults($scope.panel,_d) _.defaults($scope.panel,_d)
$scope.init = function () { $scope.init = function () {
$scope.hits = 0; $scope.hits = 0;
eventBus.register($scope,'time', function(event,time){ eventBus.register($scope,'time', function(event,time){
if($scope.panel.run_query)
set_time(time) set_time(time)
}); });
eventBus.register($scope,'query', function(event, query) { eventBus.register($scope,'query', function(event, query) {
$scope.panel.query = _.isArray(query) ? query[0] : query; $scope.panel.query = _.map(query,function(q) {
if($scope.panel.run_query) return {query: q, label: q};
})
$scope.get_data(); $scope.get_data();
}); });
eventBus.register($scope,'hits', function(event, hits) {
$scope.hits = hits;
})
// Now that we're all setup, request the time from our group // Now that we're all setup, request the time from our group
eventBus.broadcast($scope.$id,$scope.panel.group,'get_time') eventBus.broadcast($scope.$id,$scope.panel.group,'get_time')
} }
$scope.get_data = function() { $scope.get_data = function(segment,query_id) {
delete $scope.panel.error
$scope.panel.loading = true;
// Make sure we have everything for the request to complete // Make sure we have everything for the request to complete
if(_.isUndefined($scope.panel.index) || _.isUndefined($scope.time)) if(_.isUndefined($scope.panel.index) || _.isUndefined($scope.time))
return return
$scope.panel.loading = true; var _segment = _.isUndefined(segment) ? 0 : segment
var request = $scope.ejs.Request().indices($scope.panel.index); var request = $scope.ejs.Request().indices($scope.panel.index[_segment]);
var results = request // Build the question part of the query
.query(ejs.FilteredQuery( var queries = [];
ejs.QueryStringQuery($scope.panel.query || '*'), _.each($scope.panel.query, function(v) {
queries.push($scope.ejs.FilteredQuery(
ejs.QueryStringQuery(v.query || '*'),
ejs.RangeFilter($scope.time.field) ejs.RangeFilter($scope.time.field)
.from($scope.time.from) .from($scope.time.from)
.to($scope.time.to) .to($scope.time.to))
)
) )
.size(0) });
.doSearch();
// Build the facet part
_.each(queries, function(v) {
request = request
.facet($scope.ejs.QueryFacet("query"+_.indexOf(queries,v))
.query(v)
).size(0)
})
// TODO: Spy for hits panel
//$scope.populate_modal(request);
// Then run it
var results = request.doSearch();
// Populate scope when we have results // Populate scope when we have results
results.then(function(results) { results.then(function(results) {
$scope.panel.loading = false; $scope.panel.loading = false;
if(_.isUndefined(results)) { if(_segment == 0) {
$scope.panel.error = 'Your query was unsuccessful'; $scope.hits = 0;
$scope.data = [];
query_id = $scope.query_id = new Date().getTime();
}
// Check for error and abort if found
if(!(_.isUndefined(results.error))) {
$scope.panel.error = $scope.parse_error(results.error);
return; return;
} }
$scope.panel.error = false; if($scope.query_id === query_id) {
$scope.hits = results.hits.total; var i = 0;
_.each(results.facets, function(v, k) {
var hits = _.isUndefined($scope.data[i]) || _segment == 0 ?
v.count : $scope.data[i].hits+v.count
$scope.hits += v.count
// Create series
$scope.data[i] = {
label: $scope.panel.query[i].label || "query"+(parseInt(i)+1),
hits: hits,
data: [[i,hits]]
};
i++;
});
$scope.$emit('render');
if(_segment < $scope.panel.index.length-1)
$scope.get_data(_segment+1,query_id)
}
});
}
$scope.remove_query = function(q) {
$scope.panel.query = _.without($scope.panel.query,q);
$scope.get_data();
}
$scope.add_query = function(label,query) {
$scope.panel.query.unshift({
query: query,
label: label,
}); });
$scope.get_data();
} }
function set_time(time) { function set_time(time) {
...@@ -65,4 +124,88 @@ angular.module('kibana.hits', []) ...@@ -65,4 +124,88 @@ angular.module('kibana.hits', [])
$scope.get_data(); $scope.get_data();
} }
}).directive('hitsChart', function(eventBus) {
return {
restrict: 'A',
link: function(scope, elem, attrs, ctrl) {
// Receive render events
scope.$on('render',function(){
render_panel();
});
// Re-render if the window is resized
angular.element(window).bind('resize', function(){
render_panel();
});
// Function for rendering panel
function render_panel() {
var scripts = $LAB.script("common/lib/panels/jquery.flot.js")
// Populate element. Note that jvectormap appends, does not replace.
scripts.wait(function(){
// Populate element
try {
// Add plot to scope so we can build out own legend
scope.plot = $.plot(elem, scope.data, {
legend: { show: false },
series: {
lines: { show: false, },
bars: { show: true, fill: 1, barWidth: 0.8, horizontal: false },
shadowSize: 1
},
yaxis: { show: true, min: 0, color: "#000" },
xaxis: { show: false },
grid: {
backgroundColor: '#fff',
borderWidth: 0,
borderColor: '#eee',
color: "#eee",
hoverable: true,
},
colors: ['#86B22D','#BF6730','#1D7373','#BFB930','#BF3030','#77207D']
})
// Work around for missing legend at initialization
if(!scope.$$phase)
scope.$apply()
} catch(e) {
elem.text(e)
}
})
}
function tt(x, y, contents) {
var tooltip = $('#pie-tooltip').length ?
$('#pie-tooltip') : $('<div id="pie-tooltip"></div>');
//var tooltip = $('#pie-tooltip')
tooltip.html(contents).css({
position: 'absolute',
top : y + 5,
left : x + 5,
color : "#000",
border : '2px solid #000',
padding : '10px',
'font-size': '11pt',
'font-weight' : 200,
'background-color': '#FFF',
'border-radius': '10px',
}).appendTo("body");
}
elem.bind("plothover", function (event, pos, item) {
if (item) {
tt(pos.pageX, pos.pageY,
"<div style='vertical-align:middle;border-radius:10px;display:inline-block;background:"+item.series.color+";height:20px;width:20px'></div> "+
item.datapoint[1].toFixed(0))
} else {
$("#pie-tooltip").remove();
}
});
}
};
}) })
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
<div class="span3"> <div class="span3">
<form> <form>
<h6>Field</h6> <h6>Field</h6>
<input type="text" class="input-small" ng-model="panel.field"> <input bs-typeahead="fields.list" type="text" class="input-small" ng-model="panel.field">
</form> </form>
</div> </div>
<div class="span6"> <div class="span6">
......
...@@ -128,12 +128,12 @@ angular.module('kibana.map', []) ...@@ -128,12 +128,12 @@ angular.module('kibana.map', [])
$('.jvectormap-label').css({ $('.jvectormap-label').css({
"position" : "absolute", "position" : "absolute",
"display" : "none", "display" : "none",
"border" : "solid 1px #CDCDCD", "border" : "solid 2px #000",
"background" : "#292929", "background" : "#FFF",
"color" : "white", "font-weight" : 200,
"font-family" : "sans-serif, Verdana", "border-radius": "5px",
"font-size" : "smaller", "color" : "#000",
"padding" : "3px" "padding" : "5px"
}) })
var count = _.isUndefined(scope.data[code]) ? 0 : scope.data[code]; var count = _.isUndefined(scope.data[code]) ? 0 : scope.data[code];
$('.jvectormap-label').text(label.text() + ": " + count); $('.jvectormap-label').text(label.text() + ": " + count);
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<div class="span4"> <div class="span4">
<form style="margin-bottom: 0px"> <form style="margin-bottom: 0px">
<h6> Field</h6> <h6> Field</h6>
<input type="text" style="width:90%" ng-model="panel.query.field"> <input type="text" style="width:90%" bs-typeahead="fields.list" ng-model="panel.query.field">
</form> </form>
</div> </div>
<div class="span8"> <div class="span8">
......
...@@ -2,6 +2,11 @@ ...@@ -2,6 +2,11 @@
<span ng-show='panel.spyable' style="position:absolute;right:0px;top:0px" class='panelextra pointer'> <span ng-show='panel.spyable' style="position:absolute;right:0px;top:0px" class='panelextra pointer'>
<i bs-modal="'partials/modal.html'" class="icon-eye-open"></i> <i bs-modal="'partials/modal.html'" class="icon-eye-open"></i>
</span> </span>
<span ng-show="panel.legend" ng-repeat='series in legend' style='padding-right:5px'>
<div style='white-space:nowrap;display:table-cell'>
<div style="display:inline-block;background:{{series.color}};height:10px;width:10px;border-radius:5px;"></div>
<div class='small' style='display:inline-block'>{{series.label}} ({{series.percent}}%)</div>
</div>
</span>
<div pie params="{{panel}}" style="height:{{panel.height || row.height}};position:relative"></div> <div pie params="{{panel}}" style="height:{{panel.height || row.height}};position:relative"></div>
</kibana-panel> </kibana-panel>
\ No newline at end of file
...@@ -268,14 +268,21 @@ angular.module('kibana.pie', []) ...@@ -268,14 +268,21 @@ angular.module('kibana.pie', [])
}, },
//grid: { hoverable: true, clickable: true }, //grid: { hoverable: true, clickable: true },
grid: { hoverable: true, clickable: true }, grid: { hoverable: true, clickable: true },
legend: { show: scope.panel.legend }, legend: { show: false },
colors: ['#EB6841','#00A0B0','#6A4A3C','#EDC951','#CC333F'] colors: ['#86B22D','#BF6730','#1D7373','#BFB930','#BF3030','#77207D']
}; };
// Populate element // Populate element
if(elem.is(":visible")){ if(elem.is(":visible")){
scripts.wait(function(){ scripts.wait(function(){
$.plot(elem, scope.data, pie); var plot = $.plot(elem, scope.data, pie);
scope.legend = [];
_.each(plot.getData(),function(series) {
var item = _.pick(series,'label','color','percent')
item.percent = parseFloat(item.percent).toFixed(1)
scope.legend.push(item)
})
console.log(scope.legend)
}); });
} }
} }
...@@ -283,15 +290,16 @@ angular.module('kibana.pie', []) ...@@ -283,15 +290,16 @@ angular.module('kibana.pie', [])
function piett(x, y, contents) { function piett(x, y, contents) {
var tooltip = $('#pie-tooltip').length ? var tooltip = $('#pie-tooltip').length ?
$('#pie-tooltip') : $('<div id="pie-tooltip"></div>'); $('#pie-tooltip') : $('<div id="pie-tooltip"></div>');
tooltip.text(contents).css({ tooltip.html(contents).css({
position: 'absolute', position: 'absolute',
top : y + 10, top : y + 10,
left : x + 10, left : x + 10,
color : "#FFF", color : "#000",
border : '1px solid #FFF', 'font-weight': 200,
padding : '2px', 'border-radius': '5px',
'font-size': '8pt', border : '2px solid #000',
'background-color': '#000', padding : '10px',
'background-color': '#FFF',
}).appendTo("body"); }).appendTo("body");
} }
...@@ -305,7 +313,8 @@ angular.module('kibana.pie', []) ...@@ -305,7 +313,8 @@ angular.module('kibana.pie', [])
elem.bind("plothover", function (event, pos, item) { elem.bind("plothover", function (event, pos, item) {
if (item) { if (item) {
var percent = parseFloat(item.series.percent).toFixed(1) + "%"; var percent = parseFloat(item.series.percent).toFixed(1) + "%";
piett(pos.pageX, pos.pageY, percent + " " + (item.series.label||"")); piett(pos.pageX, pos.pageY, "<div style='vertical-align:middle;display:inline-block;background:"+item.series.color+";height:15px;width:15px;border-radius:10px;'></div> " +
(item.series.label||"")+ " " + percent);
} else { } else {
$("#pie-tooltip").remove(); $("#pie-tooltip").remove();
} }
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
</form> </form>
</div> </div>
<div class='row-fluid' ng-show="panel.multi && panel.multi_arrange == 'horizontal'"> <div class='row-fluid' ng-show="panel.multi && panel.multi_arrange == 'horizontal'">
<form class="form-inline" style="width:100%;" > <form class="form-inline" style="width:100%;margin:0px" >
<span ng-repeat="q in panel.query"> <span ng-repeat="q in panel.query">
<span class="input-append" style="margin-bottom:0px;margin-right:5px"> <span class="input-append" style="margin-bottom:0px;margin-right:5px">
<button class="btn btn-danger" type="submit" style="width:50px;margin-left:-50px;visibility:hidden"></button> <button class="btn btn-danger" type="submit" style="width:50px;margin-left:-50px;visibility:hidden"></button>
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
</span> </span>
</form> </form>
<button type="submit" class="btn btn-info" ng-click="send_query(panel.query)"><i class="icon-search"></i> Search</button> <button type="submit" class="btn btn-info" ng-click="send_query(panel.query)"><i class="icon-search"></i> Search</button>
<button type="submit" class="btn" ng-click="send_query(panel.query);add_query();"><i class="icon-plus"></i> Add Query</button> <button type="submit" class="btn" ng-click="add_query();"><i class="icon-plus"></i> Add Query</button>
</div> </div>
<div ng-show="panel.multi && panel.multi_arrange == 'vertical'"> <div ng-show="panel.multi && panel.multi_arrange == 'vertical'">
<form> <form>
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
<div class="span4"> <div class="span4">
<form class="input-append"> <form class="input-append">
<h6>Add field</h6> <h6>Add field</h6>
<input bs-typeahead="all_fields" type="text" class="input-small" ng-model='newfield'> <input bs-typeahead="fields.list" type="text" class="input-small" ng-model='newfield'>
<button class="btn" ng-click="toggle_field(newfield);newfield=''"><i class="icon-plus"></i></button> <button class="btn" ng-click="toggle_field(newfield);newfield=''"><i class="icon-plus"></i></button>
</form> </form>
</div> </div>
......
angular.module('kibana.table', []) angular.module('kibana.table', [])
.controller('table', function($scope, eventBus) { .controller('table', function($scope, eventBus, fields) {
// Set and populate defaults // Set and populate defaults
var _d = { var _d = {
...@@ -76,6 +76,8 @@ angular.module('kibana.table', []) ...@@ -76,6 +76,8 @@ angular.module('kibana.table', [])
} }
$scope.get_data = function(segment,query_id) { $scope.get_data = function(segment,query_id) {
$scope.panel.error = false;
// Make sure we have everything for the request to complete // Make sure we have everything for the request to complete
if(_.isUndefined($scope.panel.index) || _.isUndefined($scope.time)) if(_.isUndefined($scope.panel.index) || _.isUndefined($scope.time))
return return
...@@ -98,7 +100,7 @@ angular.module('kibana.table', []) ...@@ -98,7 +100,7 @@ angular.module('kibana.table', [])
$scope.populate_modal(request) $scope.populate_modal(request)
var results = request.doSearch(); var results = request.doSearch()
// Populate scope when we have results // Populate scope when we have results
results.then(function(results) { results.then(function(results) {
...@@ -110,11 +112,11 @@ angular.module('kibana.table', []) ...@@ -110,11 +112,11 @@ angular.module('kibana.table', [])
query_id = $scope.query_id = new Date().getTime() query_id = $scope.query_id = new Date().getTime()
} }
if(_.isUndefined(results)) { // Check for error and abort if found
$scope.panel.error = 'Your query was unsuccessful'; if(!(_.isUndefined(results.error))) {
$scope.panel.error = $scope.parse_error(results.error);
return; return;
} }
$scope.panel.error = false;
// Check that we're still on the same query, if not stop // Check that we're still on the same query, if not stop
if($scope.query_id === query_id) { if($scope.query_id === query_id) {
...@@ -142,7 +144,6 @@ angular.module('kibana.table', []) ...@@ -142,7 +144,6 @@ angular.module('kibana.table', [])
// This breaks, use $scope.data for this // This breaks, use $scope.data for this
$scope.all_fields = get_all_fields($scope.data); $scope.all_fields = get_all_fields($scope.data);
broadcast_results(); broadcast_results();
// If we're not sorting in reverse chrono order, query every index for // If we're not sorting in reverse chrono order, query every index for
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
</div> </div>
</div> </div>
<div ng-switch-when="since"> <div ng-switch-when="since">
<div class="span10"> <div class="span5">
<form class="nomargin"> <form class="nomargin">
<label><small>Since</small></label> <label><small>Since</small></label>
<input type="text" class="input-smaller" ng-change="time_check()" ng-model="timepicker.from.date" data-date-format="mm/dd/yyyy" bs-datepicker> <input type="text" class="input-smaller" ng-change="time_check()" ng-model="timepicker.from.date" data-date-format="mm/dd/yyyy" bs-datepicker>
......
...@@ -111,10 +111,6 @@ angular.module('kibana.timepicker', []) ...@@ -111,10 +111,6 @@ angular.module('kibana.timepicker', [])
} }
$scope.time_apply(); $scope.time_apply();
}); });
$scope.$on('render', function (){
$scope.time_apply();
});
} }
$scope.set_interval = function (refresh_interval) { $scope.set_interval = function (refresh_interval) {
...@@ -167,6 +163,10 @@ angular.module('kibana.timepicker', []) ...@@ -167,6 +163,10 @@ angular.module('kibana.timepicker', [])
$scope.time_apply(); $scope.time_apply();
} }
$scope.close_edit = function() {
$scope.time_apply();
}
$scope.time_check = function(){ $scope.time_check = function(){
// If time picker is defined (on initialization) // If time picker is defined (on initialization)
......
<div class="row-fluid container"> <div class="row-fluid container" style="margin-top:10px">
<!-- Rows --> <!-- Rows -->
<div ng-controller="dashcontrol" ng-init="init()"></div> <div ng-controller="dashcontrol" ng-init="init()"></div>
<div class="row-fluid" ng-controller="RowCtrl" ng-repeat="(row_name, row) in dashboards.rows"> <div class="row-fluid kibana-row" ng-controller="RowCtrl" ng-repeat="(row_name, row) in dashboards.rows" ng-style="row_style(row)">
<div class="span12"> <div class="row-control">
<div class="row-fluid row-header" style="padding:0px;margin:0px;height:0px"> <div class="row-fluid row-header" style="padding:0px;margin:0px;height:0px">
<div class="span12" style="min-height:5px;vertical-align:bottom"> <div style="vertical-align:bottom">
<div ng-show="row.collapsable">
<div ng-class="{'row-open': !row.collapse, 'row-close': row.collapse}" style="position:absolute;margin-left:-60px;">
<span class='pointer' ng-click="toggle_row(row)">{{row.title}}</span>
<i ng-show="row.editable" class="icon-edit pointer editlink" bs-modal="'partials/roweditor.html'"></i> <i ng-show="row.editable" class="icon-edit pointer editlink" bs-modal="'partials/roweditor.html'"></i>
<span ng-show="row.collapsable" ng-click="toggle_row(row)" class="pointer"><i class="pointer" ng-class="{'icon-caret-down': !row.collapse,'icon-caret-right': row.collapse}"></i> <small>{{row.title}}</small></span>
<small ng-hide="row.collapsable">{{row.title}}</small>
</div> </div>
</div> </div>
<div class="row-fluid" style="padding-top:10px" ng-hide="row.collapse"> <small ng-hide="row.collapsable" class="rotated">{{row.title}}</small>
</div>
</div>
<div class="row-fluid" style="padding-top:0px" ng-hide="row.collapse">
<!-- Panels --> <!-- Panels -->
<div ng-repeat="(name, panel) in row.panels" ng-hide="panel.span == 0 || panel.hide" class="span{{panel.span}} panel" style="min-height:{{row.height}}; position:relative"> <div ng-repeat="(name, panel) in row.panels" ng-hide="panel.span == 0 || panel.hide" class="span{{panel.span}} panel" style="min-height:{{row.height}}; position:relative">
<!-- Error Panel --> <!-- Error Panel -->
......
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3>{{panel.title}} <small>editor</small></h3> <h3>{{panel.title}} Editor</h3>
</div> </div>
<div class="modal-body"> <div class="modal-body">
...@@ -13,5 +13,5 @@ ...@@ -13,5 +13,5 @@
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-success" ng-click="dismiss();send_render()">Close</button> <button type="button" class="btn btn-success" ng-click="dismiss();close_edit()">Close</button>
</div> </div>
\ No newline at end of file
...@@ -56,5 +56,5 @@ ...@@ -56,5 +56,5 @@
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-success" ng-click="dismiss();reset_panel();send_render()">Close</button> <button type="button" class="btn btn-success" ng-click="dismiss();reset_panel();close_edit()">Close</button>
</div> </div>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment