You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airavata.apache.org by ma...@apache.org on 2021/06/23 19:38:58 UTC
[airavata-django-portal] 01/02: AIRAVATA-3322 Paginated experiment
statistics view
This is an automated email from the ASF dual-hosted git repository.
machristie pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/airavata-django-portal.git
commit bd2474661441528c425a4a5e049400a1baf29d27
Author: Marcus Christie <ma...@apache.org>
AuthorDate: Wed Jun 23 15:32:17 2021 -0400
AIRAVATA-3322 Paginated experiment statistics view
---
.../statistics/ExperimentStatisticsContainer.vue | 43 ++++++++++++++++------
django_airavata/apps/api/serializers.py | 17 +++++----
.../django_airavata_api/js/service_config.js | 3 ++
.../js/utils/PaginationIterator.js | 11 ++++--
django_airavata/apps/api/views.py | 22 ++++++++---
.../static/common/js/components/Pager.vue | 6 +++
6 files changed, 76 insertions(+), 26 deletions(-)
diff --git a/django_airavata/apps/admin/static/django_airavata_admin/src/components/statistics/ExperimentStatisticsContainer.vue b/django_airavata/apps/admin/static/django_airavata_admin/src/components/statistics/ExperimentStatisticsContainer.vue
index c15d0f1..8561d3c 100644
--- a/django_airavata/apps/admin/static/django_airavata_admin/src/components/statistics/ExperimentStatisticsContainer.vue
+++ b/django_airavata/apps/admin/static/django_airavata_admin/src/components/statistics/ExperimentStatisticsContainer.vue
@@ -151,7 +151,7 @@
header-text-variant="white"
:count="experimentStatistics.allExperimentCount || 0"
title="Total Experiments"
- @click="selectedExperimentSummariesKey = 'allExperiments'"
+ @click="selectExperiments('allExperiments')"
>
<span slot="link-text">All</span>
</experiment-statistics-card>
@@ -162,7 +162,7 @@
:count="experimentStatistics.createdExperimentCount || 0"
:states="createdStates"
title="Created Experiments"
- @click="selectedExperimentSummariesKey = 'createdExperiments'"
+ @click="selectExperiments('createdExperiments')"
>
</experiment-statistics-card>
</div>
@@ -173,7 +173,7 @@
:count="experimentStatistics.runningExperimentCount || 0"
:states="runningStates"
title="Running Experiments"
- @click="selectedExperimentSummariesKey = 'runningExperiments'"
+ @click="selectExperiments('runningExperiments')"
>
</experiment-statistics-card>
</div>
@@ -185,7 +185,7 @@
:count="experimentStatistics.completedExperimentCount || 0"
:states="completedStates"
title="Completed Experiments"
- @click="selectedExperimentSummariesKey = 'completedExperiments'"
+ @click="selectExperiments('completedExperiments')"
>
</experiment-statistics-card>
</div>
@@ -197,7 +197,7 @@
:count="experimentStatistics.cancelledExperimentCount || 0"
:states="canceledStates"
title="Cancelled Experiments"
- @click="selectedExperimentSummariesKey = 'cancelledExperiments'"
+ @click="selectExperiments('cancelledExperiments')"
>
</experiment-statistics-card>
</div>
@@ -209,7 +209,7 @@
:count="experimentStatistics.failedExperimentCount || 0"
:states="failedStates"
title="Failed Experiments"
- @click="selectedExperimentSummariesKey = 'failedExperiments'"
+ @click="selectExperiments('failedExperiments')"
>
</experiment-statistics-card>
</div>
@@ -240,6 +240,12 @@
</template>
</b-table>
</b-card>
+ <pager
+ v-if="experimentStatistics.allExperimentCount > 0"
+ :paginator="experimentStatisticsPaginator"
+ @next="experimentStatisticsPaginator.next()"
+ @previous="experimentStatisticsPaginator.previous()"
+ ></pager>
</div>
</div>
</b-tab>
@@ -279,7 +285,7 @@ export default {
const fromTime = new Date().fp_incr(0);
const toTime = new Date().fp_incr(1);
return {
- experimentStatistics: {},
+ experimentStatisticsPaginator: null,
selectedExperimentSummariesKey: null,
fromTime: fromTime,
toTime: toTime,
@@ -315,8 +321,14 @@ export default {
"compute-resource-name": components.ComputeResourceName,
"human-date": components.HumanDate,
"experiment-status-badge": components.ExperimentStatusBadge,
+ pager: components.Pager,
},
computed: {
+ experimentStatistics() {
+ return this.experimentStatisticsPaginator
+ ? this.experimentStatisticsPaginator.results
+ : {};
+ },
createdStates() {
// TODO: moved to ExperimentStatistics model
return [models.ExperimentState.CREATED, models.ExperimentState.VALIDATED];
@@ -475,8 +487,10 @@ export default {
if (this.hostnameFilterEnabled && this.hostnameFilter) {
requestData["resourceHostName"] = this.hostnameFilter;
}
- services.ExperimentStatisticsService.get(requestData).then(
- (stats) => (this.experimentStatistics = stats)
+ return services.ExperimentStatisticsService.get(requestData).then(
+ (stats) => {
+ this.experimentStatisticsPaginator = stats;
+ }
);
},
getPast24Hours() {
@@ -484,13 +498,11 @@ export default {
//this.fromTime = new Date(this.fromTime.setHours(0,0,0));
this.toTime = new Date().fp_incr(1);
this.updateDateRange();
- this.loadStatistics();
},
getPastWeek() {
this.fromTime = new Date().fp_incr(-7);
this.toTime = new Date().fp_incr(1);
this.updateDateRange();
- this.loadStatistics();
},
updateDateRange() {
this.dateRange = [
@@ -552,6 +564,15 @@ export default {
scrollTabsIntoView() {
this.$refs.tabs.$el.scrollIntoView({ behavior: "smooth" });
},
+ selectExperiments(experimentSummariesKey) {
+ if (
+ this.experimentStatisticsPaginator &&
+ this.experimentStatisticsPaginator.offset > 0
+ ) {
+ this.loadStatistics();
+ }
+ this.selectedExperimentSummariesKey = experimentSummariesKey;
+ },
},
};
</script>
diff --git a/django_airavata/apps/api/serializers.py b/django_airavata/apps/api/serializers.py
index ec68e11..700bbf6 100644
--- a/django_airavata/apps/api/serializers.py
+++ b/django_airavata/apps/api/serializers.py
@@ -531,7 +531,7 @@ class FullExperimentSerializer(serializers.Serializer):
raise Exception("Not implemented")
-class ExperimentSummarySerializer(
+class BaseExperimentSummarySerializer(
thrift_utils.create_serializer_class(ExperimentSummaryModel)):
creationTime = UTCPosixTimestampDateTimeField()
statusUpdateTime = UTCPosixTimestampDateTimeField()
@@ -543,6 +543,9 @@ class ExperimentSummarySerializer(
view_name='django_airavata_api:project-detail',
lookup_field='projectId',
lookup_url_kwarg='project_id')
+
+
+class ExperimentSummarySerializer(BaseExperimentSummarySerializer):
userHasWriteAccess = serializers.SerializerMethodField()
def get_userHasWriteAccess(self, experiment):
@@ -989,12 +992,12 @@ class NotificationSerializer(
class ExperimentStatisticsSerializer(
thrift_utils.create_serializer_class(ExperimentStatistics)):
- allExperiments = ExperimentSummarySerializer(many=True)
- completedExperiments = ExperimentSummarySerializer(many=True)
- failedExperiments = ExperimentSummarySerializer(many=True)
- cancelledExperiments = ExperimentSummarySerializer(many=True)
- createdExperiments = ExperimentSummarySerializer(many=True)
- runningExperiments = ExperimentSummarySerializer(many=True)
+ allExperiments = BaseExperimentSummarySerializer(many=True)
+ completedExperiments = BaseExperimentSummarySerializer(many=True)
+ failedExperiments = BaseExperimentSummarySerializer(many=True)
+ cancelledExperiments = BaseExperimentSummarySerializer(many=True)
+ createdExperiments = BaseExperimentSummarySerializer(many=True)
+ runningExperiments = BaseExperimentSummarySerializer(many=True)
class UnverifiedEmailUserProfile(serializers.Serializer):
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/service_config.js b/django_airavata/apps/api/static/django_airavata_api/js/service_config.js
index 4d5d39b..64ad6b1 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/service_config.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/service_config.js
@@ -218,7 +218,10 @@ export default {
"userName",
"applicationName",
"resourceHostName",
+ "limit",
+ "offset",
],
+ pagination: true,
modelClass: ExperimentStatistics,
},
},
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/utils/PaginationIterator.js b/django_airavata/apps/api/static/django_airavata_api/js/utils/PaginationIterator.js
index 5ea87e0..e98a653 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/utils/PaginationIterator.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/utils/PaginationIterator.js
@@ -30,14 +30,19 @@ export default class PaginationIterator {
this._next = pagedResponse.next;
this._previous = pagedResponse.previous;
if (this.resultType) {
- this.results = pagedResponse.results.map(
- (result) => new this.resultType(result)
- );
+ if (Array.isArray(pagedResponse.results)) {
+ this.results = pagedResponse.results.map(
+ (result) => new this.resultType(result)
+ );
+ } else {
+ this.results = new this.resultType(pagedResponse.results);
+ }
} else {
this.results = pagedResponse.results;
}
this.offset = pagedResponse.offset;
this.limit = pagedResponse.limit;
+ this.count = pagedResponse.count;
return this;
}
diff --git a/django_airavata/apps/api/views.py b/django_airavata/apps/api/views.py
index 675236c..a33f7a9 100644
--- a/django_airavata/apps/api/views.py
+++ b/django_airavata/apps/api/views.py
@@ -30,7 +30,7 @@ from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
from django.http import FileResponse, Http404, HttpResponse, JsonResponse
from django.urls import reverse
from django.views.decorators.gzip import gzip_page
-from rest_framework import mixins, status
+from rest_framework import mixins, pagination, status
from rest_framework.decorators import action, api_view
from rest_framework.exceptions import ParseError
from rest_framework.renderers import JSONRenderer
@@ -1832,12 +1832,24 @@ class ExperimentStatisticsView(APIView):
username = request.GET.get('userName', None)
application_name = request.GET.get('applicationName', None)
resource_hostname = request.GET.get('resourceHostName', None)
+ limit = int(request.GET.get('limit', '50'))
+ offset = int(request.GET.get('offset', '0'))
+
statistics = request.airavata_client.getExperimentStatistics(
request.authz_token, settings.GATEWAY_ID, from_time, to_time,
- username, application_name, resource_hostname)
- serializer = self.serializer_class(
- statistics, context={'request': request})
- return Response(serializer.data)
+ username, application_name, resource_hostname, limit, offset)
+ serializer = self.serializer_class(statistics, context={'request': request})
+
+ paginator = pagination.LimitOffsetPagination()
+ paginator.count = statistics.allExperimentCount
+ paginator.limit = limit
+ paginator.offset = offset
+ paginator.request = request
+ response = paginator.get_paginated_response(serializer.data)
+ # Also add limit and offset to the response
+ response.data['limit'] = limit
+ response.data['offset'] = offset
+ return response
class UnverifiedEmailUserViewSet(mixins.ListModelMixin,
diff --git a/django_airavata/static/common/js/components/Pager.vue b/django_airavata/static/common/js/components/Pager.vue
index 4d49aaf..69005e4 100644
--- a/django_airavata/static/common/js/components/Pager.vue
+++ b/django_airavata/static/common/js/components/Pager.vue
@@ -42,6 +42,12 @@ export default {
},
last: function () {
if (this.paginator) {
+ if (this.paginator.hasOwnProperty("count")) {
+ return Math.min(
+ this.paginator.offset + this.paginator.limit,
+ this.paginator.count
+ );
+ }
return this.paginator.offset + this.paginator.results.length;
} else {
return null;