mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
K8s: Implement folder search (#99781)
This commit is contained in:
parent
7007342704
commit
2d491a9367
@ -490,7 +490,7 @@ func setupServer(b testing.TB, sc benchScenario, features featuremgmt.FeatureTog
|
||||
SQLStore: sc.db,
|
||||
Features: features,
|
||||
QuotaService: quotaSrv,
|
||||
SearchService: search.ProvideService(sc.cfg, sc.db, starSvc, dashboardSvc),
|
||||
SearchService: search.ProvideService(sc.cfg, sc.db, starSvc, dashboardSvc, folderServiceWithFlagOn, features),
|
||||
folderService: folderServiceWithFlagOn,
|
||||
DashboardService: dashboardSvc,
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ func ParseResults(result *resource.ResourceSearchResponse, offset int64) (*v0alp
|
||||
}
|
||||
|
||||
titleIDX := 0
|
||||
folderIDX := 1
|
||||
folderIDX := -1
|
||||
tagsIDX := -1
|
||||
scoreIDX := 0
|
||||
explainIDX := 0
|
||||
@ -80,9 +80,11 @@ func ParseResults(result *resource.ResourceSearchResponse, offset int64) (*v0alp
|
||||
Resource: row.Key.Resource, // folders | dashboards
|
||||
Name: row.Key.Name, // The Grafana UID
|
||||
Title: string(row.Cells[titleIDX]),
|
||||
Folder: string(row.Cells[folderIDX]),
|
||||
Field: fields,
|
||||
}
|
||||
if folderIDX > 0 && row.Cells[folderIDX] != nil {
|
||||
hit.Folder = string(row.Cells[folderIDX])
|
||||
}
|
||||
if tagsIDX > 0 && row.Cells[tagsIDX] != nil {
|
||||
_ = json.Unmarshal(row.Cells[tagsIDX], &hit.Tags)
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
"github.com/grafana/grafana/pkg/services/publicdashboards"
|
||||
"github.com/grafana/grafana/pkg/services/search/model"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
||||
"github.com/grafana/grafana/pkg/services/store/entity"
|
||||
@ -167,6 +168,17 @@ func (s *Service) DBMigration(db db.DB) {
|
||||
s.log.Debug("syncing dashboard and folder tables finished")
|
||||
}
|
||||
|
||||
func (s *Service) SearchFolders(ctx context.Context, q folder.SearchFoldersQuery) (model.HitList, error) {
|
||||
if s.features.IsEnabledGlobally(featuremgmt.FlagKubernetesFoldersServiceV2) {
|
||||
// TODO:
|
||||
// - implement filtering by alerting folders and k6 folders (see the dashboards store `FindDashboards` method for reference)
|
||||
// - implement fallback on search client in unistore to go to legacy store (will need to read from dashboard store)
|
||||
return s.searchFoldersFromApiServer(ctx, q)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("cannot be called on the legacy folder service")
|
||||
}
|
||||
|
||||
func (s *Service) GetFolders(ctx context.Context, q folder.GetFoldersQuery) ([]*folder.Folder, error) {
|
||||
if s.features.IsEnabledGlobally(featuremgmt.FlagKubernetesFoldersServiceV2) {
|
||||
return s.getFoldersFromApiServer(ctx, q)
|
||||
|
@ -3,6 +3,7 @@ package folderimpl
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@ -20,6 +21,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/apis/folder/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/events"
|
||||
"github.com/grafana/grafana/pkg/infra/metrics"
|
||||
"github.com/grafana/grafana/pkg/infra/slugify"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
@ -28,9 +30,11 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
"github.com/grafana/grafana/pkg/services/search/model"
|
||||
"github.com/grafana/grafana/pkg/services/store/entity"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/storage/unified/resource"
|
||||
"github.com/grafana/grafana/pkg/storage/unified/search"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
)
|
||||
|
||||
@ -169,6 +173,101 @@ func (s *Service) getFromApiServer(ctx context.Context, q *folder.GetFolderQuery
|
||||
return f, err
|
||||
}
|
||||
|
||||
// searchFoldesFromApiServer uses the search grpc connection to search folders and returns the hit list
|
||||
func (s *Service) searchFoldersFromApiServer(ctx context.Context, query folder.SearchFoldersQuery) (model.HitList, error) {
|
||||
if query.OrgID == 0 {
|
||||
requester, err := identity.GetRequester(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
query.OrgID = requester.GetOrgID()
|
||||
}
|
||||
|
||||
request := &resource.ResourceSearchRequest{
|
||||
Options: &resource.ListOptions{
|
||||
Key: &resource.ResourceKey{
|
||||
Namespace: s.k8sclient.getNamespace(query.OrgID),
|
||||
Group: v0alpha1.FolderResourceInfo.GroupVersionResource().Group,
|
||||
Resource: v0alpha1.FolderResourceInfo.GroupVersionResource().Resource,
|
||||
},
|
||||
Fields: []*resource.Requirement{},
|
||||
Labels: []*resource.Requirement{},
|
||||
},
|
||||
Limit: 100000}
|
||||
|
||||
if len(query.UIDs) > 0 {
|
||||
request.Options.Fields = []*resource.Requirement{{
|
||||
Key: resource.SEARCH_FIELD_NAME,
|
||||
Operator: string(selection.In),
|
||||
Values: query.UIDs,
|
||||
}}
|
||||
} else if len(query.IDs) > 0 {
|
||||
values := make([]string, len(query.IDs))
|
||||
for i, id := range query.IDs {
|
||||
values[i] = strconv.FormatInt(id, 10)
|
||||
}
|
||||
|
||||
request.Options.Labels = append(request.Options.Labels, &resource.Requirement{
|
||||
Key: utils.LabelKeyDeprecatedInternalID, // nolint:staticcheck
|
||||
Operator: string(selection.In),
|
||||
Values: values,
|
||||
})
|
||||
}
|
||||
|
||||
if query.Title != "" {
|
||||
// allow wildcard search
|
||||
request.Query = "*" + strings.ToLower(query.Title) + "*"
|
||||
}
|
||||
|
||||
if query.Limit > 0 {
|
||||
request.Limit = query.Limit
|
||||
}
|
||||
|
||||
client := s.k8sclient.getSearcher(ctx)
|
||||
|
||||
res, err := client.Search(ctx, request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
parsedResults, err := dashboardsearch.ParseResults(res, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hitList := make([]*model.Hit, len(parsedResults.Hits))
|
||||
foldersMap := map[string]*folder.Folder{}
|
||||
for i, item := range parsedResults.Hits {
|
||||
f, ok := foldersMap[item.Folder]
|
||||
if !ok {
|
||||
f, err = s.Get(ctx, &folder.GetFolderQuery{
|
||||
UID: &item.Folder,
|
||||
OrgID: query.OrgID,
|
||||
SignedInUser: query.SignedInUser,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
foldersMap[item.Folder] = f
|
||||
}
|
||||
slug := slugify.Slugify(item.Title)
|
||||
hitList[i] = &model.Hit{
|
||||
ID: item.Field.GetNestedInt64(search.DASHBOARD_LEGACY_ID),
|
||||
UID: item.Name,
|
||||
OrgID: query.OrgID,
|
||||
Title: item.Title,
|
||||
URI: "db/" + slug,
|
||||
URL: dashboards.GetFolderURL(item.Name, slug),
|
||||
Type: model.DashHitFolder,
|
||||
FolderUID: item.Folder,
|
||||
FolderTitle: f.Title,
|
||||
FolderID: f.ID, // nolint:staticcheck
|
||||
}
|
||||
}
|
||||
|
||||
return hitList, nil
|
||||
}
|
||||
|
||||
func (s *Service) getFolderByIDFromApiServer(ctx context.Context, id int64, orgID int64) (*folder.Folder, error) {
|
||||
if id == 0 {
|
||||
return &folder.GeneralFolder, nil
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/grpc"
|
||||
"k8s.io/client-go/dynamic"
|
||||
clientrest "k8s.io/client-go/rest"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
@ -33,6 +34,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
ngstore "github.com/grafana/grafana/pkg/services/ngalert/store"
|
||||
"github.com/grafana/grafana/pkg/services/publicdashboards"
|
||||
"github.com/grafana/grafana/pkg/services/search/model"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/services/user/usertest"
|
||||
@ -605,6 +607,81 @@ func (r resourceClientMock) Search(ctx context.Context, in *resource.ResourceSea
|
||||
}, nil
|
||||
}
|
||||
|
||||
if in.Query == "*test*" {
|
||||
return &resource.ResourceSearchResponse{
|
||||
Results: &resource.ResourceTable{
|
||||
Columns: []*resource.ResourceTableColumnDefinition{
|
||||
{
|
||||
Name: "_id",
|
||||
Type: resource.ResourceTableColumnDefinition_STRING,
|
||||
},
|
||||
{
|
||||
Name: "title",
|
||||
Type: resource.ResourceTableColumnDefinition_STRING,
|
||||
},
|
||||
{
|
||||
Name: "folder",
|
||||
Type: resource.ResourceTableColumnDefinition_STRING,
|
||||
},
|
||||
},
|
||||
Rows: []*resource.ResourceTableRow{
|
||||
{
|
||||
Key: &resource.ResourceKey{
|
||||
Name: "uid",
|
||||
Resource: "folders",
|
||||
},
|
||||
Cells: [][]byte{
|
||||
[]byte("123"),
|
||||
[]byte("testing-123"),
|
||||
[]byte("parent-uid"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
TotalHits: 1,
|
||||
}, nil
|
||||
}
|
||||
|
||||
if len(in.Options.Fields) > 0 &&
|
||||
in.Options.Fields[0].Key == resource.SEARCH_FIELD_NAME &&
|
||||
in.Options.Fields[0].Operator == "in" &&
|
||||
len(in.Options.Fields[0].Values) > 0 {
|
||||
rows := []*resource.ResourceTableRow{}
|
||||
for i, row := range in.Options.Fields[0].Values {
|
||||
rows = append(rows, &resource.ResourceTableRow{
|
||||
Key: &resource.ResourceKey{
|
||||
Name: row,
|
||||
Resource: "folders",
|
||||
},
|
||||
Cells: [][]byte{
|
||||
[]byte(fmt.Sprintf("%d", i)), // set legacy id as the row id
|
||||
[]byte(fmt.Sprintf("folder%d", i)), // set title as folder + row id
|
||||
[]byte(""),
|
||||
},
|
||||
})
|
||||
}
|
||||
return &resource.ResourceSearchResponse{
|
||||
Results: &resource.ResourceTable{
|
||||
Columns: []*resource.ResourceTableColumnDefinition{
|
||||
{
|
||||
Name: "_id",
|
||||
Type: resource.ResourceTableColumnDefinition_STRING,
|
||||
},
|
||||
{
|
||||
Name: "title",
|
||||
Type: resource.ResourceTableColumnDefinition_STRING,
|
||||
},
|
||||
{
|
||||
Name: "folder",
|
||||
Type: resource.ResourceTableColumnDefinition_STRING,
|
||||
},
|
||||
},
|
||||
Rows: rows,
|
||||
},
|
||||
TotalHits: int64(len(rows)),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// not found
|
||||
return &resource.ResourceSearchResponse{
|
||||
Results: &resource.ResourceTable{},
|
||||
@ -628,3 +705,132 @@ func (r resourceClientMock) GetBlob(ctx context.Context, in *resource.GetBlobReq
|
||||
func (r resourceClientMock) IsHealthy(ctx context.Context, in *resource.HealthCheckRequest, opts ...grpc.CallOption) (*resource.HealthCheckResponse, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
type mockFoldersK8sCli struct {
|
||||
mock.Mock
|
||||
searcher resourceClientMock
|
||||
}
|
||||
|
||||
func (m *mockFoldersK8sCli) getClient(ctx context.Context, orgID int64) (dynamic.ResourceInterface, bool) {
|
||||
args := m.Called(ctx, orgID)
|
||||
return args.Get(0).(dynamic.ResourceInterface), args.Bool(1)
|
||||
}
|
||||
|
||||
func (m *mockFoldersK8sCli) getNamespace(orgID int64) string {
|
||||
if orgID == 1 {
|
||||
return "default"
|
||||
}
|
||||
return fmt.Sprintf("orgs-%d", orgID)
|
||||
}
|
||||
|
||||
func (m *mockFoldersK8sCli) getSearcher(ctx context.Context) resource.ResourceClient {
|
||||
return m.searcher
|
||||
}
|
||||
|
||||
func TestSearchFoldersFromApiServer(t *testing.T) {
|
||||
fakeK8sClient := new(mockFoldersK8sCli)
|
||||
service := Service{
|
||||
k8sclient: fakeK8sClient,
|
||||
features: featuremgmt.WithFeatures(featuremgmt.FlagKubernetesFoldersServiceV2),
|
||||
}
|
||||
fakeK8sClient.On("getSearcher", mock.Anything).Return(fakeK8sClient)
|
||||
user := &user.SignedInUser{OrgID: 1}
|
||||
ctx := identity.WithRequester(context.Background(), user)
|
||||
|
||||
t.Run("Should search by uids if provided", func(t *testing.T) {
|
||||
query := folder.SearchFoldersQuery{
|
||||
UIDs: []string{"uid1", "uid2"},
|
||||
IDs: []int64{1, 2}, // will ignore these because uid is passed in
|
||||
SignedInUser: user,
|
||||
}
|
||||
result, err := service.searchFoldersFromApiServer(ctx, query)
|
||||
require.NoError(t, err)
|
||||
|
||||
expectedResult := model.HitList{
|
||||
{
|
||||
UID: "uid1",
|
||||
// no parent folder is returned, so the general folder should be set
|
||||
FolderID: 0,
|
||||
FolderTitle: "General",
|
||||
// orgID should be taken from signed in user
|
||||
OrgID: 1,
|
||||
// the rest should be automatically set when parsing the hit results from search
|
||||
Type: model.DashHitFolder,
|
||||
URI: "db/folder0",
|
||||
Title: "folder0",
|
||||
URL: "/dashboards/f/uid1/folder0",
|
||||
},
|
||||
{
|
||||
UID: "uid2",
|
||||
FolderID: 0,
|
||||
FolderTitle: "General",
|
||||
OrgID: 1,
|
||||
Type: model.DashHitFolder,
|
||||
URI: "db/folder1",
|
||||
Title: "folder1",
|
||||
URL: "/dashboards/f/uid2/folder1",
|
||||
},
|
||||
}
|
||||
require.Equal(t, expectedResult, result)
|
||||
})
|
||||
|
||||
t.Run("Search by ID if uids are not provided", func(t *testing.T) {
|
||||
query := folder.SearchFoldersQuery{
|
||||
IDs: []int64{123},
|
||||
SignedInUser: user,
|
||||
}
|
||||
result, err := service.searchFoldersFromApiServer(ctx, query)
|
||||
require.NoError(t, err)
|
||||
|
||||
expectedResult := model.HitList{
|
||||
{
|
||||
UID: "foo",
|
||||
FolderID: 0,
|
||||
FolderTitle: "General",
|
||||
OrgID: 1,
|
||||
Type: model.DashHitFolder,
|
||||
URI: "db/folder1",
|
||||
Title: "folder1",
|
||||
URL: "/dashboards/f/foo/folder1",
|
||||
},
|
||||
}
|
||||
require.Equal(t, expectedResult, result)
|
||||
})
|
||||
|
||||
t.Run("Search by title, wildcard should be added to search request (won't match in search mock if not)", func(t *testing.T) {
|
||||
// the search here will return a parent, this will be the parent folder returned when we query for it to add to the hit info
|
||||
fakeFolderStore := folder.NewFakeStore()
|
||||
fakeFolderStore.ExpectedFolder = &folder.Folder{
|
||||
UID: "parent-uid",
|
||||
ID: 2,
|
||||
Title: "parent title",
|
||||
}
|
||||
service.unifiedStore = fakeFolderStore
|
||||
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{
|
||||
CanSaveValue: true,
|
||||
CanViewValue: true,
|
||||
})
|
||||
|
||||
query := folder.SearchFoldersQuery{
|
||||
Title: "test",
|
||||
SignedInUser: user,
|
||||
}
|
||||
result, err := service.searchFoldersFromApiServer(ctx, query)
|
||||
require.NoError(t, err)
|
||||
|
||||
expectedResult := model.HitList{
|
||||
{
|
||||
UID: "uid",
|
||||
FolderID: 2,
|
||||
FolderTitle: "parent title",
|
||||
FolderUID: "parent-uid",
|
||||
OrgID: 1,
|
||||
Type: model.DashHitFolder,
|
||||
URI: "db/testing-123",
|
||||
Title: "testing-123",
|
||||
URL: "/dashboards/f/uid/testing-123",
|
||||
},
|
||||
}
|
||||
require.Equal(t, expectedResult, result)
|
||||
})
|
||||
}
|
||||
|
@ -4,11 +4,13 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/search/model"
|
||||
)
|
||||
|
||||
type FakeService struct {
|
||||
ExpectedFolders []*folder.Folder
|
||||
ExpectedFolder *folder.Folder
|
||||
ExpectedHitList model.HitList
|
||||
ExpectedError error
|
||||
ExpectedDescendantCounts map[string]int64
|
||||
}
|
||||
@ -82,6 +84,11 @@ func (s *FakeService) GetDescendantCountsLegacy(ctx context.Context, q *folder.G
|
||||
func (s *FakeService) GetFolders(ctx context.Context, q folder.GetFoldersQuery) ([]*folder.Folder, error) {
|
||||
return s.ExpectedFolders, s.ExpectedError
|
||||
}
|
||||
|
||||
func (s *FakeService) SearchFolders(ctx context.Context, q folder.SearchFoldersQuery) (model.HitList, error) {
|
||||
return s.ExpectedHitList, s.ExpectedError
|
||||
}
|
||||
|
||||
func (s *FakeService) GetFoldersLegacy(ctx context.Context, q folder.GetFoldersQuery) ([]*folder.Folder, error) {
|
||||
return s.ExpectedFolders, s.ExpectedError
|
||||
}
|
||||
|
@ -179,6 +179,15 @@ type GetFoldersQuery struct {
|
||||
SignedInUser identity.Requester `json:"-"`
|
||||
}
|
||||
|
||||
type SearchFoldersQuery struct {
|
||||
OrgID int64
|
||||
UIDs []string
|
||||
IDs []int64
|
||||
Title string
|
||||
Limit int64
|
||||
SignedInUser identity.Requester `json:"-"`
|
||||
}
|
||||
|
||||
// GetParentsQuery captures the information required by the folder service to
|
||||
// return a list of all parent folders of a given folder.
|
||||
type GetParentsQuery struct {
|
||||
|
@ -2,6 +2,8 @@ package folder
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/search/model"
|
||||
)
|
||||
|
||||
type Service interface {
|
||||
@ -40,6 +42,9 @@ type Service interface {
|
||||
GetFolders(ctx context.Context, q GetFoldersQuery) ([]*Folder, error)
|
||||
GetFoldersLegacy(ctx context.Context, q GetFoldersQuery) ([]*Folder, error)
|
||||
|
||||
// SearchFolders returns a list of folders that match the query.
|
||||
SearchFolders(ctx context.Context, q SearchFoldersQuery) (model.HitList, error)
|
||||
|
||||
// GetChildren returns an array containing all child folders.
|
||||
GetChildren(ctx context.Context, q *GetChildrenQuery) ([]*Folder, error)
|
||||
GetChildrenLegacy(ctx context.Context, q *GetChildrenQuery) ([]*Folder, error)
|
||||
|
@ -8,7 +8,10 @@ import (
|
||||
"github.com/grafana/grafana/pkg/infra/metrics"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/search/model"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore/searchstore"
|
||||
"github.com/grafana/grafana/pkg/services/star"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
@ -17,7 +20,7 @@ import (
|
||||
|
||||
var tracer = otel.Tracer("github.com/grafana/grafana/pkg/services/search")
|
||||
|
||||
func ProvideService(cfg *setting.Cfg, sqlstore db.DB, starService star.Service, dashboardService dashboards.DashboardService) *SearchService {
|
||||
func ProvideService(cfg *setting.Cfg, sqlstore db.DB, starService star.Service, dashboardService dashboards.DashboardService, folderService folder.Service, features featuremgmt.FeatureToggles) *SearchService {
|
||||
s := &SearchService{
|
||||
Cfg: cfg,
|
||||
sortOptions: map[string]model.SortOption{
|
||||
@ -26,6 +29,8 @@ func ProvideService(cfg *setting.Cfg, sqlstore db.DB, starService star.Service,
|
||||
},
|
||||
sqlstore: sqlstore,
|
||||
starService: starService,
|
||||
folderService: folderService,
|
||||
features: features,
|
||||
dashboardService: dashboardService,
|
||||
}
|
||||
return s
|
||||
@ -61,6 +66,8 @@ type SearchService struct {
|
||||
sqlstore db.DB
|
||||
starService star.Service
|
||||
dashboardService dashboards.DashboardService
|
||||
folderService folder.Service
|
||||
features featuremgmt.FeatureToggles
|
||||
}
|
||||
|
||||
func (s *SearchService) SearchHandler(ctx context.Context, query *Query) (model.HitList, error) {
|
||||
@ -107,6 +114,20 @@ func (s *SearchService) SearchHandler(ctx context.Context, query *Query) (model.
|
||||
dashboardQuery.Sort = sortOpt
|
||||
}
|
||||
|
||||
// if folders are stored in unified storage, we need to use the folder service to query for folders
|
||||
if s.features.IsEnabledGlobally(featuremgmt.FlagKubernetesFoldersServiceV2) && (query.Type == searchstore.TypeFolder || query.Type == searchstore.TypeAlertFolder) {
|
||||
hits, err := s.folderService.SearchFolders(ctx, folder.SearchFoldersQuery{
|
||||
OrgID: query.OrgId,
|
||||
UIDs: query.FolderUIDs,
|
||||
IDs: query.FolderIds,
|
||||
Title: query.Title,
|
||||
Limit: query.Limit,
|
||||
SignedInUser: query.SignedInUser,
|
||||
})
|
||||
|
||||
return sortedHits(hits), err
|
||||
}
|
||||
|
||||
hits, err := s.dashboardService.SearchDashboards(ctx, &dashboardQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/db/dbtest"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/search/model"
|
||||
"github.com/grafana/grafana/pkg/services/star"
|
||||
"github.com/grafana/grafana/pkg/services/star/startest"
|
||||
@ -35,6 +36,7 @@ func TestSearch_SortedResults(t *testing.T) {
|
||||
sqlstore: db,
|
||||
starService: ss,
|
||||
dashboardService: ds,
|
||||
features: &featuremgmt.FeatureManager{},
|
||||
}
|
||||
|
||||
query := &Query{
|
||||
@ -76,6 +78,7 @@ func TestSearch_StarredResults(t *testing.T) {
|
||||
sqlstore: db,
|
||||
starService: ss,
|
||||
dashboardService: ds,
|
||||
features: &featuremgmt.FeatureManager{},
|
||||
}
|
||||
|
||||
query := &Query{
|
||||
|
Loading…
Reference in New Issue
Block a user