From f053b416453cf2ed702e7a4b40a769bd9417417d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 30 Sep 2015 14:37:27 +0200 Subject: [PATCH] feat(influxdb editor): more progress --- .../influxdb/partials/query.editor.html | 13 +- .../influxdb/partials/query_part.html | 6 + .../plugins/datasource/influxdb/query_ctrl.js | 42 ++--- .../plugins/datasource/influxdb/query_part.js | 168 ------------------ .../plugins/datasource/influxdb/query_part.ts | 165 +++++++++++++++++ .../datasource/influxdb/query_part_editor.js | 139 +++------------ 6 files changed, 225 insertions(+), 308 deletions(-) create mode 100644 public/app/plugins/datasource/influxdb/partials/query_part.html delete mode 100644 public/app/plugins/datasource/influxdb/query_part.js create mode 100644 public/app/plugins/datasource/influxdb/query_part.ts diff --git a/public/app/plugins/datasource/influxdb/partials/query.editor.html b/public/app/plugins/datasource/influxdb/partials/query.editor.html index 9fb39ad5abe..af40de12302 100644 --- a/public/app/plugins/datasource/influxdb/partials/query.editor.html +++ b/public/app/plugins/datasource/influxdb/partials/query.editor.html @@ -65,22 +65,20 @@
-
+
  • SELECT
  • -
  • - - +
  • +
-
  • -
  • +
