query_ctrl.ts 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. import { auto } from 'angular';
  2. import { map, size, has } from 'lodash';
  3. import { textUtil, rangeUtil } from '@grafana/data';
  4. import { QueryCtrl } from 'app/plugins/sdk';
  5. export class OpenTsQueryCtrl extends QueryCtrl {
  6. static templateUrl = 'partials/query.editor.html';
  7. aggregators: any;
  8. fillPolicies: any;
  9. filterTypes: any;
  10. tsdbVersion: any;
  11. aggregator: any;
  12. downsampleInterval: any;
  13. downsampleAggregator: any;
  14. downsampleFillPolicy: any;
  15. errors: any;
  16. suggestMetrics: any;
  17. suggestTagKeys: any;
  18. suggestTagValues: any;
  19. addTagMode = false;
  20. addFilterMode = false;
  21. /** @ngInject */
  22. constructor($scope: any, $injector: auto.IInjectorService) {
  23. super($scope, $injector);
  24. this.errors = this.validateTarget();
  25. this.aggregators = ['avg', 'sum', 'min', 'max', 'dev', 'zimsum', 'mimmin', 'mimmax'];
  26. this.fillPolicies = ['none', 'nan', 'null', 'zero'];
  27. this.filterTypes = [
  28. 'wildcard',
  29. 'iliteral_or',
  30. 'not_iliteral_or',
  31. 'not_literal_or',
  32. 'iwildcard',
  33. 'literal_or',
  34. 'regexp',
  35. ];
  36. this.tsdbVersion = this.datasource.tsdbVersion;
  37. if (!this.target.aggregator) {
  38. this.target.aggregator = 'sum';
  39. }
  40. if (!this.target.downsampleAggregator) {
  41. this.target.downsampleAggregator = 'avg';
  42. }
  43. if (!this.target.downsampleFillPolicy) {
  44. this.target.downsampleFillPolicy = 'none';
  45. }
  46. this.datasource.getAggregators().then((aggs: { length: number }) => {
  47. if (aggs.length !== 0) {
  48. this.aggregators = aggs;
  49. }
  50. });
  51. this.datasource.getFilterTypes().then((filterTypes: { length: number }) => {
  52. if (filterTypes.length !== 0) {
  53. this.filterTypes = filterTypes;
  54. }
  55. });
  56. // needs to be defined here as it is called from typeahead
  57. this.suggestMetrics = (query: string, callback: any) => {
  58. this.datasource
  59. .metricFindQuery('metrics(' + query + ')')
  60. .then(this.getTextValues)
  61. .then(callback);
  62. };
  63. this.suggestTagKeys = (query: any, callback: any) => {
  64. this.datasource.suggestTagKeys(this.target.metric).then(callback);
  65. };
  66. this.suggestTagValues = (query: string, callback: any) => {
  67. this.datasource
  68. .metricFindQuery('suggest_tagv(' + query + ')')
  69. .then(this.getTextValues)
  70. .then(callback);
  71. };
  72. }
  73. targetBlur() {
  74. this.errors = this.validateTarget();
  75. this.refresh();
  76. }
  77. getTextValues(metricFindResult: any) {
  78. return map(metricFindResult, (value) => {
  79. return textUtil.escapeHtml(value.text);
  80. });
  81. }
  82. addTag() {
  83. if (this.target.filters && this.target.filters.length > 0) {
  84. this.errors.tags = 'Please remove filters to use tags, tags and filters are mutually exclusive.';
  85. }
  86. if (!this.addTagMode) {
  87. this.addTagMode = true;
  88. return;
  89. }
  90. if (!this.target.tags) {
  91. this.target.tags = {};
  92. }
  93. this.errors = this.validateTarget();
  94. if (!this.errors.tags) {
  95. this.target.tags[this.target.currentTagKey] = this.target.currentTagValue;
  96. this.target.currentTagKey = '';
  97. this.target.currentTagValue = '';
  98. this.targetBlur();
  99. }
  100. this.addTagMode = false;
  101. }
  102. removeTag(key: string | number) {
  103. delete this.target.tags[key];
  104. this.targetBlur();
  105. }
  106. editTag(key: string | number, value: any) {
  107. this.removeTag(key);
  108. this.target.currentTagKey = key;
  109. this.target.currentTagValue = value;
  110. this.addTag();
  111. }
  112. closeAddTagMode() {
  113. this.addTagMode = false;
  114. return;
  115. }
  116. addFilter() {
  117. if (this.target.tags && size(this.target.tags) > 0) {
  118. this.errors.filters = 'Please remove tags to use filters, tags and filters are mutually exclusive.';
  119. }
  120. if (!this.addFilterMode) {
  121. this.addFilterMode = true;
  122. return;
  123. }
  124. if (!this.target.filters) {
  125. this.target.filters = [];
  126. }
  127. if (!this.target.currentFilterType) {
  128. this.target.currentFilterType = 'iliteral_or';
  129. }
  130. if (!this.target.currentFilterGroupBy) {
  131. this.target.currentFilterGroupBy = false;
  132. }
  133. this.errors = this.validateTarget();
  134. if (!this.errors.filters) {
  135. const currentFilter = {
  136. type: this.target.currentFilterType,
  137. tagk: this.target.currentFilterKey,
  138. filter: this.target.currentFilterValue,
  139. groupBy: this.target.currentFilterGroupBy,
  140. };
  141. this.target.filters.push(currentFilter);
  142. this.target.currentFilterType = 'literal_or';
  143. this.target.currentFilterKey = '';
  144. this.target.currentFilterValue = '';
  145. this.target.currentFilterGroupBy = false;
  146. this.targetBlur();
  147. }
  148. this.addFilterMode = false;
  149. }
  150. removeFilter(index: number) {
  151. this.target.filters.splice(index, 1);
  152. this.targetBlur();
  153. }
  154. editFilter(fil: { tagk: any; filter: any; type: any; groupBy: any }, index: number) {
  155. this.removeFilter(index);
  156. this.target.currentFilterKey = fil.tagk;
  157. this.target.currentFilterValue = fil.filter;
  158. this.target.currentFilterType = fil.type;
  159. this.target.currentFilterGroupBy = fil.groupBy;
  160. this.addFilter();
  161. }
  162. closeAddFilterMode() {
  163. this.addFilterMode = false;
  164. return;
  165. }
  166. validateTarget() {
  167. const errs: any = {};
  168. if (this.target.shouldDownsample) {
  169. try {
  170. if (this.target.downsampleInterval) {
  171. rangeUtil.describeInterval(this.target.downsampleInterval);
  172. } else {
  173. errs.downsampleInterval = "You must supply a downsample interval (e.g. '1m' or '1h').";
  174. }
  175. } catch (err) {
  176. errs.downsampleInterval = err.message;
  177. }
  178. }
  179. if (this.target.tags && has(this.target.tags, this.target.currentTagKey)) {
  180. errs.tags = "Duplicate tag key '" + this.target.currentTagKey + "'.";
  181. }
  182. return errs;
  183. }
  184. }