feat(panels): progress on new panel infrastructure, base classes

This commit is contained in:
Torkel Ödegaard 2016-01-25 15:09:37 -05:00
parent 73af4df96d
commit 9c6698e87b
15 changed files with 118 additions and 53 deletions

View File

@ -17,6 +17,7 @@ function (angular, _, $) {
self.state = {}; self.state = {};
self.panelScopes = []; self.panelScopes = [];
self.$scope = $scope; self.$scope = $scope;
self.dashboard = $scope.dashboard;
$scope.exitFullscreen = function() { $scope.exitFullscreen = function() {
if (self.state.fullscreen) { if (self.state.fullscreen) {
@ -74,7 +75,7 @@ function (angular, _, $) {
DashboardViewState.prototype.update = function(state, skipUrlSync) { DashboardViewState.prototype.update = function(state, skipUrlSync) {
_.extend(this.state, state); _.extend(this.state, state);
this.fullscreen = this.state.fullscreen; this.dashboard.meta.fullscreen = this.state.fullscreen;
if (!this.state.fullscreen) { if (!this.state.fullscreen) {
this.state.panelId = null; this.state.panelId = null;
@ -92,7 +93,7 @@ function (angular, _, $) {
DashboardViewState.prototype.syncState = function() { DashboardViewState.prototype.syncState = function() {
if (this.panelScopes.length === 0) { return; } if (this.panelScopes.length === 0) { return; }
if (this.fullscreen) { if (this.dashboard.meta.fullscreen) {
if (this.fullscreenPanel) { if (this.fullscreenPanel) {
this.leaveFullscreen(false); this.leaveFullscreen(false);
} }
@ -148,13 +149,13 @@ function (angular, _, $) {
ctrl.editMode = this.state.edit && this.$scope.dashboardMeta.canEdit; ctrl.editMode = this.state.edit && this.$scope.dashboardMeta.canEdit;
ctrl.height = ctrl.editMode ? editHeight : fullscreenHeight; ctrl.height = ctrl.editMode ? editHeight : fullscreenHeight;
ctrl.fullscreen = true;
this.oldTimeRange = ctrl.range; this.oldTimeRange = ctrl.range;
this.fullscreenPanel = panelScope; this.fullscreenPanel = panelScope;
$(window).scrollTop(0); $(window).scrollTop(0);
panelScope.fullscreen = true;
this.$scope.appEvent('panel-fullscreen-enter', {panelId: ctrl.panel.id}); this.$scope.appEvent('panel-fullscreen-enter', {panelId: ctrl.panel.id});
$timeout(function() { $timeout(function() {

View File

@ -3,18 +3,64 @@
import config from 'app/core/config'; import config from 'app/core/config';
import {PanelCtrl} from './panel_ctrl'; import {PanelCtrl} from './panel_ctrl';
function metricsEditorTab() {
return {templateUrl: 'public/app/partials/metrics.html'};
}
class MetricsPanelCtrl extends PanelCtrl { class MetricsPanelCtrl extends PanelCtrl {
constructor($scope) { error: boolean;
loading: boolean;
datasource: any;
constructor($scope, private $q, private datasourceSrv) {
super($scope); super($scope);
this.editorTabIndex = 1;
if (!this.panel.targets) {
this.panel.targets = [{}];
}
} }
initEditorTabs() { initEditorTabs() {
super.initEditorTabs(); this.addEditorTab('Metrics', () => {
this.editorTabs.push({title: 'Metrics', directiveFn: metricsEditorTab}); return { templateUrl: 'public/app/partials/metrics.html' };
});
}
refresh() {
this.getData();
}
refreshData(data) {
// null op
return data;
}
loadSnapshot(data) {
// null op
return data;
}
getData() {
if (this.otherPanelInFullscreenMode()) { return; }
if (this.panel.snapshotData) {
if (this.loadSnapshot) {
this.loadSnapshot(this.panel.snapshotData);
}
return;
}
delete this.error;
this.loading = true;
this.datasourceSrv.get(this.panel.datasource).then(datasource => {
this.datasource = datasource;
return this.refreshData(this.datasource) || this.$q.when({});
}).then(() => {
this.loading = false;
}, err => {
console.log('Panel data error:', err);
this.loading = false;
this.error = err.message || "Timeseries data request error";
this.inspector = {error: err};
});
} }
} }

View File

@ -29,7 +29,7 @@ class PanelDirective {
}; };
} }
link(scope) { link(scope, elem) {
return null; return null;
} }
} }

View File

@ -15,7 +15,8 @@ export class PanelCtrl {
icon: string; icon: string;
editorTabs: any; editorTabs: any;
$scope: any; $scope: any;
isMetricsPanel: boolean; fullscreen: boolean;
inspector: any;
constructor($scope) { constructor($scope) {
var plugin = config.panels[this.panel.type]; var plugin = config.panels[this.panel.type];
@ -77,4 +78,8 @@ export class PanelCtrl {
menu.push({text: 'Share', click: 'ctrl.share(); dismiss();'}); menu.push({text: 'Share', click: 'ctrl.share(); dismiss();'});
return menu; return menu;
} }
otherPanelInFullscreenMode() {
return this.dashboard.meta.fullscreen && !this.fullscreen;
}
} }

View File

@ -9,7 +9,7 @@ var directiveModule = angular.module('grafana.directives');
function panelEditorTab(dynamicDirectiveSrv) { function panelEditorTab(dynamicDirectiveSrv) {
return dynamicDirectiveSrv.create({ return dynamicDirectiveSrv.create({
scope: { scope: {
panelCtrl: "=", ctrl: "=",
editorTab: "=", editorTab: "=",
}, },
directive: scope => { directive: scope => {

View File

@ -1,4 +1,4 @@
<div class="panel-container" ng-class="{'panel-transparent': panel.transparent}"> <div class="panel-container" ng-class="{'panel-transparent': ctrl.panel.transparent}">
<div class="panel-header"> <div class="panel-header">
<span class="alert-error panel-error small pointer" config-modal="app/partials/inspector.html" ng-if="ctrl.error"> <span class="alert-error panel-error small pointer" config-modal="app/partials/inspector.html" ng-if="ctrl.error">
<span data-placement="top" bs-tooltip="ctrl.error"> <span data-placement="top" bs-tooltip="ctrl.error">
@ -39,7 +39,7 @@
<div class="gf-box-body"> <div class="gf-box-body">
<div ng-repeat="tab in ctrl.editorTabs" ng-if="ctrl.editorTabIndex === $index"> <div ng-repeat="tab in ctrl.editorTabs" ng-if="ctrl.editorTabIndex === $index">
<panel-editor-tab editor-tab="tab" panel-ctrl="ctrl"></panel-editor-tab> <panel-editor-tab editor-tab="tab" ctrl="ctrl"></panel-editor-tab>
</div> </div>
</div> </div>
</div> </div>

View File

@ -5,11 +5,11 @@ import angular from 'angular';
/** @ngInject */ /** @ngInject */
function metricsQueryEditor(dynamicDirectiveSrv, datasourceSrv) { function metricsQueryEditor(dynamicDirectiveSrv, datasourceSrv) {
return dynamicDirectiveSrv.create({ return dynamicDirectiveSrv.create({
watchPath: "panel.datasource", watchPath: "ctrl.panel.datasource",
directive: scope => { directive: scope => {
let datasource = scope.target.datasource || scope.panel.datasource; let datasource = scope.target.datasource || scope.ctrl.panel.datasource;
return datasourceSrv.get(datasource).then(ds => { return datasourceSrv.get(datasource).then(ds => {
scope.datasource = ds; scope.ctrl.datasource = ds;
if (!scope.target.refId) { if (!scope.target.refId) {
scope.target.refId = 'A'; scope.target.refId = 'A';
@ -29,9 +29,9 @@ function metricsQueryEditor(dynamicDirectiveSrv, datasourceSrv) {
/** @ngInject */ /** @ngInject */
function metricsQueryOptions(dynamicDirectiveSrv, datasourceSrv) { function metricsQueryOptions(dynamicDirectiveSrv, datasourceSrv) {
return dynamicDirectiveSrv.create({ return dynamicDirectiveSrv.create({
watchPath: "panel.datasource", watchPath: "ctrl.panel.datasource",
directive: scope => { directive: scope => {
return datasourceSrv.get(scope.panel.datasource).then(ds => { return datasourceSrv.get(scope.ctrl.panel.datasource).then(ds => {
return System.import(ds.meta.module).then(dsModule => { return System.import(ds.meta.module).then(dsModule => {
return { return {
name: 'metrics-query-options-' + ds.meta.id, name: 'metrics-query-options-' + ds.meta.id,

View File

@ -23,7 +23,7 @@
<div class="row-text pointer" ng-click="toggleRow(row)" ng-bind="row.title | interpolateTemplateVars:this"></div> <div class="row-text pointer" ng-click="toggleRow(row)" ng-bind="row.title | interpolateTemplateVars:this"></div>
</div> </div>
<div class="row-open" ng-show="!row.collapse"> <div class="row-open" ng-show="!row.collapse">
<div class='row-tab bgSuccess dropdown' ng-show="dashboardMeta.canEdit" ng-hide="dashboardViewState.fullscreen"> <div class='row-tab bgSuccess dropdown' ng-show="dashboardMeta.canEdit" ng-hide="dashboard.meta.fullscreen">
<span class="row-tab-button dropdown-toggle" data-toggle="dropdown"> <span class="row-tab-button dropdown-toggle" data-toggle="dropdown">
<i class="fa fa-bars"></i> <i class="fa fa-bars"></i>
</span> </span>
@ -79,7 +79,7 @@
<div class="row-text pointer" ng-click="toggleRow(row)" ng-if="row.showTitle" ng-bind="row.title | interpolateTemplateVars:this"> <div class="row-text pointer" ng-click="toggleRow(row)" ng-if="row.showTitle" ng-bind="row.title | interpolateTemplateVars:this">
</div> </div>
<div ng-repeat="panel in row.panels track by panel.id" class="panel" ui-draggable="!dashboardViewState.fullscreen" drag="panel.id" <div ng-repeat="panel in row.panels track by panel.id" class="panel" ui-draggable="!dashboard.meta.fullscreen" drag="panel.id"
ui-on-drop="onDrop($data, row, panel)" drag-handle-class="drag-handle" panel-width> ui-on-drop="onDrop($data, row, panel)" drag-handle-class="drag-handle" panel-width>
<panel-loader class="panel-margin" dashboard="dashboard" row="row" panel="panel"> <panel-loader class="panel-margin" dashboard="dashboard" row="row" panel="panel">
</panel-loader> </panel-loader>
@ -98,7 +98,7 @@
</div> </div>
</div> </div>
<div ng-show='dashboardMeta.canEdit' class="row-fluid add-row-panel-hint" ng-hide="dashboardViewState.fullscreen"> <div ng-show='dashboardMeta.canEdit' class="row-fluid add-row-panel-hint" ng-hide="dashboard.meta.fullscreen">
<div class="span12" style="text-align:right;"> <div class="span12" style="text-align:right;">
<span style="margin-right: 10px;" ng-click="addRowDefault()" class="pointer btn btn-info btn-small"> <span style="margin-right: 10px;" ng-click="addRowDefault()" class="pointer btn btn-info btn-small">
<span><i class="fa fa-plus"></i> ADD ROW</span> <span><i class="fa fa-plus"></i> ADD ROW</span>

View File

@ -1,25 +1,25 @@
<div class="editor-row"> <div class="editor-row">
<div class="tight-form-container"> <div class="tight-form-container">
<metrics-query-editor ng-repeat="target in panel.targets" ng-class="{'tight-form-disabled': target.hide}" > <metrics-query-editor ng-repeat="target in ctrl.panel.targets" ng-class="{'tight-form-disabled': target.hide}" >
</metrics-query-editor> </metrics-query-editor>
</div> </div>
<div style="margin: 20px 0 0 0"> <div style="margin: 20px 0 0 0">
<button class="btn btn-inverse" ng-click="addDataQuery()" ng-hide="datasource.meta.mixed"> <button class="btn btn-inverse" ng-click="ctrl.addDataQuery()" ng-hide="ctrl.datasource.meta.mixed">
<i class="fa fa-plus"></i>&nbsp; <i class="fa fa-plus"></i>&nbsp;
Query Query
</button> </button>
<div class="dropdown" ng-if="datasource.meta.mixed"> <div class="dropdown" ng-if="ctrl.datasource.meta.mixed">
<button class="btn btn-inverse dropdown-toggle" data-toggle="dropdown"> <button class="btn btn-inverse dropdown-toggle" data-toggle="dropdown">
<i class="fa fa-plus"></i>&nbsp; <i class="fa fa-plus"></i>&nbsp;
Query &nbsp; <span class="caret"></span> Query &nbsp; <span class="caret"></span>
</button> </button>
<ul class="dropdown-menu" role="menu"> <ul class="dropdown-menu" role="menu">
<li ng-repeat="datasource in datasources" role="menuitem" ng-hide="datasource.meta.builtIn"> <li ng-repeat="datasource in ctrl.getMetricSources()" role="menuitem" ng-hide="ctrl.datasource.meta.builtIn">
<a ng-click="addDataQuery(datasource);">{{datasource.name}}</a> <a ng-click="ctrl.addDataQuery(datasource);">{{datasource.name}}</a>
</li> </li>
</ul> </ul>
</div> </div>
@ -34,12 +34,12 @@
<div class="pull-right dropdown" style="margin-right: 10px;"> <div class="pull-right dropdown" style="margin-right: 10px;">
<button class="btn btn-inverse dropdown-toggle" data-toggle="dropdown" bs-tooltip="'Datasource'"> <button class="btn btn-inverse dropdown-toggle" data-toggle="dropdown" bs-tooltip="'Datasource'">
<i class="fa fa-database"></i>&nbsp; <i class="fa fa-database"></i>&nbsp;
{{datasource.name}} &nbsp; <span class="caret"></span> {{ctrl.datasource.name}} &nbsp; <span class="caret"></span>
</button> </button>
<ul class="dropdown-menu" role="menu"> <ul class="dropdown-menu" role="menu">
<li ng-repeat="datasource in datasources" role="menuitem"> <li ng-repeat="datasource in ctrl.getMetricSources()" role="menuitem">
<a ng-click="setDatasource(datasource);">{{datasource.name}}</a> <a ng-click="ctrl.setDatasource(datasource);">{{datasource.name}}</a>
</li> </li>
</ul> </ul>
</div> </div>

View File

@ -7,23 +7,23 @@
Title Title
</li> </li>
<li> <li>
<input type="text" class="input-xlarge tight-form-input" ng-model='panelCtrl.panel.title'></input> <input type="text" class="input-xlarge tight-form-input" ng-model='ctrl.panel.title'></input>
</li> </li>
<li class="tight-form-item"> <li class="tight-form-item">
Span Span
</li> </li>
<li> <li>
<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> <select class="input-mini tight-form-input" ng-model="ctrl.panel.span" ng-options="f for f in [0,1,2,3,4,5,6,7,8,9,10,11,12]"></select>
</li> </li>
<li class="tight-form-item"> <li class="tight-form-item">
Height Height
</li> </li>
<li> <li>
<input type="text" class="input-small tight-form-input" ng-model='panelCtrl.panel.height'></input> <input type="text" class="input-small tight-form-input" ng-model='ctrl.panel.height'></input>
</li> </li>
<li class="tight-form-item"> <li class="tight-form-item">
<label class="checkbox-label" for="panel.transparent">Transparent</label> <label class="checkbox-label" for="panel.transparent">Transparent</label>
<input class="cr1" id="panel.transparent" type="checkbox" ng-model="panelCtrl.panel.transparent" ng-checked="panelCtrl.panel.transparent"> <input class="cr1" id="panel.transparent" type="checkbox" ng-model="ctrl.panel.transparent" ng-checked="ctrl.panel.transparent">
<label for="panel.transparent" class="cr1"></label> <label for="panel.transparent" class="cr1"></label>
</li> </li>
</ul> </ul>
@ -38,7 +38,7 @@
Repeat Panel Repeat Panel
</li> </li>
<li> <li>
<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"> <select class="input-small tight-form-input last" ng-model="ctrl.panel.repeat" ng-options="f.name as f.name for f in ctrl.dashboard.templating.list">
<option value=""></option> <option value=""></option>
</select> </select>
</li> </li>
@ -46,7 +46,7 @@
Min span Min span
</li> </li>
<li> <li>
<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]"> <select class="input-small tight-form-input last" ng-model="ctrl.panel.minSpan" ng-options="f for f in [1,2,3,4,5,6,7,8,9,10,11,12]">
<option value=""></option> <option value=""></option>
</select> </select>
</li> </li>
@ -56,6 +56,6 @@
</div> </div>
</div> </div>
<panel-links-editor panel="panelCtrl.panel"></panel-links-editor> <panel-links-editor panel="ctrl.panel"></panel-links-editor>

View File

@ -5,7 +5,10 @@ function (GraphiteDatasource) {
'use strict'; 'use strict';
function metricsQueryEditor() { function metricsQueryEditor() {
return {controller: 'GraphiteQueryCtrl', templateUrl: 'app/plugins/datasource/graphite/partials/query.editor.html'}; return {
controller: 'GraphiteQueryCtrl',
templateUrl: 'app/plugins/datasource/graphite/partials/query.editor.html'
};
} }
function metricsQueryOptions() { function metricsQueryOptions() {

View File

@ -48,14 +48,14 @@
{{target.refId}} {{target.refId}}
</li> </li>
<li> <li>
<a class="tight-form-item" ng-click="target.hide = !target.hide; get_data();" role="menuitem"> <a class="tight-form-item" ng-click="target.hide = !target.hide; panelCtrl.getData();" role="menuitem">
<i class="fa fa-eye"></i> <i class="fa fa-eye"></i>
</a> </a>
</li> </li>
</ul> </ul>
<span style="display: block; overflow: hidden;"> <span style="display: block; overflow: hidden;">
<input type="text" class="tight-form-clear-input" style="width: 100%;" ng-model="target.target" give-focus="target.textEditor" spellcheck='false' ng-model-onblur ng-change="get_data()" ng-show="target.textEditor"></input> <input type="text" class="tight-form-clear-input" style="width: 100%;" ng-model="target.target" give-focus="target.textEditor" spellcheck='false' ng-model-onblur ng-change="panelCtrl.getData()" ng-show="target.textEditor"></input>
</span> </span>
<ul class="tight-form-list" role="menu" ng-hide="target.textEditor"> <ul class="tight-form-list" role="menu" ng-hide="target.textEditor">

View File

@ -11,6 +11,7 @@ function (angular, _, config, gfunc, Parser) {
var module = angular.module('grafana.controllers'); var module = angular.module('grafana.controllers');
module.controller('GraphiteQueryCtrl', function($scope, uiSegmentSrv, templateSrv) { module.controller('GraphiteQueryCtrl', function($scope, uiSegmentSrv, templateSrv) {
var panelCtrl = $scope.panelCtrl = $scope.ctrl;
$scope.init = function() { $scope.init = function() {
if ($scope.target) { if ($scope.target) {
@ -125,7 +126,7 @@ function (angular, _, config, gfunc, Parser) {
} }
var path = getSegmentPathUpTo(fromIndex + 1); var path = getSegmentPathUpTo(fromIndex + 1);
return $scope.datasource.metricFindQuery(path) return panelCtrl.datasource.metricFindQuery(path)
.then(function(segments) { .then(function(segments) {
if (segments.length === 0) { if (segments.length === 0) {
if (path !== '') { if (path !== '') {
@ -159,7 +160,7 @@ function (angular, _, config, gfunc, Parser) {
$scope.getAltSegments = function (index) { $scope.getAltSegments = function (index) {
var query = index === 0 ? '*' : getSegmentPathUpTo(index) + '.*'; var query = index === 0 ? '*' : getSegmentPathUpTo(index) + '.*';
return $scope.datasource.metricFindQuery(query).then(function(segments) { return panelCtrl.datasource.metricFindQuery(query).then(function(segments) {
var altSegments = _.map(segments, function(segment) { var altSegments = _.map(segments, function(segment) {
return uiSegmentSrv.newSegment({ value: segment.text, expandable: segment.expandable }); return uiSegmentSrv.newSegment({ value: segment.text, expandable: segment.expandable });
}); });
@ -208,7 +209,7 @@ function (angular, _, config, gfunc, Parser) {
$scope.targetTextChanged = function() { $scope.targetTextChanged = function() {
parseTarget(); parseTarget();
$scope.get_data(); $scope.ctrl.getData();
}; };
$scope.targetChanged = function() { $scope.targetChanged = function() {
@ -222,7 +223,7 @@ function (angular, _, config, gfunc, Parser) {
if ($scope.target.target !== oldTarget) { if ($scope.target.target !== oldTarget) {
if ($scope.segments[$scope.segments.length - 1].value !== 'select metric') { if ($scope.segments[$scope.segments.length - 1].value !== 'select metric') {
$scope.$parent.get_data(); $scope.ctrl.getData();
} }
} }
}; };

View File

@ -7,19 +7,28 @@ function optionsTab() {
} }
export class TestPanelCtrl extends MetricsPanelCtrl { export class TestPanelCtrl extends MetricsPanelCtrl {
constructor($scope) { data: any;
super($scope);
constructor($scope, $q, datasourceSrv) {
super($scope, $q, datasourceSrv);
} }
initEditorTabs() { initEditorTabs() {
super.initEditorTabs(); super.initEditorTabs();
this.editorTabs.push({title: 'Options', directiveFn: optionsTab}); }
refreshData(data) {
console.log('refreshData: ', data);
} }
} }
class TestPanel extends PanelDirective { class TestPanel extends PanelDirective {
templateUrl = `app/plugins/panel/test/module.html`; templateUrl = `app/plugins/panel/test/module.html`;
controller = TestPanelCtrl; controller = TestPanelCtrl;
link(scope, elem) {
console.log('test panel linking:', scope);
}
} }
export {TestPanel as Panel} export {TestPanel as Panel}

View File

@ -1,17 +1,17 @@
<div> <div>
<div class="row-fluid"> <div class="row-fluid">
<div class="span4"> <div class="span4">
<label class="small">Mode</label> <select class="input-medium" ng-model="panelCtrl.panel.mode" ng-options="f for f in ['html','markdown','text']"></select> <label class="small">Mode</label> <select class="input-medium" ng-model="ctrl.panel.mode" ng-options="f for f in ['html','markdown','text']"></select>
</div> </div>
<div class="span2" ng-show="panelCtrl.panel.mode == 'text'"> <div class="span2" ng-show="ctrl.panel.mode == 'text'">
<label class="small">Font Size</label> <select class="input-mini" ng-model="panelCtrl.panel.style['font-size']" ng-options="f for f in ['6pt','7pt','8pt','10pt','12pt','14pt','16pt','18pt','20pt','24pt','28pt','32pt','36pt','42pt','48pt','52pt','60pt','72pt']"></select> <label class="small">Font Size</label> <select class="input-mini" ng-model="ctrl.panel.style['font-size']" ng-options="f for f in ['6pt','7pt','8pt','10pt','12pt','14pt','16pt','18pt','20pt','24pt','28pt','32pt','36pt','42pt','48pt','52pt','60pt','72pt']"></select>
</div> </div>
</div> </div>
<label class=small>Content <label class=small>Content
<span ng-show="panelCtrl.panel.mode == 'markdown'">(This area uses <a target="_blank" href="http://en.wikipedia.org/wiki/Markdown">Markdown</a>. HTML is not supported)</span> <span ng-show="ctrl.panel.mode == 'markdown'">(This area uses <a target="_blank" href="http://en.wikipedia.org/wiki/Markdown">Markdown</a>. HTML is not supported)</span>
</label> </label>
<textarea ng-model="panelCtrl.panel.content" rows="20" style="width:95%" ng-change="panelCtrl.render()" ng-model-onblur> <textarea ng-model="ctrl.panel.content" rows="20" style="width:95%" ng-change="ctrl.render()" ng-model-onblur>
</textarea> </textarea>
</div> </div>