Skip to content

Commit 7f8edd4

Browse files
committed
adding tables into tree view
1 parent c9cbee8 commit 7f8edd4

File tree

1 file changed

+262
-73
lines changed

1 file changed

+262
-73
lines changed

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

Lines changed: 262 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -175,27 +175,113 @@
175175
</template>
176176
</v-data-table>
177177

178-
<v-treeview
179-
v-else
180-
:items="formattedDirectoriesForTreeViewFileCounts"
181-
activatable
182-
item-key="fullPath"
183-
open-on-click
184-
@update:active="onTreeFileClick"
185-
>
186-
<template #prepend="{ item, open }">
187-
<v-icon v-if="item.children.length > 0">
188-
{{ open ? 'mdi-folder-open' : 'mdi-folder' }}
189-
</v-icon>
190-
<v-icon v-else>
191-
mdi-file
192-
</v-icon>
193-
194-
<v-chip class="right ml-2">
195-
{{ item.findings }}
196-
</v-chip>
197-
</template>
198-
</v-treeview>
178+
<splitpanes v-else class="default-theme tree-split">
179+
<pane size="30" :style="{ 'min-width': '250px' }">
180+
<v-treeview
181+
:items="treeItems"
182+
item-key="fullPath"
183+
open-on-click
184+
activatable
185+
:return-object="true"
186+
dense
187+
@update:active="onTreeFileClick"
188+
>
189+
<template #prepend="{ item, open }">
190+
<v-icon v-if="item.isDirectory">
191+
{{ open ? 'mdi-folder-open' : 'mdi-folder' }}
192+
</v-icon>
193+
<v-icon v-else>
194+
mdi-file
195+
</v-icon>
196+
197+
<v-chip class="right ml-2" small>
198+
{{ item.findings }}
199+
</v-chip>
200+
</template>
201+
</v-treeview>
202+
</pane>
203+
<pane>
204+
<v-data-table
205+
v-if="treeSelectedFile"
206+
:headers="treeTableHeaders"
207+
:items="formattedTreeReports"
208+
:loading="treeReportsLoading"
209+
loading-text="Loading reports..."
210+
:must-sort="false"
211+
dense
212+
:mobile-breakpoint="1100"
213+
item-key="$id"
214+
>
215+
<template #item.checkedFile="{ item }">
216+
<router-link
217+
:to="{ name: 'report-detail', query: {
218+
...$router.currentRoute.query,
219+
'report-id': item.reportId ? item.reportId : undefined,
220+
'report-hash': item.bugHash,
221+
'report-filepath': item.checkedFile
222+
}}"
223+
class="file-name"
224+
>
225+
Line&nbsp;{{ item.line }}
226+
</router-link>
227+
</template>
228+
229+
<template #item.checkerMsg="{ item }">
230+
<span class="checker-message">
231+
{{ item.checkerMsg }}
232+
</span>
233+
</template>
234+
235+
<template #item.checkerId="{ item }">
236+
<span
237+
class="checker-name primary--text"
238+
@click="openCheckerDocDialog(
239+
item.checkerId, item.analyzerName)"
240+
>
241+
{{ item.checkerId }}
242+
</span>
243+
</template>
244+
245+
<template #item.severity="{ item }">
246+
<severity-icon :status="item.severity" />
247+
</template>
248+
249+
<template #item.bugPathLength="{ item }">
250+
<v-chip :color="getBugPathLenColor(item.bugPathLength)">
251+
{{ item.bugPathLength }}
252+
</v-chip>
253+
</template>
254+
255+
<template #item.reviewData="{ item }">
256+
<review-status-icon
257+
:status="parseInt(item.reviewData.status)"
258+
/>
259+
</template>
260+
261+
<template #item.detectionStatus="{ item }">
262+
<detection-status-icon
263+
:status="parseInt(item.detectionStatus)"
264+
:title="item.$detectionStatusTitle"
265+
/>
266+
</template>
267+
</v-data-table>
268+
269+
<v-container
270+
v-else
271+
class="text-center grey--text"
272+
fill-height
273+
>
274+
<v-row align="center" justify="center">
275+
<v-col>
276+
<v-icon large class="mb-2">
277+
mdi-cursor-default-click
278+
</v-icon>
279+
<div>Select a file from the tree to view its reports</div>
280+
</v-col>
281+
</v-row>
282+
</v-container>
283+
</pane>
284+
</splitpanes>
199285
</pane>
200286
</splitpanes>
201287
</template>
@@ -206,7 +292,14 @@ import { Pane, Splitpanes } from "splitpanes";
206292
import { mapGetters, mapMutations } from "vuex";
207293
208294
import { ccService, handleThriftError } from "@cc-api";
209-
import { Checker, Order, SortMode, SortType } from "@cc/report-server-types";
295+
import {
296+
Checker,
297+
MAX_QUERY_SIZE,
298+
Order,
299+
SortMode,
300+
SortType,
301+
ReportFilter as ThriftReportFilter
302+
} from "@cc/report-server-types";
210303
import { SET_REPORT_FILTER } from "@/store/mutations.type";
211304
212305
import { FillHeight } from "@/directives";
@@ -349,7 +442,11 @@ export default {
349442
initalized: false,
350443
checkerDocDialog: false,
351444
selectedChecker: null,
352-
expanded: []
445+
expanded: [],
446+
treeItems: [],
447+
treeSelectedFile: null,
448+
treeReports: [],
449+
treeReportsLoading: false
353450
};
354451
},
355452
@@ -421,9 +518,121 @@ export default {
421518
});
422519
},
423520
424-
formattedDirectoriesForTreeViewFileCounts() {
521+
treeTableHeaders() {
522+
return [
523+
{
524+
text: "Line",
525+
value: "checkedFile",
526+
sortable: false
527+
},
528+
{
529+
text: "Message",
530+
value: "checkerMsg",
531+
sortable: false
532+
},
533+
{
534+
text: "Checker name",
535+
value: "checkerId",
536+
sortable: false
537+
},
538+
{
539+
text: "Analyzer",
540+
value: "analyzerName",
541+
align: "center",
542+
sortable: false
543+
},
544+
{
545+
text: "Severity",
546+
value: "severity",
547+
sortable: false
548+
},
549+
{
550+
text: "Bug path length",
551+
value: "bugPathLength",
552+
align: "center",
553+
sortable: false
554+
},
555+
{
556+
text: "Latest review status",
557+
value: "reviewData",
558+
align: "center",
559+
sortable: false
560+
},
561+
{
562+
text: "Latest detection status",
563+
value: "detectionStatus",
564+
align: "center",
565+
sortable: false
566+
}
567+
];
568+
},
569+
570+
formattedTreeReports() {
571+
return this.treeReports.map((report, idx) => {
572+
const detectionStatus =
573+
this.detectionStatusFromCodeToString(report.detectionStatus);
574+
const detectedAt = report.detectedAt
575+
? this.$options.filters.prettifyDate(report.detectedAt) : null;
576+
const fixedAt = report.fixedAt
577+
? this.$options.filters.prettifyDate(report.fixedAt) : null;
578+
579+
const detectionStatusTitle = [
580+
`Status: ${detectionStatus}`,
581+
...(detectedAt ? [ `Detected at: ${detectedAt}` ] : []),
582+
...(fixedAt ? [ `Fixed at: ${fixedAt}` ] : [])
583+
].join("\n");
584+
585+
const reportId = report.reportId
586+
? report.reportId.toString() : String(idx);
587+
588+
return {
589+
...report,
590+
"$detectionStatusTitle": detectionStatusTitle,
591+
"$id": reportId + report.bugHash
592+
};
593+
});
594+
},
595+
596+
},
597+
598+
watch: {
599+
pagination: {
600+
handler() {
601+
this.updateUrl();
602+
if (this.initalized) {
603+
this.fetchReports();
604+
}
605+
},
606+
deep: true
607+
},
608+
formattedReports: {
609+
handler() {
610+
this.hasTimeStamp =
611+
this.formattedReports.some(report => report.timestamp);
612+
613+
this.hasTestCase =
614+
this.formattedReports.some(report => report.testcase);
615+
616+
this.hasChronologicalOrder =
617+
this.formattedReports.some(report => report["chronological_order"]);
618+
}
619+
},
620+
allReportsFileCounts: {
621+
handler() {
622+
this.buildTreeItems();
623+
},
624+
deep: true
625+
}
626+
},
627+
628+
methods: {
629+
...mapMutations(namespace, {
630+
setReportFilter: SET_REPORT_FILTER
631+
}),
632+
633+
buildTreeItems() {
425634
const items = [];
426-
635+
427636
Object.entries(
428637
this.allReportsFileCounts || {}
429638
).forEach(([ filePath, count ]) => {
@@ -443,7 +652,8 @@ export default {
443652
name: part,
444653
fullPath: currentPath,
445654
children: [],
446-
findings: 0
655+
findings: 0,
656+
isDirectory: true
447657
};
448658
currentLevel.push(existingPart);
449659
}
@@ -482,61 +692,33 @@ export default {
482692
}
483693
}
484694
items.forEach(countFindings);
485-
return items;
486-
},
487-
488-
489-
},
490-
491-
watch: {
492-
pagination: {
493-
handler() {
494-
this.updateUrl();
495-
if (this.initalized) {
496-
this.fetchReports();
497-
}
498-
},
499-
deep: true
695+
this.treeItems = items;
500696
},
501-
formattedReports: {
502-
handler() {
503-
this.hasTimeStamp =
504-
this.formattedReports.some(report => report.timestamp);
505-
506-
this.hasTestCase =
507-
this.formattedReports.some(report => report.testcase);
508697
509-
this.hasChronologicalOrder =
510-
this.formattedReports.some(report => report["chronological_order"]);
698+
onTreeFileClick(activeItems) {
699+
if (!activeItems || activeItems.length === 0) {
700+
this.treeSelectedFile = null;
701+
this.treeReports = [];
702+
return;
511703
}
512-
}
513-
},
514704
515-
methods: {
516-
...mapMutations(namespace, {
517-
setReportFilter: SET_REPORT_FILTER
518-
}),
705+
const item = activeItems[0];
706+
if (!item || item.isDirectory) return;
519707
520-
onTreeFileClick(activeItems) {
521-
// activeItems is an array of item-key values (fullPath)
522-
if (!activeItems || activeItems.length === 0) return;
708+
this.treeSelectedFile = item.fullPath;
709+
this.treeReportsLoading = true;
523710
524-
const filePath = activeItems[0];
525-
if (!filePath) return;
711+
const filter = new ThriftReportFilter(this.reportFilter);
712+
filter.filepath = [ item.fullPath ];
526713
527-
// Find the FilePathFilter instance inside ReportFilter
528-
// and call its setSelectedItems to select this file.
529-
const filters = this.$refs.reportFilter.$refs.filters;
530-
const filePathFilter = filters.find(
531-
f => f.id === "filepath"
714+
ccService.getClient().getRunResults(
715+
this.runIds, MAX_QUERY_SIZE, 0, [],
716+
filter, this.cmpData, false,
717+
handleThriftError(reports => {
718+
this.treeReports = reports;
719+
this.treeReportsLoading = false;
720+
})
532721
);
533-
if (filePathFilter) {
534-
filePathFilter.setSelectedItems([
535-
{ id: filePath, title: filePath, count: "N/A" }
536-
]);
537-
}
538-
539-
this.viewMode = "table";
540722
},
541723
542724
itemExpanded(expandedItem) {
@@ -547,6 +729,7 @@ export default {
547729
expandedItem.item.sameReports = sameReports;
548730
});
549731
},
732+
550733
loadFileCounts() {
551734
ccService.getClient().getFileCounts(
552735
this.runIds, this.reportFilter,
@@ -698,4 +881,10 @@ export default {
698881
cursor: pointer;
699882
}
700883
}
884+
885+
.tree-split {
886+
.splitpanes__pane {
887+
background-color: inherit;
888+
}
889+
}
701890
</style>

0 commit comments

Comments
 (0)