Search: add sort information in dashboard results (#30609)
* Search: add SortMeta in dashboard results * fix integration tests * trim SortMeta * fix searchstore tests * Update pkg/services/sqlstore/dashboard.go Co-authored-by: Emil Tullstedt <emil.tullstedt@grafana.com> Co-authored-by: Emil Tullstedt <emil.tullstedt@grafana.com>
This commit is contained in:
co-authored by
Emil Tullstedt
parent
25117f5af5
commit
3303e28b38
@@ -1,6 +1,7 @@
|
||||
package sqlstore
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -203,16 +204,17 @@ func GetDashboard(query *models.GetDashboardQuery) error {
|
||||
}
|
||||
|
||||
type DashboardSearchProjection struct {
|
||||
Id int64
|
||||
Uid string
|
||||
ID int64 `xorm:"id"`
|
||||
UID string `xorm:"uid"`
|
||||
Title string
|
||||
Slug string
|
||||
Term string
|
||||
IsFolder bool
|
||||
FolderId int64
|
||||
FolderUid string
|
||||
FolderID int64 `xorm:"folder_id"`
|
||||
FolderUID string `xorm:"folder_uid"`
|
||||
FolderSlug string
|
||||
FolderTitle string
|
||||
SortMeta int64
|
||||
}
|
||||
|
||||
func findDashboards(query *search.FindPersistedDashboardsQuery) ([]DashboardSearchProjection, error) {
|
||||
@@ -226,7 +228,9 @@ func findDashboards(query *search.FindPersistedDashboardsQuery) ([]DashboardSear
|
||||
},
|
||||
}
|
||||
|
||||
filters = append(filters, query.Filters...)
|
||||
for _, filter := range query.Sort.Filter {
|
||||
filters = append(filters, filter)
|
||||
}
|
||||
|
||||
if query.OrgId != 0 {
|
||||
filters = append(filters, searchstore.OrgFilter{OrgId: query.OrgId})
|
||||
@@ -307,27 +311,31 @@ func makeQueryResult(query *search.FindPersistedDashboardsQuery, res []Dashboard
|
||||
hits := make(map[int64]*search.Hit)
|
||||
|
||||
for _, item := range res {
|
||||
hit, exists := hits[item.Id]
|
||||
hit, exists := hits[item.ID]
|
||||
if !exists {
|
||||
hit = &search.Hit{
|
||||
Id: item.Id,
|
||||
Uid: item.Uid,
|
||||
ID: item.ID,
|
||||
UID: item.UID,
|
||||
Title: item.Title,
|
||||
Uri: "db/" + item.Slug,
|
||||
Url: models.GetDashboardFolderUrl(item.IsFolder, item.Uid, item.Slug),
|
||||
URI: "db/" + item.Slug,
|
||||
URL: models.GetDashboardFolderUrl(item.IsFolder, item.UID, item.Slug),
|
||||
Type: getHitType(item),
|
||||
FolderId: item.FolderId,
|
||||
FolderUid: item.FolderUid,
|
||||
FolderID: item.FolderID,
|
||||
FolderUID: item.FolderUID,
|
||||
FolderTitle: item.FolderTitle,
|
||||
Tags: []string{},
|
||||
}
|
||||
|
||||
if item.FolderId > 0 {
|
||||
hit.FolderUrl = models.GetFolderUrl(item.FolderUid, item.FolderSlug)
|
||||
if item.FolderID > 0 {
|
||||
hit.FolderURL = models.GetFolderUrl(item.FolderUID, item.FolderSlug)
|
||||
}
|
||||
|
||||
if query.Sort.MetaName != "" {
|
||||
hit.SortMeta = strings.TrimSpace(fmt.Sprintf("%d %s", item.SortMeta, query.Sort.MetaName))
|
||||
}
|
||||
|
||||
query.Result = append(query.Result, hit)
|
||||
hits[item.Id] = hit
|
||||
hits[item.ID] = hit
|
||||
}
|
||||
if len(item.Term) > 0 {
|
||||
hit.Tags = append(hit.Tags, item.Term)
|
||||
|
||||
@@ -33,8 +33,8 @@ func TestDashboardFolderDataAccess(t *testing.T) {
|
||||
err := SearchDashboards(query)
|
||||
So(err, ShouldBeNil)
|
||||
So(len(query.Result), ShouldEqual, 2)
|
||||
So(query.Result[0].Id, ShouldEqual, folder.Id)
|
||||
So(query.Result[1].Id, ShouldEqual, dashInRoot.Id)
|
||||
So(query.Result[0].ID, ShouldEqual, folder.Id)
|
||||
So(query.Result[1].ID, ShouldEqual, dashInRoot.Id)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -57,7 +57,7 @@ func TestDashboardFolderDataAccess(t *testing.T) {
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(len(query.Result), ShouldEqual, 1)
|
||||
So(query.Result[0].Id, ShouldEqual, dashInRoot.Id)
|
||||
So(query.Result[0].ID, ShouldEqual, dashInRoot.Id)
|
||||
})
|
||||
|
||||
Convey("when the user is given permission", func() {
|
||||
@@ -75,8 +75,8 @@ func TestDashboardFolderDataAccess(t *testing.T) {
|
||||
err := SearchDashboards(query)
|
||||
So(err, ShouldBeNil)
|
||||
So(len(query.Result), ShouldEqual, 2)
|
||||
So(query.Result[0].Id, ShouldEqual, folder.Id)
|
||||
So(query.Result[1].Id, ShouldEqual, dashInRoot.Id)
|
||||
So(query.Result[0].ID, ShouldEqual, folder.Id)
|
||||
So(query.Result[1].ID, ShouldEqual, dashInRoot.Id)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -94,8 +94,8 @@ func TestDashboardFolderDataAccess(t *testing.T) {
|
||||
err := SearchDashboards(query)
|
||||
So(err, ShouldBeNil)
|
||||
So(len(query.Result), ShouldEqual, 2)
|
||||
So(query.Result[0].Id, ShouldEqual, folder.Id)
|
||||
So(query.Result[1].Id, ShouldEqual, dashInRoot.Id)
|
||||
So(query.Result[0].ID, ShouldEqual, folder.Id)
|
||||
So(query.Result[1].ID, ShouldEqual, dashInRoot.Id)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -116,7 +116,7 @@ func TestDashboardFolderDataAccess(t *testing.T) {
|
||||
err := SearchDashboards(query)
|
||||
So(err, ShouldBeNil)
|
||||
So(len(query.Result), ShouldEqual, 1)
|
||||
So(query.Result[0].Id, ShouldEqual, dashInRoot.Id)
|
||||
So(query.Result[0].ID, ShouldEqual, dashInRoot.Id)
|
||||
})
|
||||
|
||||
Convey("when the user is given permission to child", func() {
|
||||
@@ -128,8 +128,8 @@ func TestDashboardFolderDataAccess(t *testing.T) {
|
||||
err := SearchDashboards(query)
|
||||
So(err, ShouldBeNil)
|
||||
So(len(query.Result), ShouldEqual, 2)
|
||||
So(query.Result[0].Id, ShouldEqual, childDash.Id)
|
||||
So(query.Result[1].Id, ShouldEqual, dashInRoot.Id)
|
||||
So(query.Result[0].ID, ShouldEqual, childDash.Id)
|
||||
So(query.Result[1].ID, ShouldEqual, dashInRoot.Id)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -147,9 +147,9 @@ func TestDashboardFolderDataAccess(t *testing.T) {
|
||||
err := SearchDashboards(query)
|
||||
So(err, ShouldBeNil)
|
||||
So(len(query.Result), ShouldEqual, 3)
|
||||
So(query.Result[0].Id, ShouldEqual, folder.Id)
|
||||
So(query.Result[1].Id, ShouldEqual, childDash.Id)
|
||||
So(query.Result[2].Id, ShouldEqual, dashInRoot.Id)
|
||||
So(query.Result[0].ID, ShouldEqual, folder.Id)
|
||||
So(query.Result[1].ID, ShouldEqual, childDash.Id)
|
||||
So(query.Result[2].ID, ShouldEqual, dashInRoot.Id)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -171,10 +171,10 @@ func TestDashboardFolderDataAccess(t *testing.T) {
|
||||
err := SearchDashboards(query)
|
||||
So(err, ShouldBeNil)
|
||||
So(len(query.Result), ShouldEqual, 4)
|
||||
So(query.Result[0].Id, ShouldEqual, folder1.Id)
|
||||
So(query.Result[1].Id, ShouldEqual, folder2.Id)
|
||||
So(query.Result[2].Id, ShouldEqual, childDash1.Id)
|
||||
So(query.Result[3].Id, ShouldEqual, dashInRoot.Id)
|
||||
So(query.Result[0].ID, ShouldEqual, folder1.Id)
|
||||
So(query.Result[1].ID, ShouldEqual, folder2.Id)
|
||||
So(query.Result[2].ID, ShouldEqual, childDash1.Id)
|
||||
So(query.Result[3].ID, ShouldEqual, dashInRoot.Id)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -197,7 +197,7 @@ func TestDashboardFolderDataAccess(t *testing.T) {
|
||||
err := SearchDashboards(query)
|
||||
So(err, ShouldBeNil)
|
||||
So(len(query.Result), ShouldEqual, 1)
|
||||
So(query.Result[0].Id, ShouldEqual, dashInRoot.Id)
|
||||
So(query.Result[0].ID, ShouldEqual, dashInRoot.Id)
|
||||
})
|
||||
})
|
||||
Convey("and a dashboard is moved from folder with acl to the folder without an acl", func() {
|
||||
@@ -212,10 +212,10 @@ func TestDashboardFolderDataAccess(t *testing.T) {
|
||||
err := SearchDashboards(query)
|
||||
So(err, ShouldBeNil)
|
||||
So(len(query.Result), ShouldEqual, 4)
|
||||
So(query.Result[0].Id, ShouldEqual, folder2.Id)
|
||||
So(query.Result[1].Id, ShouldEqual, childDash1.Id)
|
||||
So(query.Result[2].Id, ShouldEqual, childDash2.Id)
|
||||
So(query.Result[3].Id, ShouldEqual, dashInRoot.Id)
|
||||
So(query.Result[0].ID, ShouldEqual, folder2.Id)
|
||||
So(query.Result[1].ID, ShouldEqual, childDash1.Id)
|
||||
So(query.Result[2].ID, ShouldEqual, childDash2.Id)
|
||||
So(query.Result[3].ID, ShouldEqual, dashInRoot.Id)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -236,10 +236,10 @@ func TestDashboardFolderDataAccess(t *testing.T) {
|
||||
err := SearchDashboards(query)
|
||||
So(err, ShouldBeNil)
|
||||
So(len(query.Result), ShouldEqual, 4)
|
||||
So(query.Result[0].Id, ShouldEqual, folder2.Id)
|
||||
So(query.Result[1].Id, ShouldEqual, childDash1.Id)
|
||||
So(query.Result[2].Id, ShouldEqual, childDash2.Id)
|
||||
So(query.Result[3].Id, ShouldEqual, dashInRoot.Id)
|
||||
So(query.Result[0].ID, ShouldEqual, folder2.Id)
|
||||
So(query.Result[1].ID, ShouldEqual, childDash1.Id)
|
||||
So(query.Result[2].ID, ShouldEqual, childDash2.Id)
|
||||
So(query.Result[3].ID, ShouldEqual, dashInRoot.Id)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -267,8 +267,8 @@ func TestDashboardFolderDataAccess(t *testing.T) {
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(len(query.Result), ShouldEqual, 2)
|
||||
So(query.Result[0].Id, ShouldEqual, folder1.Id)
|
||||
So(query.Result[1].Id, ShouldEqual, folder2.Id)
|
||||
So(query.Result[0].ID, ShouldEqual, folder1.Id)
|
||||
So(query.Result[1].ID, ShouldEqual, folder2.Id)
|
||||
})
|
||||
|
||||
Convey("should have write access to all folders and dashboards", func() {
|
||||
@@ -320,8 +320,8 @@ func TestDashboardFolderDataAccess(t *testing.T) {
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(len(query.Result), ShouldEqual, 2)
|
||||
So(query.Result[0].Id, ShouldEqual, folder1.Id)
|
||||
So(query.Result[1].Id, ShouldEqual, folder2.Id)
|
||||
So(query.Result[0].ID, ShouldEqual, folder1.Id)
|
||||
So(query.Result[1].ID, ShouldEqual, folder2.Id)
|
||||
})
|
||||
|
||||
Convey("should have edit access to folders with default ACL", func() {
|
||||
@@ -352,7 +352,7 @@ func TestDashboardFolderDataAccess(t *testing.T) {
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(len(query.Result), ShouldEqual, 1)
|
||||
So(query.Result[0].Id, ShouldEqual, folder2.Id)
|
||||
So(query.Result[0].ID, ShouldEqual, folder2.Id)
|
||||
})
|
||||
|
||||
Convey("should have edit permission in folders", func() {
|
||||
@@ -416,7 +416,7 @@ func TestDashboardFolderDataAccess(t *testing.T) {
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(len(query.Result), ShouldEqual, 1)
|
||||
So(query.Result[0].Id, ShouldEqual, folder1.Id)
|
||||
So(query.Result[0].ID, ShouldEqual, folder1.Id)
|
||||
})
|
||||
|
||||
Convey("should not have edit permission in folders", func() {
|
||||
|
||||
@@ -277,7 +277,7 @@ func TestDashboardDataAccess(t *testing.T) {
|
||||
So(len(query.Result), ShouldEqual, 1)
|
||||
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.URL, ShouldEqual, fmt.Sprintf("/dashboards/f/%s/%s", savedFolder.Uid, savedFolder.Slug))
|
||||
So(hit.FolderTitle, ShouldEqual, "")
|
||||
})
|
||||
|
||||
@@ -337,12 +337,12 @@ func TestDashboardDataAccess(t *testing.T) {
|
||||
|
||||
So(len(query.Result), ShouldEqual, 2)
|
||||
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.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))
|
||||
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() {
|
||||
@@ -436,8 +436,8 @@ func TestDashboard_SortingOptions(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Len(t, dashboards, 2)
|
||||
assert.Equal(t, dashA.Id, dashboards[0].Id)
|
||||
assert.Equal(t, dashB.Id, dashboards[1].Id)
|
||||
assert.Equal(t, dashA.Id, dashboards[0].ID)
|
||||
assert.Equal(t, dashB.Id, dashboards[1].ID)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -55,8 +55,15 @@ func (b *Builder) buildSelect() {
|
||||
dashboard.folder_id,
|
||||
folder.uid AS folder_uid,
|
||||
folder.slug AS folder_slug,
|
||||
folder.title AS folder_title
|
||||
FROM `)
|
||||
folder.title AS folder_title `)
|
||||
|
||||
for _, f := range b.Filters {
|
||||
if f, ok := f.(FilterSelect); ok {
|
||||
b.sql.WriteString(fmt.Sprintf(", %s", f.Select()))
|
||||
}
|
||||
}
|
||||
|
||||
b.sql.WriteString(` FROM `)
|
||||
}
|
||||
|
||||
func (b *Builder) applyFilters() (ordering string) {
|
||||
|
||||
@@ -33,6 +33,10 @@ type FilterLeftJoin interface {
|
||||
LeftJoin() string
|
||||
}
|
||||
|
||||
type FilterSelect interface {
|
||||
Select() string
|
||||
}
|
||||
|
||||
const (
|
||||
TypeFolder = "dash-folder"
|
||||
TypeDashboard = "dash-db"
|
||||
|
||||
@@ -58,10 +58,10 @@ func TestBuilder_EqualResults_Basic(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Len(t, res, 1)
|
||||
res[0].Uid = ""
|
||||
res[0].UID = ""
|
||||
assert.EqualValues(t, []sqlstore.DashboardSearchProjection{
|
||||
{
|
||||
Id: 1,
|
||||
ID: 1,
|
||||
Title: "A",
|
||||
Slug: "a",
|
||||
Term: "templated",
|
||||
|
||||
Reference in New Issue
Block a user