-
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
cce3083
commit 5151ef6
Showing
9 changed files
with
276 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
17 changes: 17 additions & 0 deletions
17
src/SIL.XForge.Scripture/ClientApp/src/app/event-metrics/event-metric.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
export interface EventMetric { | ||
id: string; | ||
eventType: string; | ||
payload: { [key: string]: any }; | ||
projectId?: string; | ||
scope: EventScope; | ||
timeStamp: string; | ||
userId?: string; | ||
} | ||
|
||
export enum EventScope { | ||
None = 'None', | ||
Settings = 'Settings', | ||
Sync = 'Sync', | ||
Drafting = 'Drafting', | ||
Checking = 'Checking' | ||
} |
29 changes: 29 additions & 0 deletions
29
src/SIL.XForge.Scripture/ClientApp/src/app/event-metrics/event-metrics-log.component.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
@if (!isLoading) { | ||
<table mat-table id="event-metrics-log-table" [dataSource]="rows"> | ||
<tr mat-header-row *matHeaderRowDef="columnsToDisplay"></tr> | ||
<tr mat-row *matRowDef="let row; columns: columnsToDisplay"></tr> | ||
<ng-container matColumnDef="scope"> | ||
<th mat-header-cell *matHeaderCellDef>Scope</th> | ||
<td mat-cell *matCellDef="let row"> | ||
{{ row.scope }} | ||
</td> | ||
</ng-container> | ||
<ng-container matColumnDef="eventType"> | ||
<th mat-header-cell *matHeaderCellDef>Event</th> | ||
<td mat-cell *matCellDef="let row"> | ||
{{ row.eventType }} | ||
</td> | ||
</ng-container> | ||
<ng-container matColumnDef="author"> | ||
<th mat-header-cell *matHeaderCellDef>Author</th> | ||
<td mat-cell *matCellDef="let row"> | ||
<app-owner | ||
[ownerRef]="row.userId" | ||
[includeAvatar]="true" | ||
[layoutStacked]="false" | ||
[dateTime]="row.timeStamp" | ||
></app-owner> | ||
</td> | ||
</ng-container> | ||
</table> | ||
} |
Empty file.
102 changes: 102 additions & 0 deletions
102
src/SIL.XForge.Scripture/ClientApp/src/app/event-metrics/event-metrics-log.component.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; | ||
import { provideHttpClientTesting } from '@angular/common/http/testing'; | ||
import { DebugElement, getDebugNode } from '@angular/core'; | ||
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; | ||
import { By } from '@angular/platform-browser'; | ||
import { NoopAnimationsModule } from '@angular/platform-browser/animations'; | ||
import { RouterModule } from '@angular/router'; | ||
import { BehaviorSubject } from 'rxjs'; | ||
import { anything, mock, when } from 'ts-mockito'; | ||
import { ActivatedProjectService } from 'xforge-common/activated-project.service'; | ||
import { AuthService } from 'xforge-common/auth.service'; | ||
import { NoticeService } from 'xforge-common/notice.service'; | ||
import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; | ||
import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; | ||
import { UICommonModule } from 'xforge-common/ui-common.module'; | ||
import { UserService } from 'xforge-common/user.service'; | ||
import { SF_TYPE_REGISTRY } from '../core/models/sf-type-registry'; | ||
import { SFProjectService } from '../core/sf-project.service'; | ||
import { EventMetric, EventScope } from './event-metric'; | ||
import { EventMetricsLogComponent } from './event-metrics-log.component'; | ||
|
||
const mockedActivatedProjectService = mock(ActivatedProjectService); | ||
const mockedAuthService = mock(AuthService); | ||
const mockedNoticeService = mock(NoticeService); | ||
const mockedProjectService = mock(SFProjectService); | ||
const mockedUserService = mock(UserService); | ||
|
||
describe('EventMetricsLogComponent', () => { | ||
configureTestingModule(() => ({ | ||
imports: [ | ||
EventMetricsLogComponent, | ||
NoopAnimationsModule, | ||
RouterModule.forRoot([]), | ||
UICommonModule, | ||
TestTranslocoModule, | ||
TestRealtimeModule.forRoot(SF_TYPE_REGISTRY) | ||
], | ||
providers: [ | ||
{ provide: AuthService, useMock: mockedAuthService }, | ||
{ provide: ActivatedProjectService, useMock: mockedActivatedProjectService }, | ||
{ provide: NoticeService, useMock: mockedNoticeService }, | ||
{ provide: SFProjectService, useMock: mockedProjectService }, | ||
{ provide: UserService, useMock: mockedUserService }, | ||
provideHttpClient(withInterceptorsFromDi()), | ||
provideHttpClientTesting() | ||
] | ||
})); | ||
|
||
it('should not display table if no event metrics', fakeAsync(() => { | ||
const env = new TestEnvironment(); | ||
env.wait(); | ||
env.wait(); | ||
|
||
expect(env.table).toBeNull(); | ||
})); | ||
|
||
it('should display event metrics', fakeAsync(() => { | ||
const env = new TestEnvironment(); | ||
env.populateEventMetrics(); | ||
env.wait(); | ||
env.wait(); | ||
|
||
expect(env.rows.length).toEqual(1); | ||
})); | ||
}); | ||
|
||
class TestEnvironment { | ||
readonly component: EventMetricsLogComponent; | ||
readonly fixture: ComponentFixture<EventMetricsLogComponent>; | ||
|
||
mockProjectId = 'project01'; | ||
|
||
constructor() { | ||
const mockProjectId$ = new BehaviorSubject<string>(this.mockProjectId); | ||
when(mockedActivatedProjectService.projectId).thenReturn(this.mockProjectId); | ||
when(mockedActivatedProjectService.projectId$).thenReturn(mockProjectId$); | ||
when(mockedUserService.currentUserId).thenReturn('user01'); | ||
when(mockedProjectService.onlineEventMetrics(anything(), anything(), anything())).thenReturn(null); | ||
|
||
this.fixture = TestBed.createComponent(EventMetricsLogComponent); | ||
this.component = this.fixture.componentInstance; | ||
} | ||
|
||
get table(): DebugElement { | ||
return this.fixture.debugElement.query(By.css('#event-metrics-log-table')); | ||
} | ||
|
||
get rows(): DebugElement[] { | ||
return Array.from(this.table.nativeElement.querySelectorAll('tbody tr')).map(r => getDebugNode(r) as DebugElement); | ||
} | ||
|
||
populateEventMetrics(): void { | ||
when(mockedProjectService.onlineEventMetrics(anything(), anything(), anything())).thenReturn( | ||
Promise.resolve([{ scope: EventScope.Settings, timeStamp: new Date().toISOString() } as EventMetric]) | ||
); | ||
} | ||
|
||
wait(): void { | ||
this.fixture.detectChanges(); | ||
tick(); | ||
} | ||
} |
108 changes: 108 additions & 0 deletions
108
src/SIL.XForge.Scripture/ClientApp/src/app/event-metrics/event-metrics-log.component.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
import { Component, OnInit } from '@angular/core'; | ||
import { switchMap } from 'rxjs'; | ||
import { ActivatedProjectService } from 'xforge-common/activated-project.service'; | ||
import { DataLoadingComponent } from 'xforge-common/data-loading-component'; | ||
import { I18nService } from 'xforge-common/i18n.service'; | ||
import { NoticeService } from 'xforge-common/notice.service'; | ||
import { OwnerComponent } from 'xforge-common/owner/owner.component'; | ||
import { UICommonModule } from 'xforge-common/ui-common.module'; | ||
import { filterNullish } from 'xforge-common/util/rxjs-util'; | ||
import { SFProjectService } from '../core/sf-project.service'; | ||
import { EventMetric } from './event-metric'; | ||
|
||
interface Row { | ||
eventType: string; | ||
scope: string; | ||
timeStamp: string; | ||
userId: string; | ||
} | ||
|
||
@Component({ | ||
selector: 'app-event-metrics-log', | ||
templateUrl: './event-metrics-log.component.html', | ||
styleUrls: ['./event-metrics-log.component.scss'], | ||
standalone: true, | ||
imports: [UICommonModule, OwnerComponent] | ||
}) | ||
export class EventMetricsLogComponent extends DataLoadingComponent implements OnInit { | ||
columnsToDisplay: string[] = ['scope', 'eventType', 'author']; | ||
rows: Row[] = []; | ||
|
||
pageIndex: number = 0; | ||
pageSize: number = 50; | ||
|
||
private eventMetrics?: Readonly<EventMetric[]>; | ||
|
||
constructor( | ||
noticeService: NoticeService, | ||
private readonly i18n: I18nService, | ||
private readonly activatedProjectService: ActivatedProjectService, | ||
private readonly projectService: SFProjectService | ||
) { | ||
super(noticeService); | ||
} | ||
|
||
get isLoading(): boolean { | ||
return this.eventMetrics == null; | ||
} | ||
|
||
ngOnInit(): void { | ||
this.loadingStarted(); | ||
this.subscribe( | ||
this.activatedProjectService.projectId$.pipe( | ||
filterNullish(), | ||
switchMap(async projectId => { | ||
this.eventMetrics = await this.projectService.onlineEventMetrics(projectId, this.pageIndex, this.pageSize); | ||
this.generateRows(); | ||
this.loadingFinished(); | ||
}) | ||
) | ||
); | ||
} | ||
|
||
private generateRows(): void { | ||
if (this.eventMetrics == null) { | ||
return; | ||
} | ||
|
||
const rows: Row[] = []; | ||
for (const eventMetric of this.eventMetrics) { | ||
rows.push({ | ||
eventType: this.getEventType(eventMetric.eventType), | ||
scope: eventMetric.scope, | ||
timeStamp: this.i18n.formatDate(new Date(eventMetric.timeStamp), { showTimeZone: true }), | ||
userId: eventMetric.userId | ||
}); | ||
} | ||
this.rows = rows; | ||
} | ||
|
||
private getEventType(eventType: string): string { | ||
// These values are the functions that have the LogEventMetric attribute, where: | ||
// - The case is the name of the method | ||
// - The return value is a user friendly description of what the method does | ||
// NOTE: These values are not localized, but can be localized if needed. | ||
switch (eventType) { | ||
case 'CancelPreTranslationBuildAsync': | ||
return 'Cancel draft generation'; | ||
case 'CancelSyncAsync': | ||
return 'Cancel synchronization with Paratext'; | ||
case 'SetDraftAppliedAsync': | ||
return "Updated the chapter's draft applied status"; | ||
case 'SetIsValidAsync': | ||
return 'Marked chapter as valid/invalid'; | ||
case 'SetPreTranslateAsync': | ||
return 'Set drafting as enabled/disabled for the project'; | ||
case 'SetServalConfigAsync': | ||
return 'Manually update drafting configuration for the project'; | ||
case 'StartBuildAsync': | ||
return 'Begin training translation suggestions'; | ||
case 'StartPreTranslationBuildAsync': | ||
return 'Start draft generation'; | ||
case 'SyncAsync': | ||
return 'Synchronize with Paratext'; | ||
default: | ||
return eventType; | ||
} | ||
} | ||
} |
1 change: 1 addition & 0 deletions
1
src/SIL.XForge.Scripture/ClientApp/src/app/event-metrics/event-metrics.component.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
<h1>Event Log</h1> | ||
<app-event-metrics-log></app-event-metrics-log> |
3 changes: 2 additions & 1 deletion
3
src/SIL.XForge.Scripture/ClientApp/src/app/event-metrics/event-metrics.component.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,11 @@ | ||
import { Component } from '@angular/core'; | ||
import { EventMetricsLogComponent } from './event-metrics-log.component'; | ||
|
||
@Component({ | ||
selector: 'app-event-metrics', | ||
templateUrl: './event-metrics.component.html', | ||
styleUrls: ['./event-metrics.component.scss'], | ||
standalone: true, | ||
imports: [] | ||
imports: [EventMetricsLogComponent] | ||
}) | ||
export class EventMetricsComponent {} |