diff --git a/public/app/plugins/datasource/graphite/add_graphite_func.js b/public/app/plugins/datasource/graphite/add_graphite_func.js
deleted file mode 100644
index 1d72c2c11eb..00000000000
--- a/public/app/plugins/datasource/graphite/add_graphite_func.js
+++ /dev/null
@@ -1,155 +0,0 @@
-define(['angular', 'lodash', 'jquery', 'rst2html', 'tether-drop'], function(angular, _, $, rst2html, Drop) {
- 'use strict';
-
- angular.module('grafana.directives').directive('graphiteAddFunc', function($compile) {
- var inputTemplate =
- '';
-
- var buttonTemplate =
- '' +
- '';
-
- return {
- link: function($scope, elem) {
- var ctrl = $scope.ctrl;
-
- var $input = $(inputTemplate);
- var $button = $(buttonTemplate);
-
- $input.appendTo(elem);
- $button.appendTo(elem);
-
- ctrl.datasource.getFuncDefs().then(function(funcDefs) {
- var allFunctions = _.map(funcDefs, 'name').sort();
-
- $scope.functionMenu = createFunctionDropDownMenu(funcDefs);
-
- $input.attr('data-provide', 'typeahead');
- $input.typeahead({
- source: allFunctions,
- minLength: 1,
- items: 10,
- updater: function(value) {
- var funcDef = ctrl.datasource.getFuncDef(value);
- if (!funcDef) {
- // try find close match
- value = value.toLowerCase();
- funcDef = _.find(allFunctions, function(funcName) {
- return funcName.toLowerCase().indexOf(value) === 0;
- });
-
- if (!funcDef) {
- return;
- }
- }
-
- $scope.$apply(function() {
- ctrl.addFunction(funcDef);
- });
-
- $input.trigger('blur');
- return '';
- },
- });
-
- $button.click(function() {
- $button.hide();
- $input.show();
- $input.focus();
- });
-
- $input.keyup(function() {
- elem.toggleClass('open', $input.val() === '');
- });
-
- $input.blur(function() {
- // clicking the function dropdown menu wont
- // work if you remove class at once
- setTimeout(function() {
- $input.val('');
- $input.hide();
- $button.show();
- elem.removeClass('open');
- }, 200);
- });
-
- $compile(elem.contents())($scope);
- });
-
- var drop;
- var cleanUpDrop = function() {
- if (drop) {
- drop.destroy();
- drop = null;
- }
- };
-
- $(elem)
- .on('mouseenter', 'ul.dropdown-menu li', function() {
- cleanUpDrop();
-
- var funcDef;
- try {
- funcDef = ctrl.datasource.getFuncDef($('a', this).text());
- } catch (e) {
- // ignore
- }
-
- if (funcDef && funcDef.description) {
- var shortDesc = funcDef.description;
- if (shortDesc.length > 500) {
- shortDesc = shortDesc.substring(0, 497) + '...';
- }
-
- var contentElement = document.createElement('div');
- contentElement.innerHTML = '
' + funcDef.name + '
' + rst2html(shortDesc);
-
- drop = new Drop({
- target: this,
- content: contentElement,
- classes: 'drop-popover',
- openOn: 'always',
- tetherOptions: {
- attachment: 'bottom left',
- targetAttachment: 'bottom right',
- },
- });
- }
- })
- .on('mouseout', 'ul.dropdown-menu li', function() {
- cleanUpDrop();
- });
-
- $scope.$on('$destroy', cleanUpDrop);
- },
- };
- });
-
- function createFunctionDropDownMenu(funcDefs) {
- var categories = {};
-
- _.forEach(funcDefs, function(funcDef) {
- if (!funcDef.category) {
- return;
- }
- if (!categories[funcDef.category]) {
- categories[funcDef.category] = [];
- }
- categories[funcDef.category].push({
- text: funcDef.name,
- click: "ctrl.addFunction('" + funcDef.name + "')",
- });
- });
-
- return _.sortBy(
- _.map(categories, function(submenu, category) {
- return {
- text: category,
- submenu: _.sortBy(submenu, 'text'),
- };
- }),
- 'text'
- );
- }
-});
diff --git a/public/app/plugins/datasource/graphite/add_graphite_func.ts b/public/app/plugins/datasource/graphite/add_graphite_func.ts
new file mode 100644
index 00000000000..f2a596c7071
--- /dev/null
+++ b/public/app/plugins/datasource/graphite/add_graphite_func.ts
@@ -0,0 +1,159 @@
+import angular from 'angular';
+import _ from 'lodash';
+import $ from 'jquery';
+import rst2html from 'rst2html';
+import Drop from 'tether-drop';
+
+export function graphiteAddFunc($compile) {
+ const inputTemplate =
+ '';
+
+ const buttonTemplate =
+ '' +
+ '';
+
+ return {
+ link: function($scope, elem) {
+ var ctrl = $scope.ctrl;
+
+ var $input = $(inputTemplate);
+ var $button = $(buttonTemplate);
+
+ $input.appendTo(elem);
+ $button.appendTo(elem);
+
+ ctrl.datasource.getFuncDefs().then(function(funcDefs) {
+ var allFunctions = _.map(funcDefs, 'name').sort();
+
+ $scope.functionMenu = createFunctionDropDownMenu(funcDefs);
+
+ $input.attr('data-provide', 'typeahead');
+ $input.typeahead({
+ source: allFunctions,
+ minLength: 1,
+ items: 10,
+ updater: function(value) {
+ var funcDef = ctrl.datasource.getFuncDef(value);
+ if (!funcDef) {
+ // try find close match
+ value = value.toLowerCase();
+ funcDef = _.find(allFunctions, function(funcName) {
+ return funcName.toLowerCase().indexOf(value) === 0;
+ });
+
+ if (!funcDef) {
+ return '';
+ }
+ }
+
+ $scope.$apply(function() {
+ ctrl.addFunction(funcDef);
+ });
+
+ $input.trigger('blur');
+ return '';
+ },
+ });
+
+ $button.click(function() {
+ $button.hide();
+ $input.show();
+ $input.focus();
+ });
+
+ $input.keyup(function() {
+ elem.toggleClass('open', $input.val() === '');
+ });
+
+ $input.blur(function() {
+ // clicking the function dropdown menu wont
+ // work if you remove class at once
+ setTimeout(function() {
+ $input.val('');
+ $input.hide();
+ $button.show();
+ elem.removeClass('open');
+ }, 200);
+ });
+
+ $compile(elem.contents())($scope);
+ });
+
+ var drop;
+ var cleanUpDrop = function() {
+ if (drop) {
+ drop.destroy();
+ drop = null;
+ }
+ };
+
+ $(elem)
+ .on('mouseenter', 'ul.dropdown-menu li', function() {
+ cleanUpDrop();
+
+ var funcDef;
+ try {
+ funcDef = ctrl.datasource.getFuncDef($('a', this).text());
+ } catch (e) {
+ // ignore
+ }
+
+ if (funcDef && funcDef.description) {
+ var shortDesc = funcDef.description;
+ if (shortDesc.length > 500) {
+ shortDesc = shortDesc.substring(0, 497) + '...';
+ }
+
+ var contentElement = document.createElement('div');
+ contentElement.innerHTML = '' + funcDef.name + '
' + rst2html(shortDesc);
+
+ drop = new Drop({
+ target: this,
+ content: contentElement,
+ classes: 'drop-popover',
+ openOn: 'always',
+ tetherOptions: {
+ attachment: 'bottom left',
+ targetAttachment: 'bottom right',
+ },
+ });
+ }
+ })
+ .on('mouseout', 'ul.dropdown-menu li', function() {
+ cleanUpDrop();
+ });
+
+ $scope.$on('$destroy', cleanUpDrop);
+ },
+ };
+}
+
+angular.module('grafana.directives').directive('graphiteAddFunc', graphiteAddFunc);
+
+function createFunctionDropDownMenu(funcDefs) {
+ var categories = {};
+
+ _.forEach(funcDefs, function(funcDef) {
+ if (!funcDef.category) {
+ return;
+ }
+ if (!categories[funcDef.category]) {
+ categories[funcDef.category] = [];
+ }
+ categories[funcDef.category].push({
+ text: funcDef.name,
+ click: "ctrl.addFunction('" + funcDef.name + "')",
+ });
+ });
+
+ return _.sortBy(
+ _.map(categories, function(submenu, category) {
+ return {
+ text: category,
+ submenu: _.sortBy(submenu, 'text'),
+ };
+ }),
+ 'text'
+ );
+}