mirror of
				https://github.com/grafana/grafana.git
				synced 2025-02-25 18:55:37 -06:00 
			
		
		
		
	WIP: dashboard search by folder + toggle for list or tree mode
This commit is contained in:
		| @@ -15,11 +15,17 @@ func Search(c *middleware.Context) { | |||||||
| 	starred := c.Query("starred") | 	starred := c.Query("starred") | ||||||
| 	limit := c.QueryInt("limit") | 	limit := c.QueryInt("limit") | ||||||
| 	dashboardType := c.Query("type") | 	dashboardType := c.Query("type") | ||||||
|  | 	folderId := c.QueryInt64("folderId") | ||||||
|  | 	mode := c.Query("mode") | ||||||
|  |  | ||||||
| 	if limit == 0 { | 	if limit == 0 { | ||||||
| 		limit = 1000 | 		limit = 1000 | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	if mode == "" { | ||||||
|  | 		mode = "list" | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	dbids := make([]int, 0) | 	dbids := make([]int, 0) | ||||||
| 	for _, id := range c.QueryStrings("dashboardIds") { | 	for _, id := range c.QueryStrings("dashboardIds") { | ||||||
| 		dashboardId, err := strconv.Atoi(id) | 		dashboardId, err := strconv.Atoi(id) | ||||||
| @@ -37,6 +43,8 @@ func Search(c *middleware.Context) { | |||||||
| 		OrgId:        c.OrgId, | 		OrgId:        c.OrgId, | ||||||
| 		DashboardIds: dbids, | 		DashboardIds: dbids, | ||||||
| 		Type:         dashboardType, | 		Type:         dashboardType, | ||||||
|  | 		FolderId:     folderId, | ||||||
|  | 		Mode:         mode, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	err := bus.Dispatch(&searchQuery) | 	err := bus.Dispatch(&searchQuery) | ||||||
|   | |||||||
| @@ -46,6 +46,8 @@ func searchHandler(query *Query) error { | |||||||
| 		OrgId:        query.OrgId, | 		OrgId:        query.OrgId, | ||||||
| 		DashboardIds: query.DashboardIds, | 		DashboardIds: query.DashboardIds, | ||||||
| 		Type:         query.Type, | 		Type:         query.Type, | ||||||
|  | 		ParentId:     query.FolderId, | ||||||
|  | 		Mode:         query.Mode, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if err := bus.Dispatch(&dashQuery); err != nil { | 	if err := bus.Dispatch(&dashQuery); err != nil { | ||||||
|   | |||||||
| @@ -48,6 +48,8 @@ type Query struct { | |||||||
| 	IsStarred    bool | 	IsStarred    bool | ||||||
| 	Type         string | 	Type         string | ||||||
| 	DashboardIds []int | 	DashboardIds []int | ||||||
|  | 	FolderId     int64 | ||||||
|  | 	Mode         string | ||||||
|  |  | ||||||
| 	Result HitList | 	Result HitList | ||||||
| } | } | ||||||
| @@ -59,6 +61,8 @@ type FindPersistedDashboardsQuery struct { | |||||||
| 	IsStarred    bool | 	IsStarred    bool | ||||||
| 	DashboardIds []int | 	DashboardIds []int | ||||||
| 	Type         string | 	Type         string | ||||||
|  | 	ParentId     int64 | ||||||
|  | 	Mode         string | ||||||
|  |  | ||||||
| 	Result HitList | 	Result HitList | ||||||
| } | } | ||||||
|   | |||||||
| @@ -25,7 +25,7 @@ func init() { | |||||||
| func SaveDashboard(cmd *m.SaveDashboardCommand) error { | func SaveDashboard(cmd *m.SaveDashboardCommand) error { | ||||||
| 	return inTransaction(func(sess *DBSession) error { | 	return inTransaction(func(sess *DBSession) error { | ||||||
| 		dash := cmd.GetDashboardModel() | 		dash := cmd.GetDashboardModel() | ||||||
| 		fmt.Printf("ParentId: %v", dash.ParentId) |  | ||||||
| 		// try get existing dashboard | 		// try get existing dashboard | ||||||
| 		var existing, sameTitle m.Dashboard | 		var existing, sameTitle m.Dashboard | ||||||
|  |  | ||||||
| @@ -209,9 +209,15 @@ func findDashboards(query *search.FindPersistedDashboardsQuery) ([]DashboardSear | |||||||
| 		sql.WriteString(" AND dashboard.is_folder = 0") | 		sql.WriteString(" AND dashboard.is_folder = 0") | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	if query.ParentId > 0 { | ||||||
|  | 		sql.WriteString(" AND dashboard.parent_id = ?") | ||||||
|  | 		params = append(params, query.ParentId) | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	sql.WriteString(fmt.Sprintf(" ORDER BY dashboard.title ASC LIMIT 1000")) | 	sql.WriteString(fmt.Sprintf(" ORDER BY dashboard.title ASC LIMIT 1000")) | ||||||
|  |  | ||||||
| 	var res []DashboardSearchProjection | 	var res []DashboardSearchProjection | ||||||
|  |  | ||||||
| 	err := x.Sql(sql.String(), params...).Find(&res) | 	err := x.Sql(sql.String(), params...).Find(&res) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| @@ -226,36 +232,20 @@ func SearchDashboards(query *search.FindPersistedDashboardsQuery) error { | |||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	if query.Mode == "tree" { | ||||||
| 		res, err = appendDashboardFolders(res) | 		res, err = appendDashboardFolders(res) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 	query.Result = make([]*search.Hit, 0) |  | ||||||
| 	hits := make(map[int64]*search.Hit) |  | ||||||
|  |  | ||||||
| 	for _, item := range res { |  | ||||||
| 		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{}, |  | ||||||
| 			} |  | ||||||
| 			query.Result = append(query.Result, hit) |  | ||||||
| 			hits[item.Id] = hit |  | ||||||
| 		} |  | ||||||
| 		if len(item.Term) > 0 { |  | ||||||
| 			hit.Tags = append(hit.Tags, item.Term) |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	makeQueryResult(query, res) | ||||||
|  |  | ||||||
|  | 	if query.Mode == "tree" { | ||||||
| 		convertToDashboardFolders(query) | 		convertToDashboardFolders(query) | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	return err | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| // appends parent folders for any hits to the search result | // appends parent folders for any hits to the search result | ||||||
| @@ -298,6 +288,30 @@ func getHitType(item DashboardSearchProjection) search.HitType { | |||||||
| 	return hitType | 	return hitType | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func makeQueryResult(query *search.FindPersistedDashboardsQuery, res []DashboardSearchProjection) { | ||||||
|  | 	query.Result = make([]*search.Hit, 0) | ||||||
|  | 	hits := make(map[int64]*search.Hit) | ||||||
|  |  | ||||||
|  | 	for _, item := range res { | ||||||
|  | 		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{}, | ||||||
|  | 			} | ||||||
|  | 			query.Result = append(query.Result, hit) | ||||||
|  | 			hits[item.Id] = hit | ||||||
|  | 		} | ||||||
|  | 		if len(item.Term) > 0 { | ||||||
|  | 			hit.Tags = append(hit.Tags, item.Term) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| func convertToDashboardFolders(query *search.FindPersistedDashboardsQuery) error { | func convertToDashboardFolders(query *search.FindPersistedDashboardsQuery) error { | ||||||
| 	root := make(map[int64]*search.Hit) | 	root := make(map[int64]*search.Hit) | ||||||
| 	var keys []int64 | 	var keys []int64 | ||||||
|   | |||||||
| @@ -118,6 +118,7 @@ func TestDashboardDataAccess(t *testing.T) { | |||||||
| 				query := search.FindPersistedDashboardsQuery{ | 				query := search.FindPersistedDashboardsQuery{ | ||||||
| 					Title: "test dash 23", | 					Title: "test dash 23", | ||||||
| 					OrgId: 1, | 					OrgId: 1, | ||||||
|  | 					Mode:  "tree", | ||||||
| 				} | 				} | ||||||
|  |  | ||||||
| 				err := SearchDashboards(&query) | 				err := SearchDashboards(&query) | ||||||
| @@ -146,11 +147,26 @@ func TestDashboardDataAccess(t *testing.T) { | |||||||
| 				So(hit.Type, ShouldEqual, search.DashHitFolder) | 				So(hit.Type, ShouldEqual, search.DashHitFolder) | ||||||
| 			}) | 			}) | ||||||
|  |  | ||||||
|  | 			Convey("Should be able to search for a dashboard folder's children", func() { | ||||||
|  | 				query := search.FindPersistedDashboardsQuery{ | ||||||
|  | 					OrgId:    1, | ||||||
|  | 					ParentId: savedFolder.Id, | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				err := SearchDashboards(&query) | ||||||
|  | 				So(err, ShouldBeNil) | ||||||
|  |  | ||||||
|  | 				So(len(query.Result), ShouldEqual, 2) | ||||||
|  | 				hit := query.Result[0] | ||||||
|  | 				So(hit.Id, ShouldEqual, savedDash.Id) | ||||||
|  | 			}) | ||||||
|  |  | ||||||
| 			Convey("Should be able to search for dashboard by dashboard ids", func() { | 			Convey("Should be able to search for dashboard by dashboard ids", func() { | ||||||
| 				Convey("should be able to find two dashboards by id", func() { | 				Convey("should be able to find two dashboards by id", func() { | ||||||
| 					query := search.FindPersistedDashboardsQuery{ | 					query := search.FindPersistedDashboardsQuery{ | ||||||
| 						DashboardIds: []int{2, 3}, | 						DashboardIds: []int{2, 3}, | ||||||
| 						OrgId:        1, | 						OrgId:        1, | ||||||
|  | 						Mode:         "tree", | ||||||
| 					} | 					} | ||||||
|  |  | ||||||
| 					err := SearchDashboards(&query) | 					err := SearchDashboards(&query) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user