mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
feat(panel plugin): improving panel plugin model
This commit is contained in:
parent
ecdc730de7
commit
4f7fb40d9b
@ -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 () {});
|
||||
|
@ -1,15 +1,17 @@
|
||||
///<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;
|
||||
}
|
||||
}
|
||||
|
24
public/app/features/panel/panel_editor_tab.ts
Normal file
24
public/app/features/panel/panel_editor_tab.ts
Normal file
@ -0,0 +1,24 @@
|
||||
///<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 => {
|
||||
directive.templateUrl = null;
|
||||
directive.template = `<grafana-panel ctrl="ctrl">${template}</grafana-panel>`;
|
||||
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 = `<grafana-panel ctrl="ctrl">${template}</grafana-panel>`;
|
||||
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);
|
||||
|
@ -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);
|
||||
});
|
||||
|
56
public/app/features/panel/panel_meta3.ts
Normal file
56
public/app/features/panel/panel_meta3.ts
Normal file
@ -0,0 +1,56 @@
|
||||
///<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>
|
||||
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
///<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,
|
||||
}
|
||||
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,11 @@
|
||||
///<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>`;
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user