Skip to content

Commit ea603a1

Browse files
Merge pull request Ericsson#4953 from xb058t/file-tree-order
Add sortable column headers to file tree view
2 parents d3b7b63 + 2fa25c6 commit ea603a1

1 file changed

Lines changed: 171 additions & 11 deletions

File tree

web/server/vue-cli/src/views/Reports.vue

Lines changed: 171 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -199,38 +199,140 @@
199199
<div v-else class="tree-view-container">
200200
<div class="tree-header">
201201
<span class="tree-header-name">Name</span>
202-
<span class="tree-header-cell">All</span>
203-
<span class="tree-header-cell">
202+
<span
203+
class="tree-header-cell sortable"
204+
@click="toggleTreeSort('all')"
205+
>
206+
All
207+
<v-icon
208+
v-if="treeSortKey === 'all'"
209+
size="12"
210+
class="sort-icon"
211+
>
212+
{{ treeSortOrder === 'desc' ? 'mdi-arrow-down' : 'mdi-arrow-up' }}
213+
</v-icon>
214+
</span>
215+
<span
216+
class="tree-header-cell sortable"
217+
@click="toggleTreeSort('style')"
218+
>
204219
<severity-icon :status="Severity.STYLE" :size="14" />
220+
<v-icon
221+
v-if="treeSortKey === 'style'"
222+
size="12"
223+
class="sort-icon"
224+
>
225+
{{ treeSortOrder === 'desc' ? 'mdi-arrow-down' : 'mdi-arrow-up' }}
226+
</v-icon>
205227
</span>
206-
<span class="tree-header-cell">
228+
<span
229+
class="tree-header-cell sortable"
230+
@click="toggleTreeSort('low')"
231+
>
207232
<severity-icon :status="Severity.LOW" :size="14" />
233+
<v-icon
234+
v-if="treeSortKey === 'low'"
235+
size="12"
236+
class="sort-icon"
237+
>
238+
{{ treeSortOrder === 'desc' ? 'mdi-arrow-down' : 'mdi-arrow-up' }}
239+
</v-icon>
208240
</span>
209-
<span class="tree-header-cell">
241+
<span
242+
class="tree-header-cell sortable"
243+
@click="toggleTreeSort('medium')"
244+
>
210245
<severity-icon :status="Severity.MEDIUM" :size="14" />
246+
<v-icon
247+
v-if="treeSortKey === 'medium'"
248+
size="12"
249+
class="sort-icon"
250+
>
251+
{{ treeSortOrder === 'desc' ? 'mdi-arrow-down' : 'mdi-arrow-up' }}
252+
</v-icon>
211253
</span>
212-
<span class="tree-header-cell">
254+
<span
255+
class="tree-header-cell sortable"
256+
@click="toggleTreeSort('high')"
257+
>
213258
<severity-icon :status="Severity.HIGH" :size="14" />
259+
<v-icon
260+
v-if="treeSortKey === 'high'"
261+
size="12"
262+
class="sort-icon"
263+
>
264+
{{ treeSortOrder === 'desc' ? 'mdi-arrow-down' : 'mdi-arrow-up' }}
265+
</v-icon>
214266
</span>
215-
<span class="tree-header-cell">
267+
<span
268+
class="tree-header-cell sortable"
269+
@click="toggleTreeSort('critical')"
270+
>
216271
<severity-icon :status="Severity.CRITICAL" :size="14" />
272+
<v-icon
273+
v-if="treeSortKey === 'critical'"
274+
size="12"
275+
class="sort-icon"
276+
>
277+
{{ treeSortOrder === 'desc' ? 'mdi-arrow-down' : 'mdi-arrow-up' }}
278+
</v-icon>
217279
</span>
218-
<span class="tree-header-cell">
280+
<span
281+
class="tree-header-cell sortable"
282+
@click="toggleTreeSort('unreviewed')"
283+
>
219284
<review-status-icon :status="0" :size="14" />
285+
<v-icon
286+
v-if="treeSortKey === 'unreviewed'"
287+
size="12"
288+
class="sort-icon"
289+
>
290+
{{ treeSortOrder === 'desc' ? 'mdi-arrow-down' : 'mdi-arrow-up' }}
291+
</v-icon>
220292
</span>
221-
<span class="tree-header-cell">
293+
<span
294+
class="tree-header-cell sortable"
295+
@click="toggleTreeSort('confirmed')"
296+
>
222297
<review-status-icon :status="1" :size="14" />
298+
<v-icon
299+
v-if="treeSortKey === 'confirmed'"
300+
size="12"
301+
class="sort-icon"
302+
>
303+
{{ treeSortOrder === 'desc' ? 'mdi-arrow-down' : 'mdi-arrow-up' }}
304+
</v-icon>
223305
</span>
224-
<span class="tree-header-cell">
306+
<span
307+
class="tree-header-cell sortable"
308+
@click="toggleTreeSort('false_positive')"
309+
>
225310
<review-status-icon :status="2" :size="14" />
311+
<v-icon
312+
v-if="treeSortKey === 'false_positive'"
313+
size="12"
314+
class="sort-icon"
315+
>
316+
{{ treeSortOrder === 'desc' ? 'mdi-arrow-down' : 'mdi-arrow-up' }}
317+
</v-icon>
226318
</span>
227-
<span class="tree-header-cell">
319+
<span
320+
class="tree-header-cell sortable"
321+
@click="toggleTreeSort('intentional')"
322+
>
228323
<review-status-icon :status="3" :size="14" />
324+
<v-icon
325+
v-if="treeSortKey === 'intentional'"
326+
size="12"
327+
class="sort-icon"
328+
>
329+
{{ treeSortOrder === 'desc' ? 'mdi-arrow-down' : 'mdi-arrow-up' }}
330+
</v-icon>
229331
</span>
230332
</div>
231333
<v-treeview
232334
v-model:opened="openedTreeItems"
233-
:items="treeItems"
335+
:items="sortedTreeItems"
234336
item-value="fullPath"
235337
open-on-click
236338
density="compact"
@@ -426,6 +528,8 @@ const openedTreeItems = ref([]);
426528
const allReportsFileCounts = ref({});
427529
const fileSeverities = ref({});
428530
const treeItems = ref([]);
531+
const treeSortKey = ref(null);
532+
const treeSortOrder = ref(null);
429533
430534
const runIds = computed(function() {
431535
return store.getters[`${namespace}/getRunIds`];
@@ -500,6 +604,37 @@ const formattedReports = computed(function() {
500604
});
501605
});
502606
607+
function getTreeStatValue(item, statKey) {
608+
return statKey === "all" ? (item.findings || 0) : (item.stats[statKey] || 0);
609+
}
610+
611+
function sortTreeNodes(nodes) {
612+
if (!nodes) return [];
613+
614+
const _sorted = nodes.map(node => ({ ...node }));
615+
_sorted.forEach(node => {
616+
if (node.children && node.children.length > 0) {
617+
node.children = sortTreeNodes(node.children);
618+
}
619+
});
620+
621+
if (treeSortKey.value && treeSortOrder.value) {
622+
_sorted.sort((a, b) => {
623+
const _aVal = getTreeStatValue(a, treeSortKey.value);
624+
const _bVal = getTreeStatValue(b, treeSortKey.value);
625+
return treeSortOrder.value === "desc"
626+
? _bVal - _aVal
627+
: _aVal - _bVal;
628+
});
629+
}
630+
631+
return _sorted;
632+
}
633+
634+
const sortedTreeItems = computed(function() {
635+
return sortTreeNodes(treeItems.value);
636+
});
637+
503638
watch(
504639
[ page, itemsPerPage, sortBy ],
505640
() => {
@@ -540,6 +675,18 @@ function onTreeItemClick(item) {
540675
viewMode.value = "table";
541676
}
542677
678+
function toggleTreeSort(statKey) {
679+
if (treeSortKey.value !== statKey) {
680+
treeSortKey.value = statKey;
681+
treeSortOrder.value = "desc";
682+
} else if (treeSortOrder.value === "desc") {
683+
treeSortOrder.value = "asc";
684+
} else {
685+
treeSortKey.value = null;
686+
treeSortOrder.value = null;
687+
}
688+
}
689+
543690
function i64ToNum(val) {
544691
if (val == null) return 0;
545692
if (typeof val === "number") return val;
@@ -867,6 +1014,19 @@ body {
8671014
width: 50px;
8681015
text-align: center;
8691016
flex-shrink: 0;
1017+
1018+
&.sortable {
1019+
cursor: pointer;
1020+
user-select: none;
1021+
1022+
&:hover {
1023+
color: rgb(var(--v-theme-primary));
1024+
}
1025+
}
1026+
1027+
.sort-icon {
1028+
vertical-align: middle;
1029+
}
8701030
}
8711031
8721032
.tree-row {

0 commit comments

Comments
 (0)