query_ctrl.ts 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. import './add_graphite_func';
  2. import './func_editor';
  3. import _ from 'lodash';
  4. import gfunc from './gfunc';
  5. import GraphiteQuery from './graphite_query';
  6. import {QueryCtrl} from 'app/plugins/sdk';
  7. import appEvents from 'app/core/app_events';
  8. const GRAPHITE_TAG_OPERATORS = ['=', '!=', '=~', '!=~'];
  9. export class GraphiteQueryCtrl extends QueryCtrl {
  10. static templateUrl = 'partials/query.editor.html';
  11. queryModel: GraphiteQuery;
  12. segments: any[];
  13. addTagSegments: any[];
  14. removeTagValue: string;
  15. /** @ngInject **/
  16. constructor($scope, $injector, private uiSegmentSrv, private templateSrv) {
  17. super($scope, $injector);
  18. if (this.target) {
  19. this.target.target = this.target.target || '';
  20. this.queryModel = new GraphiteQuery(this.target, templateSrv);
  21. this.buildSegments();
  22. }
  23. this.removeTagValue = '-- remove tag --';
  24. }
  25. parseTarget() {
  26. this.queryModel.parseTarget();
  27. this.buildSegments();
  28. }
  29. toggleEditorMode() {
  30. this.target.textEditor = !this.target.textEditor;
  31. this.parseTarget();
  32. }
  33. buildSegments() {
  34. this.segments = _.map(this.queryModel.segments, segment => {
  35. return this.uiSegmentSrv.newSegment(segment);
  36. });
  37. let checkOtherSegmentsIndex = this.queryModel.checkOtherSegmentsIndex || 0;
  38. this.checkOtherSegments(checkOtherSegmentsIndex);
  39. if (this.queryModel.seriesByTagUsed) {
  40. this.fixTagSegments();
  41. }
  42. }
  43. addSelectMetricSegment() {
  44. this.queryModel.addSelectMetricSegment();
  45. this.segments.push(this.uiSegmentSrv.newSelectMetric());
  46. }
  47. checkOtherSegments(fromIndex) {
  48. if (fromIndex === 0) {
  49. this.addSelectMetricSegment();
  50. return;
  51. }
  52. var path = this.queryModel.getSegmentPathUpTo(fromIndex + 1);
  53. if (path === "") {
  54. return Promise.resolve();
  55. }
  56. return this.datasource.metricFindQuery(path).then(segments => {
  57. if (segments.length === 0) {
  58. if (path !== '') {
  59. this.queryModel.segments = this.queryModel.segments.splice(0, fromIndex);
  60. this.segments = this.segments.splice(0, fromIndex);
  61. this.addSelectMetricSegment();
  62. }
  63. } else if (segments[0].expandable) {
  64. if (this.segments.length === fromIndex) {
  65. this.addSelectMetricSegment();
  66. } else {
  67. return this.checkOtherSegments(fromIndex + 1);
  68. }
  69. }
  70. }).catch(err => {
  71. appEvents.emit('alert-error', ['Error', err]);
  72. });
  73. }
  74. setSegmentFocus(segmentIndex) {
  75. _.each(this.segments, (segment, index) => {
  76. segment.focus = segmentIndex === index;
  77. });
  78. }
  79. getAltSegments(index) {
  80. var query = index === 0 ? '*' : this.queryModel.getSegmentPathUpTo(index) + '.*';
  81. var options = {range: this.panelCtrl.range, requestId: "get-alt-segments"};
  82. return this.datasource.metricFindQuery(query, options).then(segments => {
  83. var altSegments = _.map(segments, segment => {
  84. return this.uiSegmentSrv.newSegment({value: segment.text, expandable: segment.expandable});
  85. });
  86. if (altSegments.length === 0) { return altSegments; }
  87. // add template variables
  88. _.each(this.templateSrv.variables, variable => {
  89. altSegments.unshift(this.uiSegmentSrv.newSegment({
  90. type: 'template',
  91. value: '$' + variable.name,
  92. expandable: true,
  93. }));
  94. });
  95. // add wildcard option
  96. altSegments.unshift(this.uiSegmentSrv.newSegment('*'));
  97. return altSegments;
  98. }).catch(err => {
  99. return [];
  100. });
  101. }
  102. segmentValueChanged(segment, segmentIndex) {
  103. this.error = null;
  104. this.queryModel.updateSegmentValue(segment, segmentIndex);
  105. if (this.queryModel.functions.length > 0 && this.queryModel.functions[0].def.fake) {
  106. this.queryModel.functions = [];
  107. }
  108. if (segment.expandable) {
  109. return this.checkOtherSegments(segmentIndex + 1).then(() => {
  110. this.setSegmentFocus(segmentIndex + 1);
  111. this.targetChanged();
  112. });
  113. } else {
  114. this.spliceSegments(segmentIndex + 1);
  115. }
  116. this.setSegmentFocus(segmentIndex + 1);
  117. this.targetChanged();
  118. }
  119. spliceSegments(index) {
  120. this.segments = this.segments.splice(0, index);
  121. this.queryModel.segments = this.queryModel.segments.splice(0, index);
  122. }
  123. emptySegments() {
  124. this.queryModel.segments = [];
  125. this.segments = [];
  126. }
  127. targetTextChanged() {
  128. this.updateModelTarget();
  129. this.refresh();
  130. }
  131. updateModelTarget() {
  132. this.queryModel.updateModelTarget(this.panelCtrl.panel.targets);
  133. }
  134. targetChanged() {
  135. if (this.queryModel.error) {
  136. return;
  137. }
  138. var oldTarget = this.queryModel.target.target;
  139. this.updateModelTarget();
  140. if (this.queryModel.target !== oldTarget) {
  141. var lastSegment = this.segments.length > 0 ? this.segments[this.segments.length - 1] : {};
  142. if (lastSegment.value !== 'select metric') {
  143. this.panelCtrl.refresh();
  144. }
  145. }
  146. }
  147. addFunction(funcDef) {
  148. var newFunc = gfunc.createFuncInstance(funcDef, { withDefaultParams: true });
  149. newFunc.added = true;
  150. this.queryModel.addFunction(newFunc);
  151. this.smartlyHandleNewAliasByNode(newFunc);
  152. if (this.segments.length === 1 && this.segments[0].fake) {
  153. this.emptySegments();
  154. }
  155. if (!newFunc.params.length && newFunc.added) {
  156. this.targetChanged();
  157. }
  158. if (newFunc.def.name === 'seriesByTag') {
  159. this.parseTarget();
  160. }
  161. }
  162. removeFunction(func) {
  163. this.queryModel.removeFunction(func);
  164. this.targetChanged();
  165. }
  166. smartlyHandleNewAliasByNode(func) {
  167. if (func.def.name !== 'aliasByNode') {
  168. return;
  169. }
  170. for (var i = 0; i < this.segments.length; i++) {
  171. if (this.segments[i].value.indexOf('*') >= 0) {
  172. func.params[0] = i;
  173. func.added = false;
  174. this.targetChanged();
  175. return;
  176. }
  177. }
  178. }
  179. getTags() {
  180. return this.datasource.getTags().then((values) => {
  181. let altTags = _.map(values, 'text');
  182. altTags.splice(0, 0, this.removeTagValue);
  183. return mapToDropdownOptions(altTags);
  184. });
  185. }
  186. getTagsAsSegments() {
  187. return this.datasource.getTags().then((values) => {
  188. return _.map(values, (val) => {
  189. return this.uiSegmentSrv.newSegment(val.text);
  190. });
  191. });
  192. }
  193. getTagOperators() {
  194. return mapToDropdownOptions(GRAPHITE_TAG_OPERATORS);
  195. }
  196. getTagValues(tag) {
  197. let tagKey = tag.key;
  198. return this.datasource.getTagValues(tagKey).then((values) => {
  199. let altValues = _.map(values, 'text');
  200. return mapToDropdownOptions(altValues);
  201. });
  202. }
  203. tagChanged(tag, tagIndex) {
  204. this.queryModel.updateTag(tag, tagIndex);
  205. this.targetChanged();
  206. }
  207. addNewTag(segment) {
  208. let newTagKey = segment.value;
  209. let newTag = {key: newTagKey, operator: '=', value: 'select tag value'};
  210. this.queryModel.addTag(newTag);
  211. this.targetChanged();
  212. this.fixTagSegments();
  213. }
  214. removeTag(index) {
  215. this.queryModel.removeTag(index);
  216. this.targetChanged();
  217. }
  218. fixTagSegments() {
  219. // Adding tag with the same name as just removed works incorrectly if single segment is used (instead of array)
  220. this.addTagSegments = [this.uiSegmentSrv.newPlusButton()];
  221. }
  222. showDelimiter(index) {
  223. return index !== this.queryModel.tags.length - 1;
  224. }
  225. }
  226. function mapToDropdownOptions(results) {
  227. return _.map(results, (value) => {
  228. return {text: value, value: value};
  229. });
  230. }