Skip to content

Commit db2b344

Browse files
committed
feat(ui): add template for weakness curation
Signed-off-by: Keshav Priyadarshi <git@keshav.space>
1 parent 7ef79cf commit db2b344

4 files changed

Lines changed: 601 additions & 10 deletions

File tree

vulnerabilities/templates/advisory_todos.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ <h1>Advisory To-Dos</h1>
127127
<a href="{% url 'todo-detail' todo_id=todo.todo_id %}" class="has-text-info">
128128
{% elif todo.issue_type == "CONFLICTING_SEVERITY_SCORES" %}
129129
<a href="{% url 'todo-severity-detail' todo_id=todo.todo_id %}" class="has-text-info">
130+
{% elif todo.issue_type == "CONFLICTING_WEAKNESSES" %}
131+
<a href="{% url 'todo-weakness-detail' todo_id=todo.todo_id %}" class="has-text-info">
130132
{% endif %}
131133
<div class="columns px-1 is-vcentered">
132134
<div class="column has-text-left" style="flex: 0 0 20%;">
Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
{% extends "base.html" %}
2+
{% load static %}
3+
{% load utils %}
4+
5+
{% block extrahead %}
6+
<style>
7+
.state-applicable {
8+
background-color: #f14668 !important;
9+
color: #fff !important;
10+
}
11+
12+
.state-not-applicable {
13+
background-color: #48c78e !important;
14+
color: #fff !important;
15+
}
16+
17+
.state-empty {
18+
background-color: #ffdd57 !important;
19+
color: #000 !important;
20+
box-shadow: inset 0 0 0 1px #dbdbdb;
21+
}
22+
23+
.table {
24+
table-layout: fixed !important;
25+
width: 100% !important;
26+
}
27+
28+
.table th {
29+
border-width: 0 1px 1px 1px !important;
30+
border-color: #dbdbdb !important;
31+
background-color: #fff !important;
32+
}
33+
34+
#table-header th {
35+
height: 140px;
36+
vertical-align: top !important;
37+
padding: 0.75rem 0.5rem !important;
38+
}
39+
40+
#table-header th>div {
41+
display: inline-flex !important;
42+
flex-direction: column !important;
43+
justify-content: space-between !important;
44+
height: 100% !important;
45+
width: 100%;
46+
}
47+
48+
#table-header th:first-child {
49+
width: 150px !important;
50+
}
51+
52+
#table-header th:nth-child(2) {
53+
width: 150px !important;
54+
}
55+
56+
#table-header th:nth-child(n+3) {
57+
width: 120px !important;
58+
}
59+
60+
.curation-cell {
61+
cursor: pointer;
62+
text-align: center !important;
63+
user-select: none;
64+
transition: background-color 0.1s ease;
65+
border: 1px solid #dbdbdb !important;
66+
vertical-align: middle !important;
67+
}
68+
69+
.curation-cell:hover {
70+
filter: brightness(0.95);
71+
box-shadow: inset 0 0 0 1px #3273dc;
72+
}
73+
74+
.advisory-cell {
75+
cursor: not-allowed;
76+
word-break: break-all;
77+
vertical-align: middle !important;
78+
}
79+
80+
.folded-row-marker,
81+
.range-row-marker {
82+
cursor: pointer;
83+
text-align: center;
84+
color: #4a4a4a;
85+
font-weight: 600;
86+
background-color: #f5f5f5;
87+
}
88+
89+
.folded-row-marker.is-expanded .icon {
90+
transform: rotate(180deg);
91+
}
92+
93+
.range-data-cell {
94+
background-color: #fafafa;
95+
padding: 6px !important;
96+
vertical-align: top !important;
97+
border: 1px solid #dbdbdb !important;
98+
99+
white-space: normal !important;
100+
word-break: break-all !important;
101+
overflow-wrap: break-word !important;
102+
}
103+
104+
#summaries-container p strong {
105+
display: block;
106+
word-break: break-all;
107+
overflow-wrap: break-word;
108+
line-height: 1.3;
109+
margin-bottom: 4px;
110+
}
111+
112+
.summary-text {
113+
line-height: 1.4;
114+
white-space: pre-wrap;
115+
word-break: break-word;
116+
}
117+
118+
div.summary-text a:link,
119+
div.summary-text a {
120+
color: #3273dc !important;
121+
}
122+
123+
div.summary-text a:visited {
124+
color: #8a4de8 !important;
125+
}
126+
127+
div.summary-text a:hover {
128+
color: #0a0a0a !important;
129+
}
130+
131+
.advisory-wrapper {
132+
width: 100%;
133+
word-break: break-all;
134+
white-space: normal;
135+
}
136+
137+
.advisory-link {
138+
display: inline-flex;
139+
align-items: center;
140+
gap: 4px;
141+
text-align: left;
142+
text-decoration: underline;
143+
white-space: normal;
144+
flex-wrap: wrap;
145+
}
146+
147+
.truncate-conflict-summary {
148+
display: -webkit-box;
149+
-webkit-line-clamp: 2;
150+
-webkit-box-orient: vertical;
151+
overflow: hidden;
152+
}
153+
154+
.table-container {
155+
overflow-x: auto;
156+
max-height: 800px;
157+
border: 1px solid #dbdbdb;
158+
border-radius: 6px;
159+
}
160+
161+
.has-tooltip-top::before {
162+
left: 0 !important;
163+
transform: translateY(-4.3rem) !important;
164+
}
165+
166+
</style>
167+
{% endblock %}
168+
169+
{% block content %}
170+
<section class="section my-0 pt-3 px-0 mx-0">
171+
<div class="container is-fluid">
172+
<div class="columns is-vcentered mb-5">
173+
<div class="column">
174+
<h1 class="title is-3">Advisory Weakness Curation</h1>
175+
<h2 class="subtitle is-5 has-text-grey">{{ vulnerability_id }}</h2>
176+
</div>
177+
178+
<div class="column is-narrow">
179+
<div class="box p-4 has-background-white shadow-soft" style="min-width: 260px; border-radius: 5px;">
180+
<div class="is-flex is-justify-content-space-between is-align-items-center mb-2">
181+
<span class="is-size-6 has-text-grey-dark uppercase has-text-weight-bold mr-2">
182+
Progress
183+
</span>
184+
<span class="tag is-info is-light has-text-weight-bold" id="progress-text">0 / 0</span>
185+
</div>
186+
<progress class="progress is-info is-small mb-0" id="progress" value="0" max="100"></progress>
187+
</div>
188+
</div>
189+
190+
</div>
191+
192+
<div class="columns">
193+
<div class="column is-3">
194+
<h3 class="title is-5">Advisory Summaries</h3>
195+
<div id="summaries-container" style="max-height: 950px; overflow-y: auto;">
196+
{% for avid, text in advisory_summaries.items %}
197+
<div class="notification is-info is-light p-3 mb-3">
198+
<p><strong>{{ avid }}</strong></p>
199+
<div class="text summary-text is-2">{{ text|normalize_links|urlize }}</div>
200+
</div>
201+
{% empty %}
202+
<div class="notification is-light p-3 mb-3 has-text-grey">
203+
No summaries available.
204+
</div>
205+
{% endfor %}
206+
</div>
207+
</div>
208+
209+
<div class="column is-9">
210+
<div class="box">
211+
<div class="mb-4">
212+
<h4 class="title is-4 mb-1" id="current-purl"></h4>
213+
<p class="text is-5" id="conflict-reason"></p>
214+
<a id="toggle-conflict" class="is-link is-5" style="display:none;">Show more</a>
215+
</div>
216+
217+
<div class="table-container">
218+
<table class="table is-bordered is-narrow is-fullwidth is-hoverable">
219+
<thead style="position: sticky; top: 0; background: white; z-index: 10;">
220+
<tr id="table-header">
221+
222+
</tr>
223+
</thead>
224+
<tbody id="curation-body">
225+
226+
</tbody>
227+
</table>
228+
</div>
229+
230+
<div class="level mt-5">
231+
<div class="level-left">
232+
<button class="button is-light" id="prev-btn" onclick="app.navigate(-1)">
233+
<span class="icon"><i class="fa fa-chevron-left"></i></span>
234+
<span>Previous Item</span>
235+
</button>
236+
</div>
237+
<div class="level-right">
238+
<button class="button is-info" id="next-btn" onclick="app.navigate(1)">
239+
<span>Next Item</span>
240+
<span class="icon"><i class="fa fa-chevron-right"></i></span>
241+
</button>
242+
<button class="button is-info is-hidden" id="finish-btn" disabled>
243+
<span class="icon"><i class="fa fa-check"></i></span>
244+
<span>Submit</span>
245+
</button>
246+
</div>
247+
</div>
248+
</div>
249+
</div>
250+
</div>
251+
</div>
252+
</section>
253+
{% endblock %}
254+
255+
256+
{% block scripts %}
257+
<script>
258+
const baseAdvisoryUrl = "{% url 'advisory_details' 0 %}";
259+
const curationItems = {{ curation_items|safe }};
260+
</script>
261+
<script src="{% static 'js/weakness_curation.js' %}"></script>
262+
{% endblock %}

