From f3501a3c6f46a2c230852fec52218308f485e38d Mon Sep 17 00:00:00 2001 From: Idir Chikhoune Date: Thu, 9 Apr 2026 12:54:15 +0200 Subject: [PATCH 1/5] Leaderboard Pagination. (#2319) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * pagination feature ready, needs to be tested * set up 50 as default value for leaderboard pagination * fix pagination in endpoint * Fix indent in competitions.py --------- Co-authored-by: Adrien Pavão --- src/apps/api/views/competitions.py | 32 +- src/static/js/ours/client.js | 4 + .../riot/competitions/detail/detail.tag | 679 ++++++++++++++++-- .../riot/competitions/detail/leaderboards.tag | 308 +++++--- 4 files changed, 883 insertions(+), 140 deletions(-) diff --git a/src/apps/api/views/competitions.py b/src/apps/api/views/competitions.py index 7cacb433b..53b9d2193 100644 --- a/src/apps/api/views/competitions.py +++ b/src/apps/api/views/competitions.py @@ -18,7 +18,7 @@ from rest_framework.response import Response from rest_framework.renderers import JSONRenderer from rest_framework_csv.renderers import CSVRenderer -from api.pagination import LargePagination +from api.pagination import DynamicChoicePagination, LargePagination from api.renderers import ZipRenderer from rest_framework.viewsets import ModelViewSet from api.serializers.competitions import CompetitionSerializerSimple, PhaseSerializer, \ @@ -774,10 +774,17 @@ def rerun_submissions(self, request, pk): def get_leaderboard(self, request, pk): phase = self.get_object() if phase.competition.fact_sheet: - fact_sheet_keys = [(phase.competition.fact_sheet[question]['key'], phase.competition.fact_sheet[question]['title']) - for question in phase.competition.fact_sheet if phase.competition.fact_sheet[question]['is_on_leaderboard'] == 'true'] + fact_sheet_keys = [ + ( + phase.competition.fact_sheet[question]['key'], + phase.competition.fact_sheet[question]['title'] + ) + for question in phase.competition.fact_sheet + if phase.competition.fact_sheet[question]['is_on_leaderboard'] == 'true' + ] else: fact_sheet_keys = None + query = LeaderboardPhaseSerializer(phase).data response = { 'title': query['leaderboard']['title'], @@ -787,9 +794,11 @@ def get_leaderboard(self, request, pk): 'fact_sheet_keys': fact_sheet_keys or None, 'primary_index': query['leaderboard']['primary_index'] } + columns = [col for col in query['columns']] submissions_keys = {} submission_detailed_results = {} + for submission in query['submissions']: submission_key = f"{submission['owner']}{submission['parent'] or submission['id']}" # gather detailed result from submissions for each task @@ -814,6 +823,7 @@ def get_leaderboard(self, request, pk): 'organization': submission['organization'], 'created_when': submission['created_when'] }) + for score in submission['scores']: # to check if a column is found @@ -851,6 +861,21 @@ def get_leaderboard(self, request, pk): for k, v in submissions_keys.items(): response['submissions'][v]['detailed_results'] = submission_detailed_results[k] + # --- pagination addition --- + total_count = len(response['submissions']) + paginator = DynamicChoicePagination() + paginated_submissions = paginator.paginate_queryset(response['submissions'], request, view=self) + if paginated_submissions is None: + paginated_submissions = response['submissions'] + + response['submissions'] = paginated_submissions + response['count'] = total_count + response['page_size'] = getattr(paginator, 'requested_page_size', request.query_params.get('page_size', 50)) + response['next'] = paginator.get_next_link() + response['previous'] = paginator.get_previous_link() + response['allowed_page_sizes'] = [50, 100, 500, 'all'] + # --- end pagination addition --- + for task in query['tasks']: # This can be used to rendered variable columns on each task tempTask = { @@ -862,6 +887,7 @@ def get_leaderboard(self, request, pk): for col in columns: tempTask['columns'].append(col) response['tasks'].append(tempTask) + return Response(response) diff --git a/src/static/js/ours/client.js b/src/static/js/ours/client.js index f43bfaaa2..decd1d6f4 100644 --- a/src/static/js/ours/client.js +++ b/src/static/js/ours/client.js @@ -147,6 +147,10 @@ CODALAB.api = { get_leaderboard_for_render: function (phase_pk) { return CODALAB.api.request('GET', `${URLS.API}phases/${phase_pk}/get_leaderboard/`) }, + get_leaderboard_for_render: function (phase_pk, params = {}) { + return CODALAB.api.request('GET', `${URLS.API}phases/${phase_pk}/get_leaderboard/`, params) + }, + update_submission_score: function (pk, data) { return CODALAB.api.request('PATCH', `${URLS.API}submission_scores/${pk}/`, data) }, diff --git a/src/static/riot/competitions/detail/detail.tag b/src/static/riot/competitions/detail/detail.tag index f0c9418c1..f971675b3 100644 --- a/src/static/riot/competitions/detail/detail.tag +++ b/src/static/riot/competitions/detail/detail.tag @@ -1,65 +1,648 @@ - - - +
+
+ + + +
+ + + + +
+ +
diff --git a/src/static/riot/competitions/detail/leaderboards.tag b/src/static/riot/competitions/detail/leaderboards.tag index 32050a480..80af465c4 100644 --- a/src/static/riot/competitions/detail/leaderboards.tag +++ b/src/static/riot/competitions/detail/leaderboards.tag @@ -41,38 +41,70 @@ - - - No submissions have been added to this leaderboard yet! - - - - - - - - - - {index + 1} - - { submission.owner } - { submission.organization.name } - - { pretty_date(submission.created_when) } - - {submission.id} - - - - - {get_score(column, submission)} - - + + + No submissions have been added to this leaderboard yet! + + + + + + + + + + + {get_row_number(index)} + + { submission.owner } + { submission.organization.name } + + { pretty_date(submission.created_when) } + + {submission.id} + + + + + {get_score(column, submission)} + + + + +