Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions component_catalog/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
from component_catalog.tests import make_package
from component_catalog.views import ComponentAddView
from component_catalog.views import ComponentListView
from component_catalog.views import PackageListView
from component_catalog.views import PackageTabScanView
from dejacode_toolkit.scancodeio import get_webhook_url
from dejacode_toolkit.vulnerablecode import VulnerableCode
Expand All @@ -55,6 +56,7 @@
from dje.tests import add_perms
from dje.tests import create_superuser
from dje.tests import create_user
from dje.views import PaginationMixin
from license_library.models import License
from license_library.models import LicenseAssignedTag
from license_library.models import LicenseTag
Expand Down Expand Up @@ -517,8 +519,8 @@ def test_component_catalog_history_tab(self):
self.assertContains(response, "Changed name.")

def test_component_catalog_productcomponent_secured_hierarchy_and_product_usage(self):
component1 = Component.objects.create(name="c1", dataspace=self.nexb_dataspace)
product1 = Product.objects.create(name="p1", dataspace=self.nexb_dataspace)
component1 = Component.objects.create(name="component1", dataspace=self.nexb_dataspace)
product1 = Product.objects.create(name="product1", dataspace=self.nexb_dataspace)
ProductComponent.objects.create(
product=product1, component=component1, dataspace=self.nexb_dataspace
)
Expand Down Expand Up @@ -1134,6 +1136,20 @@ def test_package_list_view_num_queries(self):
with self.assertNumQueries(16):
self.client.get(reverse("component_catalog:package_list"))

def test_package_list_view_pagination(self):
list_view = PackageListView()

# Default value from the PaginationMixin.default_paginate_by
with override_settings(DEJACODE_PAGINATE_BY={}):
self.assertIsNone(list_view.paginate_by)
expected = PaginationMixin.default_paginate_by
self.assertEqual(expected, list_view.get_paginate_by(queryset=None))

# Value from custom DEJACODE_PAGINATE_BY
with override_settings(DEJACODE_PAGINATE_BY={"package": 20}):
self.assertIsNone(list_view.paginate_by)
self.assertEqual(20, list_view.get_paginate_by(queryset=None))

