diff --git a/dandiapi/api/tests/test_dandiset.py b/dandiapi/api/tests/test_dandiset.py index 80d985111..899c2069d 100644 --- a/dandiapi/api/tests/test_dandiset.py +++ b/dandiapi/api/tests/test_dandiset.py @@ -1149,8 +1149,9 @@ def test_dandiset_rest_list_active_uploads( response = authenticated_api_client.get(f'/api/dandisets/{ds.identifier}/uploads/') assert response.status_code == 200 data = response.json() - assert len(data) == 1 - assert data[0]['upload_id'] == upload.upload_id + assert data['count'] == 1 + assert len(data['results']) == 1 + assert data['results'][0]['upload_id'] == upload.upload_id @pytest.mark.django_db @@ -1187,10 +1188,14 @@ def test_dandiset_rest_clear_active_uploads( assign_perm('owner', user, ds) upload_factory(dandiset=ds) - assert len(authenticated_api_client.get(f'/api/dandisets/{ds.identifier}/uploads/').json()) == 1 + response = authenticated_api_client.get(f'/api/dandisets/{ds.identifier}/uploads/').json() + assert response['count'] == 1 + assert len(response['results']) == 1 response = authenticated_api_client.delete(f'/api/dandisets/{ds.identifier}/uploads/') assert response.status_code == 204 assert ds.uploads.count() == 0 - assert len(authenticated_api_client.get(f'/api/dandisets/{ds.identifier}/uploads/').json()) == 0 + response = authenticated_api_client.get(f'/api/dandisets/{ds.identifier}/uploads/').json() + assert response['count'] == 0 + assert len(response['results']) == 0 diff --git a/dandiapi/api/views/dandiset.py b/dandiapi/api/views/dandiset.py index 839c00c93..867dd4319 100644 --- a/dandiapi/api/views/dandiset.py +++ b/dandiapi/api/views/dandiset.py @@ -43,6 +43,7 @@ DandisetSearchQueryParameterSerializer, DandisetSearchResultListSerializer, DandisetUploadSerializer, + PaginationQuerySerializer, UserSerializer, VersionMetadataSerializer, ) @@ -467,6 +468,7 @@ def users(self, request, dandiset__pk): # noqa: C901 @swagger_auto_schema( methods=['GET'], manual_parameters=[DANDISET_PK_PARAM], + query_serializer=PaginationQuerySerializer, request_body=no_body, operation_summary='List active/incomplete uploads in this dandiset.', ) @@ -478,8 +480,15 @@ def uploads(self, request, dandiset__pk): self.require_owner_perm(dandiset) uploads: QuerySet[Upload] = dandiset.uploads.all() - serializer = DandisetUploadSerializer(instance=uploads, many=True) - return Response(serializer.data, status=status.HTTP_200_OK) + + # Paginate and return + page = self.paginate_queryset(uploads) + if page is not None: + serializer = DandisetUploadSerializer(page, many=True) + return self.get_paginated_response(serializer.data) + + serializer = DandisetUploadSerializer(uploads, many=True) + return Response(serializer.data) @swagger_auto_schema( manual_parameters=[DANDISET_PK_PARAM], diff --git a/dandiapi/api/views/serializers.py b/dandiapi/api/views/serializers.py index be05589df..f12b5ca2a 100644 --- a/dandiapi/api/views/serializers.py +++ b/dandiapi/api/views/serializers.py @@ -373,6 +373,11 @@ class AssetPathsQueryParameterSerializer(serializers.Serializer): path_prefix = serializers.CharField(default='') +class PaginationQuerySerializer(serializers.Serializer): + page = serializers.IntegerField(default=1) + page_size = serializers.IntegerField(default=100) + + class AssetFileSerializer(AssetSerializer): class Meta(AssetSerializer.Meta): fields = ['asset_id', 'url'] diff --git a/web/src/rest.ts b/web/src/rest.ts index 9cde8b971..233bf73d2 100644 --- a/web/src/rest.ts +++ b/web/src/rest.ts @@ -108,8 +108,22 @@ const dandiRest = { } }, async uploads(identifier: string): Promise { - const res = await client.get(`dandisets/${identifier}/uploads/`); - return res.data; + const uploads = [] + let page = 1; + + // eslint-disable-next-line no-constant-condition + while (true) { + const res = await client.get(`dandisets/${identifier}/uploads/`, {params: { page }}); + + uploads.push(...res.data.results); + if (res.data.next === null) { + break; + } + + page += 1; + } + + return uploads; }, async clearUploads(identifier: string) { await client.delete(`dandisets/${identifier}/uploads/`);