';
- elem.replaceWith($compile(angular.element(template))(scope));
- }
- };
- });
-
- coreModule.default.directive('editorCheckbox', function($compile, $interpolate) {
- return {
- restrict: 'E',
- link: function(scope, elem, attrs) {
- var text = $interpolate(attrs.text)(scope);
- var model = $interpolate(attrs.model)(scope);
- var ngchange = attrs.change ? (' ng-change="' + attrs.change + '"') : '';
- var tip = attrs.tip ? ('
';
-
- template = template + label;
- elem.addClass('gf-form-checkbox');
- elem.html($compile(angular.element(template))(scope));
- }
- };
- });
-
- coreModule.default.directive('gfDropdown', function ($parse, $compile, $timeout) {
- function buildTemplate(items, placement) {
- var upclass = placement === 'top' ? 'dropup' : '';
- var ul = [
- ''
- ];
-
- angular.forEach(items, function (item, index) {
- if (item.divider) {
- return ul.splice(index + 1, 0, '
');
- }
-
- var li = '';
- ul.splice(index + 1, 0, li);
- });
- return ul;
- }
-
- return {
- restrict: 'EA',
- scope: true,
- link: function postLink(scope, iElement, iAttrs) {
- var getter = $parse(iAttrs.gfDropdown), items = getter(scope);
- $timeout(function () {
- var placement = iElement.data('placement');
- var dropdown = angular.element(buildTemplate(items, placement).join(''));
- dropdown.insertAfter(iElement);
- $compile(iElement.next('ul.dropdown-menu'))(scope);
- });
-
- iElement.addClass('dropdown-toggle').attr('data-toggle', 'dropdown');
- }
- };
- });
-
-});
diff --git a/public/app/core/directives/misc.ts b/public/app/core/directives/misc.ts
new file mode 100644
index 00000000000..3ec5add0c35
--- /dev/null
+++ b/public/app/core/directives/misc.ts
@@ -0,0 +1,226 @@
+import angular from "angular";
+import Clipboard from "clipboard";
+import coreModule from "../core_module";
+import kbn from "app/core/utils/kbn";
+
+/** @ngInject */
+function tip($compile) {
+ return {
+ restrict: "E",
+ link: function(scope, elem, attrs) {
+ var _t =
+ '
";
+ _t = _t.replace(/{/g, "\\{").replace(/}/g, "\\}");
+ elem.replaceWith($compile(angular.element(_t))(scope));
+ }
+ };
+}
+
+function clipboardButton() {
+ return {
+ scope: {
+ getText: "&clipboardButton"
+ },
+ link: function(scope, elem) {
+ scope.clipboard = new Clipboard(elem[0], {
+ text: function() {
+ return scope.getText();
+ }
+ });
+
+ scope.$on("$destroy", function() {
+ if (scope.clipboard) {
+ scope.clipboard.destroy();
+ }
+ });
+ }
+ };
+}
+
+/** @ngInject */
+function compile($compile) {
+ return {
+ restrict: "A",
+ link: function(scope, element, attrs) {
+ scope.$watch(
+ function(scope) {
+ return scope.$eval(attrs.compile);
+ },
+ function(value) {
+ element.html(value);
+ $compile(element.contents())(scope);
+ }
+ );
+ }
+ };
+}
+
+function watchChange() {
+ return {
+ scope: { onchange: "&watchChange" },
+ link: function(scope, element) {
+ element.on("input", function() {
+ scope.$apply(function() {
+ scope.onchange({ inputValue: element.val() });
+ });
+ });
+ }
+ };
+}
+
+/** @ngInject */
+function editorOptBool($compile) {
+ return {
+ restrict: "E",
+ link: function(scope, elem, attrs) {
+ var ngchange = attrs.change ? ' ng-change="' + attrs.change + '"' : "";
+ var tip = attrs.tip ? "
" : "";
+ var showIf = attrs.showIf ? ' ng-show="' + attrs.showIf + '" ' : "";
+
+ var template =
+ '
" +
+ '
" +
+ '
' +
+ '
';
+ elem.replaceWith($compile(angular.element(template))(scope));
+ }
+ };
+}
+
+/** @ngInject */
+function editorCheckbox($compile, $interpolate) {
+ return {
+ restrict: "E",
+ link: function(scope, elem, attrs) {
+ var text = $interpolate(attrs.text)(scope);
+ var model = $interpolate(attrs.model)(scope);
+ var ngchange = attrs.change ? ' ng-change="' + attrs.change + '"' : "";
+ var tip = attrs.tip ? "
" + attrs.tip + "" : "";
+ var label =
+ '
";
+
+ var template =
+ '
' +
+ '
';
+
+ template = template + label;
+ elem.addClass("gf-form-checkbox");
+ elem.html($compile(angular.element(template))(scope));
+ }
+ };
+}
+
+/** @ngInject */
+function gfDropdown($parse, $compile, $timeout) {
+ function buildTemplate(items, placement?) {
+ var upclass = placement === "top" ? "dropup" : "";
+ var ul = [
+ '"
+ ];
+
+ for (let index = 0; index < items.length; index++) {
+ let item = items[index];
+
+ if (item.divider) {
+ ul.splice(index + 1, 0, '
');
+ continue;
+ }
+
+ var li =
+ "";
+ ul.splice(index + 1, 0, li);
+ }
+
+ return ul;
+ }
+
+ return {
+ restrict: "EA",
+ scope: true,
+ link: function postLink(scope, iElement, iAttrs) {
+ var getter = $parse(iAttrs.gfDropdown),
+ items = getter(scope);
+ $timeout(function() {
+ var placement = iElement.data("placement");
+ var dropdown = angular.element(
+ buildTemplate(items, placement).join("")
+ );
+ dropdown.insertAfter(iElement);
+ $compile(iElement.next("ul.dropdown-menu"))(scope);
+ });
+
+ iElement.addClass("dropdown-toggle").attr("data-toggle", "dropdown");
+ }
+ };
+}
+
+coreModule.directive("tip", tip);
+coreModule.directive("clipboardButton", clipboardButton);
+coreModule.directive("compile", compile);
+coreModule.directive("watchChange", watchChange);
+coreModule.directive("editorOptBool", editorOptBool);
+coreModule.directive("editorCheckbox", editorCheckbox);
+coreModule.directive("gfDropdown", gfDropdown);
diff --git a/public/app/core/directives/ng_model_on_blur.ts b/public/app/core/directives/ng_model_on_blur.ts
index 383d04e3961..2f7de3bf20c 100644
--- a/public/app/core/directives/ng_model_on_blur.ts
+++ b/public/app/core/directives/ng_model_on_blur.ts
@@ -1,64 +1,57 @@
import coreModule from '../core_module';
import * as rangeUtil from 'app/core/utils/rangeutil';
-export class NgModelOnBlur {
- constructor() {
- return {
- restrict: 'A',
- priority: 1,
- require: 'ngModel',
- link: function(scope, elm, attr, ngModelCtrl) {
- if (attr.type === 'radio' || attr.type === 'checkbox') {
- return;
+function ngModelOnBlur() {
+ return {
+ restrict: 'A',
+ priority: 1,
+ require: 'ngModel',
+ link: function(scope, elm, attr, ngModelCtrl) {
+ if (attr.type === 'radio' || attr.type === 'checkbox') {
+ return;
+ }
+
+ elm.off('input keydown change');
+ elm.bind('blur', function() {
+ scope.$apply(function() {
+ ngModelCtrl.$setViewValue(elm.val());
+ });
+ });
+ }
+ };
+}
+
+function emptyToNull() {
+ return {
+ restrict: 'A',
+ require: 'ngModel',
+ link: function (scope, elm, attrs, ctrl) {
+ ctrl.$parsers.push(function (viewValue) {
+ if (viewValue === "") { return null; }
+ return viewValue;
+ });
+ }
+ };
+}
+
+function validTimeSpan() {
+ return {
+ require: 'ngModel',
+ link: function(scope, elm, attrs, ctrl) {
+ ctrl.$validators.integer = function(modelValue, viewValue) {
+ if (ctrl.$isEmpty(modelValue)) {
+ return true;
}
-
- elm.off('input keydown change');
- elm.bind('blur', function() {
- scope.$apply(function() {
- ngModelCtrl.$setViewValue(elm.val());
- });
- });
- }
- };
- }
+ if (viewValue.indexOf('$') === 0 || viewValue.indexOf('+$') === 0) {
+ return true; // allow template variable
+ }
+ var info = rangeUtil.describeTextRange(viewValue);
+ return info.invalid !== true;
+ };
+ }
+ };
}
-
-export class EmptyToNull {
- constructor() {
- return {
- restrict: 'A',
- require: 'ngModel',
- link: function (scope, elm, attrs, ctrl) {
- ctrl.$parsers.push(function (viewValue) {
- if (viewValue === "") { return null; }
- return viewValue;
- });
- }
- };
- }
-}
-
-export class ValidTimeSpan {
- constructor() {
- return {
- require: 'ngModel',
- link: function(scope, elm, attrs, ctrl) {
- ctrl.$validators.integer = function(modelValue, viewValue) {
- if (ctrl.$isEmpty(modelValue)) {
- return true;
- }
- if (viewValue.indexOf('$') === 0 || viewValue.indexOf('+$') === 0) {
- return true; // allow template variable
- }
- var info = rangeUtil.describeTextRange(viewValue);
- return info.invalid !== true;
- };
- }
- };
- }
-}
-
-coreModule.directive('ngModelOnblur', NgModelOnBlur);
-coreModule.directive('emptyToNull', EmptyToNull);
-coreModule.directive('validTimeSpan', ValidTimeSpan);
+coreModule.directive('ngModelOnblur', ngModelOnBlur);
+coreModule.directive('emptyToNull', emptyToNull);
+coreModule.directive('validTimeSpan', validTimeSpan);
diff --git a/public/app/core/directives/tags.js b/public/app/core/directives/tags.js
deleted file mode 100644
index a322673a342..00000000000
--- a/public/app/core/directives/tags.js
+++ /dev/null
@@ -1,135 +0,0 @@
-define([
- 'angular',
- 'jquery',
- '../core_module',
- 'vendor/tagsinput/bootstrap-tagsinput.js',
-],
-function (angular, $, coreModule) {
- 'use strict';
-
- function djb2(str) {
- var hash = 5381;
- for (var i = 0; i < str.length; i++) {
- hash = ((hash << 5) + hash) + str.charCodeAt(i); /* hash * 33 + c */
- }
- return hash;
- }
-
- function setColor(name, element) {
- var hash = djb2(name.toLowerCase());
- var colors = [
- "#E24D42","#1F78C1","#BA43A9","#705DA0","#466803",
- "#508642","#447EBC","#C15C17","#890F02","#757575",
- "#0A437C","#6D1F62","#584477","#629E51","#2F4F4F",
- "#BF1B00","#806EB7","#8a2eb8", "#699e00","#000000",
- "#3F6833","#2F575E","#99440A","#E0752D","#0E4AB4",
- "#58140C","#052B51","#511749","#3F2B5B",
- ];
- var borderColors = [
- "#FF7368","#459EE7","#E069CF","#9683C6","#6C8E29",
- "#76AC68","#6AA4E2","#E7823D","#AF3528","#9B9B9B",
- "#3069A2","#934588","#7E6A9D","#88C477","#557575",
- "#E54126","#A694DD","#B054DE", "#8FC426","#262626",
- "#658E59","#557D84","#BF6A30","#FF9B53","#3470DA",
- "#7E3A32","#2B5177","#773D6F","#655181",
- ];
- var color = colors[Math.abs(hash % colors.length)];
- var borderColor = borderColors[Math.abs(hash % borderColors.length)];
- element.css("background-color", color);
- element.css("border-color", borderColor);
- }
-
- coreModule.default.directive('tagColorFromName', function() {
- return {
- scope: { tagColorFromName: "=" },
- link: function (scope, element) {
- setColor(scope.tagColorFromName, element);
- }
- };
- });
-
- coreModule.default.directive('bootstrapTagsinput', function() {
-
- function getItemProperty(scope, property) {
- if (!property) {
- return undefined;
- }
-
- if (angular.isFunction(scope.$parent[property])) {
- return scope.$parent[property];
- }
-
- return function(item) {
- return item[property];
- };
- }
-
- return {
- restrict: 'EA',
- scope: {
- model: '=ngModel',
- onTagsUpdated: "&",
- },
- template: '
',
- replace: false,
- link: function(scope, element, attrs) {
-
- if (!angular.isArray(scope.model)) {
- scope.model = [];
- }
-
- var select = $('select', element);
-
- if (attrs.placeholder) {
- select.attr('placeholder', attrs.placeholder);
- }
-
- select.tagsinput({
- typeahead: {
- source: angular.isFunction(scope.$parent[attrs.typeaheadSource]) ? scope.$parent[attrs.typeaheadSource] : null
- },
- widthClass: attrs.widthClass,
- itemValue: getItemProperty(scope, attrs.itemvalue),
- itemText : getItemProperty(scope, attrs.itemtext),
- tagClass : angular.isFunction(scope.$parent[attrs.tagclass]) ?
- scope.$parent[attrs.tagclass] : function() { return attrs.tagclass; }
- });
-
- select.on('itemAdded', function(event) {
- if (scope.model.indexOf(event.item) === -1) {
- scope.model.push(event.item);
- if (scope.onTagsUpdated) {
- scope.onTagsUpdated();
- }
- }
- var tagElement = select.next().children("span").filter(function() { return $(this).text() === event.item; });
- setColor(event.item, tagElement);
- });
-
- select.on('itemRemoved', function(event) {
- var idx = scope.model.indexOf(event.item);
- if (idx !== -1) {
- scope.model.splice(idx, 1);
- if (scope.onTagsUpdated) {
- scope.onTagsUpdated();
- }
- }
- });
-
- scope.$watch("model", function() {
- if (!angular.isArray(scope.model)) {
- scope.model = [];
- }
-
- select.tagsinput('removeAll');
-
- for (var i = 0; i < scope.model.length; i++) {
- select.tagsinput('add', scope.model[i]);
- }
-
- }, true);
- }
- };
- });
-
-});
diff --git a/public/app/core/directives/tags.ts b/public/app/core/directives/tags.ts
new file mode 100644
index 00000000000..0f4d0990d47
--- /dev/null
+++ b/public/app/core/directives/tags.ts
@@ -0,0 +1,131 @@
+import angular from 'angular';
+import $ from 'jquery';
+import coreModule from '../core_module';
+import 'vendor/tagsinput/bootstrap-tagsinput.js';
+
+function djb2(str) {
+ var hash = 5381;
+ for (var i = 0; i < str.length; i++) {
+ hash = ((hash << 5) + hash) + str.charCodeAt(i); /* hash * 33 + c */
+ }
+ return hash;
+}
+
+function setColor(name, element) {
+ var hash = djb2(name.toLowerCase());
+ var colors = [
+ "#E24D42","#1F78C1","#BA43A9","#705DA0","#466803",
+ "#508642","#447EBC","#C15C17","#890F02","#757575",
+ "#0A437C","#6D1F62","#584477","#629E51","#2F4F4F",
+ "#BF1B00","#806EB7","#8a2eb8", "#699e00","#000000",
+ "#3F6833","#2F575E","#99440A","#E0752D","#0E4AB4",
+ "#58140C","#052B51","#511749","#3F2B5B",
+ ];
+ var borderColors = [
+ "#FF7368","#459EE7","#E069CF","#9683C6","#6C8E29",
+ "#76AC68","#6AA4E2","#E7823D","#AF3528","#9B9B9B",
+ "#3069A2","#934588","#7E6A9D","#88C477","#557575",
+ "#E54126","#A694DD","#B054DE", "#8FC426","#262626",
+ "#658E59","#557D84","#BF6A30","#FF9B53","#3470DA",
+ "#7E3A32","#2B5177","#773D6F","#655181",
+ ];
+ var color = colors[Math.abs(hash % colors.length)];
+ var borderColor = borderColors[Math.abs(hash % borderColors.length)];
+ element.css("background-color", color);
+ element.css("border-color", borderColor);
+}
+
+function tagColorFromName() {
+ return {
+ scope: { tagColorFromName: "=" },
+ link: function (scope, element) {
+ setColor(scope.tagColorFromName, element);
+ }
+ };
+}
+
+function bootstrapTagsinput() {
+ function getItemProperty(scope, property) {
+ if (!property) {
+ return undefined;
+ }
+
+ if (angular.isFunction(scope.$parent[property])) {
+ return scope.$parent[property];
+ }
+
+ return function(item) {
+ return item[property];
+ };
+ }
+
+ return {
+ restrict: 'EA',
+ scope: {
+ model: '=ngModel',
+ onTagsUpdated: "&",
+ },
+ template: '
',
+ replace: false,
+ link: function(scope, element, attrs) {
+
+ if (!angular.isArray(scope.model)) {
+ scope.model = [];
+ }
+
+ var select = $('select', element);
+
+ if (attrs.placeholder) {
+ select.attr('placeholder', attrs.placeholder);
+ }
+
+ select.tagsinput({
+ typeahead: {
+ source: angular.isFunction(scope.$parent[attrs.typeaheadSource]) ? scope.$parent[attrs.typeaheadSource] : null
+ },
+ widthClass: attrs.widthClass,
+ itemValue: getItemProperty(scope, attrs.itemvalue),
+ itemText : getItemProperty(scope, attrs.itemtext),
+ tagClass : angular.isFunction(scope.$parent[attrs.tagclass]) ?
+ scope.$parent[attrs.tagclass] : function() { return attrs.tagclass; }
+ });
+
+ select.on('itemAdded', function(event) {
+ if (scope.model.indexOf(event.item) === -1) {
+ scope.model.push(event.item);
+ if (scope.onTagsUpdated) {
+ scope.onTagsUpdated();
+ }
+ }
+ var tagElement = select.next().children("span").filter(function() { return $(this).text() === event.item; });
+ setColor(event.item, tagElement);
+ });
+
+ select.on('itemRemoved', function(event) {
+ var idx = scope.model.indexOf(event.item);
+ if (idx !== -1) {
+ scope.model.splice(idx, 1);
+ if (scope.onTagsUpdated) {
+ scope.onTagsUpdated();
+ }
+ }
+ });
+
+ scope.$watch("model", function() {
+ if (!angular.isArray(scope.model)) {
+ scope.model = [];
+ }
+
+ select.tagsinput('removeAll');
+
+ for (var i = 0; i < scope.model.length; i++) {
+ select.tagsinput('add', scope.model[i]);
+ }
+
+ }, true);
+ }
+ };
+}
+
+coreModule.directive('tagColorFromName', tagColorFromName);
+coreModule.directive('bootstrapTagsinput', bootstrapTagsinput);
diff --git a/public/app/features/dashlinks/module.js b/public/app/features/dashlinks/module.ts
similarity index 50%
rename from public/app/features/dashlinks/module.js
rename to public/app/features/dashlinks/module.ts
index 620ad421e92..9f3b4055cee 100644
--- a/public/app/features/dashlinks/module.js
+++ b/public/app/features/dashlinks/module.ts
@@ -1,92 +1,89 @@
-define([
- 'angular',
- 'lodash',
-],
-function (angular, _) {
- 'use strict';
+import angular from 'angular';
+import _ from 'lodash';
- var module = angular.module('grafana.directives');
+var iconMap = {
+ "external link": "fa-external-link",
+ "dashboard": "fa-th-large",
+ "question": "fa-question",
+ "info": "fa-info",
+ "bolt": "fa-bolt",
+ "doc": "fa-file-text-o",
+ "cloud": "fa-cloud",
+};
- var iconMap = {
- "external link": "fa-external-link",
- "dashboard": "fa-th-large",
- "question": "fa-question",
- "info": "fa-info",
- "bolt": "fa-bolt",
- "doc": "fa-file-text-o",
- "cloud": "fa-cloud",
+function dashLinksEditor() {
+ return {
+ restrict: 'E',
+ controller: 'DashLinkEditorCtrl',
+ templateUrl: 'public/app/features/dashlinks/editor.html',
+ link: function() {
+ }
};
+}
- module.directive('dashLinksEditor', function() {
- return {
- restrict: 'E',
- controller: 'DashLinkEditorCtrl',
- templateUrl: 'public/app/features/dashlinks/editor.html',
- link: function() {
+function dashLinksContainer() {
+ return {
+ scope: {
+ links: "="
+ },
+ restrict: 'E',
+ controller: 'DashLinksContainerCtrl',
+ template: '
',
+ link: function() { }
+ };
+}
+
+/** @ngInject */
+function dashLink($compile, linkSrv) {
+ return {
+ restrict: 'E',
+ link: function(scope, elem) {
+ var link = scope.link;
+ var template = '
';
- module.directive('dashLink', function($compile, linkSrv) {
- return {
- restrict: 'E',
- link: function(scope, elem) {
- var link = scope.link;
- var template = '
';
-
- elem.html(template);
- $compile(elem.contents())(scope);
-
- var anchor = elem.find('a');
- var icon = elem.find('i');
- var span = elem.find('span');
-
- function update() {
- var linkInfo = linkSrv.getAnchorInfo(link);
- span.text(linkInfo.title);
- anchor.attr("href", linkInfo.href);
- }
-
- // tooltip
- elem.find('a').tooltip({ title: scope.link.tooltip, html: true, container: 'body' });
- icon.attr('class', 'fa fa-fw ' + scope.link.icon);
- anchor.attr('target', scope.link.target);
-
- // fix for menus on the far right
- if (link.asDropdown && scope.$last) {
- elem.find('.dropdown-menu').addClass('pull-right');
- }
-
- update();
- scope.$on('refresh', update);
+ function update() {
+ var linkInfo = linkSrv.getAnchorInfo(link);
+ span.text(linkInfo.title);
+ anchor.attr("href", linkInfo.href);
}
- };
- });
- module.controller("DashLinksContainerCtrl", function($scope, $rootScope, $q, backendSrv, dashboardSrv, linkSrv) {
+ // tooltip
+ elem.find('a').tooltip({ title: scope.link.tooltip, html: true, container: 'body' });
+ icon.attr('class', 'fa fa-fw ' + scope.link.icon);
+ anchor.attr('target', scope.link.target);
+
+ // fix for menus on the far right
+ if (link.asDropdown && scope.$last) {
+ elem.find('.dropdown-menu').addClass('pull-right');
+ }
+
+ update();
+ scope.$on('refresh', update);
+ }
+ };
+}
+
+export class DashLinksContainerCtrl {
+ /** @ngInject */
+ constructor($scope, $rootScope, $q, backendSrv, dashboardSrv, linkSrv) {
var currentDashId = dashboardSrv.getCurrent().id;
function buildLinks(linkDef) {
@@ -162,10 +159,12 @@ function (angular, _) {
updateDashLinks();
$rootScope.onAppEvent('dash-links-updated', updateDashLinks, $scope);
- });
-
- module.controller('DashLinkEditorCtrl', function($scope, $rootScope) {
+ }
+}
+export class DashLinkEditorCtrl {
+ /** @ngInject */
+ constructor($scope, $rootScope) {
$scope.iconMap = iconMap;
$scope.dashboard.links = $scope.dashboard.links || [];
@@ -189,6 +188,11 @@ function (angular, _) {
$scope.dashboard.updateSubmenuVisibility();
$scope.updated();
};
+ }
+}
- });
-});
+angular.module('grafana.directives').directive('dashLinksEditor', dashLinksEditor);
+angular.module('grafana.directives').directive('dashLinksContainer', dashLinksContainer);
+angular.module('grafana.directives').directive('dashLink', dashLink);
+angular.module('grafana.directives').controller("DashLinksContainerCtrl", DashLinksContainerCtrl);
+angular.module('grafana.directives').controller('DashLinkEditorCtrl', DashLinkEditorCtrl);
diff --git a/public/app/features/panellinks/module.js b/public/app/features/panellinks/module.js
deleted file mode 100644
index a36317dc2b3..00000000000
--- a/public/app/features/panellinks/module.js
+++ /dev/null
@@ -1,56 +0,0 @@
-define([
- 'angular',
- 'lodash',
- './link_srv',
-],
-function (angular, _) {
- 'use strict';
-
- angular
- .module('grafana.directives')
- .directive('panelLinksEditor', function() {
- return {
- scope: {
- panel: "="
- },
- restrict: 'E',
- controller: 'PanelLinksEditorCtrl',
- templateUrl: 'public/app/features/panellinks/module.html',
- link: function() {
- }
- };
- }).controller('PanelLinksEditorCtrl', function($scope, backendSrv) {
-
- $scope.panel.links = $scope.panel.links || [];
-
- $scope.addLink = function() {
- $scope.panel.links.push({
- type: 'dashboard',
- });
- };
-
- $scope.searchDashboards = function(queryStr, callback) {
- backendSrv.search({query: queryStr}).then(function(hits) {
- var dashboards = _.map(hits, function(dash) {
- return dash.title;
- });
-
- callback(dashboards);
- });
- };
-
- $scope.dashboardChanged = function(link) {
- backendSrv.search({query: link.dashboard}).then(function(hits) {
- var dashboard = _.find(hits, {title: link.dashboard});
- if (dashboard) {
- link.dashUri = dashboard.uri;
- link.title = dashboard.title;
- }
- });
- };
-
- $scope.deleteLink = function(link) {
- $scope.panel.links = _.without($scope.panel.links, link);
- };
- });
-});
diff --git a/public/app/features/panellinks/module.ts b/public/app/features/panellinks/module.ts
new file mode 100644
index 00000000000..72debe2ffcf
--- /dev/null
+++ b/public/app/features/panellinks/module.ts
@@ -0,0 +1,57 @@
+import angular from 'angular';
+import _ from 'lodash';
+import './link_srv';
+
+function panelLinksEditor() {
+ return {
+ scope: {
+ panel: "="
+ },
+ restrict: 'E',
+ controller: 'PanelLinksEditorCtrl',
+ templateUrl: 'public/app/features/panellinks/module.html',
+ link: function() {
+ }
+ };
+}
+
+export class PanelLinksEditorCtrl {
+ /** @ngInject */
+ constructor($scope, backendSrv) {
+ $scope.panel.links = $scope.panel.links || [];
+
+ $scope.addLink = function() {
+ $scope.panel.links.push({
+ type: 'dashboard',
+ });
+ };
+
+ $scope.searchDashboards = function(queryStr, callback) {
+ backendSrv.search({query: queryStr}).then(function(hits) {
+ var dashboards = _.map(hits, function(dash) {
+ return dash.title;
+ });
+
+ callback(dashboards);
+ });
+ };
+
+ $scope.dashboardChanged = function(link) {
+ backendSrv.search({query: link.dashboard}).then(function(hits) {
+ var dashboard = _.find(hits, {title: link.dashboard});
+ if (dashboard) {
+ link.dashUri = dashboard.uri;
+ link.title = dashboard.title;
+ }
+ });
+ };
+
+ $scope.deleteLink = function(link) {
+ $scope.panel.links = _.without($scope.panel.links, link);
+ };
+ }
+}
+
+angular.module('grafana.directives').directive('panelLinksEditor', panelLinksEditor)
+.controller('PanelLinksEditorCtrl', PanelLinksEditorCtrl);
+
diff --git a/tslint.json b/tslint.json
index f1b414c916e..789e83975db 100644
--- a/tslint.json
+++ b/tslint.json
@@ -17,7 +17,7 @@
"max-line-length": [true, 140],
"member-access": false,
"no-arg": true,
- "no-bitwise": true,
+ "no-bitwise": false,
"no-console": [true,
"debug",
"info",