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
3 changes: 3 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ Release notes
Existing Keywords are suggested for consistency but any values is now allowed.
https://github.com/nexB/dejacode/issues/48

- Display Product inventory count on the Product list view.
https://github.com/nexB/dejacode/issues/81

### Version 5.0.1

- Improve the stability of the "Check for new Package versions" feature.
Expand Down
6 changes: 3 additions & 3 deletions component_catalog/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ class ComponentFilterSet(DataspacedFilterSet):
label=_("License"),
field_name="licenses__key",
to_field_name="key",
queryset=License.objects.all().only("key", "short_name", "dataspace"),
queryset=License.objects.only("key", "short_name", "dataspace__id"),
widget=BootstrapSelectMultipleWidget(
search_placeholder="Search licenses",
),
Expand All @@ -80,7 +80,7 @@ class ComponentFilterSet(DataspacedFilterSet):
label=_("Keyword"),
to_field_name="label",
lookup_expr="contains",
queryset=ComponentKeyword.objects.all().only("label", "dataspace"),
queryset=ComponentKeyword.objects.only("label", "dataspace__id"),
widget=BootstrapSelectMultipleWidget(
search_placeholder="Search keywords",
),
Expand Down Expand Up @@ -183,7 +183,7 @@ class PackageFilterSet(DataspacedFilterSet):
label=_("License"),
field_name="licenses__key",
to_field_name="key",
queryset=License.objects.all().only("key", "short_name", "dataspace"),
queryset=License.objects.only("key", "short_name", "dataspace__id"),
widget=BootstrapSelectMultipleWidget(
search_placeholder="Search licenses",
),
Expand Down
7 changes: 7 additions & 0 deletions dejacode/static/css/dejacode_bootstrap.css
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,10 @@ dd.reduced pre {
z-index: 1;
font-size: 0.875rem;
}
th.column-grouping {
width: 36px;
max-width: 36px;
}
th.column-selection {
width: 27px;
max-width: 27px;
Expand Down Expand Up @@ -336,6 +340,9 @@ table.products-table .column-license_expression {
table.products-table .column-owner {
min-width: 75px;
}
table.products-table .column-productinventoryitem_count {
max-width:80px;
}

/* -- Package List -- */
table.packages-table .column-usage_policy {
Expand Down
4 changes: 2 additions & 2 deletions license_library/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ class LicenseFilterSet(DataspacedFilterSet):
label=_("Category"),
field_name="category__label",
to_field_name="label",
queryset=LicenseCategory.objects.all(),
queryset=LicenseCategory.objects.only("label", "dataspace__id"),
widget=BootstrapSelectMultipleWidget(
search_placeholder="Search categories",
),
Expand All @@ -80,7 +80,7 @@ class LicenseFilterSet(DataspacedFilterSet):
label=_("License profile"),
field_name="license_profile__name",
to_field_name="name",
queryset=LicenseProfile.objects.all(),
queryset=LicenseProfile.objects.only("name", "dataspace__id"),
widget=BootstrapSelectMultipleWidget(
search_placeholder="Search license profiles",
),
Expand Down
7 changes: 4 additions & 3 deletions product_portfolio/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ class ProductFilterSet(DataspacedFilterSet):
"primary_language",
"owner",
"configuration_status",
"productinventoryitem_count",
],
field_labels={
"primary_language": "Language",
Expand All @@ -67,7 +68,7 @@ class ProductFilterSet(DataspacedFilterSet):
label=_("Configuration status"),
field_name="configuration_status__label",
to_field_name="label",
queryset=ProductStatus.objects.all(),
queryset=ProductStatus.objects.only("label", "dataspace__id"),
widget=BootstrapSelectMultipleWidget(
search=False,
search_placeholder="Search configuration status",
Expand All @@ -84,7 +85,7 @@ class ProductFilterSet(DataspacedFilterSet):
label=_("License"),
field_name="licenses__key",
to_field_name="key",
queryset=License.objects.all(),
queryset=License.objects.only("key", "short_name", "dataspace__id"),
widget=BootstrapSelectMultipleWidget(
search_placeholder="Search licenses",
),
Expand All @@ -93,7 +94,7 @@ class ProductFilterSet(DataspacedFilterSet):
label=_("Keyword"),
to_field_name="label",
lookup_expr="contains",
queryset=ComponentKeyword.objects.all().only("label", "dataspace"),
queryset=ComponentKeyword.objects.only("label", "dataspace__id"),
widget=BootstrapSelectMultipleWidget(
search_placeholder="Search keywords",
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@
{% endif %}
</td>
<td>{{ product.configuration_status|default_if_none:'' }}</td>
<td>
{% if product.productinventoryitem_count %}
<a href="{% inject_preserved_filters product.get_absolute_url %}#inventory">{{ product.productinventoryitem_count }}</a>
{% else %}
0
{% endif %}
</td>
<td>
<ul class="fa-ul ms-4 mb-0">
{% for keyword in product.keywords %}
Expand Down
29 changes: 28 additions & 1 deletion product_portfolio/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -1102,6 +1102,33 @@ def test_product_portfolio_list_view_search(self):
self.assertEqual(1, len(response.context_data["object_list"]))
self.assertIn(self.product1, response.context_data["object_list"])

def test_product_portfolio_list_view_inventory_count(self):
self.client.login(username="nexb_user", password="secret")
url = resolve_url("product_portfolio:product_list")

response = self.client.get(url)
self.assertContains(response, "<td>0</td>", html=True)
product1 = response.context_data["object_list"][0]
self.assertEqual(0, product1.productinventoryitem_count)

ProductComponent.objects.create(
product=self.product1, component=self.component1, dataspace=self.dataspace
)
response = self.client.get(url)
expected = f'<a href="{self.product1.get_absolute_url()}#inventory">1</a>'
self.assertContains(response, expected, html=True)
product1 = response.context_data["object_list"][0]
self.assertEqual(1, product1.productinventoryitem_count)

ProductPackage.objects.create(
product=self.product1, package=self.package1, dataspace=self.dataspace
)
response = self.client.get(url)
expected = f'<a href="{self.product1.get_absolute_url()}#inventory">2</a>'
self.assertContains(response, expected, html=True)
product1 = response.context_data["object_list"][0]
self.assertEqual(2, product1.productinventoryitem_count)

def test_product_portfolio_product_tree_comparison_view_proper(self):
self.client.login(username="nexb_user", password="secret")
url = resolve_url(
Expand Down Expand Up @@ -2775,7 +2802,7 @@ def test_product_portfolio_load_sbom_view(self, mock_submit):
scan.assert_called_once()

@mock.patch("dejacode_toolkit.scancodeio.ScanCodeIO.submit_project")
def test_product_portfolio_mport_manifest_view(self, mock_submit):
def test_product_portfolio_import_manifest_view(self, mock_submit):
mock_submit.return_value = None
self.client.login(username=self.super_user.username, password="secret")
url = self.product1.get_import_manifests_url()
Expand Down
9 changes: 9 additions & 0 deletions product_portfolio/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from django.core.paginator import Paginator
from django.db import models
from django.db import transaction
from django.db.models import Count
from django.db.models.functions import Lower
from django.forms import modelformset_factory
from django.http import Http404
Expand Down Expand Up @@ -147,6 +148,7 @@ class ProductListView(
Header("primary_language", "Language", filter="primary_language"),
Header("owner", "Owner"),
Header("configuration_status", "Status", filter="configuration_status"),
Header("productinventoryitem_count", "Inventory", help_text="Inventory count"),
Header("keywords", "Keywords", filter="keywords"),
)

Expand Down Expand Up @@ -175,6 +177,13 @@ def get_queryset(self):
.prefetch_related(
"licenses__usage_policy",
)
.annotate(
productinventoryitem_count=Count("productinventoryitem"),
)
.order_by(
"name",
"version",
)
)

def get_extra_add_urls(self):
Expand Down