Commit 700d6005 by Torkel Ödegaard

More work on annotations (#44, #8) It is working for annotations from graphite…

More work on annotations (#44,  #8) It is working for annotations from graphite metrics, basic annotation editor and everything is working. Needs some final touches and support for more datasources
parent bda5ae5b
...@@ -10,8 +10,6 @@ function (angular, app, _) { ...@@ -10,8 +10,6 @@ function (angular, app, _) {
module.controller('SubmenuCtrl', function($scope) { module.controller('SubmenuCtrl', function($scope) {
var _d = { var _d = {
collapse: false,
notice: false,
enable: true enable: true
}; };
......
...@@ -2,7 +2,7 @@ define([ ...@@ -2,7 +2,7 @@ define([
'angular', 'angular',
'underscore' 'underscore'
], ],
function (angular,_) { function (angular, _) {
'use strict'; 'use strict';
angular angular
...@@ -10,30 +10,29 @@ function (angular,_) { ...@@ -10,30 +10,29 @@ function (angular,_) {
.directive('configModal', function($modal,$q) { .directive('configModal', function($modal,$q) {
return { return {
restrict: 'A', restrict: 'A',
link: function(scope, elem) { link: function(scope, elem, attrs) {
var
model = attrs.kbnModel,
partial = attrs.configModal;
// create a new modal. Can't reuse one modal unforunately as the directive will not // create a new modal. Can't reuse one modal unforunately as the directive will not
// re-render on show. // re-render on show.
elem.bind('click',function(){ elem.bind('click',function(){
if (scope.openConfigureModal) {
scope.openConfigureModal();
scope.$apply();
return;
}
// Create a temp scope so we can discard changes to it if needed // Create a temp scope so we can discard changes to it if needed
var tmpScope = scope.$new(); var tmpScope = scope.$new();
tmpScope.panel = angular.copy(scope.panel); tmpScope[model] = angular.copy(scope[model]);
tmpScope.editSave = function(panel) { tmpScope.editSave = function(panel) {
// Correctly set the top level properties of the panel object // Correctly set the top level properties of the panel object
_.each(panel,function(v,k) { _.each(panel,function(v,k) {
scope.panel[k] = panel[k]; scope[model][k] = panel[k];
}); });
}; };
var panelModal = $modal({ var panelModal = $modal({
template: './app/partials/paneleditor.html', template: partial,
persist: true, persist: true,
show: false, show: false,
scope: tmpScope, scope: tmpScope,
......
...@@ -44,7 +44,8 @@ function (angular, $) { ...@@ -44,7 +44,8 @@ function (angular, $) {
'</span>' + '</span>' +
'</span>'+ '</span>'+
'<span ng-if="!panelMeta.menuItems" config-modal class="panel-text panel-title pointer" ng-show="panel.title">' + '<span ng-if="!panelMeta.menuItems" config-modal="./app/partials/paneleditor.html" ' +
' kbn-model="panel" class="panel-text panel-title pointer" >' +
'{{panel.title}}' + '{{panel.title}}' +
'</span>'+ '</span>'+
......
<div bindonce class="modal-body">
<div class="pull-right editor-title">Annotations</div>
<div class="editor-row">
<table class="table table-striped annotation-editor-table">
<thead>
<th width="1%">Type</th>
<th width="90%">Name</th>
<th width="1%"></th>
<th width="1%"></th>
<th width="1%"></th>
<th width="1%"></th>
</thead>
<tr ng-repeat="annotation in panel.annotations">
<td>{{annotation.type}}</td>
<td>{{annotation.name}}</td>
<td><i ng-click="_.move(panel.annotations,$index,$index-1)" ng-hide="$first" class="pointer icon-arrow-up"></i></td>
<td><i ng-click="_.move(panel.annotations,$index,$index+1)" ng-hide="$last" class="pointer icon-arrow-down"></i></td>
<td><i ng-click="panel.annotations = _.without(panel.annotations, annotation)" class="pointer icon-remove"></i></td>
<td><a ng-click="edit(annotation)"><i class="icon-pencil" /></a></td>
</tr>
</table>
</div>
<div class="editor-row">
<h4 ng-show="currentIsNew">Add Annotation</h4>
<h4 ng-show="!currentIsNew">Edit Annotation</h4>
<div class="editor-option">
<label class="small">Name</label>
<input type="text" class="input-medium" ng-model='currentAnnnotation.name' placeholder="name"></input>
</div>
<div class="editor-option">
<label class="small">Type</label>
<select ng-model="currentAnnnotation.type" ng-options="f for f in ['graphite metric']"></select>
</div>
</div>
<div class="editor-row" ng-if="currentAnnnotation.type === 'graphite metric'">
<div class="editor-option">
<label class="small">Graphite target expression</label>
<input type="text" class="span10" ng-model='currentAnnnotation.target' placeholder=""></input>
</div>
</div>
<div class="editor-row" ng-if="currentAnnnotation.type === 'graphite events'">
<div class="editor-option">
<label class="small">Graphite event tags</label>
<input type="text" ng-model='currentAnnnotation.tags' placeholder=""></input>
</div>
</div>
</div>
<div class="modal-footer">
<!-- close_edit() is provided here to allow for a scope to perform action on dismiss -->
<button ng-show="currentIsNew" type="button" class="btn btn-success" ng-click="add()">Add annotation</button>
<button ng-show="!currentIsNew" type="button" class="btn btn-success" ng-click="update()">Update</button>
<button type="button" class="btn btn-danger" ng-click="editSave(panel);close_edit();dismiss()">Close</button>
</div>
<div ng-controller='AnnotationsCtrl' ng-init="init()"> <div ng-controller='AnnotationsCtrl' ng-init="init()">
<!-- <div class="submenu-toggle" ng-class="{'annotation-disabled': panel.hideAll }"> <div class="submenu-toggle" ng-repeat="annotation in panel.annotations" ng-class="{'annotation-disabled': !annotation.enable }">
<a ng-click="hideAll();" class="small">Hide All</a> <i class="annotation-color-icon icon-minus"></i>
<i class="icon-ok"></i>
</div>
-->
<div class="submenu-toggle" ng-repeat="annotation in annotationList" ng-class="{'annotation-disabled': !annotation.enabled }">
<a ng-click="hide(annotation)" class="small">{{annotation.name}}</a> <a ng-click="hide(annotation)" class="small">{{annotation.name}}</a>
<i class="icon-ok"></i> </div>
<div class="submenu-control-edit">
<i class="icon-cog pointer" bs-modal="'app/panels/annotations/editor.html'" bs-tooltip="'Edit annotations'" ></i>
</div> </div>
</div> </div>
\ No newline at end of file
...@@ -14,7 +14,7 @@ function (angular, app, _) { ...@@ -14,7 +14,7 @@ function (angular, app, _) {
var module = angular.module('kibana.panels.annotations', []); var module = angular.module('kibana.panels.annotations', []);
app.useModule(module); app.useModule(module);
module.controller('AnnotationsCtrl', function($scope, dashboard, annotationsSrv, $rootScope) { module.controller('AnnotationsCtrl', function($scope, dashboard, $rootScope) {
$scope.panelMeta = { $scope.panelMeta = {
status : "Stable", status : "Stable",
...@@ -23,26 +23,46 @@ function (angular, app, _) { ...@@ -23,26 +23,46 @@ function (angular, app, _) {
// Set and populate defaults // Set and populate defaults
var _d = { var _d = {
annotations: []
};
var annotationDefaults = {
name: '',
type: 'graphite metric'
}; };
_.defaults($scope.panel,_d); _.defaults($scope.panel,_d);
$scope.init = function() { $scope.init = function() {
$scope.annotationList = annotationsSrv.annotationList; $scope.currentAnnnotation = angular.copy(annotationDefaults);
$scope.currentIsNew = true;
}; };
$scope.hideAll = function () { $scope.getAnnotationInfo = function(annotation) {
$scope.panel.hideAll = !$scope.panel.hideAll; return annotation.target;
};
_.each($scope.annotationList, function(annotation) { $scope.edit = function(annotation) {
annotation.enabled = !$scope.panel.hideAll; $scope.currentAnnnotation = annotation;
}); $scope.currentIsNew = false;
}; };
$scope.hide = function (annotation) { $scope.getInfo = function(annotation) {
annotation.enabled = !annotation.enabled; return annotation.target;
$scope.panel.hideAll = !annotation.enabled; };
$scope.update = function() {
$scope.currentAnnnotation = angular.copy(annotationDefaults);
$scope.currentIsNew = true;
};
$scope.add = function() {
$scope.panel.annotations.push($scope.currentAnnnotation);
$scope.currentAnnnotation = angular.copy(annotationDefaults);
};
$scope.hide = function (annotation) {
annotation.enable = !annotation.enable;
$rootScope.$broadcast('refresh'); $rootScope.$broadcast('refresh');
}; };
......
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
</div> </div>
<div ng-if="editor.index == 1"> <div ng-if="editor.index == 1">
<div class="row-fluid"> <div class="editor-row">
<div class="span8"> <div class="span8">
<h4>Rows</h4> <h4>Rows</h4>
<table class="table table-striped"> <table class="table table-striped">
...@@ -69,9 +69,6 @@ ...@@ -69,9 +69,6 @@
<input type="text" class="input-mini" ng-model='row.height'></input> <input type="text" class="input-mini" ng-model='row.height'></input>
</div> </div>
</div> </div>
<div class="row-fluid">
</div>
</div> </div>
<div ng-if="editor.index == 2" ng-controller="dashLoader"> <div ng-if="editor.index == 2" ng-controller="dashLoader">
...@@ -124,7 +121,7 @@ ...@@ -124,7 +121,7 @@
<div ng-if="editor.index == 2"> <div ng-if="editor.index == 2">
<div class="editor-row"> <div class="editor-row">
<div class="section"> <div class="section">
<h5>Pulldowns</h5> <h5>Feature toggles</h5>
<div class="editor-option" ng-repeat="pulldown in dashboard.current.pulldowns"> <div class="editor-option" ng-repeat="pulldown in dashboard.current.pulldowns">
<label class="small" style="text-transform:capitalize;">{{pulldown.type}}</label><input type="checkbox" ng-model="pulldown.enable" ng-checked="pulldown.enable"> <label class="small" style="text-transform:capitalize;">{{pulldown.type}}</label><input type="checkbox" ng-model="pulldown.enable" ng-checked="pulldown.enable">
</div> </div>
......
...@@ -7,27 +7,35 @@ define([ ...@@ -7,27 +7,35 @@ define([
var module = angular.module('kibana.services'); var module = angular.module('kibana.services');
module.service('annotationsSrv', function(dashboard, datasourceSrv, $q, alertSrv) { module.service('annotationsSrv', function(dashboard, datasourceSrv, $q, alertSrv, $rootScope) {
var promiseCached;
var annotationPanel;
this.init = function() { this.init = function() {
this.annotationList = [ $rootScope.$on('refresh', this.clearCache);
/* { $rootScope.$on('dashboard-loaded', this.dashboardLoaded);
type: 'graphite-target',
enabled: false, this.dashboardLoaded();
target: 'metrics_data.mysite.dolph.counters.payment.cart_klarna_payment_completed.count', };
name: 'deploys',
}, this.dashboardLoaded = function () {
{ annotationPanel = _.findWhere(dashboard.current.pulldowns, { type: 'annotations' });
type: 'graphite-target', };
enabled: true,
target: 'metrics_data.mysite.dolph.counters.payment.cart_paypal_payment_completed.count', this.clearCache = function() {
name: 'restarts', promiseCached = null;
}*/
];
}; };
this.getAnnotations = function(rangeUnparsed) { this.getAnnotations = function(rangeUnparsed) {
var graphiteAnnotations = _.where(this.annotationList, { type: 'graphite-target', enabled: true }); if (!annotationPanel.enable) {
return $q.when(null);
}
if (promiseCached) {
return promiseCached;
}
var graphiteAnnotations = _.where(annotationPanel.annotations, { type: 'graphite metric', enable: true });
var graphiteTargets = _.map(graphiteAnnotations, function(annotation) { var graphiteTargets = _.map(graphiteAnnotations, function(annotation) {
return { target: annotation.target }; return { target: annotation.target };
}); });
...@@ -43,7 +51,7 @@ define([ ...@@ -43,7 +51,7 @@ define([
maxDataPoints: 100 maxDataPoints: 100
}; };
return datasourceSrv.default.query(graphiteQuery) promiseCached = datasourceSrv.default.query(graphiteQuery)
.then(function(results) { .then(function(results) {
return _.reduce(results.data, function(list, target) { return _.reduce(results.data, function(list, target) {
_.each(target.datapoints, function (values) { _.each(target.datapoints, function (values) {
...@@ -51,12 +59,13 @@ define([ ...@@ -51,12 +59,13 @@ define([
return; return;
} }
list.push({ list.push({
min: values[1] * 1000, min: values[1] * 1000,
max: values[1] * 1000, max: values[1] * 1000,
eventType: "annotation", eventType: "annotation",
title: null, title: null,
description: "<small><i class='icon-tag icon-flip-vertical'></i>test</small><br>"+ description: "<small>" + target.target + "</small><br>"+
moment(values[1] * 1000).format('YYYY-MM-DD HH:mm:ss'), moment(values[1] * 1000).format('YYYY-MM-DD HH:mm:ss'),
score: 1 score: 1
}); });
...@@ -68,6 +77,8 @@ define([ ...@@ -68,6 +77,8 @@ define([
.then(null, function() { .then(null, function() {
alertSrv.set('Annotations','Could not fetch annotations','error'); alertSrv.set('Annotations','Could not fetch annotations','error');
}); });
return promiseCached;
}; };
// Now init // Now init
......
...@@ -28,7 +28,7 @@ function (angular, $, kbn, _, config, moment, Modernizr) { ...@@ -28,7 +28,7 @@ function (angular, $, kbn, _, config, moment, Modernizr) {
failover: false, failover: false,
panel_hints: true, panel_hints: true,
rows: [], rows: [],
pulldowns: [ { type: 'filtering' }, /*{ type: 'annotations' }*/ ], pulldowns: [ { type: 'filtering' }, { type: 'annotations' } ],
nav: [ { type: 'timepicker' } ], nav: [ { type: 'timepicker' } ],
services: {}, services: {},
loader: { loader: {
...@@ -131,13 +131,13 @@ function (angular, $, kbn, _, config, moment, Modernizr) { ...@@ -131,13 +131,13 @@ function (angular, $, kbn, _, config, moment, Modernizr) {
}); });
} }
/*var annotations = _.findWhere(dashboard.pulldowns, {type: 'annotations'}); var annotations = _.findWhere(dashboard.pulldowns, {type: 'annotations'});
if (!annotations) { if (!annotations) {
dashboard.pulldowns.push({ dashboard.pulldowns.push({
type: 'annotations', type: 'annotations',
enable: false enable: false
}); });
}*/ }
return dashboard; return dashboard;
}; };
...@@ -177,6 +177,8 @@ function (angular, $, kbn, _, config, moment, Modernizr) { ...@@ -177,6 +177,8 @@ function (angular, $, kbn, _, config, moment, Modernizr) {
// Take out any that we're not allowed to add from the gui. // Take out any that we're not allowed to add from the gui.
self.availablePanels = _.difference(self.availablePanels,config.hidden_panels); self.availablePanels = _.difference(self.availablePanels,config.hidden_panels);
$rootScope.$emit('dashboard-loaded');
return true; return true;
}; };
......
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.
...@@ -142,7 +142,7 @@ ...@@ -142,7 +142,7 @@
padding: 0 4px; padding: 0 4px;
i { i {
position: relative; position: relative;
top: 3px; top: 2px;
} }
} }
......
...@@ -565,57 +565,8 @@ div.flot-text { ...@@ -565,57 +565,8 @@ div.flot-text {
color: @white; color: @white;
} }
// Filter submenu .annotation-editor-table {
.filtering-container { td {
float: left; white-space: nowrap;
} }
.filtering-container label {
float: left;
}
.filtering-container input[type=checkbox] {
margin: 0;
}
.filter-panel-filter {
display:inline-block;
vertical-align: top;
padding: 4px 10px 3px 10px;
border-right: 1px solid @submenuBorder;
}
.filter-panel-filter:first-child {
padding-left: 0;
}
.filter-panel-filter ul {
margin-bottom: 0px;
}
.filter-deselected {
opacity: 0.5;
}
.filter-action {
float:right;
padding-right: 2px;
margin-bottom: 0px !important;
margin-left: 0px;
margin-top: 4px;
}
.add-filter-action {
padding: 3px 10px 0px 5px;
position: relative;
top: 4px;
}
.filter-mandate {
text-decoration: underline;
cursor: pointer;
}
.filter-apply {
float:right;
} }
\ No newline at end of file
...@@ -12,11 +12,15 @@ ...@@ -12,11 +12,15 @@
} }
.submenu-panel { .submenu-panel {
padding: 0 10px 0 17px; padding: 0 4px 0 8px;
border-right: 1px solid @submenuBorder; border-right: 1px solid @submenuBorder;
float: left; float: left;
} }
.submenu-panel:first-child {
padding-left: 17px;
}
.submenu-panel-title { .submenu-panel-title {
float: left; float: left;
text-transform: uppercase; text-transform: uppercase;
...@@ -30,12 +34,79 @@ ...@@ -30,12 +34,79 @@
.submenu-toggle { .submenu-toggle {
padding: 4px 0 3px 8px; padding: 4px 0 3px 8px;
float: left; float: left;
.annotation-color-icon {
position: relative;
top: 2px;
}
} }
.submenu-toggle:first-child { .submenu-toggle:first-child {
padding-left: 0; padding-left: 0;
} }
.submenu-control-edit {
padding: 4px 4px 3px 8px;
float: right;
border-left: 1px solid @submenuBorder;
margin-left: 8px;
}
.annotation-disabled, .annotation-disabled a { .annotation-disabled, .annotation-disabled a {
color: darken(@textColor, 25%); color: darken(@textColor, 25%);
} }
// Filter submenu
.filtering-container {
float: left;
}
.filtering-container label {
float: left;
}
.filtering-container input[type=checkbox] {
margin: 0;
}
.filter-panel-filter {
display:inline-block;
vertical-align: top;
padding: 4px 10px 3px 10px;
border-right: 1px solid @submenuBorder;
}
.filter-panel-filter:first-child {
padding-left: 0;
}
.filter-panel-filter ul {
margin-bottom: 0px;
}
.filter-deselected {
opacity: 0.5;
}
.filtering-container .filter-action {
float:right;
padding-right: 2px;
margin-bottom: 0px !important;
margin-left: 0px;
margin-top: 4px;
}
.add-filter-action {
padding: 3px 5px 0px 5px;
position: relative;
top: 4px;
}
.filter-mandate {
text-decoration: underline;
cursor: pointer;
}
.filter-apply {
float:right;
}
\ 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