1
+ <template >
2
+ <div >
3
+ <!-- API Error Message -->
4
+ <div v-if =" apiError" class =" error-message" v-html =" apiError" ></div >
5
+ <div v-if =" !apiError" >
6
+ <div class =" tiles-container" >
7
+ <!-- Acceptance Rate Tile -->
8
+ <v-card elevation =" 4" color =" white" variant =" elevated" class =" mx-auto my-3" style =" width : 300px ; height : 175px ;" >
9
+ <v-card-item >
10
+ <div >
11
+ <div class =" text-overline mb-1" style =" visibility : hidden ;" >filler</div >
12
+ <div class =" text-h6 mb-1" >Number of languages</div >
13
+ <div class =" text-caption" >
14
+ Over the last 28 days
15
+ </div >
16
+ <p >{{ numberOfLanguages }}</p >
17
+ </div >
18
+ </v-card-item >
19
+ </v-card >
20
+
21
+ </div >
22
+
23
+ <v-main class =" p-1" style =" min-height : 300px ;" >
24
+
25
+ <v-container style =" min-height : 300px ;" class =" px-4 elevation-2" >
26
+ <v-card >
27
+ <v-card-item class =" d-flex justify-center align-center" >
28
+ <div class =" text-overline mb-1" style =" visibility : hidden ;" >filler</div >
29
+ <div class =" text-h6 mb-1" >Top 5 languages by accepted prompts</div >
30
+ <div style =" width : 300px ; height : 300px ;" >
31
+ <Pie :data =" languagesChartDataTop5" :options =" chartOptions" />
32
+ </div >
33
+ </v-card-item >
34
+ </v-card >
35
+
36
+ <br >
37
+ <h2 >Languages Breakdown | Sorted by Accepted Lines of Code</h2 >
38
+ <br >
39
+
40
+ <v-data-table :headers =" headers" :items =" Array.from(languages)" class =" elevation-2" >
41
+ <template v-slot :item =" {item } " >
42
+ <tr >
43
+ <td >{{ item[0] }}</td >
44
+ <td >{{ item[1].acceptedPrompts }}</td >
45
+ <td >{{ item[1].acceptedLinesOfCode }}</td >
46
+ <td v-if =" item[1].acceptanceRate !== undefined" >{{ item[1].acceptanceRate.toFixed(2) }}%</td >
47
+ </tr >
48
+ </template >
49
+ </v-data-table >
50
+ </v-container >
51
+ </v-main >
52
+ </div >
53
+ </div >
54
+ </template >
55
+
56
+ <script lang="ts">
57
+ import { defineComponent , ref } from ' vue' ;
58
+ import { getGitHubCopilotMetricsApi } from ' ../api/GitHubApi' ;
59
+ import { Metrics } from ' ../model/MetricsData' ;
60
+ import { Language } from ' ../model/Language' ;
61
+ import {
62
+ Chart as ChartJS ,
63
+ ArcElement ,
64
+ CategoryScale ,
65
+ LinearScale ,
66
+ PointElement ,
67
+ LineElement ,
68
+ BarElement ,
69
+ Title ,
70
+ Tooltip ,
71
+ Legend
72
+ } from ' chart.js'
73
+
74
+ import { Pie } from ' vue-chartjs'
75
+
76
+ ChartJS .register (
77
+ ArcElement ,
78
+ CategoryScale ,
79
+ LinearScale ,
80
+ BarElement ,
81
+ PointElement ,
82
+ LineElement ,
83
+ Title ,
84
+ Tooltip ,
85
+ Legend
86
+ )
87
+
88
+
89
+ export default defineComponent ({
90
+ name: ' LanguagesBreakdown' ,
91
+ components: {
92
+ Pie
93
+ },
94
+ data() {
95
+ return {
96
+ headers: [
97
+ { title: ' Language Name' , key: ' languageName' },
98
+ { title: ' Accepted Prompts' , key: ' acceptedPrompts' },
99
+ { title: ' Accepted Lines of Code' , key: ' acceptedLinesOfCode' },
100
+ { title: ' Acceptance Rate (%)' , key: ' acceptanceRate' },
101
+ ],
102
+ };
103
+ },
104
+ setup() {
105
+ console .log (' LanguagesBreakdown setup' );
106
+
107
+ const metrics = ref <Metrics []>([]);
108
+
109
+ // API Error Message
110
+ const apiError = ref <string | null >(null );
111
+
112
+ // Create an empty map to store the languages.
113
+ const languages = ref (new Map <string , Language >());
114
+
115
+ // Number of languages
116
+ const numberOfLanguages = ref (0 );
117
+
118
+ // Languages Chart Data for languages breakdown Pie Chart
119
+ let languagesChartData = ref <{ labels: string []; datasets: any [] }>({ labels: [], datasets: [] });
120
+
121
+ let languagesChartDataTop5 = ref <{ labels: string []; datasets: any [] }>({ labels: [], datasets: [] });
122
+
123
+ const chartOptions = {
124
+ responsive: true ,
125
+ maintainAspectRatio: true ,
126
+ };
127
+
128
+ getGitHubCopilotMetricsApi ().then (data => {
129
+ metrics .value = data ;
130
+
131
+ // Process the language breakdown separately
132
+ data .forEach (m => m .breakdown .forEach (breakdown =>
133
+ {
134
+ const languageName = breakdown .language ;
135
+ let language = languages .value .get (languageName );
136
+
137
+ if (! language ) {
138
+ // Create a new Language object if it does not exist
139
+ language = new Language ({
140
+ name: languageName ,
141
+ acceptedPrompts: breakdown .acceptances_count ,
142
+ suggestedLinesOfCode: breakdown .lines_suggested ,
143
+ acceptedLinesOfCode: breakdown .lines_accepted ,
144
+ });
145
+ languages .value .set (languageName , language );
146
+ } else {
147
+ // Update the existing Language object
148
+ language .acceptedPrompts += breakdown .acceptances_count ;
149
+ language .suggestedLinesOfCode += breakdown .lines_suggested ;
150
+ language .acceptedLinesOfCode += breakdown .lines_accepted ;
151
+ }
152
+ // Recalculate the acceptance rate
153
+ language .acceptanceRate = language .suggestedLinesOfCode !== 0 ? (language .acceptedLinesOfCode / language .suggestedLinesOfCode ) * 100 : 0 ;
154
+ }));
155
+
156
+ // Sort languages map by accepted lines of code
157
+ languages .value [Symbol .iterator ] = function * () {
158
+ yield * [... this .entries ()].sort ((a , b ) => b [1 ].acceptedLinesOfCode - a [1 ].acceptedLinesOfCode );
159
+ }
160
+
161
+ // Convert the Map to an array
162
+ let languagesArray = Array .from (languages .value .entries ());
163
+
164
+ // Sort the array
165
+ languagesArray .sort ((a , b ) => b [1 ].acceptedLinesOfCode - a [1 ].acceptedLinesOfCode );
166
+
167
+ // Convert the array back to a Map
168
+ // languages.value = new Map(languagesArray);
169
+
170
+ console .log (" Languages before: " + Array .from (languages .value .values ()).map (language => language .languageName ));
171
+ console .log (" languages.value[0].languageName: " + Array .from (languages .value .values ())[0 ].languageName );
172
+ console .log (" languages.value[1].languageName: " + Array .from (languages .value .values ())[1 ].languageName );
173
+ console .log (" languages.value[2].languageName: " + Array .from (languages .value .values ())[2 ].languageName );
174
+ console .log (" languages.value[3].languageName: " + Array .from (languages .value .values ())[3 ].languageName );
175
+ console .log (" languages.value[4].languageName: " + Array .from (languages .value .values ())[4 ].languageName );
176
+
177
+ languagesChartData .value = {
178
+ labels: Array .from (languages .value .values ()).map (language => language .languageName ),
179
+ datasets: [
180
+ {
181
+ data: Array .from (languages .value .values ()).map (language => language .acceptedPrompts ),
182
+ backgroundColor: [' #41B883' , ' #E46651' , ' #00D8FF' , ' #DD1B16' ],
183
+ },
184
+ ],
185
+ };
186
+
187
+ let top5Languages = Array .from (languages .value .values ()).slice (110 , 300 );
188
+
189
+ languagesChartDataTop5 .value = {
190
+ labels: Array .from (top5Languages .values ()).map (language => language .languageName ),
191
+ datasets: [
192
+ {
193
+ data: Array .from (top5Languages .values ()).map (language => language .acceptedPrompts ),
194
+ backgroundColor: [' #41B883' , ' #E46651' , ' #00D8FF' , ' #DD1B16' ],
195
+ },
196
+ ],
197
+ };
198
+
199
+ numberOfLanguages .value = languages .value .size ;
200
+
201
+ console .log (" Number of languages: " + numberOfLanguages .value );
202
+
203
+ console .log (" LanguagesChartData: " + JSON .stringify (languagesChartData ));
204
+
205
+
206
+ }).catch (error => {
207
+ console .log (error );
208
+ // Check the status code of the error response
209
+ if (error .response && error .response .status ) {
210
+ switch (error .response .status ) {
211
+ case 401 :
212
+ apiError .value = ' 401 Unauthorized access - check if your token in the .env file is correct.' ;
213
+ break ;
214
+ case 404 :
215
+ apiError .value = ` 404 Not Found - is the organization '${process .env .VUE_APP_GITHUB_ORG }' correct? ` ;
216
+ break ;
217
+ default :
218
+ apiError .value = error .message ;
219
+ break ;
220
+ }
221
+ } else {
222
+ // Update apiError with the error message
223
+ apiError .value = error .message ;
224
+ }
225
+ // Add a new line to the apiError message
226
+ apiError .value += ' <br> If .env file is modified, restart the changes to take effect.' ;
227
+
228
+ });
229
+
230
+ return { apiError , chartOptions , languages , numberOfLanguages , languagesChartData , languagesChartDataTop5 };
231
+ },
232
+
233
+
234
+ });
235
+ </script >
236
+
237
+ <style scoped>
238
+ .error-message {
239
+ color : red ;
240
+ }
241
+
242
+ .center-table {
243
+ margin-left : auto ;
244
+ margin-right : auto ;
245
+ }
246
+
247
+ .tiles-container {
248
+ display : flex ;
249
+ justify-content : flex-start ;
250
+ flex-wrap : wrap ;
251
+ }
252
+
253
+ .tile {
254
+ border : 1px solid #ccc ;
255
+ box-shadow : 3px 3px 5px rgba (0 , 0 , 0 , 0.1 ),
256
+ -3px -3px 5px rgba (255 , 255 , 255 , 0.7 );
257
+ padding : 20px ;
258
+ border-radius : 10px ;
259
+ width : 20% ;
260
+ margin : 1% ;
261
+ }
262
+ </style >
0 commit comments