diff --git a/public/app/core/components/query_part/query_part.ts b/public/app/core/components/query_part/query_part.ts
new file mode 100644
index 00000000000..90724f65d2d
--- /dev/null
+++ b/public/app/core/components/query_part/query_part.ts
@@ -0,0 +1,123 @@
+///
+
+import _ from 'lodash';
+
+export class QueryPartDef {
+ type: string;
+ params: any[];
+ defaultParams: any[];
+ renderer: any;
+ category: any;
+ addStrategy: any;
+
+ constructor(options: any) {
+ this.type = options.type;
+ this.params = options.params;
+ this.defaultParams = options.defaultParams;
+ this.renderer = options.renderer;
+ this.category = options.category;
+ this.addStrategy = options.addStrategy;
+ }
+}
+
+export class QueryPart {
+ part: any;
+ def: QueryPartDef;
+ params: any[];
+ text: string;
+
+ constructor(part: any, def: any) {
+ this.part = part;
+ this.def = def;
+ if (!this.def) {
+ throw {message: 'Could not find query part ' + part.type};
+ }
+
+ part.params = part.params || _.clone(this.def.defaultParams);
+ this.params = part.params;
+ this.updateText();
+ }
+
+ render(innerExpr: string) {
+ return this.def.renderer(this, innerExpr);
+ }
+
+ 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.type + '()';
+ return;
+ }
+
+ var text = this.def.type + '(';
+ text += this.params.join(', ');
+ text += ')';
+ this.text = text;
+ }
+}
+
+export function functionRenderer(part, innerExpr) {
+ var str = part.def.type + '(';
+ var parameters = _.map(part.params, (value, index) => {
+ var paramType = part.def.params[index];
+ if (paramType.type === 'time') {
+ if (value === 'auto') {
+ value = '$interval';
+ }
+ }
+ if (paramType.quote === 'single') {
+ return "'" + value + "'";
+ } else if (paramType.quote === 'double') {
+ return '"' + value + '"';
+ }
+
+ return value;
+ });
+
+ if (innerExpr) {
+ parameters.unshift(innerExpr);
+ }
+ return str + parameters.join(', ') + ')';
+}
+
+
+export function suffixRenderer(part, innerExpr) {
+ return innerExpr + ' ' + part.params[0];
+}
+
+export function identityRenderer(part, innerExpr) {
+ return part.params[0];
+}
+
+export function quotedIdentityRenderer(part, innerExpr) {
+ return '"' + part.params[0] + '"';
+}
+
+
diff --git a/public/app/core/components/query_part/query_part_editor.ts b/public/app/core/components/query_part/query_part_editor.ts
new file mode 100644
index 00000000000..f9122ee283b
--- /dev/null
+++ b/public/app/core/components/query_part/query_part_editor.ts
@@ -0,0 +1,183 @@
+///
+
+import _ from 'lodash';
+import $ from 'jquery';
+import coreModule from 'app/core/core_module';
+
+var template = `
+
diff --git a/public/app/plugins/datasource/influxdb/partials/query_part.html b/public/app/plugins/datasource/influxdb/partials/query_part.html
deleted file mode 100644
index 478edfe5c29..00000000000
--- a/public/app/plugins/datasource/influxdb/partials/query_part.html
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
{{part.def.type}}()
diff --git a/public/app/plugins/datasource/influxdb/query_ctrl.ts b/public/app/plugins/datasource/influxdb/query_ctrl.ts
index 8d6a03fc4a1..69895e53c25 100644
--- a/public/app/plugins/datasource/influxdb/query_ctrl.ts
+++ b/public/app/plugins/datasource/influxdb/query_ctrl.ts
@@ -1,8 +1,5 @@
///
-import './query_part_editor';
-import './query_part_editor';
-
import angular from 'angular';
import _ from 'lodash';
import InfluxQueryBuilder from './query_builder';
diff --git a/public/app/plugins/datasource/influxdb/query_part.ts b/public/app/plugins/datasource/influxdb/query_part.ts
index 130174c3084..0081481437d 100644
--- a/public/app/plugins/datasource/influxdb/query_part.ts
+++ b/public/app/plugins/datasource/influxdb/query_part.ts
@@ -1,6 +1,14 @@
///
import _ from 'lodash';
+import {
+ QueryPartDef,
+ QueryPart,
+ functionRenderer,
+ suffixRenderer,
+ identityRenderer,
+ quotedIdentityRenderer,
+} from 'app/core/components/query_part/query_part';
var index = [];
var categories = {
@@ -12,71 +20,26 @@ var categories = {
Fields: [],
};
+function createPart(part): any {
+ var def = index[part.type];
+ if (!def) {
+ throw {message: 'Could not find query part ' + part.type};
+ }
+
+ return new QueryPart(part, def);
+};
+
+function register(options: any) {
+ index[options.type] = new QueryPartDef(options);
+ options.category.push(index[options.type]);
+}
+
var groupByTimeFunctions = [];
-class QueryPartDef {
- type: string;
- params: any[];
- defaultParams: any[];
- renderer: any;
- category: any;
- addStrategy: any;
-
- constructor(options: any) {
- this.type = options.type;
- this.params = options.params;
- this.defaultParams = options.defaultParams;
- this.renderer = options.renderer;
- this.category = options.category;
- this.addStrategy = options.addStrategy;
- }
-
- static register(options: any) {
- index[options.type] = new QueryPartDef(options);
- options.category.push(index[options.type]);
- }
-}
-
-function functionRenderer(part, innerExpr) {
- var str = part.def.type + '(';
- var parameters = _.map(part.params, (value, index) => {
- var paramType = part.def.params[index];
- if (paramType.type === 'time') {
- if (value === 'auto') {
- value = '$interval';
- }
- }
- if (paramType.quote === 'single') {
- return "'" + value + "'";
- } else if (paramType.quote === 'double') {
- return '"' + value + '"';
- }
-
- return value;
- });
-
- if (innerExpr) {
- parameters.unshift(innerExpr);
- }
- return str + parameters.join(', ') + ')';
-}
-
function aliasRenderer(part, innerExpr) {
return innerExpr + ' AS ' + '"' + part.params[0] + '"';
}
-function suffixRenderer(part, innerExpr) {
- return innerExpr + ' ' + part.params[0];
-}
-
-function identityRenderer(part, innerExpr) {
- return part.params[0];
-}
-
-function quotedIdentityRenderer(part, innerExpr) {
- return '"' + part.params[0] + '"';
-}
-
function fieldRenderer(part, innerExpr) {
if (part.params[0] === '*') {
return '*';
@@ -149,13 +112,13 @@ function addAliasStrategy(selectParts, partModel) {
function addFieldStrategy(selectParts, partModel, query) {
// copy all parts
var parts = _.map(selectParts, function(part: any) {
- return new QueryPart({type: part.def.type, params: _.clone(part.params)});
+ return createPart({type: part.def.type, params: _.clone(part.params)});
});
query.selectModels.push(parts);
}
-QueryPartDef.register({
+register({
type: 'field',
addStrategy: addFieldStrategy,
category: categories.Fields,
@@ -165,7 +128,7 @@ QueryPartDef.register({
});
// Aggregations
-QueryPartDef.register({
+register({
type: 'count',
addStrategy: replaceAggregationAddStrategy,
category: categories.Aggregations,
@@ -174,7 +137,7 @@ QueryPartDef.register({
renderer: functionRenderer,
});
-QueryPartDef.register({
+register({
type: 'distinct',
addStrategy: replaceAggregationAddStrategy,
category: categories.Aggregations,
@@ -183,7 +146,7 @@ QueryPartDef.register({
renderer: functionRenderer,
});
-QueryPartDef.register({
+register({
type: 'integral',
addStrategy: replaceAggregationAddStrategy,
category: categories.Aggregations,
@@ -192,7 +155,7 @@ QueryPartDef.register({
renderer: functionRenderer,
});
-QueryPartDef.register({
+register({
type: 'mean',
addStrategy: replaceAggregationAddStrategy,
category: categories.Aggregations,
@@ -201,7 +164,7 @@ QueryPartDef.register({
renderer: functionRenderer,
});
-QueryPartDef.register({
+register({
type: 'median',
addStrategy: replaceAggregationAddStrategy,
category: categories.Aggregations,
@@ -210,7 +173,7 @@ QueryPartDef.register({
renderer: functionRenderer,
});
-QueryPartDef.register({
+register({
type: 'sum',
addStrategy: replaceAggregationAddStrategy,
category: categories.Aggregations,
@@ -221,7 +184,7 @@ QueryPartDef.register({
// transformations
-QueryPartDef.register({
+register({
type: 'derivative',
addStrategy: addTransformationStrategy,
category: categories.Transformations,
@@ -230,7 +193,7 @@ QueryPartDef.register({
renderer: functionRenderer,
});
-QueryPartDef.register({
+register({
type: 'spread',
addStrategy: addTransformationStrategy,
category: categories.Transformations,
@@ -239,7 +202,7 @@ QueryPartDef.register({
renderer: functionRenderer,
});
-QueryPartDef.register({
+register({
type: 'non_negative_derivative',
addStrategy: addTransformationStrategy,
category: categories.Transformations,
@@ -248,7 +211,7 @@ QueryPartDef.register({
renderer: functionRenderer,
});
-QueryPartDef.register({
+register({
type: 'difference',
addStrategy: addTransformationStrategy,
category: categories.Transformations,
@@ -257,7 +220,7 @@ QueryPartDef.register({
renderer: functionRenderer,
});
-QueryPartDef.register({
+register({
type: 'moving_average',
addStrategy: addTransformationStrategy,
category: categories.Transformations,
@@ -266,7 +229,7 @@ QueryPartDef.register({
renderer: functionRenderer,
});
-QueryPartDef.register({
+register({
type: 'stddev',
addStrategy: addTransformationStrategy,
category: categories.Transformations,
@@ -275,7 +238,7 @@ QueryPartDef.register({
renderer: functionRenderer,
});
-QueryPartDef.register({
+register({
type: 'time',
category: groupByTimeFunctions,
params: [{ name: "interval", type: "time", options: ['auto', '1s', '10s', '1m', '5m', '10m', '15m', '1h'] }],
@@ -283,7 +246,7 @@ QueryPartDef.register({
renderer: functionRenderer,
});
-QueryPartDef.register({
+register({
type: 'fill',
category: groupByTimeFunctions,
params: [{ name: "fill", type: "string", options: ['none', 'null', '0', 'previous'] }],
@@ -292,7 +255,7 @@ QueryPartDef.register({
});
// Selectors
-QueryPartDef.register({
+register({
type: 'bottom',
addStrategy: replaceAggregationAddStrategy,
category: categories.Selectors,
@@ -301,7 +264,7 @@ QueryPartDef.register({
renderer: functionRenderer,
});
-QueryPartDef.register({
+register({
type: 'first',
addStrategy: replaceAggregationAddStrategy,
category: categories.Selectors,
@@ -310,7 +273,7 @@ QueryPartDef.register({
renderer: functionRenderer,
});
-QueryPartDef.register({
+register({
type: 'last',
addStrategy: replaceAggregationAddStrategy,
category: categories.Selectors,
@@ -319,7 +282,7 @@ QueryPartDef.register({
renderer: functionRenderer,
});
-QueryPartDef.register({
+register({
type: 'max',
addStrategy: replaceAggregationAddStrategy,
category: categories.Selectors,
@@ -328,7 +291,7 @@ QueryPartDef.register({
renderer: functionRenderer,
});
-QueryPartDef.register({
+register({
type: 'min',
addStrategy: replaceAggregationAddStrategy,
category: categories.Selectors,
@@ -337,7 +300,7 @@ QueryPartDef.register({
renderer: functionRenderer,
});
-QueryPartDef.register({
+register({
type: 'percentile',
addStrategy: replaceAggregationAddStrategy,
category: categories.Selectors,
@@ -346,7 +309,7 @@ QueryPartDef.register({
renderer: functionRenderer,
});
-QueryPartDef.register({
+register({
type: 'top',
addStrategy: replaceAggregationAddStrategy,
category: categories.Selectors,
@@ -355,7 +318,7 @@ QueryPartDef.register({
renderer: functionRenderer,
});
-QueryPartDef.register({
+register({
type: 'tag',
category: groupByTimeFunctions,
params: [{name: 'tag', type: 'string', dynamicLookup: true}],
@@ -363,7 +326,7 @@ QueryPartDef.register({
renderer: fieldRenderer,
});
-QueryPartDef.register({
+register({
type: 'math',
addStrategy: addMathStrategy,
category: categories.Math,
@@ -372,7 +335,7 @@ QueryPartDef.register({
renderer: suffixRenderer,
});
-QueryPartDef.register({
+register({
type: 'alias',
addStrategy: addAliasStrategy,
category: categories.Aliasing,
@@ -382,74 +345,9 @@ QueryPartDef.register({
renderer: aliasRenderer,
});
-class QueryPart {
- part: any;
- def: QueryPartDef;
- params: any[];
- text: string;
-
- constructor(part: any) {
- this.part = part;
- this.def = index[part.type];
- if (!this.def) {
- throw {message: 'Could not find query part ' + part.type};
- }
-
- part.params = part.params || _.clone(this.def.defaultParams);
- this.params = part.params;
- this.updateText();
- }
-
- render(innerExpr: string) {
- return this.def.renderer(this, innerExpr);
- }
-
- 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.type + '()';
- return;
- }
-
- var text = this.def.type + '(';
- text += this.params.join(', ');
- text += ')';
- this.text = text;
- }
-}
export default {
- create: function(part): any {
- return new QueryPart(part);
- },
-
+ create: createPart,
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
deleted file mode 100644
index 4e044eca304..00000000000
--- a/public/app/plugins/datasource/influxdb/query_part_editor.js
+++ /dev/null
@@ -1,178 +0,0 @@
-define([
- 'angular',
- 'lodash',
- 'jquery',
-],
-function (angular, _, $) {
- 'use strict';
-
- angular
- .module('grafana.directives')
- .directive('influxQueryPartEditor', function($compile, templateSrv) {
-
- var paramTemplate = '
';
- return {
- restrict: 'E',
- templateUrl: 'public/app/plugins/datasource/influxdb/partials/query_part.html',
- scope: {
- part: "=",
- removeAction: "&",
- partUpdated: "&",
- getOptions: "&",
- },
- link: function postLink($scope, elem) {
- 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(part.params[paramIndex]);
- $input.css('width', ($link.width() + 16) + 'px');
-
- $link.hide();
- $input.show();
- $input.focus();
- $input.select();
-
- var typeahead = $input.data('typeahead');
- if (typeahead) {
- $input.val('');
- typeahead.lookup();
- }
- }
-
- function inputBlur(paramIndex) {
- /*jshint validthis:true */
- var $input = $(this);
- var $link = $input.prev();
- var newValue = $input.val();
-
- if (newValue !== '' || part.def.params[paramIndex].optional) {
- $link.html(templateSrv.highlightVariablesAsHtml(newValue));
-
- part.updateParam($input.val(), paramIndex);
- $scope.$apply($scope.partUpdated);
- }
-
- $input.hide();
- $link.show();
- }
-
- function inputKeyPress(paramIndex, e) {
- /*jshint validthis:true */
- if(e.which === 13) {
- inputBlur.call(this, paramIndex);
- }
- }
-
- function inputKeyDown() {
- /*jshint validthis:true */
- this.style.width = (3 + this.value.length) * 8 + 'px';
- }
-
- function addTypeahead($input, param, paramIndex) {
- if (!param.options && !param.dynamicLookup) {
- return;
- }
-
- var typeaheadSource = function (query, callback) {
- if (param.options) { return param.options; }
-
- $scope.$apply(function() {
- $scope.getOptions().then(function(result) {
- var dynamicOptions = _.map(result, function(op) { return op.value; });
- callback(dynamicOptions);
- });
- });
- };
-
- $input.attr('data-provide', 'typeahead');
- var options = param.options;
- if (param.type === 'int') {
- options = _.map(options, function(val) { return val.toString(); });
- }
-
- $input.typeahead({
- source: typeaheadSource,
- minLength: 0,
- items: 1000,
- updater: function (value) {
- setTimeout(function() {
- inputBlur.call($input[0], paramIndex);
- }, 0);
- return value;
- }
- });
-
- var typeahead = $input.data('typeahead');
- typeahead.lookup = function () {
- this.query = this.$element.val() || '';
- var items = this.source(this.query, $.proxy(this.process, this));
- return items ? this.process(items) : items;
- };
- }
-
- $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');
- $controlsContainer.hide();
- return;
- }
-
- elem.addClass('show-function-controls');
- targetDiv.addClass('has-open-function');
- $controlsContainer.show();
- };
-
- $scope.removeActionInternal = function() {
- $scope.toggleControls();
- $scope.removeAction();
- };
-
- function addElementsAndCompile() {
- _.each(partDef.params, function(param, index) {
- if (param.optional && part.params.length <= index) {
- return;
- }
-
- if (index > 0) {
- $('
, ').appendTo($paramsContainer);
- }
-
- var paramValue = templateSrv.highlightVariablesAsHtml(part.params[index]);
- var $paramLink = $('
' + paramValue + '');
- var $input = $(paramTemplate);
-
- $paramLink.appendTo($paramsContainer);
- $input.appendTo($paramsContainer);
-
- $input.blur(_.partial(inputBlur, index));
- $input.keyup(inputKeyDown);
- $input.keypress(_.partial(inputKeyPress, index));
- $paramLink.click(_.partial(clickFuncParam, index));
-
- addTypeahead($input, param, index);
- });
- }
-
- function relink() {
- $paramsContainer.empty();
- addElementsAndCompile();
- }
-
- relink();
- }
- };
-
- });
-
-});