vulnerablecode/static/js/package_curation.js

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ const app = {
1616

1717
renderPackageCuration() {
1818
const item = curationItems[this.currentIndex];
19-
const versions = item.all_versions || item.all_version;
19+
const versions = item.all_versions;
2020

2121
const total = curationItems.length;
2222
const progPercentage = ((this.currentIndex + 1) / total) * 100;
@@ -222,7 +222,7 @@ const app = {
222222

223223
resetCurrentCuration() {
224224
const item = curationItems[this.currentIndex];
225-
const versions = item.all_versions || item.all_version;
225+
const versions = item.all_versions;
226226
versions.forEach(v => {
227227
if (item.partial_curation.affected.includes(v)) {
228228
this.userStates[this.currentIndex][v] = 'affected';
@@ -257,13 +257,12 @@ const app = {
257257

258258
if (isExpanded && advGroup.secondaries) {
259259
advGroup.secondaries.forEach(sec => {
260-
const secAffected = sec.affected || advGroup.affected;
261-
const secFixing = sec.fixing || advGroup.fixing;
260+
const secAffected = advGroup.affected;
261+
const secFixing = advGroup.fixing;
262262

263263
const secState = secAffected.includes(v) ? 'affected' : (secFixing.includes(v) ? 'fixed' : 'unaffected');
264264
const secTd = document.createElement('td');
265265
secTd.className = `state-${secState} has-text-centered advisory-cell`;
266-
secTd.style.borderLeft = "1px dashed #dbdbdb";
267266
secTd.innerText = secState.toUpperCase();
268267
tr.appendChild(secTd);
269268
});
@@ -314,7 +313,7 @@ const app = {
314313
}
315314
}
316315
const item = curationItems[this.currentIndex];
317-
const versions = item.all_versions || item.all_version;
316+
const versions = item.all_versions;
318317
this.renderBody(item, versions);
319318
},
320319

@@ -326,7 +325,7 @@ const app = {
326325
this.expandedFolds.add(colKey);
327326
}
328327
const item = curationItems[this.currentIndex];
329-
const versions = item.all_versions || item.all_version;
328+
const versions = item.all_versions;
330329

331330
this.renderHeader(item);
332331
this.renderBody(item, versions);
@@ -335,7 +334,7 @@ const app = {
335334
toggleRanges() {
336335
this.showRanges = !this.showRanges;
337336
const item = curationItems[this.currentIndex];
338-
const versions = item.all_versions || item.all_version;
337+
const versions = item.all_versions;
339338
this.renderBody(item, versions);
340339
},
341340

@@ -344,14 +343,14 @@ const app = {
344343
const current = this.userStates[this.currentIndex][v];
345344
this.userStates[this.currentIndex][v] = seq[(seq.indexOf(current) + 1) % 3];
346345
const item = curationItems[this.currentIndex];
347-
const versions = item.all_versions || item.all_version;
346+
const versions = item.all_versions;
348347
this.renderBody(item, versions);
349348
},
350349

351350
pickAdvisory(advIdx, type, secondaryIdx) {
352351
const item = curationItems[this.currentIndex];
353352
const advGroup = item.advisories[advIdx];
354-
const versions = item.all_versions || item.all_version;
353+
const versions = item.all_versions;
355354

356355
versions.forEach(v => {
357356
if (advGroup.affected.includes(v)) this.userStates[this.currentIndex][v] = 'affected';

0 commit comments

Comments
 (0)