mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Merge branch 'master' into export-dashboard
Conflicts: packaging/publish/publish.sh public/app/features/dashboard/dynamicDashboardSrv.js public/test/specs/dynamicDashboardSrv-specs.js
This commit is contained in:
commit
28eae1e7ff
@ -1,4 +1,9 @@
|
|||||||
# 3.0.0 stable (unreleased)
|
# 3.0.2 Stable (unreleased)
|
||||||
|
|
||||||
|
* **Templating**: Fixed issue mixing row repeat and panel repeats, fixes [#4988](https://github.com/grafana/grafana/issues/4988)
|
||||||
|
* **Templating**: Fixed issue detecting dependencies in nested variables, fixes [#4987](https://github.com/grafana/grafana/issues/4987), fixes [#4986](https://github.com/grafana/grafana/issues/4986)
|
||||||
|
|
||||||
|
# 3.0.1 Stable (2016-05-11)
|
||||||
|
|
||||||
* **Templating**: Fixed issue with new data source variable not persisting current selected value, fixes [#4934](https://github.com/grafana/grafana/issues/4934)
|
* **Templating**: Fixed issue with new data source variable not persisting current selected value, fixes [#4934](https://github.com/grafana/grafana/issues/4934)
|
||||||
|
|
||||||
|
8
build.go
8
build.go
@ -132,12 +132,10 @@ func readVersionFromPackageJson() {
|
|||||||
if len(parts) > 1 {
|
if len(parts) > 1 {
|
||||||
linuxPackageVersion = parts[0]
|
linuxPackageVersion = parts[0]
|
||||||
linuxPackageIteration = parts[1]
|
linuxPackageIteration = parts[1]
|
||||||
if linuxPackageIteration != "" {
|
|
||||||
// add timestamp to iteration
|
|
||||||
linuxPackageIteration = fmt.Sprintf("%s%v", linuxPackageIteration, time.Now().Unix())
|
|
||||||
}
|
|
||||||
log.Println(fmt.Sprintf("Iteration %v", linuxPackageIteration))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add timestamp to iteration
|
||||||
|
linuxPackageIteration = fmt.Sprintf("%d%s", time.Now().Unix(), linuxPackageIteration)
|
||||||
}
|
}
|
||||||
|
|
||||||
type linuxPackageOptions struct {
|
type linuxPackageOptions struct {
|
||||||
|
@ -39,12 +39,13 @@ entire experience right within Grafana.
|
|||||||
|
|
||||||
<img src="/img/v3/grafana_net_tour.png">
|
<img src="/img/v3/grafana_net_tour.png">
|
||||||
|
|
||||||
A preview of [Grafana.net](http://grafana.net) is launching along with this release. We
|
[Grafana.net](https://grafana.net) offers a central repository where the community can come together to discover, create and
|
||||||
think it’s the perfect compliment to Grafana.
|
share plugins (data sources, panels, apps) and dashboards.
|
||||||
|
|
||||||
Grafana.net currently offers a central repository where the community
|
We are also working on a hosted Graphite-compatible data source that will be optimized for use with Grafana.
|
||||||
can come together to discover and share plugins (Data Sources, Panels,
|
It’ll be easy to combine your existing data source(s) with this OpenSaaS option. Finally, Grafana.net can
|
||||||
Apps) and Dashboards for Grafana 3.0 and above.
|
also be a hub to manage all your Grafana instances. You’ll be able to monitor their health and availability,
|
||||||
|
perform dashboard backups, and more.
|
||||||
|
|
||||||
We are also working on a hosted Graphite-compatible Data Source that
|
We are also working on a hosted Graphite-compatible Data Source that
|
||||||
will be optimized for use with Grafana. It’ll be easy to combine your
|
will be optimized for use with Grafana. It’ll be easy to combine your
|
||||||
@ -65,7 +66,6 @@ Grafana 3.0 comes with a new command line tool called grafana-cli. You
|
|||||||
can easily install plugins from Grafana.net with it. For
|
can easily install plugins from Grafana.net with it. For
|
||||||
example:
|
example:
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
grafana-cli install grafana-pie-chart-panel
|
grafana-cli install grafana-pie-chart-panel
|
||||||
```
|
```
|
||||||
@ -188,6 +188,33 @@ you can still install manually from [Grafana.net](http://grafana.net)
|
|||||||
* KairosDB: This data source has also no longer shipped with Grafana,
|
* KairosDB: This data source has also no longer shipped with Grafana,
|
||||||
you can install it manually from [Grafana.net](http://grafana.net)
|
you can install it manually from [Grafana.net](http://grafana.net)
|
||||||
|
|
||||||
|
## Plugin showcase
|
||||||
|
|
||||||
|
Discovering and installing plugins is very quick and easy with Grafana 3.0 and [Grafana.net](https://grafana.net). Here
|
||||||
|
are a couple that I incurage you try!
|
||||||
|
|
||||||
|
#### [Clock Panel](https://grafana.net/plugins/grafana-clock-panel)
|
||||||
|
Support's both current time and count down mode.
|
||||||
|
<img src="/img/v3/clock_panel.png">
|
||||||
|
|
||||||
|
#### [Pie Chart Panel](https://grafana.net/plugins/grafana-piechart-panel)
|
||||||
|
A simple pie chart panel is now available as an external plugin.
|
||||||
|
<img src="/img/v3/pie_chart_panel.png">
|
||||||
|
|
||||||
|
#### [WorldPing App](https://grafana.net/plugins/raintank-worldping-app)
|
||||||
|
This is full blown Grafana App that adds new panels, data sources and pages to give
|
||||||
|
feature rich global performance monitoring directly from your on-prem Grafana.
|
||||||
|
|
||||||
|
<img src="/img/v3/wP-Screenshot-dash-web.png">
|
||||||
|
|
||||||
|
#### [Zabbix App](https://grafana.net/plugins/alexanderzobnin-zabbix-app)
|
||||||
|
This app contains the already very pouplar Zabbix data source plugin, 2 dashboards and a triggers panel. It is
|
||||||
|
created and maintained by [Alexander Zobnin](https://github.com/alexanderzobnin/grafana-zabbix).
|
||||||
|
|
||||||
|
<img src="/img/v3/zabbix_app.png">
|
||||||
|
|
||||||
|
Checkout the full list of plugins on [Grafana.net](https://grafana.net/plugins)
|
||||||
|
|
||||||
## CHANGELOG
|
## CHANGELOG
|
||||||
|
|
||||||
For a detailed list and link to github issues for everything included
|
For a detailed list and link to github issues for everything included
|
||||||
|
@ -10,20 +10,13 @@ page_keywords: grafana, installation, debian, ubuntu, guide
|
|||||||
|
|
||||||
Description | Download
|
Description | Download
|
||||||
------------ | -------------
|
------------ | -------------
|
||||||
Stable .deb for Debian-based Linux | [grafana_2.6.0_amd64.deb](https://grafanarel.s3.amazonaws.com/builds/grafana_2.6.0_amd64.deb)
|
Stable .deb for Debian-based Linux | [grafana_3.0.1_amd64.deb](https://grafanarel.s3.amazonaws.com/builds/grafana_3.0.1_amd64.deb)
|
||||||
Beta .deb for Debian-based Linux | [grafana_3.0.0-beta71462173753_amd64.deb](https://grafanarel.s3.amazonaws.com/builds/grafana_3.0.0-beta71462173753_amd64.deb)
|
|
||||||
|
|
||||||
## Install Stable
|
## Install Stable
|
||||||
|
|
||||||
$ wget https://grafanarel.s3.amazonaws.com/builds/grafana_2.6.0_amd64.deb
|
$ wget https://grafanarel.s3.amazonaws.com/builds/grafana_3.0.1_amd64.deb
|
||||||
$ sudo apt-get install -y adduser libfontconfig
|
$ sudo apt-get install -y adduser libfontconfig
|
||||||
$ sudo dpkg -i grafana_2.6.0_amd64.deb
|
$ sudo dpkg -i grafana_3.0.1_amd64.deb
|
||||||
|
|
||||||
## Install 3.0 Beta
|
|
||||||
|
|
||||||
$ wget https://grafanarel.s3.amazonaws.com/builds/grafana_3.0.0-beta71462173753_amd64.deb
|
|
||||||
$ sudo apt-get install -y adduser libfontconfig
|
|
||||||
$ sudo dpkg -i grafana_3.0.0-beta71462173753_amd64.deb
|
|
||||||
|
|
||||||
## APT Repository
|
## APT Repository
|
||||||
|
|
||||||
|
@ -10,43 +10,24 @@ page_keywords: grafana, installation, centos, fedora, opensuse, redhat, guide
|
|||||||
|
|
||||||
Description | Download
|
Description | Download
|
||||||
------------ | -------------
|
------------ | -------------
|
||||||
Stable .RPM for CentOS / Fedora / OpenSuse / Redhat Linux | [grafana-2.6.0-1.x86_64.rpm](https://grafanarel.s3.amazonaws.com/builds/grafana-2.6.0-1.x86_64.rpm)
|
Stable .RPM for CentOS / Fedora / OpenSuse / Redhat Linux | [grafana-3.0.1-1.x86_64.rpm](https://grafanarel.s3.amazonaws.com/builds/grafana-3.0.1-1.x86_64.rpm)
|
||||||
Beta .RPM for CentOS / Fedor / OpenSuse / Redhat Linux | [grafana-3.0.0-beta71462173753.x86_64.rpm](https://grafanarel.s3.amazonaws.com/builds/grafana-3.0.0-beta71462173753.x86_64.rpm)
|
|
||||||
|
|
||||||
## Install Stable Release from package file
|
## Install Stable Release from package file
|
||||||
|
|
||||||
You can install Grafana using Yum directly.
|
You can install Grafana using Yum directly.
|
||||||
|
|
||||||
$ sudo yum install https://grafanarel.s3.amazonaws.com/builds/grafana-2.6.0-1.x86_64.rpm
|
$ sudo yum install https://grafanarel.s3.amazonaws.com/builds/grafana-3.0.1-1.x86_64.rpm
|
||||||
|
|
||||||
Or install manually using `rpm`.
|
Or install manually using `rpm`.
|
||||||
|
|
||||||
#### On CentOS / Fedora / Redhat:
|
#### On CentOS / Fedora / Redhat:
|
||||||
|
|
||||||
$ sudo yum install initscripts fontconfig
|
$ sudo yum install initscripts fontconfig
|
||||||
$ sudo rpm -Uvh grafana-2.6.0-1.x86_64.rpm
|
$ sudo rpm -Uvh grafana-3.0.1-1.x86_64.rpm
|
||||||
|
|
||||||
#### On OpenSuse:
|
#### On OpenSuse:
|
||||||
|
|
||||||
$ sudo rpm -i --nodeps grafana-2.6.0-1.x86_64.rpm
|
$ sudo rpm -i --nodeps grafana-3.0.1-1.x86_64.rpm
|
||||||
|
|
||||||
## Install Beta Release from package file
|
|
||||||
|
|
||||||
You can install Grafana using Yum directly.
|
|
||||||
|
|
||||||
$ sudo yum install https://grafanarel.s3.amazonaws.com/builds/grafana-3.0.0-beta71462173753.x86_64.rpm
|
|
||||||
|
|
||||||
Or install manually using `rpm`.
|
|
||||||
|
|
||||||
#### On CentOS / Fedora / Redhat:
|
|
||||||
|
|
||||||
$ sudo yum install initscripts fontconfig
|
|
||||||
$ sudo rpm -Uvh grafana-3.0.0-beta71462173753.x86_64.rpm
|
|
||||||
|
|
||||||
#### On OpenSuse:
|
|
||||||
|
|
||||||
$ sudo rpm -i --nodeps grafana-3.0.0-beta71462173753.x86_64.rpm
|
|
||||||
|
|
||||||
|
|
||||||
## Install via YUM Repository
|
## Install via YUM Repository
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"stable": "2.6.0",
|
"stable": "3.0.1",
|
||||||
"testing": "3.0.0-beta7"
|
"testing": "3.0.1"
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"company": "Coding Instinct AB"
|
"company": "Coding Instinct AB"
|
||||||
},
|
},
|
||||||
"name": "grafana",
|
"name": "grafana",
|
||||||
"version": "3.0.0-beta7",
|
"version": "3.0.2",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "http://github.com/grafana/grafana.git"
|
"url": "http://github.com/grafana/grafana.git"
|
||||||
|
@ -14,6 +14,6 @@ CONF_DIR=/etc/grafana
|
|||||||
|
|
||||||
CONF_FILE=/etc/grafana/grafana.ini
|
CONF_FILE=/etc/grafana/grafana.ini
|
||||||
|
|
||||||
RESTART_ON_UPGRADE=false
|
RESTART_ON_UPGRADE=true
|
||||||
|
|
||||||
PLUGINS_DIR=/var/lib/grafana/plugins
|
PLUGINS_DIR=/var/lib/grafana/plugins
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#! /usr/bin/env bash
|
#! /usr/bin/env bash
|
||||||
|
|
||||||
deb_ver=3.0.0-beta51460658374
|
deb_ver=3.0.1
|
||||||
rpm_ver=3.0.0-beta51460658374
|
rpm_ver=3.0.1-1
|
||||||
|
|
||||||
#rpm_ver=3.0.0-1
|
#rpm_ver=3.0.0-1
|
||||||
|
|
||||||
@ -16,7 +16,7 @@ rpm_ver=3.0.0-beta51460658374
|
|||||||
#wget https://grafanarel.s3.amazonaws.com/builds/grafana-${rpm_ver}.x86_64.rpm
|
#wget https://grafanarel.s3.amazonaws.com/builds/grafana-${rpm_ver}.x86_64.rpm
|
||||||
|
|
||||||
#package_cloud push grafana/testing/el/6 grafana-${rpm_ver}.x86_64.rpm
|
#package_cloud push grafana/testing/el/6 grafana-${rpm_ver}.x86_64.rpm
|
||||||
package_cloud push grafana/testing/el/7 grafana-${rpm_ver}.x86_64.rpm
|
#package_cloud push grafana/testing/el/7 grafana-${rpm_ver}.x86_64.rpm
|
||||||
|
|
||||||
# package_cloud push grafana/stable/el/7 grafana-${version}-1.x86_64.rpm
|
package_cloud push grafana/stable/el/7 grafana-${rpm_ver}.x86_64.rpm
|
||||||
# package_cloud push grafana/stable/el/6 grafana-${version}-1.x86_64.rpm
|
package_cloud push grafana/stable/el/6 grafana-${rpm_ver}.x86_64.rpm
|
||||||
|
@ -14,6 +14,6 @@ CONF_DIR=/etc/grafana
|
|||||||
|
|
||||||
CONF_FILE=/etc/grafana/grafana.ini
|
CONF_FILE=/etc/grafana/grafana.ini
|
||||||
|
|
||||||
RESTART_ON_UPGRADE=false
|
RESTART_ON_UPGRADE=true
|
||||||
|
|
||||||
PLUGINS_DIR=/var/lib/grafana/plugins
|
PLUGINS_DIR=/var/lib/grafana/plugins
|
||||||
|
@ -91,14 +91,14 @@ func checkForUpdates() {
|
|||||||
|
|
||||||
resp2, err := client.Get("https://raw.githubusercontent.com/grafana/grafana/master/latest.json")
|
resp2, err := client.Get("https://raw.githubusercontent.com/grafana/grafana/master/latest.json")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Trace("Failed to get lates.json repo from github: %v", err.Error())
|
log.Trace("Failed to get latest.json repo from github: %v", err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
defer resp2.Body.Close()
|
defer resp2.Body.Close()
|
||||||
body, err = ioutil.ReadAll(resp2.Body)
|
body, err = ioutil.ReadAll(resp2.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Trace("Update check failed, reading response from github.net, %v", err.Error())
|
log.Trace("Update check failed, reading response from github.com, %v", err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
182
public/app/features/dashboard/dynamicDashboardSrv.js
Normal file
182
public/app/features/dashboard/dynamicDashboardSrv.js
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
define([
|
||||||
|
'angular',
|
||||||
|
'lodash',
|
||||||
|
],
|
||||||
|
function (angular, _) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var module = angular.module('grafana.services');
|
||||||
|
|
||||||
|
module.service('dynamicDashboardSrv', function() {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
this.init = function(dashboard) {
|
||||||
|
if (dashboard.snapshot) { return; }
|
||||||
|
|
||||||
|
this.iteration = new Date().getTime();
|
||||||
|
this.process(dashboard);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.update = function(dashboard) {
|
||||||
|
if (dashboard.snapshot) { return; }
|
||||||
|
|
||||||
|
this.iteration = this.iteration + 1;
|
||||||
|
this.process(dashboard);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.process = function(dashboard) {
|
||||||
|
if (dashboard.templating.list.length === 0) { return; }
|
||||||
|
this.dashboard = dashboard;
|
||||||
|
|
||||||
|
var i, j, row, panel;
|
||||||
|
for (i = 0; i < this.dashboard.rows.length; i++) {
|
||||||
|
row = this.dashboard.rows[i];
|
||||||
|
// handle row repeats
|
||||||
|
if (row.repeat) {
|
||||||
|
this.repeatRow(row, i);
|
||||||
|
}
|
||||||
|
// clean up old left overs
|
||||||
|
else if (row.repeatRowId && row.repeatIteration !== this.iteration) {
|
||||||
|
this.dashboard.rows.splice(i, 1);
|
||||||
|
i = i - 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// repeat panels
|
||||||
|
for (j = 0; j < row.panels.length; j++) {
|
||||||
|
panel = row.panels[j];
|
||||||
|
if (panel.repeat) {
|
||||||
|
this.repeatPanel(panel, row);
|
||||||
|
}
|
||||||
|
// clean up old left overs
|
||||||
|
else if (panel.repeatPanelId && panel.repeatIteration !== this.iteration) {
|
||||||
|
row.panels = _.without(row.panels, panel);
|
||||||
|
j = j - 1;
|
||||||
|
} else if (row.repeat || row.repeatRowId) {
|
||||||
|
continue;
|
||||||
|
} else if (!_.isEmpty(panel.scopedVars) && panel.repeatIteration !== this.iteration) {
|
||||||
|
panel.scopedVars = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// returns a new row clone or reuses a clone from previous iteration
|
||||||
|
this.getRowClone = function(sourceRow, repeatIndex, sourceRowIndex) {
|
||||||
|
if (repeatIndex === 0) {
|
||||||
|
return sourceRow;
|
||||||
|
}
|
||||||
|
|
||||||
|
var i, panel, row, copy;
|
||||||
|
var sourceRowId = sourceRowIndex + 1;
|
||||||
|
|
||||||
|
// look for row to reuse
|
||||||
|
for (i = 0; i < this.dashboard.rows.length; i++) {
|
||||||
|
row = this.dashboard.rows[i];
|
||||||
|
if (row.repeatRowId === sourceRowId && row.repeatIteration !== this.iteration) {
|
||||||
|
copy = row;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!copy) {
|
||||||
|
copy = angular.copy(sourceRow);
|
||||||
|
this.dashboard.rows.splice(sourceRowIndex + repeatIndex, 0, copy);
|
||||||
|
|
||||||
|
// set new panel ids
|
||||||
|
for (i = 0; i < copy.panels.length; i++) {
|
||||||
|
panel = copy.panels[i];
|
||||||
|
panel.id = this.dashboard.getNextPanelId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
copy.repeat = null;
|
||||||
|
copy.repeatRowId = sourceRowId;
|
||||||
|
copy.repeatIteration = this.iteration;
|
||||||
|
return copy;
|
||||||
|
};
|
||||||
|
|
||||||
|
// returns a new row clone or reuses a clone from previous iteration
|
||||||
|
this.repeatRow = function(row, rowIndex) {
|
||||||
|
var variables = this.dashboard.templating.list;
|
||||||
|
var variable = _.findWhere(variables, {name: row.repeat});
|
||||||
|
if (!variable) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var selected, copy, i, panel;
|
||||||
|
if (variable.current.text === 'All') {
|
||||||
|
selected = variable.options.slice(1, variable.options.length);
|
||||||
|
} else {
|
||||||
|
selected = _.filter(variable.options, {selected: true});
|
||||||
|
}
|
||||||
|
|
||||||
|
_.each(selected, function(option, index) {
|
||||||
|
copy = self.getRowClone(row, index, rowIndex);
|
||||||
|
copy.scopedVars = {};
|
||||||
|
copy.scopedVars[variable.name] = option;
|
||||||
|
|
||||||
|
for (i = 0; i < copy.panels.length; i++) {
|
||||||
|
panel = copy.panels[i];
|
||||||
|
panel.scopedVars = {};
|
||||||
|
panel.scopedVars[variable.name] = option;
|
||||||
|
}
|
||||||
|
}, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.getPanelClone = function(sourcePanel, row, index) {
|
||||||
|
// if first clone return source
|
||||||
|
if (index === 0) {
|
||||||
|
return sourcePanel;
|
||||||
|
}
|
||||||
|
|
||||||
|
var i, tmpId, panel, clone;
|
||||||
|
|
||||||
|
// first try finding an existing clone to use
|
||||||
|
for (i = 0; i < row.panels.length; i++) {
|
||||||
|
panel = row.panels[i];
|
||||||
|
if (panel.repeatIteration !== this.iteration && panel.repeatPanelId === sourcePanel.id) {
|
||||||
|
clone = panel;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!clone) {
|
||||||
|
clone = { id: this.dashboard.getNextPanelId() };
|
||||||
|
row.panels.push(clone);
|
||||||
|
}
|
||||||
|
|
||||||
|
// save id
|
||||||
|
tmpId = clone.id;
|
||||||
|
// copy properties from source
|
||||||
|
angular.copy(sourcePanel, clone);
|
||||||
|
// restore id
|
||||||
|
clone.id = tmpId;
|
||||||
|
clone.repeatIteration = this.iteration;
|
||||||
|
clone.repeatPanelId = sourcePanel.id;
|
||||||
|
clone.repeat = null;
|
||||||
|
return clone;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.repeatPanel = function(panel, row) {
|
||||||
|
var variables = this.dashboard.templating.list;
|
||||||
|
var variable = _.findWhere(variables, {name: panel.repeat});
|
||||||
|
if (!variable) { return; }
|
||||||
|
|
||||||
|
var selected;
|
||||||
|
if (variable.current.text === 'All') {
|
||||||
|
selected = variable.options.slice(1, variable.options.length);
|
||||||
|
} else {
|
||||||
|
selected = _.filter(variable.options, {selected: true});
|
||||||
|
}
|
||||||
|
|
||||||
|
_.each(selected, function(option, index) {
|
||||||
|
var copy = self.getPanelClone(panel, row, index);
|
||||||
|
copy.span = Math.max(12 / selected.length, panel.minSpan);
|
||||||
|
copy.scopedVars = copy.scopedVars || {};
|
||||||
|
copy.scopedVars[variable.name] = option;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
@ -97,7 +97,8 @@ function (angular, _) {
|
|||||||
if (!str) {
|
if (!str) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return str.indexOf('$' + variableName) !== -1 || str.indexOf('[[' + variableName + ']]') !== -1;
|
var match = this._regex.exec(str);
|
||||||
|
return match && (match[1] === variableName || match[2] === variableName);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.highlightVariablesAsHtml = function(str) {
|
this.highlightVariablesAsHtml = function(str) {
|
||||||
|
@ -204,7 +204,7 @@ function (angular, _, kbn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (options.length === 0) {
|
if (options.length === 0) {
|
||||||
options.push({text: 'No datasurces found', value: ''});
|
options.push({text: 'No data sources found', value: ''});
|
||||||
}
|
}
|
||||||
|
|
||||||
variable.options = options;
|
variable.options = options;
|
||||||
|
Binary file not shown.
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 114 KiB After Width: | Height: | Size: 116 KiB |
Binary file not shown.
Binary file not shown.
@ -1,10 +1,10 @@
|
|||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'grafana-icons';
|
font-family: 'grafana-icons';
|
||||||
src: url('../fonts/grafana-icons.eot?h6rv8b');
|
src: url('../fonts/grafana-icons.eot?okx5td');
|
||||||
src: url('../fonts/grafana-icons.eot?h6rv8b#iefix') format('embedded-opentype'),
|
src: url('../fonts/grafana-icons.eot?okx5td#iefix') format('embedded-opentype'),
|
||||||
url('../fonts/grafana-icons.ttf?h6rv8b') format('truetype'),
|
url('../fonts/grafana-icons.ttf?okx5td') format('truetype'),
|
||||||
url('../fonts/grafana-icons.woff?h6rv8b') format('woff'),
|
url('../fonts/grafana-icons.woff?okx5td') format('woff'),
|
||||||
url('../fonts/grafana-icons.svg?h6rv8b#grafana-icons') format('svg');
|
url('../fonts/grafana-icons.svg?okx5td#grafana-icons') format('svg');
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
@ -61,6 +61,9 @@
|
|||||||
.icon-gf-endpoint:before {
|
.icon-gf-endpoint:before {
|
||||||
content: "\e609";
|
content: "\e609";
|
||||||
}
|
}
|
||||||
|
.icon-gf-page:before {
|
||||||
|
content: "\e908";
|
||||||
|
}
|
||||||
.icon-gf-filter:before {
|
.icon-gf-filter:before {
|
||||||
content: "\e60a";
|
content: "\e60a";
|
||||||
}
|
}
|
||||||
@ -112,9 +115,6 @@
|
|||||||
.icon-gf-save:before {
|
.icon-gf-save:before {
|
||||||
content: "\e614";
|
content: "\e614";
|
||||||
}
|
}
|
||||||
.icon-gf-settings:before {
|
|
||||||
content: "\e615";
|
|
||||||
}
|
|
||||||
.icon-gf-share:before {
|
.icon-gf-share:before {
|
||||||
content: "\e616";
|
content: "\e616";
|
||||||
}
|
}
|
||||||
@ -124,10 +124,13 @@
|
|||||||
.icon-gf-search:before {
|
.icon-gf-search:before {
|
||||||
content: "\e618";
|
content: "\e618";
|
||||||
}
|
}
|
||||||
.icon-gf-tag-add:before {
|
.icon-gf-settings:before {
|
||||||
|
content: "\e615";
|
||||||
|
}
|
||||||
|
.icon-gf-add:before {
|
||||||
content: "\e619";
|
content: "\e619";
|
||||||
}
|
}
|
||||||
.icon-gf-tag-remove:before {
|
.icon-gf-remove:before {
|
||||||
content: "\e61a";
|
content: "\e61a";
|
||||||
}
|
}
|
||||||
.icon-gf-video:before {
|
.icon-gf-video:before {
|
||||||
@ -169,6 +172,12 @@
|
|||||||
.icon-gf-scale:before {
|
.icon-gf-scale:before {
|
||||||
content: "\e906";
|
content: "\e906";
|
||||||
}
|
}
|
||||||
|
.icon-gf-pending:before {
|
||||||
|
content: "\e909";
|
||||||
|
}
|
||||||
|
.icon-gf-verified:before {
|
||||||
|
content: "\e90a";
|
||||||
|
}
|
||||||
.icon-gf-worldping:before {
|
.icon-gf-worldping:before {
|
||||||
content: "\e627";
|
content: "\e627";
|
||||||
}
|
}
|
||||||
@ -176,10 +185,3 @@
|
|||||||
content: "\e903";
|
content: "\e903";
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-gf-app:before {
|
|
||||||
content: "\e902";
|
|
||||||
}
|
|
||||||
.icon-gf-datasource:before {
|
|
||||||
content: "\e607";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
268
public/test/specs/dynamicDashboardSrv-specs.js
Normal file
268
public/test/specs/dynamicDashboardSrv-specs.js
Normal file
@ -0,0 +1,268 @@
|
|||||||
|
define([
|
||||||
|
'app/features/dashboard/dynamicDashboardSrv',
|
||||||
|
'app/features/dashboard/dashboardSrv'
|
||||||
|
], function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
function dynamicDashScenario(desc, func) {
|
||||||
|
|
||||||
|
describe(desc, function() {
|
||||||
|
var ctx = {};
|
||||||
|
|
||||||
|
ctx.setup = function (setupFunc) {
|
||||||
|
|
||||||
|
beforeEach(module('grafana.services'));
|
||||||
|
beforeEach(module(function($provide) {
|
||||||
|
$provide.value('contextSrv', {
|
||||||
|
user: { timezone: 'utc'}
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(inject(function(dynamicDashboardSrv, dashboardSrv) {
|
||||||
|
ctx.dynamicDashboardSrv = dynamicDashboardSrv;
|
||||||
|
ctx.dashboardSrv = dashboardSrv;
|
||||||
|
|
||||||
|
var model = {
|
||||||
|
rows: [],
|
||||||
|
templating: { list: [] }
|
||||||
|
};
|
||||||
|
|
||||||
|
setupFunc(model);
|
||||||
|
ctx.dash = ctx.dashboardSrv.create(model);
|
||||||
|
ctx.dynamicDashboardSrv.init(ctx.dash);
|
||||||
|
ctx.rows = ctx.dash.rows;
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
func(ctx);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamicDashScenario('given dashboard with panel repeat', function(ctx) {
|
||||||
|
ctx.setup(function(dash) {
|
||||||
|
dash.rows.push({
|
||||||
|
panels: [{id: 2, repeat: 'apps'}]
|
||||||
|
});
|
||||||
|
dash.templating.list.push({
|
||||||
|
name: 'apps',
|
||||||
|
current: {
|
||||||
|
text: 'se1, se2, se3',
|
||||||
|
value: ['se1', 'se2', 'se3']
|
||||||
|
},
|
||||||
|
options: [
|
||||||
|
{text: 'se1', value: 'se1', selected: true},
|
||||||
|
{text: 'se2', value: 'se2', selected: true},
|
||||||
|
{text: 'se3', value: 'se3', selected: true},
|
||||||
|
{text: 'se4', value: 'se4', selected: false}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should repeat panel one time', function() {
|
||||||
|
expect(ctx.rows[0].panels.length).to.be(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should mark panel repeated', function() {
|
||||||
|
expect(ctx.rows[0].panels[0].repeat).to.be('apps');
|
||||||
|
expect(ctx.rows[0].panels[1].repeatPanelId).to.be(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set scopedVars on panels', function() {
|
||||||
|
expect(ctx.rows[0].panels[0].scopedVars.apps.value).to.be('se1');
|
||||||
|
expect(ctx.rows[0].panels[1].scopedVars.apps.value).to.be('se2');
|
||||||
|
expect(ctx.rows[0].panels[2].scopedVars.apps.value).to.be('se3');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('After a second iteration', function() {
|
||||||
|
var repeatedPanelAfterIteration1;
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
repeatedPanelAfterIteration1 = ctx.rows[0].panels[1];
|
||||||
|
ctx.rows[0].panels[0].fill = 10;
|
||||||
|
ctx.dynamicDashboardSrv.update(ctx.dash);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have reused same panel instances', function() {
|
||||||
|
expect(ctx.rows[0].panels[1]).to.be(repeatedPanelAfterIteration1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reused panel should copy properties from source', function() {
|
||||||
|
expect(ctx.rows[0].panels[1].fill).to.be(10);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have same panel count', function() {
|
||||||
|
expect(ctx.rows[0].panels.length).to.be(3);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('After a second iteration and selected values reduced', function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
ctx.dash.templating.list[0].options[1].selected = false;
|
||||||
|
|
||||||
|
ctx.dynamicDashboardSrv.update(ctx.dash);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should clean up repeated panel', function() {
|
||||||
|
expect(ctx.rows[0].panels.length).to.be(2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('After a second iteration and panel repeat is turned off', function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
ctx.rows[0].panels[0].repeat = null;
|
||||||
|
ctx.dynamicDashboardSrv.update(ctx.dash);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should clean up repeated panel', function() {
|
||||||
|
expect(ctx.rows[0].panels.length).to.be(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should remove scoped vars from reused panel', function() {
|
||||||
|
expect(ctx.rows[0].panels[0].scopedVars).to.be.empty();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
dynamicDashScenario('given dashboard with row repeat', function(ctx) {
|
||||||
|
ctx.setup(function(dash) {
|
||||||
|
dash.rows.push({
|
||||||
|
repeat: 'servers',
|
||||||
|
panels: [{id: 2}]
|
||||||
|
});
|
||||||
|
dash.rows.push({panels: []});
|
||||||
|
dash.templating.list.push({
|
||||||
|
name: 'servers',
|
||||||
|
current: {
|
||||||
|
text: 'se1, se2',
|
||||||
|
value: ['se1', 'se2']
|
||||||
|
},
|
||||||
|
options: [
|
||||||
|
{text: 'se1', value: 'se1', selected: true},
|
||||||
|
{text: 'se2', value: 'se2', selected: true},
|
||||||
|
]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should repeat row one time', function() {
|
||||||
|
expect(ctx.rows.length).to.be(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should keep panel ids on first row', function() {
|
||||||
|
expect(ctx.rows[0].panels[0].id).to.be(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should keep first row as repeat', function() {
|
||||||
|
expect(ctx.rows[0].repeat).to.be('servers');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should clear repeat field on repeated row', function() {
|
||||||
|
expect(ctx.rows[1].repeat).to.be(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add scopedVars to rows', function() {
|
||||||
|
expect(ctx.rows[0].scopedVars.servers.value).to.be('se1');
|
||||||
|
expect(ctx.rows[1].scopedVars.servers.value).to.be('se2');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should generate a repeartRowId based on repeat row index', function() {
|
||||||
|
expect(ctx.rows[1].repeatRowId).to.be(1);
|
||||||
|
expect(ctx.rows[1].repeatIteration).to.be(ctx.dynamicDashboardSrv.iteration);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set scopedVars on row panels', function() {
|
||||||
|
expect(ctx.rows[0].panels[0].scopedVars.servers.value).to.be('se1');
|
||||||
|
expect(ctx.rows[1].panels[0].scopedVars.servers.value).to.be('se2');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('After a second iteration', function() {
|
||||||
|
var repeatedRowAfterFirstIteration;
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
repeatedRowAfterFirstIteration = ctx.rows[1];
|
||||||
|
ctx.rows[0].height = 500;
|
||||||
|
ctx.dynamicDashboardSrv.update(ctx.dash);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should still only have 2 rows', function() {
|
||||||
|
expect(ctx.rows.length).to.be(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip('should have updated props from source', function() {
|
||||||
|
expect(ctx.rows[1].height).to.be(500);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should reuse row instance', function() {
|
||||||
|
expect(ctx.rows[1]).to.be(repeatedRowAfterFirstIteration);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('After a second iteration and selected values reduced', function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
ctx.dash.templating.list[0].options[1].selected = false;
|
||||||
|
ctx.dynamicDashboardSrv.update(ctx.dash);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should remove repeated second row', function() {
|
||||||
|
expect(ctx.rows.length).to.be(2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
dynamicDashScenario('given dashboard with row repeat and panel repeat', function(ctx) {
|
||||||
|
ctx.setup(function(dash) {
|
||||||
|
dash.rows.push({
|
||||||
|
repeat: 'servers',
|
||||||
|
panels: [{id: 2, repeat: 'metric'}]
|
||||||
|
});
|
||||||
|
dash.templating.list.push({
|
||||||
|
name: 'servers',
|
||||||
|
current: { text: 'se1, se2', value: ['se1', 'se2'] },
|
||||||
|
options: [
|
||||||
|
{text: 'se1', value: 'se1', selected: true},
|
||||||
|
{text: 'se2', value: 'se2', selected: true},
|
||||||
|
]
|
||||||
|
});
|
||||||
|
dash.templating.list.push({
|
||||||
|
name: 'metric',
|
||||||
|
current: { text: 'm1, m2', value: ['m1', 'm2'] },
|
||||||
|
options: [
|
||||||
|
{text: 'm1', value: 'm1', selected: true},
|
||||||
|
{text: 'm2', value: 'm2', selected: true},
|
||||||
|
]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should repeat row one time', function() {
|
||||||
|
expect(ctx.rows.length).to.be(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should repeat panel on both rows', function() {
|
||||||
|
expect(ctx.rows[0].panels.length).to.be(2);
|
||||||
|
expect(ctx.rows[1].panels.length).to.be(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should keep panel ids on first row', function() {
|
||||||
|
expect(ctx.rows[0].panels[0].id).to.be(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should mark second row as repeated', function() {
|
||||||
|
expect(ctx.rows[0].repeat).to.be('servers');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should clear repeat field on repeated row', function() {
|
||||||
|
expect(ctx.rows[1].repeat).to.be(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should generate a repeartRowId based on repeat row index', function() {
|
||||||
|
expect(ctx.rows[1].repeatRowId).to.be(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set scopedVars on row panels', function() {
|
||||||
|
expect(ctx.rows[0].panels[0].scopedVars.servers.value).to.be('se1');
|
||||||
|
expect(ctx.rows[1].panels[0].scopedVars.servers.value).to.be('se2');
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
@ -190,6 +190,11 @@ define([
|
|||||||
expect(contains).to.be(true);
|
expect(contains).to.be(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not find it if only part matches with $var syntax', function() {
|
||||||
|
var contains = _templateSrv.containsVariable('this.$ServerDomain.filters', 'Server');
|
||||||
|
expect(contains).to.be(false);
|
||||||
|
});
|
||||||
|
|
||||||
it('should find it with [[var]] syntax', function() {
|
it('should find it with [[var]] syntax', function() {
|
||||||
var contains = _templateSrv.containsVariable('this.[[test]].filters', 'test');
|
var contains = _templateSrv.containsVariable('this.[[test]].filters', 'test');
|
||||||
expect(contains).to.be(true);
|
expect(contains).to.be(true);
|
||||||
|
Loading…
Reference in New Issue
Block a user