From 2f78584cdb735389792de1f868a424a9cfd4c304 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 1 Feb 2016 12:42:10 +0100 Subject: [PATCH] poc(plugin editors): experimential test for plugin editors --- public/app/core/plugins/directive.ts | 0 public/app/features/panel/panel.ts | 39 +---- public/app/features/panel/panel_directive.js | 104 ------------- public/app/features/panel/panel_directive.ts | 142 ++++++++++++++++++ public/app/features/panel/query_editor.ts | 80 +++++++++- public/app/partials/metrics.html | 4 +- .../app/plugins/datasource/grafana/module.ts | 15 +- 7 files changed, 236 insertions(+), 148 deletions(-) create mode 100644 public/app/core/plugins/directive.ts delete mode 100644 public/app/features/panel/panel_directive.js create mode 100644 public/app/features/panel/panel_directive.ts 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, };