diff --git a/pkg/services/navtree/navtreeimpl/navtree.go b/pkg/services/navtree/navtreeimpl/navtree.go index 1016b4373cb..2c9124980e0 100644 --- a/pkg/services/navtree/navtreeimpl/navtree.go +++ b/pkg/services/navtree/navtreeimpl/navtree.go @@ -332,7 +332,11 @@ func (s *ServiceImpl) buildStarredItemsNavLinks(c *contextmodel.ReqContext) ([]* for uid := range starredDashboardResult.UserStars { uids = append(uids, uid) } - starredDashboards, err := s.dashboardService.GetDashboards(c.Req.Context(), &dashboards.GetDashboardsQuery{DashboardUIDs: uids, OrgID: c.SignedInUser.GetOrgID()}) + starredDashboards, err := s.dashboardService.SearchDashboards(c.Req.Context(), &dashboards.FindPersistedDashboardsQuery{ + DashboardUIDs: uids, + OrgId: c.SignedInUser.GetOrgID(), + SignedInUser: c.SignedInUser, + }) if err != nil { return nil, err } @@ -348,7 +352,7 @@ func (s *ServiceImpl) buildStarredItemsNavLinks(c *contextmodel.ReqContext) ([]* starredItemsChildNavs = append(starredItemsChildNavs, &navtree.NavLink{ Id: "starred/" + starredItem.UID, Text: starredItem.Title, - Url: starredItem.GetURL(), + Url: starredItem.URL, }) } } diff --git a/pkg/services/navtree/navtreeimpl/navtree_test.go b/pkg/services/navtree/navtreeimpl/navtree_test.go new file mode 100644 index 00000000000..b52fb8ae6df --- /dev/null +++ b/pkg/services/navtree/navtreeimpl/navtree_test.go @@ -0,0 +1,168 @@ +package navtreeimpl + +import ( + "context" + "fmt" + "net/http" + "testing" + + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + + contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" + "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/search/model" + "github.com/grafana/grafana/pkg/services/star" + "github.com/grafana/grafana/pkg/services/star/startest" + "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/web" +) + +func TestBuildStarredItemsNavLinks(t *testing.T) { + httpReq, _ := http.NewRequest(http.MethodGet, "", nil) + reqCtx := &contextmodel.ReqContext{ + SignedInUser: &user.SignedInUser{ + UserID: 1, + OrgID: 1, + }, + Context: &web.Context{Req: httpReq}, + } + + t.Run("Should return empty list when there are no starred dashboards", func(t *testing.T) { + starService := startest.NewStarServiceFake() + starService.ExpectedUserStars = &star.GetUserStarsResult{ + UserStars: map[string]bool{}, + } + + service := ServiceImpl{ + starService: starService, + } + + navLinks, err := service.buildStarredItemsNavLinks(reqCtx) + require.NoError(t, err) + require.Empty(t, navLinks) + }) + + t.Run("Should return nav links for starred dashboards", func(t *testing.T) { + starService := startest.NewStarServiceFake() + starService.ExpectedUserStars = &star.GetUserStarsResult{ + UserStars: map[string]bool{ + "dashboard1": true, + "dashboard2": true, + }, + } + + dashboardService := dashboards.NewFakeDashboardService(t) + dashboardService.On("SearchDashboards", context.Background(), &dashboards.FindPersistedDashboardsQuery{ + DashboardUIDs: []string{"dashboard1", "dashboard2"}, + OrgId: 1, + SignedInUser: reqCtx.SignedInUser, + }).Return(model.HitList{ + { + UID: "dashboard1", + Title: "Dashboard 1", + URL: "/d/dashboard1/", + }, + { + UID: "dashboard2", + Title: "Dashboard 2", + URL: "/d/dashboard2/", + }, + }, nil) + + service := ServiceImpl{ + starService: starService, + dashboardService: dashboardService, + } + + navLinks, err := service.buildStarredItemsNavLinks(reqCtx) + require.NoError(t, err) + require.Len(t, navLinks, 2) + + require.Equal(t, "starred/dashboard1", navLinks[0].Id) + require.Equal(t, "Dashboard 1", navLinks[0].Text) + require.Equal(t, "/d/dashboard1/", navLinks[0].Url) + require.Equal(t, "starred/dashboard2", navLinks[1].Id) + require.Equal(t, "Dashboard 2", navLinks[1].Text) + require.Equal(t, "/d/dashboard2/", navLinks[1].Url) + }) + + t.Run("Should limit to 50 starred dashboards", func(t *testing.T) { + starService := startest.NewStarServiceFake() + userStars := make(map[string]bool) + for i := 0; i < 60; i++ { + userStars[fmt.Sprintf("dashboard%d", i)] = true + } + starService.ExpectedUserStars = &star.GetUserStarsResult{ + UserStars: userStars, + } + + dashboardList := make(model.HitList, 60) + for i := 0; i < 60; i++ { + dashboardList[i] = &model.Hit{ + UID: fmt.Sprintf("dashboard%d", i), + Title: fmt.Sprintf("Dashboard %d", i), + URL: fmt.Sprintf("/d/dashboard%d/", i), + } + } + + dashboardService := dashboards.NewFakeDashboardService(t) + dashboardService.On("SearchDashboards", context.Background(), mock.Anything).Return(dashboardList, nil) + + service := ServiceImpl{ + starService: starService, + dashboardService: dashboardService, + } + + navLinks, err := service.buildStarredItemsNavLinks(reqCtx) + require.NoError(t, err) + require.Len(t, navLinks, 50) + }) + + t.Run("Should sort dashboards by title", func(t *testing.T) { + starService := startest.NewStarServiceFake() + starService.ExpectedUserStars = &star.GetUserStarsResult{ + UserStars: map[string]bool{ + "dashboard1": true, + "dashboard2": true, + "dashboard3": true, + }, + } + + dashboardService := dashboards.NewFakeDashboardService(t) + dashboardService.On("SearchDashboards", context.Background(), &dashboards.FindPersistedDashboardsQuery{ + DashboardUIDs: []string{"dashboard1", "dashboard2", "dashboard3"}, + OrgId: 1, + SignedInUser: reqCtx.SignedInUser, + }).Return(model.HitList{ + { + UID: "dashboard1", + Title: "C Dashboard", + URL: "/d/dashboard1/", + }, + { + UID: "dashboard2", + Title: "A Dashboard", + URL: "/d/dashboard2/", + }, + { + UID: "dashboard3", + Title: "B Dashboard", + URL: "/d/dashboard3/", + }, + }, nil) + + service := ServiceImpl{ + starService: starService, + dashboardService: dashboardService, + } + + navLinks, err := service.buildStarredItemsNavLinks(reqCtx) + require.NoError(t, err) + require.Len(t, navLinks, 3) + + require.Equal(t, "A Dashboard", navLinks[0].Text) + require.Equal(t, "B Dashboard", navLinks[1].Text) + require.Equal(t, "C Dashboard", navLinks[2].Text) + }) +}