def test_package_views_urls(self):
p1 = Package(
filename="filename.zip",
Expand Down
3 changes: 1 addition & 2 deletions component_catalog/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,6 @@ class ComponentListView(
template_list_table = "component_catalog/tables/component_list_table.html"
include_reference_dataspace = True
put_results_in_session = True
paginate_by = settings.PAGINATE_BY or 200
group_name_version = True

table_headers = (
Expand Down Expand Up @@ -1734,9 +1733,9 @@ class ScanListView(
AddPackagePermissionMixin,
APIWrapperListView,
):
paginate_by = 50
template_name = "component_catalog/scan_list.html"
template_list_table = "component_catalog/tables/scan_list_table.html"
paginate_by = settings.DEJACODE_PAGINATE_BY.get("scan", 50)

def dispatch(self, request, *args, **kwargs):
user = self.request.user
Expand Down
25 changes: 24 additions & 1 deletion dejacode/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

import sys
import tempfile
import warnings
from pathlib import Path

import environ
Expand Down Expand Up @@ -383,9 +384,31 @@ def gettext_noop(s):
# Set False to hide the "Product Portfolio" section in the navbar.
SHOW_PP_IN_NAV = env.bool("SHOW_PP_IN_NAV", default=True)

# An integer specifying how many objects should be displayed per table whithin tabs.
TAB_PAGINATE_BY = env.int("TAB_PAGINATE_BY", default=100)

# An integer specifying how many objects should be displayed per page.
PAGINATE_BY = env.int("PAGINATE_BY", default=None)
TAB_PAGINATE_BY = env.int("TAB_PAGINATE_BY", default=100)
if PAGINATE_BY:
warnings.warn("The PAGINATE_BY setting is deprecated. Use DEJACODE_PAGINATE_BY instead.")


# List views pagination, controls the number of items displayed per page.
# Syntax in .env: DEJACODE_PAGINATE_BY=product=20,package=100,license=100,request=50,scan=50
DEJACODE_PAGINATE_BY = env.dict(
"DEJACODE_PAGINATE_BY",
default={
"product": 50,
"component": 100,
"package": 100,
"license": 100,
"owner": 100,
"report": 50,
"request": 50,
"scan": 50,
"vulnerability": 100,
},
)

ADMIN_FORMS_CONFIGURATION = env.dict("ADMIN_FORMS_CONFIGURATION", default={})

Expand Down
31 changes: 27 additions & 4 deletions dje/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,8 +260,32 @@ def get_queryset(self):
return qs.scope(dataspace, include_reference=self.include_reference_dataspace)


class PreviousNextPaginationMixin:
class PaginationMixin:
query_dict_page_param = "page"
paginate_by = None
default_paginate_by = 100

def get_paginate_by(self, queryset):
"""
Determine the number of items per page.
Resolution order:
1. ``paginate_by`` set directly on the view instance.
2. Per-model value from the ``DEJACODE_PAGINATE_BY`` setting.
3. ``default_paginate_by`` as a fallback.
"""
if self.paginate_by:
return self.paginate_by

if self.model and settings.DEJACODE_PAGINATE_BY:
model_name = self.model._meta.model_name
if paginate_by := settings.DEJACODE_PAGINATE_BY.get(model_name):
try:
return int(paginate_by)
except ValueError:
return self.default_paginate_by

return self.default_paginate_by

def get_previous_next(self, page_obj):
"""Return url links for the previous and next navigation."""
Expand Down Expand Up @@ -330,12 +354,11 @@ class DataspacedFilterView(
GetDataspaceMixin,
HasPermissionMixin,
TableHeaderMixin,
PreviousNextPaginationMixin,
PaginationMixin,
FilterView,
):
template_name = "object_list_base.html"
template_list_table = None
paginate_by = settings.PAGINATE_BY or 100
# Required if `show_previous_and_next_object_links` enabled on the
# details view.
put_results_in_session = False
Expand Down Expand Up @@ -2246,7 +2269,7 @@ def page(self, number):


class APIWrapperListView(
PreviousNextPaginationMixin,
PaginationMixin,
ListView,
):
paginate_by = 100
Expand Down
10 changes: 10 additions & 0 deletions docs/application-settings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,16 @@ longer than this value.
# 1 hour, in seconds.
SESSION_COOKIE_AGE=3600
.. _dejacode_settings_paginate_by:

DEJACODE_PAGINATE_BY
--------------------

The number of objects display per page for each object type can be customized with the
following setting::

DEJACODE_PAGINATE_BY=product=20,package=100,license=100,report=50,request=50,scan=50

DEJACODE_LOG_LEVEL
------------------

Expand Down
11 changes: 5 additions & 6 deletions product_portfolio/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@
from dje.views import Header
from dje.views import LicenseDataForBuilderMixin
from dje.views import ObjectDetailsView
from dje.views import PreviousNextPaginationMixin
from dje.views import PaginationMixin
from dje.views import SendAboutFilesView
from dje.views import TabContentView
from dje.views import TabField
Expand Down Expand Up @@ -164,7 +164,6 @@ class ProductListView(
filterset_class = ProductFilterSet
template_name = "product_portfolio/product_list.html"
template_list_table = "product_portfolio/tables/product_list_table.html"
paginate_by = 50
put_results_in_session = False
group_name_version = True
table_headers = (
Expand Down Expand Up @@ -733,7 +732,7 @@ def get_context_data(self, **kwargs):
class ProductTabInventoryView(
LoginRequiredMixin,
BaseProductViewMixin,
PreviousNextPaginationMixin,
PaginationMixin,
TabContentView,
):
template_name = "product_portfolio/tabs/tab_inventory.html"
Expand Down Expand Up @@ -978,7 +977,7 @@ def inject_scan_data(scancodeio, feature_grouped, dataspace_uuid):
class ProductTabCodebaseView(
LoginRequiredMixin,
BaseProductViewMixin,
PreviousNextPaginationMixin,
PaginationMixin,
TabContentView,
):
template_name = "product_portfolio/tabs/tab_codebase.html"
Expand Down Expand Up @@ -1059,7 +1058,7 @@ def has_any_values(field_name):
class ProductTabDependenciesView(
LoginRequiredMixin,
BaseProductViewMixin,
PreviousNextPaginationMixin,
PaginationMixin,
TableHeaderMixin,
TabContentView,
):
Expand Down Expand Up @@ -1138,7 +1137,7 @@ def get_context_data(self, **kwargs):
class ProductTabVulnerabilitiesView(
LoginRequiredMixin,
BaseProductViewMixin,
PreviousNextPaginationMixin,
PaginationMixin,
TableHeaderMixin,
TabContentView,
):
Expand Down
5 changes: 2 additions & 3 deletions reporting/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
from dje.views import DataspacedFilterView
from dje.views import DownloadableMixin
from dje.views import HasPermissionMixin
from dje.views import PreviousNextPaginationMixin
from dje.views import PaginationMixin
from reporting.filters import ReportFilterSet
from reporting.forms import RuntimeFilterBaseFormSet
from reporting.forms import RuntimeFilterForm
Expand Down Expand Up @@ -81,7 +81,7 @@ def get(self, request, *args, **kwargs):

class ReportDetailsView(
LoginRequiredMixin,
PreviousNextPaginationMixin,
PaginationMixin,
BootstrapCSSMixin,
DownloadableMixin,
HasPermissionMixin,
Expand Down Expand Up @@ -294,7 +294,6 @@ class ReportListView(
filterset_class = ReportFilterSet
template_name = "reporting/report_list.html"
template_list_table = "reporting/includes/report_list_table.html"
paginate_by = 50

def get_queryset(self):
qs = super().get_queryset()
Expand Down
1 change: 0 additions & 1 deletion workflow/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ class RequestListView(
filterset_class = RequestFilterSet
template_name = "workflow/request_list.html"
template_list_table = "workflow/includes/request_list_table.html"
paginate_by = 50

def get_queryset(self):
"""
Expand Down