Search: Fix empty folder details for nested folder items (#76504)

* Introduce dashboard.folder_uid column

* Add data migration

* Search: Fix empty folder details for nested folders

* Set `dashboard.folder_uid` and update tests

* Add unique index

* lint

Ignore cyclomatic complexity of func
`(*DashboardServiceImpl).BuildSaveDashboardCommand

* Fix search by folder UID
This commit is contained in:
Sofia Papagiannaki
2023-10-24 10:04:45 +03:00
committed by GitHub
parent 442e533803
commit 03a626f1d6
28 changed files with 706 additions and 236 deletions

View File

@@ -1,6 +1,7 @@
package migrations
import (
dashboardFolderMigrations "github.com/grafana/grafana/pkg/services/dashboards/database/migrations"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/sqlstore/migrations/accesscontrol"
"github.com/grafana/grafana/pkg/services/sqlstore/migrations/anonservice"
@@ -103,6 +104,8 @@ func (*OSSMigrations) AddMigration(mg *Migrator) {
ualert.MigrationServiceMigration(mg)
ualert.CreatedFoldersMigration(mg)
dashboardFolderMigrations.AddDashboardFolderMigrations(mg)
}
func addStarMigrations(mg *Migrator) {

View File

@@ -815,8 +815,9 @@ func setupNestedTest(t *testing.T, usr *user.SignedInUser, perms []accesscontrol
// create dashboard under parent folder
_, err = dashStore.SaveDashboard(context.Background(), dashboards.SaveDashboardCommand{
OrgID: orgID,
FolderID: parent.ID,
OrgID: orgID,
FolderID: parent.ID,
FolderUID: parent.UID,
Dashboard: simplejson.NewFromAny(map[string]any{
"title": "dashboard under parent folder",
}),
@@ -825,8 +826,9 @@ func setupNestedTest(t *testing.T, usr *user.SignedInUser, perms []accesscontrol
// create dashboard under subfolder
_, err = dashStore.SaveDashboard(context.Background(), dashboards.SaveDashboardCommand{
OrgID: orgID,
FolderID: subfolder.ID,
OrgID: orgID,
FolderID: subfolder.ID,
FolderUID: subfolder.UID,
Dashboard: simplejson.NewFromAny(map[string]any{
"title": "dashboard under subfolder",
}),

View File

@@ -5,6 +5,7 @@ import (
"fmt"
"strings"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/search/model"
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
)
@@ -14,8 +15,9 @@ import (
type Builder struct {
// List of FilterWhere/FilterGroupBy/FilterOrderBy/FilterLeftJoin
// to modify the query.
Filters []any
Dialect migrator.Dialect
Filters []any
Dialect migrator.Dialect
Features featuremgmt.FeatureToggles
params []any
sql bytes.Buffer
@@ -35,9 +37,15 @@ func (b *Builder) ToSQL(limit, page int64) (string, []any) {
INNER JOIN dashboard ON ids.id = dashboard.id`)
b.sql.WriteString("\n")
b.sql.WriteString(
`LEFT OUTER JOIN dashboard AS folder ON folder.id = dashboard.folder_id
LEFT OUTER JOIN dashboard_tag ON dashboard.id = dashboard_tag.dashboard_id`)
if b.Features.IsEnabled(featuremgmt.FlagNestedFolders) {
b.sql.WriteString(
`LEFT OUTER JOIN folder ON folder.uid = dashboard.folder_uid AND folder.org_id = dashboard.org_id`)
} else {
b.sql.WriteString(`
LEFT OUTER JOIN dashboard AS folder ON folder.id = dashboard.folder_id`)
}
b.sql.WriteString(`
LEFT OUTER JOIN dashboard_tag ON dashboard.id = dashboard_tag.dashboard_id`)
b.sql.WriteString("\n")
b.sql.WriteString(orderQuery)
@@ -58,7 +66,15 @@ func (b *Builder) buildSelect() {
dashboard.is_folder,
dashboard.folder_id,
folder.uid AS folder_uid,
folder.slug AS folder_slug,
`)
if b.Features.IsEnabled(featuremgmt.FlagNestedFolders) {
b.sql.WriteString(`
folder.title AS folder_slug,`)
} else {
b.sql.WriteString(`
folder.slug AS folder_slug,`)
}
b.sql.WriteString(`
folder.title AS folder_title `)
for _, f := range b.Filters {

View File

@@ -58,9 +58,10 @@ func (f FolderFilter) Where() (string, []any) {
}
type FolderUIDFilter struct {
Dialect migrator.Dialect
OrgID int64
UIDs []string
Dialect migrator.Dialect
OrgID int64
UIDs []string
NestedFoldersEnabled bool
}
func (f FolderUIDFilter) Where() (string, []any) {
@@ -84,10 +85,16 @@ func (f FolderUIDFilter) Where() (string, []any) {
// do nothing
case len(params) == 1:
q = "dashboard.folder_id IN (SELECT id FROM dashboard WHERE org_id = ? AND uid = ?)"
if f.NestedFoldersEnabled {
q = "dashboard.org_id = ? AND dashboard.folder_uid = ?"
}
params = append([]any{f.OrgID}, params...)
default:
sqlArray := "(?" + strings.Repeat(",?", len(params)-1) + ")"
q = "dashboard.folder_id IN (SELECT id FROM dashboard WHERE org_id = ? AND uid IN " + sqlArray + ")"
if f.NestedFoldersEnabled {
q = "dashboard.org_id = ? AND dashboard.folder_uid IN " + sqlArray
}
params = append([]any{f.OrgID}, params...)
}

View File

@@ -46,7 +46,8 @@ func TestBuilder_EqualResults_Basic(t *testing.T) {
searchstore.OrgFilter{OrgId: user.OrgID},
searchstore.TitleSorter{},
},
Dialect: store.GetDialect(),
Dialect: store.GetDialect(),
Features: featuremgmt.WithFeatures(),
}
res := []dashboards.DashboardSearchProjection{}
@@ -83,7 +84,8 @@ func TestBuilder_Pagination(t *testing.T) {
searchstore.OrgFilter{OrgId: user.OrgID},
searchstore.TitleSorter{},
},
Dialect: store.GetDialect(),
Dialect: store.GetDialect(),
Features: featuremgmt.WithFeatures(),
}
resPg1 := []dashboards.DashboardSearchProjection{}
@@ -243,7 +245,8 @@ func TestBuilder_RBAC(t *testing.T) {
recursiveQueriesAreSupported,
),
},
Dialect: store.GetDialect(),
Dialect: store.GetDialect(),
Features: features,
}
res := []dashboards.DashboardSearchProjection{}