diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1d8ccbe7618..bfff6ea811a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -24,6 +24,7 @@ it allows you to add queries of differnet data source types & instances to the s
- [Issue #2563](https://github.com/grafana/grafana/issues/2563). Annotations: Fixed issue when html sanitizer failes for title to annotation body, now fallbacks to html escaping title and text
- [Issue #2564](https://github.com/grafana/grafana/issues/2564). Templating: Another atempt at fixing #2534 (Init multi value template var used in repeat panel from url)
- [Issue #2620](https://github.com/grafana/grafana/issues/2620). Graph: multi series tooltip did no highlight correct point when stacking was enabled and series were of different resolution
+- [Issue #2636](https://github.com/grafana/grafana/issues/2636). InfluxDB: Do no show template vars in dropdown for tag keys and group by keys
**Breaking Changes**
- Notice to makers/users of custom data sources, there is a minor breaking change in 2.2 that
diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml
index fd91a28693a..f44b92645a6 100644
--- a/docs/mkdocs.yml
+++ b/docs/mkdocs.yml
@@ -49,7 +49,6 @@ pages:
- ['reference/graph.md', 'Reference', 'Graph Panel']
- ['reference/singlestat.md', 'Reference', 'Singlestat Panel']
- ['reference/dashlist.md', 'Reference', 'Dashboard List Panel']
-- ['reference/text.md', 'Reference', 'Text Panel']
- ['reference/sharing.md', 'Reference', 'Sharing']
- ['reference/annotations.md', 'Reference', 'Annotations']
- ['reference/timerange.md', 'Reference', 'Time Range Controls']
diff --git a/docs/sources/datasources/influxdb.md b/docs/sources/datasources/influxdb.md
index 0c96d2b733c..b48b2b0097a 100644
--- a/docs/sources/datasources/influxdb.md
+++ b/docs/sources/datasources/influxdb.md
@@ -51,7 +51,7 @@ the tag key and select `--remove tag filter--`.
### Regex matching
You can type in regex patterns for metric names or tag filter values, be sure to wrap the regex pattern in forward slashes (`/`). Grafana
-will automaticallay adjust the filter tag condition to use the InfluxDB regex match condition operator (`=~`).
+will automatically adjust the filter tag condition to use the InfluxDB regex match condition operator (`=~`).
### Editor group by
To group by a tag click the plus icon after the `GROUP BY ($interval)` text. Pick a tag from the dropdown that appears.
diff --git a/pkg/api/org_invite.go b/pkg/api/org_invite.go
index b7d8d213853..8d916677ed2 100644
--- a/pkg/api/org_invite.go
+++ b/pkg/api/org_invite.go
@@ -154,10 +154,11 @@ func CompleteInvite(c *middleware.Context, completeInvite dtos.CompleteInviteFor
}
cmd := m.CreateUserCommand{
- Email: completeInvite.Email,
- Name: completeInvite.Name,
- Login: completeInvite.Username,
- Password: completeInvite.Password,
+ Email: completeInvite.Email,
+ Name: completeInvite.Name,
+ Login: completeInvite.Username,
+ Password: completeInvite.Password,
+ SkipOrgSetup: true,
}
if err := bus.Dispatch(&cmd); err != nil {
diff --git a/pkg/api/signup.go b/pkg/api/signup.go
index fa450b93df2..767b9801154 100644
--- a/pkg/api/signup.go
+++ b/pkg/api/signup.go
@@ -65,6 +65,7 @@ func SignUpStep2(c *middleware.Context, form dtos.SignUpStep2Form) Response {
OrgName: form.OrgName,
}
+ // verify email
if setting.VerifyEmailEnabled {
if ok, rsp := verifyUserSignUpEmail(form.Email, form.Code); !ok {
return rsp
@@ -72,11 +73,13 @@ func SignUpStep2(c *middleware.Context, form dtos.SignUpStep2Form) Response {
createUserCmd.EmailVerified = true
}
+ // check if user exists
existing := m.GetUserByLoginQuery{LoginOrEmail: form.Email}
if err := bus.Dispatch(&existing); err == nil {
return ApiError(401, "User with same email address already exists", nil)
}
+ // dispatch create command
if err := bus.Dispatch(&createUserCmd); err != nil {
return ApiError(500, "Failed to create user", err)
}
diff --git a/pkg/models/user.go b/pkg/models/user.go
index 30ab34db9a6..64067d59654 100644
--- a/pkg/models/user.go
+++ b/pkg/models/user.go
@@ -52,6 +52,7 @@ type CreateUserCommand struct {
Password string
EmailVerified bool
IsAdmin bool
+ SkipOrgSetup bool
Result User
}
diff --git a/pkg/services/notifications/notifications.go b/pkg/services/notifications/notifications.go
index 576fe828331..5857ee5247d 100644
--- a/pkg/services/notifications/notifications.go
+++ b/pkg/services/notifications/notifications.go
@@ -153,7 +153,7 @@ func signUpCompletedHandler(evt *events.SignUpCompleted) error {
return sendEmailCommandHandler(&m.SendEmailCommand{
To: []string{evt.Email},
- Template: tmplSignUpStarted,
+ Template: tmplWelcomeOnSignUp,
Data: map[string]interface{}{
"Name": evt.Name,
},
diff --git a/pkg/services/sqlstore/user.go b/pkg/services/sqlstore/user.go
index b26000673d6..6c6f581dcc4 100644
--- a/pkg/services/sqlstore/user.go
+++ b/pkg/services/sqlstore/user.go
@@ -30,6 +30,10 @@ func init() {
}
func getOrgIdForNewUser(cmd *m.CreateUserCommand, sess *session) (int64, error) {
+ if cmd.SkipOrgSetup {
+ return -1, nil
+ }
+
var org m.Org
if setting.AutoAssignOrg {
@@ -103,23 +107,6 @@ func CreateUser(cmd *m.CreateUserCommand) error {
return err
}
- // create org user link
- orgUser := m.OrgUser{
- OrgId: orgId,
- UserId: user.Id,
- Role: m.ROLE_ADMIN,
- Created: time.Now(),
- Updated: time.Now(),
- }
-
- if setting.AutoAssignOrg && !user.IsAdmin {
- orgUser.Role = m.RoleType(setting.AutoAssignOrgRole)
- }
-
- if _, err = sess.Insert(&orgUser); err != nil {
- return err
- }
-
sess.publishAfterCommit(&events.UserCreated{
Timestamp: user.Created,
Id: user.Id,
@@ -129,6 +116,26 @@ func CreateUser(cmd *m.CreateUserCommand) error {
})
cmd.Result = user
+
+ // create org user link
+ if !cmd.SkipOrgSetup {
+ orgUser := m.OrgUser{
+ OrgId: orgId,
+ UserId: user.Id,
+ Role: m.ROLE_ADMIN,
+ Created: time.Now(),
+ Updated: time.Now(),
+ }
+
+ if setting.AutoAssignOrg && !user.IsAdmin {
+ orgUser.Role = m.RoleType(setting.AutoAssignOrgRole)
+ }
+
+ if _, err = sess.Insert(&orgUser); err != nil {
+ return err
+ }
+ }
+
return nil
})
}
diff --git a/public/app/features/dashboard/partials/import.html b/public/app/features/dashboard/partials/import.html
index a942297ac59..4b44544dc7b 100644
--- a/public/app/features/dashboard/partials/import.html
+++ b/public/app/features/dashboard/partials/import.html
@@ -1,6 +1,6 @@
diff --git a/public/app/features/templating/partials/editor.html b/public/app/features/templating/partials/editor.html
index ed93e5e111e..a76c83580d5 100644
--- a/public/app/features/templating/partials/editor.html
+++ b/public/app/features/templating/partials/editor.html
@@ -200,7 +200,7 @@
Multi format
-
+
diff --git a/public/app/plugins/datasource/influxdb/queryBuilder.js b/public/app/plugins/datasource/influxdb/queryBuilder.js
index c6306f20c66..e3e4d6a27ed 100644
--- a/public/app/plugins/datasource/influxdb/queryBuilder.js
+++ b/public/app/plugins/datasource/influxdb/queryBuilder.js
@@ -102,7 +102,7 @@ function (_) {
if (i > 0) {
query += ', ';
}
- query += field.func + '(' + field.name + ')';
+ query += field.func + '("' + field.name + '")';
}
var measurement = target.measurement;
diff --git a/public/app/plugins/datasource/influxdb/queryCtrl.js b/public/app/plugins/datasource/influxdb/queryCtrl.js
index 0d1a9354b65..186ffaf1a11 100644
--- a/public/app/plugins/datasource/influxdb/queryCtrl.js
+++ b/public/app/plugins/datasource/influxdb/queryCtrl.js
@@ -119,8 +119,7 @@ function (angular, _, InfluxQueryBuilder) {
$scope.getMeasurements = function () {
var query = $scope.queryBuilder.buildExploreQuery('MEASUREMENTS');
return $scope.datasource.metricFindQuery(query)
- .then($scope.transformToSegments)
- .then($scope.addTemplateVariableSegments)
+ .then($scope.transformToSegments(true))
.then(null, $scope.handleQueryError);
};
@@ -129,42 +128,46 @@ function (angular, _, InfluxQueryBuilder) {
return [];
};
- $scope.transformToSegments = function(results) {
- return _.map(results, function(segment) {
- return new MetricSegment({ value: segment.text, expandable: segment.expandable });
- });
- };
+ $scope.transformToSegments = function(addTemplateVars) {
+ return function(results) {
+ var segments = _.map(results, function(segment) {
+ return new MetricSegment({ value: segment.text, expandable: segment.expandable });
+ });
- $scope.addTemplateVariableSegments = function(segments) {
- _.each(templateSrv.variables, function(variable) {
- segments.unshift(new MetricSegment({ type: 'template', value: '/$' + variable.name + '/', expandable: true }));
- });
- return segments;
+ if (addTemplateVars) {
+ _.each(templateSrv.variables, function(variable) {
+ segments.unshift(new MetricSegment({ type: 'template', value: '/$' + variable.name + '/', expandable: true }));
+ });
+ }
+
+ return segments;
+ };
};
$scope.getTagsOrValues = function(segment, index) {
- var query;
+ if (segment.type === 'condition') {
+ return $q.when([new MetricSegment('AND'), new MetricSegment('OR')]);
+ }
+ if (segment.type === 'operator') {
+ var nextValue = $scope.tagSegments[index+1].value;
+ if (/^\/.*\/$/.test(nextValue)) {
+ return $q.when(MetricSegment.newOperators(['=~', '!~']));
+ } else {
+ return $q.when(MetricSegment.newOperators(['=', '<>', '<', '>']));
+ }
+ }
+ var query, addTemplateVars;
if (segment.type === 'key' || segment.type === 'plus-button') {
query = $scope.queryBuilder.buildExploreQuery('TAG_KEYS');
+ addTemplateVars = false;
} else if (segment.type === 'value') {
query = $scope.queryBuilder.buildExploreQuery('TAG_VALUES', $scope.tagSegments[index-2].value);
- } else if (segment.type === 'condition') {
- return $q.when([new MetricSegment('AND'), new MetricSegment('OR')]);
- } else if (segment.type === 'operator' && /^(?!\/.*\/$)/.test($scope.tagSegments[index+1].value)) {
- return $q.when([MetricSegment.newOperator('='), MetricSegment.newOperator('<>'),
- MetricSegment.newOperator('<'), MetricSegment.newOperator('>')]);
-
- } else if (segment.type === 'operator' && /^\/.*\/$/.test($scope.tagSegments[index+1].value)) {
- return $q.when([MetricSegment.newOperator('=~'), MetricSegment.newOperator('!~')]);
- }
- else {
- return $q.when([]);
+ addTemplateVars = true;
}
return $scope.datasource.metricFindQuery(query)
- .then($scope.transformToSegments)
- .then($scope.addTemplateVariableSegments)
+ .then($scope.transformToSegments(addTemplateVars))
.then(function(results) {
if (segment.type === 'key') {
results.splice(0, 0, angular.copy($scope.removeTagFilterSegment));
@@ -177,8 +180,8 @@ function (angular, _, InfluxQueryBuilder) {
$scope.getFieldSegments = function() {
var fieldsQuery = $scope.queryBuilder.buildExploreQuery('FIELDS');
return $scope.datasource.metricFindQuery(fieldsQuery)
- .then($scope.transformToSegments)
- .then(null, $scope.handleQueryError);
+ .then($scope.transformToSegments(false))
+ .then(null, $scope.handleQueryError);
};
$scope.addField = function() {
@@ -197,8 +200,7 @@ function (angular, _, InfluxQueryBuilder) {
var query = $scope.queryBuilder.buildExploreQuery('TAG_KEYS');
return $scope.datasource.metricFindQuery(query)
- .then($scope.transformToSegments)
- .then($scope.addTemplateVariableSegments)
+ .then($scope.transformToSegments(false))
.then(function(results) {
if (segment.type !== 'plus-button') {
results.splice(0, 0, angular.copy($scope.removeGroupBySegment));
@@ -322,6 +324,12 @@ function (angular, _, InfluxQueryBuilder) {
return new MetricSegment({value: op, type: 'operator', cssClass: 'query-segment-operator' });
};
+ MetricSegment.newOperators = function(ops) {
+ return _.map(ops, function(op) {
+ return new MetricSegment({value: op, type: 'operator', cssClass: 'query-segment-operator' });
+ });
+ };
+
MetricSegment.newPlusButton = function() {
return new MetricSegment({fake: true, html: '', type: 'plus-button' });
};
diff --git a/public/app/plugins/datasource/kairosdb/datasource.js b/public/app/plugins/datasource/kairosdb/datasource.js
index a0e9ac4e949..6db99f5a244 100644
--- a/public/app/plugins/datasource/kairosdb/datasource.js
+++ b/public/app/plugins/datasource/kairosdb/datasource.js
@@ -10,7 +10,7 @@ function (angular, _, kbn) {
var module = angular.module('grafana.services');
- module.factory('KairosDBDatasource', function($q, $http, templateSrv) {
+ module.factory('KairosDBDatasource', function($q, backendSrv, templateSrv) {
function KairosDBDatasource(datasource) {
this.type = datasource.type;
@@ -51,10 +51,6 @@ function (angular, _, kbn) {
return this.performTimeSeriesQuery(queries, start, end).then(handleKairosDBQueryResponseAlias, handleQueryError);
};
- ///////////////////////////////////////////////////////////////////////
- /// Query methods
- ///////////////////////////////////////////////////////////////////////
-
KairosDBDatasource.prototype.performTimeSeriesQuery = function(queries, start, end) {
var reqBody = {
metrics: queries,
@@ -70,7 +66,7 @@ function (angular, _, kbn) {
data: reqBody
};
- return $http(options);
+ return backendSrv.datasourceRequest(options);
};
/**
@@ -83,7 +79,7 @@ function (angular, _, kbn) {
method: 'GET'
};
- return $http(options).then(function(response) {
+ return backendSrv.datasourceRequest(options).then(function(response) {
if (!response.data) {
return $q.when([]);
}
@@ -110,7 +106,7 @@ function (angular, _, kbn) {
}
};
- return $http(options).then(function(result) {
+ return backendSrv.datasourceRequest(options).then(function(result) {
if (!result.data) {
return $q.when([]);
}
@@ -139,7 +135,7 @@ function (angular, _, kbn) {
}
};
- return $http(options).then(function(result) {
+ return backendSrv.datasourceRequest(options).then(function(result) {
if (!result.data) {
return $q.when([]);
}
@@ -158,7 +154,7 @@ function (angular, _, kbn) {
}
};
- return $http(options).then(function(response) {
+ return backendSrv.datasourceRequest(options).then(function(response) {
if (!response.data) {
return [];
}
diff --git a/public/test/specs/influx09-querybuilder-specs.js b/public/test/specs/influx09-querybuilder-specs.js
index 9a9ddd15fe5..098ceeb6ca4 100644
--- a/public/test/specs/influx09-querybuilder-specs.js
+++ b/public/test/specs/influx09-querybuilder-specs.js
@@ -13,7 +13,7 @@ define([
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)');
+ expect(query).to.be('SELECT mean("value") FROM "cpu" WHERE $timeFilter GROUP BY time($interval)');
});
});
@@ -27,14 +27,14 @@ define([
var query = builder.build();
it('should generate correct query', function() {
- expect(query).to.be('SELECT mean(value) FROM "cpu" WHERE "hostname" = \'server1\' AND $timeFilter'
+ expect(query).to.be('SELECT mean("value") FROM "cpu" WHERE "hostname" = \'server1\' AND $timeFilter'
+ ' GROUP BY time($interval)');
});
it('should switch regex operator with tag value is regex', function() {
var builder = new InfluxQueryBuilder({measurement: 'cpu', tags: [{key: 'app', value: '/e.*/'}]});
var query = builder.build();
- expect(query).to.be('SELECT mean(value) FROM "cpu" WHERE "app" =~ /e.*/ AND $timeFilter GROUP BY time($interval)');
+ expect(query).to.be('SELECT mean("value") FROM "cpu" WHERE "app" =~ /e.*/ AND $timeFilter GROUP BY time($interval)');
});
});
@@ -48,7 +48,7 @@ define([
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)');
+ expect(query).to.be('SELECT sum("tx_in"), mean("tx_out") FROM "cpu" WHERE $timeFilter GROUP BY time($interval)');
});
});
@@ -61,7 +61,7 @@ define([
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 ' +
+ expect(query).to.be('SELECT mean("value") FROM "cpu" WHERE "hostname" = \'server1\' AND "app" = \'email\' AND ' +
'$timeFilter GROUP BY time($interval)');
});
});
@@ -75,7 +75,7 @@ define([
var query = builder.build();
it('should generate correct query', function() {
- expect(query).to.be('SELECT mean(value) FROM "cpu" WHERE "hostname" = \'server1\' OR "hostname" = \'server2\' AND ' +
+ expect(query).to.be('SELECT mean("value") FROM "cpu" WHERE "hostname" = \'server1\' OR "hostname" = \'server2\' AND ' +
'$timeFilter GROUP BY time($interval)');
});
});
@@ -89,7 +89,7 @@ define([
});
var query = builder.build();
- expect(query).to.be('SELECT mean(value) FROM "cpu" WHERE $timeFilter ' +
+ expect(query).to.be('SELECT mean("value") FROM "cpu" WHERE $timeFilter ' +
'GROUP BY time($interval), "host"');
});
});