Dashboards: Fix FindDashboards when kubernetesClientDashboardsFolders is disabled (#105974)

Dashboards: fix legacy FindDashboards
This commit is contained in:
Stephanie Hingtgen
2025-05-24 07:06:30 -06:00
committed by GitHub
parent a8fd34cec4
commit 5c0194955e
5 changed files with 95 additions and 113 deletions
@@ -304,9 +304,7 @@ func (c *DashboardSearchClient) Search(ctx context.Context, req *resourcepb.Reso
return nil, err
}
hits := formatQueryResult(res)
for _, dashboard := range hits {
for _, dashboard := range res {
tags, err := json.Marshal(dashboard.Tags)
if err != nil {
return nil, err
@@ -324,7 +322,7 @@ func (c *DashboardSearchClient) Search(ctx context.Context, req *resourcepb.Reso
}
list.Results.Rows = append(list.Results.Rows, &resourcepb.ResourceTableRow{
Key: getResourceKey(dashboard, req.Options.Key.Namespace),
Key: getResourceKey(&dashboard, req.Options.Key.Namespace),
Cells: cells,
})
}
@@ -352,35 +350,6 @@ func getResourceKey(item *dashboards.DashboardSearchProjection, namespace string
}
}
func formatQueryResult(res []dashboards.DashboardSearchProjection) []*dashboards.DashboardSearchProjection {
hitList := make([]*dashboards.DashboardSearchProjection, 0)
hits := make(map[string]*dashboards.DashboardSearchProjection)
for _, item := range res {
key := fmt.Sprintf("%s-%d", item.UID, item.OrgID)
hit, exists := hits[key]
if !exists {
hit = &dashboards.DashboardSearchProjection{
ID: item.ID,
UID: item.UID,
Title: item.Title,
FolderUID: item.FolderUID,
Tags: []string{},
IsFolder: item.IsFolder,
SortMeta: item.SortMeta,
}
hitList = append(hitList, hit)
hits[key] = hit
}
if len(item.Term) > 0 {
hit.Tags = append(hit.Tags, item.Term)
}
}
return hitList
}
func (c *DashboardSearchClient) GetStats(ctx context.Context, req *resourcepb.ResourceStatsRequest, _ ...grpc.CallOption) (*resourcepb.ResourceStatsResponse, error) {
info, err := claims.ParseNamespace(req.Namespace)
if err != nil {
@@ -44,8 +44,8 @@ func TestDashboardSearchClient_Search(t *testing.T) {
Type: "dash-db", // should set type based off of key
Sort: sorter,
}).Return([]dashboards.DashboardSearchProjection{
{ID: 1, UID: "uid", Title: "Test Dashboard", FolderUID: "folder1", Term: "term"},
{ID: 2, UID: "uid2", Title: "Test Dashboard2", FolderUID: "folder2"},
{ID: 1, UID: "uid", Title: "Test Dashboard", FolderUID: "folder1", Tags: []string{"term"}},
{ID: 2, UID: "uid2", Title: "Test Dashboard2", FolderUID: "folder2", Tags: []string{}},
}, nil).Once()
req := &resourcepb.ResourceSearchRequest{
@@ -121,7 +121,7 @@ func TestDashboardSearchClient_Search(t *testing.T) {
Type: "dash-db",
Sort: sortOptionAsc,
}).Return([]dashboards.DashboardSearchProjection{
{ID: 1, UID: "uid", Title: "Test Dashboard", FolderUID: "folder", SortMeta: int64(50)},
{ID: 1, UID: "uid", Title: "Test Dashboard", FolderUID: "folder", SortMeta: int64(50), Tags: []string{}},
}, nil).Once()
req := &resourcepb.ResourceSearchRequest{
@@ -186,7 +186,7 @@ func TestDashboardSearchClient_Search(t *testing.T) {
Type: "dash-db",
Sort: sortOptionAsc,
}).Return([]dashboards.DashboardSearchProjection{
{ID: 1, UID: "uid", Title: "Test Dashboard", FolderUID: "folder", SortMeta: int64(2)},
{ID: 1, UID: "uid", Title: "Test Dashboard", FolderUID: "folder", SortMeta: int64(2), Tags: []string{}},
}, nil).Once()
req := &resourcepb.ResourceSearchRequest{
+33 -1
View File
@@ -922,7 +922,39 @@ func (d *dashboardStore) FindDashboards(ctx context.Context, query *dashboards.F
return nil, err
}
return res, nil
if len(res) <= 1 {
return res, nil
}
// the search query above will return one row per dashboard tag, and dashboards
// can have multiple tags. we only want to return one row per dashboard, so dedup
// the results by id.
// note: we must preserve the order of the results as we dedup, as the query can be sorted
seen := make(map[int64]int)
uniqueRes := make([]dashboards.DashboardSearchProjection, 0, len(res))
for _, item := range res {
if idx, exists := seen[item.ID]; exists {
if item.Term != "" {
if uniqueRes[idx].Tags == nil {
uniqueRes[idx].Tags = make([]string, 0)
}
uniqueRes[idx].Tags = append(uniqueRes[idx].Tags, item.Term)
}
continue
}
if item.Tags == nil {
item.Tags = make([]string, 0)
}
if item.Term != "" {
item.Tags = append(item.Tags, item.Term)
}
seen[item.ID] = len(uniqueRes)
uniqueRes = append(uniqueRes, item)
}
return uniqueRes, nil
}
func (d *dashboardStore) GetDashboardTags(ctx context.Context, query *dashboards.GetDashboardTagsQuery) ([]*dashboards.DashboardTagCloudItem, error) {
@@ -841,7 +841,7 @@ func TestIntegrationFindDashboardsByTitle(t *testing.T) {
require.NoError(t, err)
orgID := int64(1)
insertTestDashboard(t, dashboardStore, "dashboard under general", orgID, 0, "", false)
insertTestDashboard(t, dashboardStore, "dashboard under general", orgID, 0, "", false, []string{"tag1", "tag2"})
ac := acimpl.ProvideAccessControl(features)
folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore)
@@ -869,7 +869,7 @@ func TestIntegrationFindDashboardsByTitle(t *testing.T) {
})
require.NoError(t, err)
insertTestDashboard(t, dashboardStore, "dashboard under f0", orgID, 0, f0.UID, false)
insertTestDashboard(t, dashboardStore, "dashboard under f0", orgID, 0, f0.UID, false, []string{"tag3"})
subfolder, err := folderServiceWithFlagOn.Create(context.Background(), &folder.CreateFolderCommand{
OrgID: orgID,
@@ -1244,43 +1244,35 @@ func testSearchDashboards(d dashboards.Store, query *dashboards.FindPersistedDas
func makeQueryResult(query *dashboards.FindPersistedDashboardsQuery, res []dashboards.DashboardSearchProjection) model.HitList {
hitList := make([]*model.Hit, 0)
hits := make(map[int64]*model.Hit)
for _, item := range res {
hit, exists := hits[item.ID]
if !exists {
hitType := model.DashHitDB
if item.IsFolder {
hitType = model.DashHitFolder
}
hit = &model.Hit{
ID: item.ID,
UID: item.UID,
Title: item.Title,
URI: "db/" + item.Slug,
URL: dashboards.GetDashboardFolderURL(item.IsFolder, item.UID, item.Slug),
Type: hitType,
FolderUID: item.FolderUID,
FolderTitle: item.FolderTitle,
Tags: []string{},
}
if item.FolderUID != "" {
hit.FolderURL = dashboards.GetFolderURL(item.FolderUID, item.FolderSlug)
}
if query.Sort.MetaName != "" {
hit.SortMeta = item.SortMeta
hit.SortMetaName = query.Sort.MetaName
}
hitList = append(hitList, hit)
hits[item.ID] = hit
hitType := model.DashHitDB
if item.IsFolder {
hitType = model.DashHitFolder
}
if len(item.Term) > 0 {
hit.Tags = append(hit.Tags, item.Term)
hit := &model.Hit{
ID: item.ID,
UID: item.UID,
Title: item.Title,
URI: "db/" + item.Slug,
URL: dashboards.GetDashboardFolderURL(item.IsFolder, item.UID, item.Slug),
Type: hitType,
FolderUID: item.FolderUID,
FolderTitle: item.FolderTitle,
Tags: item.Tags,
}
if item.FolderUID != "" {
hit.FolderURL = dashboards.GetFolderURL(item.FolderUID, item.FolderSlug)
}
if query.Sort.MetaName != "" {
hit.SortMeta = item.SortMeta
hit.SortMetaName = query.Sort.MetaName
}
hitList = append(hitList, hit)
}
return hitList
}
@@ -1650,55 +1650,44 @@ func getHitType(item dashboards.DashboardSearchProjection) model.HitType {
func makeQueryResult(query *dashboards.FindPersistedDashboardsQuery, res []dashboards.DashboardSearchProjection) model.HitList {
hitList := make([]*model.Hit, 0)
hits := make(map[string]*model.Hit)
for _, item := range res {
key := fmt.Sprintf("%s-%d", item.UID, item.OrgID)
hit, exists := hits[key]
if !exists {
metrics.MFolderIDsServiceCount.WithLabelValues(metrics.Dashboard).Inc()
hit = &model.Hit{
ID: item.ID,
UID: item.UID,
OrgID: item.OrgID,
Title: item.Title,
URI: "db/" + item.Slug,
URL: dashboards.GetDashboardFolderURL(item.IsFolder, item.UID, item.Slug),
Type: getHitType(item),
FolderID: item.FolderID, // nolint:staticcheck
FolderUID: item.FolderUID,
FolderTitle: item.FolderTitle,
Tags: []string{},
}
// when searching through unified storage, the dashboard will come as one
// item, when searching through legacy, the dashboard will come multiple times
// per tag. So we need to add the array here for unified, and the term below for legacy.
if item.Tags != nil {
hit.Tags = item.Tags
}
// nolint:staticcheck
if item.FolderID > 0 || item.FolderUID != "" {
hit.FolderURL = dashboards.GetFolderURL(item.FolderUID, item.FolderSlug)
}
if query.Sort.MetaName != "" {
hit.SortMeta = item.SortMeta
hit.SortMetaName = query.Sort.MetaName
}
hitList = append(hitList, hit)
hits[key] = hit
metrics.MFolderIDsServiceCount.WithLabelValues(metrics.Dashboard).Inc()
hit := &model.Hit{
ID: item.ID,
UID: item.UID,
OrgID: item.OrgID,
Title: item.Title,
URI: "db/" + item.Slug,
URL: dashboards.GetDashboardFolderURL(item.IsFolder, item.UID, item.Slug),
Type: getHitType(item),
FolderID: item.FolderID, // nolint:staticcheck
FolderUID: item.FolderUID,
FolderTitle: item.FolderTitle,
Tags: []string{},
}
if len(item.Term) > 0 {
hit.Tags = append(hit.Tags, item.Term)
if item.Tags != nil {
hit.Tags = item.Tags
}
// nolint:staticcheck
if item.FolderID > 0 || item.FolderUID != "" {
hit.FolderURL = dashboards.GetFolderURL(item.FolderUID, item.FolderSlug)
}
if query.Sort.MetaName != "" {
hit.SortMeta = item.SortMeta
hit.SortMetaName = query.Sort.MetaName
}
if item.Deleted != nil {
deletedDate := (*item.Deleted).Add(daysInTrash)
hit.IsDeleted = true
hit.PermanentlyDeleteDate = &deletedDate
}
hitList = append(hitList, hit)
}
return hitList
}