Skip to content

Commit

Permalink
UI enhancements (aboutcode-org#1267)
Browse files Browse the repository at this point in the history
* Render the JSON tab fields as YML by default

Signed-off-by: tdruez <[email protected]>

* Remove unused template

Signed-off-by: tdruez <[email protected]>

* Do not display the "Show all/Hide" button if smaller the max height

Signed-off-by: tdruez <[email protected]>

* Remove the line return in log strings

Signed-off-by: tdruez <[email protected]>

* Upgrade multiple libraries to their latest version

Signed-off-by: tdruez <[email protected]>

---------

Signed-off-by: tdruez <[email protected]>
  • Loading branch information
tdruez authored Jun 17, 2024
1 parent f7b9579 commit ea2c8ce
Show file tree
Hide file tree
Showing 8 changed files with 95 additions and 112 deletions.
91 changes: 54 additions & 37 deletions scancodeio/static/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,50 +60,61 @@ function setupCloseModalButtons() {

// Tabs

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

function activateTab($tabLink) {
const activeLink = document.querySelector('.tabs .is-active');
const activeTabContent = document.querySelector('.tab-content.is-active');
const targetId = $tabLink.dataset.target;
const targetTabContent = document.getElementById(targetId);

activeLink.classList.remove('is-active');
$tabLink.parentNode.classList.add('is-active');
if (activeTabContent) activeTabContent.classList.remove('is-active');
if (targetTabContent) targetTabContent.classList.add('is-active');
function activateTab(tabLink) {
const tabsContainer = tabLink.closest('.tabs');
if (!tabsContainer) return; // Safety check

const tabs = tabsContainer.querySelectorAll('li');
const tabContents = tabsContainer.parentNode.querySelectorAll('.tab-content');

// Deactivate all tabs
tabs.forEach(item => item.classList.remove('is-active'));
// Deactivate all tab contents
tabContents.forEach(content => content.classList.remove('is-active'));

tabLink.parentNode.classList.add('is-active');
const targetId = tabLink.getAttribute('data-target');
const targetContent = tabsContainer.parentNode.querySelector(`#${targetId}`);
if (targetContent) {
targetContent.classList.add('is-active');
}

// Set the active tab in the URL hash. The "tab-" prefix is removed to avoid
// un-wanted scrolling to the related "id" element
// Conditionally update the URL hash
const storeInHash = !tabsContainer.classList.contains('disable-hash-storage');
if (storeInHash) {
document.location.hash = targetId.replace('tab-', '');
}
}

// Activate the related tab using the current URL hash
function activateTabFromHash() {
let tabLink;
function activateTabFromHash() {
const hashValue = document.location.hash.slice(1); // Remove the '#' from the hash
if (!hashValue) return;

if (document.location.hash !== "") {
let tabName = document.location.hash.slice(1);
tabLink = document.querySelector(`a[data-target="tab-${tabName}"]`);
}
else if ($tabLinks.length) {
tabLink = $tabLinks[0];
}
if (tabLink) activateTab(tabLink);
const tabLink = document.querySelector(`a[data-target="tab-${hashValue}"]`);
if (tabLink) {
activateTab(tabLink);
}
}

$tabLinks.forEach(function ($el) {
$el.addEventListener('click', function () {
activateTab($el)
function setupTabs() {
const tabsContainers = document.querySelectorAll('.tabs');

tabsContainers.forEach(tabsContainer => {
const tabLinks = tabsContainer.querySelectorAll('a[data-target]');

tabLinks.forEach(tabLink => {
tabLink.addEventListener('click', (event) => {
event.preventDefault(); // Prevent the default behavior of the anchor tag
activateTab(tabLink);
});
});
});

// Activate the related tab if hash is present in the URL on page loading
activateTabFromHash();
activateTabFromHash();
// Enable tab history navigation (using previous/next browser button for example)
// by detecting URL hash changes.
window.addEventListener("hashchange", () => {activateTabFromHash()});
window.addEventListener("hashchange", activateTabFromHash);
}

// Menu
Expand Down Expand Up @@ -147,12 +158,18 @@ function setupHighlightControls() {
const $highlightShows = getAll(".is-more-show");

$highlightShows.forEach(function ($el) {
$el.addEventListener("click", function () {
let text = $el.querySelector("strong").textContent;
let newText = text === "Show all" ? "Hide" : "Show all";
$el.querySelector("strong").textContent = newText;
$el.parentNode.classList.toggle("is-more-clipped");
});
const parentDiv = $el.parentNode;

if (parentDiv.scrollHeight <= 250) {
$el.style.display = "none";
} else {
$el.addEventListener("click", function () {
let text = $el.querySelector("strong").textContent;
let newText = text === "Show all" ? "Hide" : "Show all";
$el.querySelector("strong").textContent = newText;
$el.parentNode.classList.toggle("is-more-clipped");
});
}
});
}

Expand Down
6 changes: 3 additions & 3 deletions scanpipe/migrations/0031_scancode_toolkit_v32_data_updates.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def compute_package_declared_license_expression_spdx(apps, schema_editor):
).only("declared_license_expression")

object_count = queryset.count()
logger.info(f"\nCompute declared_license_expression_spdx for {object_count:,} packages.")
logger.info(f"Compute declared_license_expression_spdx for {object_count:,} packages.")

chunk_size = 2000
iterator = queryset.iterator(chunk_size=chunk_size)
Expand Down Expand Up @@ -65,7 +65,7 @@ def compute_resource_detected_license_expression(apps, schema_editor):
)

object_count = queryset.count()
logger.info(f"\nCompute detected_license_expression for {object_count:,} resources.")
logger.info(f"Compute detected_license_expression for {object_count:,} resources.")

chunk_size = 2000
iterator = queryset.iterator(chunk_size=chunk_size)
Expand Down Expand Up @@ -168,7 +168,7 @@ def compute_resource_license_detections(apps, schema_editor):
queryset = CodebaseResource.objects.filter(~Q(licenses=[])).only("licenses")

object_count = queryset.count()
logger.info(f"\nCompute license_detections for {object_count:,} resources.")
logger.info(f"Compute license_detections for {object_count:,} resources.")

chunk_size = 2000
iterator = queryset.iterator(chunk_size=chunk_size)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def update_package_datasource_ids(apps, schema_editor):

object_count = queryset.count()
if object_count:
logger.info(f"\nCompute datasource_ids for {object_count:,} packages.")
logger.info(f"Compute datasource_ids for {object_count:,} packages.")

chunk_size = 2000
iterator = queryset.iterator(chunk_size=chunk_size)
Expand Down
2 changes: 1 addition & 1 deletion scanpipe/templates/scanpipe/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@
</style>
{% block extrahead %}{% endblock %}
</head>
<body>
<body class="pb-5">
{% block content %}{% endblock %}
{% include 'scanpipe/modals/search_syntax_modal.html' %}
<script src="{% static 'main.js' %}" crossorigin="anonymous"></script>
Expand Down
4 changes: 2 additions & 2 deletions scanpipe/templates/scanpipe/modals/search_syntax_modal.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
</header>
<div class="modal-card-body p-2 pb-4">
<div class="content">
<div class="tabs is-boxed mb-4">
<div class="tabs disable-hash-storage is-boxed mb-4">
<ul class="m-0">
<li class="is-active">
<a data-target="tab-syntax" >Syntax</a>
<a data-target="tab-syntax">Syntax</a>
</li>
<li>
<a data-target="tab-fields">Fields</a>
Expand Down
34 changes: 0 additions & 34 deletions scanpipe/templates/scanpipe/tabset/tab_detections.html

This file was deleted.

56 changes: 28 additions & 28 deletions scanpipe/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,13 @@ def get_fields_data(self, fields):
return fields_data

def get_field_value(self, field_name, render_func=None):
"""Return the formatted value for the given `field_name` of the object."""
"""
Return the formatted value of the specified `field_name` from the object.
By default, JSON types (list and dict) are rendered as YAML.
If a `render_func` is provided, it will take precedence and be used for
rendering the value.
"""
field_value = getattr(self.object, field_name, None)

if field_value and render_func:
Expand All @@ -315,12 +321,9 @@ def get_field_value(self, field_name, render_func=None):
if isinstance(field_value, Manager):
return list(field_value.all())

list_fields = ["datafile_paths", "datasource_ids"]

if isinstance(field_value, list):
if field_name not in list_fields:
with suppress(TypeError):
field_value = "\n".join(field_value)
if isinstance(field_value, (list, dict)):
with suppress(Exception):
field_value = render_as_yaml(field_value)

return field_value

Expand Down Expand Up @@ -1706,14 +1709,14 @@ class CodebaseResourceDetailsView(
"field_name": "detected_license_expression_spdx",
"label": "Detected license expression (SPDX)",
},
{"field_name": "license_detections", "render_func": render_as_yaml},
{"field_name": "license_clues", "render_func": render_as_yaml},
"license_detections",
"license_clues",
"percentage_of_license_text",
{"field_name": "copyrights", "render_func": render_as_yaml},
{"field_name": "holders", "render_func": render_as_yaml},
{"field_name": "authors", "render_func": render_as_yaml},
{"field_name": "emails", "render_func": render_as_yaml},
{"field_name": "urls", "render_func": render_as_yaml},
"copyrights",
"holders",
"authors",
"emails",
"urls",
],
"icon_class": "fa-solid fa-search",
},
Expand All @@ -1728,9 +1731,7 @@ class CodebaseResourceDetailsView(
"template": "scanpipe/tabset/tab_relations.html",
},
"extra_data": {
"fields": [
{"field_name": "extra_data", "render_func": render_as_yaml},
],
"fields": ["extra_data"],
"verbose_name": "Extra",
"icon_class": "fa-solid fa-plus-square",
},
Expand Down Expand Up @@ -1879,7 +1880,7 @@ class DiscoveredPackageDetailsView(
{"field_name": "sha256", "label": "SHA256"},
{"field_name": "sha512", "label": "SHA512"},
"file_references",
{"field_name": "parties", "render_func": render_as_yaml},
"parties",
"missing_resources",
"modified_resources",
"package_uid",
Expand All @@ -1904,11 +1905,8 @@ class DiscoveredPackageDetailsView(
"copyright",
"holder",
"notice_text",
{"field_name": "license_detections", "render_func": render_as_yaml},
{
"field_name": "other_license_detections",
"render_func": render_as_yaml,
},
"license_detections",
"other_license_detections",
],
"icon_class": "fa-solid fa-file-contract",
},
Expand All @@ -1923,14 +1921,14 @@ class DiscoveredPackageDetailsView(
"template": "scanpipe/tabset/tab_dependencies.html",
},
"vulnerabilities": {
"fields": ["affected_by_vulnerabilities"],
"fields": [
{"field_name": "affected_by_vulnerabilities", "render_func": list},
],
"icon_class": "fa-solid fa-bug",
"template": "scanpipe/tabset/tab_vulnerabilities.html",
},
"extra_data": {
"fields": [
{"field_name": "extra_data", "render_func": render_as_yaml},
],
"fields": ["extra_data"],
"verbose_name": "Extra",
"icon_class": "fa-solid fa-plus-square",
},
Expand Down Expand Up @@ -2052,7 +2050,9 @@ class DiscoveredDependencyDetailsView(
"icon_class": "fa-solid fa-info-circle",
},
"vulnerabilities": {
"fields": ["affected_by_vulnerabilities"],
"fields": [
{"field_name": "affected_by_vulnerabilities", "render_func": list},
],
"icon_class": "fa-solid fa-bug",
"template": "scanpipe/tabset/tab_vulnerabilities.html",
},
Expand Down
12 changes: 6 additions & 6 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ install_requires =
# Django related
Django==5.0.6
django-environ==0.11.2
django-crispy-forms==2.1
django-crispy-forms==2.2
crispy-bootstrap3==2024.1
django-filter==24.2
djangorestframework==3.15.1
Expand All @@ -66,7 +66,7 @@ install_requires =
# Task queue
rq==1.16.2
django-rq==2.10.2
redis==5.0.5
redis==5.0.6
# WSGI server
gunicorn==22.0.0
# Docker
Expand All @@ -85,13 +85,13 @@ install_requires =
aboutcode-toolkit==10.1.0
# Utilities
XlsxWriter==3.2.0
openpyxl==3.1.3
openpyxl==3.1.4
requests==2.32.3
gitpython==3.1.43
# Profiling
pyinstrument==4.6.2
# CycloneDX
cyclonedx-python-lib==7.4.0
cyclonedx-python-lib==7.4.1
jsonschema==4.22.0
# Font Awesome
fontawesomefree==6.5.1
Expand All @@ -108,13 +108,13 @@ install_requires =
[options.extras_require]
dev =
# Validation
flake8==7.0.0
flake8==7.1.0
black==24.4.2
isort==5.13.2
doc8==1.1.1
pydocstyle==6.3.0
# Security analyzer
bandit==1.7.8
bandit==1.7.9
# Debug
django-debug-toolbar==4.4.2
# Documentation
Expand Down

0 comments on commit ea2c8ce

Please sign in to comment.