2017-02-04 14:30:24 +00:00
|
|
|
import angular from 'angular';
|
|
|
|
|
import Drop from 'tether-drop';
|
2017-11-22 14:46:17 +01:00
|
|
|
import PerfectScrollbar from 'perfect-scrollbar';
|
2016-02-01 12:42:10 +01:00
|
|
|
|
|
|
|
|
var module = angular.module('grafana.directives');
|
|
|
|
|
|
2016-02-05 11:05:47 +01:00
|
|
|
var panelTemplate = `
|
2016-09-30 17:37:47 +02:00
|
|
|
<div class="panel-container">
|
2017-08-18 17:39:07 +02:00
|
|
|
<div class="panel-header grid-drag-handle">
|
2016-12-16 16:08:32 +01:00
|
|
|
<span class="panel-info-corner">
|
2016-12-16 10:34:00 +01:00
|
|
|
<i class="fa"></i>
|
|
|
|
|
<span class="panel-info-corner-inner"></span>
|
2016-02-05 11:05:47 +01:00
|
|
|
</span>
|
|
|
|
|
|
|
|
|
|
<span class="panel-loading" ng-show="ctrl.loading">
|
|
|
|
|
<i class="fa fa-spinner fa-spin"></i>
|
|
|
|
|
</span>
|
|
|
|
|
|
2017-08-09 15:33:19 +02:00
|
|
|
<panel-header class="panel-title-container" panel-ctrl="ctrl"></panel-header>
|
2016-02-05 11:05:47 +01:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="panel-content">
|
2017-11-21 14:30:33 +01:00
|
|
|
<ng-transclude></ng-transclude>
|
2016-02-05 11:05:47 +01:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="panel-full-edit" ng-if="ctrl.editMode">
|
2016-02-24 10:32:22 +01:00
|
|
|
<div class="tabbed-view tabbed-view--panel-edit">
|
2016-02-23 17:31:19 +01:00
|
|
|
<div class="tabbed-view-header">
|
2017-10-11 22:10:33 +02:00
|
|
|
<h3 class="tabbed-view-panel-title">
|
2016-02-11 13:42:18 +01:00
|
|
|
{{ctrl.pluginName}}
|
2017-10-11 22:10:33 +02:00
|
|
|
</h3>
|
2016-02-05 11:05:47 +01:00
|
|
|
|
2016-02-23 17:31:19 +01:00
|
|
|
<ul class="gf-tabs">
|
|
|
|
|
<li class="gf-tabs-item" ng-repeat="tab in ::ctrl.editorTabs">
|
2016-05-19 08:42:21 +02:00
|
|
|
<a class="gf-tabs-link" ng-click="ctrl.changeTab($index)" ng-class="{active: ctrl.editorTabIndex === $index}">
|
2016-02-23 17:31:19 +01:00
|
|
|
{{::tab.title}}
|
|
|
|
|
</a>
|
|
|
|
|
</li>
|
|
|
|
|
</ul>
|
2016-02-05 11:05:47 +01:00
|
|
|
|
2016-02-23 17:31:19 +01:00
|
|
|
<button class="tabbed-view-close-btn" ng-click="ctrl.exitFullscreen();">
|
2016-02-24 10:32:22 +01:00
|
|
|
<i class="fa fa-remove"></i>
|
2016-02-05 11:05:47 +01:00
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
|
2016-02-23 17:31:19 +01:00
|
|
|
<div class="tabbed-view-body">
|
2016-02-05 11:05:47 +01:00
|
|
|
<div ng-repeat="tab in ctrl.editorTabs" ng-if="ctrl.editorTabIndex === $index">
|
|
|
|
|
<panel-editor-tab editor-tab="tab" ctrl="ctrl" index="$index"></panel-editor-tab>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
`;
|
|
|
|
|
|
2017-03-08 17:52:33 +01:00
|
|
|
module.directive('grafanaPanel', function($rootScope, $document) {
|
2016-02-01 12:42:10 +01:00
|
|
|
return {
|
|
|
|
|
restrict: 'E',
|
2016-02-05 11:05:47 +01:00
|
|
|
template: panelTemplate,
|
2016-02-01 12:42:10 +01:00
|
|
|
transclude: true,
|
|
|
|
|
scope: { ctrl: "=" },
|
|
|
|
|
link: function(scope, elem) {
|
|
|
|
|
var panelContainer = elem.find('.panel-container');
|
2017-11-16 15:33:12 +03:00
|
|
|
var panelContent = elem.find('.panel-content');
|
2016-12-16 16:08:32 +01:00
|
|
|
var cornerInfoElem = elem.find('.panel-info-corner');
|
2016-02-01 12:42:10 +01:00
|
|
|
var ctrl = scope.ctrl;
|
2016-12-16 10:34:00 +01:00
|
|
|
var infoDrop;
|
2017-11-22 09:05:33 +03:00
|
|
|
var panelScrollbar;
|
2016-09-30 17:37:47 +02:00
|
|
|
|
|
|
|
|
// the reason for handling these classes this way is for performance
|
|
|
|
|
// limit the watchers on panels etc
|
2016-11-16 09:43:55 +01:00
|
|
|
var transparentLastState = false;
|
|
|
|
|
var lastHasAlertRule = false;
|
2016-10-11 09:51:43 +02:00
|
|
|
var lastAlertState;
|
|
|
|
|
var hasAlertRule;
|
2017-11-22 13:32:54 +01:00
|
|
|
var lastHeight = 0;
|
2016-09-30 17:37:47 +02:00
|
|
|
|
2016-11-02 15:16:48 +01:00
|
|
|
function mouseEnter() {
|
|
|
|
|
panelContainer.toggleClass('panel-hover-highlight', true);
|
|
|
|
|
ctrl.dashboard.setPanelFocus(ctrl.panel.id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function mouseLeave() {
|
|
|
|
|
panelContainer.toggleClass('panel-hover-highlight', false);
|
|
|
|
|
ctrl.dashboard.setPanelFocus(0);
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-22 13:32:54 +01:00
|
|
|
function panelHeightUpdated() {
|
2017-11-23 20:41:16 +01:00
|
|
|
panelContent.css({height: ctrl.height + 'px'});
|
2017-11-22 09:05:33 +03:00
|
|
|
if (panelScrollbar) {
|
|
|
|
|
panelScrollbar.update();
|
|
|
|
|
}
|
2017-11-22 13:32:54 +01:00
|
|
|
lastHeight = ctrl.height;
|
2017-11-22 09:05:33 +03:00
|
|
|
}
|
|
|
|
|
|
2016-11-16 09:43:55 +01:00
|
|
|
// set initial transparency
|
|
|
|
|
if (ctrl.panel.transparent) {
|
|
|
|
|
transparentLastState = true;
|
|
|
|
|
panelContainer.addClass('panel-transparent', true);
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-22 13:32:54 +01:00
|
|
|
// update scrollbar after mounting
|
|
|
|
|
ctrl.events.on('component-did-mount', () => {
|
2017-11-22 14:46:17 +01:00
|
|
|
if (ctrl.__proto__.constructor.scrollable) {
|
2017-11-23 11:12:32 +01:00
|
|
|
panelScrollbar = new PerfectScrollbar(panelContent[0]);
|
2017-11-22 14:46:17 +01:00
|
|
|
}
|
2017-11-22 13:32:54 +01:00
|
|
|
});
|
|
|
|
|
|
2016-09-30 17:37:47 +02:00
|
|
|
ctrl.events.on('render', () => {
|
2017-11-22 13:32:54 +01:00
|
|
|
if (lastHeight !== ctrl.height) {
|
|
|
|
|
panelHeightUpdated();
|
|
|
|
|
}
|
2016-11-01 15:33:20 +01:00
|
|
|
|
2016-10-11 09:51:43 +02:00
|
|
|
if (transparentLastState !== ctrl.panel.transparent) {
|
|
|
|
|
panelContainer.toggleClass('panel-transparent', ctrl.panel.transparent === true);
|
|
|
|
|
transparentLastState = ctrl.panel.transparent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hasAlertRule = ctrl.panel.alert !== undefined;
|
|
|
|
|
if (lastHasAlertRule !== hasAlertRule) {
|
|
|
|
|
panelContainer.toggleClass('panel-has-alert', hasAlertRule);
|
2016-09-30 17:37:47 +02:00
|
|
|
|
2016-10-11 09:51:43 +02:00
|
|
|
lastHasAlertRule = hasAlertRule;
|
2016-09-30 17:37:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ctrl.alertState) {
|
2016-10-11 09:51:43 +02:00
|
|
|
if (lastAlertState) {
|
|
|
|
|
panelContainer.removeClass('panel-alert-state--' + lastAlertState);
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-30 17:37:47 +02:00
|
|
|
if (ctrl.alertState.state === 'ok' || ctrl.alertState.state === 'alerting') {
|
|
|
|
|
panelContainer.addClass('panel-alert-state--' + ctrl.alertState.state);
|
|
|
|
|
}
|
2016-10-11 09:51:43 +02:00
|
|
|
|
|
|
|
|
lastAlertState = ctrl.alertState.state;
|
|
|
|
|
} else if (lastAlertState) {
|
|
|
|
|
panelContainer.removeClass('panel-alert-state--' + lastAlertState);
|
|
|
|
|
lastAlertState = null;
|
2016-09-30 17:37:47 +02:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2016-12-16 12:46:29 +01:00
|
|
|
function updatePanelCornerInfo() {
|
|
|
|
|
var cornerMode = ctrl.getInfoMode();
|
2016-12-19 16:36:09 +01:00
|
|
|
cornerInfoElem[0].className = 'panel-info-corner panel-info-corner--' + cornerMode;
|
2016-12-16 10:34:00 +01:00
|
|
|
|
2016-12-16 12:46:29 +01:00
|
|
|
if (cornerMode) {
|
2016-12-16 10:34:00 +01:00
|
|
|
if (infoDrop) {
|
|
|
|
|
infoDrop.destroy();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
infoDrop = new Drop({
|
2016-12-16 16:08:32 +01:00
|
|
|
target: cornerInfoElem[0],
|
|
|
|
|
content: function() {
|
|
|
|
|
return ctrl.getInfoContent({mode: 'tooltip'});
|
|
|
|
|
},
|
2016-12-16 11:48:32 +01:00
|
|
|
classes: ctrl.error ? 'drop-error' : 'drop-help',
|
2016-12-16 10:34:00 +01:00
|
|
|
openOn: 'hover',
|
2016-12-16 21:16:35 +01:00
|
|
|
hoverOpenDelay: 100,
|
2017-03-29 11:16:16 +02:00
|
|
|
tetherOptions: {
|
|
|
|
|
attachment: 'bottom left',
|
|
|
|
|
targetAttachment: 'top left',
|
|
|
|
|
constraints: [
|
|
|
|
|
{
|
|
|
|
|
to: 'window',
|
|
|
|
|
attachment: 'together',
|
|
|
|
|
pin: true
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
}
|
2016-12-16 10:34:00 +01:00
|
|
|
});
|
|
|
|
|
}
|
2016-12-16 12:46:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
scope.$watchGroup(['ctrl.error', 'ctrl.panel.description'], updatePanelCornerInfo);
|
|
|
|
|
scope.$watchCollection('ctrl.panel.links', updatePanelCornerInfo);
|
2016-12-16 10:34:00 +01:00
|
|
|
|
2016-12-16 16:08:32 +01:00
|
|
|
cornerInfoElem.on('click', function() {
|
|
|
|
|
infoDrop.close();
|
|
|
|
|
scope.$apply(ctrl.openInspector.bind(ctrl));
|
|
|
|
|
});
|
|
|
|
|
|
2016-11-02 22:08:17 +01:00
|
|
|
elem.on('mouseenter', mouseEnter);
|
|
|
|
|
elem.on('mouseleave', mouseLeave);
|
2016-11-02 15:16:48 +01:00
|
|
|
|
|
|
|
|
scope.$on('$destroy', function() {
|
2016-11-02 22:08:17 +01:00
|
|
|
elem.off();
|
2016-12-16 16:08:32 +01:00
|
|
|
cornerInfoElem.off();
|
2016-12-16 10:34:00 +01:00
|
|
|
|
|
|
|
|
if (infoDrop) {
|
|
|
|
|
infoDrop.destroy();
|
|
|
|
|
}
|
2017-11-23 11:12:32 +01:00
|
|
|
|
|
|
|
|
if (panelScrollbar) {
|
|
|
|
|
panelScrollbar.update();
|
|
|
|
|
}
|
2016-11-02 15:16:48 +01:00
|
|
|
});
|
2016-02-01 12:42:10 +01:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
|
2016-12-16 10:34:00 +01:00
|
|
|
module.directive('panelHelpCorner', function($rootScope) {
|
|
|
|
|
return {
|
|
|
|
|
restrict: 'E',
|
|
|
|
|
template: `
|
2017-11-21 14:30:33 +01:00
|
|
|
<span class="alert-error panel-error small pointer" ng-if="ctrl.error" ng-click="ctrl.openInspector()">
|
|
|
|
|
<span data-placement="top" bs-tooltip="ctrl.error">
|
|
|
|
|
<i class="fa fa-exclamation"></i><span class="panel-error-arrow"></span>
|
|
|
|
|
</span>
|
|
|
|
|
</span>
|
2016-12-16 10:34:00 +01:00
|
|
|
`,
|
|
|
|
|
link: function(scope, elem) {
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
|
2016-02-01 12:42:10 +01:00
|
|
|
|