Skip to content

Commit 5f9173a

Browse files
committed
Refactor Highcharts theme configuration; remove unused time setting and update table header to be disabled; enhance metrics service logging; modify seat service to include additional member details and update database schema for seat associations.
1 parent 3df8035 commit 5f9173a

File tree

12 files changed

+249
-142
lines changed

12 files changed

+249
-142
lines changed

backend/src/controllers/teams.controller.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,12 @@ class TeamsController {
3737
const Member = mongoose.model('Member');
3838
try {
3939
const members = await Member.find()
40-
.select('login name url avatar_url')
40+
.select('login org name url avatar_url')
41+
.populate({
42+
path: 'seat',
43+
select: '-_id -__v',
44+
options: { lean: true }
45+
})
4146
.sort({ login: 'asc' })
4247
.exec();
4348

backend/src/database.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -201,10 +201,15 @@ class Database {
201201
email: String,
202202
starred_at: String,
203203
user_view_type: String,
204+
seat: {
205+
type: Schema.Types.ObjectId,
206+
ref: 'Seats'
207+
}
204208
}, {
205209
timestamps: true,
206210
});
207211
memberSchema.index({ org: 1, login: 1, id: 1 }, { unique: true });
212+
memberSchema.index({ seat: 1 });
208213
memberSchema.virtual('seats', {
209214
ref: 'Seats',
210215
localField: '_id',
@@ -226,24 +231,25 @@ class Database {
226231
const seatsSchema = new mongoose.Schema({
227232
org: String,
228233
team: String,
229-
assigning_team_id: Number,
230-
plan_type: String,
234+
created_at: Date,
235+
updated_at: Date,
236+
pending_cancellation_date: Date,
231237
last_activity_at: Date,
232238
last_activity_editor: String,
233-
queryAt: Date,
234-
assignee_id: Number,
235-
assignee_login: String,
239+
plan_type: String,
236240
assignee: {
237241
type: Schema.Types.ObjectId,
238242
ref: 'Member'
239243
},
244+
queryAt: Date,
245+
assignee_id: Number,
246+
assignee_login: String,
240247
}, {
241248
timestamps: true
242249
});
243250

244251
seatsSchema.index({ org: 1, queryAt: 1, last_activity_at: -1 });
245252
seatsSchema.index({ org: 1, team: 1, queryAt: 1, assignee_id: 1 }, { unique: true });
246-
247253
mongoose.model('Seats', seatsSchema);
248254

249255
const adoptionSchema = new Schema({

backend/src/models/copilot.seats.model.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ type SeatType = {
1010
last_activity_editor: string | null;
1111
plan_type: string;
1212
assignee_id: number;
13-
assigning_team_id: number | null;
1413
createdAt: Date;
1514
updatedAt: Date;
1615
};

backend/src/services/copilot.seats.service.ts

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,19 @@ type MemberDailyActivity = {
2828

2929
class SeatsService {
3030
async getAllSeats(org?: string) {
31-
const Seats = mongoose.model('Seats');
3231
const Member = mongoose.model('Member');
33-
34-
const latestQuery = await Seats.findOne()
35-
.sort({ queryAt: -1 }) // -1 for descending order
36-
.select('queryAt');
37-
38-
const seats = await Seats.find({
39-
...(org ? { org } : {}),
40-
queryAt: latestQuery?.queryAt
32+
33+
const seats = await Member.find({
34+
...(org ? { org } : {})
4135
})
42-
.populate('assignee')
43-
.sort({ last_activity_at: -1 }); // DESC ordering ⬇️
36+
.select('org login id name url avatar_url')
37+
.populate({
38+
path: 'seat',
39+
select: '-_id -__v',
40+
options: { lean: true }
41+
})
42+
.sort({ 'seat.last_activity_at': -1 })
43+
.exec();
4444

4545
return seats;
4646
}
@@ -127,6 +127,7 @@ class SeatsService {
127127
id: { $in: data.map(seat => seat.assignee.id) }
128128
});
129129

130+
console.log('austenstone-alt2', data.find(s => s.assignee.login === 'austenstone-alt2'));
130131
const seatsData = data.map((seat) => ({
131132
queryAt,
132133
org,
@@ -137,6 +138,17 @@ class SeatsService {
137138
assignee: updatedMembers.find(m => m.id === seat.assignee.id)?._id
138139
}));
139140
const seatResults = await Seats.insertMany(seatsData);
141+
142+
// Add member seat updates
143+
const memberSeatUpdates = seatResults.map(seat => ({
144+
updateOne: {
145+
filter: { org, id: seat.assignee_id },
146+
update: {
147+
$set: { seat: seat._id }
148+
}
149+
}
150+
}));
151+
await Members.bulkWrite(memberSeatUpdates);
140152

141153
const adoptionData = {
142154
enterprise: null,

backend/src/services/metrics.service.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,7 @@ class MetricsService {
305305

306306
async insertMetrics(org: string, data: MetricDailyResponseType[], team?: string) {
307307
const Metrics = mongoose.model('Metrics');
308+
console.log('data', data);
308309
for (const day of data) {
309310
// const parts = day.date.split('-').map(Number);
310311
// const date = new Date(Date.UTC(parts[0], parts[1] - 1, parts[2] + 1));

frontend/src/app/highcharts.theme.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -192,9 +192,6 @@ const theme: Highcharts.Options = {
192192
},
193193
xAxis: xAxisConfig,
194194
yAxis: yAxisConfig,
195-
time: {
196-
useUTC: false
197-
},
198195
legend: {
199196
align: 'left',
200197
verticalAlign: 'top',

frontend/src/app/main/copilot/copilot-dashboard/dashboard-card/dashboard-card-drilldown-bar-chart/dashboard-card-drilldown-bar-chart.component.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ export class DashboardCardDrilldownBarChartComponent implements OnChanges {
6565
...this.chartOptions,
6666
...this._chartOptions
6767
};
68+
console.log('chartOptions', this._chartOptions);
6869
this.updateFlag = true;
6970
}
7071
}

frontend/src/app/main/copilot/copilot-seats/copilot-seats.component.ts

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { Component, OnInit } from '@angular/core';
1+
import { Component, OnInit, ViewChild } from '@angular/core';
22
import { ColumnOptions, TableComponent } from '../../../shared/table/table.component';
3-
import { Seat, SeatService } from '../../../services/api/seat.service';
3+
import { AllSeats, Seat, SeatService } from '../../../services/api/seat.service';
44
import { SortDirection } from '@angular/material/sort';
55
import { Router } from '@angular/router';
66
import { InstallationsService } from '../../../services/api/installations.service';
@@ -16,56 +16,60 @@ import { takeUntil } from 'rxjs';
1616
styleUrl: './copilot-seats.component.scss'
1717
})
1818
export class CopilotSeatsComponent implements OnInit {
19-
seats?: Seat[];
19+
seats?: AllSeats[];
2020
tableColumns: ColumnOptions[] = [
2121
{
2222
columnDef: 'avatar',
2323
header: '',
24-
cell: (element: Seat) => `${element.assignee.avatar_url}`,
24+
cell: (element: AllSeats) => `${element.avatar_url}`,
2525
isImage: true
2626
},
2727
{
2828
columnDef: 'login',
2929
header: 'User',
30-
cell: (element: Seat) => `${element.assignee.login}`,
31-
// link: (element: Seat) => `https://github.com/${element.assignee.login}`
30+
cell: (element: AllSeats) => `${element.login}`,
31+
// link: (element: AllSeats) => `https://github.com/${element.assignee.login}`
3232
},
3333
{
3434
columnDef: 'last_activity_at',
3535
header: 'Last Active',
36-
cell: (element: Seat) => element.last_activity_at ? new Date(element.last_activity_at).toLocaleString([], { dateStyle: 'short', timeStyle: 'short' }) : '-'
36+
cell: (element: AllSeats) => element.seat?.last_activity_at ? new Date(element.seat.last_activity_at).toLocaleString([], { dateStyle: 'short', timeStyle: 'short' }) : '-'
3737
},
3838
{
3939
columnDef: 'last_activity_editor',
4040
header: 'Editor',
41-
cell: (element: Seat) => element.last_activity_editor?.split('/')[0] || '-',
41+
cell: (element: AllSeats) => element.seat?.last_activity_editor?.split('/')[0] || '-',
4242
chipList: true,
43-
chipListIcon: (element: Seat) => this.getIconForEditor(element.last_activity_editor),
43+
chipListIcon: (element: AllSeats) => this.getIconForEditor(element.seat?.last_activity_editor),
4444
},
4545
{
4646
columnDef: 'created_at',
4747
header: 'Created',
48-
cell: (element: Seat) => new Date(element.created_at).toLocaleString([], { dateStyle: 'short' })
48+
cell: (element: AllSeats) => new Date(element.seat?.created_at).toLocaleString([], { dateStyle: 'short' })
4949
},
5050
{
5151
columnDef: 'plan_type',
5252
header: 'Plan',
53-
cell: (element: Seat) => `${element.plan_type}`,
53+
cell: (element: AllSeats) => `${element.seat?.plan_type || 'disabled'}`,
5454
chipList: true,
55-
chipListIcon: (element: Seat) => element.plan_type === 'enterprise' ? 'corporate_fare' : 'paid'
55+
chipListIcon: (element: AllSeats) => element.seat?.plan_type === 'enterprise' ? 'corporate_fare' : element.seat?.plan_type === 'business' ? 'paid' : 'close'
56+
},
57+
{
58+
columnDef: 'org',
59+
header: 'Org',
60+
cell: (element: AllSeats) => `${element.org}`,
5661
}
5762
];
5863
defaultSort = {id: 'last_activity_at', start: 'desc' as SortDirection, disableClear: false};
59-
sortingDataAccessor = (item: Seat, property: string) => {
64+
sortingDataAccessor = (item: AllSeats, property: string) => {
6065
switch(property) {
6166
case 'login':
62-
return (item.assignee as { login: string })?.login.toLowerCase();
67+
return item.login.toLowerCase();
6368
default:
64-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
65-
return (item as any)[property];
69+
return item.seat?.[property as keyof Seat]
6670
}
6771
};
68-
filterPredicate = (data: Seat, filter: string) => {
72+
filterPredicate = (data: AllSeats, filter: string) => {
6973
const searchStr = JSON.stringify(data).toLowerCase();
7074
return searchStr.includes(filter);
7175
};
@@ -81,14 +85,14 @@ export class CopilotSeatsComponent implements OnInit {
8185
takeUntil(this.installationsService.destroy$)
8286
).subscribe(installation => {
8387
this.seatsService.getAllSeats(installation?.account?.login).subscribe(seats => {
84-
this.seats = seats as Seat[];
88+
this.seats = seats;
8589
});
8690
});
8791
}
8892

89-
onRowClick(seat: Seat) {
90-
if (seat.assignee.id) {
91-
this.router.navigate(['/copilot/seats', seat.assignee.id]);
93+
onRowClick(seat: AllSeats) {
94+
if (seat.id) {
95+
this.router.navigate(['/copilot/seats', seat.id]);
9296
}
9397
}
9498

frontend/src/app/services/api/seat.service.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,20 @@ import { HttpClient } from '@angular/common/http';
22
import { Injectable } from '@angular/core';
33
import { serverUrl } from '../server.service';
44
import { Endpoints } from "@octokit/types";
5-
import { map, reduce } from 'rxjs';
5+
import { map } from 'rxjs';
66

77
type _Seat = NonNullable<Endpoints["GET /orgs/{org}/copilot/billing/seats"]["response"]["data"]["seats"]>[0];
88
export interface Seat extends _Seat {
99
plan_type: string;
1010
}
11+
export interface AllSeats {
12+
avatar_url: string,
13+
login: string,
14+
id: number,
15+
org: string,
16+
url: string,
17+
seat: Seat;
18+
}
1119
export interface ActivityResponseData {
1220
totalSeats: number,
1321
totalActive: number,
@@ -33,7 +41,7 @@ export class SeatService {
3341
constructor(private http: HttpClient) { }
3442

3543
getAllSeats(org?: string) {
36-
return this.http.get<Seat[]>(`${this.apiUrl}`, {
44+
return this.http.get<AllSeats[]>(`${this.apiUrl}`, {
3745
params: org ? { org } : undefined
3846
});
3947
}

0 commit comments

Comments
 (0)