Skip to content

Commit

Permalink
Refactor the Package details view into a generic tabset system #164 (#…
Browse files Browse the repository at this point in the history
…497)

Signed-off-by: Thomas Druez <[email protected]>
  • Loading branch information
tdruez authored Aug 15, 2022
1 parent 15b3b45 commit c187056
Show file tree
Hide file tree
Showing 7 changed files with 210 additions and 50 deletions.
3 changes: 2 additions & 1 deletion scanpipe/templates/scanpipe/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
.is-height-auto {height: auto;}
pre.log {color: #f1f1f1; background-color: #222; font-family: monospace;}
pre.wrap {white-space: pre-wrap;}
pre.is-small {padding: 0.75rem 1rem;}
.nexb-orange {color:#f7bf3c;}
.bb-legend-item-hidden {text-decoration: line-through; opacity: 0.7!important;}
.bb-chart .bb-chart-arcs .bb-chart-arcs-title {font-size: 15px !important; fill: #4a4a4a !important; text-transform: uppercase;}
Expand All @@ -36,7 +37,7 @@
.is-grey-link {color: #7a7a7a;}
.is-black-link:hover, .is-grey-link:hover {color: #3273dc; text-decoration: underline;}
#project-extra-data figure.highlight {max-height: 300px; overflow-y: scroll;}
#project-extra-data pre {background-color: initial; color: initial; padding: initial; white-space: pre-wrap;}
#project-extra-data pre {background-color: initial; color: initial; padding: initial; white-space: pre-wrap; word-break: break-all;}
#inputs-panel .panel-block.dropdown:hover {background-color: #f5f5f5;}
#inputs-panel .dropdown-menu {width: 85%;}
.is-wider .dropdown-menu {min-width: 18rem;}
Expand Down
2 changes: 2 additions & 0 deletions scanpipe/templates/scanpipe/includes/breadcrumb.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
{% endif %}
{% if current %}
<li class="is-active"><a href="#" aria-current="page">{{ current }}</a></li>
{% else %}
<li class="is-active"><a href="#" aria-current="page">{{ project.name }}</a></li>
{% endif %}
{% endif %}
</ul>
Expand Down
43 changes: 2 additions & 41 deletions scanpipe/templates/scanpipe/package_detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,45 +19,6 @@
</nav>
</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>

{% include 'scanpipe/tabset/tabset.html' %}
</div>
{% endblock %}
{% endblock %}
10 changes: 10 additions & 0 deletions scanpipe/templates/scanpipe/tabset/tab_default.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<dl>
{% for field_name, field_data in tab_data.fields.items %}
<dt class="has-text-weight-semibold">
{{ field_data.label }}
</dt>
<dd class="mb-4">
<pre class="break-all is-small">{{ field_data.value|default:''|default_if_none:''|urlize }}</pre>
</dd>
{% endfor %}
</dl>
10 changes: 10 additions & 0 deletions scanpipe/templates/scanpipe/tabset/tab_resources.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<div class="content">
<strong>{{ tab_data.fields.codebase_resources.label }}</strong>
<ul>
{% for resource in tab_data.fields.codebase_resources.value.all %}
<li>
<a href="{{ resource.get_absolute_url }}">{{ resource }}</a>
</li>
{% endfor %}
</ul>
</div>
24 changes: 24 additions & 0 deletions scanpipe/templates/scanpipe/tabset/tabset.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<div class="tabs is-boxed mx-5">
<ul>
{% for label, tab_data in tabset_data.items %}
<li{% if forloop.first %} class="is-active"{% endif %}>
<a data-target="tab-{{ label }}">
{% if tab_data.icon_class %}
<span class="icon is-small"><i class="{{ tab_data.icon_class }}"></i></span>
{% endif %}
<span>{{ label|capfirst }}</span>
</a>
</li>
{% endfor %}
</ul>
</div>

{% for label, tab_data in tabset_data.items %}
<section id="tab-{{ label }}" class="tab-content mx-5 px-1 mb-3{% if forloop.first %} is-active{% endif %}">
{% if tab_data.template %}
{% include tab_data.template with tab_data=tab_data only %}
{% else %}
{% include 'scanpipe/tabset/tab_default.html' with tab_data=tab_data only %}
{% endif %}
</section>
{% endfor %}
168 changes: 160 additions & 8 deletions scanpipe/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
from django.shortcuts import get_object_or_404
from django.shortcuts import redirect
from django.shortcuts import render
from django.template.defaultfilters import filesizeformat
from django.urls import reverse_lazy
from django.views import generic
from django.views.generic.detail import SingleObjectMixin
Expand All @@ -45,7 +46,6 @@

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 @@ -160,6 +160,100 @@ class ProjectViewMixin:
slug_field = "uuid"


def render_as_yaml(value):
if value:
return saneyaml.dump(value, indent=2)


class TabSetMixin:
"""
tabset = {
"<tab_label>": {
"fields": [
"<field_name>",
"<field_name>",
{
"field_name": "<field_name>",
"label": None,
"render_func": None,
},
]
"template": "",
"icon_class": "",
}
}
"""

tabset = {}

def get_tabset_data(self):
"""
Returns the tabset data structure used in template rendering.
"""
tabset_data = {}

for label, tab_definition in self.tabset.items():
tab_data = {
"icon_class": tab_definition.get("icon_class"),
"template": tab_definition.get("template"),
"fields": self.get_fields_data(tab_definition.get("fields")),
}
tabset_data[label] = tab_data

return tabset_data

def get_fields_data(self, fields):
"""
Returns the tab fields including their values for display.
"""
fields_data = {}

for field_definition in fields:
# Support for single "field_name" entry in fields list.
if not isinstance(field_definition, dict):
field_name = field_definition
field_data = {"field_name": field_name}
else:
field_name = field_definition.get("field_name")
field_data = field_definition.copy()

if "label" not in field_data:
field_data["label"] = self.get_field_label(field_name)

render_func = field_data.get("render_func")
field_data["value"] = self.get_field_value(field_name, render_func)

fields_data[field_name] = field_data

return fields_data

def get_field_value(self, field_name, render_func=None):
"""
Returns the formatted value for the given `field_name` on the current object.
"""
field_value = getattr(self.object, field_name, None)

if field_value and render_func:
return render_func(field_value)

if isinstance(field_value, list):
field_value = "\n".join(field_value)

return field_value

@staticmethod
def get_field_label(field_name):
"""
Returns a formatted label for display based on the `field_name`.
"""
return field_name.replace("_", " ").capitalize().replace("url", "URL")

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["tabset_data"] = self.get_tabset_data()
return context


class ExportXLSXMixin:
"""
Adds the ability to export the current filtered QuerySet of a `FilterView` into
Expand Down Expand Up @@ -405,7 +499,7 @@ def get_context_data(self, **kwargs):
)

if project.extra_data:
context["extra_data_yaml"] = saneyaml.dump(project.extra_data, indent=2)
context["extra_data_yaml"] = render_as_yaml(project.extra_data)

return context

Expand Down Expand Up @@ -701,15 +795,73 @@ def get_context_data(self, **kwargs):


class DiscoveredPackageDetailsView(
ConditionalLoginRequired, ProjectRelatedViewMixin, generic.DetailView
ConditionalLoginRequired,
ProjectRelatedViewMixin,
TabSetMixin,
PrefetchRelatedViewMixin,
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
prefetch_related = ["codebase_resources"]
tabset = {
"essentials": {
"fields": [
"package_url",
"license_expression",
"primary_language",
"homepage_url",
"download_url",
"bug_tracking_url",
"code_view_url",
"vcs_url",
"source_packages",
"keywords",
"description",
],
"icon_class": "fas fa-info-circle",
},
"terms": {
"fields": [
"license_expression",
"declared_license",
"copyright",
"notice_text",
],
"icon_class": "fas fa-file-contract",
},
"resources": {
"fields": ["codebase_resources"],
"icon_class": "fas fa-folder-open",
"template": "scanpipe/tabset/tab_resources.html",
},
"dependencies": {
"fields": [
{"field_name": "dependencies", "render_func": render_as_yaml},
],
"icon_class": "fas fa-layer-group",
},
"others": {
"fields": [
{"field_name": "size", "render_func": filesizeformat},
"release_date",
"sha1",
"md5",
"missing_resources",
"modified_resources",
"manifest_path",
"contains_source_code",
"package_uid",
],
"icon_class": "fas fa-plus-square",
},
"extra data": {
"fields": [
{"field_name": "extra_data", "render_func": render_as_yaml},
],
"icon_class": "fas fa-database",
},
}


@conditional_login_required
Expand Down

0 comments on commit c187056

Please sign in to comment.