Merge branch 'master' into settings-icons-fix

pull/11572/head
Marcus Efraimsson 7 years ago
commit 060cd6ebef
No known key found for this signature in database
GPG Key ID: EBFE0FB04612DD4A
  1. 3
      CHANGELOG.md
  2. 34
      docs/sources/features/datasources/cloudwatch.md
  3. 2
      package.json
  4. 2
      pkg/services/sqlstore/annotation.go
  5. 31
      public/app/core/components/ScrollBar/ScrollBar.tsx
  6. 1
      public/app/core/components/grafana_app.ts
  7. 41
      public/app/core/components/scroll/page_scroll.ts
  8. 52
      public/app/core/components/scroll/scroll.ts
  9. 2
      public/app/core/components/search/search.html
  10. 2
      public/app/core/core.ts
  11. 2
      public/app/features/dashboard/dashgrid/AddPanelPanel.tsx
  12. 3
      public/app/features/dashboard/view_state_srv.ts
  13. 34
      public/app/features/panel/panel_directive.ts
  14. 4
      public/app/features/templating/query_variable.ts
  15. 24
      public/app/partials/dashboard.html
  16. 30
      public/app/plugins/panel/dashlist/module.html
  17. 55
      public/app/plugins/panel/graph/legend.ts
  18. 4
      public/app/plugins/panel/graph/template.ts
  19. 9
      public/sass/components/_panel_add_panel.scss
  20. 31
      public/sass/components/_panel_graph.scss
  21. 124
      public/sass/components/_scrollbar.scss
  22. 9
      public/sass/components/_search.scss
  23. 8
      public/sass/layout/_page.scss
  24. 4
      public/views/index.template.html
  25. 15
      scripts/circle-test-backend.sh
  26. 8
      yarn.lock

