mirror of
https://github.com/grafana/grafana.git
synced 2025-12-20 11:40:21 +08:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0daadc954c | ||
|
|
8c2b6b532d | ||
|
|
71d62012e1 | ||
|
|
6f094ef215 | ||
|
|
c41c771e9a | ||
|
|
f1ec270e3e | ||
|
|
a3f2f574c6 | ||
|
|
ec19a97156 | ||
|
|
9e6056551d | ||
|
|
9eec68985d | ||
|
|
dc77d555f9 | ||
|
|
1da149d9e1 | ||
|
|
43ba563a1c | ||
|
|
e6f251011f | ||
|
|
f00cbc0aeb | ||
|
|
ee86d24797 | ||
|
|
e0e8fd6637 | ||
|
|
2416ee04c8 | ||
|
|
df0ddc0b50 | ||
|
|
37821e6d63 | ||
|
|
d474eba53a | ||
|
|
cd80884b76 | ||
|
|
8d2f350ad1 | ||
|
|
99db89067e | ||
|
|
7f0fe31881 |
@@ -10,13 +10,13 @@ page_keywords: grafana, installation, debian, ubuntu, guide
|
||||
|
||||
Description | Download
|
||||
------------ | -------------
|
||||
Stable .deb for Debian-based Linux | [grafana_3.0.1_amd64.deb](https://grafanarel.s3.amazonaws.com/builds/grafana_3.0.1_amd64.deb)
|
||||
Stable .deb for Debian-based Linux | [grafana_3.0.3-1463994644.deb](https://grafanarel.s3.amazonaws.com/builds/grafana_3.0.3-1463994644_amd64.deb)
|
||||
|
||||
## Install Stable
|
||||
|
||||
$ wget https://grafanarel.s3.amazonaws.com/builds/grafana_3.0.1_amd64.deb
|
||||
$ wget https://grafanarel.s3.amazonaws.com/builds/grafana_3.0.3-1463994644_amd64.deb
|
||||
$ sudo apt-get install -y adduser libfontconfig
|
||||
$ sudo dpkg -i grafana_3.0.1_amd64.deb
|
||||
$ sudo dpkg -i grafana_3.0.3-1463994644_amd64.deb
|
||||
|
||||
## APT Repository
|
||||
|
||||
|
||||
@@ -10,24 +10,24 @@ page_keywords: grafana, installation, centos, fedora, opensuse, redhat, guide
|
||||
|
||||
Description | Download
|
||||
------------ | -------------
|
||||
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)
|
||||
Stable .RPM for CentOS / Fedora / OpenSuse / Redhat Linux | [grafana-3.0.3-1463994644.x86_64.rpm](https://grafanarel.s3.amazonaws.com/builds/grafana-3.0.3-1463994644.x86_64.rpm)
|
||||
|
||||
## Install Stable Release from package file
|
||||
|
||||
You can install Grafana using Yum directly.
|
||||
|
||||
$ sudo yum install https://grafanarel.s3.amazonaws.com/builds/grafana-3.0.1-1.x86_64.rpm
|
||||
$ sudo yum install https://grafanarel.s3.amazonaws.com/builds/grafana-3.0.3-1463994644.x86_64.rpm
|
||||
|
||||
Or install manually using `rpm`.
|
||||
|
||||
#### On CentOS / Fedora / Redhat:
|
||||
|
||||
$ sudo yum install initscripts fontconfig
|
||||
$ sudo rpm -Uvh grafana-3.0.1-1.x86_64.rpm
|
||||
$ sudo rpm -Uvh grafana-3.0.3-1463994644.x86_64.rpm
|
||||
|
||||
#### On OpenSuse:
|
||||
|
||||
$ sudo rpm -i --nodeps grafana-3.0.1-1.x86_64.rpm
|
||||
$ sudo rpm -i --nodeps grafana-3.0.3-1463994644.x86_64.rpm
|
||||
|
||||
## Install via YUM Repository
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ page_keywords: grafana, installation, windows guide
|
||||
|
||||
Description | Download
|
||||
------------ | -------------
|
||||
Stable Zip package for Windows | [grafana.2.6.0.windows-x64.zip](https://grafanarel.s3.amazonaws.com/winbuilds/dist/grafana-2.5.0.windows-x64.zip)
|
||||
Stable Zip package for Windows | [grafana.3.0.3.windows-x64.zip](https://grafanarel.s3.amazonaws.com/winbuilds/dist/grafana-3.0.3.windows-x64.zip)
|
||||
|
||||
## Configure
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"company": "Coding Instinct AB"
|
||||
},
|
||||
"name": "grafana",
|
||||
"version": "3.0.2",
|
||||
"version": "3.0.4",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "http://github.com/grafana/grafana.git"
|
||||
|
||||
@@ -14,6 +14,6 @@ CONF_DIR=/etc/grafana
|
||||
|
||||
CONF_FILE=/etc/grafana/grafana.ini
|
||||
|
||||
RESTART_ON_UPGRADE=true
|
||||
RESTART_ON_UPGRADE=false
|
||||
|
||||
PLUGINS_DIR=/var/lib/grafana/plugins
|
||||
|
||||
@@ -1,22 +1,20 @@
|
||||
#! /usr/bin/env bash
|
||||
|
||||
deb_ver=3.0.1
|
||||
rpm_ver=3.0.1-1
|
||||
deb_ver=3.0.3-1463994644
|
||||
rpm_ver=3.0.3-1463994644
|
||||
|
||||
#rpm_ver=3.0.0-1
|
||||
wget https://grafanarel.s3.amazonaws.com/builds/grafana_${deb_ver}_amd64.deb
|
||||
|
||||
#wget https://grafanarel.s3.amazonaws.com/builds/grafana_${deb_ver}_amd64.deb
|
||||
package_cloud push grafana/stable/debian/jessie grafana_${deb_ver}_amd64.deb
|
||||
package_cloud push grafana/stable/debian/wheezy grafana_${deb_ver}_amd64.deb
|
||||
|
||||
#package_cloud push grafana/stable/debian/jessie grafana_${deb_ver}_amd64.deb
|
||||
#package_cloud push grafana/stable/debian/wheezy grafana_${deb_ver}_amd64.deb
|
||||
package_cloud push grafana/testing/debian/jessie grafana_${deb_ver}_amd64.deb
|
||||
package_cloud push grafana/testing/debian/wheezy grafana_${deb_ver}_amd64.deb
|
||||
|
||||
#package_cloud push grafana/testing/debian/jessie grafana_${deb_ver}_amd64.deb
|
||||
#package_cloud push grafana/testing/debian/wheezy grafana_${deb_ver}_amd64.deb
|
||||
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/7 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/stable/el/7 grafana-${rpm_ver}.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
|
||||
|
||||
RESTART_ON_UPGRADE=true
|
||||
RESTART_ON_UPGRADE=false
|
||||
|
||||
PLUGINS_DIR=/var/lib/grafana/plugins
|
||||
|
||||
@@ -209,7 +209,7 @@ func Register(r *macaron.Macaron) {
|
||||
r.Combo("/db/:slug").Get(GetDashboard).Delete(DeleteDashboard)
|
||||
r.Post("/db", reqEditorRole, bind(m.SaveDashboardCommand{}), PostDashboard)
|
||||
r.Get("/file/:file", GetDashboardFromJsonFile)
|
||||
r.Get("/home", GetHomeDashboard)
|
||||
r.Get("/home", wrap(GetHomeDashboard))
|
||||
r.Get("/tags", GetDashboardTags)
|
||||
r.Post("/import", bind(dtos.ImportDashboardCommand{}), wrap(ImportDashboard))
|
||||
})
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/log"
|
||||
"github.com/grafana/grafana/pkg/metrics"
|
||||
"github.com/grafana/grafana/pkg/middleware"
|
||||
m "github.com/grafana/grafana/pkg/models"
|
||||
@@ -158,30 +159,27 @@ func canEditDashboard(role m.RoleType) bool {
|
||||
return role == m.ROLE_ADMIN || role == m.ROLE_EDITOR || role == m.ROLE_READ_ONLY_EDITOR
|
||||
}
|
||||
|
||||
func GetHomeDashboard(c *middleware.Context) {
|
||||
func GetHomeDashboard(c *middleware.Context) Response {
|
||||
prefsQuery := m.GetPreferencesWithDefaultsQuery{OrgId: c.OrgId, UserId: c.UserId}
|
||||
if err := bus.Dispatch(&prefsQuery); err != nil {
|
||||
c.JsonApiErr(500, "Failed to get preferences", err)
|
||||
return ApiError(500, "Failed to get preferences", err)
|
||||
}
|
||||
|
||||
if prefsQuery.Result.HomeDashboardId != 0 {
|
||||
slugQuery := m.GetDashboardSlugByIdQuery{Id: prefsQuery.Result.HomeDashboardId}
|
||||
err := bus.Dispatch(&slugQuery)
|
||||
if err != nil {
|
||||
c.JsonApiErr(500, "Failed to get slug from database", err)
|
||||
return
|
||||
if err == nil {
|
||||
dashRedirect := dtos.DashboardRedirect{RedirectUri: "db/" + slugQuery.Result}
|
||||
return Json(200, &dashRedirect)
|
||||
} else {
|
||||
log.Warn("Failed to get slug from database, %s", err.Error())
|
||||
}
|
||||
|
||||
dashRedirect := dtos.DashboardRedirect{RedirectUri: "db/" + slugQuery.Result}
|
||||
c.JSON(200, &dashRedirect)
|
||||
return
|
||||
}
|
||||
|
||||
filePath := path.Join(setting.StaticRootPath, "dashboards/home.json")
|
||||
file, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
c.JsonApiErr(500, "Failed to load home dashboard", err)
|
||||
return
|
||||
return ApiError(500, "Failed to load home dashboard", err)
|
||||
}
|
||||
|
||||
dash := dtos.DashboardFullWithMeta{}
|
||||
@@ -189,11 +187,10 @@ func GetHomeDashboard(c *middleware.Context) {
|
||||
dash.Meta.CanEdit = canEditDashboard(c.OrgRole)
|
||||
jsonParser := json.NewDecoder(file)
|
||||
if err := jsonParser.Decode(&dash.Dashboard); err != nil {
|
||||
c.JsonApiErr(500, "Failed to load home dashboard", err)
|
||||
return
|
||||
return ApiError(500, "Failed to load home dashboard", err)
|
||||
}
|
||||
|
||||
c.JSON(200, &dash)
|
||||
return Json(200, &dash)
|
||||
}
|
||||
|
||||
func GetDashboardFromJsonFile(c *middleware.Context) {
|
||||
|
||||
@@ -88,7 +88,7 @@ func NewApiPluginProxy(ctx *middleware.Context, proxyPath string, route *plugins
|
||||
}
|
||||
|
||||
for key, value := range headers {
|
||||
log.Info("setting key %v value %v", key, value[0])
|
||||
log.Trace("setting key %v value %v", key, value[0])
|
||||
req.Header.Set(key, value[0])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -526,6 +526,17 @@ var logLevels = map[string]int{
|
||||
"Critical": 5,
|
||||
}
|
||||
|
||||
func getLogLevel(key string, defaultName string) (string, int) {
|
||||
levelName := Cfg.Section(key).Key("level").In(defaultName, []string{"Trace", "Debug", "Info", "Warn", "Error", "Critical"})
|
||||
|
||||
level, ok := logLevels[levelName]
|
||||
if !ok {
|
||||
log.Fatal(4, "Unknown log level: %s", levelName)
|
||||
}
|
||||
|
||||
return levelName, level
|
||||
}
|
||||
|
||||
func initLogging(args *CommandLineArgs) {
|
||||
//close any existing log handlers.
|
||||
log.Close()
|
||||
@@ -533,8 +544,12 @@ func initLogging(args *CommandLineArgs) {
|
||||
LogModes = strings.Split(Cfg.Section("log").Key("mode").MustString("console"), ",")
|
||||
LogsPath = makeAbsolute(Cfg.Section("paths").Key("logs").String(), HomePath)
|
||||
|
||||
defaultLevelName, _ := getLogLevel("log", "Info")
|
||||
|
||||
LogConfigs = make([]util.DynMap, len(LogModes))
|
||||
|
||||
for i, mode := range LogModes {
|
||||
|
||||
mode = strings.TrimSpace(mode)
|
||||
sec, err := Cfg.GetSection("log." + mode)
|
||||
if err != nil {
|
||||
@@ -542,12 +557,7 @@ func initLogging(args *CommandLineArgs) {
|
||||
}
|
||||
|
||||
// Log level.
|
||||
levelName := Cfg.Section("log."+mode).Key("level").In("Trace",
|
||||
[]string{"Trace", "Debug", "Info", "Warn", "Error", "Critical"})
|
||||
level, ok := logLevels[levelName]
|
||||
if !ok {
|
||||
log.Fatal(4, "Unknown log level: %s", levelName)
|
||||
}
|
||||
_, level := getLogLevel("log."+mode, defaultLevelName)
|
||||
|
||||
// Generate log configuration.
|
||||
switch mode {
|
||||
|
||||
@@ -66,14 +66,17 @@ function (angular, _, coreModule, config) {
|
||||
};
|
||||
|
||||
this.getAnnotationSources = function() {
|
||||
return _.reduce(config.datasources, function(memo, value) {
|
||||
var sources = [];
|
||||
|
||||
this.addDataSourceVariables(sources);
|
||||
|
||||
_.each(config.datasources, function(value) {
|
||||
if (value.meta && value.meta.annotations) {
|
||||
memo.push(value);
|
||||
sources.push(value);
|
||||
}
|
||||
});
|
||||
|
||||
return memo;
|
||||
}, []);
|
||||
return sources;
|
||||
};
|
||||
|
||||
this.getMetricSources = function(options) {
|
||||
@@ -90,24 +93,7 @@ function (angular, _, coreModule, config) {
|
||||
});
|
||||
|
||||
if (!options || !options.skipVariables) {
|
||||
// look for data source variables
|
||||
for (var i = 0; i < templateSrv.variables.length; i++) {
|
||||
var variable = templateSrv.variables[i];
|
||||
if (variable.type !== 'datasource') {
|
||||
continue;
|
||||
}
|
||||
|
||||
var first = variable.current.value;
|
||||
var ds = config.datasources[first];
|
||||
|
||||
if (ds) {
|
||||
metricSources.push({
|
||||
name: '$' + variable.name,
|
||||
value: '$' + variable.name,
|
||||
meta: ds.meta,
|
||||
});
|
||||
}
|
||||
}
|
||||
this.addDataSourceVariables(metricSources);
|
||||
}
|
||||
|
||||
metricSources.sort(function(a, b) {
|
||||
@@ -123,6 +109,27 @@ function (angular, _, coreModule, config) {
|
||||
return metricSources;
|
||||
};
|
||||
|
||||
this.addDataSourceVariables = function(list) {
|
||||
// look for data source variables
|
||||
for (var i = 0; i < templateSrv.variables.length; i++) {
|
||||
var variable = templateSrv.variables[i];
|
||||
if (variable.type !== 'datasource') {
|
||||
continue;
|
||||
}
|
||||
|
||||
var first = variable.current.value;
|
||||
var ds = config.datasources[first];
|
||||
|
||||
if (ds) {
|
||||
list.push({
|
||||
name: '$' + variable.name,
|
||||
value: '$' + variable.name,
|
||||
meta: ds.meta,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.init();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -173,8 +173,8 @@ export default class TimeSeries {
|
||||
|
||||
isMsResolutionNeeded() {
|
||||
for (var i = 0; i < this.datapoints.length; i++) {
|
||||
if (this.datapoints[i][0] !== null) {
|
||||
var timestamp = this.datapoints[i][0].toString();
|
||||
if (this.datapoints[i][1] !== null) {
|
||||
var timestamp = this.datapoints[i][1].toString();
|
||||
if (timestamp.length === 13 && (timestamp % 1000) !== 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ function (angular, _, $) {
|
||||
$scope.datasourceChanged = function() {
|
||||
return datasourceSrv.get($scope.currentAnnotation.datasource).then(function(ds) {
|
||||
$scope.currentDatasource = ds;
|
||||
$scope.currentAnnotation.datasource = ds.name;
|
||||
$scope.currentAnnotation.datasource = $scope.currentAnnotation.datasource;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -142,12 +142,19 @@ function (angular, _, config) {
|
||||
});
|
||||
|
||||
module.directive('panelWidth', function() {
|
||||
|
||||
return function(scope, element) {
|
||||
var fullscreen = false;
|
||||
|
||||
function updateWidth() {
|
||||
element[0].style.width = ((scope.panel.span / 1.2) * 10) + '%';
|
||||
if (!fullscreen) {
|
||||
element[0].style.width = ((scope.panel.span / 1.2) * 10) + '%';
|
||||
}
|
||||
}
|
||||
|
||||
scope.onAppEvent('panel-fullscreen-enter', function(evt, info) {
|
||||
fullscreen = true;
|
||||
|
||||
if (scope.panel.id !== info.panelId) {
|
||||
element.hide();
|
||||
} else {
|
||||
@@ -156,14 +163,20 @@ function (angular, _, config) {
|
||||
});
|
||||
|
||||
scope.onAppEvent('panel-fullscreen-exit', function(evt, info) {
|
||||
fullscreen = false;
|
||||
|
||||
if (scope.panel.id !== info.panelId) {
|
||||
element.show();
|
||||
} else {
|
||||
updateWidth();
|
||||
}
|
||||
|
||||
updateWidth();
|
||||
});
|
||||
|
||||
scope.$watch('panel.span', updateWidth);
|
||||
|
||||
if (fullscreen) {
|
||||
element.hide();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ function (angular, _, require, config) {
|
||||
$scope.shareUrl = linkSrv.addParamsToUrl(baseUrl, params);
|
||||
|
||||
var soloUrl = $scope.shareUrl;
|
||||
soloUrl = soloUrl.replace('/dashboard/', '/dashboard-solo/');
|
||||
soloUrl = soloUrl.replace(config.appSubUrl + '/dashboard/', config.appSubUrl + '/dashboard-solo/');
|
||||
soloUrl = soloUrl.replace("&fullscreen", "");
|
||||
|
||||
$scope.iframeHtml = '<iframe src="' + soloUrl + '" width="450" height="200" frameborder="0"></iframe>';
|
||||
|
||||
@@ -50,7 +50,7 @@ define([
|
||||
|
||||
if (!isNaN(value)) {
|
||||
var epoch = parseInt(value);
|
||||
return moment(epoch);
|
||||
return moment.utc(epoch);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -8,6 +8,7 @@ import $ from 'jquery';
|
||||
const TITLE_HEIGHT = 25;
|
||||
const EMPTY_TITLE_HEIGHT = 9;
|
||||
const PANEL_PADDING = 5;
|
||||
const PANEL_BORDER = 2;
|
||||
|
||||
import {Emitter} from 'app/core/core';
|
||||
|
||||
@@ -141,7 +142,7 @@ export class PanelCtrl {
|
||||
}
|
||||
}
|
||||
|
||||
this.height = this.containerHeight - (PANEL_PADDING + (this.panel.title ? TITLE_HEIGHT : EMPTY_TITLE_HEIGHT));
|
||||
this.height = this.containerHeight - (PANEL_BORDER + PANEL_PADDING + (this.panel.title ? TITLE_HEIGHT : EMPTY_TITLE_HEIGHT));
|
||||
}
|
||||
|
||||
render(payload?) {
|
||||
|
||||
@@ -42,6 +42,16 @@ function (angular, _) {
|
||||
return value.replace(/([\!\*\+\-\=<>\s\&\|\(\)\[\]\{\}\^\~\?\:\\/"])/g, "\\$1");
|
||||
}
|
||||
|
||||
this.luceneFormat = function(value) {
|
||||
if (typeof value === 'string') {
|
||||
return luceneEscape(value);
|
||||
}
|
||||
var quotedValues = _.map(value, function(val) {
|
||||
return '\"' + luceneEscape(val) + '\"';
|
||||
});
|
||||
return '(' + quotedValues.join(' OR ') + ')';
|
||||
};
|
||||
|
||||
this.formatValue = function(value, format, variable) {
|
||||
// for some scopedVars there is no variable
|
||||
variable = variable || {};
|
||||
@@ -60,13 +70,7 @@ function (angular, _) {
|
||||
return '(' + escapedValues.join('|') + ')';
|
||||
}
|
||||
case "lucene": {
|
||||
if (typeof value === 'string') {
|
||||
return luceneEscape(value);
|
||||
}
|
||||
var quotedValues = _.map(value, function(val) {
|
||||
return '\"' + luceneEscape(val) + '\"';
|
||||
});
|
||||
return '(' + quotedValues.join(' OR ') + ')';
|
||||
return this.luceneFormat(value, format, variable);
|
||||
}
|
||||
case "pipe": {
|
||||
if (typeof value === 'string') {
|
||||
@@ -97,8 +101,11 @@ function (angular, _) {
|
||||
if (!str) {
|
||||
return false;
|
||||
}
|
||||
var match = this._regex.exec(str);
|
||||
return match && (match[1] === variableName || match[2] === variableName);
|
||||
|
||||
variableName = regexEscape(variableName);
|
||||
var findVarRegex = new RegExp('\\$(' + variableName + ')(?:\\W|$)|\\[\\[(' + variableName + ')\\]\\]', 'g');
|
||||
var match = findVarRegex.exec(str);
|
||||
return match !== null;
|
||||
};
|
||||
|
||||
this.highlightVariablesAsHtml = function(str) {
|
||||
|
||||
@@ -244,15 +244,26 @@ function (angular, _, kbn) {
|
||||
this.validateVariableSelectionState = function(variable) {
|
||||
if (!variable.current) {
|
||||
if (!variable.options.length) { return; }
|
||||
return self.setVariableValue(variable, variable.options[0], true);
|
||||
return self.setVariableValue(variable, variable.options[0], false);
|
||||
}
|
||||
|
||||
if (_.isArray(variable.current.value)) {
|
||||
self.selectOptionsForCurrentValue(variable);
|
||||
// updated selected value
|
||||
var selected = {
|
||||
value: _.map(_.filter(variable.options, {selected: true}), function(op) {
|
||||
return op.value;
|
||||
})
|
||||
};
|
||||
// if none pick first
|
||||
if (selected.value.length === 0) {
|
||||
selected = variable.options[0];
|
||||
}
|
||||
return self.setVariableValue(variable, selected, false);
|
||||
} else {
|
||||
var currentOption = _.findWhere(variable.options, {text: variable.current.text});
|
||||
if (currentOption) {
|
||||
return self.setVariableValue(variable, currentOption, true);
|
||||
return self.setVariableValue(variable, currentOption, false);
|
||||
} else {
|
||||
if (!variable.options.length) { return; }
|
||||
return self.setVariableValue(variable, variable.options[0]);
|
||||
@@ -313,6 +324,14 @@ function (angular, _, kbn) {
|
||||
var value = item.value || item.text;
|
||||
var text = item.text || item.value;
|
||||
|
||||
if (_.isNumber(value)) {
|
||||
value = value.toString();
|
||||
}
|
||||
|
||||
if (_.isNumber(text)) {
|
||||
text = text.toString();
|
||||
}
|
||||
|
||||
if (regex) {
|
||||
matches = regex.exec(value);
|
||||
if (!matches) { continue; }
|
||||
|
||||
@@ -78,7 +78,7 @@ function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticRes
|
||||
range[timeField]["format"] = "epoch_millis";
|
||||
}
|
||||
|
||||
var queryInterpolated = templateSrv.replace(queryString);
|
||||
var queryInterpolated = templateSrv.replace(queryString, {}, 'lucene');
|
||||
var filter = { "bool": { "must": [{ "range": range }] } };
|
||||
var query = { "bool": { "should": [{ "query_string": { "query": queryInterpolated } }] } };
|
||||
var data = {
|
||||
@@ -204,6 +204,14 @@ function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticRes
|
||||
});
|
||||
};
|
||||
|
||||
function escapeForJson(value) {
|
||||
return value.replace(/\"/g, '\\"');
|
||||
}
|
||||
|
||||
function luceneThenJsonFormat(value) {
|
||||
return escapeForJson(templateSrv.luceneFormat(value));
|
||||
}
|
||||
|
||||
this.getFields = function(query) {
|
||||
return this._get('/_mapping').then(function(res) {
|
||||
var fields = {};
|
||||
@@ -246,7 +254,7 @@ function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticRes
|
||||
var header = this.getQueryHeader('count', range.from, range.to);
|
||||
var esQuery = angular.toJson(this.queryBuilder.getTermsQuery(queryDef));
|
||||
|
||||
esQuery = esQuery.replace("$lucene_query", queryDef.query || '*');
|
||||
esQuery = esQuery.replace("$lucene_query", escapeForJson(queryDef.query || '*'));
|
||||
esQuery = esQuery.replace(/\$timeFrom/g, range.from.valueOf());
|
||||
esQuery = esQuery.replace(/\$timeTo/g, range.to.valueOf());
|
||||
esQuery = header + '\n' + esQuery + '\n';
|
||||
@@ -260,7 +268,7 @@ function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticRes
|
||||
};
|
||||
|
||||
this.metricFindQuery = function(query) {
|
||||
query = templateSrv.replace(query);
|
||||
query = templateSrv.replace(query, {}, luceneThenJsonFormat);
|
||||
query = angular.fromJson(query);
|
||||
if (!query) {
|
||||
return $q.when([]);
|
||||
|
||||
@@ -70,9 +70,9 @@
|
||||
</div>
|
||||
|
||||
<div ng-if="agg.type === 'filters'">
|
||||
<div class="gf-form-inline" ng-repeat="filter in agg.settings.filters" ng-class="{last: $last}">
|
||||
<div class="gf-form-inline offset-width-7" ng-repeat="filter in agg.settings.filters">
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-item width-10">Query {{$index + 1}}</label>
|
||||
<label class="gf-form-label width-10">Query {{$index + 1}}</label>
|
||||
<input type="text" class="gf-form-input max-width-12" ng-model="filter.query" spellcheck='false' placeholder="Lucene query" ng-blur="onChangeInternal()">
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
@@ -88,7 +88,7 @@
|
||||
|
||||
<div ng-if="agg.type === 'geohash_grid'">
|
||||
<div class="gf-form offset-width-7">
|
||||
<label class="gf-form-label">Precision</label>
|
||||
<label class="gf-form-label width-10">Precision</label>
|
||||
<input type="number" class="gf-form-input max-width-12" ng-model="agg.settings.precision" spellcheck='false' placeholder="3" ng-blur="onChangeInternal()">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -43,7 +43,7 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS
|
||||
return value.replace(/[\\^$*+?.()|[\]{}]/g, '\\\\$&');
|
||||
}
|
||||
|
||||
function interpolateQueryExpr(value, variable, defaultFormatFn) {
|
||||
this.interpolateQueryExpr = function(value, variable, defaultFormatFn) {
|
||||
// if no multi or include all do not regexEscape
|
||||
if (!variable.multi && !variable.includeAll) {
|
||||
return value;
|
||||
@@ -59,6 +59,7 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS
|
||||
|
||||
// Called once per panel (graph)
|
||||
this.query = function(options) {
|
||||
var self = this;
|
||||
var start = getPrometheusTime(options.range.from, false);
|
||||
var end = getPrometheusTime(options.range.to, true);
|
||||
|
||||
@@ -73,7 +74,7 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS
|
||||
activeTargets.push(target);
|
||||
|
||||
var query: any = {};
|
||||
query.expr = templateSrv.replace(target.expr, options.scopedVars, interpolateQueryExpr);
|
||||
query.expr = templateSrv.replace(target.expr, options.scopedVars, self.interpolateQueryExpr);
|
||||
|
||||
var interval = target.interval || options.interval;
|
||||
var intervalFactor = target.intervalFactor || 1;
|
||||
@@ -99,7 +100,6 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS
|
||||
return this.performTimeSeriesQuery(query, start, end);
|
||||
}, this));
|
||||
|
||||
var self = this;
|
||||
return $q.all(allQueryPromise)
|
||||
.then(function(allResponse) {
|
||||
var result = [];
|
||||
@@ -160,7 +160,7 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS
|
||||
|
||||
var interpolated;
|
||||
try {
|
||||
interpolated = templateSrv.replace(expr, {}, interpolateQueryExpr);
|
||||
interpolated = templateSrv.replace(expr, {}, this.interpolateQueryExpr);
|
||||
} catch (err) {
|
||||
return $q.reject(err);
|
||||
}
|
||||
|
||||
@@ -58,10 +58,14 @@ class PrometheusQueryCtrl extends QueryCtrl {
|
||||
|
||||
updateLink() {
|
||||
var range = this.panelCtrl.range;
|
||||
if (!range) {
|
||||
return;
|
||||
}
|
||||
|
||||
var rangeDiff = Math.ceil((range.to.valueOf() - range.from.valueOf()) / 1000);
|
||||
var endTime = range.to.utc().format('YYYY-MM-DD HH:mm');
|
||||
var expr = {
|
||||
expr: this.templateSrv.replace(this.target.expr, this.panelCtrl.panel.scopedVars),
|
||||
expr: this.templateSrv.replace(this.target.expr, this.panelCtrl.panel.scopedVars, this.datasource.interpolateQueryExpr),
|
||||
range_input: rangeDiff + 's',
|
||||
end_input: endTime,
|
||||
step_input: '',
|
||||
|
||||
@@ -66,7 +66,7 @@ function (angular, $, moment, _, kbn, GraphTooltip) {
|
||||
|
||||
function getLegendHeight(panelHeight) {
|
||||
if (!panel.legend.show || panel.legend.rightSide) {
|
||||
return 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (panel.legend.alignAsTable) {
|
||||
|
||||
@@ -22,8 +22,8 @@ describe('GraphCtrl', function() {
|
||||
describe('msResolution with second resolution timestamps', function() {
|
||||
beforeEach(function() {
|
||||
var data = [
|
||||
{ target: 'test.cpu1', datapoints: [[1234567890, 45], [1234567899, 60]]},
|
||||
{ target: 'test.cpu2', datapoints: [[1236547890, 55], [1234456709, 90]]}
|
||||
{ target: 'test.cpu1', datapoints: [[45, 1234567890], [60, 1234567899]]},
|
||||
{ target: 'test.cpu2', datapoints: [[55, 1236547890], [90, 1234456709]]}
|
||||
];
|
||||
ctx.ctrl.panel.tooltip.msResolution = false;
|
||||
ctx.ctrl.onDataReceived(data);
|
||||
@@ -37,8 +37,8 @@ describe('GraphCtrl', function() {
|
||||
describe('msResolution with millisecond resolution timestamps', function() {
|
||||
beforeEach(function() {
|
||||
var data = [
|
||||
{ target: 'test.cpu1', datapoints: [[1234567890000, 45], [1234567899000, 60]]},
|
||||
{ target: 'test.cpu2', datapoints: [[1236547890001, 55], [1234456709000, 90]]}
|
||||
{ target: 'test.cpu1', datapoints: [[45, 1234567890000], [60, 1234567899000]]},
|
||||
{ target: 'test.cpu2', datapoints: [[55, 1236547890001], [90, 1234456709000]]}
|
||||
];
|
||||
ctx.ctrl.panel.tooltip.msResolution = false;
|
||||
ctx.ctrl.onDataReceived(data);
|
||||
@@ -52,8 +52,8 @@ describe('GraphCtrl', function() {
|
||||
describe('msResolution with millisecond resolution timestamps but with trailing zeroes', function() {
|
||||
beforeEach(function() {
|
||||
var data = [
|
||||
{ target: 'test.cpu1', datapoints: [[1234567890000, 45], [1234567899000, 60]]},
|
||||
{ target: 'test.cpu2', datapoints: [[1236547890000, 55], [1234456709000, 90]]}
|
||||
{ target: 'test.cpu1', datapoints: [[45, 1234567890000], [60, 1234567899000]]},
|
||||
{ target: 'test.cpu2', datapoints: [[55, 1236547890000], [90, 1234456709000]]}
|
||||
];
|
||||
ctx.ctrl.panel.tooltip.msResolution = false;
|
||||
ctx.ctrl.onDataReceived(data);
|
||||
@@ -67,9 +67,9 @@ describe('GraphCtrl', function() {
|
||||
describe('msResolution with millisecond resolution timestamps in one of the series', function() {
|
||||
beforeEach(function() {
|
||||
var data = [
|
||||
{ target: 'test.cpu1', datapoints: [[1234567890000, 45], [1234567899000, 60]]},
|
||||
{ target: 'test.cpu2', datapoints: [[1236547890010, 55], [1234456709000, 90]]},
|
||||
{ target: 'test.cpu3', datapoints: [[1236547890000, 65], [1234456709000, 120]]}
|
||||
{ target: 'test.cpu1', datapoints: [[45, 1234567890000], [60, 1234567899000]]},
|
||||
{ target: 'test.cpu2', datapoints: [[55, 1236547890010], [90, 1234456709000]]},
|
||||
{ target: 'test.cpu3', datapoints: [[65, 1236547890000], [120, 1234456709000]]}
|
||||
];
|
||||
ctx.ctrl.panel.tooltip.msResolution = false;
|
||||
ctx.ctrl.onDataReceived(data);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
<div class="singlestat-panel">
|
||||
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
|
||||
@@ -284,6 +284,9 @@ class SingleStatCtrl extends MetricsPanelCtrl {
|
||||
}
|
||||
|
||||
function addGauge() {
|
||||
var width = elem.width();
|
||||
var height = elem.height();
|
||||
|
||||
ctrl.invalidGaugeRange = false;
|
||||
if (panel.gauge.minValue > panel.gauge.maxValue) {
|
||||
ctrl.invalidGaugeRange = true;
|
||||
@@ -291,8 +294,6 @@ class SingleStatCtrl extends MetricsPanelCtrl {
|
||||
}
|
||||
|
||||
var plotCanvas = $('<div></div>');
|
||||
var width = elem.width();
|
||||
var height = elem.height();
|
||||
var plotCss = {
|
||||
top: '10px',
|
||||
margin: 'auto',
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
}
|
||||
|
||||
.singlestat-panel-value-container {
|
||||
padding: 20px;
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
|
||||
@@ -56,7 +56,7 @@ define([
|
||||
});
|
||||
});
|
||||
|
||||
describe('can detect if serie contains ms precision', function() {
|
||||
describe('can detect if series contains ms precision', function() {
|
||||
var fakedata;
|
||||
|
||||
beforeEach(function() {
|
||||
@@ -64,13 +64,13 @@ define([
|
||||
});
|
||||
|
||||
it('missing datapoint with ms precision', function() {
|
||||
fakedata.datapoints[0] = [1234567890000, 1337];
|
||||
fakedata.datapoints[0] = [1337, 1234567890000];
|
||||
series = new TimeSeries(fakedata);
|
||||
expect(series.isMsResolutionNeeded()).to.be(false);
|
||||
});
|
||||
|
||||
it('contains datapoint with ms precision', function() {
|
||||
fakedata.datapoints[0] = [1236547890001, 1337];
|
||||
fakedata.datapoints[0] = [1337, 1236547890001];
|
||||
series = new TimeSeries(fakedata);
|
||||
expect(series.isMsResolutionNeeded()).to.be(true);
|
||||
});
|
||||
|
||||
@@ -141,8 +141,8 @@ define([
|
||||
});
|
||||
|
||||
it('slash should be properly escaped in regex format', function() {
|
||||
var result = _templateSrv.formatValue('Gi3/14', 'regex');
|
||||
expect(result).to.be('Gi3\\/14');
|
||||
var result = _templateSrv.formatValue('Gi3/14', 'regex');
|
||||
expect(result).to.be('Gi3\\/14');
|
||||
});
|
||||
|
||||
});
|
||||
@@ -200,6 +200,15 @@ define([
|
||||
expect(contains).to.be(true);
|
||||
});
|
||||
|
||||
it('should find it when part of segment', function() {
|
||||
var contains = _templateSrv.containsVariable('metrics.$env.$group-*', 'group');
|
||||
expect(contains).to.be(true);
|
||||
});
|
||||
|
||||
it('should find it its the only thing', function() {
|
||||
var contains = _templateSrv.containsVariable('$env', 'env');
|
||||
expect(contains).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateTemplateData with simple value', function() {
|
||||
|
||||
@@ -126,6 +126,59 @@ define([
|
||||
});
|
||||
});
|
||||
|
||||
describeUpdateVariable('query variable with multi select and new options does not contain some selected values', function(scenario) {
|
||||
scenario.setup(function() {
|
||||
scenario.variable = {
|
||||
type: 'query',
|
||||
query: '',
|
||||
name: 'test',
|
||||
current: {
|
||||
value: ['val1', 'val2', 'val3'],
|
||||
text: 'val1 + val2 + val3'
|
||||
}
|
||||
};
|
||||
scenario.queryResult = [{text: 'val2'}, {text: 'val3'}];
|
||||
});
|
||||
|
||||
it('should update current value', function() {
|
||||
expect(scenario.variable.current.value).to.eql(['val2', 'val3']);
|
||||
expect(scenario.variable.current.text).to.eql('val2 + val3');
|
||||
});
|
||||
});
|
||||
|
||||
describeUpdateVariable('query variable with multi select and new options does not contain any selected values', function(scenario) {
|
||||
scenario.setup(function() {
|
||||
scenario.variable = {
|
||||
type: 'query',
|
||||
query: '',
|
||||
name: 'test',
|
||||
current: {
|
||||
value: ['val1', 'val2', 'val3'],
|
||||
text: 'val1 + val2 + val3'
|
||||
}
|
||||
};
|
||||
scenario.queryResult = [{text: 'val5'}, {text: 'val6'}];
|
||||
});
|
||||
|
||||
it('should update current value with first one', function() {
|
||||
expect(scenario.variable.current.value).to.eql('val5');
|
||||
expect(scenario.variable.current.text).to.eql('val5');
|
||||
});
|
||||
});
|
||||
|
||||
describeUpdateVariable('query variable with numeric results', function(scenario) {
|
||||
scenario.setup(function() {
|
||||
scenario.variable = { type: 'query', query: '', name: 'test', current: {} };
|
||||
scenario.queryResult = [{text: 12, value: 12}];
|
||||
});
|
||||
|
||||
it('should set current value to first option', function() {
|
||||
expect(scenario.variable.current.value).to.be('12');
|
||||
expect(scenario.variable.options[0].value).to.be('12');
|
||||
expect(scenario.variable.options[0].text).to.be('12');
|
||||
});
|
||||
});
|
||||
|
||||
describeUpdateVariable('interval variable without auto', function(scenario) {
|
||||
scenario.setup(function() {
|
||||
scenario.variable = { type: 'interval', query: '1s,2h,5h,1d', name: 'test' };
|
||||
|
||||
Reference in New Issue
Block a user