Skip to content

Commit ecd3a17

Browse files
committed
feature: Team metrics support
1 parent d7c3a34 commit ecd3a17

File tree

6 files changed

+111
-25
lines changed

6 files changed

+111
-25
lines changed

.env

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ VUE_APP_GITHUB_ORG=octodemo
1010

1111
VUE_APP_GITHUB_ENT=
1212

13+
# Determines the team name if exists to target API calls.
14+
VUE_APP_GITHUB_TEAM=
15+
1316
# Determines the GitHub Personal Access Token to use for API calls.
1417
# Create with scopes copilot, manage_billing:copilot or manage_billing:enterprise, read:enterprise AND read:org
1518
VUE_APP_GITHUB_TOKEN=

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ The language breakdown analysis tab also displays a table showing the Accepted P
7474
<p align="center">
7575
<img width="800" alt="image" src="https://github.com/github-copilot-resources/copilot-metrics-viewer/assets/54096296/51747194-df30-4bfb-8849-54a0510fffcb">
7676
</p>
77+
7778
1. **Total Assigned:** This metric represents the total number of Copilot seats assigned within current organization/enterprise.
7879

7980
2. **Assigned But Never Used:** This metric shows seats that were assigned but never used within the current organization/enterprise. The assigned timestamp is also displayed in the chart.
@@ -103,7 +104,15 @@ VUE_APP_GITHUB_ORG= <YOUR-ORGANIZATION>
103104
104105
VUE_APP_GITHUB_ENT=
105106
````
107+
#### VUE_APP_GITHUB_TEAM
108+
109+
The `VUE_APP_GITHUB_TEAM` environment variable filters metrics for a specific GitHub team within an Enterprise or Organization account.
110+
‼️ Important ‼️ When this variable is set, all displayed metrics will pertain exclusively to the specified team. To view metrics for the entire Organization or Enterprise, remove this environment variable.
106111

112+
````
113+
VUE_APP_GITHUB_TEAM=
114+
115+
````
107116

108117
#### VUE_APP_MOCKED_DATA
109118

public/assets/app-config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ window._ENV_ = {
55
VUE_APP_GITHUB_ORG: "${VUE_APP_GITHUB_ORG}",
66
VUE_APP_GITHUB_ENT: "${VUE_APP_GITHUB_ENT}",
77
VUE_APP_GITHUB_TOKEN: "${VUE_APP_GITHUB_TOKEN}",
8+
VUE_APP_GITHUB_TEAM: "${VUE_APP_GITHUB_TEAM}",
89
};

src/api/GitHubApi.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,24 @@ export const getTeams = async (): Promise<string[]> => {
5050
return response.data;
5151
}
5252

53+
export const getTeamMetricsApi = async (): Promise<Metrics[]> => {
54+
console.log("config.github.team: " + config.github.team);
55+
56+
if (config.github.team && config.github.team.trim() !== '') {
57+
const response = await axios.get(
58+
`${config.github.apiUrl}/team/${config.github.team}/copilot/usage`,
59+
{
60+
headers: {
61+
Accept: "application/vnd.github+json",
62+
Authorization: `Bearer ${config.github.token}`,
63+
"X-GitHub-Api-Version": "2022-11-28",
64+
},
65+
}
66+
);
67+
68+
return response.data.map((item: any) => new Metrics(item));
69+
}
70+
71+
return [];
72+
73+
}

src/components/MainComponent.vue

Lines changed: 74 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,22 @@
55
<v-icon>mdi-github</v-icon>
66
</v-btn>
77

8-
<v-toolbar-title class="toolbar-title">Copilot Metrics Viewer | {{ capitalizedItemName }} : {{ displayedViewName }}</v-toolbar-title>
8+
<v-toolbar-title class="toolbar-title">Copilot Metrics Viewer | {{ capitalizedItemName }} : {{ displayedViewName }} {{ teamName }}
9+
10+
</v-toolbar-title>
911
<h2 class="error-message"> {{ mockedDataMessage }} </h2>
1012
<v-spacer></v-spacer>
1113

1214
<template v-slot:extension>
15+
1316
<v-tabs v-model="tab" align-tabs="title">
1417
<v-tab v-for="item in tabItems" :key="item" :value="item">
1518
{{ item }}
1619
</v-tab>
1720
</v-tabs>
21+
1822
</template>
23+
1924
</v-toolbar>
2025

