diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index b7d73592ef4..e53a1159941 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,20 +1,19 @@ -Thank you! For helping us make Grafana even better. +Thank you for helping us make Grafana even better! -To help us respond to your issues faster, please make sure to add as much information as possible. +To help us respond to your issues more quickly, please make sure to add as much information as possible. -If this issue is about a plugin, please open the issue in that repository. +If this issue is about a plugin, please open the issue in that plugin's repository. -Start your issues title with [Feature Request] / [Bug] / [Question] or no tag if your unsure. Also, please be aware that GitHub now supports uploading of screenshots; look at the bottom of this input field. +Start your issue's title with [Feature Request] / [Bug] / [Question] or no tag if you're unsure. Also, please be aware that GitHub now supports uploading of screenshots; look at the bottom of this input field. Please include some basic information: -- What grafana version are you using? +- What Grafana version are you using? - What datasource are you using? - What OS are you running grafana on? - What did you do? - What was the expected result? - What happenend instead? -If you question/bug relates to a metric query / unexpected data visualization, please include: +If your question/bug relates to a metric query / unexpected data visualization, please include: - An image or text representation of your metric query - The raw query and response from your data source (check this in chrome dev tools network tab) - diff --git a/CHANGELOG.md b/CHANGELOG.md index bf074487057..323aaaecac2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,33 @@ -# 3.1.0 +# 3.1.0 (unreleased) ### Enhancements +* **Dashboard Url**: Time range changes updates url, closes [#458](https://github.com/grafana/grafana/issues/458) +* **Dashboard Url**: Template variable change updates url, closes [#5002](https://github.com/grafana/grafana/issues/5002) * **Singlestat**: Add support for range to text mappings, closes [#1319](https://github.com/grafana/grafana/issues/1319) * **Graph**: Adds sort order options for graph tooltip, closes [#1189](https://github.com/grafana/grafana/issues/1189) * **Theme**: Add default theme to config file [#5011](https://github.com/grafana/grafana/pull/5011) +* **Page Footer**: Added page footer with links to docs, shows Grafana version and info if new version is available, closes [#4889](https://github.com/grafana/grafana/pull/4889) -# 3.0.3 Patch release (unreleased) +# 3.0.4 Patch release (2016-05-25) +* **Panel**: Fixed blank dashboard issue when switching to other dashboard while in fullscreen edit mode, fixes [#5163](https://github.com/grafana/grafana/pull/5163) +* **Templating**: Fixed issue with nested multi select variables and cascading and updating child variable selection state, fixes [#4861](https://github.com/grafana/grafana/pull/4861) +* **Templating**: Fixed issue with using templated data source in another template variable query, fixes [#5165](https://github.com/grafana/grafana/pull/5165) +* **Singlestat gauge**: Fixed issue with gauge render position, fixes [#5143](https://github.com/grafana/grafana/pull/5143) +* **Home dashboard**: Fixes broken home dashboard api, fixes [#5167](https://github.com/grafana/grafana/issues/5167) + +# 3.0.3 Patch release (2016-05-23) +* **Annotations**: Annotations can now use a template variable as data source, closes [#5054](https://github.com/grafana/grafana/issues/5054) * **Time picker**: Fixed issue timepicker and UTC when reading time from URL, fixes [#5078](https://github.com/grafana/grafana/issues/5078) * **CloudWatch**: Support for Multiple Account by AssumeRole, closes [#3522](https://github.com/grafana/grafana/issues/3522) +* **Singlestat**: Fixed alignment and minium height issue, fixes [#5113](https://github.com/grafana/grafana/issues/5113), fixes [#4679](https://github.com/grafana/grafana/issues/4679) +* **Share modal**: Fixed link when using grafana under dashboard sub url, fixes [#5109](https://github.com/grafana/grafana/issues/5109) +* **Prometheus**: Fixed bug in query editor that caused it not to load when reloading page, fixes [#5107](https://github.com/grafana/grafana/issues/5107) +* **Elasticsearch**: Fixed bug when template variable query returns numeric values, fixes [#5097](https://github.com/grafana/grafana/issues/5097), fixes [#5088](https://github.com/grafana/grafana/issues/5088) +* **Logging**: Fixed issue with reading logging level value, fixes [#5079](https://github.com/grafana/grafana/issues/5079) +* **Timepicker**: Fixed issue with timepicker and UTC when reading time from URL, fixes [#5078](https://github.com/grafana/grafana/issues/5078) +* **Docs**: Added docs for org & user preferences HTTP API, closes [#5069](https://github.com/grafana/grafana/issues/5069) +* **Plugin list panel**: Now shows correct enable state for apps when not enabled, fixes [#5068](https://github.com/grafana/grafana/issues/5068) +* **Elasticsearch**: Templating & Annotation queries that use template variables are now formatted correctly, fixes [#5135](https://github.com/grafana/grafana/issues/5135) # 3.0.2 Patch release (2016-05-16) diff --git a/docs/sources/installation/configuration.md b/docs/sources/installation/configuration.md index e7d1d68523a..bbfe381d1f0 100644 --- a/docs/sources/installation/configuration.md +++ b/docs/sources/installation/configuration.md @@ -226,7 +226,7 @@ organization to be created for that new user. The role new users will be assigned for the main organization (if the above setting is set to true). Defaults to `Viewer`, other valid -options are `Admin` and `Editor`. +options are `Admin` and `Editor` and `Read-Only Editor`.
diff --git a/docs/sources/installation/debian.md b/docs/sources/installation/debian.md index 1b3957fa684..6084b9b317d 100644 --- a/docs/sources/installation/debian.md +++ b/docs/sources/installation/debian.md @@ -10,13 +10,13 @@ page_keywords: grafana, installation, debian, ubuntu, guide Description | Download ------------ | ------------- -Stable .deb for Debian-based Linux | [grafana_3.0.2-1463383025_amd64.deb](https://grafanarel.s3.amazonaws.com/builds/grafana_3.0.2-1463383025_amd64.deb) +Stable .deb for Debian-based Linux | [grafana_3.0.4-1464167696.deb](https://grafanarel.s3.amazonaws.com/builds/grafana_3.0.4-1464167696_amd64.deb) ## Install Stable - $ wget https://grafanarel.s3.amazonaws.com/builds/grafana_3.0.2-1463383025_amd64.deb + $ wget https://grafanarel.s3.amazonaws.com/builds/grafana_3.0.4-1464167696_amd64.deb $ sudo apt-get install -y adduser libfontconfig - $ sudo dpkg -i grafana_3.0.2-1463383025_amd64.deb + $ sudo dpkg -i grafana_3.0.4-1464167696_amd64.deb ## APT Repository diff --git a/docs/sources/installation/rpm.md b/docs/sources/installation/rpm.md index af3ae7f8288..854ba91fcf7 100644 --- a/docs/sources/installation/rpm.md +++ b/docs/sources/installation/rpm.md @@ -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.2-1463383025.x86_64.rpm](https://grafanarel.s3.amazonaws.com/builds/grafana-3.0.2-1463383025.x86_64.rpm) +Stable .RPM for CentOS / Fedora / OpenSuse / Redhat Linux | [grafana-3.0.4-1464167696.x86_64.rpm](https://grafanarel.s3.amazonaws.com/builds/grafana-3.0.4-1464167696.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.2-1463383025.x86_64.rpm + $ sudo yum install https://grafanarel.s3.amazonaws.com/builds/grafana-3.0.4-1464167696.x86_64.rpm Or install manually using `rpm`. #### On CentOS / Fedora / Redhat: $ sudo yum install initscripts fontconfig - $ sudo rpm -Uvh grafana-3.0.2-1463383025.x86_64.rpm + $ sudo rpm -Uvh grafana-3.0.4-1464167696.x86_64.rpm #### On OpenSuse: - $ sudo rpm -i --nodeps grafana-3.0.2-1463383025.x86_64.rpm + $ sudo rpm -i --nodeps grafana-3.0.4-1464167696.x86_64.rpm ## Install via YUM Repository diff --git a/docs/sources/installation/windows.md b/docs/sources/installation/windows.md index baa13d0350c..858f8cfea2d 100644 --- a/docs/sources/installation/windows.md +++ b/docs/sources/installation/windows.md @@ -10,7 +10,7 @@ page_keywords: grafana, installation, windows guide Description | Download ------------ | ------------- -Stable Zip package for Windows | [grafana.3.0.2.windows-x64.zip](https://grafanarel.s3.amazonaws.com/winbuilds/dist/grafana-3.0.2.windows-x64.zip) +Stable Zip package for Windows | [grafana.3.0.4.windows-x64.zip](https://grafanarel.s3.amazonaws.com/winbuilds/dist/grafana-3.0.4.windows-x64.zip) ## Configure diff --git a/latest.json b/latest.json index 443a440a529..7fe27b91983 100644 --- a/latest.json +++ b/latest.json @@ -1,4 +1,4 @@ { - "stable": "3.0.2", - "testing": "3.0.2" + "stable": "3.0.4", + "testing": "3.0.4" } diff --git a/packaging/publish/publish.sh b/packaging/publish/publish.sh index 79da73d441a..892bfc178cc 100755 --- a/packaging/publish/publish.sh +++ b/packaging/publish/publish.sh @@ -1,22 +1,20 @@ #! /usr/bin/env bash -deb_ver=3.0.1 -rpm_ver=3.0.1-1 +deb_ver=3.0.4-1464167696 +rpm_ver=3.0.4-1464167696 -#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 diff --git a/pkg/api/api.go b/pkg/api/api.go index f14802d2a70..7d2d679362e 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -211,7 +211,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)) }) diff --git a/pkg/api/cloudwatch/cloudwatch.go b/pkg/api/cloudwatch/cloudwatch.go index 5b4449b5c02..4e9c6cc9064 100644 --- a/pkg/api/cloudwatch/cloudwatch.go +++ b/pkg/api/cloudwatch/cloudwatch.go @@ -57,11 +57,12 @@ var awsCredentialCache map[string]cache = make(map[string]cache) var credentialCacheLock sync.RWMutex func getCredentials(profile string, region string, assumeRoleArn string) *credentials.Credentials { + cacheKey := profile + ":" + assumeRoleArn credentialCacheLock.RLock() - if _, ok := awsCredentialCache[profile]; ok { - if awsCredentialCache[profile].expiration != nil && - (*awsCredentialCache[profile].expiration).After(time.Now().UTC()) { - result := awsCredentialCache[profile].credential + if _, ok := awsCredentialCache[cacheKey]; ok { + if awsCredentialCache[cacheKey].expiration != nil && + (*awsCredentialCache[cacheKey].expiration).After(time.Now().UTC()) { + result := awsCredentialCache[cacheKey].credential credentialCacheLock.RUnlock() return result } @@ -118,7 +119,7 @@ func getCredentials(profile string, region string, assumeRoleArn string) *creden &ec2rolecreds.EC2RoleProvider{Client: ec2metadata.New(sess), ExpiryWindow: 5 * time.Minute}, }) credentialCacheLock.Lock() - awsCredentialCache[profile] = cache{ + awsCredentialCache[cacheKey] = cache{ credential: creds, expiration: expiration, } diff --git a/pkg/api/dashboard.go b/pkg/api/dashboard.go index b55a1377bd8..cad9da19e82 100644 --- a/pkg/api/dashboard.go +++ b/pkg/api/dashboard.go @@ -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) { diff --git a/pkg/api/dtos/index.go b/pkg/api/dtos/index.go index 21201d30adf..b813c78f2bb 100644 --- a/pkg/api/dtos/index.go +++ b/pkg/api/dtos/index.go @@ -1,13 +1,17 @@ package dtos type IndexViewData struct { - User *CurrentUser - Settings map[string]interface{} - AppUrl string - AppSubUrl string - GoogleAnalyticsId string - GoogleTagManagerId string - MainNavLinks []*NavLink + User *CurrentUser + Settings map[string]interface{} + AppUrl string + AppSubUrl string + GoogleAnalyticsId string + GoogleTagManagerId string + MainNavLinks []*NavLink + BuildVersion string + BuildCommit string + NewGrafanaVersionExists bool + NewGrafanaVersion string } type PluginCss struct { diff --git a/pkg/api/index.go b/pkg/api/index.go index b921c9d17c6..0a02c129b5d 100644 --- a/pkg/api/index.go +++ b/pkg/api/index.go @@ -36,11 +36,15 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) { LightTheme: prefs.Theme == "light", Timezone: prefs.Timezone, }, - Settings: settings, - AppUrl: setting.AppUrl, - AppSubUrl: setting.AppSubUrl, - GoogleAnalyticsId: setting.GoogleAnalyticsId, - GoogleTagManagerId: setting.GoogleTagManagerId, + Settings: settings, + AppUrl: setting.AppUrl, + AppSubUrl: setting.AppSubUrl, + GoogleAnalyticsId: setting.GoogleAnalyticsId, + GoogleTagManagerId: setting.GoogleTagManagerId, + BuildVersion: setting.BuildVersion, + BuildCommit: setting.BuildCommit, + NewGrafanaVersion: plugins.GrafanaLatestVersion, + NewGrafanaVersionExists: plugins.GrafanaHasUpdate, } if setting.DisableGravatar { diff --git a/pkg/api/pluginproxy/pluginproxy.go b/pkg/api/pluginproxy/pluginproxy.go index 92d07988b64..21d40ecb948 100644 --- a/pkg/api/pluginproxy/pluginproxy.go +++ b/pkg/api/pluginproxy/pluginproxy.go @@ -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]) } } diff --git a/pkg/cmd/grafana-server/main.go b/pkg/cmd/grafana-server/main.go index b2c66ba185e..35fae1cbac4 100644 --- a/pkg/cmd/grafana-server/main.go +++ b/pkg/cmd/grafana-server/main.go @@ -24,7 +24,7 @@ import ( "github.com/grafana/grafana/pkg/social" ) -var version = "3.0.0-beta4" +var version = "3.1.0" var commit = "NA" var buildstamp string var build_date string diff --git a/public/app/core/controllers/login_ctrl.js b/public/app/core/controllers/login_ctrl.js index 4249d55a44f..45a47558ed7 100644 --- a/public/app/core/controllers/login_ctrl.js +++ b/public/app/core/controllers/login_ctrl.js @@ -35,15 +35,6 @@ function (angular, coreModule, config) { } }; - // build info view model - $scope.buildInfo = { - version: config.buildInfo.version, - commit: config.buildInfo.commit, - buildstamp: new Date(config.buildInfo.buildstamp * 1000), - latestVersion: config.buildInfo.latestVersion, - hasUpdate: config.buildInfo.hasUpdate, - }; - $scope.submit = function() { if ($scope.loginMode) { $scope.login(); diff --git a/public/app/core/directives/metric_segment.js b/public/app/core/directives/metric_segment.js index 61415a660b2..4b3cd2e8de3 100644 --- a/public/app/core/directives/metric_segment.js +++ b/public/app/core/directives/metric_segment.js @@ -209,7 +209,9 @@ function (_, $, coreModule) { // needs to call this after digest so // property is synced with outerscope $scope.$$postDigest(function() { - $scope.onChange(); + $scope.$apply(function() { + $scope.onChange(); + }); }); }; diff --git a/public/app/core/services/datasource_srv.js b/public/app/core/services/datasource_srv.js index a71b2bd3767..b8b94cd286d 100644 --- a/public/app/core/services/datasource_srv.js +++ b/public/app/core/services/datasource_srv.js @@ -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(); }); }); diff --git a/public/app/core/time_series2.ts b/public/app/core/time_series2.ts index cbceff7afd8..dfae26fb48b 100644 --- a/public/app/core/time_series2.ts +++ b/public/app/core/time_series2.ts @@ -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; } diff --git a/public/app/features/annotations/editor_ctrl.js b/public/app/features/annotations/editor_ctrl.js index ca754b094a8..c37592cc905 100644 --- a/public/app/features/annotations/editor_ctrl.js +++ b/public/app/features/annotations/editor_ctrl.js @@ -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; }); }; diff --git a/public/app/features/dashboard/rowCtrl.js b/public/app/features/dashboard/rowCtrl.js index 5607f1eecac..4534b9bc510 100644 --- a/public/app/features/dashboard/rowCtrl.js +++ b/public/app/features/dashboard/rowCtrl.js @@ -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(); + } }; }); diff --git a/public/app/features/dashboard/shareModalCtrl.js b/public/app/features/dashboard/shareModalCtrl.js index f1b0f38a48f..462812efa29 100644 --- a/public/app/features/dashboard/shareModalCtrl.js +++ b/public/app/features/dashboard/shareModalCtrl.js @@ -74,12 +74,12 @@ 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 = ''; - $scope.imageUrl = soloUrl.replace('/dashboard-solo/', '/render/dashboard-solo/'); + $scope.imageUrl = soloUrl.replace(config.appSubUrl + '/dashboard-solo/', config.appSubUrl + '/render/dashboard-solo/'); $scope.imageUrl += '&width=1000'; $scope.imageUrl += '&height=500'; }; diff --git a/public/app/features/dashboard/submenu/submenu.ts b/public/app/features/dashboard/submenu/submenu.ts index 8e7984a4085..c1e83428003 100644 --- a/public/app/features/dashboard/submenu/submenu.ts +++ b/public/app/features/dashboard/submenu/submenu.ts @@ -1,6 +1,7 @@ /// import angular from 'angular'; +import _ from 'lodash'; export class SubmenuCtrl { annotations: any; @@ -8,7 +9,11 @@ export class SubmenuCtrl { dashboard: any; /** @ngInject */ - constructor(private $rootScope, private templateValuesSrv) { + constructor(private $rootScope, + private templateValuesSrv, + private templateSrv, + private dynamicDashboardSrv, + private $location) { this.annotations = this.dashboard.templating.list; this.variables = this.dashboard.templating.list; } @@ -22,8 +27,26 @@ export class SubmenuCtrl { return this.templateValuesSrv.getValuesForTag(variable, tagKey); } + updateUrlParamsWithCurrentVariables() { + // update url + var params = this.$location.search(); + // remove variable params + _.each(params, function(value, key) { + if (key.indexOf('var-') === 0) { + delete params[key]; + } + }); + + // add new values + this.templateSrv.fillVariableValuesForUrl(params); + // update url + this.$location.search(params); + } + variableUpdated(variable) { this.templateValuesSrv.variableUpdated(variable).then(() => { + this.dynamicDashboardSrv.update(this.dashboard); + this.updateUrlParamsWithCurrentVariables(); this.$rootScope.$emit('template-variable-value-updated'); this.$rootScope.$broadcast('refresh'); }); diff --git a/public/app/features/dashboard/timeSrv.js b/public/app/features/dashboard/timeSrv.js index cd52155ff5f..96ba832f8b0 100644 --- a/public/app/features/dashboard/timeSrv.js +++ b/public/app/features/dashboard/timeSrv.js @@ -10,7 +10,7 @@ define([ var module = angular.module('grafana.services'); - module.service('timeSrv', function($rootScope, $timeout, $routeParams, timer) { + module.service('timeSrv', function($rootScope, $timeout, $routeParams, timer, $location) { var self = this; this.init = function(dashboard) { @@ -108,6 +108,13 @@ define([ this.old_refresh = null; } + // update url params + var urlParams = $location.search(); + var urlRange = this.timeRangeForUrl(); + urlParams.from = urlRange.from; + urlParams.to = urlRange.to; + $location.search(urlParams); + $rootScope.appEvent('time-range-changed', this.time); $timeout(this.refreshDashboard, 0); }; diff --git a/public/app/features/panel/panel_ctrl.ts b/public/app/features/panel/panel_ctrl.ts index 82e19f8681b..e47e3444564 100644 --- a/public/app/features/panel/panel_ctrl.ts +++ b/public/app/features/panel/panel_ctrl.ts @@ -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'; @@ -90,6 +91,23 @@ export class PanelCtrl { this.addEditorTab('General', 'public/app/partials/panelgeneral.html'); this.editModeInitiated = true; this.events.emit('init-edit-mode', null); + + var routeParams = this.$injector.get('$routeParams'); + if (routeParams.editorTab) { + this.editorTabs.forEach((tab, i) => { + if (tab.title === routeParams.editorTab) { + this.editorTabIndex = i; + } + }); + } + } + + changeTab(newIndex) { + this.editorTabIndex = newIndex; + var route = this.$injector.get('$route'); + + route.current.params.editorTab = this.editorTabs[newIndex].title; + route.updateParams(); } addEditorTab(title, directiveFn, index?) { @@ -141,7 +159,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?) { diff --git a/public/app/features/panel/panel_directive.ts b/public/app/features/panel/panel_directive.ts index a9bb75760f5..7d63e620f98 100644 --- a/public/app/features/panel/panel_directive.ts +++ b/public/app/features/panel/panel_directive.ts @@ -36,7 +36,7 @@ var panelTemplate = `