mirror of
https://github.com/grafana/grafana.git
synced 2025-08-03 03:13:49 +08:00
Merge branch 'influxdb-09-fields-enhancements'
This commit is contained in:
@ -48,7 +48,6 @@ in the main Time Picker in the upper right, but they can also have relative time
|
||||
2. To edit the graph you click on the graph title to open the panel menu, then `Edit`.
|
||||
3. This should take you to the `Metrics` tab. In this tab you should see the editor for your default data source.
|
||||
|
||||
|
||||
## Drag-and-Drop panels
|
||||
|
||||
You can Drag-and-Drop Panels within and between Rows. Click and hold the Panel title, and drag it to its new location.
|
||||
|
@ -11,22 +11,36 @@ function (angular, _, $) {
|
||||
.directive('influxdbFuncEditor', function($compile) {
|
||||
|
||||
var funcSpanTemplate = '<a gf-dropdown="functionMenu" class="dropdown-toggle" ' +
|
||||
'data-toggle="dropdown">{{target.function}}</a><span>(</span>';
|
||||
'data-toggle="dropdown">{{field.func}}</a><span>(</span>';
|
||||
|
||||
var paramTemplate = '<input type="text" style="display:none"' +
|
||||
' class="input-mini tight-form-func-param"></input>';
|
||||
|
||||
var functionList = [
|
||||
'count', 'mean', 'sum', 'min', 'max', 'mode', 'distinct', 'median',
|
||||
'derivative', 'stddev', 'first', 'last', 'difference'
|
||||
];
|
||||
|
||||
var functionMenu = _.map(functionList, function(func) {
|
||||
return { text: func, click: "changeFunction('" + func + "');" };
|
||||
});
|
||||
|
||||
return {
|
||||
restrict: 'A',
|
||||
scope: {
|
||||
field: "=",
|
||||
getFields: "&",
|
||||
onChange: "&",
|
||||
},
|
||||
link: function postLink($scope, elem) {
|
||||
var $funcLink = $(funcSpanTemplate);
|
||||
|
||||
$scope.functionMenu = _.map($scope.functions, function(func) {
|
||||
return {
|
||||
text: func,
|
||||
click: "changeFunction('" + func + "');"
|
||||
};
|
||||
});
|
||||
$scope.functionMenu = functionMenu;
|
||||
|
||||
$scope.changeFunction = function(func) {
|
||||
$scope.field.func = func;
|
||||
$scope.onChange();
|
||||
};
|
||||
|
||||
function clickFuncParam() {
|
||||
/*jshint validthis:true */
|
||||
@ -34,7 +48,7 @@ function (angular, _, $) {
|
||||
var $link = $(this);
|
||||
var $input = $link.next();
|
||||
|
||||
$input.val($scope.target.column);
|
||||
$input.val($scope.field.name);
|
||||
$input.css('width', ($link.width() + 16) + 'px');
|
||||
|
||||
$link.hide();
|
||||
@ -58,8 +72,8 @@ function (angular, _, $) {
|
||||
if ($input.val() !== '') {
|
||||
$link.text($input.val());
|
||||
|
||||
$scope.target.column = $input.val();
|
||||
$scope.$apply($scope.get_data);
|
||||
$scope.field.name = $input.val();
|
||||
$scope.$apply($scope.onChange());
|
||||
}
|
||||
|
||||
$input.hide();
|
||||
@ -83,8 +97,10 @@ function (angular, _, $) {
|
||||
$input.attr('data-provide', 'typeahead');
|
||||
|
||||
$input.typeahead({
|
||||
source: function () {
|
||||
return $scope.listColumns.apply(null, arguments);
|
||||
source: function (query, callback) {
|
||||
return $scope.getFields().then(function(results) {
|
||||
callback(results);
|
||||
});
|
||||
},
|
||||
minLength: 0,
|
||||
items: 20,
|
||||
@ -108,7 +124,7 @@ function (angular, _, $) {
|
||||
function addElementsAndCompile() {
|
||||
$funcLink.appendTo(elem);
|
||||
|
||||
var $paramLink = $('<a ng-click="" class="graphite-func-param-link">value</a>');
|
||||
var $paramLink = $('<a ng-click="" class="graphite-func-param-link">' + $scope.field.name + '</a>');
|
||||
var $input = $(paramTemplate);
|
||||
|
||||
$paramLink.appendTo(elem);
|
||||
|
@ -65,10 +65,12 @@
|
||||
<li class="tight-form-item query-keyword" style="width: 75px;">
|
||||
SELECT
|
||||
</li>
|
||||
<li class="dropdown tight-form-item">
|
||||
<a gf-dropdown="functionMenu" class="dropdown-toggle" data-toggle="dropdown">
|
||||
{{target.function}}<span>(value)</span>
|
||||
</a>
|
||||
<li class="dropdown" ng-repeat="field in target.fields">
|
||||
<span influxdb-func-editor field="field" get-fields="getFields()" on-change="fieldChanged(field)" class="tight-form-item">
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<metric-segment segment="addFieldSegment" get-alt-segments="getFieldSegments()" on-value-changed="addField()"></metric-segment>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@ -114,8 +116,8 @@
|
||||
<i class="fa fa-eye invisible"></i>
|
||||
</li>
|
||||
|
||||
<li class="tight-form-item" >
|
||||
<span class="query-keyword">GROUP BY</span>
|
||||
<li class="tight-form-item query-keyword">
|
||||
GROUP BY
|
||||
</li>
|
||||
|
||||
<li class="tight-form-item">
|
||||
|
@ -32,12 +32,15 @@ function (_) {
|
||||
|
||||
if (type === 'TAG_KEYS') {
|
||||
query = 'SHOW TAG KEYS';
|
||||
measurement= this.target.measurement;
|
||||
measurement = this.target.measurement;
|
||||
} else if (type === 'TAG_VALUES') {
|
||||
query = 'SHOW TAG VALUES';
|
||||
measurement= this.target.measurement;
|
||||
measurement = this.target.measurement;
|
||||
} else if (type === 'MEASUREMENTS') {
|
||||
query = 'SHOW MEASUREMENTS';
|
||||
} else if (type === 'FIELDS') {
|
||||
query = 'SHOW FIELD KEYS FROM "' + this.target.measurement + '"';
|
||||
return query;
|
||||
}
|
||||
|
||||
if (measurement) {
|
||||
@ -73,15 +76,25 @@ function (_) {
|
||||
throw "Metric measurement is missing";
|
||||
}
|
||||
|
||||
var query = 'SELECT ';
|
||||
var measurement = target.measurement;
|
||||
var aggregationFunc = target.function || 'mean';
|
||||
if (!target.fields) {
|
||||
target.fields = [{name: 'value', func: target.function || 'mean'}];
|
||||
}
|
||||
|
||||
var query = 'SELECT ';
|
||||
var i;
|
||||
for (i = 0; i < target.fields.length; i++) {
|
||||
var field = target.fields[i];
|
||||
if (i > 0) {
|
||||
query += ', ';
|
||||
}
|
||||
query += field.func + '(' + field.name + ')';
|
||||
}
|
||||
|
||||
var measurement = target.measurement;
|
||||
if (!measurement.match('^/.*/') && !measurement.match(/^merge\(.*\)/)) {
|
||||
measurement = '"' + measurement+ '"';
|
||||
}
|
||||
|
||||
query += aggregationFunc + '(value)';
|
||||
query += ' FROM ' + measurement + ' WHERE ';
|
||||
var conditions = _.map(target.tags, function(tag, index) {
|
||||
return renderTagCondition(tag, index);
|
||||
|
@ -10,20 +10,14 @@ function (angular, _, InfluxQueryBuilder) {
|
||||
|
||||
module.controller('InfluxQueryCtrl', function($scope, $timeout, $sce, templateSrv, $q) {
|
||||
|
||||
$scope.functionList = [
|
||||
'count', 'mean', 'sum', 'min', 'max', 'mode', 'distinct', 'median',
|
||||
'derivative', 'stddev', 'first', 'last', 'difference'
|
||||
];
|
||||
|
||||
$scope.functionMenu = _.map($scope.functionList, function(func) {
|
||||
return { text: func, click: "changeFunction('" + func + "');" };
|
||||
});
|
||||
|
||||
$scope.init = function() {
|
||||
var target = $scope.target;
|
||||
target.function = target.function || 'mean';
|
||||
target.tags = target.tags || [];
|
||||
target.groupByTags = target.groupByTags || [];
|
||||
target.fields = target.fields || [{
|
||||
name: 'value',
|
||||
func: target.function || 'mean'
|
||||
}];
|
||||
|
||||
$scope.queryBuilder = new InfluxQueryBuilder(target);
|
||||
|
||||
@ -33,6 +27,8 @@ function (angular, _, InfluxQueryBuilder) {
|
||||
$scope.measurementSegment = new MetricSegment(target.measurement);
|
||||
}
|
||||
|
||||
$scope.addFieldSegment = MetricSegment.newPlusButton();
|
||||
|
||||
$scope.tagSegments = [];
|
||||
_.each(target.tags, function(tag) {
|
||||
if (tag.condition) {
|
||||
@ -94,6 +90,18 @@ function (angular, _, InfluxQueryBuilder) {
|
||||
$scope.$parent.get_data();
|
||||
};
|
||||
|
||||
$scope.getFields = function() {
|
||||
var fieldsQuery = $scope.queryBuilder.buildExploreQuery('FIELDS');
|
||||
return $scope.datasource.metricFindQuery(fieldsQuery)
|
||||
.then(function(results) {
|
||||
var values = _.pluck(results, 'text');
|
||||
if ($scope.target.fields.length > 1) {
|
||||
values.splice(0, 0, "-- remove from select --");
|
||||
}
|
||||
return values;
|
||||
});
|
||||
};
|
||||
|
||||
$scope.toggleQueryMode = function () {
|
||||
$scope.target.rawQuery = !$scope.target.rawQuery;
|
||||
};
|
||||
@ -159,6 +167,25 @@ function (angular, _, InfluxQueryBuilder) {
|
||||
.then(null, $scope.handleQueryError);
|
||||
};
|
||||
|
||||
$scope.getFieldSegments = function() {
|
||||
var fieldsQuery = $scope.queryBuilder.buildExploreQuery('FIELDS');
|
||||
return $scope.datasource.metricFindQuery(fieldsQuery)
|
||||
.then($scope.transformToSegments)
|
||||
.then(null, $scope.handleQueryError);
|
||||
};
|
||||
|
||||
$scope.addField = function() {
|
||||
$scope.target.fields.push({name: $scope.addFieldSegment.value, func: 'mean'});
|
||||
_.extend($scope.addFieldSegment, MetricSegment.newPlusButton());
|
||||
};
|
||||
|
||||
$scope.fieldChanged = function(field) {
|
||||
if (field.name === '-- remove from select --') {
|
||||
$scope.target.fields = _.without($scope.target.fields, field);
|
||||
}
|
||||
$scope.get_data();
|
||||
};
|
||||
|
||||
$scope.getGroupByTagSegments = function(segment) {
|
||||
var query = $scope.queryBuilder.buildExploreQuery('TAG_KEYS');
|
||||
|
||||
|
@ -38,6 +38,20 @@ define([
|
||||
});
|
||||
});
|
||||
|
||||
describe('series with multiple fields', function() {
|
||||
var builder = new InfluxQueryBuilder({
|
||||
measurement: 'cpu',
|
||||
tags: [],
|
||||
fields: [{ name: 'tx_in', func: 'sum' }, { name: 'tx_out', func: 'mean' }]
|
||||
});
|
||||
|
||||
var query = builder.build();
|
||||
|
||||
it('should generate correct query', function() {
|
||||
expect(query).to.be('SELECT sum(tx_in), mean(tx_out) FROM "cpu" WHERE $timeFilter GROUP BY time($interval) ORDER BY asc');
|
||||
});
|
||||
});
|
||||
|
||||
describe('series with multiple tags only', function() {
|
||||
var builder = new InfluxQueryBuilder({
|
||||
measurement: 'cpu',
|
||||
@ -130,6 +144,12 @@ define([
|
||||
expect(query).to.be('SHOW TAG VALUES FROM "cpu" WITH KEY = "app" WHERE "host" =~ /server.*/');
|
||||
});
|
||||
|
||||
it('should build show field query', function() {
|
||||
var builder = new InfluxQueryBuilder({measurement: 'cpu', tags: [{key: 'app', value: 'email'}]});
|
||||
var query = builder.buildExploreQuery('FIELDS');
|
||||
expect(query).to.be('SHOW FIELD KEYS FROM "cpu"');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
Reference in New Issue
Block a user