mirror of https://github.com/grafana/grafana.git
				
				
				
			dashboard and folder search with permissions
This commit is contained in:
		
							parent
							
								
									b84fd3a7ae
								
							
						
					
					
						commit
						8e8f3c4332
					
				|  | @ -261,8 +261,6 @@ func (hs *HttpServer) registerRoutes() { | ||||||
| 			dashboardRoute.Get("/tags", GetDashboardTags) | 			dashboardRoute.Get("/tags", GetDashboardTags) | ||||||
| 			dashboardRoute.Post("/import", bind(dtos.ImportDashboardCommand{}), wrap(ImportDashboard)) | 			dashboardRoute.Post("/import", bind(dtos.ImportDashboardCommand{}), wrap(ImportDashboard)) | ||||||
| 
 | 
 | ||||||
| 			dashboardRoute.Get("/folders", wrap(GetFoldersForSignedInUser)) |  | ||||||
| 
 |  | ||||||
| 			dashboardRoute.Group("/id/:dashboardId", func(dashIdRoute RouteRegister) { | 			dashboardRoute.Group("/id/:dashboardId", func(dashIdRoute RouteRegister) { | ||||||
| 				dashIdRoute.Get("/versions", wrap(GetDashboardVersions)) | 				dashIdRoute.Get("/versions", wrap(GetDashboardVersions)) | ||||||
| 				dashIdRoute.Get("/versions/:id", wrap(GetDashboardVersion)) | 				dashIdRoute.Get("/versions/:id", wrap(GetDashboardVersion)) | ||||||
|  |  | ||||||
|  | @ -490,19 +490,3 @@ func GetDashboardTags(c *middleware.Context) { | ||||||
| 
 | 
 | ||||||
| 	c.JSON(200, query.Result) | 	c.JSON(200, query.Result) | ||||||
| } | } | ||||||
| 
 |  | ||||||
| func GetFoldersForSignedInUser(c *middleware.Context) Response { |  | ||||||
| 	title := c.Query("query") |  | ||||||
| 	query := m.GetFoldersForSignedInUserQuery{ |  | ||||||
| 		OrgId:        c.OrgId, |  | ||||||
| 		SignedInUser: c.SignedInUser, |  | ||||||
| 		Title:        title, |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	err := bus.Dispatch(&query) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return ApiError(500, "Failed to get folders from database", err) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return Json(200, query.Result) |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  | @ -6,6 +6,7 @@ import ( | ||||||
| 	"github.com/grafana/grafana/pkg/bus" | 	"github.com/grafana/grafana/pkg/bus" | ||||||
| 	"github.com/grafana/grafana/pkg/metrics" | 	"github.com/grafana/grafana/pkg/metrics" | ||||||
| 	"github.com/grafana/grafana/pkg/middleware" | 	"github.com/grafana/grafana/pkg/middleware" | ||||||
|  | 	"github.com/grafana/grafana/pkg/models" | ||||||
| 	"github.com/grafana/grafana/pkg/services/search" | 	"github.com/grafana/grafana/pkg/services/search" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | @ -15,11 +16,16 @@ 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") | ||||||
|  | 	permission := models.PERMISSION_VIEW | ||||||
| 
 | 
 | ||||||
| 	if limit == 0 { | 	if limit == 0 { | ||||||
| 		limit = 1000 | 		limit = 1000 | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if c.Query("permission") == "Edit" { | ||||||
|  | 		permission = models.PERMISSION_EDIT | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	dbids := make([]int64, 0) | 	dbids := make([]int64, 0) | ||||||
| 	for _, id := range c.QueryStrings("dashboardIds") { | 	for _, id := range c.QueryStrings("dashboardIds") { | ||||||
| 		dashboardId, err := strconv.ParseInt(id, 10, 64) | 		dashboardId, err := strconv.ParseInt(id, 10, 64) | ||||||
|  | @ -46,6 +52,7 @@ func Search(c *middleware.Context) { | ||||||
| 		DashboardIds: dbids, | 		DashboardIds: dbids, | ||||||
| 		Type:         dashboardType, | 		Type:         dashboardType, | ||||||
| 		FolderIds:    folderIds, | 		FolderIds:    folderIds, | ||||||
|  | 		Permission:   permission, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	err := bus.Dispatch(&searchQuery) | 	err := bus.Dispatch(&searchQuery) | ||||||
|  |  | ||||||
|  | @ -270,18 +270,6 @@ type GetDashboardsBySlugQuery struct { | ||||||
| 	Result []*Dashboard | 	Result []*Dashboard | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type GetFoldersForSignedInUserQuery struct { |  | ||||||
| 	OrgId        int64 |  | ||||||
| 	SignedInUser *SignedInUser |  | ||||||
| 	Title        string |  | ||||||
| 	Result       []*DashboardFolder |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| type DashboardFolder struct { |  | ||||||
| 	Id    int64  `json:"id"` |  | ||||||
| 	Title string `json:"title"` |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| type DashboardPermissionForUser struct { | type DashboardPermissionForUser struct { | ||||||
| 	DashboardId    int64          `json:"dashboardId"` | 	DashboardId    int64          `json:"dashboardId"` | ||||||
| 	Permission     PermissionType `json:"permission"` | 	Permission     PermissionType `json:"permission"` | ||||||
|  |  | ||||||
|  | @ -21,6 +21,7 @@ func searchHandler(query *Query) error { | ||||||
| 		FolderIds:    query.FolderIds, | 		FolderIds:    query.FolderIds, | ||||||
| 		Tags:         query.Tags, | 		Tags:         query.Tags, | ||||||
| 		Limit:        query.Limit, | 		Limit:        query.Limit, | ||||||
|  | 		Permission:   query.Permission, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if err := bus.Dispatch(&dashQuery); err != nil { | 	if err := bus.Dispatch(&dashQuery); err != nil { | ||||||
|  |  | ||||||
|  | @ -52,6 +52,7 @@ type Query struct { | ||||||
| 	Type         string | 	Type         string | ||||||
| 	DashboardIds []int64 | 	DashboardIds []int64 | ||||||
| 	FolderIds    []int64 | 	FolderIds    []int64 | ||||||
|  | 	Permission   models.PermissionType | ||||||
| 
 | 
 | ||||||
| 	Result HitList | 	Result HitList | ||||||
| } | } | ||||||
|  | @ -66,7 +67,7 @@ type FindPersistedDashboardsQuery struct { | ||||||
| 	FolderIds    []int64 | 	FolderIds    []int64 | ||||||
| 	Tags         []string | 	Tags         []string | ||||||
| 	Limit        int | 	Limit        int | ||||||
| 	IsBrowse     bool | 	Permission   models.PermissionType | ||||||
| 
 | 
 | ||||||
| 	Result HitList | 	Result HitList | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| package sqlstore | package sqlstore | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"fmt" | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
|  | @ -21,7 +22,6 @@ func init() { | ||||||
| 	bus.AddHandler("sql", GetDashboardSlugById) | 	bus.AddHandler("sql", GetDashboardSlugById) | ||||||
| 	bus.AddHandler("sql", GetDashboardUIDById) | 	bus.AddHandler("sql", GetDashboardUIDById) | ||||||
| 	bus.AddHandler("sql", GetDashboardsByPluginId) | 	bus.AddHandler("sql", GetDashboardsByPluginId) | ||||||
| 	bus.AddHandler("sql", GetFoldersForSignedInUser) |  | ||||||
| 	bus.AddHandler("sql", GetDashboardPermissionsForUser) | 	bus.AddHandler("sql", GetDashboardPermissionsForUser) | ||||||
| 	bus.AddHandler("sql", GetDashboardsBySlug) | 	bus.AddHandler("sql", GetDashboardsBySlug) | ||||||
| } | } | ||||||
|  | @ -256,7 +256,7 @@ func findDashboards(query *search.FindPersistedDashboardsQuery) ([]DashboardSear | ||||||
| 		limit = 1000 | 		limit = 1000 | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	sb := NewSearchBuilder(query.SignedInUser, limit). | 	sb := NewSearchBuilder(query.SignedInUser, limit, query.Permission). | ||||||
| 		WithTags(query.Tags). | 		WithTags(query.Tags). | ||||||
| 		WithDashboardIdsIn(query.DashboardIds) | 		WithDashboardIdsIn(query.DashboardIds) | ||||||
| 
 | 
 | ||||||
|  | @ -279,6 +279,7 @@ func findDashboards(query *search.FindPersistedDashboardsQuery) ([]DashboardSear | ||||||
| 	var res []DashboardSearchProjection | 	var res []DashboardSearchProjection | ||||||
| 
 | 
 | ||||||
| 	sql, params := sb.ToSql() | 	sql, params := sb.ToSql() | ||||||
|  | 	fmt.Printf("%s, %v", sql, params) | ||||||
| 	sqlog.Info("sql", "sql", sql, "params", params) | 	sqlog.Info("sql", "sql", sql, "params", params) | ||||||
| 	err := x.Sql(sql, params...).Find(&res) | 	err := x.Sql(sql, params...).Find(&res) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|  | @ -358,54 +359,6 @@ func GetDashboardTags(query *m.GetDashboardTagsQuery) error { | ||||||
| 	return err | 	return err | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func GetFoldersForSignedInUser(query *m.GetFoldersForSignedInUserQuery) error { |  | ||||||
| 	query.Result = make([]*m.DashboardFolder, 0) |  | ||||||
| 	var err error |  | ||||||
| 
 |  | ||||||
| 	if query.SignedInUser.OrgRole == m.ROLE_ADMIN { |  | ||||||
| 		sql := `SELECT distinct d.id, d.title |  | ||||||
| 		FROM dashboard AS d WHERE d.is_folder = ? AND d.org_id = ? |  | ||||||
| 		ORDER BY d.title ASC` |  | ||||||
| 
 |  | ||||||
| 		err = x.Sql(sql, dialect.BooleanStr(true), query.OrgId).Find(&query.Result) |  | ||||||
| 	} else { |  | ||||||
| 		params := make([]interface{}, 0) |  | ||||||
| 		sql := `SELECT distinct d.id, d.title |  | ||||||
| 		FROM dashboard AS d |  | ||||||
| 			LEFT JOIN dashboard_acl AS da ON d.id = da.dashboard_id |  | ||||||
| 			LEFT JOIN team_member AS ugm ON ugm.team_id =  da.team_id |  | ||||||
| 			LEFT JOIN org_user ou ON ou.role = da.role AND ou.user_id = ? |  | ||||||
| 			LEFT JOIN org_user ouRole ON ouRole.role = 'Editor' AND ouRole.user_id = ? AND ouRole.org_id = ?` |  | ||||||
| 		params = append(params, query.SignedInUser.UserId) |  | ||||||
| 		params = append(params, query.SignedInUser.UserId) |  | ||||||
| 		params = append(params, query.OrgId) |  | ||||||
| 
 |  | ||||||
| 		sql += ` WHERE |  | ||||||
| 			d.org_id = ? AND |  | ||||||
| 			d.is_folder = ? AND |  | ||||||
| 			( |  | ||||||
| 				(d.has_acl = ? AND da.permission > 1 AND (da.user_id = ? OR ugm.user_id = ? OR ou.id IS NOT NULL)) |  | ||||||
| 				OR (d.has_acl = ? AND ouRole.id IS NOT NULL) |  | ||||||
| 			)` |  | ||||||
| 		params = append(params, query.OrgId) |  | ||||||
| 		params = append(params, dialect.BooleanStr(true)) |  | ||||||
| 		params = append(params, dialect.BooleanStr(true)) |  | ||||||
| 		params = append(params, query.SignedInUser.UserId) |  | ||||||
| 		params = append(params, query.SignedInUser.UserId) |  | ||||||
| 		params = append(params, dialect.BooleanStr(false)) |  | ||||||
| 
 |  | ||||||
| 		if len(query.Title) > 0 { |  | ||||||
| 			sql += " AND d.title " + dialect.LikeStr() + " ?" |  | ||||||
| 			params = append(params, "%"+query.Title+"%") |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		sql += ` ORDER BY d.title ASC` |  | ||||||
| 		err = x.Sql(sql, params...).Find(&query.Result) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return err |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func DeleteDashboard(cmd *m.DeleteDashboardCommand) error { | func DeleteDashboard(cmd *m.DeleteDashboardCommand) error { | ||||||
| 	return inTransaction(func(sess *DBSession) error { | 	return inTransaction(func(sess *DBSession) error { | ||||||
| 		dashboard := m.Dashboard{Id: cmd.Id, OrgId: cmd.OrgId} | 		dashboard := m.Dashboard{Id: cmd.Id, OrgId: cmd.OrgId} | ||||||
|  |  | ||||||
|  | @ -227,12 +227,14 @@ func TestDashboardFolderDataAccess(t *testing.T) { | ||||||
| 
 | 
 | ||||||
| 			Convey("Admin users", func() { | 			Convey("Admin users", func() { | ||||||
| 				Convey("Should have write access to all dashboard folders in their org", func() { | 				Convey("Should have write access to all dashboard folders in their org", func() { | ||||||
| 					query := m.GetFoldersForSignedInUserQuery{ | 					query := search.FindPersistedDashboardsQuery{ | ||||||
| 						OrgId:        1, | 						OrgId:        1, | ||||||
| 						SignedInUser: &m.SignedInUser{UserId: adminUser.Id, OrgRole: m.ROLE_ADMIN}, | 						SignedInUser: &m.SignedInUser{UserId: adminUser.Id, OrgRole: m.ROLE_ADMIN, OrgId: 1}, | ||||||
|  | 						Permission:   m.PERMISSION_VIEW, | ||||||
|  | 						Type:         "dash-folder", | ||||||
| 					} | 					} | ||||||
| 
 | 
 | ||||||
| 					err := GetFoldersForSignedInUser(&query) | 					err := SearchDashboards(&query) | ||||||
| 					So(err, ShouldBeNil) | 					So(err, ShouldBeNil) | ||||||
| 
 | 
 | ||||||
| 					So(len(query.Result), ShouldEqual, 2) | 					So(len(query.Result), ShouldEqual, 2) | ||||||
|  | @ -260,13 +262,14 @@ func TestDashboardFolderDataAccess(t *testing.T) { | ||||||
| 			}) | 			}) | ||||||
| 
 | 
 | ||||||
| 			Convey("Editor users", func() { | 			Convey("Editor users", func() { | ||||||
| 				query := m.GetFoldersForSignedInUserQuery{ | 				query := search.FindPersistedDashboardsQuery{ | ||||||
| 					OrgId:        1, | 					OrgId:        1, | ||||||
| 					SignedInUser: &m.SignedInUser{UserId: editorUser.Id, OrgRole: m.ROLE_EDITOR}, | 					SignedInUser: &m.SignedInUser{UserId: editorUser.Id, OrgRole: m.ROLE_EDITOR, OrgId: 1}, | ||||||
|  | 					Permission:   m.PERMISSION_EDIT, | ||||||
| 				} | 				} | ||||||
| 
 | 
 | ||||||
| 				Convey("Should have write access to all dashboard folders with default ACL", func() { | 				Convey("Should have write access to all dashboard folders with default ACL", func() { | ||||||
| 					err := GetFoldersForSignedInUser(&query) | 					err := SearchDashboards(&query) | ||||||
| 					So(err, ShouldBeNil) | 					So(err, ShouldBeNil) | ||||||
| 
 | 
 | ||||||
| 					So(len(query.Result), ShouldEqual, 2) | 					So(len(query.Result), ShouldEqual, 2) | ||||||
|  | @ -295,7 +298,7 @@ func TestDashboardFolderDataAccess(t *testing.T) { | ||||||
| 				Convey("Should have write access to one dashboard folder if default role changed to view for one folder", func() { | 				Convey("Should have write access to one dashboard folder if default role changed to view for one folder", func() { | ||||||
| 					updateTestDashboardWithAcl(folder1.Id, editorUser.Id, m.PERMISSION_VIEW) | 					updateTestDashboardWithAcl(folder1.Id, editorUser.Id, m.PERMISSION_VIEW) | ||||||
| 
 | 
 | ||||||
| 					err := GetFoldersForSignedInUser(&query) | 					err := SearchDashboards(&query) | ||||||
| 					So(err, ShouldBeNil) | 					So(err, ShouldBeNil) | ||||||
| 
 | 
 | ||||||
| 					So(len(query.Result), ShouldEqual, 1) | 					So(len(query.Result), ShouldEqual, 1) | ||||||
|  | @ -305,13 +308,14 @@ func TestDashboardFolderDataAccess(t *testing.T) { | ||||||
| 			}) | 			}) | ||||||
| 
 | 
 | ||||||
| 			Convey("Viewer users", func() { | 			Convey("Viewer users", func() { | ||||||
| 				query := m.GetFoldersForSignedInUserQuery{ | 				query := search.FindPersistedDashboardsQuery{ | ||||||
| 					OrgId:        1, | 					OrgId:        1, | ||||||
| 					SignedInUser: &m.SignedInUser{UserId: viewerUser.Id, OrgRole: m.ROLE_VIEWER}, | 					SignedInUser: &m.SignedInUser{UserId: viewerUser.Id, OrgRole: m.ROLE_VIEWER, OrgId: 1}, | ||||||
|  | 					Permission:   m.PERMISSION_EDIT, | ||||||
| 				} | 				} | ||||||
| 
 | 
 | ||||||
| 				Convey("Should have no write access to any dashboard folders with default ACL", func() { | 				Convey("Should have no write access to any dashboard folders with default ACL", func() { | ||||||
| 					err := GetFoldersForSignedInUser(&query) | 					err := SearchDashboards(&query) | ||||||
| 					So(err, ShouldBeNil) | 					So(err, ShouldBeNil) | ||||||
| 
 | 
 | ||||||
| 					So(len(query.Result), ShouldEqual, 0) | 					So(len(query.Result), ShouldEqual, 0) | ||||||
|  | @ -338,7 +342,7 @@ func TestDashboardFolderDataAccess(t *testing.T) { | ||||||
| 				Convey("Should be able to get one dashboard folder if default role changed to edit for one folder", func() { | 				Convey("Should be able to get one dashboard folder if default role changed to edit for one folder", func() { | ||||||
| 					updateTestDashboardWithAcl(folder1.Id, viewerUser.Id, m.PERMISSION_EDIT) | 					updateTestDashboardWithAcl(folder1.Id, viewerUser.Id, m.PERMISSION_EDIT) | ||||||
| 
 | 
 | ||||||
| 					err := GetFoldersForSignedInUser(&query) | 					err := SearchDashboards(&query) | ||||||
| 					So(err, ShouldBeNil) | 					So(err, ShouldBeNil) | ||||||
| 
 | 
 | ||||||
| 					So(len(query.Result), ShouldEqual, 1) | 					So(len(query.Result), ShouldEqual, 1) | ||||||
|  |  | ||||||
|  | @ -18,12 +18,14 @@ type SearchBuilder struct { | ||||||
| 	whereTypeFolder     bool | 	whereTypeFolder     bool | ||||||
| 	whereTypeDash       bool | 	whereTypeDash       bool | ||||||
| 	whereFolderIds      []int64 | 	whereFolderIds      []int64 | ||||||
|  | 	permission          m.PermissionType | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func NewSearchBuilder(signedInUser *m.SignedInUser, limit int) *SearchBuilder { | func NewSearchBuilder(signedInUser *m.SignedInUser, limit int, permission m.PermissionType) *SearchBuilder { | ||||||
| 	searchBuilder := &SearchBuilder{ | 	searchBuilder := &SearchBuilder{ | ||||||
| 		signedInUser: signedInUser, | 		signedInUser: signedInUser, | ||||||
| 		limit:        limit, | 		limit:        limit, | ||||||
|  | 		permission:   permission, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return searchBuilder | 	return searchBuilder | ||||||
|  | @ -174,7 +176,7 @@ func (sb *SearchBuilder) buildSearchWhereClause() { | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	sb.writeDashboardPermissionFilter(sb.signedInUser, m.PERMISSION_VIEW) | 	sb.writeDashboardPermissionFilter(sb.signedInUser, sb.permission) | ||||||
| 
 | 
 | ||||||
| 	if len(sb.whereTitle) > 0 { | 	if len(sb.whereTitle) > 0 { | ||||||
| 		sb.sql.WriteString(" AND dashboard.title " + dialect.LikeStr() + " ?") | 		sb.sql.WriteString(" AND dashboard.title " + dialect.LikeStr() + " ?") | ||||||
|  |  | ||||||
|  | @ -16,7 +16,8 @@ func TestSearchBuilder(t *testing.T) { | ||||||
| 			OrgId:  1, | 			OrgId:  1, | ||||||
| 			UserId: 1, | 			UserId: 1, | ||||||
| 		} | 		} | ||||||
| 		sb := NewSearchBuilder(signedInUser, 1000) | 
 | ||||||
|  | 		sb := NewSearchBuilder(signedInUser, 1000, m.PERMISSION_VIEW) | ||||||
| 
 | 
 | ||||||
| 		Convey("When building a normal search", func() { | 		Convey("When building a normal search", func() { | ||||||
| 			sql, params := sb.IsStarred().WithTitle("test").ToSql() | 			sql, params := sb.IsStarred().WithTitle("test").ToSql() | ||||||
|  |  | ||||||
|  | @ -12,7 +12,7 @@ type SqlBuilder struct { | ||||||
| 	params []interface{} | 	params []interface{} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (sb *SqlBuilder) writeDashboardPermissionFilter(user *m.SignedInUser, minPermission m.PermissionType) { | func (sb *SqlBuilder) writeDashboardPermissionFilter(user *m.SignedInUser, permission m.PermissionType) { | ||||||
| 
 | 
 | ||||||
| 	if user.OrgRole == m.ROLE_ADMIN { | 	if user.OrgRole == m.ROLE_ADMIN { | ||||||
| 		return | 		return | ||||||
|  | @ -40,6 +40,6 @@ func (sb *SqlBuilder) writeDashboardPermissionFilter(user *m.SignedInUser, minPe | ||||||
| 		) | 		) | ||||||
| 	)`) | 	)`) | ||||||
| 
 | 
 | ||||||
| 	sb.params = append(sb.params, user.OrgId, minPermission, user.UserId, user.UserId) | 	sb.params = append(sb.params, user.OrgId, permission, user.UserId, user.UserId) | ||||||
| 	sb.params = append(sb.params, okRoles...) | 	sb.params = append(sb.params, okRoles...) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -30,7 +30,13 @@ export class FolderPickerCtrl { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   getOptions(query) { |   getOptions(query) { | ||||||
|     return this.backendSrv.get('api/dashboards/folders', { query: query }).then(result => { |     const params = { | ||||||
|  |       query: query, | ||||||
|  |       type: 'dash-folder', | ||||||
|  |       permission: 'Edit', | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     return this.backendSrv.get('api/search', params).then(result => { | ||||||
|       if ( |       if ( | ||||||
|         query === '' || |         query === '' || | ||||||
|         query.toLowerCase() === 'g' || |         query.toLowerCase() === 'g' || | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue