diff --git a/apps/dashboard/pkg/apis/dashboard/v0alpha1/search.go b/apps/dashboard/pkg/apis/dashboard/v0alpha1/search.go index ea0084efe2a..dffca7bc430 100644 --- a/apps/dashboard/pkg/apis/dashboard/v0alpha1/search.go +++ b/apps/dashboard/pkg/apis/dashboard/v0alpha1/search.go @@ -4,6 +4,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1" + "github.com/grafana/grafana/pkg/apimachinery/utils" ) // +k8s:deepcopy-gen=true @@ -69,6 +70,8 @@ type DashboardHit struct { Tags []string `json:"tags,omitempty"` // The k8s name (eg, grafana UID) for the parent folder Folder string `json:"folder,omitempty"` + // The resource is managed + ManagedBy ManagedBy `json:"managedBy,omitzero,omitempty"` // Stick untyped extra fields in this object (including the sort value) Field *common.Unstructured `json:"field,omitzero,omitempty"` // When using "real" search, this is the score @@ -77,6 +80,15 @@ type DashboardHit struct { Explain *common.Unstructured `json:"explain,omitzero,omitempty"` } +type ManagedBy struct { + Kind utils.ManagerKind `json:"kind"` + ID string `json:"id,omitempty"` +} + +func (m ManagedBy) IsZero() bool { + return m.Kind == "" && m.ID == "" +} + // +k8s:deepcopy-gen=true type FacetResult struct { Field string `json:"field,omitempty"` diff --git a/apps/dashboard/pkg/apis/dashboard/v0alpha1/zz_generated.deepcopy.go b/apps/dashboard/pkg/apis/dashboard/v0alpha1/zz_generated.deepcopy.go index 99a44dde4e3..efdbdf07999 100644 --- a/apps/dashboard/pkg/apis/dashboard/v0alpha1/zz_generated.deepcopy.go +++ b/apps/dashboard/pkg/apis/dashboard/v0alpha1/zz_generated.deepcopy.go @@ -76,6 +76,7 @@ func (in *DashboardHit) DeepCopyInto(out *DashboardHit) { *out = make([]string, len(*in)) copy(*out, *in) } + out.ManagedBy = in.ManagedBy if in.Field != nil { in, out := &in.Field, &out.Field *out = (*in).DeepCopy() diff --git a/apps/dashboard/pkg/apis/dashboard/v0alpha1/zz_generated.openapi.go b/apps/dashboard/pkg/apis/dashboard/v0alpha1/zz_generated.openapi.go index a26bc80e5d4..0027a8b8cc4 100644 --- a/apps/dashboard/pkg/apis/dashboard/v0alpha1/zz_generated.openapi.go +++ b/apps/dashboard/pkg/apis/dashboard/v0alpha1/zz_generated.openapi.go @@ -35,6 +35,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1.LibraryPanelList": schema_pkg_apis_dashboard_v0alpha1_LibraryPanelList(ref), "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1.LibraryPanelSpec": schema_pkg_apis_dashboard_v0alpha1_LibraryPanelSpec(ref), "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1.LibraryPanelStatus": schema_pkg_apis_dashboard_v0alpha1_LibraryPanelStatus(ref), + "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1.ManagedBy": schema_pkg_apis_dashboard_v0alpha1_ManagedBy(ref), "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1.SearchResults": schema_pkg_apis_dashboard_v0alpha1_SearchResults(ref), "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1.SortBy": schema_pkg_apis_dashboard_v0alpha1_SortBy(ref), "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1.SortableField": schema_pkg_apis_dashboard_v0alpha1_SortableField(ref), @@ -337,6 +338,13 @@ func schema_pkg_apis_dashboard_v0alpha1_DashboardHit(ref common.ReferenceCallbac Format: "", }, }, + "managedBy": { + SchemaProps: spec.SchemaProps{ + Description: "The resource is managed", + Default: map[string]interface{}{}, + Ref: ref("github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1.ManagedBy"), + }, + }, "field": { SchemaProps: spec.SchemaProps{ Description: "Stick untyped extra fields in this object (including the sort value)", @@ -361,7 +369,7 @@ func schema_pkg_apis_dashboard_v0alpha1_DashboardHit(ref common.ReferenceCallbac }, }, Dependencies: []string{ - "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1.Unstructured"}, + "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1.ManagedBy", "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1.Unstructured"}, } } @@ -1027,6 +1035,32 @@ func schema_pkg_apis_dashboard_v0alpha1_LibraryPanelStatus(ref common.ReferenceC } } +func schema_pkg_apis_dashboard_v0alpha1_ManagedBy(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "id": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"kind"}, + }, + }, + } +} + func schema_pkg_apis_dashboard_v0alpha1_SearchResults(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ diff --git a/pkg/registry/apis/dashboard/register.go b/pkg/registry/apis/dashboard/register.go index 1f295b29d21..21ce04ec92d 100644 --- a/pkg/registry/apis/dashboard/register.go +++ b/pkg/registry/apis/dashboard/register.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "maps" + "strings" "github.com/prometheus/client_golang/prometheus" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -640,6 +641,57 @@ func (b *DashboardsAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefiniti func (b *DashboardsAPIBuilder) PostProcessOpenAPI(oas *spec3.OpenAPI) (*spec3.OpenAPI, error) { oas.Info.Description = "Grafana dashboards as resources" + + // Add dashboard hits manually + if oas.Info.Title == "dashboard.grafana.app/v0alpha1" { + defs := b.GetOpenAPIDefinitions()(func(path string) spec.Ref { return spec.Ref{} }) + defsBase := "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1." + refsBase := "com.github.grafana.grafana.apps.dashboard.pkg.apis.dashboard.v0alpha1." + + kinds := []string{"SearchResults", "DashboardHit", "ManagedBy", "FacetResult", "TermFacet", "SortBy"} + + // Add any missing definitions + //----------------------------- + for _, k := range kinds { + v := defs[defsBase+k] + clean := strings.Replace(k, defsBase, refsBase, 1) + if oas.Components.Schemas[clean] == nil { + switch k { + case "SearchResults": + v.Schema.Properties["sortBy"] = *spec.RefProperty( + "#/components/schemas/SortBy") + v.Schema.Properties["hits"] = *spec.ArrayProperty( + spec.RefProperty("#/components/schemas/DashboardHit"), + ) + v.Schema.Properties["facets"] = *spec.MapProperty( + spec.RefProperty("#/components/schemas/FacetResult"), + ) + case "DashboardHit": + v.Schema.Properties["managedBy"] = *spec.RefProperty( + "#/components/schemas/ManagedBy") + case "FacetResult": + v.Schema.Properties["terms"] = *spec.ArrayProperty( + spec.RefProperty("#/components/schemas/TermFacet"), + ) + } + oas.Components.Schemas[clean] = &v.Schema + } + } + + p := oas.Paths.Paths["/apis/dashboard.grafana.app/v0alpha1/namespaces/{namespace}/search"] + p.Get.Responses.StatusCodeResponses[200] = &spec3.Response{ + ResponseProps: spec3.ResponseProps{ + Content: map[string]*spec3.MediaType{ + "application/json": { + MediaTypeProps: spec3.MediaTypeProps{ + Schema: spec.RefSchema("#/components/schemas/SearchResults"), + }, + }, + }, + }, + } + } + return oas, nil } diff --git a/pkg/registry/apis/dashboard/search.go b/pkg/registry/apis/dashboard/search.go index 6747f8ed69b..e209a3c8786 100644 --- a/pkg/registry/apis/dashboard/search.go +++ b/pkg/registry/apis/dashboard/search.go @@ -291,7 +291,7 @@ func (s *SearchHandler) DoSearch(w http.ResponseWriter, r *http.Request) { Page: int64(page), // for modes 0-2 (legacy) Explain: queryParams.Has("explain") && queryParams.Get("explain") != "false", } - fields := []string{"title", "folder", "tags", "description"} + fields := []string{"title", "folder", "tags", "description", "manager.kind", "manager.id"} if queryParams.Has("field") { // add fields to search and exclude duplicates for _, f := range queryParams["field"] { diff --git a/pkg/registry/apis/dashboard/search_test.go b/pkg/registry/apis/dashboard/search_test.go index 0fd42970135..4224d5927b3 100644 --- a/pkg/registry/apis/dashboard/search_test.go +++ b/pkg/registry/apis/dashboard/search_test.go @@ -213,7 +213,7 @@ func TestSearchHandler(t *testing.T) { if mockClient.LastSearchRequest == nil { t.Fatalf("expected Search to be called, but it was not") } - expectedFields := []string{"title", "folder", "tags", "description", "field1", "field2", "field3"} + expectedFields := []string{"title", "folder", "tags", "description", "manager.kind", "manager.id", "field1", "field2", "field3"} if fmt.Sprintf("%v", mockClient.LastSearchRequest.Fields) != fmt.Sprintf("%v", expectedFields) { t.Errorf("expected fields %v, got %v", expectedFields, mockClient.LastSearchRequest.Fields) } @@ -242,7 +242,7 @@ func TestSearchHandler(t *testing.T) { if mockClient.LastSearchRequest == nil { t.Fatalf("expected Search to be called, but it was not") } - expectedFields := []string{"title", "folder", "tags", "description", "field1"} + expectedFields := []string{"title", "folder", "tags", "description", "manager.kind", "manager.id", "field1"} if fmt.Sprintf("%v", mockClient.LastSearchRequest.Fields) != fmt.Sprintf("%v", expectedFields) { t.Errorf("expected fields %v, got %v", expectedFields, mockClient.LastSearchRequest.Fields) } @@ -271,7 +271,7 @@ func TestSearchHandler(t *testing.T) { if mockClient.LastSearchRequest == nil { t.Fatalf("expected Search to be called, but it was not") } - expectedFields := []string{"title", "folder", "tags", "description"} + expectedFields := []string{"title", "folder", "tags", "description", "manager.kind", "manager.id"} if fmt.Sprintf("%v", mockClient.LastSearchRequest.Fields) != fmt.Sprintf("%v", expectedFields) { t.Errorf("expected fields %v, got %v", expectedFields, mockClient.LastSearchRequest.Fields) } diff --git a/pkg/services/dashboards/service/dashboard_service.go b/pkg/services/dashboards/service/dashboard_service.go index ad83e1d8338..b9962afd285 100644 --- a/pkg/services/dashboards/service/dashboard_service.go +++ b/pkg/services/dashboards/service/dashboard_service.go @@ -2043,13 +2043,13 @@ func (dr *DashboardServiceImpl) searchProvisionedDashboardsThroughK8s(ctx contex dashs := make([]*dashboardProvisioningWithUID, 0) for _, hit := range searchResults.Hits { - if utils.ParseManagerKindString(hit.Field.GetNestedString(resource.SEARCH_FIELD_MANAGER_KIND)) != utils.ManagerKindClassicFP { // nolint:staticcheck + if utils.ParseManagerKindString(string(hit.ManagedBy.Kind)) != utils.ManagerKindClassicFP { // nolint:staticcheck continue } provisioning := &dashboardProvisioningWithUID{ DashboardProvisioning: dashboards.DashboardProvisioning{ - Name: hit.Field.GetNestedString(resource.SEARCH_FIELD_MANAGER_ID), + Name: hit.ManagedBy.ID, ExternalID: hit.Field.GetNestedString(resource.SEARCH_FIELD_SOURCE_PATH), CheckSum: hit.Field.GetNestedString(resource.SEARCH_FIELD_SOURCE_CHECKSUM), Updated: hit.Field.GetNestedInt64(resource.SEARCH_FIELD_SOURCE_TIME), diff --git a/pkg/services/dashboards/service/search/search.go b/pkg/services/dashboards/service/search/search.go index 93fdf30689a..79e61eab99a 100644 --- a/pkg/services/dashboards/service/search/search.go +++ b/pkg/services/dashboards/service/search/search.go @@ -5,21 +5,24 @@ import ( "encoding/json" "fmt" - common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1" - "github.com/grafana/grafana/pkg/storage/unified/resourcepb" - "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1" + common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1" + "github.com/grafana/grafana/pkg/apimachinery/utils" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) var ( - excludedFields = map[string]string{ - resource.SEARCH_FIELD_EXPLAIN: "", - resource.SEARCH_FIELD_SCORE: "", - resource.SEARCH_FIELD_TITLE: "", - resource.SEARCH_FIELD_FOLDER: "", - resource.SEARCH_FIELD_TAGS: "", - resource.SEARCH_FIELD_DESCRIPTION: "", + // These fields exist at the top-level of DashboardHit + standardFields = map[string]string{ + resource.SEARCH_FIELD_EXPLAIN: "", + resource.SEARCH_FIELD_SCORE: "", + resource.SEARCH_FIELD_TITLE: "", + resource.SEARCH_FIELD_FOLDER: "", + resource.SEARCH_FIELD_TAGS: "", + resource.SEARCH_FIELD_DESCRIPTION: "", + resource.SEARCH_FIELD_MANAGER_ID: "", + resource.SEARCH_FIELD_MANAGER_KIND: "", } IncludeFields = []string{ @@ -56,6 +59,8 @@ func ParseResults(result *resourcepb.ResourceSearchResponse, offset int64) (v0al descriptionIDX := -1 scoreIDX := -1 explainIDX := -1 + managerKindIDX := -1 + managerIdIDX := -1 for i, v := range result.Results.Columns { switch v.Name { @@ -69,6 +74,10 @@ func ParseResults(result *resourcepb.ResourceSearchResponse, offset int64) (v0al folderIDX = i case resource.SEARCH_FIELD_TAGS: tagsIDX = i + case resource.SEARCH_FIELD_MANAGER_ID: + managerIdIDX = i + case resource.SEARCH_FIELD_MANAGER_KIND: + managerKindIDX = i case resource.SEARCH_FIELD_DESCRIPTION: descriptionIDX = i } @@ -89,9 +98,10 @@ func ParseResults(result *resourcepb.ResourceSearchResponse, offset int64) (v0al return v0alpha1.SearchResults{}, fmt.Errorf("error parsing Search Response: mismatch number of columns and cells") } + // Dynamically defined fields fields := &common.Unstructured{} for colIndex, col := range result.Results.Columns { - if _, ok := excludedFields[col.Name]; !ok { + if _, ok := standardFields[col.Name]; !ok { val, err := resource.DecodeCell(col, colIndex, row.Cells[colIndex]) if err != nil { return v0alpha1.SearchResults{}, err @@ -122,6 +132,12 @@ func ParseResults(result *resourcepb.ResourceSearchResponse, offset int64) (v0al if descriptionIDX >= 0 && row.Cells[descriptionIDX] != nil { hit.Description = string(row.Cells[descriptionIDX]) } + if managerIdIDX >= 0 && row.Cells[managerIdIDX] != nil { + hit.ManagedBy.ID = string(row.Cells[managerIdIDX]) + } + if managerKindIDX >= 0 && row.Cells[managerKindIDX] != nil { + hit.ManagedBy.Kind = utils.ManagerKind(row.Cells[managerKindIDX]) + } if tagsIDX >= 0 && row.Cells[tagsIDX] != nil { _ = json.Unmarshal(row.Cells[tagsIDX], &hit.Tags) } diff --git a/pkg/services/folder/folderimpl/unifiedstore.go b/pkg/services/folder/folderimpl/unifiedstore.go index c3dd6347b11..0487af8aa40 100644 --- a/pkg/services/folder/folderimpl/unifiedstore.go +++ b/pkg/services/folder/folderimpl/unifiedstore.go @@ -276,12 +276,8 @@ func (ss *FolderUnifiedStoreImpl) GetChildren(ctx context.Context, q folder.GetC UID: item.Name, Title: item.Title, ParentUID: item.Folder, + ManagedBy: item.ManagedBy.Kind, } - - if item.Field.GetNestedString(resource.SEARCH_FIELD_MANAGER_KIND) != "" { - f.ManagedBy = utils.ParseManagerKindString(item.Field.GetNestedString(resource.SEARCH_FIELD_MANAGER_KIND)) - } - hits = append(hits, f) } diff --git a/pkg/tests/apis/openapi_snapshots/dashboard.grafana.app-v0alpha1.json b/pkg/tests/apis/openapi_snapshots/dashboard.grafana.app-v0alpha1.json index e8daf1b3a34..c9ba9823986 100644 --- a/pkg/tests/apis/openapi_snapshots/dashboard.grafana.app-v0alpha1.json +++ b/pkg/tests/apis/openapi_snapshots/dashboard.grafana.app-v0alpha1.json @@ -1856,59 +1856,7 @@ "content": { "application/json": { "schema": { - "type": "object", - "required": [ - "totalHits", - "hits" - ], - "properties": { - "apiVersion": { - "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - "type": "string" - }, - "facets": { - "description": "Facet results", - "type": "object", - "additionalProperties": { - "default": {} - } - }, - "hits": { - "description": "The dashboard body (unstructured for now)", - "type": "array", - "items": { - "default": {} - } - }, - "kind": { - "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - "type": "string" - }, - "maxScore": { - "description": "Max score", - "type": "number", - "format": "double" - }, - "offset": { - "description": "Where the query started from", - "type": "integer", - "format": "int64" - }, - "queryCost": { - "description": "Cost of running the query", - "type": "number", - "format": "double" - }, - "sortBy": { - "description": "How are the results sorted" - }, - "totalHits": { - "description": "The number of matching results", - "type": "integer", - "format": "int64", - "default": 0 - } - } + "$ref": "#/components/schemas/SearchResults" } } } @@ -1970,6 +1918,180 @@ }, "components": { "schemas": { + "DashboardHit": { + "type": "object", + "required": [ + "resource", + "name", + "title" + ], + "properties": { + "description": { + "description": "Dashboard description", + "type": "string" + }, + "explain": { + "description": "Explain the score (if possible)" + }, + "field": { + "description": "Stick untyped extra fields in this object (including the sort value)" + }, + "folder": { + "description": "The k8s name (eg, grafana UID) for the parent folder", + "type": "string" + }, + "managedBy": { + "$ref": "#/components/schemas/ManagedBy" + }, + "name": { + "description": "The k8s \"name\" (eg, grafana UID)", + "type": "string", + "default": "" + }, + "resource": { + "description": "Dashboard or folder", + "type": "string", + "default": "" + }, + "score": { + "description": "When using \"real\" search, this is the score", + "type": "number", + "format": "double" + }, + "tags": { + "description": "Filter tags", + "type": "array", + "items": { + "type": "string", + "default": "" + } + }, + "title": { + "description": "The display name", + "type": "string", + "default": "" + } + } + }, + "FacetResult": { + "type": "object", + "properties": { + "field": { + "type": "string" + }, + "missing": { + "description": "The number of documents that do *not* have this field", + "type": "integer", + "format": "int64" + }, + "terms": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TermFacet" + } + }, + "total": { + "description": "The distinct terms", + "type": "integer", + "format": "int64" + } + } + }, + "ManagedBy": { + "type": "object", + "required": [ + "kind" + ], + "properties": { + "id": { + "type": "string" + }, + "kind": { + "type": "string", + "default": "" + } + } + }, + "SearchResults": { + "type": "object", + "required": [ + "totalHits", + "hits" + ], + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + "type": "string" + }, + "facets": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/FacetResult" + } + }, + "hits": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DashboardHit" + } + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + "type": "string" + }, + "maxScore": { + "description": "Max score", + "type": "number", + "format": "double" + }, + "offset": { + "description": "Where the query started from", + "type": "integer", + "format": "int64" + }, + "queryCost": { + "description": "Cost of running the query", + "type": "number", + "format": "double" + }, + "sortBy": { + "$ref": "#/components/schemas/SortBy" + }, + "totalHits": { + "description": "The number of matching results", + "type": "integer", + "format": "int64", + "default": 0 + } + } + }, + "SortBy": { + "type": "object", + "required": [ + "field" + ], + "properties": { + "desc": { + "type": "boolean" + }, + "field": { + "type": "string", + "default": "" + } + } + }, + "TermFacet": { + "type": "object", + "properties": { + "count": { + "type": "integer", + "format": "int64" + }, + "term": { + "type": "string" + } + } + }, "com.github.grafana.grafana-plugin-sdk-go.experimental.apis.data.v0alpha1.DataQuery": { "description": "Generic query properties", "type": "object", diff --git a/public/app/api/clients/dashboard/v0alpha1/endpoints.gen.ts b/public/app/api/clients/dashboard/v0alpha1/endpoints.gen.ts index 1c5c6d627ac..5abfbe269e8 100644 --- a/public/app/api/clients/dashboard/v0alpha1/endpoints.gen.ts +++ b/public/app/api/clients/dashboard/v0alpha1/endpoints.gen.ts @@ -26,28 +26,7 @@ const injectedRtkApi = api overrideExisting: false, }); export { injectedRtkApi as generatedAPI }; -export type GetSearchApiResponse = /** status 200 undefined */ { - /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ - apiVersion?: string; - /** Facet results */ - facets?: { - [key: string]: any; - }; - /** The dashboard body (unstructured for now) */ - hits: any[]; - /** Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ - kind?: string; - /** Max score */ - maxScore?: number; - /** Where the query started from */ - offset?: number; - /** Cost of running the query */ - queryCost?: number; - /** How are the results sorted */ - sortBy?: any; - /** The number of matching results */ - totalHits: number; -}; +export type GetSearchApiResponse = /** status 200 undefined */ SearchResults; export type GetSearchApiArg = { /** user query string */ query?: string; @@ -66,3 +45,63 @@ export type GetSearchApiArg = { /** add debugging info that may help explain why the result matched */ explain?: boolean; }; +export type TermFacet = { + count?: number; + term?: string; +}; +export type FacetResult = { + field?: string; + /** The number of documents that do *not* have this field */ + missing?: number; + terms?: TermFacet[]; + /** The distinct terms */ + total?: number; +}; +export type ManagedBy = { + id?: string; + kind: string; +}; +export type DashboardHit = { + /** Dashboard description */ + description?: string; + /** Explain the score (if possible) */ + explain?: any; + /** Stick untyped extra fields in this object (including the sort value) */ + field?: any; + /** The k8s name (eg, grafana UID) for the parent folder */ + folder?: string; + managedBy?: ManagedBy; + /** The k8s "name" (eg, grafana UID) */ + name: string; + /** Dashboard or folder */ + resource: string; + /** When using "real" search, this is the score */ + score?: number; + /** Filter tags */ + tags?: string[]; + /** The display name */ + title: string; +}; +export type SortBy = { + desc?: boolean; + field: string; +}; +export type SearchResults = { + /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ + apiVersion?: string; + facets?: { + [key: string]: FacetResult; + }; + hits: DashboardHit[]; + /** Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind?: string; + /** Max score */ + maxScore?: number; + /** Where the query started from */ + offset?: number; + /** Cost of running the query */ + queryCost?: number; + sortBy?: SortBy; + /** The number of matching results */ + totalHits: number; +}; diff --git a/public/app/core/components/NestedFolderPicker/useFoldersQueryAppPlatform.ts b/public/app/core/components/NestedFolderPicker/useFoldersQueryAppPlatform.ts index 546a7b177db..60ca40f798e 100644 --- a/public/app/core/components/NestedFolderPicker/useFoldersQueryAppPlatform.ts +++ b/public/app/core/components/NestedFolderPicker/useFoldersQueryAppPlatform.ts @@ -6,7 +6,7 @@ import { dashboardAPIv0alpha1 } from 'app/api/clients/dashboard/v0alpha1'; import { DashboardViewItemWithUIItems, DashboardsTreeItem } from 'app/features/browse-dashboards/types'; import { useDispatch, useSelector } from 'app/types/store'; -import { AnnoKeyManagerKind, ManagerKind } from '../../../features/apiserver/types'; +import { ManagerKind } from '../../../features/apiserver/types'; import { PAGE_SIZE } from '../../../features/browse-dashboards/api/services'; import { getPaginationPlaceholders } from '../../../features/browse-dashboards/state/utils'; @@ -138,8 +138,8 @@ export function useFoldersQueryAppPlatform({ // query by it. uid: name, // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - managedBy: item.metadata?.annotations?.[AnnoKeyManagerKind] as ManagerKind | undefined, - parentUID: item.parentUID, + managedBy: item.managedBy?.kind as ManagerKind | undefined, + parentUID: item.folder, }, };