mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Merge branch 'master' into 10630_folder_api
This commit is contained in:
commit
3c6bc263dc
@ -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)
|
# 5.0.0-beta3 (2018-02-16)
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
# This file is only an example.
|
|
||||||
# Grafana will never read sample.yaml files
|
|
||||||
|
|
||||||
# # config file version
|
# # config file version
|
||||||
# apiVersion: 1
|
apiVersion: 1
|
||||||
|
|
||||||
#providers:
|
#providers:
|
||||||
# - name: 'default'
|
# - name: 'default'
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
# This file is only an example.
|
|
||||||
# Grafana will never read sample.yaml files
|
|
||||||
|
|
||||||
# # config file version
|
# # config file version
|
||||||
# apiVersion: 1
|
apiVersion: 1
|
||||||
|
|
||||||
# # list of datasources that should be deleted from the database
|
# # list of datasources that should be deleted from the database
|
||||||
#deleteDatasources:
|
#deleteDatasources:
|
||||||
|
25
docker/blocks/prometheus2/docker-compose.yaml
Normal file
25
docker/blocks/prometheus2/docker-compose.yaml
Normal 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"
|
@ -16,7 +16,7 @@ weight = 1
|
|||||||
Description | Download
|
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)
|
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
|
Read [Upgrading Grafana]({{< relref "installation/upgrading.md" >}}) for tips and guidance on updating an existing
|
||||||
installation.
|
installation.
|
||||||
@ -33,9 +33,9 @@ sudo dpkg -i grafana_4.6.3_amd64.deb
|
|||||||
## Install Latest Beta
|
## Install Latest Beta
|
||||||
|
|
||||||
```bash
|
```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 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
|
## APT Repository
|
||||||
|
@ -16,7 +16,7 @@ weight = 2
|
|||||||
Description | Download
|
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)
|
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
|
Read [Upgrading Grafana]({{< relref "installation/upgrading.md" >}}) for tips and guidance on updating an existing
|
||||||
installation.
|
installation.
|
||||||
@ -32,7 +32,7 @@ $ sudo yum install https://s3-us-west-2.amazonaws.com/grafana-releases/release/g
|
|||||||
## Install Beta
|
## Install Beta
|
||||||
|
|
||||||
```bash
|
```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`.
|
Or install manually using `rpm`.
|
||||||
|
@ -14,7 +14,7 @@ weight = 3
|
|||||||
Description | Download
|
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 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
|
Read [Upgrading Grafana]({{< relref "installation/upgrading.md" >}}) for tips and guidance on updating an existing
|
||||||
installation.
|
installation.
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"company": "Grafana Labs"
|
"company": "Grafana Labs"
|
||||||
},
|
},
|
||||||
"name": "grafana",
|
"name": "grafana",
|
||||||
"version": "5.0.0-beta3",
|
"version": "5.0.0-beta4",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "http://github.com/grafana/grafana.git"
|
"url": "http://github.com/grafana/grafana.git"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#! /usr/bin/env bash
|
#! /usr/bin/env bash
|
||||||
deb_ver=5.0.0-beta3
|
deb_ver=5.0.0-beta4
|
||||||
rpm_ver=5.0.0-beta3
|
rpm_ver=5.0.0-beta4
|
||||||
|
|
||||||
wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_${deb_ver}_amd64.deb
|
wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_${deb_ver}_amd64.deb
|
||||||
|
|
||||||
|
@ -58,21 +58,22 @@ type DataSource struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var knownDatasourcePlugins map[string]bool = map[string]bool{
|
var knownDatasourcePlugins map[string]bool = map[string]bool{
|
||||||
DS_ES: true,
|
DS_ES: true,
|
||||||
DS_GRAPHITE: true,
|
DS_GRAPHITE: true,
|
||||||
DS_INFLUXDB: true,
|
DS_INFLUXDB: true,
|
||||||
DS_INFLUXDB_08: true,
|
DS_INFLUXDB_08: true,
|
||||||
DS_KAIROSDB: true,
|
DS_KAIROSDB: true,
|
||||||
DS_CLOUDWATCH: true,
|
DS_CLOUDWATCH: true,
|
||||||
DS_PROMETHEUS: true,
|
DS_PROMETHEUS: true,
|
||||||
DS_OPENTSDB: true,
|
DS_OPENTSDB: true,
|
||||||
DS_POSTGRES: true,
|
DS_POSTGRES: true,
|
||||||
DS_MYSQL: true,
|
DS_MYSQL: true,
|
||||||
"opennms": true,
|
"opennms": true,
|
||||||
"druid": true,
|
"abhisant-druid-datasource": true,
|
||||||
"dalmatinerdb": true,
|
"dalmatinerdb-datasource": true,
|
||||||
"gnocci": true,
|
"gnocci": true,
|
||||||
"zabbix": true,
|
"zabbix": true,
|
||||||
|
"alexanderzobnin-zabbix-datasource": true,
|
||||||
"newrelic-app": true,
|
"newrelic-app": true,
|
||||||
"grafana-datadog-datasource": true,
|
"grafana-datadog-datasource": true,
|
||||||
"grafana-simple-json": true,
|
"grafana-simple-json": true,
|
||||||
|
@ -35,7 +35,7 @@ type DashboardInputMissingError struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e DashboardInputMissingError) Error() string {
|
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() {
|
func init() {
|
||||||
|
@ -118,6 +118,7 @@ func (dr *dashboardServiceImpl) buildSaveDashboardCommand(dto *SaveDashboardDTO,
|
|||||||
UserId: dto.User.UserId,
|
UserId: dto.User.UserId,
|
||||||
FolderId: dash.FolderId,
|
FolderId: dash.FolderId,
|
||||||
IsFolder: dash.IsFolder,
|
IsFolder: dash.IsFolder,
|
||||||
|
PluginId: dash.PluginId,
|
||||||
}
|
}
|
||||||
|
|
||||||
if !dto.UpdatedAt.IsZero() {
|
if !dto.UpdatedAt.IsZero() {
|
||||||
|
@ -63,7 +63,7 @@ func (cr *configReader) readConfig() ([]*DashboardsAsConfig, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, file := range files {
|
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
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
apiVersion: 1
|
apiVersion: 1
|
||||||
|
|
||||||
providers:
|
#providers:
|
||||||
- name: 'gasdf'
|
#- name: 'gasdf'
|
||||||
orgId: 2
|
# orgId: 2
|
||||||
folder: 'developers'
|
# folder: 'developers'
|
||||||
editable: true
|
# editable: true
|
||||||
type: file
|
# type: file
|
||||||
options:
|
# options:
|
||||||
path: /var/lib/grafana/dashboards
|
# path: /var/lib/grafana/dashboards
|
||||||
|
@ -24,7 +24,7 @@ func (cr *configReader) readConfig(path string) ([]*DatasourcesAsConfig, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, file := range files {
|
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)
|
datasource, err := cr.parseDatasourceConfig(path, file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -138,7 +138,7 @@ func TestDatasourceAsConfig(t *testing.T) {
|
|||||||
t.Fatalf("readConfig return an error %v", err)
|
t.Fatalf("readConfig return an error %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
So(len(cfg), ShouldEqual, 2)
|
So(len(cfg), ShouldEqual, 3)
|
||||||
|
|
||||||
dsCfg := cfg[0]
|
dsCfg := cfg[0]
|
||||||
|
|
||||||
@ -146,6 +146,17 @@ func TestDatasourceAsConfig(t *testing.T) {
|
|||||||
|
|
||||||
validateDatasource(dsCfg)
|
validateDatasource(dsCfg)
|
||||||
validateDeleteDatasources(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() {
|
Convey("can read all properties from version 0", func() {
|
||||||
|
@ -3,30 +3,30 @@
|
|||||||
|
|
||||||
apiVersion: 1
|
apiVersion: 1
|
||||||
|
|
||||||
datasources:
|
#datasources:
|
||||||
- name: name
|
# - name: name
|
||||||
type: type
|
# type: type
|
||||||
access: proxy
|
# access: proxy
|
||||||
orgId: 2
|
# orgId: 2
|
||||||
url: url
|
# url: url
|
||||||
password: password
|
# password: password
|
||||||
user: user
|
# user: user
|
||||||
database: database
|
# database: database
|
||||||
basicAuth: true
|
# basicAuth: true
|
||||||
basicAuthUser: basic_auth_user
|
# basicAuthUser: basic_auth_user
|
||||||
basicAuthPassword: basic_auth_password
|
# basicAuthPassword: basic_auth_password
|
||||||
withCredentials: true
|
# withCredentials: true
|
||||||
jsonData:
|
# jsonData:
|
||||||
graphiteVersion: "1.1"
|
# graphiteVersion: "1.1"
|
||||||
tlsAuth: true
|
# tlsAuth: true
|
||||||
tlsAuthWithCACert: true
|
# tlsAuthWithCACert: true
|
||||||
secureJsonData:
|
# secureJsonData:
|
||||||
tlsCACert: "MjNOcW9RdkbUDHZmpco2HCYzVq9dE+i6Yi+gmUJotq5CDA=="
|
# tlsCACert: "MjNOcW9RdkbUDHZmpco2HCYzVq9dE+i6Yi+gmUJotq5CDA=="
|
||||||
tlsClientCert: "ckN0dGlyMXN503YNfjTcf9CV+GGQneN+xmAclQ=="
|
# tlsClientCert: "ckN0dGlyMXN503YNfjTcf9CV+GGQneN+xmAclQ=="
|
||||||
tlsClientKey: "ZkN4aG1aNkja/gKAB1wlnKFIsy2SRDq4slrM0A=="
|
# tlsClientKey: "ZkN4aG1aNkja/gKAB1wlnKFIsy2SRDq4slrM0A=="
|
||||||
editable: true
|
# editable: true
|
||||||
version: 10
|
# version: 10
|
||||||
|
#
|
||||||
deleteDatasources:
|
#deleteDatasources:
|
||||||
- name: old-graphite3
|
# - name: old-graphite3
|
||||||
orgId: 2
|
# orgId: 2
|
||||||
|
@ -210,7 +210,7 @@ func (s *SocialGithub) UserInfo(client *http.Client, token *oauth2.Token) (*Basi
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Error getting user info: %s", err)
|
return nil, fmt.Errorf("Error getting user info: %s", err)
|
||||||
}
|
}
|
||||||
data.OrganizationsUrl = s.apiUrl + "/user/orgs"
|
|
||||||
userInfo := &BasicUserInfo{
|
userInfo := &BasicUserInfo{
|
||||||
Name: data.Login,
|
Name: data.Login,
|
||||||
Login: data.Login,
|
Login: data.Login,
|
||||||
|
@ -70,7 +70,7 @@ func (query *Query) renderTags() []string {
|
|||||||
} else if tag.Operator == "<" || tag.Operator == ">" {
|
} else if tag.Operator == "<" || tag.Operator == ">" {
|
||||||
textValue = tag.Value
|
textValue = tag.Value
|
||||||
} else {
|
} 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))
|
res = append(res, fmt.Sprintf(`%s"%s" %s %s`, str, tag.Key, tag.Operator, textValue))
|
||||||
|
@ -170,6 +170,12 @@ func TestInfluxdbQueryBuilder(t *testing.T) {
|
|||||||
So(strings.Join(query.renderTags(), ""), ShouldEqual, `"key" = 'value'`)
|
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() {
|
Convey("can render regular measurement", func() {
|
||||||
query := &Query{Measurement: `apa`, Policy: "policy"}
|
query := &Query{Measurement: `apa`, Policy: "policy"}
|
||||||
|
|
||||||
|
@ -15,8 +15,7 @@ const template = `
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="modal-content">
|
<div class="modal-content modal-content--has-scroll" grafana-scrollbar>
|
||||||
<div class="gf-form-group">
|
|
||||||
<table class="filter-table form-inline">
|
<table class="filter-table form-inline">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
<div class="search-section__header" ng-show="section.hideHeader"></div>
|
<div class="search-section__header" ng-show="section.hideHeader"></div>
|
||||||
|
|
||||||
<div ng-if="section.expanded">
|
<div ng-if="section.expanded">
|
||||||
<a ng-repeat="item in section.items" class="search-item" ng-class="{'selected': item.selected}" ng-href="{{::item.url}}">
|
<a ng-repeat="item in section.items" class="search-item" ng-class="{'selected': item.selected}" ng-href="{{::item.url}}" >
|
||||||
<div ng-click="ctrl.toggleSelection(item, $event)">
|
<div ng-click="ctrl.toggleSelection(item, $event)">
|
||||||
<gf-form-switch
|
<gf-form-switch
|
||||||
ng-show="ctrl.editable"
|
ng-show="ctrl.editable"
|
||||||
|
@ -12,7 +12,7 @@ export class InvitedCtrl {
|
|||||||
icon: 'gicon gicon-branding',
|
icon: 'gicon gicon-branding',
|
||||||
text: 'Invite',
|
text: 'Invite',
|
||||||
subTitle: 'Register your Grafana account',
|
subTitle: 'Register your Grafana account',
|
||||||
breadcrumbs: [{ title: 'Login', url: '/login' }],
|
breadcrumbs: [{ title: 'Login', url: 'login' }],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -10,6 +10,13 @@ export class SignUpCtrl {
|
|||||||
$scope.formModel = {};
|
$scope.formModel = {};
|
||||||
|
|
||||||
var params = $location.search();
|
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.orgName = params.email;
|
||||||
$scope.formModel.email = params.email;
|
$scope.formModel.email = params.email;
|
||||||
$scope.formModel.username = params.email;
|
$scope.formModel.username = params.email;
|
||||||
|
@ -75,7 +75,7 @@ export class AlertTabCtrl {
|
|||||||
|
|
||||||
getAlertHistory() {
|
getAlertHistory() {
|
||||||
this.backendSrv
|
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 => {
|
.then(res => {
|
||||||
this.alertHistory = _.map(res, ah => {
|
this.alertHistory = _.map(res, ah => {
|
||||||
ah.time = this.dashboardSrv.getCurrent().formatDate(ah.time, 'MMM D, YYYY HH:mm:ss');
|
ah.time = this.dashboardSrv.getCurrent().formatDate(ah.time, 'MMM D, YYYY HH:mm:ss');
|
||||||
|
@ -63,11 +63,17 @@ export class DashboardMigrator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (panel.y_format) {
|
if (panel.y_format) {
|
||||||
|
if (!panel.y_formats) {
|
||||||
|
panel.y_formats = [];
|
||||||
|
}
|
||||||
panel.y_formats[0] = panel.y_format;
|
panel.y_formats[0] = panel.y_format;
|
||||||
delete panel.y_format;
|
delete panel.y_format;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (panel.y2_format) {
|
if (panel.y2_format) {
|
||||||
|
if (!panel.y_formats) {
|
||||||
|
panel.y_formats = [];
|
||||||
|
}
|
||||||
panel.y_formats[1] = panel.y2_format;
|
panel.y_formats[1] = panel.y2_format;
|
||||||
delete panel.y2_format;
|
delete panel.y2_format;
|
||||||
}
|
}
|
||||||
|
@ -1,44 +1,26 @@
|
|||||||
<div class="container">
|
<page-header model="navModel"></page-header>
|
||||||
|
|
||||||
<div class="signup-page-background">
|
<div class="page-container page-body">
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="login-content">
|
<div class="signup">
|
||||||
|
<div class="login-form">
|
||||||
<div class="login-branding">
|
|
||||||
<img src="img/logo_transparent_200x75.png">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="invite-box">
|
|
||||||
<h3>
|
|
||||||
<i class="fa fa-users"></i>
|
|
||||||
Change active organization
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
<div class="modal-tagline">
|
<div class="modal-tagline">
|
||||||
You have been added to another Organization <br>
|
You have been added to another Organization due to an open invitation!
|
||||||
due to an open invitation!
|
|
||||||
<br><br>
|
|
||||||
|
|
||||||
Please select which organization you want to <br>
|
Please select which organization you want to <br>
|
||||||
use right now (you can change this later at any time).
|
use right now (you can change this later at any time).
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="display: inline-block; width: 400px; margin: 30px 0">
|
<div style="display: inline-block; width: 400px; margin: 30px 0">
|
||||||
<table class="filter-table">
|
<div ng-repeat="org in orgs">
|
||||||
<tr ng-repeat="org in orgs">
|
<a ng-click="setUsingOrg(org)" class="btn btn-success">
|
||||||
<td class="nobg max-width-btns">
|
{{org.name}} ({{org.role}})
|
||||||
<a ng-click="setUsingOrg(org)" class="btn btn-inverse">
|
</a>
|
||||||
{{org.name}} ({{org.role}})
|
</div>
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
@ -6,6 +6,14 @@ export class SelectOrgCtrl {
|
|||||||
constructor($scope, backendSrv, contextSrv) {
|
constructor($scope, backendSrv, contextSrv) {
|
||||||
contextSrv.sidemenu = false;
|
contextSrv.sidemenu = false;
|
||||||
|
|
||||||
|
$scope.navModel = {
|
||||||
|
main: {
|
||||||
|
icon: 'gicon gicon-branding',
|
||||||
|
subTitle: 'Preferences',
|
||||||
|
text: 'Select active organization',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
$scope.init = function() {
|
$scope.init = function() {
|
||||||
$scope.getUserOrgs();
|
$scope.getUserOrgs();
|
||||||
};
|
};
|
||||||
|
@ -9,9 +9,7 @@
|
|||||||
<a href="{{dash.importedUrl}}" ng-show="dash.imported">
|
<a href="{{dash.importedUrl}}" ng-show="dash.imported">
|
||||||
{{dash.title}}
|
{{dash.title}}
|
||||||
</a>
|
</a>
|
||||||
<span ng-show="!dash.imported">
|
<span ng-show="!dash.imported">{{dash.title}}</span>
|
||||||
{{dash.title}}
|
|
||||||
</span>
|
|
||||||
</td>
|
</td>
|
||||||
<td style="text-align: right">
|
<td style="text-align: right">
|
||||||
<button class="btn btn-secondary btn-small" ng-click="ctrl.import(dash, false)" ng-show="!dash.imported">
|
<button class="btn btn-secondary btn-small" ng-click="ctrl.import(dash, false)" ng-show="!dash.imported">
|
||||||
|
@ -151,7 +151,11 @@ module.directive('graphLegend', function(popoverSrv, $timeout) {
|
|||||||
|
|
||||||
if (panel.legend.sort) {
|
if (panel.legend.sort) {
|
||||||
seriesList = _.sortBy(seriesList, function(series) {
|
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) {
|
if (panel.legend.sortDesc) {
|
||||||
seriesList = seriesList.reverse();
|
seriesList = seriesList.reverse();
|
||||||
|
@ -43,7 +43,7 @@
|
|||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<label class="gf-form-label width-8">Point Radius</label>
|
<label class="gf-form-label width-8">Point Radius</label>
|
||||||
<div class="gf-form-select-wrapper max-width-5">
|
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,13 +8,18 @@ import { getColorScale, getOpacityScale } from './color_scale';
|
|||||||
|
|
||||||
let module = angular.module('grafana.directives');
|
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.
|
* Color legend for heatmap editor.
|
||||||
*/
|
*/
|
||||||
module.directive('colorLegend', function() {
|
module.directive('colorLegend', function() {
|
||||||
return {
|
return {
|
||||||
restrict: 'E',
|
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) {
|
link: function(scope, elem, attrs) {
|
||||||
let ctrl = scope.ctrl;
|
let ctrl = scope.ctrl;
|
||||||
let panel = scope.ctrl.panel;
|
let panel = scope.ctrl.panel;
|
||||||
@ -50,7 +55,7 @@ module.directive('colorLegend', function() {
|
|||||||
module.directive('heatmapLegend', function() {
|
module.directive('heatmapLegend', function() {
|
||||||
return {
|
return {
|
||||||
restrict: 'E',
|
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) {
|
link: function(scope, elem, attrs) {
|
||||||
let ctrl = scope.ctrl;
|
let ctrl = scope.ctrl;
|
||||||
let panel = scope.ctrl.panel;
|
let panel = scope.ctrl.panel;
|
||||||
@ -163,10 +168,10 @@ function drawLegendValues(elem, colorScale, rangeFrom, rangeTo, maxValue, minVal
|
|||||||
let xAxis = d3
|
let xAxis = d3
|
||||||
.axisBottom(legendValueScale)
|
.axisBottom(legendValueScale)
|
||||||
.tickValues(ticks)
|
.tickValues(ticks)
|
||||||
.tickSize(2);
|
.tickSize(LEGEND_TICK_SIZE);
|
||||||
|
|
||||||
let colorRect = legendElem.find(':first-child');
|
let colorRect = legendElem.find(':first-child');
|
||||||
let posY = getSvgElemHeight(legendElem) + 2;
|
let posY = getSvgElemHeight(legendElem) + LEGEND_VALUE_MARGIN;
|
||||||
let posX = getSvgElemX(colorRect);
|
let posX = getSvgElemX(colorRect);
|
||||||
|
|
||||||
d3
|
d3
|
||||||
|
@ -66,8 +66,7 @@ export default function link(scope, elem, attrs, ctrl) {
|
|||||||
height = parseInt(height.replace('px', ''), 10);
|
height = parseInt(height.replace('px', ''), 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
height -= 5; // padding
|
height -= panel.legend.show ? 28 : 11; // bottom padding and space for legend
|
||||||
height -= panel.title ? 24 : 9; // subtract panel title bar
|
|
||||||
|
|
||||||
$heatmap.css('height', height + 'px');
|
$heatmap.css('height', height + 'px');
|
||||||
|
|
||||||
|
@ -51,6 +51,9 @@ describe('grafanaHeatmap', function() {
|
|||||||
colorScheme: 'interpolateOranges',
|
colorScheme: 'interpolateOranges',
|
||||||
fillBackground: false,
|
fillBackground: false,
|
||||||
},
|
},
|
||||||
|
legend: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
xBucketSize: 1000,
|
xBucketSize: 1000,
|
||||||
xBucketNumber: null,
|
xBucketNumber: null,
|
||||||
yBucketSize: 1,
|
yBucketSize: 1,
|
||||||
|
@ -67,6 +67,11 @@
|
|||||||
|
|
||||||
.modal-content {
|
.modal-content {
|
||||||
padding: $spacer*2;
|
padding: $spacer*2;
|
||||||
|
|
||||||
|
&--has-scroll {
|
||||||
|
max-height: calc(100vh - 400px);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove bottom margin if need be
|
// Remove bottom margin if need be
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
$font-size-heatmap-tick: 11px;
|
||||||
|
|
||||||
.heatmap-canvas-wrapper {
|
.heatmap-canvas-wrapper {
|
||||||
// position: relative;
|
// position: relative;
|
||||||
cursor: crosshair;
|
cursor: crosshair;
|
||||||
@ -10,7 +12,7 @@
|
|||||||
text {
|
text {
|
||||||
fill: $text-color;
|
fill: $text-color;
|
||||||
color: $text-color;
|
color: $text-color;
|
||||||
font-size: $font-size-sm;
|
font-size: $font-size-heatmap-tick;
|
||||||
}
|
}
|
||||||
|
|
||||||
line {
|
line {
|
||||||
@ -56,12 +58,12 @@
|
|||||||
.heatmap-legend-wrapper {
|
.heatmap-legend-wrapper {
|
||||||
@include clearfix();
|
@include clearfix();
|
||||||
margin: 0 $spacer;
|
margin: 0 $spacer;
|
||||||
padding-top: 10px;
|
padding-top: 4px;
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 300px;
|
max-width: 300px;
|
||||||
height: 33px;
|
height: 18px;
|
||||||
float: left;
|
float: left;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
@ -75,7 +77,7 @@
|
|||||||
text {
|
text {
|
||||||
fill: $text-color;
|
fill: $text-color;
|
||||||
color: $text-color;
|
color: $text-color;
|
||||||
font-size: $font-size-sm;
|
font-size: $font-size-heatmap-tick;
|
||||||
}
|
}
|
||||||
|
|
||||||
line {
|
line {
|
||||||
|
@ -75,7 +75,7 @@
|
|||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
width: 6px;
|
width: 6px;
|
||||||
/* there must be 'right' for ps__thumb-y */
|
/* there must be 'right' for ps__thumb-y */
|
||||||
right: 2px;
|
right: 0px;
|
||||||
/* please don't change 'position' */
|
/* please don't change 'position' */
|
||||||
position: absolute;
|
position: absolute;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user