From bde5499552ca7a273f1fc39905192a85579f99ac Mon Sep 17 00:00:00 2001 From: Tyler Tolley Date: Fri, 2 Feb 2018 07:29:54 -0700 Subject: [PATCH 01/48] #10724 Fix finding the x bucket --- public/app/plugins/panel/heatmap/heatmap_tooltip.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/public/app/plugins/panel/heatmap/heatmap_tooltip.ts b/public/app/plugins/panel/heatmap/heatmap_tooltip.ts index 17621dfe398..a1f8691f84f 100644 --- a/public/app/plugins/panel/heatmap/heatmap_tooltip.ts +++ b/public/app/plugins/panel/heatmap/heatmap_tooltip.ts @@ -153,7 +153,15 @@ export class HeatmapTooltip { getXBucketIndex(offsetX, data) { let x = this.scope.xScale.invert(offsetX - this.scope.yAxisWidth).valueOf(); - let xBucketIndex = getValueBucketBound(x, data.xBucketSize, 1); + let xBucket = _.find(data.buckets, (bucket, bucketIndex) => { + return x-bucket.x <= data.xBucketSize && x-bucket.x >0; + }); + let xBucketIndex; + if(!xBucket) + xBucketIndex = getValueBucketBound(x, data.xBucketSize, 1); + else + xBucketIndex = xBucket.x; + return xBucketIndex; } From ca3c1d8c631c1d04f2db7d4a50c9faccc34a2dc2 Mon Sep 17 00:00:00 2001 From: Tyler Tolley Date: Fri, 2 Feb 2018 09:31:05 -0700 Subject: [PATCH 02/48] #10724 Fix whitespace --- public/app/plugins/panel/heatmap/heatmap_tooltip.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/public/app/plugins/panel/heatmap/heatmap_tooltip.ts b/public/app/plugins/panel/heatmap/heatmap_tooltip.ts index a1f8691f84f..81bac685d3a 100644 --- a/public/app/plugins/panel/heatmap/heatmap_tooltip.ts +++ b/public/app/plugins/panel/heatmap/heatmap_tooltip.ts @@ -157,11 +157,11 @@ export class HeatmapTooltip { return x-bucket.x <= data.xBucketSize && x-bucket.x >0; }); let xBucketIndex; - if(!xBucket) + if (!xBucket) { xBucketIndex = getValueBucketBound(x, data.xBucketSize, 1); - else + } else { xBucketIndex = xBucket.x; - + } return xBucketIndex; } From 32054ad9a689db273a764854e7ac2c6e38684aed Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Sun, 4 Feb 2018 17:29:16 +0100 Subject: [PATCH 03/48] dashboard: fix redirect of legacy dashboard url's Redirect of /dashboard/db/:slug to /d/:uid/:slug and /dashboard-solo/db/:slug to /d-solo/:uid/:slug now includes querystring parameters. Fixes #10752 --- pkg/middleware/dashboard_redirect.go | 3 +++ pkg/middleware/dashboard_redirect_test.go | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/pkg/middleware/dashboard_redirect.go b/pkg/middleware/dashboard_redirect.go index 1ca4ef741c6..4a3812fb8a2 100644 --- a/pkg/middleware/dashboard_redirect.go +++ b/pkg/middleware/dashboard_redirect.go @@ -1,6 +1,7 @@ package middleware import ( + "fmt" "strings" "github.com/grafana/grafana/pkg/bus" @@ -24,6 +25,7 @@ func RedirectFromLegacyDashboardUrl() macaron.Handler { if slug != "" { if url, err := getDashboardUrlBySlug(c.OrgId, slug); err == nil { + url = fmt.Sprintf("%s?%s", url, c.Req.URL.RawQuery) c.Redirect(url, 301) return } @@ -38,6 +40,7 @@ func RedirectFromLegacyDashboardSoloUrl() macaron.Handler { if slug != "" { if url, err := getDashboardUrlBySlug(c.OrgId, slug); err == nil { url = strings.Replace(url, "/d/", "/d-solo/", 1) + url = fmt.Sprintf("%s?%s", url, c.Req.URL.RawQuery) c.Redirect(url, 301) return } diff --git a/pkg/middleware/dashboard_redirect_test.go b/pkg/middleware/dashboard_redirect_test.go index 21fc12e5e84..0af06347ed0 100644 --- a/pkg/middleware/dashboard_redirect_test.go +++ b/pkg/middleware/dashboard_redirect_test.go @@ -30,19 +30,20 @@ func TestMiddlewareDashboardRedirect(t *testing.T) { middlewareScenario("GET dashboard by legacy url", func(sc *scenarioContext) { sc.m.Get("/dashboard/db/:slug", redirectFromLegacyDashboardUrl, sc.defaultHandler) - sc.fakeReqWithParams("GET", "/dashboard/db/dash", map[string]string{}).exec() + sc.fakeReqWithParams("GET", "/dashboard/db/dash?orgId=1&panelId=2", map[string]string{}).exec() Convey("Should redirect to new dashboard url with a 301 Moved Permanently", func() { So(sc.resp.Code, ShouldEqual, 301) redirectUrl, _ := sc.resp.Result().Location() So(redirectUrl.Path, ShouldEqual, m.GetDashboardUrl(fakeDash.Uid, fakeDash.Slug)) + So(len(redirectUrl.Query()), ShouldEqual, 2) }) }) middlewareScenario("GET dashboard solo by legacy url", func(sc *scenarioContext) { sc.m.Get("/dashboard-solo/db/:slug", redirectFromLegacyDashboardSoloUrl, sc.defaultHandler) - sc.fakeReqWithParams("GET", "/dashboard-solo/db/dash", map[string]string{}).exec() + sc.fakeReqWithParams("GET", "/dashboard-solo/db/dash?orgId=1&panelId=2", map[string]string{}).exec() Convey("Should redirect to new dashboard url with a 301 Moved Permanently", func() { So(sc.resp.Code, ShouldEqual, 301) @@ -50,6 +51,7 @@ func TestMiddlewareDashboardRedirect(t *testing.T) { expectedUrl := m.GetDashboardUrl(fakeDash.Uid, fakeDash.Slug) expectedUrl = strings.Replace(expectedUrl, "/d/", "/d-solo/", 1) So(redirectUrl.Path, ShouldEqual, expectedUrl) + So(len(redirectUrl.Query()), ShouldEqual, 2) }) }) }) From 40c9d5f2a3694c8ce7ea697a72516362e0851c07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sun, 4 Feb 2018 17:32:27 +0100 Subject: [PATCH 04/48] ux: hide sidemenu in kiosk mode, and while playlist is playing, fixes #107402 --- public/app/core/components/grafana_app.ts | 4 ++++ public/app/core/directives/dash_class.js | 4 ---- public/sass/components/_view_states.scss | 7 ++++++- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/public/app/core/components/grafana_app.ts b/public/app/core/components/grafana_app.ts index 31b6f5b8096..70a1bda3e8b 100644 --- a/public/app/core/components/grafana_app.ts +++ b/public/app/core/components/grafana_app.ts @@ -83,6 +83,10 @@ export function grafanaAppDirective(playlistSrv, contextSrv, $timeout, $rootScop body.toggleClass('sidemenu-hidden'); }); + scope.$watch(() => playlistSrv.isPlaying, function(newValue) { + elem.toggleClass('playlist-active', newValue === true); + }); + // tooltip removal fix // manage page classes var pageClass; diff --git a/public/app/core/directives/dash_class.js b/public/app/core/directives/dash_class.js index 9df53bdbd48..4a139272632 100644 --- a/public/app/core/directives/dash_class.js +++ b/public/app/core/directives/dash_class.js @@ -18,10 +18,6 @@ function (_, $, coreModule) { elem.toggleClass('panel-in-fullscreen', false); }); - $scope.$watch('ctrl.playlistSrv.isPlaying', function(newValue) { - elem.toggleClass('playlist-active', newValue === true); - }); - $scope.$watch('ctrl.dashboardViewState.state.editview', function(newValue) { if (newValue) { elem.toggleClass('dashboard-page--settings-opening', _.isString(newValue)); diff --git a/public/sass/components/_view_states.scss b/public/sass/components/_view_states.scss index 45fa3a631ee..be5361ceeb4 100644 --- a/public/sass/components/_view_states.scss +++ b/public/sass/components/_view_states.scss @@ -1,5 +1,6 @@ .page-kiosk-mode { - dashnav { + .sidemenu, + .navbar { display: none; } } @@ -31,6 +32,10 @@ } } + .sidemenu { + display: none; + } + .gf-timepicker-nav-btn { transform: translate3d(40px, 0, 0); } From d379aa3815ac555510743854a8e908ab58fd9d97 Mon Sep 17 00:00:00 2001 From: Leonard Gram Date: Fri, 2 Feb 2018 11:17:25 +0100 Subject: [PATCH 05/48] docs: typos and wording. --- docs/sources/administration/permissions.md | 6 +++--- docs/sources/guides/whats-new-in-v5.md | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/sources/administration/permissions.md b/docs/sources/administration/permissions.md index 5cfc6ecac9c..34459e2319a 100644 --- a/docs/sources/administration/permissions.md +++ b/docs/sources/administration/permissions.md @@ -28,10 +28,10 @@ in that organization. Can do everything scoped to the organization. For example: -- Add & Edit data data sources. +- Add & Edit data sources. - Add & Edit organization users & teams. - Configure App plugins & set org settings. - + ### Editor Role - Can create and modify dashboards & alert rules. This can be disabled on specific folders and dashboards. @@ -73,4 +73,4 @@ The highest permission always wins so if you for example want to hide a folder o Access Control List (ACL). - You cannot override permissions for users with **Org Admin Role** -- A more specific permission with lower permission level will not have any effect if a more general rule exists with higher permission level. For example if "Everyone with Editor Role Can Edit" exists in the ACL list then **John Doe** will still have Edit permission even after you have specifically added a permission for this user with the permission set to **View**. You need to remove or lower the permission level of the more general rule. \ No newline at end of file +- A more specific permission with lower permission level will not have any effect if a more general rule exists with higher permission level. For example if "Everyone with Editor Role Can Edit" exists in the ACL list then **John Doe** will still have Edit permission even after you have specifically added a permission for this user with the permission set to **View**. You need to remove or lower the permission level of the more general rule. diff --git a/docs/sources/guides/whats-new-in-v5.md b/docs/sources/guides/whats-new-in-v5.md index 3f5b3626773..0cda207d650 100644 --- a/docs/sources/guides/whats-new-in-v5.md +++ b/docs/sources/guides/whats-new-in-v5.md @@ -36,7 +36,7 @@ The new dashboard layout engine allows for much easier movement and sizing of pa a very intuitive way. Panels are sized independently, so rows are no longer necessary to create layouts. This opens up many new types of layouts where panels of different heights can be aligned easily. Checkout the new grid in the video above or on the [play site](http://play.grafana.org). All your existing dashboards will automatically migrate to the -new position system and look close to identical. The new panel position makes dashboards saved in v5.0 not compatible +new position system and look close to identical. The new panel position makes dashboards saved in v5.0 incompatible with older versions of Grafana.
@@ -61,7 +61,7 @@ settings views have been combined with a side nav which allows you to easily mov {{< docs-imagebox img="/img/docs/v50/new_white_theme.png" max-width="1000px" class="docs-image--right" >}} -This theme has not seen a lot of love in recent years and we felt it was time to rework it and give it a major overhaul. We are very happy with the result. +This theme has not seen a lot of love in recent years and we felt it was time to give it a major overhaul. We are very happy with the result.
@@ -78,7 +78,7 @@ which is very useful if you have a lot of dashboards or multiple teams. ## Teams -A team is a new concept in Grafana v5. They are simply a group of users that can be then be used in the new permission system for dashboards and folders. Only an admin can create teams. +A team is a new concept in Grafana v5. They are simply a group of users that can be used in the new permission system for dashboards and folders. Only an admin can create teams. We hope to do more with teams in future releases like integration with LDAP and a team landing page. ## Permissions @@ -93,7 +93,7 @@ You can assign permissions to folders and dashboards. The default user role-base In previous versions of Grafana, you could only use the API for provisioning data sources and dashboards. But that required the service to be running before you started creating dashboards and you also needed to -set up credentials for the HTTP API. In 5.0 we decided to improve this experience by adding a new active +set up credentials for the HTTP API. In v5.0 we decided to improve this experience by adding a new active provisioning system that uses config files. This will make GitOps more natural as data sources and dashboards can be defined via files that can be version controlled. We hope to extend this system to later add support for users, orgs and alerts as well. From 07fa2f17222fb81b83c96601367d4b8e967be886 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 5 Feb 2018 09:42:41 +0100 Subject: [PATCH 06/48] fix: alert list links did not work, changed dashboardUri to Url, this is breaking api change in alert api (#10756) --- docs/sources/http_api/alerting.md | 8 ++++---- pkg/api/alerting.go | 2 +- pkg/api/dtos/alerting.go | 2 +- .../app/containers/AlertRuleList/AlertRuleList.jest.tsx | 2 +- public/app/containers/AlertRuleList/AlertRuleList.tsx | 2 +- public/app/plugins/panel/alertlist/module.html | 2 +- public/app/stores/AlertListStore/AlertListStore.jest.ts | 2 +- public/app/stores/AlertListStore/AlertRule.ts | 2 +- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/sources/http_api/alerting.md b/docs/sources/http_api/alerting.md index 221552414e9..3860ae490b1 100644 --- a/docs/sources/http_api/alerting.md +++ b/docs/sources/http_api/alerting.md @@ -62,7 +62,7 @@ Content-Type: application/json } "newStateDate": "2016-12-25", "executionError": "", - "dashboardUri": "http://grafana.com/dashboard/db/sensors" + "url": "http://grafana.com/dashboard/db/sensors" } ] ``` @@ -94,7 +94,7 @@ Content-Type: application/json "state": "alerting", "newStateDate": "2016-12-25", "executionError": "", - "dashboardUri": "http://grafana.com/dashboard/db/sensors" + "url": "http://grafana.com/dashboard/db/sensors" } ``` @@ -196,7 +196,7 @@ Content-Type: application/json ## Create alert notification -You can find the full list of [supported notifers](/alerting/notifications/#all-supported-notifier) at the alert notifiers page. +You can find the full list of [supported notifers](/alerting/notifications/#all-supported-notifier) at the alert notifiers page. `POST /api/alert-notifications` @@ -294,4 +294,4 @@ Content-Type: application/json { "message": "Notification deleted" } -``` \ No newline at end of file +``` diff --git a/pkg/api/alerting.go b/pkg/api/alerting.go index 1fc3d893681..16f5f7ceb6f 100644 --- a/pkg/api/alerting.go +++ b/pkg/api/alerting.go @@ -105,7 +105,7 @@ func transformToDTOs(alerts []*models.Alert, c *middleware.Context) ([]*dtos.Ale for _, alert := range alertDTOs { for _, dash := range dashboardsQuery.Result { if alert.DashboardId == dash.Id { - alert.DashbboardUri = dash.GenerateUrl() + alert.Url = dash.GenerateUrl() break } } diff --git a/pkg/api/dtos/alerting.go b/pkg/api/dtos/alerting.go index c32edb6e51c..d30f2697f3f 100644 --- a/pkg/api/dtos/alerting.go +++ b/pkg/api/dtos/alerting.go @@ -19,7 +19,7 @@ type AlertRule struct { EvalDate time.Time `json:"evalDate"` EvalData *simplejson.Json `json:"evalData"` ExecutionError string `json:"executionError"` - DashbboardUri string `json:"dashboardUri"` + Url string `json:"url"` CanEdit bool `json:"canEdit"` } diff --git a/public/app/containers/AlertRuleList/AlertRuleList.jest.tsx b/public/app/containers/AlertRuleList/AlertRuleList.jest.tsx index eaeba48f0a6..eac18a6c69d 100644 --- a/public/app/containers/AlertRuleList/AlertRuleList.jest.tsx +++ b/public/app/containers/AlertRuleList/AlertRuleList.jest.tsx @@ -23,7 +23,7 @@ describe('AlertRuleList', () => { .format(), evalData: {}, executionError: '', - dashboardUri: 'd/ufkcofof/my-goal', + url: 'd/ufkcofof/my-goal', canEdit: true, }, ]) diff --git a/public/app/containers/AlertRuleList/AlertRuleList.tsx b/public/app/containers/AlertRuleList/AlertRuleList.tsx index 5ce1efd9ee3..6fb6e3b7d8f 100644 --- a/public/app/containers/AlertRuleList/AlertRuleList.tsx +++ b/public/app/containers/AlertRuleList/AlertRuleList.tsx @@ -137,7 +137,7 @@ export class AlertRuleItem extends React.Component { 'fa-pause': !rule.isPaused, }); - let ruleUrl = `${rule.dashboardUri}?panelId=${rule.panelId}&fullscreen=true&edit=true&tab=alert`; + let ruleUrl = `${rule.url}?panelId=${rule.panelId}&fullscreen=true&edit=true&tab=alert`; return (
  • diff --git a/public/app/plugins/panel/alertlist/module.html b/public/app/plugins/panel/alertlist/module.html index e795c4fa59f..b8055b5fc7f 100644 --- a/public/app/plugins/panel/alertlist/module.html +++ b/public/app/plugins/panel/alertlist/module.html @@ -12,7 +12,7 @@

    - + {{alert.name}}

    diff --git a/public/app/stores/AlertListStore/AlertListStore.jest.ts b/public/app/stores/AlertListStore/AlertListStore.jest.ts index 9092ed26df2..f0ab24b6cfc 100644 --- a/public/app/stores/AlertListStore/AlertListStore.jest.ts +++ b/public/app/stores/AlertListStore/AlertListStore.jest.ts @@ -14,7 +14,7 @@ function getRule(name, state, info) { .format(), evalData: {}, executionError: '', - dashboardUri: 'db/mygool', + url: 'db/mygool', stateText: state, stateIcon: 'fa', stateClass: 'asd', diff --git a/public/app/stores/AlertListStore/AlertRule.ts b/public/app/stores/AlertListStore/AlertRule.ts index 2933daeb7c5..00881650949 100644 --- a/public/app/stores/AlertListStore/AlertRule.ts +++ b/public/app/stores/AlertListStore/AlertRule.ts @@ -13,7 +13,7 @@ export const AlertRule = types stateClass: types.string, stateAge: types.string, info: types.optional(types.string, ''), - dashboardUri: types.string, + url: types.string, canEdit: types.boolean, }) .views(self => ({ From 0701188e64474167724467d07ec9eee99642f69d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 5 Feb 2018 09:44:36 +0100 Subject: [PATCH 07/48] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d7dd13dba98..2dacbb716e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,9 @@ From `/etc/grafana/datasources` to `/etc/grafana/provisioning/datasources` when * **Pagerduty** The notifier now defaults to not auto resolve incidents. More details at [#10222](https://github.com/grafana/grafana/issues/10222) +* **HTTP API** +- `GET /api/alerts` property dashboardUri renamed to url and is now the full url (that is including app sub url). + ## New Dashboard Grid The new grid engine is a major upgrade for how you can position and move panels. It enables new layouts and a much easier dashboard building experience. The change is backward compatible. So you can upgrade your current version to 5.0 without breaking dashboards, but you cannot downgrade from 5.0 to previous versions. Grafana will automatically upgrade your dashboards to the new schema and position panels to match your existing layout. There might be minor differences in panel height. If you upgrade to 5.0 and for some reason want to rollback to the previous version you can restore dashboards to previous versions using dashboard history. But that should only be seen as an emergency solution. From cc0cc8dd735d54924510f690f56ae56942d6ad24 Mon Sep 17 00:00:00 2001 From: Carl Bergquist Date: Mon, 5 Feb 2018 10:24:48 +0100 Subject: [PATCH 08/48] changes to new urlformat for home dashboard (#10738) --- pkg/api/dashboard.go | 5 +++-- pkg/models/dashboards.go | 2 +- pkg/services/alerting/eval_context.go | 2 +- pkg/services/sqlstore/dashboard.go | 2 +- public/app/routes/dashboard_loaders.ts | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/pkg/api/dashboard.go b/pkg/api/dashboard.go index 0267e2097eb..4478a5af55e 100644 --- a/pkg/api/dashboard.go +++ b/pkg/api/dashboard.go @@ -293,10 +293,11 @@ func GetHomeDashboard(c *middleware.Context) Response { } if prefsQuery.Result.HomeDashboardId != 0 { - slugQuery := m.GetDashboardSlugByIdQuery{Id: prefsQuery.Result.HomeDashboardId} + slugQuery := m.GetDashboardRefByIdQuery{Id: prefsQuery.Result.HomeDashboardId} err := bus.Dispatch(&slugQuery) if err == nil { - dashRedirect := dtos.DashboardRedirect{RedirectUri: "db/" + slugQuery.Result} + url := m.GetDashboardUrl(slugQuery.Result.Uid, slugQuery.Result.Slug) + dashRedirect := dtos.DashboardRedirect{RedirectUri: url} return Json(200, &dashRedirect) } else { log.Warn("Failed to get slug from database, %s", err.Error()) diff --git a/pkg/models/dashboards.go b/pkg/models/dashboards.go index 089a98c4f00..12216718b44 100644 --- a/pkg/models/dashboards.go +++ b/pkg/models/dashboards.go @@ -293,7 +293,7 @@ type DashboardRef struct { Slug string } -type GetDashboardUIDByIdQuery struct { +type GetDashboardRefByIdQuery struct { Id int64 Result *DashboardRef } diff --git a/pkg/services/alerting/eval_context.go b/pkg/services/alerting/eval_context.go index 60c5530d486..d598203d675 100644 --- a/pkg/services/alerting/eval_context.go +++ b/pkg/services/alerting/eval_context.go @@ -90,7 +90,7 @@ func (c *EvalContext) GetDashboardUID() (*m.DashboardRef, error) { return c.dashboardRef, nil } - uidQuery := &m.GetDashboardUIDByIdQuery{Id: c.Rule.DashboardId} + uidQuery := &m.GetDashboardRefByIdQuery{Id: c.Rule.DashboardId} if err := bus.Dispatch(uidQuery); err != nil { return nil, err } diff --git a/pkg/services/sqlstore/dashboard.go b/pkg/services/sqlstore/dashboard.go index 16270b2ce1d..2e2537cacb9 100644 --- a/pkg/services/sqlstore/dashboard.go +++ b/pkg/services/sqlstore/dashboard.go @@ -569,7 +569,7 @@ func GetDashboardsBySlug(query *m.GetDashboardsBySlugQuery) error { return nil } -func GetDashboardUIDById(query *m.GetDashboardUIDByIdQuery) error { +func GetDashboardUIDById(query *m.GetDashboardRefByIdQuery) error { var rawSql = `SELECT uid, slug from dashboard WHERE Id=?` us := &m.DashboardRef{} diff --git a/public/app/routes/dashboard_loaders.ts b/public/app/routes/dashboard_loaders.ts index e17ca6fb054..7d3099a54fd 100644 --- a/public/app/routes/dashboard_loaders.ts +++ b/public/app/routes/dashboard_loaders.ts @@ -9,7 +9,7 @@ export class LoadDashboardCtrl { if (!$routeParams.uid && !$routeParams.slug) { backendSrv.get('/api/dashboards/home').then(function(homeDash) { if (homeDash.redirectUri) { - $location.path('dashboard/' + homeDash.redirectUri); + $location.path(homeDash.redirectUri); } else { var meta = homeDash.meta; meta.canSave = meta.canShare = meta.canStar = false; From 6def21e83fc4334e03feae1756db03ce6d3abe24 Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Mon, 5 Feb 2018 10:31:53 +0100 Subject: [PATCH 09/48] dashboard: fix loading of snapshot and scripted dashboard (#10755) Fixes #10753 --- public/app/routes/dashboard_loaders.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/public/app/routes/dashboard_loaders.ts b/public/app/routes/dashboard_loaders.ts index 7d3099a54fd..a9ccd60ee4f 100644 --- a/public/app/routes/dashboard_loaders.ts +++ b/public/app/routes/dashboard_loaders.ts @@ -31,10 +31,12 @@ export class LoadDashboardCtrl { } dashboardLoaderSrv.loadDashboard($routeParams.type, $routeParams.slug, $routeParams.uid).then(function(result) { - const url = locationUtil.stripBaseFromUrl(result.meta.url); + if (result.meta.url) { + const url = locationUtil.stripBaseFromUrl(result.meta.url); - if (url !== $location.path()) { - $location.path(url).replace(); + if (url !== $location.path()) { + $location.path(url).replace(); + } } if ($routeParams.keepRows) { From 7d3b990e917200ba7f53847cbc38423b22b6acd0 Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Mon, 5 Feb 2018 11:09:05 +0100 Subject: [PATCH 10/48] permissions: fix link to folder from permissions list Also, closing Add Permissions CTA when DashboardPermissions and FolderPermissions unmounts. Fixes #10749" --- pkg/api/dashboard.go | 2 +- pkg/api/dtos/dashboard.go | 2 +- .../ManageDashboards/FolderPermissions.tsx | 5 +++++ public/app/core/angular_wrappers.ts | 8 +------- .../components/Permissions/DashboardPermissions.tsx | 13 ++++++++----- .../app/core/components/Permissions/FolderInfo.ts | 4 ++-- .../components/Permissions/PermissionsListItem.tsx | 2 +- .../app/features/dashboard/settings/settings.html | 4 +--- public/app/features/dashboard/settings/settings.ts | 8 ++++++++ 9 files changed, 28 insertions(+), 20 deletions(-) diff --git a/pkg/api/dashboard.go b/pkg/api/dashboard.go index 0267e2097eb..439f04f0799 100644 --- a/pkg/api/dashboard.go +++ b/pkg/api/dashboard.go @@ -99,7 +99,7 @@ func GetDashboard(c *middleware.Context) Response { return ApiError(500, "Dashboard folder could not be read", err) } meta.FolderTitle = query.Result.Title - meta.FolderSlug = query.Result.Slug + meta.FolderUrl = query.Result.GetUrl() } // make sure db version is in sync with json model version diff --git a/pkg/api/dtos/dashboard.go b/pkg/api/dtos/dashboard.go index 44fc68e4659..e4c66aebbda 100644 --- a/pkg/api/dtos/dashboard.go +++ b/pkg/api/dtos/dashboard.go @@ -27,7 +27,7 @@ type DashboardMeta struct { IsFolder bool `json:"isFolder"` FolderId int64 `json:"folderId"` FolderTitle string `json:"folderTitle"` - FolderSlug string `json:"folderSlug"` + FolderUrl string `json:"folderUrl"` } type DashboardFullWithMeta struct { diff --git a/public/app/containers/ManageDashboards/FolderPermissions.tsx b/public/app/containers/ManageDashboards/FolderPermissions.tsx index 93b9520739e..a62165d7194 100644 --- a/public/app/containers/ManageDashboards/FolderPermissions.tsx +++ b/public/app/containers/ManageDashboards/FolderPermissions.tsx @@ -17,6 +17,11 @@ export class FolderPermissions extends Component { this.loadStore(); } + componentWillUnmount() { + const { permissions } = this.props; + permissions.hideAddPermissions(); + } + loadStore() { const { nav, folder, view } = this.props; return folder.load(view.routeParams.get('uid') as string).then(res => { diff --git a/public/app/core/angular_wrappers.ts b/public/app/core/angular_wrappers.ts index bc3fb08d822..ace0eb00b07 100644 --- a/public/app/core/angular_wrappers.ts +++ b/public/app/core/angular_wrappers.ts @@ -20,11 +20,5 @@ export function registerAngularDirectives() { ['tagOptions', { watchDepth: 'reference' }], ]); react2AngularDirective('selectUserPicker', UserPicker, ['backendSrv', 'handlePicked']); - react2AngularDirective('dashboardPermissions', DashboardPermissions, [ - 'backendSrv', - 'dashboardId', - 'folderTitle', - 'folderSlug', - 'folderId', - ]); + react2AngularDirective('dashboardPermissions', DashboardPermissions, ['backendSrv', 'dashboardId', 'folder']); } diff --git a/public/app/core/components/Permissions/DashboardPermissions.tsx b/public/app/core/components/Permissions/DashboardPermissions.tsx index a1b86e121bf..d6b293da4bb 100644 --- a/public/app/core/components/Permissions/DashboardPermissions.tsx +++ b/public/app/core/components/Permissions/DashboardPermissions.tsx @@ -6,12 +6,11 @@ import Tooltip from 'app/core/components/Tooltip/Tooltip'; import PermissionsInfo from 'app/core/components/Permissions/PermissionsInfo'; import AddPermissions from 'app/core/components/Permissions/AddPermissions'; import SlideDown from 'app/core/components/Animations/SlideDown'; +import { FolderInfo } from './FolderInfo'; export interface IProps { dashboardId: number; - folderId: number; - folderTitle: string; - folderSlug: string; + folder?: FolderInfo; backendSrv: any; } @observer @@ -28,8 +27,12 @@ class DashboardPermissions extends Component { this.permissions.toggleAddPermissions(); } + componentWillUnmount() { + this.permissions.hideAddPermissions(); + } + render() { - const { dashboardId, folderTitle, folderSlug, folderId, backendSrv } = this.props; + const { dashboardId, folder, backendSrv } = this.props; return (
    @@ -56,7 +59,7 @@ class DashboardPermissions extends Component { permissions={this.permissions} isFolder={false} dashboardId={dashboardId} - folderInfo={{ title: folderTitle, slug: folderSlug, id: folderId }} + folderInfo={folder} backendSrv={backendSrv} />
    diff --git a/public/app/core/components/Permissions/FolderInfo.ts b/public/app/core/components/Permissions/FolderInfo.ts index 67ebb753df0..d4a6020bb71 100644 --- a/public/app/core/components/Permissions/FolderInfo.ts +++ b/public/app/core/components/Permissions/FolderInfo.ts @@ -1,5 +1,5 @@ export interface FolderInfo { - title: string; id: number; - slug: string; + title: string; + url: string; } diff --git a/public/app/core/components/Permissions/PermissionsListItem.tsx b/public/app/core/components/Permissions/PermissionsListItem.tsx index 291ee20e157..3140b8fcc0c 100644 --- a/public/app/core/components/Permissions/PermissionsListItem.tsx +++ b/public/app/core/components/Permissions/PermissionsListItem.tsx @@ -30,7 +30,7 @@ export default observer(({ item, removeItem, permissionChanged, itemIndex, folde folderInfo && ( Inherited from folder{' '} - + {folderInfo.title} {' '} diff --git a/public/app/features/dashboard/settings/settings.html b/public/app/features/dashboard/settings/settings.html index 47c3bae2ef6..af9358aecf7 100644 --- a/public/app/features/dashboard/settings/settings.html +++ b/public/app/features/dashboard/settings/settings.html @@ -99,9 +99,7 @@
    diff --git a/public/app/features/dashboard/settings/settings.ts b/public/app/features/dashboard/settings/settings.ts index c538f171fa0..09aa96e42ae 100755 --- a/public/app/features/dashboard/settings/settings.ts +++ b/public/app/features/dashboard/settings/settings.ts @@ -197,6 +197,14 @@ export class SettingsCtrl { this.dashboard.meta.folderTitle = folder.title; this.dashboard.meta.folderSlug = folder.slug; } + + getFolder() { + return { + id: this.dashboard.meta.folderId, + title: this.dashboard.meta.folderTitle, + url: this.dashboard.meta.folderUrl, + }; + } } export function dashboardSettings() { From 20feb123c9009450791f2d39215de873ff26829c Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Mon, 5 Feb 2018 13:49:59 +0300 Subject: [PATCH 11/48] fix panel menu caret placement (#10759) --- public/sass/components/_dropdown.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/sass/components/_dropdown.scss b/public/sass/components/_dropdown.scss index d91a6d0a5a7..cc94a379e07 100644 --- a/public/sass/components/_dropdown.scss +++ b/public/sass/components/_dropdown.scss @@ -255,7 +255,7 @@ } // Caret to indicate there is a submenu -.dropdown-submenu > a::before { +.dropdown-submenu > a::after { display: block; content: ' '; float: right; From a879dd8c0c391bf8edea48d797340d8eb8979378 Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Mon, 5 Feb 2018 13:23:24 +0100 Subject: [PATCH 12/48] dashboards: render correct link for folder when searching for dashboards (#10763) Fixes #10761 --- pkg/services/search/models.go | 3 ++- pkg/services/sqlstore/dashboard.go | 7 ++++++- pkg/services/sqlstore/dashboard_test.go | 5 +++++ pkg/services/sqlstore/search_builder.go | 1 + public/app/core/services/search_srv.ts | 4 ++-- public/app/core/specs/manage_dashboards.jest.ts | 11 +++-------- public/app/core/specs/search_srv.jest.ts | 7 +++++++ 7 files changed, 26 insertions(+), 12 deletions(-) diff --git a/pkg/services/search/models.go b/pkg/services/search/models.go index f5d87b1f5c8..6dea975d9fe 100644 --- a/pkg/services/search/models.go +++ b/pkg/services/search/models.go @@ -21,8 +21,9 @@ type Hit struct { Tags []string `json:"tags"` IsStarred bool `json:"isStarred"` FolderId int64 `json:"folderId,omitempty"` + FolderUid string `json:"folderUid,omitempty"` FolderTitle string `json:"folderTitle,omitempty"` - FolderSlug string `json:"folderSlug,omitempty"` + FolderUrl string `json:"folderUrl,omitempty"` } type HitList []*Hit diff --git a/pkg/services/sqlstore/dashboard.go b/pkg/services/sqlstore/dashboard.go index 2e2537cacb9..af87c324216 100644 --- a/pkg/services/sqlstore/dashboard.go +++ b/pkg/services/sqlstore/dashboard.go @@ -245,6 +245,7 @@ type DashboardSearchProjection struct { Term string IsFolder bool FolderId int64 + FolderUid string FolderSlug string FolderTitle string } @@ -323,11 +324,15 @@ func makeQueryResult(query *search.FindPersistedDashboardsQuery, res []Dashboard Url: m.GetDashboardFolderUrl(item.IsFolder, item.Uid, item.Slug), Type: getHitType(item), FolderId: item.FolderId, + FolderUid: item.FolderUid, FolderTitle: item.FolderTitle, - FolderSlug: item.FolderSlug, Tags: []string{}, } + if item.FolderId > 0 { + hit.FolderUrl = m.GetFolderUrl(item.FolderUid, item.FolderSlug) + } + query.Result = append(query.Result, hit) hits[item.Id] = hit } diff --git a/pkg/services/sqlstore/dashboard_test.go b/pkg/services/sqlstore/dashboard_test.go index 0a9a97dbe7a..97ab5472d94 100644 --- a/pkg/services/sqlstore/dashboard_test.go +++ b/pkg/services/sqlstore/dashboard_test.go @@ -147,6 +147,7 @@ func TestDashboardDataAccess(t *testing.T) { hit := query.Result[0] So(hit.Type, ShouldEqual, search.DashHitFolder) So(hit.Url, ShouldEqual, fmt.Sprintf("/dashboards/f/%s/%s", savedFolder.Uid, savedFolder.Slug)) + So(hit.FolderTitle, ShouldEqual, "") }) Convey("Should be able to search for a dashboard folder's children", func() { @@ -163,6 +164,10 @@ func TestDashboardDataAccess(t *testing.T) { hit := query.Result[0] So(hit.Id, ShouldEqual, savedDash.Id) So(hit.Url, ShouldEqual, fmt.Sprintf("/d/%s/%s", savedDash.Uid, savedDash.Slug)) + So(hit.FolderId, ShouldEqual, savedFolder.Id) + So(hit.FolderUid, ShouldEqual, savedFolder.Uid) + So(hit.FolderTitle, ShouldEqual, savedFolder.Title) + So(hit.FolderUrl, ShouldEqual, fmt.Sprintf("/dashboards/f/%s/%s", savedFolder.Uid, savedFolder.Slug)) }) Convey("Should be able to search for dashboard by dashboard ids", func() { diff --git a/pkg/services/sqlstore/search_builder.go b/pkg/services/sqlstore/search_builder.go index 480e7fa99e6..627074d5453 100644 --- a/pkg/services/sqlstore/search_builder.go +++ b/pkg/services/sqlstore/search_builder.go @@ -107,6 +107,7 @@ func (sb *SearchBuilder) buildSelect() { dashboard_tag.term, dashboard.is_folder, dashboard.folder_id, + folder.uid as folder_uid, folder.slug as folder_slug, folder.title as folder_title FROM `) diff --git a/public/app/core/services/search_srv.ts b/public/app/core/services/search_srv.ts index 7bee5cdfec6..9f32e21f3f6 100644 --- a/public/app/core/services/search_srv.ts +++ b/public/app/core/services/search_srv.ts @@ -150,9 +150,9 @@ export class SearchSrv { if (hit.folderId) { section = { id: hit.folderId, - uid: hit.uid, + uid: hit.folderUid, title: hit.folderTitle, - url: hit.url, + url: hit.folderUrl, items: [], icon: 'fa fa-folder-open', toggle: this.toggleFolder.bind(this), diff --git a/public/app/core/specs/manage_dashboards.jest.ts b/public/app/core/specs/manage_dashboards.jest.ts index 8c640bc0630..4b51e6848d0 100644 --- a/public/app/core/specs/manage_dashboards.jest.ts +++ b/public/app/core/specs/manage_dashboards.jest.ts @@ -20,9 +20,6 @@ describe('ManageDashboards', () => { icon: 'fa fa-folder', tags: [], isStarred: false, - folderId: 410, - folderTitle: 'afolder', - folderSlug: 'afolder', }, ], tags: [], @@ -77,9 +74,6 @@ describe('ManageDashboards', () => { icon: 'fa fa-folder', tags: [], isStarred: false, - folderId: 410, - folderTitle: 'afolder', - folderSlug: 'afolder', }, ], tags: [], @@ -112,8 +106,9 @@ describe('ManageDashboards', () => { tags: [], isStarred: false, folderId: 410, - folderTitle: 'afolder', - folderSlug: 'afolder', + folderUid: 'uid', + folderTitle: 'Folder', + folderUrl: '/dashboards/f/uid/folder', }, { id: 500, diff --git a/public/app/core/specs/search_srv.jest.ts b/public/app/core/specs/search_srv.jest.ts index 444939d1f4a..550d11bbf9e 100644 --- a/public/app/core/specs/search_srv.jest.ts +++ b/public/app/core/specs/search_srv.jest.ts @@ -190,7 +190,9 @@ describe('SearchSrv', () => { title: 'dash in folder1 1', type: 'dash-db', folderId: 1, + folderUid: 'uid', folderTitle: 'folder1', + folderUrl: '/dashboards/f/uid/folder1', }, ]) ); @@ -206,6 +208,11 @@ describe('SearchSrv', () => { it('should group results by folder', () => { expect(results).toHaveLength(2); + expect(results[0].id).toEqual(0); + expect(results[1].id).toEqual(1); + expect(results[1].uid).toEqual('uid'); + expect(results[1].title).toEqual('folder1'); + expect(results[1].url).toEqual('/dashboards/f/uid/folder1'); }); }); From 8ce2074eb20a84f52303deacb220702925c23748 Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Mon, 5 Feb 2018 14:05:06 +0100 Subject: [PATCH 13/48] docs: fix links in HTTP API Reference page Fixes #10745 --- docs/sources/http_api/index.md | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/docs/sources/http_api/index.md b/docs/sources/http_api/index.md index 9c5d0e7d49a..cbfe004b14c 100644 --- a/docs/sources/http_api/index.md +++ b/docs/sources/http_api/index.md @@ -18,12 +18,15 @@ dashboards, creating users and updating data sources. ## Supported HTTP APIs: -* [Authentication API]({{< relref "auth.md" >}}) -* [Dashboard API]({{< relref "dashboard.md" >}}) -* [Data Source API]({{< relref "data_source.md" >}}) -* [Organisation API]({{< relref "org.md" >}}) -* [User API]({{< relref "user.md" >}}) -* [Admin API]({{< relref "admin.md" >}}) -* [Snapshot API]({{< relref "snapshot.md" >}}) -* [Preferences API]({{< relref "preferences.md" >}}) -* [Other API]({{< relref "other.md" >}}) +* [Authentication API]({{< relref "/http_api/auth.md" >}}) +* [Dashboard API]({{< relref "/http_api/dashboard.md" >}}) +* [Dashboard Versions API]({{< relref "http_api/dashboard_versions.md" >}}) +* [Data Source API]({{< relref "http_api/data_source.md" >}}) +* [Organisation API]({{< relref "http_api/org.md" >}}) +* [Snapshot API]({{< relref "http_api/snapshot.md" >}}) +* [Annotations API]({{< relref "http_api/annotations.md" >}}) +* [Alerting API]({{< relref "http_api/alerting.md" >}}) +* [User API]({{< relref "http_api/user.md" >}}) +* [Admin API]({{< relref "http_api/admin.md" >}}) +* [Preferences API]({{< relref "http_api/preferences.md" >}}) +* [Other API]({{< relref "http_api/other.md" >}}) From 04a94ce39638573d311750549af589ab071c8317 Mon Sep 17 00:00:00 2001 From: Carl Bergquist Date: Mon, 5 Feb 2018 14:11:19 +0100 Subject: [PATCH 14/48] adds unique index for org_id+folder_id+title on dashboards (#10766) --- pkg/services/sqlstore/migrations/dashboard_mig.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/services/sqlstore/migrations/dashboard_mig.go b/pkg/services/sqlstore/migrations/dashboard_mig.go index edca733e174..bb2aea4bd51 100644 --- a/pkg/services/sqlstore/migrations/dashboard_mig.go +++ b/pkg/services/sqlstore/migrations/dashboard_mig.go @@ -167,4 +167,8 @@ func addDashboardMigration(mg *Migrator) { mg.AddMigration("Remove unique index org_id_slug", NewDropIndexMigration(dashboardV2, &Index{ Cols: []string{"org_id", "slug"}, Type: UniqueIndex, })) + + mg.AddMigration("Add unique index for dashboard_org_id_title_folder_id", NewAddIndexMigration(dashboardV2, &Index{ + Cols: []string{"org_id", "folder_id", "title"}, Type: UniqueIndex, + })) } From 2d1bd270fbe3965afab589fec897a84237c537ec Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Mon, 5 Feb 2018 13:28:24 +0000 Subject: [PATCH 15/48] Stale permissions (#10768) * dashfolders: hide permissions in settings if folder has changed and the dashboard has not been saved yet. Otherwise the use will see stale permissions from the original folder. * dashfolders: return folder url for inherited permissions --- pkg/api/dashboard_acl.go | 6 ++++ pkg/models/dashboard_acl.go | 5 +++ pkg/services/sqlstore/dashboard_acl.go | 32 +++++++++++++++---- .../ManageDashboards/FolderPermissions.tsx | 2 +- .../Permissions/AddPermissions.jest.tsx | 2 +- .../components/Permissions/AddPermissions.tsx | 7 ---- .../Permissions/DashboardPermissions.tsx | 2 +- .../features/dashboard/settings/settings.html | 5 ++- .../features/dashboard/settings/settings.ts | 8 ++++- 9 files changed, 51 insertions(+), 18 deletions(-) diff --git a/pkg/api/dashboard_acl.go b/pkg/api/dashboard_acl.go index 6eb11047723..b5d912d25f1 100644 --- a/pkg/api/dashboard_acl.go +++ b/pkg/api/dashboard_acl.go @@ -24,6 +24,12 @@ func GetDashboardAclList(c *middleware.Context) Response { return ApiError(500, "Failed to get dashboard acl", err) } + for _, perm := range acl { + if perm.Slug != "" { + perm.Url = m.GetDashboardFolderUrl(perm.IsFolder, perm.Uid, perm.Slug) + } + } + return Json(200, acl) } diff --git a/pkg/models/dashboard_acl.go b/pkg/models/dashboard_acl.go index fa7ad00de7f..933487650e3 100644 --- a/pkg/models/dashboard_acl.go +++ b/pkg/models/dashboard_acl.go @@ -59,6 +59,11 @@ type DashboardAclInfoDTO struct { Role *RoleType `json:"role,omitempty"` Permission PermissionType `json:"permission"` PermissionName string `json:"permissionName"` + Uid string `json:"uid"` + Title string `json:"title"` + Slug string `json:"slug"` + IsFolder bool `json:"isFolder"` + Url string `json:"url"` } // diff --git a/pkg/services/sqlstore/dashboard_acl.go b/pkg/services/sqlstore/dashboard_acl.go index 9027f74f33a..829182a8195 100644 --- a/pkg/services/sqlstore/dashboard_acl.go +++ b/pkg/services/sqlstore/dashboard_acl.go @@ -113,6 +113,7 @@ func SetDashboardAcl(cmd *m.SetDashboardAclCommand) error { }) } +// RemoveDashboardAcl removes a specified permission from the dashboard acl func RemoveDashboardAcl(cmd *m.RemoveDashboardAclCommand) error { return inTransaction(func(sess *DBSession) error { var rawSQL = "DELETE FROM " + dialect.Quote("dashboard_acl") + " WHERE org_id =? and id=?" @@ -125,6 +126,11 @@ func RemoveDashboardAcl(cmd *m.RemoveDashboardAclCommand) error { }) } +// GetDashboardAclInfoList returns a list of permissions for a dashboard. They can be fetched from three +// different places. +// 1) Permissions for the dashboard +// 2) permissions for its parent folder +// 3) if no specific permissions have been set for the dashboard or its parent folder then get the default permissions func GetDashboardAclInfoList(query *m.GetDashboardAclInfoListQuery) error { var err error @@ -141,7 +147,11 @@ func GetDashboardAclInfoList(query *m.GetDashboardAclInfoListQuery) error { da.updated, '' as user_login, '' as user_email, - '' as team + '' as team, + '' as title, + '' as slug, + '' as uid,` + + dialect.BooleanStr(false) + ` AS is_folder FROM dashboard_acl as da WHERE da.dashboard_id = -1` query.Result = make([]*m.DashboardAclInfoDTO, 0) @@ -155,6 +165,7 @@ func GetDashboardAclInfoList(query *m.GetDashboardAclInfoListQuery) error { )`, query.DashboardId, query.DashboardId) rawSQL := ` + -- get permissions for the dashboard and its parent folder SELECT da.id, da.org_id, @@ -167,13 +178,18 @@ func GetDashboardAclInfoList(query *m.GetDashboardAclInfoListQuery) error { da.updated, u.login AS user_login, u.email AS user_email, - ug.name AS team + ug.name AS team, + d.title, + d.slug, + d.uid, + d.is_folder FROM` + dialect.Quote("dashboard_acl") + ` as da LEFT OUTER JOIN ` + dialect.Quote("user") + ` AS u ON u.id = da.user_id LEFT OUTER JOIN team ug on ug.id = da.team_id + LEFT OUTER JOIN dashboard d on da.dashboard_id = d.id WHERE dashboard_id ` + dashboardFilter + ` AND da.org_id = ? - -- Also include default permission if has_acl = 0 + -- Also include default permissions if folder or dashboard field "has_acl" is false UNION SELECT @@ -188,10 +204,14 @@ func GetDashboardAclInfoList(query *m.GetDashboardAclInfoListQuery) error { da.updated, '' as user_login, '' as user_email, - '' as team - FROM dashboard_acl as da, + '' as team, + folder.title, + folder.slug, + folder.uid, + folder.is_folder + FROM dashboard_acl as da, dashboard as dash - LEFT JOIN dashboard folder on dash.folder_id = folder.id + LEFT OUTER JOIN dashboard folder on dash.folder_id = folder.id WHERE dash.id = ? AND ( dash.has_acl = ` + dialect.BooleanStr(false) + ` or diff --git a/public/app/containers/ManageDashboards/FolderPermissions.tsx b/public/app/containers/ManageDashboards/FolderPermissions.tsx index a62165d7194..500072c1da0 100644 --- a/public/app/containers/ManageDashboards/FolderPermissions.tsx +++ b/public/app/containers/ManageDashboards/FolderPermissions.tsx @@ -63,7 +63,7 @@ export class FolderPermissions extends Component {
    - + diff --git a/public/app/core/components/Permissions/AddPermissions.jest.tsx b/public/app/core/components/Permissions/AddPermissions.jest.tsx index 98a00a8bd7b..48ff20a16aa 100644 --- a/public/app/core/components/Permissions/AddPermissions.jest.tsx +++ b/public/app/core/components/Permissions/AddPermissions.jest.tsx @@ -26,7 +26,7 @@ describe('AddPermissions', () => { } ); - wrapper = shallow(); + wrapper = shallow(); instance = wrapper.instance(); return store.permissions.load(1, true, false); }); diff --git a/public/app/core/components/Permissions/AddPermissions.tsx b/public/app/core/components/Permissions/AddPermissions.tsx index 3ce4360ff86..94afa7c1180 100644 --- a/public/app/core/components/Permissions/AddPermissions.tsx +++ b/public/app/core/components/Permissions/AddPermissions.tsx @@ -9,7 +9,6 @@ import { permissionOptions } from 'app/stores/PermissionsStore/PermissionsStore' export interface IProps { permissions: any; backendSrv: any; - dashboardId: any; } @observer class AddPermissions extends Component { @@ -31,12 +30,6 @@ class AddPermissions extends Component { const { value } = evt.target; const { permissions } = this.props; - // if (value === 'Viewer' || value === 'Editor') { - // // permissions.addStoreItem({ permission: 1, role: value, dashboardId: dashboardId }, dashboardId); - // // this.resetNewType(); - // return; - // } - permissions.setNewType(value); } diff --git a/public/app/core/components/Permissions/DashboardPermissions.tsx b/public/app/core/components/Permissions/DashboardPermissions.tsx index d6b293da4bb..12339cc7c34 100644 --- a/public/app/core/components/Permissions/DashboardPermissions.tsx +++ b/public/app/core/components/Permissions/DashboardPermissions.tsx @@ -53,7 +53,7 @@ class DashboardPermissions extends Component { - +
    - +
    +
    You have changed folder, please save to view permissions.
    +
    diff --git a/public/app/features/dashboard/settings/settings.ts b/public/app/features/dashboard/settings/settings.ts index 09aa96e42ae..e9d5c6180be 100755 --- a/public/app/features/dashboard/settings/settings.ts +++ b/public/app/features/dashboard/settings/settings.ts @@ -14,6 +14,7 @@ export class SettingsCtrl { canSave: boolean; canDelete: boolean; sections: any[]; + hasUnsavedFolderChange: boolean; /** @ngInject */ constructor(private $scope, private $location, private $rootScope, private backendSrv, private dashboardSrv) { @@ -38,6 +39,7 @@ export class SettingsCtrl { this.$rootScope.onAppEvent('$routeUpdate', this.onRouteUpdated.bind(this), $scope); this.$rootScope.appEvent('dash-scroll', { animate: false, pos: 0 }); + this.$rootScope.onAppEvent('dashboard-saved', this.onPostSave.bind(this), $scope); } buildSectionList() { @@ -135,6 +137,10 @@ export class SettingsCtrl { this.dashboardSrv.saveDashboard(); } + onPostSave() { + this.hasUnsavedFolderChange = false; + } + hideSettings() { var urlParams = this.$location.search(); delete urlParams.editview; @@ -195,7 +201,7 @@ export class SettingsCtrl { onFolderChange(folder) { this.dashboard.meta.folderId = folder.id; this.dashboard.meta.folderTitle = folder.title; - this.dashboard.meta.folderSlug = folder.slug; + this.hasUnsavedFolderChange = true; } getFolder() { From e6b82b2fb190fb59c40ee07e9f396f1f0ce3c777 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 5 Feb 2018 15:23:46 +0100 Subject: [PATCH 16/48] fix: fixed permission list caching issue, fixes #10750 --- .../ManageDashboards/FolderPermissions.tsx | 3 ++- .../ManageDashboards/FolderSettings.jest.tsx | 17 +++++++++++++---- public/app/stores/FolderStore/FolderStore.ts | 9 +++++++++ .../stores/PermissionsStore/PermissionsStore.ts | 10 +++++++--- 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/public/app/containers/ManageDashboards/FolderPermissions.tsx b/public/app/containers/ManageDashboards/FolderPermissions.tsx index 500072c1da0..93cfe9494c2 100644 --- a/public/app/containers/ManageDashboards/FolderPermissions.tsx +++ b/public/app/containers/ManageDashboards/FolderPermissions.tsx @@ -1,4 +1,4 @@ -import React, { Component } from 'react'; +import React, { Component } from 'react'; import { inject, observer } from 'mobx-react'; import { toJS } from 'mobx'; import IContainerProps from 'app/containers/IContainerProps'; @@ -8,6 +8,7 @@ import Tooltip from 'app/core/components/Tooltip/Tooltip'; import PermissionsInfo from 'app/core/components/Permissions/PermissionsInfo'; import AddPermissions from 'app/core/components/Permissions/AddPermissions'; import SlideDown from 'app/core/components/Animations/SlideDown'; + @inject('nav', 'folder', 'view', 'permissions') @observer export class FolderPermissions extends Component { diff --git a/public/app/containers/ManageDashboards/FolderSettings.jest.tsx b/public/app/containers/ManageDashboards/FolderSettings.jest.tsx index bf7b35ed05d..3630bf534ba 100644 --- a/public/app/containers/ManageDashboards/FolderSettings.jest.tsx +++ b/public/app/containers/ManageDashboards/FolderSettings.jest.tsx @@ -14,6 +14,7 @@ describe('FolderSettings', () => { dashboard: { id: 1, title: 'Folder Name', + uid: 'uid-str', }, meta: { url: '/dashboards/f/uid/folder-name', @@ -23,19 +24,27 @@ describe('FolderSettings', () => { ); const store = RootStore.create( - {}, + { + view: { + path: 'asd', + query: {}, + routeParams: { + uid: 'uid-str', + }, + }, + }, { backendSrv: backendSrv, } ); wrapper = shallow(); - return wrapper - .dive() + page = wrapper.dive(); + return page .instance() .loadStore() .then(() => { - page = wrapper.dive(); + page.update(); }); }); diff --git a/public/app/stores/FolderStore/FolderStore.ts b/public/app/stores/FolderStore/FolderStore.ts index 6f14e7221f8..e4533f6a3a9 100644 --- a/public/app/stores/FolderStore/FolderStore.ts +++ b/public/app/stores/FolderStore/FolderStore.ts @@ -5,6 +5,7 @@ export const Folder = types.model('Folder', { title: types.string, url: types.string, canSave: types.boolean, + uid: types.string, hasChanged: types.boolean, }); @@ -14,15 +15,23 @@ export const FolderStore = types }) .actions(self => ({ load: flow(function* load(uid: string) { + // clear folder state + if (self.folder && self.folder.uid !== uid) { + self.folder = null; + } + const backendSrv = getEnv(self).backendSrv; const res = yield backendSrv.getDashboardByUid(uid); + self.folder = Folder.create({ id: res.dashboard.id, title: res.dashboard.title, url: res.meta.url, + uid: res.dashboard.uid, canSave: res.meta.canSave, hasChanged: false, }); + return res; }), diff --git a/public/app/stores/PermissionsStore/PermissionsStore.ts b/public/app/stores/PermissionsStore/PermissionsStore.ts index 9db76c4e124..02413f6b0a1 100644 --- a/public/app/stores/PermissionsStore/PermissionsStore.ts +++ b/public/app/stores/PermissionsStore/PermissionsStore.ts @@ -115,6 +115,7 @@ export const PermissionsStore = types self.fetching = false; self.error = null; }), + addStoreItem: flow(function* addStoreItem() { self.error = null; let item = { @@ -152,11 +153,13 @@ export const PermissionsStore = types resetNewType(); return updateItems(self); }), + removeStoreItem: flow(function* removeStoreItem(idx: number) { self.error = null; self.items.splice(idx, 1); return updateItems(self); }), + updatePermissionOnIndex: flow(function* updatePermissionOnIndex( idx: number, permission: number, @@ -166,18 +169,19 @@ export const PermissionsStore = types self.items[idx].updatePermission(permission, permissionName); return updateItems(self); }), + setNewType(newType: string) { self.newItem = NewPermissionsItem.create({ type: newType }); }, + resetNewType() { resetNewType(); }, + toggleAddPermissions() { self.isAddPermissionsVisible = !self.isAddPermissionsVisible; }, - showAddPermissions() { - self.isAddPermissionsVisible = true; - }, + hideAddPermissions() { self.isAddPermissionsVisible = false; }, From 3e2da1fee53675ec9254995472ae403000b94e83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 5 Feb 2018 15:28:57 +0100 Subject: [PATCH 17/48] build: increased version to beta1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index acb992a0936..aad7d2ce92c 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "company": "Grafana Labs" }, "name": "grafana", - "version": "5.0.0-pre1", + "version": "5.0.0-beta1", "repository": { "type": "git", "url": "http://github.com/grafana/grafana.git" From 8f98e8b8f4d5968f1a74c185ecc6002ebce4819a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 5 Feb 2018 15:36:16 +0100 Subject: [PATCH 18/48] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2dacbb716e4..62d9385a526 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -61,6 +61,7 @@ Dashboard panels and rows are positioned using a gridPos object `{x: 0, y: 0, w: * **Singlestat**: suppress error when result contains no datapoints [#9636](https://github.com/grafana/grafana/issues/9636), thx [@utkarshcmu](https://github.com/utkarshcmu) * **Postgres/MySQL**: Control quoting in SQL-queries when using template variables [#9030](https://github.com/grafana/grafana/issues/9030), thanks [@svenklemm](https://github.com/svenklemm) * **Pagerduty**: Pagerduty dont auto resolve incidents by default anymore. [#10222](https://github.com/grafana/grafana/issues/10222) +* **Cloudwatch**: Fix for multi-valued templated queries. [#9903](https://github.com/grafana/grafana/issues/9903) ## Tech * **RabbitMq**: Remove support for publishing events to RabbitMQ [#9645](https://github.com/grafana/grafana/issues/9645) From b2f62ae19c9c6c14440a4f96cd485e7aac67dd7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 5 Feb 2018 16:02:17 +0100 Subject: [PATCH 19/48] docs: update docs with download links --- docs/sources/installation/debian.md | 10 ++++++++++ docs/sources/installation/rpm.md | 7 +++++++ docs/sources/installation/upgrading.md | 5 +++++ docs/sources/installation/windows.md | 1 + 4 files changed, 23 insertions(+) diff --git a/docs/sources/installation/debian.md b/docs/sources/installation/debian.md index b742e96c869..bfc7fdc0a3d 100644 --- a/docs/sources/installation/debian.md +++ b/docs/sources/installation/debian.md @@ -16,6 +16,7 @@ weight = 1 Description | Download ------------ | ------------- Stable for Debian-based Linux | [grafana_4.6.3_amd64.deb](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_4.6.3_amd64.deb) +Beta for Debian-based Linux | [grafana_5.0.0-beta1_amd64.deb](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_5.0.0-beta1_amd64.deb) Read [Upgrading Grafana]({{< relref "installation/upgrading.md" >}}) for tips and guidance on updating an existing installation. @@ -27,6 +28,15 @@ installation. wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_4.6.3_amd64.deb sudo apt-get install -y adduser libfontconfig sudo dpkg -i grafana_4.6.3_amd64.deb +``` + +## Install Latest Beta + +```bash +wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_5.0.0-beta1_amd64.deb +sudo apt-get install -y adduser libfontconfig +sudo dpkg -i grafana_5.0.0-beta1_amd64.deb + ``` ## APT Repository diff --git a/docs/sources/installation/rpm.md b/docs/sources/installation/rpm.md index d3e796a78c8..f0c498c819f 100644 --- a/docs/sources/installation/rpm.md +++ b/docs/sources/installation/rpm.md @@ -16,6 +16,7 @@ weight = 2 Description | Download ------------ | ------------- Stable for CentOS / Fedora / OpenSuse / Redhat Linux | [4.6.3 (x86-64 rpm)](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-4.6.3-1.x86_64.rpm) +Latest Beta for CentOS / Fedora / OpenSuse / Redhat Linux | [5.0.0-beta1 (x86-64 rpm)](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.0.0-beta1.x86_64.rpm) Read [Upgrading Grafana]({{< relref "installation/upgrading.md" >}}) for tips and guidance on updating an existing installation. @@ -28,6 +29,12 @@ You can install Grafana using Yum directly. $ sudo yum install https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-4.6.3-1.x86_64.rpm ``` +## Install Beta + +```bash +$ sudo yum install https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.0.0-beta1.x86_64.rpm +``` + Or install manually using `rpm`. #### On CentOS / Fedora / Redhat: diff --git a/docs/sources/installation/upgrading.md b/docs/sources/installation/upgrading.md index 6a4b4e8f047..af40c20a40b 100644 --- a/docs/sources/installation/upgrading.md +++ b/docs/sources/installation/upgrading.md @@ -101,3 +101,8 @@ as this will make upgrades easier without risking losing your config changes. ## Upgrading from 2.x We are not aware of any issues upgrading directly from 2.x to 4.x but to be on the safe side go via 3.x => 4.x. + +## Upgrading to v5.0 + +The dashboard grid layout engine has changed. All dashboards will be automatically upgraded to new +positioning system when you load them in v5. Dashboards saved in v5 will not work in older versions of Grafana. diff --git a/docs/sources/installation/windows.md b/docs/sources/installation/windows.md index 7c6a97085df..08d234d63f9 100644 --- a/docs/sources/installation/windows.md +++ b/docs/sources/installation/windows.md @@ -14,6 +14,7 @@ weight = 3 Description | Download ------------ | ------------- Latest stable package for Windows | [grafana.4.6.3.windows-x64.zip](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-4.6.3.windows-x64.zip) +Latest beta package for Windows | [grafana.5.0.0-beta1.windows-x64.zip](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.0.0-beta1.windows-x64.zip) Read [Upgrading Grafana]({{< relref "installation/upgrading.md" >}}) for tips and guidance on updating an existing installation. From 97bba1d82612b0aaa2eb29b27f30d6d0b1bb9317 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 5 Feb 2018 16:29:10 +0100 Subject: [PATCH 20/48] build: updated publish script --- packaging/publish/publish_testing.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packaging/publish/publish_testing.sh b/packaging/publish/publish_testing.sh index 276193ad63f..ca5e7aea90c 100755 --- a/packaging/publish/publish_testing.sh +++ b/packaging/publish/publish_testing.sh @@ -1,6 +1,6 @@ #! /usr/bin/env bash -deb_ver=4.6.0-beta1 -rpm_ver=4.6.0-beta1 +deb_ver=5.0.0-beta1 +rpm_ver=5.0.0-beta1 wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_${deb_ver}_amd64.deb From 9138b38b93ba2a419b3210af57a0cb571a7472d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 5 Feb 2018 16:32:30 +0100 Subject: [PATCH 21/48] Update CHANGELOG.md --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 62d9385a526..c24983bf38d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,6 @@ -# 5.0.0 (unreleased / master branch) +# 5.0.0-beta2 (unrelased) + +# 5.0.0-beta1 (2018-02-05) Grafana v5.0 is going to be the biggest and most foundational release Grafana has ever had, coming with a ton of UX improvements, a new dashboard grid engine, dashboard folders, user teams and permissions. Checkout out this [video preview](https://www.youtube.com/watch?v=BC_YRNpqj5k) of Grafana v5. From e86fe0b1444bb0ec33a952be1f14c81dacc4bcad Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Mon, 5 Feb 2018 16:40:49 +0100 Subject: [PATCH 22/48] docs: update dashboard model, new url structure and api changes in what's new in v5 --- docs/sources/guides/whats-new-in-v5.md | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/docs/sources/guides/whats-new-in-v5.md b/docs/sources/guides/whats-new-in-v5.md index 0cda207d650..6c70682d3f6 100644 --- a/docs/sources/guides/whats-new-in-v5.md +++ b/docs/sources/guides/whats-new-in-v5.md @@ -111,10 +111,17 @@ in sync with dashboards in Grafana's database. The dashboard provisioner has mul which makes it possible to star them, use one as the home dashboard, set permissions and other features in Grafana that expects the dashboards to exist in the database. More info in the [dashboard provisioning docs](/administration/provisioning/#dashboards) -# Dashboard model & API +# Dashboard model, new url structure & API changes -We are introducing a new identifier (`uid`) in the dashboard JSON model. The new identifier will be a 9-12 character long unique id. -We are also changing the route for getting dashboards to use this `uid` instead of the slug that the current route and API are using. -We will keep supporting the old route for backward compatibility. This will make it possible to change the title on dashboards without breaking links. -Sharing dashboards between instances becomes much easier since the uid is unique (unique enough). This might seem like a small change, -but we are incredibly excited about it since it will make it much easier to manage, collaborate and navigate between dashboards. +We are introducing a new unique identifier (`uid`) in the dashboard JSON model. It's automatically +generated if not provided when creating a dashboard and will have a length of 9-12 characters. + +The unique identifier allows having consistent URL's for accessing dashboards and sharing them +between instances. The new routes and API's for accessing dashboards will use the `uid` instead +of the `slug`. We'll keep supporting the old routes for accessing dashboards for backward +compatibility, but please note that we'll deprecate the old slug-based routes in the future. +This means that changing the title of dashboards will not break any bookmarked links. + +Sharing dashboards between instances becomes much easier since the `uid` is unique (unique enough). +This might seem like a small change, but we are incredibly excited about it since it will make it +much easier to manage, collaborate and navigate between dashboards. From 24a1abaab2b98a59f589acfee39efbdeca28790b Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Mon, 5 Feb 2018 16:50:33 +0100 Subject: [PATCH 23/48] Update CHANGELOG.md --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c24983bf38d..68470d6a1c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ Grafana v5.0 is going to be the biggest and most foundational release Grafana ha - **Templating**: Vertical repeat direction for panel repeats. - **UX**: Major update to page header and navigation - **Dashboard settings**: Combine dashboard settings views into one with side menu, [#9750](https://github.com/grafana/grafana/issues/9750) +- **Persistent dashboard url's**: New url's for dashboards that allows renaming dashboards without breaking links. [#7883](https://github.com/grafana/grafana/issues/7883) ## Breaking changes @@ -21,7 +22,7 @@ From `/etc/grafana/datasources` to `/etc/grafana/provisioning/datasources` when * **Pagerduty** The notifier now defaults to not auto resolve incidents. More details at [#10222](https://github.com/grafana/grafana/issues/10222) * **HTTP API** -- `GET /api/alerts` property dashboardUri renamed to url and is now the full url (that is including app sub url). +- `GET /api/alerts` property dashboardUri renamed to url and is now the full url (that is including app sub url). ## New Dashboard Grid From 7a968c10251538225a8f3f9f45e45f73dfbe6668 Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Mon, 5 Feb 2018 16:53:32 +0100 Subject: [PATCH 24/48] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 68470d6a1c5..901a2145e0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,7 +22,7 @@ From `/etc/grafana/datasources` to `/etc/grafana/provisioning/datasources` when * **Pagerduty** The notifier now defaults to not auto resolve incidents. More details at [#10222](https://github.com/grafana/grafana/issues/10222) * **HTTP API** -- `GET /api/alerts` property dashboardUri renamed to url and is now the full url (that is including app sub url). + - `GET /api/alerts` property dashboardUri renamed to url and is now the full url (that is including app sub url). ## New Dashboard Grid From e9aadab3552b2ea21da7dc2cf0106591528b4a1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 5 Feb 2018 16:59:06 +0100 Subject: [PATCH 25/48] docs: updated whats new --- docs/sources/guides/whats-new-in-v5.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/sources/guides/whats-new-in-v5.md b/docs/sources/guides/whats-new-in-v5.md index 6c70682d3f6..5eef8b73615 100644 --- a/docs/sources/guides/whats-new-in-v5.md +++ b/docs/sources/guides/whats-new-in-v5.md @@ -12,6 +12,8 @@ weight = -6 # What's New in Grafana v5.0 +> Out in beta: [Download now!](https://grafana.com/grafana/download/5.0.0-beta1) + This is the most substantial update that Grafana has ever seen. This article will detail the major new features and enhancements. - [New Dashboard Layout Engine]({{< relref "#new-dashboard-layout-engine" >}}) enables a much easier drag, drop and resize experience and new types of layouts. From 061320ba7b2d8cbfc498ffb7e8fb2c7f1fca5a6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 5 Feb 2018 17:26:44 +0100 Subject: [PATCH 26/48] docs: minor update --- docs/sources/administration/permissions.md | 11 ++++++++++- docs/sources/guides/whats-new-in-v5.md | 8 ++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/docs/sources/administration/permissions.md b/docs/sources/administration/permissions.md index 34459e2319a..5796d50f1fe 100644 --- a/docs/sources/administration/permissions.md +++ b/docs/sources/administration/permissions.md @@ -31,7 +31,7 @@ Can do everything scoped to the organization. For example: - Add & Edit data sources. - Add & Edit organization users & teams. - Configure App plugins & set org settings. - + ### Editor Role - Can create and modify dashboards & alert rules. This can be disabled on specific folders and dashboards. @@ -74,3 +74,12 @@ Access Control List (ACL). - You cannot override permissions for users with **Org Admin Role** - A more specific permission with lower permission level will not have any effect if a more general rule exists with higher permission level. For example if "Everyone with Editor Role Can Edit" exists in the ACL list then **John Doe** will still have Edit permission even after you have specifically added a permission for this user with the permission set to **View**. You need to remove or lower the permission level of the more general rule. + +### Data source permissions + +Permissions on dashboards and folders **do not** include permissions on data sources. A user with `Viewer` role +can still issue any possible query to a data source, not just those queries that exist on dashboards he/she has access to. +We hope to add permissions on data sources in a future release. Until then **do not** view dashboard permissions as a secure +way to restrict user data access. Dashboard permissions only limits what dashboards & folders a user can view & edit not which +data sources a user can access nor what queries a user can issue. + diff --git a/docs/sources/guides/whats-new-in-v5.md b/docs/sources/guides/whats-new-in-v5.md index 5eef8b73615..0dd9337e404 100644 --- a/docs/sources/guides/whats-new-in-v5.md +++ b/docs/sources/guides/whats-new-in-v5.md @@ -12,7 +12,7 @@ weight = -6 # What's New in Grafana v5.0 -> Out in beta: [Download now!](https://grafana.com/grafana/download/5.0.0-beta1) +> Out in beta: [Download now!](https://www.youtube.com/watch?v=Izr0IBgoTZQ) This is the most substantial update that Grafana has ever seen. This article will detail the major new features and enhancements. @@ -87,7 +87,11 @@ We hope to do more with teams in future releases like integration with LDAP and {{< docs-imagebox img="/img/docs/v50/folder_permissions.png" max-width="1000px" class="docs-image--right" >}} -You can assign permissions to folders and dashboards. The default user role-based permissions can be removed and replaced with specific teams or users enabling more control over what a user can see and edit. +You can assign permissions to folders and dashboards. The default user role-based permissions can be removed and +replaced with specific teams or users enabling more control over what a user can see and edit. + +Dashboard permissions only limits what dashboards & folders a user can view & edit not which +data sources a user can access nor what queries a user can issue.
    From e800b19ef6c07eeb85b261b0b9797790e41e873d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 5 Feb 2018 17:56:48 +0100 Subject: [PATCH 27/48] docs: fix download link --- docs/sources/guides/whats-new-in-v5.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/sources/guides/whats-new-in-v5.md b/docs/sources/guides/whats-new-in-v5.md index 0dd9337e404..9712976e0dc 100644 --- a/docs/sources/guides/whats-new-in-v5.md +++ b/docs/sources/guides/whats-new-in-v5.md @@ -12,7 +12,7 @@ weight = -6 # What's New in Grafana v5.0 -> Out in beta: [Download now!](https://www.youtube.com/watch?v=Izr0IBgoTZQ) +> Out in beta: [Download now!](https://grafana.com/grafana/download/5.0.0-beta1) This is the most substantial update that Grafana has ever seen. This article will detail the major new features and enhancements. @@ -27,7 +27,7 @@ This is the most substantial update that Grafana has ever seen. This article wil ### Video showing new features - +
    ## New Dashboard Layout Engine From e1d857887fe1064385a29b7008f7b9bcd6589e7c Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Mon, 5 Feb 2018 17:58:43 +0100 Subject: [PATCH 28/48] docs: update dashboard model, persistent urls and api changes in what's new in v5 --- docs/sources/guides/whats-new-in-v5.md | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/docs/sources/guides/whats-new-in-v5.md b/docs/sources/guides/whats-new-in-v5.md index 0dd9337e404..90651872964 100644 --- a/docs/sources/guides/whats-new-in-v5.md +++ b/docs/sources/guides/whats-new-in-v5.md @@ -24,6 +24,7 @@ This is the most substantial update that Grafana has ever seen. This article wil - [Group users into teams]({{< relref "#teams" >}}) and use them in the new permission system. - [Datasource provisioning]({{< relref "#data-sources" >}}) makes it possible to setup datasources via config files. - [Dashboard provisioning]({{< relref "#dashboards" >}}) makes it possible to setup dashboards via config files. +- [Persistent dashboard url's]({{< relref "#dashboard-model-persistent-url-s-and-api-changes" >}}) makes it possible to rename dashboards without breaking links. ### Video showing new features @@ -51,7 +52,7 @@ Almost every page has seen significant UX improvements. All pages (except dashbo
    -### Dashboard Settings +## Dashboard Settings {{< docs-imagebox img="/img/docs/v50/dashboard_settings.png" max-width="1000px" class="docs-image--right" >}} Dashboard pages have a new header toolbar where buttons and actions are now all moved to the right. All the dashboard @@ -95,7 +96,7 @@ data sources a user can access nor what queries a user can issue.
    -# Provisioning from configuration +## Provisioning from configuration In previous versions of Grafana, you could only use the API for provisioning data sources and dashboards. But that required the service to be running before you started creating dashboards and you also needed to @@ -117,17 +118,22 @@ in sync with dashboards in Grafana's database. The dashboard provisioner has mul which makes it possible to star them, use one as the home dashboard, set permissions and other features in Grafana that expects the dashboards to exist in the database. More info in the [dashboard provisioning docs](/administration/provisioning/#dashboards) -# Dashboard model, new url structure & API changes +## Dashboard model, persistent url's and API changes We are introducing a new unique identifier (`uid`) in the dashboard JSON model. It's automatically generated if not provided when creating a dashboard and will have a length of 9-12 characters. -The unique identifier allows having consistent URL's for accessing dashboards and sharing them -between instances. The new routes and API's for accessing dashboards will use the `uid` instead -of the `slug`. We'll keep supporting the old routes for accessing dashboards for backward -compatibility, but please note that we'll deprecate the old slug-based routes in the future. -This means that changing the title of dashboards will not break any bookmarked links. +The unique identifier allows having persistent URL's for accessing dashboards, sharing them +between instances and when using [dashboard provisioning](#dashboards). This means that dashboard can +be renamed without breaking any links. We're changing the url format for dashboards +from `/dashboard/db/:slug` to `/d/:uid/:slug`. We'll keep supporting the old slug-based url's for dashboards +and redirects to the new one for backward compatibility. Please note that the old slug-based url's +have been deprecated and will be removed in a future release. Sharing dashboards between instances becomes much easier since the `uid` is unique (unique enough). This might seem like a small change, but we are incredibly excited about it since it will make it much easier to manage, collaborate and navigate between dashboards. + +### API changes +New uid-based routes in the dashboard API have been introduced to retrieve and delete dashboards. +The corresponding slug-based routes have been deprecated and will be removed in a future release. From 4ce862c5b49a6d5d8e6fd69c10378d16b855e1ee Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Mon, 5 Feb 2018 18:11:43 +0100 Subject: [PATCH 29/48] scroll: use wheelpropagation. Ref #10772 Once the vertical scrollbar comes to its end position, it should allow the page scroll bar to start scrolling. --- public/app/core/components/ScrollBar/ScrollBar.tsx | 5 +++-- public/app/core/components/scroll/scroll.ts | 4 +++- public/app/features/panel/panel_directive.ts | 4 +++- public/app/plugins/panel/graph/legend.ts | 1 + 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/public/app/core/components/ScrollBar/ScrollBar.tsx b/public/app/core/components/ScrollBar/ScrollBar.tsx index 49a200b0f3b..7d9e015df94 100644 --- a/public/app/core/components/ScrollBar/ScrollBar.tsx +++ b/public/app/core/components/ScrollBar/ScrollBar.tsx @@ -7,7 +7,6 @@ export interface Props { } export default class ScrollBar extends React.Component { - private container: any; private ps: PerfectScrollbar; @@ -16,7 +15,9 @@ export default class ScrollBar extends React.Component { } componentDidMount() { - this.ps = new PerfectScrollbar(this.container); + this.ps = new PerfectScrollbar(this.container, { + wheelPropagation: true, + }); } componentDidUpdate() { diff --git a/public/app/core/components/scroll/scroll.ts b/public/app/core/components/scroll/scroll.ts index 99245ed3331..720334d8973 100644 --- a/public/app/core/components/scroll/scroll.ts +++ b/public/app/core/components/scroll/scroll.ts @@ -6,7 +6,9 @@ export function geminiScrollbar() { return { restrict: 'A', link: function(scope, elem, attrs) { - let scrollbar = new PerfectScrollbar(elem[0]); + let scrollbar = new PerfectScrollbar(elem[0], { + wheelPropagation: true, + }); let lastPos = 0; appEvents.on( diff --git a/public/app/features/panel/panel_directive.ts b/public/app/features/panel/panel_directive.ts index 01730e2fede..dec7868a553 100644 --- a/public/app/features/panel/panel_directive.ts +++ b/public/app/features/panel/panel_directive.ts @@ -100,7 +100,9 @@ module.directive('grafanaPanel', function($rootScope, $document, $timeout) { // update scrollbar after mounting ctrl.events.on('component-did-mount', () => { if (ctrl.__proto__.constructor.scrollable) { - panelScrollbar = new PerfectScrollbar(panelContent[0]); + panelScrollbar = new PerfectScrollbar(panelContent[0], { + wheelPropagation: true, + }); } }); diff --git a/public/app/plugins/panel/graph/legend.ts b/public/app/plugins/panel/graph/legend.ts index 5db0a122b31..cd43ac58469 100644 --- a/public/app/plugins/panel/graph/legend.ts +++ b/public/app/plugins/panel/graph/legend.ts @@ -246,6 +246,7 @@ module.directive('graphLegend', function(popoverSrv, $timeout) { // Number of pixels the content height can surpass the container height without enabling the scroll bar. scrollYMarginOffset: 2, suppressScrollX: true, + wheelPropagation: true, }; if (!legendScrollbar) { From 24d882e7d89e0c5259e6f6d39cc2519c0aa6e9d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 5 Feb 2018 18:12:45 +0100 Subject: [PATCH 30/48] docs: fix --- docs/sources/guides/whats-new-in-v5.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/guides/whats-new-in-v5.md b/docs/sources/guides/whats-new-in-v5.md index 7b52bf6fe89..14419f7a4be 100644 --- a/docs/sources/guides/whats-new-in-v5.md +++ b/docs/sources/guides/whats-new-in-v5.md @@ -28,7 +28,7 @@ This is the most substantial update that Grafana has ever seen. This article wil ### Video showing new features - +
    ## New Dashboard Layout Engine From f97be541af45f7112619957bcf1f195b4c424a46 Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Mon, 5 Feb 2018 20:17:47 +0300 Subject: [PATCH 31/48] redirect "permission denied" requests to "/" (#10773) --- pkg/middleware/auth.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/middleware/auth.go b/pkg/middleware/auth.go index be3415d990b..826287e12f3 100644 --- a/pkg/middleware/auth.go +++ b/pkg/middleware/auth.go @@ -42,8 +42,7 @@ func accessForbidden(c *Context) { return } - c.SetCookie("redirect_to", url.QueryEscape(setting.AppSubUrl+c.Req.RequestURI), 0, setting.AppSubUrl+"/") - c.Redirect(setting.AppSubUrl + "/login") + c.Redirect(setting.AppSubUrl + "/") } func notAuthorized(c *Context) { From 690beac277ab37bc4edab9e6475bd8cacae95f68 Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Mon, 5 Feb 2018 18:42:47 +0100 Subject: [PATCH 32/48] Update changelog with deprecation notes of http api --- CHANGELOG.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 901a2145e0f..6508c4ff76a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ # 5.0.0-beta1 (2018-02-05) -Grafana v5.0 is going to be the biggest and most foundational release Grafana has ever had, coming with a ton of UX improvements, a new dashboard grid engine, dashboard folders, user teams and permissions. Checkout out this [video preview](https://www.youtube.com/watch?v=BC_YRNpqj5k) of Grafana v5. +Grafana v5.0 is going to be the biggest and most foundational release Grafana has ever had, coming with a ton of UX improvements, a new dashboard grid engine, dashboard folders, user teams and permissions. Checkout out this [video preview](https://www.youtube.com/watch?v=Izr0IBgoTZQ) of Grafana v5. ### New Major Features - **Dashboards** Dashboard folders, [#1611](https://github.com/grafana/grafana/issues/1611) @@ -69,6 +69,17 @@ Dashboard panels and rows are positioned using a gridPos object `{x: 0, y: 0, w: ## Tech * **RabbitMq**: Remove support for publishing events to RabbitMQ [#9645](https://github.com/grafana/grafana/issues/9645) +## Deprecation notes + +### HTTP API +The following operations have been deprecated and will be removed in a future release: + - `GET /api/dashboards/db/:slug` -> Use `GET /api/dashboards/uid/:uid` instead + - `DELETE /api/dashboards/db/:slug` -> Use `DELETE /api/dashboards/uid/:uid` instead + +The following properties have been deprecated and will be removed in a future release: + - `uri` property in `GET /api/search` -> Use new `url` or `uid` property instead + - `meta.slug` property in `GET /api/dashboards/uid/:uid` and `GET /api/dashboards/db/:slug` -> Use new `meta.url` or `dashboard.uid` property instead + # 4.6.3 (2017-12-14) ## Fixes From 1a8501450cfd400a3423baffe83c601a280352a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 5 Feb 2018 18:46:03 +0100 Subject: [PATCH 33/48] docs: video fix --- docs/sources/guides/whats-new-in-v5.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/guides/whats-new-in-v5.md b/docs/sources/guides/whats-new-in-v5.md index 14419f7a4be..bf056442e6b 100644 --- a/docs/sources/guides/whats-new-in-v5.md +++ b/docs/sources/guides/whats-new-in-v5.md @@ -28,7 +28,7 @@ This is the most substantial update that Grafana has ever seen. This article wil ### Video showing new features - +
    ## New Dashboard Layout Engine From 5d756707ab665b5aabb17bfd9d5af996507d770d Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Mon, 5 Feb 2018 19:18:20 +0100 Subject: [PATCH 34/48] dashlist: scroll fix when no header The first item in the dashlist has a margin that messes up the height calculation for the scroll bar when the Show headings option is not selected. This fix adds a margin-top set to 0 for the 1st item in the list in this case. This prevents a scrollbar being shown incorrectly. Fixes #10772 --- public/app/plugins/panel/dashlist/module.html | 2 +- public/sass/components/_panel_dashlist.scss | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/public/app/plugins/panel/dashlist/module.html b/public/app/plugins/panel/dashlist/module.html index 8fa3e7ef71f..586e7f7d097 100644 --- a/public/app/plugins/panel/dashlist/module.html +++ b/public/app/plugins/panel/dashlist/module.html @@ -4,7 +4,7 @@ {{group.header}}
    - + {{dash.title}} diff --git a/public/sass/components/_panel_dashlist.scss b/public/sass/components/_panel_dashlist.scss index 09ad4208099..5d100c7421c 100644 --- a/public/sass/components/_panel_dashlist.scss +++ b/public/sass/components/_panel_dashlist.scss @@ -21,4 +21,8 @@ .fa-star { color: $orange; } + + &--no-margintop { + margin-top: 0; + } } From 8c027ea7075fca07c53a8d8ab93f710447f43635 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Mon, 5 Feb 2018 19:31:16 +0100 Subject: [PATCH 35/48] scroll: css for #10722 Missed adding to previous commit. Ref #10722 --- public/sass/components/_panel_dashlist.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/sass/components/_panel_dashlist.scss b/public/sass/components/_panel_dashlist.scss index 5d100c7421c..2ac95a97ee0 100644 --- a/public/sass/components/_panel_dashlist.scss +++ b/public/sass/components/_panel_dashlist.scss @@ -22,7 +22,7 @@ color: $orange; } - &--no-margintop { + &--no-section-header { margin-top: 0; } } From 45d66e4b29ce325ee873dac53dc9834fa20772f1 Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Tue, 6 Feb 2018 12:01:10 +0300 Subject: [PATCH 36/48] embedded panel: hide side menu during init (#10788) --- public/app/features/panel/solo_panel_ctrl.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/features/panel/solo_panel_ctrl.ts b/public/app/features/panel/solo_panel_ctrl.ts index 323a88ddaee..2c7698db08e 100644 --- a/public/app/features/panel/solo_panel_ctrl.ts +++ b/public/app/features/panel/solo_panel_ctrl.ts @@ -9,7 +9,7 @@ export class SoloPanelCtrl { $scope.init = function() { contextSrv.sidemenu = false; - appEvents.emit('toggle-sidemenu'); + appEvents.emit('toggle-sidemenu-hidden'); var params = $location.search(); panelId = parseInt(params.panelId); From 5ca03972a89763dba10ec741cb0b0ace9e412200 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Tue, 6 Feb 2018 10:02:28 +0100 Subject: [PATCH 37/48] org-switcher: should redirect to home page (#10782) Fixes #10776 --- public/app/core/components/org_switcher.ts | 10 +++------- public/app/core/specs/org_switcher.jest.ts | 13 +++++++++---- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/public/app/core/components/org_switcher.ts b/public/app/core/components/org_switcher.ts index d6efeb51779..1816e11af49 100644 --- a/public/app/core/components/org_switcher.ts +++ b/public/app/core/components/org_switcher.ts @@ -1,5 +1,6 @@ import coreModule from 'app/core/core_module'; import { contextSrv } from 'app/core/services/context_srv'; +import config from 'app/core/config'; const template = `