Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
f4186d4
add drill down links to the main compliance dashboard
tdruez May 26, 2026
b4c841c
add bottom margin
tdruez May 27, 2026
14ba385
fix missing quote
tdruez May 27, 2026
d6268f1
add new licenses tab to product details
tdruez May 27, 2026
463c806
adjust CSS
tdruez May 27, 2026
3edb389
add link to the badge to the licenses tab
tdruez May 27, 2026
1d46597
improve and refine the ProductTabLicensesView
tdruez May 27, 2026
cd4cf38
merge license and notice to a single Terms tab
tdruez May 27, 2026
badd2af
regroup history and changes in the imports tab
tdruez May 27, 2026
8e93e78
modernize the import table in tab
tdruez May 27, 2026
8949dd5
merge the requests in the import and history tab
tdruez May 27, 2026
e50182d
complete the merge into a single grouped Activity tab
tdruez May 27, 2026
64eefa2
fix htmx wrapping and js issues
tdruez May 27, 2026
5f5f67b
fix the modal js error
tdruez May 27, 2026
3bba24b
add summary and navigation button for the activity tab
tdruez May 28, 2026
1f122cd
extract the left/right key navigation to main js file
tdruez May 28, 2026
9446007
add link in compliance tab to licenses tab
tdruez May 28, 2026
4091709
fix the text wrapping of the license expression in licenses tab
tdruez May 28, 2026
ba28173
fix vulnerability link to bypass threshold
tdruez May 28, 2026
1d8efcd
refine the ProductTabLicensesView for performances
tdruez May 28, 2026
45f4d14
add link to clear the search and filters
tdruez May 28, 2026
3b2a29a
improve rendering of the licenses tab
tdruez May 28, 2026
bda0220
improve rendering of the licenses tab
tdruez May 28, 2026
bc5fada
improve rendering of the summary
tdruez May 28, 2026
2a10897
add drill-down links from the "Compliance watchlist" card
tdruez May 28, 2026
a48a7ec
refine CSS rendering
tdruez May 29, 2026
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
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
{% include 'component_catalog/includes/vulnerability_icon_link.html' with url=instance.get_absolute_url count=relation.vulnerability_count %}
{% endif %}
{% if relation.package_id and relation.package.declared_dependencies.all %}
<a class="btn badge text-bg-primary rounded-pill ms-1"
<a class="btn badge bg-primary-subtle text-primary-emphasis rounded-pill ms-1"
href="{{ product.get_absolute_url }}?dependencies-for_package__uuid={{ relation.package.uuid }}#dependencies" data-bs-toggle="tooltip" title="Dependencies" aria-label="Dependencies">
{{ relation.package.declared_dependencies.all|length }}<i class="fa-solid fa-share-nodes ms-1"></i>
</a>
Expand Down
20 changes: 19 additions & 1 deletion dejacode/static/css/dejacode_bootstrap.css
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,9 @@ table.text-break thead {
background-color: var(--bs-djc-blue-bg);
height: 54px;
}
.nav {
--bs-nav-link-padding-x: 0.75rem;
}
.navbar-nav .active>.nav-link,
.navbar-nav .show>.nav-link
.navbar-nav .nav-link.active,
Expand Down Expand Up @@ -470,6 +473,11 @@ table.vulnerabilities-table .column-summary {
font-size: 0.75rem;
}

/* -- Licenses tab -- */
#tab_licenses .column-usage_policy {
min-width: 175px;
}

/* -- Package Details -- */
textarea.licenseexpressionwidget {
height: 62px;
Expand Down Expand Up @@ -700,7 +708,17 @@ td.sub-header {
.tab-content .table thead tr th {
font-size: 0.875rem;
}
th a.sort i {width: auto;}
th a.sort i {
width: auto;
}
tr.row-alert-danger > td:first-child {
box-shadow: inset 4px 0 0 var(--bs-danger);
padding-left: 1rem;
}
tr.row-alert-warning > td:first-child {
box-shadow: inset 4px 0 0 var(--bs-warning);
padding-left: 1rem;
}

/* -- Better looks for the popover fake links -- */
.tag_popover,
Expand Down
39 changes: 39 additions & 0 deletions dejacode/static/js/dejacode_main.js
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,43 @@ function setupDismissibleAlerts() {
});
}

