NestedFolderPicker: Migrate to app platform API (#106926)

* Add /children endpoint

* Update folder client

* Add comment

* Add feature toggle

* Add new version of useFoldersQuery

* Error handling

* Format

* Rename feature toggle

* Remove options and move root folder constant

* Fix feature toggle merge

* Add feature toggle again

* Rename useFoldersQuery files

* Update API spec

* Fix test

* Add test

* Better typings

---------

Co-authored-by: Clarity-89 <homes89@ukr.net>
This commit is contained in:
Andrej Ocenas
2025-07-03 16:15:23 +02:00
committed by GitHub
co-authored by Clarity-89
parent 185ce90a4b
commit e76f470b44
18 changed files with 1102 additions and 193 deletions
+5
View File
@@ -192,6 +192,11 @@ func (b *FolderAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.API
storage[resourceInfo.StoragePath("counts")] = &subCountREST{searcher: b.searcher}
storage[resourceInfo.StoragePath("access")] = &subAccessREST{b.folderSvc, b.ac}
// Adds a path to return children of a given folder
storage[resourceInfo.StoragePath("children")] = &subChildrenREST{
lister: storage[resourceInfo.StoragePath()].(rest.Lister),
}
apiGroupInfo.VersionedResourcesStorageMap[folders.VERSION] = storage
b.storage = storage[resourceInfo.StoragePath()].(grafanarest.Storage)
return nil
+73
View File
@@ -0,0 +1,73 @@
package folders
import (
"context"
"fmt"
"net/http"
"k8s.io/apimachinery/pkg/apis/meta/internalversion"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/registry/rest"
folders "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1"
)
type subChildrenREST struct {
lister rest.Lister
}
var _ = rest.Connecter(&subChildrenREST{})
var _ = rest.StorageMetadata(&subChildrenREST{})
// RootFolderName Hardcoded magic const to get root folders without parent.
var RootFolderName = "general"
func (r *subChildrenREST) New() runtime.Object {
return &folders.FolderList{}
}
func (r *subChildrenREST) Destroy() {
}
func (r *subChildrenREST) ProducesMIMETypes(verb string) []string {
return nil
}
func (r *subChildrenREST) ProducesObject(verb string) interface{} {
return &folders.FolderList{}
}
func (r *subChildrenREST) ConnectMethods() []string {
return []string{"GET"}
}
func (r *subChildrenREST) NewConnectOptions() (runtime.Object, bool, string) {
return nil, false, "" // true means you can use the trailing path as a variable
}
func (r *subChildrenREST) Connect(ctx context.Context, name string, opts runtime.Object, responder rest.Responder) (http.Handler, error) {
obj, err := r.lister.List(ctx, &internalversion.ListOptions{})
if err != nil {
return nil, err
}
allFolders, ok := obj.(*folders.FolderList)
if !ok {
return nil, fmt.Errorf("could not list folders")
}
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
children := &folders.FolderList{}
parentName := ""
if name != RootFolderName {
parentName = name
}
for _, folder := range allFolders.Items {
if parentName == getParent(&folder) {
children.Items = append(children.Items, folder)
}
}
responder.Object(http.StatusOK, children)
}), nil
}