Commit 0fe343f7 authored by Konstantin Schulz's avatar Konstantin Schulz

added semantics page to display vector networks for the Panegyrici Latini corpus

parent 2586a03a
Pipeline #10889 passed with stage
in 2 minutes and 14 seconds
stages:
- test
- deploy
coverage:
stage: test
script:
......
......@@ -12,7 +12,7 @@
"schematics": {},
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"builder": "@angular-builders/custom-webpack:browser",
"options": {
"outputPath": "www",
"index": "src/index.html",
......
This diff is collapsed.
{
"name": "mc_frontend",
"version": "1.7.0",
"version": "1.7.2",
"author": "Ionic Framework",
"homepage": "https://ionicframework.com/",
"scripts": {
......@@ -9,6 +9,7 @@
"build": "ng build",
"test": "ng test --code-coverage --watch=false",
"test-debug": "ng test --watch=true --browsers=Chrome",
"test-cov": "ng test --code-coverage --watch=true",
"lint": "ng lint",
"e2e": "ng e2e"
},
......@@ -37,7 +38,7 @@
"cordova-plugin-splashscreen": "^5.0.3",
"cordova-plugin-statusbar": "^2.4.3",
"cordova-plugin-whitelist": "^1.3.4",
"core-js": "^2.6.11",
"core-js": "^3.6.4",
"rxjs": "^6.5.4",
"tslib": "^1.11.1",
"webpack": "^4.42.0",
......@@ -53,17 +54,17 @@
"@angular/compiler-cli": "^9.0.4",
"@angular/language-service": "^7.2.16",
"@ionic/angular-toolkit": "^2.2.0",
"@types/jasmine": "~2.8.8",
"@types/jasmine": "^3.5.9",
"@types/jasminewd2": "^2.0.8",
"@types/node": "^12.0.12",
"codelyzer": "^5.2.1",
"jasmine-core": "~2.99.1",
"jasmine-core": "^3.5.0",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~4.1.0",
"karma": "^4.4.1",
"karma-chrome-launcher": "^3.1.0",
"karma-coverage-istanbul-reporter": "^2.0.6",
"karma-jasmine": "~1.1.2",
"karma-jasmine-html-reporter": "^0.2.2",
"karma-jasmine": "^3.1.1",
"karma-jasmine-html-reporter": "^1.5.2",
"protractor": "^5.4.3",
"ts-node": "^8.1.1",
"tslint": "~5.16.0",
......
......@@ -22,6 +22,10 @@ const routes: Routes = [
{ path: 'doc-voc-unit', loadChildren: './doc-voc-unit/doc-voc-unit.module#DocVocUnitPageModule' },
{ path: 'doc-exercises', loadChildren: './doc-exercises/doc-exercises.module#DocExercisesPageModule' },
{ path: 'doc-software', loadChildren: './doc-software/doc-software.module#DocSoftwarePageModule' },
{
path: 'semantics',
loadChildren: () => import('./semantics/semantics.module').then( m => m.SemanticsPageModule)
},
......
......@@ -14,32 +14,39 @@
<ion-grid style="text-align: left">
<ion-row>
<ion-col>
<a (click)="HelperService.goToHomePage(navCtrl).then(closeMenu.bind(this))">
<a (click)="helperService.goToHomePage(navCtrl).then(closeMenu.bind(this))">
{{'HOME' | translate}}
</a>
</ion-col>
</ion-row>
<ion-row>
<ion-col>
<a (click)="HelperService.goToAuthorPage(navCtrl).then(closeMenu.bind(this))">
<a (click)="helperService.goToAuthorPage(navCtrl).then(closeMenu.bind(this))">
{{ 'EXERCISE_GENERATE' | translate }}
</a>
</ion-col>
</ion-row>
<ion-row>
<ion-col>
<a (click)="HelperService.goToExerciseListPage(navCtrl).then(closeMenu.bind(this))">
<a (click)="helperService.goToExerciseListPage(navCtrl).then(closeMenu.bind(this))">
{{ 'EXERCISE_LIST' | translate }}
</a>
</ion-col>
</ion-row>
<ion-row>
<ion-col>
<a (click)="HelperService.goToTestPage(navCtrl).then(closeMenu.bind(this))">
<a (click)="helperService.goToTestPage(navCtrl).then(closeMenu.bind(this))">
{{ 'TEST' | translate }}
</a>
</ion-col>
</ion-row>
<ion-row>
<ion-col>
<a (click)="helperService.goToSemanticsPage(navCtrl).then(closeMenu.bind(this))">
{{ 'SEMANTICS' | translate }}
</a>
</ion-col>
</ion-row>
<ion-row>
<ion-grid style="text-align: left; padding: 0">
<ion-title>
......@@ -47,35 +54,35 @@
</ion-title>
<ion-row>
<ion-col>
<a (click)="HelperService.goToInfoPage(navCtrl).then(closeMenu.bind(this))">
<a (click)="helperService.goToInfoPage(navCtrl).then(closeMenu.bind(this))">
{{ 'ABOUT' | translate }}
</a>
</ion-col>
</ion-row>
<ion-row>
<ion-col>
<a (click)="HelperService.goToDocSoftwarePage(navCtrl).then(closeMenu.bind(this))">
<a (click)="helperService.goToDocSoftwarePage(navCtrl).then(closeMenu.bind(this))">
{{ 'DOC_SOFTWARE' | translate }}
</a>
</ion-col>
</ion-row>
<ion-row>
<ion-col>
<a (click)="HelperService.goToDocExercisesPage(navCtrl).then(closeMenu.bind(this))">
<a (click)="helperService.goToDocExercisesPage(navCtrl).then(closeMenu.bind(this))">
{{ 'DOC_EXERCISES' | translate }}
</a>
</ion-col>
</ion-row>
<ion-row>
<ion-col>
<a (click)="HelperService.goToDocVocUnitPage(navCtrl).then(closeMenu.bind(this))">
<a (click)="helperService.goToDocVocUnitPage(navCtrl).then(closeMenu.bind(this))">
{{ 'DOC_VOC_UNIT' | translate }}
</a>
</ion-col>
</ion-row>
<ion-row>
<ion-col>
<a (click)="HelperService.goToSourcesPage(navCtrl).then(closeMenu.bind(this))">
<a (click)="helperService.goToSourcesPage(navCtrl).then(closeMenu.bind(this))">
{{ 'SOURCES' | translate }}
</a>
</ion-col>
......
import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
import {TestBed, async} from '@angular/core/testing';
import {TestBed, async, ComponentFixture} from '@angular/core/testing';
import {MenuController, Platform} from '@ionic/angular';
import {SplashScreen} from '@ionic-native/splash-screen/ngx';
......@@ -13,9 +13,14 @@ import {TranslateTestingModule} from './translate-testing/translate-testing.modu
import {APP_BASE_HREF} from '@angular/common';
import {Subscription} from 'rxjs';
import {HelperService} from './helper.service';
import MockMC from './models/mock';
import {CorpusService} from './corpus.service';
import Spy = jasmine.Spy;
import MockMC from './models/mockMC';
describe('AppComponent', () => {
let statusBarSpy, splashScreenSpy, platformReadySpy, fixture: ComponentFixture<AppComponent>,
appComponent: AppComponent;
class PlatformStub {
backButton = {
subscribeWithPriority(priority: number, callback: () => (Promise<any> | void)): Subscription {
......@@ -30,7 +35,6 @@ describe('AppComponent', () => {
}
}
let statusBarSpy, splashScreenSpy, platformReadySpy, fixture;
beforeEach(async(() => {
platformReadySpy = Promise.resolve();
statusBarSpy = jasmine.createSpyObj('StatusBar', ['styleDefault']);
......@@ -49,11 +53,16 @@ describe('AppComponent', () => {
{provide: SplashScreen, useValue: splashScreenSpy},
{provide: Platform, useClass: PlatformStub},
{provide: APP_BASE_HREF, useValue: '/'},
{provide: MenuController}
{provide: MenuController},
{provide: CorpusService, useValue: {initCorpusService: () => Promise.resolve()}},
{
provide: HelperService,
useValue: {makeGetRequest: () => Promise.resolve(MockMC.apiResponseCorporaGet)}
}
],
}).compileComponents();
spyOn(HelperService, 'makeGetRequest').and.returnValue(Promise.resolve(MockMC.apiResponseCorporaGet));
}).compileComponents().then();
fixture = TestBed.createComponent(AppComponent);
appComponent = fixture.componentInstance;
}));
it('should create the app', () => {
......@@ -69,6 +78,20 @@ describe('AppComponent', () => {
expect(splashScreenSpy.hide).toHaveBeenCalled();
});
it('should close the menu', () => {
const closeSpy: Spy = spyOn(appComponent.menuCtrl, 'close').and.returnValue(Promise.resolve(true));
appComponent.closeMenu(true);
expect(closeSpy).toHaveBeenCalledTimes(1);
});
it('should initialize the translations', () => {
spyOn(appComponent.translate, 'getBrowserLang').and.returnValue(undefined);
const languageSpy: Spy = spyOn(appComponent.translate, 'getDefaultLang').and.returnValue('de');
appComponent.initTranslate();
expect(appComponent.translate.currentLang).toBe('de');
expect(languageSpy).toHaveBeenCalledTimes(1);
});
// TODO: add more tests!
});
......@@ -13,7 +13,6 @@ import {CorpusService} from './corpus.service';
})
export class AppComponent {
public configMC = configMC;
public HelperService = HelperService;
constructor(platform: Platform,
public statusBar: StatusBar,
......
......@@ -2,13 +2,13 @@
<ion-toolbar>
<ion-buttons slot="start">
<div class="home-logo">
<a (click)="HelperService.goToHomePage(navCtrl)">
<a (click)="helperService.goToHomePage(navCtrl)">
<img src="assets/imgs/logo.png" width="32px" height="32px" alt="CALLIDUS Logo">
</a>
</div>
</ion-buttons>
<ion-spinner *ngIf="HelperService.isLoading"></ion-spinner>
<ion-title *ngIf="HelperService.applicationState | async as state">{{ state.currentSetup.currentAuthor?.name }}</ion-title>
<ion-spinner *ngIf="helperService.openRequests.length"></ion-spinner>
<ion-title *ngIf="helperService.applicationState | async as state">{{ state.currentSetup.currentAuthor?.name }}</ion-title>
<ion-buttons slot="end">
<ion-menu-button autoHide="false">
<ion-icon name="menu"></ion-icon>
......@@ -19,7 +19,7 @@
<ion-content class="ion-padding">
<ion-list *ngIf="HelperService.applicationState | async as state">
<ion-list *ngIf="helperService.applicationState | async as state">
<ion-item *ngFor="let corpus of state.currentSetup.currentAuthor?.corpora">
<button (click)="showPossibleReferences(corpus)">
<span>{{corpus.title}}</span>
......
......@@ -7,9 +7,11 @@ import {IonicStorageModule} from '@ionic/storage';
import {TranslateTestingModule} from '../translate-testing/translate-testing.module';
import {APP_BASE_HREF} from '@angular/common';
import {HttpClientTestingModule} from '@angular/common/http/testing';
import Spy = jasmine.Spy;
import {CorpusMC} from '../models/corpusMC';
describe('AuthorDetailPage', () => {
let component: AuthorDetailPage;
let authorDetailPage: AuthorDetailPage;
let fixture: ComponentFixture<AuthorDetailPage>;
beforeEach(async(() => {
......@@ -31,11 +33,19 @@ describe('AuthorDetailPage', () => {
beforeEach(() => {
fixture = TestBed.createComponent(AuthorDetailPage);
component = fixture.componentInstance;
authorDetailPage = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
expect(authorDetailPage).toBeTruthy();
});
it('should show possible references', () => {
const currentCorpusSpy: Spy = spyOn(authorDetailPage.corpusService, 'setCurrentCorpus');
const textRangeSpy: Spy = spyOn(authorDetailPage.helperService, 'goToTextRangePage').and.returnValue(Promise.resolve(true));
authorDetailPage.showPossibleReferences(new CorpusMC());
expect(currentCorpusSpy).toHaveBeenCalledTimes(1);
expect(textRangeSpy).toHaveBeenCalledTimes(1);
});
});
......@@ -12,16 +12,16 @@ import {HttpClient} from '@angular/common/http';
styleUrls: ['./author-detail.page.scss'],
})
export class AuthorDetailPage {
HelperService = HelperService;
constructor(public navCtrl: NavController,
public corpusService: CorpusService,
public translate: TranslateService,
public http: HttpClient) {
public http: HttpClient,
public helperService: HelperService) {
}
showPossibleReferences(corpus: CorpusMC) {
this.corpusService.saveNewCorpus(corpus);
HelperService.goToTextRangePage(this.navCtrl).then();
this.corpusService.setCurrentCorpus(corpus);
this.helperService.goToTextRangePage(this.navCtrl).then();
}
}
......@@ -2,12 +2,12 @@
<ion-toolbar>
<ion-buttons slot="start">
<div class="home-logo">
<a (click)="HelperService.goToHomePage(navCtrl)">
<a (click)="helperService.goToHomePage(navCtrl)">
<img src="assets/imgs/logo.png" width="32px" height="32px" alt="CALLIDUS Logo">
</a>
</div>
</ion-buttons>
<ion-spinner *ngIf="HelperService.isLoading"></ion-spinner>
<ion-spinner *ngIf="helperService.openRequests.length"></ion-spinner>
<ion-title>{{ 'AUTHOR_SELECT' | translate }}</ion-title>
<ion-buttons slot="end">
<ion-menu-button autoHide="false">
......@@ -25,7 +25,7 @@
</ion-col>
</ion-row>
<div *ngIf="HelperService.applicationState | async as state">
<div *ngIf="helperService.applicationState | async as state">
<ion-row
*ngIf="state.mostRecentSetup && state.mostRecentSetup.currentCorpus && state.mostRecentSetup.currentUrn; else noEntryFound">
<ion-col>
......
......@@ -8,9 +8,13 @@ import {HttpClientModule} from '@angular/common/http';
import {IonicStorageModule} from '@ionic/storage';
import {TranslateTestingModule} from '../translate-testing/translate-testing.module';
import {APP_BASE_HREF} from '@angular/common';
import {Author} from '../models/author';
import {CorpusMC} from '../models/corpusMC';
import Spy = jasmine.Spy;
import MockMC from '../models/mockMC';
describe('AuthorPage', () => {
let component: AuthorPage;
let authorPage: AuthorPage;
let fixture: ComponentFixture<AuthorPage>;
beforeEach(async(() => {
......@@ -35,11 +39,66 @@ describe('AuthorPage', () => {
beforeEach(() => {
fixture = TestBed.createComponent(AuthorPage);
component = fixture.componentInstance;
authorPage = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
expect(authorPage).toBeTruthy();
});
it('should filter an author', () => {
const result: boolean = AuthorPage.filterAuthor(new Author({name: 'name'}), 'b');
expect(result).toBe(false);
});
it('should get authors', () => {
authorPage.showOnlyTreebanks = true;
authorPage.getAuthors('');
expect(authorPage.authorsDisplayed).toBe(authorPage.baseAuthorList);
authorPage.showOnlyTreebanks = false;
authorPage.getAuthors('');
expect(authorPage.authorsDisplayed).toBe(authorPage.corpusService.availableAuthors);
authorPage.baseAuthorList.push(new Author({name: 'test'}));
authorPage.getAuthors('test');
expect(authorPage.authorsDisplayed.length).toBe(1);
});
it('should be initialized', () => {
authorPage.corpusService.availableAuthors = [new Author({
corpora: [new CorpusMC({source_urn: 'proiel'})],
name: 'name'
})];
authorPage.ngOnInit();
expect(authorPage.baseAuthorList.length).toBe(1);
});
it('should restore the last setup', (done) => {
const restoreSpy: Spy = spyOn(authorPage.corpusService, 'restoreLastCorpus').and.callFake(() => Promise.reject());
const showTextSpy: Spy = spyOn(authorPage.helperService, 'goToShowTextPage').and.returnValue(Promise.resolve(true));
const vocCheckSpy: Spy = spyOn(authorPage.helperService, 'goToVocabularyCheckPage').and.returnValue(Promise.resolve(true));
authorPage.helperService.isVocabularyCheck = false;
authorPage.restoreLastSetup().then(() => {
}, () => {
expect(showTextSpy).toHaveBeenCalledTimes(0);
restoreSpy.and.returnValue(Promise.resolve());
authorPage.restoreLastSetup().then(() => {
expect(showTextSpy).toHaveBeenCalledTimes(1);
authorPage.helperService.isVocabularyCheck = true;
authorPage.restoreLastSetup().then(() => {
expect(vocCheckSpy).toHaveBeenCalledTimes(1);
const a = 0;
done();
});
});
});
});
it('should show corpora', () => {
authorPage.helperService.applicationState.next(authorPage.helperService.deepCopy(MockMC.applicationState));
spyOn(authorPage.helperService, 'goToAuthorDetailPage').and.returnValue(Promise.resolve(true));
const author: Author = new Author({name: '', corpora: []});
authorPage.showCorpora(author);
expect(authorPage.corpusService.currentAuthor).toBe(author);
});
});
import {Component} from '@angular/core';
import {Component, OnInit} from '@angular/core';
import {Author} from 'src/app/models/author';
import {NavController} from '@ionic/angular';
import {TranslateService} from '@ngx-translate/core';
......@@ -21,34 +21,25 @@ import {take} from 'rxjs/operators';
templateUrl: './author.page.html',
styleUrls: ['./author.page.scss'],
})
export class AuthorPage {
export class AuthorPage implements OnInit {
constructor(public navCtrl: NavController,
public translate: TranslateService,
public corpusService: CorpusService,
public http: HttpClient,
public exerciseService: ExerciseService,
public helperService: HelperService) {
if (!this.corpusService.availableAuthors.length) {
this.corpusService.loadCorporaFromLocalStorage().then(() => {
this.toggleTreebankAuthors();
});
} else {
this.toggleTreebankAuthors();
}
}
public authorsDisplayed: Author[];
public baseAuthorList: Author[];
HelperService = HelperService;
showOnlyTreebanks = true;
currentSearchValue = '';
static filterAuthor(author: Author, filterValue: string) {
static filterAuthor(author: Author, filterValue: string): boolean {
return author.name.toLowerCase().includes(filterValue.toLowerCase());
}
getAuthors(newSearchValue: string) {
getAuthors(newSearchValue: string): void {
this.baseAuthorList = this.showOnlyTreebanks ? this.getAuthorsFiltered() : this.corpusService.availableAuthors;
if (!newSearchValue) {
this.authorsDisplayed = this.baseAuthorList;
......@@ -59,31 +50,46 @@ export class AuthorPage {
}
}
getAuthorsFiltered() {
getAuthorsFiltered(): Author[] {
return this.corpusService.availableAuthors.filter(author => author.corpora.some(corpus => this.corpusService.isTreebank(corpus)));
}
restoreLastSetup() {
this.corpusService.restoreLastCorpus().then(() => {
if (HelperService.isVocabularyCheck) {
HelperService.goToVocabularyCheckPage(this.navCtrl).then();
} else {
HelperService.goToShowTextPage(this.navCtrl).then();
}
}, () => {
ngOnInit(): void {
if (!this.corpusService.availableAuthors.length) {
this.corpusService.loadCorporaFromLocalStorage().then(() => {
this.toggleTreebankAuthors();
});
} else {
this.toggleTreebankAuthors();
}
}
restoreLastSetup(): Promise<void> {
return new Promise<void>((resolve, reject) => {
this.corpusService.restoreLastCorpus().then(() => {
if (this.helperService.isVocabularyCheck) {
this.helperService.goToVocabularyCheckPage(this.navCtrl).then();
return resolve();
} else {
this.helperService.goToShowTextPage(this.navCtrl).then();
return resolve();
}
}, () => {
return reject();
});
});
}
showCorpora(author: Author) {
showCorpora(author: Author): void {
this.corpusService.currentAuthor = author;
HelperService.applicationState.pipe(take(1)).subscribe((as: ApplicationState) => {
this.helperService.applicationState.pipe(take(1)).subscribe((as: ApplicationState) => {
as.currentSetup.currentAuthor = author;
this.helperService.saveApplicationState(as).then();
this.navCtrl.navigateForward('/author-detail').then();
this.helperService.goToAuthorDetailPage(this.navCtrl).then();
});
}
toggleTreebankAuthors() {
toggleTreebankAuthors(): void {
this.baseAuthorList = this.showOnlyTreebanks ? this.getAuthorsFiltered() : this.corpusService.availableAuthors;
this.authorsDisplayed = this.baseAuthorList.filter((author: Author) => {
return AuthorPage.filterAuthor(author, this.currentSearchValue);
......
......@@ -9,7 +9,7 @@ import {TranslateTestingModule} from '../translate-testing/translate-testing.mod
import {APP_BASE_HREF} from '@angular/common';
describe('ConfirmCancelPage', () => {
let component: ConfirmCancelPage;
let confirmCancelPage: ConfirmCancelPage;
let fixture: ComponentFixture<ConfirmCancelPage>;
beforeEach(async(() => {
......@@ -26,16 +26,23 @@ describe('ConfirmCancelPage', () => {
],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
.compileComponents();
.compileComponents().then();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ConfirmCancelPage);
component = fixture.componentInstance;
confirmCancelPage = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
expect(confirmCancelPage).toBeTruthy();
});
it('should confirm', () => {
confirmCancelPage.helperService.currentPopover = {dismiss: () => Promise.resolve(true)} as HTMLIonPopoverElement;
spyOn(confirmCancelPage.helperService, 'goToHomePage').and.returnValue(Promise.resolve(true));
confirmCancelPage.confirm();
expect(confirmCancelPage.helperService.currentPopover).toBeFalsy();
});
});
import {Component, OnInit} from '@angular/core';
import {Component} from '@angular/core';
import {HelperService} from '../helper.service';
import {NavController} from "@ionic/angular";
import {NavController} from '@ionic/angular';
@Component({
selector: 'app-confirm-cancel',
templateUrl: './confirm-cancel.page.html',