Skip to content

Commit

Permalink
Package details view #164 #464 (#481)
Browse files Browse the repository at this point in the history
* Add simple package details view including all model fields #164

Signed-off-by: Thomas Druez <[email protected]>

* Display only 5 Resources per Packages in list view #464

Signed-off-by: Thomas Druez <[email protected]>

* Add Resources in Package details using new tabs system #164

Signed-off-by: Thomas Druez <[email protected]>

* Add CHANGELOG entry #164 #464

Signed-off-by: Thomas Druez <[email protected]>
  • Loading branch information
tdruez authored Aug 1, 2022
1 parent 11c29c0 commit 97bb941
Show file tree
Hide file tree
Showing 11 changed files with 177 additions and 22 deletions.
8 changes: 6 additions & 2 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,17 @@ v31.0.0 (next)

https://github.com/nexB/scancode.io/issues/413

- Correctly extract symlinks in docker images. We now usse the latest
- Correctly extract symlinks in docker images. We now use the latest
container-inspector to fix symlinks extraction in docker image tarballs.
In particular broken synlinks are not treated as an error anymore
In particular broken symlinks are not treated as an error anymore
and symlinks are extracted correctly.
https://github.com/nexB/scancode.io/issues/471
https://github.com/nexB/scancode.io/issues/407

- Add a Package details view including all model fields and resources.
Display only 5 resources per package in the list view.
https://github.com/nexB/scancode.io/issues/164
https://github.com/nexB/scancode.io/issues/464

v30.2.0 (2021-12-17)
--------------------
Expand Down
21 changes: 21 additions & 0 deletions scancodeio/static/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,26 @@ function setupCloseModalButtons() {
}
}

// Tabs

function setupTabs() {
const $tabLinks = getAll('.tabs a');

$tabLinks.forEach(function ($el) {
$el.addEventListener('click', function (event) {
const activeLink = document.querySelector('.tabs .is-active');
const activeTabContent = document.querySelector('.tab-content.is-active');
const target_id = $el.dataset.target;
const targetTabContent = document.getElementById(target_id);

activeLink.classList.remove('is-active');
$el.parentNode.classList.add('is-active');
activeTabContent.classList.remove('is-active');
targetTabContent.classList.add('is-active');
});
});
}

// Utils, available globally

