Code owners
Assign users and groups as approvers for specific file changes. Learn more.
test-controller.component.ts 31.95 KiB
import {ReviewDialogComponent} from './review-dialog/review-dialog.component';
import {ActivatedRoute, Router} from '@angular/router';
import {MainDataService} from '../maindata.service';
import {BackendService} from './backend.service';
import {TestControllerService} from './test-controller.service';
import {Component, HostListener, Inject, OnDestroy, OnInit} from '@angular/core';
import {EnvironmentData, MaxTimerData, Testlet, UnitDef} from './test-controller.classes';
import {
AppFocusState,
Command,
MaxTimerDataType,
ReviewDialogData,
StateReportEntry,
TaggedString,
TestControllerState,
TestData,
TestLogEntryKey,
TestStateKey,
UnitData,
UnitNavigationTarget, UnitStateKey,
WindowFocusState
} from './test-controller.interfaces';
import {from, Observable, of, Subscription, throwError} from 'rxjs';
import {concatMap, debounceTime, distinctUntilChanged, map, switchMap} from 'rxjs/operators';
import {CustomtextService} from 'iqb-components';
import {MatDialog} from '@angular/material/dialog';
import {MatSnackBar} from '@angular/material/snack-bar';
import {BookletConfig} from '../config/booklet-config';
import {TestMode} from '../config/test-mode';
import {CommandService} from './command.service';
@Component({
templateUrl: './test-controller.component.html',
styleUrls: ['./test-controller.component.css']
})
export class TestControllerComponent implements OnInit, OnDestroy {
static localStorageTestKey = 'iqb-tc-t';
private errorReportingSubscription: Subscription = null;
private testStatusSubscription: Subscription = null;
private routingSubscription: Subscription = null;
private maxTimerSubscription: Subscription = null;
private unitLoadXmlSubscription: Subscription = null;
private unitLoadBlobSubscription: Subscription = null;
private appWindowHasFocusSubscription: Subscription = null;
private appFocusSubscription: Subscription = null;
private commandSubscription: Subscription = null;
private lastUnitSequenceId = 0;
private lastTestletIndex = 0;
public timerValue: MaxTimerData = null;
private timerRunning = false;
private allUnitIds: string[] = [];
private loadedUnitCount = 0;
private unitLoadQueue: TaggedString[] = [];
private resumeTargetUnitId = 0;
unitNavigationTarget = UnitNavigationTarget;
debugPane = false;
constructor (
@Inject('APP_VERSION') public appVersion: string,
@Inject('IS_PRODUCTION_MODE') public isProductionMode,
private mds: MainDataService,
public tcs: TestControllerService,
private bs: BackendService,
private reviewDialog: MatDialog,
private snackBar: MatSnackBar,
private router: Router,
private route: ActivatedRoute,
private cts: CustomtextService,
public cmd: CommandService
) {
}
private static getChildElements(element) {
return Array.prototype.slice.call(element.childNodes)
.filter(function (e) { return e.nodeType === 1; });
}
// private: recursive reading testlets/units from xml
private addTestletContentFromBookletXml(targetTestlet: Testlet, node: Element) {
const childElements = TestControllerComponent.getChildElements(node);
if (childElements.length > 0) {
let codeToEnter = '';
let codePrompt = '';
let maxTime = -1;
let restrictionElement: Element = null;
for (let childIndex = 0; childIndex < childElements.length; childIndex++) {
if (childElements[childIndex].nodeName === 'Restrictions') {
restrictionElement = childElements[childIndex];
break;
}
}
if (restrictionElement !== null) {
const restrictionElements = TestControllerComponent.getChildElements(restrictionElement);
for (let childIndex = 0; childIndex < restrictionElements.length; childIndex++) {
if (restrictionElements[childIndex].nodeName === 'CodeToEnter') {
const restrictionParameter = restrictionElements[childIndex].getAttribute('code');
if ((typeof restrictionParameter !== 'undefined') && (restrictionParameter !== null)) {
codeToEnter = restrictionParameter.toUpperCase();
codePrompt = restrictionElements[childIndex].textContent;
}
} else if (restrictionElements[childIndex].nodeName === 'TimeMax') {
const restrictionParameter = restrictionElements[childIndex].getAttribute('minutes');
if ((typeof restrictionParameter !== 'undefined') && (restrictionParameter !== null)) {
maxTime = Number(restrictionParameter);
if (isNaN(maxTime)) {
maxTime = -1;
}
}
}
}
}
if (codeToEnter.length > 0) {
targetTestlet.codeToEnter = codeToEnter;
targetTestlet.codePrompt = codePrompt;
}
targetTestlet.maxTimeLeft = maxTime;
if (this.tcs.LastMaxTimerState) {
if (this.tcs.LastMaxTimerState.hasOwnProperty(targetTestlet.id)) {
targetTestlet.maxTimeLeft = this.tcs.LastMaxTimerState[targetTestlet.id];
}
}
for (let childIndex = 0; childIndex < childElements.length; childIndex++) {
if (childElements[childIndex].nodeName === 'Unit') {
const myUnitId = childElements[childIndex].getAttribute('id');
let myUnitAlias = childElements[childIndex].getAttribute('alias');
if (!myUnitAlias) {
myUnitAlias = myUnitId;
}
let myUnitAliasClear = myUnitAlias;
let unitIdSuffix = 1;
while (this.allUnitIds.indexOf(myUnitAliasClear) > -1) {
myUnitAliasClear = myUnitAlias + '-' + unitIdSuffix.toString();
unitIdSuffix += 1;
}
this.allUnitIds.push(myUnitAliasClear);
targetTestlet.addUnit(this.lastUnitSequenceId, myUnitId,
childElements[childIndex].getAttribute('label'), myUnitAliasClear,
childElements[childIndex].getAttribute('labelshort'));
this.lastUnitSequenceId += 1;
} else if (childElements[childIndex].nodeName === 'Testlet') {
let testletId: string = childElements[childIndex].getAttribute('id');
if (!testletId) {
testletId = 'Testlet' + this.lastTestletIndex.toString();
this.lastTestletIndex += 1;
}
let testletLabel: string = childElements[childIndex].getAttribute('label');
testletLabel = testletLabel ? testletLabel.trim() : '';
this.addTestletContentFromBookletXml(targetTestlet.addTestlet(testletId, testletLabel), childElements[childIndex]);
}
}
}
}
private getBookletFromXml(xmlString: string): Testlet {
let rootTestlet: Testlet = null;
try {
const oParser = new DOMParser();
const oDOM = oParser.parseFromString(xmlString, 'text/xml');
if (oDOM.documentElement.nodeName === 'Booklet') {
const metadataElements = oDOM.documentElement.getElementsByTagName('Metadata');
if (metadataElements.length > 0) {
const metadataElement = metadataElements[0];
const IdElement = metadataElement.getElementsByTagName('Id')[0];
const LabelElement = metadataElement.getElementsByTagName('Label')[0];
rootTestlet = new Testlet(0, IdElement.textContent, LabelElement.textContent);
const unitsElements = oDOM.documentElement.getElementsByTagName('Units');
if (unitsElements.length > 0) {
const customTextsElements = oDOM.documentElement.getElementsByTagName('CustomTexts');
if (customTextsElements.length > 0) {
const customTexts = TestControllerComponent.getChildElements(customTextsElements[0]);
const customTextsForBooklet = {};
for (let childIndex = 0; childIndex < customTexts.length; childIndex++) {
if (customTexts[childIndex].nodeName === 'Text') {
const customTextKey = customTexts[childIndex].getAttribute('key');
if ((typeof customTextKey !== 'undefined') && (customTextKey !== null)) {
customTextsForBooklet[customTextKey] = customTexts[childIndex].textContent;
}
}
}
this.cts.addCustomTexts(customTextsForBooklet);
}
const bookletConfigElements = oDOM.documentElement.getElementsByTagName('BookletConfig');
this.tcs.bookletConfig = new BookletConfig();
this.tcs.bookletConfig.setFromKeyValuePairs(MainDataService.getTestConfig());
if (bookletConfigElements.length > 0) {
this.tcs.bookletConfig.setFromXml(bookletConfigElements[0]);
}
// recursive call through all testlets
this.lastUnitSequenceId = 1;
this.lastTestletIndex = 1;
this.allUnitIds = [];
this.addTestletContentFromBookletXml(rootTestlet, unitsElements[0]);
}
}
}
} catch (error) {
console.error('error reading booklet XML:', error);
rootTestlet = null;
}
return rootTestlet;
}
private incrementProgressValueBy1() {
this.loadedUnitCount += 1;
this.tcs.loadProgressValue = this.loadedUnitCount * 100 / this.lastUnitSequenceId;
}
// private: read unitdata
private loadUnitOk (myUnit: UnitDef, sequenceId: number): Observable<number> {
myUnit.setCanEnter('n', 'Fehler beim Laden');
return this.bs.getUnitData(this.tcs.testId, myUnit.id)
.pipe(
switchMap(myData => {
if (myData === false) {
return throwError(`error requesting unit ${this.tcs.testId}/${myUnit.id}`);
} else {
const myUnitData = myData as UnitData;
if (myUnitData.restorepoint) {
this.tcs.addUnitStateData(sequenceId, JSON.parse(myUnitData.restorepoint));
}
let playerId = null;
let definitionRef = '';
if (myUnitData.laststate && myUnitData.laststate[UnitStateKey.PRESENTATION_PROGRESS]) {
this.tcs.setOldUnitPresentationComplete(sequenceId, myUnitData.laststate[UnitStateKey.PRESENTATION_PROGRESS]);
}
try {
const oParser = new DOMParser();
const oDOM = oParser.parseFromString(myUnitData.xml, 'text/xml');
if (oDOM.documentElement.nodeName === 'Unit') {
const defElements = oDOM.documentElement.getElementsByTagName('Definition');
if (defElements.length > 0) {
const defElement = defElements[0];
this.tcs.addUnitDefinition(sequenceId, defElement.textContent);
playerId = defElement.getAttribute('player');
} else {
const defRefElements = oDOM.documentElement.getElementsByTagName('DefinitionRef');
if (defRefElements.length > 0) {
const defRefElement = defRefElements[0];
definitionRef = defRefElement.textContent;
// this.tcs.addUnitDefinition(sequenceId, '');
playerId = defRefElement.getAttribute('player');
}
}
}
} catch (error) {
return throwError(`error parsing unit def ${this.tcs.testId}/${myUnit.id} (${error.toString()})`);
}
if (playerId) {
myUnit.playerId = playerId;
if (definitionRef.length > 0) {
this.unitLoadQueue.push(<TaggedString>{
tag: sequenceId.toString(),
value: definitionRef
});
}
myUnit.setCanEnter('y', '');
if (this.tcs.hasPlayer(playerId)) {
return of(sequenceId);
} else {
// to avoid multiple calls before returning:
this.tcs.addPlayer(playerId, '');
return this.bs.getResource(this.tcs.testId, '', this.tcs.normaliseId(playerId, 'html'), true)
.pipe(
switchMap((data: number|TaggedString) => {
if (typeof data === 'number') {
return throwError(`error getting player "${playerId}"`);
} else {
const player = data as TaggedString;
if (player.value.length > 0) {
this.tcs.addPlayer(playerId, player.value);
return of(sequenceId);
} else {
return throwError(`error getting player "${playerId}" (size = 0)`);
}
}
}));
}
} else {
return throwError(`player def missing for unit ${this.tcs.testId}/${myUnit.id}`);
}
}
})
);
}
@HostListener('window:unload', ['$event'])
unloadHandler() {
if (this.cmd.connectionStatus$.getValue() !== 'ws-online') {
this.bs.notifyDyingTest(this.tcs.testId);
}
}
ngOnInit() {
setTimeout(() => {
this.mds.progressVisualEnabled = false;
// TODO rethink if different behaviour in production and normal mode is dangerous maybe
if (this.isProductionMode && this.tcs.testMode.saveResponses) {
this.mds.errorReportingSilent = true;
}
this.errorReportingSubscription = this.mds.appError$.subscribe(e => {
if (this.isProductionMode && this.tcs.testMode.saveResponses) {
console.error(e.label + ' / ' + e.description);
}
this.tcs.testStatus$.next(TestControllerState.ERROR);
});
this.testStatusSubscription = this.tcs.testStatus$.subscribe(testControllerState => {
if (this.tcs.testMode.saveResponses && [TestControllerState.FINISHED, TestControllerState.INIT, TestControllerState.LOADING].indexOf(testControllerState) === -1) {
this.bs.updateTestState(this.tcs.testId, [<StateReportEntry>{
key: TestStateKey.CONTROLLER, timeStamp: Date.now(), content: testControllerState
}]);
}
switch (testControllerState) {
case TestControllerState.ERROR:
this.tcs.loadProgressValue = 0;
this.tcs.setUnitNavigationRequest(UnitNavigationTarget.ERROR);
break;
case TestControllerState.PAUSED:
// TODO pause time
this.tcs.setUnitNavigationRequest(UnitNavigationTarget.PAUSE, true);
break;
}
});
this.appWindowHasFocusSubscription = this.mds.appWindowHasFocus$.subscribe(hasFocus => {
this.tcs.windowFocusState$.next(hasFocus ? WindowFocusState.HOST : WindowFocusState.UNKNOWN);
});
this.commandSubscription = this.cmd.command$.pipe(
distinctUntilChanged((command1: Command, command2: Command): boolean => (command1.id === command2.id))
)
.subscribe((command: Command) => {
this.handleCommand(command.keyword, command.arguments);
});
this.routingSubscription = this.route.params.subscribe(params => {
if (this.tcs.testStatus$.getValue() !== TestControllerState.ERROR) {
this.tcs.testId = params['t'];
localStorage.setItem(TestControllerComponent.localStorageTestKey, params['t']);
this.unsubscribeTestSubscriptions();
this.maxTimerSubscription = this.tcs.maxTimeTimer$.subscribe(maxTimerData => {
switch (maxTimerData.type) {
case MaxTimerDataType.STARTED:
this.snackBar.open(this.cts.getCustomText('booklet_msgTimerStarted')
+ maxTimerData.timeLeftMinString, '', {duration: 3000});
this.timerValue = maxTimerData;
break;
case MaxTimerDataType.ENDED:
this.snackBar.open(this.cts.getCustomText('booklet_msgTimeOver'), '', {duration: 3000});
this.tcs.rootTestlet.setTimeLeft(maxTimerData.testletId, 0);
this.tcs.LastMaxTimerState[maxTimerData.testletId] = 0;
if (this.tcs.testMode.saveResponses) {
this.bs.updateTestState(this.tcs.testId, [<StateReportEntry>{
key: TestStateKey.TESTLETS_TIMELEFT, timeStamp: Date.now(), content: JSON.stringify(this.tcs.LastMaxTimerState)
}]);
}
this.timerRunning = false;
this.timerValue = null;
if (this.tcs.testMode.forceTimeRestrictions) {
this.tcs.setUnitNavigationRequest(UnitNavigationTarget.NEXT);
}
break;
case MaxTimerDataType.CANCELLED:
this.snackBar.open(this.cts.getCustomText('booklet_msgTimerCancelled'), '', {duration: 3000});
this.tcs.rootTestlet.setTimeLeft(maxTimerData.testletId, 0);
this.tcs.LastMaxTimerState[maxTimerData.testletId] = 0;
if (this.tcs.testMode.saveResponses) {
this.bs.updateTestState(this.tcs.testId, [<StateReportEntry>{
key: TestStateKey.TESTLETS_TIMELEFT, timeStamp: Date.now(), content: JSON.stringify(this.tcs.LastMaxTimerState)
}]);
}
this.timerValue = null;
break;
case MaxTimerDataType.INTERRUPTED:
this.tcs.rootTestlet.setTimeLeft(maxTimerData.testletId, this.tcs.LastMaxTimerState[maxTimerData.testletId]);
this.timerValue = null;
break;
case MaxTimerDataType.STEP:
this.timerValue = maxTimerData;
if ((maxTimerData.timeLeftSeconds % 15) === 0) {
this.tcs.LastMaxTimerState[maxTimerData.testletId] = Math.round(maxTimerData.timeLeftSeconds / 60);
if (this.tcs.testMode.saveResponses) {
this.bs.updateTestState(this.tcs.testId, [<StateReportEntry>{
key: TestStateKey.TESTLETS_TIMELEFT, timeStamp: Date.now(), content: JSON.stringify(this.tcs.LastMaxTimerState)
}]);
}
}
if ((maxTimerData.timeLeftSeconds / 60) === 5) {
this.snackBar.open(this.cts.getCustomText('booklet_msgSoonTimeOver5Minutes'), '', {duration: 3000});
} else if ((maxTimerData.timeLeftSeconds / 60) === 1) {
this.snackBar.open(this.cts.getCustomText('booklet_msgSoonTimeOver1Minute'), '', {duration: 3000});
}
break;
}
});
this.tcs.resetDataStore();
const loadStartTimeStamp = Date.now();
const envData = new EnvironmentData(this.appVersion);
this.tcs.testStatus$.next(TestControllerState.LOADING);
this.tcs.loadProgressValue = 0;
this.tcs.loadComplete = false;
this.bs.getTestData(this.tcs.testId).subscribe((testData: TestData|boolean) => {
if ((testData === false) || (testData === true)) {
this.mds.appError$.next({
label: 'Konnte Testinformation nicht laden',
description: 'TestController.Component: getTestData()',
category: 'PROBLEM'
});
} else {
this.tcs.testMode = new TestMode(testData.mode);
let navTargetUnitId = '';
let newTestStatus = TestControllerState.RUNNING;
if (testData.laststate !== null) {
Object.keys(testData.laststate).forEach(stateKey => {
switch (stateKey) {
case (TestStateKey.CURRENT_UNIT_ID):
navTargetUnitId = testData.laststate[stateKey];
break;
case (TestStateKey.TESTLETS_TIMELEFT):
this.tcs.LastMaxTimerState = JSON.parse(testData.laststate[stateKey]);
break;
case (TestStateKey.CONTROLLER):
if (testData.laststate[stateKey] === TestControllerState.PAUSED) {
newTestStatus = TestControllerState.PAUSED;
}
break;
case (TestStateKey.TESTLETS_CLEARED_CODE):
this.tcs.clearCodeTestlets = JSON.parse(testData.laststate[stateKey]);
break;
}
});
}
this.tcs.rootTestlet = this.getBookletFromXml(testData.xml);
document.documentElement.style.setProperty('--tc-unit-title-height',
this.tcs.bookletConfig.unit_title === 'ON' ? this.mds.defaultTcUnitTitleHeight : '0');
document.documentElement.style.setProperty('--tc-header-height',
this.tcs.bookletConfig.unit_screenheader === 'OFF' ? '0' : this.mds.defaultTcHeaderHeight);
document.documentElement.style.setProperty('--tc-unit-page-nav-height',
this.tcs.bookletConfig.page_navibuttons === 'SEPARATE_BOTTOM' ? this.mds.defaultTcUnitPageNavHeight : '0');
if (this.tcs.rootTestlet === null) {
this.mds.appError$.next({
label: 'Problem beim Laden der Testinformation',
description: 'TestController.Component: getBookletFromXml(testData.xml)',
category: 'PROBLEM'
});
this.tcs.testStatus$.next(TestControllerState.ERROR);
} else {
this.tcs.maxUnitSequenceId = this.lastUnitSequenceId - 1;
if (this.tcs.clearCodeTestlets.length > 0) {
this.tcs.rootTestlet.clearTestletCodes(this.tcs.clearCodeTestlets);
}
this.loadedUnitCount = 0;
const sequArray = [];
for (let i = 1; i < this.tcs.maxUnitSequenceId + 1; i++) {
sequArray.push(i);
}
this.unitLoadXmlSubscription = from(sequArray).pipe(
concatMap(uSequ => {
const ud = this.tcs.rootTestlet.getUnitAt(uSequ);
return this.loadUnitOk(ud.unitDef, uSequ);
})
).subscribe(() => {
this.incrementProgressValueBy1();
},
errorMessage => {
this.mds.appError$.next({
label: 'Problem beim Laden der Testinformation',
description: errorMessage,
category: 'PROBLEM'
});
},
() => {
this.tcs.rootTestlet.lockUnitsIfTimeLeftNull();
let navTarget = 1;
if (navTargetUnitId) {
const tmpNavTarget = this.tcs.rootTestlet.getSequenceIdByUnitAlias(navTargetUnitId);
if (tmpNavTarget > 0) {
navTarget = tmpNavTarget;
}
}
this.tcs.updateMinMaxUnitSequenceId(navTarget);
this.loadedUnitCount = 0;
this.unitLoadBlobSubscription = from(this.unitLoadQueue).pipe(
concatMap(queueEntry => {
const unitSequ = Number(queueEntry.tag);
if (this.tcs.bookletConfig.loading_mode === 'EAGER') {
this.incrementProgressValueBy1();
}
// avoid to load unit def if not necessary
if (unitSequ < this.tcs.minUnitSequenceId) {
return of(<TaggedString>{tag: unitSequ.toString(), value: ''});
} else {
return this.bs.getResource(this.tcs.testId, queueEntry.tag, queueEntry.value).pipe(
map(response => {
if (typeof response === 'number') {
return throwError(`error loading voud ${this.tcs.testId} / ${queueEntry.tag} / ${queueEntry.value}: status ${response}`);
} else {
return response;
}
})
);
}
})
).subscribe(
(def: TaggedString) => {
this.tcs.addUnitDefinition(Number(def.tag), def.value);
},
errorMessage => {
this.mds.appError$.next({
label: 'Problem beim Laden der Testinformation',
description: errorMessage,
category: 'PROBLEM'
});
this.tcs.testStatus$.next(TestControllerState.ERROR);
},
() => { // complete
if (this.tcs.testMode.saveResponses) {
envData.loadTime = Date.now() - loadStartTimeStamp;
this.bs.addTestLog(this.tcs.testId, [<StateReportEntry>{
key: TestLogEntryKey.LOADCOMPLETE, timeStamp: Date.now(), content: JSON.stringify(envData)
}]);
}
this.tcs.loadProgressValue = 100;
this.tcs.loadComplete = true;
if (this.tcs.bookletConfig.loading_mode === 'EAGER') {
this.resumeTargetUnitId = navTarget;
this.tcs.setUnitNavigationRequest(navTarget.toString());
this.tcs.testStatus$.next(newTestStatus);
if (this.tcs.testMode.saveResponses) {
this.addAppFocusSubscription();
}
}
}
);
if (this.tcs.bookletConfig.loading_mode === 'LAZY') {
this.resumeTargetUnitId = navTarget;
this.tcs.setUnitNavigationRequest(navTarget.toString());
this.tcs.testStatus$.next(newTestStatus);
if (this.tcs.testMode.saveResponses) {
this.addAppFocusSubscription();
}
}
} // complete
);
}
}
}); // getTestData
}
}); // routingSubscription
this.cmd.connectionStatus$
.pipe(
map(status => status === 'ws-online'),
distinctUntilChanged()
)
.subscribe(isWsConnected => {
this.bs.updateTestState(this.tcs.testId, [{
key: TestStateKey.CONNECTION,
content: isWsConnected ? 'WEBSOCKET' : 'POLLING',
timeStamp: Date.now()
}]);
});
}); // setTimeOut
}
private addAppFocusSubscription() {
if (this.appFocusSubscription !== null) {
this.appFocusSubscription.unsubscribe();
}
this.appFocusSubscription = this.tcs.windowFocusState$.pipe(
debounceTime(500)
).subscribe((newState: WindowFocusState) => {
if (newState === WindowFocusState.UNKNOWN) {
this.bs.updateTestState(this.tcs.testId, [<StateReportEntry>{
key: TestStateKey.FOCUS, timeStamp: Date.now(), content: AppFocusState.HAS_NOT
}]);
} else {
this.bs.updateTestState(this.tcs.testId, [<StateReportEntry>{
key: TestStateKey.FOCUS, timeStamp: Date.now(), content: AppFocusState.HAS
}]);
}
});
}
showReviewDialog() {
if (this.tcs.rootTestlet === null) {
this.snackBar.open('Kein Testheft verfügbar.', '', {duration: 3000});
} else {
const authData = MainDataService.getAuthData();
const dialogRef = this.reviewDialog.open(ReviewDialogComponent, {
width: '700px',
data: <ReviewDialogData>{
loginname: authData.displayName,
bookletname: this.tcs.rootTestlet.title,
unitTitle: this.tcs.currentUnitTitle,
unitDbKey: this.tcs.currentUnitDbKey
}
});
dialogRef.afterClosed().subscribe(result => {
if (typeof result !== 'undefined') {
if (result !== false) {
const targetSelection = result['target'];
if (targetSelection === 'u') {
this.bs.saveUnitReview(
this.tcs.testId,
this.tcs.currentUnitDbKey,
result['priority'],
dialogRef.componentInstance.getCategories(),
result['sender'] ? result['sender'] + ': ' + result['entry'] : result['entry']
).subscribe(ok => {
if (!ok) {
this.snackBar.open('Konnte Kommentar nicht speichern', '', {duration: 3000});
} else {
this.snackBar.open('Kommentar gespeichert', '', {duration: 1000});
}
});
} else {
this.bs.saveTestReview(
this.tcs.testId,
result['priority'],
dialogRef.componentInstance.getCategories(),
result['sender'] ? result['sender'] + ': ' + result['entry'] : result['entry']
).subscribe(ok => {
if (!ok) {
this.snackBar.open('Konnte Kommentar nicht speichern', '', {duration: 3000});
} else {
this.snackBar.open('Kommentar gespeichert', '', {duration: 1000});
}
});
}
}
}
});
}
}
private unsubscribeTestSubscriptions() {
if (this.maxTimerSubscription !== null) {
this.maxTimerSubscription.unsubscribe();
this.maxTimerSubscription = null;
}
if (this.unitLoadXmlSubscription !== null) {
this.unitLoadXmlSubscription.unsubscribe();
this.unitLoadXmlSubscription = null;
}
if (this.unitLoadBlobSubscription !== null) {
this.unitLoadBlobSubscription.unsubscribe();
this.unitLoadBlobSubscription = null;
}
}
handleCommand(commandName: string, params: string[]) {
switch (commandName.toLowerCase()) {
case 'debug':
this.debugPane = params.length === 0 || params[0].toLowerCase() !== 'off';
if (this.debugPane) {
console.log('select (focus) app window to see the debugPane');
}
break;
case 'pause':
this.tcs.interruptMaxTimer();
this.tcs.testStatus$.next(TestControllerState.PAUSED);
this.resumeTargetUnitId = this.tcs.currentUnitSequenceId;
break;
case 'resume':
const navTarget = (this.resumeTargetUnitId > 0) ? this.resumeTargetUnitId.toString() : UnitNavigationTarget.FIRST;
this.tcs.testStatus$.next(TestControllerState.RUNNING);
this.tcs.setUnitNavigationRequest(navTarget, true);
break;
case 'terminate':
this.tcs.terminateTest('BOOKLETLOCKEDbyOPERATOR');
break;
case 'goto':
this.tcs.testStatus$.next(TestControllerState.RUNNING);
let gotoTarget: string;
if ((params.length === 2) && (params[0] === 'id')) {
gotoTarget = (this.allUnitIds.indexOf(params[1]) + 1).toString(10);
} else if (params.length === 1) {
gotoTarget = params[0];
}
if (gotoTarget && gotoTarget !== '0') {
console.log('YES', gotoTarget);
this.resumeTargetUnitId = 0;
this.tcs.interruptMaxTimer();
this.tcs.setUnitNavigationRequest(gotoTarget, true);
}
break;
}
}
ngOnDestroy() {
if (this.routingSubscription !== null) {
this.routingSubscription.unsubscribe();
}
if (this.errorReportingSubscription !== null) {
this.errorReportingSubscription.unsubscribe();
}
if (this.testStatusSubscription !== null) {
this.testStatusSubscription.unsubscribe();
}
if (this.appWindowHasFocusSubscription !== null) {
this.appWindowHasFocusSubscription.unsubscribe();
}
if (this.appFocusSubscription !== null) {
this.appFocusSubscription.unsubscribe();
}
if (this.commandSubscription !== null) {
this.commandSubscription.unsubscribe();
}
this.unsubscribeTestSubscriptions();
this.mds.progressVisualEnabled = true;
this.mds.errorReportingSilent = false;
}
}