@@ -93,8 +91,7 @@ GROUP BY
  • - - +
  • diff --git a/public/app/plugins/datasource/influxdb/partials/query_part.html b/public/app/plugins/datasource/influxdb/partials/query_part.html new file mode 100644 index 00000000000..0a28bee11f7 --- /dev/null +++ b/public/app/plugins/datasource/influxdb/partials/query_part.html @@ -0,0 +1,6 @@ +
    + + +
    + +{{part.def.name}}() diff --git a/public/app/plugins/datasource/influxdb/query_ctrl.js b/public/app/plugins/datasource/influxdb/query_ctrl.js index 247205ab39d..d4c4a7f6181 100644 --- a/public/app/plugins/datasource/influxdb/query_ctrl.js +++ b/public/app/plugins/datasource/influxdb/query_ctrl.js @@ -10,7 +10,7 @@ function (angular, _, InfluxQueryBuilder, queryPart) { var module = angular.module('grafana.controllers'); - module.controller('InfluxQueryCtrl', function($scope, $timeout, $sce, templateSrv, $q, uiSegmentSrv) { + module.controller('InfluxQueryCtrl', function($scope, templateSrv, $q, uiSegmentSrv) { $scope.init = function() { if (!$scope.target) { return; } @@ -19,25 +19,14 @@ function (angular, _, InfluxQueryBuilder, queryPart) { target.tags = target.tags || []; target.groupBy = target.groupBy || [{type: 'time', interval: 'auto'}]; target.fields = target.fields || [{name: 'value'}]; - target.select = target.select || [[{type: 'field', params: ['value']}]]; - target.select[0] = [ - {type: 'field', params: ['value']}, - {type: 'mean', params: []}, - {type: 'derivate', params: ['10s']}, - {type: 'math', params: ['/ 100']}, - {type: 'alias', params: ['google']}, - ]; + target.select = target.select || [[ + {name: 'field', params: ['value']}, + {name: 'mean', params: []}, + ]]; - $scope.select = _.map(target.select, function(parts) { - return _.map(parts, function(part) { - var partModel = queryPart.create(part.type); - partModel.params = part.params; - partModel.updateText(); - return partModel; - }); - }); + $scope.updateSelectParts(); - $scope.func = queryPart.create('time', { withDefaultParams: true }); + $scope.groupByParts = queryPart.create({name: 'time', params:['$interval']}); $scope.queryBuilder = new InfluxQueryBuilder(target); @@ -89,14 +78,27 @@ function (angular, _, InfluxQueryBuilder, queryPart) { }; $scope.addSelect = function() { - $scope.target.fields.push({name: "select field", func: 'mean'}); + $scope.target.select.push([ + {name: 'field', params: ['value']}, + {name: 'mean', params: []}, + ]); + $scope.updateSelectParts(); }; $scope.removeSelect = function(index) { - $scope.target.fields.splice(index, 1); + $scope.target.select.splice(index, 1); + $scope.updateSelectParts(); $scope.get_data(); }; + $scope.updateSelectParts = function() { + $scope.selectParts = _.map($scope.target.select, function(parts) { + return _.map(parts, function(part) { + return queryPart.create(part); + }); + }); + }; + $scope.changeFunction = function(func) { $scope.target.function = func; $scope.$parent.get_data(); diff --git a/public/app/plugins/datasource/influxdb/query_part.js b/public/app/plugins/datasource/influxdb/query_part.js deleted file mode 100644 index 37433d54951..00000000000 --- a/public/app/plugins/datasource/influxdb/query_part.js +++ /dev/null @@ -1,168 +0,0 @@ -define([ - 'lodash', - 'jquery' -], -function (_, $) { - 'use strict'; - - var index = []; - var categories = { - Combine: [], - Transform: [], - Calculate: [], - Filter: [], - Special: [] - }; - - function addFuncDef(funcDef) { - funcDef.params = funcDef.params || []; - funcDef.defaultParams = funcDef.defaultParams || []; - - if (funcDef.category) { - funcDef.category.push(funcDef); - } - index[funcDef.name] = funcDef; - index[funcDef.shortName || funcDef.name] = funcDef; - } - - addFuncDef({ - name: 'field', - category: categories.Transform, - params: [{type: 'field'}], - defaultParams: ['value'], - }); - - addFuncDef({ - name: 'mean', - category: categories.Transform, - params: [], - defaultParams: [], - }); - - addFuncDef({ - name: 'derivate', - category: categories.Transform, - params: [{ name: "rate", type: "interval", options: ['1s', '10s', '1m', '5min', '10m', '15m', '1h'] }], - defaultParams: ['10s'], - }); - - addFuncDef({ - name: 'time', - category: categories.Transform, - params: [{ name: "rate", type: "interval", options: ['$interval', '1s', '10s', '1m', '5min', '10m', '15m', '1h'] }], - defaultParams: ['$interval'], - }); - - addFuncDef({ - name: 'math', - category: categories.Transform, - params: [{ name: "expr", type: "string"}], - defaultParams: [' / 100'], - }); - - addFuncDef({ - name: 'alias', - category: categories.Transform, - params: [{ name: "name", type: "string"}], - defaultParams: ['alias'], - }); - - _.each(categories, function(funcList, catName) { - categories[catName] = _.sortBy(funcList, 'name'); - }); - - function FuncInstance(funcDef, options) { - this.def = funcDef; - this.params = []; - - if (options && options.withDefaultParams) { - this.params = funcDef.defaultParams.slice(0); - } - - this.updateText(); - } - - FuncInstance.prototype.render = function(metricExp) { - var str = this.def.name + '('; - var parameters = _.map(this.params, function(value, index) { - - var paramType = this.def.params[index].type; - if (paramType === 'int' || paramType === 'value_or_series' || paramType === 'boolean') { - return value; - } - else if (paramType === 'int_or_interval' && $.isNumeric(value)) { - return value; - } - - return "'" + value + "'"; - - }, this); - - if (metricExp) { - parameters.unshift(metricExp); - } - - return str + parameters.join(', ') + ')'; - }; - - FuncInstance.prototype._hasMultipleParamsInString = function(strValue, index) { - if (strValue.indexOf(',') === -1) { - return false; - } - - return this.def.params[index + 1] && this.def.params[index + 1].optional; - }; - - FuncInstance.prototype.updateParam = function(strValue, index) { - // handle optional parameters - // if string contains ',' and next param is optional, split and update both - if (this._hasMultipleParamsInString(strValue, index)) { - _.each(strValue.split(','), function(partVal, idx) { - this.updateParam(partVal.trim(), idx); - }, this); - return; - } - - if (strValue === '' && this.def.params[index].optional) { - this.params.splice(index, 1); - } - else { - this.params[index] = strValue; - } - - this.updateText(); - }; - - FuncInstance.prototype.updateText = function () { - if (this.params.length === 0) { - this.text = this.def.name + '()'; - return; - } - - var text = this.def.name + '('; - text += this.params.join(', '); - text += ')'; - this.text = text; - }; - - return { - create: function(funcDef, options) { - if (_.isString(funcDef)) { - if (!index[funcDef]) { - throw { message: 'Method not found ' + name }; - } - funcDef = index[funcDef]; - } - return new FuncInstance(funcDef, options); - }, - - getFuncDef: function(name) { - return index[name]; - }, - - getCategories: function() { - return categories; - } - }; - -}); diff --git a/public/app/plugins/datasource/influxdb/query_part.ts b/public/app/plugins/datasource/influxdb/query_part.ts new file mode 100644 index 00000000000..7e5dfff3277 --- /dev/null +++ b/public/app/plugins/datasource/influxdb/query_part.ts @@ -0,0 +1,165 @@ +/// + +import _ = require('lodash'); + +var index = []; +var categories = { + Combine: [], + Transform: [], + Calculate: [], + Filter: [], + Special: [] +}; + +class QueryPartDef { + name: string; + params: any[]; + defaultParams: any[]; + + constructor(options: any) { + this.name = options.name; + this.params = options.params; + this.defaultParams = options.defaultParams; + } + + static register(options: any) { + index[options.name] = new QueryPartDef(options); + } +} + +QueryPartDef.register({ + name: 'field', + category: categories.Transform, + params: [{type: 'field'}], + defaultParams: ['value'], +}); + +QueryPartDef.register({ + name: 'mean', + category: categories.Transform, + params: [], + defaultParams: [], +}); + +QueryPartDef.register({ + name: 'derivate', + category: categories.Transform, + params: [{ name: "rate", type: "interval", options: ['1s', '10s', '1m', '5min', '10m', '15m', '1h'] }], + defaultParams: ['10s'], +}); + +QueryPartDef.register({ + name: 'time', + category: categories.Transform, + params: [{ name: "rate", type: "interval", options: ['$interval', '1s', '10s', '1m', '5min', '10m', '15m', '1h'] }], + defaultParams: ['$interval'], +}); + +QueryPartDef.register({ + name: 'math', + category: categories.Transform, + params: [{ name: "expr", type: "string"}], + defaultParams: [' / 100'], +}); + +QueryPartDef.register({ + name: 'alias', + category: categories.Transform, + params: [{ name: "name", type: "string"}], + defaultParams: ['alias'], +}); + +class QueryPart { + part: any; + def: QueryPartDef; + params: any[]; + text: string; + + constructor(part: any) { + this.part = part; + this.def = index[part.name]; + if (!this.def) { + throw {message: 'Could not find query part ' + part.name}; + } + + this.params = part.params || _.clone(this.def.defaultParams); + } + + render(innerExpr: string) { + var str = this.def.name + '('; + var parameters = _.map(this.params, (value, index) => { + + var paramType = this.def.params[index].type; + if (paramType === 'int' || paramType === 'value_or_series' || paramType === 'boolean') { + return value; + } + else if (paramType === 'int_or_interval' && _.isNumber(value)) { + return value; + } + + return "'" + value + "'"; + + }); + + if (innerExpr) { + parameters.unshift(innerExpr); + } + + return str + parameters.join(', ') + ')'; + } + + hasMultipleParamsInString (strValue, index) { + if (strValue.indexOf(',') === -1) { + return false; + } + + return this.def.params[index + 1] && this.def.params[index + 1].optional; + } + + updateParam (strValue, index) { + // handle optional parameters + // if string contains ',' and next param is optional, split and update both + if (this.hasMultipleParamsInString(strValue, index)) { + _.each(strValue.split(','), function(partVal: string, idx) { + this.updateParam(partVal.trim(), idx); + }, this); + return; + } + + if (strValue === '' && this.def.params[index].optional) { + this.params.splice(index, 1); + } + else { + this.params[index] = strValue; + } + + this.part.params = this.params; + this.updateText(); + } + + updateText() { + if (this.params.length === 0) { + this.text = this.def.name + '()'; + return; + } + + var text = this.def.name + '('; + text += this.params.join(', '); + text += ')'; + this.text = text; + } +} + +export = { + create: function(part): any { + return new QueryPart(part); + }, + + getFuncDef: function(name) { + return index[name]; + }, + + getCategories: function() { + return categories; + } +}; diff --git a/public/app/plugins/datasource/influxdb/query_part_editor.js b/public/app/plugins/datasource/influxdb/query_part_editor.js index fd0dc3e1a6b..6cfcda5f4e7 100644 --- a/public/app/plugins/datasource/influxdb/query_part_editor.js +++ b/public/app/plugins/datasource/influxdb/query_part_editor.js @@ -10,33 +10,26 @@ function (angular, _, $) { .module('grafana.directives') .directive('influxQueryPartEditor', function($compile, templateSrv) { - var funcSpanTemplate = '{{func.def.name}}('; var paramTemplate = ''; - - var funcControlsTemplate = - '
    ' + - '' + - '' + - '
    '; - return { - restrict: 'A', + restrict: 'E', + templateUrl: 'app/plugins/datasource/influxdb/partials/query_part.html', + scope: { + part: "=" + }, link: function postLink($scope, elem) { - var $funcLink = $(funcSpanTemplate); - var $funcControls = $(funcControlsTemplate); - var func = $scope.func; - var funcDef = func.def; - var scheduledRelink = false; - var paramCountAtLink = 0; + var part = $scope.part; + var partDef = part.def; + var $paramsContainer = elem.find('.query-part-parameters'); + var $controlsContainer = elem.find('.tight-form-func-controls'); function clickFuncParam(paramIndex) { /*jshint validthis:true */ - var $link = $(this); var $input = $link.next(); - $input.val(func.params[paramIndex]); + $input.val(part.params[paramIndex]); $input.css('width', ($link.width() + 16) + 'px'); $link.hide(); @@ -51,32 +44,16 @@ function (angular, _, $) { } } - function scheduledRelinkIfNeeded() { - if (paramCountAtLink === func.params.length) { - return; - } - - if (!scheduledRelink) { - scheduledRelink = true; - setTimeout(function() { - relink(); - scheduledRelink = false; - }, 200); - } - } - function inputBlur(paramIndex) { /*jshint validthis:true */ var $input = $(this); var $link = $input.prev(); var newValue = $input.val(); - if (newValue !== '' || func.def.params[paramIndex].optional) { + if (newValue !== '' || part.def.params[paramIndex].optional) { $link.html(templateSrv.highlightVariablesAsHtml(newValue)); - func.updateParam($input.val(), paramIndex); - scheduledRelinkIfNeeded(); - + part.updateParam($input.val(), paramIndex); $scope.$apply($scope.targetChanged); } @@ -99,8 +76,8 @@ function (angular, _, $) { function addTypeahead($input, paramIndex) { $input.attr('data-provide', 'typeahead'); - var options = funcDef.params[paramIndex].options; - if (funcDef.params[paramIndex].type === 'int') { + var options = partDef.params[paramIndex].options; + if (partDef.params[paramIndex].type === 'int') { options = _.map(options, function(val) { return val.toString(); }); } @@ -123,114 +100,52 @@ function (angular, _, $) { }; } - function toggleFuncControls() { + $scope.toggleControls = function() { var targetDiv = elem.closest('.tight-form'); if (elem.hasClass('show-function-controls')) { elem.removeClass('show-function-controls'); targetDiv.removeClass('has-open-function'); - $funcControls.hide(); + $controlsContainer.hide(); return; } elem.addClass('show-function-controls'); targetDiv.addClass('has-open-function'); - - $funcControls.show(); - } + $controlsContainer.show(); + }; function addElementsAndCompile() { - $funcControls.appendTo(elem); - $funcLink.appendTo(elem); - - _.each(funcDef.params, function(param, index) { - if (param.optional && func.params.length <= index) { + _.each(partDef.params, function(param, index) { + if (param.optional && part.params.length <= index) { return; } if (index > 0) { - $(', ').appendTo(elem); + $(', ').appendTo($paramsContainer); } - var paramValue = templateSrv.highlightVariablesAsHtml(func.params[index]); - var $paramLink = $('' + paramValue + ''); + var paramValue = templateSrv.highlightVariablesAsHtml(part.params[index]); + var $paramLink = $('' + paramValue + ''); var $input = $(paramTemplate); - paramCountAtLink++; - - $paramLink.appendTo(elem); - $input.appendTo(elem); + $paramLink.appendTo($paramsContainer); + $input.appendTo($paramsContainer); $input.blur(_.partial(inputBlur, index)); $input.keyup(inputKeyDown); $input.keypress(_.partial(inputKeyPress, index)); $paramLink.click(_.partial(clickFuncParam, index)); - if (funcDef.params[index].options) { + if (partDef.params[index].options) { addTypeahead($input, index); } - - }); - - $(')').appendTo(elem); - - $compile(elem.contents())($scope); - } - - function ifJustAddedFocusFistParam() { - if ($scope.func.added) { - $scope.func.added = false; - setTimeout(function() { - elem.find('.graphite-func-param-link').first().click(); - }, 10); - } - } - - function registerFuncControlsToggle() { - $funcLink.click(toggleFuncControls); - } - - function registerFuncControlsActions() { - $funcControls.click(function(e) { - var $target = $(e.target); - if ($target.hasClass('fa-remove')) { - toggleFuncControls(); - $scope.$apply(function() { - $scope.removeFunction($scope.func); - }); - return; - } - - if ($target.hasClass('fa-arrow-left')) { - $scope.$apply(function() { - _.move($scope.functions, $scope.$index, $scope.$index - 1); - $scope.targetChanged(); - }); - return; - } - - if ($target.hasClass('fa-arrow-right')) { - $scope.$apply(function() { - _.move($scope.functions, $scope.$index, $scope.$index + 1); - $scope.targetChanged(); - }); - return; - } - - if ($target.hasClass('fa-question-circle')) { - window.open("http://graphite.readthedocs.org/en/latest/functions.html#graphite.render.functions." + funcDef.name,'_blank'); - return; - } }); } function relink() { - elem.children().remove(); - + $paramsContainer.empty(); addElementsAndCompile(); - ifJustAddedFocusFistParam(); - registerFuncControlsToggle(); - registerFuncControlsActions(); } relink();