Skip to content

Commit 79986e5

Browse files
committed
Merge branch 'query-part-refactor'
Conflicts: public/app/plugins/datasource/influxdb/query_part.ts
2 parents 1d8fdc0 + b8aa8b3 commit 79986e5

File tree

8 files changed

+358
-338
lines changed

8 files changed

+358
-338
lines changed
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
///<reference path="../../../headers/common.d.ts" />
2+
3+
import _ from 'lodash';
4+
5+
export class QueryPartDef {
6+
type: string;
7+
params: any[];
8+
defaultParams: any[];
9+
renderer: any;
10+
category: any;
11+
addStrategy: any;
12+
13+
constructor(options: any) {
14+
this.type = options.type;
15+
this.params = options.params;
16+
this.defaultParams = options.defaultParams;
17+
this.renderer = options.renderer;
18+
this.category = options.category;
19+
this.addStrategy = options.addStrategy;
20+
}
21+
}
22+
23+
export class QueryPart {
24+
part: any;
25+
def: QueryPartDef;
26+
params: any[];
27+
text: string;
28+
29+
constructor(part: any, def: any) {
30+
this.part = part;
31+
this.def = def;
32+
if (!this.def) {
33+
throw {message: 'Could not find query part ' + part.type};
34+
}
35+
36+
part.params = part.params || _.clone(this.def.defaultParams);
37+
this.params = part.params;
38+
this.updateText();
39+
}
40+
41+
render(innerExpr: string) {
42+
return this.def.renderer(this, innerExpr);
43+
}
44+
45+
hasMultipleParamsInString (strValue, index) {
46+
if (strValue.indexOf(',') === -1) {
47+
return false;
48+
}
49+
50+
return this.def.params[index + 1] && this.def.params[index + 1].optional;
51+
}
52+
53+
updateParam (strValue, index) {
54+
// handle optional parameters
55+
// if string contains ',' and next param is optional, split and update both
56+
if (this.hasMultipleParamsInString(strValue, index)) {
57+
_.each(strValue.split(','), function(partVal: string, idx) {
58+
this.updateParam(partVal.trim(), idx);
59+
}, this);
60+
return;
61+
}
62+
63+
if (strValue === '' && this.def.params[index].optional) {
64+
this.params.splice(index, 1);
65+
} else {
66+
this.params[index] = strValue;
67+
}
68+
69+
this.part.params = this.params;
70+
this.updateText();
71+
}
72+
73+
updateText() {
74+
if (this.params.length === 0) {
75+
this.text = this.def.type + '()';
76+
return;
77+
}
78+
79+
var text = this.def.type + '(';
80+
text += this.params.join(', ');
81+
text += ')';
82+
this.text = text;
83+
}
84+
}
85+
86+
export function functionRenderer(part, innerExpr) {
87+
var str = part.def.type + '(';
88+
var parameters = _.map(part.params, (value, index) => {
89+
var paramType = part.def.params[index];
90+
if (paramType.type === 'time') {
91+
if (value === 'auto') {
92+
value = '$interval';
93+
}
94+
}
95+
if (paramType.quote === 'single') {
96+
return "'" + value + "'";
97+
} else if (paramType.quote === 'double') {
98+
return '"' + value + '"';
99+
}
100+
101+
return value;
102+
});
103+
104+
if (innerExpr) {
105+
parameters.unshift(innerExpr);
106+
}
107+
return str + parameters.join(', ') + ')';
108+
}
109+
110+
111+
export function suffixRenderer(part, innerExpr) {
112+
return innerExpr + ' ' + part.params[0];
113+
}
114+
115+
export function identityRenderer(part, innerExpr) {
116+
return part.params[0];
117+
}
118+
119+
export function quotedIdentityRenderer(part, innerExpr) {
120+
return '"' + part.params[0] + '"';
121+
}
122+
123+
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
///<reference path="../../../headers/common.d.ts" />
2+
3+
import _ from 'lodash';
4+
import $ from 'jquery';
5+
import coreModule from 'app/core/core_module';
6+
7+
var template = `
8+
<div class="tight-form-func-controls">
9+
<span class="pointer fa fa-remove" ng-click="removeActionInternal()"></span>
10+
</div>
11+
12+
<a ng-click="toggleControls()" class="query-part-name">{{part.def.type}}</a>
13+
<span>(</span><span class="query-part-parameters"></span><span>)</span>
14+
`;
15+
16+
/** @ngInject */
17+
export function queryPartEditorDirective($compile, templateSrv) {
18+
19+
var paramTemplate = '<input type="text" style="display:none"' +
20+
' class="input-mini tight-form-func-param"></input>';
21+
return {
22+
restrict: 'E',
23+
template: template,
24+
scope: {
25+
part: "=",
26+
removeAction: "&",
27+
partUpdated: "&",
28+
getOptions: "&",
29+
},
30+
link: function postLink($scope, elem) {
31+
var part = $scope.part;
32+
var partDef = part.def;
33+
var $paramsContainer = elem.find('.query-part-parameters');
34+
var $controlsContainer = elem.find('.tight-form-func-controls');
35+
36+
function clickFuncParam(paramIndex) {
37+
/*jshint validthis:true */
38+
var $link = $(this);
39+
var $input = $link.next();
40+
41+
$input.val(part.params[paramIndex]);
42+
$input.css('width', ($link.width() + 16) + 'px');
43+
44+
$link.hide();
45+
$input.show();
46+
$input.focus();
47+
$input.select();
48+
49+
var typeahead = $input.data('typeahead');
50+
if (typeahead) {
51+
$input.val('');
52+
typeahead.lookup();
53+
}
54+
}
55+
56+
function inputBlur(paramIndex) {
57+
/*jshint validthis:true */
58+
var $input = $(this);
59+
var $link = $input.prev();
60+
var newValue = $input.val();
61+
62+
if (newValue !== '' || part.def.params[paramIndex].optional) {
63+
$link.html(templateSrv.highlightVariablesAsHtml(newValue));
64+
65+
part.updateParam($input.val(), paramIndex);
66+
$scope.$apply($scope.partUpdated);
67+
}
68+
69+
$input.hide();
70+
$link.show();
71+
}
72+
73+
function inputKeyPress(paramIndex, e) {
74+
/*jshint validthis:true */
75+
if (e.which === 13) {
76+
inputBlur.call(this, paramIndex);
77+
}
78+
}
79+
80+
function inputKeyDown() {
81+
/*jshint validthis:true */
82+
this.style.width = (3 + this.value.length) * 8 + 'px';
83+
}
84+
85+
function addTypeahead($input, param, paramIndex) {
86+
if (!param.options && !param.dynamicLookup) {
87+
return;
88+
}
89+
90+
var typeaheadSource = function (query, callback) {
91+
if (param.options) { return param.options; }
92+
93+
$scope.$apply(function() {
94+
$scope.getOptions().then(function(result) {
95+
var dynamicOptions = _.map(result, function(op) { return op.value; });
96+
callback(dynamicOptions);
97+
});
98+
});
99+
};
100+
101+
$input.attr('data-provide', 'typeahead');
102+
var options = param.options;
103+
if (param.type === 'int') {
104+
options = _.map(options, function(val) { return val.toString(); });
105+
}
106+
107+
$input.typeahead({
108+
source: typeaheadSource,
109+
minLength: 0,
110+
items: 1000,
111+
updater: function (value) {
112+
setTimeout(function() {
113+
inputBlur.call($input[0], paramIndex);
114+
}, 0);
115+
return value;
116+
}
117+
});
118+
119+
var typeahead = $input.data('typeahead');
120+
typeahead.lookup = function () {
121+
this.query = this.$element.val() || '';
122+
var items = this.source(this.query, $.proxy(this.process, this));
123+
return items ? this.process(items) : items;
124+
};
125+
}
126+
127+
$scope.toggleControls = function() {
128+
var targetDiv = elem.closest('.tight-form');
129+
130+
if (elem.hasClass('show-function-controls')) {
131+
elem.removeClass('show-function-controls');
132+
targetDiv.removeClass('has-open-function');
133+
$controlsContainer.hide();
134+
return;
135+
}
136+
137+
elem.addClass('show-function-controls');
138+
targetDiv.addClass('has-open-function');
139+
$controlsContainer.show();
140+
};
141+
142+
$scope.removeActionInternal = function() {
143+
$scope.toggleControls();
144+
$scope.removeAction();
145+
};
146+
147+
function addElementsAndCompile() {
148+
_.each(partDef.params, function(param, index) {
149+
if (param.optional && part.params.length <= index) {
150+
return;
151+
}
152+
153+
if (index > 0) {
154+
$('<span>, </span>').appendTo($paramsContainer);
155+
}
156+
157+
var paramValue = templateSrv.highlightVariablesAsHtml(part.params[index]);
158+
var $paramLink = $('<a class="graphite-func-param-link pointer">' + paramValue + '</a>');
159+
var $input = $(paramTemplate);
160+
161+
$paramLink.appendTo($paramsContainer);
162+
$input.appendTo($paramsContainer);
163+
164+
$input.blur(_.partial(inputBlur, index));
165+
$input.keyup(inputKeyDown);
166+
$input.keypress(_.partial(inputKeyPress, index));
167+
$paramLink.click(_.partial(clickFuncParam, index));
168+
169+
addTypeahead($input, param, index);
170+
});
171+
}
172+
173+
function relink() {
174+
$paramsContainer.empty();
175+
addElementsAndCompile();
176+
}
177+
178+
relink();
179+
}
180+
};
181+
}
182+
183+
coreModule.directive('queryPartEditor', queryPartEditorDirective);

