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-
.nav>.disabled>a{color:#4d4d4d;}
.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-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 .container{width:auto;}
.nav-collapse.collapse{height:auto;overflow:visible;}
......
......@@ -6,6 +6,50 @@
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 {
background-color: #f9f9f9;
}
......@@ -95,4 +139,9 @@
background-color: #A60000;
}
.typeahead { z-index: 1051; }
\ No newline at end of file
.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
* Copyright (c) 2013 FullScale Labs, LLC; Licensed MIT */
/*jshint browser:true */
/*global angular:true */
/*jshint es5:true */
'use strict';
/*
......@@ -26,8 +27,8 @@ angular.module('elasticjs.service', [])
(successcb || angular.noop)(response.data);
return response.data;
}, function (response) {
(errorcb || angular.noop)(undefined);
return undefined;
(errorcb || angular.noop)(response.data);
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
* 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 @@
<div class="navbar navbar-static-top">
<div class="navbar-inner">
<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>
<div class="brand"><i class='icon-edit pointer' ng-show='dashboards.editable' bs-modal="'partials/dasheditor.html'"></i></div>
</div>
</div>
</div>
<div class="container-fluid">
<div class="container-fluid main">
<div class="row-fluid">
<div ng-view></div>
</div>
......
......@@ -27,7 +27,7 @@ var labjs = $LAB
.script("common/lib/angular-strap.min.js")
.script("common/lib/angular-sanitize.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/date.js")
.script("common/lib/datepicker.js")
......
......@@ -3,7 +3,7 @@
'use strict';
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 = {
title: "",
......@@ -14,7 +14,11 @@ angular.module('kibana.controllers', [])
$scope.init = function() {
$scope.config = config;
// Make underscore.js available to views
$scope._ = _;
// Provide a global list of all see fields
$scope.fields = fields
$scope.reset_row();
$scope.clear_all_alerts();
......@@ -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) {
var alert = {
title: title,
......@@ -70,6 +78,12 @@ angular.module('kibana.controllers', [])
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();
})
......@@ -86,7 +100,7 @@ angular.module('kibana.controllers', [])
_.defaults($scope.row,_d)
$scope.init = function(){
$scope.init = function() {
$scope.reset_panel();
}
......@@ -94,13 +108,14 @@ angular.module('kibana.controllers', [])
row.collapse = row.collapse ? false : true;
if (!row.collapse) {
$timeout(function() {
$scope.send_render();
$scope.$broadcast('render')
});
}
}
$scope.send_render = function() {
$scope.$broadcast('render');
// This can be overridden by individual panel
$scope.close_edit = function() {
$scope.$broadcast('render')
}
$scope.add_panel = function(row,panel) {
......@@ -109,11 +124,11 @@ angular.module('kibana.controllers', [])
$scope.reset_panel = function() {
$scope.panel = {
loading: false,
error: false,
span: 3,
loading : false,
error : false,
span : 3,
editable: true,
group: ['default'],
group : ['default'],
};
};
......
......@@ -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) {
// This service really just tracks a list of $timeout promises to give us a
// method for cancelling them all when we need to
......
......@@ -187,8 +187,9 @@ angular.module('kibana.dashcontrol', [])
var results = request.query(
$scope.ejs.QueryStringQuery(query || '*')
).size($scope.panel.elasticsearch_size).doSearch();
results.then(function(results) {
if(_.isUndefined(results)) {
if(_.isUndefined(results.hits)) {
return;
}
$scope.panel.error = false;
......
<div class="row-fluid" ng-controller='histogram'>
<div class="span3">
<form style="margin-bottom: 0px">
<h6>Label</h6>
<input type="text" placeholder="New Label" style="width:70%" ng-model="newlabel">
</form>
<div ng-controller='histogram'>
<div class="row-fluid">
<div class="span3">
<form style="margin-bottom: 0px">
<h6>Label</h6>
<input type="text" placeholder="New Label" style="width:70%" ng-model="newlabel">
</form>
</div>
<div class="span8">
<form class="input-append" style="margin-bottom: 0px">
<h6>Query</h6>
<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>
</div>
<div class="span1">
</div>
</div>
<div class="span8">
<form class="input-append" style="margin-bottom: 0px">
<h6>Query</h6>
<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>
<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 class="span1">
<h5>Chart Options</h5>
<div class="row-fluid" style="margin-bottom:10px;">
<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 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">
<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>
</div>
<div class="span2">
<label class="small">Zoom Links</label><input type="checkbox" ng-model="panel.zoomlinks" ng-checked="panel.zoomlinks">
</div>
</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 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 class="span3">
<label class="small">Line Fill (1 - 10)</label>
<input ng-change="$emit('render')" type="number" class="input-mini" ng-model="panel.fill">
</div>
<div class="span3">
<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>
</div>
<div class="span2">
<label class="small">Zoom Links</label><input type="checkbox" ng-model="panel.zoomlinks" ng-checked="panel.zoomlinks">
</div>
</div>
<h5>Panel Spy</h5>
<div class="row-fluid">
<div class="span2">
<label class="small">Spyable</label><input type="checkbox" ng-model="panel.spyable" ng-checked="panel.spyable">
</div>
<div class="span9 small">
The panel spy shows 'behind the scenes' information about a panel. It can
be accessed by clicking the <i class='icon-eye-open'></i> in the top right
of the panel.
<h5>Panel Spy</h5>
<div class="row-fluid">
<div class="span2">
<label class="small">Spyable</label><input type="checkbox" ng-model="panel.spyable" ng-checked="panel.spyable">
</div>
<div class="span9 small">
The panel spy shows 'behind the scenes' information about a panel. It can
be accessed by clicking the <i class='icon-eye-open'></i> in the top right
of the panel.
</div>
</div>
</div>
......@@ -2,15 +2,16 @@
<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>
</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(2)'><i class='icon-zoom-out'></i> Zoom Out</a>
</center>
<div>
<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"></div>
</span> |
<span ng-show="panel.legend" ng-repeat='series in plot.getData()' style='display:inline-block;padding-right:5px'>
<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.hits}})</div>
</span><span class="small"> per <strong>{{panel.interval}}</strong> | (<strong>{{hits}}</strong> total)</span>
</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>
\ No newline at end of file
......@@ -3,19 +3,28 @@ angular.module('kibana.histogram', [])
// Set and populate defaults
var _d = {
group : "default",
query : [ {query: "*", label:"Query"} ],
interval : secondsToHms(calculate_interval($scope.from,$scope.to,40,0)/1000),
show : ['bars','y-axis','x-axis','legend'],
fill : 3,
linewidth : 3,
timezone : 'browser', // browser, utc or a standard timezone
spyable : 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)
$scope.init = function() {
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) {
if(_.isArray(query)) {
$scope.panel.query = _.map(query,function(q) {
......@@ -26,6 +35,7 @@ angular.module('kibana.histogram', [])
}
$scope.get_data();
});
// Now that we're all setup, request the time from our group if we don't
// have it yet
if(_.isUndefined($scope.time))
......@@ -48,13 +58,13 @@ angular.module('kibana.histogram', [])
}
$scope.get_data = function(segment,query_id) {
delete $scope.panel.error
// Make sure we have everything for the request to complete
if(_.isUndefined($scope.panel.index) || _.isUndefined($scope.time))
return
var _segment = _.isUndefined(segment) ? 0 : segment
$scope.panel.loading = true;
var _segment = _.isUndefined(segment) ? 0 : segment
var request = $scope.ejs.Request().indices($scope.panel.index[_segment]);
// Build the question part of the query
......@@ -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) {
request = request
.facet($scope.ejs.DateHistogramFacet("chart"+_.indexOf(queries,v))
......@@ -78,6 +88,7 @@ angular.module('kibana.histogram', [])
).size(0)
})
// Populate the inspector panel
$scope.populate_modal(request);
// Then run it
......@@ -92,16 +103,17 @@ angular.module('kibana.histogram', [])
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) {
var i = 0;
_.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
if(_.isUndefined($scope.data[i]) || _segment == 0) {
......@@ -116,14 +128,14 @@ angular.module('kibana.histogram', [])
var segment_data = [];
_.each(v.entries, function(v, k) {
segment_data.push([v['time'],v['count']])
hits += v['count'];
$scope.hits += v['count'];
hits += v['count']; // The series level hits counter
$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 = {
data: {
label: $scope.panel.query[i].label || "query"+(parseInt(i)+1),
......@@ -140,8 +152,10 @@ angular.module('kibana.histogram', [])
i++;
});
eventBus.broadcast($scope.$id,$scope.panel.group,'hits',$scope.hits)
// Tell the histogram directive to render.
$scope.$emit('render')
// If we still have segments left, get them
if(_segment < $scope.panel.index.length-1) {
$scope.get_data(_segment+1,query_id)
}
......@@ -176,15 +190,13 @@ angular.module('kibana.histogram', [])
}
})
.directive('histogram', function(eventBus) {
.directive('histogramChart', function(eventBus) {
return {
restrict: 'A',
link: function(scope, elem, attrs, ctrl) {
var height = scope.panel.height || scope.row.height;
elem.html('<center><img src="common/img/load_big.gif"></center>')
// Receive render events
scope.$on('render',function(){
render_panel();
......@@ -197,19 +209,6 @@ angular.module('kibana.histogram', [])
// Function for rendering 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
var barwidth = interval_to_seconds(scope.panel.interval)*1000
......@@ -221,31 +220,36 @@ angular.module('kibana.histogram', [])
// Populate element. Note that jvectormap appends, does not replace.
scripts.wait(function(){
var stack = scope.panel.stack ? true : null;
// Populate element
try {
var plot = $.plot(elem, scope.data, {
legend: {
show: false,
},
scope.plot = $.plot(elem, scope.data, {
legend: { show: false },
series: {
stack: show.stack,
lines: { show: show.lines, fill: scope.panel.fill/10 },
bars: { show: show.bars, fill: 1, barWidth: barwidth/1.8 },
points: { show: show.points, fill: 1, fillColor: false},
stack: stack,
lines: {
show: scope.panel.lines,
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
},
yaxis: { show: show['y-axis'], min: 0, color: "#000" },
yaxis: { show: scope.panel['y-axis'], min: 0, color: "#000" },
xaxis: {
timezone: scope.panel.timezone,
show: show['x-axis'],
show: scope.panel['x-axis'],
mode: "time",
timeformat: time_format(scope.panel.interval),
label: "Datetime",
color: "#000",
},
selection: {
mode: "x"
mode: "x",
color: '#666'
},
grid: {
backgroundColor: '#fff',
......@@ -254,12 +258,13 @@ angular.module('kibana.histogram', [])
color: "#eee",
hoverable: true,
},
colors: ['#EB6841','#00A0B0','#6A4A3C','#EDC951','#CC333F']
})
scope.legend = [];
_.each(plot.getData(),function(series) {
scope.legend.push(_.pick(series,'label','color','hits'))
colors: ['#86B22D',
'#BF6730',
'#1D7373',
'#BFB930',
'#BF3030',
'#77207D'
]
})
// Work around for missing legend at initialization
......@@ -288,23 +293,25 @@ angular.module('kibana.histogram', [])
var tooltip = $('#pie-tooltip').length ?
$('#pie-tooltip') : $('<div id="pie-tooltip"></div>');
//var tooltip = $('#pie-tooltip')
tooltip.text(contents).css({
tooltip.html(contents).css({
position: 'absolute',
top : y + 5,
left : x + 5,
color : "#FFF",
border : '1px solid #FFF',
padding : '2px',
'font-size': '8pt',
'background-color': '#000',
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) {
var percent = parseFloat(item.series.percent).toFixed(1) + "%";
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'));
} else {
$("#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">
<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 class="span3" ng-show="!panel.aggregate"><label class="small">Counter Style</label>
<select class="input-small" ng-model="panel.arrangement" ng-options="f for f in ['none','horizontal','vertical']"></select></span>
</div>
<div class="span2" ng-show="!panel.aggregate">
<label class="small">Chart</label><input type="checkbox" ng-model="panel.chart" ng-checked="panel.chart">
</div>
</div>
<div class="row-fluid">
<div class="span3">
<form style="margin-bottom: 0px">
<label class="small">Label</label>
<input type="text" placeholder="New Label" style="width:70%" ng-model="newlabel">
</form>
</div>
<div class="span9" ng-show='!panel.run_query'>
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>.
<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>
</div>
<div class="span9" ng-show='panel.run_query'>
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>
<div class="span1">
</div>
</div>
<div class="row-fluid">
<div class="span9" ng-show='panel.run_query'>
<form class="input-append">
<h6>Query</h6>
<input type="text" style="width:85%" ng-model="panel.query">
<button class="btn" ng-click="get_data();"><i class="icon-search"></i></button>
<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="span3"><h6>Font Size</h6>
<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 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>
<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>
\ No newline at end of file
......@@ -5,64 +5,207 @@ angular.module('kibana.hits', [])
var _d = {
query : "*",
group : "default",
style : { "font-size": '36pt', "font-weight": "bold" },
run_query : false
style : { "font-size": '10pt'},
aggregate : true,
arrangement : 'vertical',
chart : true,
counters: true,
count_pos: 'above'
}
_.defaults($scope.panel,_d)
$scope.init = function () {
$scope.hits = 0;
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) {
$scope.panel.query = _.isArray(query) ? query[0] : query;
if($scope.panel.run_query)
$scope.get_data();
$scope.panel.query = _.map(query,function(q) {
return {query: q, label: q};
})
$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
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
if(_.isUndefined($scope.panel.index) || _.isUndefined($scope.time))
return
$scope.panel.loading = true;
var request = $scope.ejs.Request().indices($scope.panel.index);
var results = request
.query(ejs.FilteredQuery(
ejs.QueryStringQuery($scope.panel.query || '*'),
var _segment = _.isUndefined(segment) ? 0 : segment
var request = $scope.ejs.Request().indices($scope.panel.index[_segment]);
// Build the question part of the query
var queries = [];
_.each($scope.panel.query, function(v) {
queries.push($scope.ejs.FilteredQuery(
ejs.QueryStringQuery(v.query || '*'),
ejs.RangeFilter($scope.time.field)
.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
results.then(function(results) {
$scope.panel.loading = false;
if(_.isUndefined(results)) {
$scope.panel.error = 'Your query was unsuccessful';
if(_segment == 0) {
$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;
}
$scope.panel.error = false;
$scope.hits = results.hits.total;
if($scope.query_id === query_id) {
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) {
$scope.time = time;
$scope.panel.index = _.isUndefined(time.index) ? $scope.panel.index : time.index
$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 @@
<div class="span3">
<form>
<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>
</div>
<div class="span6">
......
......@@ -128,12 +128,12 @@ angular.module('kibana.map', [])
$('.jvectormap-label').css({
"position" : "absolute",
"display" : "none",
"border" : "solid 1px #CDCDCD",
"background" : "#292929",
"color" : "white",
"font-family" : "sans-serif, Verdana",
"font-size" : "smaller",
"padding" : "3px"
"border" : "solid 2px #000",
"background" : "#FFF",
"font-weight" : 200,
"border-radius": "5px",
"color" : "#000",
"padding" : "5px"
})
var count = _.isUndefined(scope.data[code]) ? 0 : scope.data[code];
$('.jvectormap-label').text(label.text() + ": " + count);
......
......@@ -4,7 +4,7 @@
<div class="span4">
<form style="margin-bottom: 0px">
<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>
</div>
<div class="span8">
......
......@@ -2,6 +2,11 @@
<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>
</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>
</kibana-panel>
\ No newline at end of file
......@@ -268,14 +268,21 @@ angular.module('kibana.pie', [])
},
//grid: { hoverable: true, clickable: true },
grid: { hoverable: true, clickable: true },
legend: { show: scope.panel.legend },
colors: ['#EB6841','#00A0B0','#6A4A3C','#EDC951','#CC333F']
legend: { show: false },
colors: ['#86B22D','#BF6730','#1D7373','#BFB930','#BF3030','#77207D']
};
// Populate element
if(elem.is(":visible")){
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', [])
function piett(x, y, contents) {
var tooltip = $('#pie-tooltip').length ?
$('#pie-tooltip') : $('<div id="pie-tooltip"></div>');
tooltip.text(contents).css({
tooltip.html(contents).css({
position: 'absolute',
top : y + 10,
left : x + 10,
color : "#FFF",
border : '1px solid #FFF',
padding : '2px',
'font-size': '8pt',
'background-color': '#000',
color : "#000",
'font-weight': 200,
'border-radius': '5px',
border : '2px solid #000',
padding : '10px',
'background-color': '#FFF',
}).appendTo("body");
}
......@@ -305,7 +313,8 @@ angular.module('kibana.pie', [])
elem.bind("plothover", function (event, pos, item) {
if (item) {
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 {
$("#pie-tooltip").remove();
}
......
......@@ -21,7 +21,7 @@
</form>
</div>
<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 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>
......@@ -31,7 +31,7 @@
</span>
</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" 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 ng-show="panel.multi && panel.multi_arrange == 'vertical'">
<form>
......
......@@ -11,7 +11,7 @@
<div class="span4">
<form class="input-append">
<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>
</form>
</div>
......
angular.module('kibana.table', [])
.controller('table', function($scope, eventBus) {
.controller('table', function($scope, eventBus, fields) {
// Set and populate defaults
var _d = {
......@@ -76,6 +76,8 @@ angular.module('kibana.table', [])
}
$scope.get_data = function(segment,query_id) {
$scope.panel.error = false;
// Make sure we have everything for the request to complete
if(_.isUndefined($scope.panel.index) || _.isUndefined($scope.time))
return
......@@ -98,7 +100,7 @@ angular.module('kibana.table', [])
$scope.populate_modal(request)
var results = request.doSearch();
var results = request.doSearch()
// Populate scope when we have results
results.then(function(results) {
......@@ -110,11 +112,11 @@ angular.module('kibana.table', [])
query_id = $scope.query_id = new Date().getTime()
}
if(_.isUndefined(results)) {
$scope.panel.error = 'Your query was unsuccessful';
// Check for error and abort if found
if(!(_.isUndefined(results.error))) {
$scope.panel.error = $scope.parse_error(results.error);
return;
}
$scope.panel.error = false;
// Check that we're still on the same query, if not stop
if($scope.query_id === query_id) {
......@@ -142,7 +144,6 @@ angular.module('kibana.table', [])
// This breaks, use $scope.data for this
$scope.all_fields = get_all_fields($scope.data);
broadcast_results();
// If we're not sorting in reverse chrono order, query every index for
......
......@@ -23,7 +23,7 @@
</div>
</div>
<div ng-switch-when="since">
<div class="span10">
<div class="span5">
<form class="nomargin">
<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>
......
......@@ -111,10 +111,6 @@ angular.module('kibana.timepicker', [])
}
$scope.time_apply();
});
$scope.$on('render', function (){
$scope.time_apply();
});
}
$scope.set_interval = function (refresh_interval) {
......@@ -167,6 +163,10 @@ angular.module('kibana.timepicker', [])
$scope.time_apply();
}
$scope.close_edit = function() {
$scope.time_apply();
}
$scope.time_check = function(){
// If time picker is defined (on initialization)
......
<div class="row-fluid container">
<div class="row-fluid container" style="margin-top:10px">
<!-- Rows -->
<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="span12">
<div class="row-fluid kibana-row" ng-controller="RowCtrl" ng-repeat="(row_name, row) in dashboards.rows" ng-style="row_style(row)">
<div class="row-control">
<div class="row-fluid row-header" style="padding:0px;margin:0px;height:0px">
<div class="span12" style="min-height:5px;vertical-align:bottom">
<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 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>
</div>
</div>
<small ng-hide="row.collapsable" class="rotated">{{row.title}}</small>
</div>
</div>
<div class="row-fluid" style="padding-top:10px" ng-hide="row.collapse">
<div class="row-fluid" style="padding-top:0px" ng-hide="row.collapse">
<!-- 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">
<!-- Error Panel -->
......
<div class="modal-header">
<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 class="modal-body">
......@@ -13,5 +13,5 @@
</div>
<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>
\ No newline at end of file
......@@ -56,5 +56,5 @@
</div>
</div>
<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>
\ 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