Commit 4f7fb40d by Torkel Ödegaard

feat(panel plugin): improving panel plugin model

parent ecdc730d
......@@ -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,
}
}
......
......@@ -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;
......
......@@ -6,4 +6,5 @@ define([
'./solo_panel_ctrl',
'./panel_loader',
'./query_editor',
'./panel_editor_tab',
], function () {});
///<reference path="../../headers/common.d.ts" />
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;
}
}
///<reference path="../../headers/common.d.ts" />
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);
......@@ -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 => {
function addPanel(name, Panel) {
if (Panel.registered) {
addPanelAndCompile(name);
}
if (Panel.promise) {
Panel.promise.then(() => {
addPanelAndCompile(name);
});
return;
}
var panelInstance = $injector.instantiate(Panel);
var directive = panelInstance.getDirective();
Panel.promise = getTemplate(directive).then(template => {
directive.templateUrl = null;
directive.template = `<grafana-panel ctrl="ctrl">${template}</grafana-panel>`;
directive.controllerAs = 'ctrl';
directive.bindToController = true;
directive.scope = {
dashboard: "=",
panel: "=",
row: "="
};
directiveModule.directive(attrs.$normalize(name), function() {
return directive;
});
directive.registered = true;
Panel.registered = true;
addPanelAndCompile(name);
});
}
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);
......@@ -11,9 +11,9 @@ function (angular, $, _) {
.directive('panelMenu', function($compile, linkSrv) {
var linkTemplate =
'<span class="panel-title drag-handle pointer">' +
'<span class="panel-title-text drag-handle">{{ctrl.panel.title}}</span>' +
'<span class="panel-title-text drag-handle">{{ctrl.panel.title | interpolateTemplateVars:this}}</span>' +
'<span class="panel-links-btn"><i class="fa fa-external-link"></i></span>' +
'<span class="panel-time-info" ng-show="ctrl.panelMeta.timeInfo"><i class="fa fa-clock-o"></i> {{ctrl.panelMeta.timeInfo}}</span>' +
'<span class="panel-time-info" ng-show="ctrl.meta.timeInfo"><i class="fa fa-clock-o"></i> {{ctrl.panelMeta.timeInfo}}</span>' +
'</span>';
function createExternalLinkMenu(ctrl) {
......@@ -44,7 +44,7 @@ function (angular, $, _) {
template += '<div class="panel-menu-row">';
template += '<a class="panel-menu-link" gf-dropdown="extendedMenu"><i class="fa fa-bars"></i></a>';
_.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);
});
......
///<reference path="../../headers/common.d.ts" />
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});
}
}
......@@ -23,12 +23,12 @@
<div class="gf-box">
<div class="gf-box-header">
<div class="gf-box-title">
<i ng-class="panelMeta.editIcon"></i>
{{ctrl.panelMeta.panelName}}
<i ng-class="ctrl.meta.icon"></i>
{{ctrl.meta.name}}
</div>
<div ng-model="editor.index" bs-tabs>
<div ng-repeat="tab in panelMeta.editorTabs" data-title="{{tab.title}}">
<div ng-model="ctrl.tabIndex" bs-tabs>
<div ng-repeat="tab in ctrl.meta.editorTabs" data-title="{{tab.title}}">
</div>
</div>
......@@ -38,8 +38,8 @@
</div>
<div class="gf-box-body">
<div ng-repeat="tab in panelMeta.editorTabs" ng-if="editor.index === $index">
<div ng-include src="tab.src"></div>
<div ng-repeat="tab in ctrl.meta.editorTabs" ng-if="ctrl.tabIndex === $index">
<panel-editor-tab editor-tab="tab" panel-ctrl="ctrl"></panel-editor-tab>
</div>
</div>
</div>
......
......@@ -7,23 +7,23 @@
Title
</li>
<li>
<input type="text" class="input-xlarge tight-form-input" ng-model='panel.title'></input>
<input type="text" class="input-xlarge tight-form-input" ng-model='panelCtrl.panel.title'></input>
</li>
<li class="tight-form-item">
Span
</li>
<li>
<select class="input-mini tight-form-input" ng-model="panel.span" ng-options="f for f in [0,1,2,3,4,5,6,7,8,9,10,11,12]"></select>
<select class="input-mini tight-form-input" ng-model="panelCtrl.panel.span" ng-options="f for f in [0,1,2,3,4,5,6,7,8,9,10,11,12]"></select>
</li>
<li class="tight-form-item">
Height
</li>
<li>
<input type="text" class="input-small tight-form-input" ng-model='panel.height'></input>
<input type="text" class="input-small tight-form-input" ng-model='panelCtrl.panel.height'></input>
</li>
<li class="tight-form-item">
<label class="checkbox-label" for="panel.transparent">Transparent</label>
<input class="cr1" id="panel.transparent" type="checkbox" ng-model="panel.transparent" ng-checked="panel.transparent">
<input class="cr1" id="panel.transparent" type="checkbox" ng-model="panelCtrl.panel.transparent" ng-checked="panelCtrl.panel.transparent">
<label for="panel.transparent" class="cr1"></label>
</li>
</ul>
......@@ -38,7 +38,7 @@
Repeat Panel
</li>
<li>
<select class="input-small tight-form-input last" ng-model="panel.repeat" ng-options="f.name as f.name for f in dashboard.templating.list">
<select class="input-small tight-form-input last" ng-model="panelCtrl.panel.repeat" ng-options="f.name as f.name for f in panelCtrl.dashboard.templating.list">
<option value=""></option>
</select>
</li>
......@@ -46,7 +46,7 @@
Min span
</li>
<li>
<select class="input-small tight-form-input last" ng-model="panel.minSpan" ng-options="f for f in [1,2,3,4,5,6,7,8,9,10,11,12]">
<select class="input-small tight-form-input last" ng-model="panelCtrl.panel.minSpan" ng-options="f for f in [1,2,3,4,5,6,7,8,9,10,11,12]">
<option value=""></option>
</select>
</li>
......@@ -56,6 +56,6 @@
</div>
</div>
<panel-links-editor panel="panel"></panel-links-editor>
<panel-links-editor panel="panelCtrl.panel"></panel-links-editor>
///<reference path="../../../headers/common.d.ts" />
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,
}
{
"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"
}
}
}
///<reference path="../../../headers/common.d.ts" />
export function unknownPanelDirective() {
return {
restrict: 'E',
template: `
<grafana-panel>
<div class="text-center" style="padding-top: 2rem">
Unknown panel type: <strong>{{panel.type}}</strong>
</div>
</grafana-panel>
`,
};
import {PanelDirective} from '../../../features/panel/panel';
export class UnknownPanel extends PanelDirective {
template = `<div class="text-center" style="padding-top: 2rem">
Unknown panel type: <strong>{{ctrl.panel.type}}</strong>
</div>`;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment