Skip to content

Commit 044115d

Browse files
committed
Merge remote-tracking branch 'fix/main' into feature/configuration
2 parents 7584684 + 0be8402 commit 044115d

File tree

11 files changed

+140
-65
lines changed

11 files changed

+140
-65
lines changed

.dockerignore

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1-
dist
2-
node_modules
3-
.github
1+
.env
2+
.dockerignore
3+
.git
4+
.gitignore
5+
node_modules/
6+
dist/
7+
.history/
8+
.github/
9+
Dockerfile
10+
*.md

Dockerfile

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ COPY . .
77
RUN npm run build
88

99
# Stage 2: Serve the application with Nginx
10-
FROM nginx:1.19 as production-stage
10+
FROM nginx:1.27 as production-stage
1111
COPY --from=build-stage /app/dist /usr/share/nginx/html
12+
COPY --from=build-stage /app/dist/assets/app-config.js /usr/share/nginx/html-template/app-config.template.js
13+
COPY ./docker-entrypoint.d/*.sh /docker-entrypoint.d/
14+
RUN chmod +x /docker-entrypoint.d/*.sh
1215
EXPOSE 80
13-
CMD ["nginx", "-g", "daemon off;"]
16+
CMD ["nginx", "-g", "daemon off;"]

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ docker build -t copilot-metrics-viewer .
138138

139139
### Docker run
140140
```
141-
docker run -p 8080:80 copilot-metrics-viewer
141+
docker run -p 8080:80 --env-file ./.env copilot-metrics-viewer
142142
```
143143
The application will be accessible at http://localhost:8080
144144

docker-entrypoint.d/99-config-app.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/bin/sh
2+
3+
configTemplateFile=/usr/share/nginx/html-template/app-config.template.js
4+
configTargetFile=/usr/share/nginx/html/assets/app-config.js
5+
6+
envsubst <"$configTemplateFile" >"$configTargetFile"

public/assets/app-config.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
window._ENV_ = {
2+
// These values are replaced by the entrypoint of Docker Image
3+
VUE_APP_MOCKED_DATA: "${VUE_APP_MOCKED_DATA}",
4+
VUE_APP_SCOPE: "${VUE_APP_SCOPE}",
5+
VUE_APP_GITHUB_ORG: "${VUE_APP_GITHUB_ORG}",
6+
VUE_APP_GITHUB_ENT: "${VUE_APP_GITHUB_ENT}",
7+
VUE_APP_GITHUB_TOKEN: "${VUE_APP_GITHUB_TOKEN}",
8+
};

public/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
<meta name="viewport" content="width=device-width,initial-scale=1.0">
77
<link rel="icon" href="<%= BASE_URL %>favicon.svg">
88
<title><%= htmlWebpackPlugin.options.title %></title>
9+
<script src="<%= BASE_URL %>assets/app-config.js"></script>
910
</head>
1011
<body>
1112
<noscript>

src/api/ExtractSeats.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// TypeScript
22
import axios from "axios";
33
import { Seat } from "../model/Seat";
4+
import config from '../config';
45

56
import organizationMockedResponse_seats from '../assets/organization_response_sample_seats.json';
67
import enterpriseMockedResponse_seats from '../assets/enterprise_response_sample_seats.json';
@@ -11,18 +12,18 @@ export const getSeatsApi = async (): Promise<Seat[]> => {
1112
let seatsData: Seat[] = [];
1213

1314
let response;
14-
if (process.env.VUE_APP_SCOPE !== "organization") {
15+
if (config.scope.type !== "organization") {
1516
// when the scope is not organization, return seatsData,by default it will return empty array
1617
return seatsData;
1718
}
18-
else{
19-
if (process.env.VUE_APP_MOCKED_DATA === "true") {
19+
else {
20+
if (config.mockedData) {
2021
response = organizationMockedResponse_seats;
2122
seatsData = seatsData.concat(response.seats.map((item: any) => new Seat(item)));
2223
}
23-
else if (process.env.VUE_APP_MOCKED_DATA === "false") {
24+
else {
2425
// Fetch the first page to get the total number of seats
25-
response = await axios.get(`/api/github/orgs/${process.env.VUE_APP_GITHUB_ORG}/copilot/billing/seats`, {
26+
response = await axios.get(`${config.github.apiUrl}/copilot/billing/seats`, {
2627
headers: {
2728
Accept: "application/vnd.github+json",
2829
"X-GitHub-Api-Version": "2022-11-28",
@@ -40,7 +41,7 @@ export const getSeatsApi = async (): Promise<Seat[]> => {
4041

4142
// Fetch the remaining pages
4243
for (page = 2; page <= totalPages; page++) {
43-
response = await axios.get(`/api/github/orgs/${process.env.VUE_APP_GITHUB_ORG}/copilot/billing/seats`, {
44+
response = await axios.get(`${config.github.apiUrl}/copilot/billing/seats`, {
4445
headers: {
4546
Accept: "application/vnd.github+json",
4647
"X-GitHub-Api-Version": "2022-11-28",
@@ -52,8 +53,8 @@ export const getSeatsApi = async (): Promise<Seat[]> => {
5253
});
5354

5455
seatsData = seatsData.concat(response.data.seats.map((item: any) => new Seat(item)));
55-
} //end of else if (process.env.VUE_APP_MOCKED_DATA === "false")
56-
} //end of else if (process.env.VUE_APP_SCOPE !== "organization")
57-
return seatsData;
58-
}
56+
}
57+
}
58+
return seatsData;
59+
}
5960
}

src/api/GitHubApi.ts

Lines changed: 17 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -9,56 +9,40 @@ import axios from "axios";
99
import { Metrics } from "../model/Metrics";
1010
import organizationMockedResponse from '../assets/organization_response_sample.json';
1111
import enterpriseMockedResponse from '../assets/enterprise_response_sample.json';
12-
12+
import config from '../config';
1313

1414
export const getMetricsApi = async (): Promise<Metrics[]> => {
15-
15+
1616
let response;
1717
let metricsData;
1818

19-
if (process.env.VUE_APP_MOCKED_DATA === "true") {
19+
if (config.mockedData) {
2020
console.log("Using mock data. Check VUE_APP_MOCKED_DATA variable.");
21-
if (process.env.VUE_APP_SCOPE === "organization") {
22-
response = organizationMockedResponse;
23-
} else if (process.env.VUE_APP_SCOPE === "enterprise") {
24-
response = enterpriseMockedResponse;
25-
} else {
26-
throw new Error(`Invalid VUE_APP_SCOPE value: ${process.env.VUE_APP_SCOPE}. Expected "organization" or "enterprise".`);
27-
}
28-
21+
response = config.scope.type === "organization" ? organizationMockedResponse : enterpriseMockedResponse;
2922
metricsData = response.map((item: any) => new Metrics(item));
3023
} else {
31-
// if VUE_APP_GITHUB_TOKEN is not set, throw an error
32-
// if (!process.env.VUE_APP_GITHUB_TOKEN) {
33-
// throw new Error("VUE_APP_GITHUB_TOKEN environment variable is not set.");
34-
// }
35-
if (process.env.VUE_APP_SCOPE === "organization") {
36-
response = await axios.get(
37-
`/api/github/orgs/${process.env.VUE_APP_GITHUB_ORG}/copilot/usage`);
38-
} else if (process.env.VUE_APP_SCOPE === "enterprise") {
24+
response = await axios.get(
25+
`${config.github.apiUrl}/copilot/usage`,
26+
{
27+
headers: {
28+
Accept: "application/vnd.github+json",
29+
Authorization: `Bearer ${config.github.token}`,
30+
"X-GitHub-Api-Version": "2022-11-28",
31+
},
32+
}
33+
);
3934

40-
response = await axios.get(
41-
`/api/github/enterprises/${process.env.VUE_APP_GITHUB_ENT}/copilot/usage`,
42-
{
43-
headers: {
44-
Accept: "application/vnd.github+json",
45-
"X-GitHub-Api-Version": "2022-11-28",
46-
},
47-
}
48-
);
49-
} else {
50-
throw new Error(`Invalid VUE_APP_SCOPE value: ${process.env.VUE_APP_SCOPE}. Expected "organization" or "enterprise".`);
51-
}
5235

5336
metricsData = response.data.map((item: any) => new Metrics(item));
5437
}
5538
return metricsData;
5639
};
5740

58-
export const getTeams = async (): Promise<string[]> =>{
59-
const response = await axios.get(`/api/github/orgs/${process.env.VUE_APP_GITHUB_ORG}/teams`, {
41+
export const getTeams = async (): Promise<string[]> => {
42+
const response = await axios.get(`${config.github.apiUrl}/teams`, {
6043
headers: {
6144
Accept: 'application/vnd.github+json',
45+
Authorization: `Bearer ${config.github.token}`,
6246
'X-GitHub-Api-Version': '2022-11-28',
6347
},
6448
});

src/components/ApiResponse.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030

3131
<script lang="ts">
3232
import { defineComponent } from 'vue';
33+
import config from '../config';
3334
3435
export default defineComponent({
3536
name: 'ApiResponse',
@@ -45,7 +46,7 @@ export default defineComponent({
4546
},
4647
data() {
4748
return {
48-
vueAppScope: process.env.VUE_APP_SCOPE,
49+
vueAppScope: config.scope.type,
4950
showCopyMessage: false,
5051
showSeatMessage: false,
5152
isError: false,

src/components/MainComponent.vue

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ import BreakdownComponent from './BreakdownComponent.vue'
5757
import CopilotChatViewer from './CopilotChatViewer.vue'
5858
import SeatsAnalysisViewer from './SeatsAnalysisViewer.vue'
5959
import ApiResponse from './ApiResponse.vue'
60+
import config from '../config';
6061
6162
export default defineComponent({
6263
name: 'MainComponent',
@@ -69,27 +70,22 @@ export default defineComponent({
6970
},
7071
computed: {
7172
gitHubOrgName() {
72-
return process.env.VUE_APP_GITHUB_ORG;
73+
return config.github.org;
7374
},
7475
itemName() {
75-
if (process.env.VUE_APP_SCOPE === 'enterprise' || process.env.VUE_APP_SCOPE === 'organization') {
76-
return process.env.VUE_APP_SCOPE;
77-
} else {
78-
console.log("invalid");
79-
return 'invalid';
80-
}
76+
return config.scope.type;
8177
},
8278
capitalizedItemName():string {
8379
return this.itemName.charAt(0).toUpperCase() + this.itemName.slice(1);
8480
},
8581
displayedViewName(): string {
86-
return this.capitalizedItemName === 'Enterprise' ? process.env.VUE_APP_GITHUB_ENT: process.env.VUE_APP_GITHUB_ORG;
82+
return config.scope.name;
8783
},
8884
isScopeOrganization() {
89-
return process.env.VUE_APP_SCOPE === 'organization';
85+
return config.scope.type === 'organization';
9086
},
9187
mockedDataMessage() {
92-
return process.env.VUE_APP_MOCKED_DATA === 'true' ? 'Using mock data - see README if unintended' : '';
88+
return config.mockedData ? 'Using mock data - see README if unintended' : '';
9389
}
9490
},
9591
data () {
@@ -99,10 +95,8 @@ export default defineComponent({
9995
}
10096
},
10197
created() {
102-
if(this.itemName !== 'invalid'){
10398
this.tabItems.unshift(this.itemName);
104-
}
105-
if (process.env.VUE_APP_SCOPE === 'organization') {
99+
if (config.scope.type === 'organization') {
106100
// get the last item in the array,which is 'api response'
107101
//and add 'seat analysis' before it
108102
let lastItem = this.tabItems.pop();
@@ -135,7 +129,7 @@ export default defineComponent({
135129
apiError.value = '401 Unauthorized access Login to GitHub using this link <a href="/login">Login</a>.';
136130
break;
137131
case 404:
138-
apiError.value = `404 Not Found - is the organization '${process.env.VUE_APP_GITHUB_ORG}' correct?`;
132+
apiError.value = `404 Not Found - is the ${config.scope.type} '${config.scope.name}' correct?`;
139133
break;
140134
default:
141135
apiError.value = error.message;
@@ -165,7 +159,7 @@ export default defineComponent({
165159
apiError.value = '401 Unauthorized access Login to GitHub using this link <a href="/login">Login</a>.';
166160
break;
167161
case 404:
168-
apiError.value = `404 Not Found - is the organization '${process.env.VUE_APP_GITHUB_ORG}' correct?`;
162+
apiError.value = `404 Not Found - is the ${config.scope.type} '${config.scope.name}' correct?`;
169163
break;
170164
default:
171165
apiError.value = error.message;

0 commit comments

Comments
 (0)