function setupScrollToTargets() {
// Scroll to an in-page section when an element with data-scroll-to is clicked.
// The offset accounts for the sticky header via the body's padding-top.
document.addEventListener('click', (event) => {
const trigger = event.target.closest('[data-scroll-to]');
if (!trigger) return;
const target = document.getElementById(trigger.dataset.scrollTo);
if (!target) return;
const offset = parseFloat(getComputedStyle(document.body).paddingTop) || 0;
const top = target.getBoundingClientRect().top + window.scrollY - offset;
window.scrollTo({ top, behavior: 'smooth' });
});
}

function setupPaginationKeys() {
// Arrow key navigation for the page's own pagination. Pagination living inside
// a .tab-content is excluded: arrow keys there belong to the tab's own logic.
// Disabled links render as <span> (no href), so querying <a> skips them.
const isPageLevel = (link) => link && !link.closest('.tab-content');
const previousLink = [...document.querySelectorAll('a.page-link[aria-label="Previous"]')].find(isPageLevel);
const nextLink = [...document.querySelectorAll('a.page-link[aria-label="Next"]')].find(isPageLevel);
if (!previousLink && !nextLink) return;

const anyInputHasFocus = () => document.querySelector('input:focus, textarea:focus') !== null;

document.addEventListener('keydown', (event) => {
if (anyInputHasFocus()) return;
if (event.key === 'ArrowLeft' && previousLink) {
event.preventDefault();
window.location.href = previousLink.href;
} else if (event.key === 'ArrowRight' && nextLink) {
event.preventDefault();
window.location.href = nextLink.href;
}
});
}

