Merge branch 'master' into alerting_definitions
This commit is contained in:
+14
-1
@@ -1,7 +1,20 @@
|
||||
# 3.0.0-beta6 (unreleased)
|
||||
# 3.0.0-beta7 (2016-05-02)
|
||||
|
||||
### Bug fixes
|
||||
* **Dashboard title**: Fixed max dashboard title width (media query) for large screens, fixes [#4859](https://github.com/grafana/grafana/issues/4859)
|
||||
* **Annotations**: Fixed issue with entering annotation edit view, fixes [#4857](https://github.com/grafana/grafana/issues/4857)
|
||||
* **Remove query**: Fixed issue with removing query for data sources without collapsable query editors, fixes [#4856](https://github.com/grafana/grafana/issues/4856)
|
||||
* **Graphite PNG*: Fixed issue graphite png rendering option, fixes [#4864](https://github.com/grafana/grafana/issues/4864)
|
||||
* **InfluxDB**: Fixed issue missing plus group by iconn, fixes [#4862](https://github.com/grafana/grafana/issues/4862)
|
||||
|
||||
### Enhancements
|
||||
* **InfluxDB**: Added new functions moving_average and difference to query editor, closes [#4698](https://github.com/grafana/grafana/issues/4698)
|
||||
|
||||
# 3.0.0-beta6 (2016-04-29)
|
||||
|
||||
### Enhancements
|
||||
* **Singlestat**: Support for gauges in singlestat panel. closes [#3688](https://github.com/grafana/grafana/pull/3688)
|
||||
* **Templating**: Support for data source as variable, closes [#816](https://github.com/grafana/grafana/pull/816)
|
||||
|
||||
### Bug fixes
|
||||
* **InfluxDB 0.12**: Fixed issue templating and `show tag values` query only returning tags for first measurement, fixes [#4726](https://github.com/grafana/grafana/issues/4726)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
influxdb:
|
||||
image: tutum/influxdb:latest
|
||||
image: tutum/influxdb:0.12
|
||||
ports:
|
||||
- "2004:2004"
|
||||
- "8083:8083"
|
||||
|
||||
@@ -11,7 +11,7 @@ page_keywords: grafana, installation, debian, ubuntu, guide
|
||||
Description | Download
|
||||
------------ | -------------
|
||||
Stable .deb for Debian-based Linux | [grafana_2.6.0_amd64.deb](https://grafanarel.s3.amazonaws.com/builds/grafana_2.6.0_amd64.deb)
|
||||
Beta .deb for Debian-based Linux | [grafana_3.0.0-beta51460725904_amd64.deb](https://grafanarel.s3.amazonaws.com/builds/grafana_3.0.0-beta51460725904_amd64.deb)
|
||||
Beta .deb for Debian-based Linux | [grafana_3.0.0-beta71462173753_amd64.deb](https://grafanarel.s3.amazonaws.com/builds/grafana_3.0.0-beta71462173753_amd64.deb)
|
||||
|
||||
## Install Stable
|
||||
|
||||
@@ -21,9 +21,9 @@ Beta .deb for Debian-based Linux | [grafana_3.0.0-beta51460725904_amd64.deb](h
|
||||
|
||||
## Install 3.0 Beta
|
||||
|
||||
$ wget https://grafanarel.s3.amazonaws.com/builds/grafana_3.0.0-beta51460725904_amd64.deb
|
||||
$ wget https://grafanarel.s3.amazonaws.com/builds/grafana_3.0.0-beta71462173753_amd64.deb
|
||||
$ sudo apt-get install -y adduser libfontconfig
|
||||
$ sudo dpkg -i grafana_3.0.0-beta51460725904_amd64.deb
|
||||
$ sudo dpkg -i grafana_3.0.0-beta71462173753_amd64.deb
|
||||
|
||||
## APT Repository
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ page_keywords: grafana, installation, centos, fedora, opensuse, redhat, guide
|
||||
Description | Download
|
||||
------------ | -------------
|
||||
Stable .RPM for CentOS / Fedora / OpenSuse / Redhat Linux | [grafana-2.6.0-1.x86_64.rpm](https://grafanarel.s3.amazonaws.com/builds/grafana-2.6.0-1.x86_64.rpm)
|
||||
Beta .RPM for CentOS / Fedor / OpenSuse / Redhat Linux | [grafana-3.0.0-beta51460725904.x86_64.rpm](https://grafanarel.s3.amazonaws.com/builds/grafana-3.0.0-beta51460725904§.x86_64.rpm)
|
||||
Beta .RPM for CentOS / Fedor / OpenSuse / Redhat Linux | [grafana-3.0.0-beta71462173753.x86_64.rpm](https://grafanarel.s3.amazonaws.com/builds/grafana-3.0.0-beta71462173753.x86_64.rpm)
|
||||
|
||||
## Install Stable Release from package file
|
||||
|
||||
@@ -34,18 +34,18 @@ Or install manually using `rpm`.
|
||||
|
||||
You can install Grafana using Yum directly.
|
||||
|
||||
$ sudo yum install https://grafanarel.s3.amazonaws.com/builds/grafana-3.0.0-beta51460725904.x86_64.rpm
|
||||
$ sudo yum install https://grafanarel.s3.amazonaws.com/builds/grafana-3.0.0-beta71462173753.x86_64.rpm
|
||||
|
||||
Or install manually using `rpm`.
|
||||
|
||||
#### On CentOS / Fedora / Redhat:
|
||||
|
||||
$ sudo yum install initscripts fontconfig
|
||||
$ sudo rpm -Uvh grafana-3.0.0-beta51460725904.x86_64.rpm
|
||||
$ sudo rpm -Uvh grafana-3.0.0-beta71462173753.x86_64.rpm
|
||||
|
||||
#### On OpenSuse:
|
||||
|
||||
$ sudo rpm -i --nodeps grafana-3.0.0-beta51460725904.x86_64.rpm
|
||||
$ sudo rpm -i --nodeps grafana-3.0.0-beta71462173753.x86_64.rpm
|
||||
|
||||
|
||||
## Install via YUM Repository
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"stable": "2.6.0",
|
||||
"testing": "3.0.0-beta5"
|
||||
"testing": "3.0.0-beta7"
|
||||
}
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
"company": "Coding Instinct AB"
|
||||
},
|
||||
"name": "grafana",
|
||||
"version": "3.0.0-beta6",
|
||||
"version": "3.0.0-beta7",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "http://github.com/grafana/grafana.git"
|
||||
|
||||
@@ -11,7 +11,6 @@ export function infoPopover() {
|
||||
template: '<i class="fa fa-info-circle"></i>',
|
||||
transclude: true,
|
||||
link: function(scope, elem, attrs, ctrl, transclude) {
|
||||
|
||||
var offset = attrs.offset || '0 -10px';
|
||||
var position = attrs.position || 'right middle';
|
||||
var classes = 'drop-help drop-hide-out-of-bounds';
|
||||
@@ -39,6 +38,7 @@ export function infoPopover() {
|
||||
position: position,
|
||||
classes: classes,
|
||||
openOn: openOn,
|
||||
hoverOpenDelay: 400,
|
||||
tetherOptions: {
|
||||
offset: offset
|
||||
}
|
||||
|
||||
@@ -7,36 +7,11 @@ define([
|
||||
function (angular, _, coreModule, config) {
|
||||
'use strict';
|
||||
|
||||
coreModule.default.service('datasourceSrv', function($q, $injector, $rootScope) {
|
||||
coreModule.default.service('datasourceSrv', function($q, $injector, $rootScope, templateSrv) {
|
||||
var self = this;
|
||||
|
||||
this.init = function() {
|
||||
this.datasources = {};
|
||||
this.metricSources = [];
|
||||
this.annotationSources = [];
|
||||
|
||||
_.each(config.datasources, function(value, key) {
|
||||
if (value.meta && value.meta.metrics) {
|
||||
self.metricSources.push({
|
||||
value: key === config.defaultDatasource ? null : key,
|
||||
name: key,
|
||||
meta: value.meta,
|
||||
});
|
||||
}
|
||||
if (value.meta && value.meta.annotations) {
|
||||
self.annotationSources.push(value);
|
||||
}
|
||||
});
|
||||
|
||||
this.metricSources.sort(function(a, b) {
|
||||
if (a.meta.builtIn || a.name > b.name) {
|
||||
return 1;
|
||||
}
|
||||
if (a.name < b.name) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
};
|
||||
|
||||
this.get = function(name) {
|
||||
@@ -44,6 +19,8 @@ function (angular, _, coreModule, config) {
|
||||
return this.get(config.defaultDatasource);
|
||||
}
|
||||
|
||||
name = templateSrv.replace(name);
|
||||
|
||||
if (this.datasources[name]) {
|
||||
return $q.when(this.datasources[name]);
|
||||
}
|
||||
@@ -89,11 +66,61 @@ function (angular, _, coreModule, config) {
|
||||
};
|
||||
|
||||
this.getAnnotationSources = function() {
|
||||
return this.annotationSources;
|
||||
return _.reduce(config.datasources, function(memo, value) {
|
||||
|
||||
if (value.meta && value.meta.annotations) {
|
||||
memo.push(value);
|
||||
}
|
||||
|
||||
return memo;
|
||||
}, []);
|
||||
};
|
||||
|
||||
this.getMetricSources = function() {
|
||||
return this.metricSources;
|
||||
this.getMetricSources = function(options) {
|
||||
var metricSources = [];
|
||||
|
||||
_.each(config.datasources, function(value, key) {
|
||||
if (value.meta && value.meta.metrics) {
|
||||
metricSources.push({
|
||||
value: key === config.defaultDatasource ? null : key,
|
||||
name: key,
|
||||
meta: value.meta,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (!options || !options.skipVariables) {
|
||||
// look for data source variables
|
||||
for (var i = 0; i < templateSrv.variables.length; i++) {
|
||||
var variable = templateSrv.variables[i];
|
||||
if (variable.type !== 'datasource') {
|
||||
continue;
|
||||
}
|
||||
|
||||
var first = variable.current.value;
|
||||
var ds = config.datasources[first];
|
||||
|
||||
if (ds) {
|
||||
metricSources.push({
|
||||
name: '$' + variable.name,
|
||||
value: '$' + variable.name,
|
||||
meta: ds.meta,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
metricSources.sort(function(a, b) {
|
||||
if (a.meta.builtIn || a.name > b.name) {
|
||||
return 1;
|
||||
}
|
||||
if (a.name < b.name) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
return metricSources;
|
||||
};
|
||||
|
||||
this.init();
|
||||
|
||||
@@ -19,7 +19,7 @@ function (angular, _, coreModule) {
|
||||
|
||||
if (_.isString(options)) {
|
||||
this.value = options;
|
||||
this.html = $sce.trustAsHtml(this.value);
|
||||
this.html = $sce.trustAsHtml(templateSrv.highlightVariablesAsHtml(this.value));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -184,6 +184,7 @@ function (angular, $, _, moment) {
|
||||
p.formatDate = function(date, format) {
|
||||
date = moment.isMoment(date) ? date : moment(date);
|
||||
format = format || 'YYYY-MM-DD HH:mm:ss';
|
||||
this.timezone = this.getTimezone();
|
||||
|
||||
return this.timezone === 'browser' ?
|
||||
moment(date).format(format) :
|
||||
|
||||
@@ -172,7 +172,7 @@ export class DashNavCtrl {
|
||||
var clone = $scope.dashboard.getSaveModelClone();
|
||||
var blob = new Blob([angular.toJson(clone, true)], { type: "application/json;charset=utf-8" });
|
||||
var wnd: any = window;
|
||||
wnd.saveAs(blob, $scope.dashboard.title + '-' + new Date().getTime());
|
||||
wnd.saveAs(blob, $scope.dashboard.title + '-' + new Date().getTime() + '.json');
|
||||
};
|
||||
|
||||
$scope.snapshot = function() {
|
||||
|
||||
@@ -63,6 +63,10 @@ export class MetricsDsSelectorCtrl {
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.current) {
|
||||
this.current = {name: dsValue + ' not found', value: null};
|
||||
}
|
||||
|
||||
this.dsSegment = uiSegmentSrv.newSegment(this.current.name);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ class MetricsPanelCtrl extends PanelCtrl {
|
||||
error: boolean;
|
||||
loading: boolean;
|
||||
datasource: any;
|
||||
datasourceName: any;
|
||||
$q: any;
|
||||
$timeout: any;
|
||||
datasourceSrv: any;
|
||||
@@ -244,6 +245,7 @@ class MetricsPanelCtrl extends PanelCtrl {
|
||||
}
|
||||
|
||||
this.panel.datasource = datasource.value;
|
||||
this.datasourceName = datasource.name;
|
||||
this.datasource = null;
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
@@ -44,8 +44,8 @@ export class PanelCtrl {
|
||||
this.pluginName = plugin.name;
|
||||
}
|
||||
|
||||
$scope.$on("refresh", this.refresh.bind(this));
|
||||
$scope.$on("render", this.render.bind(this));
|
||||
$scope.$on("refresh", () => this.refresh());
|
||||
$scope.$on("render", () => this.render());
|
||||
$scope.$on("$destroy", () => this.events.emit('panel-teardown'));
|
||||
}
|
||||
|
||||
|
||||
@@ -79,7 +79,10 @@ export class QueryRowCtrl {
|
||||
}
|
||||
|
||||
removeQuery() {
|
||||
delete this.panelCtrl.__collapsedQueryCache[this.target.refId];
|
||||
if (this.panelCtrl.__collapsedQueryCache) {
|
||||
delete this.panelCtrl.__collapsedQueryCache[this.target.refId];
|
||||
}
|
||||
|
||||
this.panel.targets = _.without(this.panel.targets, this.target);
|
||||
this.panelCtrl.refresh();
|
||||
}
|
||||
|
||||
@@ -20,6 +20,13 @@ function (angular, _) {
|
||||
multi: false,
|
||||
};
|
||||
|
||||
$scope.variableTypes = [
|
||||
{value: "query", text: "Query"},
|
||||
{value: "interval", text: "Interval"},
|
||||
{value: "datasource", text: "Data source"},
|
||||
{value: "custom", text: "Custom"},
|
||||
];
|
||||
|
||||
$scope.refreshOptions = [
|
||||
{value: 0, text: "Never"},
|
||||
{value: 1, text: "On Dashboard Load"},
|
||||
@@ -35,10 +42,16 @@ function (angular, _) {
|
||||
$scope.init = function() {
|
||||
$scope.mode = 'list';
|
||||
|
||||
$scope.datasourceTypes = {};
|
||||
$scope.datasources = _.filter(datasourceSrv.getMetricSources(), function(ds) {
|
||||
$scope.datasourceTypes[ds.meta.id] = {text: ds.meta.name, value: ds.meta.id};
|
||||
return !ds.meta.builtIn;
|
||||
});
|
||||
|
||||
$scope.datasourceTypes = _.map($scope.datasourceTypes, function(value) {
|
||||
return value;
|
||||
});
|
||||
|
||||
$scope.variables = templateSrv.variables;
|
||||
$scope.reset();
|
||||
|
||||
@@ -132,9 +145,16 @@ function (angular, _) {
|
||||
if ($scope.current.type === 'interval') {
|
||||
$scope.current.query = '1m,10m,30m,1h,6h,12h,1d,7d,14d,30d';
|
||||
}
|
||||
|
||||
if ($scope.current.type === 'query') {
|
||||
$scope.current.query = '';
|
||||
}
|
||||
|
||||
if ($scope.current.type === 'datasource') {
|
||||
$scope.current.query = $scope.datasourceTypes[0].value;
|
||||
$scope.current.regex = '';
|
||||
$scope.current.refresh = 1;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.removeVariable = function(variable) {
|
||||
|
||||
@@ -75,39 +75,49 @@
|
||||
<div class="gf-form-group">
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form max-width-19">
|
||||
<span class="gf-form-label width-7">Name</span>
|
||||
<input type="text" class="gf-form-input max-width-12" placeholder="name" ng-model='current.name'></input>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-4">Type</span>
|
||||
<div class="gf-form-select-wrapper">
|
||||
<select class="gf-form-input width-7" ng-model="current.type" ng-options="f for f in ['query', 'interval', 'custom']" ng-change="typeChanged()"></select>
|
||||
</div>
|
||||
<span class="gf-form-label width-6">Name</span>
|
||||
<input type="text" class="gf-form-input" placeholder="name" ng-model='current.name'></input>
|
||||
</div>
|
||||
<div class="gf-form max-width-19">
|
||||
<span class="gf-form-label width-7" ng-show="current.type === 'query'">Data source</span>
|
||||
<div class="gf-form-select-wrapper max-width-12" ng-show="current.type === 'query'">
|
||||
<select class="gf-form-input" ng-model="current.datasource" ng-options="f.value as f.name for f in datasources"></select>
|
||||
<span class="gf-form-label width-6">
|
||||
Type
|
||||
<info-popover mode="right-normal">
|
||||
<dl>
|
||||
<dt>Query</dt>
|
||||
<dd>Variable values are fetched from a metric names query to a data source</dd>
|
||||
<dt>Interval</dt>
|
||||
<dd>Timespan variable type</dd>
|
||||
<dt>Datasource</dt>
|
||||
<dd>Dynamically switch data sources using this type of variable</dd>
|
||||
<dt>Custom</dt>
|
||||
<dd>Define variable values manually</dd>
|
||||
</dl>
|
||||
<a href="http://docs.grafana.org/reference/templating" target="_blank">Templating docs</a>
|
||||
</info-popover>
|
||||
</span>
|
||||
<div class="gf-form-select-wrapper max-width-17">
|
||||
<select class="gf-form-input" ng-model="current.type" ng-options="f.value as f.text for f in variableTypes" ng-change="typeChanged()"></select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form max-width-19">
|
||||
<span class="gf-form-label width-7">Label</span>
|
||||
<input type="text" class="gf-form-input max-width-12" ng-model='current.label' placeholder="optional display name"></input>
|
||||
<span class="gf-form-label width-6">Label</span>
|
||||
<input type="text" class="gf-form-input" ng-model='current.label' placeholder="optional display name"></input>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-4">Hide</span>
|
||||
<div class="gf-form-select-wrapper">
|
||||
<select class="gf-form-input width-7" ng-model="current.hide" ng-options="f.value as f.text for f in hideOptions"></select>
|
||||
<div class="gf-form max-width-19">
|
||||
<span class="gf-form-label width-6">Hide</span>
|
||||
<div class="gf-form-select-wrapper max-width-15">
|
||||
<select class="gf-form-input" ng-model="current.hide" ng-options="f.value as f.text for f in hideOptions"></select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<h5 class="section-heading">Value Options</h5>
|
||||
<div ng-show="current.type === 'interval'" class="gf-form-group">
|
||||
<h5 class="section-heading">Interval Options</h5>
|
||||
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-9">Values</span>
|
||||
<input type="text" class="gf-form-input" placeholder="name" ng-model='current.query' placeholder="1m,10m,1h,6h,1d,7d" ng-model-onblur ng-change="runQuery()"></input>
|
||||
@@ -135,6 +145,7 @@
|
||||
</div>
|
||||
|
||||
<div ng-show="current.type === 'custom'" class="gf-form-group">
|
||||
<h5 class="section-heading">Custom Options</h5>
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-13">Values seperated by comma</span>
|
||||
<input type="text" class="gf-form-input" ng-model='current.query' ng-blur="runQuery()" placeholder="1, 10, 20, myvalue"></input>
|
||||
@@ -142,43 +153,69 @@
|
||||
</div>
|
||||
|
||||
<div ng-show="current.type === 'query'" class="gf-form-group">
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-7">Query</span>
|
||||
<input type="text" class="gf-form-input" ng-model='current.query' placeholder="metric name or tags query" ng-model-onblur ng-change="runQuery()"></input>
|
||||
<!-- <info-popover position="bottom center" wide="true"> -->
|
||||
<!-- Example queries: -->
|
||||
<!-- <ul> -->
|
||||
<!-- <li> -->
|
||||
<!-- <code>SHOW TAG VALUES WITH KEY = "hostname"</code> -->
|
||||
<!-- </li> -->
|
||||
<!-- <li> -->
|
||||
<!-- <code>SHOW TAG VALUES WITH KEY = "hostname"</code> -->
|
||||
<!-- </li> -->
|
||||
<!-- <li> -->
|
||||
<!-- <code>SHOW TAG VALUES WITH KEY = "hostname"</code> -->
|
||||
<!-- </li> -->
|
||||
<!-- <li> -->
|
||||
<!-- <a href="http://docs.grafana.org" target="_blank">Templating docs</a> -->
|
||||
<!-- </li> -->
|
||||
<!-- </ul> -->
|
||||
<!-- </info-popover> -->
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-7">
|
||||
Regex
|
||||
<tip>Optional, if you want to extract part of a series name or metric node segment</tip>
|
||||
</span>
|
||||
<input type="text" class="gf-form-input" ng-model='current.regex' placeholder="/.*-(.*)-.*/" ng-model-onblur ng-change="runQuery()"></input>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-7">Refresh</span>
|
||||
<select class="gf-form-input max-width-14" ng-model="current.refresh" ng-options="f.value as f.text for f in refreshOptions"></select>
|
||||
<tip>When to update the values of this variable, will slow down dashboard load / time change</tip>
|
||||
</div>
|
||||
</div>
|
||||
<h5 class="section-heading">Query Options</h5>
|
||||
|
||||
<div class="section gf-form-group" >
|
||||
<h5 class="section-heading">Selection Options</h5>
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form max-width-21">
|
||||
<span class="gf-form-label width-7" ng-show="current.type === 'query'">Data source</span>
|
||||
<div class="gf-form-select-wrapper max-width-14">
|
||||
<select class="gf-form-input" ng-model="current.datasource" ng-options="f.value as f.name for f in datasources"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gf-form max-width-21">
|
||||
<span class="gf-form-label width-7">
|
||||
Refresh
|
||||
<info-popover mode="right-normal">
|
||||
When to update the values of this variable.
|
||||
</info-popover>
|
||||
</span>
|
||||
<div class="gf-form-select-wrapper max-width-14">
|
||||
<select class="gf-form-input" ng-model="current.refresh" ng-options="f.value as f.text for f in refreshOptions"></select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-7">Query</span>
|
||||
<input type="text" class="gf-form-input" ng-model='current.query' placeholder="metric name or tags query" ng-model-onblur ng-change="runQuery()"></input>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-7">
|
||||
Regex
|
||||
<info-popover mode="right-normal">
|
||||
Optional, if you want to extract part of a series name or metric node segment.
|
||||
</info-popover>
|
||||
</span>
|
||||
<input type="text" class="gf-form-input" ng-model='current.regex' placeholder="/.*-(.*)-.*/" ng-model-onblur ng-change="runQuery()"></input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-show="current.type === 'datasource'" class="gf-form-group">
|
||||
<h5 class="section-heading">Data source options</h5>
|
||||
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label width-12">Type</label>
|
||||
<div class="gf-form-select-wrapper max-width-18">
|
||||
<select class="gf-form-input" ng-model="current.query" ng-options="f.value as f.text for f in datasourceTypes" ng-change="runQuery()"></select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label width-12">
|
||||
Instance name filter
|
||||
<info-popover mode="right-normal">
|
||||
Regex filter for which data source instances to choose from in
|
||||
the variable value dropdown. Leave empty for all.
|
||||
<br><br>
|
||||
Example: <code>/^prod/</code>
|
||||
|
||||
</info-popover>
|
||||
</label>
|
||||
<input type="text" class="gf-form-input max-width-18" ng-model='current.regex' placeholder="/.*-(.*)-.*/" ng-model-onblur ng-change="runQuery()"></input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section gf-form-group" ng-hide="current.type === 'datasource'">
|
||||
<h5 class="section-heading">Selection Options</h5>
|
||||
<div class="section">
|
||||
<gf-form-switch class="gf-form"
|
||||
label="Multi-value"
|
||||
|
||||
@@ -63,7 +63,9 @@ function (angular, _, kbn) {
|
||||
// determine our dependencies.
|
||||
if (variable.type === "query") {
|
||||
_.forEach(this.variables, function(v) {
|
||||
if (templateSrv.containsVariable(variable.query, v.name)) {
|
||||
// both query and datasource can contain variable
|
||||
if (templateSrv.containsVariable(variable.query, v.name) ||
|
||||
templateSrv.containsVariable(variable.datasource, v.name)) {
|
||||
dependencies.push(self.variableLock[v.name].promise);
|
||||
}
|
||||
});
|
||||
@@ -149,7 +151,8 @@ function (angular, _, kbn) {
|
||||
if (otherVariable === updatedVariable) {
|
||||
return;
|
||||
}
|
||||
if (templateSrv.containsVariable(otherVariable.query, updatedVariable.name)) {
|
||||
if (templateSrv.containsVariable(otherVariable.query, updatedVariable.name) ||
|
||||
templateSrv.containsVariable(otherVariable.datasource, updatedVariable.name)) {
|
||||
return self.updateOptions(otherVariable);
|
||||
}
|
||||
});
|
||||
@@ -158,6 +161,11 @@ function (angular, _, kbn) {
|
||||
};
|
||||
|
||||
this._updateNonQueryVariable = function(variable) {
|
||||
if (variable.type === 'datasource') {
|
||||
self.updateDataSourceVariable(variable);
|
||||
return;
|
||||
}
|
||||
|
||||
// extract options in comma seperated string
|
||||
variable.options = _.map(variable.query.split(/[,]+/), function(text) {
|
||||
return { text: text.trim(), value: text.trim() };
|
||||
@@ -172,6 +180,36 @@ function (angular, _, kbn) {
|
||||
}
|
||||
};
|
||||
|
||||
this.updateDataSourceVariable = function(variable) {
|
||||
var options = [];
|
||||
var sources = datasourceSrv.getMetricSources({skipVariables: true});
|
||||
var regex;
|
||||
|
||||
if (variable.regex) {
|
||||
regex = kbn.stringToJsRegex(templateSrv.replace(variable.regex));
|
||||
}
|
||||
|
||||
for (var i = 0; i < sources.length; i++) {
|
||||
var source = sources[i];
|
||||
// must match on type
|
||||
if (source.meta.id !== variable.query) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (regex && !regex.exec(source.name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
options.push({text: source.name, value: source.name});
|
||||
}
|
||||
|
||||
if (options.length === 0) {
|
||||
options.push({text: 'No datasurces found', value: ''});
|
||||
}
|
||||
|
||||
variable.options = options;
|
||||
};
|
||||
|
||||
this.updateOptions = function(variable) {
|
||||
if (variable.type !== 'query') {
|
||||
self._updateNonQueryVariable(variable);
|
||||
@@ -288,9 +326,7 @@ function (angular, _, kbn) {
|
||||
options[value] = {text: text, value: value};
|
||||
}
|
||||
|
||||
return _.map(_.keys(options).sort(), function(key) {
|
||||
return options[key];
|
||||
});
|
||||
return _.sortBy(options, 'text');
|
||||
};
|
||||
|
||||
this.addAllOption = function(variable) {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
</label>
|
||||
|
||||
<metric-segment-model property="agg.type" options="bucketAggTypes" on-change="onTypeChanged()" custom="false" css-class="width-10"></metric-segment-model>
|
||||
<metric-segment-model ng-if="agg.field" property="agg.field" get-options="getFieldsInternal()" on-change="onChange()" css-class="width-12"></metric-segment>
|
||||
<metric-segment-model ng-if="agg.field" property="agg.field" get-options="getFieldsInternal()" on-change="onChange()" css-class="width-12"></metric-segment-model>
|
||||
</div>
|
||||
|
||||
<div class="gf-form gf-form--grow">
|
||||
|
||||
@@ -31,7 +31,7 @@ export function GraphiteDatasource(instanceSettings, $q, backendSrv, templateSrv
|
||||
}
|
||||
|
||||
if (options.format === 'png') {
|
||||
return $q.when(this.url + '/render' + '?' + params.join('&'));
|
||||
return $q.when({data: this.url + '/render' + '?' + params.join('&')});
|
||||
}
|
||||
|
||||
var httpOptions: any = {method: this.render_method, url: '/render'};
|
||||
|
||||
@@ -70,6 +70,10 @@
|
||||
</influx-query-part-editor>
|
||||
</div>
|
||||
|
||||
<div class="gf-form">
|
||||
<metric-segment segment="ctrl.groupBySegment" get-options="ctrl.getGroupByOptions()" on-change="ctrl.groupByAction(part, $index)"></metric-segment>
|
||||
</div>
|
||||
|
||||
<div class="gf-form gf-form--grow">
|
||||
<div class="gf-form-label gf-form-label--grow"></div>
|
||||
</div>
|
||||
|
||||
@@ -239,6 +239,24 @@ QueryPartDef.register({
|
||||
renderer: functionRenderer,
|
||||
});
|
||||
|
||||
QueryPartDef.register({
|
||||
type: 'difference',
|
||||
addStrategy: addTransformationStrategy,
|
||||
category: categories.Transformations,
|
||||
params: [],
|
||||
defaultParams: [],
|
||||
renderer: functionRenderer,
|
||||
});
|
||||
|
||||
QueryPartDef.register({
|
||||
type: 'moving_average',
|
||||
addStrategy: addTransformationStrategy,
|
||||
category: categories.Transformations,
|
||||
params: [{ name: "window", type: "number", options: [5, 10, 20, 30, 40]}],
|
||||
defaultParams: [10],
|
||||
renderer: functionRenderer,
|
||||
});
|
||||
|
||||
QueryPartDef.register({
|
||||
type: 'stddev',
|
||||
addStrategy: addTransformationStrategy,
|
||||
|
||||
@@ -63,11 +63,14 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS
|
||||
var end = getPrometheusTime(options.range.to, true);
|
||||
|
||||
var queries = [];
|
||||
var activeTargets = [];
|
||||
|
||||
options = _.clone(options);
|
||||
_.each(options.targets, _.bind(function(target) {
|
||||
if (!target.expr || target.hide) {
|
||||
return;
|
||||
}
|
||||
activeTargets.push(target);
|
||||
|
||||
var query: any = {};
|
||||
query.expr = templateSrv.replace(target.expr, options.scopedVars, interpolateQueryExpr);
|
||||
@@ -109,7 +112,7 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS
|
||||
delete self.lastErrors.query;
|
||||
|
||||
_.each(response.data.data.result, function(metricData) {
|
||||
result.push(self.transformMetricData(metricData, options.targets[index], start, end));
|
||||
result.push(self.transformMetricData(metricData, activeTargets[index], start, end));
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.dashnav-dashboards-btn a {
|
||||
.page-dashboard .navbar-page-btn {
|
||||
max-width: none;
|
||||
}
|
||||
.gf-timepicker-nav-btn {
|
||||
|
||||
@@ -11,15 +11,12 @@ pre {
|
||||
background-color: $code-tag-bg;
|
||||
color: $text-color;
|
||||
border: 1px solid $code-tag-border;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
// Inline code
|
||||
code {
|
||||
color: $text-color;
|
||||
background-color: $code-tag-bg;
|
||||
border: 1px solid darken($code-tag-bg, 15%);
|
||||
white-space: nowrap;
|
||||
padding: 2px 5px;
|
||||
margin: 0 2px;
|
||||
@@ -27,7 +24,7 @@ code {
|
||||
|
||||
code.code--small {
|
||||
font-size: $font-size-xs;
|
||||
padding: 5px;
|
||||
padding: 0.2rem;
|
||||
margin: 0 2px;
|
||||
}
|
||||
|
||||
@@ -41,6 +38,7 @@ pre {
|
||||
white-space: pre;
|
||||
white-space: pre-wrap;
|
||||
background-color: $code-tag-bg;
|
||||
padding: 10px;
|
||||
|
||||
// Make prettyprint styles more spaced out for readability
|
||||
&.prettyprint {
|
||||
|
||||
@@ -92,6 +92,7 @@ define([
|
||||
var ds = {};
|
||||
ds.metricFindQuery = sinon.stub().returns(ctx.$q.when(scenario.queryResult));
|
||||
ctx.datasourceSrv.get = sinon.stub().returns(ctx.$q.when(ds));
|
||||
ctx.datasourceSrv.getMetricSources = sinon.stub().returns(scenario.metricSources);
|
||||
|
||||
ctx.service.updateOptions(scenario.variable);
|
||||
ctx.$rootScope.$digest();
|
||||
@@ -137,7 +138,6 @@ define([
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describeUpdateVariable('interval variable with auto', function(scenario) {
|
||||
scenario.setup(function() {
|
||||
scenario.variable = { type: 'interval', query: '1s,2h,5h,1d', name: 'test', auto: true, auto_count: 10 };
|
||||
@@ -237,7 +237,7 @@ define([
|
||||
});
|
||||
});
|
||||
|
||||
describeUpdateVariable('regex pattern without slashes', function(scenario) {
|
||||
describeUpdateVariable('regex pattern without slashes', function(scenario) {
|
||||
scenario.setup(function() {
|
||||
scenario.variable = { type: 'query', query: 'apps.*', name: 'test' };
|
||||
scenario.variable.regex = 'backend_01';
|
||||
@@ -284,6 +284,23 @@ define([
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
describeUpdateVariable('datasource variable with regex filter', function(scenario) {
|
||||
scenario.setup(function() {
|
||||
scenario.variable = {type: 'datasource', query: 'graphite', name: 'test', current: {}, regex: '/pee$/' };
|
||||
scenario.metricSources = [
|
||||
{name: 'backend1', meta: {id: 'influx'}},
|
||||
{name: 'backend2_pee', meta: {id: 'graphite'}},
|
||||
{name: 'backend3', meta: {id: 'graphite'}},
|
||||
{name: 'backend4_pee', meta: {id: 'graphite'}},
|
||||
];
|
||||
});
|
||||
|
||||
it('should set only contain graphite ds and filtered using regex', function() {
|
||||
expect(scenario.variable.options.length).to.be(2);
|
||||
expect(scenario.variable.options[0].value).to.be('backend2_pee');
|
||||
expect(scenario.variable.options[1].value).to.be('backend4_pee');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user