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"
|
||||
"strings"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||
"github.com/grafana/grafana/pkg/infra/filestorage"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
@ -34,7 +33,7 @@ type StorageService interface {
|
||||
registry.BackgroundService
|
||||
|
||||
// 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(ctx context.Context, user *models.SignedInUser, path string) (*filestorage.File, error)
|
||||
@ -114,7 +113,7 @@ func getOrgId(user *models.SignedInUser) int64 {
|
||||
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
|
||||
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")
|
||||
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")
|
||||
require.NoError(t, err)
|
||||
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)
|
||||
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) {
|
||||
|
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)
|
||||
}
|
||||
|
||||
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 == "/" {
|
||||
t.assureOrgIsInitialized(orgId)
|
||||
|
||||
@ -102,13 +102,13 @@ func (t *nestedTree) ListFolder(ctx context.Context, orgId int64, path string) (
|
||||
readOnly := data.NewFieldFromFieldType(data.FieldTypeBool, count)
|
||||
builtIn := data.NewFieldFromFieldType(data.FieldTypeBool, count)
|
||||
mtype := data.NewFieldFromFieldType(data.FieldTypeString, count)
|
||||
title.Name = "title"
|
||||
names.Name = "name"
|
||||
descr.Name = "description"
|
||||
mtype.Name = "mediaType"
|
||||
types.Name = "storageType"
|
||||
readOnly.Name = "readOnly"
|
||||
builtIn.Name = "builtIn"
|
||||
title.Name = titleListFrameField
|
||||
names.Name = nameListFrameField
|
||||
descr.Name = descriptionListFrameField
|
||||
mtype.Name = mediaTypeListFrameField
|
||||
types.Name = storageTypeListFrameField
|
||||
readOnly.Name = readOnlyListFrameField
|
||||
builtIn.Name = builtInListFrameField
|
||||
for _, f := range t.rootsByOrgId[ac.GlobalOrgID] {
|
||||
meta := f.Meta()
|
||||
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{
|
||||
Type: data.FrameTypeDirectoryListing,
|
||||
})
|
||||
return frame, nil
|
||||
return &StorageListFrame{frame}, nil
|
||||
}
|
||||
|
||||
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)
|
||||
mtype := data.NewFieldFromFieldType(data.FieldTypeString, count)
|
||||
fsize := data.NewFieldFromFieldType(data.FieldTypeInt64, count)
|
||||
names.Name = "name"
|
||||
mtype.Name = "mediaType"
|
||||
fsize.Name = "size"
|
||||
names.Name = nameListFrameField
|
||||
mtype.Name = mediaTypeListFrameField
|
||||
fsize.Name = sizeListFrameField
|
||||
fsize.Config = &data.FieldConfig{
|
||||
Unit: "bytes",
|
||||
}
|
||||
@ -178,5 +178,5 @@ func (t *nestedTree) ListFolder(ctx context.Context, orgId int64, path string) (
|
||||
"HasMore": listResponse.HasMore,
|
||||
},
|
||||
})
|
||||
return frame, nil
|
||||
return &StorageListFrame{frame}, nil
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ type WriteValueResponse struct {
|
||||
|
||||
type storageTree interface {
|
||||
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"`
|
||||
}
|
||||
|
||||
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
|
||||
frame, err := s.store.List(ctx, nil, path)
|
||||
listFrame, err := s.store.List(ctx, nil, path)
|
||||
response.Error = err
|
||||
if frame != nil {
|
||||
response.Frames = data.Frames{frame}
|
||||
if listFrame != nil {
|
||||
response.Frames = data.Frames{listFrame.Frame}
|
||||
}
|
||||
return response
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user