public/app/core/core.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import {Emitter} from './utils/emitter';
3333
import {layoutSelector} from './components/layout_selector/layout_selector';
3434
import {switchDirective} from './components/switch';
3535
import {dashboardSelector} from './components/dashboard_selector';
36+
import {queryPartEditorDirective} from './components/query_part/query_part_editor';
3637
import 'app/core/controllers/all';
3738
import 'app/core/services/all';
3839
import 'app/core/routes/routes';
@@ -56,4 +57,5 @@ export {
5657
Emitter,
5758
appEvents,
5859
dashboardSelector,
60+
queryPartEditorDirective,
5961
};

public/app/plugins/datasource/influxdb/partials/query.editor.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,13 @@
3535
</div>
3636

3737
<div class="gf-form" ng-repeat="part in selectParts">
38-
<influx-query-part-editor
38+
<query-part-editor
3939
class="gf-form-label query-part"
4040
part="part"
4141
remove-action="ctrl.removeSelectPart(selectParts, part)"
4242
part-updated="ctrl.selectPartUpdated(selectParts, part)"
4343
get-options="ctrl.getPartOptions(part)">
44-
</influx-query-part-editor>
44+
</query-part-editor>
4545
</div>
4646

4747
<div class="gf-form">
@@ -62,12 +62,12 @@
6262
<span>GROUP BY</span>
6363
</label>
6464

65-
<influx-query-part-editor
65+
<query-part-editor
6666
ng-repeat="part in ctrl.queryModel.groupByParts"
6767
part="part"
6868
class="gf-form-label query-part"
6969
remove-action="ctrl.removeGroupByPart(part, $index)" part-updated="ctrl.refresh();" get-options="ctrl.getPartOptions(part)">
70-
</influx-query-part-editor>
70+
</query-part-editor>
7171
</div>
7272

7373
<div class="gf-form">

public/app/plugins/datasource/influxdb/partials/query_part.html

Lines changed: 0 additions & 5 deletions
This file was deleted.

public/app/plugins/datasource/influxdb/query_ctrl.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
///<reference path="../../../headers/common.d.ts" />
22

3-
import './query_part_editor';
4-
import './query_part_editor';
5-
63
import angular from 'angular';
74
import _ from 'lodash';
85
import InfluxQueryBuilder from './query_builder';

0 commit comments

Comments
 (0)