Merge branch 'master' into alerting_definitions

pull/5622/head
Torkel Ödegaard 9 years ago
commit dee5f582d7
  1. 1
      CHANGELOG.md
  2. 1
      pkg/services/search/handlers.go
  3. 1
      pkg/services/search/models.go
  4. 8
      pkg/services/sqlstore/dashboard.go
  5. 123
      public/app/core/components/query_part/query_part.ts
  6. 183
      public/app/core/components/query_part/query_part_editor.ts
  7. 2
      public/app/core/core.ts
  8. 2
      public/app/features/org/partials/profile.html
  9. 8
      public/app/plugins/datasource/influxdb/partials/query.editor.html
  10. 5
      public/app/plugins/datasource/influxdb/partials/query_part.html
  11. 3
      public/app/plugins/datasource/influxdb/query_ctrl.ts
  12. 194
      public/app/plugins/datasource/influxdb/query_part.ts
  13. 178
      public/app/plugins/datasource/influxdb/query_part_editor.js
  14. 5
      public/app/plugins/datasource/opentsdb/datasource.js

@ -10,6 +10,7 @@
* **InfluxDB**: Add spread function, closes [#5211](https://github.com/grafana/grafana/issues/5211)
* **Scripts**: Use restart instead of start for deb package script, closes [#5282](https://github.com/grafana/grafana/pull/5282)
* **Logging**: Moved to structured logging lib, and moved to component specific level filters via config file, closes [#4590](https://github.com/grafana/grafana/issues/4590)
* **Search**: Add search limit query parameter, closes [#5292](https://github.com/grafana/grafana/pull/5292)
## Breaking changes
* **Logging** : Changed default logging output format (now structured into message, and key value pairs, with logger key acting as component). You can also no change in config to json log ouput.

@ -44,6 +44,7 @@ func searchHandler(query *Query) error {
IsStarred: query.IsStarred,
OrgId: query.OrgId,
DashboardIds: query.DashboardIds,
Limit: query.Limit,
}
if err := bus.Dispatch(&dashQuery); err != nil {

@ -42,6 +42,7 @@ type FindPersistedDashboardsQuery struct {
UserId int64
IsStarred bool
DashboardIds []int
Limit int
Result HitList
}

@ -123,6 +123,11 @@ type DashboardSearchProjection struct {
}
func SearchDashboards(query *search.FindPersistedDashboardsQuery) error {
limit := query.Limit
if limit == 0 {
limit = 1000
}
var sql bytes.Buffer
params := make([]interface{}, 0)
@ -165,7 +170,8 @@ func SearchDashboards(query *search.FindPersistedDashboardsQuery) error {
params = append(params, "%"+query.Title+"%")
}
sql.WriteString(fmt.Sprintf(" ORDER BY dashboard.title ASC LIMIT 1000"))
sql.WriteString(fmt.Sprintf(" ORDER BY dashboard.title ASC LIMIT ?"))
params = append(params, limit)
var res []DashboardSearchProjection

@ -0,0 +1,123 @@
///<reference path="../../../headers/common.d.ts" />
import _ from 'lodash';
export class QueryPartDef {
type: string;
params: any[];
defaultParams: any[];
renderer: any;
category: any;
addStrategy: any;
constructor(options: any) {
this.type = options.type;
this.params = options.params;
this.defaultParams = options.defaultParams;
this.renderer = options.renderer;
this.category = options.category;
this.addStrategy = options.addStrategy;
}
}
export class QueryPart {
part: any;
def: QueryPartDef;
params: any[];
text: string;
constructor(part: any, def: any) {
this.part = part;
this.def = def;
if (!this.def) {
throw {message: 'Could not find query part ' + part.type};
}
part.params = part.params || _.clone(this.def.defaultParams);
this.params = part.params;
this.updateText();
}
render(innerExpr: string) {
return this.def.renderer(this, innerExpr);
}
hasMultipleParamsInString (strValue, index) {
if (strValue.indexOf(',') === -1) {
return false;
}
return this.def.params[index + 1] && this.def.params[index + 1].optional;
}
updateParam (strValue, index) {
// handle optional parameters
// if string contains ',' and next param is optional, split and update both
if (this.hasMultipleParamsInString(strValue, index)) {
_.each(strValue.split(','), function(partVal: string, idx) {
this.updateParam(partVal.trim(), idx);
}, this);
return;
}
if (strValue === '' && this.def.params[index].optional) {
this.params.splice(index, 1);
} else {
this.params[index] = strValue;
}
this.part.params = this.params;
this.updateText();
}
updateText() {
if (this.params.length === 0) {
this.text = this.def.type + '()';
return;
}
var text = this.def.type + '(';
text += this.params.join(', ');
text += ')';
this.text = text;
}
}
export function functionRenderer(part, innerExpr) {
var str = part.def.type + '(';
var parameters = _.map(part.params, (value, index) => {
var paramType = part.def.params[index];
if (paramType.type === 'time') {
if (value === 'auto') {
value = '$interval';
}
}
if (paramType.quote === 'single') {
return "'" + value + "'";
} else if (paramType.quote === 'double') {
return '"' + value + '"';
}
return value;
});
if (innerExpr) {
parameters.unshift(innerExpr);
}
return str + parameters.join(', ') + ')';
}
export function suffixRenderer(part, innerExpr) {
return innerExpr + ' ' + part.params[0];
}
export function identityRenderer(part, innerExpr) {
return part.params[0];
}
export function quotedIdentityRenderer(part, innerExpr) {
return '"' + part.params[0] + '"';
}

@ -0,0 +1,183 @@
///<reference path="../../../headers/common.d.ts" />
import _ from 'lodash';
import $ from 'jquery';
import coreModule from 'app/core/core_module';
var template = `
<div class="tight-form-func-controls">
<span class="pointer fa fa-remove" ng-click="removeActionInternal()"></span>
</div>
<a ng-click="toggleControls()" class="query-part-name">{{part.def.type}}</a>
<span>(</span><span class="query-part-parameters"></span><span>)</span>
`;
/** @ngInject */
export function queryPartEditorDirective($compile, templateSrv) {
var paramTemplate = '<input type="text" style="display:none"' +
' class="input-mini tight-form-func-param"></input>';
return {
restrict: 'E',
template: template,
scope: {
part: "=",
removeAction: "&",
partUpdated: "&",
getOptions: "&",
},
link: function postLink($scope, elem) {
var part = $scope.part;
var partDef = part.def;
var $paramsContainer = elem.find('.query-part-parameters');
var $controlsContainer = elem.find('.tight-form-func-controls');
function clickFuncParam(paramIndex) {
/*jshint validthis:true */
var $link = $(this);
var $input = $link.next();
$input.val(part.params[paramIndex]);
$input.css('width', ($link.width() + 16) + 'px');
$link.hide();
$input.show();
$input.focus();
$input.select();
var typeahead = $input.data('typeahead');
if (typeahead) {
$input.val('');
typeahead.lookup();
}
}
function inputBlur(paramIndex) {
/*jshint validthis:true */
var $input = $(this);
var $link = $input.prev();
var newValue = $input.val();
if (newValue !== '' || part.def.params[paramIndex].optional) {
$link.html(templateSrv.highlightVariablesAsHtml(newValue));
part.updateParam($input.val(), paramIndex);
$scope.$apply($scope.partUpdated);
}
$input.hide();
$link.show();
}
function inputKeyPress(paramIndex, e) {
/*jshint validthis:true */
if (e.which === 13) {
inputBlur.call(this, paramIndex);
}
}
function inputKeyDown() {
/*jshint validthis:true */
this.style.width = (3 + this.value.length) * 8 + 'px';
}
function addTypeahead($input, param, paramIndex) {
if (!param.options && !param.dynamicLookup) {
return;
}
var typeaheadSource = function (query, callback) {
if (param.options) { return param.options; }
$scope.$apply(function() {
$scope.getOptions().then(function(result) {
var dynamicOptions = _.map(result, function(op) { return op.value; });
callback(dynamicOptions);
});
});
};
$input.attr('data-provide', 'typeahead');
var options = param.options;
if (param.type === 'int') {
options = _.map(options, function(val) { return val.toString(); });
}
$input.typeahead({
source: typeaheadSource,
minLength: 0,
items: 1000,
updater: function (value) {
setTimeout(function() {
inputBlur.call($input[0], paramIndex);
}, 0);
return value;
}
});
var typeahead = $input.data('typeahead');
typeahead.lookup = function () {
this.query = this.$element.val() || '';
var items = this.source(this.query, $.proxy(this.process, this));
return items ? this.process(items) : items;
};
}
$scope.toggleControls = function() {
var targetDiv = elem.closest('.tight-form');
if (elem.hasClass('show-function-controls')) {
elem.removeClass('show-function-controls');
targetDiv.removeClass('has-open-function');
$controlsContainer.hide();
return;
}
elem.addClass('show-function-controls');
targetDiv.addClass('has-open-function');
$controlsContainer.show();
};
$scope.removeActionInternal = function() {
$scope.toggleControls();
$scope.removeAction();
};
function addElementsAndCompile() {
_.each(partDef.params, function(param, index) {
if (param.optional && part.params.length <= index) {
return;
}
if (index > 0) {
$('<span>, </span>').appendTo($paramsContainer);
}
var paramValue = templateSrv.highlightVariablesAsHtml(part.params[index]);
var $paramLink = $('<a class="graphite-func-param-link pointer">' + paramValue + '</a>');
var $input = $(paramTemplate);
$paramLink.appendTo($paramsContainer);
$input.appendTo($paramsContainer);
$input.blur(_.partial(inputBlur, index));
$input.keyup(inputKeyDown);
$input.keypress(_.partial(inputKeyPress, index));
$paramLink.click(_.partial(clickFuncParam, index));
addTypeahead($input, param, index);
});
}
function relink() {
$paramsContainer.empty();
addElementsAndCompile();
}
relink();
}
};
}
coreModule.directive('queryPartEditor', queryPartEditorDirective);

@ -33,6 +33,7 @@ import {Emitter} from './utils/emitter';
import {layoutSelector} from './components/layout_selector/layout_selector';
import {switchDirective} from './components/switch';
import {dashboardSelector} from './components/dashboard_selector';
import {queryPartEditorDirective} from './components/query_part/query_part_editor';
import 'app/core/controllers/all';
import 'app/core/services/all';
import 'app/core/routes/routes';
@ -56,4 +57,5 @@ export {
Emitter,
appEvents,
dashboardSelector,
queryPartEditorDirective,
};

@ -51,7 +51,7 @@
<span class="btn btn-primary btn-mini" ng-show="org.orgId === contextSrv.user.orgId">
Current
</span>
<a ng-click="setUsingOrg(org)" class="btn btn-inverse btn-mini" ng-show="org.orgId !== contextSrv.user.orgId">
<a ng-click="ctrl.setUsingOrg(org)" class="btn btn-inverse btn-mini" ng-show="org.orgId !== contextSrv.user.orgId">
Select
</a>
</td>

@ -35,13 +35,13 @@
</div>
<div class="gf-form" ng-repeat="part in selectParts">
<influx-query-part-editor
<query-part-editor
class="gf-form-label query-part"
part="part"
remove-action="ctrl.removeSelectPart(selectParts, part)"
part-updated="ctrl.selectPartUpdated(selectParts, part)"
get-options="ctrl.getPartOptions(part)">
</influx-query-part-editor>
</query-part-editor>
</div>
<div class="gf-form">
@ -62,12 +62,12 @@
<span>GROUP BY</span>
</label>
<influx-query-part-editor
<query-part-editor
ng-repeat="part in ctrl.queryModel.groupByParts"
part="part"
class="gf-form-label query-part"
remove-action="ctrl.removeGroupByPart(part, $index)" part-updated="ctrl.refresh();" get-options="ctrl.getPartOptions(part)">
</influx-query-part-editor>
</query-part-editor>
</div>
<div class="gf-form">

@ -1,5 +0,0 @@
<div class="tight-form-func-controls">
<span class="pointer fa fa-remove" ng-click="removeActionInternal()" ></span>
</div>
<a ng-click="toggleControls()" class="query-part-name">{{part.def.type}}</a><span>(</span><span class="query-part-parameters"></span><span>)</span>

@ -1,8 +1,5 @@
///<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';

@ -1,6 +1,14 @@
///<reference path="../../../headers/common.d.ts" />
import _ from 'lodash';
import {
QueryPartDef,
QueryPart,
functionRenderer,
suffixRenderer,
identityRenderer,
quotedIdentityRenderer,
} from 'app/core/components/query_part/query_part';
var index = [];
var categories = {
@ -12,71 +20,26 @@ var categories = {
Fields: [],
};
var groupByTimeFunctions = [];
class QueryPartDef {
type: string;
params: any[];
defaultParams: any[];
renderer: any;
category: any;
addStrategy: any;
constructor(options: any) {
this.type = options.type;
this.params = options.params;
this.defaultParams = options.defaultParams;
this.renderer = options.renderer;
this.category = options.category;
this.addStrategy = options.addStrategy;
}
static register(options: any) {
index[options.type] = new QueryPartDef(options);
options.category.push(index[options.type]);
function createPart(part): any {
var def = index[part.type];
if (!def) {
throw {message: 'Could not find query part ' + part.type};
}
}
function functionRenderer(part, innerExpr) {
var str = part.def.type + '(';
var parameters = _.map(part.params, (value, index) => {
var paramType = part.def.params[index];
if (paramType.type === 'time') {
if (value === 'auto') {
value = '$interval';
}
}
if (paramType.quote === 'single') {
return "'" + value + "'";
} else if (paramType.quote === 'double') {
return '"' + value + '"';
}
return value;
});
return new QueryPart(part, def);
};
if (innerExpr) {
parameters.unshift(innerExpr);
}
return str + parameters.join(', ') + ')';
function register(options: any) {
index[options.type] = new QueryPartDef(options);
options.category.push(index[options.type]);
}
var groupByTimeFunctions = [];
function aliasRenderer(part, innerExpr) {
return innerExpr + ' AS ' + '"' + part.params[0] + '"';
}
function suffixRenderer(part, innerExpr) {
return innerExpr + ' ' + part.params[0];
}
function identityRenderer(part, innerExpr) {
return part.params[0];
}
function quotedIdentityRenderer(part, innerExpr) {
return '"' + part.params[0] + '"';
}
function fieldRenderer(part, innerExpr) {
if (part.params[0] === '*') {
return '*';
@ -149,13 +112,13 @@ function addAliasStrategy(selectParts, partModel) {
function addFieldStrategy(selectParts, partModel, query) {
// copy all parts
var parts = _.map(selectParts, function(part: any) {
return new QueryPart({type: part.def.type, params: _.clone(part.params)});
return createPart({type: part.def.type, params: _.clone(part.params)});
});
query.selectModels.push(parts);
}
QueryPartDef.register({
register({
type: 'field',
addStrategy: addFieldStrategy,
category: categories.Fields,
@ -165,7 +128,7 @@ QueryPartDef.register({
});
// Aggregations
QueryPartDef.register({
register({
type: 'count',
addStrategy: replaceAggregationAddStrategy,
category: categories.Aggregations,
@ -174,7 +137,7 @@ QueryPartDef.register({
renderer: functionRenderer,
});
QueryPartDef.register({
register({
type: 'distinct',
addStrategy: replaceAggregationAddStrategy,
category: categories.Aggregations,
@ -183,7 +146,7 @@ QueryPartDef.register({
renderer: functionRenderer,
});
QueryPartDef.register({
register({
type: 'integral',
addStrategy: replaceAggregationAddStrategy,
category: categories.Aggregations,
@ -192,7 +155,7 @@ QueryPartDef.register({
renderer: functionRenderer,
});
QueryPartDef.register({
register({
type: 'mean',
addStrategy: replaceAggregationAddStrategy,
category: categories.Aggregations,
@ -201,7 +164,7 @@ QueryPartDef.register({
renderer: functionRenderer,
});
QueryPartDef.register({
register({
type: 'median',
addStrategy: replaceAggregationAddStrategy,
category: categories.Aggregations,
@ -210,7 +173,7 @@ QueryPartDef.register({
renderer: functionRenderer,
});
QueryPartDef.register({
register({
type: 'sum',
addStrategy: replaceAggregationAddStrategy,
category: categories.Aggregations,
@ -221,7 +184,7 @@ QueryPartDef.register({
// transformations
QueryPartDef.register({
register({
type: 'derivative',
addStrategy: addTransformationStrategy,
category: categories.Transformations,
@ -230,7 +193,7 @@ QueryPartDef.register({
renderer: functionRenderer,
});
QueryPartDef.register({
register({
type: 'spread',
addStrategy: addTransformationStrategy,
category: categories.Transformations,
@ -239,7 +202,7 @@ QueryPartDef.register({
renderer: functionRenderer,
});
QueryPartDef.register({
register({
type: 'non_negative_derivative',
addStrategy: addTransformationStrategy,
category: categories.Transformations,
@ -248,7 +211,7 @@ QueryPartDef.register({
renderer: functionRenderer,
});
QueryPartDef.register({
register({
type: 'difference',
addStrategy: addTransformationStrategy,
category: categories.Transformations,
@ -257,7 +220,7 @@ QueryPartDef.register({
renderer: functionRenderer,
});
QueryPartDef.register({
register({
type: 'moving_average',
addStrategy: addTransformationStrategy,
category: categories.Transformations,
@ -266,7 +229,7 @@ QueryPartDef.register({
renderer: functionRenderer,
});
QueryPartDef.register({
register({
type: 'stddev',
addStrategy: addTransformationStrategy,
category: categories.Transformations,
@ -275,7 +238,7 @@ QueryPartDef.register({
renderer: functionRenderer,
});
QueryPartDef.register({
register({
type: 'time',
category: groupByTimeFunctions,
params: [{ name: "interval", type: "time", options: ['auto', '1s', '10s', '1m', '5m', '10m', '15m', '1h'] }],
@ -283,7 +246,7 @@ QueryPartDef.register({
renderer: functionRenderer,
});
QueryPartDef.register({
register({
type: 'fill',
category: groupByTimeFunctions,
params: [{ name: "fill", type: "string", options: ['none', 'null', '0', 'previous'] }],
@ -292,7 +255,7 @@ QueryPartDef.register({
});
// Selectors
QueryPartDef.register({
register({
type: 'bottom',
addStrategy: replaceAggregationAddStrategy,
category: categories.Selectors,
@ -301,7 +264,7 @@ QueryPartDef.register({
renderer: functionRenderer,
});
QueryPartDef.register({
register({
type: 'first',
addStrategy: replaceAggregationAddStrategy,
category: categories.Selectors,
@ -310,7 +273,7 @@ QueryPartDef.register({
renderer: functionRenderer,
});
QueryPartDef.register({
register({
type: 'last',
addStrategy: replaceAggregationAddStrategy,
category: categories.Selectors,
@ -319,7 +282,7 @@ QueryPartDef.register({
renderer: functionRenderer,
});
QueryPartDef.register({
register({
type: 'max',
addStrategy: replaceAggregationAddStrategy,
category: categories.Selectors,
@ -328,7 +291,7 @@ QueryPartDef.register({
renderer: functionRenderer,
});
QueryPartDef.register({
register({
type: 'min',
addStrategy: replaceAggregationAddStrategy,
category: categories.Selectors,
@ -337,7 +300,7 @@ QueryPartDef.register({
renderer: functionRenderer,
});
QueryPartDef.register({
register({
type: 'percentile',
addStrategy: replaceAggregationAddStrategy,
category: categories.Selectors,
@ -346,7 +309,7 @@ QueryPartDef.register({
renderer: functionRenderer,
});
QueryPartDef.register({
register({
type: 'top',
addStrategy: replaceAggregationAddStrategy,
category: categories.Selectors,
@ -355,7 +318,7 @@ QueryPartDef.register({
renderer: functionRenderer,
});
QueryPartDef.register({
register({
type: 'tag',
category: groupByTimeFunctions,
params: [{name: 'tag', type: 'string', dynamicLookup: true}],
@ -363,7 +326,7 @@ QueryPartDef.register({
renderer: fieldRenderer,
});
QueryPartDef.register({
register({
type: 'math',
addStrategy: addMathStrategy,
category: categories.Math,
@ -372,7 +335,7 @@ QueryPartDef.register({
renderer: suffixRenderer,
});
QueryPartDef.register({
register({
type: 'alias',
addStrategy: addAliasStrategy,
category: categories.Aliasing,
@ -382,74 +345,9 @@ QueryPartDef.register({
renderer: aliasRenderer,
});
class QueryPart {
part: any;
def: QueryPartDef;
params: any[];
text: string;
constructor(part: any) {
this.part = part;
this.def = index[part.type];
if (!this.def) {
throw {message: 'Could not find query part ' + part.type};
}
part.params = part.params || _.clone(this.def.defaultParams);
this.params = part.params;
this.updateText();
}
render(innerExpr: string) {
return this.def.renderer(this, innerExpr);
}
hasMultipleParamsInString (strValue, index) {
if (strValue.indexOf(',') === -1) {
return false;
}
return this.def.params[index + 1] && this.def.params[index + 1].optional;
}
updateParam (strValue, index) {
// handle optional parameters
// if string contains ',' and next param is optional, split and update both
if (this.hasMultipleParamsInString(strValue, index)) {
_.each(strValue.split(','), function(partVal: string, idx) {
this.updateParam(partVal.trim(), idx);
}, this);
return;
}
if (strValue === '' && this.def.params[index].optional) {
this.params.splice(index, 1);
} else {
this.params[index] = strValue;
}
this.part.params = this.params;
this.updateText();
}
updateText() {
if (this.params.length === 0) {
this.text = this.def.type + '()';
return;
}
var text = this.def.type + '(';
text += this.params.join(', ');
text += ')';
this.text = text;
}
}
export default {
create: function(part): any {
return new QueryPart(part);
},
create: createPart,
getCategories: function() {
return categories;
}

@ -1,178 +0,0 @@
define([
'angular',
'lodash',
'jquery',
],
function (angular, _, $) {
'use strict';
angular
.module('grafana.directives')
.directive('influxQueryPartEditor', function($compile, templateSrv) {
var paramTemplate = '<input type="text" style="display:none"' +
' class="input-mini tight-form-func-param"></input>';
return {
restrict: 'E',
templateUrl: 'public/app/plugins/datasource/influxdb/partials/query_part.html',
scope: {
part: "=",
removeAction: "&",
partUpdated: "&",
getOptions: "&",
},
link: function postLink($scope, elem) {
var part = $scope.part;
var partDef = part.def;
var $paramsContainer = elem.find('.query-part-parameters');
var $controlsContainer = elem.find('.tight-form-func-controls');
function clickFuncParam(paramIndex) {
/*jshint validthis:true */
var $link = $(this);
var $input = $link.next();
$input.val(part.params[paramIndex]);
$input.css('width', ($link.width() + 16) + 'px');
$link.hide();
$input.show();
$input.focus();
$input.select();
var typeahead = $input.data('typeahead');
if (typeahead) {
$input.val('');
typeahead.lookup();
}
}
function inputBlur(paramIndex) {
/*jshint validthis:true */
var $input = $(this);
var $link = $input.prev();
var newValue = $input.val();
if (newValue !== '' || part.def.params[paramIndex].optional) {
$link.html(templateSrv.highlightVariablesAsHtml(newValue));
part.updateParam($input.val(), paramIndex);
$scope.$apply($scope.partUpdated);
}
$input.hide();
$link.show();
}
function inputKeyPress(paramIndex, e) {
/*jshint validthis:true */
if(e.which === 13) {
inputBlur.call(this, paramIndex);
}
}
function inputKeyDown() {
/*jshint validthis:true */
this.style.width = (3 + this.value.length) * 8 + 'px';
}
function addTypeahead($input, param, paramIndex) {
if (!param.options && !param.dynamicLookup) {
return;
}
var typeaheadSource = function (query, callback) {
if (param.options) { return param.options; }
$scope.$apply(function() {
$scope.getOptions().then(function(result) {
var dynamicOptions = _.map(result, function(op) { return op.value; });
callback(dynamicOptions);
});
});
};
$input.attr('data-provide', 'typeahead');
var options = param.options;
if (param.type === 'int') {
options = _.map(options, function(val) { return val.toString(); });
}
$input.typeahead({
source: typeaheadSource,
minLength: 0,
items: 1000,
updater: function (value) {
setTimeout(function() {
inputBlur.call($input[0], paramIndex);
}, 0);
return value;
}
});
var typeahead = $input.data('typeahead');
typeahead.lookup = function () {
this.query = this.$element.val() || '';
var items = this.source(this.query, $.proxy(this.process, this));
return items ? this.process(items) : items;
};
}
$scope.toggleControls = function() {
var targetDiv = elem.closest('.tight-form');
if (elem.hasClass('show-function-controls')) {
elem.removeClass('show-function-controls');
targetDiv.removeClass('has-open-function');
$controlsContainer.hide();
return;
}
elem.addClass('show-function-controls');
targetDiv.addClass('has-open-function');
$controlsContainer.show();
};
$scope.removeActionInternal = function() {
$scope.toggleControls();
$scope.removeAction();
};
function addElementsAndCompile() {
_.each(partDef.params, function(param, index) {
if (param.optional && part.params.length <= index) {
return;
}
if (index > 0) {
$('<span>, </span>').appendTo($paramsContainer);
}
var paramValue = templateSrv.highlightVariablesAsHtml(part.params[index]);
var $paramLink = $('<a class="graphite-func-param-link pointer">' + paramValue + '</a>');
var $input = $(paramTemplate);
$paramLink.appendTo($paramsContainer);
$input.appendTo($paramsContainer);
$input.blur(_.partial(inputBlur, index));
$input.keyup(inputKeyDown);
$input.keypress(_.partial(inputKeyPress, index));
$paramLink.click(_.partial(clickFuncParam, index));
addTypeahead($input, param, index);
});
}
function relink() {
$paramsContainer.empty();
addElementsAndCompile();
}
relink();
}
};
});
});

@ -403,10 +403,7 @@ function (angular, _, dateMath) {
} else {
return _.findIndex(options.targets, function(target) {
if (target.filters && target.filters.length > 0) {
return target.metric === metricData.metric &&
_.all(target.filters, function(filter) {
return filter.tagk === interpolatedTagValue === "*";
});
return target.metric === metricData.metric;
} else {
return target.metric === metricData.metric &&
_.all(target.tags, function(tagV, tagK) {

Loading…
Cancel
Save