From a065f937774c97bc4cc9eb97769835d6d421e477 Mon Sep 17 00:00:00 2001 From: raj dutt Date: Wed, 15 Jul 2015 14:27:55 -0700 Subject: [PATCH 01/13] Update singlestat.md --- docs/sources/reference/singlestat.md | 37 ++++++++++++++-------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/docs/sources/reference/singlestat.md b/docs/sources/reference/singlestat.md index 4e5a38544c5..40a3551a4e0 100644 --- a/docs/sources/reference/singlestat.md +++ b/docs/sources/reference/singlestat.md @@ -8,42 +8,41 @@ page_keywords: grafana, singlestat, panel, documentation ![](/img/v1/singlestat_panel2.png) -The singlestat panel allows you to show the one main summery stat of a single series (like max, min, avg, sum). It also -provides thresholds to color that singlestat metric or the panel background. +The singlestat Panel allows you to show the one main summary stat of a single series (like max, min, avg, sum). It also provides thresholds to color the stat or the Panel background. -### Big Value Configuration +### Singlestat Panel Configuration -The big value configuration allows you to both customize the look of your singlestat metric, as well as add additional labels to contexualize the metric. +The singlestat panel has a normal query editor to allow you define your exact metric queries like many other Panels. Through the Options tab, you can access the Singlestat-specific functionality. -1. `Big Value`: Big Value refers to the collection of values displayed in the singlestat panel. -2. `Prefixes`: The Prefix fields let you define a custom label and font-size (as a %) to appear *before* the singlestat metric. -3. `Values`: The Value fields let you set the (min, max, average, current, total) and font-size (as a %) of the singlestat metric. -4. `Potsfixes`: The Postfix fields let you define a custom label and font-size (as a %) to appear *after* the singlestat metric. -5. `Units`: Units are appended to the the singlestat metric within the panel, and will respect the color and threshold settings for the Value. -6. `Decimals`: The Decimal field allows you to override automatic decimal precision, inceasing the digits displayed for your singlestat metric. +1. `Big Value`: Big Value refers to how we display the main stat for the Singlestat Panel. This is always a single value that is displayed in the Panel in between two strings, `Prefix` and `Suffix`. The single number is calculated by choosing a function (min,max,average,current,total) of your metric query. This functions reduces your query into a single numeric value. +2. `Font Size`: You can use this section +3. `Values`: The Value fields let you set the function (min, max, average, current, total) that your entire query is reduced into a single value with. You can also set the font size of theand font-size (as a %) of the metric query that the Panel is configured with. This reduces the entire query into a single summary value that is displayed. +4. `Postfixes`: The Postfix fields let you define a custom label and font-size (as a %) to appear *after* the value +5. `Units`: Units are appended to the the Singlestat within the panel, and will respect the color and threshold settings for the value. +6. `Decimals`: The Decimal field allows you to override the automatic decimal precision, and set it explicitely. ### Coloring -The coloring options of the singlestat config allow you to dynamically change the colors based on the displayed data. +The coloring options of the Singlestat Panel config allow you to dynamically change the colors based on the Singlestat value. -1. `Background`: The Background checkbox applies the configured thresholds and colors to the entirity of the singlestat panel background. -2. `Value`: The Value checkbox applies the configured thresholds and colors to the value within the singlestat panel. -3. `Thresholds`: Thresholds allow you to change the background and value colors dyanmically within the panel. The threshold field accepts **3 comma-separated** values, corresponding to the three colors directly to the right. -4. `Colors`: The color picker allows you to select a color and opacity +1. `Background`: This checkbox applies the configured thresholds and colors to the entirity of the Singlestat Panel background. +2. `Value`: This checkbox applies the configured thresholds and colors to the summary stat. +3. `Thresholds`: Change the background and value colors dyanmically within the panel, depending on the Singlestat value. The threshold field accepts **3 comma-separated** values, corresponding to the three colors directly to the right. +4. `Colors`: Select a color and opacity 5. `Invert order`: This link toggles the threshold color order.
For example: Green, Orange, Red () will become Red, Orange, Green (). ### Spark Lines -Spark lines are a great way of seeing the historical data associated with a single stat value, providing valuable context at a glance. Spark lines act differently than traditional graph panels and do not include x or y axis, coordinates, a legend, or ability to interact with the graph. +Sparklines are a great way of seeing the historical data related to the summary stat, providing valuable context at a glance. Sparklines act differently than traditional graph panels and do not include x or y axis, coordinates, a legend, or ability to interact with the graph. -1. `Show`: The show checkbox will toggle whether the spark line is shown in the panel. When unselected, only the value will appear. -2. `Background`: Check if you want the sparklines to take up the full panel width or uncheck if they should only be at the bottom. +1. `Show`: The show checkbox will toggle whether the spark line is shown in the Panel. When unselected, only the Singlestat value will appear. +2. `Background`: Check if you want the sparklines to take up the full panel width, or uncheck if they should be below the main Singlestat value. 3. `Line Color`: This color selection applies to the color of the sparkline itself. 4. `Fill Color`: This color selection applies to the area below the sparkline. @@ -51,7 +50,7 @@ Spark lines are a great way of seeing the historical data associated with a sing ### Value to text mapping -Value to text mapping allows you to translate values into explcit text. The text will respect all styling, thresholds and customization defined for the value. +Value to text mapping allows you to translate the value of the summary stat into explicit text. The text will respect all styling, thresholds and customization defined for the value. This can be useful to translate the number of the main Singlestat value into a context-specific human-readable word or message. From 9afdea8d2a726aacb8f884f3fce236fb301a6126 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Thu, 16 Jul 2015 11:57:59 +0200 Subject: [PATCH 02/13] feat(ldap): added config options for ssl skip verify, and ssl server name, #1450 --- conf/ldap.toml | 4 ++++ docs/sources/installation/ldap.md | 4 ++++ pkg/login/ldap.go | 7 ++++++- pkg/login/settings.go | 14 ++++++++------ 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/conf/ldap.toml b/conf/ldap.toml index 957fc1258ba..eb6e320a091 100644 --- a/conf/ldap.toml +++ b/conf/ldap.toml @@ -8,6 +8,10 @@ host = "127.0.0.1" port = 389 # Set to true if ldap server supports TLS use_ssl = false +# set to true if you want to skip ssl cert validation +ssl_skip_verify = false +# if cert validation is enabled, provide ldap cert server name +ssl_server_name = "" # Search user bind dn bind_dn = "cn=admin,dc=grafana,dc=org" diff --git a/docs/sources/installation/ldap.md b/docs/sources/installation/ldap.md index 261d975886a..f6365414222 100644 --- a/docs/sources/installation/ldap.md +++ b/docs/sources/installation/ldap.md @@ -27,6 +27,10 @@ host = "127.0.0.1" port = 389 # Set to true if ldap server supports TLS use_ssl = false +# set to true if you want to skip ssl cert validation +ssl_skip_verify = false +# if cert validation is enabled, provide ldap cert server name +ssl_server_name = "" # Search user bind dn bind_dn = "cn=admin,dc=grafana,dc=org" diff --git a/pkg/login/ldap.go b/pkg/login/ldap.go index 324ba6d18a4..4131c05b2a4 100644 --- a/pkg/login/ldap.go +++ b/pkg/login/ldap.go @@ -1,6 +1,7 @@ package login import ( + "crypto/tls" "errors" "fmt" "strings" @@ -25,7 +26,11 @@ func (a *ldapAuther) Dial() error { address := fmt.Sprintf("%s:%d", a.server.Host, a.server.Port) var err error if a.server.UseSSL { - a.conn, err = ldap.DialTLS("tcp", address, nil) + tlsCfg := &tls.Config{ + InsecureSkipVerify: a.server.SkipVerifySSL, + ServerName: a.server.CertServerName, + } + a.conn, err = ldap.DialTLS("tcp", address, tlsCfg) } else { a.conn, err = ldap.Dial("tcp", address) } diff --git a/pkg/login/settings.go b/pkg/login/settings.go index 9b5f68a252c..0a437045660 100644 --- a/pkg/login/settings.go +++ b/pkg/login/settings.go @@ -13,12 +13,14 @@ type LdapConfig struct { } type LdapServerConf struct { - Host string `toml:"host"` - Port int `toml:"port"` - UseSSL bool `toml:"use_ssl"` - BindDN string `toml:"bind_dn"` - BindPassword string `toml:"bind_password"` - Attr LdapAttributeMap `toml:"attributes"` + Host string `toml:"host"` + Port int `toml:"port"` + UseSSL bool `toml:"use_ssl"` + SkipVerifySSL bool `toml:"ssl_skip_verify"` + CertServerName string `toml:"ssl_server_name"` + BindDN string `toml:"bind_dn"` + BindPassword string `toml:"bind_password"` + Attr LdapAttributeMap `toml:"attributes"` SearchFilter string `toml:"search_filter"` SearchBaseDNs []string `toml:"search_base_dns"` From 2f4d3be303677f2496899297739277e771d70446 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Thu, 16 Jul 2015 12:06:49 +0200 Subject: [PATCH 03/13] fix(panellinks): fixed open in new tab issue for dashboard links, Fixes #2354 --- public/app/features/panellinks/linkSrv.js | 1 + 1 file changed, 1 insertion(+) diff --git a/public/app/features/panellinks/linkSrv.js b/public/app/features/panellinks/linkSrv.js index c11cdb40b52..664bb8063d8 100644 --- a/public/app/features/panellinks/linkSrv.js +++ b/public/app/features/panellinks/linkSrv.js @@ -70,6 +70,7 @@ function (angular, kbn, _) { else if (link.dashUri) { info.href = 'dashboard/' + link.dashUri + '?'; info.title = templateSrv.replace(link.title || ''); + info.target = link.targetBlank ? '_blank' : ''; } else { info.title = templateSrv.replace(link.title || ''); From 5b0585ac7fa072b5df00913244b059ebf7cb7c85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Thu, 16 Jul 2015 12:58:30 +0200 Subject: [PATCH 04/13] feat(ldap): removed ssl_server_name and added some validation to ldap config, #1450 --- conf/ldap.toml | 2 -- docs/sources/installation/ldap.md | 2 -- pkg/login/ldap.go | 2 +- pkg/login/settings.go | 41 +++++++++++++++++++++++++------ 4 files changed, 34 insertions(+), 13 deletions(-) diff --git a/conf/ldap.toml b/conf/ldap.toml index eb6e320a091..7572a7f38c8 100644 --- a/conf/ldap.toml +++ b/conf/ldap.toml @@ -10,8 +10,6 @@ port = 389 use_ssl = false # set to true if you want to skip ssl cert validation ssl_skip_verify = false -# if cert validation is enabled, provide ldap cert server name -ssl_server_name = "" # Search user bind dn bind_dn = "cn=admin,dc=grafana,dc=org" diff --git a/docs/sources/installation/ldap.md b/docs/sources/installation/ldap.md index f6365414222..4cba472d053 100644 --- a/docs/sources/installation/ldap.md +++ b/docs/sources/installation/ldap.md @@ -29,8 +29,6 @@ port = 389 use_ssl = false # set to true if you want to skip ssl cert validation ssl_skip_verify = false -# if cert validation is enabled, provide ldap cert server name -ssl_server_name = "" # Search user bind dn bind_dn = "cn=admin,dc=grafana,dc=org" diff --git a/pkg/login/ldap.go b/pkg/login/ldap.go index 4131c05b2a4..479a599fbe6 100644 --- a/pkg/login/ldap.go +++ b/pkg/login/ldap.go @@ -28,7 +28,7 @@ func (a *ldapAuther) Dial() error { if a.server.UseSSL { tlsCfg := &tls.Config{ InsecureSkipVerify: a.server.SkipVerifySSL, - ServerName: a.server.CertServerName, + ServerName: a.server.Host, } a.conn, err = ldap.DialTLS("tcp", address, tlsCfg) } else { diff --git a/pkg/login/settings.go b/pkg/login/settings.go index 0a437045660..0a50df33c19 100644 --- a/pkg/login/settings.go +++ b/pkg/login/settings.go @@ -1,6 +1,8 @@ package login import ( + "fmt" + "github.com/BurntSushi/toml" "github.com/grafana/grafana/pkg/log" m "github.com/grafana/grafana/pkg/models" @@ -13,14 +15,13 @@ type LdapConfig struct { } type LdapServerConf struct { - Host string `toml:"host"` - Port int `toml:"port"` - UseSSL bool `toml:"use_ssl"` - SkipVerifySSL bool `toml:"ssl_skip_verify"` - CertServerName string `toml:"ssl_server_name"` - BindDN string `toml:"bind_dn"` - BindPassword string `toml:"bind_password"` - Attr LdapAttributeMap `toml:"attributes"` + Host string `toml:"host"` + Port int `toml:"port"` + UseSSL bool `toml:"use_ssl"` + SkipVerifySSL bool `toml:"ssl_skip_verify"` + BindDN string `toml:"bind_dn"` + BindPassword string `toml:"bind_password"` + Attr LdapAttributeMap `toml:"attributes"` SearchFilter string `toml:"search_filter"` SearchBaseDNs []string `toml:"search_base_dns"` @@ -56,8 +57,17 @@ func loadLdapConfig() { log.Fatal(3, "Failed to load ldap config file: %s", err) } + if len(ldapCfg.Servers) == 0 { + log.Fatal(3, "ldap enabled but no ldap servers defined in config file: %s", setting.LdapConfigFile) + } + // set default org id for _, server := range ldapCfg.Servers { + assertNotEmptyCfg(server.Host, "host") + assertNotEmptyCfg(server.BindDN, "bind_dn") + assertNotEmptyCfg(server.SearchFilter, "search_filter") + assertNotEmptyCfg(server.SearchBaseDNs, "search_base_dns") + for _, groupMap := range server.LdapGroups { if groupMap.OrgId == 0 { groupMap.OrgId = 1 @@ -65,3 +75,18 @@ func loadLdapConfig() { } } } + +func assertNotEmptyCfg(val interface{}, propName string) { + switch v := val.(type) { + case string: + if v == "" { + log.Fatal(3, "LDAP config file is missing option: %s", propName) + } + case []string: + if len(v) == 0 { + log.Fatal(3, "LDAP config file is missing option: %s", propName) + } + default: + fmt.Println("unknown") + } +} From 8ac47b4e245c8b3b7d7f8a34e822b1294c4b4aac Mon Sep 17 00:00:00 2001 From: Mitsuhiro Tanda Date: Fri, 17 Jul 2015 15:38:36 +0900 Subject: [PATCH 05/13] fix dashboard/panel link in scripted dashboard --- public/app/features/dashlinks/module.js | 2 +- public/app/features/panellinks/linkSrv.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/public/app/features/dashlinks/module.js b/public/app/features/dashlinks/module.js index 9fc1bc4d4b5..23ce8c0ffae 100644 --- a/public/app/features/dashlinks/module.js +++ b/public/app/features/dashlinks/module.js @@ -114,7 +114,7 @@ function (angular, _) { title: linkDef.title, icon: iconMap[linkDef.icon], tooltip: linkDef.tooltip, - target: linkDef.targetBlank ? "_blank" : "", + target: linkDef.targetBlank ? "_blank" : "_self", keepTime: linkDef.keepTime, includeVars: linkDef.includeVars, }]); diff --git a/public/app/features/panellinks/linkSrv.js b/public/app/features/panellinks/linkSrv.js index 664bb8063d8..49ddcb95316 100644 --- a/public/app/features/panellinks/linkSrv.js +++ b/public/app/features/panellinks/linkSrv.js @@ -62,7 +62,7 @@ function (angular, kbn, _) { this.getPanelLinkAnchorInfo = function(link) { var info = {}; if (link.type === 'absolute') { - info.target = link.targetBlank ? '_blank' : ''; + info.target = link.targetBlank ? '_blank' : '_self'; info.href = templateSrv.replace(link.url || ''); info.title = templateSrv.replace(link.title || ''); info.href += '?'; From c7dafd4b42cbc510c993afdc8572f1e37e55a0ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Fri, 17 Jul 2015 14:45:49 +0200 Subject: [PATCH 06/13] fix(repeat panel): fixed issue with snapshoting a dashboard with repeated panels, Fixes #2352 --- public/app/features/dashboard/dynamicDashboardSrv.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/public/app/features/dashboard/dynamicDashboardSrv.js b/public/app/features/dashboard/dynamicDashboardSrv.js index bb58e2dbc06..8e3c24f7202 100644 --- a/public/app/features/dashboard/dynamicDashboardSrv.js +++ b/public/app/features/dashboard/dynamicDashboardSrv.js @@ -11,11 +11,15 @@ function (angular, _) { 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); }; From 666013b0100a0c03452f36ef888a4b7085faade1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Fri, 17 Jul 2015 14:59:05 +0200 Subject: [PATCH 07/13] fix(panel repeat): fixed issue with repeat panels in combination with setting variable values from URL, fixes #2351 --- .../features/templating/templateValuesSrv.js | 39 +++++++++++-------- public/test/specs/templateValuesSrv-specs.js | 14 ++++--- 2 files changed, 30 insertions(+), 23 deletions(-) diff --git a/public/app/features/templating/templateValuesSrv.js b/public/app/features/templating/templateValuesSrv.js index a5767ffa312..6f7e5398618 100644 --- a/public/app/features/templating/templateValuesSrv.js +++ b/public/app/features/templating/templateValuesSrv.js @@ -80,6 +80,7 @@ function (angular, _, kbn) { if (_.isArray(variable.current.value)) { variable.current.text = variable.current.value.join(' + '); + this.selectOptionsForCurrentValue(variable); } templateSrv.updateTemplateData(); @@ -128,6 +129,18 @@ function (angular, _, kbn) { .then(_.partial(this.validateVariableSelectionState, variable)); }; + this.selectOptionsForCurrentValue = function(variable) { + for (var i = 0; i < variable.current.value.length; i++) { + var value = variable.current.value[i]; + for (var y = 0; y < variable.options.length; y++) { + var option = variable.options[y]; + if (option.value === value) { + option.selected = true; + } + } + } + }; + this.validateVariableSelectionState = function(variable) { if (!variable.current) { if (!variable.options.length) { return; } @@ -135,15 +148,7 @@ function (angular, _, kbn) { } if (_.isArray(variable.current.value)) { - for (var i = 0; i < variable.current.value.length; i++) { - var value = variable.current.value[i]; - for (var y = 0; y < variable.options.length; y++) { - var option = variable.options[y]; - if (option.value === value) { - option.selected = true; - } - } - } + this.selectOptionsForCurrentValue(variable); } else { var currentOption = _.findWhere(variable.options, { text: variable.current.text }); if (currentOption) { @@ -225,17 +230,17 @@ function (angular, _, kbn) { this.addAllOption = function(variable) { var allValue = ''; switch(variable.allFormat) { - case 'wildcard': - allValue = '*'; + case 'wildcard': + allValue = '*'; break; - case 'regex wildcard': - allValue = '.*'; + case 'regex wildcard': + allValue = '.*'; break; - case 'regex values': - allValue = '(' + _.pluck(variable.options, 'text').join('|') + ')'; + case 'regex values': + allValue = '(' + _.pluck(variable.options, 'text').join('|') + ')'; break; - default: - allValue = '{'; + default: + allValue = '{'; allValue += _.pluck(variable.options, 'text').join(','); allValue += '}'; } diff --git a/public/test/specs/templateValuesSrv-specs.js b/public/test/specs/templateValuesSrv-specs.js index 6c7a3035ff9..d0af589a068 100644 --- a/public/test/specs/templateValuesSrv-specs.js +++ b/public/test/specs/templateValuesSrv-specs.js @@ -52,23 +52,25 @@ define([ var variable = { name: 'apps', multi: true, - current: {text: "test", value: "test"}, - options: [{text: "test", value: "test"}] + current: {text: "val1", value: "val1"}, + options: [{text: "val1", value: "val1"}, {text: 'val2', value: 'val2'}] }; beforeEach(function() { var dashboard = { templating: { list: [variable] } }; var urlParams = {}; - urlParams["var-apps"] = ["new", "other"]; + urlParams["var-apps"] = ["val1", "val2"]; ctx.$location.search = sinon.stub().returns(urlParams); ctx.service.init(dashboard); }); it('should update current value', function() { expect(variable.current.value.length).to.be(2); - expect(variable.current.value[0]).to.be("new"); - expect(variable.current.value[1]).to.be("other"); - expect(variable.current.text).to.be("new + other"); + expect(variable.current.value[0]).to.be("val1"); + expect(variable.current.value[1]).to.be("val2"); + expect(variable.current.text).to.be("val1 + val2"); + expect(variable.options[0].selected).to.be(true); + expect(variable.options[1].selected).to.be(true); }); }); From ea198fea6e4d86ecd9c0a937cf55be0e7ce398bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Fri, 17 Jul 2015 15:20:12 +0200 Subject: [PATCH 08/13] fix(graph): fixed legend color when having many many series, fixes #2359 --- .../app/features/templating/templateValuesSrv.js | 16 ++++++++-------- public/app/panels/graph/module.js | 3 ++- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/public/app/features/templating/templateValuesSrv.js b/public/app/features/templating/templateValuesSrv.js index 6f7e5398618..c1d787804d7 100644 --- a/public/app/features/templating/templateValuesSrv.js +++ b/public/app/features/templating/templateValuesSrv.js @@ -230,17 +230,17 @@ function (angular, _, kbn) { this.addAllOption = function(variable) { var allValue = ''; switch(variable.allFormat) { - case 'wildcard': - allValue = '*'; + case 'wildcard': + allValue = '*'; break; - case 'regex wildcard': - allValue = '.*'; + case 'regex wildcard': + allValue = '.*'; break; - case 'regex values': - allValue = '(' + _.pluck(variable.options, 'text').join('|') + ')'; + case 'regex values': + allValue = '(' + _.pluck(variable.options, 'text').join('|') + ')'; break; - default: - allValue = '{'; + default: + allValue = '{'; allValue += _.pluck(variable.options, 'text').join(','); allValue += '}'; } diff --git a/public/app/panels/graph/module.js b/public/app/panels/graph/module.js index 867f864123c..ea0a1e958ad 100644 --- a/public/app/panels/graph/module.js +++ b/public/app/panels/graph/module.js @@ -175,7 +175,8 @@ function (angular, app, $, _, kbn, moment, TimeSeries, PanelMeta) { $scope.seriesHandler = function(seriesData, index) { var datapoints = seriesData.datapoints; var alias = seriesData.target; - var color = $scope.panel.aliasColors[alias] || $rootScope.colors[index]; + var colorIndex = index % $rootScope.colors.length; + var color = $scope.panel.aliasColors[alias] || $rootScope.colors[colorIndex]; var series = new TimeSeries({ datapoints: datapoints, From 142a323efdc4f69b2880a8f0c8fd7cf95e5c0aa2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Fri, 17 Jul 2015 15:34:15 +0200 Subject: [PATCH 09/13] fix(save as): fixed issue with save as and overwriting a dashboard with the same name --- .../features/dashboard/saveDashboardAsCtrl.js | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/public/app/features/dashboard/saveDashboardAsCtrl.js b/public/app/features/dashboard/saveDashboardAsCtrl.js index 16dc291e9fa..ec8327755f8 100644 --- a/public/app/features/dashboard/saveDashboardAsCtrl.js +++ b/public/app/features/dashboard/saveDashboardAsCtrl.js @@ -14,16 +14,33 @@ function (angular) { $scope.clone.title = $scope.clone.title + " Copy"; }; + function saveDashboard(options) { + return backendSrv.saveDashboard($scope.clone, options).then(function(result) { + $scope.appEvent('alert-success', ['Dashboard saved', 'Saved as ' + $scope.clone.title]); + + $location.url('/dashboard/db/' + result.slug); + + $scope.appEvent('dashboard-saved', $scope.clone); + $scope.dismiss(); + }); + } + $scope.saveClone = function() { - backendSrv.saveDashboard($scope.clone) - .then(function(result) { - $scope.appEvent('alert-success', ['Dashboard saved', 'Saved as ' + $scope.clone.title]); + saveDashboard({overwrite: false}).then(null, function(err) { + if (err.data && err.data.status === "name-exists") { + err.isHandled = true; - $location.url('/dashboard/db/' + result.slug); - - $scope.appEvent('dashboard-saved', $scope.clone); - $scope.dismiss(); - }); + $scope.appEvent('confirm-modal', { + title: 'Another dashboard with the same name exists', + text: "Would you still like to save this dashboard?", + yesText: "Save & Overwrite", + icon: "fa-warning", + onConfirm: function() { + saveDashboard({overwrite: true}); + } + }); + } + }); }; }); From f3342ae7d33777c794488cacfa92cb9658cb3bfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sat, 18 Jul 2015 09:30:09 +0200 Subject: [PATCH 10/13] fix(ldap conf): updated ldap conf example to use literal string syntax for bind_password --- conf/ldap.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/ldap.toml b/conf/ldap.toml index 7572a7f38c8..1582e469242 100644 --- a/conf/ldap.toml +++ b/conf/ldap.toml @@ -14,7 +14,7 @@ ssl_skip_verify = false # Search user bind dn bind_dn = "cn=admin,dc=grafana,dc=org" # Search user bind password -bind_password = "grafana" +bind_password = 'grafana' # Search filter, for example "(cn=%s)" or "(sAMAccountName=%s)" search_filter = "(cn=%s)" From 5744c70399416f9094fca6ab9732a9282843fe4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sat, 18 Jul 2015 09:31:53 +0200 Subject: [PATCH 11/13] fix(ldap conf): fixed another issue in ldap conf example --- conf/ldap.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/ldap.toml b/conf/ldap.toml index 1582e469242..7deb090f9d5 100644 --- a/conf/ldap.toml +++ b/conf/ldap.toml @@ -36,7 +36,7 @@ org_role = "Admin" # The Grafana organization database id, optional, if left out the default org (id 1) will be used # org_id = 1 -[[server.ldap_group_to_org_role_mappings]] +[[server.group_mappings]] group_dn = "cn=users,dc=grafana,dc=org" org_role = "Editor" From 9bf9bb02734e9db88249d62dd895c81f8a8c5315 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sat, 18 Jul 2015 09:55:21 +0200 Subject: [PATCH 12/13] fix(ldap): fixed issue with ldap group mappings to org roles sync, #1450 --- pkg/login/ldap.go | 19 ++++++++++++------- pkg/login/ldap_test.go | 20 ++++++++++++++++++++ 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/pkg/login/ldap.go b/pkg/login/ldap.go index 479a599fbe6..abc3c6a587a 100644 --- a/pkg/login/ldap.go +++ b/pkg/login/ldap.go @@ -130,14 +130,17 @@ func (a *ldapAuther) syncOrgRoles(user *m.User, ldapUser *ldapUserInfo) error { return err } - // remove or update org roles + // update or remove org roles for _, org := range orgsQuery.Result { + match := false + for _, group := range a.server.LdapGroups { if org.OrgId != group.OrgId { continue } if ldapUser.isMemberOf(group.GroupDN) { + match = true if org.Role != group.OrgRole { // update role cmd := m.UpdateOrgUserCommand{OrgId: org.OrgId, UserId: user.Id, Role: group.OrgRole} @@ -147,12 +150,14 @@ func (a *ldapAuther) syncOrgRoles(user *m.User, ldapUser *ldapUserInfo) error { } // ignore subsequent ldap group mapping matches break - } else { - // remove role - cmd := m.RemoveOrgUserCommand{OrgId: org.OrgId, UserId: user.Id} - if err := bus.Dispatch(&cmd); err != nil { - return err - } + } + } + + // remove role if no mappings match + if !match { + cmd := m.RemoveOrgUserCommand{OrgId: org.OrgId, UserId: user.Id} + if err := bus.Dispatch(&cmd); err != nil { + return err } } } diff --git a/pkg/login/ldap_test.go b/pkg/login/ldap_test.go index 3d19115f878..6713d0ca3fe 100644 --- a/pkg/login/ldap_test.go +++ b/pkg/login/ldap_test.go @@ -139,6 +139,26 @@ func TestLdapAuther(t *testing.T) { }) }) + ldapAutherScenario("given org role is updated in config", func(sc *scenarioContext) { + ldapAuther := NewLdapAuthenticator(&LdapServerConf{ + LdapGroups: []*LdapGroupToOrgRole{ + {GroupDN: "cn=admin", OrgId: 1, OrgRole: "Admin"}, + {GroupDN: "cn=users", OrgId: 1, OrgRole: "Viewer"}, + }, + }) + + sc.userOrgsQueryReturns([]*m.UserOrgDTO{{OrgId: 1, Role: m.ROLE_EDITOR}}) + err := ldapAuther.syncOrgRoles(&m.User{}, &ldapUserInfo{ + MemberOf: []string{"cn=users"}, + }) + + Convey("Should update org role", func() { + So(err, ShouldBeNil) + So(sc.removeOrgUserCmd, ShouldBeNil) + So(sc.updateOrgUserCmd, ShouldNotBeNil) + }) + }) + ldapAutherScenario("given multiple matching ldap groups", func(sc *scenarioContext) { ldapAuther := NewLdapAuthenticator(&LdapServerConf{ LdapGroups: []*LdapGroupToOrgRole{ From 0a59d6ab2fb4646e309ea748ad35566b1d992379 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sat, 18 Jul 2015 10:14:21 +0200 Subject: [PATCH 13/13] fix(repeat panel): fix for unwanted unsaved changes warnings when using repeat panel, #2364 --- public/app/features/dashboard/unsavedChangesSrv.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/public/app/features/dashboard/unsavedChangesSrv.js b/public/app/features/dashboard/unsavedChangesSrv.js index 7318d4824d5..eeff9ae05c7 100644 --- a/public/app/features/dashboard/unsavedChangesSrv.js +++ b/public/app/features/dashboard/unsavedChangesSrv.js @@ -80,6 +80,9 @@ function(angular, _) { // remove scopedVars panel.scopedVars = null; + // ignore span changes + panel.span = null; + // ignore panel legend sort if (panel.legend) { delete panel.legend.sort;