mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
K8s/Folder: Show parent folder information (#97938)
This commit is contained in:
parent
00b51c0422
commit
eb38a63559
@ -45,14 +45,20 @@ type FolderInfoList struct {
|
||||
// FolderInfo briefly describes a folder -- unlike a folder resource,
|
||||
// this is a partial record of the folder metadata used for navigating parents and children
|
||||
type FolderInfo struct {
|
||||
// UID is the unique identifier for a folder (and the k8s name)
|
||||
UID string `json:"uid"`
|
||||
// Name is the k8s name (eg, the unique identifier) for a folder
|
||||
Name string `json:"name"`
|
||||
|
||||
// Title is the display value
|
||||
Title string `json:"title"`
|
||||
|
||||
// The folder description
|
||||
Description string `json:"description,omitempty"`
|
||||
|
||||
// The parent folder UID
|
||||
Parent string `json:"parent,omitempty"`
|
||||
|
||||
// This folder does not resolve
|
||||
Detached bool `json:"detached,omitempty"`
|
||||
}
|
||||
|
||||
// Access control information for the current user
|
||||
|
@ -170,9 +170,9 @@ func schema_pkg_apis_folder_v0alpha1_FolderInfo(ref common.ReferenceCallback) co
|
||||
Description: "FolderInfo briefly describes a folder -- unlike a folder resource, this is a partial record of the folder metadata used for navigating parents and children",
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"uid": {
|
||||
"name": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "UID is the unique identifier for a folder (and the k8s name)",
|
||||
Description: "Name is the k8s name (eg, the unique identifier) for a folder",
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
@ -186,6 +186,13 @@ func schema_pkg_apis_folder_v0alpha1_FolderInfo(ref common.ReferenceCallback) co
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"description": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "The folder description",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"parent": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "The parent folder UID",
|
||||
@ -193,8 +200,15 @@ func schema_pkg_apis_folder_v0alpha1_FolderInfo(ref common.ReferenceCallback) co
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"detached": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "This folder does not resolve",
|
||||
Type: []string{"boolean"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"uid", "title"},
|
||||
Required: []string{"name", "title"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -126,11 +126,6 @@ func (b *FolderAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.API
|
||||
|
||||
storage := map[string]rest.Storage{}
|
||||
storage[resourceInfo.StoragePath()] = legacyStore
|
||||
storage[resourceInfo.StoragePath("parents")] = &subParentsREST{b.folderSvc}
|
||||
storage[resourceInfo.StoragePath("access")] = &subAccessREST{b.folderSvc}
|
||||
storage[resourceInfo.StoragePath("counts")] = &subCountREST{searcher: b.searcher}
|
||||
|
||||
// enable dual writer
|
||||
if optsGetter != nil && dualWriteBuilder != nil {
|
||||
store, err := grafanaregistry.NewRegistryStore(scheme, resourceInfo, optsGetter)
|
||||
if err != nil {
|
||||
@ -141,6 +136,11 @@ func (b *FolderAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.API
|
||||
return err
|
||||
}
|
||||
}
|
||||
storage[resourceInfo.StoragePath("parents")] = &subParentsREST{
|
||||
getter: storage[resourceInfo.StoragePath()].(rest.Getter), // Get the parents
|
||||
}
|
||||
storage[resourceInfo.StoragePath("counts")] = &subCountREST{searcher: b.searcher}
|
||||
storage[resourceInfo.StoragePath("access")] = &subAccessREST{b.folderSvc}
|
||||
|
||||
apiGroupInfo.VersionedResourcesStorageMap[v0alpha1.VERSION] = storage
|
||||
b.storage = storage[resourceInfo.StoragePath()].(grafanarest.Storage)
|
||||
|
@ -2,18 +2,20 @@ package folders
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"slices"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apiserver/pkg/registry/rest"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||
"github.com/grafana/grafana/pkg/apis/folder/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
)
|
||||
|
||||
type subParentsREST struct {
|
||||
service folder.Service
|
||||
getter rest.Getter
|
||||
}
|
||||
|
||||
var _ = rest.Connecter(&subParentsREST{})
|
||||
@ -43,32 +45,58 @@ func (r *subParentsREST) NewConnectOptions() (runtime.Object, bool, string) {
|
||||
}
|
||||
|
||||
func (r *subParentsREST) Connect(ctx context.Context, name string, opts runtime.Object, responder rest.Responder) (http.Handler, error) {
|
||||
obj, err := r.getter.Get(ctx, name, &metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
folder, ok := obj.(*v0alpha1.Folder)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expecting folder, found: %T", folder)
|
||||
}
|
||||
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
ns, err := request.NamespaceInfoFrom(ctx, true)
|
||||
if err != nil {
|
||||
responder.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
parents, err := r.service.GetParents(ctx, folder.GetParentsQuery{
|
||||
UID: name,
|
||||
OrgID: ns.OrgID,
|
||||
})
|
||||
if err != nil {
|
||||
responder.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
info := &v0alpha1.FolderInfoList{
|
||||
Items: make([]v0alpha1.FolderInfo, 0),
|
||||
Items: []v0alpha1.FolderInfo{},
|
||||
}
|
||||
for _, parent := range parents {
|
||||
for folder != nil {
|
||||
parent := ""
|
||||
meta, _ := utils.MetaAccessor(folder)
|
||||
if meta != nil {
|
||||
parent = meta.GetFolder()
|
||||
}
|
||||
info.Items = append(info.Items, v0alpha1.FolderInfo{
|
||||
UID: parent.UID,
|
||||
Title: parent.Title,
|
||||
Parent: parent.ParentUID,
|
||||
Name: folder.Name,
|
||||
Title: folder.Spec.Title,
|
||||
Description: folder.Spec.Description,
|
||||
Parent: parent,
|
||||
})
|
||||
if parent == "" {
|
||||
break
|
||||
}
|
||||
|
||||
obj, err = r.getter.Get(ctx, parent, &metav1.GetOptions{})
|
||||
if err != nil {
|
||||
info.Items = append(info.Items, v0alpha1.FolderInfo{
|
||||
Name: parent,
|
||||
Detached: true,
|
||||
Description: err.Error(),
|
||||
})
|
||||
break
|
||||
}
|
||||
|
||||
folder, ok = obj.(*v0alpha1.Folder)
|
||||
if !ok {
|
||||
info.Items = append(info.Items, v0alpha1.FolderInfo{
|
||||
Name: parent,
|
||||
Detached: true,
|
||||
Description: fmt.Sprintf("expected folder, found: %T", obj),
|
||||
})
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Start from the root
|
||||
slices.Reverse(info.Items)
|
||||
responder.Object(http.StatusOK, info)
|
||||
}), nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user