|
|
@@ -3,141 +3,70 @@ import './func_editor';
|
|
|
|
|
|
import _ from 'lodash';
|
|
|
import gfunc from './gfunc';
|
|
|
-import {Parser} from './parser';
|
|
|
+import GraphiteQuery from './graphite_query';
|
|
|
import {QueryCtrl} from 'app/plugins/sdk';
|
|
|
import appEvents from 'app/core/app_events';
|
|
|
|
|
|
const GRAPHITE_TAG_OPERATORS = ['=', '!=', '=~', '!=~'];
|
|
|
+const TAG_PREFIX = 'tag: ';
|
|
|
|
|
|
export class GraphiteQueryCtrl extends QueryCtrl {
|
|
|
static templateUrl = 'partials/query.editor.html';
|
|
|
|
|
|
- functions: any[];
|
|
|
+ queryModel: GraphiteQuery;
|
|
|
segments: any[];
|
|
|
addTagSegments: any[];
|
|
|
- tags: any[];
|
|
|
- seriesByTagUsed: boolean;
|
|
|
removeTagValue: string;
|
|
|
+ supportsTags: boolean;
|
|
|
|
|
|
/** @ngInject **/
|
|
|
constructor($scope, $injector, private uiSegmentSrv, private templateSrv) {
|
|
|
super($scope, $injector);
|
|
|
+ this.supportsTags = this.datasource.supportsTags;
|
|
|
|
|
|
if (this.target) {
|
|
|
this.target.target = this.target.target || '';
|
|
|
- this.parseTarget();
|
|
|
+ this.queryModel = new GraphiteQuery(this.target, templateSrv);
|
|
|
+ this.buildSegments();
|
|
|
}
|
|
|
|
|
|
this.removeTagValue = '-- remove tag --';
|
|
|
}
|
|
|
|
|
|
- toggleEditorMode() {
|
|
|
- this.target.textEditor = !this.target.textEditor;
|
|
|
- this.parseTarget();
|
|
|
- }
|
|
|
-
|
|
|
parseTarget() {
|
|
|
- this.functions = [];
|
|
|
- this.segments = [];
|
|
|
- this.error = null;
|
|
|
-
|
|
|
- if (this.target.textEditor) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- var parser = new Parser(this.target.target);
|
|
|
- var astNode = parser.getAst();
|
|
|
- if (astNode === null) {
|
|
|
- this.checkOtherSegments(0);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (astNode.type === 'error') {
|
|
|
- this.error = astNode.message + " at position: " + astNode.pos;
|
|
|
- this.target.textEditor = true;
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- try {
|
|
|
- this.parseTargetRecursive(astNode, null, 0);
|
|
|
- } catch (err) {
|
|
|
- console.log('error parsing target:', err.message);
|
|
|
- this.error = err.message;
|
|
|
- this.target.textEditor = true;
|
|
|
- }
|
|
|
-
|
|
|
- this.checkOtherSegments(this.segments.length - 1);
|
|
|
- this.checkForSeriesByTag();
|
|
|
+ this.queryModel.parseTarget();
|
|
|
+ this.buildSegments();
|
|
|
}
|
|
|
|
|
|
- addFunctionParameter(func, value, index, shiftBack) {
|
|
|
- if (shiftBack) {
|
|
|
- index = Math.max(index - 1, 0);
|
|
|
- }
|
|
|
- func.params[index] = value;
|
|
|
+ toggleEditorMode() {
|
|
|
+ this.target.textEditor = !this.target.textEditor;
|
|
|
+ this.parseTarget();
|
|
|
}
|
|
|
|
|
|
- parseTargetRecursive(astNode, func, index) {
|
|
|
- if (astNode === null) {
|
|
|
- return null;
|
|
|
- }
|
|
|
-
|
|
|
- switch (astNode.type) {
|
|
|
- case 'function':
|
|
|
- var innerFunc = gfunc.createFuncInstance(astNode.name, { withDefaultParams: false });
|
|
|
- _.each(astNode.params, (param, index) => {
|
|
|
- this.parseTargetRecursive(param, innerFunc, index);
|
|
|
- });
|
|
|
-
|
|
|
- innerFunc.updateText();
|
|
|
- this.functions.push(innerFunc);
|
|
|
- break;
|
|
|
- case 'series-ref':
|
|
|
- this.addFunctionParameter(func, astNode.value, index, this.segments.length > 0);
|
|
|
- break;
|
|
|
- case 'bool':
|
|
|
- case 'string':
|
|
|
- case 'number':
|
|
|
- if ((index-1) >= func.def.params.length) {
|
|
|
- throw { message: 'invalid number of parameters to method ' + func.def.name };
|
|
|
- }
|
|
|
- var shiftBack = this.isShiftParamsBack(func);
|
|
|
- this.addFunctionParameter(func, astNode.value, index, shiftBack);
|
|
|
- break;
|
|
|
- case 'metric':
|
|
|
- if (this.segments.length > 0) {
|
|
|
- if (astNode.segments.length !== 1) {
|
|
|
- throw { message: 'Multiple metric params not supported, use text editor.' };
|
|
|
- }
|
|
|
- this.addFunctionParameter(func, astNode.segments[0].value, index, true);
|
|
|
- break;
|
|
|
- }
|
|
|
+ buildSegments() {
|
|
|
+ this.segments = _.map(this.queryModel.segments, segment => {
|
|
|
+ return this.uiSegmentSrv.newSegment(segment);
|
|
|
+ });
|
|
|
+ let checkOtherSegmentsIndex = this.queryModel.checkOtherSegmentsIndex || 0;
|
|
|
+ this.checkOtherSegments(checkOtherSegmentsIndex);
|
|
|
|
|
|
- this.segments = _.map(astNode.segments, segment => {
|
|
|
- return this.uiSegmentSrv.newSegment(segment);
|
|
|
- });
|
|
|
+ if (this.queryModel.seriesByTagUsed) {
|
|
|
+ this.fixTagSegments();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- isShiftParamsBack(func) {
|
|
|
- return func.def.name !== 'seriesByTag';
|
|
|
- }
|
|
|
-
|
|
|
- getSegmentPathUpTo(index) {
|
|
|
- var arr = this.segments.slice(0, index);
|
|
|
-
|
|
|
- return _.reduce(arr, function(result, segment) {
|
|
|
- return result ? (result + "." + segment.value) : segment.value;
|
|
|
- }, "");
|
|
|
+ addSelectMetricSegment() {
|
|
|
+ this.queryModel.addSelectMetricSegment();
|
|
|
+ this.segments.push(this.uiSegmentSrv.newSelectMetric());
|
|
|
}
|
|
|
|
|
|
checkOtherSegments(fromIndex) {
|
|
|
if (fromIndex === 0) {
|
|
|
- this.segments.push(this.uiSegmentSrv.newSelectMetric());
|
|
|
+ this.addSelectMetricSegment();
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- var path = this.getSegmentPathUpTo(fromIndex + 1);
|
|
|
+ var path = this.queryModel.getSegmentPathUpTo(fromIndex + 1);
|
|
|
if (path === "") {
|
|
|
return Promise.resolve();
|
|
|
}
|
|
|
@@ -145,12 +74,13 @@ export class GraphiteQueryCtrl extends QueryCtrl {
|
|
|
return this.datasource.metricFindQuery(path).then(segments => {
|
|
|
if (segments.length === 0) {
|
|
|
if (path !== '') {
|
|
|
+ this.queryModel.segments = this.queryModel.segments.splice(0, fromIndex);
|
|
|
this.segments = this.segments.splice(0, fromIndex);
|
|
|
- this.segments.push(this.uiSegmentSrv.newSelectMetric());
|
|
|
+ this.addSelectMetricSegment();
|
|
|
}
|
|
|
} else if (segments[0].expandable) {
|
|
|
if (this.segments.length === fromIndex) {
|
|
|
- this.segments.push(this.uiSegmentSrv.newSelectMetric());
|
|
|
+ this.addSelectMetricSegment();
|
|
|
} else {
|
|
|
return this.checkOtherSegments(fromIndex + 1);
|
|
|
}
|
|
|
@@ -166,12 +96,8 @@ export class GraphiteQueryCtrl extends QueryCtrl {
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- wrapFunction(target, func) {
|
|
|
- return func.render(target);
|
|
|
- }
|
|
|
-
|
|
|
getAltSegments(index) {
|
|
|
- var query = index === 0 ? '*' : this.getSegmentPathUpTo(index) + '.*';
|
|
|
+ var query = index === 0 ? '*' : this.queryModel.getSegmentPathUpTo(index) + '.*';
|
|
|
var options = {range: this.panelCtrl.range, requestId: "get-alt-segments"};
|
|
|
|
|
|
return this.datasource.metricFindQuery(query, options).then(segments => {
|
|
|
@@ -192,17 +118,44 @@ export class GraphiteQueryCtrl extends QueryCtrl {
|
|
|
|
|
|
// add wildcard option
|
|
|
altSegments.unshift(this.uiSegmentSrv.newSegment('*'));
|
|
|
- return altSegments;
|
|
|
+
|
|
|
+ if (this.supportsTags && index === 0) {
|
|
|
+ this.removeTaggedEntry(altSegments);
|
|
|
+ return this.addAltTagSegments(index, altSegments);
|
|
|
+ } else {
|
|
|
+ return altSegments;
|
|
|
+ }
|
|
|
}).catch(err => {
|
|
|
return [];
|
|
|
});
|
|
|
}
|
|
|
|
|
|
+ addAltTagSegments(index, altSegments) {
|
|
|
+ return this.getTagsAsSegments().then((tagSegments) => {
|
|
|
+ tagSegments = _.map(tagSegments, (segment) => {
|
|
|
+ segment.value = TAG_PREFIX + segment.value;
|
|
|
+ return segment;
|
|
|
+ });
|
|
|
+ return altSegments.concat(...tagSegments);
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ removeTaggedEntry(altSegments) {
|
|
|
+ altSegments = _.remove(altSegments, (s) => s.value === '_tagged');
|
|
|
+ }
|
|
|
+
|
|
|
segmentValueChanged(segment, segmentIndex) {
|
|
|
this.error = null;
|
|
|
+ this.queryModel.updateSegmentValue(segment, segmentIndex);
|
|
|
+
|
|
|
+ if (this.queryModel.functions.length > 0 && this.queryModel.functions[0].def.fake) {
|
|
|
+ this.queryModel.functions = [];
|
|
|
+ }
|
|
|
|
|
|
- if (this.functions.length > 0 && this.functions[0].def.fake) {
|
|
|
- this.functions = [];
|
|
|
+ if (segment.type === 'tag') {
|
|
|
+ let tag = removeTagPrefix(segment.value);
|
|
|
+ this.addSeriesByTagFunc(tag);
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
if (segment.expandable) {
|
|
|
@@ -211,81 +164,41 @@ export class GraphiteQueryCtrl extends QueryCtrl {
|
|
|
this.targetChanged();
|
|
|
});
|
|
|
} else {
|
|
|
- this.segments = this.segments.splice(0, segmentIndex + 1);
|
|
|
+ this.spliceSegments(segmentIndex + 1);
|
|
|
}
|
|
|
|
|
|
this.setSegmentFocus(segmentIndex + 1);
|
|
|
this.targetChanged();
|
|
|
}
|
|
|
|
|
|
+ spliceSegments(index) {
|
|
|
+ this.segments = this.segments.splice(0, index);
|
|
|
+ this.queryModel.segments = this.queryModel.segments.splice(0, index);
|
|
|
+ }
|
|
|
+
|
|
|
+ emptySegments() {
|
|
|
+ this.queryModel.segments = [];
|
|
|
+ this.segments = [];
|
|
|
+ }
|
|
|
+
|
|
|
targetTextChanged() {
|
|
|
this.updateModelTarget();
|
|
|
this.refresh();
|
|
|
}
|
|
|
|
|
|
updateModelTarget() {
|
|
|
- // render query
|
|
|
- if (!this.target.textEditor) {
|
|
|
- var metricPath = this.getSegmentPathUpTo(this.segments.length);
|
|
|
- this.target.target = _.reduce(this.functions, this.wrapFunction, metricPath);
|
|
|
- }
|
|
|
-
|
|
|
- this.updateRenderedTarget(this.target);
|
|
|
-
|
|
|
- // loop through other queries and update targetFull as needed
|
|
|
- for (const target of this.panelCtrl.panel.targets || []) {
|
|
|
- if (target.refId !== this.target.refId) {
|
|
|
- this.updateRenderedTarget(target);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- updateRenderedTarget(target) {
|
|
|
- // render nested query
|
|
|
- var targetsByRefId = _.keyBy(this.panelCtrl.panel.targets, 'refId');
|
|
|
-
|
|
|
- // no references to self
|
|
|
- delete targetsByRefId[target.refId];
|
|
|
-
|
|
|
- var nestedSeriesRefRegex = /\#([A-Z])/g;
|
|
|
- var targetWithNestedQueries = target.target;
|
|
|
-
|
|
|
- // Keep interpolating until there are no query references
|
|
|
- // The reason for the loop is that the referenced query might contain another reference to another query
|
|
|
- while (targetWithNestedQueries.match(nestedSeriesRefRegex)) {
|
|
|
- var updated = targetWithNestedQueries.replace(nestedSeriesRefRegex, (match, g1) => {
|
|
|
- var t = targetsByRefId[g1];
|
|
|
- if (!t) {
|
|
|
- return match;
|
|
|
- }
|
|
|
-
|
|
|
- // no circular references
|
|
|
- delete targetsByRefId[g1];
|
|
|
- return t.target;
|
|
|
- });
|
|
|
-
|
|
|
- if (updated === targetWithNestedQueries) {
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- targetWithNestedQueries = updated;
|
|
|
- }
|
|
|
-
|
|
|
- delete target.targetFull;
|
|
|
- if (target.target !== targetWithNestedQueries) {
|
|
|
- target.targetFull = targetWithNestedQueries;
|
|
|
- }
|
|
|
+ this.queryModel.updateModelTarget(this.panelCtrl.panel.targets);
|
|
|
}
|
|
|
|
|
|
targetChanged() {
|
|
|
- if (this.error) {
|
|
|
+ if (this.queryModel.error) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- var oldTarget = this.target.target;
|
|
|
+ var oldTarget = this.queryModel.target.target;
|
|
|
this.updateModelTarget();
|
|
|
|
|
|
- if (this.target.target !== oldTarget) {
|
|
|
+ if (this.queryModel.target !== oldTarget) {
|
|
|
var lastSegment = this.segments.length > 0 ? this.segments[this.segments.length - 1] : {};
|
|
|
if (lastSegment.value !== 'select metric') {
|
|
|
this.panelCtrl.refresh();
|
|
|
@@ -293,21 +206,14 @@ export class GraphiteQueryCtrl extends QueryCtrl {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- removeFunction(func) {
|
|
|
- this.functions = _.without(this.functions, func);
|
|
|
- this.targetChanged();
|
|
|
- }
|
|
|
-
|
|
|
addFunction(funcDef) {
|
|
|
var newFunc = gfunc.createFuncInstance(funcDef, { withDefaultParams: true });
|
|
|
newFunc.added = true;
|
|
|
- this.functions.push(newFunc);
|
|
|
-
|
|
|
- this.moveAliasFuncLast();
|
|
|
+ this.queryModel.addFunction(newFunc);
|
|
|
this.smartlyHandleNewAliasByNode(newFunc);
|
|
|
|
|
|
if (this.segments.length === 1 && this.segments[0].fake) {
|
|
|
- this.segments = [];
|
|
|
+ this.emptySegments();
|
|
|
}
|
|
|
|
|
|
if (!newFunc.params.length && newFunc.added) {
|
|
|
@@ -319,17 +225,22 @@ export class GraphiteQueryCtrl extends QueryCtrl {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- moveAliasFuncLast() {
|
|
|
- var aliasFunc = _.find(this.functions, function(func) {
|
|
|
- return func.def.name === 'alias' ||
|
|
|
- func.def.name === 'aliasByNode' ||
|
|
|
- func.def.name === 'aliasByMetric';
|
|
|
- });
|
|
|
+ removeFunction(func) {
|
|
|
+ this.queryModel.removeFunction(func);
|
|
|
+ this.targetChanged();
|
|
|
+ }
|
|
|
|
|
|
- if (aliasFunc) {
|
|
|
- this.functions = _.without(this.functions, aliasFunc);
|
|
|
- this.functions.push(aliasFunc);
|
|
|
- }
|
|
|
+ addSeriesByTagFunc(tag) {
|
|
|
+ let funcDef = gfunc.getFuncDef('seriesByTag');
|
|
|
+ let newFunc = gfunc.createFuncInstance(funcDef, { withDefaultParams: false });
|
|
|
+ let tagParam = `${tag}=select tag value`;
|
|
|
+ newFunc.params = [tagParam];
|
|
|
+ this.queryModel.addFunction(newFunc);
|
|
|
+ newFunc.added = true;
|
|
|
+
|
|
|
+ this.emptySegments();
|
|
|
+ this.targetChanged();
|
|
|
+ this.parseTarget();
|
|
|
}
|
|
|
|
|
|
smartlyHandleNewAliasByNode(func) {
|
|
|
@@ -338,7 +249,7 @@ export class GraphiteQueryCtrl extends QueryCtrl {
|
|
|
}
|
|
|
|
|
|
for (var i = 0; i < this.segments.length; i++) {
|
|
|
- if (this.segments[i].value.indexOf('*') >= 0) {
|
|
|
+ if (this.segments[i].value.indexOf('*') >= 0) {
|
|
|
func.params[0] = i;
|
|
|
func.added = false;
|
|
|
this.targetChanged();
|
|
|
@@ -347,40 +258,18 @@ export class GraphiteQueryCtrl extends QueryCtrl {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- //////////////////////////////////
|
|
|
- // Graphite seriesByTag support //
|
|
|
- //////////////////////////////////
|
|
|
-
|
|
|
- checkForSeriesByTag() {
|
|
|
- let seriesByTagFunc = _.find(this.functions, (func) => func.def.name === 'seriesByTag');
|
|
|
- if (seriesByTagFunc) {
|
|
|
- this.seriesByTagUsed = true;
|
|
|
- let tags = this.splitSeriesByTagParams(seriesByTagFunc);
|
|
|
- this.tags = tags;
|
|
|
- this.fixTagSegments();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- splitSeriesByTagParams(func) {
|
|
|
- const tagPattern = /([^\!=~]+)([\!=~]+)([^\!=~]+)/;
|
|
|
- return _.flatten(_.map(func.params, (param: string) => {
|
|
|
- let matches = tagPattern.exec(param);
|
|
|
- if (matches) {
|
|
|
- let tag = matches.slice(1);
|
|
|
- if (tag.length === 3) {
|
|
|
- return {
|
|
|
- key: tag[0],
|
|
|
- operator: tag[1],
|
|
|
- value: tag[2]
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- return [];
|
|
|
- }));
|
|
|
+ getAllTags() {
|
|
|
+ return this.datasource.getTags().then((values) => {
|
|
|
+ let altTags = _.map(values, 'text');
|
|
|
+ altTags.splice(0, 0, this.removeTagValue);
|
|
|
+ return mapToDropdownOptions(altTags);
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
- getTags() {
|
|
|
- return this.datasource.getTags().then((values) => {
|
|
|
+ getTags(index, tagPrefix) {
|
|
|
+ let tagExpressions = this.queryModel.renderTagExpressions(index);
|
|
|
+ return this.datasource.getTagsAutoComplete(tagExpressions, tagPrefix)
|
|
|
+ .then((values) => {
|
|
|
let altTags = _.map(values, 'text');
|
|
|
altTags.splice(0, 0, this.removeTagValue);
|
|
|
return mapToDropdownOptions(altTags);
|
|
|
@@ -388,9 +277,11 @@ export class GraphiteQueryCtrl extends QueryCtrl {
|
|
|
}
|
|
|
|
|
|
getTagsAsSegments() {
|
|
|
- return this.datasource.getTags().then((values) => {
|
|
|
+ let tagExpressions = this.queryModel.renderTagExpressions();
|
|
|
+ return this.datasource.getTagsAutoComplete(tagExpressions)
|
|
|
+ .then((values) => {
|
|
|
return _.map(values, (val) => {
|
|
|
- return this.uiSegmentSrv.newSegment(val.text);
|
|
|
+ return this.uiSegmentSrv.newSegment({value: val.text, type: 'tag', expandable: false});
|
|
|
});
|
|
|
});
|
|
|
}
|
|
|
@@ -399,7 +290,7 @@ export class GraphiteQueryCtrl extends QueryCtrl {
|
|
|
return mapToDropdownOptions(GRAPHITE_TAG_OPERATORS);
|
|
|
}
|
|
|
|
|
|
- getTagValues(tag) {
|
|
|
+ getAllTagValues(tag) {
|
|
|
let tagKey = tag.key;
|
|
|
return this.datasource.getTagValues(tagKey).then((values) => {
|
|
|
let altValues = _.map(values, 'text');
|
|
|
@@ -407,46 +298,30 @@ export class GraphiteQueryCtrl extends QueryCtrl {
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- tagChanged(tag, tagIndex) {
|
|
|
- this.error = null;
|
|
|
-
|
|
|
- if (tag.key === this.removeTagValue) {
|
|
|
- this.removeTag(tagIndex);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- let newTagParam = renderTagString(tag);
|
|
|
- this.getSeriesByTagFunc().params[tagIndex] = newTagParam;
|
|
|
- this.tags[tagIndex] = tag;
|
|
|
- this.targetChanged();
|
|
|
- }
|
|
|
-
|
|
|
- getSeriesByTagFuncIndex() {
|
|
|
- return _.findIndex(this.functions, (func) => func.def.name === 'seriesByTag');
|
|
|
+ getTagValues(tag, index, valuePrefix) {
|
|
|
+ let tagExpressions = this.queryModel.renderTagExpressions(index);
|
|
|
+ let tagKey = tag.key;
|
|
|
+ return this.datasource.getTagValuesAutoComplete(tagExpressions, tagKey, valuePrefix).then((values) => {
|
|
|
+ let altValues = _.map(values, 'text');
|
|
|
+ return mapToDropdownOptions(altValues);
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
- getSeriesByTagFunc() {
|
|
|
- let seriesByTagFuncIndex = this.getSeriesByTagFuncIndex();
|
|
|
- if (seriesByTagFuncIndex >= 0) {
|
|
|
- return this.functions[seriesByTagFuncIndex];
|
|
|
- } else {
|
|
|
- return undefined;
|
|
|
- }
|
|
|
+ tagChanged(tag, tagIndex) {
|
|
|
+ this.queryModel.updateTag(tag, tagIndex);
|
|
|
+ this.targetChanged();
|
|
|
}
|
|
|
|
|
|
addNewTag(segment) {
|
|
|
let newTagKey = segment.value;
|
|
|
let newTag = {key: newTagKey, operator: '=', value: 'select tag value'};
|
|
|
- let newTagParam = renderTagString(newTag);
|
|
|
- this.getSeriesByTagFunc().params.push(newTagParam);
|
|
|
- this.tags.push(newTag);
|
|
|
+ this.queryModel.addTag(newTag);
|
|
|
this.targetChanged();
|
|
|
this.fixTagSegments();
|
|
|
}
|
|
|
|
|
|
removeTag(index) {
|
|
|
- this.getSeriesByTagFunc().params.splice(index, 1);
|
|
|
- this.tags.splice(index, 1);
|
|
|
+ this.queryModel.removeTag(index);
|
|
|
this.targetChanged();
|
|
|
}
|
|
|
|
|
|
@@ -456,16 +331,16 @@ export class GraphiteQueryCtrl extends QueryCtrl {
|
|
|
}
|
|
|
|
|
|
showDelimiter(index) {
|
|
|
- return index !== this.tags.length - 1;
|
|
|
+ return index !== this.queryModel.tags.length - 1;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-function renderTagString(tag) {
|
|
|
- return tag.key + tag.operator + tag.value;
|
|
|
-}
|
|
|
-
|
|
|
function mapToDropdownOptions(results) {
|
|
|
return _.map(results, (value) => {
|
|
|
return {text: value, value: value};
|
|
|
});
|
|
|
}
|
|
|
+
|
|
|
+function removeTagPrefix(value: string): string {
|
|
|
+ return value.replace(TAG_PREFIX, '');
|
|
|
+}
|