Skip to content

Commit

Permalink
Merge pull request #32 from DevOps-zhuang/feature/SeatAnalysis
Browse files Browse the repository at this point in the history
add copilot seat analysis supports
  • Loading branch information
martedesco authored Jun 2, 2024
2 parents 18a0c42 + de79474 commit a2b13ed
Show file tree
Hide file tree
Showing 8 changed files with 513 additions and 6 deletions.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,20 @@ The language breakdown analysis tab also displays a table showing the Accepted P

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.

## Seat Analysis

![image](https://github.com/DevOps-zhuang/copilot-metrics-viewer/assets/54096296/d1fa9d1d-4fab-4e87-84ba-7be189dd4dd0)

1. **Total Assigned:** This metric represents the total number of Copilot seats assigned within current organization.

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.

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

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.



## Setup instructions

In the `.env` file, you can configure several environment variables that control the behavior of the application.
Expand Down
61 changes: 61 additions & 0 deletions src/api/ExtractSeats.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// TypeScript
import axios from "axios";
import { Seat } from "../model/Seat";

import organizationMockedResponse_seats from '../assets/organization_response_sample_seats.json';
import enterpriseMockedResponse_seats from '../assets/enterprise_response_sample_seats.json';

export const getSeatsApi = async (): Promise<Seat[]> => {
const perPage = 50;
let page = 1;
let seatsData: Seat[] = [];

let response;
if (process.env.VUE_APP_SCOPE !== "organization") {
// when the scope is not organization, return seatsData,by default it will return empty array
return seatsData;
}
else{
if (process.env.VUE_APP_MOCKED_DATA === "true") {
response = organizationMockedResponse_seats;
seatsData = seatsData.concat(response.seats.map((item: any) => new Seat(item)));
}
else if (process.env.VUE_APP_MOCKED_DATA === "false") {
// Fetch the first page to get the total number of seats
response = await axios.get(`https://api.github.com/orgs/${process.env.VUE_APP_GITHUB_ORG}/copilot/billing/seats`, {
headers: {
Accept: "application/vnd.github+json",
Authorization: `Bearer ${process.env.VUE_APP_GITHUB_TOKEN}`,
"X-GitHub-Api-Version": "2022-11-28",
},
params: {
per_page: perPage,
page: page
}
});

seatsData = seatsData.concat(response.data.seats.map((item: any) => new Seat(item)));
// Calculate the total pages
const totalSeats = response.data.total_seats;
const totalPages = Math.ceil(totalSeats / perPage);

// Fetch the remaining pages
for (page = 2; page <= totalPages; page++) {
response = await axios.get(`https://api.github.com/orgs/${process.env.VUE_APP_GITHUB_ORG}/copilot/billing/seats`, {
headers: {
Accept: "application/vnd.github+json",
Authorization: `Bearer ${process.env.VUE_APP_GITHUB_TOKEN}`,
"X-GitHub-Api-Version": "2022-11-28",
},
params: {
per_page: perPage,
page: page
}
});

seatsData = seatsData.concat(response.data.seats.map((item: any) => new Seat(item)));
} //end of else if (process.env.VUE_APP_MOCKED_DATA === "false")
} //end of else if (process.env.VUE_APP_SCOPE !== "organization")
return seatsData;
}
}
74 changes: 74 additions & 0 deletions src/assets/enterprise_response_sample_seats.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
{
"total_seats": 2,
"seats": [
{
"created_at": "2021-08-03T18:00:00-06:00",
"updated_at": "2021-09-23T15:00:00-06:00",
"pending_cancellation_date": null,
"last_activity_at": "2021-10-14T00:53:32-06:00",
"last_activity_editor": "vscode/1.77.3/copilot/1.86.82",
"assignee": {
"login": "octocat",
"id": 1,
"node_id": "MDQ6VXNlcjE=",
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
"gravatar_id": "",
"url": "https://api.github.com/users/octocat",
"html_url": "https://github.com/octocat",
"followers_url": "https://api.github.com/users/octocat/followers",
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
"organizations_url": "https://api.github.com/users/octocat/orgs",
"repos_url": "https://api.github.com/users/octocat/repos",
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
"received_events_url": "https://api.github.com/users/octocat/received_events",
"type": "User",
"site_admin": false
},
"assigning_team": {
"id": 1,
"node_id": "MDQ6VGVhbTE=",
"url": "https://api.github.com/teams/1",
"html_url": "https://github.com/orgs/github/teams/justice-league",
"name": "Justice League",
"slug": "justice-league",
"description": "A great team.",
"privacy": "closed",
"notification_setting": "notifications_enabled",
"permission": "admin",
"members_url": "https://api.github.com/teams/1/members{/member}",
"repositories_url": "https://api.github.com/teams/1/repos",
"parent": null
}
},
{
"created_at": "2021-09-23T18:00:00-06:00",
"updated_at": "2021-09-23T15:00:00-06:00",
"pending_cancellation_date": "2021-11-01",
"last_activity_at": "2021-10-13T00:53:32-06:00",
"last_activity_editor": "vscode/1.77.3/copilot/1.86.82",
"assignee": {
"login": "octokitten",
"id": 1,
"node_id": "MDQ76VNlcjE=",
"avatar_url": "https://github.com/images/error/octokitten_happy.gif",
"gravatar_id": "",
"url": "https://api.github.com/users/octokitten",
"html_url": "https://github.com/octokitten",
"followers_url": "https://api.github.com/users/octokitten/followers",
"following_url": "https://api.github.com/users/octokitten/following{/other_user}",
"gists_url": "https://api.github.com/users/octokitten/gists{/gist_id}",
"starred_url": "https://api.github.com/users/octokitten/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/octokitten/subscriptions",
"organizations_url": "https://api.github.com/users/octokitten/orgs",
"repos_url": "https://api.github.com/users/octokitten/repos",
"events_url": "https://api.github.com/users/octokitten/events{/privacy}",
"received_events_url": "https://api.github.com/users/octokitten/received_events",
"type": "User",
"site_admin": false
}
}
]
}
74 changes: 74 additions & 0 deletions src/assets/organization_response_sample_seats.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
{
"total_seats": 2,
"seats": [
{
"created_at": "2021-08-03T18:00:00-06:00",
"updated_at": "2021-09-23T15:00:00-06:00",
"pending_cancellation_date": null,
"last_activity_at": "2021-10-14T00:53:32-06:00",
"last_activity_editor": "vscode/1.77.3/copilot/1.86.82",
"assignee": {
"login": "octocat",
"id": 1,
"node_id": "MDQ6VXNlcjE=",
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
"gravatar_id": "",
"url": "https://api.github.com/users/octocat",
"html_url": "https://github.com/octocat",
"followers_url": "https://api.github.com/users/octocat/followers",
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
"organizations_url": "https://api.github.com/users/octocat/orgs",
"repos_url": "https://api.github.com/users/octocat/repos",
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
"received_events_url": "https://api.github.com/users/octocat/received_events",
"type": "User",
"site_admin": false
},
"assigning_team": {
"id": 1,
"node_id": "MDQ6VGVhbTE=",
"url": "https://api.github.com/teams/1",
"html_url": "https://github.com/orgs/github/teams/justice-league",
"name": "Justice League",
"slug": "justice-league",
"description": "A great team.",
"privacy": "closed",
"notification_setting": "notifications_enabled",
"permission": "admin",
"members_url": "https://api.github.com/teams/1/members{/member}",
"repositories_url": "https://api.github.com/teams/1/repos",
"parent": null
}
},
{
"created_at": "2021-09-23T18:00:00-06:00",
"updated_at": "2021-09-23T15:00:00-06:00",
"pending_cancellation_date": "2021-11-01",
"last_activity_at": "2021-10-13T00:53:32-06:00",
"last_activity_editor": "vscode/1.77.3/copilot/1.86.82",
"assignee": {
"login": "octokitten",
"id": 1,
"node_id": "MDQ76VNlcjE=",
"avatar_url": "https://github.com/images/error/octokitten_happy.gif",
"gravatar_id": "",
"url": "https://api.github.com/users/octokitten",
"html_url": "https://github.com/octokitten",
"followers_url": "https://api.github.com/users/octokitten/followers",
"following_url": "https://api.github.com/users/octokitten/following{/other_user}",
"gists_url": "https://api.github.com/users/octokitten/gists{/gist_id}",
"starred_url": "https://api.github.com/users/octokitten/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/octokitten/subscriptions",
"organizations_url": "https://api.github.com/users/octokitten/orgs",
"repos_url": "https://api.github.com/users/octokitten/repos",
"events_url": "https://api.github.com/users/octokitten/events{/privacy}",
"received_events_url": "https://api.github.com/users/octokitten/received_events",
"type": "User",
"site_admin": false
}
}
]
}
32 changes: 32 additions & 0 deletions src/components/ApiResponse.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,20 @@
<div v-if="showCopyMessage" :class="{'copy-message': true, 'error': isError}">{{ message }}</div>
</transition>
</div>

<br><br>
<div v-if="vueAppScope === 'organization'">
<v-card max-height="575px" class="overflow-y-auto">
<pre ref="jsonText">{{ JSON.stringify(seats, null, 2) }}</pre>
</v-card>
<br>
<div class="copy-container">
<v-btn @click="showSeatCount">Show Assigned Seats count</v-btn>
<transition name="fade">
<div v-if="showSeatMessage" :class="{'copy-message': true, 'error': isError}">{{ message }}</div>
</transition>
</div>
</div>
</v-container>
</template>

Expand All @@ -23,11 +37,17 @@ export default defineComponent({
metrics: {
type: Object,
required: true
},
seats: {
type: Array,
required: true
}
},
data() {
return {
vueAppScope: process.env.VUE_APP_SCOPE,
showCopyMessage: false,
showSeatMessage: false,
isError: false,
message : ''
Expand All @@ -51,7 +71,19 @@ export default defineComponent({
setTimeout(() => {
this.showCopyMessage = false;
}, 3000);
},
showSeatCount() {
const seatCount = this.seats.length;
//console.log('Seat count:', seatCount);
this.message = `Seat count: ${seatCount}`;
this.showSeatMessage = true;
setTimeout(() => {
this.showSeatMessage = false;
}, 3000);
}
}
});
Expand Down
Loading

0 comments on commit a2b13ed

Please sign in to comment.