[search] - filter by starred (#98651)

[search] - filter by starred
This commit is contained in:
Scott Lepper
2025-01-09 16:45:04 -05:00
committed by GitHub
parent 1e9f5367af
commit 07d3bdbe72
16 changed files with 58 additions and 31 deletions

View File

@ -303,6 +303,20 @@ func (s *SearchHandler) DoSearch(w http.ResponseWriter, r *http.Request) {
}}
}
// The names filter
names, ok := queryParams["name"]
if ok {
if searchRequest.Options.Fields == nil {
searchRequest.Options.Fields = []*resource.Requirement{}
}
namesFilter := []*resource.Requirement{{
Key: "name",
Operator: "in",
Values: names,
}}
searchRequest.Options.Fields = append(searchRequest.Options.Fields, namesFilter...)
}
// Run the query
result, err := s.client.Search(ctx, searchRequest)
if err != nil {

View File

@ -53,8 +53,8 @@ type IndexableDocument struct {
// The resource key
Key *ResourceKey `json:"key"`
// The resource type ( for federated indexes )
Kind string `json:"kind,omitempty"`
// The k8s name
Name string `json:"name,omitempty"`
// Resource version for the resource (if known)
RV int64 `json:"rv,omitempty"`
@ -164,8 +164,8 @@ func NewIndexableDocument(key *ResourceKey, rv int64, obj utils.GrafanaMetaAcces
}
doc := &IndexableDocument{
Key: key,
Kind: key.Resource,
RV: rv,
Name: key.Name,
Title: title, // We always want *something* to display
TitleSort: strings.ToLower(title), // Lowercase for case-insensitive sorting
Labels: obj.GetLabels(),

View File

@ -33,13 +33,13 @@ func TestStandardDocumentBuilder(t *testing.T) {
"resource": "playlists",
"name": "test1"
},
"kind": "playlists",
"rv": 10,
"title": "test playlist unified storage",
"title_sort": "test playlist unified storage",
"created": 1717236672000,
"createdBy": "user:ABC",
"updatedBy": "user:XYZ",
"name": "test1",
"repository": {
"name": "SQL",
"path": "15",

View File

@ -487,6 +487,7 @@ func requirementQuery(req *resource.Requirement, prefix string) (query.Query, *r
if len(req.Values) == 0 {
return query.NewMatchAllQuery(), nil
}
if len(req.Values[0]) == 1 {
q := query.NewMatchQuery(req.Values[0])
q.FieldVal = prefix + req.Key

View File

@ -17,6 +17,13 @@ func getBleveMappings(fields resource.SearchableDocumentFields) mapping.IndexMap
func getBleveDocMappings(_ resource.SearchableDocumentFields) *mapping.DocumentMapping {
mapper := bleve.NewDocumentStaticMapping()
nameMapping := &mapping.FieldMapping{
Analyzer: keyword.Name,
Type: "text",
Index: true,
}
mapper.AddFieldMappingsAt(resource.SEARCH_FIELD_NAME, nameMapping)
// for sorting by title
titleSortMapping := bleve.NewKeywordFieldMapping()
mapper.AddFieldMappingsAt(resource.SEARCH_FIELD_TITLE_SORT, titleSortMapping)
@ -25,10 +32,6 @@ func getBleveDocMappings(_ resource.SearchableDocumentFields) *mapping.DocumentM
titleSearchMapping := bleve.NewTextFieldMapping()
mapper.AddFieldMappingsAt(resource.SEARCH_FIELD_TITLE, titleSearchMapping)
// for filtering by kind/resource ( federated search )
kindMapping := bleve.NewTextFieldMapping()
mapper.AddFieldMappingsAt(resource.SEARCH_FIELD_KIND, kindMapping)
descriptionMapping := &mapping.FieldMapping{
Name: resource.SEARCH_FIELD_DESCRIPTION,
Type: "text",
@ -76,8 +79,8 @@ func getBleveDocMappings(_ resource.SearchableDocumentFields) *mapping.DocumentM
}
mapper.AddFieldMappingsAt(resource.SEARCH_FIELD_REPOSITORY, repoMapping)
// TODO: we use the static mapper. why set dynamic to true?
mapper.Dynamic = true
labelMapper := bleve.NewDocumentMapping()
mapper.AddSubDocumentMapping(resource.SEARCH_FIELD_LABELS, labelMapper)
return mapper
}

View File

@ -42,5 +42,5 @@ func TestDocumentMapping(t *testing.T) {
fmt.Printf("DOC: fields %d\n", len(doc.Fields))
fmt.Printf("DOC: size %d\n", doc.Size())
require.Equal(t, 17, len(doc.Fields))
require.Equal(t, 12, len(doc.Fields))
}

View File

@ -62,7 +62,8 @@ func TestBleveBackend(t *testing.T) {
Resource: key.Resource,
}, 2, rv, info.Fields, func(index resource.ResourceIndex) (int64, error) {
_ = index.Write(&resource.IndexableDocument{
RV: 1,
RV: 1,
Name: "aaa",
Key: &resource.ResourceKey{
Name: "aaa",
Namespace: "ns",
@ -83,7 +84,8 @@ func TestBleveBackend(t *testing.T) {
Tags: []string{"aa", "bb"},
})
_ = index.Write(&resource.IndexableDocument{
RV: 2,
RV: 2,
Name: "bbb",
Key: &resource.ResourceKey{
Name: "bbb",
Namespace: "ns",
@ -112,6 +114,7 @@ func TestBleveBackend(t *testing.T) {
Group: "dashboard.grafana.app",
Resource: "dashboards",
},
Name: "ccc",
Title: "ccc (dash)",
TitleSort: "ccc (dash)",
Folder: "zzz",

View File

@ -5,7 +5,7 @@
"resource": "dashboards",
"name": "aaa"
},
"kind": "dashboards",
"name": "aaa",
"rv": 1234,
"title": "Test title",
"title_sort": "test title",

View File

@ -5,7 +5,7 @@
"resource": "dashboards",
"name": "aaa"
},
"kind": "dashboards",
"name": "aaa",
"rv": 1234,
"title": "test-aaa",
"title_sort": "test-aaa",

View File

@ -5,7 +5,7 @@
"resource": "dashboards",
"name": "bbb"
},
"kind": "dashboards",
"name": "bbb",
"rv": 1234,
"title": "test-bbb",
"title_sort": "test-bbb",

View File

@ -5,7 +5,7 @@
"resource": "dashboards",
"name": "aaa"
},
"kind": "dashboards",
"name": "aaa",
"rv": 1234,
"title": "Test AAA",
"title_sort": "test aaa",

View File

@ -5,7 +5,7 @@
"resource": "dashboards",
"name": "aaa"
},
"kind": "dashboards",
"name": "aaa",
"rv": 1234,
"title": "Test AAA",
"title_sort": "test aaa",

View File

@ -74,8 +74,8 @@
"aa"
],
"zzz",
3,
0,
null,
null,
null,
null,
null
@ -98,8 +98,8 @@
"aa"
],
"xxx",
2,
0,
null,
null,
null,
null,
null
@ -123,8 +123,8 @@
"bb"
],
"xxx",
1,
0,
null,
null,
null,
null,
null

View File

@ -51,8 +51,8 @@
"yyy (folder)",
null,
null,
2,
0
null,
null
],
"object": {
"kind": "folders",
@ -70,8 +70,8 @@
"zzz (folder)",
null,
null,
1,
0
null,
null
],
"object": {
"kind": "folders",

View File

@ -17,6 +17,7 @@ export interface SearchQuery {
tags?: string[];
kind?: string[];
panel_type?: string;
name?: string[];
uid?: string[];
facet?: FacetField[];
explain?: boolean;

View File

@ -72,10 +72,11 @@ export class UnifiedSearcher implements GrafanaSearcher {
throw new Error('facets not supported!');
}
// get the starred dashboards
const starsUIDS = await getBackendSrv().get('api/user/stars');
if (starsUIDS?.length) {
const starsIds = await getBackendSrv().get('api/user/stars');
if (starsIds?.length) {
return this.doSearchQuery({
uid: starsUIDS,
...query,
name: starsIds,
query: query.query ?? '*',
});
}
@ -223,6 +224,10 @@ export class UnifiedSearcher implements GrafanaSearcher {
const sort = query.sort.replace('_sort', '').replace('name', 'title');
uri += `&sort=${sort}`;
}
if (query.name?.length) {
uri += '&' + query.name.map((name) => `name=${encodeURIComponent(name)}`).join('&');
}
return uri;
}