function getAll(selector) {
Expand Down Expand Up @@ -122,6 +142,7 @@ document.addEventListener('DOMContentLoaded', function () {

setupOpenModalButtons();
setupCloseModalButtons();
setupTabs();

// Close modals and dropdowns on pressing "escape" key
document.addEventListener('keydown', function (event) {
Expand Down
27 changes: 17 additions & 10 deletions scanpipe/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@

from django.apps import apps
from django.db import models
from django.utils.translation import gettext_lazy as _

import django_filters
from django_filters.widgets import LinkWidget
Expand Down Expand Up @@ -117,9 +116,11 @@ class BulmaDropdownWidget(BulmaLinkWidget):


class ProjectFilterSet(FilterSetUtilsMixin, django_filters.FilterSet):
search = django_filters.CharFilter(field_name="name", lookup_expr="icontains")
search = django_filters.CharFilter(
label="Search", field_name="name", lookup_expr="icontains"
)
sort = django_filters.OrderingFilter(
label=_("Sort"),
label="Sort",
fields=["created_date", "name"],
empty_label="Newest",
choices=(
Expand All @@ -130,7 +131,7 @@ class ProjectFilterSet(FilterSetUtilsMixin, django_filters.FilterSet):
widget=BulmaDropdownWidget,
)
pipeline = django_filters.ChoiceFilter(
label=_("Pipeline"),
label="Pipeline",
field_name="runs__pipeline_name",
choices=scanpipe_app.get_pipeline_choices(include_blank=False),
widget=BulmaDropdownWidget,
Expand Down Expand Up @@ -177,8 +178,8 @@ def filter(self, qs, value):
class InPackageFilter(django_filters.ChoiceFilter):
def __init__(self, *args, **kwargs):
kwargs["choices"] = (
("true", _("Yes")),
("false", _("No")),
("true", "Yes"),
("false", "No"),
)
super().__init__(*args, **kwargs)

Expand All @@ -191,7 +192,9 @@ def filter(self, qs, value):


class ResourceFilterSet(FilterSetUtilsMixin, django_filters.FilterSet):
search = django_filters.CharFilter(field_name="path", lookup_expr="icontains")
search = django_filters.CharFilter(
label="Search", field_name="path", lookup_expr="icontains"
)
in_package = InPackageFilter(label="In a Package")

class Meta:
Expand Down Expand Up @@ -236,8 +239,10 @@ def filter_for_lookup(cls, field, lookup_type):


class PackageFilterSet(FilterSetUtilsMixin, django_filters.FilterSet):
search = django_filters.CharFilter(field_name="name", lookup_expr="icontains")
purl = PackageURLFilter()
search = django_filters.CharFilter(
label="Search", field_name="name", lookup_expr="icontains"
)
purl = PackageURLFilter(label="Package URL")

class Meta:
model = DiscoveredPackage
Expand Down Expand Up @@ -271,7 +276,9 @@ class Meta:


class ErrorFilterSet(FilterSetUtilsMixin, django_filters.FilterSet):
search = django_filters.CharFilter(field_name="message", lookup_expr="icontains")
search = django_filters.CharFilter(
label="Search", field_name="message", lookup_expr="icontains"
)

class Meta:
model = ProjectError
Expand Down
10 changes: 10 additions & 0 deletions scanpipe/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1756,6 +1756,16 @@ class Meta:
def __str__(self):
return self.package_url or str(self.uuid)

def get_absolute_url(self):
return reverse("package_detail", args=[self.project_id, self.pk])

@cached_property
def resources(self):
"""
Returns the assigned codebase_resources QuerySet as a list.
"""
return list(self.codebase_resources.all())

@property
def purl(self):
"""
Expand Down
3 changes: 3 additions & 0 deletions scanpipe/templates/scanpipe/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@
button.as-link {height: auto; line-height: initial; font-size: inherit;}
.file.is-boxed.has-name .file-cta {border-width: medium; border-style: dashed;}
progress.file-upload::before {content: 'Files upload: 'attr(value)'%'; position: absolute; top: -14%; left: 43%; color: black; font-weight: 400;}
.is-clipped-list ul {--snippet-spacing: 0.95rem; height: calc(8 * var(--snippet-spacing)); overflow: hidden;}
.tab-content {display: none;}
.tab-content.is-active {display: revert !important;}
</style>
{% block extrahead %}{% endblock %}
</head>
Expand Down
12 changes: 9 additions & 3 deletions scanpipe/templates/scanpipe/error_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,17 @@
<td style="max-width: 130px;">
<a href="?model={{ error.model }}" class="is-black-link">{{ error.model }}</a>
</td>
<td style="max-width: 150px;">
<a href="?message={{ error.message }}" class="is-black-link">{{ error.message }}</a>
<td class="break-word" style="max-width: 250px;">
<div style="max-height: 200px; overflow-y: scroll;">
{% if error.message|length < 100 %}
<a href="?message={{ error.message }}" class="is-black-link">{{ error.message }}</a>
{% else %}
{{ error.message }}
{% endif %}
</div>
</td>
<td class="break-all" style="max-width: 450px;">
<div style="max-height: 150px; overflow-y: scroll;">
<div style="max-height: 200px; overflow-y: scroll;">
{% if error.details.codebase_resource_pk and error.details.codebase_resource_path %}
<div>
<strong>Codebase resource</strong>:
Expand Down
66 changes: 66 additions & 0 deletions scanpipe/templates/scanpipe/package_detail.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{% extends "scanpipe/base.html" %}
{% load static humanize %}

{% block title %}ScanCode.io: {{ project.name }} - {{ object.name }}{% endblock %}

{% block content %}
<div class="container is-max-desktop">
{% include 'scanpipe/includes/navbar_header.html' %}
<div class="mx-5 mb-2">{% include 'scanpipe/includes/messages.html' %}</div>

<section class="mx-5 mb-3">
<nav class="breadcrumb is-medium mb-1" aria-label="breadcrumbs">
<ul>
<li><a href="{% url 'project_list' %}">Projects</a></li>
<li><a href="{{ project.get_absolute_url }}">{{ project.name }}</a></li>
<li><a href="{% url 'project_packages' project.uuid %}">Discovered Packages</a></li>
</ul>
</nav>
<div class="tags has-addons my-3">
<span class="tag is-dark">Package URL</span>
<span class="tag is-info">{{ object }}</span>
</div>
</section>

<div class="tabs is-boxed mx-5">
<ul>
<li class="is-active">
<a data-target="tab-details">
<span class="icon is-small"><i class="fas fa-info-circle"></i></span>
<span>Details</span>
</a>
</li>
<li>
<a data-target="tab-resources">
<span class="icon is-small"><i class="fas fa-file-alt"></i></span>
<span>Resources</span>
</a>
</li>
</ul>
</div>

<section id="tab-details" class="tab-content is-active mx-5">
<dl>
{% for field, value in package_data.items %}
<dt class="has-text-weight-semibold">
{{ field }}
</dt>
<dd class="mb-4">
<pre>{{ value|default_if_none:'' }}</pre>
</dd>
{% endfor %}
</dl>
</section>

<section id="tab-resources" class="tab-content mx-5">
<ul>
{% for resource in object.resources %}
<li>
<a href="{{ resource.get_absolute_url }}">{{ resource }}</a>
</li>
{% endfor %}
</ul>
</section>

</div>
{% endblock %}
28 changes: 24 additions & 4 deletions scanpipe/templates/scanpipe/package_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,22 +28,25 @@
{% for package in object_list %}
<tr class="break-word">
<td style="min-width: 500px;" title="{{ package.package_uid }}">
{{ package.package_url }}
<a href="{{ package.get_absolute_url }}">{{ package.package_url }}</a>
</td>
<td style="min-width: 300px; max-width: 400px;">
{{ package.license_expression|linebreaksbr }}
</td>
<td title="{{ package.copyright }}">
{{ package.copyright|truncatechars:150|linebreaksbr }}
</td>
<td>
<td class="is-clipped-list">
<ul>
{% for resource in package.codebase_resources.all %}
{% for resource in package.resources %}
<li>
<a href="{{ resource.get_absolute_url }}">{{ resource }}</a>
<a href="{{ resource.get_absolute_url }}" title="{{ resource.path }}">{{ resource.name }}</a>
</li>
{% endfor %}
</ul>
{% if package.resources|length > 5 %}
<button class="button is-small is-fullwidth show-clipped">Show {{ package.resources|length }} resources</button>
{% endif %}
</td>
</tr>
{% endfor %}
Expand All @@ -55,4 +58,21 @@
{% include 'scanpipe/includes/pagination.html' with page_obj=page_obj %}
{% endif %}
</div>
{% endblock %}

{% block scripts %}
<script>
let $showClippedButton = getAll("button.show-clipped");

$showClippedButton.forEach(function ($el) {
$el.addEventListener("click", function () {
$el.parentNode.classList.toggle("is-clipped-list");
let text = $el.textContent;
if (text.startsWith("Show"))
$el.textContent = text.toggle("Show", "Hide");
else
$el.textContent = text.replace("Hide", "Show");
});
});
</script>
{% endblock %}
6 changes: 3 additions & 3 deletions scanpipe/templates/scanpipe/resource_detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
<section class="mx-5 mb-3">
<nav class="breadcrumb is-medium mb-1" aria-label="breadcrumbs">
<ul>
<li><a href="{% url 'project_list' %}">Projects</a></li>
<li><a href="{{ project.get_absolute_url }}">{{ project.name }}</a></li>
<li><a href="{% url 'project_resources' project.uuid %}">Codebase Resources</a></li>
<li><a href="{% url 'project_list' %}">Projects</a></li>
<li><a href="{{ project.get_absolute_url }}">{{ project.name }}</a></li>
<li><a href="{% url 'project_resources' project.uuid %}">Codebase Resources</a></li>
</ul>
</nav>
</section>
Expand Down
5 changes: 5 additions & 0 deletions scanpipe/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@
views.CodebaseResourceDetailsView.as_view(),
name="resource_detail",
),
path(
"project/<uuid:uuid>/packages/<int:pk>/",
views.DiscoveredPackageDetailsView.as_view(),
name="package_detail",
),
path(
"project/<uuid:uuid>/resources/",
views.CodebaseResourceListView.as_view(),
Expand Down
13 changes: 13 additions & 0 deletions scanpipe/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@

from scancodeio.auth import ConditionalLoginRequired
from scancodeio.auth import conditional_login_required
from scanpipe.api.serializers import DiscoveredPackageSerializer
from scanpipe.filters import ErrorFilterSet
from scanpipe.filters import PackageFilterSet
from scanpipe.filters import ProjectFilterSet
Expand Down Expand Up @@ -664,6 +665,18 @@ def get_context_data(self, **kwargs):
return context


class DiscoveredPackageDetailsView(
ConditionalLoginRequired, ProjectRelatedViewMixin, generic.DetailView
):
model = DiscoveredPackage
template_name = "scanpipe/package_detail.html"

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["package_data"] = DiscoveredPackageSerializer(self.object).data
return context


@conditional_login_required
def run_detail_view(request, uuid):
template = "scanpipe/includes/run_modal_content.html"
Expand Down

0 comments on commit 97bb941

Please sign in to comment.