Merge branch 'master' into 10630_folder_api

This commit is contained in:
Marcus Efraimsson 2018-02-21 11:25:56 +01:00
commit 3c6bc263dc
37 changed files with 186 additions and 122 deletions

View File

@ -1,3 +1,11 @@
# 5.0.0-beta4 (2018-02-19)
### Fixes
- **Dashboard** Fixed dashboard overwrite permission issue [#10814](https://github.com/grafana/grafana/issues/10814)
- **Keyboard shortcuts** Fixed Esc key when in panel edit/view mode [#10945](https://github.com/grafana/grafana/issues/10945)
- **Save dashboard** Fixed issue with time range & variable reset after saving [#10946](https://github.com/grafana/grafana/issues/10946)
# 5.0.0-beta3 (2018-02-16)
### Fixes

View File

@ -1,8 +1,5 @@
# This file is only an example.
# Grafana will never read sample.yaml files
# # config file version
# apiVersion: 1
apiVersion: 1
#providers:
# - name: 'default'

View File

@ -1,8 +1,5 @@
# This file is only an example.
# Grafana will never read sample.yaml files
# # config file version
# apiVersion: 1
apiVersion: 1
# # list of datasources that should be deleted from the database
#deleteDatasources:

View File

@ -0,0 +1,25 @@
prometheus:
build: blocks/prometheus2
network_mode: host
ports:
- "9090:9090"
node_exporter:
image: prom/node-exporter
network_mode: host
ports:
- "9100:9100"
fake-prometheus-data:
image: grafana/fake-data-gen
network_mode: host
ports:
- "9091:9091"
environment:
FD_DATASOURCE: prom
alertmanager:
image: quay.io/prometheus/alertmanager
network_mode: host
ports:
- "9093:9093"

View File

@ -16,7 +16,7 @@ weight = 1
Description | Download
------------ | -------------
Stable for Debian-based Linux | [grafana_4.6.3_amd64.deb](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_4.6.3_amd64.deb)
Beta for Debian-based Linux | [grafana_5.0.0-beta3_amd64.deb](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_5.0.0-beta3_amd64.deb)
Beta for Debian-based Linux | [grafana_5.0.0-beta4_amd64.deb](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_5.0.0-beta4_amd64.deb)
Read [Upgrading Grafana]({{< relref "installation/upgrading.md" >}}) for tips and guidance on updating an existing
installation.
@ -33,9 +33,9 @@ sudo dpkg -i grafana_4.6.3_amd64.deb
## Install Latest Beta
```bash
wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_5.0.0-beta3_amd64.deb
wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_5.0.0-beta4_amd64.deb
sudo apt-get install -y adduser libfontconfig
sudo dpkg -i grafana_5.0.0-beta3_amd64.deb
sudo dpkg -i grafana_5.0.0-beta4_amd64.deb
```
## APT Repository

View File

@ -16,7 +16,7 @@ weight = 2
Description | Download
------------ | -------------
Stable for CentOS / Fedora / OpenSuse / Redhat Linux | [4.6.3 (x86-64 rpm)](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-4.6.3-1.x86_64.rpm)
Latest Beta for CentOS / Fedora / OpenSuse / Redhat Linux | [5.0.0-beta3 (x86-64 rpm)](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.0.0-beta3.x86_64.rpm)
Latest Beta for CentOS / Fedora / OpenSuse / Redhat Linux | [5.0.0-beta4 (x86-64 rpm)](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.0.0-beta4.x86_64.rpm)
Read [Upgrading Grafana]({{< relref "installation/upgrading.md" >}}) for tips and guidance on updating an existing
installation.
@ -32,7 +32,7 @@ $ sudo yum install https://s3-us-west-2.amazonaws.com/grafana-releases/release/g
## Install Beta
```bash
$ sudo yum install https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.0.0-beta3.x86_64.rpm
$ sudo yum install https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.0.0-beta4.x86_64.rpm
```
Or install manually using `rpm`.

View File

@ -14,7 +14,7 @@ weight = 3
Description | Download
------------ | -------------
Latest stable package for Windows | [grafana.4.6.3.windows-x64.zip](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-4.6.3.windows-x64.zip)
Latest beta package for Windows | [grafana.5.0.0-beta3.windows-x64.zip](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.0.0-beta3.windows-x64.zip)
Latest beta package for Windows | [grafana.5.0.0-beta4.windows-x64.zip](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.0.0-beta4.windows-x64.zip)
Read [Upgrading Grafana]({{< relref "installation/upgrading.md" >}}) for tips and guidance on updating an existing
installation.

View File

@ -4,7 +4,7 @@
"company": "Grafana Labs"
},
"name": "grafana",
"version": "5.0.0-beta3",
"version": "5.0.0-beta4",
"repository": {
"type": "git",
"url": "http://github.com/grafana/grafana.git"

View File

@ -1,6 +1,6 @@
#! /usr/bin/env bash
deb_ver=5.0.0-beta3
rpm_ver=5.0.0-beta3
deb_ver=5.0.0-beta4
rpm_ver=5.0.0-beta4
wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_${deb_ver}_amd64.deb

View File

@ -69,10 +69,11 @@ var knownDatasourcePlugins map[string]bool = map[string]bool{
DS_POSTGRES: true,
DS_MYSQL: true,
"opennms": true,
"druid": true,
"dalmatinerdb": true,
"abhisant-druid-datasource": true,
"dalmatinerdb-datasource": true,
"gnocci": true,
"zabbix": true,
"alexanderzobnin-zabbix-datasource": true,
"newrelic-app": true,
"grafana-datadog-datasource": true,
"grafana-simple-json": true,

View File

@ -35,7 +35,7 @@ type DashboardInputMissingError struct {
}
func (e DashboardInputMissingError) Error() string {
return fmt.Sprintf("Dashbord input variable: %v missing from import command", e.VariableName)
return fmt.Sprintf("Dashboard input variable: %v missing from import command", e.VariableName)
}
func init() {

View File

@ -118,6 +118,7 @@ func (dr *dashboardServiceImpl) buildSaveDashboardCommand(dto *SaveDashboardDTO,
UserId: dto.User.UserId,
FolderId: dash.FolderId,
IsFolder: dash.IsFolder,
PluginId: dash.PluginId,
}
if !dto.UpdatedAt.IsZero() {

View File

@ -63,7 +63,7 @@ func (cr *configReader) readConfig() ([]*DashboardsAsConfig, error) {
}
for _, file := range files {
if (!strings.HasSuffix(file.Name(), ".yaml") && !strings.HasSuffix(file.Name(), ".yml")) || file.Name() == "sample.yaml" {
if !strings.HasSuffix(file.Name(), ".yaml") && !strings.HasSuffix(file.Name(), ".yml") {
continue
}

View File

@ -1,10 +1,10 @@
apiVersion: 1
providers:
- name: 'gasdf'
orgId: 2
folder: 'developers'
editable: true
type: file
options:
path: /var/lib/grafana/dashboards
#providers:
#- name: 'gasdf'
# orgId: 2
# folder: 'developers'
# editable: true
# type: file
# options:
# path: /var/lib/grafana/dashboards

View File

@ -24,7 +24,7 @@ func (cr *configReader) readConfig(path string) ([]*DatasourcesAsConfig, error)
}
for _, file := range files {
if (strings.HasSuffix(file.Name(), ".yaml") || strings.HasSuffix(file.Name(), ".yml")) && file.Name() != "sample.yaml" {
if strings.HasSuffix(file.Name(), ".yaml") || strings.HasSuffix(file.Name(), ".yml") {
datasource, err := cr.parseDatasourceConfig(path, file)
if err != nil {
return nil, err

View File

@ -138,7 +138,7 @@ func TestDatasourceAsConfig(t *testing.T) {
t.Fatalf("readConfig return an error %v", err)
}
So(len(cfg), ShouldEqual, 2)
So(len(cfg), ShouldEqual, 3)
dsCfg := cfg[0]
@ -146,6 +146,17 @@ func TestDatasourceAsConfig(t *testing.T) {
validateDatasource(dsCfg)
validateDeleteDatasources(dsCfg)
dsCount := 0
delDsCount := 0
for _, c := range cfg {
dsCount += len(c.Datasources)
delDsCount += len(c.DeleteDatasources)
}
So(dsCount, ShouldEqual, 2)
So(delDsCount, ShouldEqual, 1)
})
Convey("can read all properties from version 0", func() {

View File

@ -3,30 +3,30 @@
apiVersion: 1
datasources:
- name: name
type: type
access: proxy
orgId: 2
url: url
password: password
user: user
database: database
basicAuth: true
basicAuthUser: basic_auth_user
basicAuthPassword: basic_auth_password
withCredentials: true
jsonData:
graphiteVersion: "1.1"
tlsAuth: true
tlsAuthWithCACert: true
secureJsonData:
tlsCACert: "MjNOcW9RdkbUDHZmpco2HCYzVq9dE+i6Yi+gmUJotq5CDA=="
tlsClientCert: "ckN0dGlyMXN503YNfjTcf9CV+GGQneN+xmAclQ=="
tlsClientKey: "ZkN4aG1aNkja/gKAB1wlnKFIsy2SRDq4slrM0A=="
editable: true
version: 10
deleteDatasources:
- name: old-graphite3
orgId: 2
#datasources:
# - name: name
# type: type
# access: proxy
# orgId: 2
# url: url
# password: password
# user: user
# database: database
# basicAuth: true
# basicAuthUser: basic_auth_user
# basicAuthPassword: basic_auth_password
# withCredentials: true
# jsonData:
# graphiteVersion: "1.1"
# tlsAuth: true
# tlsAuthWithCACert: true
# secureJsonData:
# tlsCACert: "MjNOcW9RdkbUDHZmpco2HCYzVq9dE+i6Yi+gmUJotq5CDA=="
# tlsClientCert: "ckN0dGlyMXN503YNfjTcf9CV+GGQneN+xmAclQ=="
# tlsClientKey: "ZkN4aG1aNkja/gKAB1wlnKFIsy2SRDq4slrM0A=="
# editable: true
# version: 10
#
#deleteDatasources:
# - name: old-graphite3
# orgId: 2

View File

@ -210,7 +210,7 @@ func (s *SocialGithub) UserInfo(client *http.Client, token *oauth2.Token) (*Basi
if err != nil {
return nil, fmt.Errorf("Error getting user info: %s", err)
}
data.OrganizationsUrl = s.apiUrl + "/user/orgs"
userInfo := &BasicUserInfo{
Name: data.Login,
Login: data.Login,

View File

@ -70,7 +70,7 @@ func (query *Query) renderTags() []string {
} else if tag.Operator == "<" || tag.Operator == ">" {
textValue = tag.Value
} else {
textValue = fmt.Sprintf("'%s'", tag.Value)
textValue = fmt.Sprintf("'%s'", strings.Replace(tag.Value, `\`, `\\`, -1))
}
res = append(res, fmt.Sprintf(`%s"%s" %s %s`, str, tag.Key, tag.Operator, textValue))

View File

@ -170,6 +170,12 @@ func TestInfluxdbQueryBuilder(t *testing.T) {
So(strings.Join(query.renderTags(), ""), ShouldEqual, `"key" = 'value'`)
})
Convey("can escape backslashes when rendering string tags", func() {
query := &Query{Tags: []*Tag{{Operator: "=", Value: `C:\test\`, Key: "key"}}}
So(strings.Join(query.renderTags(), ""), ShouldEqual, `"key" = 'C:\\test\\'`)
})
Convey("can render regular measurement", func() {
query := &Query{Measurement: `apa`, Policy: "policy"}

View File

@ -15,8 +15,7 @@ const template = `
</a>
</div>
<div class="modal-content">
<div class="gf-form-group">
<div class="modal-content modal-content--has-scroll" grafana-scrollbar>
<table class="filter-table form-inline">
<thead>
<tr>

View File

@ -12,7 +12,7 @@ export class InvitedCtrl {
icon: 'gicon gicon-branding',
text: 'Invite',
subTitle: 'Register your Grafana account',
breadcrumbs: [{ title: 'Login', url: '/login' }],
breadcrumbs: [{ title: 'Login', url: 'login' }],
},
};

View File

@ -10,6 +10,13 @@ export class SignUpCtrl {
$scope.formModel = {};
var params = $location.search();
// validate email is semi ok
if (params.email && !params.email.match(/^\S+@\S+$/)) {
console.log('invalid email');
return;
}
$scope.formModel.orgName = params.email;
$scope.formModel.email = params.email;
$scope.formModel.username = params.email;

View File

@ -75,7 +75,7 @@ export class AlertTabCtrl {
getAlertHistory() {
this.backendSrv
.get(`/api/annotations?dashboardId=${this.panelCtrl.dashboard.id}&panelId=${this.panel.id}&limit=50`)
.get(`/api/annotations?dashboardId=${this.panelCtrl.dashboard.id}&panelId=${this.panel.id}&limit=50&type=alert`)
.then(res => {
this.alertHistory = _.map(res, ah => {
ah.time = this.dashboardSrv.getCurrent().formatDate(ah.time, 'MMM D, YYYY HH:mm:ss');

View File

@ -63,11 +63,17 @@ export class DashboardMigrator {
}
if (panel.y_format) {
if (!panel.y_formats) {
panel.y_formats = [];
}
panel.y_formats[0] = panel.y_format;
delete panel.y_format;
}
if (panel.y2_format) {
if (!panel.y_formats) {
panel.y_formats = [];
}
panel.y_formats[1] = panel.y2_format;
delete panel.y2_format;
}

View File

@ -1,44 +1,26 @@
<div class="container">
<page-header model="navModel"></page-header>
<div class="signup-page-background">
</div>
<div class="page-container page-body">
<div class="login-content">
<div class="login-branding">
<img src="img/logo_transparent_200x75.png">
</div>
<div class="invite-box">
<h3>
<i class="fa fa-users"></i>&nbsp;
Change active organization
</h3>
<div class="signup">
<div class="login-form">
<div class="modal-tagline">
You have been added to another Organization <br>
due to an open invitation!
<br><br>
You have been added to another Organization due to an open invitation!
Please select which organization you want to <br>
use right now (you can change this later at any time).
</div>
<div style="display: inline-block; width: 400px; margin: 30px 0">
<table class="filter-table">
<tr ng-repeat="org in orgs">
<td class="nobg max-width-btns">
<a ng-click="setUsingOrg(org)" class="btn btn-inverse">
<div ng-repeat="org in orgs">
<a ng-click="setUsingOrg(org)" class="btn btn-success">
{{org.name}} ({{org.role}})
</a>
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@ -6,6 +6,14 @@ export class SelectOrgCtrl {
constructor($scope, backendSrv, contextSrv) {
contextSrv.sidemenu = false;
$scope.navModel = {
main: {
icon: 'gicon gicon-branding',
subTitle: 'Preferences',
text: 'Select active organization',
},
};
$scope.init = function() {
$scope.getUserOrgs();
};

View File

@ -9,9 +9,7 @@
<a href="{{dash.importedUrl}}" ng-show="dash.imported">
{{dash.title}}
</a>
<span ng-show="!dash.imported">
{{dash.title}}
</span>
<span ng-show="!dash.imported">{{dash.title}}</span>
</td>
<td style="text-align: right">
<button class="btn btn-secondary btn-small" ng-click="ctrl.import(dash, false)" ng-show="!dash.imported">

View File

@ -151,7 +151,11 @@ module.directive('graphLegend', function(popoverSrv, $timeout) {
if (panel.legend.sort) {
seriesList = _.sortBy(seriesList, function(series) {
return series.stats[panel.legend.sort];
let sort = series.stats[panel.legend.sort];
if (sort === null) {
sort = -Infinity;
}
return sort;
});
if (panel.legend.sortDesc) {
seriesList = seriesList.reverse();

View File

@ -43,7 +43,7 @@
<div class="gf-form">
<label class="gf-form-label width-8">Point Radius</label>
<div class="gf-form-select-wrapper max-width-5">
<select class="gf-form-input" ng-model="ctrl.panel.pointradius" ng-options="f for f in [1,2,3,4,5,6,7,8,9,10]" ng-change="ctrl.render()" ng-disabled="!ctrl.panel.points"></select>
<select class="gf-form-input" ng-model="ctrl.panel.pointradius" ng-options="f for f in [0.5,1,2,3,4,5,6,7,8,9,10]" ng-change="ctrl.render()" ng-disabled="!ctrl.panel.points"></select>
</div>
</div>
</div>

View File

@ -8,13 +8,18 @@ import { getColorScale, getOpacityScale } from './color_scale';
let module = angular.module('grafana.directives');
const LEGEND_HEIGHT_PX = 6;
const LEGEND_WIDTH_PX = 100;
const LEGEND_TICK_SIZE = 0;
const LEGEND_VALUE_MARGIN = 0;
/**
* Color legend for heatmap editor.
*/
module.directive('colorLegend', function() {
return {
restrict: 'E',
template: '<div class="heatmap-color-legend"><svg width="16.8rem" height="24px"></svg></div>',
template: '<div class="heatmap-color-legend"><svg width="16.5rem" height="24px"></svg></div>',
link: function(scope, elem, attrs) {
let ctrl = scope.ctrl;
let panel = scope.ctrl.panel;
@ -50,7 +55,7 @@ module.directive('colorLegend', function() {
module.directive('heatmapLegend', function() {
return {
restrict: 'E',
template: '<div class="heatmap-color-legend"><svg width="100px" height="14px"></svg></div>',
template: `<div class="heatmap-color-legend"><svg width="${LEGEND_WIDTH_PX}px" height="${LEGEND_HEIGHT_PX}px"></svg></div>`,
link: function(scope, elem, attrs) {
let ctrl = scope.ctrl;
let panel = scope.ctrl.panel;
@ -163,10 +168,10 @@ function drawLegendValues(elem, colorScale, rangeFrom, rangeTo, maxValue, minVal
let xAxis = d3
.axisBottom(legendValueScale)
.tickValues(ticks)
.tickSize(2);
.tickSize(LEGEND_TICK_SIZE);
let colorRect = legendElem.find(':first-child');
let posY = getSvgElemHeight(legendElem) + 2;
let posY = getSvgElemHeight(legendElem) + LEGEND_VALUE_MARGIN;
let posX = getSvgElemX(colorRect);
d3

View File

@ -66,8 +66,7 @@ export default function link(scope, elem, attrs, ctrl) {
height = parseInt(height.replace('px', ''), 10);
}
height -= 5; // padding
height -= panel.title ? 24 : 9; // subtract panel title bar
height -= panel.legend.show ? 28 : 11; // bottom padding and space for legend
$heatmap.css('height', height + 'px');

View File

@ -51,6 +51,9 @@ describe('grafanaHeatmap', function() {
colorScheme: 'interpolateOranges',
fillBackground: false,
},
legend: {
show: false,
},
xBucketSize: 1000,
xBucketNumber: null,
yBucketSize: 1,

View File

@ -67,6 +67,11 @@
.modal-content {
padding: $spacer*2;
&--has-scroll {
max-height: calc(100vh - 400px);
position: relative;
}
}
// Remove bottom margin if need be

View File

@ -1,3 +1,5 @@
$font-size-heatmap-tick: 11px;
.heatmap-canvas-wrapper {
// position: relative;
cursor: crosshair;
@ -10,7 +12,7 @@
text {
fill: $text-color;
color: $text-color;
font-size: $font-size-sm;
font-size: $font-size-heatmap-tick;
}
line {
@ -56,12 +58,12 @@
.heatmap-legend-wrapper {
@include clearfix();
margin: 0 $spacer;
padding-top: 10px;
padding-top: 4px;
svg {
width: 100%;
max-width: 300px;
height: 33px;
height: 18px;
float: left;
white-space: nowrap;
padding-left: 10px;
@ -75,7 +77,7 @@
text {
fill: $text-color;
color: $text-color;
font-size: $font-size-sm;
font-size: $font-size-heatmap-tick;
}
line {

View File

@ -75,7 +75,7 @@
border-radius: 6px;
width: 6px;
/* there must be 'right' for ps__thumb-y */
right: 2px;
right: 0px;
/* please don't change 'position' */
position: absolute;
}