add_graphite_func.ts 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. import angular from 'angular';
  2. import _ from 'lodash';
  3. import $ from 'jquery';
  4. import rst2html from 'rst2html';
  5. import Drop from 'tether-drop';
  6. export function graphiteAddFunc($compile) {
  7. const inputTemplate =
  8. '<input type="text"' + ' class="gf-form-input"' + ' spellcheck="false" style="display:none"></input>';
  9. const buttonTemplate =
  10. '<a class="gf-form-label query-part dropdown-toggle"' +
  11. ' tabindex="1" gf-dropdown="functionMenu" data-toggle="dropdown">' +
  12. '<i class="fa fa-plus"></i></a>';
  13. return {
  14. link: function($scope, elem) {
  15. var ctrl = $scope.ctrl;
  16. var $input = $(inputTemplate);
  17. var $button = $(buttonTemplate);
  18. $input.appendTo(elem);
  19. $button.appendTo(elem);
  20. ctrl.datasource.getFuncDefs().then(function(funcDefs) {
  21. var allFunctions = _.map(funcDefs, 'name').sort();
  22. $scope.functionMenu = createFunctionDropDownMenu(funcDefs);
  23. $input.attr('data-provide', 'typeahead');
  24. $input.typeahead({
  25. source: allFunctions,
  26. minLength: 1,
  27. items: 10,
  28. updater: function(value) {
  29. var funcDef = ctrl.datasource.getFuncDef(value);
  30. if (!funcDef) {
  31. // try find close match
  32. value = value.toLowerCase();
  33. funcDef = _.find(allFunctions, function(funcName) {
  34. return funcName.toLowerCase().indexOf(value) === 0;
  35. });
  36. if (!funcDef) {
  37. return '';
  38. }
  39. }
  40. $scope.$apply(function() {
  41. ctrl.addFunction(funcDef);
  42. });
  43. $input.trigger('blur');
  44. return '';
  45. },
  46. });
  47. $button.click(function() {
  48. $button.hide();
  49. $input.show();
  50. $input.focus();
  51. });
  52. $input.keyup(function() {
  53. elem.toggleClass('open', $input.val() === '');
  54. });
  55. $input.blur(function() {
  56. // clicking the function dropdown menu wont
  57. // work if you remove class at once
  58. setTimeout(function() {
  59. $input.val('');
  60. $input.hide();
  61. $button.show();
  62. elem.removeClass('open');
  63. }, 200);
  64. });
  65. $compile(elem.contents())($scope);
  66. });
  67. var drop;
  68. var cleanUpDrop = function() {
  69. if (drop) {
  70. drop.destroy();
  71. drop = null;
  72. }
  73. };
  74. $(elem)
  75. .on('mouseenter', 'ul.dropdown-menu li', function() {
  76. cleanUpDrop();
  77. var funcDef;
  78. try {
  79. funcDef = ctrl.datasource.getFuncDef($('a', this).text());
  80. } catch (e) {
  81. // ignore
  82. }
  83. if (funcDef && funcDef.description) {
  84. var shortDesc = funcDef.description;
  85. if (shortDesc.length > 500) {
  86. shortDesc = shortDesc.substring(0, 497) + '...';
  87. }
  88. var contentElement = document.createElement('div');
  89. contentElement.innerHTML = '<h4>' + funcDef.name + '</h4>' + rst2html(shortDesc);
  90. drop = new Drop({
  91. target: this,
  92. content: contentElement,
  93. classes: 'drop-popover',
  94. openOn: 'always',
  95. tetherOptions: {
  96. attachment: 'bottom left',
  97. targetAttachment: 'bottom right',
  98. },
  99. });
  100. }
  101. })
  102. .on('mouseout', 'ul.dropdown-menu li', function() {
  103. cleanUpDrop();
  104. });
  105. $scope.$on('$destroy', cleanUpDrop);
  106. },
  107. };
  108. }
  109. angular.module('grafana.directives').directive('graphiteAddFunc', graphiteAddFunc);
  110. function createFunctionDropDownMenu(funcDefs) {
  111. var categories = {};
  112. _.forEach(funcDefs, function(funcDef) {
  113. if (!funcDef.category) {
  114. return;
  115. }
  116. if (!categories[funcDef.category]) {
  117. categories[funcDef.category] = [];
  118. }
  119. categories[funcDef.category].push({
  120. text: funcDef.name,
  121. click: "ctrl.addFunction('" + funcDef.name + "')",
  122. });
  123. });
  124. return _.sortBy(
  125. _.map(categories, function(submenu, category) {
  126. return {
  127. text: category,
  128. submenu: _.sortBy(submenu, 'text'),
  129. };
  130. }),
  131. 'text'
  132. );
  133. }