|
|
@@ -28,7 +28,6 @@ export class GraphiteQueryCtrl extends QueryCtrl {
|
|
|
}
|
|
|
|
|
|
toggleEditorMode() {
|
|
|
- this.target.textEditor = !this.target.textEditor;
|
|
|
this.parseTarget();
|
|
|
}
|
|
|
|
|
|
@@ -55,7 +54,7 @@ export class GraphiteQueryCtrl extends QueryCtrl {
|
|
|
}
|
|
|
|
|
|
try {
|
|
|
- this.parseTargeRecursive(astNode, null, 0);
|
|
|
+ this.parseTargetRecursive(astNode, null, 0);
|
|
|
} catch (err) {
|
|
|
console.log('error parsing target:', err.message);
|
|
|
this.error = err.message;
|
|
|
@@ -72,7 +71,7 @@ export class GraphiteQueryCtrl extends QueryCtrl {
|
|
|
func.params[index] = value;
|
|
|
}
|
|
|
|
|
|
- parseTargeRecursive(astNode, func, index) {
|
|
|
+ parseTargetRecursive(astNode, func, index) {
|
|
|
if (astNode === null) {
|
|
|
return null;
|
|
|
}
|
|
|
@@ -81,7 +80,7 @@ export class GraphiteQueryCtrl extends QueryCtrl {
|
|
|
case 'function':
|
|
|
var innerFunc = gfunc.createFuncInstance(astNode.name, { withDefaultParams: false });
|
|
|
_.each(astNode.params, (param, index) => {
|
|
|
- this.parseTargeRecursive(param, innerFunc, index);
|
|
|
+ this.parseTargetRecursive(param, innerFunc, index);
|
|
|
});
|
|
|
|
|
|
innerFunc.updateText();
|
|
|
@@ -209,30 +208,61 @@ export class GraphiteQueryCtrl extends QueryCtrl {
|
|
|
}
|
|
|
|
|
|
targetTextChanged() {
|
|
|
- this.parseTarget();
|
|
|
- this.panelCtrl.refresh();
|
|
|
+ this.updateModelTarget();
|
|
|
+ this.refresh();
|
|
|
}
|
|
|
|
|
|
updateModelTarget() {
|
|
|
// render query
|
|
|
- var metricPath = this.getSegmentPathUpTo(this.segments.length);
|
|
|
- this.target.target = _.reduce(this.functions, this.wrapFunction, metricPath);
|
|
|
+ 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 = this.target.target.replace(nestedSeriesRefRegex, (match, g1) => {
|
|
|
- var target = targetsByRefId[g1];
|
|
|
- if (!target) {
|
|
|
- return match;
|
|
|
+ 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;
|
|
|
}
|
|
|
|
|
|
- return target.targetFull || target.target;
|
|
|
- });
|
|
|
+ targetWithNestedQueries = updated;
|
|
|
+ }
|
|
|
|
|
|
- delete this.target.targetFull;
|
|
|
- if (this.target.target !== targetWithNestedQueries) {
|
|
|
- this.target.targetFull = targetWithNestedQueries;
|
|
|
+ delete target.targetFull;
|
|
|
+ if (target.target !== targetWithNestedQueries) {
|
|
|
+ target.targetFull = targetWithNestedQueries;
|
|
|
}
|
|
|
}
|
|
|
|