Files
grafana/src/app/controllers/graphiteTarget.js

328 lines
9.0 KiB
JavaScript
Raw Normal View History

2013-12-17 22:53:31 +01:00
define([
'angular',
2014-08-07 14:35:19 +02:00
'lodash',
2013-12-22 21:09:02 +01:00
'config',
'../services/graphite/gfunc',
'../services/graphite/parser'
2013-12-17 22:53:31 +01:00
],
function (angular, _, config, gfunc, Parser) {
2013-12-17 22:53:31 +01:00
'use strict';
2014-07-28 18:11:52 +02:00
var module = angular.module('grafana.controllers');
var targetLetters = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O'];
2013-12-17 22:53:31 +01:00
module.controller('GraphiteTargetCtrl', function($scope, $sce, templateSrv) {
2013-12-20 09:50:50 +01:00
$scope.init = function() {
$scope.target.target = $scope.target.target || '';
$scope.targetLetter = targetLetters[$scope.$index];
parseTarget();
};
// The way parsing and the target editor works needs
// to be rewritten to handle functions that take multiple series
function parseTarget() {
2013-12-22 15:39:25 +01:00
$scope.functions = [];
$scope.segments = [];
2013-12-24 18:26:51 +01:00
$scope.showTextEditor = false;
delete $scope.parserError;
var parser = new Parser($scope.target.target);
var astNode = parser.getAst();
2013-12-30 14:49:02 +01:00
if (astNode === null) {
checkOtherSegments(0);
return;
2013-12-30 14:49:02 +01:00
}
if (astNode.type === 'error') {
$scope.parserError = astNode.message + " at position: " + astNode.pos;
$scope.showTextEditor = true;
return;
}
try {
parseTargeRecursive(astNode);
}
catch (err) {
console.log('error parsing target:', err.message);
$scope.parserError = err.message;
$scope.showTextEditor = true;
}
2014-01-13 21:43:08 +01:00
checkOtherSegments($scope.segments.length - 1);
}
2013-12-20 09:50:50 +01:00
function parseTargeRecursive(astNode, func, index) {
if (astNode === null) {
return null;
}
switch(astNode.type) {
case 'function':
var innerFunc = gfunc.createFuncInstance(astNode.name, { withDefaultParams: false });
_.each(astNode.params, function(param, index) {
parseTargeRecursive(param, innerFunc, index);
});
innerFunc.updateText();
$scope.functions.push(innerFunc);
break;
case 'series-ref':
if ($scope.segments.length === 0) {
func.params[index] = astNode.value;
}
else {
func.params[index - 1] = astNode.value;
}
break;
case 'string':
case 'number':
if ((index-1) >= func.def.params.length) {
throw { message: 'invalid number of parameters to method ' + func.def.name };
}
if (index === 0) {
func.params[index] = astNode.value;
}
else {
func.params[index - 1] = astNode.value;
}
break;
case 'metric':
if ($scope.segments.length > 0) {
throw { message: 'Multiple metric params not supported, use text editor.' };
}
$scope.segments = _.map(astNode.segments, function(segment) {
2014-08-06 08:16:54 +02:00
return new MetricSegment(segment);
});
}
}
function getSegmentPathUpTo(index) {
2013-12-20 09:50:50 +01:00
var arr = $scope.segments.slice(0, index);
return _.reduce(arr, function(result, segment) {
2014-08-06 08:16:54 +02:00
return result ? (result + "." + segment.value) : segment.value;
}, "");
2013-12-20 09:50:50 +01:00
}
function checkOtherSegments(fromIndex) {
if (fromIndex === 0) {
2014-08-06 08:16:54 +02:00
$scope.segments.push(new MetricSegment('select metric'));
return;
}
var path = getSegmentPathUpTo(fromIndex + 1);
return $scope.datasource.metricFindQuery(path)
2014-01-02 10:38:04 +01:00
.then(function(segments) {
if (segments.length === 0) {
if (path !== '') {
$scope.segments = $scope.segments.splice(0, fromIndex);
$scope.segments.push(new MetricSegment('select metric'));
}
return;
}
2014-01-02 10:38:04 +01:00
if (segments[0].expandable) {
if ($scope.segments.length === fromIndex) {
2014-08-06 08:16:54 +02:00
$scope.segments.push(new MetricSegment('select metric'));
}
else {
return checkOtherSegments(fromIndex + 1);
}
}
})
.then(null, function(err) {
$scope.parserError = err.message || 'Failed to issue metric query';
});
}
function setSegmentFocus(segmentIndex) {
_.each($scope.segments, function(segment, index) {
2013-12-22 14:58:15 +01:00
segment.focus = segmentIndex === index;
});
}
2013-12-22 21:09:02 +01:00
function wrapFunction(target, func) {
return func.render(target);
2013-12-22 21:09:02 +01:00
}
$scope.getAltSegments = function (index) {
2013-12-20 09:50:50 +01:00
$scope.altSegments = [];
var query = index === 0 ? '*' : getSegmentPathUpTo(index) + '.*';
return $scope.datasource.metricFindQuery(query)
.then(function(segments) {
2014-08-06 08:16:54 +02:00
$scope.altSegments = _.map(segments, function(segment) {
return new MetricSegment({ value: segment.text, expandable: segment.expandable });
});
_.each(templateSrv.variables, function(variable) {
2014-08-06 08:16:54 +02:00
$scope.altSegments.unshift(new MetricSegment({
type: 'template',
value: '$' + variable.name + ']]',
expandable: true,
2014-08-06 08:16:54 +02:00
}));
});
2014-08-06 08:16:54 +02:00
$scope.altSegments.unshift(new MetricSegment('*'));
})
.then(null, function(err) {
$scope.parserError = err.message || 'Failed to issue metric query';
2013-12-20 09:50:50 +01:00
});
};
2013-12-17 22:53:31 +01:00
$scope.segmentValueChanged = function (segment, segmentIndex) {
delete $scope.parserError;
if ($scope.functions.length > 0 && $scope.functions[0].def.fake) {
$scope.functions = [];
}
if (segment.expandable) {
return checkOtherSegments(segmentIndex + 1)
.then(function () {
setSegmentFocus(segmentIndex + 1);
$scope.targetChanged();
});
}
else {
$scope.segments = $scope.segments.splice(0, segmentIndex + 1);
}
setSegmentFocus(segmentIndex + 1);
2013-12-20 09:50:50 +01:00
$scope.targetChanged();
};
2013-12-20 08:18:08 +01:00
$scope.targetTextChanged = function() {
parseTarget();
$scope.$parent.get_data();
};
2013-12-20 09:50:50 +01:00
$scope.targetChanged = function() {
if ($scope.parserError) {
return;
}
var oldTarget = $scope.target.target;
2013-12-22 21:09:02 +01:00
var target = getSegmentPathUpTo($scope.segments.length);
$scope.target.target = _.reduce($scope.functions, wrapFunction, target);
if ($scope.target.target !== oldTarget) {
$scope.$parent.get_data();
}
2013-12-20 09:50:50 +01:00
};
2013-12-17 22:53:31 +01:00
2013-12-20 19:24:32 +01:00
$scope.removeFunction = function(func) {
$scope.functions = _.without($scope.functions, func);
2013-12-22 21:09:02 +01:00
$scope.targetChanged();
2013-12-20 19:24:32 +01:00
};
2013-12-22 15:39:25 +01:00
$scope.addFunction = function(funcDef) {
var newFunc = gfunc.createFuncInstance(funcDef, { withDefaultParams: true });
newFunc.added = true;
$scope.functions.push(newFunc);
$scope.moveAliasFuncLast();
$scope.smartlyHandleNewAliasByNode(newFunc);
if ($scope.segments.length === 1 && $scope.segments[0].value === 'select metric') {
$scope.segments = [];
}
if (!newFunc.params.length && newFunc.added) {
$scope.targetChanged();
}
};
$scope.moveAliasFuncLast = function() {
var aliasFunc = _.find($scope.functions, function(func) {
return func.def.name === 'alias' ||
func.def.name === 'aliasByNode' ||
func.def.name === 'aliasByMetric';
});
if (aliasFunc) {
$scope.functions = _.without($scope.functions, aliasFunc);
$scope.functions.push(aliasFunc);
}
};
$scope.smartlyHandleNewAliasByNode = function(func) {
if (func.def.name !== 'aliasByNode') {
return;
}
for(var i = 0; i < $scope.segments.length; i++) {
if ($scope.segments[i].value.indexOf('*') >= 0) {
func.params[0] = i;
func.added = false;
$scope.targetChanged();
return;
}
}
2013-12-20 19:24:32 +01:00
};
$scope.toggleMetricOptions = function() {
$scope.panel.metricOptionsEnabled = !$scope.panel.metricOptionsEnabled;
if (!$scope.panel.metricOptionsEnabled) {
delete $scope.panel.cacheTimeout;
}
};
$scope.duplicate = function() {
var clone = angular.copy($scope.target);
$scope.panel.targets.push(clone);
};
2014-08-06 08:16:54 +02:00
function MetricSegment(options) {
if (options === '*' || options.value === '*') {
this.value = '*';
this.html = $sce.trustAsHtml('<i class="icon-asterisk"><i>');
this.expandable = true;
return;
}
if (_.isString(options)) {
this.value = options;
this.html = $sce.trustAsHtml(this.value);
return;
}
this.value = options.value;
this.type = options.type;
this.expandable = options.expandable;
if (options.type === 'template') {
this.html = $sce.trustAsHtml(options.value);
2014-08-06 08:16:54 +02:00
}
else {
this.html = $sce.trustAsHtml(this.value);
}
}
});
2013-12-20 09:50:50 +01:00
module.directive('focusMe', function($timeout, $parse) {
return {
//scope: true, // optionally create a child scope
link: function(scope, element, attrs) {
var model = $parse(attrs.focusMe);
scope.$watch(model, function(value) {
if(value === true) {
$timeout(function() {
element[0].focus();
});
}
});
}
};
2013-12-20 09:50:50 +01:00
});
});