document.addEventListener('DOMContentLoaded', () => {
NEXB = {};
NEXB.client_data = JSON.parse(document.getElementById("client_data").textContent);
Expand Down Expand Up @@ -277,4 +314,6 @@ document.addEventListener('DOMContentLoaded', () => {
setupThemeSwitcher();
setupPlatformHints();
setupDismissibleAlerts();
setupScrollToTargets();
setupPaginationKeys();
});
2 changes: 1 addition & 1 deletion dje/templates/dataspace_home.html
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ <h2 class="card-header fw-bold px-2 h6">{{ card.title }}</h2>
{% if forloop.first %}
<ul class="mb-1 ps-3">
{% endif %}
<li>{{ obj }}</li>
<li class="mb-1">{{ obj }}</li>
{% if forloop.last %}
</ul>
{% endif %}
Expand Down
11 changes: 7 additions & 4 deletions dje/templates/hierarchy_base.js.html
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,13 @@
// Draw if the hierarchy tab is active
if (isTabActive(tabId)) jsPlumbHierarchy.setSuspendDrawing(false, true);

document.querySelector('button[data-bs-target="#tab_hierarchy"]').addEventListener('shown.bs.tab', function (e) {
// Second argument instructs jsPlumb to perform a full repaint.
jsPlumbHierarchy.setSuspendDrawing(false, true);
});
const hierarchyTab = document.querySelector('button[data-bs-target="#tab_hierarchy"]');
if (hierarchyTab) {
hierarchyTab.addEventListener('shown.bs.tab', function (e) {
// Second argument instructs jsPlumb to perform a full repaint.
jsPlumbHierarchy.setSuspendDrawing(false, true);
});
}

// Repaint on resizing the browser window if the related tab is active
window.addEventListener('resize', function(){
Expand Down
2 changes: 1 addition & 1 deletion dje/templates/object_details_base.html
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ <h1 class="header-title text-break">
{% endblock %}

<nav role="navigation">
<ul class="nav nav-tabs container px-3" id="details_tab" role="tablist">
<ul class="nav nav-tabs container px-1" id="details_tab" role="tablist">
{% for tab_name, tab_context in tabsets.items %}
<li class="nav-item" role="presentation"{% if tab_context.tooltip %} data-bs-toggle="tooltip" title="{{ tab_context.tooltip }}"{% endif %}>
<button class="nav-link{% if forloop.first %} active{% endif %}" id="tab_{{ tab_name|slugify }}-tab" data-bs-toggle="tab" data-bs-target="#tab_{{ tab_name|slugify }}" type="button" role="tab" aria-controls="tab_{{ tab_name|slugify }}" aria-selected="{% if forloop.first %}true{% else %}false{% endif %}"{% if tab_context.disabled %} disabled="disabled"{% endif %}>
Expand Down
24 changes: 0 additions & 24 deletions dje/templates/object_list_base.html
Original file line number Diff line number Diff line change
Expand Up @@ -96,30 +96,6 @@
$('.h-link').tooltip({placement: 'bottom', title: 'Hierarchy view', container: 'body'});
$('.r-link').tooltip({placement: 'bottom', title: 'Request view', container: 'body'});

/* Left and Right keys navigation */
{% if is_paginated %}
document.addEventListener("keydown", function(e) {
// Do not trigger the navigation if an <input> or <textarea> currently has the focus
var anyInputHasFocus = function() {
return document.querySelector("input:focus, textarea:focus") !== null;
};

{% if page_obj.has_previous %}
if (e.keyCode === 37 && !anyInputHasFocus()) {
e.preventDefault();
window.location.href = window.location.href.replace(/[\?#].*|$/, "?{{ previous_url }}");
}
{% endif %}

{% if page_obj.has_next %}
if (e.keyCode === 39 && !anyInputHasFocus()) {
e.preventDefault();
window.location.href = window.location.href.replace(/[\?#].*|$/, "?{{ next_url }}");
}
{% endif %}
});
{% endif %}

$('select.bootstrap-select-filter')
.selectpicker()
.on('changed.bs.select', function (event) {
Expand Down
2 changes: 2 additions & 0 deletions license_library/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ class LicenseFilterSet(DataspacedFilterSet):
"category",
"license_profile",
"owner",
"usage_policy",
],
empty_label="Relevance",
)
Expand Down Expand Up @@ -98,6 +99,7 @@ class Meta:
"license_profile",
"usage_policy",
"in_spdx_list",
"usage_policy__compliance_alert",
]

def __init__(self, *args, **kwargs):
Expand Down
3 changes: 0 additions & 3 deletions product_portfolio/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -431,9 +431,6 @@ def get_manage_components_url(self):
def get_manage_packages_url(self):
return self.get_url("manage_packages")

def get_license_summary_url(self):
return self.get_url("license_summary")

def get_check_package_version_url(self):
return self.get_url("check_package_version")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,17 +137,17 @@ <h1 class="h3 mb-0">
</td>
<td class="text-end">
{% if product.license_error_count %}
<span class="badge bg-danger-subtle text-danger-emphasis">
<a href="{{ product_url }}?licenses-usage_policy__compliance_alert=error#licenses" class="badge bg-danger-subtle text-danger-emphasis">
{{ product.license_error_count }} {% trans "error" %}{{ product.license_error_count|pluralize }}
</span>
</a>
{% endif %}
{% if product.license_warning_count %}
<span class="badge bg-warning-subtle text-warning-emphasis ms-1">
<a href="{{ product_url }}?licenses-usage_policy__compliance_alert=warning#licenses" class="badge bg-warning-subtle text-warning-emphasis ms-1">
{{ product.license_warning_count }} {% trans "warning" %}{{ product.license_warning_count|pluralize }}
</span>
</a>
{% endif %}
{% if not product.license_error_count and not product.license_warning_count %}
<span class="badge bg-success-subtle text-success-emphasis">{% trans "OK" %}</span>
<a href="{{ product_url }}#licenses" class="badge bg-success-subtle text-success-emphasis">{% trans "OK" %}</a>
{% endif %}
</td>
<td class="text-end">
Expand All @@ -170,16 +170,16 @@ <h1 class="h3 mb-0">
</span>
{% endif %}
{% if product.critical_count %}
<span class="badge bg-danger-subtle text-danger-emphasis">{{ product.critical_count }} {% trans "critical" %}</span>
<a href="{{ product_url }}?vulnerabilities-weighted_risk_score=critical#vulnerabilities" class="badge bg-danger-subtle text-danger-emphasis">{{ product.critical_count }} {% trans "critical" %}</a>
{% endif %}
{% if product.high_count %}
<span class="badge bg-warning-orange-subtle text-warning-orange ms-1">{{ product.high_count }} {% trans "high" %}</span>
<a href="{{ product_url }}?vulnerabilities-weighted_risk_score=high#vulnerabilities" class="badge bg-warning-orange-subtle text-warning-orange ms-1">{{ product.high_count }} {% trans "high" %}</a>
{% endif %}
{% if product.medium_count %}
<span class="badge bg-warning-subtle text-warning-emphasis ms-1">{{ product.medium_count }} {% trans "medium" %}</span>
<a href="{{ product_url }}?vulnerabilities-weighted_risk_score=medium#vulnerabilities" class="badge bg-warning-subtle text-warning-emphasis ms-1">{{ product.medium_count }} {% trans "medium" %}</a>
{% endif %}
{% if product.low_count %}
<span class="badge bg-info-subtle text-info-emphasis ms-1">{{ product.low_count }} {% trans "low" %}</span>
<a href="{{ product_url }}?vulnerabilities-weighted_risk_score=low#vulnerabilities" class="badge bg-info-subtle text-info-emphasis ms-1">{{ product.low_count }} {% trans "low" %}</a>
{% endif %}
{% if not product.vulnerability_count %}
<span class="text-body-tertiary small">{% trans "None" %}</span>
Expand All @@ -202,5 +202,8 @@ <h1 class="h3 mb-0">
<div class="d-flex justify-content-center">
{% include 'pagination/object_list_pagination.html' %}
</div>
<div class="text-center">
<strong>Tip:</strong> You can use <kbd>&larr;</kbd> and <kbd>&rarr;</kbd> keys to navigate.
</div>
{% endif %}
{% endblock %}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{% load i18n %}
{% url product.get_absolute_url as product_url %}
<div class="row g-4 mb-4">
{# License panel #}
<div class="col-lg-6">
Expand Down Expand Up @@ -43,9 +44,9 @@ <h3 class="fs-6 fw-medium mb-0">{% trans "License compliance" %}</h3>
{% if license_issues_count == 0 %}
<span class="badge bg-success-subtle text-success-emphasis">{% trans "OK" %}</span>
{% elif license_error_count > 0 %}
<span class="badge bg-danger-subtle text-danger-emphasis">{% trans "Error" %}</span>
<a href="{{ product_url }}?licenses-usage_policy__compliance_alert=error#licenses" class="badge bg-danger-subtle text-danger-emphasis">{% trans "Error" %}</a>
{% else %}
<span class="badge bg-warning-subtle text-warning-emphasis">{% trans "Warning" %}</span>
<a href="{{ product_url }}?licenses-usage_policy__compliance_alert=warning#licenses" class="badge bg-warning-subtle text-warning-emphasis">{% trans "Warning" %}</a>
{% endif %}
</div>
</div>
Expand Down Expand Up @@ -76,9 +77,9 @@ <h3 class="fs-6 fw-medium mb-0">{% trans "License compliance" %}</h3>
</td>
<td class="text-end">
{% if license.compliance_alert == "error" %}
<span class="badge bg-danger-subtle text-danger-emphasis">{% trans "Error" %}</span>
<a href="{{ product_url }}?licenses-usage_policy__compliance_alert=error#licenses" class="badge bg-danger-subtle text-danger-emphasis">{% trans "Error" %}</a>
{% elif license.compliance_alert == "warning" %}
<span class="badge bg-warning-subtle text-warning-emphasis">{% trans "Warning" %}</span>
<a href="{{ product_url }}?licenses-usage_policy__compliance_alert=warning#licenses" class="badge bg-warning-subtle text-warning-emphasis">{% trans "Warning" %}</a>
{% else %}
<span class="badge bg-success-subtle text-success-emphasis">{% trans "OK" %}</span>
{% endif %}
Expand All @@ -88,10 +89,11 @@ <h3 class="fs-6 fw-medium mb-0">{% trans "License compliance" %}</h3>
</tbody>
</table>
{% if remaining_license_count > 0 %}
<div class=" mt-2 pt-2">
<small class="text-body-tertiary">
+ {{ remaining_license_count }} {% trans "other license" %}{{ remaining_license_count|pluralize }}{% if license_issues_count == 0 %}, {% trans "all within policy" %}{% endif %}
</small>
<div class="mt-2">
<a href="#" class="text-decoration-none small" onclick="event.preventDefault(); new bootstrap.Tab(document.querySelector('#tab_licenses-tab')).show(); window.scrollTo({ top: 0, behavior: 'smooth' });">
View all {{ remaining_license_count }} {% trans "other license" %}{{ remaining_license_count|pluralize }}{% if license_issues_count == 0 %}, {% trans "all within policy" %}{% endif %}
<i class="fas fa-arrow-right ms-1"></i>
</a>
</div>
{% endif %}
</div>
Expand Down Expand Up @@ -204,7 +206,7 @@ <h3 class="fs-6 fw-medium mb-0">{% trans "Security compliance" %}</h3>
{# View all link #}
{% if vulnerabilities|length < vulnerability_count %}
<div class="mt-2">
<a href="#vulnerabilities" class="text-decoration-none small" onclick="new bootstrap.Tab(document.querySelector('#tab_vulnerabilities-tab')).show()">
<a href="{{ product_url }}?vulnerabilities-bypass_risk_threshold=Yes#vulnerabilities" class="text-decoration-none small">
{% trans "View all" %} {{ vulnerability_count }} {% trans "vulnerabilities" %}
<i class="fas fa-arrow-right ms-1"></i>
</a>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,17 @@ <h2 class="card-header fw-bold px-2 h6 d-flex justify-content-between align-item
</h2>
<div class="card-body p-2">
{% for product in compliance_qs %}
{% with product_url=product.get_absolute_url %}
<div>
<a class="fw-semibold" href="{{ product.get_absolute_url }}#compliance">{{ product }}</a>
<div class="row g-0 small">
<div class="col-4 text-body-secondary">License</div>
<div class="col-8">
{% if product.license_error_count %}
<span class="badge bg-danger-subtle text-danger-emphasis">{{ product.license_error_count }} error{{ product.license_error_count|pluralize }}</span>
<a href="{{ product_url }}?licenses-usage_policy__compliance_alert=error#licenses" class="badge bg-danger-subtle text-danger-emphasis">{{ product.license_error_count }} error{{ product.license_error_count|pluralize }}</a>
{% endif %}
{% if product.license_warning_count %}
<span class="badge bg-warning-subtle text-warning-emphasis{% if product.license_error_count %} ms-1{% endif %}">{{ product.license_warning_count }} warning{{ product.license_warning_count|pluralize }}</span>
<a href="{{ product_url }}?licenses-usage_policy__compliance_alert=warning#licenses" class="badge bg-warning-subtle text-warning-emphasis{% if product.license_error_count %} ms-1{% endif %}">{{ product.license_warning_count }} warning{{ product.license_warning_count|pluralize }}</a>
{% endif %}
{% if not product.license_error_count and not product.license_warning_count %}
<span class="badge bg-success-subtle text-success-emphasis">OK</span>
Expand All @@ -30,16 +31,16 @@ <h2 class="card-header fw-bold px-2 h6 d-flex justify-content-between align-item
<div class="col-4 text-body-secondary">Vulnerabilities</div>
<div class="col-8">
{% if product.critical_count %}
<span class="badge bg-danger-subtle text-danger-emphasis">{{ product.critical_count }} critical</span>
<a href="{{ product_url }}?vulnerabilities-weighted_risk_score=critical#vulnerabilities" class="badge bg-danger-subtle text-danger-emphasis">{{ product.critical_count }} critical</a>
{% endif %}
{% if product.high_count %}
<span class="badge bg-warning-orange-subtle text-warning-orange{% if product.critical_count %} ms-1{% endif %}">{{ product.high_count }} high</span>
<a href="{{ product_url }}?vulnerabilities-weighted_risk_score=high#vulnerabilities" class="badge bg-warning-orange-subtle text-warning-orange{% if product.critical_count %} ms-1{% endif %}">{{ product.high_count }} high</a>
{% endif %}
{% if product.medium_count %}
<span class="badge bg-warning-subtle text-warning-emphasis{% if product.critical_count or product.high_count %} ms-1{% endif %}">{{ product.medium_count }} medium</span>
<a href="{{ product_url }}?vulnerabilities-weighted_risk_score=medium#vulnerabilities" class="badge bg-warning-subtle text-warning-emphasis{% if product.critical_count or product.high_count %} ms-1{% endif %}">{{ product.medium_count }} medium</a>
{% endif %}
{% if product.low_count %}
<span class="badge bg-info-subtle text-info-emphasis{% if product.critical_count or product.high_count or product.medium_count %} ms-1{% endif %}">{{ product.low_count }} low</span>
<a href="{{ product_url }}?vulnerabilities-weighted_risk_score=low#vulnerabilities" class="badge bg-info-subtle text-info-emphasis{% if product.critical_count or product.high_count or product.medium_count %} ms-1{% endif %}">{{ product.low_count }} low</a>
{% endif %}
{% if not product.critical_count and not product.high_count and not product.medium_count and not product.low_count %}
<span class="text-body-tertiary">None</span>
Expand All @@ -48,6 +49,7 @@ <h2 class="card-header fw-bold px-2 h6 d-flex justify-content-between align-item
</div>
</div>
{% if not forloop.last %}<hr class="my-2">{% endif %}
{% endwith %}
{% empty %}
<div class="text-center py-4">
<i class="fa-solid fa-circle-check text-success fs-3"></i>
Expand Down
Loading
Loading