dashboard folder search fix

This commit is contained in:
Torkel Ödegaard
2017-06-23 16:00:26 -04:00
parent 456225365f
commit fc69d59cae
19 changed files with 146 additions and 254 deletions
+1 -1
View File
@@ -44,7 +44,7 @@ func searchHandler(query *Query) error {
IsStarred: query.IsStarred,
DashboardIds: query.DashboardIds,
Type: query.Type,
ParentId: query.FolderId,
FolderId: query.FolderId,
Mode: query.Mode,
}
+1 -3
View File
@@ -20,9 +20,7 @@ func TestSearch(t *testing.T) {
&Hit{Id: 10, Title: "AABB", Type: "dash-db", Tags: []string{"CC", "AA"}},
&Hit{Id: 15, Title: "BBAA", Type: "dash-db", Tags: []string{"EE", "AA", "BB"}},
&Hit{Id: 25, Title: "bbAAa", Type: "dash-db", Tags: []string{"EE", "AA", "BB"}},
&Hit{Id: 17, Title: "FOLDER", Type: "dash-folder", Dashboards: []Hit{
{Id: 18, Title: "ZZAA", Tags: []string{"ZZ"}},
}},
&Hit{Id: 17, Title: "FOLDER", Type: "dash-folder"},
}
return nil
})
+10 -9
View File
@@ -14,14 +14,15 @@ const (
)
type Hit struct {
Id int64 `json:"id"`
Title string `json:"title"`
Uri string `json:"uri"`
Type HitType `json:"type"`
Tags []string `json:"tags"`
IsStarred bool `json:"isStarred"`
ParentId int64 `json:"parentId"`
Dashboards []Hit `json:"dashboards"`
Id int64 `json:"id"`
Title string `json:"title"`
Uri string `json:"uri"`
Type HitType `json:"type"`
Tags []string `json:"tags"`
IsStarred bool `json:"isStarred"`
FolderId int64 `json:"folderId,omitempty"`
FolderTitle string `json:"folderTitle,omitempty"`
FolderSlug string `json:"folderSlug,omitempty"`
}
type HitList []*Hit
@@ -62,7 +63,7 @@ type FindPersistedDashboardsQuery struct {
IsStarred bool
DashboardIds []int64
Type string
ParentId int64
FolderId int64
Mode string
Result HitList
+17 -70
View File
@@ -81,7 +81,7 @@ func SaveDashboard(cmd *m.SaveDashboardCommand) error {
} else {
dash.Version += 1
dash.Data.Set("version", dash.Version)
affectedRows, err = sess.MustCols("parent_id").Id(dash.Id).Update(dash)
affectedRows, err = sess.MustCols("folder_id").Id(dash.Id).Update(dash)
}
if err != nil {
@@ -153,7 +153,7 @@ type DashboardSearchProjection struct {
Slug string
Term string
IsFolder bool
ParentId int64
FolderId int64
FolderSlug string
FolderTitle string
}
@@ -168,11 +168,11 @@ func findDashboards(query *search.FindPersistedDashboardsQuery) ([]DashboardSear
dashboard.slug,
dashboard_tag.term,
dashboard.is_folder,
dashboard.parent_id,
dashboard.folder_id,
f.slug as folder_slug,
f.title as folder_title
FROM dashboard
LEFT OUTER JOIN dashboard f on f.id = dashboard.parent_id
LEFT OUTER JOIN dashboard f on f.id = dashboard.folder_id
LEFT OUTER JOIN dashboard_tag on dashboard_tag.dashboard_id = dashboard.id`)
if query.IsStarred {
@@ -204,7 +204,7 @@ func findDashboards(query *search.FindPersistedDashboardsQuery) ([]DashboardSear
allowedDashboardsSubQuery := ` AND (dashboard.has_acl = 0 OR dashboard.id in (
SELECT distinct d.id AS DashboardId
FROM dashboard AS d
LEFT JOIN dashboard_acl as da on d.parent_id = da.dashboard_id or d.id = da.dashboard_id
LEFT JOIN dashboard_acl as da on d.folder_id = da.dashboard_id or d.id = da.dashboard_id
LEFT JOIN user_group_member as ugm on ugm.user_group_id = da.user_group_id
LEFT JOIN org_user ou on ou.role = da.role
WHERE
@@ -230,9 +230,9 @@ func findDashboards(query *search.FindPersistedDashboardsQuery) ([]DashboardSear
sql.WriteString(" AND dashboard.is_folder = 0")
}
if query.ParentId > 0 {
sql.WriteString(" AND dashboard.parent_id = ?")
params = append(params, query.ParentId)
if query.FolderId > 0 {
sql.WriteString(" AND dashboard.folder_id = ?")
params = append(params, query.FolderId)
}
sql.WriteString(fmt.Sprintf(" ORDER BY dashboard.title ASC LIMIT 1000"))
@@ -253,38 +253,11 @@ func SearchDashboards(query *search.FindPersistedDashboardsQuery) error {
return err
}
if query.Mode == "tree" {
res, err = appendDashboardFolders(res)
if err != nil {
return err
}
}
makeQueryResult(query, res)
if query.Mode == "tree" {
convertToDashboardFolders(query)
}
return nil
}
// appends parent folders for any hits to the search result
func appendDashboardFolders(res []DashboardSearchProjection) ([]DashboardSearchProjection, error) {
for _, item := range res {
if item.ParentId > 0 {
res = append(res, DashboardSearchProjection{
Id: item.ParentId,
IsFolder: true,
Slug: item.FolderSlug,
Title: item.FolderTitle,
})
}
}
return res, nil
}
func getHitType(item DashboardSearchProjection) search.HitType {
var hitType search.HitType
if item.IsFolder {
@@ -304,12 +277,14 @@ func makeQueryResult(query *search.FindPersistedDashboardsQuery, res []Dashboard
hit, exists := hits[item.Id]
if !exists {
hit = &search.Hit{
Id: item.Id,
Title: item.Title,
Uri: "db/" + item.Slug,
Type: getHitType(item),
ParentId: item.ParentId,
Tags: []string{},
Id: item.Id,
Title: item.Title,
Uri: "db/" + item.Slug,
Type: getHitType(item),
FolderId: item.FolderId,
FolderTitle: item.FolderTitle,
FolderSlug: item.FolderSlug,
Tags: []string{},
}
query.Result = append(query.Result, hit)
hits[item.Id] = hit
@@ -320,34 +295,6 @@ func makeQueryResult(query *search.FindPersistedDashboardsQuery, res []Dashboard
}
}
func convertToDashboardFolders(query *search.FindPersistedDashboardsQuery) error {
root := make(map[int64]*search.Hit)
var keys []int64
// Add dashboards and folders that should be at the root level
for _, item := range query.Result {
if item.Type == search.DashHitFolder || item.ParentId == 0 {
root[item.Id] = item
keys = append(keys, item.Id)
}
}
// Populate folders with their child dashboards
for _, item := range query.Result {
if item.Type == search.DashHitDB && item.ParentId > 0 {
root[item.ParentId].Dashboards = append(root[item.ParentId].Dashboards, *item)
}
}
query.Result = make([]*search.Hit, 0)
for _, key := range keys {
query.Result = append(query.Result, root[key])
}
return nil
}
func GetDashboardTags(query *m.GetDashboardTagsQuery) error {
sql := `SELECT
COUNT(*) as count,
@@ -379,7 +326,7 @@ func DeleteDashboard(cmd *m.DeleteDashboardCommand) error {
"DELETE FROM dashboard WHERE id = ?",
"DELETE FROM playlist_item WHERE type = 'dashboard_by_id' AND value = ?",
"DELETE FROM dashboard_version WHERE dashboard_id = ?",
"DELETE FROM dashboard WHERE parent_id = ?",
"DELETE FROM dashboard WHERE folder_id = ?",
}
for _, sql := range deletes {
+3 -3
View File
@@ -40,7 +40,7 @@ func UpdateDashboardAcl(cmd *m.UpdateDashboardAclCommand) error {
// Update dashboard HasAcl flag
dashboard := m.Dashboard{HasAcl: true}
if _, err := sess.Cols("has_acl").Where("id=? OR parent_id=?", cmd.DashboardId, cmd.DashboardId).Update(&dashboard); err != nil {
if _, err := sess.Cols("has_acl").Where("id=? OR folder_id=?", cmd.DashboardId, cmd.DashboardId).Update(&dashboard); err != nil {
return err
}
return nil
@@ -105,7 +105,7 @@ func SetDashboardAcl(cmd *m.SetDashboardAclCommand) error {
HasAcl: true,
}
if _, err := sess.Cols("has_acl").Where("id=? OR parent_id=?", cmd.DashboardId, cmd.DashboardId).Update(&dashboard); err != nil {
if _, err := sess.Cols("has_acl").Where("id=? OR folder_id=?", cmd.DashboardId, cmd.DashboardId).Update(&dashboard); err != nil {
return err
}
@@ -129,7 +129,7 @@ func GetDashboardAclInfoList(query *m.GetDashboardAclInfoListQuery) error {
dashboardFilter := fmt.Sprintf(`IN (
SELECT %d
UNION
SELECT parent_id from dashboard where id = %d
SELECT folder_id from dashboard where id = %d
)`, query.DashboardId, query.DashboardId)
rawSQL := `
+16 -37
View File
@@ -11,10 +11,10 @@ import (
"github.com/grafana/grafana/pkg/setting"
)
func insertTestDashboard(title string, orgId int64, parentId int64, isFolder bool, tags ...interface{}) *m.Dashboard {
func insertTestDashboard(title string, orgId int64, folderId int64, isFolder bool, tags ...interface{}) *m.Dashboard {
cmd := m.SaveDashboardCommand{
OrgId: orgId,
ParentId: parentId,
FolderId: folderId,
IsFolder: isFolder,
Dashboard: simplejson.NewFromAny(map[string]interface{}{
"id": nil,
@@ -45,13 +45,13 @@ func TestDashboardDataAccess(t *testing.T) {
So(savedDash.Slug, ShouldEqual, "test-dash-23")
So(savedDash.Id, ShouldNotEqual, 0)
So(savedDash.IsFolder, ShouldBeFalse)
So(savedDash.ParentId, ShouldBeGreaterThan, 0)
So(savedDash.FolderId, ShouldBeGreaterThan, 0)
So(savedFolder.Title, ShouldEqual, "1 test dash folder")
So(savedFolder.Slug, ShouldEqual, "1-test-dash-folder")
So(savedFolder.Id, ShouldNotEqual, 0)
So(savedFolder.IsFolder, ShouldBeTrue)
So(savedFolder.ParentId, ShouldEqual, 0)
So(savedFolder.FolderId, ShouldEqual, 0)
})
Convey("Should be able to get dashboard", func() {
@@ -112,26 +112,6 @@ func TestDashboardDataAccess(t *testing.T) {
So(err, ShouldNotBeNil)
})
Convey("Should be able to search for dashboard and return in folder hierarchy", func() {
query := search.FindPersistedDashboardsQuery{
Title: "test dash 23",
OrgId: 1,
Mode: "tree",
SignedInUser: &m.SignedInUser{OrgId: 1},
}
err := SearchDashboards(&query)
So(err, ShouldBeNil)
So(len(query.Result), ShouldEqual, 1)
hit := query.Result[0].Dashboards[0]
So(len(hit.Tags), ShouldEqual, 2)
So(hit.Type, ShouldEqual, search.DashHitDB)
So(hit.ParentId, ShouldBeGreaterThan, 0)
})
Convey("Should be able to search for dashboard folder", func() {
query := search.FindPersistedDashboardsQuery{
Title: "1 test dash folder",
@@ -150,7 +130,7 @@ func TestDashboardDataAccess(t *testing.T) {
Convey("Should be able to search for a dashboard folder's children", func() {
query := search.FindPersistedDashboardsQuery{
OrgId: 1,
ParentId: savedFolder.Id,
FolderId: savedFolder.Id,
SignedInUser: &m.SignedInUser{OrgId: 1},
}
@@ -166,19 +146,18 @@ func TestDashboardDataAccess(t *testing.T) {
Convey("should be able to find two dashboards by id", func() {
query := search.FindPersistedDashboardsQuery{
DashboardIds: []int64{2, 3},
Mode: "tree",
SignedInUser: &m.SignedInUser{OrgId: 1},
}
err := SearchDashboards(&query)
So(err, ShouldBeNil)
So(len(query.Result[0].Dashboards), ShouldEqual, 2)
So(len(query.Result), ShouldEqual, 2)
hit := query.Result[0].Dashboards[0]
hit := query.Result[0]
So(len(hit.Tags), ShouldEqual, 2)
hit2 := query.Result[0].Dashboards[1]
hit2 := query.Result[1]
So(len(hit2.Tags), ShouldEqual, 1)
})
@@ -208,30 +187,30 @@ func TestDashboardDataAccess(t *testing.T) {
So(err, ShouldNotBeNil)
})
Convey("Should be able to update dashboard and remove parentId", func() {
Convey("Should be able to update dashboard and remove folderId", func() {
cmd := m.SaveDashboardCommand{
OrgId: 1,
Dashboard: simplejson.NewFromAny(map[string]interface{}{
"id": 1,
"title": "parentId",
"title": "folderId",
"tags": []interface{}{},
}),
Overwrite: true,
ParentId: 2,
FolderId: 2,
}
err := SaveDashboard(&cmd)
So(err, ShouldBeNil)
So(cmd.Result.ParentId, ShouldEqual, 2)
So(cmd.Result.FolderId, ShouldEqual, 2)
cmd = m.SaveDashboardCommand{
OrgId: 1,
Dashboard: simplejson.NewFromAny(map[string]interface{}{
"id": 1,
"title": "parentId",
"title": "folderId",
"tags": []interface{}{},
}),
ParentId: 0,
FolderId: 0,
Overwrite: true,
}
@@ -245,7 +224,7 @@ func TestDashboardDataAccess(t *testing.T) {
err = GetDashboard(&query)
So(err, ShouldBeNil)
So(query.Result.ParentId, ShouldEqual, 0)
So(query.Result.FolderId, ShouldEqual, 0)
})
Convey("Should be able to delete a dashboard folder and its children", func() {
@@ -255,7 +234,7 @@ func TestDashboardDataAccess(t *testing.T) {
query := search.FindPersistedDashboardsQuery{
OrgId: 1,
ParentId: savedFolder.Id,
FolderId: savedFolder.Id,
SignedInUser: &m.SignedInUser{},
}
@@ -137,9 +137,9 @@ func addDashboardMigration(mg *Migrator) {
{Name: "term", Type: DB_NVarchar, Length: 50, Nullable: false},
}))
// add column to store parent_id for dashboard folder structure
mg.AddMigration("Add column parent_id in dashboard", NewAddColumnMigration(dashboardV2, &Column{
Name: "parent_id", Type: DB_BigInt, Nullable: true,
// add column to store folder_id for dashboard folder structure
mg.AddMigration("Add column folder_id in dashboard", NewAddColumnMigration(dashboardV2, &Column{
Name: "folder_id", Type: DB_BigInt, Nullable: true,
}))
mg.AddMigration("Add column isFolder in dashboard", NewAddColumnMigration(dashboardV2, &Column{