diff --git a/pkg/infra/filestorage/api.go b/pkg/infra/filestorage/api.go index 184881a5b7d..775e8686dd3 100644 --- a/pkg/infra/filestorage/api.go +++ b/pkg/infra/filestorage/api.go @@ -93,8 +93,10 @@ type FileMetadata struct { } type Paging struct { + // The number of items to return + Limit int + // Starting after the key After string - First int } type UpsertFileCommand struct { diff --git a/pkg/infra/filestorage/cdk_blob_filestorage.go b/pkg/infra/filestorage/cdk_blob_filestorage.go index b3c14bb5305..81c76c629be 100644 --- a/pkg/infra/filestorage/cdk_blob_filestorage.go +++ b/pkg/infra/filestorage/cdk_blob_filestorage.go @@ -292,7 +292,7 @@ func (c cdkBlobStorage) list(ctx context.Context, folderPath string, paging *Pag })} recursive := options.Recursive - pageSize := paging.First + pageSize := paging.Limit foundCursor := true if paging.After != "" { diff --git a/pkg/infra/filestorage/db_filestorage.go b/pkg/infra/filestorage/db_filestorage.go index 50d0ffddde4..47cb64e4273 100644 --- a/pkg/infra/filestorage/db_filestorage.go +++ b/pkg/infra/filestorage/db_filestorage.go @@ -345,7 +345,7 @@ func (s dbFileStorage) List(ctx context.Context, folderPath string, paging *Pagi sess.OrderBy("path") - pageSize := paging.First + pageSize := paging.Limit sess.Limit(pageSize + 1) if cursor != "" { diff --git a/pkg/infra/filestorage/fs_integration_test.go b/pkg/infra/filestorage/fs_integration_test.go index 6cecfe89a9d..9336636ab23 100644 --- a/pkg/infra/filestorage/fs_integration_test.go +++ b/pkg/infra/filestorage/fs_integration_test.go @@ -467,7 +467,7 @@ func TestIntegrationFsStorage(t *testing.T) { }, }, queryListFiles{ - input: queryListFilesInput{path: "/", options: &ListOptions{Recursive: true}, paging: &Paging{First: 2, After: ""}}, + input: queryListFilesInput{path: "/", options: &ListOptions{Recursive: true}, paging: &Paging{Limit: 2, After: ""}}, list: checks(listSize(2), listHasMore(true), listLastPath("/folder1/b")), files: [][]any{ checks(fPath("/folder1/a")), @@ -475,7 +475,7 @@ func TestIntegrationFsStorage(t *testing.T) { }, }, queryListFiles{ - input: queryListFilesInput{path: "/", options: &ListOptions{Recursive: true, WithFiles: true, WithFolders: true}, paging: &Paging{First: 2, After: ""}}, + input: queryListFilesInput{path: "/", options: &ListOptions{Recursive: true, WithFiles: true, WithFolders: true}, paging: &Paging{Limit: 2, After: ""}}, list: checks(listSize(2), listHasMore(true), listLastPath("/folder1/a")), files: [][]any{ checks(fPath("/folder1"), fMimeType(DirectoryMimeType)), @@ -483,49 +483,49 @@ func TestIntegrationFsStorage(t *testing.T) { }, }, queryListFiles{ - input: queryListFilesInput{path: "/", options: &ListOptions{Recursive: true, WithFiles: true, WithFolders: true}, paging: &Paging{First: 1, After: "/folder1"}}, + input: queryListFilesInput{path: "/", options: &ListOptions{Recursive: true, WithFiles: true, WithFolders: true}, paging: &Paging{Limit: 1, After: "/folder1"}}, list: checks(listSize(1), listHasMore(true), listLastPath("/folder1/a")), files: [][]any{ checks(fPath("/folder1/a")), }, }, queryListFiles{ - input: queryListFilesInput{path: "/", options: &ListOptions{Recursive: true}, paging: &Paging{First: 1, After: "/folder1/a"}}, + input: queryListFilesInput{path: "/", options: &ListOptions{Recursive: true}, paging: &Paging{Limit: 1, After: "/folder1/a"}}, list: checks(listSize(1), listHasMore(true), listLastPath("/folder1/b")), files: [][]any{ checks(fPath("/folder1/b")), }, }, queryListFiles{ - input: queryListFilesInput{path: "/", options: &ListOptions{Recursive: true, WithFiles: true, WithFolders: true}, paging: &Paging{First: 1, After: "/folder1/a"}}, + input: queryListFilesInput{path: "/", options: &ListOptions{Recursive: true, WithFiles: true, WithFolders: true}, paging: &Paging{Limit: 1, After: "/folder1/a"}}, list: checks(listSize(1), listHasMore(true), listLastPath("/folder1/b")), files: [][]any{ checks(fPath("/folder1/b")), }, }, queryListFiles{ - input: queryListFilesInput{path: "/", options: &ListOptions{Recursive: true}, paging: &Paging{First: 1, After: "/folder1/b"}}, + input: queryListFilesInput{path: "/", options: &ListOptions{Recursive: true}, paging: &Paging{Limit: 1, After: "/folder1/b"}}, list: checks(listSize(1), listHasMore(false), listLastPath("/folder2/c")), files: [][]any{ checks(fPath("/folder2/c")), }, }, queryListFiles{ - input: queryListFilesInput{path: "/", options: &ListOptions{Recursive: true, WithFiles: true, WithFolders: true}, paging: &Paging{First: 1, After: "/folder1/b"}}, + input: queryListFilesInput{path: "/", options: &ListOptions{Recursive: true, WithFiles: true, WithFolders: true}, paging: &Paging{Limit: 1, After: "/folder1/b"}}, list: checks(listSize(1), listHasMore(true), listLastPath("/folder2")), files: [][]any{ checks(fPath("/folder2"), fMimeType(DirectoryMimeType)), }, }, queryListFiles{ - input: queryListFilesInput{path: "/", options: &ListOptions{Recursive: true, WithFiles: true, WithFolders: true}, paging: &Paging{First: 1, After: "/folder2"}}, + input: queryListFilesInput{path: "/", options: &ListOptions{Recursive: true, WithFiles: true, WithFolders: true}, paging: &Paging{Limit: 1, After: "/folder2"}}, list: checks(listSize(1), listHasMore(false), listLastPath("/folder2/c")), files: [][]any{ checks(fPath("/folder2/c")), }, }, queryListFiles{ - input: queryListFilesInput{path: "/", options: &ListOptions{Recursive: true}, paging: &Paging{First: 5, After: ""}}, + input: queryListFilesInput{path: "/", options: &ListOptions{Recursive: true}, paging: &Paging{Limit: 5, After: ""}}, list: checks(listSize(3), listHasMore(false), listLastPath("/folder2/c")), files: [][]any{ checks(fPath("/folder1/a")), @@ -534,7 +534,7 @@ func TestIntegrationFsStorage(t *testing.T) { }, }, queryListFiles{ - input: queryListFilesInput{path: "/", options: &ListOptions{Recursive: true, WithFiles: true, WithFolders: true}, paging: &Paging{First: 5, After: ""}}, + input: queryListFilesInput{path: "/", options: &ListOptions{Recursive: true, WithFiles: true, WithFolders: true}, paging: &Paging{Limit: 5, After: ""}}, list: checks(listSize(5), listHasMore(false), listLastPath("/folder2/c")), files: [][]any{ checks(fPath("/folder1"), fMimeType(DirectoryMimeType)), @@ -545,19 +545,19 @@ func TestIntegrationFsStorage(t *testing.T) { }, }, queryListFiles{ - input: queryListFilesInput{path: "/", options: &ListOptions{Recursive: true}, paging: &Paging{First: 5, After: "/folder2"}}, + input: queryListFilesInput{path: "/", options: &ListOptions{Recursive: true}, paging: &Paging{Limit: 5, After: "/folder2"}}, list: checks(listSize(1), listHasMore(false)), }, queryListFiles{ - input: queryListFilesInput{path: "/", options: &ListOptions{Recursive: true, WithFiles: true, WithFolders: true}, paging: &Paging{First: 5, After: "/folder2"}}, + input: queryListFilesInput{path: "/", options: &ListOptions{Recursive: true, WithFiles: true, WithFolders: true}, paging: &Paging{Limit: 5, After: "/folder2"}}, list: checks(listSize(1), listHasMore(false)), }, queryListFiles{ - input: queryListFilesInput{path: "/", options: &ListOptions{Recursive: true}, paging: &Paging{First: 5, After: "/folder2/c"}}, + input: queryListFilesInput{path: "/", options: &ListOptions{Recursive: true}, paging: &Paging{Limit: 5, After: "/folder2/c"}}, list: checks(listSize(0), listHasMore(false)), }, queryListFiles{ - input: queryListFilesInput{path: "/", options: &ListOptions{Recursive: true, WithFiles: true, WithFolders: true}, paging: &Paging{First: 5, After: "/folder2/c"}}, + input: queryListFilesInput{path: "/", options: &ListOptions{Recursive: true, WithFiles: true, WithFolders: true}, paging: &Paging{Limit: 5, After: "/folder2/c"}}, list: checks(listSize(0), listHasMore(false)), }, }, diff --git a/pkg/infra/filestorage/test_utils.go b/pkg/infra/filestorage/test_utils.go index f63cba35caf..0445807a094 100644 --- a/pkg/infra/filestorage/test_utils.go +++ b/pkg/infra/filestorage/test_utils.go @@ -321,7 +321,7 @@ func handleQuery(t *testing.T, ctx context.Context, query interface{}, queryName } resp, err := fs.List(ctx, inputPath, &Paging{ After: "", - First: 100000, + Limit: 100000, }, opts) require.NotNil(t, resp) require.NoError(t, err, "%s: should be able to list folders in %s", queryName, inputPath) diff --git a/pkg/infra/filestorage/wrapper.go b/pkg/infra/filestorage/wrapper.go index 62ddef6c0fb..aa236d9cbe5 100644 --- a/pkg/infra/filestorage/wrapper.go +++ b/pkg/infra/filestorage/wrapper.go @@ -200,12 +200,12 @@ func (b wrapper) Upsert(ctx context.Context, file *UpsertFileCommand) error { func (b wrapper) pagingOptionsWithDefaults(paging *Paging) *Paging { if paging == nil { return &Paging{ - First: 100, + Limit: 100, } } - if paging.First <= 0 { - paging.First = 100 + if paging.Limit <= 0 { + paging.Limit = 100 } if paging.After != "" { paging.After = b.addRoot(paging.After) @@ -381,7 +381,7 @@ func (b wrapper) List(ctx context.Context, folderPath string, paging *Paging, op } func (b wrapper) isFolderEmpty(ctx context.Context, path string) (bool, error) { - resp, err := b.List(ctx, path, &Paging{First: 1}, &ListOptions{Recursive: true, WithFolders: true, WithFiles: true}) + resp, err := b.List(ctx, path, &Paging{Limit: 1}, &ListOptions{Recursive: true, WithFolders: true, WithFiles: true}) if err != nil { return false, err } diff --git a/pkg/services/store/http.go b/pkg/services/store/http.go index 939995011e8..ad748a4a07b 100644 --- a/pkg/services/store/http.go +++ b/pkg/services/store/http.go @@ -260,7 +260,8 @@ func (s *standardStorageService) doCreateFolder(c *contextmodel.ReqContext) resp func (s *standardStorageService) list(c *contextmodel.ReqContext) response.Response { params := web.Params(c.Req) path := params["*"] - frame, err := s.List(c.Req.Context(), c.SignedInUser, path) + // maxFiles of 0 will result in default behaviour from wrapper + frame, err := s.List(c.Req.Context(), c.SignedInUser, path, 0) if err != nil { return response.Error(400, "error reading path", err) } diff --git a/pkg/services/store/service.go b/pkg/services/store/service.go index 61bb61a50f0..1ad4ad85558 100644 --- a/pkg/services/store/service.go +++ b/pkg/services/store/service.go @@ -64,7 +64,7 @@ type StorageService interface { RegisterHTTPRoutes(routing.RouteRegister) // List folder contents - List(ctx context.Context, user *user.SignedInUser, path string) (*StorageListFrame, error) + List(ctx context.Context, user *user.SignedInUser, path string, maxFiles int) (*StorageListFrame, error) // Read raw file contents out of the store Read(ctx context.Context, user *user.SignedInUser, path string) (*filestorage.File, error) @@ -340,9 +340,9 @@ func getOrgId(user *user.SignedInUser) int64 { return user.OrgID } -func (s *standardStorageService) List(ctx context.Context, user *user.SignedInUser, path string) (*StorageListFrame, error) { +func (s *standardStorageService) List(ctx context.Context, user *user.SignedInUser, path string, maxFiles int) (*StorageListFrame, error) { guardian := s.authService.newGuardian(ctx, user, getFirstSegment(path)) - return s.tree.ListFolder(ctx, getOrgId(user), path, guardian.getPathFilter(ActionFilesRead)) + return s.tree.ListFolder(ctx, getOrgId(user), path, maxFiles, guardian.getPathFilter(ActionFilesRead)) } func (s *standardStorageService) Read(ctx context.Context, user *user.SignedInUser, path string) (*filestorage.File, error) { diff --git a/pkg/services/store/service_test.go b/pkg/services/store/service_test.go index 05fe50066d9..0546461787a 100644 --- a/pkg/services/store/service_test.go +++ b/pkg/services/store/service_test.go @@ -74,7 +74,7 @@ func TestListFiles(t *testing.T) { store := newStandardStorageService(db.InitTestDB(t), roots, func(orgId int64) []storageRuntime { return make([]storageRuntime, 0) }, allowAllAuthService, cfg, nil) - frame, err := store.List(context.Background(), dummyUser, "public/maps") + frame, err := store.List(context.Background(), dummyUser, "public/maps", 0) require.NoError(t, err) experimental.CheckGoldenJSONFrame(t, "testdata", "public_testdata.golden", frame.Frame, true) @@ -95,7 +95,7 @@ func TestListFilesWithoutPermissions(t *testing.T) { store := newStandardStorageService(db.InitTestDB(t), roots, func(orgId int64) []storageRuntime { return make([]storageRuntime, 0) }, denyAllAuthService, cfg, nil) - frame, err := store.List(context.Background(), dummyUser, "public/maps") + frame, err := store.List(context.Background(), dummyUser, "public/maps", 0) require.NoError(t, err) rowLen, err := frame.RowLen() require.NoError(t, err) @@ -371,7 +371,7 @@ func TestContentRootWithNestedStorage(t *testing.T) { Files: []*filestorage.File{}, }, nil) - _, err := store.List(context.Background(), test.user, RootContent+"/"+test.nestedRoot) + _, err := store.List(context.Background(), test.user, RootContent+"/"+test.nestedRoot, 0) require.NoError(t, err) }) @@ -387,7 +387,7 @@ func TestContentRootWithNestedStorage(t *testing.T) { Files: []*filestorage.File{}, }, nil) - _, err := store.List(context.Background(), test.user, strings.Join([]string{RootContent, test.nestedRoot, "folder1", "folder2"}, "/")) + _, err := store.List(context.Background(), test.user, strings.Join([]string{RootContent, test.nestedRoot, "folder1", "folder2"}, "/"), 0) require.NoError(t, err) }) @@ -434,16 +434,16 @@ func TestContentRootWithNestedStorage(t *testing.T) { Files: []*filestorage.File{}, }, nil) - _, err := store.List(context.Background(), test.user, strings.Join([]string{RootContent, "not-nested-content"}, "/")) + _, err := store.List(context.Background(), test.user, strings.Join([]string{RootContent, "not-nested-content"}, "/"), 0) require.NoError(t, err) - _, err = store.List(context.Background(), test.user, strings.Join([]string{RootContent, "a", "b", "c"}, "/")) + _, err = store.List(context.Background(), test.user, strings.Join([]string{RootContent, "a", "b", "c"}, "/"), 0) require.NoError(t, err) - _, err = store.List(context.Background(), test.user, strings.Join([]string{RootContent, test.nestedRoot + "a"}, "/")) + _, err = store.List(context.Background(), test.user, strings.Join([]string{RootContent, test.nestedRoot + "a"}, "/"), 0) require.NoError(t, err) - _, err = store.List(context.Background(), test.user, strings.Join([]string{RootContent, test.nestedRoot + "a", "b"}, "/")) + _, err = store.List(context.Background(), test.user, strings.Join([]string{RootContent, test.nestedRoot + "a", "b"}, "/"), 0) require.NoError(t, err) }) @@ -536,7 +536,7 @@ func TestShadowingExistingFolderByNestedContentRoot(t *testing.T) { AllowUnsanitizedSvgUpload: true, } - resp, err := store.List(ctx, globalUser, "content/nested") + resp, err := store.List(ctx, globalUser, "content/nested", 0) require.NoError(t, err) require.NotNil(t, resp) @@ -544,7 +544,7 @@ func TestShadowingExistingFolderByNestedContentRoot(t *testing.T) { require.NoError(t, err) require.Equal(t, 0, rowLen) // nested storage is empty - resp, err = store.List(ctx, globalUser, "content") + resp, err = store.List(ctx, globalUser, "content", 0) require.NoError(t, err) require.NotNil(t, resp) diff --git a/pkg/services/store/tree.go b/pkg/services/store/tree.go index 5f88d48eb34..fe276c2c126 100644 --- a/pkg/services/store/tree.go +++ b/pkg/services/store/tree.go @@ -165,7 +165,7 @@ func (t *nestedTree) getStorages(orgId int64) []storageRuntime { return storages } -func (t *nestedTree) ListFolder(ctx context.Context, orgId int64, path string, accessFilter filestorage.PathFilter) (*StorageListFrame, error) { +func (t *nestedTree) ListFolder(ctx context.Context, orgId int64, path string, maxFiles int, accessFilter filestorage.PathFilter) (*StorageListFrame, error) { if path == "" || path == "/" { t.assureOrgIsInitialized(orgId) @@ -224,12 +224,16 @@ func (t *nestedTree) ListFolder(ctx context.Context, orgId int64, path string, a ) } - listResponse, err := store.List(ctx, path, nil, &filestorage.ListOptions{ - Recursive: false, - WithFolders: true, - WithFiles: true, - Filter: pathFilter, - }) + listResponse, err := store.List(ctx, path, + &filestorage.Paging{ + Limit: maxFiles, + }, + &filestorage.ListOptions{ + Recursive: false, + WithFolders: true, + WithFiles: true, + Filter: pathFilter, + }) if err != nil { return nil, err diff --git a/pkg/services/store/types.go b/pkg/services/store/types.go index 861ddfd5423..0cde74107b9 100644 --- a/pkg/services/store/types.go +++ b/pkg/services/store/types.go @@ -40,7 +40,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, accessFilter filestorage.PathFilter) (*StorageListFrame, error) + ListFolder(ctx context.Context, orgId int64, path string, maxFiles int, accessFilter filestorage.PathFilter) (*StorageListFrame, error) } //------------------------------------------- diff --git a/pkg/tsdb/grafanads/grafana.go b/pkg/tsdb/grafanads/grafana.go index f35a7cfb96a..e3eb5c7f8bd 100644 --- a/pkg/tsdb/grafanads/grafana.go +++ b/pkg/tsdb/grafanads/grafana.go @@ -124,7 +124,8 @@ func (s *Service) doListQuery(ctx context.Context, query backend.DataQuery) back } path := store.RootPublicStatic + "/" + q.Path - listFrame, err := s.store.List(ctx, nil, path) + maxFiles := int(query.MaxDataPoints) + listFrame, err := s.store.List(ctx, nil, path, maxFiles) response.Error = err if listFrame != nil { response.Frames = data.Frames{listFrame.Frame} diff --git a/public/app/features/canvas/elements/icon.tsx b/public/app/features/canvas/elements/icon.tsx index c6c66317887..2f5eec04394 100644 --- a/public/app/features/canvas/elements/icon.tsx +++ b/public/app/features/canvas/elements/icon.tsx @@ -115,6 +115,7 @@ export const iconItem: CanvasElementItem = { editor: ResourceDimensionEditor, settings: { resourceType: 'icon', + maxFiles: 2000, }, }) .addCustomEditor({ diff --git a/public/app/features/dimensions/editors/FolderPickerTab.tsx b/public/app/features/dimensions/editors/FolderPickerTab.tsx index cad3463ef84..ec7c2255022 100644 --- a/public/app/features/dimensions/editors/FolderPickerTab.tsx +++ b/public/app/features/dimensions/editors/FolderPickerTab.tsx @@ -35,10 +35,11 @@ interface Props { folderName: ResourceFolderName; newValue: string; setNewValue: Dispatch>; + maxFiles?: number; } export const FolderPickerTab = (props: Props) => { - const { value, mediaType, folderName, newValue, setNewValue } = props; + const { value, mediaType, folderName, newValue, setNewValue, maxFiles } = props; const styles = useStyles2(getStyles); const folders = getFolders(mediaType).map((v) => ({ @@ -75,7 +76,7 @@ export const FolderPickerTab = (props: Props) => { getDatasourceSrv() .get('-- Grafana --') .then((ds) => { - (ds as GrafanaDatasource).listFiles(folder).subscribe({ + (ds as GrafanaDatasource).listFiles(folder, maxFiles).subscribe({ next: (frame) => { const cards: ResourceItem[] = []; frame.forEach((item) => { @@ -95,7 +96,7 @@ export const FolderPickerTab = (props: Props) => { }); }); } - }, [mediaType, currentFolder]); + }, [mediaType, currentFolder, maxFiles]); return ( <> diff --git a/public/app/features/dimensions/editors/ResourceDimensionEditor.tsx b/public/app/features/dimensions/editors/ResourceDimensionEditor.tsx index 4141fe73a79..925ac4fdbb7 100644 --- a/public/app/features/dimensions/editors/ResourceDimensionEditor.tsx +++ b/public/app/features/dimensions/editors/ResourceDimensionEditor.tsx @@ -65,6 +65,7 @@ export const ResourceDimensionEditor = ( const showSourceRadio = item.settings?.showSourceRadio ?? true; const mediaType = item.settings?.resourceType ?? MediaType.Icon; const folderName = item.settings?.folderName ?? ResourceFolderName.Icon; + const maxFiles = item.settings?.maxFiles; // undefined leads to backend default let srcPath = ''; if (mediaType === MediaType.Icon) { if (value?.fixed) { @@ -106,6 +107,7 @@ export const ResourceDimensionEditor = ( mediaType={mediaType} folderName={folderName} size={ResourcePickerSize.NORMAL} + maxFiles={maxFiles} /> )} {mode === ResourceDimensionMode.Mapping && ( diff --git a/public/app/features/dimensions/editors/ResourcePicker.tsx b/public/app/features/dimensions/editors/ResourcePicker.tsx index 488c32c8970..19af481161d 100644 --- a/public/app/features/dimensions/editors/ResourcePicker.tsx +++ b/public/app/features/dimensions/editors/ResourcePicker.tsx @@ -32,17 +32,24 @@ interface Props { name?: string; placeholder?: string; color?: string; + maxFiles?: number; } export const ResourcePicker = (props: Props) => { - const { value, src, name, placeholder, onChange, onClear, mediaType, folderName, size, color } = props; + const { value, src, name, placeholder, onChange, onClear, mediaType, folderName, size, color, maxFiles } = props; const styles = useStyles2(getStyles); const theme = useTheme2(); const pickerTriggerRef = createRef(); const popoverElement = ( - + ); let sanitizedSrc = src; diff --git a/public/app/features/dimensions/editors/ResourcePickerPopover.tsx b/public/app/features/dimensions/editors/ResourcePickerPopover.tsx index 50df16fdc2e..2a72c20a9e2 100644 --- a/public/app/features/dimensions/editors/ResourcePickerPopover.tsx +++ b/public/app/features/dimensions/editors/ResourcePickerPopover.tsx @@ -20,13 +20,14 @@ interface Props { onChange: (value?: string) => void; mediaType: MediaType; folderName: ResourceFolderName; + maxFiles?: number; } interface ErrorResponse { message: string; } export const ResourcePickerPopover = (props: Props) => { - const { value, onChange, mediaType, folderName } = props; + const { value, onChange, mediaType, folderName, maxFiles } = props; const styles = useStyles2(getStyles); const onClose = () => { @@ -55,6 +56,7 @@ export const ResourcePickerPopover = (props: Props) => { folderName={folderName} newValue={newValue} setNewValue={setNewValue} + maxFiles={maxFiles} /> ); diff --git a/public/app/features/dimensions/types.ts b/public/app/features/dimensions/types.ts index 9e6720f4b9b..b1c1d7ec3b0 100644 --- a/public/app/features/dimensions/types.ts +++ b/public/app/features/dimensions/types.ts @@ -59,6 +59,7 @@ export interface ResourceDimensionOptions { placeholderValue?: string; // If you want your icon to be driven by value of a field showSourceRadio?: boolean; + maxFiles?: number; } export enum ResourceFolderName { diff --git a/public/app/plugins/datasource/grafana/datasource.ts b/public/app/plugins/datasource/grafana/datasource.ts index 7b0d886eb11..1f9cb331962 100644 --- a/public/app/plugins/datasource/grafana/datasource.ts +++ b/public/app/plugins/datasource/grafana/datasource.ts @@ -170,7 +170,7 @@ export class GrafanaDatasource extends DataSourceWithBackend { return of(); // nothing } - listFiles(path: string): Observable> { + listFiles(path: string, maxDataPoints?: number): Observable> { return this.query({ targets: [ { @@ -179,6 +179,7 @@ export class GrafanaDatasource extends DataSourceWithBackend { path, }, ], + maxDataPoints, } as any).pipe( map((v) => { const frame = v.data[0] ?? new MutableDataFrame(); diff --git a/public/app/plugins/panel/geomap/editor/StyleEditor.tsx b/public/app/plugins/panel/geomap/editor/StyleEditor.tsx index 7fb29cc507f..e11b5d895e6 100644 --- a/public/app/plugins/panel/geomap/editor/StyleEditor.tsx +++ b/public/app/plugins/panel/geomap/editor/StyleEditor.tsx @@ -120,6 +120,7 @@ export const StyleEditor = (props: Props) => { const propertyOptions = useObservable(settings?.layerInfo ?? of()); const featuresHavePoints = propertyOptions?.geometryType === GeometryTypeId.Point; const hasTextLabel = styleUsesText(value); + const maxFiles = 2000; // Simple fixed value display if (settings?.simpleFixedValues) { @@ -141,6 +142,7 @@ export const StyleEditor = (props: Props) => { placeholderText: hasTextLabel ? 'Select a symbol' : 'Select a symbol or add a text label', placeholderValue: defaultStyleConfig.symbol.fixed, showSourceRadio: false, + maxFiles, }, } as StandardEditorsRegistryItem } @@ -230,6 +232,7 @@ export const StyleEditor = (props: Props) => { placeholderText: hasTextLabel ? 'Select a symbol' : 'Select a symbol or add a text label', placeholderValue: defaultStyleConfig.symbol.fixed, showSourceRadio: false, + maxFiles, }, } as StandardEditorsRegistryItem }