diff --git a/docs/sources/reference/playlist.md b/docs/sources/reference/playlist.md index 3e90f7361a3..5d546b1a3df 100644 --- a/docs/sources/reference/playlist.md +++ b/docs/sources/reference/playlist.md @@ -18,11 +18,11 @@ The Playlist feature can be accessed from Grafana's sidemenu. Click the 'Playlis Click on "New Playlist" button to create a new playlist. Firstly, name your playlist and configure a time interval for Grafana to wait on a particular Dashboard before advancing to the next one on the Playlist. -You can search Dashboards by name (or use a regular expression), and add them to your Playlist. By default, your starred dashboards will appear as candidates for the Playlist. +You can search Dashboards by name (or use a regular expression), and add them to your Playlist. Or you could add tags which will include all the dashboards that belongs to a tag when the playlist start playing. By default, your starred dashboards will appear as candidates for the Playlist. Be sure to click the "Add to dashboard" button next to the Dashboard name to add it to the Playlist. To remove a dashboard from the playlist click on "Remove[x]" button from the playlist. -Since the Playlist is basically a list of Dashboards, ensure that all the Dashboards you want to appear in your Playlist are added here. +Since the Playlist is basically a list of Dashboards, ensure that all the Dashboards you want to appear in your Playlist are added here. ## Saving the playlist diff --git a/pkg/api/playlist.go b/pkg/api/playlist.go index 0b017d6e2cb..abc092b8021 100644 --- a/pkg/api/playlist.go +++ b/pkg/api/playlist.go @@ -1,11 +1,8 @@ package api import ( - "errors" - "strconv" - "github.com/grafana/grafana/pkg/bus" - "github.com/grafana/grafana/pkg/log" + _ "github.com/grafana/grafana/pkg/log" "github.com/grafana/grafana/pkg/middleware" m "github.com/grafana/grafana/pkg/models" ) @@ -101,39 +98,6 @@ func LoadPlaylistItems(id int64) ([]m.PlaylistItem, error) { return *itemQuery.Result, nil } -func LoadPlaylistDashboards(id int64) ([]m.PlaylistDashboardDto, error) { - playlistItems, _ := LoadPlaylistItems(id) - - dashboardIds := make([]int64, 0) - - for _, i := range playlistItems { - dashboardId, _ := strconv.ParseInt(i.Value, 10, 64) - dashboardIds = append(dashboardIds, dashboardId) - } - - if len(dashboardIds) == 0 { - return make([]m.PlaylistDashboardDto, 0), nil - } - - dashboardQuery := m.GetPlaylistDashboardsQuery{DashboardIds: dashboardIds} - if err := bus.Dispatch(&dashboardQuery); err != nil { - log.Warn("dashboardquery failed: %v", err) - return nil, errors.New("Playlist not found") - } - - dtos := make([]m.PlaylistDashboardDto, 0) - for _, item := range *dashboardQuery.Result { - dtos = append(dtos, m.PlaylistDashboardDto{ - Id: item.Id, - Slug: item.Slug, - Title: item.Title, - Uri: "db/" + item.Slug, - }) - } - - return dtos, nil -} - func GetPlaylistItems(c *middleware.Context) Response { id := c.ParamsInt64(":id") @@ -147,9 +111,9 @@ func GetPlaylistItems(c *middleware.Context) Response { } func GetPlaylistDashboards(c *middleware.Context) Response { - id := c.ParamsInt64(":id") + playlistId := c.ParamsInt64(":id") - playlists, err := LoadPlaylistDashboards(id) + playlists, err := LoadPlaylistDashboards(c.OrgId, c.UserId, playlistId) if err != nil { return ApiError(500, "Could not load dashboards", err) } diff --git a/pkg/api/playlist_play.go b/pkg/api/playlist_play.go new file mode 100644 index 00000000000..9bfcf1532fa --- /dev/null +++ b/pkg/api/playlist_play.go @@ -0,0 +1,88 @@ +package api + +import ( + "errors" + "strconv" + + "github.com/grafana/grafana/pkg/bus" + _ "github.com/grafana/grafana/pkg/log" + m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/search" +) + +func populateDashboardsById(dashboardByIds []int64) ([]m.PlaylistDashboardDto, error) { + result := make([]m.PlaylistDashboardDto, 0) + + if len(dashboardByIds) > 0 { + dashboardQuery := m.GetDashboardsQuery{DashboardIds: dashboardByIds} + if err := bus.Dispatch(&dashboardQuery); err != nil { + return result, errors.New("Playlist not found") //TODO: dont swallow error + } + + for _, item := range *dashboardQuery.Result { + result = append(result, m.PlaylistDashboardDto{ + Id: item.Id, + Slug: item.Slug, + Title: item.Title, + Uri: "db/" + item.Slug, + }) + } + } + + return result, nil +} + +func populateDashboardsByTag(orgId, userId int64, dashboardByTag []string) []m.PlaylistDashboardDto { + result := make([]m.PlaylistDashboardDto, 0) + + if len(dashboardByTag) > 0 { + for _, tag := range dashboardByTag { + searchQuery := search.Query{ + Title: "", + Tags: []string{tag}, + UserId: userId, + Limit: 100, + IsStarred: false, + OrgId: orgId, + } + + if err := bus.Dispatch(&searchQuery); err == nil { + for _, item := range searchQuery.Result { + result = append(result, m.PlaylistDashboardDto{ + Id: item.Id, + Title: item.Title, + Uri: item.Uri, + }) + } + } + } + } + + return result +} + +func LoadPlaylistDashboards(orgId, userId, playlistId int64) ([]m.PlaylistDashboardDto, error) { + playlistItems, _ := LoadPlaylistItems(playlistId) + + dashboardByIds := make([]int64, 0) + dashboardByTag := make([]string, 0) + + for _, i := range playlistItems { + if i.Type == "dashboard_by_id" { + dashboardId, _ := strconv.ParseInt(i.Value, 10, 64) + dashboardByIds = append(dashboardByIds, dashboardId) + } + + if i.Type == "dashboard_by_tag" { + dashboardByTag = append(dashboardByTag, i.Value) + } + } + + result := make([]m.PlaylistDashboardDto, 0) + + var k, _ = populateDashboardsById(dashboardByIds) + result = append(result, k...) + result = append(result, populateDashboardsByTag(orgId, userId, dashboardByTag)...) + + return result, nil +} diff --git a/pkg/models/dashboards.go b/pkg/models/dashboards.go index ddf5dd244f5..63ed1f5c006 100644 --- a/pkg/models/dashboards.go +++ b/pkg/models/dashboards.go @@ -146,3 +146,8 @@ type GetDashboardTagsQuery struct { OrgId int64 Result []*DashboardTagCloudItem } + +type GetDashboardsQuery struct { + DashboardIds []int64 + Result *[]Dashboard +} diff --git a/pkg/models/playlist.go b/pkg/models/playlist.go index 4c37c369b3e..4c6eacbb6a6 100644 --- a/pkg/models/playlist.go +++ b/pkg/models/playlist.go @@ -76,9 +76,7 @@ type UpdatePlaylistCommand struct { OrgId int64 `json:"-"` Id int64 `json:"id" binding:"Required"` Name string `json:"name" binding:"Required"` - Type string `json:"type"` Interval string `json:"interval"` - Data []int64 `json:"data"` Items []PlaylistItemDTO `json:"items"` Result *PlaylistDTO @@ -86,9 +84,7 @@ type UpdatePlaylistCommand struct { type CreatePlaylistCommand struct { Name string `json:"name" binding:"Required"` - Type string `json:"type"` Interval string `json:"interval"` - Data []int64 `json:"data"` Items []PlaylistItemDTO `json:"items"` OrgId int64 `json:"-"` @@ -121,8 +117,3 @@ type GetPlaylistItemsByIdQuery struct { PlaylistId int64 Result *[]PlaylistItem } - -type GetPlaylistDashboardsQuery struct { - DashboardIds []int64 - Result *PlaylistDashboards -} diff --git a/pkg/services/sqlstore/dashboard.go b/pkg/services/sqlstore/dashboard.go index bbec541589c..2a8ff2dc941 100644 --- a/pkg/services/sqlstore/dashboard.go +++ b/pkg/services/sqlstore/dashboard.go @@ -14,6 +14,7 @@ import ( func init() { bus.AddHandler("sql", SaveDashboard) bus.AddHandler("sql", GetDashboard) + bus.AddHandler("sql", GetDashboards) bus.AddHandler("sql", DeleteDashboard) bus.AddHandler("sql", SearchDashboards) bus.AddHandler("sql", GetDashboardTags) @@ -223,3 +224,20 @@ func DeleteDashboard(cmd *m.DeleteDashboardCommand) error { return nil }) } + +func GetDashboards(query *m.GetDashboardsQuery) error { + if len(query.DashboardIds) == 0 { + return m.ErrCommandValidationFailed + } + + var dashboards = make([]m.Dashboard, 0) + + err := x.In("id", query.DashboardIds).Find(&dashboards) + query.Result = &dashboards + + if err != nil { + return err + } + + return nil +} diff --git a/pkg/services/sqlstore/playlist.go b/pkg/services/sqlstore/playlist.go index ee0b3b950c7..56fae9d3feb 100644 --- a/pkg/services/sqlstore/playlist.go +++ b/pkg/services/sqlstore/playlist.go @@ -15,7 +15,6 @@ func init() { bus.AddHandler("sql", DeletePlaylist) bus.AddHandler("sql", SearchPlaylists) bus.AddHandler("sql", GetPlaylist) - bus.AddHandler("sql", GetPlaylistDashboards) bus.AddHandler("sql", GetPlaylistItem) } @@ -162,20 +161,3 @@ func GetPlaylistItem(query *m.GetPlaylistItemsByIdQuery) error { return err } - -func GetPlaylistDashboards(query *m.GetPlaylistDashboardsQuery) error { - if len(query.DashboardIds) == 0 { - return m.ErrCommandValidationFailed - } - - var dashboards = make(m.PlaylistDashboards, 0) - - err := x.In("id", query.DashboardIds).Find(&dashboards) - query.Result = &dashboards - - if err != nil { - return err - } - - return nil -} diff --git a/pkg/services/sqlstore/playlist_test.go b/pkg/services/sqlstore/playlist_test.go new file mode 100644 index 00000000000..ba530f74fcf --- /dev/null +++ b/pkg/services/sqlstore/playlist_test.go @@ -0,0 +1,44 @@ +package sqlstore + +import ( + "testing" + + . "github.com/smartystreets/goconvey/convey" + + m "github.com/grafana/grafana/pkg/models" +) + +func TestPlaylistDataAccess(t *testing.T) { + + Convey("Testing Playlist data access", t, func() { + InitTestDB(t) + + Convey("Can create playlist", func() { + items := []m.PlaylistItemDTO{ + {Title: "graphite", Value: "graphite", Type: "dashboard_by_tag"}, + {Title: "Backend response times", Value: "3", Type: "dashboard_by_id"}, + } + cmd := m.CreatePlaylistCommand{Name: "NYC office", Interval: "10m", OrgId: 1, Items: items} + err := CreatePlaylist(&cmd) + So(err, ShouldBeNil) + + Convey("can update playlist", func() { + items := []m.PlaylistItemDTO{ + {Title: "influxdb", Value: "influxdb", Type: "dashboard_by_tag"}, + {Title: "Backend response times", Value: "2", Type: "dashboard_by_id"}, + } + query := m.UpdatePlaylistCommand{Name: "NYC office ", OrgId: 1, Id: 1, Interval: "10s", Items: items} + err = UpdatePlaylist(&query) + + So(err, ShouldBeNil) + + Convey("can remove playlist", func() { + query := m.DeletePlaylistCommand{Id: 1} + err = DeletePlaylist(&query) + + So(err, ShouldBeNil) + }) + }) + }) + }) +} diff --git a/public/app/features/dashboard/dashnav/dashnav.html b/public/app/features/dashboard/dashnav/dashnav.html index 22478f47ec4..1e416b4f90d 100644 --- a/public/app/features/dashboard/dashnav/dashnav.html +++ b/public/app/features/dashboard/dashnav/dashnav.html @@ -24,8 +24,16 @@ -
  • - +
  • diff --git a/public/app/features/dashboard/dashnav/dashnav.ts b/public/app/features/dashboard/dashnav/dashnav.ts index 1b1424018f9..9df3ea03eb2 100644 --- a/public/app/features/dashboard/dashnav/dashnav.ts +++ b/public/app/features/dashboard/dashnav/dashnav.ts @@ -42,10 +42,13 @@ export class DashNavCtrl { } }; - $scope.shareDashboard = function() { + $scope.shareDashboard = function(tabIndex) { + var modalScope = $scope.$new(); + modalScope.tabIndex = tabIndex; + $scope.appEvent('show-modal', { src: './app/features/dashboard/partials/shareModal.html', - scope: $scope.$new(), + scope: modalScope }); }; diff --git a/public/app/features/dashboard/partials/shareModal.html b/public/app/features/dashboard/partials/shareModal.html index 9bd64dd0bef..77ed80015e3 100644 --- a/public/app/features/dashboard/partials/shareModal.html +++ b/public/app/features/dashboard/partials/shareModal.html @@ -89,7 +89,7 @@