2126
<!-- API Error Message -->
@@ -45,6 +50,7 @@
4550
<script lang='ts'>
4651
import { defineComponent, ref } from 'vue'
4752
import { getMetricsApi } from '../api/GitHubApi';
53+
import { getTeamMetricsApi } from '../api/GitHubApi';
4854
import { getSeatsApi } from '../api/ExtractSeats';
4955
import { Metrics } from '../model/Metrics';
5056
import { Seat } from "../model/Seat";
@@ -82,6 +88,15 @@ export default defineComponent({
8288
isScopeOrganization() {
8389
return config.scope.type === 'organization';
8490
},
91+
teamName(){
92+
var teamName;
93+
if (config.github.team && config.github.team.trim() !== '') {
94+
teamName = "| Team : " + config.github.team;
95+
} else {
96+
teamName = '';
97+
}
98+
return teamName;
99+
},
85100
mockedDataMessage() {
86101
return config.mockedData ? 'Using mock data - see README if unintended' : '';
87102
}
@@ -112,35 +127,70 @@ export default defineComponent({
112127
// API Error Message
113128
const apiError = ref<string | undefined>(undefined);
114129
115-
getMetricsApi().then(data => {
130+
131+
if(config.github.team && config.github.team.trim() !== '') {
132+
getTeamMetricsApi().then(data => {
116133
metrics.value = data;
117134
118135
// Set metricsReady to true after the call completes.
119136
metricsReady.value = true;
120-
137+
121138
}).catch(error => {
122-
console.log(error);
123-
// Check the status code of the error response
124-
if (error.response && error.response.status) {
125-
switch (error.response.status) {
126-
case 401:
127-
apiError.value = '401 Unauthorized access - check if your token in the .env file is correct.';
128-
break;
129-
case 404:
130-
apiError.value = `404 Not Found - is the ${config.scope.type} '${config.scope.name}' correct?`;
131-
break;
132-
default:
133-
apiError.value = error.message;
134-
break;
139+
console.log(error);
140+
// Check the status code of the error response
141+
if (error.response && error.response.status) {
142+
switch (error.response.status) {
143+
case 401:
144+
apiError.value = '401 Unauthorized access - check if your token in the .env file is correct.';
145+
break;
146+
case 404:
147+
apiError.value = `404 Not Found - is the ${config.scope.type} '${config.scope.name}' correct?`;
148+
break;
149+
default:
150+
apiError.value = error.message;
151+
break;
152+
}
153+
} else {
154+
// Update apiError with the error message
155+
apiError.value = error.message;
135156
}
136-
} else {
137-
// Update apiError with the error message
138-
apiError.value = error.message;
157+
// Add a new line to the apiError message
158+
apiError.value += ' <br> If .env file is modified, restart the app for the changes to take effect.';
159+
160+
});
139161
}
140-
// Add a new line to the apiError message
141-
apiError.value += ' <br> If .env file is modified, restart the app for the changes to take effect.';
142-
143-
});
162+
163+
if (metricsReady.value === false) {
164+
getMetricsApi().then(data => {
165+
metrics.value = data;
166+
167+
// Set metricsReady to true after the call completes.
168+
metricsReady.value = true;
169+
170+
}).catch(error => {
171+
console.log(error);
172+
// Check the status code of the error response
173+
if (error.response && error.response.status) {
174+
switch (error.response.status) {
175+
case 401:
176+
apiError.value = '401 Unauthorized access - check if your token in the .env file is correct.';
177+
break;
178+
case 404:
179+
apiError.value = `404 Not Found - is the ${config.scope.type} '${config.scope.name}' correct?`;
180+
break;
181+
default:
182+
apiError.value = error.message;
183+
break;
184+
}
185+
} else {
186+
// Update apiError with the error message
187+
apiError.value = error.message;
188+
}
189+
// Add a new line to the apiError message
190+
apiError.value += ' <br> If .env file is modified, restart the app for the changes to take effect.';
191+
192+
});
193+
}
144194
145195
getSeatsApi().then(data => {
146196
seats.value = data;
@@ -187,4 +237,5 @@ export default defineComponent({
187237
.error-message {
188238
color: red;
189239
}
240+
190241
</style>

src/config.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const PROPS = ["MOCKED_DATA", "SCOPE", "GITHUB_ORG", "GITHUB_ENT", "GITHUB_TOKEN"];
1+
const PROPS = ["MOCKED_DATA", "SCOPE", "GITHUB_ORG", "GITHUB_ENT", "GITHUB_TEAM", "GITHUB_TOKEN"];
22

33
const env: any = {};
44
PROPS.forEach(prop => {
@@ -40,11 +40,11 @@ const config: Config = {
4040
scope: {
4141
type: scopeType,
4242
name: scopeName
43-
4443
},
4544
github: {
4645
org: githubOrgName,
4746
ent: githubEntName,
47+
team: env.VUE_APP_GITHUB_TEAM,
4848
token: env.VUE_APP_GITHUB_TOKEN,
4949
apiUrl
5050
}
@@ -64,6 +64,7 @@ interface Config {
6464
github: {
6565
org: string;
6666
ent: string;
67+
team: string;
6768
token: string;
6869
apiUrl: string;
6970
}

0 commit comments

Comments
 (0)