More work on new influxdb query editor, #1525

This commit is contained in:
Torkel Ödegaard 2015-05-15 19:04:49 +02:00
parent d14b570d76
commit 6fd37779b8
6 changed files with 203 additions and 27 deletions

View File

@ -91,7 +91,7 @@
time($interval)
</li>
<li ng-repeat="segment in groupBySegments">
<metric-segment segment="segment" get-alt-segments="getTagsOrValues(segment, 0)" on-value-changed="groupByTagUpdated(segment, $index)"></metric-segment>
<metric-segment segment="segment" get-alt-segments="getGroupByTagSegments(segment, 0)" on-value-changed="groupByTagUpdated(segment, $index)"></metric-segment>
</li>
<li class="dropdown">
<a class="tight-form-item pointer" data-toggle="dropdown" bs-tooltip="'Insert missing values, important when stacking'" data-placement="right">

View File

@ -1,5 +1,5 @@
define([
'lodash'
'lodash'
],
function (_) {
'use strict';
@ -32,12 +32,18 @@ function (_) {
}
query += aggregationFunc + '(value)';
query += ' FROM ' + measurement + ' WHERE $timeFilter';
query += _.map(target.tags, function(tag) {
return ' AND ' + tag.key + '=' + "'" + tag.value + "'";
}).join('');
query += ' FROM ' + measurement + ' WHERE ';
var conditions = _.map(target.tags, function(tag) {
return tag.key + '=' + "'" + tag.value + "' ";
});
conditions.push('$timeFilter');
query += conditions.join('AND ');
query += ' GROUP BY time($interval)';
if (target.groupByTags && target.groupByTags.length > 0) {
query += ', ' + target.groupByTags.join();
}
if (target.fill) {
query += ' fill(' + target.fill + ')';

View File

@ -35,14 +35,12 @@ function (angular, _) {
if (tag.condition) {
$scope.tagSegments.push(MetricSegment.newCondition(tag.condition));
}
$scope.tagSegments.push(new MetricSegment({value: tag.key, type: 'key' }));
$scope.tagSegments.push(new MetricSegment({fake: true, value: "="}));
$scope.tagSegments.push(new MetricSegment({value: tag.value, type: 'value'}));
$scope.tagSegments.push(new MetricSegment({value: tag.key, type: 'key', cssClass: 'query-segment-key' }));
$scope.tagSegments.push(new MetricSegment({fake: true, value: "=", cssClass: 'query-segment-operator'}));
$scope.tagSegments.push(new MetricSegment({value: tag.value, type: 'value', cssClass: 'query-segment-value'}));
});
if ($scope.tagSegments.length % 3 === 0) {
$scope.tagSegments.push(MetricSegment.newPlusButton());
}
$scope.fixTagSegments();
$scope.groupBySegments = [];
_.each(target.groupByTags, function(tag) {
@ -50,12 +48,37 @@ function (angular, _) {
});
$scope.groupBySegments.push(MetricSegment.newPlusButton());
$scope.removeTagFilterSegment = new MetricSegment({fake: true, value: 'remove tag filter'});
$scope.removeGroupBySegment = new MetricSegment({fake: true, value: 'remove group by'});
};
$scope.fixTagSegments = function() {
var count = $scope.tagSegments.length;
var lastSegment = $scope.tagSegments[Math.max(count-1, 0)];
if (!lastSegment || lastSegment.type !== 'plus-button') {
$scope.tagSegments.push(MetricSegment.newPlusButton());
}
};
$scope.groupByTagUpdated = function(segment, index) {
if (segment.value === $scope.removeGroupBySegment.value) {
$scope.target.groupByTags.splice(index, 1);
$scope.groupBySegments.splice(index, 1);
$scope.$parent.get_data();
return;
}
if (index === $scope.groupBySegments.length-1) {
$scope.groupBySegments.push(MetricSegment.newPlusButton());
}
segment.type = 'group-by-key';
segment.fake = false;
$scope.target.groupByTags[index] = segment.value;
$scope.$parent.get_data();
};
$scope.changeFunction = function(func) {
@ -65,7 +88,6 @@ function (angular, _) {
$scope.measurementChanged = function() {
$scope.target.measurement = $scope.measurementSegment.value;
console.log('measurement updated', $scope.target.measurement);
$scope.$parent.get_data();
};
@ -126,8 +148,23 @@ function (angular, _) {
.then($scope.transformToSegments)
.then($scope.addTemplateVariableSegments)
.then(function(results) {
if (queryType === 'TAG_KEYS' && segment.type !== 'plus-button') {
results.push(new MetricSegment({fake: true, value: 'remove tag filter'}));
if (queryType === 'TAG_KEYS' && segment.type === 'key') {
results.push(angular.copy($scope.removeTagFilterSegment));
}
return results;
})
.then(null, $scope.handleQueryError);
};
$scope.getGroupByTagSegments = function(segment) {
var query = 'SHOW TAG KEYS FROM "' + $scope.target.measurement + '"';
return $scope.datasource.metricFindQuery(query, 'TAG_KEYS')
.then($scope.transformToSegments)
.then($scope.addTemplateVariableSegments)
.then(function(results) {
if (segment.type !== 'plus-button') {
results.push(angular.copy($scope.removeGroupBySegment));
}
return results;
})
@ -137,13 +174,15 @@ function (angular, _) {
$scope.tagSegmentUpdated = function(segment, index) {
$scope.tagSegments[index] = segment;
if (segment.value === 'remove tag filter') {
if (segment.value === $scope.removeTagFilterSegment.value) {
$scope.tagSegments.splice(index, 3);
if ($scope.tagSegments.length === 0) {
$scope.tagSegments.push(MetricSegment.newPlusButton());
} else {
$scope.tagSegments.splice(index-1, 1);
$scope.tagSegments.push(MetricSegment.newPlusButton());
} else if ($scope.tagSegments.length > 2) {
$scope.tagSegments.splice(Math.max(index-1, 0), 1);
if ($scope.tagSegments[$scope.tagSegments.length-1].type !== 'plus-button') {
$scope.tagSegments.push(MetricSegment.newPlusButton());
}
}
}
else {
@ -151,9 +190,10 @@ function (angular, _) {
if (index > 2) {
$scope.tagSegments.splice(index, 0, MetricSegment.newCondition('AND'));
}
$scope.tagSegments.push(new MetricSegment({fake: true, value: '=', type: 'operator'}));
$scope.tagSegments.push(new MetricSegment({fake: true, value: 'select tag value', type: 'value' }));
$scope.tagSegments.push(MetricSegment.newFake('=', 'operator', 'query-segment-operator'));
$scope.tagSegments.push(MetricSegment.newFake('select tag value', 'value', 'query-segment-value'));
segment.type = 'key';
segment.cssClass = 'query-segment-key';
}
if ((index+1) === $scope.tagSegments.length) {
@ -165,10 +205,13 @@ function (angular, _) {
};
$scope.rebuildTargetTagConditions = function() {
var tags = [{}];
var tags = [];
var tagIndex = 0;
_.each($scope.tagSegments, function(segment2) {
if (segment2.type === 'key') {
if (tags.length === 0) {
tags.push({});
}
tags[tagIndex].key = segment2.value;
}
else if (segment2.type === 'value') {
@ -211,6 +254,10 @@ function (angular, _) {
return new MetricSegment({value: 'select measurement', fake: true});
};
MetricSegment.newFake = function(text, type, cssClass) {
return new MetricSegment({value: text, fake: true, type: type, cssClass: cssClass});
};
MetricSegment.newCondition = function(condition) {
return new MetricSegment({value: condition, type: 'condition', cssClass: 'query-keyword' });
};

View File

@ -343,4 +343,16 @@
color: @blue;
}
.query-segment-key {
border-right: none;
padding-right: 1px;
}
.query-segment-operator {
padding-right: 1px;
border-right: none;
color: @orange;
}

View File

@ -18,7 +18,7 @@ define([
});
describe('series with tags only', function() {
describe('series with single tag only', function() {
var builder = new InfluxQueryBuilder({
measurement: 'cpu',
tags: [{key: 'hostname', value: 'server1'}]
@ -27,12 +27,41 @@ define([
var query = builder.build();
it('should generate correct query', function() {
expect(query).to.be('SELECT mean(value) FROM "cpu" WHERE $timeFilter ' +
'AND hostname=\'server1\' GROUP BY time($interval) ORDER BY asc');
expect(query).to.be('SELECT mean(value) FROM "cpu" WHERE hostname=\'server1\' AND $timeFilter'
+ ' GROUP BY time($interval) ORDER BY asc');
});
});
describe('series with multiple tags only', function() {
var builder = new InfluxQueryBuilder({
measurement: 'cpu',
tags: [{key: 'hostname', value: 'server1'}, {key: 'app', value: 'email', condition: "AND"}]
});
var query = builder.build();
it('should generate correct query', function() {
expect(query).to.be('SELECT mean(value) FROM "cpu" WHERE hostname=\'server1\' AND app=\'email\' AND ' +
'$timeFilter GROUP BY time($interval) ORDER BY asc');
});
});
describe('series with groupByTag', function() {
var builder = new InfluxQueryBuilder({
measurement: 'cpu',
tags: [],
groupByTags: ["host"]
});
var query = builder.build();
it('should generate correct query', function() {
expect(query).to.be('SELECT mean(value) FROM "cpu" WHERE $timeFilter ' +
'GROUP BY time($interval), host ORDER BY asc');
});
});
});
});

View File

@ -101,13 +101,31 @@ define([
});
});
describe('when deleting is changed', function() {
describe('when deleting first tag filter after value is selected', function() {
beforeEach(function() {
ctx.scope.init();
ctx.scope.tagSegmentUpdated({value: 'asd', type: 'plus-button' }, 0);
ctx.scope.tagSegmentUpdated({value: 'server1', type: 'value'}, 2);
ctx.scope.tagSegmentUpdated(ctx.scope.removeTagFilterSegment, 0);
});
it('should remove tags', function() {
expect(ctx.scope.target.tags.length).to.be(0);
});
it('should remove all segment after 2 and replace with plus button', function() {
expect(ctx.scope.tagSegments.length).to.be(1);
expect(ctx.scope.tagSegments[0].type).to.be('plus-button');
});
});
describe('when deleting second tag value before second tag value is complete', function() {
beforeEach(function() {
ctx.scope.init();
ctx.scope.tagSegmentUpdated({value: 'asd', type: 'plus-button' }, 0);
ctx.scope.tagSegmentUpdated({value: 'server1', type: 'value'}, 2);
ctx.scope.tagSegmentUpdated({value: 'key2', type: 'plus-button'}, 3);
ctx.scope.tagSegmentUpdated({value: 'remove tag filter', type: 'key'}, 4);
ctx.scope.tagSegmentUpdated(ctx.scope.removeTagFilterSegment, 4);
});
it('should remove all segment after 2 and replace with plus button', function() {
@ -116,5 +134,69 @@ define([
});
});
describe('when deleting second tag value before second tag value is complete', function() {
beforeEach(function() {
ctx.scope.init();
ctx.scope.tagSegmentUpdated({value: 'asd', type: 'plus-button' }, 0);
ctx.scope.tagSegmentUpdated({value: 'server1', type: 'value'}, 2);
ctx.scope.tagSegmentUpdated({value: 'key2', type: 'plus-button'}, 3);
ctx.scope.tagSegmentUpdated(ctx.scope.removeTagFilterSegment, 4);
});
it('should remove all segment after 2 and replace with plus button', function() {
expect(ctx.scope.tagSegments.length).to.be(4);
expect(ctx.scope.tagSegments[3].type).to.be('plus-button');
});
});
describe('when deleting second tag value after second tag filter is complete', function() {
beforeEach(function() {
ctx.scope.init();
ctx.scope.tagSegmentUpdated({value: 'asd', type: 'plus-button' }, 0);
ctx.scope.tagSegmentUpdated({value: 'server1', type: 'value'}, 2);
ctx.scope.tagSegmentUpdated({value: 'key2', type: 'plus-button'}, 3);
ctx.scope.tagSegmentUpdated({value: 'value', type: 'value'}, 6);
ctx.scope.tagSegmentUpdated(ctx.scope.removeTagFilterSegment, 4);
});
it('should remove all segment after 2 and replace with plus button', function() {
expect(ctx.scope.tagSegments.length).to.be(4);
expect(ctx.scope.tagSegments[3].type).to.be('plus-button');
});
});
describe('when adding group by', function() {
beforeEach(function() {
ctx.scope.init();
ctx.scope.groupByTagUpdated({value: 'host', type: 'plus-button' }, 0);
});
it('should add group by', function() {
expect(ctx.scope.target.groupByTags.length).to.be(1);
expect(ctx.scope.target.groupByTags[0]).to.be('host');
});
it('should add another plus button segment', function() {
expect(ctx.scope.groupBySegments[1].type).to.be('plus-button');
});
});
describe('when removing group by', function() {
beforeEach(function() {
ctx.scope.init();
ctx.scope.groupByTagUpdated({value: 'host', type: 'plus-button' }, 0);
ctx.scope.groupByTagUpdated(ctx.scope.removeGroupBySegment, 0);
});
it('should add group by', function() {
expect(ctx.scope.target.groupByTags.length).to.be(0);
});
it('should remove segment', function() {
expect(ctx.scope.groupBySegments.length).to.be(1);
expect(ctx.scope.groupBySegments[0].type).to.be('plus-button');
});
});
});
});