From ecd5671551a7f56cb363a343f8dbf2a028b120ad Mon Sep 17 00:00:00 2001 From: Austen Stone Date: Thu, 5 Dec 2024 09:59:30 -0500 Subject: [PATCH 1/7] Refactor status component and enhance API integration; update styles and improve development scripts --- backend/package.json | 2 +- backend/src/controllers/seats.controller.ts | 9 +- backend/src/routes/index.ts | 2 + backend/src/services/copilot.seats.service.ts | 48 ++++-- backend/src/services/status.service.ts | 55 ++++--- frontend/src/app/guards/setup.guard.ts | 6 +- .../dashboard.component.html | 39 +---- .../dashboard.component.scss | 7 +- .../copilot-dashboard/dashboard.component.ts | 149 ++++++++---------- .../status/status.component.html | 34 ++-- .../status/status.component.scss | 7 +- .../status/status.component.ts | 5 +- .../copilot-metrics.component.html | 38 ++++- .../copilot-metrics.component.ts | 96 ++++++++--- .../copilot-seat/copilot-seat.component.html | 10 +- .../copilot-seats/copilot-seats.component.ts | 2 +- .../copilot/copilot-value/value.component.ts | 55 ++++--- .../app/services/api/installations.service.ts | 8 +- frontend/src/app/services/api/seat.service.ts | 9 +- frontend/src/styles.scss | 4 +- 20 files changed, 352 insertions(+), 233 deletions(-) diff --git a/backend/package.json b/backend/package.json index 609b0d2f..865ee0a9 100644 --- a/backend/package.json +++ b/backend/package.json @@ -8,7 +8,7 @@ "start": "node --enable-source-maps dist/index.js | bunyan -o short -l info", "test": "jest", "build": "tsc", - "dev": "tsx watch src/index.ts | bunyan -o short -l debug", + "dev": "tsx watch src/index.ts | bunyan -o short -l info", "lint": "eslint src/**/*.ts", "db:start": "docker-compose -f ../compose.yml up -d db", "dotenv": "cp -n .env.example .env || true" diff --git a/backend/src/controllers/seats.controller.ts b/backend/src/controllers/seats.controller.ts index e1c8862f..039207b7 100644 --- a/backend/src/controllers/seats.controller.ts +++ b/backend/src/controllers/seats.controller.ts @@ -32,7 +32,11 @@ class SeatsController { return; } try { - const activityDays = await SeatsService.getMembersActivity(org, _daysInactive, precision as 'hour' | 'day' | 'minute'); + const activityDays = await SeatsService.getMembersActivity({ + org, + daysInactive: _daysInactive, + precision: precision as 'hour' | 'day' + }); res.status(200).json(activityDays); } catch (error) { res.status(500).json(error); @@ -40,9 +44,8 @@ class SeatsController { } async getActivityTotals(req: Request, res: Response): Promise { - const org = req.query.org?.toString() try { - const totals = await SeatsService.getMembersActivityTotals(org); + const totals = await SeatsService.getMembersActivityTotals(req.query); res.status(200).json(totals); } catch (error) { res.status(500).json(error); diff --git a/backend/src/routes/index.ts b/backend/src/routes/index.ts index db40f853..fc1020e4 100644 --- a/backend/src/routes/index.ts +++ b/backend/src/routes/index.ts @@ -47,6 +47,8 @@ router.post('/setup/existing-app', setupController.addExistingApp); router.post('/setup/db', setupController.setupDB); router.get('/setup/status', setupController.setupStatus); +router.get('/status', setupController.getStatus); + router.get('/predictive-modeling/targets', targetValuesController.getTargetValues); router.post('/predictive-modeling/targets', targetValuesController.updateTargetValues); diff --git a/backend/src/services/copilot.seats.service.ts b/backend/src/services/copilot.seats.service.ts index 93476712..2ccab328 100644 --- a/backend/src/services/copilot.seats.service.ts +++ b/backend/src/services/copilot.seats.service.ts @@ -1,6 +1,6 @@ import { Endpoints } from '@octokit/types'; import { Seat } from "../models/copilot.seats.model.js"; -import { QueryTypes, Sequelize } from 'sequelize'; +import { Op, QueryTypes, Sequelize } from 'sequelize'; import { components } from "@octokit/openapi-types"; import { Member, Team } from '../models/teams.model.js'; import app from '../index.js'; @@ -142,7 +142,14 @@ class SeatsService { } } - async getMembersActivity(org?: string, daysInactive = 30, precision = 'day' as 'hour' | 'day' | 'minute'): Promise { + async getMembersActivity(params: { + org?: string; + daysInactive?: number; + precision?: 'hour' | 'day' | 'minute'; + since?: string; + until?: string; + } = {}): Promise { + const { org, daysInactive = 30, precision = 'day', since, until } = params; if (!app.database.sequelize) throw new Error('No database connection available'); // const assignees = await app.database.sequelize.query( // `SELECT @@ -165,6 +172,11 @@ class SeatsService { // mapToModel: true // 🎯 Maps results to the Model // } // ); + + const dateFilter = { + ...(since && { [Op.gte]: new Date(since as string) }), + ...(until && { [Op.lte]: new Date(until as string) }) + }; const assignees = await Member.findAll({ attributes: ['login', 'id'], include: [ @@ -175,6 +187,7 @@ class SeatsService { order: [['last_activity_at', 'ASC']], where: { ...(org ? { org } : {}), + ...Object.getOwnPropertySymbols(dateFilter).length ? { createdAt: dateFilter } : {} } } ], @@ -230,17 +243,25 @@ class SeatsService { return sortedActivityDays; } - async getMembersActivityTotals(org?: string) { - const assignees2 = await app.database.sequelize?.query(` - SELECT \`Member\`.\`login\`, \`Member\`.\`id\`, \`activity\`.\`id\` AS \`activity.id\`, \`activity\`.\`last_activity_at\` AS \`activity.last_activity_at\` - FROM \`Members\` AS \`Member\` - INNER JOIN \`Seats\` AS \`activity\` ON \`Member\`.\`id\` = \`activity\`.\`assignee_id\` - `, { - replacements: { org }, - type: QueryTypes.SELECT - }); - console.log(assignees2); - + async getMembersActivityTotals(params: { + org?: string; + since?: string; + until?: string; + }) { + // const assignees2 = await app.database.sequelize?.query(` + // SELECT \`Member\`.\`login\`, \`Member\`.\`id\`, \`activity\`.\`id\` AS \`activity.id\`, \`activity\`.\`last_activity_at\` AS \`activity.last_activity_at\` + // FROM \`Members\` AS \`Member\` + // INNER JOIN \`Seats\` AS \`activity\` ON \`Member\`.\`id\` = \`activity\`.\`assignee_id\` + // `, { + // replacements: { org }, + // type: QueryTypes.SELECT + // }); + // console.log(assignees2); + const { org, since, until } = params; + const dateFilter = { + ...(since && { [Op.gte]: new Date(since as string) }), + ...(until && { [Op.lte]: new Date(until as string) }) + }; const assignees = await Member.findAll({ attributes: ['login', 'id'], include: [{ @@ -250,6 +271,7 @@ class SeatsService { order: [['last_activity_at', 'ASC']], where: { ...(org ? { org } : {}), + ...Object.getOwnPropertySymbols(dateFilter).length ? { createdAt: dateFilter } : {} } }] }); diff --git a/backend/src/services/status.service.ts b/backend/src/services/status.service.ts index e65a1bc5..70bc9620 100644 --- a/backend/src/services/status.service.ts +++ b/backend/src/services/status.service.ts @@ -1,21 +1,21 @@ +import app from "index.js"; import { Seat } from "../models/copilot.seats.model.js"; import { Survey } from "../models/survey.model.js"; import { Member } from "../models/teams.model.js"; +import { Endpoints } from "@octokit/types"; +import copilotSeatsService from "./copilot.seats.service.js"; export interface StatusType { - github?: { - isGood: boolean + github?: boolean; + seatsHistory?: { + oldestCreatedAt: string; + daysSinceOldestCreatedAt?: number; }; - pollingHistory?: { - isGood: boolean; - message: string; - value?: any; - progress?: string; - }; - repos?: { - value: number; - }; - surveys?: StatusType; + installations: { + installation: Endpoints["GET /app/installations"]["response"]["data"][0] + repos: Endpoints["GET /app/installations"]["response"]["data"]; + }[]; + surveyCount: number; } class StatusService { @@ -24,6 +24,7 @@ class StatusService { } async getStatus(): Promise { + console.log('Getting status'); const status = {} as StatusType; const assignee = await Member.findOne(); @@ -36,28 +37,40 @@ class StatusService { where: { assignee_id: assignee.id }, - order: [['createdAt', 'DESC']], + order: [['createdAt', 'ASC']], }); const oldestSeat = seats.find(seat => seat.createdAt); const daysSince = oldestSeat ? Math.floor((new Date().getTime() - oldestSeat.createdAt.getTime()) / (1000 * 3600 * 24)) : undefined; - status.pollingHistory = { - isGood: true, - message: `${oldestSeat?.createdAt}`, - value: daysSince + status.seatsHistory = { + oldestCreatedAt: oldestSeat?.createdAt.toISOString() || 'No data', + daysSinceOldestCreatedAt: daysSince } } + + status.installations = []; + for (const installation of app.github.installations) { + const repos = await installation.octokit.request(installation.installation.repositories_url); + status.installations.push({ + installation: installation.installation, + repos: repos.data.repositories + }); + } + const surveys = await Survey.findAll({ order: [['updatedAt', 'DESC']] }); if (surveys) { - // status.surveys = { - // message: `${surveys.length} surveys created`, - // value: surveys.length - // } + status.surveyCount = surveys.length; } + const yesterday = new Date(new Date().setDate(new Date().getDate() - 1)); + const activity = await copilotSeatsService.getMembersActivity({ + since: yesterday.toISOString(), + }); + console.log(Object.keys(activity)); + return status; } } diff --git a/frontend/src/app/guards/setup.guard.ts b/frontend/src/app/guards/setup.guard.ts index 37b387ce..2f2fcfca 100644 --- a/frontend/src/app/guards/setup.guard.ts +++ b/frontend/src/app/guards/setup.guard.ts @@ -2,20 +2,24 @@ import { Injectable, isDevMode } from '@angular/core'; import { CanActivate, GuardResult, MaybeAsync, Router } from '@angular/router'; import { of } from 'rxjs'; import { catchError, map } from 'rxjs/operators'; -import { InstallationsService } from '../services/api/installations.service'; +import { InstallationsService, statusResponse } from '../services/api/installations.service'; @Injectable({ providedIn: 'root' }) export class SetupStatusGuard implements CanActivate { + responseCache?: statusResponse; + constructor( private installationsService: InstallationsService, private router: Router ) {} canActivate(): MaybeAsync { + if (this.responseCache?.isSetup === true) return of(true); return this.installationsService.refreshStatus().pipe( map((response) => { + this.responseCache = response; if (!response.dbConnected) { this.router.navigate(['/setup/db']); return false; diff --git a/frontend/src/app/main/copilot/copilot-dashboard/dashboard.component.html b/frontend/src/app/main/copilot/copilot-dashboard/dashboard.component.html index f23919f3..fe30b063 100644 --- a/frontend/src/app/main/copilot/copilot-dashboard/dashboard.component.html +++ b/frontend/src/app/main/copilot/copilot-dashboard/dashboard.component.html @@ -5,14 +5,14 @@

Dashboard

-->
- + [change]="totalSurveysThisWeek" changeSuffix="" changeDescription=" this week"> --> @@ -39,37 +39,12 @@

Dashboard

- + @for (status of statuses; track $index) { + + + + } - - - Engagement - - - - - - - - Engagement Breakdown - - - - - - - - - - Most Active Users - - - - -
diff --git a/frontend/src/app/main/copilot/copilot-dashboard/dashboard.component.scss b/frontend/src/app/main/copilot/copilot-dashboard/dashboard.component.scss index 9561b9f8..eae32ce7 100644 --- a/frontend/src/app/main/copilot/copilot-dashboard/dashboard.component.scss +++ b/frontend/src/app/main/copilot/copilot-dashboard/dashboard.component.scss @@ -1,6 +1,7 @@ @use '@angular/material' as mat; .cards-grid { + margin-top:24px; display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 24px; @@ -28,9 +29,9 @@ overflow: hidden; } - #status { - grid-column: span 3; - } + // #status { + // grid-column: span 3; + // } } /* Add media query for smaller screens */ diff --git a/frontend/src/app/main/copilot/copilot-dashboard/dashboard.component.ts b/frontend/src/app/main/copilot/copilot-dashboard/dashboard.component.ts index aac35d1f..783f3d53 100644 --- a/frontend/src/app/main/copilot/copilot-dashboard/dashboard.component.ts +++ b/frontend/src/app/main/copilot/copilot-dashboard/dashboard.component.ts @@ -1,19 +1,16 @@ -import { ChangeDetectorRef, Component, OnInit } from '@angular/core'; +import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; import { AppModule } from '../../../app.module'; -import { DashboardCardBarsComponent } from "./dashboard-card/dashboard-card-bars/dashboard-card-bars.component"; import { DashboardCardValueComponent } from './dashboard-card/dashboard-card-value/dashboard-card-value.component'; -import { DashboardCardDrilldownBarChartComponent } from './dashboard-card/dashboard-card-drilldown-bar-chart/dashboard-card-drilldown-bar-chart.component'; import { MetricsService } from '../../../services/api/metrics.service'; import { CopilotMetrics } from '../../../services/api/metrics.service.interfaces'; import { ActivityResponse, Seat, SeatService } from '../../../services/api/seat.service'; import { MembersService } from '../../../services/api/members.service'; import { CopilotSurveyService, Survey } from '../../../services/api/copilot-survey.service'; -import { forkJoin, takeUntil } from 'rxjs'; +import { forkJoin, Subject, Subscription, takeUntil } from 'rxjs'; import { AdoptionChartComponent } from '../copilot-value/adoption-chart/adoption-chart.component'; import { DailyActivityChartComponent } from '../copilot-value/daily-activity-chart/daily-activity-chart.component'; import { TimeSavedChartComponent } from '../copilot-value/time-saved-chart/time-saved-chart.component'; import { LoadingSpinnerComponent } from '../../../shared/loading-spinner/loading-spinner.component'; -import { ActiveUsersChartComponent } from './dashboard-card/active-users-chart/active-users-chart.component'; import { InstallationsService } from '../../../services/api/installations.service'; import { StatusComponent } from './status/status.component'; @@ -23,32 +20,20 @@ import { StatusComponent } from './status/status.component'; imports: [ AppModule, DashboardCardValueComponent, - DashboardCardBarsComponent, - DashboardCardDrilldownBarChartComponent, AdoptionChartComponent, DailyActivityChartComponent, TimeSavedChartComponent, LoadingSpinnerComponent, - ActiveUsersChartComponent, StatusComponent ], templateUrl: './dashboard.component.html', styleUrl: './dashboard.component.scss' }) -export class CopilotDashboardComponent implements OnInit { - allSeats?: Seat[]; - totalMembers?: number; - totalSeats?: number; - surveysData?: Survey[]; - totalSurveys?: number; - totalSurveysThisWeek?: number; +export class CopilotDashboardComponent implements OnInit, OnDestroy { + subscriptions = [] as Subscription[]; metricsData?: CopilotMetrics[]; activityData?: ActivityResponse; - seatPercentage?: number; - activeToday?: number; - activeWeeklyChangePercent?: number; - activeCurrentWeekAverage?: number; - activeLastWeekAverage?: number; + surveysData?: Survey[]; chartOptions: Highcharts.Options = { chart: { marginTop: 0, @@ -86,8 +71,15 @@ export class CopilotDashboardComponent implements OnInit { } } } + private readonly _destroy$ = new Subject(); activityTotals?: Record; + status?: any; + statuses = [] as { + title: string, + message: string, + status: 'success' | 'error' | 'warning' + }[]; statusChecks = [ // First column: Telemetry { title: 'API Connectivity', statusMessage: 'Unknown' }, @@ -106,7 +98,7 @@ export class CopilotDashboardComponent implements OnInit { { title: 'Estimates/Daily-User Ratio', statusMessage: 'Unknown' }, { title: 'Target Levels Acquired', statusMessage: '0 Levels Acquired' } ]; - + constructor( private metricsService: MetricsService, private membersService: MembersService, @@ -122,77 +114,64 @@ export class CopilotDashboardComponent implements OnInit { const formattedSince = since.toISOString().split('T')[0]; this.installationsService.currentInstallation.pipe( - takeUntil(this.installationsService.destroy$) + takeUntil(this._destroy$.asObservable()) ).subscribe(installation => { - this.activityTotals = undefined; - this.allSeats = undefined; - this.totalMembers = undefined; - this.totalSeats = undefined; - this.seatPercentage = undefined; - this.activeToday = undefined; - this.activeWeeklyChangePercent = undefined; - this.activeCurrentWeekAverage = undefined; - this.activeLastWeekAverage = undefined; - this.totalSurveys = undefined; - this.totalSurveysThisWeek = undefined; + this.subscriptions.forEach(s => s.unsubscribe()); this.metricsData = undefined; this.activityData = undefined; - this.surveysData = undefined; - - this.surveyService.getAllSurveys().subscribe(data => { - this.surveysData = data; - this.totalSurveys = data.length; - this.totalSurveysThisWeek = data.reduce((acc, survey) => { - const surveyDate = new Date(survey.createdAt!); - const oneWeekAgo = new Date(); - oneWeekAgo.setDate(oneWeekAgo.getDate() - 7); - return surveyDate > oneWeekAgo ? acc + 1 : acc; - }, 0); - this.cdr.detectChanges(); - }); - - forkJoin({ - members: this.membersService.getAllMembers(), - seats: this.seatService.getAllSeats(installation?.account?.login) - }).subscribe(result => { - this.allSeats = result.seats; - this.totalMembers = result.members.length; - this.totalSeats = result.seats.length; - this.seatPercentage = (this.totalSeats / this.totalMembers) * 100; - }); + this.statuses = []; - this.seatService.getActivity(installation?.account?.login, 30).subscribe((activity) => { - this.activityData = activity; - this.cdr.detectChanges(); - }) + this.subscriptions.push( + this.installationsService.getStatus2().subscribe(status => { + console.log('Status:', status); + this.status = status; + this.statuses[0] = { + title: 'GitHub App', + message: status.installations.reduce((acc: number, i: any) => acc += i.repos.length, 0) + ' repositories', + status: status.installations.length > 0 ? 'success' : 'error' + }; + this.statuses[1] = { + title: 'Polling History', + message: status.seatsHistory.daysSinceOldestCreatedAt + ' days', + status: status.seatsHistory.daysSinceOldestCreatedAt > 30 ? 'success' : status.seatsHistory.daysSinceOldestCreatedAt > 5 ? 'warning' : 'error' + }; + }) + ); - this.seatService.getActivityTotals(installation?.account?.login).subscribe(totals => { - Object.keys(totals).forEach((key, index) => index > 10 ? delete totals[key] : null); - this.activityTotals = totals; - this.cdr.detectChanges(); - }); + this.subscriptions.push( + this.surveyService.getAllSurveys().subscribe(data => { + this.surveysData = data; + this.cdr.detectChanges(); + this.statuses[2] = { + title: 'Estimates Collected', + message: this.surveysData.length + ' estimates', + status: this.surveysData.length > 0 ? 'success' : 'warning' + } + }) + ) - this.metricsService.getMetrics({ - org: installation?.account?.login, - since: formattedSince, - }).subscribe(data => { - this.metricsData = data; - this.activeToday = data[data.length - 1]?.total_active_users || 0; - const currentWeekData = data.slice(-7); - this.activeCurrentWeekAverage = currentWeekData.reduce((sum, day) => - sum + day.total_active_users, 0) / currentWeekData.length; - const lastWeekData = data.slice(-14, -7); - this.activeLastWeekAverage = lastWeekData.length > 0 - ? lastWeekData.reduce((sum, day) => sum + day.total_active_users, 0) / lastWeekData.length - : 0; + this.subscriptions.push( + this.seatService.getActivity(installation?.account?.login, 30).subscribe((activity) => { + this.activityData = activity; + this.cdr.detectChanges(); + }) + ) - const percentChange = this.activeLastWeekAverage === 0 - ? 100 - : ((this.activeCurrentWeekAverage - this.activeLastWeekAverage) / this.activeLastWeekAverage) * 100; - - this.activeWeeklyChangePercent = Math.round(percentChange * 10) / 10; - this.cdr.detectChanges(); - }); + this.subscriptions.push( + this.metricsService.getMetrics({ + org: installation?.account?.login, + since: formattedSince, + }).subscribe(data => { + this.metricsData = data; + this.cdr.detectChanges(); + }) + ) }); } + + ngOnDestroy() { + this.subscriptions.forEach(s => s.unsubscribe()); + this._destroy$.next(); + this._destroy$.complete(); + } } diff --git a/frontend/src/app/main/copilot/copilot-dashboard/status/status.component.html b/frontend/src/app/main/copilot/copilot-dashboard/status/status.component.html index 5661b3ea..be5a5faf 100644 --- a/frontend/src/app/main/copilot/copilot-dashboard/status/status.component.html +++ b/frontend/src/app/main/copilot/copilot-dashboard/status/status.component.html @@ -1,14 +1,22 @@ -@for (s of status; track $index) { -
-
- {{s.title}} - {{s.statusMessage}} -
- -
- -
+
+
+ {{title}} + {{message}}
-} \ No newline at end of file + +
+ +
+
diff --git a/frontend/src/app/main/copilot/copilot-dashboard/status/status.component.scss b/frontend/src/app/main/copilot/copilot-dashboard/status/status.component.scss index 90917677..ca3590d9 100644 --- a/frontend/src/app/main/copilot/copilot-dashboard/status/status.component.scss +++ b/frontend/src/app/main/copilot/copilot-dashboard/status/status.component.scss @@ -1,12 +1,7 @@ -:host { - display: grid; - grid-template-columns: 1fr 1fr 1fr; -} - .status { display: flex; + flex-direction: row; padding: 17.6px 20px 16px 20px; - border: var(--mdc-outlined-card-outline-width) solid var(--mdc-outlined-card-outline-color, var(--mat-app-outline-variant)); .status-icon { display: flex; justify-content: center; diff --git a/frontend/src/app/main/copilot/copilot-dashboard/status/status.component.ts b/frontend/src/app/main/copilot/copilot-dashboard/status/status.component.ts index 964033ec..4de2e4ba 100644 --- a/frontend/src/app/main/copilot/copilot-dashboard/status/status.component.ts +++ b/frontend/src/app/main/copilot/copilot-dashboard/status/status.component.ts @@ -16,8 +16,9 @@ import { MatIconModule } from '@angular/material/icon'; changeDetection: ChangeDetectionStrategy.OnPush, }) export class StatusComponent { - @Input() status?: any[]; - + @Input() title?: string; + @Input() message?: string; + @Input() status?: 'success' | 'error' | 'warning' = 'error'; constructor() { } diff --git a/frontend/src/app/main/copilot/copilot-metrics/copilot-metrics.component.html b/frontend/src/app/main/copilot/copilot-metrics/copilot-metrics.component.html index 09b111ba..3ee83da6 100644 --- a/frontend/src/app/main/copilot/copilot-metrics/copilot-metrics.component.html +++ b/frontend/src/app/main/copilot/copilot-metrics/copilot-metrics.component.html @@ -3,7 +3,7 @@

Metrics

- +

@@ -14,8 +14,40 @@

Metrics

IDE Completions - + + + + + + + + Most Active Users + + + + + + + + + Engagement Breakdown + + + + + - \ No newline at end of file + + + + \ No newline at end of file diff --git a/frontend/src/app/main/copilot/copilot-metrics/copilot-metrics.component.ts b/frontend/src/app/main/copilot/copilot-metrics/copilot-metrics.component.ts index 42c0b862..c3725460 100644 --- a/frontend/src/app/main/copilot/copilot-metrics/copilot-metrics.component.ts +++ b/frontend/src/app/main/copilot/copilot-metrics/copilot-metrics.component.ts @@ -1,11 +1,18 @@ -import { Component, OnInit } from '@angular/core'; +import { ChangeDetectorRef, Component, OnInit } from '@angular/core'; import { DateRangeSelectComponent } from "../../../shared/date-range-select/date-range-select.component"; import { MetricsService } from '../../../services/api/metrics.service'; import { CopilotMetrics } from '../../../services/api/metrics.service.interfaces'; import { CopilotMetricsPieChartComponent } from './copilot-metrics-pie-chart/copilot-metrics-pie-chart.component'; import { MatCardModule } from '@angular/material/card'; import { Installation, InstallationsService } from '../../../services/api/installations.service'; -import { takeUntil } from 'rxjs'; +import { forkJoin, Subject, Subscription, takeUntil } from 'rxjs'; +import { DashboardCardBarsComponent } from '../copilot-dashboard/dashboard-card/dashboard-card-bars/dashboard-card-bars.component'; +import { DashboardCardDrilldownBarChartComponent } from '../copilot-dashboard/dashboard-card/dashboard-card-drilldown-bar-chart/dashboard-card-drilldown-bar-chart.component'; +import { ActiveUsersChartComponent } from '../copilot-dashboard/dashboard-card/active-users-chart/active-users-chart.component'; +import { SeatService } from '../../../services/api/seat.service'; +import { MembersService } from '../../../services/api/members.service'; +import { CommonModule } from '@angular/common'; +import { LoadingSpinnerComponent } from '../../../shared/loading-spinner/loading-spinner.component'; @Component({ selector: 'app-metrics', @@ -13,7 +20,12 @@ import { takeUntil } from 'rxjs'; imports: [ DateRangeSelectComponent, CopilotMetricsPieChartComponent, - MatCardModule + MatCardModule, + DashboardCardBarsComponent, + DashboardCardDrilldownBarChartComponent, + ActiveUsersChartComponent, + CommonModule, + LoadingSpinnerComponent, ], templateUrl: './copilot-metrics.component.html', styleUrls: [ @@ -25,39 +37,83 @@ export class CopilotMetricsComponent implements OnInit { metrics?: CopilotMetrics[]; metricsTotals?: CopilotMetrics; installation?: Installation = undefined; + activityTotals?: Record; + totalSeats?: number; + subscriptions: Subscription[] = []; + private readonly _destroy$ = new Subject(); + range?: { start: Date, end: Date }; constructor( private metricsService: MetricsService, - private installationsService: InstallationsService + private installationsService: InstallationsService, + private seatService: SeatService, + private cdr: ChangeDetectorRef, + private membersService: MembersService ) { } ngOnInit() { this.installationsService.currentInstallation.pipe( - takeUntil(this.installationsService.destroy$) + takeUntil(this._destroy$.asObservable()) ).subscribe(installation => { this.installation = installation; + if (this.range) { + this.dateRangeChange(this.range); + } }); } - dateRangeChange(event: {start: Date, end: Date}) { + ngOnDestroy() { + this.reset(); + this._destroy$.next(); + this._destroy$.complete(); + } + + reset() { + this.subscriptions.forEach(s => s.unsubscribe()); + this.metrics = undefined; + this.metricsTotals = undefined; + this.activityTotals = undefined; + this.totalSeats = undefined; + } + + dateRangeChange(event: { start: Date, end: Date }) { const utcStart = Date.UTC(event.start.getFullYear(), event.start.getMonth(), event.start.getDate()); const utcEnd = Date.UTC(event.end.getFullYear(), event.end.getMonth(), event.end.getDate()); const startModified = new Date(utcStart - 1); const endModified = new Date(utcEnd + 1); - this.metricsService.getMetrics({ - org: this.installation?.account?.login, - since: startModified.toISOString(), - until: endModified.toISOString() - }).subscribe((metrics) => { - this.metrics = metrics; - }); - this.metricsService.getMetricsTotals({ - org: this.installation?.account?.login, - since: startModified.toISOString(), - until: endModified.toISOString() - }).subscribe((metricsTotals) => { - this.metricsTotals = metricsTotals; - }) + this.reset(); + + this.subscriptions.push( + this.seatService.getActivityTotals({ + org: this.installation?.account?.login, + since: startModified.toISOString(), + until: endModified.toISOString() + }).subscribe(totals => { + Object.keys(totals).forEach((key, index) => index > 10 ? delete totals[key] : null); + this.activityTotals = totals; + this.cdr.detectChanges(); + }) + ) + + this.subscriptions.push( + this.metricsService.getMetrics({ + org: this.installation?.account?.login, + since: startModified.toISOString(), + until: endModified.toISOString() + }).subscribe((metrics) => { + this.metrics = metrics; + }) + ) + + this.subscriptions.push( + this.metricsService.getMetricsTotals({ + org: this.installation?.account?.login, + since: startModified.toISOString(), + until: endModified.toISOString() + }).subscribe((metricsTotals) => { + this.metricsTotals = metricsTotals; + }) + ) } } diff --git a/frontend/src/app/main/copilot/copilot-seats/copilot-seat/copilot-seat.component.html b/frontend/src/app/main/copilot/copilot-seats/copilot-seat/copilot-seat.component.html index fddd1c12..cf8d695f 100644 --- a/frontend/src/app/main/copilot/copilot-seats/copilot-seat/copilot-seat.component.html +++ b/frontend/src/app/main/copilot/copilot-seats/copilot-seat/copilot-seat.component.html @@ -1,9 +1,11 @@
diff --git a/frontend/src/app/main/copilot/copilot-seats/copilot-seats.component.ts b/frontend/src/app/main/copilot/copilot-seats/copilot-seats.component.ts index 08f3419e..612e6168 100644 --- a/frontend/src/app/main/copilot/copilot-seats/copilot-seats.component.ts +++ b/frontend/src/app/main/copilot/copilot-seats/copilot-seats.component.ts @@ -28,7 +28,7 @@ export class CopilotSeatsComponent implements OnInit { columnDef: 'login', header: 'User', cell: (element: Seat) => `${element.assignee.login}`, - link: (element: Seat) => `https://github.com/${element.assignee.login}` + // link: (element: Seat) => `https://github.com/${element.assignee.login}` }, { columnDef: 'last_activity_at', diff --git a/frontend/src/app/main/copilot/copilot-value/value.component.ts b/frontend/src/app/main/copilot/copilot-value/value.component.ts index d8a51a79..aaad5975 100644 --- a/frontend/src/app/main/copilot/copilot-value/value.component.ts +++ b/frontend/src/app/main/copilot/copilot-value/value.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit } from '@angular/core'; +import { ChangeDetectorRef, Component, OnInit } from '@angular/core'; import { AppModule } from '../../../app.module'; import { AdoptionChartComponent } from "./adoption-chart/adoption-chart.component"; import { ActivityResponse, SeatService } from '../../../services/api/seat.service'; @@ -7,7 +7,7 @@ import { TimeSavedChartComponent } from './time-saved-chart/time-saved-chart.com import { CopilotMetrics } from '../../../services/api/metrics.service.interfaces'; import { MetricsService } from '../../../services/api/metrics.service'; import { FormControl } from '@angular/forms'; -import { combineLatest, startWith, takeUntil } from 'rxjs'; +import { combineLatest, startWith, Subscription, takeUntil } from 'rxjs'; import { CopilotSurveyService, Survey } from '../../../services/api/copilot-survey.service'; import * as Highcharts from 'highcharts'; import HC_exporting from 'highcharts/modules/exporting'; @@ -71,37 +71,54 @@ export class CopilotValueComponent implements OnInit { } } }; + subscriptions = [] as Subscription[]; constructor( private seatService: SeatService, private metricsService: MetricsService, private copilotSurveyService: CopilotSurveyService, - private installationsService: InstallationsService + private installationsService: InstallationsService, + private cdr: ChangeDetectorRef ) { } ngOnInit() { this.installationsService.currentInstallation.pipe( takeUntil(this.installationsService.destroy$) ).subscribe(installation => { - combineLatest([ - this.daysInactive.valueChanges.pipe(startWith(this.daysInactive.value || 30)), - this.adoptionFidelity.valueChanges.pipe(startWith(this.adoptionFidelity.value || 'day')) - ]).subscribe(([days, fidelity]) => { - this.seatService.getActivity(installation?.account?.login, days || 30, fidelity || 'day').subscribe(data => { - this.activityData = data; - }); - }); - this.metricsService.getMetrics({ - org: installation?.account?.login, - }).subscribe(data => { - this.metricsData = data; - }); - this.copilotSurveyService.getAllSurveys(installation?.account?.login).subscribe(data => { - this.surveysData = data; - }); + this.subscriptions.forEach(s => s.unsubscribe()); + this.subscriptions = []; + + this.subscriptions.push( + combineLatest([ + this.daysInactive.valueChanges.pipe(startWith(this.daysInactive.value || 30)), + this.adoptionFidelity.valueChanges.pipe(startWith(this.adoptionFidelity.value || 'day')) + ]).subscribe(([days, fidelity]) => { + this.seatService.getActivity(installation?.account?.login, days || 30, fidelity || 'day').subscribe(data => { + this.activityData = data; + this.cdr.detectChanges(); + }); + }) + ) + this.subscriptions.push( + this.metricsService.getMetrics({ + org: installation?.account?.login, + }).subscribe(data => { + this.metricsData = data; + }) + ) + + this.subscriptions.push( + this.copilotSurveyService.getAllSurveys(installation?.account?.login).subscribe(data => { + this.surveysData = data; + }) + ) }); } + ngOnDestroy() { + this.subscriptions.forEach(s => s.unsubscribe()); + } + chartChanged(chart: Highcharts.Chart, include = true) { if (chart && !this.charts.includes(chart)) { const _chart = chart; diff --git a/frontend/src/app/services/api/installations.service.ts b/frontend/src/app/services/api/installations.service.ts index f95be51a..d5885eae 100644 --- a/frontend/src/app/services/api/installations.service.ts +++ b/frontend/src/app/services/api/installations.service.ts @@ -1,4 +1,4 @@ -import { Injectable, OnDestroy } from '@angular/core'; +import { Injectable, OnDestroy, OnInit } from '@angular/core'; import { BehaviorSubject, of, Subject, tap } from 'rxjs'; import { serverUrl } from '../server.service'; import { Endpoints } from '@octokit/types'; @@ -38,7 +38,8 @@ export class InstallationsService implements OnDestroy { } } - public ngOnDestroy(): void { + ngOnDestroy(): void { + console.log('DESTROY!'); this._destroy$.next(); this._destroy$.complete(); } @@ -72,5 +73,8 @@ export class InstallationsService implements OnDestroy { localStorage.setItem('installation', id.toString()); } + getStatus2() { + return this.http.get(`${serverUrl}/api/status`); + } } diff --git a/frontend/src/app/services/api/seat.service.ts b/frontend/src/app/services/api/seat.service.ts index b90fcacf..ef671567 100644 --- a/frontend/src/app/services/api/seat.service.ts +++ b/frontend/src/app/services/api/seat.service.ts @@ -45,9 +45,14 @@ export class SeatService { ); }; - getActivityTotals(org?: string) { + getActivityTotals(queryParams?: { + org?: string | undefined; + since?: string; + until?: string; + }) { + if (!queryParams?.org) delete queryParams?.org; return this.http.get>(`${this.apiUrl}/activity/totals`, { - params: org ? { org } : undefined + params: queryParams }); } } \ No newline at end of file diff --git a/frontend/src/styles.scss b/frontend/src/styles.scss index 9cc8f96f..dbc66c16 100644 --- a/frontend/src/styles.scss +++ b/frontend/src/styles.scss @@ -95,6 +95,6 @@ highcharts-chart { :root { --error: #93000a; /* Error */ - --success: #28a745; /* Green */ - --warning: #FFAB00; /* Orange/Yellow */ + --success: #388e3c; /* Green */ + --warning: #f57c00; /* Orange/Yellow */ } \ No newline at end of file From 4f3784974d13c281c07bcd26608dca973ae0ba97 Mon Sep 17 00:00:00 2001 From: Austen Stone Date: Fri, 6 Dec 2024 11:56:25 -0500 Subject: [PATCH 2/7] Remove unnecessary console log statements across various components and services for cleaner code --- backend/src/controllers/survey.controller.ts | 9 --------- backend/src/services/copilot.seats.service.ts | 1 - backend/src/services/status.service.ts | 7 ------- .../copilot/copilot-dashboard/dashboard.component.ts | 1 - .../copilot/copilot-dashboard/status/status.component.ts | 6 ------ .../new-copilot-survey/new-copilot-survey.component.ts | 1 - frontend/src/app/main/settings/settings.component.ts | 1 - frontend/src/app/services/api/installations.service.ts | 1 - 8 files changed, 27 deletions(-) diff --git a/backend/src/controllers/survey.controller.ts b/backend/src/controllers/survey.controller.ts index 13795534..c5418ebf 100644 --- a/backend/src/controllers/survey.controller.ts +++ b/backend/src/controllers/survey.controller.ts @@ -58,7 +58,6 @@ class SurveyController { }) res.status(201).json(survey); } catch (error) { - console.log(error); res.status(500).json(error); return; } @@ -83,14 +82,6 @@ class SurveyController { } : {} } as WhereOptions }); - console.log('test', JSON.stringify({ - reason: { - [Op.and]: [ - { [Op.ne]: '' }, - { [Op.gte]: minReasonLength } - ] - } - })); res.status(200).json(surveys); } catch (error) { res.status(500).json(error); diff --git a/backend/src/services/copilot.seats.service.ts b/backend/src/services/copilot.seats.service.ts index 2ccab328..d1e074b4 100644 --- a/backend/src/services/copilot.seats.service.ts +++ b/backend/src/services/copilot.seats.service.ts @@ -256,7 +256,6 @@ class SeatsService { // replacements: { org }, // type: QueryTypes.SELECT // }); - // console.log(assignees2); const { org, since, until } = params; const dateFilter = { ...(since && { [Op.gte]: new Date(since as string) }), diff --git a/backend/src/services/status.service.ts b/backend/src/services/status.service.ts index 70bc9620..b6aa8a77 100644 --- a/backend/src/services/status.service.ts +++ b/backend/src/services/status.service.ts @@ -24,7 +24,6 @@ class StatusService { } async getStatus(): Promise { - console.log('Getting status'); const status = {} as StatusType; const assignee = await Member.findOne(); @@ -65,12 +64,6 @@ class StatusService { status.surveyCount = surveys.length; } - const yesterday = new Date(new Date().setDate(new Date().getDate() - 1)); - const activity = await copilotSeatsService.getMembersActivity({ - since: yesterday.toISOString(), - }); - console.log(Object.keys(activity)); - return status; } } diff --git a/frontend/src/app/main/copilot/copilot-dashboard/dashboard.component.ts b/frontend/src/app/main/copilot/copilot-dashboard/dashboard.component.ts index 783f3d53..5e4d1faf 100644 --- a/frontend/src/app/main/copilot/copilot-dashboard/dashboard.component.ts +++ b/frontend/src/app/main/copilot/copilot-dashboard/dashboard.component.ts @@ -123,7 +123,6 @@ export class CopilotDashboardComponent implements OnInit, OnDestroy { this.subscriptions.push( this.installationsService.getStatus2().subscribe(status => { - console.log('Status:', status); this.status = status; this.statuses[0] = { title: 'GitHub App', diff --git a/frontend/src/app/main/copilot/copilot-dashboard/status/status.component.ts b/frontend/src/app/main/copilot/copilot-dashboard/status/status.component.ts index 4de2e4ba..5b111506 100644 --- a/frontend/src/app/main/copilot/copilot-dashboard/status/status.component.ts +++ b/frontend/src/app/main/copilot/copilot-dashboard/status/status.component.ts @@ -19,10 +19,4 @@ export class StatusComponent { @Input() title?: string; @Input() message?: string; @Input() status?: 'success' | 'error' | 'warning' = 'error'; - constructor() { - } - - ngOnInit() { - console.log(this.status); - } } diff --git a/frontend/src/app/main/copilot/copilot-surveys/new-copilot-survey/new-copilot-survey.component.ts b/frontend/src/app/main/copilot/copilot-surveys/new-copilot-survey/new-copilot-survey.component.ts index b190388d..a7877c80 100644 --- a/frontend/src/app/main/copilot/copilot-surveys/new-copilot-survey/new-copilot-survey.component.ts +++ b/frontend/src/app/main/copilot/copilot-surveys/new-copilot-survey/new-copilot-survey.component.ts @@ -98,7 +98,6 @@ export class NewCopilotSurveyComponent implements OnInit { kudos: survey.kudos ? survey.kudos + 1 : 1 }).subscribe(() => { survey.kudos = (survey.kudos || 0) + 1; - console.log(`Kudos added to survey with id ${survey.id}. Total kudos: ${survey.kudos}`); }); } } diff --git a/frontend/src/app/main/settings/settings.component.ts b/frontend/src/app/main/settings/settings.component.ts index 743b558f..38de62f2 100644 --- a/frontend/src/app/main/settings/settings.component.ts +++ b/frontend/src/app/main/settings/settings.component.ts @@ -109,7 +109,6 @@ export class SettingsComponent implements OnInit { percentCoding: this.form.controls.percentCoding.value, percentTimeSaved: this.form.controls.percentTimeSaved.value }; - console.log('Saving settings', settings) // Now you can store the settings object in the database this.settingsService.createSettings(settings).subscribe(() => { diff --git a/frontend/src/app/services/api/installations.service.ts b/frontend/src/app/services/api/installations.service.ts index d5885eae..c416600f 100644 --- a/frontend/src/app/services/api/installations.service.ts +++ b/frontend/src/app/services/api/installations.service.ts @@ -39,7 +39,6 @@ export class InstallationsService implements OnDestroy { } ngOnDestroy(): void { - console.log('DESTROY!'); this._destroy$.next(); this._destroy$.complete(); } From 82d2a2633be24ae0d89c3200b23f92dc841c8e70 Mon Sep 17 00:00:00 2001 From: Austen Stone Date: Fri, 6 Dec 2024 13:03:55 -0500 Subject: [PATCH 3/7] Comment out unused parameters and code in database and chart components for improved clarity and maintainability --- .../src/app/database/database.component.ts | 2 +- .../time-saved-chart.component.ts | 4 +- .../src/app/services/highcharts.service.ts | 60 ++++++++++--------- 3 files changed, 34 insertions(+), 32 deletions(-) diff --git a/frontend/src/app/database/database.component.ts b/frontend/src/app/database/database.component.ts index 41d55760..1876369e 100644 --- a/frontend/src/app/database/database.component.ts +++ b/frontend/src/app/database/database.component.ts @@ -64,7 +64,7 @@ export class DatabaseComponent implements AfterViewInit { }), finalize(async () => { await this.router.navigate(['/copilot'], { - queryParams: { celebrate: true } + // queryParams: { celebrate: true } }) }) ).subscribe(() => this.checkStatus()); diff --git a/frontend/src/app/main/copilot/copilot-value/time-saved-chart/time-saved-chart.component.ts b/frontend/src/app/main/copilot/copilot-value/time-saved-chart/time-saved-chart.component.ts index 65d930c1..5f80c3fc 100644 --- a/frontend/src/app/main/copilot/copilot-value/time-saved-chart/time-saved-chart.component.ts +++ b/frontend/src/app/main/copilot/copilot-value/time-saved-chart/time-saved-chart.component.ts @@ -27,7 +27,7 @@ export class TimeSavedChartComponent implements OnInit, OnChanges { text: 'Time Saved (hrs per week)' }, min: 0, - max: 12, + // max: 12, labels: { format: '{value}hrs' }, @@ -61,7 +61,7 @@ export class TimeSavedChartComponent implements OnInit, OnChanges { headerFormat: '{point.x:%b %d, %Y}
', pointFormat: [ '{series.name}: ', - '{point.y:.1f}%' + '{point.y:.1f}hrs' ].join(''), style: { fontSize: '14px' diff --git a/frontend/src/app/services/highcharts.service.ts b/frontend/src/app/services/highcharts.service.ts index dc25554b..f2342cfe 100644 --- a/frontend/src/app/services/highcharts.service.ts +++ b/frontend/src/app/services/highcharts.service.ts @@ -488,8 +488,8 @@ export class HighchartsService { ); if (dateSurveys.length > 0) { - acc[dateKey].sum = dateSurveys.reduce((sum, survey) => - sum + survey.percentTimeSaved, 0); + const avgPercentTimeSaved = dateSurveys.reduce((sum, survey) => sum + survey.percentTimeSaved, 0) + acc[dateKey].sum = avgPercentTimeSaved * 0.01 * 0.3 * 40; // TODO pull settings acc[dateKey].count = dateSurveys.length; } @@ -539,33 +539,35 @@ export class HighchartsService { lineWidth: 3 } } - }, { - type: 'scatter' as const, - name: 'Survey', - data: surveys.map(survey => ({ - x: new Date(survey.createdAt!).getTime(), - y: survey.percentTimeSaved, - raw: survey - })), - marker: { - enabled: true, - radius: 4, - symbol: 'triangle', - }, - tooltip: { - headerFormat: '{point.x:%b %d, %Y}
', - pointFormatter: function () { - return [ - `User: `, - '' + this.raw?.userId + '', - `
Time saved: `, - '' + Math.round(this.y || 0) + '%', - `
PR: `, - '#' + this.raw?.prNumber + '', - ].join(''); - } as Highcharts.FormatterCallbackFunction - } - }] + }, + // { + // type: 'scatter' as const, + // name: 'Survey', + // data: surveys.map(survey => ({ + // x: new Date(survey.createdAt!).getTime(), + // y: survey.percentTimeSaved, + // raw: survey + // })), + // marker: { + // enabled: true, + // radius: 4, + // symbol: 'triangle', + // }, + // tooltip: { + // headerFormat: '{point.x:%b %d, %Y}
', + // pointFormatter: function () { + // return [ + // `User: `, + // '' + this.raw?.userId + '', + // `
Time saved: `, + // '' + Math.round(this.y || 0) + '%', + // `
PR: `, + // '#' + this.raw?.prNumber + '', + // ].join(''); + // } as Highcharts.FormatterCallbackFunction + // } + // } + ] }; } From 088c914893bbb83fa2c9c60a0460440cc29ff7b1 Mon Sep 17 00:00:00 2001 From: Austen Stone Date: Fri, 6 Dec 2024 13:05:35 -0500 Subject: [PATCH 4/7] Refactor HighchartsService to improve code readability by adjusting formatting and commenting out unused scatter series code --- .../src/app/services/highcharts.service.ts | 109 +++++++++--------- 1 file changed, 55 insertions(+), 54 deletions(-) diff --git a/frontend/src/app/services/highcharts.service.ts b/frontend/src/app/services/highcharts.service.ts index f2342cfe..6c135e5d 100644 --- a/frontend/src/app/services/highcharts.service.ts +++ b/frontend/src/app/services/highcharts.service.ts @@ -479,22 +479,22 @@ export class HighchartsService { const surveyAverages = Object.keys(activity).reduce((acc, activityDate) => { const dateKey = activityDate.split('T')[0]; acc[dateKey] = { - sum: 0, - count: 0 + sum: 0, + count: 0 }; - - const dateSurveys = surveys.filter(survey => - new Date(survey.createdAt!).toISOString().split('T')[0] === dateKey + + const dateSurveys = surveys.filter(survey => + new Date(survey.createdAt!).toISOString().split('T')[0] === dateKey ); - + if (dateSurveys.length > 0) { - const avgPercentTimeSaved = dateSurveys.reduce((sum, survey) => sum + survey.percentTimeSaved, 0) - acc[dateKey].sum = avgPercentTimeSaved * 0.01 * 0.3 * 40; // TODO pull settings - acc[dateKey].count = dateSurveys.length; + const avgPercentTimeSaved = dateSurveys.reduce((sum, survey) => sum + survey.percentTimeSaved, 0) + acc[dateKey].sum = avgPercentTimeSaved * 0.01 * 0.3 * 40; // TODO pull settings + acc[dateKey].count = dateSurveys.length; } - + return acc; - }, {} as Record); + }, {} as Record); // Generate series with 7-day rolling average @@ -524,50 +524,51 @@ export class HighchartsService { .sort((a, b) => a.x - b.x); return { - series: [{ - name: 'Time Saved', - type: 'spline' as const, - data: seriesData, - lineWidth: 2, - marker: { - enabled: true, - radius: 4, - symbol: 'circle' - }, - states: { - hover: { - lineWidth: 3 + series: [ + { + name: 'Time Saved', + type: 'spline' as const, + data: seriesData, + lineWidth: 2, + marker: { + enabled: true, + radius: 4, + symbol: 'circle' + }, + states: { + hover: { + lineWidth: 3 + } } - } - }, - // { - // type: 'scatter' as const, - // name: 'Survey', - // data: surveys.map(survey => ({ - // x: new Date(survey.createdAt!).getTime(), - // y: survey.percentTimeSaved, - // raw: survey - // })), - // marker: { - // enabled: true, - // radius: 4, - // symbol: 'triangle', - // }, - // tooltip: { - // headerFormat: '{point.x:%b %d, %Y}
', - // pointFormatter: function () { - // return [ - // `User: `, - // '' + this.raw?.userId + '', - // `
Time saved: `, - // '' + Math.round(this.y || 0) + '%', - // `
PR: `, - // '#' + this.raw?.prNumber + '', - // ].join(''); - // } as Highcharts.FormatterCallbackFunction - // } - // } - ] + }, + // { + // type: 'scatter' as const, + // name: 'Survey', + // data: surveys.map(survey => ({ + // x: new Date(survey.createdAt!).getTime(), + // y: survey.percentTimeSaved, + // raw: survey + // })), + // marker: { + // enabled: true, + // radius: 4, + // symbol: 'triangle', + // }, + // tooltip: { + // headerFormat: '{point.x:%b %d, %Y}
', + // pointFormatter: function () { + // return [ + // `User: `, + // '' + this.raw?.userId + '', + // `
Time saved: `, + // '' + Math.round(this.y || 0) + '%', + // `
PR: `, + // '#' + this.raw?.prNumber + '', + // ].join(''); + // } as Highcharts.FormatterCallbackFunction + // } + // } + ] }; } From 5d05b587cb0b85819051b8ce8c240420d26b8460 Mon Sep 17 00:00:00 2001 From: Austen Stone Date: Fri, 6 Dec 2024 13:43:20 -0500 Subject: [PATCH 5/7] Refactor imports in status.service.ts for correct path resolution; update styles in status.component.scss for better visibility; comment out GitHub repository link in settings.component.html for future reference. --- backend/src/services/status.service.ts | 3 +-- .../copilot/copilot-dashboard/status/status.component.scss | 3 +++ frontend/src/app/main/settings/settings.component.html | 5 ++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/backend/src/services/status.service.ts b/backend/src/services/status.service.ts index b6aa8a77..000c9cfb 100644 --- a/backend/src/services/status.service.ts +++ b/backend/src/services/status.service.ts @@ -1,9 +1,8 @@ -import app from "index.js"; +import app from "../index.js"; import { Seat } from "../models/copilot.seats.model.js"; import { Survey } from "../models/survey.model.js"; import { Member } from "../models/teams.model.js"; import { Endpoints } from "@octokit/types"; -import copilotSeatsService from "./copilot.seats.service.js"; export interface StatusType { github?: boolean; diff --git a/frontend/src/app/main/copilot/copilot-dashboard/status/status.component.scss b/frontend/src/app/main/copilot/copilot-dashboard/status/status.component.scss index ca3590d9..cfac0bad 100644 --- a/frontend/src/app/main/copilot/copilot-dashboard/status/status.component.scss +++ b/frontend/src/app/main/copilot/copilot-dashboard/status/status.component.scss @@ -11,12 +11,15 @@ .error { background-color: var(--error) !important; + color:white; } .success { background-color: var(--success) !important; + color:white; } .warning { background-color: var(--warning) !important; + color:white; } \ No newline at end of file diff --git a/frontend/src/app/main/settings/settings.component.html b/frontend/src/app/main/settings/settings.component.html index 16e460f2..86b3e209 100644 --- a/frontend/src/app/main/settings/settings.component.html +++ b/frontend/src/app/main/settings/settings.component.html @@ -155,4 +155,7 @@

Advanced

- \ No newline at end of file + + From 3f3d548df2df6a5e0c7d6e132cde133ae0f817a2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Dec 2024 13:44:41 +0000 Subject: [PATCH 6/7] Bump the npm_and_yarn group in /backend with 2 updates Bumps the npm_and_yarn group in /backend with 2 updates: [path-to-regexp](https://github.com/pillarjs/path-to-regexp) and [express](https://github.com/expressjs/express). Updates `path-to-regexp` from 0.1.10 to 0.1.12 - [Release notes](https://github.com/pillarjs/path-to-regexp/releases) - [Changelog](https://github.com/pillarjs/path-to-regexp/blob/master/History.md) - [Commits](https://github.com/pillarjs/path-to-regexp/compare/v0.1.10...v0.1.12) Updates `express` from 4.21.1 to 4.21.2 - [Release notes](https://github.com/expressjs/express/releases) - [Changelog](https://github.com/expressjs/express/blob/4.21.2/History.md) - [Commits](https://github.com/expressjs/express/compare/4.21.1...4.21.2) --- updated-dependencies: - dependency-name: path-to-regexp dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: express dependency-type: direct:production dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] --- backend/package-lock.json | 22 ++++++++++++---------- backend/package.json | 2 +- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/backend/package-lock.json b/backend/package-lock.json index 9592b459..b08edaa4 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -14,7 +14,7 @@ "cron": "^3.2.1", "dotenv": "^16.4.5", "eventsource": "^2.0.2", - "express": "^4.21.1", + "express": "^4.21.2", "express-rate-limit": "^7.4.1", "mysql2": "^3.11.4", "octokit": "^4.0.2", @@ -3921,10 +3921,9 @@ } }, "node_modules/express": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", - "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", - "license": "MIT", + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", @@ -3945,7 +3944,7 @@ "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.10", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", "qs": "6.13.0", "range-parser": "~1.2.1", @@ -3960,6 +3959,10 @@ }, "engines": { "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/express-rate-limit": { @@ -6234,10 +6237,9 @@ "peer": true }, "node_modules/path-to-regexp": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", - "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", - "license": "MIT" + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" }, "node_modules/pg-connection-string": { "version": "2.7.0", diff --git a/backend/package.json b/backend/package.json index 865ee0a9..95dd141b 100644 --- a/backend/package.json +++ b/backend/package.json @@ -19,7 +19,7 @@ "cron": "^3.2.1", "dotenv": "^16.4.5", "eventsource": "^2.0.2", - "express": "^4.21.1", + "express": "^4.21.2", "express-rate-limit": "^7.4.1", "mysql2": "^3.11.4", "octokit": "^4.0.2", From 130f25dad46b2ebd63cd702fb6f1cc3963774e7c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Dec 2024 13:45:05 +0000 Subject: [PATCH 7/7] Bump the development-dependencies group across 1 directory with 5 updates Bumps the development-dependencies group with 5 updates in the /backend directory: | Package | From | To | | --- | --- | --- | | [@eslint/js](https://github.com/eslint/eslint/tree/HEAD/packages/js) | `9.15.0` | `9.16.0` | | [eslint](https://github.com/eslint/eslint) | `9.14.0` | `9.16.0` | | [globals](https://github.com/sindresorhus/globals) | `15.12.0` | `15.13.0` | | [typescript](https://github.com/microsoft/TypeScript) | `5.6.3` | `5.7.2` | | [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) | `8.14.0` | `8.17.0` | Updates `@eslint/js` from 9.15.0 to 9.16.0 - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint/eslint/commits/v9.16.0/packages/js) Updates `eslint` from 9.14.0 to 9.16.0 - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint/eslint/compare/v9.14.0...v9.16.0) Updates `globals` from 15.12.0 to 15.13.0 - [Release notes](https://github.com/sindresorhus/globals/releases) - [Commits](https://github.com/sindresorhus/globals/compare/v15.12.0...v15.13.0) Updates `typescript` from 5.6.3 to 5.7.2 - [Release notes](https://github.com/microsoft/TypeScript/releases) - [Changelog](https://github.com/microsoft/TypeScript/blob/main/azure-pipelines.release.yml) - [Commits](https://github.com/microsoft/TypeScript/compare/v5.6.3...v5.7.2) Updates `typescript-eslint` from 8.14.0 to 8.17.0 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.17.0/packages/typescript-eslint) --- updated-dependencies: - dependency-name: "@eslint/js" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: development-dependencies - dependency-name: eslint dependency-type: direct:development update-type: version-update:semver-minor dependency-group: development-dependencies - dependency-name: globals dependency-type: direct:development update-type: version-update:semver-minor dependency-group: development-dependencies - dependency-name: typescript dependency-type: direct:development update-type: version-update:semver-minor dependency-group: development-dependencies - dependency-name: typescript-eslint dependency-type: direct:development update-type: version-update:semver-minor dependency-group: development-dependencies ... Signed-off-by: dependabot[bot] --- backend/package-lock.json | 254 ++++++++++++++++---------------------- backend/package.json | 10 +- 2 files changed, 108 insertions(+), 156 deletions(-) diff --git a/backend/package-lock.json b/backend/package-lock.json index 9592b459..6c20a588 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -24,17 +24,17 @@ "why-is-node-running": "^3.2.1" }, "devDependencies": { - "@eslint/js": "^9.14.0", + "@eslint/js": "^9.16.0", "@types/bunyan": "^1.8.11", "@types/cors": "^2.8.17", "@types/eventsource": "^1.1.15", "@types/express": "^4.17.21", - "eslint": "9.14", - "globals": "^15.12.0", + "eslint": "9.16", + "globals": "^15.13.0", "ts-jest": "^29.2.5", "tsx": "^4.19.2", - "typescript": "^5.6.3", - "typescript-eslint": "^8.14.0" + "typescript": "^5.7.2", + "typescript-eslint": "^8.17.0" }, "engines": { "node": ">=18.0.0" @@ -1037,13 +1037,12 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", - "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.1.tgz", + "integrity": "sha512-fo6Mtm5mWyKjA/Chy1BYTdn5mGJoDNjC7C64ug20ADsRDGrA85bN3uK3MaKbeRkRuuIEAR5N33Jr1pbm411/PA==", "dev": true, - "license": "Apache-2.0", "dependencies": { - "@eslint/object-schema": "^2.1.4", + "@eslint/object-schema": "^2.1.5", "debug": "^4.3.1", "minimatch": "^3.1.2" }, @@ -1052,11 +1051,13 @@ } }, "node_modules/@eslint/core": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.7.0.tgz", - "integrity": "sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==", + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.9.1.tgz", + "integrity": "sha512-GuUdqkyyzQI5RMIWkHhvTWLCyLo1jNK3vzkSyaExH5kHPDHcuL2VOpHjmMY+y3+NC69qAKToBqldTBgYeLSr9Q==", "dev": true, - "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } @@ -1099,21 +1100,19 @@ } }, "node_modules/@eslint/js": { - "version": "9.15.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.15.0.tgz", - "integrity": "sha512-tMTqrY+EzbXmKJR5ToI8lxu7jaN5EdmrBFJpQk5JmSlyLsx6o4t27r883K5xsLuCYCpfKBCGswMSWXsM+jB7lg==", + "version": "9.16.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.16.0.tgz", + "integrity": "sha512-tw2HxzQkrbeuvyj1tG2Yqq+0H9wGoI2IMk4EOsQeX+vmd75FtJAzf+gTA69WF+baUKRYQ3x2kbLE08js5OsTVg==", "dev": true, - "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@eslint/object-schema": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", - "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.5.tgz", + "integrity": "sha512-o0bhxnL89h5Bae5T318nFoFzGy+YE5i/gGkoPAgkmTVdRKTiv3p8JHevPiPaMwoloKfEiiaHlawCqaZMqRm+XQ==", "dev": true, - "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } @@ -1690,7 +1689,6 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, - "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -1704,7 +1702,6 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, - "license": "MIT", "engines": { "node": ">= 8" } @@ -1714,7 +1711,6 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, - "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -2386,17 +2382,16 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.14.0.tgz", - "integrity": "sha512-tqp8H7UWFaZj0yNO6bycd5YjMwxa6wIHOLZvWPkidwbgLCsBMetQoGj7DPuAlWa2yGO3H48xmPwjhsSPPCGU5w==", + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.17.0.tgz", + "integrity": "sha512-HU1KAdW3Tt8zQkdvNoIijfWDMvdSweFYm4hWh+KwhPstv+sCmWb89hCIP8msFm9N1R/ooh9honpSuvqKWlYy3w==", "dev": true, - "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.14.0", - "@typescript-eslint/type-utils": "8.14.0", - "@typescript-eslint/utils": "8.14.0", - "@typescript-eslint/visitor-keys": "8.14.0", + "@typescript-eslint/scope-manager": "8.17.0", + "@typescript-eslint/type-utils": "8.17.0", + "@typescript-eslint/utils": "8.17.0", + "@typescript-eslint/visitor-keys": "8.17.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -2420,16 +2415,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.14.0.tgz", - "integrity": "sha512-2p82Yn9juUJq0XynBXtFCyrBDb6/dJombnz6vbo6mgQEtWHfvHbQuEa9kAOVIt1c9YFwi7H6WxtPj1kg+80+RA==", + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.17.0.tgz", + "integrity": "sha512-Drp39TXuUlD49F7ilHHCG7TTg8IkA+hxCuULdmzWYICxGXvDXmDmWEjJYZQYgf6l/TFfYNE167m7isnc3xlIEg==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "8.14.0", - "@typescript-eslint/types": "8.14.0", - "@typescript-eslint/typescript-estree": "8.14.0", - "@typescript-eslint/visitor-keys": "8.14.0", + "@typescript-eslint/scope-manager": "8.17.0", + "@typescript-eslint/types": "8.17.0", + "@typescript-eslint/typescript-estree": "8.17.0", + "@typescript-eslint/visitor-keys": "8.17.0", "debug": "^4.3.4" }, "engines": { @@ -2449,14 +2443,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.14.0.tgz", - "integrity": "sha512-aBbBrnW9ARIDn92Zbo7rguLnqQ/pOrUguVpbUwzOhkFg2npFDwTgPGqFqE0H5feXcOoJOfX3SxlJaKEVtq54dw==", + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.17.0.tgz", + "integrity": "sha512-/ewp4XjvnxaREtqsZjF4Mfn078RD/9GmiEAtTeLQ7yFdKnqwTOgRMSvFz4et9U5RiJQ15WTGXPLj89zGusvxBg==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.14.0", - "@typescript-eslint/visitor-keys": "8.14.0" + "@typescript-eslint/types": "8.17.0", + "@typescript-eslint/visitor-keys": "8.17.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2467,14 +2460,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.14.0.tgz", - "integrity": "sha512-Xcz9qOtZuGusVOH5Uk07NGs39wrKkf3AxlkK79RBK6aJC1l03CobXjJbwBPSidetAOV+5rEVuiT1VSBUOAsanQ==", + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.17.0.tgz", + "integrity": "sha512-q38llWJYPd63rRnJ6wY/ZQqIzPrBCkPdpIsaCfkR3Q4t3p6sb422zougfad4TFW9+ElIFLVDzWGiGAfbb/v2qw==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.14.0", - "@typescript-eslint/utils": "8.14.0", + "@typescript-eslint/typescript-estree": "8.17.0", + "@typescript-eslint/utils": "8.17.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -2485,6 +2477,9 @@ "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + }, "peerDependenciesMeta": { "typescript": { "optional": true @@ -2492,11 +2487,10 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.14.0.tgz", - "integrity": "sha512-yjeB9fnO/opvLJFAsPNYlKPnEM8+z4og09Pk504dkqonT02AyL5Z9SSqlE0XqezS93v6CXn49VHvB2G7XSsl0g==", + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.17.0.tgz", + "integrity": "sha512-gY2TVzeve3z6crqh2Ic7Cr+CAv6pfb0Egee7J5UAVWCpVvDI/F71wNfolIim4FE6hT15EbpZFVUj9j5i38jYXA==", "dev": true, - "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -2506,14 +2500,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.14.0.tgz", - "integrity": "sha512-OPXPLYKGZi9XS/49rdaCbR5j/S14HazviBlUQFvSKz3npr3NikF+mrgK7CFVur6XEt95DZp/cmke9d5i3vtVnQ==", + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.17.0.tgz", + "integrity": "sha512-JqkOopc1nRKZpX+opvKqnM3XUlM7LpFMD0lYxTqOTKQfCWAmxw45e3qlOCsEqEB2yuacujivudOFpCnqkBDNMw==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "8.14.0", - "@typescript-eslint/visitor-keys": "8.14.0", + "@typescript-eslint/types": "8.17.0", + "@typescript-eslint/visitor-keys": "8.17.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -2539,7 +2532,6 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } @@ -2549,7 +2541,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -2565,7 +2556,6 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, - "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -2574,16 +2564,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.14.0.tgz", - "integrity": "sha512-OGqj6uB8THhrHj0Fk27DcHPojW7zKwKkPmHXHvQ58pLYp4hy8CSUdTKykKeh+5vFqTTVmjz0zCOOPKRovdsgHA==", + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.17.0.tgz", + "integrity": "sha512-bQC8BnEkxqG8HBGKwG9wXlZqg37RKSMY7v/X8VEWD8JG2JuTHuNK0VFvMPMUKQcbk6B+tf05k+4AShAEtCtJ/w==", "dev": true, - "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.14.0", - "@typescript-eslint/types": "8.14.0", - "@typescript-eslint/typescript-estree": "8.14.0" + "@typescript-eslint/scope-manager": "8.17.0", + "@typescript-eslint/types": "8.17.0", + "@typescript-eslint/typescript-estree": "8.17.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2594,17 +2583,21 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.14.0.tgz", - "integrity": "sha512-vG0XZo8AdTH9OE6VFRwAZldNc7qtJ/6NLGWak+BtENuEUXGZgFpihILPiBvKXvJ2nFu27XNGC6rKiwuaoMbYzQ==", + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.17.0.tgz", + "integrity": "sha512-1Hm7THLpO6ww5QU6H/Qp+AusUUl+z/CAm3cNZZ0jQvon9yicgO7Rwd+/WWRpMKLYV6p2UvdbR27c86rzCPpreg==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.14.0", - "eslint-visitor-keys": "^3.4.3" + "@typescript-eslint/types": "8.17.0", + "eslint-visitor-keys": "^4.2.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2614,19 +2607,6 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -3670,27 +3650,26 @@ } }, "node_modules/eslint": { - "version": "9.14.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.14.0.tgz", - "integrity": "sha512-c2FHsVBr87lnUtjP4Yhvk4yEhKrQavGafRA/Se1ouse8PfbfC/Qh9Mxa00yWsZRlqeUB9raXip0aiiUZkgnr9g==", + "version": "9.16.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.16.0.tgz", + "integrity": "sha512-whp8mSQI4C8VXd+fLgSM0lh3UlmcFtVwUQjyKCFfsp+2ItAIYhlq/hqGahGqHE6cv9unM41VlqKk2VtKYR2TaA==", "dev": true, - "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.18.0", - "@eslint/core": "^0.7.0", - "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.14.0", - "@eslint/plugin-kit": "^0.2.0", + "@eslint/config-array": "^0.19.0", + "@eslint/core": "^0.9.0", + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "9.16.0", + "@eslint/plugin-kit": "^0.2.3", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.0", + "@humanwhocodes/retry": "^0.4.1", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", + "cross-spawn": "^7.0.5", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.2.0", @@ -3709,8 +3688,7 @@ "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "text-table": "^0.2.0" + "optionator": "^0.9.3" }, "bin": { "eslint": "bin/eslint.js" @@ -3760,16 +3738,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/@eslint/js": { - "version": "9.14.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.14.0.tgz", - "integrity": "sha512-pFoEtFWCPyDOl+C6Ift+wC7Ro89otjigCf5vcuWqWgqNSQbRrpjSvdeE6ofLz4dHmyxD5f7gIdGT4+p36L6Twg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, "node_modules/espree": { "version": "10.3.0", "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", @@ -4004,7 +3972,6 @@ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, - "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -4021,7 +3988,6 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, - "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -4048,7 +4014,6 @@ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dev": true, - "license": "ISC", "dependencies": { "reusify": "^1.0.4" } @@ -4369,11 +4334,10 @@ } }, "node_modules/globals": { - "version": "15.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-15.12.0.tgz", - "integrity": "sha512-1+gLErljJFhbOVyaetcwJiJ4+eLe45S2E7P5UiZ9xGfeq3ATQf5DOv9G7MH3gGbKQLkzmNh2DxfZwLdw+j6oTQ==", + "version": "15.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.13.0.tgz", + "integrity": "sha512-49TewVEz0UxZjr1WYYsWpPrhyC/B/pA8Bq0fUmet2n+eR7yn0IvNzNaoBwnK6mdkzcN+se7Ez9zUgULTz2QH4g==", "dev": true, - "license": "MIT", "engines": { "node": ">=18" }, @@ -4404,8 +4368,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/has-flag": { "version": "4.0.0", @@ -5734,7 +5697,6 @@ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 8" } @@ -6480,8 +6442,7 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "license": "MIT" + ] }, "node_modules/range-parser": { "version": "1.2.1", @@ -6612,7 +6573,6 @@ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true, - "license": "MIT", "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -6669,7 +6629,6 @@ "url": "https://feross.org/support" } ], - "license": "MIT", "dependencies": { "queue-microtask": "^1.2.2" } @@ -7171,13 +7130,6 @@ "node": ">=8" } }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true, - "license": "MIT" - }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -7224,11 +7176,10 @@ "license": "MIT" }, "node_modules/ts-api-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.0.tgz", - "integrity": "sha512-032cPxaEKwM+GT3vA5JXNzIaizx388rhsSW79vGRNGXfRRAdEAn2mvk36PvK5HnOchyWZ7afLEXqYCvPCrzuzQ==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", + "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", "dev": true, - "license": "MIT", "engines": { "node": ">=16" }, @@ -7370,11 +7321,10 @@ } }, "node_modules/typescript": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", - "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", + "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", "dev": true, - "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -7384,15 +7334,14 @@ } }, "node_modules/typescript-eslint": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.14.0.tgz", - "integrity": "sha512-K8fBJHxVL3kxMmwByvz8hNdBJ8a0YqKzKDX6jRlrjMuNXyd5T2V02HIq37+OiWXvUUOXgOOGiSSOh26Mh8pC3w==", + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.17.0.tgz", + "integrity": "sha512-409VXvFd/f1br1DCbuKNFqQpXICoTB+V51afcwG1pn1a3Cp92MqAUges3YjwEdQ0cMUoCIodjVDAYzyD8h3SYA==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.14.0", - "@typescript-eslint/parser": "8.14.0", - "@typescript-eslint/utils": "8.14.0" + "@typescript-eslint/eslint-plugin": "8.17.0", + "@typescript-eslint/parser": "8.17.0", + "@typescript-eslint/utils": "8.17.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7401,6 +7350,9 @@ "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + }, "peerDependenciesMeta": { "typescript": { "optional": true diff --git a/backend/package.json b/backend/package.json index 865ee0a9..c372f995 100644 --- a/backend/package.json +++ b/backend/package.json @@ -29,17 +29,17 @@ "why-is-node-running": "^3.2.1" }, "devDependencies": { - "@eslint/js": "^9.14.0", + "@eslint/js": "^9.16.0", "@types/bunyan": "^1.8.11", "@types/cors": "^2.8.17", "@types/eventsource": "^1.1.15", "@types/express": "^4.17.21", - "eslint": "9.14", - "globals": "^15.12.0", + "eslint": "9.16", + "globals": "^15.13.0", "ts-jest": "^29.2.5", "tsx": "^4.19.2", - "typescript": "^5.6.3", - "typescript-eslint": "^8.14.0" + "typescript": "^5.7.2", + "typescript-eslint": "^8.17.0" }, "engines": { "node": ">=18.0.0"