From c68da40710fd4c837b43bdd0615bd7b7a2abe498 Mon Sep 17 00:00:00 2001 From: bergquist Date: Fri, 15 Feb 2019 15:05:01 +0100 Subject: [PATCH 01/48] run db tests in all packages --- .circleci/config.yml | 4 ++-- scripts/circle-test-mysql.sh | 17 +++++++++++++++++ scripts/circle-test-postgres.sh | 17 +++++++++++++++++ 3 files changed, 36 insertions(+), 2 deletions(-) create mode 100755 scripts/circle-test-mysql.sh create mode 100755 scripts/circle-test-postgres.sh diff --git a/.circleci/config.yml b/.circleci/config.yml index 8144956773b..69cea87dccd 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -35,7 +35,7 @@ jobs: - run: cat devenv/docker/blocks/mysql_tests/setup.sql | mysql -h 127.0.0.1 -P 3306 -u root -prootpass - run: name: mysql integration tests - command: 'GRAFANA_TEST_DB=mysql go test ./pkg/services/sqlstore/... ./pkg/tsdb/mysql/... ' + command: './scripts/circle-test-mysql.sh' postgres-integration-test: docker: @@ -54,7 +54,7 @@ jobs: - run: 'PGPASSWORD=grafanatest psql -p 5432 -h 127.0.0.1 -U grafanatest -d grafanatest -f devenv/docker/blocks/postgres_tests/setup.sql' - run: name: postgres integration tests - command: 'GRAFANA_TEST_DB=postgres go test ./pkg/services/sqlstore/... ./pkg/tsdb/postgres/...' + command: './scripts/circle-test-postgres.sh' codespell: docker: diff --git a/scripts/circle-test-mysql.sh b/scripts/circle-test-mysql.sh new file mode 100755 index 00000000000..4d2fea90c4d --- /dev/null +++ b/scripts/circle-test-mysql.sh @@ -0,0 +1,17 @@ +#!/bin/bash +function exit_if_fail { + command=$@ + echo "Executing '$command'" + eval $command + rc=$? + if [ $rc -ne 0 ]; then + echo "'$command' returned $rc." + exit $rc + fi +} + +export GRAFANA_TEST_DB=mysql + +time for d in $(go list ./pkg/...); do + exit_if_fail go test -tags=integration $d +done \ No newline at end of file diff --git a/scripts/circle-test-postgres.sh b/scripts/circle-test-postgres.sh new file mode 100755 index 00000000000..7ddfe6887d9 --- /dev/null +++ b/scripts/circle-test-postgres.sh @@ -0,0 +1,17 @@ +#!/bin/bash +function exit_if_fail { + command=$@ + echo "Executing '$command'" + eval $command + rc=$? + if [ $rc -ne 0 ]; then + echo "'$command' returned $rc." + exit $rc + fi +} + +export GRAFANA_TEST_DB=postgres + +time for d in $(go list ./pkg/...); do + exit_if_fail go test -tags=integration $d +done \ No newline at end of file From dc155dfa2f5e0eadffe8f08c1c6fddff997ce7df Mon Sep 17 00:00:00 2001 From: Leonard Gram Date: Tue, 19 Feb 2019 16:52:47 +0100 Subject: [PATCH 02/48] docs: howto for recreating our debian repositories. --- scripts/build/update_repo/init-deb-repo.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/build/update_repo/init-deb-repo.sh b/scripts/build/update_repo/init-deb-repo.sh index 2b245dc2d42..ff9057ee876 100755 --- a/scripts/build/update_repo/init-deb-repo.sh +++ b/scripts/build/update_repo/init-deb-repo.sh @@ -10,3 +10,6 @@ mkdir -p /deb-repo/db \ aptly repo create -distribution=stable -component=main grafana aptly repo create -distribution=beta -component=main beta + +aptly publish repo -architectures=amd64,i386,arm64,armhf grafana filesystem:repo:grafana +aptly publish repo -architectures=amd64,i386,arm64,armhf beta filesystem:repo:grafana From 09cd173e9249d5e54cf3c304d2430f0390c68f45 Mon Sep 17 00:00:00 2001 From: Maddin-619 Date: Fri, 22 Feb 2019 14:19:15 +0100 Subject: [PATCH 03/48] updates all cols except created so user and password of the database can be chaned to no user and password --- pkg/services/sqlstore/datasource.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/services/sqlstore/datasource.go b/pkg/services/sqlstore/datasource.go index ccab1106880..65d8369d763 100644 --- a/pkg/services/sqlstore/datasource.go +++ b/pkg/services/sqlstore/datasource.go @@ -180,7 +180,7 @@ func UpdateDataSource(cmd *m.UpdateDataSourceCommand) error { updateSession = sess.Where("id=? and org_id=?", ds.Id, ds.OrgId) } - affected, err := updateSession.Update(ds) + affected, err := updateSession.AllCols().Omit("created").Update(ds) if err != nil { return err } From 0bdca7957aa0ce01bccea90f0f9ad7069ad57168 Mon Sep 17 00:00:00 2001 From: Jon Ferreira Date: Fri, 22 Feb 2019 14:56:13 -0500 Subject: [PATCH 04/48] Toggle stack should trigger a render, not a refresh --- public/app/plugins/panel/graph/tab_display.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/plugins/panel/graph/tab_display.html b/public/app/plugins/panel/graph/tab_display.html index a6287922cfe..e6f5b597e1b 100644 --- a/public/app/plugins/panel/graph/tab_display.html +++ b/public/app/plugins/panel/graph/tab_display.html @@ -114,7 +114,7 @@ label="Stack" label-class="width-7" checked="ctrl.panel.stack" - on-change="ctrl.refresh()" + on-change="ctrl.render()" > Date: Tue, 26 Feb 2019 11:41:55 +0100 Subject: [PATCH 05/48] service: fix for disabled internal metrics. Update of the internal metrics for Grafana was disabled by mistake when refactoring the code. Fixes #15651 --- pkg/cmd/grafana-server/server.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/cmd/grafana-server/server.go b/pkg/cmd/grafana-server/server.go index b454b362d90..53218147ae0 100644 --- a/pkg/cmd/grafana-server/server.go +++ b/pkg/cmd/grafana-server/server.go @@ -31,6 +31,7 @@ import ( _ "github.com/grafana/grafana/pkg/infra/metrics" _ "github.com/grafana/grafana/pkg/infra/serverlock" _ "github.com/grafana/grafana/pkg/infra/tracing" + _ "github.com/grafana/grafana/pkg/infra/usagestats" _ "github.com/grafana/grafana/pkg/plugins" _ "github.com/grafana/grafana/pkg/services/alerting" _ "github.com/grafana/grafana/pkg/services/auth" From e7b630e633375756529dfad0c66093f35af34061 Mon Sep 17 00:00:00 2001 From: Ben Drucker Date: Tue, 26 Feb 2019 11:34:49 -0800 Subject: [PATCH 06/48] Style and grammar fixes --- docs/sources/guides/whats-new-in-v6-0.md | 38 ++++++++++++------------ 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/docs/sources/guides/whats-new-in-v6-0.md b/docs/sources/guides/whats-new-in-v6-0.md index 7c61df1c3c4..1506cee6dbd 100644 --- a/docs/sources/guides/whats-new-in-v6-0.md +++ b/docs/sources/guides/whats-new-in-v6-0.md @@ -12,7 +12,7 @@ weight = -11 # What's New in Grafana v6.0 -This update to Grafana introduces a new way of exploring your data, support for log data and tons of other features. +This update to Grafana introduces a new way of exploring your data, support for log data, and tons of other features. The main highlights are: @@ -25,24 +25,24 @@ The main highlights are: - [Azure Monitor]({{< relref "#azure-monitor-datasource" >}}) plugin is ported from being an external plugin to being a core datasource - [React Plugin]({{< relref "#react-panels-query-editors" >}}) support enables an easier way to build plugins. - [Named Colors]({{< relref "#named-colors" >}}) in our new improved color picker. -- [Removal of user session storage]({{< relref "#easier-to-deploy-improved-security" >}}) makes Grafana easier to deploy & improves security. +- [Removal of user session storage]({{< relref "#easier-to-deploy-improved-security" >}}) makes Grafana easier to deploy and improves security. ## Explore {{< docs-imagebox img="/img/docs/v60/explore_prometheus.png" max-width="800px" class="docs-image--right" caption="Screenshot of the new Explore option in the panel menu" >}} -Grafana's dashboard UI is all about building dashboards for visualization. **Explore** strips away all the dashboard and panel options so that you can focus on the query & metric exploration. Iterate until you have a working query and then think about building a dashboard. You can also jump from a dashboard panel into **Explore** and from there do some ad-hoc query exporation with the panel queries as a starting point. +Grafana's dashboard UI is all about building dashboards for visualization. **Explore** strips away all the dashboard and panel options so that you can focus on the query and metric exploration. Iterate until you have a working query and then think about building a dashboard. You can also jump from a dashboard panel into **Explore** and from there do some ad-hoc query exporation with the panel queries as a starting point. For infrastructure monitoring and incident response, you no longer need to switch to other tools to debug what went wrong. **Explore** allows you to dig deeper into your metrics and logs to find the cause. Grafana's new logging datasource, [Loki](https://github.com/grafana/loki) is tightly integrated into Explore and allows you to correlate metrics and logs by viewing them side-by-side. **Explore** is a new paradigm for Grafana. It creates a new interactive debugging workflow that integrates two pillars -of observability - metrics and logs. Explore works with every datasource but for Prometheus we have customized the +of observability—metrics and logs. Explore works with every datasource but for Prometheus we have customized the query editor and the experience to provide the best possible exploration UX. ### Explore and Prometheus Explore features a new [Prometheus query editor](/features/explore/#prometheus-specific-features). This new editor has improved autocomplete, metric tree selector, -integrations with the Explore table view for easy label filtering and useful query hints that can automatically apply +integrations with the Explore table view for easy label filtering, and useful query hints that can automatically apply functions to your query. There is also integration between Prometheus and Grafana Loki (see more about Loki below) that enabled jumping between metrics query and logs query with preserved label filters. @@ -78,8 +78,8 @@ for other log sources to Explore and the next planned integration is Elasticsear ## New Panel Editor Grafana v6.0 has a completely redesigned UX around editing panels. You can now resize the visualization area if you want -more space for queries & options and vice versa. You can now also change visualization (panel type) from within the new -panel edit mode. No need to add a new panel to try out different visualizations! Checkout the +more space for queries/options and vice versa. You can now also change visualization (panel type) from within the new +panel edit mode. No need to add a new panel to try out different visualizations! Check out the video below to see the new Panel Editor in action.
@@ -94,7 +94,7 @@ video below to see the new Panel Editor in action. ### Gauge Panel We have created a new separate Gauge panel as we felt having this visualization be a hidden option in the Singlestat panel -was not ideal. When it supports 100% of the Singlestat Gauge features we plan to add a migration so all +was not ideal. When it supports 100% of the Singlestat Gauge features, we plan to add a migration so all singlestats that use it become Gauge panels instead. This new panel contains a new **Threshold** editor that we will continue to refine and start using in other panels. @@ -105,7 +105,7 @@ continue to refine and start using in other panels. ### React Panels & Query Editors A major part of all the work that has gone into Grafana v6.0 has been on the migration to React. This investment -is part of the future proofing of Grafana's code base and ecosystem. Starting in v6.0 **Panels** and **Data +is part of the future-proofing of Grafana's code base and ecosystem. Starting in v6.0 **Panels** and **Data source** plugins can be written in React using our published `@grafana/ui` sdk library. More information on this will be shared soon. @@ -120,7 +120,7 @@ To get started read the guide: [Using Google Stackdriver in Grafana](/features/d ## Azure Monitor Datasource -One of the goals of the Grafana v6.0 release is to add support for the three major clouds. Amazon Cloudwatch has been a core datasource for years and Google Stackdriver is also now supported. We developed an external plugin for Azure Monitor last year and for this release the [plugin](https://grafana.com/plugins/grafana-azure-monitor-datasource) is being moved into Grafana to be one of the built-in datasources. For users of the external plugin, Grafana will automatically start using the built-in version. As a core datasource, the Azure Monitor datasource is able to get alerting support, in the 6.0 release alerting is supported for the Azure Monitor service, with the rest to follow. +One of the goals of the Grafana v6.0 release is to add support for the three major clouds. Amazon CloudWatch has been a core datasource for years and Google Stackdriver is also now supported. We developed an external plugin for Azure Monitor last year and for this release the [plugin](https://grafana.com/plugins/grafana-azure-monitor-datasource) is being moved into Grafana to be one of the built-in datasources. For users of the external plugin, Grafana will automatically start using the built-in version. As a core datasource, the Azure Monitor datasource is able to get alerting support, in the 6.0 release alerting is supported for the Azure Monitor service, with the rest to follow. The Azure Monitor datasource integrates four Azure services with Grafana - Azure Monitor, Azure Log Analytics, Azure Application Insights and Azure Application Insights Analytics. @@ -128,15 +128,15 @@ Please read [Using Azure Monitor in Grafana documentation](/features/datasources ## Provisioning support for alert notifiers -Grafana now added support for provisioning alert notifiers from configuration files. Allowing operators to provision notifiers without using the UI or the API. A new field called `uid` has been introduced which is a string identifier that the administrator can set themselves. Same kind of identifier used for dashboards since v5.0. This feature makes it possible to use the same notifier configuration in multiple environments and refer to notifiers in dashboard json by a string identifier instead of the numeric id which depends on insert order and how many notifiers that exists in the instance. +Grafana now has support for provisioning alert notifiers from configuration files, allowing operators to provision notifiers without using the UI or the API. A new field called `uid` has been introduced which is a string identifier that the administrator can set themselves. This is the same kind of identifier used for dashboards since v5.0. This feature makes it possible to use the same notifier configuration in multiple environments and refer to notifiers in dashboard json by a string identifier instead of the numeric id which depends on insert order and how many notifiers exist in the instance. ## Easier to deploy & improved security -Grafana 6.0 removes the need of configuring and setup of additional storage for [user sessions](/tutorials/ha_setup/#user-sessions). This should make it easier to deploy and operate Grafana in a -high availability setup and/or if you're using a stateless user session storage like Redis, Memcache, Postgres or MySQL. +Grafana 6.0 removes the need to configure and set up additional storage for [user sessions](/tutorials/ha_setup/#user-sessions). This should make it easier to deploy and operate Grafana in a +high availability setup and/or if you're using a stateless user session store like Redis, Memcache, Postgres or MySQL. -Instead of user sessions a solution based on short-lived tokens that are rotated frequently have been implemented. This also replaces the old "remember me cookie" -solution, which allowed a user to be logged in between browser sessions, and which have been subject to several security holes throughout the years. +Instead of user sessions, we've implemented a solution based on short-lived tokens that are rotated frequently. This also replaces the old "remember me cookie" +solution, which allowed a user to be logged in between browser sessions and which have been subject to several security holes throughout the years. Read more about the short-lived token solution and how to configure it [here](/auth/overview/#login-and-short-lived-tokens). > Please note that due to these changes, all users will be required to login upon next visit after upgrade. @@ -146,15 +146,15 @@ Besides these changes we have also made security improvements regarding Cross-Si * Cookies are per default using the [SameSite](/installation/configuration/#cookie-samesite) attribute to protect against CSRF attacks * Script tags in text panels are per default [disabled](/installation/configuration/#disable-sanitize-html) to protect against XSS attacks -> If you're using [Auth Proxy Authentication](/auth/auth-proxy/) you still need to have user sessions setup and configured -but our goal is to remove this requirements in a near future. +> If you're using [Auth Proxy Authentication](/auth/auth-proxy/) you still need to have user sessions set up and configured +but our goal is to remove this requirement in the near future. ## Named Colors {{< docs-imagebox img="/img/docs/v60/named_colors.png" max-width="400px" class="docs-image--right" caption="Named Colors" >}} We have updated the color picker to show named colors and primary colors. We hope this will improve accessibility and -helps making colors more consistent across dashboards. We hope to do more in this color picker in the future, like show +helps making colors more consistent across dashboards. We hope to do more in this color picker in the future, like showing colors used in the dashboard. Named colors also enables Grafana to adapt colors to the current theme. @@ -163,7 +163,7 @@ Named colors also enables Grafana to adapt colors to the current theme. ## Other features -- The ElasticSearch datasource now supports [bucket script pipeline aggregations](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-pipeline-bucket-script-aggregation.html). This gives the ability to do per bucket computations like the difference or ratio between two metrics. +- The ElasticSearch datasource now supports [bucket script pipeline aggregations](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-pipeline-bucket-script-aggregation.html). This gives the ability to do per-bucket computations like the difference or ratio between two metrics. - Support for Google Hangouts Chat alert notifications - New built in template variables for the current time range in `$__from` and `$__to` From 8d5ccc7831361bf6159a9850d1bd967d8c1a073e Mon Sep 17 00:00:00 2001 From: Johannes Schill Date: Thu, 28 Feb 2019 10:35:53 +0100 Subject: [PATCH 07/48] fix: Return url when query dashboards by tag --- pkg/api/playlist_play.go | 2 ++ pkg/services/search/models.go | 1 + 2 files changed, 3 insertions(+) diff --git a/pkg/api/playlist_play.go b/pkg/api/playlist_play.go index 5ca136c32c4..2757f245060 100644 --- a/pkg/api/playlist_play.go +++ b/pkg/api/playlist_play.go @@ -52,8 +52,10 @@ func populateDashboardsByTag(orgID int64, signedInUser *m.SignedInUser, dashboar for _, item := range searchQuery.Result { result = append(result, dtos.PlaylistDashboard{ Id: item.Id, + Slug: item.Slug, Title: item.Title, Uri: item.Uri, + Url: m.GetDashboardUrl(item.Uid, item.Slug), Order: dashboardTagOrder[tag], }) } diff --git a/pkg/services/search/models.go b/pkg/services/search/models.go index 2da09672f13..475cb4a3777 100644 --- a/pkg/services/search/models.go +++ b/pkg/services/search/models.go @@ -17,6 +17,7 @@ type Hit struct { Title string `json:"title"` Uri string `json:"uri"` Url string `json:"url"` + Slug string `json:"slug"` Type HitType `json:"type"` Tags []string `json:"tags"` IsStarred bool `json:"isStarred"` From 84b2c0447ee108fbb630e2b2c8898be20da1bc95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Thu, 28 Feb 2019 07:57:59 -0800 Subject: [PATCH 08/48] Fixed right side scrollbar margin on dashboard page --- .../src/components/CustomScrollbar/CustomScrollbar.tsx | 4 ++-- public/app/features/dashboard/containers/DashboardPage.tsx | 7 ++++++- .../containers/__snapshots__/DashboardPage.test.tsx.snap | 2 ++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/grafana-ui/src/components/CustomScrollbar/CustomScrollbar.tsx b/packages/grafana-ui/src/components/CustomScrollbar/CustomScrollbar.tsx index d52d2fea80d..61fc584c7ca 100644 --- a/packages/grafana-ui/src/components/CustomScrollbar/CustomScrollbar.tsx +++ b/packages/grafana-ui/src/components/CustomScrollbar/CustomScrollbar.tsx @@ -1,4 +1,4 @@ -import React, { PureComponent } from 'react'; +import React, { Component } from 'react'; import isNil from 'lodash/isNil'; import classNames from 'classnames'; import Scrollbars from 'react-custom-scrollbars'; @@ -20,7 +20,7 @@ interface Props { /** * Wraps component into component from `react-custom-scrollbars` */ -export class CustomScrollbar extends PureComponent { +export class CustomScrollbar extends Component { static defaultProps: Partial = { autoHide: false, autoHideTimeout: 200, diff --git a/public/app/features/dashboard/containers/DashboardPage.tsx b/public/app/features/dashboard/containers/DashboardPage.tsx index c52774f7e0e..ce2d3fa74df 100644 --- a/public/app/features/dashboard/containers/DashboardPage.tsx +++ b/public/app/features/dashboard/containers/DashboardPage.tsx @@ -268,7 +268,12 @@ export class DashboardPage extends PureComponent { onAddPanel={this.onAddPanel} />
- + {editview && } {initError && this.renderInitFailedState()} diff --git a/public/app/features/dashboard/containers/__snapshots__/DashboardPage.test.tsx.snap b/public/app/features/dashboard/containers/__snapshots__/DashboardPage.test.tsx.snap index fec0e18c349..0e3720bada0 100644 --- a/public/app/features/dashboard/containers/__snapshots__/DashboardPage.test.tsx.snap +++ b/public/app/features/dashboard/containers/__snapshots__/DashboardPage.test.tsx.snap @@ -109,6 +109,7 @@ exports[`DashboardPage Dashboard init completed Should render dashboard grid 1` autoHide={false} autoHideDuration={200} autoHideTimeout={200} + className="custom-scrollbar--page" hideTracksWhenNotNeeded={false} scrollTop={0} setScrollTop={[Function]} @@ -344,6 +345,7 @@ exports[`DashboardPage When dashboard has editview url state should render setti autoHide={false} autoHideDuration={200} autoHideTimeout={200} + className="custom-scrollbar--page" hideTracksWhenNotNeeded={false} scrollTop={0} setScrollTop={[Function]} From 41024c29bb96b3126d9f48988d5a1c5b771f5eff Mon Sep 17 00:00:00 2001 From: Samuel Date: Sun, 3 Mar 2019 05:34:48 +1000 Subject: [PATCH 09/48] Return 404 on user not found (#15606) Return 404 on user not found closes #10506 --- pkg/api/org_invite.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/api/org_invite.go b/pkg/api/org_invite.go index 86067cd7721..4b731db5d3d 100644 --- a/pkg/api/org_invite.go +++ b/pkg/api/org_invite.go @@ -27,6 +27,10 @@ func GetPendingOrgInvites(c *m.ReqContext) Response { } func AddOrgInvite(c *m.ReqContext, inviteDto dtos.AddInviteForm) Response { + if setting.DisableLoginForm { + return Error(400, "Cannot invite when login is disabled.", nil) + } + if !inviteDto.Role.IsValid() { return Error(400, "Invalid role specified", nil) } @@ -37,10 +41,6 @@ func AddOrgInvite(c *m.ReqContext, inviteDto dtos.AddInviteForm) Response { if err != m.ErrUserNotFound { return Error(500, "Failed to query db for existing user check", err) } - - if setting.DisableLoginForm { - return Error(401, "User could not be found", nil) - } } else { return inviteExistingUserToOrg(c, userQuery.Result, &inviteDto) } From dafd7afb971fd5be7b73704f069710b5d763dfca Mon Sep 17 00:00:00 2001 From: bergquist Date: Sat, 2 Mar 2019 18:54:31 +0100 Subject: [PATCH 10/48] changelog: adds note about closing #15651 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d67030873c3..3001521b2e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# 6.0.1 (unreleased) + +### Bug Fixes +* **Metrics**: Fixes broken usagestats metrics for /metrics [#15651](https://github.com/grafana/grafana/issues/15651) + # 6.0.0 stable (2019-02-25) ### Bug Fixes From cde3a21434e664081a024c3f93bbfa3fc8bafaf5 Mon Sep 17 00:00:00 2001 From: bergquist Date: Sat, 2 Mar 2019 20:37:36 +0100 Subject: [PATCH 11/48] changelog: adds note about closing #10506 --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3001521b2e0..fd16d06b81a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ + +# 6.1.0 (unreleased) + +### Bug Fixes +* **Api**: Invalid org invite code [#10506](https://github.com/grafana/grafana/issues/10506) + # 6.0.1 (unreleased) ### Bug Fixes From d49f0bedd33b00e1d9dbe0c20fad4f550f669fae Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Sat, 2 Mar 2019 12:18:26 -0800 Subject: [PATCH 12/48] fix: prevent datasource json data stored as nil (#15508) prevent datasource json data stored as nil closes #14239 --- pkg/services/sqlstore/datasource.go | 10 ++++++++++ pkg/services/sqlstore/migrations/datasource_mig.go | 3 +++ 2 files changed, 13 insertions(+) diff --git a/pkg/services/sqlstore/datasource.go b/pkg/services/sqlstore/datasource.go index 1b69cce8c99..071577eb6d6 100644 --- a/pkg/services/sqlstore/datasource.go +++ b/pkg/services/sqlstore/datasource.go @@ -3,6 +3,8 @@ package sqlstore import ( "time" + "github.com/grafana/grafana/pkg/components/simplejson" + "github.com/go-xorm/xorm" "github.com/grafana/grafana/pkg/bus" @@ -95,6 +97,10 @@ func AddDataSource(cmd *m.AddDataSourceCommand) error { return m.ErrDataSourceNameExists } + if cmd.JsonData == nil { + cmd.JsonData = simplejson.New() + } + ds := &m.DataSource{ OrgId: cmd.OrgId, Name: cmd.Name, @@ -142,6 +148,10 @@ func updateIsDefaultFlag(ds *m.DataSource, sess *DBSession) error { func UpdateDataSource(cmd *m.UpdateDataSourceCommand) error { return inTransaction(func(sess *DBSession) error { + if cmd.JsonData == nil { + cmd.JsonData = simplejson.New() + } + ds := &m.DataSource{ Id: cmd.Id, OrgId: cmd.OrgId, diff --git a/pkg/services/sqlstore/migrations/datasource_mig.go b/pkg/services/sqlstore/migrations/datasource_mig.go index fc617be72a1..54d86d34dba 100644 --- a/pkg/services/sqlstore/migrations/datasource_mig.go +++ b/pkg/services/sqlstore/migrations/datasource_mig.go @@ -130,4 +130,7 @@ func addDataSourceMigration(mg *Migrator) { const migrateLoggingToLoki = `UPDATE data_source SET type = 'loki' WHERE type = 'logging'` mg.AddMigration("Migrate logging ds to loki ds", NewRawSqlMigration(migrateLoggingToLoki)) + + const setEmptyJSONWhereNullJSON = `UPDATE data_source SET json_data = '{}' WHERE json_data is null` + mg.AddMigration("Update json_data with nulls", NewRawSqlMigration(setEmptyJSONWhereNullJSON)) } From 27dc3586b1a7565b588d2e297aa6c286c8c8b602 Mon Sep 17 00:00:00 2001 From: bergquist Date: Sat, 2 Mar 2019 21:27:09 +0100 Subject: [PATCH 13/48] changelog: adds note about closing #14239 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd16d06b81a..a458a07a76e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ### Bug Fixes * **Api**: Invalid org invite code [#10506](https://github.com/grafana/grafana/issues/10506) +* **Datasource**: Handles nil jsondata field gracefully [#14239](https://github.com/grafana/grafana/issues/14239) # 6.0.1 (unreleased) From a9ca8e9dec8243eb077ab8c9a524e525ff565fab Mon Sep 17 00:00:00 2001 From: Peter Holmberg Date: Sat, 2 Mar 2019 13:51:55 -0800 Subject: [PATCH 14/48] fix --- packages/grafana-ui/src/utils/valueFormats/categories.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grafana-ui/src/utils/valueFormats/categories.ts b/packages/grafana-ui/src/utils/valueFormats/categories.ts index e127285b473..806da582bb3 100644 --- a/packages/grafana-ui/src/utils/valueFormats/categories.ts +++ b/packages/grafana-ui/src/utils/valueFormats/categories.ts @@ -125,7 +125,7 @@ export const getCategories = (): ValueFormatCategory[] => [ { name: 'Data (Metric)', formats: [ - { name: 'bits', id: 'decbits', fn: decimalSIPrefix('d') }, + { name: 'bits', id: 'decbits', fn: decimalSIPrefix('b') }, { name: 'bytes', id: 'decbytes', fn: decimalSIPrefix('B') }, { name: 'kilobytes', id: 'deckbytes', fn: decimalSIPrefix('B', 1) }, { name: 'megabytes', id: 'decmbytes', fn: decimalSIPrefix('B', 2) }, From 6fd6f893aa5b98ea92f0e05f91311f5e5ee1d709 Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Mon, 4 Mar 2019 00:38:19 -0800 Subject: [PATCH 15/48] new stable docs version --- docs/versions.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/versions.json b/docs/versions.json index b1e447d5aa0..d1eab9afa51 100644 --- a/docs/versions.json +++ b/docs/versions.json @@ -1,5 +1,6 @@ [ - { "version": "v5.4", "path": "/", "archived": false, "current": true }, + { "version": "v6.0", "path": "/", "archived": false, "current": true }, + { "version": "v5.4", "path": "/v5.4", "archived": true }, { "version": "v5.3", "path": "/v5.3", "archived": true }, { "version": "v5.2", "path": "/v5.2", "archived": true }, { "version": "v5.1", "path": "/v5.1", "archived": true }, From 25b09168ebeb9678589a6396cc42437958a398dc Mon Sep 17 00:00:00 2001 From: parry <45209+thatsparesh@users.noreply.github.com> Date: Mon, 4 Mar 2019 02:56:47 -0600 Subject: [PATCH 16/48] Don't mutate seriesList parameter in mergeSeriesByTime (#15619) * do not mutate seriesList in mergeSeriesByTime * extendedseriesList -> extendedDatapointsList * remove toString() from datapoints, since the value can be null --- public/app/core/specs/file_export.test.ts | 10 +++++++++ public/app/core/utils/file_export.ts | 27 ++++++++++++----------- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/public/app/core/specs/file_export.test.ts b/public/app/core/specs/file_export.test.ts index 98f5a5be742..9e2ff0a7ce1 100644 --- a/public/app/core/specs/file_export.test.ts +++ b/public/app/core/specs/file_export.test.ts @@ -60,6 +60,16 @@ describe('file_export', () => { expect(text).toBe(expectedText); }); + + it('should not modify series.datapoints', () => { + const expectedSeries1DataPoints = ctx.seriesList[0].datapoints.slice(); + const expectedSeries2DataPoints = ctx.seriesList[1].datapoints.slice(); + + fileExport.convertSeriesListToCsvColumns(ctx.seriesList, ctx.timeFormat); + + expect(expectedSeries1DataPoints).toEqual(ctx.seriesList[0].datapoints); + expect(expectedSeries2DataPoints).toEqual(ctx.seriesList[1].datapoints); + }); }); describe('when exporting table data to csv', () => { diff --git a/public/app/core/utils/file_export.ts b/public/app/core/utils/file_export.ts index 1f999da72a5..c59d646839f 100644 --- a/public/app/core/utils/file_export.ts +++ b/public/app/core/utils/file_export.ts @@ -88,18 +88,18 @@ export function convertSeriesListToCsvColumns(seriesList, dateTimeFormat = DEFAU ) ); // process data - seriesList = mergeSeriesByTime(seriesList); + const extendedDatapointsList = mergeSeriesByTime(seriesList); // make text - for (let i = 0; i < seriesList[0].datapoints.length; i += 1) { - const timestamp = moment(seriesList[0].datapoints[i][POINT_TIME_INDEX]).format(dateTimeFormat); + for (let i = 0; i < extendedDatapointsList[0].length; i += 1) { + const timestamp = moment(extendedDatapointsList[0][i][POINT_TIME_INDEX]).format(dateTimeFormat); text += formatRow( [timestamp].concat( - seriesList.map(series => { - return series.datapoints[i][POINT_VALUE_INDEX]; + extendedDatapointsList.map(datapoints => { + return datapoints[i][POINT_VALUE_INDEX]; }) ), - i < seriesList[0].datapoints.length - 1 + i < extendedDatapointsList[0].length - 1 ); } @@ -120,22 +120,23 @@ function mergeSeriesByTime(seriesList) { } timestamps = sortedUniq(timestamps.sort()); + const result = []; for (let i = 0; i < seriesList.length; i++) { const seriesPoints = seriesList[i].datapoints; const seriesTimestamps = seriesPoints.map(p => p[POINT_TIME_INDEX]); - const extendedSeries = []; - let pointIndex; + const extendedDatapoints = []; for (let j = 0; j < timestamps.length; j++) { - pointIndex = sortedIndexOf(seriesTimestamps, timestamps[j]); + const timestamp = timestamps[j]; + const pointIndex = sortedIndexOf(seriesTimestamps, timestamp); if (pointIndex !== -1) { - extendedSeries.push(seriesPoints[pointIndex]); + extendedDatapoints.push(seriesPoints[pointIndex]); } else { - extendedSeries.push([null, timestamps[j]]); + extendedDatapoints.push([null, timestamp]); } } - seriesList[i].datapoints = extendedSeries; + result.push(extendedDatapoints); } - return seriesList; + return result; } export function exportSeriesListToCsvColumns(seriesList, dateTimeFormat = DEFAULT_DATETIME_FORMAT, excel = false) { From 3a65e27e83eb0d28b82f6055df46d1a74271f644 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=A4ggmark?= Date: Mon, 4 Mar 2019 10:42:59 +0100 Subject: [PATCH 17/48] Fixes #15739 --- packages/grafana-ui/src/types/datasource.ts | 12 +++++++++++- public/app/features/dashboard/dashgrid/DataPanel.tsx | 5 ++++- .../app/features/dashboard/dashgrid/PanelChrome.tsx | 1 + .../dashboard/dashgrid/PanelHeader/PanelHeader.tsx | 3 ++- .../dashgrid/PanelHeader/PanelHeaderCorner.tsx | 5 +++-- public/app/features/dashboard/state/PanelModel.ts | 4 ++-- 6 files changed, 23 insertions(+), 7 deletions(-) diff --git a/packages/grafana-ui/src/types/datasource.ts b/packages/grafana-ui/src/types/datasource.ts index a34f39b59c6..79c5b22488d 100644 --- a/packages/grafana-ui/src/types/datasource.ts +++ b/packages/grafana-ui/src/types/datasource.ts @@ -39,6 +39,16 @@ export interface DataQueryError { statusText?: string; } +export interface ScopedVar { + text: any; + value: any; + [key: string]: any; +} + +export interface ScopedVars { + [key: string]: ScopedVar; +} + export interface DataQueryOptions { timezone: string; range: TimeRange; @@ -50,7 +60,7 @@ export interface DataQueryOptions { interval: string; intervalMs: number; maxDataPoints: number; - scopedVars: object; + scopedVars: ScopedVars; } export interface QueryFix { diff --git a/public/app/features/dashboard/dashgrid/DataPanel.tsx b/public/app/features/dashboard/dashgrid/DataPanel.tsx index 9718e150e2a..ae3486e40fe 100644 --- a/public/app/features/dashboard/dashgrid/DataPanel.tsx +++ b/public/app/features/dashboard/dashgrid/DataPanel.tsx @@ -15,6 +15,7 @@ import { TableData, TimeRange, TimeSeries, + ScopedVars, } from '@grafana/ui'; interface RenderProps { @@ -33,6 +34,7 @@ export interface Props { refreshCounter: number; minInterval?: string; maxDataPoints?: number; + scopedVars?: ScopedVars; children: (r: RenderProps) => JSX.Element; onDataResponse?: (data: DataQueryResponse) => void; onError: (message: string, error: DataQueryError) => void; @@ -95,6 +97,7 @@ export class DataPanel extends Component { timeRange, widthPixels, maxDataPoints, + scopedVars, onDataResponse, onError, } = this.props; @@ -127,7 +130,7 @@ export class DataPanel extends Component { intervalMs: intervalRes.intervalMs, targets: queries, maxDataPoints: maxDataPoints || widthPixels, - scopedVars: {}, + scopedVars: scopedVars || {}, cacheTimeout: null, }; diff --git a/public/app/features/dashboard/dashgrid/PanelChrome.tsx b/public/app/features/dashboard/dashgrid/PanelChrome.tsx index cb6d1529b94..16f8f0820bb 100644 --- a/public/app/features/dashboard/dashgrid/PanelChrome.tsx +++ b/public/app/features/dashboard/dashgrid/PanelChrome.tsx @@ -179,6 +179,7 @@ export class PanelChrome extends PureComponent { isVisible={this.isVisible} widthPixels={width} refreshCounter={refreshCounter} + scopedVars={panel.scopedVars} onDataResponse={this.onDataResponse} onError={this.onDataError} > diff --git a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeader.tsx b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeader.tsx index 0f6563836f0..a8a3560743f 100644 --- a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeader.tsx +++ b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeader.tsx @@ -1,6 +1,7 @@ import React, { Component } from 'react'; import classNames from 'classnames'; import { isEqual } from 'lodash'; +import { ScopedVars } from '@grafana/ui'; import PanelHeaderCorner from './PanelHeaderCorner'; import { PanelHeaderMenu } from './PanelHeaderMenu'; @@ -16,7 +17,7 @@ export interface Props { timeInfo: string; title?: string; description?: string; - scopedVars?: string; + scopedVars?: ScopedVars; links?: []; error?: string; isFullscreen: boolean; diff --git a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderCorner.tsx b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderCorner.tsx index 42b89bc1273..12f3b95ca21 100644 --- a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderCorner.tsx +++ b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderCorner.tsx @@ -1,6 +1,7 @@ import React, { Component } from 'react'; import Remarkable from 'remarkable'; -import { Tooltip } from '@grafana/ui'; +import { Tooltip, ScopedVars } from '@grafana/ui'; + import { PanelModel } from 'app/features/dashboard/state/PanelModel'; import templateSrv from 'app/features/templating/template_srv'; import { LinkSrv } from 'app/features/panel/panellinks/link_srv'; @@ -16,7 +17,7 @@ interface Props { panel: PanelModel; title?: string; description?: string; - scopedVars?: string; + scopedVars?: ScopedVars; links?: []; error?: string; } diff --git a/public/app/features/dashboard/state/PanelModel.ts b/public/app/features/dashboard/state/PanelModel.ts index ac3722d61c2..c0739b6d8bc 100644 --- a/public/app/features/dashboard/state/PanelModel.ts +++ b/public/app/features/dashboard/state/PanelModel.ts @@ -3,7 +3,7 @@ import _ from 'lodash'; // Types import { Emitter } from 'app/core/utils/emitter'; -import { DataQuery, TimeSeries, Threshold } from '@grafana/ui'; +import { DataQuery, TimeSeries, Threshold, ScopedVars } from '@grafana/ui'; import { TableData } from '@grafana/ui/src'; export interface GridPos { @@ -71,7 +71,7 @@ export class PanelModel { type: string; title: string; alert?: any; - scopedVars?: any; + scopedVars?: ScopedVars; repeat?: string; repeatIteration?: number; repeatPanelId?: number; From 818ccb572e703ad23b5e3917d2ddbf9f7fac1a86 Mon Sep 17 00:00:00 2001 From: Leonard Gram Date: Mon, 4 Mar 2019 11:22:30 +0100 Subject: [PATCH 18/48] devenv: fixes incorrect influxdb config. [skip ci] --- devenv/docker/blocks/influxdb/docker-compose.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/devenv/docker/blocks/influxdb/docker-compose.yaml b/devenv/docker/blocks/influxdb/docker-compose.yaml index e3ca81ced22..f34a7ef4978 100644 --- a/devenv/docker/blocks/influxdb/docker-compose.yaml +++ b/devenv/docker/blocks/influxdb/docker-compose.yaml @@ -1,5 +1,3 @@ -version: '2' -services: influxdb: image: influxdb:latest container_name: influxdb From cc40a515be3362e5fd213f794d05579e446aec18 Mon Sep 17 00:00:00 2001 From: Johannes Schill Date: Mon, 4 Mar 2019 13:46:10 +0100 Subject: [PATCH 19/48] fix: When in tv-mode, autofitpanel should not take space from the navbar #15650 --- public/app/features/dashboard/state/DashboardModel.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/app/features/dashboard/state/DashboardModel.ts b/public/app/features/dashboard/state/DashboardModel.ts index 17af2dbd801..2a445c9a58c 100644 --- a/public/app/features/dashboard/state/DashboardModel.ts +++ b/public/app/features/dashboard/state/DashboardModel.ts @@ -887,8 +887,8 @@ export class DashboardModel { } // add back navbar height - if (kioskMode === KIOSK_MODE_TV) { - visibleHeight += 55; + if (kioskMode && kioskMode !== KIOSK_MODE_TV) { + visibleHeight += navbarHeight; } const visibleGridHeight = Math.floor(visibleHeight / (GRID_CELL_HEIGHT + GRID_CELL_VMARGIN)); From ae23773db3db95cb5c84fb4b56bb78cb9cc8290b Mon Sep 17 00:00:00 2001 From: "Bryan T. Richardson" Date: Sun, 27 Jan 2019 14:48:40 -0700 Subject: [PATCH 20/48] Added MaximumUsedTransactionIDs metric to list of AWS RDS metrics. --- pkg/tsdb/cloudwatch/metric_find_query.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/tsdb/cloudwatch/metric_find_query.go b/pkg/tsdb/cloudwatch/metric_find_query.go index cb95d39d82d..83fafbd87b5 100644 --- a/pkg/tsdb/cloudwatch/metric_find_query.go +++ b/pkg/tsdb/cloudwatch/metric_find_query.go @@ -101,7 +101,7 @@ func init() { "AWS/NetworkELB": {"ActiveFlowCount", "ConsumedLCUs", "HealthyHostCount", "NewFlowCount", "ProcessedBytes", "TCP_Client_Reset_Count", "TCP_ELB_Reset_Count", "TCP_Target_Reset_Count", "UnHealthyHostCount"}, "AWS/OpsWorks": {"cpu_idle", "cpu_nice", "cpu_system", "cpu_user", "cpu_waitio", "load_1", "load_5", "load_15", "memory_buffers", "memory_cached", "memory_free", "memory_swap", "memory_total", "memory_used", "procs"}, "AWS/Redshift": {"CPUUtilization", "DatabaseConnections", "HealthStatus", "MaintenanceMode", "NetworkReceiveThroughput", "NetworkTransmitThroughput", "PercentageDiskSpaceUsed", "QueriesCompletedPerSecond", "QueryDuration", "QueryRuntimeBreakdown", "ReadIOPS", "ReadLatency", "ReadThroughput", "WLMQueriesCompletedPerSecond", "WLMQueryDuration", "WLMQueueLength", "WriteIOPS", "WriteLatency", "WriteThroughput"}, - "AWS/RDS": {"ActiveTransactions", "AuroraBinlogReplicaLag", "AuroraReplicaLag", "AuroraReplicaLagMaximum", "AuroraReplicaLagMinimum", "BinLogDiskUsage", "BlockedTransactions", "BufferCacheHitRatio", "BurstBalance", "CommitLatency", "CommitThroughput", "BinLogDiskUsage", "CPUCreditBalance", "CPUCreditUsage", "CPUUtilization", "DatabaseConnections", "DDLLatency", "DDLThroughput", "Deadlocks", "DeleteLatency", "DeleteThroughput", "DiskQueueDepth", "DMLLatency", "DMLThroughput", "EngineUptime", "FailedSqlStatements", "FreeableMemory", "FreeLocalStorage", "FreeStorageSpace", "InsertLatency", "InsertThroughput", "LoginFailures", "NetworkReceiveThroughput", "NetworkTransmitThroughput", "NetworkThroughput", "Queries", "ReadIOPS", "ReadLatency", "ReadThroughput", "ReplicaLag", "ResultSetCacheHitRatio", "SelectLatency", "SelectThroughput", "ServerlessDatabaseCapacity", "SwapUsage", "TotalConnections", "UpdateLatency", "UpdateThroughput", "VolumeBytesUsed", "VolumeReadIOPS", "VolumeWriteIOPS", "WriteIOPS", "WriteLatency", "WriteThroughput"}, + "AWS/RDS": {"ActiveTransactions", "AuroraBinlogReplicaLag", "AuroraReplicaLag", "AuroraReplicaLagMaximum", "AuroraReplicaLagMinimum", "BinLogDiskUsage", "BlockedTransactions", "BufferCacheHitRatio", "BurstBalance", "CommitLatency", "CommitThroughput", "BinLogDiskUsage", "CPUCreditBalance", "CPUCreditUsage", "CPUUtilization", "DatabaseConnections", "DDLLatency", "DDLThroughput", "Deadlocks", "DeleteLatency", "DeleteThroughput", "DiskQueueDepth", "DMLLatency", "DMLThroughput", "EngineUptime", "FailedSqlStatements", "FreeableMemory", "FreeLocalStorage", "FreeStorageSpace", "InsertLatency", "InsertThroughput", "LoginFailures", "MaximumUsedTransactionIDs", "NetworkReceiveThroughput", "NetworkTransmitThroughput", "NetworkThroughput", "Queries", "ReadIOPS", "ReadLatency", "ReadThroughput", "ReplicaLag", "ResultSetCacheHitRatio", "SelectLatency", "SelectThroughput", "ServerlessDatabaseCapacity", "SwapUsage", "TotalConnections", "UpdateLatency", "UpdateThroughput", "VolumeBytesUsed", "VolumeReadIOPS", "VolumeWriteIOPS", "WriteIOPS", "WriteLatency", "WriteThroughput"}, "AWS/Route53": {"ChildHealthCheckHealthyCount", "HealthCheckStatus", "HealthCheckPercentageHealthy", "ConnectionTime", "SSLHandshakeTime", "TimeToFirstByte"}, "AWS/S3": {"BucketSizeBytes", "NumberOfObjects", "AllRequests", "GetRequests", "PutRequests", "DeleteRequests", "HeadRequests", "PostRequests", "ListRequests", "BytesDownloaded", "BytesUploaded", "4xxErrors", "5xxErrors", "FirstByteLatency", "TotalRequestLatency"}, "AWS/SES": {"Bounce", "Complaint", "Delivery", "Reject", "Send", "Reputation.BounceRate", "Reputation.ComplaintRate"}, From a29b99b96b1e668640c7d9ce10b78f55e74fba6e Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Mon, 4 Mar 2019 15:48:07 +0100 Subject: [PATCH 21/48] only editor/admin should have access to alert list/notifications pages --- pkg/api/api.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/api/api.go b/pkg/api/api.go index 6da127fb550..82f660a2bd6 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -77,8 +77,8 @@ func (hs *HTTPServer) registerRoutes() { r.Get("/playlists/", reqSignedIn, hs.Index) r.Get("/playlists/*", reqSignedIn, hs.Index) - r.Get("/alerting/", reqSignedIn, hs.Index) - r.Get("/alerting/*", reqSignedIn, hs.Index) + r.Get("/alerting/", reqEditorRole, hs.Index) + r.Get("/alerting/*", reqEditorRole, hs.Index) // sign up r.Get("/signup", hs.Index) From 5638c67be89df2fa72b9821f89d7af15affddf86 Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Mon, 4 Mar 2019 15:51:18 +0100 Subject: [PATCH 22/48] org admins should only be able to access org admin pages --- pkg/api/api.go | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/pkg/api/api.go b/pkg/api/api.go index 82f660a2bd6..c80129eac6f 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -33,17 +33,17 @@ func (hs *HTTPServer) registerRoutes() { r.Get("/profile/", reqSignedIn, hs.Index) r.Get("/profile/password", reqSignedIn, hs.Index) r.Get("/profile/switch-org/:id", reqSignedIn, hs.ChangeActiveOrgAndRedirectToHome) - r.Get("/org/", reqSignedIn, hs.Index) - r.Get("/org/new", reqSignedIn, hs.Index) - r.Get("/datasources/", reqSignedIn, hs.Index) - r.Get("/datasources/new", reqSignedIn, hs.Index) - r.Get("/datasources/edit/*", reqSignedIn, hs.Index) - r.Get("/org/users", reqSignedIn, hs.Index) - r.Get("/org/users/new", reqSignedIn, hs.Index) - r.Get("/org/users/invite", reqSignedIn, hs.Index) - r.Get("/org/teams", reqSignedIn, hs.Index) - r.Get("/org/teams/*", reqSignedIn, hs.Index) - r.Get("/org/apikeys/", reqSignedIn, hs.Index) + r.Get("/org/", reqOrgAdmin, hs.Index) + r.Get("/org/new", reqGrafanaAdmin, hs.Index) + r.Get("/datasources/", reqOrgAdmin, hs.Index) + r.Get("/datasources/new", reqOrgAdmin, hs.Index) + r.Get("/datasources/edit/*", reqOrgAdmin, hs.Index) + r.Get("/org/users", reqOrgAdmin, hs.Index) + r.Get("/org/users/new", reqOrgAdmin, hs.Index) + r.Get("/org/users/invite", reqOrgAdmin, hs.Index) + r.Get("/org/teams", reqOrgAdmin, hs.Index) + r.Get("/org/teams/*", reqOrgAdmin, hs.Index) + r.Get("/org/apikeys/", reqOrgAdmin, hs.Index) r.Get("/dashboard/import/", reqSignedIn, hs.Index) r.Get("/configuration", reqGrafanaAdmin, hs.Index) r.Get("/admin", reqGrafanaAdmin, hs.Index) From c36047674aa90803d550445e32c035000be32fef Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Mon, 4 Mar 2019 16:07:51 +0100 Subject: [PATCH 23/48] changelog: add notes about closing #15077 --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a458a07a76e..8095dd1e3be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ - # 6.1.0 (unreleased) +### Minor +* **Cloudwatch**: Add AWS RDS MaximumUsedTransactionIDs metric [#15077](https://github.com/grafana/grafana/pull/15077), thx [@activeshadow](https://github.com/activeshadow) + ### Bug Fixes * **Api**: Invalid org invite code [#10506](https://github.com/grafana/grafana/issues/10506) * **Datasource**: Handles nil jsondata field gracefully [#14239](https://github.com/grafana/grafana/issues/14239) From 92ec8757d3f20e5b5f0d9d530028577cbc4fa94f Mon Sep 17 00:00:00 2001 From: Johannes Schill Date: Mon, 4 Mar 2019 16:33:00 +0100 Subject: [PATCH 24/48] fix: Kiosk mode should have &kiosk appended to the url #15765 --- public/app/routes/GrafanaCtrl.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/public/app/routes/GrafanaCtrl.ts b/public/app/routes/GrafanaCtrl.ts index d327bc0cf7d..479c5e77f3d 100644 --- a/public/app/routes/GrafanaCtrl.ts +++ b/public/app/routes/GrafanaCtrl.ts @@ -75,7 +75,7 @@ export class GrafanaCtrl { } } -function setViewModeBodyClass(body, mode: KioskUrlValue, sidemenuOpen: boolean) { +function setViewModeBodyClass(body: JQuery, mode: KioskUrlValue, sidemenuOpen: boolean) { body.removeClass('view-mode--tv'); body.removeClass('view-mode--kiosk'); body.removeClass('view-mode--inactive'); @@ -174,8 +174,8 @@ export function grafanaAppDirective(playlistSrv, contextSrv, $timeout, $rootScop }); // handle kiosk mode - appEvents.on('toggle-kiosk-mode', options => { - const search = $location.search(); + appEvents.on('toggle-kiosk-mode', (options: { exit?: boolean }) => { + const search: { kiosk?: KioskUrlValue } = $location.search(); if (options && options.exit) { search.kiosk = '1'; @@ -197,7 +197,7 @@ export function grafanaAppDirective(playlistSrv, contextSrv, $timeout, $rootScop } } - $location.search(search); + $timeout(() => $location.search(search)); setViewModeBodyClass(body, search.kiosk, sidemenuOpen); }); From a6056ba565b6f8ddd20c287cc498b24405600d4b Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Mon, 4 Mar 2019 17:38:27 +0100 Subject: [PATCH 25/48] changelog: add notes about closing #15765 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8095dd1e3be..28da1ff05ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ ### Bug Fixes * **Metrics**: Fixes broken usagestats metrics for /metrics [#15651](https://github.com/grafana/grafana/issues/15651) +* **Dashboard**: Fixes kiosk mode should have &kiosk appended to the url [#15765](https://github.com/grafana/grafana/issues/15765) # 6.0.0 stable (2019-02-25) From 989147a1ce1b076386735d6a1238ca067fd0adde Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Mon, 4 Mar 2019 17:47:16 +0100 Subject: [PATCH 26/48] changelog: add notes about closing #15650 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 28da1ff05ef..c2a9760dcd5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ ### Bug Fixes * **Metrics**: Fixes broken usagestats metrics for /metrics [#15651](https://github.com/grafana/grafana/issues/15651) * **Dashboard**: Fixes kiosk mode should have &kiosk appended to the url [#15765](https://github.com/grafana/grafana/issues/15765) +* **Dashboard**: Fixes kiosk=tv mode with autofitpanels should respect header [#15650](https://github.com/grafana/grafana/issues/15650) # 6.0.0 stable (2019-02-25) From 77d709d9dff5e2bb200b7c5d705eda25ddf72124 Mon Sep 17 00:00:00 2001 From: ryan Date: Mon, 4 Mar 2019 11:21:05 -0800 Subject: [PATCH 27/48] use updateOptions rather than onChange --- packages/grafana-ui/src/types/panel.ts | 2 +- .../dashboard/panel_editor/VisualizationTab.tsx | 2 +- public/app/plugins/panel/gauge/GaugeOptionsBox.tsx | 8 ++++---- public/app/plugins/panel/gauge/GaugePanelEditor.tsx | 10 +++++----- public/app/plugins/panel/graph2/GraphPanelEditor.tsx | 6 +++--- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/grafana-ui/src/types/panel.ts b/packages/grafana-ui/src/types/panel.ts index 2da48b0fec6..0cd4bb8a1a4 100644 --- a/packages/grafana-ui/src/types/panel.ts +++ b/packages/grafana-ui/src/types/panel.ts @@ -22,7 +22,7 @@ export interface PanelData { export interface PanelEditorProps { options: T; - onChange: (options: T) => void; + updateOptions: (options: T) => void; } export class ReactPanelPlugin { diff --git a/public/app/features/dashboard/panel_editor/VisualizationTab.tsx b/public/app/features/dashboard/panel_editor/VisualizationTab.tsx index 8a904961a4f..41fc5988256 100644 --- a/public/app/features/dashboard/panel_editor/VisualizationTab.tsx +++ b/public/app/features/dashboard/panel_editor/VisualizationTab.tsx @@ -66,7 +66,7 @@ export class VisualizationTab extends PureComponent { const PanelEditor = plugin.exports.reactPanel.editor; if (PanelEditor) { - return ; + return ; } } diff --git a/public/app/plugins/panel/gauge/GaugeOptionsBox.tsx b/public/app/plugins/panel/gauge/GaugeOptionsBox.tsx index b5d6acca806..ea2f10f4629 100644 --- a/public/app/plugins/panel/gauge/GaugeOptionsBox.tsx +++ b/public/app/plugins/panel/gauge/GaugeOptionsBox.tsx @@ -10,14 +10,14 @@ import { GaugeOptions } from './types'; export class GaugeOptionsBox extends PureComponent> { onToggleThresholdLabels = () => - this.props.onChange({ ...this.props.options, showThresholdLabels: !this.props.options.showThresholdLabels }); + this.props.updateOptions({ ...this.props.options, showThresholdLabels: !this.props.options.showThresholdLabels }); onToggleThresholdMarkers = () => - this.props.onChange({ ...this.props.options, showThresholdMarkers: !this.props.options.showThresholdMarkers }); + this.props.updateOptions({ ...this.props.options, showThresholdMarkers: !this.props.options.showThresholdMarkers }); - onMinValueChange = ({ target }) => this.props.onChange({ ...this.props.options, minValue: target.value }); + onMinValueChange = ({ target }) => this.props.updateOptions({ ...this.props.options, minValue: target.value }); - onMaxValueChange = ({ target }) => this.props.onChange({ ...this.props.options, maxValue: target.value }); + onMaxValueChange = ({ target }) => this.props.updateOptions({ ...this.props.options, maxValue: target.value }); render() { const { options } = this.props; diff --git a/public/app/plugins/panel/gauge/GaugePanelEditor.tsx b/public/app/plugins/panel/gauge/GaugePanelEditor.tsx index 63031f9d895..0109de33fc5 100644 --- a/public/app/plugins/panel/gauge/GaugePanelEditor.tsx +++ b/public/app/plugins/panel/gauge/GaugePanelEditor.tsx @@ -14,31 +14,31 @@ import { GaugeOptions, SingleStatValueOptions } from './types'; export class GaugePanelEditor extends PureComponent> { onThresholdsChanged = (thresholds: Threshold[]) => - this.props.onChange({ + this.props.updateOptions({ ...this.props.options, thresholds, }); onValueMappingsChanged = (valueMappings: ValueMapping[]) => - this.props.onChange({ + this.props.updateOptions({ ...this.props.options, valueMappings, }); onValueOptionsChanged = (valueOptions: SingleStatValueOptions) => - this.props.onChange({ + this.props.updateOptions({ ...this.props.options, valueOptions, }); render() { - const { onChange, options } = this.props; + const { updateOptions, options } = this.props; return ( <> - + diff --git a/public/app/plugins/panel/graph2/GraphPanelEditor.tsx b/public/app/plugins/panel/graph2/GraphPanelEditor.tsx index 80b17ccd5c4..9141324274a 100644 --- a/public/app/plugins/panel/graph2/GraphPanelEditor.tsx +++ b/public/app/plugins/panel/graph2/GraphPanelEditor.tsx @@ -8,15 +8,15 @@ import { Options } from './types'; export class GraphPanelEditor extends PureComponent> { onToggleLines = () => { - this.props.onChange({ ...this.props.options, showLines: !this.props.options.showLines }); + this.props.updateOptions({ ...this.props.options, showLines: !this.props.options.showLines }); }; onToggleBars = () => { - this.props.onChange({ ...this.props.options, showBars: !this.props.options.showBars }); + this.props.updateOptions({ ...this.props.options, showBars: !this.props.options.showBars }); }; onTogglePoints = () => { - this.props.onChange({ ...this.props.options, showPoints: !this.props.options.showPoints }); + this.props.updateOptions({ ...this.props.options, showPoints: !this.props.options.showPoints }); }; render() { From 251008f590c1e89672a41aa521851074d79fdeda Mon Sep 17 00:00:00 2001 From: ryan Date: Mon, 4 Mar 2019 11:44:38 -0800 Subject: [PATCH 28/48] use replaceVariables rather than onInterpolate --- packages/grafana-ui/src/types/panel.ts | 2 +- public/app/features/dashboard/dashgrid/PanelChrome.tsx | 4 ++-- public/app/plugins/panel/gauge/GaugePanel.tsx | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/grafana-ui/src/types/panel.ts b/packages/grafana-ui/src/types/panel.ts index 2da48b0fec6..6cc56c9287d 100644 --- a/packages/grafana-ui/src/types/panel.ts +++ b/packages/grafana-ui/src/types/panel.ts @@ -12,7 +12,7 @@ export interface PanelProps { renderCounter: number; width: number; height: number; - onInterpolate: InterpolateFunction; + replaceVariables: InterpolateFunction; } export interface PanelData { diff --git a/public/app/features/dashboard/dashgrid/PanelChrome.tsx b/public/app/features/dashboard/dashgrid/PanelChrome.tsx index 16f8f0820bb..80ce2f39b70 100644 --- a/public/app/features/dashboard/dashgrid/PanelChrome.tsx +++ b/public/app/features/dashboard/dashgrid/PanelChrome.tsx @@ -85,7 +85,7 @@ export class PanelChrome extends PureComponent { }); }; - onInterpolate = (value: string, format?: string) => { + replaceVariables = (value: string, format?: string) => { return templateSrv.replace(value, this.props.panel.scopedVars, format); }; @@ -158,7 +158,7 @@ export class PanelChrome extends PureComponent { width={width - 2 * variables.panelhorizontalpadding} height={height - PANEL_HEADER_HEIGHT - variables.panelverticalpadding} renderCounter={renderCounter} - onInterpolate={this.onInterpolate} + replaceVariables={this.replaceVariables} />
); diff --git a/public/app/plugins/panel/gauge/GaugePanel.tsx b/public/app/plugins/panel/gauge/GaugePanel.tsx index e7e60a7c417..2a42e31b9ab 100644 --- a/public/app/plugins/panel/gauge/GaugePanel.tsx +++ b/public/app/plugins/panel/gauge/GaugePanel.tsx @@ -15,11 +15,11 @@ interface Props extends PanelProps {} export class GaugePanel extends PureComponent { render() { - const { panelData, width, height, onInterpolate, options } = this.props; + const { panelData, width, height, replaceVariables, options } = this.props; const { valueOptions } = options; - const prefix = onInterpolate(valueOptions.prefix); - const suffix = onInterpolate(valueOptions.suffix); + const prefix = replaceVariables(valueOptions.prefix); + const suffix = replaceVariables(valueOptions.suffix); let value: TimeSeriesValue; if (panelData.timeSeries) { From 3d165284590d25352b0f9969368639859e04e5c6 Mon Sep 17 00:00:00 2001 From: ryan Date: Mon, 4 Mar 2019 12:35:24 -0800 Subject: [PATCH 29/48] use onOptionsChange --- packages/grafana-ui/src/types/panel.ts | 2 +- .../dashboard/panel_editor/VisualizationTab.tsx | 2 +- public/app/plugins/panel/gauge/GaugeOptionsBox.tsx | 11 +++++++---- public/app/plugins/panel/gauge/GaugePanelEditor.tsx | 10 +++++----- public/app/plugins/panel/graph2/GraphPanelEditor.tsx | 6 +++--- 5 files changed, 17 insertions(+), 14 deletions(-) diff --git a/packages/grafana-ui/src/types/panel.ts b/packages/grafana-ui/src/types/panel.ts index 0cd4bb8a1a4..81068083803 100644 --- a/packages/grafana-ui/src/types/panel.ts +++ b/packages/grafana-ui/src/types/panel.ts @@ -22,7 +22,7 @@ export interface PanelData { export interface PanelEditorProps { options: T; - updateOptions: (options: T) => void; + onOptionsChange: (options: T) => void; } export class ReactPanelPlugin { diff --git a/public/app/features/dashboard/panel_editor/VisualizationTab.tsx b/public/app/features/dashboard/panel_editor/VisualizationTab.tsx index 41fc5988256..5330baf1be6 100644 --- a/public/app/features/dashboard/panel_editor/VisualizationTab.tsx +++ b/public/app/features/dashboard/panel_editor/VisualizationTab.tsx @@ -66,7 +66,7 @@ export class VisualizationTab extends PureComponent { const PanelEditor = plugin.exports.reactPanel.editor; if (PanelEditor) { - return ; + return ; } } diff --git a/public/app/plugins/panel/gauge/GaugeOptionsBox.tsx b/public/app/plugins/panel/gauge/GaugeOptionsBox.tsx index ea2f10f4629..bb3043ddd8b 100644 --- a/public/app/plugins/panel/gauge/GaugeOptionsBox.tsx +++ b/public/app/plugins/panel/gauge/GaugeOptionsBox.tsx @@ -10,14 +10,17 @@ import { GaugeOptions } from './types'; export class GaugeOptionsBox extends PureComponent> { onToggleThresholdLabels = () => - this.props.updateOptions({ ...this.props.options, showThresholdLabels: !this.props.options.showThresholdLabels }); + this.props.onOptionsChange({ ...this.props.options, showThresholdLabels: !this.props.options.showThresholdLabels }); onToggleThresholdMarkers = () => - this.props.updateOptions({ ...this.props.options, showThresholdMarkers: !this.props.options.showThresholdMarkers }); + this.props.onOptionsChange({ + ...this.props.options, + showThresholdMarkers: !this.props.options.showThresholdMarkers, + }); - onMinValueChange = ({ target }) => this.props.updateOptions({ ...this.props.options, minValue: target.value }); + onMinValueChange = ({ target }) => this.props.onOptionsChange({ ...this.props.options, minValue: target.value }); - onMaxValueChange = ({ target }) => this.props.updateOptions({ ...this.props.options, maxValue: target.value }); + onMaxValueChange = ({ target }) => this.props.onOptionsChange({ ...this.props.options, maxValue: target.value }); render() { const { options } = this.props; diff --git a/public/app/plugins/panel/gauge/GaugePanelEditor.tsx b/public/app/plugins/panel/gauge/GaugePanelEditor.tsx index 0109de33fc5..f226be7328c 100644 --- a/public/app/plugins/panel/gauge/GaugePanelEditor.tsx +++ b/public/app/plugins/panel/gauge/GaugePanelEditor.tsx @@ -14,31 +14,31 @@ import { GaugeOptions, SingleStatValueOptions } from './types'; export class GaugePanelEditor extends PureComponent> { onThresholdsChanged = (thresholds: Threshold[]) => - this.props.updateOptions({ + this.props.onOptionsChange({ ...this.props.options, thresholds, }); onValueMappingsChanged = (valueMappings: ValueMapping[]) => - this.props.updateOptions({ + this.props.onOptionsChange({ ...this.props.options, valueMappings, }); onValueOptionsChanged = (valueOptions: SingleStatValueOptions) => - this.props.updateOptions({ + this.props.onOptionsChange({ ...this.props.options, valueOptions, }); render() { - const { updateOptions, options } = this.props; + const { onOptionsChange, options } = this.props; return ( <> - + diff --git a/public/app/plugins/panel/graph2/GraphPanelEditor.tsx b/public/app/plugins/panel/graph2/GraphPanelEditor.tsx index 9141324274a..1a64290759c 100644 --- a/public/app/plugins/panel/graph2/GraphPanelEditor.tsx +++ b/public/app/plugins/panel/graph2/GraphPanelEditor.tsx @@ -8,15 +8,15 @@ import { Options } from './types'; export class GraphPanelEditor extends PureComponent> { onToggleLines = () => { - this.props.updateOptions({ ...this.props.options, showLines: !this.props.options.showLines }); + this.props.onOptionsChange({ ...this.props.options, showLines: !this.props.options.showLines }); }; onToggleBars = () => { - this.props.updateOptions({ ...this.props.options, showBars: !this.props.options.showBars }); + this.props.onOptionsChange({ ...this.props.options, showBars: !this.props.options.showBars }); }; onTogglePoints = () => { - this.props.updateOptions({ ...this.props.options, showPoints: !this.props.options.showPoints }); + this.props.onOptionsChange({ ...this.props.options, showPoints: !this.props.options.showPoints }); }; render() { From 8f9246dff0d5a9ccaafa42bef202a4a231b1f2a8 Mon Sep 17 00:00:00 2001 From: Julien Pivotto Date: Mon, 4 Mar 2019 23:17:33 +0100 Subject: [PATCH 30/48] Add #15752 in CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2a9760dcd5..c010a279c73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ ### Bug Fixes * **Api**: Invalid org invite code [#10506](https://github.com/grafana/grafana/issues/10506) * **Datasource**: Handles nil jsondata field gracefully [#14239](https://github.com/grafana/grafana/issues/14239) +* **Gauge**: Interpolate scoped variables in repeated gauges [#15732](https://github.com/grafana/grafana/pull/15752) # 6.0.1 (unreleased) From cee5f030dc8d9bdd1ea3b3b4837fadb626603d93 Mon Sep 17 00:00:00 2001 From: Dominik Prokop Date: Tue, 5 Mar 2019 07:35:45 +0100 Subject: [PATCH 31/48] Fixed url of back button in datasource edit page, when root_url configured (#15759) * Fixed url of back button in datasource edit page, when root_url configured * Update snapshots * Use app config directly in ButtonRow instead of passing datasources page URL via prop * Snapshots update --- public/app/features/datasources/settings/ButtonRow.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/public/app/features/datasources/settings/ButtonRow.tsx b/public/app/features/datasources/settings/ButtonRow.tsx index 9f633ee6bcf..5bae5e7f98d 100644 --- a/public/app/features/datasources/settings/ButtonRow.tsx +++ b/public/app/features/datasources/settings/ButtonRow.tsx @@ -1,4 +1,5 @@ import React, { FC } from 'react'; +import config from 'app/core/config'; export interface Props { isReadOnly: boolean; @@ -23,7 +24,7 @@ const ButtonRow: FC = ({ isReadOnly, onDelete, onSubmit, onTest }) => { - + Back
From 707d0e13bd081a741b700720316e929626888fb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 5 Mar 2019 09:22:26 +0100 Subject: [PATCH 32/48] Update frontend.md --- style_guides/frontend.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/style_guides/frontend.md b/style_guides/frontend.md index 8d0849506a3..4f4c5dd7a3b 100644 --- a/style_guides/frontend.md +++ b/style_guides/frontend.md @@ -21,7 +21,7 @@ Generally we follow the Airbnb [React Style Guide](https://github.com/airbnb/ja * Components and types that needs to be used by external plugins needs to go into @grafana/ui * Components should get their own folder under features/xxx/components - * Sub components can live in that component folders, so not small component needs their own folder + * Sub components can live in that component folders, so small component do not need their own folder * Place test next to their component file (same dir) * Mocks in __mocks__ dir * Test utils in __tests__ dir From 590450291af2c4c15593923115f8159a786cef7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 5 Mar 2019 09:23:04 +0100 Subject: [PATCH 33/48] Update frontend.md --- style_guides/frontend.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/style_guides/frontend.md b/style_guides/frontend.md index 4f4c5dd7a3b..caef4f711ef 100644 --- a/style_guides/frontend.md +++ b/style_guides/frontend.md @@ -22,9 +22,7 @@ Generally we follow the Airbnb [React Style Guide](https://github.com/airbnb/ja * Components and types that needs to be used by external plugins needs to go into @grafana/ui * Components should get their own folder under features/xxx/components * Sub components can live in that component folders, so small component do not need their own folder - * Place test next to their component file (same dir) - * Mocks in __mocks__ dir - * Test utils in __tests__ dir + * Place test next to their component file (same dir) * Component sass should live in the same folder as component code * State logic & domain models should live in features/xxx/state * Containers (pages) can live in feature root features/xxx From 8b1e25b50a5943b856127a5d01506d7917acf235 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Tue, 5 Mar 2019 09:32:02 +0100 Subject: [PATCH 34/48] utils: show string errors. Fixes #15782 --- public/app/core/utils/errors.test.ts | 55 ++++++++++++++++++++++++++++ public/app/core/utils/errors.ts | 2 +- 2 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 public/app/core/utils/errors.test.ts diff --git a/public/app/core/utils/errors.test.ts b/public/app/core/utils/errors.test.ts new file mode 100644 index 00000000000..a5783fe7204 --- /dev/null +++ b/public/app/core/utils/errors.test.ts @@ -0,0 +1,55 @@ +import { getMessageFromError } from 'app/core/utils/errors'; + +describe('errors functions', () => { + let message; + + describe('when getMessageFromError gets an error string', () => { + beforeEach(() => { + message = getMessageFromError('error string'); + }); + + it('should return the string', () => { + expect(message).toBe('error string'); + }); + }); + + describe('when getMessageFromError gets an error object with message field', () => { + beforeEach(() => { + message = getMessageFromError({ message: 'error string' }); + }); + + it('should return the message text', () => { + expect(message).toBe('error string'); + }); + }); + + describe('when getMessageFromError gets an error object with data.message field', () => { + beforeEach(() => { + message = getMessageFromError({ data: { message: 'error string' } }); + }); + + it('should return the message text', () => { + expect(message).toBe('error string'); + }); + }); + + describe('when getMessageFromError gets an error object with statusText field', () => { + beforeEach(() => { + message = getMessageFromError({ statusText: 'error string' }); + }); + + it('should return the statusText text', () => { + expect(message).toBe('error string'); + }); + }); + + describe('when getMessageFromError gets an error object', () => { + beforeEach(() => { + message = getMessageFromError({ customError: 'error string' }); + }); + + it('should return the stringified error', () => { + expect(message).toBe('{"customError":"error string"}'); + }); + }); +}); diff --git a/public/app/core/utils/errors.ts b/public/app/core/utils/errors.ts index 3f6f1cfbc8d..afdf5270ade 100644 --- a/public/app/core/utils/errors.ts +++ b/public/app/core/utils/errors.ts @@ -13,5 +13,5 @@ export function getMessageFromError(err: any): string | null { } } - return null; + return err; } From fde63fc1cf90059093fc9ad752667478e0765132 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 5 Mar 2019 10:47:52 +0100 Subject: [PATCH 35/48] Updated react select fork to 2.4.1 --- package.json | 2 +- yarn.lock | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 9e0b88804fd..ad08ddbf6f4 100644 --- a/package.json +++ b/package.json @@ -162,7 +162,7 @@ "license": "Apache-2.0", "dependencies": { "@babel/polyfill": "^7.0.0", - "@torkelo/react-select": "2.1.1", + "@torkelo/react-select": "2.4.1", "@types/reselect": "^2.2.0", "angular": "1.6.6", "angular-bindonce": "0.3.1", diff --git a/yarn.lock b/yarn.lock index 3d97ef64374..cec36884075 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1501,6 +1501,19 @@ react-input-autosize "^2.2.1" react-transition-group "^2.2.1" +"@torkelo/react-select@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@torkelo/react-select/-/react-select-2.4.1.tgz#fb7bcb8f7a12b3453bb817ca9a1294edecd1363b" + integrity sha512-x8798Y7WT4PSyNiEhk8JbsS5/EA+sxrObWkmfAnWNUJCDKoELWDCPrPBinRvITlCQYzLww5RaoNJutI5VBqKOQ== + dependencies: + classnames "^2.2.5" + emotion "^9.1.2" + memoize-one "^5.0.0" + prop-types "^15.6.0" + raf "^3.4.0" + react-input-autosize "^2.2.1" + react-transition-group "^2.2.1" + "@types/chalk@^2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@types/chalk/-/chalk-2.2.0.tgz#b7f6e446f4511029ee8e3f43075fb5b73fbaa0ba" @@ -11412,6 +11425,11 @@ memoize-one@^4.0.0: resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-4.1.0.tgz#a2387c58c03fff27ca390c31b764a79addf3f906" integrity sha512-2GApq0yI/b22J2j9rhbrAlsHb0Qcz+7yWxeLG8h+95sl1XPUgeLimQSOdur4Vw7cUhrBHwaUZxWFZueojqNRzA== +memoize-one@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.0.0.tgz#d55007dffefb8de7546659a1722a5d42e128286e" + integrity sha512-7g0+ejkOaI9w5x6LvQwmj68kUj6rxROywPSCqmclG/HBacmFnZqhVscQ8kovkn9FBCNJmOz6SY42+jnvZzDWdw== + memory-fs@^0.4.0, memory-fs@~0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" From 48570c627299e151ee5538230954cfe9777785d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=A4ggmark?= Date: Tue, 5 Mar 2019 10:49:45 +0100 Subject: [PATCH 36/48] Made sure that DataSourceOption displays value and fires onChange/onBlur events (#15757) * Fixed #15682 * fix: Add hideTimeOverride to state since we need to control the Switch * fix: Back the maxDataPoints change, we need to keep it as a string Co-authored-by:johannes.schill@polyester.se --- .../panel_editor/DataSourceOption.tsx | 17 +- .../dashboard/panel_editor/QueryOptions.tsx | 149 ++++++++++-------- 2 files changed, 93 insertions(+), 73 deletions(-) diff --git a/public/app/features/dashboard/panel_editor/DataSourceOption.tsx b/public/app/features/dashboard/panel_editor/DataSourceOption.tsx index 08285960805..a72eaae6ed9 100644 --- a/public/app/features/dashboard/panel_editor/DataSourceOption.tsx +++ b/public/app/features/dashboard/panel_editor/DataSourceOption.tsx @@ -1,16 +1,17 @@ -import React, { FC } from 'react'; +import React, { FC, ChangeEvent } from 'react'; import { FormLabel } from '@grafana/ui'; interface Props { label: string; placeholder?: string; - name?: string; - value?: string; - onChange?: (evt: any) => void; + name: string; + value: string; + onBlur: (event: ChangeEvent) => void; + onChange: (event: ChangeEvent) => void; tooltipInfo?: any; } -export const DataSourceOptions: FC = ({ label, placeholder, name, value, onChange, tooltipInfo }) => { +export const DataSourceOption: FC = ({ label, placeholder, name, value, onBlur, onChange, tooltipInfo }) => { return (
{label} @@ -20,10 +21,10 @@ export const DataSourceOptions: FC = ({ label, placeholder, name, value, placeholder={placeholder} name={name} spellCheck={false} - onBlur={evt => onChange(evt.target.value)} + onBlur={onBlur} + onChange={onChange} + value={value} />
); }; - -export default DataSourceOptions; diff --git a/public/app/features/dashboard/panel_editor/QueryOptions.tsx b/public/app/features/dashboard/panel_editor/QueryOptions.tsx index d203f3bc25f..8c59edf456d 100644 --- a/public/app/features/dashboard/panel_editor/QueryOptions.tsx +++ b/public/app/features/dashboard/panel_editor/QueryOptions.tsx @@ -1,5 +1,5 @@ // Libraries -import React, { PureComponent } from 'react'; +import React, { PureComponent, ChangeEvent, FocusEvent } from 'react'; // Utils import { isValidTimeSpan } from 'app/core/utils/rangeutil'; @@ -9,7 +9,7 @@ import { Switch } from '@grafana/ui'; import { Input } from 'app/core/components/Form'; import { EventsWithValidation } from 'app/core/components/Form/Input'; import { InputStatus } from 'app/core/components/Form/Input'; -import DataSourceOption from './DataSourceOption'; +import { DataSourceOption } from './DataSourceOption'; import { FormLabel } from '@grafana/ui'; // Types @@ -43,32 +43,79 @@ interface Props { interface State { relativeTime: string; timeShift: string; + cacheTimeout: string; + maxDataPoints: string; + interval: string; + hideTimeOverride: boolean; } export class QueryOptions extends PureComponent { + allOptions = { + cacheTimeout: { + label: 'Cache timeout', + placeholder: '60', + name: 'cacheTimeout', + tooltipInfo: ( + <> + If your time series store has a query cache this option can override the default cache timeout. Specify a + numeric value in seconds. + + ), + }, + maxDataPoints: { + label: 'Max data points', + placeholder: 'auto', + name: 'maxDataPoints', + tooltipInfo: ( + <> + The maximum data points the query should return. For graphs this is automatically set to one data point per + pixel. + + ), + }, + minInterval: { + label: 'Min time interval', + placeholder: '0', + name: 'minInterval', + panelKey: 'interval', + tooltipInfo: ( + <> + A lower limit for the auto group by time interval. Recommended to be set to write frequency, for example{' '} + 1m if your data is written every minute. Access auto interval via variable{' '} + $__interval for time range string and $__interval_ms for numeric variable that can + be used in math expressions. + + ), + }, + }; + constructor(props) { super(props); this.state = { relativeTime: props.panel.timeFrom || '', timeShift: props.panel.timeShift || '', + cacheTimeout: props.panel.cacheTimeout || '', + maxDataPoints: props.panel.maxDataPoints || '', + interval: props.panel.interval || '', + hideTimeOverride: props.panel.hideTimeOverride || false, }; } - onRelativeTimeChange = event => { + onRelativeTimeChange = (event: ChangeEvent) => { this.setState({ relativeTime: event.target.value, }); }; - onTimeShiftChange = event => { + onTimeShiftChange = (event: ChangeEvent) => { this.setState({ timeShift: event.target.value, }); }; - onOverrideTime = (evt, status: InputStatus) => { - const { value } = evt.target; + onOverrideTime = (event: FocusEvent, status: InputStatus) => { + const { value } = event.target; const { panel } = this.props; const emptyToNullValue = emptyToNull(value); if (status === InputStatus.Valid && panel.timeFrom !== emptyToNullValue) { @@ -77,8 +124,8 @@ export class QueryOptions extends PureComponent { } }; - onTimeShift = (evt, status: InputStatus) => { - const { value } = evt.target; + onTimeShift = (event: FocusEvent, status: InputStatus) => { + const { value } = event.target; const { panel } = this.props; const emptyToNullValue = emptyToNull(value); if (status === InputStatus.Valid && panel.timeShift !== emptyToNullValue) { @@ -89,77 +136,49 @@ export class QueryOptions extends PureComponent { onToggleTimeOverride = () => { const { panel } = this.props; - panel.hideTimeOverride = !panel.hideTimeOverride; + this.setState({ hideTimeOverride: !this.state.hideTimeOverride }, () => { + panel.hideTimeOverride = this.state.hideTimeOverride; + panel.refresh(); + }); + }; + + onDataSourceOptionBlur = (panelKey: string) => () => { + const { panel } = this.props; + + panel[panelKey] = this.state[panelKey]; panel.refresh(); }; - renderOptions() { - const { datasource, panel } = this.props; + onDataSourceOptionChange = (panelKey: string) => (event: ChangeEvent) => { + this.setState({ ...this.state, [panelKey]: event.target.value }); + }; + + renderOptions = () => { + const { datasource } = this.props; const { queryOptions } = datasource.meta; if (!queryOptions) { return null; } - const onChangeFn = (panelKey: string) => { - return (value: string | number) => { - panel[panelKey] = value; - panel.refresh(); - }; - }; - - const allOptions = { - cacheTimeout: { - label: 'Cache timeout', - placeholder: '60', - name: 'cacheTimeout', - value: panel.cacheTimeout, - tooltipInfo: ( - <> - If your time series store has a query cache this option can override the default cache timeout. Specify a - numeric value in seconds. - - ), - }, - maxDataPoints: { - label: 'Max data points', - placeholder: 'auto', - name: 'maxDataPoints', - value: panel.maxDataPoints, - tooltipInfo: ( - <> - The maximum data points the query should return. For graphs this is automatically set to one data point per - pixel. - - ), - }, - minInterval: { - label: 'Min time interval', - placeholder: '0', - name: 'minInterval', - value: panel.interval, - panelKey: 'interval', - tooltipInfo: ( - <> - A lower limit for the auto group by time interval. Recommended to be set to write frequency, for example{' '} - 1m if your data is written every minute. Access auto interval via variable{' '} - $__interval for time range string and $__interval_ms for numeric variable that can - be used in math expressions. - - ), - }, - }; - return Object.keys(queryOptions).map(key => { - const options = allOptions[key]; - return ; + const options = this.allOptions[key]; + const panelKey = options.panelKey || key; + return ( + + ); }); - } + }; render() { - const hideTimeOverride = this.props.panel.hideTimeOverride; + const { hideTimeOverride } = this.state; const { relativeTime, timeShift } = this.state; - return (
{this.renderOptions()} From a5455691b3443df74075d5ebf5919c4fd8a71feb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 5 Mar 2019 11:43:25 +0100 Subject: [PATCH 37/48] Hide time info switch when no time options are specified --- .../app/features/dashboard/panel_editor/QueryOptions.tsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/public/app/features/dashboard/panel_editor/QueryOptions.tsx b/public/app/features/dashboard/panel_editor/QueryOptions.tsx index 8c59edf456d..0d031cb12ba 100644 --- a/public/app/features/dashboard/panel_editor/QueryOptions.tsx +++ b/public/app/features/dashboard/panel_editor/QueryOptions.tsx @@ -210,10 +210,11 @@ export class QueryOptions extends PureComponent { value={timeShift} />
- -
- -
+ {(timeShift || relativeTime) && ( +
+ +
+ )} ); } From 978cdfba00e48aa3f02bdb18857bbb6ee5583ea4 Mon Sep 17 00:00:00 2001 From: Peter Holmberg Date: Tue, 5 Mar 2019 12:08:57 +0100 Subject: [PATCH 38/48] Wrapperd playlist controls in clickoutsidewrapper --- .../dashboard/components/DashNav/DashNav.tsx | 43 ++++++++++--------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/public/app/features/dashboard/components/DashNav/DashNav.tsx b/public/app/features/dashboard/components/DashNav/DashNav.tsx index 453c5d1f9ac..27ca8a28672 100644 --- a/public/app/features/dashboard/components/DashNav/DashNav.tsx +++ b/public/app/features/dashboard/components/DashNav/DashNav.tsx @@ -16,6 +16,7 @@ import { updateLocation } from 'app/core/actions'; // Types import { DashboardModel } from '../../state'; +import { ClickOutsideWrapper } from '../../../../core/components/ClickOutsideWrapper/ClickOutsideWrapper'; export interface Props { dashboard: DashboardModel; @@ -173,26 +174,28 @@ export class DashNav extends PureComponent { {this.renderDashboardTitleSearchButton()} {this.playlistSrv.isPlaying && ( -
- - - -
+ +
+ + + +
+
)}
From a158a192721c8f89a1be37aafada0ff51c11683a Mon Sep 17 00:00:00 2001 From: Peter Holmberg Date: Tue, 5 Mar 2019 12:10:20 +0100 Subject: [PATCH 39/48] reordered import --- public/app/features/dashboard/components/DashNav/DashNav.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/features/dashboard/components/DashNav/DashNav.tsx b/public/app/features/dashboard/components/DashNav/DashNav.tsx index 27ca8a28672..d2f22d7d010 100644 --- a/public/app/features/dashboard/components/DashNav/DashNav.tsx +++ b/public/app/features/dashboard/components/DashNav/DashNav.tsx @@ -8,6 +8,7 @@ import { appEvents } from 'app/core/app_events'; import { PlaylistSrv } from 'app/features/playlist/playlist_srv'; // Components +import { ClickOutsideWrapper } from 'app/core/components/ClickOutsideWrapper/ClickOutsideWrapper'; import { DashNavButton } from './DashNavButton'; import { Tooltip } from '@grafana/ui'; @@ -16,7 +17,6 @@ import { updateLocation } from 'app/core/actions'; // Types import { DashboardModel } from '../../state'; -import { ClickOutsideWrapper } from '../../../../core/components/ClickOutsideWrapper/ClickOutsideWrapper'; export interface Props { dashboard: DashboardModel; From e6a83bf0e1aba6577544736f5fdec4b5c8508842 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 5 Mar 2019 12:37:19 +0100 Subject: [PATCH 40/48] Fixed scrolling issue that caused scroll to be locked to the bottom of a long dashboard, fixes #15712 --- .../src/components/CustomScrollbar/CustomScrollbar.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/grafana-ui/src/components/CustomScrollbar/CustomScrollbar.tsx b/packages/grafana-ui/src/components/CustomScrollbar/CustomScrollbar.tsx index 61fc584c7ca..1bc1fd42792 100644 --- a/packages/grafana-ui/src/components/CustomScrollbar/CustomScrollbar.tsx +++ b/packages/grafana-ui/src/components/CustomScrollbar/CustomScrollbar.tsx @@ -42,11 +42,7 @@ export class CustomScrollbar extends Component { const ref = this.ref.current; if (ref && !isNil(this.props.scrollTop)) { - if (this.props.scrollTop > 10000) { - ref.scrollToBottom(); - } else { - ref.scrollTop(this.props.scrollTop); - } + ref.scrollTop(this.props.scrollTop); } } From a81d5486b096c77b4d39ee0483a0c127f4480881 Mon Sep 17 00:00:00 2001 From: Johannes Schill Date: Tue, 5 Mar 2019 12:41:01 +0100 Subject: [PATCH 41/48] Viewers with viewers_can_edit should be able to access /explore (#15787) * fix: Viewers with viewers_can_edit should be able to access /explore #15773 * refactoring initial PR a bit to simplify function and reduce duplication --- pkg/api/api.go | 2 +- pkg/middleware/auth.go | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/pkg/api/api.go b/pkg/api/api.go index c80129eac6f..81ea83eae61 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -73,7 +73,7 @@ func (hs *HTTPServer) registerRoutes() { r.Get("/dashboards/", reqSignedIn, hs.Index) r.Get("/dashboards/*", reqSignedIn, hs.Index) - r.Get("/explore", reqEditorRole, hs.Index) + r.Get("/explore", reqSignedIn, middleware.EnsureEditorOrViewerCanEdit, hs.Index) r.Get("/playlists/", reqSignedIn, hs.Index) r.Get("/playlists/*", reqSignedIn, hs.Index) diff --git a/pkg/middleware/auth.go b/pkg/middleware/auth.go index 27248342c8d..e06409211eb 100644 --- a/pkg/middleware/auth.go +++ b/pkg/middleware/auth.go @@ -4,7 +4,7 @@ import ( "net/url" "strings" - "gopkg.in/macaron.v1" + macaron "gopkg.in/macaron.v1" m "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/setting" @@ -52,6 +52,12 @@ func notAuthorized(c *m.ReqContext) { c.Redirect(setting.AppSubUrl + "/login") } +func EnsureEditorOrViewerCanEdit(c *m.ReqContext) { + if !c.SignedInUser.HasRole(m.ROLE_EDITOR) && !setting.ViewersCanEdit { + accessForbidden(c) + } +} + func RoleAuth(roles ...m.RoleType) macaron.Handler { return func(c *m.ReqContext) { ok := false From e3d08e24f327b56b97448e9ff50e8b5a39f111e7 Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Tue, 5 Mar 2019 12:58:02 +0100 Subject: [PATCH 42/48] update version to 6.1.0-pre --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ad08ddbf6f4..04a6967fdb9 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "company": "Grafana Labs" }, "name": "grafana", - "version": "6.0.0-pre3", + "version": "6.1.0-pre", "repository": { "type": "git", "url": "http://github.com/grafana/grafana.git" From d3642a3e91a52df7dd55d1b72ecddfd8ab1ecf53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=A4ggmark?= Date: Tue, 5 Mar 2019 13:02:41 +0100 Subject: [PATCH 43/48] Moved Server Admin and children to separate menu item on Side Menu (#15592) * Moved Server Admin and children to separate menu item on Side Menu * Removed style guide after PR comments --- pkg/api/index.go | 41 ++++++++----------- public/app/features/admin/AdminEditOrgCtrl.ts | 2 +- .../app/features/admin/AdminEditUserCtrl.ts | 2 +- .../app/features/admin/AdminListOrgsCtrl.ts | 2 +- .../app/features/admin/AdminListUsersCtrl.ts | 2 +- public/app/features/admin/StyleGuideCtrl.ts | 2 +- public/app/features/admin/index.ts | 4 +- public/app/features/org/NewOrgCtrl.ts | 2 +- 8 files changed, 25 insertions(+), 32 deletions(-) diff --git a/pkg/api/index.go b/pkg/api/index.go index 248ebf63f0f..904a885b171 100644 --- a/pkg/api/index.go +++ b/pkg/api/index.go @@ -307,33 +307,26 @@ func (hs *HTTPServer) setIndexViewData(c *m.ReqContext) (*dtos.IndexViewData, er } } - if c.OrgRole == m.ROLE_ADMIN && c.IsGrafanaAdmin { - cfgNode.Children = append(cfgNode.Children, &dtos.NavLink{ - Divider: true, HideFromTabs: true, Id: "admin-divider", Text: "Text", - }) - } - - if c.IsGrafanaAdmin { - cfgNode.Children = append(cfgNode.Children, &dtos.NavLink{ - Text: "Server Admin", - HideFromTabs: true, - SubTitle: "Manage all users & orgs", - Id: "admin", - Icon: "gicon gicon-shield", - Url: setting.AppSubUrl + "/admin/users", - Children: []*dtos.NavLink{ - {Text: "Users", Id: "global-users", Url: setting.AppSubUrl + "/admin/users", Icon: "gicon gicon-user"}, - {Text: "Orgs", Id: "global-orgs", Url: setting.AppSubUrl + "/admin/orgs", Icon: "gicon gicon-org"}, - {Text: "Settings", Id: "server-settings", Url: setting.AppSubUrl + "/admin/settings", Icon: "gicon gicon-preferences"}, - {Text: "Stats", Id: "server-stats", Url: setting.AppSubUrl + "/admin/stats", Icon: "fa fa-fw fa-bar-chart"}, - {Text: "Style Guide", Id: "styleguide", Url: setting.AppSubUrl + "/styleguide", Icon: "fa fa-fw fa-eyedropper"}, - }, - }) - } - data.NavTree = append(data.NavTree, cfgNode) } + if c.IsGrafanaAdmin { + data.NavTree = append(data.NavTree, &dtos.NavLink{ + Text: "Server Admin", + SubTitle: "Manage all users & orgs", + HideFromTabs: true, + Id: "admin", + Icon: "gicon gicon-shield", + Url: setting.AppSubUrl + "/admin/users", + Children: []*dtos.NavLink{ + {Text: "Users", Id: "global-users", Url: setting.AppSubUrl + "/admin/users", Icon: "gicon gicon-user"}, + {Text: "Orgs", Id: "global-orgs", Url: setting.AppSubUrl + "/admin/orgs", Icon: "gicon gicon-org"}, + {Text: "Settings", Id: "server-settings", Url: setting.AppSubUrl + "/admin/settings", Icon: "gicon gicon-preferences"}, + {Text: "Stats", Id: "server-stats", Url: setting.AppSubUrl + "/admin/stats", Icon: "fa fa-fw fa-bar-chart"}, + }, + }) + } + data.NavTree = append(data.NavTree, &dtos.NavLink{ Text: "Help", SubTitle: fmt.Sprintf(`%s v%s (%s)`, setting.ApplicationName, setting.BuildVersion, setting.BuildCommit), diff --git a/public/app/features/admin/AdminEditOrgCtrl.ts b/public/app/features/admin/AdminEditOrgCtrl.ts index 60514a86392..4ce0e2366f6 100644 --- a/public/app/features/admin/AdminEditOrgCtrl.ts +++ b/public/app/features/admin/AdminEditOrgCtrl.ts @@ -2,7 +2,7 @@ export default class AdminEditOrgCtrl { /** @ngInject */ constructor($scope, $routeParams, backendSrv, $location, navModelSrv) { $scope.init = () => { - $scope.navModel = navModelSrv.getNav('cfg', 'admin', 'global-orgs', 1); + $scope.navModel = navModelSrv.getNav('admin', 'global-orgs', 0); if ($routeParams.id) { $scope.getOrg($routeParams.id); diff --git a/public/app/features/admin/AdminEditUserCtrl.ts b/public/app/features/admin/AdminEditUserCtrl.ts index bf72c1746aa..a5dcae52d50 100644 --- a/public/app/features/admin/AdminEditUserCtrl.ts +++ b/public/app/features/admin/AdminEditUserCtrl.ts @@ -6,7 +6,7 @@ export default class AdminEditUserCtrl { $scope.user = {}; $scope.newOrg = { name: '', role: 'Editor' }; $scope.permissions = {}; - $scope.navModel = navModelSrv.getNav('cfg', 'admin', 'global-users', 1); + $scope.navModel = navModelSrv.getNav('admin', 'global-users', 0); $scope.init = () => { if ($routeParams.id) { diff --git a/public/app/features/admin/AdminListOrgsCtrl.ts b/public/app/features/admin/AdminListOrgsCtrl.ts index 8783efc182c..d6ee4b33dbb 100644 --- a/public/app/features/admin/AdminListOrgsCtrl.ts +++ b/public/app/features/admin/AdminListOrgsCtrl.ts @@ -2,7 +2,7 @@ export default class AdminListOrgsCtrl { /** @ngInject */ constructor($scope, backendSrv, navModelSrv) { $scope.init = () => { - $scope.navModel = navModelSrv.getNav('cfg', 'admin', 'global-orgs', 1); + $scope.navModel = navModelSrv.getNav('admin', 'global-orgs', 0); $scope.getOrgs(); }; diff --git a/public/app/features/admin/AdminListUsersCtrl.ts b/public/app/features/admin/AdminListUsersCtrl.ts index 1b5b27a4d66..5b5321d13ce 100644 --- a/public/app/features/admin/AdminListUsersCtrl.ts +++ b/public/app/features/admin/AdminListUsersCtrl.ts @@ -10,7 +10,7 @@ export default class AdminListUsersCtrl { /** @ngInject */ constructor(private $scope, private backendSrv, navModelSrv) { - this.navModel = navModelSrv.getNav('cfg', 'admin', 'global-users', 1); + this.navModel = navModelSrv.getNav('admin', 'global-users', 0); this.query = ''; this.getUsers(); } diff --git a/public/app/features/admin/StyleGuideCtrl.ts b/public/app/features/admin/StyleGuideCtrl.ts index e38e1a3344d..6548aa09198 100644 --- a/public/app/features/admin/StyleGuideCtrl.ts +++ b/public/app/features/admin/StyleGuideCtrl.ts @@ -9,7 +9,7 @@ export default class StyleGuideCtrl { /** @ngInject */ constructor(private $routeParams, private backendSrv, navModelSrv) { - this.navModel = navModelSrv.getNav('cfg', 'admin', 'styleguide', 1); + this.navModel = navModelSrv.getNav('admin', 'styleguide', 0); this.theme = config.bootData.user.lightTheme ? 'light' : 'dark'; } diff --git a/public/app/features/admin/index.ts b/public/app/features/admin/index.ts index 7d06155b6f8..fecc04bc410 100644 --- a/public/app/features/admin/index.ts +++ b/public/app/features/admin/index.ts @@ -11,7 +11,7 @@ class AdminSettingsCtrl { /** @ngInject */ constructor($scope, backendSrv, navModelSrv) { - this.navModel = navModelSrv.getNav('cfg', 'admin', 'server-settings', 1); + this.navModel = navModelSrv.getNav('admin', 'server-settings', 0); backendSrv.get('/api/admin/settings').then(settings => { $scope.settings = settings; @@ -24,7 +24,7 @@ class AdminHomeCtrl { /** @ngInject */ constructor(navModelSrv) { - this.navModel = navModelSrv.getNav('cfg', 'admin', 1); + this.navModel = navModelSrv.getNav('admin', 0); } } diff --git a/public/app/features/org/NewOrgCtrl.ts b/public/app/features/org/NewOrgCtrl.ts index 6a8808abfac..46c12b1d5d5 100644 --- a/public/app/features/org/NewOrgCtrl.ts +++ b/public/app/features/org/NewOrgCtrl.ts @@ -4,7 +4,7 @@ import config from 'app/core/config'; export class NewOrgCtrl { /** @ngInject */ constructor($scope, $http, backendSrv, navModelSrv) { - $scope.navModel = navModelSrv.getNav('cfg', 'admin', 'global-orgs', 1); + $scope.navModel = navModelSrv.getNav('admin', 'global-orgs', 0); $scope.newOrg = { name: '' }; $scope.createOrg = () => { From ff7eaced252ed0cc1bbdd39c727d595b29367d49 Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Tue, 5 Mar 2019 13:03:46 +0100 Subject: [PATCH 44/48] changelog: add notes about closing #15739 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c010a279c73..24fb134d82a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ ### Bug Fixes * **Api**: Invalid org invite code [#10506](https://github.com/grafana/grafana/issues/10506) * **Datasource**: Handles nil jsondata field gracefully [#14239](https://github.com/grafana/grafana/issues/14239) -* **Gauge**: Interpolate scoped variables in repeated gauges [#15732](https://github.com/grafana/grafana/pull/15752) +* **Gauge**: Interpolate scoped variables in repeated gauges [#15739](https://github.com/grafana/grafana/issues/15739) # 6.0.1 (unreleased) From ae9327ff3ac5c9f54e5add0ad4629739e34cb9a9 Mon Sep 17 00:00:00 2001 From: bergquist Date: Tue, 5 Mar 2019 13:41:40 +0100 Subject: [PATCH 45/48] remove `UseBool` since we use `AllCols` --- pkg/services/sqlstore/datasource.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/pkg/services/sqlstore/datasource.go b/pkg/services/sqlstore/datasource.go index 65d8369d763..ef42051f738 100644 --- a/pkg/services/sqlstore/datasource.go +++ b/pkg/services/sqlstore/datasource.go @@ -164,11 +164,6 @@ func UpdateDataSource(cmd *m.UpdateDataSourceCommand) error { Version: cmd.Version + 1, } - sess.UseBool("is_default") - sess.UseBool("basic_auth") - sess.UseBool("with_credentials") - sess.UseBool("read_only") - var updateSession *xorm.Session if cmd.Version != 0 { // the reason we allow cmd.version > db.version is make it possible for people to force From 062b5f26fe93fa8a1f377fafe401f3e1cb19d907 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=A4ggmark?= Date: Tue, 5 Mar 2019 13:46:22 +0100 Subject: [PATCH 46/48] style: add gicon-shield to sidemenu class Closes #15591 --- public/sass/base/_icons.scss | 3 +++ 1 file changed, 3 insertions(+) diff --git a/public/sass/base/_icons.scss b/public/sass/base/_icons.scss index 8d171673f6b..4e5751c6919 100644 --- a/public/sass/base/_icons.scss +++ b/public/sass/base/_icons.scss @@ -212,6 +212,9 @@ .gicon-explore { background-image: url('../img/icons_dark_theme/icon_explore.svg'); } + .gicon-shield { + background-image: url('../img/icons_dark_theme/icon_shield.svg'); + } } .fa--permissions-list { From ee4df155261eb65b6c69b705232306f0c06250f0 Mon Sep 17 00:00:00 2001 From: Peter Holmberg Date: Tue, 5 Mar 2019 13:55:29 +0100 Subject: [PATCH 47/48] moving --- .../grafana-ui/src/components/UnitPicker}/UnitPicker.tsx | 8 +++++--- packages/grafana-ui/src/components/index.ts | 1 + public/app/plugins/panel/gauge/SingleStatValueEditor.tsx | 3 +-- 3 files changed, 7 insertions(+), 5 deletions(-) rename {public/app/core/components/Select => packages/grafana-ui/src/components/UnitPicker}/UnitPicker.tsx (87%) diff --git a/public/app/core/components/Select/UnitPicker.tsx b/packages/grafana-ui/src/components/UnitPicker/UnitPicker.tsx similarity index 87% rename from public/app/core/components/Select/UnitPicker.tsx rename to packages/grafana-ui/src/components/UnitPicker/UnitPicker.tsx index f9dbc0ae421..3a34df02a39 100644 --- a/public/app/core/components/Select/UnitPicker.tsx +++ b/packages/grafana-ui/src/components/UnitPicker/UnitPicker.tsx @@ -1,6 +1,8 @@ import React, { PureComponent } from 'react'; -import { getValueFormats } from '@grafana/ui'; -import { Select } from '@grafana/ui'; + +import { Select } from '..'; + +import { getValueFormats } from '../../utils'; interface Props { onChange: (item: any) => void; @@ -8,7 +10,7 @@ interface Props { width?: number; } -export default class UnitPicker extends PureComponent { +export class UnitPicker extends PureComponent { static defaultProps = { width: 12, }; diff --git a/packages/grafana-ui/src/components/index.ts b/packages/grafana-ui/src/components/index.ts index ca8899bd928..b62fdff6498 100644 --- a/packages/grafana-ui/src/components/index.ts +++ b/packages/grafana-ui/src/components/index.ts @@ -26,3 +26,4 @@ export { ValueMappingsEditor } from './ValueMappingsEditor/ValueMappingsEditor'; export { Gauge } from './Gauge/Gauge'; export { Switch } from './Switch/Switch'; export { EmptySearchResult } from './EmptySearchResult/EmptySearchResult'; +export { UnitPicker } from './UnitPicker/UnitPicker'; diff --git a/public/app/plugins/panel/gauge/SingleStatValueEditor.tsx b/public/app/plugins/panel/gauge/SingleStatValueEditor.tsx index 86c177bb5e5..e711df6a2d3 100644 --- a/public/app/plugins/panel/gauge/SingleStatValueEditor.tsx +++ b/public/app/plugins/panel/gauge/SingleStatValueEditor.tsx @@ -2,8 +2,7 @@ import React, { PureComponent } from 'react'; // Components -import UnitPicker from 'app/core/components/Select/UnitPicker'; -import { FormField, FormLabel, PanelOptionsGroup, Select } from '@grafana/ui'; +import { FormField, FormLabel, PanelOptionsGroup, Select, UnitPicker } from '@grafana/ui'; // Types import { SingleStatValueOptions } from './types'; From d4c718091c0409c0c6999c223031a4455a14cc9a Mon Sep 17 00:00:00 2001 From: bergquist Date: Tue, 5 Mar 2019 14:41:04 +0100 Subject: [PATCH 48/48] changelog: adds note about closing #15608 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 24fb134d82a..cb2a344b014 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ * **Api**: Invalid org invite code [#10506](https://github.com/grafana/grafana/issues/10506) * **Datasource**: Handles nil jsondata field gracefully [#14239](https://github.com/grafana/grafana/issues/14239) * **Gauge**: Interpolate scoped variables in repeated gauges [#15739](https://github.com/grafana/grafana/issues/15739) +* **Datasource**: Empty user/password was not updated when updating datasources [#15608](https://github.com/grafana/grafana/pull/15608), thx [@Maddin-619](https://github.com/Maddin-619) # 6.0.1 (unreleased)