mirror of https://github.com/grafana/grafana
parent
05dfccbb74
commit
eecf844ca2
@ -1,220 +0,0 @@ |
||||
define([ |
||||
'angular', |
||||
'lodash', |
||||
'app/core/utils/datemath', |
||||
'./influx_series', |
||||
'./influx_query', |
||||
], |
||||
function (angular, _, dateMath, InfluxSeries, InfluxQuery) { |
||||
'use strict'; |
||||
|
||||
InfluxQuery = InfluxQuery.default; |
||||
|
||||
/** @ngInject */ |
||||
function InfluxDatasource(instanceSettings, $q, backendSrv, templateSrv) { |
||||
this.type = 'influxdb'; |
||||
this.urls = _.map(instanceSettings.url.split(','), function(url) { |
||||
return url.trim(); |
||||
}); |
||||
|
||||
this.username = instanceSettings.username; |
||||
this.password = instanceSettings.password; |
||||
this.name = instanceSettings.name; |
||||
this.database = instanceSettings.database; |
||||
this.basicAuth = instanceSettings.basicAuth; |
||||
|
||||
this.supportAnnotations = true; |
||||
this.supportMetrics = true; |
||||
|
||||
this.query = function(options) { |
||||
var timeFilter = getTimeFilter(options); |
||||
var queryTargets = []; |
||||
var i, y; |
||||
|
||||
var allQueries = _.map(options.targets, function(target) { |
||||
if (target.hide) { return []; } |
||||
|
||||
queryTargets.push(target); |
||||
|
||||
// build query
|
||||
var queryModel = new InfluxQuery(target); |
||||
var query = queryModel.render(); |
||||
query = query.replace(/\$interval/g, (target.interval || options.interval)); |
||||
return query; |
||||
|
||||
}).join("\n"); |
||||
|
||||
// replace grafana variables
|
||||
allQueries = allQueries.replace(/\$timeFilter/g, timeFilter); |
||||
|
||||
// replace templated variables
|
||||
allQueries = templateSrv.replace(allQueries, options.scopedVars); |
||||
|
||||
return this._seriesQuery(allQueries).then(function(data) { |
||||
if (!data || !data.results) { |
||||
return []; |
||||
} |
||||
|
||||
var seriesList = []; |
||||
for (i = 0; i < data.results.length; i++) { |
||||
var result = data.results[i]; |
||||
if (!result || !result.series) { continue; } |
||||
|
||||
var target = queryTargets[i]; |
||||
var alias = target.alias; |
||||
if (alias) { |
||||
alias = templateSrv.replace(target.alias, options.scopedVars); |
||||
} |
||||
|
||||
var influxSeries = new InfluxSeries({ series: data.results[i].series, alias: alias }); |
||||
|
||||
switch(target.resultFormat) { |
||||
case 'table': { |
||||
seriesList.push(influxSeries.getTable()); |
||||
break; |
||||
} |
||||
default: { |
||||
var timeSeries = influxSeries.getTimeSeries(); |
||||
for (y = 0; y < timeSeries.length; y++) { |
||||
seriesList.push(timeSeries[y]); |
||||
} |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
return { data: seriesList }; |
||||
}); |
||||
}; |
||||
|
||||
this.annotationQuery = function(options) { |
||||
var timeFilter = getTimeFilter({rangeRaw: options.rangeRaw}); |
||||
var query = options.annotation.query.replace('$timeFilter', timeFilter); |
||||
query = templateSrv.replace(query); |
||||
|
||||
return this._seriesQuery(query).then(function(data) { |
||||
if (!data || !data.results || !data.results[0]) { |
||||
throw { message: 'No results in response from InfluxDB' }; |
||||
} |
||||
return new InfluxSeries({series: data.results[0].series, annotation: options.annotation}).getAnnotations(); |
||||
}); |
||||
}; |
||||
|
||||
this.metricFindQuery = function (query) { |
||||
var interpolated; |
||||
try { |
||||
interpolated = templateSrv.replace(query); |
||||
} |
||||
catch (err) { |
||||
return $q.reject(err); |
||||
} |
||||
|
||||
return this._seriesQuery(interpolated).then(function (results) { |
||||
if (!results || results.results.length === 0) { return []; } |
||||
|
||||
var influxResults = results.results[0]; |
||||
if (!influxResults.series) { |
||||
return []; |
||||
} |
||||
|
||||
var series = influxResults.series[0]; |
||||
return _.map(series.values, function(value) { |
||||
if (_.isArray(value)) { |
||||
return { text: value[0] }; |
||||
} else { |
||||
return { text: value }; |
||||
} |
||||
}); |
||||
}); |
||||
}; |
||||
|
||||
this._seriesQuery = function(query) { |
||||
return this._influxRequest('GET', '/query', {q: query, epoch: 'ms'}); |
||||
}; |
||||
|
||||
this.testDatasource = function() { |
||||
return this.metricFindQuery('SHOW MEASUREMENTS LIMIT 1').then(function () { |
||||
return { status: "success", message: "Data source is working", title: "Success" }; |
||||
}); |
||||
}; |
||||
|
||||
this._influxRequest = function(method, url, data) { |
||||
var self = this; |
||||
|
||||
var currentUrl = self.urls.shift(); |
||||
self.urls.push(currentUrl); |
||||
|
||||
var params = { |
||||
u: self.username, |
||||
p: self.password, |
||||
}; |
||||
|
||||
if (self.database) { |
||||
params.db = self.database; |
||||
} |
||||
|
||||
if (method === 'GET') { |
||||
_.extend(params, data); |
||||
data = null; |
||||
} |
||||
|
||||
var options = { |
||||
method: method, |
||||
url: currentUrl + url, |
||||
params: params, |
||||
data: data, |
||||
precision: "ms", |
||||
inspect: { type: 'influxdb' }, |
||||
}; |
||||
|
||||
options.headers = options.headers || {}; |
||||
if (self.basicAuth) { |
||||
options.headers.Authorization = self.basicAuth; |
||||
} |
||||
|
||||
return backendSrv.datasourceRequest(options).then(function(result) { |
||||
return result.data; |
||||
}, function(err) { |
||||
if (err.status !== 0 || err.status >= 300) { |
||||
if (err.data && err.data.error) { |
||||
throw { message: 'InfluxDB Error Response: ' + err.data.error, data: err.data, config: err.config }; |
||||
} |
||||
else { |
||||
throw { message: 'InfluxDB Error: ' + err.message, data: err.data, config: err.config }; |
||||
} |
||||
} |
||||
}); |
||||
}; |
||||
|
||||
function getTimeFilter(options) { |
||||
var from = getInfluxTime(options.rangeRaw.from, false); |
||||
var until = getInfluxTime(options.rangeRaw.to, true); |
||||
var fromIsAbsolute = from[from.length-1] === 's'; |
||||
|
||||
if (until === 'now()' && !fromIsAbsolute) { |
||||
return 'time > ' + from; |
||||
} |
||||
|
||||
return 'time > ' + from + ' and time < ' + until; |
||||
} |
||||
|
||||
function getInfluxTime(date, roundUp) { |
||||
if (_.isString(date)) { |
||||
if (date === 'now') { |
||||
return 'now()'; |
||||
} |
||||
|
||||
var parts = /^now-(\d+)([d|h|m|s])$/.exec(date); |
||||
if (parts) { |
||||
var amount = parseInt(parts[1]); |
||||
var unit = parts[2]; |
||||
return 'now() - ' + amount + unit; |
||||
} |
||||
date = dateMath.parse(date, roundUp); |
||||
} |
||||
return (date.valueOf() / 1000).toFixed(0) + 's'; |
||||
} |
||||
} |
||||
|
||||
return InfluxDatasource; |
||||
}); |
@ -0,0 +1,213 @@ |
||||
///<reference path="../../../headers/common.d.ts" />
|
||||
|
||||
import angular from 'angular'; |
||||
import _ from 'lodash'; |
||||
|
||||
import * as dateMath from 'app/core/utils/datemath'; |
||||
import InfluxSeries from './influx_series'; |
||||
import InfluxQuery from './influx_query'; |
||||
|
||||
/** @ngInject */ |
||||
export function InfluxDatasource(instanceSettings, $q, backendSrv, templateSrv) { |
||||
this.type = 'influxdb'; |
||||
this.urls = _.map(instanceSettings.url.split(','), function(url) { |
||||
return url.trim(); |
||||
}); |
||||
|
||||
this.username = instanceSettings.username; |
||||
this.password = instanceSettings.password; |
||||
this.name = instanceSettings.name; |
||||
this.database = instanceSettings.database; |
||||
this.basicAuth = instanceSettings.basicAuth; |
||||
|
||||
this.supportAnnotations = true; |
||||
this.supportMetrics = true; |
||||
|
||||
this.query = function(options) { |
||||
var timeFilter = getTimeFilter(options); |
||||
var queryTargets = []; |
||||
var i, y; |
||||
|
||||
var allQueries = _.map(options.targets, function(target) { |
||||
if (target.hide) { return []; } |
||||
|
||||
queryTargets.push(target); |
||||
|
||||
// build query
|
||||
var queryModel = new InfluxQuery(target); |
||||
var query = queryModel.render(); |
||||
query = query.replace(/\$interval/g, (target.interval || options.interval)); |
||||
return query; |
||||
|
||||
}).join("\n"); |
||||
|
||||
// replace grafana variables
|
||||
allQueries = allQueries.replace(/\$timeFilter/g, timeFilter); |
||||
|
||||
// replace templated variables
|
||||
allQueries = templateSrv.replace(allQueries, options.scopedVars); |
||||
|
||||
return this._seriesQuery(allQueries).then(function(data): any { |
||||
if (!data || !data.results) { |
||||
return []; |
||||
} |
||||
|
||||
var seriesList = []; |
||||
for (i = 0; i < data.results.length; i++) { |
||||
var result = data.results[i]; |
||||
if (!result || !result.series) { continue; } |
||||
|
||||
var target = queryTargets[i]; |
||||
var alias = target.alias; |
||||
if (alias) { |
||||
alias = templateSrv.replace(target.alias, options.scopedVars); |
||||
} |
||||
|
||||
var influxSeries = new InfluxSeries({ series: data.results[i].series, alias: alias }); |
||||
|
||||
switch (target.resultFormat) { |
||||
case 'table': { |
||||
seriesList.push(influxSeries.getTable()); |
||||
break; |
||||
} |
||||
default: { |
||||
var timeSeries = influxSeries.getTimeSeries(); |
||||
for (y = 0; y < timeSeries.length; y++) { |
||||
seriesList.push(timeSeries[y]); |
||||
} |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
return { data: seriesList }; |
||||
}); |
||||
}; |
||||
|
||||
this.annotationQuery = function(options) { |
||||
var timeFilter = getTimeFilter({rangeRaw: options.rangeRaw}); |
||||
var query = options.annotation.query.replace('$timeFilter', timeFilter); |
||||
query = templateSrv.replace(query); |
||||
|
||||
return this._seriesQuery(query).then(function(data) { |
||||
if (!data || !data.results || !data.results[0]) { |
||||
throw { message: 'No results in response from InfluxDB' }; |
||||
} |
||||
return new InfluxSeries({series: data.results[0].series, annotation: options.annotation}).getAnnotations(); |
||||
}); |
||||
}; |
||||
|
||||
this.metricFindQuery = function (query) { |
||||
var interpolated; |
||||
try { |
||||
interpolated = templateSrv.replace(query); |
||||
} catch (err) { |
||||
return $q.reject(err); |
||||
} |
||||
|
||||
return this._seriesQuery(interpolated).then(function (results) { |
||||
if (!results || results.results.length === 0) { return []; } |
||||
|
||||
var influxResults = results.results[0]; |
||||
if (!influxResults.series) { |
||||
return []; |
||||
} |
||||
|
||||
var series = influxResults.series[0]; |
||||
return _.map(series.values, function(value) { |
||||
if (_.isArray(value)) { |
||||
return { text: value[0] }; |
||||
} else { |
||||
return { text: value }; |
||||
} |
||||
}); |
||||
}); |
||||
}; |
||||
|
||||
this._seriesQuery = function(query) { |
||||
return this._influxRequest('GET', '/query', {q: query, epoch: 'ms'}); |
||||
}; |
||||
|
||||
this.testDatasource = function() { |
||||
return this.metricFindQuery('SHOW MEASUREMENTS LIMIT 1').then(function () { |
||||
return { status: "success", message: "Data source is working", title: "Success" }; |
||||
}); |
||||
}; |
||||
|
||||
this._influxRequest = function(method, url, data) { |
||||
var self = this; |
||||
|
||||
var currentUrl = self.urls.shift(); |
||||
self.urls.push(currentUrl); |
||||
|
||||
var params: any = { |
||||
u: self.username, |
||||
p: self.password, |
||||
}; |
||||
|
||||
if (self.database) { |
||||
params.db = self.database; |
||||
} |
||||
|
||||
if (method === 'GET') { |
||||
_.extend(params, data); |
||||
data = null; |
||||
} |
||||
|
||||
var options: any = { |
||||
method: method, |
||||
url: currentUrl + url, |
||||
params: params, |
||||
data: data, |
||||
precision: "ms", |
||||
inspect: { type: 'influxdb' }, |
||||
}; |
||||
|
||||
options.headers = options.headers || {}; |
||||
if (self.basicAuth) { |
||||
options.headers.Authorization = self.basicAuth; |
||||
} |
||||
|
||||
return backendSrv.datasourceRequest(options).then(function(result) { |
||||
return result.data; |
||||
}, function(err) { |
||||
if (err.status !== 0 || err.status >= 300) { |
||||
if (err.data && err.data.error) { |
||||
throw { message: 'InfluxDB Error Response: ' + err.data.error, data: err.data, config: err.config }; |
||||
} else { |
||||
throw { message: 'InfluxDB Error: ' + err.message, data: err.data, config: err.config }; |
||||
} |
||||
} |
||||
}); |
||||
}; |
||||
|
||||
function getTimeFilter(options) { |
||||
var from = getInfluxTime(options.rangeRaw.from, false); |
||||
var until = getInfluxTime(options.rangeRaw.to, true); |
||||
var fromIsAbsolute = from[from.length-1] === 's'; |
||||
|
||||
if (until === 'now()' && !fromIsAbsolute) { |
||||
return 'time > ' + from; |
||||
} |
||||
|
||||
return 'time > ' + from + ' and time < ' + until; |
||||
} |
||||
|
||||
function getInfluxTime(date, roundUp) { |
||||
if (_.isString(date)) { |
||||
if (date === 'now') { |
||||
return 'now()'; |
||||
} |
||||
|
||||
var parts = /^now-(\d+)([d|h|m|s])$/.exec(date); |
||||
if (parts) { |
||||
var amount = parseInt(parts[1]); |
||||
var unit = parts[2]; |
||||
return 'now() - ' + amount + unit; |
||||
} |
||||
date = dateMath.parse(date, roundUp); |
||||
} |
||||
return (date.valueOf() / 1000).toFixed(0) + 's'; |
||||
} |
||||
} |
||||
|
@ -1,30 +0,0 @@ |
||||
define([ |
||||
'./datasource', |
||||
], |
||||
function (InfluxDatasource) { |
||||
'use strict'; |
||||
|
||||
function influxMetricsQueryEditor() { |
||||
return {controller: 'InfluxQueryCtrl', templateUrl: 'public/app/plugins/datasource/influxdb/partials/query.editor.html'}; |
||||
} |
||||
|
||||
function influxMetricsQueryOptions() { |
||||
return {templateUrl: 'public/app/plugins/datasource/influxdb/partials/query.options.html'}; |
||||
} |
||||
|
||||
function influxAnnotationsQueryEditor() { |
||||
return {templateUrl: 'public/app/plugins/datasource/influxdb/partials/annotations.editor.html'}; |
||||
} |
||||
|
||||
function influxConfigView() { |
||||
return {templateUrl: 'public/app/plugins/datasource/influxdb/partials/config.html'}; |
||||
} |
||||
|
||||
return { |
||||
Datasource: InfluxDatasource, |
||||
metricsQueryEditor: influxMetricsQueryEditor, |
||||
metricsQueryOptions: influxMetricsQueryOptions, |
||||
annotationsQueryEditor: influxAnnotationsQueryEditor, |
||||
configView: influxConfigView, |
||||
}; |
||||
}); |
@ -0,0 +1,53 @@ |
||||
import {InfluxDatasource} from './datasource'; |
||||
import {InfluxQueryCtrl} from './query_ctrl'; |
||||
|
||||
class InfluxConfigCtrl { |
||||
static templateUrl = 'public/app/plugins/datasource/influxdb/partials/config.html'; |
||||
} |
||||
|
||||
class InfluxQueryOptionsCtrl { |
||||
static templateUrl = 'public/app/plugins/datasource/influxdb/partials/query.options.html'; |
||||
} |
||||
|
||||
class InfluxAnnotationsQueryCtrl { |
||||
static templateUrl = 'public/app/plugins/datasource/influxdb/partials/annotations.editor.html'; |
||||
} |
||||
|
||||
export { |
||||
InfluxDatasource as Datasource, |
||||
InfluxQueryCtrl as QueryCtrl, |
||||
InfluxConfigCtrl as ConfigCtrl, |
||||
InfluxQueryOptionsCtrl as QueryOptionsCtrl, |
||||
InfluxAnnotationsQueryCtrl as AnnotationsQueryCtrl, |
||||
}; |
||||
|
||||
// define([
|
||||
// './datasource',
|
||||
// ],
|
||||
// function (InfluxDatasource) {
|
||||
// 'use strict';
|
||||
//
|
||||
// function influxMetricsQueryEditor() {
|
||||
// return {controller: 'InfluxQueryCtrl', templateUrl: 'public/app/plugins/datasource/influxdb/partials/query.editor.html'};
|
||||
// }
|
||||
//
|
||||
// function influxMetricsQueryOptions() {
|
||||
// return {templateUrl: 'public/app/plugins/datasource/influxdb/partials/query.options.html'};
|
||||
// }
|
||||
//
|
||||
// function influxAnnotationsQueryEditor() {
|
||||
// return {templateUrl: 'public/app/plugins/datasource/influxdb/partials/annotations.editor.html'};
|
||||
// }
|
||||
//
|
||||
// function influxConfigView() {
|
||||
// return {templateUrl: 'public/app/plugins/datasource/influxdb/partials/config.html'};
|
||||
// }
|
||||
//
|
||||
// return {
|
||||
// Datasource: InfluxDatasource,
|
||||
// metricsQueryEditor: influxMetricsQueryEditor,
|
||||
// metricsQueryOptions: influxMetricsQueryOptions,
|
||||
// annotationsQueryEditor: influxAnnotationsQueryEditor,
|
||||
// configView: influxConfigView,
|
||||
// };
|
||||
// });
|
@ -1,119 +1,73 @@ |
||||
<div class=""> |
||||
<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="toggleQueryMode()">Switch editor mode</a></li> |
||||
<li role="menuitem"><a tabindex="1" ng-click="panelCtrl.duplicateDataQuery(target)">Duplicate</a></li> |
||||
<li role="menuitem"><a tabindex="1" ng-click="panelCtrl.moveDataQuery($index, $index-1)">Move up</a></li> |
||||
<li role="menuitem"><a tabindex="1" ng-click="panelCtrl.moveDataQuery($index, $index+1)">Move down</a></li> |
||||
</ul> |
||||
</div> |
||||
</li> |
||||
|
||||
<li class="tight-form-item last"> |
||||
<a class="pointer" tabindex="1" ng-click="panelCtrl.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; panelCtrl.refresh();" role="menuitem"> |
||||
<i class="fa fa-eye"></i> |
||||
</a> |
||||
</li> |
||||
</ul> |
||||
|
||||
<ul class="tight-form-list" ng-hide="target.rawQuery"> |
||||
<query-editor-row ctrl="ctrl"> |
||||
<ul class="tight-form-list" ng-hide="ctrl.target.rawQuery"> |
||||
<li class="tight-form-item query-keyword" style="width: 75px"> |
||||
FROM |
||||
</li> |
||||
<li> |
||||
<metric-segment segment="policySegment" get-options="getPolicySegments()" on-change="policyChanged()"></metric-segment> |
||||
<metric-segment segment="ctrl.policySegment" get-options="ctrl.getPolicySegments()" on-change="ctrl.policyChanged()"></metric-segment> |
||||
</li> |
||||
<li> |
||||
<metric-segment segment="measurementSegment" get-options="getMeasurements()" on-change="measurementChanged()"></metric-segment> |
||||
<metric-segment segment="ctrl.measurementSegment" get-options="ctrl.getMeasurements()" on-change="ctrl.measurementChanged()"></metric-segment> |
||||
</li> |
||||
<li class="tight-form-item query-keyword" style="padding-left: 15px; padding-right: 15px;"> |
||||
WHERE |
||||
</li> |
||||
<li ng-repeat="segment in tagSegments"> |
||||
<metric-segment segment="segment" get-options="getTagsOrValues(segment, $index)" on-change="tagSegmentUpdated(segment, $index)"></metric-segment> |
||||
<li ng-repeat="segment in ctrl.tagSegments"> |
||||
<metric-segment segment="segment" get-options="ctrl.getTagsOrValues(segment, $index)" on-change="ctrl.tagSegmentUpdated(segment, $index)"></metric-segment> |
||||
</li> |
||||
</ul> |
||||
|
||||
<div class="tight-form-flex-wrapper" ng-show="target.rawQuery"> |
||||
<input type="text" class="tight-form-clear-input" ng-model="target.query" spellcheck="false" style="width: 100%;" ng-blur="panelCtrl.refresh()"></input> |
||||
<input type="text" class="tight-form-clear-input" ng-model="ctrl.target.query" spellcheck="false" style="width: 100%;" ng-blur="ctrl.refresh()"></input> |
||||
</div> |
||||
</query-editor-row> |
||||
|
||||
<div ng-hide="ctrl.target.rawQuery"> |
||||
<div class="tight-form" ng-repeat="selectParts in ctrl.queryModel.selectModels"> |
||||
<ul class="tight-form-list"> |
||||
<li class="tight-form-item query-keyword tight-form-align" style="width: 75px;"> |
||||
<span ng-show="$index === 0">SELECT</span> |
||||
</li> |
||||
<li ng-repeat="part in selectParts"> |
||||
<influx-query-part-editor part="part" class="tight-form-item tight-form-func" remove-action="ctrl.removeSelectPart(selectParts, part)" part-updated="ctrl.selectPartUpdated(selectParts, part)" get-options="ctrl.getPartOptions(part)"></influx-query-part-editor> |
||||
</li> |
||||
<li class="dropdown" dropdown-typeahead="ctrl.selectMenu" dropdown-typeahead-on-select="ctrl.addSelectPart(selectParts, $item, $subItem)"> |
||||
</li> |
||||
</ul> |
||||
<div class="clearfix"></div> |
||||
</div> |
||||
|
||||
<div ng-hide="target.rawQuery"> |
||||
|
||||
<div class="tight-form" ng-repeat="selectParts in queryModel.selectModels"> |
||||
<ul class="tight-form-list"> |
||||
<li class="tight-form-item query-keyword tight-form-align" style="width: 75px;"> |
||||
<span ng-show="$index === 0">SELECT</span> |
||||
</li> |
||||
<li ng-repeat="part in selectParts"> |
||||
<influx-query-part-editor part="part" class="tight-form-item tight-form-func" remove-action="removeSelectPart(selectParts, part)" part-updated="selectPartUpdated(selectParts, part)" get-options="getPartOptions(part)"></influx-query-part-editor> |
||||
</li> |
||||
<li class="dropdown" dropdown-typeahead="selectMenu" dropdown-typeahead-on-select="addSelectPart(selectParts, $item, $subItem)"> |
||||
</li> |
||||
</ul> |
||||
<div class="clearfix"></div> |
||||
</div> |
||||
|
||||
<div class="tight-form"> |
||||
<ul class="tight-form-list"> |
||||
<li class="tight-form-item query-keyword tight-form-align" style="width: 75px;"> |
||||
<span>GROUP BY</span> |
||||
</li> |
||||
<li ng-repeat="part in queryModel.groupByParts"> |
||||
<influx-query-part-editor part="part" class="tight-form-item tight-form-func" remove-action="removeGroupByPart(part, $index)" part-updated="panelCtrl.refresh();" get-options="getPartOptions(part)"></influx-query-part-editor> |
||||
</li> |
||||
<li> |
||||
<metric-segment segment="groupBySegment" get-options="getGroupByOptions()" on-change="groupByAction(part, $index)"></metric-segment> |
||||
</li> |
||||
</ul> |
||||
<div class="clearfix"></div> |
||||
</div> |
||||
</div> |
||||
|
||||
<div class="tight-form"> |
||||
<ul class="tight-form-list"> |
||||
<li class="tight-form-item query-keyword tight-form-align" style="width: 75px;"> |
||||
ALIAS BY |
||||
<span>GROUP BY</span> |
||||
</li> |
||||
<li> |
||||
<input type="text" class="tight-form-clear-input input-xlarge" ng-model="target.alias" spellcheck='false' placeholder="Naming pattern" ng-blur="panelCtrl.refresh()"> |
||||
</li> |
||||
<li class="tight-form-item"> |
||||
Format as |
||||
<li ng-repeat="part in ctrl.queryModel.groupByParts"> |
||||
<influx-query-part-editor part="part" class="tight-form-item tight-form-func" remove-action="ctrl.removeGroupByPart(part, $index)" part-updated="ctrl.refresh();" get-options="ctrl.getPartOptions(part)"></influx-query-part-editor> |
||||
</li> |
||||
<li> |
||||
<select class="input-small tight-form-input" style="width: 104px" ng-model="target.resultFormat" ng-options="f.value as f.text for f in resultFormats" ng-change="panelCtrl.refresh()"></select> |
||||
<metric-segment segment="ctrl.groupBySegment" get-options="ctrl.getGroupByOptions()" on-change="ctrl.groupByAction(part, $index)"></metric-segment> |
||||
</li> |
||||
</ul> |
||||
<div class="clearfix"></div> |
||||
</div> |
||||
</div> |
||||
|
||||
<div class="tight-form"> |
||||
<ul class="tight-form-list"> |
||||
<li class="tight-form-item query-keyword tight-form-align" style="width: 75px;"> |
||||
ALIAS BY |
||||
</li> |
||||
<li> |
||||
<input type="text" class="tight-form-clear-input input-xlarge" ng-model="ctrl.target.alias" spellcheck='false' placeholder="Naming pattern" ng-blur="ctrl.refresh()"> |
||||
</li> |
||||
<li class="tight-form-item"> |
||||
Format as |
||||
</li> |
||||
<li> |
||||
<select class="input-small tight-form-input" style="width: 104px" ng-model="ctrl.target.resultFormat" ng-options="f.value as f.text for f in ctrl.resultFormats" ng-change="ctrl.refresh()"></select> |
||||
</li> |
||||
</ul> |
||||
<div class="clearfix"></div> |
||||
</div> |
||||
|
||||
|
@ -1,322 +0,0 @@ |
||||
define([ |
||||
'angular', |
||||
'lodash', |
||||
'./query_builder', |
||||
'./influx_query', |
||||
'./query_part', |
||||
'./query_part_editor', |
||||
], |
||||
function (angular, _, InfluxQueryBuilder, InfluxQuery, queryPart) { |
||||
'use strict'; |
||||
|
||||
var module = angular.module('grafana.controllers'); |
||||
|
||||
InfluxQuery = InfluxQuery.default; |
||||
queryPart = queryPart.default; |
||||
|
||||
module.controller('InfluxQueryCtrl', function($scope, templateSrv, $q, uiSegmentSrv) { |
||||
var panelCtrl = $scope.ctrl; |
||||
var datasource = $scope.datasource; |
||||
$scope.panelCtrl = panelCtrl; |
||||
|
||||
$scope.init = function() { |
||||
if (!$scope.target) { return; } |
||||
|
||||
$scope.target = $scope.target; |
||||
$scope.queryModel = new InfluxQuery($scope.target); |
||||
$scope.queryBuilder = new InfluxQueryBuilder($scope.target, datasource.database); |
||||
$scope.groupBySegment = uiSegmentSrv.newPlusButton(); |
||||
$scope.resultFormats = [ |
||||
{text: 'Time series', value: 'time_series'}, |
||||
{text: 'Table', value: 'table'}, |
||||
]; |
||||
|
||||
$scope.policySegment = uiSegmentSrv.newSegment($scope.target.policy); |
||||
|
||||
if (!$scope.target.measurement) { |
||||
$scope.measurementSegment = uiSegmentSrv.newSelectMeasurement(); |
||||
} else { |
||||
$scope.measurementSegment = uiSegmentSrv.newSegment($scope.target.measurement); |
||||
} |
||||
|
||||
$scope.tagSegments = []; |
||||
_.each($scope.target.tags, function(tag) { |
||||
if (!tag.operator) { |
||||
if (/^\/.*\/$/.test(tag.value)) { |
||||
tag.operator = "=~"; |
||||
} else { |
||||
tag.operator = '='; |
||||
} |
||||
} |
||||
|
||||
if (tag.condition) { |
||||
$scope.tagSegments.push(uiSegmentSrv.newCondition(tag.condition)); |
||||
} |
||||
|
||||
$scope.tagSegments.push(uiSegmentSrv.newKey(tag.key)); |
||||
$scope.tagSegments.push(uiSegmentSrv.newOperator(tag.operator)); |
||||
$scope.tagSegments.push(uiSegmentSrv.newKeyValue(tag.value)); |
||||
}); |
||||
|
||||
$scope.fixTagSegments(); |
||||
$scope.buildSelectMenu(); |
||||
$scope.removeTagFilterSegment = uiSegmentSrv.newSegment({fake: true, value: '-- remove tag filter --'}); |
||||
}; |
||||
|
||||
$scope.buildSelectMenu = function() { |
||||
var categories = queryPart.getCategories(); |
||||
$scope.selectMenu = _.reduce(categories, function(memo, cat, key) { |
||||
var menu = {text: key}; |
||||
menu.submenu = _.map(cat, function(item) { |
||||
return {text: item.type, value: item.type}; |
||||
}); |
||||
memo.push(menu); |
||||
return memo; |
||||
}, []); |
||||
}; |
||||
|
||||
$scope.getGroupByOptions = function() { |
||||
var query = $scope.queryBuilder.buildExploreQuery('TAG_KEYS'); |
||||
|
||||
return datasource.metricFindQuery(query) |
||||
.then(function(tags) { |
||||
var options = []; |
||||
if (!$scope.queryModel.hasFill()) { |
||||
options.push(uiSegmentSrv.newSegment({value: 'fill(null)'})); |
||||
} |
||||
if (!$scope.queryModel.hasGroupByTime()) { |
||||
options.push(uiSegmentSrv.newSegment({value: 'time($interval)'})); |
||||
} |
||||
_.each(tags, function(tag) { |
||||
options.push(uiSegmentSrv.newSegment({value: 'tag(' + tag.text + ')'})); |
||||
}); |
||||
return options; |
||||
}) |
||||
.then(null, $scope.handleQueryError); |
||||
}; |
||||
|
||||
$scope.groupByAction = function() { |
||||
$scope.queryModel.addGroupBy($scope.groupBySegment.value); |
||||
var plusButton = uiSegmentSrv.newPlusButton(); |
||||
$scope.groupBySegment.value = plusButton.value; |
||||
$scope.groupBySegment.html = plusButton.html; |
||||
panelCtrl.refresh(); |
||||
}; |
||||
|
||||
$scope.removeGroupByPart = function(part, index) { |
||||
$scope.queryModel.removeGroupByPart(part, index); |
||||
panelCtrl.refresh(); |
||||
}; |
||||
|
||||
$scope.addSelectPart = function(selectParts, cat, subitem) { |
||||
$scope.queryModel.addSelectPart(selectParts, subitem.value); |
||||
panelCtrl.refresh(); |
||||
}; |
||||
|
||||
$scope.removeSelectPart = function(selectParts, part) { |
||||
$scope.queryModel.removeSelectPart(selectParts, part); |
||||
panelCtrl.refresh(); |
||||
}; |
||||
|
||||
$scope.selectPartUpdated = function() { |
||||
panelCtrl.refresh(); |
||||
}; |
||||
|
||||
$scope.fixTagSegments = function() { |
||||
var count = $scope.tagSegments.length; |
||||
var lastSegment = $scope.tagSegments[Math.max(count-1, 0)]; |
||||
|
||||
if (!lastSegment || lastSegment.type !== 'plus-button') { |
||||
$scope.tagSegments.push(uiSegmentSrv.newPlusButton()); |
||||
} |
||||
}; |
||||
|
||||
$scope.measurementChanged = function() { |
||||
$scope.target.measurement = $scope.measurementSegment.value; |
||||
panelCtrl.refresh(); |
||||
}; |
||||
|
||||
$scope.getPolicySegments = function() { |
||||
var policiesQuery = $scope.queryBuilder.buildExploreQuery('RETENTION POLICIES'); |
||||
return datasource.metricFindQuery(policiesQuery) |
||||
.then($scope.transformToSegments(false)) |
||||
.then(null, $scope.handleQueryError); |
||||
}; |
||||
|
||||
$scope.policyChanged = function() { |
||||
$scope.target.policy = $scope.policySegment.value; |
||||
panelCtrl.refresh(); |
||||
}; |
||||
|
||||
$scope.toggleQueryMode = function () { |
||||
$scope.target.rawQuery = !$scope.target.rawQuery; |
||||
}; |
||||
|
||||
$scope.getMeasurements = function () { |
||||
var query = $scope.queryBuilder.buildExploreQuery('MEASUREMENTS'); |
||||
return datasource.metricFindQuery(query) |
||||
.then($scope.transformToSegments(true), $scope.handleQueryError); |
||||
}; |
||||
|
||||
$scope.getPartOptions = function(part) { |
||||
if (part.def.type === 'field') { |
||||
var fieldsQuery = $scope.queryBuilder.buildExploreQuery('FIELDS'); |
||||
return datasource.metricFindQuery(fieldsQuery) |
||||
.then($scope.transformToSegments(true), $scope.handleQueryError); |
||||
} |
||||
if (part.def.type === 'tag') { |
||||
var tagsQuery = $scope.queryBuilder.buildExploreQuery('TAG_KEYS'); |
||||
return datasource.metricFindQuery(tagsQuery) |
||||
.then($scope.transformToSegments(true), $scope.handleQueryError); |
||||
} |
||||
}; |
||||
|
||||
$scope.handleQueryError = function(err) { |
||||
$scope.parserError = err.message || 'Failed to issue metric query'; |
||||
return []; |
||||
}; |
||||
|
||||
$scope.transformToSegments = function(addTemplateVars) { |
||||
return function(results) { |
||||
var segments = _.map(results, function(segment) { |
||||
return uiSegmentSrv.newSegment({ value: segment.text, expandable: segment.expandable }); |
||||
}); |
||||
|
||||
if (addTemplateVars) { |
||||
_.each(templateSrv.variables, function(variable) { |
||||
segments.unshift(uiSegmentSrv.newSegment({ type: 'template', value: '/$' + variable.name + '$/', expandable: true })); |
||||
}); |
||||
} |
||||
|
||||
return segments; |
||||
}; |
||||
}; |
||||
|
||||
$scope.getTagsOrValues = function(segment, index) { |
||||
if (segment.type === 'condition') { |
||||
return $q.when([uiSegmentSrv.newSegment('AND'), uiSegmentSrv.newSegment('OR')]); |
||||
} |
||||
if (segment.type === 'operator') { |
||||
var nextValue = $scope.tagSegments[index+1].value; |
||||
if (/^\/.*\/$/.test(nextValue)) { |
||||
return $q.when(uiSegmentSrv.newOperators(['=~', '!~'])); |
||||
} else { |
||||
return $q.when(uiSegmentSrv.newOperators(['=', '<>', '<', '>'])); |
||||
} |
||||
} |
||||
|
||||
var query, addTemplateVars; |
||||
if (segment.type === 'key' || segment.type === 'plus-button') { |
||||
query = $scope.queryBuilder.buildExploreQuery('TAG_KEYS'); |
||||
addTemplateVars = false; |
||||
} else if (segment.type === 'value') { |
||||
query = $scope.queryBuilder.buildExploreQuery('TAG_VALUES', $scope.tagSegments[index-2].value); |
||||
addTemplateVars = true; |
||||
} |
||||
|
||||
return datasource.metricFindQuery(query) |
||||
.then($scope.transformToSegments(addTemplateVars)) |
||||
.then(function(results) { |
||||
if (segment.type === 'key') { |
||||
results.splice(0, 0, angular.copy($scope.removeTagFilterSegment)); |
||||
} |
||||
return results; |
||||
}) |
||||
.then(null, $scope.handleQueryError); |
||||
}; |
||||
|
||||
$scope.getFieldSegments = function() { |
||||
var fieldsQuery = $scope.queryBuilder.buildExploreQuery('FIELDS'); |
||||
return datasource.metricFindQuery(fieldsQuery) |
||||
.then($scope.transformToSegments(false)) |
||||
.then(null, $scope.handleQueryError); |
||||
}; |
||||
|
||||
$scope.getTagOptions = function() { |
||||
}; |
||||
|
||||
$scope.setFill = function(fill) { |
||||
$scope.target.fill = fill; |
||||
panelCtrl.refresh(); |
||||
}; |
||||
|
||||
$scope.tagSegmentUpdated = function(segment, index) { |
||||
$scope.tagSegments[index] = segment; |
||||
|
||||
// handle remove tag condition
|
||||
if (segment.value === $scope.removeTagFilterSegment.value) { |
||||
$scope.tagSegments.splice(index, 3); |
||||
if ($scope.tagSegments.length === 0) { |
||||
$scope.tagSegments.push(uiSegmentSrv.newPlusButton()); |
||||
} else if ($scope.tagSegments.length > 2) { |
||||
$scope.tagSegments.splice(Math.max(index-1, 0), 1); |
||||
if ($scope.tagSegments[$scope.tagSegments.length-1].type !== 'plus-button') { |
||||
$scope.tagSegments.push(uiSegmentSrv.newPlusButton()); |
||||
} |
||||
} |
||||
} |
||||
else { |
||||
if (segment.type === 'plus-button') { |
||||
if (index > 2) { |
||||
$scope.tagSegments.splice(index, 0, uiSegmentSrv.newCondition('AND')); |
||||
} |
||||
$scope.tagSegments.push(uiSegmentSrv.newOperator('=')); |
||||
$scope.tagSegments.push(uiSegmentSrv.newFake('select tag value', 'value', 'query-segment-value')); |
||||
segment.type = 'key'; |
||||
segment.cssClass = 'query-segment-key'; |
||||
} |
||||
|
||||
if ((index+1) === $scope.tagSegments.length) { |
||||
$scope.tagSegments.push(uiSegmentSrv.newPlusButton()); |
||||
} |
||||
} |
||||
|
||||
$scope.rebuildTargetTagConditions(); |
||||
}; |
||||
|
||||
$scope.rebuildTargetTagConditions = function() { |
||||
var tags = []; |
||||
var tagIndex = 0; |
||||
var tagOperator = ""; |
||||
_.each($scope.tagSegments, function(segment2, index) { |
||||
if (segment2.type === 'key') { |
||||
if (tags.length === 0) { |
||||
tags.push({}); |
||||
} |
||||
tags[tagIndex].key = segment2.value; |
||||
} |
||||
else if (segment2.type === 'value') { |
||||
tagOperator = $scope.getTagValueOperator(segment2.value, tags[tagIndex].operator); |
||||
if (tagOperator) { |
||||
$scope.tagSegments[index-1] = uiSegmentSrv.newOperator(tagOperator); |
||||
tags[tagIndex].operator = tagOperator; |
||||
} |
||||
tags[tagIndex].value = segment2.value; |
||||
} |
||||
else if (segment2.type === 'condition') { |
||||
tags.push({ condition: segment2.value }); |
||||
tagIndex += 1; |
||||
} |
||||
else if (segment2.type === 'operator') { |
||||
tags[tagIndex].operator = segment2.value; |
||||
} |
||||
}); |
||||
|
||||
$scope.target.tags = tags; |
||||
panelCtrl.refresh(); |
||||
}; |
||||
|
||||
$scope.getTagValueOperator = function(tagValue, tagOperator) { |
||||
if (tagOperator !== '=~' && tagOperator !== '!~' && /^\/.*\/$/.test(tagValue)) { |
||||
return '=~'; |
||||
} |
||||
else if ((tagOperator === '=~' || tagOperator === '!~') && /^(?!\/.*\/$)/.test(tagValue)) { |
||||
return '='; |
||||
} |
||||
}; |
||||
|
||||
$scope.init(); |
||||
|
||||
}); |
||||
|
||||
}); |
@ -0,0 +1,318 @@ |
||||
///<reference path="../../../headers/common.d.ts" />
|
||||
|
||||
import './query_part_editor'; |
||||
import './query_part_editor'; |
||||
|
||||
import angular from 'angular'; |
||||
import _ from 'lodash'; |
||||
import InfluxQueryBuilder from './query_builder'; |
||||
import InfluxQuery from './influx_query'; |
||||
import queryPart from './query_part'; |
||||
import {QueryCtrl} from 'app/features/panel/panel'; |
||||
|
||||
export class InfluxQueryCtrl extends QueryCtrl { |
||||
static templateUrl = 'public/app/plugins/datasource/influxdb/partials/query.editor.html'; |
||||
|
||||
queryModel: InfluxQuery; |
||||
queryBuilder: any; |
||||
groupBySegment: any; |
||||
resultFormats: any[]; |
||||
policySegment: any; |
||||
tagSegments: any[]; |
||||
selectMenu: any; |
||||
measurementSegment: any; |
||||
removeTagFilterSegment: any; |
||||
|
||||
constructor($scope, $injector, private templateSrv, private $q, private uiSegmentSrv) { |
||||
super($scope, $injector); |
||||
|
||||
this.target = this.target; |
||||
this.queryModel = new InfluxQuery(this.target); |
||||
this.queryBuilder = new InfluxQueryBuilder(this.target, this.datasource.database); |
||||
this.groupBySegment = this.uiSegmentSrv.newPlusButton(); |
||||
this.resultFormats = [ |
||||
{text: 'Time series', value: 'time_series'}, |
||||
{text: 'Table', value: 'table'}, |
||||
]; |
||||
|
||||
this.policySegment = uiSegmentSrv.newSegment(this.target.policy); |
||||
|
||||
if (!this.target.measurement) { |
||||
this.measurementSegment = uiSegmentSrv.newSelectMeasurement(); |
||||
} else { |
||||
this.measurementSegment = uiSegmentSrv.newSegment(this.target.measurement); |
||||
} |
||||
|
||||
this.tagSegments = []; |
||||
for (let tag of this.target.tags) { |
||||
if (!tag.operator) { |
||||
if (/^\/.*\/$/.test(tag.value)) { |
||||
tag.operator = "=~"; |
||||
} else { |
||||
tag.operator = '='; |
||||
} |
||||
} |
||||
|
||||
if (tag.condition) { |
||||
this.tagSegments.push(uiSegmentSrv.newCondition(tag.condition)); |
||||
} |
||||
|
||||
this.tagSegments.push(uiSegmentSrv.newKey(tag.key)); |
||||
this.tagSegments.push(uiSegmentSrv.newOperator(tag.operator)); |
||||
this.tagSegments.push(uiSegmentSrv.newKeyValue(tag.value)); |
||||
} |
||||
|
||||
this.fixTagSegments(); |
||||
this.buildSelectMenu(); |
||||
this.removeTagFilterSegment = uiSegmentSrv.newSegment({fake: true, value: '-- remove tag filter --'}); |
||||
} |
||||
|
||||
buildSelectMenu() { |
||||
var categories = queryPart.getCategories(); |
||||
this.selectMenu = _.reduce(categories, function(memo, cat, key) { |
||||
var menu = { |
||||
text: key, |
||||
submenu: cat.map(item => { |
||||
return {text: item.type, value: item.type}; |
||||
}), |
||||
}; |
||||
memo.push(menu); |
||||
return memo; |
||||
}, []); |
||||
} |
||||
|
||||
getGroupByOptions() { |
||||
var query = this.queryBuilder.buildExploreQuery('TAG_KEYS'); |
||||
|
||||
return this.datasource.metricFindQuery(query).then(tags => { |
||||
var options = []; |
||||
if (!this.queryModel.hasFill()) { |
||||
options.push(this.uiSegmentSrv.newSegment({value: 'fill(null)'})); |
||||
} |
||||
if (!this.queryModel.hasGroupByTime()) { |
||||
options.push(this.uiSegmentSrv.newSegment({value: 'time($interval)'})); |
||||
} |
||||
for (let tag of tags) { |
||||
options.push(this.uiSegmentSrv.newSegment({value: 'tag(' + tag.text + ')'})); |
||||
} |
||||
return options; |
||||
}).catch(this.handleQueryError.bind(this)); |
||||
} |
||||
|
||||
groupByAction() { |
||||
this.queryModel.addGroupBy(this.groupBySegment.value); |
||||
var plusButton = this.uiSegmentSrv.newPlusButton(); |
||||
this.groupBySegment.value = plusButton.value; |
||||
this.groupBySegment.html = plusButton.html; |
||||
this.panelCtrl.refresh(); |
||||
} |
||||
|
||||
removeGroupByPart(part, index) { |
||||
this.queryModel.removeGroupByPart(part, index); |
||||
this.panelCtrl.refresh(); |
||||
} |
||||
|
||||
addSelectPart(selectParts, cat, subitem) { |
||||
this.queryModel.addSelectPart(selectParts, subitem.value); |
||||
this.panelCtrl.refresh(); |
||||
} |
||||
|
||||
removeSelectPart(selectParts, part) { |
||||
this.queryModel.removeSelectPart(selectParts, part); |
||||
this.panelCtrl.refresh(); |
||||
} |
||||
|
||||
selectPartUpdated() { |
||||
this.panelCtrl.refresh(); |
||||
} |
||||
|
||||
fixTagSegments() { |
||||
var count = this.tagSegments.length; |
||||
var lastSegment = this.tagSegments[Math.max(count-1, 0)]; |
||||
|
||||
if (!lastSegment || lastSegment.type !== 'plus-button') { |
||||
this.tagSegments.push(this.uiSegmentSrv.newPlusButton()); |
||||
} |
||||
} |
||||
|
||||
measurementChanged() { |
||||
this.target.measurement = this.measurementSegment.value; |
||||
this.panelCtrl.refresh(); |
||||
} |
||||
|
||||
getPolicySegments() { |
||||
var policiesQuery = this.queryBuilder.buildExploreQuery('RETENTION POLICIES'); |
||||
return this.datasource.metricFindQuery(policiesQuery) |
||||
.then(this.transformToSegments(false)) |
||||
.catch(this.handleQueryError.bind(this)); |
||||
} |
||||
|
||||
policyChanged() { |
||||
this.target.policy = this.policySegment.value; |
||||
this.panelCtrl.refresh(); |
||||
} |
||||
|
||||
toggleQueryMode() { |
||||
this.target.rawQuery = !this.target.rawQuery; |
||||
} |
||||
|
||||
getMeasurements() { |
||||
var query = this.queryBuilder.buildExploreQuery('MEASUREMENTS'); |
||||
return this.datasource.metricFindQuery(query) |
||||
.then(this.transformToSegments(true)) |
||||
.catch(this.handleQueryError.bind(this)); |
||||
} |
||||
|
||||
getPartOptions(part) { |
||||
if (part.def.type === 'field') { |
||||
var fieldsQuery = this.queryBuilder.buildExploreQuery('FIELDS'); |
||||
return this.datasource.metricFindQuery(fieldsQuery) |
||||
.then(this.transformToSegments(true)) |
||||
.catch(this.handleQueryError.bind(this)); |
||||
} |
||||
if (part.def.type === 'tag') { |
||||
var tagsQuery = this.queryBuilder.buildExploreQuery('TAG_KEYS'); |
||||
return this.datasource.metricFindQuery(tagsQuery) |
||||
.then(this.transformToSegments(true)) |
||||
.catch(this.handleQueryError.bind(true)); |
||||
} |
||||
} |
||||
|
||||
handleQueryError(err) { |
||||
this.error = err.message || 'Failed to issue metric query'; |
||||
return []; |
||||
} |
||||
|
||||
transformToSegments(addTemplateVars) { |
||||
return (results) => { |
||||
var segments = _.map(results, segment => { |
||||
return this.uiSegmentSrv.newSegment({ value: segment.text, expandable: segment.expandable }); |
||||
}); |
||||
|
||||
if (addTemplateVars) { |
||||
for (let variable of this.templateSrv.variables) { |
||||
segments.unshift(this.uiSegmentSrv.newSegment({ type: 'template', value: '/$' + variable.name + '$/', expandable: true })); |
||||
} |
||||
} |
||||
|
||||
return segments; |
||||
}; |
||||
} |
||||
|
||||
getTagsOrValues(segment, index) { |
||||
if (segment.type === 'condition') { |
||||
return this.$q.when([this.uiSegmentSrv.newSegment('AND'), this.uiSegmentSrv.newSegment('OR')]); |
||||
} |
||||
if (segment.type === 'operator') { |
||||
var nextValue = this.tagSegments[index+1].value; |
||||
if (/^\/.*\/$/.test(nextValue)) { |
||||
return this.$q.when(this.uiSegmentSrv.newOperators(['=~', '!~'])); |
||||
} else { |
||||
return this.$q.when(this.uiSegmentSrv.newOperators(['=', '<>', '<', '>'])); |
||||
} |
||||
} |
||||
|
||||
var query, addTemplateVars; |
||||
if (segment.type === 'key' || segment.type === 'plus-button') { |
||||
query = this.queryBuilder.buildExploreQuery('TAG_KEYS'); |
||||
addTemplateVars = false; |
||||
} else if (segment.type === 'value') { |
||||
query = this.queryBuilder.buildExploreQuery('TAG_VALUES', this.tagSegments[index-2].value); |
||||
addTemplateVars = true; |
||||
} |
||||
|
||||
return this.datasource.metricFindQuery(query) |
||||
.then(this.transformToSegments(addTemplateVars)) |
||||
.then(results => { |
||||
if (segment.type === 'key') { |
||||
results.splice(0, 0, angular.copy(this.removeTagFilterSegment)); |
||||
} |
||||
return results; |
||||
}) |
||||
.catch(this.handleQueryError.bind(this)); |
||||
} |
||||
|
||||
getFieldSegments() { |
||||
var fieldsQuery = this.queryBuilder.buildExploreQuery('FIELDS'); |
||||
return this.datasource.metricFindQuery(fieldsQuery) |
||||
.then(this.transformToSegments(false)) |
||||
.catch(this.handleQueryError); |
||||
} |
||||
|
||||
setFill(fill) { |
||||
this.target.fill = fill; |
||||
this.panelCtrl.refresh(); |
||||
} |
||||
|
||||
tagSegmentUpdated(segment, index) { |
||||
this.tagSegments[index] = segment; |
||||
|
||||
// handle remove tag condition
|
||||
if (segment.value === this.removeTagFilterSegment.value) { |
||||
this.tagSegments.splice(index, 3); |
||||
if (this.tagSegments.length === 0) { |
||||
this.tagSegments.push(this.uiSegmentSrv.newPlusButton()); |
||||
} else if (this.tagSegments.length > 2) { |
||||
this.tagSegments.splice(Math.max(index-1, 0), 1); |
||||
if (this.tagSegments[this.tagSegments.length-1].type !== 'plus-button') { |
||||
this.tagSegments.push(this.uiSegmentSrv.newPlusButton()); |
||||
} |
||||
} |
||||
} else { |
||||
if (segment.type === 'plus-button') { |
||||
if (index > 2) { |
||||
this.tagSegments.splice(index, 0, this.uiSegmentSrv.newCondition('AND')); |
||||
} |
||||
this.tagSegments.push(this.uiSegmentSrv.newOperator('=')); |
||||
this.tagSegments.push(this.uiSegmentSrv.newFake('select tag value', 'value', 'query-segment-value')); |
||||
segment.type = 'key'; |
||||
segment.cssClass = 'query-segment-key'; |
||||
} |
||||
|
||||
if ((index+1) === this.tagSegments.length) { |
||||
this.tagSegments.push(this.uiSegmentSrv.newPlusButton()); |
||||
} |
||||
} |
||||
|
||||
this.rebuildTargetTagConditions(); |
||||
} |
||||
|
||||
rebuildTargetTagConditions() { |
||||
var tags = []; |
||||
var tagIndex = 0; |
||||
var tagOperator = ""; |
||||
|
||||
_.each(this.tagSegments, (segment2, index) => { |
||||
if (segment2.type === 'key') { |
||||
if (tags.length === 0) { |
||||
tags.push({}); |
||||
} |
||||
tags[tagIndex].key = segment2.value; |
||||
} else if (segment2.type === 'value') { |
||||
tagOperator = this.getTagValueOperator(segment2.value, tags[tagIndex].operator); |
||||
if (tagOperator) { |
||||
this.tagSegments[index-1] = this.uiSegmentSrv.newOperator(tagOperator); |
||||
tags[tagIndex].operator = tagOperator; |
||||
} |
||||
tags[tagIndex].value = segment2.value; |
||||
} else if (segment2.type === 'condition') { |
||||
tags.push({ condition: segment2.value }); |
||||
tagIndex += 1; |
||||
} else if (segment2.type === 'operator') { |
||||
tags[tagIndex].operator = segment2.value; |
||||
} |
||||
}); |
||||
|
||||
this.target.tags = tags; |
||||
this.panelCtrl.refresh(); |
||||
} |
||||
|
||||
getTagValueOperator(tagValue, tagOperator) { |
||||
if (tagOperator !== '=~' && tagOperator !== '!~' && /^\/.*\/$/.test(tagValue)) { |
||||
return '=~'; |
||||
} else if ((tagOperator === '=~' || tagOperator === '!~') && /^(?!\/.*\/$)/.test(tagValue)) { |
||||
return '='; |
||||
} |
||||
} |
||||
} |
||||
|
Loading…
Reference in new issue