From 7de528923640ff09d41139db79e3e3ad118e9857 Mon Sep 17 00:00:00 2001 From: Konstantin Schulz <schulzkx@hu-berlin.de> Date: Tue, 17 Nov 2020 13:56:51 +0100 Subject: [PATCH] the pages for exercise list and authors may now be accessed using deep links --- README.md | 5 ++- mc_frontend/src/app/app.component.spec.ts | 7 +++- mc_frontend/src/app/app.component.ts | 6 ++- .../src/app/author/author.page.spec.ts | 39 +++++++++++++++---- mc_frontend/src/app/author/author.page.ts | 27 +++++++++---- mc_frontend/src/app/corpus.service.spec.ts | 19 +-------- mc_frontend/src/app/corpus.service.ts | 21 ++-------- .../exercise-list/exercise-list.page.spec.ts | 3 ++ .../app/exercise-list/exercise-list.page.ts | 10 +++-- mc_frontend/src/app/helper.service.spec.ts | 17 ++++++++ mc_frontend/src/app/helper.service.ts | 18 +++++++++ 11 files changed, 111 insertions(+), 61 deletions(-) diff --git a/README.md b/README.md index 5545c23..fa93595 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,10 @@ To generate class structures for this project automatically: ## Documentation ### API -To view the API documentation, visit https://korpling.org/mc-service/mc/api/v1.0/ui/ . +To view the official API documentation, visit https://korpling.org/mc-service/mc/api/v1.0/ui/ . + +If you make local changes to the source code, your own API documentation will be published at http://localhost:5000/mc/api/v1.0/ui/ . +The port (5000) and API path (/mc/api/v1.0/) may change depending on your configuration. ### Changelog To update the changelog, use: `git log --oneline --decorate > CHANGELOG` diff --git a/mc_frontend/src/app/app.component.spec.ts b/mc_frontend/src/app/app.component.spec.ts index 9714dcf..d8679f5 100644 --- a/mc_frontend/src/app/app.component.spec.ts +++ b/mc_frontend/src/app/app.component.spec.ts @@ -16,7 +16,7 @@ import { TranslateTestingModule } from './translate-testing/translate-testing.module'; import {APP_BASE_HREF} from '@angular/common'; -import {Subscription} from 'rxjs'; +import {ReplaySubject, Subscription} from 'rxjs'; import {HelperService} from './helper.service'; import {CorpusService} from './corpus.service'; import Spy = jasmine.Spy; @@ -63,7 +63,10 @@ describe('AppComponent', () => { {provide: Platform, useClass: PlatformStub}, {provide: APP_BASE_HREF, useValue: '/'}, {provide: MenuController}, - {provide: CorpusService, useValue: {initCorpusService: () => Promise.resolve()}}, + { + provide: CorpusService, + useValue: {initCorpusService: () => Promise.resolve(), isInitialized: new ReplaySubject<boolean>(1)} + }, { provide: HelperService, useValue: {makeGetRequest: () => Promise.resolve(MockMC.apiResponseCorporaGet)} diff --git a/mc_frontend/src/app/app.component.ts b/mc_frontend/src/app/app.component.ts index 8a667b4..d9e2512 100644 --- a/mc_frontend/src/app/app.component.ts +++ b/mc_frontend/src/app/app.component.ts @@ -24,8 +24,10 @@ export class AppComponent { public menuCtrl: MenuController, public corpusService: CorpusService, ) { - platform.ready().then(() => { - this.corpusService.initCorpusService().then(); + platform.ready().then(async () => { + this.corpusService.initCorpusService().then(() => { + this.corpusService.isInitialized.next(true); + }); // Okay, so the platform is ready and our plugins are available. // Here you can do any higher level native things you might need. this.statusBar.styleDefault(); diff --git a/mc_frontend/src/app/author/author.page.spec.ts b/mc_frontend/src/app/author/author.page.spec.ts index 9e50c20..43d4dd7 100644 --- a/mc_frontend/src/app/author/author.page.spec.ts +++ b/mc_frontend/src/app/author/author.page.spec.ts @@ -11,6 +11,7 @@ import {APP_BASE_HREF} from '@angular/common'; import {Author} from '../models/author'; import Spy = jasmine.Spy; import MockMC from '../models/mockMC'; +import {CorpusService} from '../corpus.service'; describe('AuthorPage', () => { let authorPage: AuthorPage; @@ -30,10 +31,19 @@ describe('AuthorPage', () => { ], providers: [ {provide: APP_BASE_HREF, useValue: '/'}, + { + provide: CorpusService, + useValue: { + availableAuthors: [], + getCorpora: () => Promise.resolve(), + isTreebank: () => true, + restoreLastCorpus: () => Promise.resolve() + } + } ], schemas: [CUSTOM_ELEMENTS_SCHEMA], }) - .compileComponents(); + .compileComponents().then(); })); beforeEach(() => { @@ -63,13 +73,19 @@ describe('AuthorPage', () => { expect(authorPage.authorsDisplayed.length).toBe(1); }); - it('should be initialized', () => { - authorPage.corpusService.availableAuthors = [new Author({ - corpora: [{source_urn: 'proiel'}], - name: 'name' - })]; - authorPage.ngOnInit(); - expect(authorPage.baseAuthorList.length).toBe(1); + it('should be initialized', (done) => { + const storageSpy: Spy = spyOn(authorPage.storage, 'get').and.returnValue(Promise.resolve(null)); + authorPage.ngOnInit().then(async () => { + expect(storageSpy).toHaveBeenCalledTimes(1); + authorPage.corpusService.availableAuthors = [new Author({ + corpora: [{source_urn: 'proiel'}], + name: 'name' + })]; + await authorPage.ngOnInit(); + expect(storageSpy).toHaveBeenCalledTimes(1); + expect(authorPage.baseAuthorList.length).toBe(1); + done(); + }); }); it('should restore the last setup', (done) => { @@ -100,4 +116,11 @@ describe('AuthorPage', () => { authorPage.showCorpora(author); expect(authorPage.corpusService.currentAuthor).toBe(author); }); + + it('should toggle treebank authors', () => { + authorPage.showOnlyTreebanks = false; + authorPage.corpusService.availableAuthors = [{corpora: [], name: ''}]; + authorPage.toggleTreebankAuthors(); + expect(authorPage.baseAuthorList.length).toBe(1); + }); }); diff --git a/mc_frontend/src/app/author/author.page.ts b/mc_frontend/src/app/author/author.page.ts index 46def0c..9e94ece 100644 --- a/mc_frontend/src/app/author/author.page.ts +++ b/mc_frontend/src/app/author/author.page.ts @@ -9,6 +9,8 @@ import {ExerciseService} from '../exercise.service'; import {ApplicationState} from '../models/applicationState'; import {take} from 'rxjs/operators'; import configMC from '../../configMC'; +import {UpdateInfo} from '../models/updateInfo'; +import {Storage} from '@ionic/storage'; /** * Generated class for the AuthorPage page. @@ -28,7 +30,8 @@ export class AuthorPage implements OnInit { public corpusService: CorpusService, public http: HttpClient, public exerciseService: ExerciseService, - public helperService: HelperService) { + public helperService: HelperService, + public storage: Storage) { } public authorsDisplayed: Author[]; @@ -55,14 +58,22 @@ export class AuthorPage implements OnInit { return this.corpusService.availableAuthors.filter(author => author.corpora.some(corpus => this.corpusService.isTreebank(corpus))); } - ngOnInit(): void { - if (!this.corpusService.availableAuthors.length) { - this.corpusService.loadCorporaFromLocalStorage().then(() => { + ngOnInit(): Promise<void> { + return new Promise<void>(resolve => { + if (!this.corpusService.availableAuthors.length) { + this.storage.get(configMC.localStorageKeyUpdateInfo).then((jsonString: string) => { + // check local storage for necessary updates + const updateInfo: UpdateInfo = JSON.parse(jsonString) as UpdateInfo; + this.corpusService.getCorpora(updateInfo ? updateInfo.corpora : 0).then(() => { + this.toggleTreebankAuthors(); + return resolve(); + }); + }); + } else { this.toggleTreebankAuthors(); - }); - } else { - this.toggleTreebankAuthors(); - } + return resolve(); + } + }); } restoreLastSetup(): Promise<void> { diff --git a/mc_frontend/src/app/corpus.service.spec.ts b/mc_frontend/src/app/corpus.service.spec.ts index 538e546..9b7597d 100644 --- a/mc_frontend/src/app/corpus.service.spec.ts +++ b/mc_frontend/src/app/corpus.service.spec.ts @@ -238,7 +238,7 @@ describe('CorpusService', () => { it('should initialize the corpus service', (done) => { const annisRespSpy: Spy = spyOn(corpusService, 'checkAnnisResponse').and.callFake(() => Promise.reject()); const restoreSpy: Spy = spyOn(corpusService, 'restoreLastCorpus').and.returnValue(Promise.resolve()); - const updateInfoSpy: Spy = spyOn(corpusService, 'initUpdateInfo').and.callFake(() => Promise.reject()); + const updateInfoSpy: Spy = spyOn(corpusService.helperService, 'initUpdateInfo').and.callFake(() => Promise.reject()); helperService.applicationState.next(helperService.deepCopy(MockMC.applicationState) as ApplicationState); corpusService.initCorpusService().then(() => { }, () => { @@ -286,23 +286,6 @@ describe('CorpusService', () => { expect(corpus).toBeTruthy(); })); - it('should initialize the update information', (done) => { - const updateInfoSpy: Spy = spyOn(corpusService.storage, 'get').withArgs(configMC.localStorageKeyUpdateInfo); - updateInfoSpy.and.returnValue(Promise.resolve('')); - corpusService.initUpdateInfo().then(() => { - updateInfoSpy.and.callThrough(); - corpusService.storage.get(configMC.localStorageKeyUpdateInfo).then((jsonString: string) => { - const updateInfo: UpdateInfo = JSON.parse(jsonString) as UpdateInfo; - expect(updateInfo.corpora).toBe(1); - const setSpy: Spy = spyOn(corpusService.storage, 'set').and.returnValue(Promise.resolve()); - corpusService.initUpdateInfo().then(() => { - expect(setSpy).toHaveBeenCalledTimes(0); - done(); - }); - }); - }); - }); - it('should load corpora from local storage', (done) => { corpusService.availableCorpora = []; spyOn(corpusService.storage, 'get').withArgs(configMC.localStorageKeyCorpora).and.returnValue( diff --git a/mc_frontend/src/app/corpus.service.ts b/mc_frontend/src/app/corpus.service.ts index 124f4d3..633eee6 100644 --- a/mc_frontend/src/app/corpus.service.ts +++ b/mc_frontend/src/app/corpus.service.ts @@ -66,6 +66,7 @@ export class CorpusService { public invalidQueryCorpusString: string; public invalidSentenceCountString: string; public invalidTextRangeString: string; + public isInitialized: ReplaySubject<boolean>; public isTextRangeCorrect = false; public phenomenonMap: PhenomenonMap = new PhenomenonMap({ dependency: new PhenomenonMapContent({translationObject: DependencyTranslation}), @@ -305,9 +306,10 @@ export class CorpusService { initCorpusService(): Promise<void> { return new Promise<void>((resolve, reject) => { + this.isInitialized = new ReplaySubject<boolean>(1); this.initCurrentCorpus().then(); this.initCurrentTextRange(); - this.initUpdateInfo().then(() => { + this.helperService.initUpdateInfo().then(() => { this.checkForUpdates().finally(() => { this.checkAnnisResponse().then(() => { this.restoreLastCorpus().then(() => { @@ -370,23 +372,6 @@ export class CorpusService { }); } - initUpdateInfo(): Promise<void> { - return new Promise<void>(resolve => { - this.storage.get(configMC.localStorageKeyUpdateInfo).then((jsonString: string) => { - if (jsonString) { - return resolve(); - } - const ui: UpdateInfo = new UpdateInfo({ - corpora: 1, - exerciseList: 1 - }); - this.storage.set(configMC.localStorageKeyUpdateInfo, JSON.stringify(ui)).then(() => { - return resolve(); - }); - }); - }); - } - isTreebank(corpus: CorpusMC): boolean { return corpus.source_urn.includes('proiel'); } diff --git a/mc_frontend/src/app/exercise-list/exercise-list.page.spec.ts b/mc_frontend/src/app/exercise-list/exercise-list.page.spec.ts index 9ab66da..b4526d7 100644 --- a/mc_frontend/src/app/exercise-list/exercise-list.page.spec.ts +++ b/mc_frontend/src/app/exercise-list/exercise-list.page.spec.ts @@ -17,6 +17,7 @@ import Spy = jasmine.Spy; import configMC from '../../configMC'; import {UpdateInfo} from '../models/updateInfo'; import {VocabularyMC} from '../../../openapi'; +import {ReplaySubject} from 'rxjs'; describe('ExerciseListPage', () => { let exerciseListPage: ExerciseListPage; @@ -46,6 +47,8 @@ describe('ExerciseListPage', () => { fixture = TestBed.createComponent(ExerciseListPage); exerciseListPage = fixture.componentInstance; getExerciseListSpy = spyOn(exerciseListPage, 'getExerciseList').and.returnValue(Promise.resolve()); + exerciseListPage.corpusService.isInitialized = new ReplaySubject<boolean>(1); + exerciseListPage.corpusService.isInitialized.next(true); fixture.detectChanges(); }); diff --git a/mc_frontend/src/app/exercise-list/exercise-list.page.ts b/mc_frontend/src/app/exercise-list/exercise-list.page.ts index a3f2ae7..6287ce0 100644 --- a/mc_frontend/src/app/exercise-list/exercise-list.page.ts +++ b/mc_frontend/src/app/exercise-list/exercise-list.page.ts @@ -124,10 +124,12 @@ export class ExerciseListPage implements OnInit { ngOnInit(): Promise<void> { return new Promise<void>(((resolve, reject) => { this.vocService.currentReferenceVocabulary = null; - this.getExerciseList().then(() => { - return resolve(); - }, () => { - return resolve(); + this.corpusService.isInitialized.pipe(take(1)).subscribe(() => { + this.getExerciseList().then(() => { + return resolve(); + }, () => { + return resolve(); + }); }); })); } diff --git a/mc_frontend/src/app/helper.service.spec.ts b/mc_frontend/src/app/helper.service.spec.ts index 6ff054b..960644e 100644 --- a/mc_frontend/src/app/helper.service.spec.ts +++ b/mc_frontend/src/app/helper.service.spec.ts @@ -16,6 +16,7 @@ import {ApplicationState} from './models/applicationState'; import {take} from 'rxjs/operators'; import {HttpErrorResponse, HttpParams} from '@angular/common/http'; import MockMC from './models/mockMC'; +import {UpdateInfo} from './models/updateInfo'; describe('HelperService', () => { let helperService: HelperService; @@ -157,6 +158,22 @@ describe('HelperService', () => { }); }); }); + it('should initialize the update information', (done) => { + const updateInfoSpy: Spy = spyOn(helperService.storage, 'get').withArgs(configMC.localStorageKeyUpdateInfo); + updateInfoSpy.and.returnValue(Promise.resolve('')); + helperService.initUpdateInfo().then(() => { + updateInfoSpy.and.callThrough(); + helperService.storage.get(configMC.localStorageKeyUpdateInfo).then((jsonString: string) => { + const updateInfo: UpdateInfo = JSON.parse(jsonString) as UpdateInfo; + expect(updateInfo.corpora).toBe(1); + const setSpy: Spy = spyOn(helperService.storage, 'set').and.returnValue(Promise.resolve()); + helperService.initUpdateInfo().then(() => { + expect(setSpy).toHaveBeenCalledTimes(0); + done(); + }); + }); + }); + }); it('should make a get request', (done) => { const toastCtrl: ToastController = TestBed.inject(ToastController); diff --git a/mc_frontend/src/app/helper.service.ts b/mc_frontend/src/app/helper.service.ts index 84a9cd3..444014b 100644 --- a/mc_frontend/src/app/helper.service.ts +++ b/mc_frontend/src/app/helper.service.ts @@ -12,6 +12,7 @@ import {ReplaySubject} from 'rxjs'; import {TextData} from './models/textData'; import configMC from '../configMC'; import EventRegistry from './models/eventRegistry'; +import {UpdateInfo} from './models/updateInfo'; declare var H5P: any; // dirty hack to prevent H5P access errors after resize events @@ -271,6 +272,23 @@ export class HelperService { }); } + initUpdateInfo(): Promise<void> { + return new Promise<void>(resolve => { + this.storage.get(configMC.localStorageKeyUpdateInfo).then((jsonString: string) => { + if (jsonString) { + return resolve(); + } + const ui: UpdateInfo = new UpdateInfo({ + corpora: 1, + exerciseList: 1 + }); + this.storage.set(configMC.localStorageKeyUpdateInfo, JSON.stringify(ui)).then(() => { + return resolve(); + }); + }); + }); + } + loadTranslations(translate: TranslateService): void { // dirty hack to wait until the translation loader is initialized in IE11 this.getDelayedTranslation(translate, 'CORPUS_UPDATE_COMPLETED').then((value: string) => { -- GitLab