github.com/covergates/covergates@v0.2.2-0.20201009050117-42ef8a19fb95/web/src/components/ReportFiles.vue (about) 1 <template> 2 <v-container> 3 <v-sheet> 4 <v-text-field 5 v-model="searchText" 6 append-icon="mdi-magnify" 7 label="Search" 8 single-line 9 outlined 10 dense 11 :rounded="false" 12 color="accent" 13 hide-details 14 ></v-text-field> 15 <v-data-table 16 class="rounded-t" 17 :items="fileInfos" 18 item-key="name" 19 :headers="headers" 20 :header-props="{sortIcon: 'mdi-chevron-up'}" 21 :fixed-header="true" 22 sort-by="coverage" 23 :sort-desc="true" 24 :search="searchText" 25 > 26 <template v-slot:item.name="{ item }"> 27 <span class="file-icon fiv-viv mr-5" :class="[fileIcon(item.name)]"></span> 28 <router-link :append="true" :to="fileLink(item)">{{item.name}}</router-link> 29 </template> 30 </v-data-table> 31 </v-sheet> 32 </v-container> 33 </template> 34 35 <script lang="ts"> 36 import { Component, Mixins } from 'vue-property-decorator'; 37 import { Location } from 'vue-router'; 38 import Vue from '@/vue'; 39 import ReportMixin from '@/mixins/report'; 40 41 type FileInfo = { 42 name: string; 43 coverage: number; 44 hits: number; 45 }; 46 47 @Component 48 export default class ReportFiles extends ((Mixins(ReportMixin) as typeof Vue) && 49 ReportMixin) { 50 /** 51 * Table Headers 52 */ 53 headerClass = 'text-subtitle-1 align-center accent white--text'; 54 headers = [ 55 { 56 text: 'File Path', 57 align: 'start', 58 value: 'name', 59 class: this.headerClass 60 }, 61 { 62 text: 'Hit Lines', 63 value: 'hits', 64 width: '150px', 65 class: this.headerClass 66 }, 67 { 68 text: 'Coverage', 69 value: 'coverage', 70 width: '150px', 71 class: this.headerClass 72 } 73 ]; 74 75 searchText = ''; 76 77 get report(): Report | undefined { 78 return this.$store.state.report.current; 79 } 80 81 get fileInfos(): FileInfo[] { 82 if (!this.report) { 83 return []; 84 } 85 const info = {} as { [key: string]: FileInfo }; 86 if (this.report.files) { 87 for (const file of this.report.files) { 88 info[file] = { 89 name: file, 90 coverage: 0, 91 hits: 0 92 }; 93 } 94 } 95 for (const name in this.$sourceFiles) { 96 const file = this.$sourceFiles[name]; 97 const coverage = Math.round(file.StatementCoverage * 10000) / 100; 98 const hitLine = file.StatementHits.filter(hit => { 99 return hit.Hits > 0; 100 }).length; 101 if (info[file.Name]) { 102 info[file.Name].coverage = coverage; 103 info[file.Name].hits = hitLine; 104 } else { 105 info[file.Name] = { 106 name: file.Name, 107 coverage: coverage, 108 hits: hitLine 109 }; 110 } 111 } 112 return Object.values(info).sort((a, b) => { 113 return a.name > b.name ? 1 : -1; 114 }); 115 } 116 117 fileIcon(name: string): string { 118 const ext = name.split('.').pop(); 119 return `fiv-icon-${ext}`; 120 } 121 122 fileLink(file: FileInfo): Location { 123 return { 124 path: file.name, 125 query: this.$route.query 126 }; 127 } 128 } 129 </script> 130 131 <style lang="scss" scoped> 132 @import '@/assets/styles/variables'; 133 134 ::v-deep table { 135 border-collapse: collapse !important; 136 } 137 138 .file-icon { 139 font-size: 20px; 140 } 141 </style>