Skip to content

Commit 32c009e

Browse files
committed
Merge remote-tracking branch 'fork/main' into feature/configuration
2 parents 07a5f61 + 720713f commit 32c009e

12 files changed

+103
-63
lines changed

.env

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ VUE_APP_GITHUB_ORG=octodemo
1111
VUE_APP_GITHUB_ENT=
1212

1313
# Determines the GitHub Personal Access Token to use for API calls.
14-
# Create with scopes copilot, manage_billing:copilot, admin:enterprise, or manage_billing:enterprise, read:enterprise AND read:org
14+
# Create with scopes copilot, manage_billing:copilot or manage_billing:enterprise, read:enterprise AND read:org
1515
VUE_APP_GITHUB_TOKEN=
1616

1717
# GitHub Api Url

README.md

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -71,19 +71,18 @@ The language breakdown analysis tab also displays a table showing the Accepted P
7171
4. **Total Active Copilot Chat Users:** a bar chart that illustrates the total number of users who have actively interacted with Copilot over the past 28 days.
7272

7373
## Seat Analysis
74+
<p align="center">
75+
<img width="800" alt="image" src="https://github.com/github-copilot-resources/copilot-metrics-viewer/assets/54096296/51747194-df30-4bfb-8849-54a0510fffcb">
76+
</p>
77+
1. **Total Assigned:** This metric represents the total number of Copilot seats assigned within current organization/enterprise.
7478

