diff --git a/CHANGELOG.md b/CHANGELOG.md index a0741e2e0ec..8e77be6b6f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ * **Graph Panel**: Fixed issue with axis labels overlapping Y-axis, fixes [#4626](https://github.com/grafana/grafana/issues/4626) * **InfluxDB**: Fixed issue with templating query containing template variable, fixes [#4602](https://github.com/grafana/grafana/issues/4602) * **Graph Panel**: Fixed issue with hiding series and stacking, fixes [#4557](https://github.com/grafana/grafana/issues/4557) -* **Mixed Datasources**: Fixed issue with mixing many datasources in same graph, fixes [#4604](https://github.com/grafana/grafana/issues/4604) +* **Graph Panel**: Fixed issue with legend height in table mode with few series, affected iframe embedding as well, fixes [#4640](https://github.com/grafana/grafana/issues/4640) # 3.0.0-beta2 (2016-04-04) diff --git a/conf/defaults.ini b/conf/defaults.ini index 851c88efc7c..6f63891d1ee 100644 --- a/conf/defaults.ini +++ b/conf/defaults.ini @@ -111,6 +111,13 @@ gc_interval_time = 86400 # Change this option to false to disable reporting. reporting_enabled = true +# Set to false to disable all checks to https://grafana.net +# for new vesions (grafana itself and plugins), check is used +# in some UI views to notify that grafana or plugin update exists +# This option does not cause any auto updates, nor send any information +# only a GET request to http://grafana.net to get latest versions +check_for_updates = true + # Google Analytics universal tracking code, only enabled if you specify an id here google_analytics_ua_id = diff --git a/conf/sample.ini b/conf/sample.ini index b875cbda093..4ab923c1376 100644 --- a/conf/sample.ini +++ b/conf/sample.ini @@ -100,6 +100,13 @@ # Change this option to false to disable reporting. ;reporting_enabled = true +# Set to false to disable all checks to https://grafana.net +# for new vesions (grafana itself and plugins), check is used +# in some UI views to notify that grafana or plugin update exists +# This option does not cause any auto updates, nor send any information +# only a GET request to http://grafana.net to get latest versions +check_for_updates = true + # Google Analytics universal tracking code, only enabled if you specify an id here ;google_analytics_ua_id = diff --git a/latest.json b/latest.json index 79eb42a8527..6bb5ba3e411 100644 --- a/latest.json +++ b/latest.json @@ -1,3 +1,4 @@ { - "version": "2.1.1" + "stable": "2.6.0", + "testing": "3.0.0-beta1" } diff --git a/pkg/api/dtos/plugins.go b/pkg/api/dtos/plugins.go index 53c911c10fa..fbdf8d4e0ea 100644 --- a/pkg/api/dtos/plugins.go +++ b/pkg/api/dtos/plugins.go @@ -15,15 +15,20 @@ type PluginSetting struct { Dependencies *plugins.PluginDependencies `json:"dependencies"` JsonData map[string]interface{} `json:"jsonData"` DefaultNavUrl string `json:"defaultNavUrl"` + + LatestVersion string `json:"latestVersion"` + HasUpdate bool `json:"hasUpdate"` } type PluginListItem struct { - Name string `json:"name"` - Type string `json:"type"` - Id string `json:"id"` - Enabled bool `json:"enabled"` - Pinned bool `json:"pinned"` - Info *plugins.PluginInfo `json:"info"` + Name string `json:"name"` + Type string `json:"type"` + Id string `json:"id"` + Enabled bool `json:"enabled"` + Pinned bool `json:"pinned"` + Info *plugins.PluginInfo `json:"info"` + LatestVersion string `json:"latestVersion"` + HasUpdate bool `json:"hasUpdate"` } type PluginList []PluginListItem diff --git a/pkg/api/frontendsettings.go b/pkg/api/frontendsettings.go index f23f416b47a..dd84f7827eb 100644 --- a/pkg/api/frontendsettings.go +++ b/pkg/api/frontendsettings.go @@ -137,9 +137,11 @@ func getFrontendSettingsMap(c *middleware.Context) (map[string]interface{}, erro "allowOrgCreate": (setting.AllowUserOrgCreate && c.IsSignedIn) || c.IsGrafanaAdmin, "authProxyEnabled": setting.AuthProxyEnabled, "buildInfo": map[string]interface{}{ - "version": setting.BuildVersion, - "commit": setting.BuildCommit, - "buildstamp": setting.BuildStamp, + "version": setting.BuildVersion, + "commit": setting.BuildCommit, + "buildstamp": setting.BuildStamp, + "latestVersion": plugins.GrafanaLatestVersion, + "hasUpdate": plugins.GrafanaHasUpdate, }, } diff --git a/pkg/api/plugins.go b/pkg/api/plugins.go index 3e8f80132d3..6446f7fee33 100644 --- a/pkg/api/plugins.go +++ b/pkg/api/plugins.go @@ -40,10 +40,12 @@ func GetPluginList(c *middleware.Context) Response { } listItem := dtos.PluginListItem{ - Id: pluginDef.Id, - Name: pluginDef.Name, - Type: pluginDef.Type, - Info: &pluginDef.Info, + Id: pluginDef.Id, + Name: pluginDef.Name, + Type: pluginDef.Type, + Info: &pluginDef.Info, + LatestVersion: pluginDef.GrafanaNetVersion, + HasUpdate: pluginDef.GrafanaNetHasUpdate, } if pluginSetting, exists := pluginSettingsMap[pluginDef.Id]; exists { @@ -87,6 +89,8 @@ func GetPluginSettingById(c *middleware.Context) Response { BaseUrl: def.BaseUrl, Module: def.Module, DefaultNavUrl: def.DefaultNavUrl, + LatestVersion: def.GrafanaNetVersion, + HasUpdate: def.GrafanaNetHasUpdate, } query := m.GetPluginSettingByIdQuery{PluginId: pluginId, OrgId: c.OrgId} diff --git a/pkg/metrics/report_usage.go b/pkg/metrics/report_usage.go index c5c2afed7f7..85a87155f6d 100644 --- a/pkg/metrics/report_usage.go +++ b/pkg/metrics/report_usage.go @@ -10,6 +10,7 @@ import ( "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/log" m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/setting" ) @@ -56,6 +57,9 @@ func sendUsageStats() { metrics["stats.users.count"] = statsQuery.Result.UserCount metrics["stats.orgs.count"] = statsQuery.Result.OrgCount metrics["stats.playlist.count"] = statsQuery.Result.PlaylistCount + metrics["stats.plugins.apps.count"] = len(plugins.Apps) + metrics["stats.plugins.panels.count"] = len(plugins.Panels) + metrics["stats.plugins.datasources.count"] = len(plugins.DataSources) dsStats := m.GetDataSourceStatsQuery{} if err := bus.Dispatch(&dsStats); err != nil { diff --git a/pkg/plugins/models.go b/pkg/plugins/models.go index d35a78000b0..68268239c51 100644 --- a/pkg/plugins/models.go +++ b/pkg/plugins/models.go @@ -45,6 +45,9 @@ type PluginBase struct { DefaultNavUrl string `json:"-"` IsCorePlugin bool `json:"-"` + GrafanaNetVersion string `json:"-"` + GrafanaNetHasUpdate bool `json:"-"` + // cache for readme file contents Readme []byte `json:"-"` } diff --git a/pkg/plugins/plugins.go b/pkg/plugins/plugins.go index 0d69d5745b9..073685afc79 100644 --- a/pkg/plugins/plugins.go +++ b/pkg/plugins/plugins.go @@ -22,6 +22,9 @@ var ( Apps map[string]*AppPlugin Plugins map[string]*PluginBase PluginTypes map[string]interface{} + + GrafanaLatestVersion string + GrafanaHasUpdate bool ) type PluginScanner struct { @@ -70,6 +73,7 @@ func Init() error { app.initApp() } + go StartPluginUpdateChecker() return nil } diff --git a/pkg/plugins/update_checker.go b/pkg/plugins/update_checker.go new file mode 100644 index 00000000000..6d3626fff16 --- /dev/null +++ b/pkg/plugins/update_checker.go @@ -0,0 +1,110 @@ +package plugins + +import ( + "encoding/json" + "io/ioutil" + "net/http" + "strings" + "time" + + "github.com/grafana/grafana/pkg/log" + "github.com/grafana/grafana/pkg/setting" +) + +type GrafanaNetPlugins struct { + Plugins []GrafanaNetPlugin `json:"plugins"` +} + +type GrafanaNetPlugin struct { + Id string `json:"id"` + Versions []GrafanaNetPluginVersion `json:"versions"` +} + +type GrafanaNetPluginVersion struct { + Version string `json:"version"` +} + +type GithubLatest struct { + Stable string `json:"stable"` + Testing string `json:"testing"` +} + +func StartPluginUpdateChecker() { + if !setting.CheckForUpdates { + return + } + + ticker := time.NewTicker(time.Second * 24) + for { + select { + case <-ticker.C: + checkForUpdates() + } + } +} + +func checkForUpdates() { + log.Trace("Checking for updates") + + client := http.Client{Timeout: time.Duration(5 * time.Second)} + resp, err := client.Get("https://grafana.net/api/plugins/repo") + + if err != nil { + log.Trace("Failed to get plugins repo from grafana.net, %v", err.Error()) + return + } + + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + log.Trace("Update check failed, reading response from grafana.net, %v", err.Error()) + return + } + + var data GrafanaNetPlugins + err = json.Unmarshal(body, &data) + if err != nil { + log.Trace("Failed to unmarshal plugin repo, reading response from grafana.net, %v", err.Error()) + return + } + + for _, plug := range Plugins { + for _, gplug := range data.Plugins { + if gplug.Id == plug.Id { + if len(gplug.Versions) > 0 { + plug.GrafanaNetVersion = gplug.Versions[0].Version + plug.GrafanaNetHasUpdate = plug.Info.Version != plug.GrafanaNetVersion + } + } + } + } + + resp2, err := client.Get("https://raw.githubusercontent.com/grafana/grafana/master/latest.json") + if err != nil { + log.Trace("Failed to get lates.json repo from github: %v", err.Error()) + return + } + + defer resp2.Body.Close() + body, err = ioutil.ReadAll(resp2.Body) + if err != nil { + log.Trace("Update check failed, reading response from github.net, %v", err.Error()) + return + } + + var githubLatest GithubLatest + err = json.Unmarshal(body, &githubLatest) + if err != nil { + log.Trace("Failed to unmarshal github latest, reading response from github: %v", err.Error()) + return + } + + if strings.Contains(setting.BuildVersion, "-") { + GrafanaLatestVersion = githubLatest.Testing + GrafanaHasUpdate = githubLatest.Testing != setting.BuildVersion + } else { + GrafanaLatestVersion = githubLatest.Stable + GrafanaHasUpdate = githubLatest.Stable != setting.BuildVersion + } +} diff --git a/pkg/setting/setting.go b/pkg/setting/setting.go index b8e8d7f7fcf..2d1bad945eb 100644 --- a/pkg/setting/setting.go +++ b/pkg/setting/setting.go @@ -124,6 +124,7 @@ var ( appliedEnvOverrides []string ReportingEnabled bool + CheckForUpdates bool GoogleAnalyticsId string GoogleTagManagerId string @@ -475,6 +476,7 @@ func NewConfigContext(args *CommandLineArgs) error { analytics := Cfg.Section("analytics") ReportingEnabled = analytics.Key("reporting_enabled").MustBool(true) + CheckForUpdates = analytics.Key("check_for_updates").MustBool(true) GoogleAnalyticsId = analytics.Key("google_analytics_ua_id").String() GoogleTagManagerId = analytics.Key("google_tag_manager_id").String() diff --git a/public/app/core/components/switch.ts b/public/app/core/components/switch.ts index 1dddae20d49..10211b5b914 100644 --- a/public/app/core/components/switch.ts +++ b/public/app/core/components/switch.ts @@ -21,14 +21,14 @@ export class SwitchCtrl { id: any; /** @ngInject */ - constructor($scope) { + constructor($scope, private $timeout) { this.show = true; this.id = $scope.$id; } internalOnChange() { return new Promise(resolve => { - setTimeout(() => { + this.$timeout(() => { this.onChange(); resolve(); }); diff --git a/public/app/core/controllers/login_ctrl.js b/public/app/core/controllers/login_ctrl.js index 89757c3d141..4249d55a44f 100644 --- a/public/app/core/controllers/login_ctrl.js +++ b/public/app/core/controllers/login_ctrl.js @@ -39,7 +39,9 @@ function (angular, coreModule, config) { $scope.buildInfo = { version: config.buildInfo.version, commit: config.buildInfo.commit, - buildstamp: new Date(config.buildInfo.buildstamp * 1000) + buildstamp: new Date(config.buildInfo.buildstamp * 1000), + latestVersion: config.buildInfo.latestVersion, + hasUpdate: config.buildInfo.hasUpdate, }; $scope.submit = function() { diff --git a/public/app/features/dashboard/partials/shareModal.html b/public/app/features/dashboard/partials/shareModal.html index 41c08fede0b..c8462c7bffc 100644 --- a/public/app/features/dashboard/partials/shareModal.html +++ b/public/app/features/dashboard/partials/shareModal.html @@ -38,31 +38,26 @@
-