mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Storage: simplify retrieving the file names from the response frame (#51805)
* add util method for storage list frame * use go:embed * remove enum
This commit is contained in:
parent
4f931afe29
commit
052132be46
@ -6,7 +6,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
|
||||||
"github.com/grafana/grafana/pkg/infra/filestorage"
|
"github.com/grafana/grafana/pkg/infra/filestorage"
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
@ -34,7 +33,7 @@ type StorageService interface {
|
|||||||
registry.BackgroundService
|
registry.BackgroundService
|
||||||
|
|
||||||
// List folder contents
|
// List folder contents
|
||||||
List(ctx context.Context, user *models.SignedInUser, path string) (*data.Frame, error)
|
List(ctx context.Context, user *models.SignedInUser, path string) (*StorageListFrame, error)
|
||||||
|
|
||||||
// Read raw file contents out of the store
|
// Read raw file contents out of the store
|
||||||
Read(ctx context.Context, user *models.SignedInUser, path string) (*filestorage.File, error)
|
Read(ctx context.Context, user *models.SignedInUser, path string) (*filestorage.File, error)
|
||||||
@ -114,7 +113,7 @@ func getOrgId(user *models.SignedInUser) int64 {
|
|||||||
return user.OrgId
|
return user.OrgId
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *standardStorageService) List(ctx context.Context, user *models.SignedInUser, path string) (*data.Frame, error) {
|
func (s *standardStorageService) List(ctx context.Context, user *models.SignedInUser, path string) (*StorageListFrame, error) {
|
||||||
// apply access control here
|
// apply access control here
|
||||||
return s.tree.ListFolder(ctx, getOrgId(user), path)
|
return s.tree.ListFolder(ctx, getOrgId(user), path)
|
||||||
}
|
}
|
||||||
|
@ -43,15 +43,15 @@ func TestListFiles(t *testing.T) {
|
|||||||
frame, err := store.List(context.Background(), dummyUser, "public/testdata")
|
frame, err := store.List(context.Background(), dummyUser, "public/testdata")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
experimental.CheckGoldenJSONFrame(t, "testdata", "public_testdata.golden", frame, true)
|
experimental.CheckGoldenJSONFrame(t, "testdata", "public_testdata.golden", frame.Frame, true)
|
||||||
|
|
||||||
file, err := store.Read(context.Background(), dummyUser, "public/testdata/js_libraries.csv")
|
file, err := store.Read(context.Background(), dummyUser, "public/testdata/js_libraries.csv")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotNil(t, file)
|
require.NotNil(t, file)
|
||||||
|
|
||||||
frame, err = testdatasource.LoadCsvContent(bytes.NewReader(file.Contents), file.Name)
|
testDsFrame, err := testdatasource.LoadCsvContent(bytes.NewReader(file.Contents), file.Name)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
experimental.CheckGoldenJSONFrame(t, "testdata", "public_testdata_js_libraries.golden", frame, true)
|
experimental.CheckGoldenJSONFrame(t, "testdata", "public_testdata_js_libraries.golden", testDsFrame, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpload(t *testing.T) {
|
func TestUpload(t *testing.T) {
|
||||||
|
73
pkg/services/store/testdata/example_list_frame.json
vendored
Normal file
73
pkg/services/store/testdata/example_list_frame.json
vendored
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
{
|
||||||
|
"schema": {
|
||||||
|
"meta": {
|
||||||
|
"type": "directory-listing",
|
||||||
|
"custom": {
|
||||||
|
"HasMore": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "name",
|
||||||
|
"type": "string",
|
||||||
|
"typeInfo": {
|
||||||
|
"frame": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mediaType",
|
||||||
|
"type": "string",
|
||||||
|
"typeInfo": {
|
||||||
|
"frame": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "size",
|
||||||
|
"type": "number",
|
||||||
|
"typeInfo": {
|
||||||
|
"frame": "int64"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"unit": "bytes"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"values": [
|
||||||
|
[
|
||||||
|
"DL_1.jpg",
|
||||||
|
"Screen Shot 2022-06-23 at 9.05.39 PM.png",
|
||||||
|
"Screen Shot 2022-06-24 at 11.58.32 AM.png",
|
||||||
|
"Screen Shot 2022-06-30 at 3.45.03 PM.png",
|
||||||
|
"Screen Shot 2022-07-05 at 3.24.27 PM.png",
|
||||||
|
"image.png",
|
||||||
|
"rocket_1f680.png",
|
||||||
|
"test-folder",
|
||||||
|
"topcoder12.png"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"image/jpeg",
|
||||||
|
"image/png",
|
||||||
|
"image/png",
|
||||||
|
"image/png",
|
||||||
|
"image/png",
|
||||||
|
"image/png",
|
||||||
|
"image/png",
|
||||||
|
"directory",
|
||||||
|
"image/png"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
943004,
|
||||||
|
684257,
|
||||||
|
256396,
|
||||||
|
8796,
|
||||||
|
388290,
|
||||||
|
182568,
|
||||||
|
29066,
|
||||||
|
0,
|
||||||
|
90563
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
90
pkg/services/store/testdata/example_root_level_list.json
vendored
Normal file
90
pkg/services/store/testdata/example_root_level_list.json
vendored
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
{
|
||||||
|
"schema": {
|
||||||
|
"meta": {
|
||||||
|
"type": "directory-listing"
|
||||||
|
},
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "name",
|
||||||
|
"type": "string",
|
||||||
|
"typeInfo": {
|
||||||
|
"frame": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "title",
|
||||||
|
"type": "string",
|
||||||
|
"typeInfo": {
|
||||||
|
"frame": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "description",
|
||||||
|
"type": "string",
|
||||||
|
"typeInfo": {
|
||||||
|
"frame": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mediaType",
|
||||||
|
"type": "string",
|
||||||
|
"typeInfo": {
|
||||||
|
"frame": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "storageType",
|
||||||
|
"type": "string",
|
||||||
|
"typeInfo": {
|
||||||
|
"frame": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "readOnly",
|
||||||
|
"type": "boolean",
|
||||||
|
"typeInfo": {
|
||||||
|
"frame": "bool"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "builtIn",
|
||||||
|
"type": "boolean",
|
||||||
|
"typeInfo": {
|
||||||
|
"frame": "bool"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"values": [
|
||||||
|
[
|
||||||
|
"public-static",
|
||||||
|
"resources"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"Public static files",
|
||||||
|
"Resources"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"Access files from the static public files",
|
||||||
|
"Upload custom resource files"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"directory",
|
||||||
|
"directory"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"disk",
|
||||||
|
"sql"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
true,
|
||||||
|
false
|
||||||
|
],
|
||||||
|
[
|
||||||
|
true,
|
||||||
|
true
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
@ -85,7 +85,7 @@ func (t *nestedTree) GetFile(ctx context.Context, orgId int64, path string) (*fi
|
|||||||
return root.Get(ctx, path)
|
return root.Get(ctx, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *nestedTree) ListFolder(ctx context.Context, orgId int64, path string) (*data.Frame, error) {
|
func (t *nestedTree) ListFolder(ctx context.Context, orgId int64, path string) (*StorageListFrame, error) {
|
||||||
if path == "" || path == "/" {
|
if path == "" || path == "/" {
|
||||||
t.assureOrgIsInitialized(orgId)
|
t.assureOrgIsInitialized(orgId)
|
||||||
|
|
||||||
@ -102,13 +102,13 @@ func (t *nestedTree) ListFolder(ctx context.Context, orgId int64, path string) (
|
|||||||
readOnly := data.NewFieldFromFieldType(data.FieldTypeBool, count)
|
readOnly := data.NewFieldFromFieldType(data.FieldTypeBool, count)
|
||||||
builtIn := data.NewFieldFromFieldType(data.FieldTypeBool, count)
|
builtIn := data.NewFieldFromFieldType(data.FieldTypeBool, count)
|
||||||
mtype := data.NewFieldFromFieldType(data.FieldTypeString, count)
|
mtype := data.NewFieldFromFieldType(data.FieldTypeString, count)
|
||||||
title.Name = "title"
|
title.Name = titleListFrameField
|
||||||
names.Name = "name"
|
names.Name = nameListFrameField
|
||||||
descr.Name = "description"
|
descr.Name = descriptionListFrameField
|
||||||
mtype.Name = "mediaType"
|
mtype.Name = mediaTypeListFrameField
|
||||||
types.Name = "storageType"
|
types.Name = storageTypeListFrameField
|
||||||
readOnly.Name = "readOnly"
|
readOnly.Name = readOnlyListFrameField
|
||||||
builtIn.Name = "builtIn"
|
builtIn.Name = builtInListFrameField
|
||||||
for _, f := range t.rootsByOrgId[ac.GlobalOrgID] {
|
for _, f := range t.rootsByOrgId[ac.GlobalOrgID] {
|
||||||
meta := f.Meta()
|
meta := f.Meta()
|
||||||
names.Set(idx, meta.Config.Prefix)
|
names.Set(idx, meta.Config.Prefix)
|
||||||
@ -138,7 +138,7 @@ func (t *nestedTree) ListFolder(ctx context.Context, orgId int64, path string) (
|
|||||||
frame.SetMeta(&data.FrameMeta{
|
frame.SetMeta(&data.FrameMeta{
|
||||||
Type: data.FrameTypeDirectoryListing,
|
Type: data.FrameTypeDirectoryListing,
|
||||||
})
|
})
|
||||||
return frame, nil
|
return &StorageListFrame{frame}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
root, path := t.getRoot(orgId, path)
|
root, path := t.getRoot(orgId, path)
|
||||||
@ -160,9 +160,9 @@ func (t *nestedTree) ListFolder(ctx context.Context, orgId int64, path string) (
|
|||||||
names := data.NewFieldFromFieldType(data.FieldTypeString, count)
|
names := data.NewFieldFromFieldType(data.FieldTypeString, count)
|
||||||
mtype := data.NewFieldFromFieldType(data.FieldTypeString, count)
|
mtype := data.NewFieldFromFieldType(data.FieldTypeString, count)
|
||||||
fsize := data.NewFieldFromFieldType(data.FieldTypeInt64, count)
|
fsize := data.NewFieldFromFieldType(data.FieldTypeInt64, count)
|
||||||
names.Name = "name"
|
names.Name = nameListFrameField
|
||||||
mtype.Name = "mediaType"
|
mtype.Name = mediaTypeListFrameField
|
||||||
fsize.Name = "size"
|
fsize.Name = sizeListFrameField
|
||||||
fsize.Config = &data.FieldConfig{
|
fsize.Config = &data.FieldConfig{
|
||||||
Unit: "bytes",
|
Unit: "bytes",
|
||||||
}
|
}
|
||||||
@ -178,5 +178,5 @@ func (t *nestedTree) ListFolder(ctx context.Context, orgId int64, path string) (
|
|||||||
"HasMore": listResponse.HasMore,
|
"HasMore": listResponse.HasMore,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
return frame, nil
|
return &StorageListFrame{frame}, nil
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ type WriteValueResponse struct {
|
|||||||
|
|
||||||
type storageTree interface {
|
type storageTree interface {
|
||||||
GetFile(ctx context.Context, orgId int64, path string) (*filestorage.File, error)
|
GetFile(ctx context.Context, orgId int64, path string) (*filestorage.File, error)
|
||||||
ListFolder(ctx context.Context, orgId int64, path string) (*data.Frame, error)
|
ListFolder(ctx context.Context, orgId int64, path string) (*StorageListFrame, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------
|
//-------------------------------------------
|
||||||
@ -95,3 +95,38 @@ type RootStorageMeta struct {
|
|||||||
|
|
||||||
Config RootStorageConfig `json:"config"`
|
Config RootStorageConfig `json:"config"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type StorageListFrame struct {
|
||||||
|
*data.Frame
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
titleListFrameField = "title"
|
||||||
|
nameListFrameField = "name"
|
||||||
|
descriptionListFrameField = "description"
|
||||||
|
mediaTypeListFrameField = "mediaType"
|
||||||
|
storageTypeListFrameField = "storageType"
|
||||||
|
readOnlyListFrameField = "readOnly"
|
||||||
|
builtInListFrameField = "builtIn"
|
||||||
|
sizeListFrameField = "size"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *StorageListFrame) GetFileNames() []string {
|
||||||
|
var fileNames []string
|
||||||
|
if s == nil {
|
||||||
|
return fileNames
|
||||||
|
}
|
||||||
|
|
||||||
|
field, idx := s.FieldByName(nameListFrameField)
|
||||||
|
if field.Len() == 0 || idx == -1 {
|
||||||
|
return fileNames
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < field.Len(); i++ {
|
||||||
|
if stringValue, ok := field.At(i).(string); ok {
|
||||||
|
fileNames = append(fileNames, stringValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fileNames
|
||||||
|
}
|
||||||
|
47
pkg/services/store/types_test.go
Normal file
47
pkg/services/store/types_test.go
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package store
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "embed"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
//go:embed testdata/example_list_frame.json
|
||||||
|
exampleListFrameJSON string
|
||||||
|
|
||||||
|
//go:embed testdata/example_root_level_list.json
|
||||||
|
exampleRootLevelListJSON string
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetFileNames(t *testing.T) {
|
||||||
|
frame := &data.Frame{}
|
||||||
|
err := frame.UnmarshalJSON([]byte(exampleListFrameJSON))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
listFrame := StorageListFrame{frame}
|
||||||
|
require.Equal(t, []string{
|
||||||
|
"DL_1.jpg",
|
||||||
|
"Screen Shot 2022-06-23 at 9.05.39 PM.png",
|
||||||
|
"Screen Shot 2022-06-24 at 11.58.32 AM.png",
|
||||||
|
"Screen Shot 2022-06-30 at 3.45.03 PM.png",
|
||||||
|
"Screen Shot 2022-07-05 at 3.24.27 PM.png",
|
||||||
|
"image.png", "rocket_1f680.png",
|
||||||
|
"test-folder",
|
||||||
|
"topcoder12.png",
|
||||||
|
}, listFrame.GetFileNames())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetFileNamesRootLevel(t *testing.T) {
|
||||||
|
frame := &data.Frame{}
|
||||||
|
err := frame.UnmarshalJSON([]byte(exampleRootLevelListJSON))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
listFrame := StorageListFrame{frame}
|
||||||
|
require.Equal(t, []string{
|
||||||
|
"public-static",
|
||||||
|
"resources",
|
||||||
|
}, listFrame.GetFileNames())
|
||||||
|
}
|
@ -109,10 +109,10 @@ func (s *Service) doListQuery(ctx context.Context, query backend.DataQuery) back
|
|||||||
}
|
}
|
||||||
|
|
||||||
path := store.RootPublicStatic + "/" + q.Path
|
path := store.RootPublicStatic + "/" + q.Path
|
||||||
frame, err := s.store.List(ctx, nil, path)
|
listFrame, err := s.store.List(ctx, nil, path)
|
||||||
response.Error = err
|
response.Error = err
|
||||||
if frame != nil {
|
if listFrame != nil {
|
||||||
response.Frames = data.Frames{frame}
|
response.Frames = data.Frames{listFrame.Frame}
|
||||||
}
|
}
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user