mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Folder/parent subresource (#98392)
* Expose get folder parents endpoint * Add tests
This commit is contained in:
@@ -76,6 +76,7 @@ func (hs *HTTPServer) registerFolderAPI(apiRoute routing.RouteRegister, authoriz
|
|||||||
} else {
|
} else {
|
||||||
folderUidRoute.Post("/move", authorize(accesscontrol.EvalPermission(dashboards.ActionFoldersWrite, uidScope)), routing.Wrap(hs.MoveFolder))
|
folderUidRoute.Post("/move", authorize(accesscontrol.EvalPermission(dashboards.ActionFoldersWrite, uidScope)), routing.Wrap(hs.MoveFolder))
|
||||||
}
|
}
|
||||||
|
folderUidRoute.Get("parents", handler.getFolderParents)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
folderRoute.Post("/", authorize(accesscontrol.EvalPermission(dashboards.ActionFoldersCreate)), routing.Wrap(hs.CreateFolder))
|
folderRoute.Post("/", authorize(accesscontrol.EvalPermission(dashboards.ActionFoldersCreate)), routing.Wrap(hs.CreateFolder))
|
||||||
@@ -816,6 +817,23 @@ func (fk8s *folderK8sHandler) countFolderContent(c *contextmodel.ReqContext) {
|
|||||||
c.JSON(http.StatusOK, out)
|
c.JSON(http.StatusOK, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fk8s *folderK8sHandler) getFolderParents(c *contextmodel.ReqContext) {
|
||||||
|
client, ok := fk8s.getClient(c)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
uid := web.Params(c.Req)[":uid"]
|
||||||
|
|
||||||
|
out, err := client.Get(c.Req.Context(), uid, v1.GetOptions{}, "parents")
|
||||||
|
if err != nil {
|
||||||
|
fk8s.writeError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, out)
|
||||||
|
}
|
||||||
|
|
||||||
func (fk8s *folderK8sHandler) getFolder(c *contextmodel.ReqContext) {
|
func (fk8s *folderK8sHandler) getFolder(c *contextmodel.ReqContext) {
|
||||||
client, ok := fk8s.getClient(c)
|
client, ok := fk8s.getClient(c)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|||||||
77
pkg/registry/apis/folders/sub_parent_test.go
Normal file
77
pkg/registry/apis/folders/sub_parent_test.go
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
package folders
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/apis/folder/v0alpha1"
|
||||||
|
grafanarest "github.com/grafana/grafana/pkg/apiserver/rest"
|
||||||
|
"github.com/stretchr/testify/mock"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSubParent(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
input *v0alpha1.Folder
|
||||||
|
expected *v0alpha1.FolderInfoList
|
||||||
|
setuFn func(*mock.Mock)
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "no parents",
|
||||||
|
input: &v0alpha1.Folder{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "test",
|
||||||
|
Annotations: map[string]string{},
|
||||||
|
},
|
||||||
|
Spec: v0alpha1.Spec{
|
||||||
|
Title: "some tittle",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: &v0alpha1.FolderInfoList{Items: []v0alpha1.FolderInfo{{Name: "test", Title: "some tittle"}}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "has a parent",
|
||||||
|
input: &v0alpha1.Folder{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "test",
|
||||||
|
Annotations: map[string]string{"grafana.app/folder": "parent-test"},
|
||||||
|
},
|
||||||
|
Spec: v0alpha1.Spec{
|
||||||
|
Title: "some tittle",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
setuFn: func(m *mock.Mock) {
|
||||||
|
m.On("Get", context.TODO(), "parent-test", &metav1.GetOptions{}).Return(&v0alpha1.Folder{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "parent-test",
|
||||||
|
Annotations: map[string]string{},
|
||||||
|
},
|
||||||
|
Spec: v0alpha1.Spec{
|
||||||
|
Title: "some other tittle",
|
||||||
|
},
|
||||||
|
}, nil).Once()
|
||||||
|
},
|
||||||
|
expected: &v0alpha1.FolderInfoList{Items: []v0alpha1.FolderInfo{
|
||||||
|
{Name: "test", Title: "some tittle", Parent: "parent-test"},
|
||||||
|
{Name: "parent-test", Title: "some other tittle"}},
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
s := (grafanarest.Storage)(nil)
|
||||||
|
m := &mock.Mock{}
|
||||||
|
gm := storageMock{m, s}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
r := &subParentsREST{
|
||||||
|
getter: gm,
|
||||||
|
}
|
||||||
|
if tt.setuFn != nil {
|
||||||
|
tt.setuFn(m)
|
||||||
|
}
|
||||||
|
parents := r.parents(context.TODO(), tt.input)
|
||||||
|
require.Equal(t, tt.expected, parents)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,7 +10,6 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apiserver/pkg/registry/rest"
|
"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/apis/folder/v0alpha1"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -55,15 +54,19 @@ func (r *subParentsREST) Connect(ctx context.Context, name string, opts runtime.
|
|||||||
}
|
}
|
||||||
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
info := r.parents(ctx, folder)
|
||||||
|
// Start from the root
|
||||||
|
slices.Reverse(info.Items)
|
||||||
|
responder.Object(http.StatusOK, info)
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *subParentsREST) parents(ctx context.Context, folder *v0alpha1.Folder) *v0alpha1.FolderInfoList {
|
||||||
info := &v0alpha1.FolderInfoList{
|
info := &v0alpha1.FolderInfoList{
|
||||||
Items: []v0alpha1.FolderInfo{},
|
Items: []v0alpha1.FolderInfo{},
|
||||||
}
|
}
|
||||||
for folder != nil {
|
for folder != nil {
|
||||||
parent := ""
|
parent := getParent(folder)
|
||||||
meta, _ := utils.MetaAccessor(folder)
|
|
||||||
if meta != nil {
|
|
||||||
parent = meta.GetFolder()
|
|
||||||
}
|
|
||||||
info.Items = append(info.Items, v0alpha1.FolderInfo{
|
info.Items = append(info.Items, v0alpha1.FolderInfo{
|
||||||
Name: folder.Name,
|
Name: folder.Name,
|
||||||
Title: folder.Spec.Title,
|
Title: folder.Spec.Title,
|
||||||
@@ -74,7 +77,7 @@ func (r *subParentsREST) Connect(ctx context.Context, name string, opts runtime.
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
obj, err = r.getter.Get(ctx, parent, &metav1.GetOptions{})
|
obj, err := r.getter.Get(ctx, parent, &metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
info.Items = append(info.Items, v0alpha1.FolderInfo{
|
info.Items = append(info.Items, v0alpha1.FolderInfo{
|
||||||
Name: parent,
|
Name: parent,
|
||||||
@@ -84,7 +87,7 @@ func (r *subParentsREST) Connect(ctx context.Context, name string, opts runtime.
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
folder, ok = obj.(*v0alpha1.Folder)
|
parentFolder, ok := obj.(*v0alpha1.Folder)
|
||||||
if !ok {
|
if !ok {
|
||||||
info.Items = append(info.Items, v0alpha1.FolderInfo{
|
info.Items = append(info.Items, v0alpha1.FolderInfo{
|
||||||
Name: parent,
|
Name: parent,
|
||||||
@@ -93,10 +96,7 @@ func (r *subParentsREST) Connect(ctx context.Context, name string, opts runtime.
|
|||||||
})
|
})
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
folder = parentFolder
|
||||||
}
|
}
|
||||||
|
return info
|
||||||
// Start from the root
|
|
||||||
slices.Reverse(info.Items)
|
|
||||||
responder.Object(http.StatusOK, info)
|
|
||||||
}), nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user