75-
![image](https://github.com/DevOps-zhuang/copilot-metrics-viewer/assets/54096296/d1fa9d1d-4fab-4e87-84ba-7be189dd4dd0)
76-
77-
1. **Total Assigned:** This metric represents the total number of Copilot seats assigned within current organization.
78-
79-
2. **Assigned But Never Used:** This metric shows seats that were assigned but never within the current organization. The assigned timestamp is also displayed in the below chart.
79+
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.
8080

8181
3. **No Activity in the Last 7 days:** never used seats or seats used, but with no activity in the past 7 days.
8282

8383
4. **No Activity in the last 7 days (including never used seats):** a table to display seats that have had no activity in the past 7 days, ordered by the date of last activity. Seats that were used earlier are displayed at the top.
8484

8585

86-
8786
## Setup instructions
8887

8988
In the `.env` file, you can configure several environment variables that control the behavior of the application.
@@ -115,7 +114,7 @@ To access Copilot metrics from the last 28 days via the API and display actual d
115114
```
116115

117116
#### VUE_APP_GITHUB_TOKEN
118-
Specifies the GitHub Personal Access Token utilized for API requests. Generate this token with the following scopes: _copilot_, _manage_billing:copilot_, _manage_billing:enterprise_, _read:enterprise_, _admin:org_.
117+
Specifies the GitHub Personal Access Token utilized for API requests. Generate this token with the following scopes: _copilot_, _manage_billing:copilot_, _manage_billing:enterprise_, _read:enterprise_, _read:org_.
119118

120119
```
121120
VUE_APP_GITHUB_TOKEN=

package-lock.json

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "copilot-metrics-viewer",
3-
"version": "1.5.0",
3+
"version": "1.6.0",
44
"private": true,
55
"scripts": {
66
"serve": "vue-cli-service serve",

src/api/ExtractSeats.ts

Lines changed: 57 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -15,46 +15,76 @@ const headers = {
1515
export const getSeatsApi = async (): Promise<Seat[]> => {
1616
const perPage = 50;
1717
let page = 1;
18+
let seatUrl = config.github.apiUrl;
1819
let seatsData: Seat[] = [];
1920

2021
let response;
21-
if (config.scope.type !== "organization") {
22-
// when the scope is not organization, return seatsData,by default it will return empty array
23-
return seatsData;
22+
23+
24+
if (process.env.VUE_APP_MOCKED_DATA === "true") {
25+
console.log("Using mock data. Check VUE_APP_MOCKED_DATA variable.");
26+
if (process.env.VUE_APP_SCOPE === "organization") {
27+
response = organizationMockedResponse_seats;
28+
}
29+
else if (process.env.VUE_APP_SCOPE === "enterprise") {
30+
response = enterpriseMockedResponse_seats;
31+
}
32+
else {
33+
throw new Error(`Invalid VUE_APP_SCOPE value: ${process.env.VUE_APP_SCOPE}. Expected "organization" or "enterprise".`);
34+
}
35+
seatsData = seatsData.concat(response.seats.map((item: any) => new Seat(item)));
36+
return seatsData;
2437
}
2538
else {
26-
if (config.mockedData) {
27-
response = organizationMockedResponse_seats;
28-
seatsData = seatsData.concat(response.seats.map((item: any) => new Seat(item)));
29-
}
39+
// if VUE_APP_GITHUB_TOKEN is not set, throw an error
40+
if (!process.env.VUE_APP_GITHUB_TOKEN) {
41+
throw new Error("VUE_APP_GITHUB_TOKEN environment variable is not set.");
42+
return seatsData;
43+
}
44+
else if (process.env.VUE_APP_SCOPE === "organization") {
45+
seatUrl=seatUrl+`orgs/${process.env.VUE_APP_GITHUB_ORG}/copilot/billing/seats`;
46+
}
47+
else if (process.env.VUE_APP_SCOPE === "enterprise") {
48+
seatUrl=seatUrl+`enterprises/${process.env.VUE_APP_GITHUB_ENT}/copilot/billing/seats`;
49+
}
3050
else {
51+
throw new Error(`Invalid VUE_APP_SCOPE value: ${process.env.VUE_APP_SCOPE}. Expected "organization" or "enterprise".`);
52+
return seatsData;
53+
}
54+
3155
// Fetch the first page to get the total number of seats
32-
response = await axios.get(`${config.github.apiUrl}/copilot/billing/seats`, {
33-
headers,
56+
response = await axios.get(seatUrl, {
57+
headers: {
58+
Accept: "application/vnd.github+json",
59+
Authorization: `Bearer ${process.env.VUE_APP_GITHUB_TOKEN}`,
60+
"X-GitHub-Api-Version": "2022-11-28",
61+
},
62+
params: {
63+
per_page: perPage,
64+
page: page
65+
}
66+
});
67+
68+
seatsData = seatsData.concat(response.data.seats.map((item: any) => new Seat(item)));
69+
// Calculate the total pages
70+
const totalSeats = response.data.total_seats;
71+
const totalPages = Math.ceil(totalSeats / perPage);
72+
73+
// Fetch the remaining pages
74+
for (page = 2; page <= totalPages; page++) {
75+
response = await axios.get(seatUrl, {
76+
headers: {
77+
Accept: "application/vnd.github+json",
78+
Authorization: `Bearer ${process.env.VUE_APP_GITHUB_TOKEN}`,
79+
"X-GitHub-Api-Version": "2022-11-28",
80+
},
3481
params: {
3582
per_page: perPage,
3683
page: page
3784
}
3885
});
39-
4086
seatsData = seatsData.concat(response.data.seats.map((item: any) => new Seat(item)));
41-
// Calculate the total pages
42-
const totalSeats = response.data.total_seats;
43-
const totalPages = Math.ceil(totalSeats / perPage);
44-
45-
// Fetch the remaining pages
46-
for (page = 2; page <= totalPages; page++) {
47-
response = await axios.get(`${config.github.apiUrl}/copilot/billing/seats`, {
48-
headers,
49-
params: {
50-
per_page: perPage,
51-
page: page
52-
}
53-
});
54-
55-
seatsData = seatsData.concat(response.data.seats.map((item: any) => new Seat(item)));
56-
}
5787
}
5888
return seatsData;
89+
}
5990
}
60-
}

src/assets/enterprise_response_sample_seats.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"last_activity_at": "2021-10-14T00:53:32-06:00",
99
"last_activity_editor": "vscode/1.77.3/copilot/1.86.82",
1010
"assignee": {
11-
"login": "octocat",
11+
"login": "octocat_byEnterprise",
1212
"id": 1,
1313
"node_id": "MDQ6VXNlcjE=",
1414
"avatar_url": "https://github.com/images/error/octocat_happy.gif",

src/assets/organization_response_sample_seats.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"last_activity_at": "2021-10-14T00:53:32-06:00",
99
"last_activity_editor": "vscode/1.77.3/copilot/1.86.82",
1010
"assignee": {
11-
"login": "octocat",
11+
"login": "octocat_org",
1212
"id": 1,
1313
"node_id": "MDQ6VXNlcjE=",
1414
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
@@ -50,7 +50,7 @@
5050
"last_activity_at": "2021-10-13T00:53:32-06:00",
5151
"last_activity_editor": "vscode/1.77.3/copilot/1.86.82",
5252
"assignee": {
53-
"login": "octokitten",
53+
"login": "octokitten_org",
5454
"id": 1,
5555
"node_id": "MDQ76VNlcjE=",
5656
"avatar_url": "https://github.com/images/error/octokitten_happy.gif",

src/components/ApiResponse.vue

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
</div>
1414

1515
<br><br>
16-
<div v-if="vueAppScope === 'organization'">
16+
1717
<v-card max-height="575px" class="overflow-y-auto">
1818
<pre ref="jsonText">{{ JSON.stringify(seats, null, 2) }}</pre>
1919
</v-card>
@@ -24,7 +24,6 @@
2424
<div v-if="showSeatMessage" :class="{'copy-message': true, 'error': isError}">{{ message }}</div>
2525
</transition>
2626
</div>
27-
</div>
2827
</v-container>
2928
</template>
3029

src/components/MainComponent.vue

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,7 @@
3131
<BreakdownComponent v-if="item === 'languages'" :metrics="metrics" :breakdownKey="'language'"/>
3232
<BreakdownComponent v-if="item === 'editors'" :metrics="metrics" :breakdownKey="'editor'"/>
3333
<CopilotChatViewer v-if="item === 'copilot chat'" :metrics="metrics" />
34-
<div v-if="isScopeOrganization">
35-
<SeatsAnalysisViewer v-if="item === 'seat analysis'" :seats="seats" />
36-
</div>
34+
<SeatsAnalysisViewer v-if="item === 'seat analysis'" :seats="seats" />
3735
<ApiResponse v-if="item === 'api response'" :metrics="metrics" :seats="seats" />
3836
</v-card>
3937
</v-window-item>
@@ -90,21 +88,12 @@ export default defineComponent({
9088
},
9189
data () {
9290
return {
93-
tabItems: ['languages', 'editors', 'copilot chat', 'api response'],
91+
tabItems: ['languages', 'editors', 'copilot chat','seat analysis' , 'api response'],
9492
tab: null
9593
}
9694
},
9795
created() {
98-
this.tabItems.unshift(this.itemName);
99-
if (config.scope.type === 'organization') {
100-
// get the last item in the array,which is 'api response'
101-
//and add 'seat analysis' before it
102-
let lastItem = this.tabItems.pop();
103-
this.tabItems.push('seat analysis');
104-
if (lastItem) {
105-
this.tabItems.push(lastItem);
106-
}
107-
}
96+
this.tabItems.unshift(this.itemName);
10897
},
10998
setup() {
11099
const metricsReady = ref(false);

src/components/SeatsAnalysisViewer.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
<tr>
5151
<td>{{ item.login }}</td>
5252
<td>{{ item.id }}</td>
53+
<td>{{ item.team }}</td>
5354
<td>{{ item.created_at }}</td>
5455
<td>{{ item.last_activity_at }}</td>
5556
<td>{{ item.last_activity_editor }}</td>
@@ -103,7 +104,8 @@ data() {
103104
headers: [
104105
{ title: 'Login', key: 'login' },
105106
{ title: 'GitHub ID', key: 'id' },
106-
{ title: 'Assigned to the Organization At', key: 'created_at' },
107+
{ title: 'Assigning team', key: 'team' },
108+
{ title: 'Assigned time', key: 'created_at' },
107109
{ title: 'Last Activity At', key: 'last_activity_at' },
108110
{ title: 'Last Activity Editor', key: 'last_activity_editor' },
109111
],

0 commit comments

Comments
 (0)