diff --git a/public/app/core/plugins/directive.ts b/public/app/core/plugins/directive.ts
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/public/app/features/panel/panel.ts b/public/app/features/panel/panel.ts
index 7312e18ccc7..535ccdcf06a 100644
--- a/public/app/features/panel/panel.ts
+++ b/public/app/features/panel/panel.ts
@@ -4,44 +4,7 @@ import config from 'app/core/config';
import {PanelCtrl} from './panel_ctrl';
import {MetricsPanelCtrl} from './metrics_panel_ctrl';
-
-export class DefaultPanelCtrl extends PanelCtrl {
- constructor($scope, $injector) {
- super($scope, $injector);
- }
-}
-
-class PanelDirective {
- template: string;
- templateUrl: string;
- bindToController: boolean;
- scope: any;
- controller: any;
- controllerAs: string;
-
- getDirective() {
- if (!this.controller) {
- this.controller = DefaultPanelCtrl;
- }
-
- return {
- template: this.template,
- templateUrl: this.templateUrl,
- controller: this.controller,
- controllerAs: 'ctrl',
- bindToController: true,
- scope: {dashboard: "=", panel: "=", row: "="},
- link: (scope, elem, attrs, ctrl) => {
- ctrl.init();
- this.link(scope, elem, attrs, ctrl);
- }
- };
- }
-
- link(scope, elem, attrs, ctrl) {
- return null;
- }
-}
+import {PanelDirective} from './panel_directive';
export {
PanelCtrl,
diff --git a/public/app/features/panel/panel_directive.js b/public/app/features/panel/panel_directive.js
deleted file mode 100644
index ffe978a55ad..00000000000
--- a/public/app/features/panel/panel_directive.js
+++ /dev/null
@@ -1,104 +0,0 @@
-define([
- 'angular',
- 'jquery',
-],
-function (angular, $) {
- 'use strict';
-
- var module = angular.module('grafana.directives');
-
- module.directive('grafanaPanel', function() {
- return {
- restrict: 'E',
- templateUrl: 'app/features/panel/partials/panel.html',
- transclude: true,
- scope: { ctrl: "=" },
- link: function(scope, elem) {
- var panelContainer = elem.find('.panel-container');
- var ctrl = scope.ctrl;
- scope.$watchGroup(['ctrl.fullscreen', 'ctrl.height', 'ctrl.panel.height', 'ctrl.row.height'], function() {
- panelContainer.css({ minHeight: ctrl.height || ctrl.panel.height || ctrl.row.height, display: 'block' });
- elem.toggleClass('panel-fullscreen', ctrl.fullscreen ? true : false);
- });
- }
- };
- });
-
- module.directive('panelResizer', function($rootScope) {
- return {
- restrict: 'E',
- template: '',
- link: function(scope, elem) {
- var resizing = false;
- var lastPanel = false;
- var ctrl = scope.ctrl;
- var handleOffset;
- var originalHeight;
- var originalWidth;
- var maxWidth;
-
- function dragStartHandler(e) {
- e.preventDefault();
- resizing = true;
-
- handleOffset = $(e.target).offset();
- originalHeight = parseInt(ctrl.row.height);
- originalWidth = ctrl.panel.span;
- maxWidth = $(document).width();
-
- lastPanel = ctrl.row.panels[ctrl.row.panels.length - 1];
-
- $('body').on('mousemove', moveHandler);
- $('body').on('mouseup', dragEndHandler);
- }
-
- function moveHandler(e) {
- ctrl.row.height = originalHeight + (e.pageY - handleOffset.top);
- ctrl.panel.span = originalWidth + (((e.pageX - handleOffset.left) / maxWidth) * 12);
- ctrl.panel.span = Math.min(Math.max(ctrl.panel.span, 1), 12);
-
- var rowSpan = ctrl.dashboard.rowSpan(ctrl.row);
-
- // auto adjust other panels
- if (Math.floor(rowSpan) < 14) {
- // last panel should not push row down
- if (lastPanel === ctrl.panel && rowSpan > 12) {
- lastPanel.span -= rowSpan - 12;
- }
- // reduce width of last panel so total in row is 12
- else if (lastPanel !== ctrl.panel) {
- lastPanel.span = lastPanel.span - (rowSpan - 12);
- lastPanel.span = Math.min(Math.max(lastPanel.span, 1), 12);
- }
- }
-
- scope.$apply(function() {
- scope.$broadcast('render');
- });
- }
-
- function dragEndHandler() {
- // if close to 12
- var rowSpan = ctrl.dashboard.rowSpan(ctrl.row);
- if (rowSpan < 12 && rowSpan > 11) {
- lastPanel.span += 12 - rowSpan;
- }
-
- scope.$apply(function() {
- $rootScope.$broadcast('render');
- });
-
- $('body').off('mousemove', moveHandler);
- $('body').off('mouseup', dragEndHandler);
- }
-
- elem.on('mousedown', dragStartHandler);
-
- scope.$on("$destroy", function() {
- elem.off('mousedown', dragStartHandler);
- });
- }
- };
- });
-
-});
diff --git a/public/app/features/panel/panel_directive.ts b/public/app/features/panel/panel_directive.ts
new file mode 100644
index 00000000000..eac2594a26e
--- /dev/null
+++ b/public/app/features/panel/panel_directive.ts
@@ -0,0 +1,142 @@
+///
+
+import angular from 'angular';
+import $ from 'jquery';
+
+import {PanelCtrl} from './panel_ctrl';
+
+export class DefaultPanelCtrl extends PanelCtrl {
+ constructor($scope, $injector) {
+ super($scope, $injector);
+ }
+}
+
+export class PanelDirective {
+ template: string;
+ templateUrl: string;
+ bindToController: boolean;
+ scope: any;
+ controller: any;
+ controllerAs: string;
+
+ getDirective() {
+ if (!this.controller) {
+ this.controller = DefaultPanelCtrl;
+ }
+
+ return {
+ template: this.template,
+ templateUrl: this.templateUrl,
+ controller: this.controller,
+ controllerAs: 'ctrl',
+ bindToController: true,
+ scope: {dashboard: "=", panel: "=", row: "="},
+ link: (scope, elem, attrs, ctrl) => {
+ ctrl.init();
+ this.link(scope, elem, attrs, ctrl);
+ }
+ };
+ }
+
+ link(scope, elem, attrs, ctrl) {
+ return null;
+ }
+}
+
+
+var module = angular.module('grafana.directives');
+
+module.directive('grafanaPanel', function() {
+ return {
+ restrict: 'E',
+ templateUrl: 'app/features/panel/partials/panel.html',
+ transclude: true,
+ scope: { ctrl: "=" },
+ link: function(scope, elem) {
+ var panelContainer = elem.find('.panel-container');
+ var ctrl = scope.ctrl;
+ scope.$watchGroup(['ctrl.fullscreen', 'ctrl.height', 'ctrl.panel.height', 'ctrl.row.height'], function() {
+ panelContainer.css({ minHeight: ctrl.height || ctrl.panel.height || ctrl.row.height, display: 'block' });
+ elem.toggleClass('panel-fullscreen', ctrl.fullscreen ? true : false);
+ });
+ }
+ };
+});
+
+module.directive('panelResizer', function($rootScope) {
+ return {
+ restrict: 'E',
+ template: '',
+ link: function(scope, elem) {
+ var resizing = false;
+ var lastPanel;
+ var ctrl = scope.ctrl;
+ var handleOffset;
+ var originalHeight;
+ var originalWidth;
+ var maxWidth;
+
+ function dragStartHandler(e) {
+ e.preventDefault();
+ resizing = true;
+
+ handleOffset = $(e.target).offset();
+ originalHeight = parseInt(ctrl.row.height);
+ originalWidth = ctrl.panel.span;
+ maxWidth = $(document).width();
+
+ lastPanel = ctrl.row.panels[ctrl.row.panels.length - 1];
+
+ $('body').on('mousemove', moveHandler);
+ $('body').on('mouseup', dragEndHandler);
+ }
+
+ function moveHandler(e) {
+ ctrl.row.height = originalHeight + (e.pageY - handleOffset.top);
+ ctrl.panel.span = originalWidth + (((e.pageX - handleOffset.left) / maxWidth) * 12);
+ ctrl.panel.span = Math.min(Math.max(ctrl.panel.span, 1), 12);
+
+ var rowSpan = ctrl.dashboard.rowSpan(ctrl.row);
+
+ // auto adjust other panels
+ if (Math.floor(rowSpan) < 14) {
+ // last panel should not push row down
+ if (lastPanel === ctrl.panel && rowSpan > 12) {
+ lastPanel.span -= rowSpan - 12;
+ } else if (lastPanel !== ctrl.panel) {
+ // reduce width of last panel so total in row is 12
+ lastPanel.span = lastPanel.span - (rowSpan - 12);
+ lastPanel.span = Math.min(Math.max(lastPanel.span, 1), 12);
+ }
+ }
+
+ scope.$apply(function() {
+ scope.$broadcast('render');
+ });
+ }
+
+ function dragEndHandler() {
+ // if close to 12
+ var rowSpan = ctrl.dashboard.rowSpan(ctrl.row);
+ if (rowSpan < 12 && rowSpan > 11) {
+ lastPanel.span += 12 - rowSpan;
+ }
+
+ scope.$apply(function() {
+ $rootScope.$broadcast('render');
+ });
+
+ $('body').off('mousemove', moveHandler);
+ $('body').off('mouseup', dragEndHandler);
+ }
+
+ elem.on('mousedown', dragStartHandler);
+
+ scope.$on("$destroy", function() {
+ elem.off('mousedown', dragStartHandler);
+ });
+ }
+ };
+});
+
+
diff --git a/public/app/features/panel/query_editor.ts b/public/app/features/panel/query_editor.ts
index 5b493362762..5c33480a3ab 100644
--- a/public/app/features/panel/query_editor.ts
+++ b/public/app/features/panel/query_editor.ts
@@ -1,6 +1,80 @@
///
import angular from 'angular';
+import _ from 'lodash';
+
+var directivesModule = angular.module('grafana.directives');
+
+function pluginDirectiveLoader($compile, datasourceSrv) {
+
+ function getPluginComponentDirective(options) {
+ return function() {
+ return {
+ templateUrl: options.Component.templateUrl,
+ restrict: 'E',
+ controller: options.Component,
+ controllerAs: 'ctrl',
+ bindToController: true,
+ scope: options.bindings,
+ link: (scope, elem, attrs, ctrl) => {
+ if (ctrl.link) {
+ ctrl.link(scope, elem, attrs, ctrl);
+ }
+ }
+ };
+ };
+ }
+
+ function getModule(scope, attrs) {
+ switch (attrs.type) {
+ case "metrics-query-editor": {
+ let datasource = scope.target.datasource || scope.ctrl.panel.datasource;
+ return datasourceSrv.get(datasource).then(ds => {
+ return System.import(ds.meta.module).then(dsModule => {
+ return {
+ name: 'metrics-query-editor-' + ds.meta.id,
+ bindings: {target: "=", panelCtrl: "="},
+ attrs: {"target": "target", "panel-ctrl": "ctrl"},
+ Component: dsModule.MetricsQueryEditor
+ };
+ });
+ });
+ }
+ }
+ }
+
+ function appendAndCompile(scope, elem, componentInfo) {
+ var child = angular.element(document.createElement(componentInfo.name));
+ _.each(componentInfo.attrs, (value, key) => {
+ child.attr(key, value);
+ });
+
+ $compile(child)(scope);
+
+ elem.empty();
+ elem.append(child);
+ }
+
+ function registerPluginComponent(scope, elem, attrs, componentInfo) {
+ if (!componentInfo.Component.registered) {
+ var directiveName = attrs.$normalize(componentInfo.name);
+ var directiveFn = getPluginComponentDirective(componentInfo);
+ directivesModule.directive(directiveName, directiveFn);
+ componentInfo.Component.registered = true;
+ }
+
+ appendAndCompile(scope, elem, componentInfo);
+ }
+
+ return {
+ restrict: 'E',
+ link: function(scope, elem, attrs) {
+ getModule(scope, attrs).then(function (componentInfo) {
+ registerPluginComponent(scope, elem, attrs, componentInfo);
+ });
+ }
+ };
+}
/** @ngInject */
function metricsQueryEditor(dynamicDirectiveSrv, datasourceSrv) {
@@ -43,6 +117,6 @@ function metricsQueryOptions(dynamicDirectiveSrv, datasourceSrv) {
});
}
-angular.module('grafana.directives')
- .directive('metricsQueryEditor', metricsQueryEditor)
- .directive('metricsQueryOptions', metricsQueryOptions);
+directivesModule.directive('pluginDirectiveLoader', pluginDirectiveLoader);
+directivesModule.directive('metricsQueryEditor', metricsQueryEditor);
+directivesModule.directive('metricsQueryOptions', metricsQueryOptions);
diff --git a/public/app/partials/metrics.html b/public/app/partials/metrics.html
index 8a7eb1bfd71..6d580e7575f 100644
--- a/public/app/partials/metrics.html
+++ b/public/app/partials/metrics.html
@@ -1,8 +1,8 @@
diff --git a/public/app/plugins/datasource/grafana/module.ts b/public/app/plugins/datasource/grafana/module.ts
index f52676adb1c..b725a162426 100644
--- a/public/app/plugins/datasource/grafana/module.ts
+++ b/public/app/plugins/datasource/grafana/module.ts
@@ -9,10 +9,23 @@ function grafanaMetricsQueryEditor() {
return {templateUrl: 'app/plugins/datasource/grafana/partials/query.editor.html'};
}
+export class MetricsQueryEditor {
+ panelCtrl: any;
+ target: any;
+}
+
+class GrafanaMetricsQueryEditor extends MetricsQueryEditor {
+ static templateUrl = 'app/plugins/datasource/grafana/partials/query.editor.html';
+
+ constructor() {
+ super();
+ console.log('this is a metrics editor', this.panelCtrl, this.target);
+ }
+}
export {
GrafanaDatasource,
GrafanaDatasource as Datasource,
- grafanaMetricsQueryEditor as metricsQueryEditor
+ GrafanaMetricsQueryEditor as MetricsQueryEditor,
};