Closes #164, typeahead / autocomplete for adding graphite functions to a target expression

This commit is contained in:
Torkel Ödegaard 2014-03-04 18:50:38 +01:00
parent 238de4d8b4
commit 2be71c577c
8 changed files with 117 additions and 32 deletions

View File

@ -13,7 +13,6 @@ function (angular, _, config, gfunc, Parser) {
module.controller('GraphiteTargetCtrl', function($scope, $http, filterSrv) {
$scope.init = function() {
$scope.funcCategories = gfunc.getCategories();
parseTarget();
};

View File

@ -0,0 +1,101 @@
define([
'angular',
'app',
'underscore',
'jquery',
'../services/graphite/gfunc',
],
function (angular, app, _, $, gfunc) {
'use strict';
angular
.module('kibana.directives')
.directive('graphiteAddFunc', function($compile) {
var inputTemplate = '<input type="text"'+
' class="grafana-target-segment-input input-medium grafana-target-segment-input"' +
' spellcheck="false" style="display:none"></input>';
var buttonTemplate = '<a class="grafana-target-segment grafana-target-function dropdown-toggle"' +
' tabindex="1" gf-dropdown="functionMenu" data-toggle="dropdown"' +
' data-placement="bottom"><i class="icon-plus"></i></a>';
return {
link: function($scope, elem) {
var categories = gfunc.getCategories();
var allFunctions = getAllFunctionNames(categories);
$scope.functionMenu = createFunctionDropDownMenu(categories);
var $input = $(inputTemplate);
var $button = $(buttonTemplate);
$input.appendTo(elem);
$button.appendTo(elem);
$input.attr('data-provide', 'typeahead');
$input.typeahead({
source: allFunctions,
minLength: 1,
items: 10,
updater: function (value) {
var funcDef = gfunc.getFuncDef(value);
$scope.$apply(function() {
$scope.addFunction(funcDef);
});
$input.trigger('blur');
return '';
}
});
$button.click(function() {
$button.hide();
$input.show();
$input.focus();
});
$input.keyup(function() {
elem.toggleClass('open', $input.val() === '');
});
$input.blur(function() {
$input.hide();
$input.val('');
$button.show();
$button.focus();
// clicking the function dropdown menu wont
// work if you remove class at once
setTimeout(function() {
elem.removeClass('open');
}, 200);
});
$compile(elem.contents())($scope);
}
};
});
function getAllFunctionNames(categories) {
return _.reduce(categories, function(list, category) {
_.each(category, function(func) {
list.push(func.name);
});
return list;
}, []);
}
function createFunctionDropDownMenu(categories) {
return _.map(categories, function(list, category) {
return {
text: category,
submenu: _.map(list, function(value) {
return {
text: value.name,
click: "addFunction('" + value.name + "')",
};
})
};
});
}
});

View File

@ -12,5 +12,6 @@ define([
'./spectrumPicker',
'./grafanaGraph',
'./bootstrap-tagsinput',
'./bodyClass'
'./bodyClass',
'./addGraphiteFunc'
], function () {});

View File

@ -31,4 +31,4 @@ function (angular, app, _) {
}
};
});
});
});

View File

@ -101,8 +101,8 @@ function (angular, $) {
}
var li = '<li' + (item.submenu && item.submenu.length ? ' class="dropdown-submenu"' : '') + '>' +
'<a tabindex="-1" ng-href="' + (item.href || '') + '"' + (item.click ? '" ng-click="' + item.click + '"' : '') +
(item.target ? '" target="' + item.target + '"' : '') + (item.method ? '" data-method="' + item.method + '"' : '') +
'<a tabindex="-1" ng-href="' + (item.href || '') + '"' + (item.click ? ' ng-click="' + item.click + '"' : '') +
(item.target ? ' target="' + item.target + '"' : '') + (item.method ? ' data-method="' + item.method + '"' : '') +
(item.configModal ? ' config-modal="' + item.configModal + '"' : "") +
'>' + (item.text || '') + '</a>';

View File

@ -53,7 +53,7 @@
</ul>
<input type="text"
class="grafana-target-text-input span12"
class="grafana-target-text-input span10"
ng-model="target.target"
focus-me="showTextEditor"
spellcheck='false'
@ -80,28 +80,8 @@
{{func.text}}
</a>
</li>
<li class="dropdown dropup">
<a class="grafana-target-segment grafana-target-function dropdown-toggle"
data-toggle="dropdown"
tabindex="1"
ng-click="addFunction">
<i class="icon-plus"></i>
</a>
<ul class="dropdown-menu" role="menu">
<li ng-repeat="(category, funcList) in funcCategories" class="dropdown-submenu" role="menuitem">
<a href="javascript:void(0)"
tabindex="1">
{{category}}
</a>
<ul class="dropdown-menu" role="menu">
<li ng-repeat="func in funcList" role="menuitem">
<a ng-click="addFunction(func)" tabindex="1">
{{func.name}}
</a>
</li>
</ul>
</li>
</ul>
<li class="dropdown" graphite-add-func>
</li>
</ul>

View File

@ -245,8 +245,8 @@ function (_) {
name: 'lowestCurrent',
category: categories.Filter,
params: [ { name: "count", type: "int" } ],
defaultParams: [5]
});
defaultParams: [5]
});
addFuncDef({
name: 'movingAverage',
@ -260,7 +260,7 @@ function (_) {
category: categories.Filter,
params: [ { name: "count", type: "int" } ],
defaultParams: [5]
});
});
addFuncDef({
name: 'lowestAverage',
@ -318,6 +318,10 @@ function (_) {
return new FuncInstance(funcDef);
},
getFuncDef: function(name) {
return index[name];
},
getCategories: function() {
return categories;
}

View File

@ -393,7 +393,7 @@ angular.module('$strap.directives').directive('bsDropdown', [
angular.forEach(items, function (item, index) {
if (item.divider)
return ul.splice(index + 1, 0, '<li class="divider"></li>');
var li = '<li' + (item.submenu && item.submenu.length ? ' class="dropdown-submenu"' : '') + '>' + '<a tabindex="-1" ng-href="' + (item.href || '') + '"' + (item.click ? '" ng-click="' + item.click + '"' : '') + (item.target ? '" target="' + item.target + '"' : '') + (item.method ? '" data-method="' + item.method + '"' : '') + '>' + (item.text || '') + '</a>';
var li = '<li' + (item.submenu && item.submenu.length ? ' class="dropdown-submenu"' : '') + '>' + '<a tabindex="1" ng-href="' + (item.href || '') + '"' + (item.click ? '" ng-click="' + item.click + '"' : '') + (item.target ? '" target="' + item.target + '"' : '') + (item.method ? ' data-method="' + item.method + '"' : '') + '>' + (item.text || '') + '</a>';
if (item.submenu && item.submenu.length)
li += buildTemplate(item.submenu).join('\n');
li += '</li>';