diff --git a/src/app/group-monitor/backend.service.ts b/src/app/group-monitor/backend.service.ts index cf4b616b32a040208563104bd9d9a3f7b9c70c89..4c5c002bb84410149182572bd8b20d9de0cdcdbf 100644 --- a/src/app/group-monitor/backend.service.ts +++ b/src/app/group-monitor/backend.service.ts @@ -21,7 +21,7 @@ export class BackendService extends WebsocketBackendService<TestSession[]> { public getBooklet(bookletName: string): Observable<string|BookletError> { - console.log("load booklet for " + bookletName); + console.log('load booklet for ' + bookletName); const headers = new HttpHeaders({ 'Content-Type': 'text/xml' }).set('Accept', 'text/xml'); @@ -38,7 +38,8 @@ export class BackendService extends WebsocketBackendService<TestSession[]> { // TODO interceptor be omitted return of(missingFileError); } else { - // TODO should interceptor should have interfered and moved to error-page https://github.com/iqb-berlin/testcenter-frontend/issues/53 + // TODO should interceptor should have interfered and moved to error-page ... + // https://github.com/iqb-berlin/testcenter-frontend/issues/53 return of(generalError); } }) @@ -50,8 +51,8 @@ export class BackendService extends WebsocketBackendService<TestSession[]> { return this.http .get<GroupData>(this.serverUrl + `monitor/group/${groupName}`) .pipe(catchError(() => { - - // TODO interceptor should have interfered and moved to error-page https://github.com/iqb-berlin/testcenter-frontend/issues/53 + // TODO interceptor should have interfered and moved to error-page ... + // https://github.com/iqb-berlin/testcenter-frontend/issues/53 console.warn(`failed: monitor/group/${groupName}`); return of(<GroupData>{ name: 'error', diff --git a/src/app/group-monitor/booklet.service.spec.ts b/src/app/group-monitor/booklet.service.spec.ts index c09c2d42d23576b4d34bdaf5b9db731e6951a840..2095f24c09db5abd13b7541f7f434fbcc694074a 100644 --- a/src/app/group-monitor/booklet.service.spec.ts +++ b/src/app/group-monitor/booklet.service.spec.ts @@ -76,7 +76,7 @@ fdescribe('BookletService', () => { it('xmlCountChildrenOfTagNames() should count all (grand-)children of the defined types', () => { const domParser = new DOMParser(); - const testXml = "<root><a>x<b>x</b><b /><b></b></a><b><!-- ! --><c>x</c>x</b><a><b></b></a>x</root>"; + const testXml = '<root><a>x<b>x</b><b /><b></b></a><b><!-- ! --><c>x</c>x</b><a><b></b></a>x</root>'; const testContent = domParser.parseFromString(testXml, 'text/xml').documentElement; let result = BookletService['xmlCountChildrenOfTagNames'](testContent, ['a']); diff --git a/src/app/group-monitor/group-monitor-routing.module.ts b/src/app/group-monitor/group-monitor-routing.module.ts index 858bbd119d3b56e5425ea56e17702de21402d7cc..491e4c7aa40aed0094de3ae87d6988170cbffed8 100644 --- a/src/app/group-monitor/group-monitor-routing.module.ts +++ b/src/app/group-monitor/group-monitor-routing.module.ts @@ -1,6 +1,6 @@ import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; -import {GroupMonitorComponent} from "./group-monitor.component"; +import {GroupMonitorComponent} from './group-monitor.component'; const routes: Routes = [ diff --git a/src/app/group-monitor/group-monitor.component.html b/src/app/group-monitor/group-monitor.component.html index 07a372abd647820fcfab4913b26a4dc85a02c3cd..dc7f571ed3cbbb6c979de846e2cd5c3bfd8a2f9e 100644 --- a/src/app/group-monitor/group-monitor.component.html +++ b/src/app/group-monitor/group-monitor.component.html @@ -68,12 +68,12 @@ </tr> </thead> - <test-view + <tc-test-view *ngFor="let session of sessions$ | async; trackBy: trackSession" [testSession]="session" [displayOptions]="displayOptions" > - </test-view> + </tc-test-view> </table> <!-- <p>Connected Admins: {{clientCount$ | async}}</p>--> diff --git a/src/app/group-monitor/group-monitor.component.ts b/src/app/group-monitor/group-monitor.component.ts index 727b9e31e6b819d220ffaf6011189ba342988d00..852bbd626f3c7188abb1e7d567dce3fe69ae9ac7 100644 --- a/src/app/group-monitor/group-monitor.component.ts +++ b/src/app/group-monitor/group-monitor.component.ts @@ -14,7 +14,6 @@ import {Sort} from '@angular/material/sort'; styleUrls: ['./group-monitor.component.css'] }) export class GroupMonitorComponent implements OnInit, OnDestroy { - private routingSubscription: Subscription = null; ownGroup$: Observable<GroupData>; @@ -34,13 +33,10 @@ export class GroupMonitorComponent implements OnInit, OnDestroy { private bs: BackendService, ) {} - ngOnInit(): void { - this.autoSelectViewMode(); this.routingSubscription = this.route.params.subscribe(params => { - this.ownGroup$ = this.bs.getGroupData(params['group-name']); }); @@ -54,19 +50,15 @@ export class GroupMonitorComponent implements OnInit, OnDestroy { this.connectionStatus$ = this.bs.connectionStatus$; } - ngOnDestroy() { - if (this.routingSubscription !== null) { this.routingSubscription.unsubscribe(); } this.bs.cutConnection(); } - @HostListener('window:resize', ['$event']) autoSelectViewMode(): void { - const screenWidth = window.innerWidth; if (screenWidth > 1200) { this.displayOptions.view = 'full'; @@ -77,33 +69,27 @@ export class GroupMonitorComponent implements OnInit, OnDestroy { } } - trackSession(index: number, session: TestSession): number { - return session.personId * 10000 + session.testId; } - sortSessions(sort: Sort, sessions: TestSession[]): TestSession[] { - return sessions.sort( (testSession1, testSession2) => { - if (sort.active === "timestamp") { + if (sort.active === 'timestamp') { return (testSession2.timestamp - testSession1.timestamp) * (sort.direction === 'asc' ? 1 : -1); } - const stringA = (testSession1[sort.active] || "zzzzz"); - const stringB = (testSession2[sort.active] || "zzzzz"); + const stringA = (testSession1[sort.active] || 'zzzzz'); + const stringB = (testSession2[sort.active] || 'zzzzz'); return stringA.localeCompare(stringB) * (sort.direction === 'asc' ? 1 : -1); } - ) + ); } - setTableSorting(sort: Sort): void { - if (!sort.active || sort.direction === '') { return; } @@ -111,9 +97,7 @@ export class GroupMonitorComponent implements OnInit, OnDestroy { this.sortBy$.next(sort); } - setDisplayOption(option: string, value: TestViewDisplayOptions[TestViewDisplayOptionKey]): void { - this.displayOptions[option] = value; } } diff --git a/src/app/group-monitor/group-monitor.interfaces.ts b/src/app/group-monitor/group-monitor.interfaces.ts index 8a0a11593f4402e26ad808948fd1fbca399c4ee7..a4c1a334404c088af5e2ef9028c7324cf96fa3e2 100644 --- a/src/app/group-monitor/group-monitor.interfaces.ts +++ b/src/app/group-monitor/group-monitor.interfaces.ts @@ -27,7 +27,7 @@ export interface Booklet { } export interface BookletError { - error: 'xml' | 'missing-id' | 'missing-file' | 'general', + error: 'xml' | 'missing-id' | 'missing-file' | 'general'; } export interface BookletMetadata { @@ -45,7 +45,7 @@ export interface Testlet { label: string; restrictions?: Restrictions; children: (Unit|Testlet)[]; - descendantCount: number + descendantCount: number; } export interface Unit { @@ -58,7 +58,7 @@ export interface Restrictions { codeToEnter?: { code: string; message: string; - } + }; timeMax?: { minutes: number }; diff --git a/src/app/group-monitor/group-monitor.module.ts b/src/app/group-monitor/group-monitor.module.ts index 886d9fa8fb35bc4b2e312de874daf8548907fd52..a4f0c2a9544d0a6c055c07ee5748769346219392 100644 --- a/src/app/group-monitor/group-monitor.module.ts +++ b/src/app/group-monitor/group-monitor.module.ts @@ -6,7 +6,7 @@ import { GroupMonitorComponent } from './group-monitor.component'; import {MatTableModule} from '@angular/material/table'; import {MatTooltipModule} from '@angular/material/tooltip'; -import { MatChipsModule } from "@angular/material/chips"; +import { MatChipsModule } from '@angular/material/chips'; import { CdkTableModule } from '@angular/cdk/table'; import {BackendService} from './backend.service'; @@ -20,7 +20,6 @@ import {MatMenuModule} from '@angular/material/menu'; import {MatButtonModule} from '@angular/material/button'; - @NgModule({ declarations: [ GroupMonitorComponent, diff --git a/src/app/group-monitor/test-view/test-view.component.spec.ts b/src/app/group-monitor/test-view/test-view.component.spec.ts index 312b45787cd3e5942824989696cb5ce5e50fd611..6dd616e88037db203e45a3f921e549743986bf74 100644 --- a/src/app/group-monitor/test-view/test-view.component.spec.ts +++ b/src/app/group-monitor/test-view/test-view.component.spec.ts @@ -32,14 +32,14 @@ const exampleBooklet: Booklet = { // labels are: {global index}-{ancestor index} ]} ]} ]} -} +}; const exampleSession: TestSession = { personId: 0, testState: {}, timestamp: 0, unitState: {} -} +}; class MockBookletService { @@ -51,7 +51,7 @@ class MockBookletService { return of(false); } - if (bookletName == 'test') { + if (bookletName === 'test') { return of(exampleBooklet); } @@ -82,7 +82,7 @@ fdescribe('TestViewComponent', () => { fixture = TestBed.createComponent(TestViewComponent); component = fixture.componentInstance; - component.testSession = exampleSession + component.testSession = exampleSession; component.displayOptions = {groupColumn: undefined, view: undefined}; fixture.detectChanges(); }); @@ -136,27 +136,27 @@ fdescribe('TestViewComponent', () => { 'unit-8': {global: 7, ancestor: 2, local: 2, parentName: 'root', ancestorName: 'root'}, 'unit-9': {global: 8, ancestor: 0, local: 0, parentName: 'ellie', ancestorName: 'ellie'}, 'unit-10': {global: 9, ancestor: 1, local: 0, parentName: 'fred', ancestorName: 'ellie'}, - } + }; - for (let i = 0; i < 11; i++ ){ + for (let i = 0; i < 11; i++ ) { const result = component.getUnitContext(exampleBooklet.units, 'unit-' + i); const expectation = expectations['unit-' + i]; - expect(result.indexGlobal).withContext("global index of unit-" + i).toEqual(expectation.global); - expect(result.indexAncestor).withContext("ancestor-index of unit-" + i).toEqual(expectation.ancestor); - expect(result.indexLocal).withContext("local index of unit-" + i).toEqual(expectation.local); + expect(result.indexGlobal).withContext('global index of unit-' + i).toEqual(expectation.global); + expect(result.indexAncestor).withContext('ancestor-index of unit-' + i).toEqual(expectation.ancestor); + expect(result.indexLocal).withContext('local index of unit-' + i).toEqual(expectation.local); if ('parentName' in expectation) { - expect(result.unit.id).withContext("featured unit of unit-" + i).toEqual('unit-' + i); - expect(result.parent.id).withContext("parent of unit-" + i).toEqual(expectation.parentName); - expect(result.ancestor.id).withContext("ancestor of unit-" + i).toEqual(expectation.ancestorName); + expect(result.unit.id).withContext('featured unit of unit-' + i).toEqual('unit-' + i); + expect(result.parent.id).withContext('parent of unit-' + i).toEqual(expectation.parentName); + expect(result.ancestor.id).withContext('ancestor of unit-' + i).toEqual(expectation.ancestorName); } else { - expect(result.unit).withContext("not found unit-" + i).toBeNull(); - expect(result.parent).withContext("no parent of unit-" + i).toBeNull(); + expect(result.unit).withContext('not found unit-' + i).toBeNull(); + expect(result.parent).withContext('no parent of unit-' + i).toBeNull(); } } }); diff --git a/src/app/group-monitor/test-view/test-view.component.ts b/src/app/group-monitor/test-view/test-view.component.ts index 6a436ab56e5a964385fc12ae6fe40cb4b4413548..84a85746b65745765e3f53f60be3c3a15dde0658 100644 --- a/src/app/group-monitor/test-view/test-view.component.ts +++ b/src/app/group-monitor/test-view/test-view.component.ts @@ -12,19 +12,19 @@ function isUnit(testletOrUnit: Testlet|Unit): testletOrUnit is Unit { interface UnitContext { - unit?: Unit, - parent?: Testlet, - ancestor?: Testlet, - unitCount: number, - unitCountGlobal: number, - indexGlobal: number, - indexLocal: number, - indexAncestor: number, - unitCountAncestor: number, + unit?: Unit; + parent?: Testlet; + ancestor?: Testlet; + unitCount: number; + unitCountGlobal: number; + indexGlobal: number; + indexLocal: number; + indexAncestor: number; + unitCountAncestor: number; } @Component({ - selector: 'test-view', + selector: 'tc-test-view', templateUrl: './test-view.component.html', styleUrls: ['./test-view.component.css', './test-view-table.css'] }) @@ -33,8 +33,8 @@ export class TestViewComponent implements OnInit, OnChanges { @Input() displayOptions: TestViewDisplayOptions; public testSession$: Subject<TestSession> = new Subject<TestSession>(); - public booklet$: Observable<Booklet|BookletError>;// = new Subject<Booklet|BookletError>(); - public featuredUnit$: Observable<UnitContext|null> + public booklet$: Observable<Booklet|BookletError>; + public featuredUnit$: Observable<UnitContext|null>; public maxTimeLeft: object|null; // TODO make observable maybe @@ -47,7 +47,7 @@ export class TestViewComponent implements OnInit, OnChanges { ngOnInit() { console.log('NEW test-view component:' + this.testSession.personId, this.testSession.bookletName); - this.booklet$ = this.bookletsService.getBooklet(this.testSession.bookletName || ""); + this.booklet$ = this.bookletsService.getBooklet(this.testSession.bookletName || ''); this.featuredUnit$ = combineLatest<[Booklet|BookletError, TestSession]>([this.booklet$, this.testSession$]) .pipe(map((bookletAndSession: [Booklet|BookletError, TestSession]): UnitContext|null => { @@ -79,15 +79,15 @@ export class TestViewComponent implements OnInit, OnChanges { } getTestletType(testletOrUnit: Unit|Testlet): 'testlet'|'unit' { - return isUnit(testletOrUnit) ? 'unit': 'testlet'; + return isUnit(testletOrUnit) ? 'unit' : 'testlet'; } hasState(stateObject: object, key: string, value: any = null): boolean { - return ((typeof stateObject[key] !== "undefined") && ((value !== null) ? (stateObject[key] === value) : true)); + return ((typeof stateObject[key] !== 'undefined') && ((value !== null) ? (stateObject[key] === value) : true)); } parseJsonState(testStateObject: object, key: string): object|null { - if (typeof testStateObject[key] === "undefined") { + if (typeof testStateObject[key] === 'undefined') { return null; } @@ -109,10 +109,10 @@ export class TestViewComponent implements OnInit, OnChanges { return { modeId: modeString, modeLabel: 'Testleiter' - } + }; } - let testMode = new TestMode(modeString); + const testMode = new TestMode(modeString); return { modeId: testMode.modeId, modeLabel: testMode.modeLabel @@ -136,7 +136,7 @@ export class TestViewComponent implements OnInit, OnChanges { indexGlobal: -1, indexLocal: -1, indexAncestor: -1, - } + }; let i = -1; @@ -146,7 +146,7 @@ export class TestViewComponent implements OnInit, OnChanges { if (isUnit(testletOrUnit)) { - if (testletOrUnit.id == unitName) { + if (testletOrUnit.id === unitName) { result.indexGlobal = result.unitCountGlobal; result.indexLocal = result.unitCount; diff --git a/src/app/group-monitor/websocket-backend.service.ts b/src/app/group-monitor/websocket-backend.service.ts index ddf8493e75f254e209b12097c246f4d2b6afadae..43641b1db049bb097e11a312bbad3e45e2b94d41 100644 --- a/src/app/group-monitor/websocket-backend.service.ts +++ b/src/app/group-monitor/websocket-backend.service.ts @@ -5,7 +5,7 @@ import {ApiError} from '../app.interfaces'; import {HttpClient, HttpResponse} from '@angular/common/http'; import {WebsocketService} from './websocket.service'; -export type ConnectionStatus = "initial" | "ws-offline" | "ws-online" | "polling-sleep" | "polling-fetch" | "error"; +export type ConnectionStatus = 'initial' | 'ws-offline' | 'ws-online' | 'polling-sleep' | 'polling-fetch' | 'error'; export abstract class WebsocketBackendService<T> extends WebsocketService implements OnDestroy { abstract pollingEndpoint: string; @@ -14,13 +14,13 @@ export abstract class WebsocketBackendService<T> extends WebsocketService implem abstract initialData: T; public data$: BehaviorSubject<T>; - public connectionStatus$: BehaviorSubject<ConnectionStatus> = new BehaviorSubject<ConnectionStatus>("initial"); + public connectionStatus$: BehaviorSubject<ConnectionStatus> = new BehaviorSubject<ConnectionStatus>('initial'); private wsConnectionStatusSubscription: Subscription = null; private wsDataSubscription: Subscription = null; private pollingTimeoutId: number = null; - protected connectionClosed: boolean = true; + protected connectionClosed = true; constructor( @Inject('SERVER_URL') protected serverUrl: string, @@ -48,7 +48,7 @@ export abstract class WebsocketBackendService<T> extends WebsocketService implem this.unsubscribeFromWebsocket(); - this.connectionStatus$.next("polling-fetch"); + this.connectionStatus$.next('polling-fetch'); this.http .get<T>(this.serverUrl + this.pollingEndpoint, {observe: 'response'}) @@ -56,7 +56,7 @@ export abstract class WebsocketBackendService<T> extends WebsocketService implem // TODO interceptor should have interfered and moved to error-page https://github.com/iqb-berlin/testcenter-frontend/issues/53 catchError((err: ApiError) => { console.warn(`Api-Error: ${err.code} ${err.info}`); - this.connectionStatus$.next("error"); + this.connectionStatus$.next('error'); return new Observable<T>(); }) ) @@ -72,14 +72,14 @@ export abstract class WebsocketBackendService<T> extends WebsocketService implem } else { - this.connectionStatus$.next("polling-sleep"); + this.connectionStatus$.next('polling-sleep'); this.scheduleNextPoll(); } }); } public cutConnection(): void { - console.log("cut monitor connection"); + console.log('cut monitor connection'); this.unsubscribeFromWebsocket(); this.closeConnection(); @@ -96,7 +96,7 @@ export abstract class WebsocketBackendService<T> extends WebsocketService implem } this.pollingTimeoutId = window.setTimeout( - () => {if (!this.connectionClosed) this.pollNext();}, + () => {if (!this.connectionClosed) { this.pollNext(); }}, this.pollingInterval ); } @@ -124,7 +124,7 @@ export abstract class WebsocketBackendService<T> extends WebsocketService implem this.scheduleNextPoll(); } }), - map((wsConnected: boolean): ConnectionStatus => wsConnected ? "ws-online" : "ws-offline") + map((wsConnected: boolean): ConnectionStatus => wsConnected ? 'ws-online' : 'ws-offline') ) .subscribe(this.connectionStatus$); } diff --git a/src/app/group-monitor/websocket.service.ts b/src/app/group-monitor/websocket.service.ts index e286dbafebe06585e735e8811eef04b82b88f215..3276e72be7c1829274d7c03f7dd7f6e3cccbb6d6 100644 --- a/src/app/group-monitor/websocket.service.ts +++ b/src/app/group-monitor/websocket.service.ts @@ -9,7 +9,7 @@ interface WsMessage { } export class WebsocketService { - protected wsUrl: string = ""; + protected wsUrl = ''; private wsSubject$: WebSocketSubject<any>; public wsConnected$ = new BehaviorSubject<boolean>(null); private wsSubscription: Subscription; @@ -18,7 +18,6 @@ export class WebsocketService { ) { } - public connect() { if (!this.wsSubject$) { @@ -61,7 +60,6 @@ export class WebsocketService { } } - protected closeConnection(): void { this.wsConnected$.next(false); this.wsSubscription.unsubscribe(); @@ -69,7 +67,6 @@ export class WebsocketService { this.wsSubject$ = null; } - public send(event: string, data: any) { if (!this.wsSubject$) { this.connect(); @@ -78,7 +75,6 @@ export class WebsocketService { this.wsSubject$.next({event, data}); } - public getChannel<T>(channelName: string): Observable<T> { if (!this.wsSubject$) { this.connect();