From 4f7fb40d9b542f696238c33fa049f45632adffa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sun, 24 Jan 2016 16:39:25 -0500 Subject: [PATCH] feat(panel plugin): improving panel plugin model --- pkg/api/frontendsettings.go | 1 + public/app/core/filters/filters.ts | 9 ++- public/app/features/panel/all.js | 1 + .../panel/{panel_ctrl.ts => panel.ts} | 28 ++++++++- public/app/features/panel/panel_editor_tab.ts | 24 ++++++++ public/app/features/panel/panel_loader.ts | 57 ++++++++++--------- public/app/features/panel/panel_menu.js | 10 ++-- public/app/features/panel/panel_meta3.ts | 56 ++++++++++++++++++ public/app/features/panel/partials/panel.html | 12 ++-- public/app/partials/panelgeneral.html | 14 ++--- public/app/plugins/panel/test/module.ts | 24 +++++--- public/app/plugins/panel/test/plugin.json | 15 ++++- public/app/plugins/panel/unknown/module.ts | 18 +++--- 13 files changed, 201 insertions(+), 68 deletions(-) rename public/app/features/panel/{panel_ctrl.ts => panel.ts} (55%) create mode 100644 public/app/features/panel/panel_editor_tab.ts create mode 100644 public/app/features/panel/panel_meta3.ts diff --git a/pkg/api/frontendsettings.go b/pkg/api/frontendsettings.go index 7bea0b6338c..256ff15e881 100644 --- a/pkg/api/frontendsettings.go +++ b/pkg/api/frontendsettings.go @@ -123,6 +123,7 @@ func getFrontendSettingsMap(c *middleware.Context) (map[string]interface{}, erro panels[panel.Id] = map[string]interface{}{ "module": panel.Module, "name": panel.Name, + "info": panel.Info, } } diff --git a/public/app/core/filters/filters.ts b/public/app/core/filters/filters.ts index 57b2b1bd9ba..6122a010182 100644 --- a/public/app/core/filters/filters.ts +++ b/public/app/core/filters/filters.ts @@ -59,11 +59,14 @@ coreModule.filter('noXml', function() { coreModule.filter('interpolateTemplateVars', function (templateSrv) { var filterFunc: any = function(text, scope) { - if (scope.panel) { - return templateSrv.replaceWithText(text, scope.panel.scopedVars); + var scopedVars; + if (scope.ctrl && scope.ctrl.panel) { + scopedVars = scope.ctrl.panel.scopedVars; } else { - return templateSrv.replaceWithText(text, scope.row.scopedVars); + scopedVars = scope.row.scopedVars; } + + return templateSrv.replaceWithText(text, scopedVars); }; filterFunc.$stateful = true; diff --git a/public/app/features/panel/all.js b/public/app/features/panel/all.js index ef3ea9b9b0f..ad635d83f07 100644 --- a/public/app/features/panel/all.js +++ b/public/app/features/panel/all.js @@ -6,4 +6,5 @@ define([ './solo_panel_ctrl', './panel_loader', './query_editor', + './panel_editor_tab', ], function () {}); diff --git a/public/app/features/panel/panel_ctrl.ts b/public/app/features/panel/panel.ts similarity index 55% rename from public/app/features/panel/panel_ctrl.ts rename to public/app/features/panel/panel.ts index cc020c23423..a3bf35db9a4 100644 --- a/public/app/features/panel/panel_ctrl.ts +++ b/public/app/features/panel/panel.ts @@ -1,15 +1,17 @@ /// -import PanelMeta from './panel_meta2'; +import PanelMeta from './panel_meta3'; export class PanelCtrl { meta: any; panel: any; row: any; dashboard: any; + tabIndex: number; constructor(private scope) { this.meta = new PanelMeta(this.panel); + this.tabIndex = 0; this.publishAppEvent('panel-instantiated', {scope: scope}); } @@ -36,4 +38,28 @@ export class PanelCtrl { } } +export class PanelDirective { + template: string; + templateUrl: string; + bindToController: boolean; + scope: any; + controller: any; + controllerAs: string; + + getDirective() { + return { + template: this.template, + templateUrl: this.templateUrl, + controller: this.controller, + controllerAs: 'ctrl', + bindToController: true, + scope: {dashboard: "=", panel: "=", row: "="}, + link: this.link + }; + } + + link(scope) { + return null; + } +} diff --git a/public/app/features/panel/panel_editor_tab.ts b/public/app/features/panel/panel_editor_tab.ts new file mode 100644 index 00000000000..56e3078962e --- /dev/null +++ b/public/app/features/panel/panel_editor_tab.ts @@ -0,0 +1,24 @@ +/// + +import angular from 'angular'; +import config from 'app/core/config'; + +var directiveModule = angular.module('grafana.directives'); + +/** @ngInject */ +function panelEditorTab(dynamicDirectiveSrv) { + return dynamicDirectiveSrv.create({ + scope: { + panelCtrl: "=", + editorTab: "=", + }, + directive: scope => { + return Promise.resolve({ + name: 'panel-editor-tab-' + scope.editorTab.title, + fn: scope.editorTab.directiveFn, + }); + } + }); +} + +directiveModule.directive('panelEditorTab', panelEditorTab); diff --git a/public/app/features/panel/panel_loader.ts b/public/app/features/panel/panel_loader.ts index dd0284138ab..cf42458a9a7 100644 --- a/public/app/features/panel/panel_loader.ts +++ b/public/app/features/panel/panel_loader.ts @@ -3,12 +3,12 @@ import angular from 'angular'; import config from 'app/core/config'; -import {unknownPanelDirective} from '../../plugins/panel/unknown/module'; +import {UnknownPanel} from '../../plugins/panel/unknown/module'; var directiveModule = angular.module('grafana.directives'); /** @ngInject */ -function panelLoader($compile, dynamicDirectiveSrv, $http, $q) { +function panelLoader($compile, dynamicDirectiveSrv, $http, $q, $injector) { return { restrict: 'E', scope: { @@ -18,11 +18,11 @@ function panelLoader($compile, dynamicDirectiveSrv, $http, $q) { }, link: function(scope, elem, attrs) { - function getTemplate(component) { - if (component.template) { - return $q.when(component.template); + function getTemplate(directive) { + if (directive.template) { + return $q.when(directive.template); } - return $http.get(component.templateUrl).then(res => { + return $http.get(directive.templateUrl).then(res => { return res.data; }); } @@ -38,37 +38,42 @@ function panelLoader($compile, dynamicDirectiveSrv, $http, $q) { elem.append(child); } - function addPanel(name, directive) { - if (!directive.registered) { - getTemplate(directive).then(template => { - directive.templateUrl = null; - directive.template = `${template}`; - directive.controllerAs = 'ctrl'; - directive.bindToController = true; - directive.scope = { - dashboard: "=", - panel: "=", - row: "=" - }; + function addPanel(name, Panel) { + if (Panel.registered) { + addPanelAndCompile(name); + } - directiveModule.directive(attrs.$normalize(name), function() { - return directive; - }); - directive.registered = true; + if (Panel.promise) { + Panel.promise.then(() => { addPanelAndCompile(name); }); + return; } - addPanelAndCompile(name); + + var panelInstance = $injector.instantiate(Panel); + var directive = panelInstance.getDirective(); + + Panel.promise = getTemplate(directive).then(template => { + directive.templateUrl = null; + directive.template = `${template}`; + directiveModule.directive(attrs.$normalize(name), function() { + return directive; + }); + Panel.registered = true; + addPanelAndCompile(name); + }); + + return; } var panelElemName = 'panel-directive-' + scope.panel.type; let panelInfo = config.panels[scope.panel.type]; if (!panelInfo) { - addPanel(panelElemName, unknownPanelDirective); + addPanel(panelElemName, UnknownPanel); } System.import(panelInfo.module).then(function(panelModule) { - addPanel(panelElemName, panelModule.panel); + addPanel(panelElemName, panelModule.Panel); }).catch(err => { console.log('Panel err: ', err); }); @@ -76,4 +81,4 @@ function panelLoader($compile, dynamicDirectiveSrv, $http, $q) { }; } -angular.module('grafana.directives').directive('panelLoader', panelLoader); +directiveModule.directive('panelLoader', panelLoader); diff --git a/public/app/features/panel/panel_menu.js b/public/app/features/panel/panel_menu.js index bea8d27d2fa..16ee311ff52 100644 --- a/public/app/features/panel/panel_menu.js +++ b/public/app/features/panel/panel_menu.js @@ -11,9 +11,9 @@ function (angular, $, _) { .directive('panelMenu', function($compile, linkSrv) { var linkTemplate = '' + - '{{ctrl.panel.title}}' + + '{{ctrl.panel.title | interpolateTemplateVars:this}}' + '' + - ' {{ctrl.panelMeta.timeInfo}}' + + ' {{ctrl.panelMeta.timeInfo}}' + ''; function createExternalLinkMenu(ctrl) { @@ -44,7 +44,7 @@ function (angular, $, _) { template += '
'; template += ''; - _.each(ctrl.panelMeta.menu, function(item) { + _.each(ctrl.meta.menu, function(item) { // skip edit actions if not editor if (item.role === 'Editor' && !ctrl.dashboard.meta.canEdit) { return; @@ -64,7 +64,7 @@ function (angular, $, _) { } function getExtendedMenu(ctrl) { - return angular.copy(ctrl.panelMeta.extendedMenu); + return angular.copy(ctrl.meta.extendedMenu); } return { @@ -80,7 +80,7 @@ function (angular, $, _) { elem.append($link); - $scope.$watchCollection('panel.links', function(newValue) { + $scope.$watchCollection('ctrl.panel.links', function(newValue) { var showIcon = (newValue ? newValue.length > 0 : false) && ctrl.panel.title !== ''; $panelLinksBtn.toggle(showIcon); }); diff --git a/public/app/features/panel/panel_meta3.ts b/public/app/features/panel/panel_meta3.ts new file mode 100644 index 00000000000..056a75d5ee3 --- /dev/null +++ b/public/app/features/panel/panel_meta3.ts @@ -0,0 +1,56 @@ +/// + +import config from 'app/core/config'; + +function panelOptionsTab() { + return {templateUrl: 'app/partials/panelgeneral.html'}; +} + +export default class PanelMeta { + description: any; + icon: any; + name: any; + menu: any; + editorTabs: any; + extendedMenu: any; + + constructor(panel) { + let panelInfo = config.panels[panel.type]; + console.log(panelInfo); + + this.icon = panelInfo.icon; + this.name = panelInfo.name; + this.menu = []; + this.editorTabs = []; + this.extendedMenu = []; + + if (panelInfo.fullscreen) { + this.addMenuItem('View', 'icon-eye-open', 'ctrl.viewPanel(); dismiss();'); + } + + this.addMenuItem('Edit', 'icon-cog', 'ctrl.editPanel(); dismiss();', 'Editor'); + this.addMenuItem('Duplicate', 'icon-copy', 'ctrl.duplicate()', 'Editor'); + this.addMenuItem('Share', 'icon-share', 'ctrl.share(); dismiss();'); + + this.addEditorTab('General', panelOptionsTab); + + if (panelInfo.metricsEditor) { + this.addEditorTab('Metrics', 'app/partials/metrics.html'); + } + + this.addExtendedMenuItem('Panel JSON', '', 'ctrl.editPanelJson(); dismiss();'); + } + + addMenuItem (text, icon, click, role?) { + this.menu.push({text: text, icon: icon, click: click, role: role}); + } + + addExtendedMenuItem (text, icon, click, role?) { + this.extendedMenu.push({text: text, icon: icon, click: click, role: role}); + } + + addEditorTab(title, directiveFn) { + this.editorTabs.push({title: title, directiveFn: directiveFn}); + } +} + diff --git a/public/app/features/panel/partials/panel.html b/public/app/features/panel/partials/panel.html index 3b325366826..c3fb0090241 100644 --- a/public/app/features/panel/partials/panel.html +++ b/public/app/features/panel/partials/panel.html @@ -23,12 +23,12 @@
- - {{ctrl.panelMeta.panelName}} + + {{ctrl.meta.name}}
-
-
+
+
@@ -38,8 +38,8 @@
-
-
+
+
diff --git a/public/app/partials/panelgeneral.html b/public/app/partials/panelgeneral.html index 09ccbe86dfa..d0e41e5180f 100644 --- a/public/app/partials/panelgeneral.html +++ b/public/app/partials/panelgeneral.html @@ -7,23 +7,23 @@ Title
  • - +
  • Span
  • - +
  • Height
  • - +
  • - +
  • @@ -38,7 +38,7 @@ Repeat Panel
  • -
  • @@ -46,7 +46,7 @@ Min span
  • -
  • @@ -56,6 +56,6 @@
    - + diff --git a/public/app/plugins/panel/test/module.ts b/public/app/plugins/panel/test/module.ts index ae9af416ed0..da1682544a4 100644 --- a/public/app/plugins/panel/test/module.ts +++ b/public/app/plugins/panel/test/module.ts @@ -1,6 +1,6 @@ /// -import {PanelCtrl} from '../../../features/panel/panel_ctrl'; +import {PanelDirective, PanelCtrl} from '../../../features/panel/panel'; class TestPanelCtrl extends PanelCtrl { constructor($scope) { @@ -8,15 +8,23 @@ class TestPanelCtrl extends PanelCtrl { } } -var panel = { - templateUrl: `app/plugins/panel/test/module.html`, - controller: TestPanelCtrl, - link: function(scope, elem) { - console.log('panel link'); + +class TestPanel extends PanelDirective { + templateUrl = `app/plugins/panel/test/module.html`; + controller = TestPanelCtrl; + + constructor($http) { + super(); + console.log('panel ctor: ', $http); } -}; + + link(scope) { + console.log('panel link: ', scope.ctrl.panel.id); + } +} export { TestPanelCtrl, - panel, + // testPanelDirective as panel, + TestPanel as Panel, } diff --git a/public/app/plugins/panel/test/plugin.json b/public/app/plugins/panel/test/plugin.json index b2d7b9b42c6..08fb883af76 100644 --- a/public/app/plugins/panel/test/plugin.json +++ b/public/app/plugins/panel/test/plugin.json @@ -1,5 +1,18 @@ { "type": "panel", "name": "Test", - "id": "test" + "id": "test", + + "info": { + "description": "Test panel", + "author": { + "name": "Core Grafana Team.", + "url": "http://grafana.org" + }, + "logos": { + "icon": "fa fa-fw th-large", + "small": "img/logo_small.png", + "large": "img/logo_large.png" + } + } } diff --git a/public/app/plugins/panel/unknown/module.ts b/public/app/plugins/panel/unknown/module.ts index 8d1ce6c1f9a..4f729649395 100644 --- a/public/app/plugins/panel/unknown/module.ts +++ b/public/app/plugins/panel/unknown/module.ts @@ -1,15 +1,11 @@ /// -export function unknownPanelDirective() { - return { - restrict: 'E', - template: ` - -
    - Unknown panel type: {{panel.type}} -
    -
    - `, - }; +import {PanelDirective} from '../../../features/panel/panel'; + +export class UnknownPanel extends PanelDirective { + template = `
    + Unknown panel type: {{ctrl.panel.type}} +
    `; } +