From f79445fbcbd5231dcb2b68c7b7e474a6ba537f79 Mon Sep 17 00:00:00 2001 From: Michael Derynck Date: Mon, 19 Aug 2024 07:59:01 -0600 Subject: [PATCH] Fix pagination behavior when page # exceeds search results (#4817) # What this PR does Change pagination to return last available page if the page number exceeds the pages available instead of returning 404. This came up from if the user is on a page other than the first and they enter a search and the number of search results are smaller than what would be needed to reach the current page number it would give a blank page and 404. ## Which issue(s) this PR closes Related to [issue link here] ## Checklist - [x] Unit, integration, and e2e (if applicable) tests updated - [x] Documentation added (or `pr:no public docs` PR label added if not required) - [x] Added the relevant release notes label (see labels prefixed w/ `release:`). These labels dictate how your PR will show up in the autogenerated release notes. --------- Co-authored-by: Rares Mardare --- .../public_api/tests/test_alert_groups.py | 5 +-- engine/common/api_helpers/paginators.py | 39 +++++++++++++++++++ .../src/pages/integrations/Integrations.tsx | 8 ++-- 3 files changed, 46 insertions(+), 6 deletions(-) diff --git a/engine/apps/public_api/tests/test_alert_groups.py b/engine/apps/public_api/tests/test_alert_groups.py index 51d07421..9c88fec8 100644 --- a/engine/apps/public_api/tests/test_alert_groups.py +++ b/engine/apps/public_api/tests/test_alert_groups.py @@ -447,10 +447,9 @@ def test_pagination(settings, alert_group_public_api_setup): token, alert_groups, _, _ = alert_group_public_api_setup client = APIClient() - url = reverse("api-public:alert_groups-list") + url = "{}?perpage=1".format(reverse("api-public:alert_groups-list")) - with patch("common.api_helpers.paginators.PathPrefixedPagePagination.get_page_size", return_value=1): - response = client.get(url, HTTP_AUTHORIZATION=token) + response = client.get(url, HTTP_AUTHORIZATION=token) assert response.status_code == status.HTTP_200_OK result = response.json() diff --git a/engine/common/api_helpers/paginators.py b/engine/common/api_helpers/paginators.py index e85ed62a..5c5b508c 100644 --- a/engine/common/api_helpers/paginators.py +++ b/engine/common/api_helpers/paginators.py @@ -1,5 +1,6 @@ import typing +from django.core.paginator import EmptyPage from rest_framework.pagination import BasePagination, CursorPagination, PageNumberPagination from rest_framework.response import Response @@ -54,6 +55,44 @@ class PathPrefixedPagePagination(BasePathPrefixedPagination, PageNumberPaginatio ) return paginated_schema + def paginate_queryset(self, queryset, request, view=None): + request.build_absolute_uri = lambda: create_engine_url(request.get_full_path()) + per_page = request.query_params.get(self.page_size_query_param, self.page_size) + try: + per_page = int(per_page) + except ValueError: + per_page = self.page_size + + if per_page < 1: + per_page = self.page_size + + paginator = self.django_paginator_class(queryset, per_page) + page_number = request.query_params.get(self.page_query_param, 1) + try: + page_number = int(page_number) + except ValueError: + page_number = 1 + + if page_number < 1: + page_number = 1 + + try: + self.page = self.get_page(page_number, paginator) + except EmptyPage: + self.page = paginator.page(paginator.num_pages) + + if paginator.num_pages > 1 and self.template is not None: + self.display_page_controls = True + + self.request = request + return list(self.page) + + def get_page(self, page_number, paginator): + try: + return paginator.page(page_number) + except EmptyPage: + return paginator.page(paginator.num_pages) + class PathPrefixedCursorPagination(BasePathPrefixedPagination, CursorPagination): def get_paginated_response(self, data: PaginatedData) -> Response: diff --git a/grafana-plugin/src/pages/integrations/Integrations.tsx b/grafana-plugin/src/pages/integrations/Integrations.tsx index fed1b4c3..1df6f1cc 100644 --- a/grafana-plugin/src/pages/integrations/Integrations.tsx +++ b/grafana-plugin/src/pages/integrations/Integrations.tsx @@ -660,6 +660,7 @@ class _IntegrationsPage extends React.Component { const { store } = this.props; + return requestedPage !== store.filtersStore.currentTablePageNum[PAGE.Integrations]; }; @@ -696,6 +697,10 @@ class _IntegrationsPage extends React.Component { + store.filtersStore.currentTablePageNum[PAGE.Integrations] = newPage; + }); + await alertReceiveChannelStore.fetchPaginatedItems({ filters: this.getFiltersBasedOnCurrentTab(), page: newPage, @@ -703,9 +708,6 @@ class _IntegrationsPage extends React.Component this.invalidateRequestFn(newPage), }); - runInAction(() => { - store.filtersStore.currentTablePageNum[PAGE.Integrations] = newPage; - }); LocationHelper.update({ p: newPage }, 'partial'); };