@ -28,7 +28,8 @@
* **AuthProxy**: Support IPv6 in Auth proxy white list [#11330](https://github.com/grafana/grafana/pull/11330), thx [@corny](https://github.com/corny)
* **SMTP**: Don't connect to STMP server using TLS unless configured. [#7189](https://github.com/grafana/grafana/issues/7189)
* **Prometheus**: Escape backslash in labels correctly. [#10555](https://github.com/grafana/grafana/issues/10555), thx [@roidelapluie](https://github.com/roidelapluie)
* **Variables** Case-insensitive sorting for template values [#11128](https://github.com/grafana/grafana/issues/11128) thx [@cross](https://github.com/cross)
* **Variables**: Case-insensitive sorting for template values [#11128](https://github.com/grafana/grafana/issues/11128) thx [@cross](https://github.com/cross)
* **Annotations (native)**: Change default limit from 10 to 100 when querying api [#11569](https://github.com/grafana/grafana/issues/11569), thx [@flopp999](https://github.com/flopp999)
# 5.0.4 (2018-03-28)

@ -43,6 +43,40 @@ server is running on AWS you can use IAM Roles and authentication will be handle
Checkout AWS docs on [IAM Roles](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html)
## IAM Policies
Grafana needs permissions granted via IAM to be able to read CloudWatch metrics
and EC2 tags/instances. You can attach these permissions to IAM roles and
utilize Grafana's built-in support for assuming roles.
Here is a minimal policy example:
```json
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowReadingMetricsFromCloudWatch",
"Effect": "Allow",
"Action": [
"cloudwatch:ListMetrics",
"cloudwatch:GetMetricStatistics"
],
"Resource": "*"
},
{
"Sid": "AllowReadingTagsFromEC2",
"Effect": "Allow",
"Action": [
"ec2:DescribeTags",
"ec2:DescribeInstances"
],
"Resource": "*"
}
]
}
```
### AWS credentials file
Create a file at `~/.aws/credentials`. That is the `HOME` path for user running grafana-server.

@ -136,6 +136,7 @@
"angular-route": "^1.6.6",
"angular-sanitize": "^1.6.6",
"babel-polyfill": "^6.26.0",
"baron": "^3.0.3",
"brace": "^0.10.0",
"classnames": "^2.2.5",
"clipboard": "^1.7.1",
@ -151,7 +152,6 @@
"moment": "^2.18.1",
"mousetrap": "^1.6.0",
"mousetrap-global-bind": "^1.1.0",
"perfect-scrollbar": "^1.2.0",
"prop-types": "^15.6.0",
"react": "^16.2.0",
"react-dom": "^16.2.0",

@ -202,7 +202,7 @@ func (r *SqlAnnotationRepo) Find(query *annotations.ItemQuery) ([]*annotations.I
}
if query.Limit == 0 {
query.Limit = 10
query.Limit = 100
}
sql.WriteString(fmt.Sprintf(" ORDER BY epoch DESC LIMIT %v", query.Limit))

@ -1,5 +1,5 @@
import React from 'react';
import PerfectScrollbar from 'perfect-scrollbar';
import baron from 'baron';
export interface Props {
children: any;
@ -8,31 +8,36 @@ export interface Props {
export default class ScrollBar extends React.Component<Props, any> {
private container: any;
private ps: PerfectScrollbar;
private scrollbar: baron;
constructor(props) {
super(props);
}
componentDidMount() {
this.ps = new PerfectScrollbar(this.container, {
wheelPropagation: true,
this.scrollbar = baron({
root: this.container.parentElement,
scroller: this.container,
bar: '.baron__bar',
barOnCls: '_scrollbar',
scrollingCls: '_scrolling',
track: '.baron__track',
});
}
componentDidUpdate() {
this.ps.update();
this.scrollbar.update();
}
componentWillUnmount() {
this.ps.destroy();
this.scrollbar.dispose();
}
// methods can be invoked by outside
setScrollTop(top) {
if (this.container) {
this.container.scrollTop = top;
this.ps.update();
this.scrollbar.update();
return true;
}
@ -42,7 +47,7 @@ export default class ScrollBar extends React.Component<Props, any> {
setScrollLeft(left) {
if (this.container) {
this.container.scrollLeft = left;
this.ps.update();
this.scrollbar.update();
return true;
}
@ -55,8 +60,14 @@ export default class ScrollBar extends React.Component<Props, any> {
render() {
return (
<div className={this.props.className} ref={this.handleRef}>
{this.props.children}
<div className="baron baron__root baron__clipper">
<div className={this.props.className + ' baron__scroller'} ref={this.handleRef}>
{this.props.children}
</div>
<div className="baron__track">
<div className="baron__bar" />
</div>
</div>
);
}

@ -167,6 +167,7 @@ export function grafanaAppDirective(playlistSrv, contextSrv, $timeout, $rootScop
if (sidemenuHidden) {
sidemenuHidden = false;
body.addClass('sidemenu-open');
appEvents.emit('toggle-inactive-mode');
$timeout(function() {
$rootScope.$broadcast('render');
}, 100);

@ -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 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() {
return {
restrict: 'A',
link: function(scope, elem, attrs) {
let scrollbar = new PerfectScrollbar(elem[0], {
wheelPropagation: true,
wheelSpeed: 3,
});
let scrollRoot = elem.parent();
let scroller = elem;
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;
appEvents.on(
@ -31,13 +60,24 @@ export function geminiScrollbar() {
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', () => {
lastPos = 0;
elem[0].scrollTop = 0;
});
scope.$on('$destroy', () => {
scrollbar.destroy();
scrollbar.dispose();
});
},
};

@ -19,6 +19,7 @@
<div class="search-dropdown">
<div class="search-dropdown__col_1">
<div class="search-results-scroller">
<div class="search-results-container" grafana-scrollbar>
<h6 ng-show="!ctrl.isLoading && ctrl.results.length === 0">No dashboards matching your query were found.</h6>
<dashboard-search-results
@ -27,6 +28,7 @@
on-folder-expanding="ctrl.folderExpanding()"
on-folder-expanded="ctrl.folderExpanded($folder)" />
</div>
</div>
</div>
<div class="search-dropdown__col_2">

@ -47,6 +47,7 @@ import { NavModelSrv, NavModel } from './nav_model_srv';
import { userPicker } from './components/user_picker';
import { teamPicker } from './components/team_picker';
import { geminiScrollbar } from './components/scroll/scroll';
import { pageScrollbar } from './components/scroll/page_scroll';
import { gfPageDirective } from './components/gf_page';
import { orgSwitcher } from './components/org_switcher';
import { profiler } from './profiler';
@ -85,6 +86,7 @@ export {
userPicker,
teamPicker,
geminiScrollbar,
pageScrollbar,
gfPageDirective,
orgSwitcher,
manageDashboardsDirective,

@ -103,7 +103,7 @@ export class AddPanelPanel extends React.Component<AddPanelPanelProps, AddPanelP
render() {
return (
<div className="panel-container">
<div className="panel-container add-panel-container">
<div className="add-panel">
<div className="add-panel__header">
<i className="gicon gicon-add-panel" />

@ -196,9 +196,10 @@ export class DashboardViewState {
this.oldTimeRange = ctrl.range;
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.$scope.appEvent('panel-fullscreen-enter', { panelId: ctrl.panel.id });
this.$scope.appEvent('dash-scroll', { animate: false, pos: 0 });
}
registerPanel(panelScope) {

@ -1,6 +1,7 @@
import angular from 'angular';
import $ from 'jquery';
import Drop from 'tether-drop';
import PerfectScrollbar from 'perfect-scrollbar';
import baron from 'baron';
var module = angular.module('grafana.directives');
@ -86,6 +87,9 @@ module.directive('grafanaPanel', function($rootScope, $document, $timeout) {
function panelHeightUpdated() {
panelContent.css({ height: ctrl.height + 'px' });
}
function resizeScrollableContent() {
if (panelScrollbar) {
panelScrollbar.update();
}
@ -100,9 +104,30 @@ module.directive('grafanaPanel', function($rootScope, $document, $timeout) {
// update scrollbar after mounting
ctrl.events.on('component-did-mount', () => {
if (ctrl.__proto__.constructor.scrollable) {
panelScrollbar = new PerfectScrollbar(panelContent[0], {
wheelPropagation: true,
const scrollRootClass = 'baron baron__root baron__clipper panel-content--scrollable';
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();
panelHeightUpdated();
$timeout(() => {
resizeScrollableContent();
ctrl.render();
});
});
@ -199,7 +225,7 @@ module.directive('grafanaPanel', function($rootScope, $document, $timeout) {
}
if (panelScrollbar) {
panelScrollbar.update();
panelScrollbar.dispose();
}
});
},

@ -198,7 +198,9 @@ export class QueryVariable implements Variable {
}
});
} else if (sortType === 3) {
options = _.sortBy(options, opt => { return _.toLower(opt.text); });
options = _.sortBy(options, opt => {
return _.toLower(opt.text);
});
}
if (reverseSort) {

@ -1,18 +1,18 @@
<div dash-class ng-if="ctrl.dashboard">
<dashnav dashboard="ctrl.dashboard"></dashnav>
<div class="scroll-canvas scroll-canvas--dashboard" grafana-scrollbar>
<dashboard-settings dashboard="ctrl.dashboard"
ng-if="ctrl.dashboardViewState.state.editview"
class="dashboard-settings">
</dashboard-settings>
<div class="scroll-canvas scroll-canvas--dashboard" page-scrollbar>
<dashboard-settings dashboard="ctrl.dashboard"
ng-if="ctrl.dashboardViewState.state.editview"
class="dashboard-settings">
</dashboard-settings>
<div class="dashboard-container">
<dashboard-submenu ng-if="ctrl.dashboard.meta.submenuEnabled" dashboard="ctrl.dashboard">
</dashboard-submenu>
<div class="dashboard-container">
<dashboard-submenu ng-if="ctrl.dashboard.meta.submenuEnabled" dashboard="ctrl.dashboard">
</dashboard-submenu>
<dashboard-grid get-panel-container="ctrl.getPanelContainer">
</dashboard-grid>
</div>
</div>
<dashboard-grid get-panel-container="ctrl.getPanelContainer">
</dashboard-grid>
</div>
</div>
</div>

@ -1,17 +1,19 @@
<div class="dashlist" ng-repeat="group in ctrl.groups">
<div class="dashlist-section" ng-if="group.show">
<h6 class="dashlist-section-header" ng-show="ctrl.panel.headings">
{{group.header}}
</h6>
<div class="dashlist-item" ng-repeat="dash in group.list">
<a class="dashlist-link dashlist-link-{{dash.type}}" href="{{dash.url}}">
<span class="dashlist-title">
{{dash.title}}
</span>
<span class="dashlist-star" ng-click="ctrl.starDashboard(dash, $event)">
<i class="fa" ng-class="{'fa-star': dash.isStarred, 'fa-star-o': dash.isStarred === false}"></i>
</span>
</a>
<div>
<div class="dashlist" ng-repeat="group in ctrl.groups">
<div class="dashlist-section" ng-if="group.show">
<h6 class="dashlist-section-header" ng-show="ctrl.panel.headings">
{{group.header}}
</h6>
<div class="dashlist-item" ng-repeat="dash in group.list">
<a class="dashlist-link dashlist-link-{{dash.type}}" href="{{dash.url}}">
<span class="dashlist-title">
{{dash.title}}
</span>
<span class="dashlist-star" ng-click="ctrl.starDashboard(dash, $event)">
<i class="fa" ng-class="{'fa-star': dash.isStarred, 'fa-star-o': dash.isStarred === false}"></i>
</span>
</a>
</div>
</div>
</div>
</div>

@ -1,7 +1,7 @@
import angular from 'angular';
import _ from 'lodash';
import $ from 'jquery';
import PerfectScrollbar from 'perfect-scrollbar';
import baron from 'baron';
var module = angular.module('grafana.directives');
@ -16,11 +16,10 @@ module.directive('graphLegend', function(popoverSrv, $timeout) {
var i;
var legendScrollbar;
const legendRightDefaultWidth = 10;
let legendElem = elem.parent();
scope.$on('$destroy', function() {
if (legendScrollbar) {
legendScrollbar.destroy();
}
destroyScrollbar();
});
ctrl.events.on('render-legend', () => {
@ -112,7 +111,7 @@ module.directive('graphLegend', function(popoverSrv, $timeout) {
}
function render() {
let legendWidth = elem.width();
let legendWidth = legendElem.width();
if (!ctrl.panel.legend.show) {
elem.empty();
firstRender = true;
@ -134,8 +133,8 @@ module.directive('graphLegend', function(popoverSrv, $timeout) {
// Set width so it works with IE11
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' : '';
elem.css('min-width', width);
elem.css('width', ieWidth);
legendElem.css('min-width', width);
legendElem.css('width', ieWidth);
elem.toggleClass('graph-legend-table', panel.legend.alignAsTable === true);
@ -241,8 +240,10 @@ module.directive('graphLegend', function(popoverSrv, $timeout) {
tbodyElem.append(tableHeaderElem);
tbodyElem.append(seriesElements);
elem.append(tbodyElem);
tbodyElem.wrap('<div class="graph-legend-scroll"></div>');
} 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)) {
@ -253,23 +254,45 @@ module.directive('graphLegend', function(popoverSrv, $timeout) {
}
function addScrollbar() {
const scrollbarOptions = {
// Number of pixels the content height can surpass the container height without enabling the scroll bar.
scrollYMarginOffset: 2,
suppressScrollX: true,
wheelPropagation: true,
const scrollRootClass = 'baron baron__root';
const scrollerClass = 'baron__scroller';
const scrollBarHTML = `
<div class="baron__track">
<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) {
legendScrollbar = new PerfectScrollbar(elem[0], scrollbarOptions);
legendScrollbar = baron(scrollbarParams);
} else {
legendScrollbar.update();
destroyScrollbar();
legendScrollbar = baron(scrollbarParams);
}
legendScrollbar.scroll();
}
function destroyScrollbar() {
if (legendScrollbar) {
legendScrollbar.destroy();
legendScrollbar.dispose();
legendScrollbar = undefined;
}
}

@ -3,7 +3,9 @@ var template = `
<div class="graph-panel__chart" grafana-graph ng-dblclick="ctrl.zoomOut()">
</div>
<div class="graph-legend" graph-legend></div>
<div class="graph-legend">
<div class="graph-legend-content" graph-legend></div>
</div>
</div>
`;

@ -1,5 +1,13 @@
.add-panel-container {
height: 100%;
}
.add-panel {
height: 100%;
.baron__root {
height: calc(100% - 43px);
}
}
.add-panel__header {
@ -39,7 +47,6 @@
flex-direction: row;
flex-wrap: wrap;
overflow: auto;
height: calc(100% - 43px);
align-content: flex-start;
justify-content: space-around;
position: relative;

@ -49,6 +49,7 @@
}
.graph-legend {
display: flex;
flex: 0 1 auto;
max-height: 30%;
margin: 0;
@ -56,11 +57,27 @@
padding-top: 6px;
position: relative;
// fix for Firefox (white stripe on the right of scrollbar)
width: calc(100% - 1px);
.popover-content {
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 {
position: relative;
padding-right: 4px;
@ -115,8 +132,20 @@
// fix for phantomjs
.body--phantomjs {
.graph-panel--legend-right {
.graph-legend {
display: inline-block;
}
.graph-panel__chart {
display: flex;
}
.graph-legend-table {
display: table;
.graph-legend-scroll {
display: table;
}
}
}
}
@ -124,9 +153,9 @@
.graph-legend-table {
tbody {
display: block;
position: relative;
overflow-y: auto;
overflow-x: hidden;
height: 100%;
padding-bottom: 1px;
padding-right: 5px;
padding-left: 5px;

@ -9,6 +9,11 @@
-ms-touch-action: auto;
}
// ._scrollbar {
// overflow-x: hidden !important;
// overflow-y: auto;
// }
/*
* Scrollbar rail styles
*/
@ -101,7 +106,7 @@
opacity: 0.9;
}
// Srollbars
// Scrollbars
//
::-webkit-scrollbar {
@ -172,3 +177,120 @@
border-top: 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 {
height: 100%;
display: block;
padding: $spacer;
position: relative;
flex-grow: 10;
margin-bottom: 1rem;
// Fix for search scroller in mobile view
height: unset;
.label-tag {
margin-left: 6px;
font-size: 11px;

@ -28,12 +28,20 @@
width: 100%;
overflow: auto;
height: 100%;
-webkit-overflow-scrolling: touch;
&--dashboard {
height: calc(100% - 56px);
}
}
// fix for phantomjs
.body--phantomjs {
.scroll-canvas {
overflow: hidden;
}
}
.page-body {
padding-top: $spacer*2;
min-height: 500px;

@ -16,7 +16,7 @@
<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="apple-touch-icon" href="public/img/fav32.png">
</head>
<body ng-cloak class="theme-[[ .Theme ]]">
@ -40,7 +40,7 @@
</div>
<div class="main-view">
<div class="scroll-canvas" grafana-scrollbar>
<div class="scroll-canvas" page-scrollbar>
<div ng-view></div>
<footer class="footer">

@ -20,17 +20,4 @@ echo "building backend with install to cache pkgs"
exit_if_fail time go install ./pkg/cmd/grafana-server
echo "running go test"
set -e
echo "" > coverage.txt
time for d in $(go list ./pkg/...); do
exit_if_fail go test -coverprofile=profile.out -covermode=atomic $d
if [ -f profile.out ]; then
cat profile.out >> coverage.txt
rm profile.out
fi
done
echo "Publishing go code coverage"
bash <(curl -s https://codecov.io/bash) -cF go
go test ./pkg/...

@ -1162,6 +1162,10 @@ balanced-match@^1.0.0:
version "1.0.0"
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:
version "0.1.5"
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"
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:
version "0.2.0"
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5"

Loading…
Cancel
Save