mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Merge pull request #11456 from alexanderzobnin/fix-11053
Migrating to baron scrollbar WIP
This commit is contained in:
commit
b481e1515d
@ -136,6 +136,7 @@
|
|||||||
"angular-route": "^1.6.6",
|
"angular-route": "^1.6.6",
|
||||||
"angular-sanitize": "^1.6.6",
|
"angular-sanitize": "^1.6.6",
|
||||||
"babel-polyfill": "^6.26.0",
|
"babel-polyfill": "^6.26.0",
|
||||||
|
"baron": "^3.0.3",
|
||||||
"brace": "^0.10.0",
|
"brace": "^0.10.0",
|
||||||
"classnames": "^2.2.5",
|
"classnames": "^2.2.5",
|
||||||
"clipboard": "^1.7.1",
|
"clipboard": "^1.7.1",
|
||||||
@ -151,7 +152,6 @@
|
|||||||
"moment": "^2.18.1",
|
"moment": "^2.18.1",
|
||||||
"mousetrap": "^1.6.0",
|
"mousetrap": "^1.6.0",
|
||||||
"mousetrap-global-bind": "^1.1.0",
|
"mousetrap-global-bind": "^1.1.0",
|
||||||
"perfect-scrollbar": "^1.2.0",
|
|
||||||
"prop-types": "^15.6.0",
|
"prop-types": "^15.6.0",
|
||||||
"react": "^16.2.0",
|
"react": "^16.2.0",
|
||||||
"react-dom": "^16.2.0",
|
"react-dom": "^16.2.0",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PerfectScrollbar from 'perfect-scrollbar';
|
import baron from 'baron';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
children: any;
|
children: any;
|
||||||
@ -8,31 +8,36 @@ export interface Props {
|
|||||||
|
|
||||||
export default class ScrollBar extends React.Component<Props, any> {
|
export default class ScrollBar extends React.Component<Props, any> {
|
||||||
private container: any;
|
private container: any;
|
||||||
private ps: PerfectScrollbar;
|
private scrollbar: baron;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.ps = new PerfectScrollbar(this.container, {
|
this.scrollbar = baron({
|
||||||
wheelPropagation: true,
|
root: this.container.parentElement,
|
||||||
|
scroller: this.container,
|
||||||
|
bar: '.baron__bar',
|
||||||
|
barOnCls: '_scrollbar',
|
||||||
|
scrollingCls: '_scrolling',
|
||||||
|
track: '.baron__track',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate() {
|
componentDidUpdate() {
|
||||||
this.ps.update();
|
this.scrollbar.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
this.ps.destroy();
|
this.scrollbar.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
// methods can be invoked by outside
|
// methods can be invoked by outside
|
||||||
setScrollTop(top) {
|
setScrollTop(top) {
|
||||||
if (this.container) {
|
if (this.container) {
|
||||||
this.container.scrollTop = top;
|
this.container.scrollTop = top;
|
||||||
this.ps.update();
|
this.scrollbar.update();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -42,7 +47,7 @@ export default class ScrollBar extends React.Component<Props, any> {
|
|||||||
setScrollLeft(left) {
|
setScrollLeft(left) {
|
||||||
if (this.container) {
|
if (this.container) {
|
||||||
this.container.scrollLeft = left;
|
this.container.scrollLeft = left;
|
||||||
this.ps.update();
|
this.scrollbar.update();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -55,8 +60,14 @@ export default class ScrollBar extends React.Component<Props, any> {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className={this.props.className} ref={this.handleRef}>
|
<div className="baron baron__root baron__clipper">
|
||||||
{this.props.children}
|
<div className={this.props.className + ' baron__scroller'} ref={this.handleRef}>
|
||||||
|
{this.props.children}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="baron__track">
|
||||||
|
<div className="baron__bar" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -167,6 +167,7 @@ export function grafanaAppDirective(playlistSrv, contextSrv, $timeout, $rootScop
|
|||||||
if (sidemenuHidden) {
|
if (sidemenuHidden) {
|
||||||
sidemenuHidden = false;
|
sidemenuHidden = false;
|
||||||
body.addClass('sidemenu-open');
|
body.addClass('sidemenu-open');
|
||||||
|
appEvents.emit('toggle-inactive-mode');
|
||||||
$timeout(function() {
|
$timeout(function() {
|
||||||
$rootScope.$broadcast('render');
|
$rootScope.$broadcast('render');
|
||||||
}, 100);
|
}, 100);
|
||||||
|
41
public/app/core/components/scroll/page_scroll.ts
Normal file
41
public/app/core/components/scroll/page_scroll.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import coreModule from 'app/core/core_module';
|
||||||
|
import appEvents from 'app/core/app_events';
|
||||||
|
|
||||||
|
export function pageScrollbar() {
|
||||||
|
return {
|
||||||
|
restrict: 'A',
|
||||||
|
link: function(scope, elem, attrs) {
|
||||||
|
let lastPos = 0;
|
||||||
|
|
||||||
|
appEvents.on(
|
||||||
|
'dash-scroll',
|
||||||
|
evt => {
|
||||||
|
if (evt.restore) {
|
||||||
|
elem[0].scrollTop = lastPos;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastPos = elem[0].scrollTop;
|
||||||
|
|
||||||
|
if (evt.animate) {
|
||||||
|
elem.animate({ scrollTop: evt.pos }, 500);
|
||||||
|
} else {
|
||||||
|
elem[0].scrollTop = evt.pos;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scope
|
||||||
|
);
|
||||||
|
|
||||||
|
scope.$on('$routeChangeSuccess', () => {
|
||||||
|
lastPos = 0;
|
||||||
|
elem[0].scrollTop = 0;
|
||||||
|
elem[0].focus();
|
||||||
|
});
|
||||||
|
|
||||||
|
elem[0].tabIndex = -1;
|
||||||
|
elem[0].focus();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
coreModule.directive('pageScrollbar', pageScrollbar);
|
@ -1,15 +1,44 @@
|
|||||||
import PerfectScrollbar from 'perfect-scrollbar';
|
import $ from 'jquery';
|
||||||
|
import baron from 'baron';
|
||||||
import coreModule from 'app/core/core_module';
|
import coreModule from 'app/core/core_module';
|
||||||
import appEvents from 'app/core/app_events';
|
import appEvents from 'app/core/app_events';
|
||||||
|
|
||||||
|
const scrollBarHTML = `
|
||||||
|
<div class="baron__track">
|
||||||
|
<div class="baron__bar"></div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
const scrollRootClass = 'baron baron__root';
|
||||||
|
const scrollerClass = 'baron__scroller';
|
||||||
|
|
||||||
export function geminiScrollbar() {
|
export function geminiScrollbar() {
|
||||||
return {
|
return {
|
||||||
restrict: 'A',
|
restrict: 'A',
|
||||||
link: function(scope, elem, attrs) {
|
link: function(scope, elem, attrs) {
|
||||||
let scrollbar = new PerfectScrollbar(elem[0], {
|
let scrollRoot = elem.parent();
|
||||||
wheelPropagation: true,
|
let scroller = elem;
|
||||||
wheelSpeed: 3,
|
|
||||||
});
|
if (attrs.grafanaScrollbar && attrs.grafanaScrollbar === 'scrollonroot') {
|
||||||
|
scrollRoot = scroller;
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollRoot.addClass(scrollRootClass);
|
||||||
|
$(scrollBarHTML).appendTo(scrollRoot);
|
||||||
|
elem.addClass(scrollerClass);
|
||||||
|
|
||||||
|
let scrollParams = {
|
||||||
|
root: scrollRoot[0],
|
||||||
|
scroller: scroller[0],
|
||||||
|
bar: '.baron__bar',
|
||||||
|
barOnCls: '_scrollbar',
|
||||||
|
scrollingCls: '_scrolling',
|
||||||
|
track: '.baron__track',
|
||||||
|
direction: 'v',
|
||||||
|
};
|
||||||
|
|
||||||
|
let scrollbar = baron(scrollParams);
|
||||||
|
|
||||||
let lastPos = 0;
|
let lastPos = 0;
|
||||||
|
|
||||||
appEvents.on(
|
appEvents.on(
|
||||||
@ -31,13 +60,24 @@ export function geminiScrollbar() {
|
|||||||
scope
|
scope
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// force updating dashboard width
|
||||||
|
appEvents.on('toggle-sidemenu', forceUpdate, scope);
|
||||||
|
appEvents.on('toggle-sidemenu-hidden', forceUpdate, scope);
|
||||||
|
appEvents.on('toggle-view-mode', forceUpdate, scope);
|
||||||
|
appEvents.on('toggle-kiosk-mode', forceUpdate, scope);
|
||||||
|
appEvents.on('toggle-inactive-mode', forceUpdate, scope);
|
||||||
|
|
||||||
|
function forceUpdate() {
|
||||||
|
scrollbar.scroll();
|
||||||
|
}
|
||||||
|
|
||||||
scope.$on('$routeChangeSuccess', () => {
|
scope.$on('$routeChangeSuccess', () => {
|
||||||
lastPos = 0;
|
lastPos = 0;
|
||||||
elem[0].scrollTop = 0;
|
elem[0].scrollTop = 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
scope.$on('$destroy', () => {
|
scope.$on('$destroy', () => {
|
||||||
scrollbar.destroy();
|
scrollbar.dispose();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
<div class="search-dropdown">
|
<div class="search-dropdown">
|
||||||
<div class="search-dropdown__col_1">
|
<div class="search-dropdown__col_1">
|
||||||
|
<div class="search-results-scroller">
|
||||||
<div class="search-results-container" grafana-scrollbar>
|
<div class="search-results-container" grafana-scrollbar>
|
||||||
<h6 ng-show="!ctrl.isLoading && ctrl.results.length === 0">No dashboards matching your query were found.</h6>
|
<h6 ng-show="!ctrl.isLoading && ctrl.results.length === 0">No dashboards matching your query were found.</h6>
|
||||||
<dashboard-search-results
|
<dashboard-search-results
|
||||||
@ -27,6 +28,7 @@
|
|||||||
on-folder-expanding="ctrl.folderExpanding()"
|
on-folder-expanding="ctrl.folderExpanding()"
|
||||||
on-folder-expanded="ctrl.folderExpanded($folder)" />
|
on-folder-expanded="ctrl.folderExpanded($folder)" />
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="search-dropdown__col_2">
|
<div class="search-dropdown__col_2">
|
||||||
|
@ -47,6 +47,7 @@ import { NavModelSrv, NavModel } from './nav_model_srv';
|
|||||||
import { userPicker } from './components/user_picker';
|
import { userPicker } from './components/user_picker';
|
||||||
import { teamPicker } from './components/team_picker';
|
import { teamPicker } from './components/team_picker';
|
||||||
import { geminiScrollbar } from './components/scroll/scroll';
|
import { geminiScrollbar } from './components/scroll/scroll';
|
||||||
|
import { pageScrollbar } from './components/scroll/page_scroll';
|
||||||
import { gfPageDirective } from './components/gf_page';
|
import { gfPageDirective } from './components/gf_page';
|
||||||
import { orgSwitcher } from './components/org_switcher';
|
import { orgSwitcher } from './components/org_switcher';
|
||||||
import { profiler } from './profiler';
|
import { profiler } from './profiler';
|
||||||
@ -85,6 +86,7 @@ export {
|
|||||||
userPicker,
|
userPicker,
|
||||||
teamPicker,
|
teamPicker,
|
||||||
geminiScrollbar,
|
geminiScrollbar,
|
||||||
|
pageScrollbar,
|
||||||
gfPageDirective,
|
gfPageDirective,
|
||||||
orgSwitcher,
|
orgSwitcher,
|
||||||
manageDashboardsDirective,
|
manageDashboardsDirective,
|
||||||
|
@ -103,7 +103,7 @@ export class AddPanelPanel extends React.Component<AddPanelPanelProps, AddPanelP
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className="panel-container">
|
<div className="panel-container add-panel-container">
|
||||||
<div className="add-panel">
|
<div className="add-panel">
|
||||||
<div className="add-panel__header">
|
<div className="add-panel__header">
|
||||||
<i className="gicon gicon-add-panel" />
|
<i className="gicon gicon-add-panel" />
|
||||||
|
@ -196,9 +196,10 @@ export class DashboardViewState {
|
|||||||
this.oldTimeRange = ctrl.range;
|
this.oldTimeRange = ctrl.range;
|
||||||
this.fullscreenPanel = panelScope;
|
this.fullscreenPanel = panelScope;
|
||||||
|
|
||||||
|
// Firefox doesn't return scrollTop postion properly if 'dash-scroll' is emitted after setViewMode()
|
||||||
|
this.$scope.appEvent('dash-scroll', { animate: false, pos: 0 });
|
||||||
this.dashboard.setViewMode(ctrl.panel, true, ctrl.editMode);
|
this.dashboard.setViewMode(ctrl.panel, true, ctrl.editMode);
|
||||||
this.$scope.appEvent('panel-fullscreen-enter', { panelId: ctrl.panel.id });
|
this.$scope.appEvent('panel-fullscreen-enter', { panelId: ctrl.panel.id });
|
||||||
this.$scope.appEvent('dash-scroll', { animate: false, pos: 0 });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
registerPanel(panelScope) {
|
registerPanel(panelScope) {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import angular from 'angular';
|
import angular from 'angular';
|
||||||
|
import $ from 'jquery';
|
||||||
import Drop from 'tether-drop';
|
import Drop from 'tether-drop';
|
||||||
import PerfectScrollbar from 'perfect-scrollbar';
|
import baron from 'baron';
|
||||||
|
|
||||||
var module = angular.module('grafana.directives');
|
var module = angular.module('grafana.directives');
|
||||||
|
|
||||||
@ -86,6 +87,9 @@ module.directive('grafanaPanel', function($rootScope, $document, $timeout) {
|
|||||||
|
|
||||||
function panelHeightUpdated() {
|
function panelHeightUpdated() {
|
||||||
panelContent.css({ height: ctrl.height + 'px' });
|
panelContent.css({ height: ctrl.height + 'px' });
|
||||||
|
}
|
||||||
|
|
||||||
|
function resizeScrollableContent() {
|
||||||
if (panelScrollbar) {
|
if (panelScrollbar) {
|
||||||
panelScrollbar.update();
|
panelScrollbar.update();
|
||||||
}
|
}
|
||||||
@ -100,9 +104,30 @@ module.directive('grafanaPanel', function($rootScope, $document, $timeout) {
|
|||||||
// update scrollbar after mounting
|
// update scrollbar after mounting
|
||||||
ctrl.events.on('component-did-mount', () => {
|
ctrl.events.on('component-did-mount', () => {
|
||||||
if (ctrl.__proto__.constructor.scrollable) {
|
if (ctrl.__proto__.constructor.scrollable) {
|
||||||
panelScrollbar = new PerfectScrollbar(panelContent[0], {
|
const scrollRootClass = 'baron baron__root baron__clipper panel-content--scrollable';
|
||||||
wheelPropagation: true,
|
const scrollerClass = 'baron__scroller';
|
||||||
|
const scrollBarHTML = `
|
||||||
|
<div class="baron__track">
|
||||||
|
<div class="baron__bar"></div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
let scrollRoot = panelContent;
|
||||||
|
let scroller = panelContent.find(':first').find(':first');
|
||||||
|
|
||||||
|
scrollRoot.addClass(scrollRootClass);
|
||||||
|
$(scrollBarHTML).appendTo(scrollRoot);
|
||||||
|
scroller.addClass(scrollerClass);
|
||||||
|
|
||||||
|
panelScrollbar = baron({
|
||||||
|
root: scrollRoot[0],
|
||||||
|
scroller: scroller[0],
|
||||||
|
bar: '.baron__bar',
|
||||||
|
barOnCls: '_scrollbar',
|
||||||
|
scrollingCls: '_scrolling',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
panelScrollbar.scroll();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -110,6 +135,7 @@ module.directive('grafanaPanel', function($rootScope, $document, $timeout) {
|
|||||||
ctrl.calculatePanelHeight();
|
ctrl.calculatePanelHeight();
|
||||||
panelHeightUpdated();
|
panelHeightUpdated();
|
||||||
$timeout(() => {
|
$timeout(() => {
|
||||||
|
resizeScrollableContent();
|
||||||
ctrl.render();
|
ctrl.render();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -199,7 +225,7 @@ module.directive('grafanaPanel', function($rootScope, $document, $timeout) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (panelScrollbar) {
|
if (panelScrollbar) {
|
||||||
panelScrollbar.update();
|
panelScrollbar.dispose();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -198,7 +198,9 @@ export class QueryVariable implements Variable {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if (sortType === 3) {
|
} else if (sortType === 3) {
|
||||||
options = _.sortBy(options, opt => { return _.toLower(opt.text); });
|
options = _.sortBy(options, opt => {
|
||||||
|
return _.toLower(opt.text);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reverseSort) {
|
if (reverseSort) {
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
<div dash-class ng-if="ctrl.dashboard">
|
<div dash-class ng-if="ctrl.dashboard">
|
||||||
<dashnav dashboard="ctrl.dashboard"></dashnav>
|
<dashnav dashboard="ctrl.dashboard"></dashnav>
|
||||||
|
|
||||||
<div class="scroll-canvas scroll-canvas--dashboard" grafana-scrollbar>
|
<div class="scroll-canvas scroll-canvas--dashboard" page-scrollbar>
|
||||||
<dashboard-settings dashboard="ctrl.dashboard"
|
<dashboard-settings dashboard="ctrl.dashboard"
|
||||||
ng-if="ctrl.dashboardViewState.state.editview"
|
ng-if="ctrl.dashboardViewState.state.editview"
|
||||||
class="dashboard-settings">
|
class="dashboard-settings">
|
||||||
</dashboard-settings>
|
</dashboard-settings>
|
||||||
|
|
||||||
<div class="dashboard-container">
|
<div class="dashboard-container">
|
||||||
<dashboard-submenu ng-if="ctrl.dashboard.meta.submenuEnabled" dashboard="ctrl.dashboard">
|
<dashboard-submenu ng-if="ctrl.dashboard.meta.submenuEnabled" dashboard="ctrl.dashboard">
|
||||||
</dashboard-submenu>
|
</dashboard-submenu>
|
||||||
|
|
||||||
<dashboard-grid get-panel-container="ctrl.getPanelContainer">
|
<dashboard-grid get-panel-container="ctrl.getPanelContainer">
|
||||||
</dashboard-grid>
|
</dashboard-grid>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,17 +1,19 @@
|
|||||||
<div class="dashlist" ng-repeat="group in ctrl.groups">
|
<div>
|
||||||
<div class="dashlist-section" ng-if="group.show">
|
<div class="dashlist" ng-repeat="group in ctrl.groups">
|
||||||
<h6 class="dashlist-section-header" ng-show="ctrl.panel.headings">
|
<div class="dashlist-section" ng-if="group.show">
|
||||||
{{group.header}}
|
<h6 class="dashlist-section-header" ng-show="ctrl.panel.headings">
|
||||||
</h6>
|
{{group.header}}
|
||||||
<div class="dashlist-item" ng-repeat="dash in group.list">
|
</h6>
|
||||||
<a class="dashlist-link dashlist-link-{{dash.type}}" href="{{dash.url}}">
|
<div class="dashlist-item" ng-repeat="dash in group.list">
|
||||||
<span class="dashlist-title">
|
<a class="dashlist-link dashlist-link-{{dash.type}}" href="{{dash.url}}">
|
||||||
{{dash.title}}
|
<span class="dashlist-title">
|
||||||
</span>
|
{{dash.title}}
|
||||||
<span class="dashlist-star" ng-click="ctrl.starDashboard(dash, $event)">
|
</span>
|
||||||
<i class="fa" ng-class="{'fa-star': dash.isStarred, 'fa-star-o': dash.isStarred === false}"></i>
|
<span class="dashlist-star" ng-click="ctrl.starDashboard(dash, $event)">
|
||||||
</span>
|
<i class="fa" ng-class="{'fa-star': dash.isStarred, 'fa-star-o': dash.isStarred === false}"></i>
|
||||||
</a>
|
</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import angular from 'angular';
|
import angular from 'angular';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import PerfectScrollbar from 'perfect-scrollbar';
|
import baron from 'baron';
|
||||||
|
|
||||||
var module = angular.module('grafana.directives');
|
var module = angular.module('grafana.directives');
|
||||||
|
|
||||||
@ -16,11 +16,10 @@ module.directive('graphLegend', function(popoverSrv, $timeout) {
|
|||||||
var i;
|
var i;
|
||||||
var legendScrollbar;
|
var legendScrollbar;
|
||||||
const legendRightDefaultWidth = 10;
|
const legendRightDefaultWidth = 10;
|
||||||
|
let legendElem = elem.parent();
|
||||||
|
|
||||||
scope.$on('$destroy', function() {
|
scope.$on('$destroy', function() {
|
||||||
if (legendScrollbar) {
|
destroyScrollbar();
|
||||||
legendScrollbar.destroy();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
ctrl.events.on('render-legend', () => {
|
ctrl.events.on('render-legend', () => {
|
||||||
@ -112,7 +111,7 @@ module.directive('graphLegend', function(popoverSrv, $timeout) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
let legendWidth = elem.width();
|
let legendWidth = legendElem.width();
|
||||||
if (!ctrl.panel.legend.show) {
|
if (!ctrl.panel.legend.show) {
|
||||||
elem.empty();
|
elem.empty();
|
||||||
firstRender = true;
|
firstRender = true;
|
||||||
@ -134,8 +133,8 @@ module.directive('graphLegend', function(popoverSrv, $timeout) {
|
|||||||
// Set width so it works with IE11
|
// Set width so it works with IE11
|
||||||
var width: any = panel.legend.rightSide && panel.legend.sideWidth ? panel.legend.sideWidth + 'px' : '';
|
var width: any = panel.legend.rightSide && panel.legend.sideWidth ? panel.legend.sideWidth + 'px' : '';
|
||||||
var ieWidth: any = panel.legend.rightSide && panel.legend.sideWidth ? panel.legend.sideWidth - 1 + 'px' : '';
|
var ieWidth: any = panel.legend.rightSide && panel.legend.sideWidth ? panel.legend.sideWidth - 1 + 'px' : '';
|
||||||
elem.css('min-width', width);
|
legendElem.css('min-width', width);
|
||||||
elem.css('width', ieWidth);
|
legendElem.css('width', ieWidth);
|
||||||
|
|
||||||
elem.toggleClass('graph-legend-table', panel.legend.alignAsTable === true);
|
elem.toggleClass('graph-legend-table', panel.legend.alignAsTable === true);
|
||||||
|
|
||||||
@ -241,8 +240,10 @@ module.directive('graphLegend', function(popoverSrv, $timeout) {
|
|||||||
tbodyElem.append(tableHeaderElem);
|
tbodyElem.append(tableHeaderElem);
|
||||||
tbodyElem.append(seriesElements);
|
tbodyElem.append(seriesElements);
|
||||||
elem.append(tbodyElem);
|
elem.append(tbodyElem);
|
||||||
|
tbodyElem.wrap('<div class="graph-legend-scroll"></div>');
|
||||||
} else {
|
} else {
|
||||||
elem.append(seriesElements);
|
elem.append('<div class="graph-legend-scroll"></div>');
|
||||||
|
elem.find('.graph-legend-scroll').append(seriesElements);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!panel.legend.rightSide || (panel.legend.rightSide && legendWidth !== legendRightDefaultWidth)) {
|
if (!panel.legend.rightSide || (panel.legend.rightSide && legendWidth !== legendRightDefaultWidth)) {
|
||||||
@ -253,23 +254,45 @@ module.directive('graphLegend', function(popoverSrv, $timeout) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function addScrollbar() {
|
function addScrollbar() {
|
||||||
const scrollbarOptions = {
|
const scrollRootClass = 'baron baron__root';
|
||||||
// Number of pixels the content height can surpass the container height without enabling the scroll bar.
|
const scrollerClass = 'baron__scroller';
|
||||||
scrollYMarginOffset: 2,
|
const scrollBarHTML = `
|
||||||
suppressScrollX: true,
|
<div class="baron__track">
|
||||||
wheelPropagation: true,
|
<div class="baron__bar"></div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
let scrollRoot = elem;
|
||||||
|
let scroller = elem.find('.graph-legend-scroll');
|
||||||
|
|
||||||
|
// clear existing scroll bar track to prevent duplication
|
||||||
|
scrollRoot.find('.baron__track').remove();
|
||||||
|
|
||||||
|
scrollRoot.addClass(scrollRootClass);
|
||||||
|
$(scrollBarHTML).appendTo(scrollRoot);
|
||||||
|
scroller.addClass(scrollerClass);
|
||||||
|
|
||||||
|
let scrollbarParams = {
|
||||||
|
root: scrollRoot[0],
|
||||||
|
scroller: scroller[0],
|
||||||
|
bar: '.baron__bar',
|
||||||
|
track: '.baron__track',
|
||||||
|
barOnCls: '_scrollbar',
|
||||||
|
scrollingCls: '_scrolling',
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!legendScrollbar) {
|
if (!legendScrollbar) {
|
||||||
legendScrollbar = new PerfectScrollbar(elem[0], scrollbarOptions);
|
legendScrollbar = baron(scrollbarParams);
|
||||||
} else {
|
} else {
|
||||||
legendScrollbar.update();
|
destroyScrollbar();
|
||||||
|
legendScrollbar = baron(scrollbarParams);
|
||||||
}
|
}
|
||||||
|
legendScrollbar.scroll();
|
||||||
}
|
}
|
||||||
|
|
||||||
function destroyScrollbar() {
|
function destroyScrollbar() {
|
||||||
if (legendScrollbar) {
|
if (legendScrollbar) {
|
||||||
legendScrollbar.destroy();
|
legendScrollbar.dispose();
|
||||||
legendScrollbar = undefined;
|
legendScrollbar = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,9 @@ var template = `
|
|||||||
<div class="graph-panel__chart" grafana-graph ng-dblclick="ctrl.zoomOut()">
|
<div class="graph-panel__chart" grafana-graph ng-dblclick="ctrl.zoomOut()">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="graph-legend" graph-legend></div>
|
<div class="graph-legend">
|
||||||
|
<div class="graph-legend-content" graph-legend></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
@ -1,5 +1,13 @@
|
|||||||
|
.add-panel-container {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.add-panel {
|
.add-panel {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
|
.baron__root {
|
||||||
|
height: calc(100% - 43px);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.add-panel__header {
|
.add-panel__header {
|
||||||
@ -39,7 +47,6 @@
|
|||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
height: calc(100% - 43px);
|
|
||||||
align-content: flex-start;
|
align-content: flex-start;
|
||||||
justify-content: space-around;
|
justify-content: space-around;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
@ -49,6 +49,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.graph-legend {
|
.graph-legend {
|
||||||
|
display: flex;
|
||||||
flex: 0 1 auto;
|
flex: 0 1 auto;
|
||||||
max-height: 30%;
|
max-height: 30%;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@ -56,11 +57,27 @@
|
|||||||
padding-top: 6px;
|
padding-top: 6px;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
|
// fix for Firefox (white stripe on the right of scrollbar)
|
||||||
|
width: calc(100% - 1px);
|
||||||
|
|
||||||
.popover-content {
|
.popover-content {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.graph-legend-content {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
// fix for Firefox (white stripe on the right of scrollbar)
|
||||||
|
width: calc(100% - 1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.graph-legend-scroll {
|
||||||
|
position: relative;
|
||||||
|
overflow: auto !important;
|
||||||
|
padding: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
.graph-legend-icon {
|
.graph-legend-icon {
|
||||||
position: relative;
|
position: relative;
|
||||||
padding-right: 4px;
|
padding-right: 4px;
|
||||||
@ -115,8 +132,20 @@
|
|||||||
// fix for phantomjs
|
// fix for phantomjs
|
||||||
.body--phantomjs {
|
.body--phantomjs {
|
||||||
.graph-panel--legend-right {
|
.graph-panel--legend-right {
|
||||||
|
.graph-legend {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.graph-panel__chart {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
.graph-legend-table {
|
.graph-legend-table {
|
||||||
display: table;
|
display: table;
|
||||||
|
|
||||||
|
.graph-legend-scroll {
|
||||||
|
display: table;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -124,9 +153,9 @@
|
|||||||
.graph-legend-table {
|
.graph-legend-table {
|
||||||
tbody {
|
tbody {
|
||||||
display: block;
|
display: block;
|
||||||
|
position: relative;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
height: 100%;
|
|
||||||
padding-bottom: 1px;
|
padding-bottom: 1px;
|
||||||
padding-right: 5px;
|
padding-right: 5px;
|
||||||
padding-left: 5px;
|
padding-left: 5px;
|
||||||
|
@ -9,6 +9,11 @@
|
|||||||
-ms-touch-action: auto;
|
-ms-touch-action: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ._scrollbar {
|
||||||
|
// overflow-x: hidden !important;
|
||||||
|
// overflow-y: auto;
|
||||||
|
// }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Scrollbar rail styles
|
* Scrollbar rail styles
|
||||||
*/
|
*/
|
||||||
@ -101,7 +106,7 @@
|
|||||||
opacity: 0.9;
|
opacity: 0.9;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Srollbars
|
// Scrollbars
|
||||||
//
|
//
|
||||||
|
|
||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
@ -172,3 +177,120 @@
|
|||||||
border-top: 1px solid $scrollbarBorder;
|
border-top: 1px solid $scrollbarBorder;
|
||||||
border-left: 1px solid $scrollbarBorder;
|
border-left: 1px solid $scrollbarBorder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Baron styles
|
||||||
|
|
||||||
|
.baron {
|
||||||
|
// display: inline-block; // this brakes phantomjs rendering (width becomes 0)
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fix for side menu on mobile devices
|
||||||
|
.main-view.baron {
|
||||||
|
width: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.baron__clipper {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.baron__scroller {
|
||||||
|
overflow-y: scroll;
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
border: 0;
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
/* remove line to customize scrollbar in iOs */
|
||||||
|
}
|
||||||
|
|
||||||
|
.baron__scroller::-webkit-scrollbar {
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.baron__track {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.baron._scrollbar .baron__track {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.baron__free {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.baron__bar {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
z-index: 1;
|
||||||
|
// width: 10px;
|
||||||
|
background: #999;
|
||||||
|
|
||||||
|
// height: 15px;
|
||||||
|
width: 15px;
|
||||||
|
transition: background-color 0.2s linear, opacity 0.2s linear;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.baron._scrollbar .baron__bar {
|
||||||
|
display: block;
|
||||||
|
|
||||||
|
@include gradient-vertical($scrollbarBackground, $scrollbarBackground2);
|
||||||
|
border-radius: 6px;
|
||||||
|
width: 6px;
|
||||||
|
/* there must be 'right' for ps__thumb-y */
|
||||||
|
right: 0px;
|
||||||
|
/* please don't change 'position' */
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
|
// background-color: transparent;
|
||||||
|
// opacity: 0.6;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
// background-color: transparent;
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-hover-highlight .baron__track .baron__bar {
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.baron._scrolling > .baron__track .baron__bar {
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fix for phantomjs
|
||||||
|
.body--phantomjs .baron__track .baron__bar {
|
||||||
|
opacity: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.baron__control {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.baron.panel-content--scrollable {
|
||||||
|
// Width needs to be set to prevent content width issues
|
||||||
|
// Set to less than 100% for fixing Firefox issue (white stripe on the right of scrollbar)
|
||||||
|
width: calc(100% - 2px);
|
||||||
|
|
||||||
|
.baron__scroller {
|
||||||
|
padding-top: 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -102,14 +102,21 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.search-results-scroller {
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
.search-results-container {
|
.search-results-container {
|
||||||
height: 100%;
|
|
||||||
display: block;
|
display: block;
|
||||||
padding: $spacer;
|
padding: $spacer;
|
||||||
position: relative;
|
position: relative;
|
||||||
flex-grow: 10;
|
flex-grow: 10;
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
|
|
||||||
|
// Fix for search scroller in mobile view
|
||||||
|
height: unset;
|
||||||
|
|
||||||
.label-tag {
|
.label-tag {
|
||||||
margin-left: 6px;
|
margin-left: 6px;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
|
@ -28,12 +28,20 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
|
||||||
&--dashboard {
|
&--dashboard {
|
||||||
height: calc(100% - 56px);
|
height: calc(100% - 56px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fix for phantomjs
|
||||||
|
.body--phantomjs {
|
||||||
|
.scroll-canvas {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.page-body {
|
.page-body {
|
||||||
padding-top: $spacer*2;
|
padding-top: $spacer*2;
|
||||||
min-height: 500px;
|
min-height: 500px;
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
<link rel="icon" type="image/png" href="public/img/fav32.png">
|
<link rel="icon" type="image/png" href="public/img/fav32.png">
|
||||||
<link rel="mask-icon" href="public/img/grafana_mask_icon.svg" color="#F05A28">
|
<link rel="mask-icon" href="public/img/grafana_mask_icon.svg" color="#F05A28">
|
||||||
<link rel="apple-touch-icon" href="public/img/fav32.png">
|
<link rel="apple-touch-icon" href="public/img/fav32.png">
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body ng-cloak class="theme-[[ .Theme ]]">
|
<body ng-cloak class="theme-[[ .Theme ]]">
|
||||||
@ -40,7 +40,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="main-view">
|
<div class="main-view">
|
||||||
<div class="scroll-canvas" grafana-scrollbar>
|
<div class="scroll-canvas" page-scrollbar>
|
||||||
<div ng-view></div>
|
<div ng-view></div>
|
||||||
|
|
||||||
<footer class="footer">
|
<footer class="footer">
|
||||||
|
@ -1162,6 +1162,10 @@ balanced-match@^1.0.0:
|
|||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
|
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
|
||||||
|
|
||||||
|
baron@^3.0.3:
|
||||||
|
version "3.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/baron/-/baron-3.0.3.tgz#0f0a08a567062882e130a0ecfd41a46d52103f4a"
|
||||||
|
|
||||||
base64-arraybuffer@0.1.5:
|
base64-arraybuffer@0.1.5:
|
||||||
version "0.1.5"
|
version "0.1.5"
|
||||||
resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8"
|
resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8"
|
||||||
@ -7503,10 +7507,6 @@ pend@~1.2.0:
|
|||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
|
resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
|
||||||
|
|
||||||
perfect-scrollbar@^1.2.0:
|
|
||||||
version "1.2.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/perfect-scrollbar/-/perfect-scrollbar-1.2.0.tgz#ad23a2529c17f4535f21d1486f8bc3046e31a9d2"
|
|
||||||
|
|
||||||
performance-now@^0.2.0:
|
performance-now@^0.2.0:
|
||||||
version "0.2.0"
|
version "0.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5"
|
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5"
|
||||||
|
Loading…
Reference in New Issue
Block a user