mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Merge branch 'query-editor-breakout'
Conflicts: CHANGELOG.md
This commit is contained in:
commit
9a9c9b2b12
12
CHANGELOG.md
12
CHANGELOG.md
@ -1,12 +1,22 @@
|
||||
# 2.2 (unreleased)
|
||||
|
||||
**New Features && Enhancements**
|
||||
** New Feature: Mix data sources **
|
||||
A built in data source is now available named `-- Mixed --`, When picked in the metrics tab,
|
||||
it allows you to add queries of differnet data source types & instances to the same graph/panel!
|
||||
[Issue #436](https://github.com/grafana/grafana/issues/436)
|
||||
|
||||
** Other new Features && Enhancements**
|
||||
- [Issue #2457](https://github.com/grafana/grafana/issues/2457). Admin: admin page for all grafana organizations (list / edit view)
|
||||
- [Issue #1186](https://github.com/grafana/grafana/issues/1186). Time Picker: New option `today`, will set time range from midnight to now
|
||||
|
||||
**Fixes**
|
||||
- [Issue #2490](https://github.com/grafana/grafana/issues/2490). Graphite: Dashboard import was broken in 2.1 and 2.1.1, working now
|
||||
|
||||
**Breaking Changes**
|
||||
- Notice to makers/users of custom data sources, there is a minor breaking change in 2.2 that
|
||||
require and update to custom data sources for them to work in 2.2. [Read this doc](https://github.com/grafana/grafana/tree/master/docs/sources/datasources/plugin_api.md) for more on the
|
||||
data source api change.
|
||||
|
||||
# 2.1.x (currently unreleased patch branch)
|
||||
|
||||
**Fixes**
|
||||
|
40
docs/sources/datasources/plugin_api.md
Normal file
40
docs/sources/datasources/plugin_api.md
Normal file
@ -0,0 +1,40 @@
|
||||
----
|
||||
page_title: Data source Plugin API
|
||||
page_description: Data Source Plugin Description
|
||||
page_keywords: grafana, data source, plugin, api, docs
|
||||
---
|
||||
|
||||
# Data source plugin API
|
||||
|
||||
All data sources in Grafana are implemented as plugins.
|
||||
|
||||
## Breaking change in 2.2
|
||||
|
||||
In Grafana 2.2 a breaking change was introduced for how data source query editors
|
||||
are structured, defined and loaded. This was in order to support mixing multiple data sources
|
||||
in the same panel.
|
||||
|
||||
In Grafana 2.2, the query editor is no longer defined using the partials section in
|
||||
`plugin.json`, but defined via an angular directive named using convention naming
|
||||
scheme like `metricQueryEditor<data source type name>`. For example
|
||||
|
||||
Graphite defines a directive like this:
|
||||
|
||||
```javascript
|
||||
module.directive('metricQueryEditorGraphite', function() {
|
||||
return {controller: 'GraphiteQueryCtrl', templateUrl: 'app/plugins/datasource/graphite/partials/query.editor.html'};
|
||||
});
|
||||
```
|
||||
|
||||
Even though the data source type name is with lowercase `g`, the directive uses capital `G` in `Graphite` because
|
||||
that is how angular directives needs to be named in order to match an element with name `<metric-query-editor-graphite />`.
|
||||
You also specify the query controller here instead of in the query.editor.html partial like before.
|
||||
|
||||
### query.editor.html
|
||||
|
||||
This partial needs to be updated, remove the `np-repeat` this is done in the outer partial now,m the query.editor.html
|
||||
should only render a single query. Take a look at the Graphite or InfluxDB partials for `query.editor.html` for reference.
|
||||
You should also add a `tight-form-item` with `{{target.refId}}`, all queries needs to be assigned a letter (`refId`).
|
||||
These query reference letters are going to be utilized in a later feature.
|
||||
|
||||
|
@ -112,5 +112,13 @@ func UpdateDataSource(c *middleware.Context, cmd m.UpdateDataSourceCommand) {
|
||||
}
|
||||
|
||||
func GetDataSourcePlugins(c *middleware.Context) {
|
||||
c.JSON(200, plugins.DataSources)
|
||||
dsList := make(map[string]interface{})
|
||||
|
||||
for key, value := range plugins.DataSources {
|
||||
if value.(map[string]interface{})["builtIn"] == nil {
|
||||
dsList[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(200, dsList)
|
||||
}
|
||||
|
@ -86,11 +86,17 @@ func getFrontendSettingsMap(c *middleware.Context) (map[string]interface{}, erro
|
||||
|
||||
// add grafana backend data source
|
||||
grafanaDatasourceMeta, _ := plugins.DataSources["grafana"]
|
||||
datasources["grafana"] = map[string]interface{}{
|
||||
datasources["-- Grafana --"] = map[string]interface{}{
|
||||
"type": "grafana",
|
||||
"meta": grafanaDatasourceMeta,
|
||||
}
|
||||
|
||||
// add mixed backend data source
|
||||
datasources["-- Mixed --"] = map[string]interface{}{
|
||||
"type": "mixed",
|
||||
"meta": plugins.DataSources["mixed"],
|
||||
}
|
||||
|
||||
if defaultDatasource == "" {
|
||||
defaultDatasource = "grafana"
|
||||
}
|
||||
|
@ -16,8 +16,11 @@ function (angular) {
|
||||
}
|
||||
setTimeout(function() {
|
||||
element.focus();
|
||||
var pos = element.val().length * 2;
|
||||
element[0].setSelectionRange(pos, pos);
|
||||
var domEl = element[0];
|
||||
if (domEl.setSelectionRange) {
|
||||
var pos = element.val().length * 2;
|
||||
domEl.setSelectionRange(pos, pos);
|
||||
}
|
||||
}, 200);
|
||||
},true);
|
||||
};
|
||||
|
@ -15,7 +15,7 @@ function (angular, app, _, $) {
|
||||
' spellcheck="false" style="display:none"></input>';
|
||||
|
||||
var buttonTemplate = '<a class="tight-form-item" ng-class="segment.cssClass" ' +
|
||||
'tabindex="1" focus-me="segment.focus" ng-bind-html="segment.html"></a>';
|
||||
'tabindex="1" give-focus="segment.focus" ng-bind-html="segment.html"></a>';
|
||||
|
||||
return {
|
||||
scope: {
|
||||
|
@ -72,8 +72,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-include src="currentDatasource.meta.partials.annotations">
|
||||
</div>
|
||||
<datasource-editor-view datasource="currentAnnotation.datasource" name="annotations-query-editor"></datasource-editor-view>
|
||||
|
||||
<br>
|
||||
<button ng-show="editor.index === 1" type="button" class="btn btn-success" ng-click="add()">Add</button>
|
||||
|
@ -6,35 +6,108 @@ define([
|
||||
function (angular, $, config) {
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('grafana.directives')
|
||||
.directive('panelLoader', function($compile, $parse) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
link: function(scope, elem, attr) {
|
||||
var getter = $parse(attr.type), panelType = getter(scope);
|
||||
var panelPath = config.panels[panelType].path;
|
||||
var module = angular.module('grafana.directives');
|
||||
|
||||
scope.require([panelPath + "/module"], function () {
|
||||
var panelEl = angular.element(document.createElement('grafana-panel-' + panelType));
|
||||
module.directive('panelLoader', function($compile, $parse) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
link: function(scope, elem, attr) {
|
||||
var getter = $parse(attr.type), panelType = getter(scope);
|
||||
var panelPath = config.panels[panelType].path;
|
||||
|
||||
scope.require([panelPath + "/module"], function () {
|
||||
var panelEl = angular.element(document.createElement('grafana-panel-' + panelType));
|
||||
elem.append(panelEl);
|
||||
$compile(panelEl)(scope);
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
module.directive('grafanaPanel', function() {
|
||||
return {
|
||||
restrict: 'E',
|
||||
templateUrl: 'app/features/panel/partials/panel.html',
|
||||
transclude: true,
|
||||
link: function(scope, elem) {
|
||||
var panelContainer = elem.find('.panel-container');
|
||||
|
||||
scope.$watchGroup(['fullscreen', 'height', 'panel.height', 'row.height'], function() {
|
||||
panelContainer.css({ minHeight: scope.height || scope.panel.height || scope.row.height, display: 'block' });
|
||||
elem.toggleClass('panel-fullscreen', scope.fullscreen ? true : false);
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
module.service('dynamicDirectiveSrv', function($compile, $parse, datasourceSrv) {
|
||||
var self = this;
|
||||
|
||||
this.addDirective = function(options, type, editorScope) {
|
||||
var panelEl = angular.element(document.createElement(options.name + '-' + type));
|
||||
options.parentElem.append(panelEl);
|
||||
$compile(panelEl)(editorScope);
|
||||
};
|
||||
|
||||
this.define = function(options) {
|
||||
var editorScope;
|
||||
options.scope.$watch(options.datasourceProperty, function(newVal) {
|
||||
if (editorScope) {
|
||||
editorScope.$destroy();
|
||||
options.parentElem.empty();
|
||||
}
|
||||
|
||||
editorScope = options.scope.$new();
|
||||
datasourceSrv.get(newVal).then(function(ds) {
|
||||
self.addDirective(options, ds.meta.type, editorScope);
|
||||
});
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
module.directive('queryEditorLoader', function($compile, $parse, datasourceSrv) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
link: function(scope, elem) {
|
||||
var editorScope;
|
||||
|
||||
scope.$watch("panel.datasource", function() {
|
||||
var datasource = scope.target.datasource || scope.panel.datasource;
|
||||
|
||||
datasourceSrv.get(datasource).then(function(ds) {
|
||||
if (editorScope) {
|
||||
editorScope.$destroy();
|
||||
elem.empty();
|
||||
}
|
||||
|
||||
editorScope = scope.$new();
|
||||
editorScope.datasource = ds;
|
||||
|
||||
if (!scope.target.refId) {
|
||||
scope.target.refId = 'A';
|
||||
}
|
||||
|
||||
var panelEl = angular.element(document.createElement('metric-query-editor-' + ds.meta.type));
|
||||
elem.append(panelEl);
|
||||
$compile(panelEl)(scope);
|
||||
$compile(panelEl)(editorScope);
|
||||
});
|
||||
}
|
||||
};
|
||||
}).directive('grafanaPanel', function() {
|
||||
return {
|
||||
restrict: 'E',
|
||||
templateUrl: 'app/features/panel/partials/panel.html',
|
||||
transclude: true,
|
||||
link: function(scope, elem) {
|
||||
var panelContainer = elem.find('.panel-container');
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
module.directive('datasourceEditorView', function(dynamicDirectiveSrv) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
link: function(scope, elem, attrs) {
|
||||
dynamicDirectiveSrv.define({
|
||||
datasourceProperty: attrs.datasource,
|
||||
name: attrs.name,
|
||||
scope: scope,
|
||||
parentElem: elem,
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
scope.$watchGroup(['fullscreen', 'height', 'panel.height', 'row.height'], function() {
|
||||
panelContainer.css({ minHeight: scope.height || scope.panel.height || scope.row.height, display: 'block' });
|
||||
elem.toggleClass('panel-fullscreen', scope.fullscreen ? true : false);
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
|
@ -43,8 +43,21 @@ function (angular, _, config) {
|
||||
});
|
||||
};
|
||||
|
||||
$scope.addDataQuery = function() {
|
||||
$scope.panel.targets.push({target: ''});
|
||||
$scope.addDataQuery = function(datasource) {
|
||||
var letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
var target = {};
|
||||
|
||||
if (datasource) {
|
||||
target.datasource = datasource.name;
|
||||
}
|
||||
|
||||
target.refId = _.find(letters, function(refId) {
|
||||
return _.every($scope.panel.targets, function(other) {
|
||||
return other.refId !== refId;
|
||||
});
|
||||
});
|
||||
|
||||
$scope.panel.targets.push(target);
|
||||
};
|
||||
|
||||
$scope.removeDataQuery = function (query) {
|
||||
@ -53,7 +66,23 @@ function (angular, _, config) {
|
||||
};
|
||||
|
||||
$scope.setDatasource = function(datasource) {
|
||||
$scope.panel.datasource = datasource;
|
||||
// switching to mixed
|
||||
if (datasource.meta.mixed) {
|
||||
_.each($scope.panel.targets, function(target) {
|
||||
target.datasource = $scope.panel.datasource;
|
||||
if (target.datasource === null) {
|
||||
target.datasource = config.defaultDatasource;
|
||||
}
|
||||
});
|
||||
}
|
||||
// switching from mixed
|
||||
else if ($scope.datasource && $scope.datasource.meta.mixed) {
|
||||
_.each($scope.panel.targets, function(target) {
|
||||
delete target.datasource;
|
||||
});
|
||||
}
|
||||
|
||||
$scope.panel.datasource = datasource.value;
|
||||
$scope.datasource = null;
|
||||
$scope.get_data();
|
||||
};
|
||||
|
@ -23,7 +23,10 @@ function (angular, _) {
|
||||
|
||||
$scope.init = function() {
|
||||
$scope.editor = { index: 0 };
|
||||
$scope.datasources = datasourceSrv.getMetricSources();
|
||||
$scope.datasources = _.filter(datasourceSrv.getMetricSources(), function(ds) {
|
||||
return !ds.meta.builtIn;
|
||||
});
|
||||
|
||||
$scope.variables = templateSrv.variables;
|
||||
$scope.reset();
|
||||
|
||||
|
@ -1,24 +1,48 @@
|
||||
<div ng-include src="datasource.meta.partials.query"></div>
|
||||
<div class="editor-row">
|
||||
|
||||
<div class="tight-form-container">
|
||||
<query-editor-loader ng-repeat="target in panel.targets" ng-class="{'tight-form-disabled': target.hide}" >
|
||||
</query-editor-loader>
|
||||
</div>
|
||||
|
||||
<div class="editor-row" style="margin-top: 30px">
|
||||
<button class="btn btn-inverse pull-right" ng-click="addDataQuery(panel.target)">
|
||||
<i class="fa fa-plus"></i>
|
||||
Add query
|
||||
</button>
|
||||
|
||||
<div class="pull-right dropdown" style="margin-right: 10px;">
|
||||
<button class="btn btn-inverse dropdown-toggle" data-toggle="dropdown" bs-tooltip="'Datasource'">
|
||||
<i class="fa fa-database"></i>
|
||||
{{datasource.name}} <span class="caret"></span>
|
||||
<div style="margin: 20px 0 0 0">
|
||||
<button class="btn btn-inverse" ng-click="addDataQuery()" ng-hide="datasource.meta.mixed">
|
||||
<i class="fa fa-plus"></i>
|
||||
Query
|
||||
</button>
|
||||
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li ng-repeat="datasource in datasources" role="menuitem">
|
||||
<a ng-click="setDatasource(datasource.value);">{{datasource.name}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="dropdown" ng-if="datasource.meta.mixed">
|
||||
<button class="btn btn-inverse dropdown-toggle" data-toggle="dropdown">
|
||||
<i class="fa fa-plus"></i>
|
||||
Query <span class="caret"></span>
|
||||
</button>
|
||||
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li ng-repeat="datasource in datasources" role="menuitem" ng-hide="datasource.meta.builtIn">
|
||||
<a ng-click="addDataQuery(datasource);">{{datasource.name}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<datasource-editor-view datasource="panel.datasource" name="metric-query-options"></datasource-editor-view>
|
||||
</div>
|
||||
|
||||
<div class="editor-row" style="margin-top: 30px">
|
||||
|
||||
<div class="pull-right dropdown" style="margin-right: 10px;">
|
||||
<button class="btn btn-inverse dropdown-toggle" data-toggle="dropdown" bs-tooltip="'Datasource'">
|
||||
<i class="fa fa-database"></i>
|
||||
{{datasource.name}} <span class="caret"></span>
|
||||
</button>
|
||||
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li ng-repeat="datasource in datasources" role="menuitem">
|
||||
<a ng-click="setDatasource(datasource);">{{datasource.name}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
|
@ -3,7 +3,8 @@ define([
|
||||
'lodash',
|
||||
'config',
|
||||
'kbn',
|
||||
'moment'
|
||||
'moment',
|
||||
'./directives'
|
||||
],
|
||||
function (angular, _, config, kbn, moment) {
|
||||
'use strict';
|
||||
|
13
public/app/plugins/datasource/elasticsearch/directives.js
Normal file
13
public/app/plugins/datasource/elasticsearch/directives.js
Normal file
@ -0,0 +1,13 @@
|
||||
define([
|
||||
'angular',
|
||||
],
|
||||
function (angular) {
|
||||
'use strict';
|
||||
|
||||
var module = angular.module('grafana.directives');
|
||||
|
||||
module.directive('annotationsQueryEditorElasticsearch', function() {
|
||||
return {templateUrl: 'app/plugins/datasource/elasticsearch/partials/annotations.editor.html'};
|
||||
});
|
||||
|
||||
});
|
@ -2,6 +2,7 @@ define([
|
||||
'angular',
|
||||
'lodash',
|
||||
'kbn',
|
||||
'./directives',
|
||||
],
|
||||
function (angular, _, kbn) {
|
||||
'use strict';
|
||||
@ -13,16 +14,6 @@ function (angular, _, kbn) {
|
||||
function GrafanaDatasource() {
|
||||
}
|
||||
|
||||
GrafanaDatasource.prototype.getDashboard = function(slug, isTemp) {
|
||||
var url = '/dashboards/' + slug;
|
||||
|
||||
if (isTemp) {
|
||||
url = '/temp/' + slug;
|
||||
}
|
||||
|
||||
return backendSrv.get('/api/dashboards/db/' + slug);
|
||||
};
|
||||
|
||||
GrafanaDatasource.prototype.query = function(options) {
|
||||
// get from & to in seconds
|
||||
var from = kbn.parseDate(options.range.from).getTime();
|
||||
@ -35,36 +26,6 @@ function (angular, _, kbn) {
|
||||
return $q.when([]);
|
||||
};
|
||||
|
||||
GrafanaDatasource.prototype.starDashboard = function(dashId) {
|
||||
return backendSrv.post('/api/user/stars/dashboard/' + dashId);
|
||||
};
|
||||
|
||||
GrafanaDatasource.prototype.unstarDashboard = function(dashId) {
|
||||
return backendSrv.delete('/api/user/stars/dashboard/' + dashId);
|
||||
};
|
||||
|
||||
GrafanaDatasource.prototype.saveDashboard = function(dashboard) {
|
||||
return backendSrv.post('/api/dashboards/db/', { dashboard: dashboard })
|
||||
.then(function(data) {
|
||||
return { title: dashboard.title, url: '/dashboard/db/' + data.slug };
|
||||
}, function(err) {
|
||||
err.isHandled = true;
|
||||
err.data = err.data || {};
|
||||
throw err.data.message || "Unknown error";
|
||||
});
|
||||
};
|
||||
|
||||
GrafanaDatasource.prototype.deleteDashboard = function(id) {
|
||||
return backendSrv.delete('/api/dashboards/db/' + id);
|
||||
};
|
||||
|
||||
GrafanaDatasource.prototype.searchDashboards = function(query) {
|
||||
return backendSrv.get('/api/search/', query)
|
||||
.then(function(data) {
|
||||
return data;
|
||||
});
|
||||
};
|
||||
|
||||
return GrafanaDatasource;
|
||||
|
||||
});
|
||||
|
13
public/app/plugins/datasource/grafana/directives.js
Normal file
13
public/app/plugins/datasource/grafana/directives.js
Normal file
@ -0,0 +1,13 @@
|
||||
define([
|
||||
'angular',
|
||||
],
|
||||
function (angular) {
|
||||
'use strict';
|
||||
|
||||
var module = angular.module('grafana.directives');
|
||||
|
||||
module.directive('metricQueryEditorGrafana', function() {
|
||||
return {templateUrl: 'app/plugins/datasource/grafana/partials/query.editor.html'};
|
||||
});
|
||||
|
||||
});
|
@ -1,16 +1,56 @@
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list pull-right">
|
||||
<li ng-show="parserError" class="tight-form-item">
|
||||
<a bs-tooltip="parserError" style="color: rgb(229, 189, 28)" role="menuitem">
|
||||
<i class="fa fa-warning"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
<div class="dropdown">
|
||||
<a class="pointer dropdown-toggle" data-toggle="dropdown" tabindex="1">
|
||||
<i class="fa fa-bars"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu pull-right" role="menu">
|
||||
<li role="menuitem">
|
||||
<a tabindex="1"
|
||||
ng-click="duplicate()">
|
||||
Duplicate
|
||||
</a>
|
||||
</li>
|
||||
<li role="menuitem">
|
||||
<a tabindex="1"
|
||||
ng-click="moveMetricQuery($index, $index-1)">
|
||||
Move up
|
||||
</a>
|
||||
</li>
|
||||
<li role="menuitem">
|
||||
<a tabindex="1"
|
||||
ng-click="moveMetricQuery($index, $index+1)">
|
||||
Move down
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
<li class="tight-form-item last">
|
||||
<a class="pointer" tabindex="1" ng-click="removeDataQuery(target)">
|
||||
<i class="fa fa-remove"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="fluid-row" style="margin-top: 20px">
|
||||
<div class="span2"></div>
|
||||
<div class="grafana-info-box span8">
|
||||
<h5>Test graph</h5>
|
||||
|
||||
<p>
|
||||
This is just a test data source that generates random walk series. If this is your only data source
|
||||
open the left side menu and navigate to the data sources admin screen and add your data sources (you need to be
|
||||
logged in to do this). You can change data source using the button to the left of the <strong>Add query</strong> button.
|
||||
</p>
|
||||
</div>
|
||||
<div class="span2"></div>
|
||||
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item" style="min-width: 15px; text-align: center">
|
||||
{{target.refId}}
|
||||
</li>
|
||||
<li>
|
||||
<a class="tight-form-item" ng-click="target.hide = !target.hide; get_data();" role="menuitem">
|
||||
<i class="fa fa-eye"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
Test metric (fake data source)
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
|
@ -1,15 +1,11 @@
|
||||
{
|
||||
"pluginType": "datasource",
|
||||
"name": "Grafana (for testing)",
|
||||
"name": "Grafana",
|
||||
"builtIn": true,
|
||||
|
||||
"type": "grafana",
|
||||
"serviceName": "GrafanaDatasource",
|
||||
|
||||
"module": "plugins/datasource/grafana/datasource",
|
||||
|
||||
"partials": {
|
||||
"query": "app/plugins/datasource/grafana/partials/query.editor.html"
|
||||
},
|
||||
|
||||
"metrics": true
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ define([
|
||||
'config',
|
||||
'kbn',
|
||||
'moment',
|
||||
'./directives',
|
||||
'./queryCtrl',
|
||||
'./funcEditor',
|
||||
'./addGraphiteFunc',
|
||||
@ -228,21 +229,13 @@ function (angular, _, $, config, kbn, moment) {
|
||||
return backendSrv.datasourceRequest(options);
|
||||
};
|
||||
|
||||
GraphiteDatasource.prototype._seriesRefLetters = [
|
||||
'#A', '#B', '#C', '#D',
|
||||
'#E', '#F', '#G', '#H',
|
||||
'#I', '#J', '#K', '#L',
|
||||
'#M', '#N', '#O', '#P',
|
||||
'#Q', '#R', '#S', '#T',
|
||||
'#U', '#V', '#W', '#X',
|
||||
'#Y', '#Z'
|
||||
];
|
||||
GraphiteDatasource.prototype._seriesRefLetters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
|
||||
GraphiteDatasource.prototype.buildGraphiteParams = function(options, scopedVars) {
|
||||
var graphite_options = ['from', 'until', 'rawData', 'format', 'maxDataPoints', 'cacheTimeout'];
|
||||
var clean_options = [], targets = {};
|
||||
var target, targetValue, i;
|
||||
var regex = /(\#[A-Z])/g;
|
||||
var regex = /\#([A-Z])/g;
|
||||
var intervalFormatFixRegex = /'(\d+)m'/gi;
|
||||
|
||||
if (options.format !== 'png') {
|
||||
@ -259,13 +252,17 @@ function (angular, _, $, config, kbn, moment) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!target.refId) {
|
||||
target.refId = this._seriesRefLetters[i];
|
||||
}
|
||||
|
||||
targetValue = templateSrv.replace(target.target, scopedVars);
|
||||
targetValue = targetValue.replace(intervalFormatFixRegex, fixIntervalFormat);
|
||||
targets[this._seriesRefLetters[i]] = targetValue;
|
||||
targets[target.refId] = targetValue;
|
||||
}
|
||||
|
||||
function nestedSeriesRegexReplacer(match) {
|
||||
return targets[match];
|
||||
function nestedSeriesRegexReplacer(match, g1) {
|
||||
return targets[g1];
|
||||
}
|
||||
|
||||
for (i = 0; i < options.targets.length; i++) {
|
||||
@ -274,9 +271,9 @@ function (angular, _, $, config, kbn, moment) {
|
||||
continue;
|
||||
}
|
||||
|
||||
targetValue = targets[this._seriesRefLetters[i]];
|
||||
targetValue = targets[target.refId];
|
||||
targetValue = targetValue.replace(regex, nestedSeriesRegexReplacer);
|
||||
targets[this._seriesRefLetters[i]] = targetValue;
|
||||
targets[target.refId] = targetValue;
|
||||
|
||||
if (!target.hide) {
|
||||
clean_options.push("target=" + encodeURIComponent(targetValue));
|
||||
|
21
public/app/plugins/datasource/graphite/directives.js
Normal file
21
public/app/plugins/datasource/graphite/directives.js
Normal file
@ -0,0 +1,21 @@
|
||||
define([
|
||||
'angular',
|
||||
],
|
||||
function (angular) {
|
||||
'use strict';
|
||||
|
||||
var module = angular.module('grafana.directives');
|
||||
|
||||
module.directive('metricQueryEditorGraphite', function() {
|
||||
return {controller: 'GraphiteQueryCtrl', templateUrl: 'app/plugins/datasource/graphite/partials/query.editor.html'};
|
||||
});
|
||||
|
||||
module.directive('metricQueryOptionsGraphite', function() {
|
||||
return {templateUrl: 'app/plugins/datasource/graphite/partials/query.options.html'};
|
||||
});
|
||||
|
||||
module.directive('annotationsQueryEditorGraphite', function() {
|
||||
return {templateUrl: 'app/plugins/datasource/graphite/partials/annotations.editor.html'};
|
||||
});
|
||||
|
||||
});
|
@ -1,221 +1,72 @@
|
||||
<div class="editor-row">
|
||||
|
||||
<div ng-repeat="target in panel.targets"
|
||||
class="tight-form"
|
||||
ng-class="{'tight-form-disabled': target.hide}"
|
||||
ng-controller="GraphiteQueryCtrl"
|
||||
ng-init="init()">
|
||||
<ul class="tight-form-list pull-right">
|
||||
<li ng-show="parserError" class="tight-form-item">
|
||||
<a bs-tooltip="parserError" style="color: rgb(229, 189, 28)" role="menuitem">
|
||||
<i class="fa fa-warning"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
<a class="pointer" tabindex="1" ng-click="toggleEditorMode()">
|
||||
<i class="fa fa-pencil"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
<div class="dropdown">
|
||||
<a class="pointer dropdown-toggle"
|
||||
data-toggle="dropdown"
|
||||
tabindex="1">
|
||||
<i class="fa fa-bars"></i>
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list pull-right">
|
||||
<li ng-show="parserError" class="tight-form-item">
|
||||
<a bs-tooltip="parserError" style="color: rgb(229, 189, 28)" role="menuitem">
|
||||
<i class="fa fa-warning"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li class="tight-form-item small" ng-show="target.datasource">
|
||||
<em>{{target.datasource}}</em>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
<div class="dropdown">
|
||||
<a class="pointer dropdown-toggle" data-toggle="dropdown" tabindex="1">
|
||||
<i class="fa fa-bars"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu pull-right" role="menu">
|
||||
<li role="menuitem">
|
||||
<a tabindex="1" ng-click="toggleEditorMode()">
|
||||
Switch editor mode
|
||||
</a>
|
||||
<ul class="dropdown-menu pull-right" role="menu">
|
||||
<li role="menuitem">
|
||||
<a tabindex="1"
|
||||
ng-click="duplicate()">
|
||||
Duplicate
|
||||
</a>
|
||||
</li>
|
||||
<li role="menuitem">
|
||||
<a tabindex="1"
|
||||
ng-click="moveMetricQuery($index, $index-1)">
|
||||
Move up
|
||||
</a>
|
||||
</li>
|
||||
<li role="menuitem">
|
||||
<a tabindex="1"
|
||||
ng-click="moveMetricQuery($index, $index+1)">
|
||||
Move down
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
<li class="tight-form-item last">
|
||||
<a class="pointer" tabindex="1" ng-click="removeDataQuery(target)">
|
||||
<i class="fa fa-remove"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li role="menuitem">
|
||||
<a tabindex="1" ng-click="duplicate()">Duplicate</a>
|
||||
</li>
|
||||
<li role="menuitem">
|
||||
<a tabindex="1" ng-click="moveMetricQuery($index, $index-1)">Move up</a>
|
||||
</li>
|
||||
<li role="menuitem">
|
||||
<a tabindex="1" ng-click="moveMetricQuery($index, $index+1)">Move down</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
<li class="tight-form-item last">
|
||||
<a class="pointer" tabindex="1" ng-click="removeDataQuery(target)">
|
||||
<i class="fa fa-remove"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item" style="min-width: 15px; text-align: center">
|
||||
{{targetLetters[$index]}}
|
||||
</li>
|
||||
<li>
|
||||
<a class="tight-form-item"
|
||||
ng-click="target.hide = !target.hide; get_data();"
|
||||
role="menuitem">
|
||||
<i class="fa fa-eye"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item" style="min-width: 15px; text-align: center">
|
||||
{{target.refId}}
|
||||
</li>
|
||||
<li>
|
||||
<a class="tight-form-item" ng-click="target.hide = !target.hide; get_data();" role="menuitem">
|
||||
<i class="fa fa-eye"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<input type="text" class="tight-form-clear-input span10"
|
||||
ng-model="target.target"
|
||||
focus-me="target.textEditor"
|
||||
spellcheck='false'
|
||||
ng-model-onblur ng-change="get_data()"
|
||||
ng-show="target.textEditor" />
|
||||
<input type="text" class="tight-form-clear-input span10"
|
||||
ng-model="target.target"
|
||||
give-focus="target.textEditor"
|
||||
spellcheck='false'
|
||||
ng-model-onblur ng-change="get_data()"
|
||||
ng-show="target.textEditor" />
|
||||
|
||||
<ul class="tight-form-list" role="menu" ng-hide="target.textEditor">
|
||||
<li ng-repeat="segment in segments" role="menuitem">
|
||||
<metric-segment segment="segment" get-alt-segments="getAltSegments($index)" on-value-changed="segmentValueChanged(segment, $index)"></metric-segment>
|
||||
</li>
|
||||
<li ng-repeat="func in functions">
|
||||
<span graphite-func-editor class="tight-form-item tight-form-func">
|
||||
</span>
|
||||
</li>
|
||||
<li class="dropdown" graphite-add-func>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section class="grafana-metric-options">
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item tight-form-item-icon">
|
||||
<i class="fa fa-wrench"></i>
|
||||
<ul class="tight-form-list" role="menu" ng-hide="target.textEditor">
|
||||
<li ng-repeat="segment in segments" role="menuitem">
|
||||
<metric-segment segment="segment" get-alt-segments="getAltSegments($index)" on-value-changed="segmentValueChanged(segment, $index)"></metric-segment>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
Cache timeout
|
||||
<li ng-repeat="func in functions">
|
||||
<span graphite-func-editor class="tight-form-item tight-form-func">
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<input type="text"
|
||||
class="input-mini tight-form-input"
|
||||
ng-model="panel.cacheTimeout"
|
||||
bs-tooltip="'Graphite parameter to override memcache default timeout (unit is seconds)'"
|
||||
data-placement="right"
|
||||
spellcheck='false'
|
||||
placeholder="60">
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
Max data points
|
||||
</li>
|
||||
<li>
|
||||
<input type="text"
|
||||
class="input-mini tight-form-input"
|
||||
ng-model="panel.maxDataPoints"
|
||||
bs-tooltip="'Override max data points, automatically set to graph width in pixels.'"
|
||||
data-placement="right"
|
||||
ng-model-onblur ng-change="get_data()"
|
||||
spellcheck='false'
|
||||
placeholder="auto">
|
||||
<li class="dropdown" graphite-add-func>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item tight-form-item-icon">
|
||||
<i class="fa fa-info-circle"></i>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
<a ng-click="toggleEditorHelp(1);" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
||||
shorter legend names
|
||||
</a>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
<a ng-click="toggleEditorHelp(2);" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
||||
series as parameters
|
||||
</a>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
<a ng-click="toggleEditorHelp(3)" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
||||
stacking
|
||||
</a>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
<a ng-click="toggleEditorHelp(4)" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
||||
templating
|
||||
</a>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
<a ng-click="toggleEditorHelp(5)" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
||||
max data points
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="editor-row">
|
||||
<div class="pull-left" style="margin-top: 30px;">
|
||||
|
||||
<div class="grafana-info-box span8" ng-if="editorHelpIndex === 1">
|
||||
<h5>Shorter legend names</h5>
|
||||
<ul>
|
||||
<li>alias() function to specify a custom series name</li>
|
||||
<li>aliasByNode(2) to alias by a specific part of your metric path</li>
|
||||
<li>aliasByNode(2, -1) you can add multiple segment paths, and use negative index</li>
|
||||
<li>groupByNode(2, 'sum') is useful if you have 2 wildcards in your metric path and want to sumSeries and group by</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="grafana-info-box span8" ng-if="editorHelpIndex === 2">
|
||||
<h5>Series as parameter</h5>
|
||||
<ul>
|
||||
<li>Some graphite functions allow you to have many series arguments</li>
|
||||
<li>Use #[A-Z] to use a graphite query as parameter to a function</li>
|
||||
<li>
|
||||
Examples:
|
||||
<ul>
|
||||
<li>asPercent(#A, #B)</li>
|
||||
<li>prod.srv-01.counters.count - asPercent(#A) : percentage of count in comparison with A query</li>
|
||||
<li>prod.srv-01.counters.count - sumSeries(#A) : sum count and series A </li>
|
||||
<li>divideSeries(#A, #B)</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>If a query is added only to be used as a parameter, hide it from the graph with the eye icon</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="grafana-info-box span6" ng-if="editorHelpIndex === 3">
|
||||
<h5>Stacking</h5>
|
||||
<ul>
|
||||
<li>You find the stacking option under Display Styles tab</li>
|
||||
<li>When stacking is enabled make sure null point mode is set to 'null as zero'</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="grafana-info-box span6" ng-if="editorHelpIndex === 4">
|
||||
<h5>Templating</h5>
|
||||
<ul>
|
||||
<li>You can use a template variable in place of metric names</li>
|
||||
<li>You can use a template variable in place of function parameters</li>
|
||||
<li>You enable the templating feature in Dashboard settings / Feature toggles </li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="grafana-info-box span6" ng-if="editorHelpIndex === 5">
|
||||
<h5>Max data points</h5>
|
||||
<ul>
|
||||
<li>Every graphite request is issued with a maxDataPoints parameter</li>
|
||||
<li>Graphite uses this parameter to consolidate the real number of values down to this number</li>
|
||||
<li>If there are more real values, then by default they will be consolidated using averages</li>
|
||||
<li>This could hide real peaks and max values in your series</li>
|
||||
<li>You can change how point consolidation is made using the consolidateBy graphite function</li>
|
||||
<li>Point consolidation will effect series legend values (min,max,total,current)</li>
|
||||
<li>If you override maxDataPoint and set a high value performance can be severely effected</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
@ -0,0 +1,132 @@
|
||||
<section class="grafana-metric-options">
|
||||
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item tight-form-item-icon">
|
||||
<i class="fa fa-wrench"></i>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
Cache timeout
|
||||
</li>
|
||||
<li>
|
||||
<input type="text"
|
||||
class="input-mini tight-form-input"
|
||||
ng-model="panel.cacheTimeout"
|
||||
bs-tooltip="'Graphite parameter to override memcache default timeout (unit is seconds)'"
|
||||
data-placement="right"
|
||||
spellcheck='false'
|
||||
placeholder="60"></input>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
Max data points
|
||||
</li>
|
||||
<li>
|
||||
<input type="text"
|
||||
class="input-mini tight-form-input"
|
||||
ng-model="panel.maxDataPoints"
|
||||
bs-tooltip="'Override max data points, automatically set to graph width in pixels.'"
|
||||
data-placement="right"
|
||||
ng-model-onblur ng-change="get_data()"
|
||||
spellcheck='false'
|
||||
placeholder="auto"></input>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item tight-form-item-icon">
|
||||
<i class="fa fa-info-circle"></i>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
<a ng-click="toggleEditorHelp(1);" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
||||
shorter legend names
|
||||
</a>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
<a ng-click="toggleEditorHelp(2);" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
||||
series as parameters
|
||||
</a>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
<a ng-click="toggleEditorHelp(3)" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
||||
stacking
|
||||
</a>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
<a ng-click="toggleEditorHelp(4)" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
||||
templating
|
||||
</a>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
<a ng-click="toggleEditorHelp(5)" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
||||
max data points
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="editor-row">
|
||||
<div class="pull-left" style="margin-top: 30px;">
|
||||
|
||||
<div class="grafana-info-box span8" ng-if="editorHelpIndex === 1">
|
||||
<h5>Shorter legend names</h5>
|
||||
<ul>
|
||||
<li>alias() function to specify a custom series name</li>
|
||||
<li>aliasByNode(2) to alias by a specific part of your metric path</li>
|
||||
<li>aliasByNode(2, -1) you can add multiple segment paths, and use negative index</li>
|
||||
<li>groupByNode(2, 'sum') is useful if you have 2 wildcards in your metric path and want to sumSeries and group by</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="grafana-info-box span8" ng-if="editorHelpIndex === 2">
|
||||
<h5>Series as parameter</h5>
|
||||
<ul>
|
||||
<li>Some graphite functions allow you to have many series arguments</li>
|
||||
<li>Use #[A-Z] to use a graphite query as parameter to a function</li>
|
||||
<li>
|
||||
Examples:
|
||||
<ul>
|
||||
<li>asPercent(#A, #B)</li>
|
||||
<li>prod.srv-01.counters.count - asPercent(#A) : percentage of count in comparison with A query</li>
|
||||
<li>prod.srv-01.counters.count - sumSeries(#A) : sum count and series A </li>
|
||||
<li>divideSeries(#A, #B)</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>If a query is added only to be used as a parameter, hide it from the graph with the eye icon</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="grafana-info-box span6" ng-if="editorHelpIndex === 3">
|
||||
<h5>Stacking</h5>
|
||||
<ul>
|
||||
<li>You find the stacking option under Display Styles tab</li>
|
||||
<li>When stacking is enabled make sure null point mode is set to 'null as zero'</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="grafana-info-box span6" ng-if="editorHelpIndex === 4">
|
||||
<h5>Templating</h5>
|
||||
<ul>
|
||||
<li>You can use a template variable in place of metric names</li>
|
||||
<li>You can use a template variable in place of function parameters</li>
|
||||
<li>You enable the templating feature in Dashboard settings / Feature toggles </li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="grafana-info-box span6" ng-if="editorHelpIndex === 5">
|
||||
<h5>Max data points</h5>
|
||||
<ul>
|
||||
<li>Every graphite request is issued with a maxDataPoints parameter</li>
|
||||
<li>Graphite uses this parameter to consolidate the real number of values down to this number</li>
|
||||
<li>If there are more real values, then by default they will be consolidated using averages</li>
|
||||
<li>This could hide real peaks and max values in your series</li>
|
||||
<li>You can change how point consolidation is made using the consolidateBy graphite function</li>
|
||||
<li>Point consolidation will effect series legend values (min,max,total,current)</li>
|
||||
<li>If you override maxDataPoint and set a high value performance can be severely effected</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -8,9 +8,7 @@
|
||||
"module": "plugins/datasource/graphite/datasource",
|
||||
|
||||
"partials": {
|
||||
"config": "app/plugins/datasource/graphite/partials/config.html",
|
||||
"query": "app/plugins/datasource/graphite/partials/query.editor.html",
|
||||
"annotations": "app/plugins/datasource/graphite/partials/annotations.editor.html"
|
||||
"config": "app/plugins/datasource/graphite/partials/config.html"
|
||||
},
|
||||
|
||||
"metrics": true,
|
||||
|
@ -9,15 +9,14 @@ function (angular, _, config, gfunc, Parser) {
|
||||
'use strict';
|
||||
|
||||
var module = angular.module('grafana.controllers');
|
||||
var targetLetters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
|
||||
module.controller('GraphiteQueryCtrl', function($scope, $sce, templateSrv) {
|
||||
|
||||
$scope.init = function() {
|
||||
$scope.target.target = $scope.target.target || '';
|
||||
$scope.targetLetters = targetLetters;
|
||||
|
||||
parseTarget();
|
||||
if ($scope.target) {
|
||||
$scope.target.target = $scope.target.target || '';
|
||||
parseTarget();
|
||||
}
|
||||
};
|
||||
|
||||
$scope.toggleEditorMode = function() {
|
||||
@ -313,22 +312,8 @@ function (angular, _, config, gfunc, Parser) {
|
||||
return new MetricSegment({value: 'select metric', fake: true});
|
||||
};
|
||||
|
||||
});
|
||||
$scope.init();
|
||||
|
||||
module.directive('focusMe', function($timeout, $parse) {
|
||||
return {
|
||||
//scope: true, // optionally create a child scope
|
||||
link: function(scope, element, attrs) {
|
||||
var model = $parse(attrs.focusMe);
|
||||
scope.$watch(model, function(value) {
|
||||
if(value === true) {
|
||||
$timeout(function() {
|
||||
element[0].focus();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
});
|
||||
|
@ -4,6 +4,7 @@ define([
|
||||
'kbn',
|
||||
'./influxSeries',
|
||||
'./queryBuilder',
|
||||
'./directives',
|
||||
'./queryCtrl',
|
||||
'./funcEditor',
|
||||
],
|
||||
|
21
public/app/plugins/datasource/influxdb/directives.js
Normal file
21
public/app/plugins/datasource/influxdb/directives.js
Normal file
@ -0,0 +1,21 @@
|
||||
define([
|
||||
'angular',
|
||||
],
|
||||
function (angular) {
|
||||
'use strict';
|
||||
|
||||
var module = angular.module('grafana.directives');
|
||||
|
||||
module.directive('metricQueryEditorInfluxdb', function() {
|
||||
return {controller: 'InfluxQueryCtrl', templateUrl: 'app/plugins/datasource/influxdb/partials/query.editor.html'};
|
||||
});
|
||||
|
||||
module.directive('metricQueryOptionsInfluxdb', function() {
|
||||
return {templateUrl: 'app/plugins/datasource/influxdb/partials/query.options.html'};
|
||||
});
|
||||
|
||||
module.directive('annotationsQueryEditorInfluxdb', function() {
|
||||
return {templateUrl: 'app/plugins/datasource/influxdb/partials/annotations.editor.html'};
|
||||
});
|
||||
|
||||
});
|
@ -1,65 +1,56 @@
|
||||
<div class="editor-row">
|
||||
|
||||
<div ng-repeat="target in panel.targets" ng-controller="InfluxQueryCtrl" ng-init="init()" ng-class="{'tight-form-disabled': target.hide}" class="tight-form-container-no-item-borders" style="margin-bottom: 10px">
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list pull-right">
|
||||
<li ng-show="parserError" class="tight-form-item">
|
||||
<a bs-tooltip="parserError" style="color: rgb(229, 189, 28)" role="menuitem">
|
||||
<i class="fa fa-warning"></i>
|
||||
<div class="tight-form-container-no-item-borders">
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list pull-right">
|
||||
<li ng-show="parserError" class="tight-form-item">
|
||||
<a bs-tooltip="parserError" style="color: rgb(229, 189, 28)" role="menuitem">
|
||||
<i class="fa fa-warning"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li class="tight-form-item small" ng-show="target.datasource">
|
||||
<em>{{target.datasource}}</em>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
<div class="dropdown">
|
||||
<a class="pointer dropdown-toggle" data-toggle="dropdown" tabindex="1">
|
||||
<i class="fa fa-bars"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
<a class="pointer" tabindex="1" ng-click="toggleQueryMode()">
|
||||
<i class="fa fa-pencil"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
<div class="dropdown">
|
||||
<a class="pointer dropdown-toggle"
|
||||
data-toggle="dropdown"
|
||||
tabindex="1">
|
||||
<i class="fa fa-bars"></i>
|
||||
<ul class="dropdown-menu pull-right" role="menu">
|
||||
<a tabindex="1" ng-click="toggleEditorMode()">
|
||||
Switch editor mode
|
||||
</a>
|
||||
<ul class="dropdown-menu pull-right" role="menu">
|
||||
<li role="menuitem">
|
||||
<a tabindex="1"
|
||||
ng-click="duplicate()">
|
||||
Duplicate
|
||||
</a>
|
||||
</li>
|
||||
<li role="menuitem">
|
||||
<a tabindex="1"
|
||||
ng-click="moveMetricQuery($index, $index-1)">
|
||||
Move up
|
||||
</a>
|
||||
</li>
|
||||
<li role="menuitem">
|
||||
<a tabindex="1"
|
||||
ng-click="moveMetricQuery($index, $index+1)">
|
||||
Move down
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
<li class="tight-form-item last">
|
||||
<a class="pointer" tabindex="1" ng-click="removeDataQuery(target)">
|
||||
<i class="fa fa-remove"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<li role="menuitem">
|
||||
<a tabindex="1" ng-click="duplicate()">Duplicate</a>
|
||||
</li>
|
||||
<li role="menuitem">
|
||||
<a tabindex="1" ng-click="moveMetricQuery($index, $index-1)">Move up</a>
|
||||
</li>
|
||||
<li role="menuitem">
|
||||
<a tabindex="1" ng-click="moveMetricQuery($index, $index+1)">Move down</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
<li class="tight-form-item last">
|
||||
<a class="pointer" tabindex="1" ng-click="removeDataQuery(target)">
|
||||
<i class="fa fa-remove"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul class="tight-form-list">
|
||||
<li>
|
||||
<a class="tight-form-item"
|
||||
ng-click="target.hide = !target.hide; get_data();"
|
||||
role="menuitem">
|
||||
<i class="fa fa-eye"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item" style="min-width: 15px; text-align: center">
|
||||
{{target.refId}}
|
||||
</li>
|
||||
<li>
|
||||
<a class="tight-form-item"
|
||||
ng-click="target.hide = !target.hide; get_data();"
|
||||
role="menuitem">
|
||||
<i class="fa fa-eye"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<input type="text" class="tight-form-clear-input" style="width: 80%" ng-model="target.query" focus-me="target.rawQuery" spellcheck='false' ng-model-onblur ng-change="get_data()" ng-show="target.rawQuery"/>
|
||||
<input type="text" class="tight-form-clear-input" style="width: 80%" ng-model="target.query" give-focus="target.rawQuery" spellcheck='false' ng-model-onblur ng-change="get_data()" ng-show="target.rawQuery"/>
|
||||
|
||||
<ul class="tight-form-list" role="menu" ng-hide="target.rawQuery">
|
||||
<li class="tight-form-item query-keyword" style="width: 75px;">
|
||||
@ -79,10 +70,7 @@
|
||||
|
||||
<div class="tight-form" ng-hide="target.rawQuery">
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item">
|
||||
<i class="fa fa-eye invisible"></i>
|
||||
</li>
|
||||
<li class="tight-form-item query-keyword" style="width: 75px;">
|
||||
<li class="tight-form-item query-keyword tight-form-align" style="width: 75px;">
|
||||
FROM
|
||||
</li>
|
||||
<li>
|
||||
@ -95,11 +83,7 @@
|
||||
|
||||
<div class="tight-form" ng-hide="target.rawQuery">
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item">
|
||||
<i class="fa fa-eye invisible"></i>
|
||||
</li>
|
||||
|
||||
<li class="tight-form-item query-keyword" style="width: 75px;">
|
||||
<li class="tight-form-item query-keyword tight-form-align" style="width: 75px;">
|
||||
WHERE
|
||||
</li>
|
||||
|
||||
@ -112,11 +96,7 @@
|
||||
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list" ng-hide="target.rawQuery">
|
||||
<li class="tight-form-item">
|
||||
<i class="fa fa-eye invisible"></i>
|
||||
</li>
|
||||
|
||||
<li class="tight-form-item query-keyword">
|
||||
<li class="tight-form-item query-keyword tight-form-align">
|
||||
GROUP BY
|
||||
</li>
|
||||
|
||||
@ -150,7 +130,9 @@
|
||||
Alias pattern
|
||||
</li>
|
||||
<li>
|
||||
<input type="text" class="input-medium tight-form-input" ng-model="target.alias" spellcheck='false' placeholder="alias" ng-model-onblur ng-change="get_data()">
|
||||
<input type="text" class="input-medium tight-form-input"
|
||||
ng-model="target.alias" spellcheck='false' placeholder="alias"
|
||||
ng-model-onblur ng-change="get_data()"></input>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
@ -159,90 +141,3 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section class="grafana-metric-options">
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item tight-form-item-icon">
|
||||
<i class="fa fa-wrench"></i>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
Group by time interval
|
||||
</li>
|
||||
<li>
|
||||
<input type="text" class="input-medium tight-form-input" ng-model="panel.interval" ng-blur="get_data();"
|
||||
spellcheck='false' placeholder="example: >10s">
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
<i class="fa fa-question-circle" bs-tooltip="'Set a low limit by having a greater sign: example: >60s'" data-placement="right"></i>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item tight-form-item-icon">
|
||||
<i class="fa fa-info-circle"></i>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
<a ng-click="toggleEditorHelp(1);" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
||||
alias patterns
|
||||
</a>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
<a ng-click="toggleEditorHelp(2)" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
||||
stacking & and fill
|
||||
</a>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
<a ng-click="toggleEditorHelp(3)" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
||||
group by time
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="editor-row">
|
||||
<div class="pull-left" style="margin-top: 30px;">
|
||||
|
||||
<div class="grafana-info-box span6" ng-if="editorHelpIndex === 1">
|
||||
<h5>Alias patterns</h5>
|
||||
<ul>
|
||||
<li>$m = replaced with measurement name</li>
|
||||
<li>$measurement = replaced with measurement name</li>
|
||||
<li>$col = replaced with column name</li>
|
||||
<li>$tag_hostname = replaced with the value of the hostname tag</li>
|
||||
<li>You can also use [[tag_hostname]] pattern replacement syntax</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="grafana-info-box span6" ng-if="editorHelpIndex === 2">
|
||||
<h5>Stacking and fill</h5>
|
||||
<ul>
|
||||
<li>When stacking is enabled it important that points align</li>
|
||||
<li>If there are missing points for one series it can cause gaps or missing bars</li>
|
||||
<li>You must use fill(0), and select a group by time low limit</li>
|
||||
<li>Use the group by time option below your queries and specify for example >10s if your metrics are written every 10 seconds</li>
|
||||
<li>This will insert zeros for series that are missing measurements and will make stacking work properly</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="grafana-info-box span6" ng-if="editorHelpIndex === 3">
|
||||
<h5>Group by time</h5>
|
||||
<ul>
|
||||
<li>Group by time is important, otherwise the query could return many thousands of datapoints that will slow down Grafana</li>
|
||||
<li>Leave the group by time field empty for each query and it will be calculated based on time range and pixel width of the graph</li>
|
||||
<li>If you use fill(0) or fill(null) set a low limit for the auto group by time interval</li>
|
||||
<li>The low limit can only be set in the group by time option below your queries</li>
|
||||
<li>You set a low limit by adding a greater sign before the interval</li>
|
||||
<li>Example: >60s if you write metrics to InfluxDB every 60 seconds</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
@ -0,0 +1,87 @@
|
||||
<section class="grafana-metric-options">
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item tight-form-item-icon">
|
||||
<i class="fa fa-wrench"></i>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
Group by time interval
|
||||
</li>
|
||||
<li>
|
||||
<input type="text" class="input-medium tight-form-input" ng-model="panel.interval" ng-blur="get_data();"
|
||||
spellcheck='false' placeholder="example: >10s">
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
<i class="fa fa-question-circle" bs-tooltip="'Set a low limit by having a greater sign: example: >60s'" data-placement="right"></i>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item tight-form-item-icon">
|
||||
<i class="fa fa-info-circle"></i>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
<a ng-click="toggleEditorHelp(1);" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
||||
alias patterns
|
||||
</a>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
<a ng-click="toggleEditorHelp(2)" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
||||
stacking & and fill
|
||||
</a>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
<a ng-click="toggleEditorHelp(3)" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
||||
group by time
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="editor-row">
|
||||
<div class="pull-left" style="margin-top: 30px;">
|
||||
|
||||
<div class="grafana-info-box span6" ng-if="editorHelpIndex === 1">
|
||||
<h5>Alias patterns</h5>
|
||||
<ul>
|
||||
<li>$m = replaced with measurement name</li>
|
||||
<li>$measurement = replaced with measurement name</li>
|
||||
<li>$col = replaced with column name</li>
|
||||
<li>$tag_hostname = replaced with the value of the hostname tag</li>
|
||||
<li>You can also use [[tag_hostname]] pattern replacement syntax</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="grafana-info-box span6" ng-if="editorHelpIndex === 2">
|
||||
<h5>Stacking and fill</h5>
|
||||
<ul>
|
||||
<li>When stacking is enabled it important that points align</li>
|
||||
<li>If there are missing points for one series it can cause gaps or missing bars</li>
|
||||
<li>You must use fill(0), and select a group by time low limit</li>
|
||||
<li>Use the group by time option below your queries and specify for example >10s if your metrics are written every 10 seconds</li>
|
||||
<li>This will insert zeros for series that are missing measurements and will make stacking work properly</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="grafana-info-box span6" ng-if="editorHelpIndex === 3">
|
||||
<h5>Group by time</h5>
|
||||
<ul>
|
||||
<li>Group by time is important, otherwise the query could return many thousands of datapoints that will slow down Grafana</li>
|
||||
<li>Leave the group by time field empty for each query and it will be calculated based on time range and pixel width of the graph</li>
|
||||
<li>If you use fill(0) or fill(null) set a low limit for the auto group by time interval</li>
|
||||
<li>The low limit can only be set in the group by time option below your queries</li>
|
||||
<li>You set a low limit by adding a greater sign before the interval</li>
|
||||
<li>Example: >60s if you write metrics to InfluxDB every 60 seconds</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -8,9 +8,7 @@
|
||||
"module": "plugins/datasource/influxdb/datasource",
|
||||
|
||||
"partials": {
|
||||
"config": "app/plugins/datasource/influxdb/partials/config.html",
|
||||
"query": "app/plugins/datasource/influxdb/partials/query.editor.html",
|
||||
"annotations": "app/plugins/datasource/influxdb/partials/annotations.editor.html"
|
||||
"config": "app/plugins/datasource/influxdb/partials/config.html"
|
||||
},
|
||||
|
||||
"metrics": true,
|
||||
|
@ -11,6 +11,8 @@ function (angular, _, InfluxQueryBuilder) {
|
||||
module.controller('InfluxQueryCtrl', function($scope, $timeout, $sce, templateSrv, $q) {
|
||||
|
||||
$scope.init = function() {
|
||||
if (!$scope.target) { return; }
|
||||
|
||||
var target = $scope.target;
|
||||
target.tags = target.tags || [];
|
||||
target.groupByTags = target.groupByTags || [];
|
||||
@ -337,6 +339,8 @@ function (angular, _, InfluxQueryBuilder) {
|
||||
return new MetricSegment({value: 'select tag value', fake: true});
|
||||
};
|
||||
|
||||
$scope.init();
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
@ -4,6 +4,7 @@ define([
|
||||
'kbn',
|
||||
'./influxSeries',
|
||||
'./queryBuilder',
|
||||
'./directives',
|
||||
'./queryCtrl',
|
||||
'./funcEditor',
|
||||
],
|
||||
|
21
public/app/plugins/datasource/influxdb_08/directives.js
Normal file
21
public/app/plugins/datasource/influxdb_08/directives.js
Normal file
@ -0,0 +1,21 @@
|
||||
define([
|
||||
'angular',
|
||||
],
|
||||
function (angular) {
|
||||
'use strict';
|
||||
|
||||
var module = angular.module('grafana.directives');
|
||||
|
||||
module.directive('metricQueryEditorInfluxdb08', function() {
|
||||
return {controller: 'InfluxQueryCtrl_08', templateUrl: 'app/plugins/datasource/influxdb_08/partials/query.editor.html'};
|
||||
});
|
||||
|
||||
module.directive('metricQueryOptionsInfluxdb08', function() {
|
||||
return {templateUrl: 'app/plugins/datasource/influxdb_08/partials/query.options.html'};
|
||||
});
|
||||
|
||||
module.directive('annotationsQueryEditorInfluxdb08', function() {
|
||||
return {templateUrl: 'app/plugins/datasource/influxdb_08/partials/annotations.editor.html'};
|
||||
});
|
||||
|
||||
});
|
@ -1,256 +1,165 @@
|
||||
<div class="editor-row">
|
||||
<div ng-repeat="target in panel.targets" ng-controller="InfluxQueryCtrl_08" ng-init="init()" ng-class="{'tight-form-disabled': target.hide}" class="tight-form-container">
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list pull-right">
|
||||
<li class="tight-form-item">
|
||||
<div class="dropdown">
|
||||
<a class="pointer dropdown-toggle"
|
||||
data-toggle="dropdown"
|
||||
tabindex="1">
|
||||
<i class="fa fa-bars"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu pull-right" role="menu">
|
||||
<li role="menuitem"><a tabindex="1" ng-click="duplicate()">Duplicate</a></li>
|
||||
<li role="menuitem"><a tabindex="1" ng-click="showQuery()" ng-hide="target.rawQuery">Raw query mode</a></li>
|
||||
<li role="menuitem"><a tabindex="1" ng-click="hideQuery()" ng-show="target.rawQuery">Query editor mode</a></li>
|
||||
<li role="menuitem"><a tabindex="1" ng-click="moveMetricQuery($index, $index-1)">Move up </a></li>
|
||||
<li role="menuitem"><a tabindex="1" ng-click="moveMetricQuery($index, $index+1)">Move down</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
<li class="tight-form-item last">
|
||||
<a class="pointer" tabindex="1" ng-click="removeDataQuery(target)">
|
||||
<i class="fa fa-remove"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list pull-right">
|
||||
<li class="tight-form-item">
|
||||
<div class="dropdown">
|
||||
<a class="pointer dropdown-toggle"
|
||||
data-toggle="dropdown"
|
||||
tabindex="1">
|
||||
<i class="fa fa-bars"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu pull-right" role="menu">
|
||||
<li role="menuitem"><a tabindex="1" ng-click="duplicate()">Duplicate</a></li>
|
||||
<li role="menuitem"><a tabindex="1" ng-click="showQuery()" ng-hide="target.rawQuery">Raw query mode</a></li>
|
||||
<li role="menuitem"><a tabindex="1" ng-click="hideQuery()" ng-show="target.rawQuery">Query editor mode</a></li>
|
||||
<li role="menuitem"><a tabindex="1" ng-click="moveMetricQuery($index, $index-1)">Move up </a></li>
|
||||
<li role="menuitem"><a tabindex="1" ng-click="moveMetricQuery($index, $index+1)">Move down</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
<li class="tight-form-item last">
|
||||
<a class="pointer" tabindex="1" ng-click="removeDataQuery(target)">
|
||||
<i class="fa fa-remove"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul class="tight-form-list">
|
||||
<li>
|
||||
<a class="tight-form-item" ng-click="target.hide = !target.hide; get_data();" role="menuitem">
|
||||
<i class="fa fa-eye"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item" style="min-width: 15px; text-align: center">
|
||||
{{target.refId}}
|
||||
</li>
|
||||
<li>
|
||||
<a class="tight-form-item" ng-click="target.hide = !target.hide; get_data();" role="menuitem">
|
||||
<i class="fa fa-eye"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- Raw Query mode -->
|
||||
<ul class="tight-form-list" ng-show="target.rawQuery">
|
||||
<li>
|
||||
<input type="text"
|
||||
class="tight-form-input span10"
|
||||
ng-model="target.query"
|
||||
placeholder="select ..."
|
||||
focus-me="target.rawQuery"
|
||||
spellcheck='false'
|
||||
data-min-length=0 data-items=100
|
||||
ng-model-onblur
|
||||
ng-blur="get_data()">
|
||||
</li>
|
||||
</ul>
|
||||
<!-- Raw Query mode -->
|
||||
<ul class="tight-form-list" ng-show="target.rawQuery">
|
||||
<li>
|
||||
<input type="text"
|
||||
class="tight-form-input span10"
|
||||
ng-model="target.query"
|
||||
placeholder="select ..."
|
||||
give-focus="target.rawQuery"
|
||||
spellcheck='false'
|
||||
data-min-length=0 data-items=100
|
||||
ng-model-onblur
|
||||
ng-blur="get_data()">
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- Query editor mode -->
|
||||
<ul class="tight-form-list" role="menu" ng-hide="target.rawQuery">
|
||||
<li class="tight-form-item">
|
||||
series
|
||||
</li>
|
||||
<li>
|
||||
<input type="text"
|
||||
class="tight-form-input span8"
|
||||
ng-model="target.series"
|
||||
spellcheck='false'
|
||||
bs-typeahead="listSeries"
|
||||
match-all="true"
|
||||
min-length="3"
|
||||
placeholder="series name"
|
||||
data-min-length=0 data-items=100
|
||||
ng-blur="seriesBlur()">
|
||||
</li>
|
||||
<!-- Query editor mode -->
|
||||
<ul class="tight-form-list" role="menu" ng-hide="target.rawQuery">
|
||||
<li class="tight-form-item">
|
||||
series
|
||||
</li>
|
||||
<li>
|
||||
<input type="text"
|
||||
class="tight-form-input span8"
|
||||
ng-model="target.series"
|
||||
spellcheck='false'
|
||||
bs-typeahead="listSeries"
|
||||
match-all="true"
|
||||
min-length="3"
|
||||
placeholder="series name"
|
||||
data-min-length=0 data-items=100
|
||||
ng-blur="seriesBlur()">
|
||||
</li>
|
||||
|
||||
<li class="tight-form-item">
|
||||
alias
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
alias
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<input type="text" class="input-medium tight-form-input" ng-model="target.alias"
|
||||
spellcheck='false' placeholder="alias" ng-blur="get_data()">
|
||||
</li>
|
||||
<li>
|
||||
<input type="text" class="input-medium tight-form-input" ng-model="target.alias"
|
||||
spellcheck='false' placeholder="alias" ng-blur="get_data()">
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</ul>
|
||||
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
|
||||
<div class="tight-form">
|
||||
<!-- Raw Query mode -->
|
||||
<ul class="tight-form-list" ng-show="target.rawQuery">
|
||||
<li class="tight-form-item">
|
||||
<i class="fa fa-eye invisible"></i>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
alias
|
||||
</li>
|
||||
<li>
|
||||
<input type="text"
|
||||
class="input-medium tight-form-input"
|
||||
ng-model="target.alias"
|
||||
spellcheck='false'
|
||||
placeholder="alias"
|
||||
ng-blur="get_data()">
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
group by time
|
||||
</li>
|
||||
<li>
|
||||
<input type="text" class="input-mini tight-form-input" ng-model="target.interval"
|
||||
spellcheck='false' placeholder="{{interval}}" data-placement="right"
|
||||
bs-tooltip="'Leave blank for auto handling based on time range and panel width'"
|
||||
ng-model-onblur ng-change="get_data()" >
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- Query editor mode -->
|
||||
<ul class="tight-form-list" role="menu" ng-hide="target.rawQuery">
|
||||
<li class="tight-form-item">
|
||||
<i class="fa fa-eye invisible"></i>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
select
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<span influxdb-func-editor08 class="tight-form-item tight-form-func">
|
||||
</span>
|
||||
</li>
|
||||
|
||||
<li class="tight-form-item">
|
||||
where
|
||||
</li>
|
||||
<li>
|
||||
<input type="text" class="input-medium tight-form-input" ng-model="target.condition"
|
||||
bs-tooltip="'Add a where clause'" data-placement="right" spellcheck='false' placeholder="column ~= value" ng-blur="get_data()">
|
||||
</li>
|
||||
|
||||
<li class="tight-form-item">
|
||||
group by time
|
||||
</li>
|
||||
<li>
|
||||
<input type="text" class="input-mini tight-form-input" ng-model="target.interval"
|
||||
spellcheck='false' placeholder="{{interval}}" data-placement="right"
|
||||
bs-tooltip="'Leave blank for auto handling based on time range and panel width'"
|
||||
ng-model-onblur ng-change="get_data()" >
|
||||
</li>
|
||||
|
||||
<li class="tight-form-item">
|
||||
and
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<input type="text" class="input-small tight-form-input" ng-model="target.groupby_field" bs-tooltip="'Add a group by column or leave blank'"
|
||||
placeholder="column" spellcheck="false" bs-typeahead="listColumns" data-min-length=0 ng-blur="get_data()">
|
||||
</li>
|
||||
|
||||
<li class="dropdown">
|
||||
<a class="tight-form-item pointer" data-toggle="dropdown" bs-tooltip="'Insert missing values, important when stacking'" data-placement="right">
|
||||
<span ng-show="target.fill">
|
||||
fill ({{target.fill}})
|
||||
</span>
|
||||
<span ng-show="!target.fill">
|
||||
no fill
|
||||
</span>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a ng-click="target.fill = ''">no fill</a></li>
|
||||
<li><a ng-click="target.fill = 'null'">fill (null)</a></li>
|
||||
<li><a ng-click="target.fill = '0'">fill (0)</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
|
||||
<section class="grafana-metric-options">
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item tight-form-item-icon">
|
||||
<i class="fa fa-wrench"></i>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
group by time
|
||||
</li>
|
||||
<li>
|
||||
<input type="text" class="input-medium tight-form-input" ng-model="panel.interval" ng-blur="get_data();"
|
||||
spellcheck='false' placeholder="example: >10s">
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
<i class="fa fa-question-circle" bs-tooltip="'Set a low limit by having a greater sign: example: >60s'" data-placement="right"></i>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
<div class="tight-form">
|
||||
<!-- Raw Query mode -->
|
||||
<ul class="tight-form-list" ng-show="target.rawQuery">
|
||||
<li class="tight-form-item tight-form-align">
|
||||
alias
|
||||
</li>
|
||||
<li>
|
||||
<input type="text"
|
||||
class="input-medium tight-form-input"
|
||||
ng-model="target.alias"
|
||||
spellcheck='false'
|
||||
placeholder="alias"
|
||||
ng-blur="get_data()">
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
group by time
|
||||
</li>
|
||||
<li>
|
||||
<input type="text" class="input-mini tight-form-input" ng-model="target.interval"
|
||||
spellcheck='false' placeholder="{{interval}}" data-placement="right"
|
||||
bs-tooltip="'Leave blank for auto handling based on time range and panel width'"
|
||||
ng-model-onblur ng-change="get_data()" >
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item tight-form-item-icon">
|
||||
<i class="fa fa-info-circle"></i>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
<a ng-click="toggleEditorHelp(1);" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
||||
alias patterns
|
||||
</a>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
<a ng-click="toggleEditorHelp(2)" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
||||
stacking & and fill
|
||||
</a>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
<a ng-click="toggleEditorHelp(3)" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
||||
group by time
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Query editor mode -->
|
||||
<ul class="tight-form-list" role="menu" ng-hide="target.rawQuery">
|
||||
<li class="tight-form-item tight-form-align">
|
||||
select
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<span influxdb-func-editor08 class="tight-form-item tight-form-func">
|
||||
</span>
|
||||
</li>
|
||||
|
||||
<div class="editor-row">
|
||||
<div class="pull-left" style="margin-top: 30px;">
|
||||
<li class="tight-form-item">
|
||||
where
|
||||
</li>
|
||||
<li>
|
||||
<input type="text" class="input-medium tight-form-input" ng-model="target.condition"
|
||||
bs-tooltip="'Add a where clause'" data-placement="right" spellcheck='false' placeholder="column ~= value" ng-blur="get_data()">
|
||||
</li>
|
||||
|
||||
<div class="grafana-info-box span6" ng-if="editorHelpIndex === 1">
|
||||
<h5>Alias patterns</h5>
|
||||
<ul>
|
||||
<li>$s = series name</li>
|
||||
<li>$g = group by</li>
|
||||
<li>$[0-9] part of series name for series names seperated by dots.</li>
|
||||
<li class="tight-form-item">
|
||||
group by time
|
||||
</li>
|
||||
<li>
|
||||
<input type="text" class="input-mini tight-form-input" ng-model="target.interval"
|
||||
spellcheck='false' placeholder="{{interval}}" data-placement="right"
|
||||
bs-tooltip="'Leave blank for auto handling based on time range and panel width'"
|
||||
ng-model-onblur ng-change="get_data()" >
|
||||
</li>
|
||||
|
||||
<li class="tight-form-item">
|
||||
and
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<input type="text" class="input-small tight-form-input" ng-model="target.groupby_field" bs-tooltip="'Add a group by column or leave blank'"
|
||||
placeholder="column" spellcheck="false" bs-typeahead="listColumns" data-min-length=0 ng-blur="get_data()">
|
||||
</li>
|
||||
|
||||
<li class="dropdown">
|
||||
<a class="tight-form-item pointer" data-toggle="dropdown" bs-tooltip="'Insert missing values, important when stacking'" data-placement="right">
|
||||
<span ng-show="target.fill">
|
||||
fill ({{target.fill}})
|
||||
</span>
|
||||
<span ng-show="!target.fill">
|
||||
no fill
|
||||
</span>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a ng-click="target.fill = ''">no fill</a></li>
|
||||
<li><a ng-click="target.fill = 'null'">fill (null)</a></li>
|
||||
<li><a ng-click="target.fill = '0'">fill (0)</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="grafana-info-box span6" ng-if="editorHelpIndex === 2">
|
||||
<h5>Stacking and fill</h5>
|
||||
<ul>
|
||||
<li>When stacking is enabled it important that points align</li>
|
||||
<li>If there are missing points for one series it can cause gaps or missing bars</li>
|
||||
<li>You must use fill(0), and select a group by time low limit</li>
|
||||
<li>Use the group by time option below your queries and specify for example >10s if your metrics are written every 10 seconds</li>
|
||||
<li>This will insert zeros for series that are missing measurements and will make stacking work properly</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="grafana-info-box span6" ng-if="editorHelpIndex === 3">
|
||||
<h5>Group by time</h5>
|
||||
<ul>
|
||||
<li>Group by time is important, otherwise the query could return many thousands of datapoints that will slow down Grafana</li>
|
||||
<li>Leave the group by time field empty for each query and it will be calculated based on time range and pixel width of the graph</li>
|
||||
<li>If you use fill(0) or fill(null) set a low limit for the auto group by time interval</li>
|
||||
<li>The low limit can only be set in the group by time option below your queries</li>
|
||||
<li>You set a low limit by adding a greater sign before the interval</li>
|
||||
<li>Example: >60s if you write metrics to InfluxDB every 60 seconds</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
|
||||
|
||||
|
@ -0,0 +1,85 @@
|
||||
<section class="grafana-metric-options">
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item tight-form-item-icon">
|
||||
<i class="fa fa-wrench"></i>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
group by time
|
||||
</li>
|
||||
<li>
|
||||
<input type="text" class="input-medium tight-form-input" ng-model="panel.interval" ng-blur="get_data();"
|
||||
spellcheck='false' placeholder="example: >10s">
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
<i class="fa fa-question-circle" bs-tooltip="'Set a low limit by having a greater sign: example: >60s'" data-placement="right"></i>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item tight-form-item-icon">
|
||||
<i class="fa fa-info-circle"></i>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
<a ng-click="toggleEditorHelp(1);" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
||||
alias patterns
|
||||
</a>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
<a ng-click="toggleEditorHelp(2)" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
||||
stacking & and fill
|
||||
</a>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
<a ng-click="toggleEditorHelp(3)" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
||||
group by time
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="editor-row">
|
||||
<div class="pull-left" style="margin-top: 30px;">
|
||||
|
||||
<div class="grafana-info-box span6" ng-if="editorHelpIndex === 1">
|
||||
<h5>Alias patterns</h5>
|
||||
<ul>
|
||||
<li>$s = series name</li>
|
||||
<li>$g = group by</li>
|
||||
<li>$[0-9] part of series name for series names seperated by dots.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="grafana-info-box span6" ng-if="editorHelpIndex === 2">
|
||||
<h5>Stacking and fill</h5>
|
||||
<ul>
|
||||
<li>When stacking is enabled it important that points align</li>
|
||||
<li>If there are missing points for one series it can cause gaps or missing bars</li>
|
||||
<li>You must use fill(0), and select a group by time low limit</li>
|
||||
<li>Use the group by time option below your queries and specify for example >10s if your metrics are written every 10 seconds</li>
|
||||
<li>This will insert zeros for series that are missing measurements and will make stacking work properly</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="grafana-info-box span6" ng-if="editorHelpIndex === 3">
|
||||
<h5>Group by time</h5>
|
||||
<ul>
|
||||
<li>Group by time is important, otherwise the query could return many thousands of datapoints that will slow down Grafana</li>
|
||||
<li>Leave the group by time field empty for each query and it will be calculated based on time range and pixel width of the graph</li>
|
||||
<li>If you use fill(0) or fill(null) set a low limit for the auto group by time interval</li>
|
||||
<li>The low limit can only be set in the group by time option below your queries</li>
|
||||
<li>You set a low limit by adding a greater sign before the interval</li>
|
||||
<li>Example: >60s if you write metrics to InfluxDB every 60 seconds</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -8,9 +8,7 @@
|
||||
"module": "plugins/datasource/influxdb_08/datasource",
|
||||
|
||||
"partials": {
|
||||
"config": "app/plugins/datasource/influxdb_08/partials/config.html",
|
||||
"query": "app/plugins/datasource/influxdb_08/partials/query.editor.html",
|
||||
"annotations": "app/plugins/datasource/influxdb_08/partials/annotations.editor.html"
|
||||
"config": "app/plugins/datasource/influxdb_08/partials/config.html"
|
||||
},
|
||||
|
||||
"metrics": true,
|
||||
|
@ -3,6 +3,7 @@ define([
|
||||
'lodash',
|
||||
'kbn',
|
||||
'./queryCtrl',
|
||||
'./directives',
|
||||
],
|
||||
function (angular, _, kbn) {
|
||||
'use strict';
|
||||
|
17
public/app/plugins/datasource/kairosdb/directives.js
Normal file
17
public/app/plugins/datasource/kairosdb/directives.js
Normal file
@ -0,0 +1,17 @@
|
||||
define([
|
||||
'angular',
|
||||
],
|
||||
function (angular) {
|
||||
'use strict';
|
||||
|
||||
var module = angular.module('grafana.directives');
|
||||
|
||||
module.directive('metricQueryEditorKairosdb', function() {
|
||||
return {controller: 'KairosDBQueryCtrl', templateUrl: 'app/plugins/datasource/kairosdb/partials/query.editor.html'};
|
||||
});
|
||||
|
||||
module.directive('metricQueryOptionsKairosdb', function() {
|
||||
return {templateUrl: 'app/plugins/datasource/kairosdb/partials/query.options.html'};
|
||||
});
|
||||
|
||||
});
|
@ -1,384 +1,328 @@
|
||||
<div class="editor-row">
|
||||
<div ng-repeat="target in panel.targets"
|
||||
class="tight-form-container"
|
||||
ng-class="{'tight-form-disabled': target.hide}"
|
||||
ng-controller="KairosDBQueryCtrl"
|
||||
ng-init="init()">
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list pull-right">
|
||||
<li class="tight-form-item">
|
||||
<div class="dropdown">
|
||||
<a class="pointer dropdown-toggle" data-toggle="dropdown" tabindex="1">
|
||||
<i class="fa fa-bars"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu pull-right" role="menu">
|
||||
<li role="menuitem"><a tabindex="1" ng-click="duplicate()">Duplicate</a></li>
|
||||
<li role="menuitem"><a tabindex="1" ng-click="moveMetricQuery($index, $index-1)">Move up</a></li>
|
||||
<li role="menuitem"><a tabindex="1" ng-click="moveMetricQuery($index, $index+1)">Move down</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
<li class="tight-form-item last">
|
||||
<a class="pointer" tabindex="1" ng-click="removeDataQuery(target)">
|
||||
<i class="fa fa-remove"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list pull-right">
|
||||
<li class="tight-form-item">
|
||||
<div class="dropdown">
|
||||
<a class="pointer dropdown-toggle"
|
||||
data-toggle="dropdown"
|
||||
tabindex="1">
|
||||
<i class="fa fa-bars"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu pull-right" role="menu">
|
||||
<li role="menuitem"><a tabindex="1" ng-click="duplicate()">Duplicate</a></li>
|
||||
<li role="menuitem"><a tabindex="1" ng-click="moveMetricQuery($index, $index-1)">Move up</a></li>
|
||||
<li role="menuitem"><a tabindex="1" ng-click="moveMetricQuery($index, $index+1)">Move down</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
<li class="tight-form-item last">
|
||||
<a class="pointer" tabindex="1" ng-click="removeDataQuery(target)">
|
||||
<i class="fa fa-remove"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item" style="min-width: 15px; text-align: center">
|
||||
{{target.refId}}
|
||||
</li>
|
||||
<li>
|
||||
<a class="tight-form-item" ng-click="target.hide = !target.hide; targetBlur();" role="menuitem">
|
||||
<i class="fa fa-eye"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
Metric
|
||||
</li>
|
||||
<li>
|
||||
<input type="text" class="input-large tight-form-input"
|
||||
ng-model="target.metric"
|
||||
spellcheck="false"
|
||||
bs-typeahead="suggestMetrics"
|
||||
placeholder="metric name"
|
||||
data-min-length=0 data-items=100
|
||||
ng-blur="targetBlur()">
|
||||
<a bs-tooltip="target.errors.metric"
|
||||
style="color: rgb(229, 189, 28)"
|
||||
ng-show="target.errors.metric">
|
||||
<i class="fa fa-warning"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
Alias
|
||||
</li>
|
||||
<li>
|
||||
<input type="text" class="input-medium tight-form-input" ng-model="target.alias"
|
||||
spellcheck='false' placeholder="alias" ng-blur="targetBlur()">
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
Peak filter
|
||||
<input class="input-medium" type="checkbox" ng-model="target.exOuter" ng-change="targetBlur()">
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul class="tight-form-list">
|
||||
<li>
|
||||
<a class="tight-form-item" ng-click="target.hide = !target.hide; targetBlur();" role="menuitem">
|
||||
<i class="fa fa-eye"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
Metric
|
||||
</li>
|
||||
<li>
|
||||
<input type="text"
|
||||
class="input-large tight-form-input"
|
||||
ng-model="target.metric"
|
||||
spellcheck="false"
|
||||
bs-typeahead="suggestMetrics"
|
||||
placeholder="metric name"
|
||||
data-min-length=0 data-items=100
|
||||
ng-blur="targetBlur()"
|
||||
>
|
||||
<a bs-tooltip="target.errors.metric"
|
||||
style="color: rgb(229, 189, 28)"
|
||||
ng-show="target.errors.metric">
|
||||
<i class="fa fa-warning"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
Alias
|
||||
</li>
|
||||
<li>
|
||||
<input type="text" class="input-medium tight-form-input" ng-model="target.alias"
|
||||
spellcheck='false' placeholder="alias" ng-blur="targetBlur()">
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
Peak filter
|
||||
<input class="input-medium" type="checkbox" ng-model="target.exOuter" ng-change="targetBlur()">
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
|
||||
<!-- TAGS -->
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list" role="menu">
|
||||
<li class="tight-form-item">
|
||||
<i class="fa fa-eye invisible"></i>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
Tags
|
||||
</li>
|
||||
<li ng-repeat="(key, value) in target.tags track by $index" class="tight-form-item">
|
||||
{{key}} = {{value}}
|
||||
<a ng-click="removeFilterTag(key)">
|
||||
<i class="fa fa-remove"></i>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="tight-form-item" ng-hide="addFilterTagMode">
|
||||
<a ng-click="addFilterTag()">
|
||||
<i class="fa fa-plus"></i>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li ng-show="addFilterTagMode">
|
||||
<input type="text"
|
||||
class="input-small tight-form-input"
|
||||
spellcheck='false'
|
||||
bs-typeahead="suggestTagKeys"
|
||||
ng-change="validateFilterTag()"
|
||||
data-min-length=0 data-items=100
|
||||
ng-model="target.currentTagKey"
|
||||
placeholder="key">
|
||||
</li>
|
||||
<li ng-show="addFilterTagMode">
|
||||
<input type="text"
|
||||
class="input-small tight-form-input"
|
||||
spellcheck='false'
|
||||
bs-typeahead="suggestTagValues"
|
||||
ng-change="validateFilterTag()"
|
||||
data-min-length=0 data-items=100
|
||||
ng-model="target.currentTagValue"
|
||||
placeholder="value">
|
||||
<a bs-tooltip="target.errors.tags"
|
||||
style="color: rgb(229, 189, 28)"
|
||||
ng-show="target.errors.tags">
|
||||
<i class="fa fa-warning"></i>
|
||||
</a>
|
||||
<li class="tight-form-item" ng-show="addFilterTagMode">
|
||||
<a ng-click="addFilterTag()">
|
||||
<i ng-show="target.errors.tags" class="fa fa-remove"></i>
|
||||
<i ng-hide="target.errors.tags" class="fa fa-plus-circle"></i>
|
||||
</a>
|
||||
</li>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
|
||||
<!-- GROUP BY -->
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list" role="menu">
|
||||
<li class="tight-form-item">
|
||||
<i class="fa fa-eye invisible"></i>
|
||||
</li>
|
||||
|
||||
<li class="tight-form-item">
|
||||
Group By
|
||||
</li>
|
||||
|
||||
<li class="tight-form-item" ng-show="target.groupByTags">
|
||||
tags:
|
||||
</li>
|
||||
|
||||
<li ng-repeat="key in target.groupByTags track by $index" class="tight-form-item">
|
||||
{{key}}
|
||||
<a ng-click="removeGroupByTag($index)">
|
||||
<i class="fa fa-remove"></i>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="tight-form-item" ng-show="target.groupByTags && target.nonTagGroupBys">
|
||||
and by:
|
||||
</li>
|
||||
|
||||
<li ng-repeat="groupByObject in target.nonTagGroupBys track by $index" class="tight-form-item">
|
||||
{{_.values(groupByObject)}}
|
||||
<a ng-click="removeNonTagGroupBy($index)">
|
||||
<i class="fa fa-remove"></i>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="tight-form-item" ng-hide="addGroupByMode">
|
||||
<a ng-click="addGroupBy()">
|
||||
<i class="fa fa-plus"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li ng-show="addGroupByMode">
|
||||
<select class="input-small tight-form-input"
|
||||
ng-change="changeGroupByInput()"
|
||||
ng-model="target.currentGroupByType"
|
||||
ng-options="f for f in ['tag','value','time']"></select>
|
||||
</li>
|
||||
<li ng-show="isTagGroupBy">
|
||||
<input type="text"
|
||||
class="input-small tight-form-input"
|
||||
spellcheck='false'
|
||||
bs-typeahead="suggestTagKeys"
|
||||
ng-change = "validateGroupBy()"
|
||||
data-min-length=0 data-items=100
|
||||
ng-model="target.groupBy.tagKey"
|
||||
placeholder="key">
|
||||
<a bs-tooltip="target.errors.groupBy.tagKey"
|
||||
style="color: rgb(229, 189, 28)"
|
||||
ng-show="target.errors.groupBy.tagKey">
|
||||
<i class="fa fa-warning"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li ng-show="isValueGroupBy">
|
||||
<input type="text"
|
||||
class="input-mini tight-form-input"
|
||||
spellcheck='false'
|
||||
ng-model="target.groupBy.valueRange"
|
||||
placeholder="range"
|
||||
bs-tooltip="'Range on which values are considered in the same group'"
|
||||
ng-change = "validateGroupBy()" >
|
||||
<a bs-tooltip="target.errors.groupBy.valueRange"
|
||||
style="color: rgb(229, 189, 28)"
|
||||
ng-show="target.errors.groupBy.valueRange">
|
||||
<i class="fa fa-warning"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li ng-show="isTimeGroupBy">
|
||||
<input type="text"
|
||||
class="input-mini tight-form-input"
|
||||
ng-model="target.groupBy.timeInterval"
|
||||
ng-init="target.groupBy.timeInterval='1s'"
|
||||
placeholder="interval"
|
||||
bs-tooltip="'Duration of time groups'"
|
||||
spellcheck='false'
|
||||
ng-change="validateGroupBy()">
|
||||
<a bs-tooltip="target.errors.groupBy.timeInterval"
|
||||
style="color: rgb(229, 189, 28)"
|
||||
ng-show="target.errors.groupBy.timeInterval">
|
||||
<i class="fa fa-warning"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li ng-show="isTimeGroupBy">
|
||||
<input type="text"
|
||||
class="input-mini tight-form-input"
|
||||
ng-model="target.groupBy.groupCount"
|
||||
placeholder="Count"
|
||||
bs-tooltip="'Number of time groups to be formed'"
|
||||
spellcheck='false'
|
||||
ng-change="validateGroupBy()">
|
||||
<a bs-tooltip="target.errors.groupBy.groupCount"
|
||||
style="color: rgb(229, 189, 28)"
|
||||
ng-show="target.errors.groupBy.groupCount">
|
||||
<i class="fa fa-warning"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li class="tight-form-item" ng-show="addGroupByMode">
|
||||
<a ng-click="addGroupBy()">
|
||||
<i ng-hide="isGroupByValid" class="fa fa-remove"></i>
|
||||
<i ng-show="isGroupByValid" class="fa fa-plus-circle"></i>
|
||||
</a>
|
||||
</li>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
|
||||
<!-- HORIZONTAL AGGREGATION -->
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list" role="menu">
|
||||
<li class="tight-form-item">
|
||||
<i class="fa fa-eye invisible"></i>
|
||||
</li>
|
||||
|
||||
<li class="tight-form-item">
|
||||
Aggregators
|
||||
</li>
|
||||
<li ng-repeat="aggregatorObject in target.horizontalAggregators track by $index" class="tight-form-item">
|
||||
{{aggregatorObject.name}}(
|
||||
<span ng-repeat="aggKey in _.keys(_.omit(aggregatorObject,'name'))" bs-tooltip="aggKey">
|
||||
{{$last?aggregatorObject[aggKey]:aggregatorObject[aggKey]+","}}
|
||||
</span>
|
||||
)
|
||||
<a ng-click="removeHorizontalAggregator($index)">
|
||||
<i class="fa fa-remove"></i>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="tight-form-item" ng-hide="addHorizontalAggregatorMode">
|
||||
<a ng-click="addHorizontalAggregator()">
|
||||
<i class="fa fa-plus"></i>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li ng-show="addHorizontalAggregatorMode">
|
||||
<select class="input-medium tight-form-input"
|
||||
ng-change="changeHorAggregationInput()"
|
||||
ng-model="target.currentHorizontalAggregatorName"
|
||||
ng-options="f for f in ['avg','dev','max','min','rate','sampler','count','sum','least_squares','percentile','scale','div']"></select>
|
||||
</li>
|
||||
|
||||
<!-- Different parameters -->
|
||||
<li ng-show="hasSamplingRate" class="tight-form-item">
|
||||
every
|
||||
</li>
|
||||
<li ng-show="hasSamplingRate">
|
||||
<input type="text"
|
||||
class="input-mini tight-form-input"
|
||||
ng-model="target.horAggregator.samplingRate"
|
||||
ng-init="target.horAggregator.samplingRate='1s'"
|
||||
spellcheck='false'
|
||||
ng-change="validateHorizontalAggregator()" >
|
||||
<a bs-tooltip="target.errors.horAggregator.samplingRate"
|
||||
style="color: rgb(229, 189, 28)"
|
||||
ng-show="target.errors.horAggregator.samplingRate">
|
||||
<i class="fa fa-warning"></i>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li ng-show="hasUnit" class="tight-form-item">
|
||||
every
|
||||
</li>
|
||||
<li ng-show="hasUnit">
|
||||
<select class="input-medium tight-form-input"
|
||||
ng-model="target.horAggregator.unit"
|
||||
ng-init="target.horAggregator.unit='millisecond'"
|
||||
ng-options="f for f in ['millisecond','second','minute','hour','day','week','month','year']"></select>
|
||||
</li>
|
||||
|
||||
<li ng-show="hasFactor" class="tight-form-item">
|
||||
by
|
||||
</li>
|
||||
<li ng-show="hasFactor">
|
||||
<input type="text"
|
||||
class="input-mini tight-form-input"
|
||||
ng-model="target.horAggregator.factor"
|
||||
ng-init="target.horAggregator.factor='1'"
|
||||
spellcheck='false'
|
||||
ng-change="validateHorizontalAggregator()" >
|
||||
<a bs-tooltip="target.errors.horAggregator.factor"
|
||||
style="color: rgb(229, 189, 28)"
|
||||
ng-show="target.errors.horAggregator.factor">
|
||||
<i class="fa fa-warning"></i>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li ng-show="hasPercentile" class="tight-form-item">
|
||||
percentile
|
||||
</li>
|
||||
<li ng-show="hasPercentile">
|
||||
<input type="text"
|
||||
class="input-mini tight-form-input"
|
||||
ng-model="target.horAggregator.percentile"
|
||||
ng-init="target.horAggregator.percentile='0.75'"
|
||||
spellcheck='false'
|
||||
ng-change="validateHorizontalAggregator()" >
|
||||
<a bs-tooltip="target.errors.horAggregator.percentile"
|
||||
style="color: rgb(229, 189, 28)"
|
||||
ng-show="target.errors.horAggregator.percentile">
|
||||
<i class="fa fa-warning"></i>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="tight-form-item" ng-show="addHorizontalAggregatorMode">
|
||||
<a ng-click="addHorizontalAggregator()">
|
||||
<i ng-hide="isAggregatorValid" class="fa fa-remove"></i>
|
||||
<i ng-show="isAggregatorValid" class="fa fa-plus-circle"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
|
||||
<section class="grafana-metric-options" ng-controller="KairosDBQueryCtrl">
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item tight-form-item-icon">
|
||||
<i class="fa fa-wrench"></i>
|
||||
</li>
|
||||
<!-- TAGS -->
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list" role="menu">
|
||||
<li class="tight-form-item tight-form-align">
|
||||
Tags
|
||||
</li>
|
||||
<li ng-repeat="(key, value) in target.tags track by $index" class="tight-form-item">
|
||||
{{key}} = {{value}}
|
||||
<a ng-click="removeFilterTag(key)">
|
||||
<i class="fa fa-remove"></i>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="tight-form-item">
|
||||
Downsampling with
|
||||
</li>
|
||||
<li>
|
||||
<select class="input-medium tight-form-input" ng-change="panelBlur()" ng-model="panel.downsampling" ng-options="f for f in ['(NONE)','avg', 'sum', 'min', 'max', 'dev']" ></select>
|
||||
</li>
|
||||
<li class="tight-form-item" ng-hide="addFilterTagMode">
|
||||
<a ng-click="addFilterTag()">
|
||||
<i class="fa fa-plus"></i>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<!-- SAMPLING RATE -->
|
||||
<li ng-hide="panel.downsampling=='(NONE)'" class="tight-form-item">
|
||||
every
|
||||
</li>
|
||||
<li>
|
||||
<input type="text"
|
||||
ng-hide="panel.downsampling=='(NONE)'"
|
||||
class="input-mini tight-form-input"
|
||||
ng-model="panel.sampling"
|
||||
placeholder="{{interval}}"
|
||||
bs-tooltip="'Leave blank for auto handling based on time range and panel width'"
|
||||
spellcheck='false'
|
||||
ng-blur="panelBlur()" >
|
||||
<a bs-tooltip="target.errors.sampling"
|
||||
style="color: rgb(229, 189, 28)"
|
||||
ng-show="target.errors.sampling">
|
||||
<i class="fa fa-warning"></i>
|
||||
<li ng-show="addFilterTagMode">
|
||||
<input type="text"
|
||||
class="input-small tight-form-input"
|
||||
spellcheck='false'
|
||||
bs-typeahead="suggestTagKeys"
|
||||
ng-change="validateFilterTag()"
|
||||
data-min-length=0 data-items=100
|
||||
ng-model="target.currentTagKey"
|
||||
placeholder="key">
|
||||
</li>
|
||||
<li ng-show="addFilterTagMode">
|
||||
<input type="text"
|
||||
class="input-small tight-form-input"
|
||||
spellcheck='false'
|
||||
bs-typeahead="suggestTagValues"
|
||||
ng-change="validateFilterTag()"
|
||||
data-min-length=0 data-items=100
|
||||
ng-model="target.currentTagValue"
|
||||
placeholder="value">
|
||||
<a bs-tooltip="target.errors.tags"
|
||||
style="color: rgb(229, 189, 28)"
|
||||
ng-show="target.errors.tags">
|
||||
<i class="fa fa-warning"></i>
|
||||
</a>
|
||||
<li class="tight-form-item" ng-show="addFilterTagMode">
|
||||
<a ng-click="addFilterTag()">
|
||||
<i ng-show="target.errors.tags" class="fa fa-remove"></i>
|
||||
<i ng-hide="target.errors.tags" class="fa fa-plus-circle"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</section>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
|
||||
<!-- GROUP BY -->
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list" role="menu">
|
||||
<li class="tight-form-item tight-form-align">
|
||||
Group By
|
||||
</li>
|
||||
|
||||
<li class="tight-form-item" ng-show="target.groupByTags">
|
||||
tags:
|
||||
</li>
|
||||
|
||||
<li ng-repeat="key in target.groupByTags track by $index" class="tight-form-item">
|
||||
{{key}}
|
||||
<a ng-click="removeGroupByTag($index)">
|
||||
<i class="fa fa-remove"></i>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="tight-form-item" ng-show="target.groupByTags && target.nonTagGroupBys">
|
||||
and by:
|
||||
</li>
|
||||
|
||||
<li ng-repeat="groupByObject in target.nonTagGroupBys track by $index" class="tight-form-item">
|
||||
{{_.values(groupByObject)}}
|
||||
<a ng-click="removeNonTagGroupBy($index)">
|
||||
<i class="fa fa-remove"></i>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="tight-form-item" ng-hide="addGroupByMode">
|
||||
<a ng-click="addGroupBy()">
|
||||
<i class="fa fa-plus"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li ng-show="addGroupByMode">
|
||||
<select class="input-small tight-form-input"
|
||||
ng-change="changeGroupByInput()"
|
||||
ng-model="target.currentGroupByType"
|
||||
ng-options="f for f in ['tag','value','time']"></select>
|
||||
</li>
|
||||
<li ng-show="isTagGroupBy">
|
||||
<input type="text"
|
||||
class="input-small tight-form-input"
|
||||
spellcheck='false'
|
||||
bs-typeahead="suggestTagKeys"
|
||||
ng-change = "validateGroupBy()"
|
||||
data-min-length=0 data-items=100
|
||||
ng-model="target.groupBy.tagKey"
|
||||
placeholder="key">
|
||||
<a bs-tooltip="target.errors.groupBy.tagKey"
|
||||
style="color: rgb(229, 189, 28)"
|
||||
ng-show="target.errors.groupBy.tagKey">
|
||||
<i class="fa fa-warning"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li ng-show="isValueGroupBy">
|
||||
<input type="text"
|
||||
class="input-mini tight-form-input"
|
||||
spellcheck='false'
|
||||
ng-model="target.groupBy.valueRange"
|
||||
placeholder="range"
|
||||
bs-tooltip="'Range on which values are considered in the same group'"
|
||||
ng-change = "validateGroupBy()" >
|
||||
<a bs-tooltip="target.errors.groupBy.valueRange"
|
||||
style="color: rgb(229, 189, 28)"
|
||||
ng-show="target.errors.groupBy.valueRange">
|
||||
<i class="fa fa-warning"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li ng-show="isTimeGroupBy">
|
||||
<input type="text"
|
||||
class="input-mini tight-form-input"
|
||||
ng-model="target.groupBy.timeInterval"
|
||||
ng-init="target.groupBy.timeInterval='1s'"
|
||||
placeholder="interval"
|
||||
bs-tooltip="'Duration of time groups'"
|
||||
spellcheck='false'
|
||||
ng-change="validateGroupBy()">
|
||||
<a bs-tooltip="target.errors.groupBy.timeInterval"
|
||||
style="color: rgb(229, 189, 28)"
|
||||
ng-show="target.errors.groupBy.timeInterval">
|
||||
<i class="fa fa-warning"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li ng-show="isTimeGroupBy">
|
||||
<input type="text"
|
||||
class="input-mini tight-form-input"
|
||||
ng-model="target.groupBy.groupCount"
|
||||
placeholder="Count"
|
||||
bs-tooltip="'Number of time groups to be formed'"
|
||||
spellcheck='false'
|
||||
ng-change="validateGroupBy()">
|
||||
<a bs-tooltip="target.errors.groupBy.groupCount"
|
||||
style="color: rgb(229, 189, 28)"
|
||||
ng-show="target.errors.groupBy.groupCount">
|
||||
<i class="fa fa-warning"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li class="tight-form-item" ng-show="addGroupByMode">
|
||||
<a ng-click="addGroupBy()">
|
||||
<i ng-hide="isGroupByValid" class="fa fa-remove"></i>
|
||||
<i ng-show="isGroupByValid" class="fa fa-plus-circle"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
|
||||
<!-- HORIZONTAL AGGREGATION -->
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list" role="menu">
|
||||
<li class="tight-form-item tight-form-align">
|
||||
Aggregators
|
||||
</li>
|
||||
<li ng-repeat="aggregatorObject in target.horizontalAggregators track by $index" class="tight-form-item">
|
||||
{{aggregatorObject.name}}(
|
||||
<span ng-repeat="aggKey in _.keys(_.omit(aggregatorObject,'name'))" bs-tooltip="aggKey">
|
||||
{{$last?aggregatorObject[aggKey]:aggregatorObject[aggKey]+","}}
|
||||
</span>
|
||||
)
|
||||
<a ng-click="removeHorizontalAggregator($index)">
|
||||
<i class="fa fa-remove"></i>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="tight-form-item" ng-hide="addHorizontalAggregatorMode">
|
||||
<a ng-click="addHorizontalAggregator()">
|
||||
<i class="fa fa-plus"></i>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li ng-show="addHorizontalAggregatorMode">
|
||||
<select class="input-medium tight-form-input"
|
||||
ng-change="changeHorAggregationInput()"
|
||||
ng-model="target.currentHorizontalAggregatorName"
|
||||
ng-options="f for f in ['avg','dev','max','min','rate','sampler','count','sum','least_squares','percentile','scale','div']"></select>
|
||||
</li>
|
||||
|
||||
<!-- Different parameters -->
|
||||
<li ng-show="hasSamplingRate" class="tight-form-item">
|
||||
every
|
||||
</li>
|
||||
<li ng-show="hasSamplingRate">
|
||||
<input type="text"
|
||||
class="input-mini tight-form-input"
|
||||
ng-model="target.horAggregator.samplingRate"
|
||||
ng-init="target.horAggregator.samplingRate='1s'"
|
||||
spellcheck='false'
|
||||
ng-change="validateHorizontalAggregator()" >
|
||||
<a bs-tooltip="target.errors.horAggregator.samplingRate"
|
||||
style="color: rgb(229, 189, 28)"
|
||||
ng-show="target.errors.horAggregator.samplingRate">
|
||||
<i class="fa fa-warning"></i>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li ng-show="hasUnit" class="tight-form-item">
|
||||
every
|
||||
</li>
|
||||
<li ng-show="hasUnit">
|
||||
<select class="input-medium tight-form-input"
|
||||
ng-model="target.horAggregator.unit"
|
||||
ng-init="target.horAggregator.unit='millisecond'"
|
||||
ng-options="f for f in ['millisecond','second','minute','hour','day','week','month','year']"></select>
|
||||
</li>
|
||||
|
||||
<li ng-show="hasFactor" class="tight-form-item">
|
||||
by
|
||||
</li>
|
||||
<li ng-show="hasFactor">
|
||||
<input type="text"
|
||||
class="input-mini tight-form-input"
|
||||
ng-model="target.horAggregator.factor"
|
||||
ng-init="target.horAggregator.factor='1'"
|
||||
spellcheck='false'
|
||||
ng-change="validateHorizontalAggregator()" >
|
||||
<a bs-tooltip="target.errors.horAggregator.factor"
|
||||
style="color: rgb(229, 189, 28)"
|
||||
ng-show="target.errors.horAggregator.factor">
|
||||
<i class="fa fa-warning"></i>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li ng-show="hasPercentile" class="tight-form-item">
|
||||
percentile
|
||||
</li>
|
||||
<li ng-show="hasPercentile">
|
||||
<input type="text"
|
||||
class="input-mini tight-form-input"
|
||||
ng-model="target.horAggregator.percentile"
|
||||
ng-init="target.horAggregator.percentile='0.75'"
|
||||
spellcheck='false'
|
||||
ng-change="validateHorizontalAggregator()" >
|
||||
<a bs-tooltip="target.errors.horAggregator.percentile"
|
||||
style="color: rgb(229, 189, 28)"
|
||||
ng-show="target.errors.horAggregator.percentile">
|
||||
<i class="fa fa-warning"></i>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="tight-form-item" ng-show="addHorizontalAggregatorMode">
|
||||
<a ng-click="addHorizontalAggregator()">
|
||||
<i ng-hide="isAggregatorValid" class="fa fa-remove"></i>
|
||||
<i ng-show="isAggregatorValid" class="fa fa-plus-circle"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
|
||||
|
||||
|
@ -0,0 +1,37 @@
|
||||
<section class="grafana-metric-options" ng-controller="KairosDBQueryCtrl">
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item tight-form-item-icon">
|
||||
<i class="fa fa-wrench"></i>
|
||||
</li>
|
||||
|
||||
<li class="tight-form-item">
|
||||
Downsampling with
|
||||
</li>
|
||||
<li>
|
||||
<select class="input-medium tight-form-input" ng-change="panelBlur()" ng-model="panel.downsampling" ng-options="f for f in ['(NONE)','avg', 'sum', 'min', 'max', 'dev']" ></select>
|
||||
</li>
|
||||
|
||||
<!-- SAMPLING RATE -->
|
||||
<li ng-hide="panel.downsampling=='(NONE)'" class="tight-form-item">
|
||||
every
|
||||
</li>
|
||||
<li>
|
||||
<input type="text"
|
||||
ng-hide="panel.downsampling=='(NONE)'"
|
||||
class="input-mini tight-form-input"
|
||||
ng-model="panel.sampling"
|
||||
placeholder="{{interval}}"
|
||||
bs-tooltip="'Leave blank for auto handling based on time range and panel width'"
|
||||
spellcheck='false'
|
||||
ng-blur="panelBlur()" >
|
||||
<a bs-tooltip="target.errors.sampling"
|
||||
style="color: rgb(229, 189, 28)"
|
||||
ng-show="target.errors.sampling">
|
||||
<i class="fa fa-warning"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</section>
|
@ -8,8 +8,7 @@
|
||||
"module": "plugins/datasource/kairosdb/datasource",
|
||||
|
||||
"partials": {
|
||||
"config": "app/plugins/datasource/kairosdb/partials/config.html",
|
||||
"query": "app/plugins/datasource/kairosdb/partials/query.editor.html"
|
||||
"config": "app/plugins/datasource/kairosdb/partials/config.html"
|
||||
},
|
||||
|
||||
"metrics": true,
|
||||
|
35
public/app/plugins/datasource/mixed/datasource.js
Normal file
35
public/app/plugins/datasource/mixed/datasource.js
Normal file
@ -0,0 +1,35 @@
|
||||
define([
|
||||
'angular',
|
||||
'lodash',
|
||||
],
|
||||
function (angular, _) {
|
||||
'use strict';
|
||||
|
||||
var module = angular.module('grafana.services');
|
||||
|
||||
module.factory('MixedDatasource', function($q, backendSrv, datasourceSrv) {
|
||||
|
||||
function MixedDatasource() {
|
||||
}
|
||||
|
||||
MixedDatasource.prototype.query = function(options) {
|
||||
var sets = _.groupBy(options.targets, 'datasource');
|
||||
var promises = _.map(sets, function(targets) {
|
||||
return datasourceSrv.get(targets[0].datasource).then(function(ds) {
|
||||
var opt = angular.copy(options);
|
||||
opt.targets = targets;
|
||||
return ds.query(opt);
|
||||
});
|
||||
});
|
||||
|
||||
return $q.all(promises).then(function(results) {
|
||||
return { data: _.flatten(_.pluck(results, 'data')) };
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
return MixedDatasource;
|
||||
|
||||
});
|
||||
|
||||
});
|
12
public/app/plugins/datasource/mixed/plugin.json
Normal file
12
public/app/plugins/datasource/mixed/plugin.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"pluginType": "datasource",
|
||||
"name": "Mixed datasource",
|
||||
"builtIn": true,
|
||||
"mixed": true,
|
||||
|
||||
"type": "mixed",
|
||||
"serviceName": "MixedDatasource",
|
||||
|
||||
"module": "plugins/datasource/mixed/datasource",
|
||||
"metrics": true
|
||||
}
|
@ -3,6 +3,7 @@ define([
|
||||
'lodash',
|
||||
'kbn',
|
||||
'moment',
|
||||
'./directives',
|
||||
'./queryCtrl',
|
||||
],
|
||||
function (angular, _, kbn) {
|
||||
|
16
public/app/plugins/datasource/opentsdb/directives.js
Normal file
16
public/app/plugins/datasource/opentsdb/directives.js
Normal file
@ -0,0 +1,16 @@
|
||||
define([
|
||||
'angular',
|
||||
],
|
||||
function (angular) {
|
||||
'use strict';
|
||||
|
||||
var module = angular.module('grafana.directives');
|
||||
|
||||
module.directive('metricQueryEditorOpentsdb', function() {
|
||||
return {
|
||||
controller: 'OpenTSDBQueryCtrl',
|
||||
templateUrl: 'app/plugins/datasource/opentsdb/partials/query.editor.html',
|
||||
};
|
||||
});
|
||||
|
||||
});
|
@ -1,241 +1,208 @@
|
||||
<div class="editor-row" style="margin-top: 10px;">
|
||||
|
||||
<div ng-repeat="target in panel.targets"
|
||||
style="margin-bottom: 10px;"
|
||||
ng-class="{'tight-form-disabled': target.hide}"
|
||||
ng-controller="OpenTSDBQueryCtrl"
|
||||
ng-init="init()">
|
||||
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list pull-right">
|
||||
<li class="tight-form-item">
|
||||
<div class="dropdown">
|
||||
<a class="pointer dropdown-toggle"
|
||||
data-toggle="dropdown"
|
||||
tabindex="1">
|
||||
<i class="fa fa-bars"></i>
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list pull-right">
|
||||
<li class="tight-form-item">
|
||||
<div class="dropdown">
|
||||
<a class="pointer dropdown-toggle"
|
||||
data-toggle="dropdown"
|
||||
tabindex="1">
|
||||
<i class="fa fa-bars"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu pull-right" role="menu">
|
||||
<li role="menuitem">
|
||||
<a tabindex="1"
|
||||
ng-click="duplicate()">
|
||||
Duplicate
|
||||
</a>
|
||||
<ul class="dropdown-menu pull-right" role="menu">
|
||||
<li role="menuitem">
|
||||
<a tabindex="1"
|
||||
ng-click="duplicate()">
|
||||
Duplicate
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
<li class="tight-form-item last">
|
||||
<a class="pointer" tabindex="1" ng-click="removeDataQuery(target)">
|
||||
<i class="fa fa-remove"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
<li class="tight-form-item last">
|
||||
<a class="pointer" tabindex="1" ng-click="removeDataQuery(target)">
|
||||
<i class="fa fa-remove"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul class="tight-form-list">
|
||||
<li>
|
||||
<a class="tight-form-item"
|
||||
ng-click="target.hide = !target.hide; get_data();"
|
||||
role="menuitem">
|
||||
<i class="fa fa-eye"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item" style="min-width: 15px; text-align: center">
|
||||
{{target.refId}}
|
||||
</li>
|
||||
<li>
|
||||
<a class="tight-form-item"
|
||||
ng-click="target.hide = !target.hide; get_data();"
|
||||
role="menuitem">
|
||||
<i class="fa fa-eye"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul class="tight-form-list" role="menu">
|
||||
<li class="tight-form-item" style="width: 86px">
|
||||
Metric
|
||||
</li>
|
||||
<li>
|
||||
<input type="text"
|
||||
class="input-large tight-form-input"
|
||||
ng-model="target.metric"
|
||||
spellcheck='false'
|
||||
bs-typeahead="suggestMetrics"
|
||||
placeholder="metric name"
|
||||
data-min-length=0 data-items=100
|
||||
ng-model-onblur
|
||||
ng-change="targetBlur()"
|
||||
>
|
||||
<a bs-tooltip="target.errors.metric"
|
||||
style="color: rgb(229, 189, 28)"
|
||||
ng-show="target.errors.metric">
|
||||
<i class="fa fa-warning"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
Aggregator
|
||||
</li>
|
||||
<li>
|
||||
<select ng-model="target.aggregator"
|
||||
class="tight-form-input input-small"
|
||||
ng-options="agg for agg in aggregators"
|
||||
ng-change="targetBlur()">
|
||||
</select>
|
||||
<a bs-tooltip="target.errors.aggregator"
|
||||
style="color: rgb(229, 189, 28)"
|
||||
ng-show="target.errors.aggregator">
|
||||
<i class="fa fa-warning"></i>
|
||||
</a>
|
||||
</li>
|
||||
<ul class="tight-form-list" role="menu">
|
||||
<li class="tight-form-item" style="width: 86px">
|
||||
Metric
|
||||
</li>
|
||||
<li>
|
||||
<input type="text"
|
||||
class="input-large tight-form-input"
|
||||
ng-model="target.metric"
|
||||
spellcheck='false'
|
||||
bs-typeahead="suggestMetrics"
|
||||
placeholder="metric name"
|
||||
data-min-length=0 data-items=100
|
||||
ng-model-onblur
|
||||
ng-change="targetBlur()">
|
||||
</input>
|
||||
<a bs-tooltip="target.errors.metric" style="color: rgb(229, 189, 28)" ng-show="target.errors.metric">
|
||||
<i class="fa fa-warning"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
Aggregator
|
||||
</li>
|
||||
<li>
|
||||
<select ng-model="target.aggregator" class="tight-form-input input-small"
|
||||
ng-options="agg for agg in aggregators"
|
||||
ng-change="targetBlur()">
|
||||
</select>
|
||||
<a bs-tooltip="target.errors.aggregator" style="color: rgb(229, 189, 28)" ng-show="target.errors.aggregator">
|
||||
<i class="fa fa-warning"></i>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="tight-form-item">
|
||||
Alias:
|
||||
<tip>Use patterns like $tag_tagname to replace part of the alias for a tag value</tip>
|
||||
</li>
|
||||
<li>
|
||||
<li class="tight-form-item">
|
||||
Alias:
|
||||
<tip>Use patterns like $tag_tagname to replace part of the alias for a tag value</tip>
|
||||
</li>
|
||||
<li>
|
||||
<input type="text" class="tight-form-input input-large"
|
||||
ng-model="target.alias"
|
||||
spellcheck='false'
|
||||
placeholder="series alias"
|
||||
data-min-length=0 data-items=100
|
||||
ng-blur="targetBlur()"></input>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list" role="menu">
|
||||
<li class="tight-form-item tight-form-align" style="width: 86px">
|
||||
Down sample
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<input type="text" class="input-large tight-form-input"
|
||||
ng-model="target.downsampleInterval"
|
||||
ng-model-onblur
|
||||
ng-change="targetBlur()"
|
||||
placeholder="interval (empty = auto)">
|
||||
</li>
|
||||
|
||||
<li class="tight-form-item">
|
||||
Aggregator
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<select ng-model="target.downsampleAggregator" class="tight-form-input input-small"
|
||||
ng-options="agg for agg in aggregators"
|
||||
ng-change="targetBlur()">
|
||||
</select>
|
||||
</li>
|
||||
|
||||
<li class="tight-form-item">
|
||||
<editor-checkbox text="Disable downsampling" model="target.disableDownsampling" change="targetBlur()"></editor-checkbox>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list" role="menu">
|
||||
<li class="tight-form-item tight-form-align" style="width: 86px">
|
||||
Tags
|
||||
</li>
|
||||
<li ng-repeat="(key, value) in target.tags track by $index" class="tight-form-item">
|
||||
{{key}} = {{value}}
|
||||
<a ng-click="removeTag(key)">
|
||||
<i class="fa fa-remove"></i>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="tight-form-item" ng-hide="addTagMode">
|
||||
<a ng-click="addTag()">
|
||||
<i class="fa fa-plus"></i>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li ng-show="addTagMode">
|
||||
<input type="text" class="input-small tight-form-input"
|
||||
spellcheck='false'
|
||||
bs-typeahead="suggestTagKeys"
|
||||
data-min-length=0 data-items=100
|
||||
ng-model="target.currentTagKey"
|
||||
placeholder="key">
|
||||
<input type="text"
|
||||
class="tight-form-input input-large"
|
||||
ng-model="target.alias"
|
||||
spellcheck='false'
|
||||
placeholder="series alias"
|
||||
data-min-length=0 data-items=100
|
||||
ng-blur="targetBlur()"
|
||||
/>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list" role="menu">
|
||||
<li class="tight-form-item">
|
||||
<i class="fa fa-eye invisible"></i>
|
||||
class="input-small tight-form-input"
|
||||
spellcheck='false'
|
||||
bs-typeahead="suggestTagValues"
|
||||
data-min-length=0 data-items=100
|
||||
ng-model="target.currentTagValue"
|
||||
placeholder="value">
|
||||
</input>
|
||||
<a ng-click="addTag()">
|
||||
add tag
|
||||
</a>
|
||||
<a bs-tooltip="target.errors.tags"
|
||||
style="color: rgb(229, 189, 28)"
|
||||
ng-show="target.errors.tags">
|
||||
<i class="fa fa-warning"></i>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="tight-form-item" style="width: 86px">
|
||||
Down sample
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<input type="text"
|
||||
class="input-large tight-form-input"
|
||||
ng-model="target.downsampleInterval"
|
||||
ng-model-onblur
|
||||
ng-change="targetBlur()"
|
||||
placeholder="interval (empty = auto)"
|
||||
>
|
||||
</li>
|
||||
|
||||
<li class="tight-form-item">
|
||||
Aggregator
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<select ng-model="target.downsampleAggregator"
|
||||
class="tight-form-input input-small"
|
||||
ng-options="agg for agg in aggregators"
|
||||
ng-change="targetBlur()">
|
||||
</select>
|
||||
</li>
|
||||
|
||||
<li class="tight-form-item">
|
||||
<editor-checkbox text="Disable downsampling" model="target.disableDownsampling" change="targetBlur()"></editor-checkbox>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list" role="menu">
|
||||
<li class="tight-form-item">
|
||||
<i class="fa fa-eye invisible"></i>
|
||||
</li>
|
||||
|
||||
<li class="tight-form-item" style="width: 86px">
|
||||
Tags
|
||||
</li>
|
||||
<li ng-repeat="(key, value) in target.tags track by $index" class="tight-form-item">
|
||||
{{key}} = {{value}}
|
||||
<a ng-click="removeTag(key)">
|
||||
<i class="fa fa-remove"></i>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="tight-form-item" ng-hide="addTagMode">
|
||||
<a ng-click="addTag()">
|
||||
<i class="fa fa-plus"></i>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li ng-show="addTagMode">
|
||||
<input type="text"
|
||||
class="input-small tight-form-input"
|
||||
spellcheck='false'
|
||||
bs-typeahead="suggestTagKeys"
|
||||
data-min-length=0 data-items=100
|
||||
ng-model="target.currentTagKey"
|
||||
placeholder="key">
|
||||
<input type="text"
|
||||
class="input-small tight-form-input"
|
||||
spellcheck='false'
|
||||
bs-typeahead="suggestTagValues"
|
||||
data-min-length=0 data-items=100
|
||||
ng-model="target.currentTagValue"
|
||||
placeholder="value">
|
||||
<a ng-click="addTag()">
|
||||
add tag
|
||||
</a>
|
||||
<a bs-tooltip="target.errors.tags"
|
||||
style="color: rgb(229, 189, 28)"
|
||||
ng-show="target.errors.tags">
|
||||
<i class="fa fa-warning"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list" role="menu">
|
||||
<li class="tight-form-item">
|
||||
<i class="fa fa-eye invisible"></i>
|
||||
</li>
|
||||
|
||||
<li class="tight-form-item" style="width: 86px">
|
||||
<li class="tight-form-item tight-form-align" style="width: 86px">
|
||||
<editor-checkbox text="Rate" model="target.shouldComputeRate" change="targetBlur()"></editor-checkbox>
|
||||
</li>
|
||||
|
||||
<li class="tight-form-item" ng-hide="!target.shouldComputeRate">
|
||||
<li class="tight-form-item" ng-hide="!target.shouldComputeRate">
|
||||
<editor-checkbox text="Counter" model="target.isCounter" change="targetBlur()"></editor-checkbox>
|
||||
</li>
|
||||
|
||||
<li class="tight-form-item" ng-hide="!target.isCounter">
|
||||
Counter Max:
|
||||
</li>
|
||||
Counter Max:
|
||||
</li>
|
||||
|
||||
<li ng-hide="!target.isCounter">
|
||||
<input type="text"
|
||||
class="tight-form-input input-small"
|
||||
ng-disabled="!target.shouldComputeRate"
|
||||
ng-model="target.counterMax"
|
||||
spellcheck='false'
|
||||
placeholder="max value"
|
||||
ng-model-onblur
|
||||
ng-blur="targetBlur()"
|
||||
/>
|
||||
</li>
|
||||
<li class="tight-form-item" ng-hide="!target.isCounter">
|
||||
Reset Value:
|
||||
</li>
|
||||
<li ng-hide="!target.isCounter">
|
||||
<input type="text"
|
||||
class="tight-form-input input-small"
|
||||
ng-disabled="!target.shouldComputeRate"
|
||||
ng-model="target.counterResetValue"
|
||||
spellcheck='false'
|
||||
placeholder="reset value"
|
||||
ng-model-onblur
|
||||
ng-blur="targetBlur()"
|
||||
/>
|
||||
</li>
|
||||
<li ng-hide="!target.isCounter">
|
||||
<input type="text" class="tight-form-input input-small"
|
||||
ng-disabled="!target.shouldComputeRate"
|
||||
ng-model="target.counterMax"
|
||||
spellcheck='false'
|
||||
placeholder="max value"
|
||||
ng-model-onblur
|
||||
ng-blur="targetBlur()"></input>
|
||||
</li>
|
||||
<li class="tight-form-item" ng-hide="!target.isCounter">
|
||||
Reset Value:
|
||||
</li>
|
||||
<li ng-hide="!target.isCounter">
|
||||
<input type="text" class="tight-form-input input-small"
|
||||
ng-disabled="!target.shouldComputeRate"
|
||||
ng-model="target.counterResetValue"
|
||||
spellcheck='false'
|
||||
placeholder="reset value"
|
||||
ng-model-onblur
|
||||
ng-blur="targetBlur()"></input>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -8,8 +8,7 @@
|
||||
"module": "plugins/datasource/opentsdb/datasource",
|
||||
|
||||
"partials": {
|
||||
"config": "app/plugins/datasource/opentsdb/partials/config.html",
|
||||
"query": "app/plugins/datasource/opentsdb/partials/query.editor.html"
|
||||
"config": "app/plugins/datasource/opentsdb/partials/config.html"
|
||||
},
|
||||
|
||||
"metrics": true
|
||||
|
@ -113,6 +113,7 @@ function (angular, _, kbn) {
|
||||
return errs;
|
||||
}
|
||||
|
||||
$scope.init();
|
||||
});
|
||||
|
||||
});
|
||||
|
@ -20,13 +20,24 @@ function (angular, _, config) {
|
||||
if (value.meta && value.meta.metrics) {
|
||||
self.metricSources.push({
|
||||
value: key === config.defaultDatasource ? null : key,
|
||||
name: 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) {
|
||||
|
@ -358,7 +358,6 @@ div.subnav {
|
||||
|
||||
// BUTTONS
|
||||
// -----------------------------------------------------
|
||||
|
||||
.btn {
|
||||
padding: 5px 12px;
|
||||
background-image: none;
|
||||
@ -389,13 +388,6 @@ div.subnav {
|
||||
}
|
||||
|
||||
.btn-group {
|
||||
|
||||
& > .btn:first-child,
|
||||
& > .btn:last-child,
|
||||
& > .dropdown-toggle {
|
||||
.border-radius(0);
|
||||
}
|
||||
|
||||
& > .btn + .dropdown-toggle {
|
||||
.box-shadow(none);
|
||||
}
|
||||
|
@ -22,12 +22,14 @@
|
||||
|
||||
.tight-form-container-no-item-borders {
|
||||
border: 1px solid @grafanaTargetBorder;
|
||||
border-bottom: none;
|
||||
|
||||
.tight-form, .tight-form-item, [type=text].tight-form-input, [type=text].tight-form-clear-input {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.spaced-form {
|
||||
.tight-form {
|
||||
margin: 7px 0;
|
||||
@ -42,12 +44,11 @@
|
||||
}
|
||||
|
||||
.tight-form-container {
|
||||
border-bottom: 1px solid @grafanaTargetBorder;
|
||||
|
||||
.tight-form:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
&:last-child {
|
||||
border-bottom: 1px solid @grafanaTargetBorder;
|
||||
}
|
||||
}
|
||||
|
||||
.tight-form-btn {
|
||||
@ -63,7 +64,7 @@
|
||||
}
|
||||
|
||||
.grafana-metric-options {
|
||||
margin-top: 35px;
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
.tight-form-item {
|
||||
@ -209,3 +210,7 @@ select.tight-form-input {
|
||||
}
|
||||
}
|
||||
|
||||
.tight-form-align {
|
||||
padding-left: 66px;
|
||||
}
|
||||
|
||||
|
@ -13,9 +13,7 @@ define([
|
||||
beforeEach(ctx.createControllerPhase('GraphiteQueryCtrl'));
|
||||
|
||||
beforeEach(function() {
|
||||
ctx.scope.target = {
|
||||
target: 'aliasByNode(scaleToSeconds(test.prod.*,1),2)'
|
||||
};
|
||||
ctx.scope.target = {target: 'aliasByNode(scaleToSeconds(test.prod.*,1),2)'};
|
||||
|
||||
ctx.scope.datasource = ctx.datasource;
|
||||
ctx.scope.datasource.metricFindQuery = sinon.stub().returns(ctx.$q.when([]));
|
||||
|
58
public/test/specs/panelSrv-specs.js
Normal file
58
public/test/specs/panelSrv-specs.js
Normal file
@ -0,0 +1,58 @@
|
||||
define([
|
||||
'helpers',
|
||||
'features/panel/panelSrv',
|
||||
], function() {
|
||||
'use strict';
|
||||
|
||||
describe('PanelSrv', function() {
|
||||
var _panelSrv;
|
||||
var _panelScope;
|
||||
var _datasourceSrvStub;
|
||||
|
||||
beforeEach(module('grafana.services'));
|
||||
beforeEach(module(function($provide) {
|
||||
_datasourceSrvStub = {
|
||||
getMetricSources: sinon.spy(),
|
||||
};
|
||||
$provide.value('datasourceSrv', _datasourceSrvStub);
|
||||
}));
|
||||
|
||||
beforeEach(inject(function(panelSrv, $rootScope) {
|
||||
_panelSrv = panelSrv;
|
||||
_panelScope = $rootScope.$new();
|
||||
_panelScope.panel = {
|
||||
targets: [],
|
||||
};
|
||||
_panelScope.dashboardViewState = {
|
||||
registerPanel: sinon.spy(),
|
||||
};
|
||||
}));
|
||||
|
||||
describe('init', function() {
|
||||
beforeEach(function() {
|
||||
_panelSrv.init(_panelScope);
|
||||
});
|
||||
|
||||
describe('addDataQuery', function() {
|
||||
it('should add target', function() {
|
||||
_panelScope.addDataQuery();
|
||||
expect(_panelScope.panel.targets.length).to.be(1);
|
||||
});
|
||||
|
||||
it('should set refId', function() {
|
||||
_panelScope.addDataQuery();
|
||||
expect(_panelScope.panel.targets[0].refId).to.be('A');
|
||||
});
|
||||
|
||||
it('should set refId to first available letter', function() {
|
||||
_panelScope.panel.targets = [{refId: 'A'}];
|
||||
_panelScope.addDataQuery();
|
||||
expect(_panelScope.panel.targets[1].refId).to.be('B');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
@ -139,6 +139,7 @@ require([
|
||||
'specs/seriesOverridesCtrl-specs',
|
||||
'specs/shareModalCtrl-specs',
|
||||
'specs/timeSrv-specs',
|
||||
'specs/panelSrv-specs',
|
||||
'specs/templateSrv-specs',
|
||||
'specs/templateValuesSrv-specs',
|
||||
'specs/kbn-format-specs',
|
||||
|
1
public/vendor/bootstrap/less/bootstrap.less
vendored
1
public/vendor/bootstrap/less/bootstrap.less
vendored
@ -32,6 +32,7 @@
|
||||
|
||||
// Components: Buttons & Alerts
|
||||
@import "buttons.less";
|
||||
@import "button-groups.less";
|
||||
@import "alerts.less"; // Note: alerts share common CSS with buttons and thus have styles in buttons.less
|
||||
|
||||
// Components: Nav
|
||||
|
Loading…
Reference in New Issue
Block a user