From bda6331c59824f0a3d9107bb0139f05460d3d6f9 Mon Sep 17 00:00:00 2001 From: VLE2FE Date: Wed, 2 Sep 2020 16:31:59 +0200 Subject: [PATCH 1/4] implemented no measurements or condition filter --- src/app/samples/samples.component.html | 6 ++++++ src/app/samples/samples.component.scss | 4 ++++ src/app/samples/samples.component.ts | 7 +++++++ src/app/users/users.component.html | 7 ++++--- 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/app/samples/samples.component.html b/src/app/samples/samples.component.html index 4c93668..6ef8aa6 100644 --- a/src/app/samples/samples.component.html +++ b/src/app/samples/samples.component.html @@ -104,6 +104,12 @@ + + has no condition + + + has no measurements + diff --git a/src/app/samples/samples.component.scss b/src/app/samples/samples.component.scss index 8f7e06d..faf9435 100644 --- a/src/app/samples/samples.component.scss +++ b/src/app/samples/samples.component.scss @@ -178,6 +178,10 @@ rb-table { float: left; margin-right: 30px; } + + & > rb-form-checkbox { + float: left; + } } .filtermode { diff --git a/src/app/samples/samples.component.ts b/src/app/samples/samples.component.ts index 331d0b8..88061e7 100644 --- a/src/app/samples/samples.component.ts +++ b/src/app/samples/samples.component.ts @@ -52,6 +52,7 @@ export class SamplesComponent implements OnInit { pageSize: 25, toPage: 0, sort: 'added-asc', + no: {condition: false, measurements: false}, filters: [ {field: 'number', label: 'Number', active: false, autocomplete: [], mode: 'eq', values: ['']}, {field: 'material.name', label: 'Product name', active: false, autocomplete: [], mode: 'eq', values: ['']}, @@ -265,6 +266,12 @@ export class SamplesComponent implements OnInit { .filter(e => e.active && e.values.length > 0) .map(e => 'filters[]=' + encodeURIComponent(JSON.stringify(pick(e, ['mode', 'field', 'values'])))) ); + if (this.filters.no.condition) { + query.push('filters[]=' + encodeURIComponent( JSON.stringify({mode: 'eq', field: 'condition', values: [{}]}))); + } + if (this.filters.no.measurements) { + query.push('filters[]=' + encodeURIComponent( JSON.stringify( {mode: 'eq', field: 'measurements', values: [null]}))); + } if (!options.export) { additionalTableKeys.forEach(key => { if (query.indexOf('fields[]=' + key) < 0) { // add key if not already added diff --git a/src/app/users/users.component.html b/src/app/users/users.component.html index 9c095e2..b745808 100644 --- a/src/app/users/users.component.html +++ b/src/app/users/users.component.html @@ -15,7 +15,8 @@ Cannot be empty - {{locationInput.errors.failure}} Cannot be empty @@ -100,13 +101,13 @@ + appValidate="string" [name]="'device-' + item.i" [ngModel]="item.value"> - From 2dc962c75482095892c991ac4e8b244c2c9f7abf Mon Sep 17 00:00:00 2001 From: VLE2FE Date: Thu, 3 Sep 2020 10:53:41 +0200 Subject: [PATCH 2/4] implemented editable help --- src/app/app.component.ts | 2 +- .../documentation-database.component.html | 17 +++++++++ src/app/help/help.component.html | 37 ++++++++++++------- src/app/help/help.component.scss | 3 ++ src/app/help/help.component.ts | 36 ++++++++++++++++-- src/app/models/help.model.spec.ts | 7 ++++ src/app/models/help.model.ts | 6 +++ 7 files changed, 90 insertions(+), 18 deletions(-) create mode 100644 src/app/models/help.model.spec.ts create mode 100644 src/app/models/help.model.ts diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 25d053b..7d08253 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -37,7 +37,7 @@ export class AppComponent implements OnInit{ ngOnInit() { this.login.login().then(res => { - if (!res && !(this.route.snapshot.url.length && this.route.snapshot.url[0].path === '/documentation')) { + if (!res && !(/\/documentation/.test(this.router.url))) { this.router.navigate(['/']); } }); diff --git a/src/app/documentation/documentation-database/documentation-database.component.html b/src/app/documentation/documentation-database/documentation-database.component.html index e2ede6d..4562eb1 100644 --- a/src/app/documentation/documentation-database/documentation-database.component.html +++ b/src/app/documentation/documentation-database/documentation-database.component.html @@ -387,4 +387,21 @@ Every time: The user that executed this command '5f2e63118d1c020f8cda6a09' + + help + + _id + Automatically generated unique id + '5f2e63d28d1c020f8cda6f86' + + + key + The key used to find the required help text + '/documentation/database' + + + text + The actual help text + 'This page documents the database.' + diff --git a/src/app/help/help.component.html b/src/app/help/help.component.html index 2b615dc..7e6450b 100644 --- a/src/app/help/help.component.html +++ b/src/app/help/help.component.html @@ -1,14 +1,25 @@ -

Help

+

Help + +

- -

Please log in for further access. If you do not have an account yet, please contact - {{d.contact.name}}. -

-

Please log in for further access. If you do not have an account yet, please contact - {{d.contact.name}}. -

-

- Sadly, currently there is no help available for this page. Please contact - {{d.contact.name}} for further questions. -

-
+
+ + + + + + Save + Delete +
+ + +

+ {{content.text}} +

+ + + Sadly, currently there is no help available for this page. Please contact + {{d.contact.name}} for further questions. + + +
diff --git a/src/app/help/help.component.scss b/src/app/help/help.component.scss index e69de29..b7b3479 100644 --- a/src/app/help/help.component.scss +++ b/src/app/help/help.component.scss @@ -0,0 +1,3 @@ +.delete-btn { + float: right; +} diff --git a/src/app/help/help.component.ts b/src/app/help/help.component.ts index 371000d..77db6ec 100644 --- a/src/app/help/help.component.ts +++ b/src/app/help/help.component.ts @@ -1,6 +1,9 @@ import { Component, OnInit } from '@angular/core'; import {Router} from '@angular/router'; import {DataService} from '../services/data.service'; +import {ApiService} from '../services/api.service'; +import {HelpModel} from '../models/help.model'; +import {LoginService} from '../services/login.service'; @Component({ selector: 'app-help', @@ -9,16 +12,41 @@ import {DataService} from '../services/data.service'; }) export class HelpComponent implements OnInit { - route = ''; + content: HelpModel = new HelpModel().deserialize({text: null, level: 'none'}); + edit = false; + private route = ''; constructor( private router: Router, - public d: DataService + public d: DataService, + private api: ApiService, + public login: LoginService ) { } ngOnInit(): void { - this.route = this.router.url.replace(/\/[0-9a-f]{24}/, ''); // remove ids - console.log(this.route); + this.route = encodeURIComponent(this.router.url.replace(/\/[0-9a-f]{24}/, '')); + // remove ids from path and get help content + this.api.get('/help/' + this.route, (data, err) => { + if (!err) { // content was found + this.content = new HelpModel().deserialize(data); + } + else { + this.content.text = ''; + } + console.log(this.content); + }); } + saveHelp() { + this.api.post('/help/' + this.route, this.content.sendFormat(), () => { + this.edit = false; + }); + } + + deleteHelp() { + this.api.delete('/help/' + this.route, (ignore, ignore) => { + this.content = new HelpModel().deserialize({text: null, level: 'none'}); + this.edit = false; + }); + } } diff --git a/src/app/models/help.model.spec.ts b/src/app/models/help.model.spec.ts new file mode 100644 index 0000000..899436f --- /dev/null +++ b/src/app/models/help.model.spec.ts @@ -0,0 +1,7 @@ +import { HelpModel } from './help.model'; + +describe('Help.Model', () => { + it('should create an instance', () => { + expect(new HelpModel()).toBeTruthy(); + }); +}); diff --git a/src/app/models/help.model.ts b/src/app/models/help.model.ts new file mode 100644 index 0000000..cc4e63b --- /dev/null +++ b/src/app/models/help.model.ts @@ -0,0 +1,6 @@ +import {BaseModel} from './base.model'; + +export class HelpModel extends BaseModel { + text = ''; + level = 'none'; +} From 1440e9a6fcde31ff900bfff99a0b88b5d01f5cd0 Mon Sep 17 00:00:00 2001 From: VLE2FE Date: Thu, 3 Sep 2020 10:54:20 +0200 Subject: [PATCH 3/4] implemented editable help --- src/app/help/help.component.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/app/help/help.component.ts b/src/app/help/help.component.ts index 77db6ec..019b469 100644 --- a/src/app/help/help.component.ts +++ b/src/app/help/help.component.ts @@ -44,9 +44,11 @@ export class HelpComponent implements OnInit { } deleteHelp() { - this.api.delete('/help/' + this.route, (ignore, ignore) => { - this.content = new HelpModel().deserialize({text: null, level: 'none'}); - this.edit = false; + this.api.delete('/help/' + this.route, (ignore, err) => { + if (!err) { + this.content = new HelpModel().deserialize({text: null, level: 'none'}); + this.edit = false; + } }); } } From c38d0be4578be9e84d594614a6a94411715c051e Mon Sep 17 00:00:00 2001 From: VLE2FE Date: Thu, 3 Sep 2020 15:51:53 +0200 Subject: [PATCH 4/4] code improvements --- e2e/src/app.e2e-spec.ts | 17 --- e2e/src/app.po.ts | 11 -- src/app/app-routing.module.ts | 3 +- src/app/app.component.spec.ts | 63 -------- src/app/app.component.ts | 7 +- src/app/app.module.ts | 6 +- src/app/changelog/changelog.component.html | 1 - src/app/changelog/changelog.component.spec.ts | 56 +------ src/app/changelog/changelog.component.ts | 9 +- ...cumentation-architecture.component.spec.ts | 20 --- .../documentation-database.component.html | 6 +- .../documentation-database.component.spec.ts | 36 ----- .../documentation-models.component.spec.ts | 20 --- .../documentation.component.html | 1 - .../documentation.component.spec.ts | 37 ----- src/app/error/error.component.spec.ts | 43 ------ src/app/error/error.component.ts | 4 +- src/app/exists.pipe.spec.ts | 1 - src/app/exists.pipe.ts | 1 - src/app/help/help.component.html | 2 +- src/app/help/help.component.scss | 4 + src/app/help/help.component.spec.ts | 20 --- src/app/help/help.component.ts | 9 +- src/app/home/home.component.spec.ts | 34 ----- .../img-magnifier.component.spec.ts | 44 +----- .../img-magnifier/img-magnifier.component.ts | 14 +- src/app/login/login.component.spec.ts | 136 ----------------- src/app/login/login.component.ts | 6 +- src/app/material/material.component.spec.ts | 20 --- src/app/material/material.component.ts | 17 ++- src/app/materials/materials.component.spec.ts | 20 --- src/app/materials/materials.component.ts | 24 +-- .../model-templates.component.html | 1 - .../model-templates.component.spec.ts | 20 --- .../model-templates.component.ts | 25 ++-- src/app/object.pipe.spec.ts | 1 - src/app/parameters.pipe.spec.ts | 1 - src/app/parameters.pipe.ts | 3 +- src/app/prediction/prediction.component.html | 1 - .../prediction/prediction.component.spec.ts | 42 ------ src/app/prediction/prediction.component.ts | 23 +-- .../array-input-helper.service.spec.ts | 13 -- .../array-input-helper.service.ts | 4 +- .../rb-array-input.component.spec.ts | 31 +--- .../rb-array-input.component.ts | 24 +-- .../rb-custom-inputs.module.ts | 3 +- .../rb-icon-button.component.spec.ts | 24 --- .../rb-table/rb-table.component.scss | 1 - .../rb-table/rb-table.component.spec.ts | 23 --- src/app/sample/sample.component.spec.ts | 81 +--------- src/app/sample/sample.component.ts | 73 +++++---- src/app/samples/samples.component.scss | 17 --- src/app/samples/samples.component.spec.ts | 82 +---------- src/app/samples/samples.component.ts | 76 +++++----- src/app/services/api.service.spec.ts | 138 ------------------ src/app/services/api.service.ts | 23 ++- src/app/services/autocomplete.service.spec.ts | 32 ---- src/app/services/data.service.spec.ts | 28 ---- src/app/services/data.service.ts | 13 +- src/app/services/login.service.spec.ts | 90 ------------ src/app/services/login.service.ts | 9 +- src/app/services/validation.service.spec.ts | 111 -------------- src/app/services/validation.service.ts | 12 +- src/app/settings/settings.component.html | 1 - src/app/settings/settings.component.spec.ts | 67 +-------- src/app/settings/settings.component.ts | 10 +- src/app/templates/templates.component.html | 1 - src/app/templates/templates.component.spec.ts | 52 ------- src/app/templates/templates.component.ts | 30 ++-- src/app/users/users.component.html | 1 - src/app/users/users.component.spec.ts | 48 ------ src/app/users/users.component.ts | 16 +- src/app/validate.directive.spec.ts | 19 +-- 73 files changed, 276 insertions(+), 1686 deletions(-) delete mode 100644 e2e/src/app.po.ts diff --git a/e2e/src/app.e2e-spec.ts b/e2e/src/app.e2e-spec.ts index f72e716..896723d 100644 --- a/e2e/src/app.e2e-spec.ts +++ b/e2e/src/app.e2e-spec.ts @@ -2,22 +2,5 @@ import { AppPage } from './app.po'; import { browser, logging } from 'protractor'; describe('workspace-project App', () => { - let page: AppPage; - beforeEach(() => { - page = new AppPage(); - }); - - it('should display the page title', () => { - page.navigateTo(); - expect(page.getTitleText()).toEqual('Digital Fingerprint of Plastics'); - }); - - afterEach(async () => { - // Assert that there are no errors emitted from the browser - const logs = await browser.manage().logs().get(logging.Type.BROWSER); - expect(logs).not.toContain(jasmine.objectContaining({ - level: logging.Level.SEVERE, - } as logging.Entry)); - }); }); diff --git a/e2e/src/app.po.ts b/e2e/src/app.po.ts deleted file mode 100644 index 992a008..0000000 --- a/e2e/src/app.po.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { browser, by, element } from 'protractor'; - -export class AppPage { - navigateTo() { - return browser.get(browser.baseUrl) as Promise; - } - - getTitleText() { - return element(by.css('app-root div .sub-brand-content')).getText() as Promise; - } -} diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 3c3ebdd..7ccfff6 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -12,7 +12,8 @@ import {ChangelogComponent} from './changelog/changelog.component'; import {DocumentationDatabaseComponent} from './documentation/documentation-database/documentation-database.component'; import {PredictionComponent} from './prediction/prediction.component'; import {ModelTemplatesComponent} from './model-templates/model-templates.component'; -import {DocumentationArchitectureComponent} from './documentation/documentation-architecture/documentation-architecture.component'; +import {DocumentationArchitectureComponent} from + './documentation/documentation-architecture/documentation-architecture.component'; import {MaterialsComponent} from './materials/materials.component'; import {MaterialComponent} from './material/material.component'; import {DocumentationModelsComponent} from './documentation/documentation-models/documentation-models.component'; diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts index 6eae18e..87f4db8 100644 --- a/src/app/app.component.spec.ts +++ b/src/app/app.component.spec.ts @@ -1,68 +1,5 @@ import {TestBed, async, ComponentFixture} from '@angular/core/testing'; -import { AppComponent } from './app.component'; -import {By} from '@angular/platform-browser'; -import {RbUiComponentsModule} from '@inst-iot/bosch-angular-ui-components'; -import {RouterTestingModule} from '@angular/router/testing'; -import {LoginService} from './services/login.service'; -import {Router} from '@angular/router'; -import {Observable} from 'rxjs'; -import {Test} from 'tslint'; -import {RbCustomInputsModule} from './rb-custom-inputs/rb-custom-inputs.module'; - -// TODO - -let loginServiceSpy: jasmine.SpyObj; -let routerServiceSpy: Router; -let windowServiceSpy: jasmine.SpyObj; describe('AppComponent', () => { - let component: AppComponent; - let fixture: ComponentFixture; - let css; // get native element by css selector - - beforeEach(async(() => { - const loginSpy = jasmine.createSpyObj('LoginService', ['login', 'isLevel', 'isLoggedIn']); - const windowSpy = jasmine.createSpyObj('Window', ['location', 'innerWidth', 'innerHeight', 'scroll']); - - TestBed.configureTestingModule({ - declarations: [ AppComponent ], - imports: [ - RbUiComponentsModule, - RbCustomInputsModule, - RouterTestingModule - ], - providers: [ - {provide: LoginService, useValue: loginSpy}, - {provide: Window, useValue: windowSpy} - ] - }).compileComponents(); - - loginServiceSpy = TestBed.inject(LoginService) as jasmine.SpyObj; - routerServiceSpy = TestBed.inject(Router); - windowServiceSpy = TestBed.inject(Window) as jasmine.SpyObj; - })); - - beforeEach(() => { - fixture = TestBed.createComponent(AppComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - css = (selector) => fixture.debugElement.query(By.css(selector)).nativeElement; - }); - - it('should create the app', () => { - expect(component).toBeTruthy(); - }); - - it('should have the header', () => { - expect(css('rb-full-header')).toBeTruthy(); - }); - - it('should have the correct app title', () => { - expect(css('rb-full-header div.sub-brand-content > div').innerText).toBe('BugDEVELOPMENT DeFinMa'); - }); - - it('should have the page container', () => { - expect(css('.container')).toBeTruthy(); - }); }); diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 7d08253..75f844d 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -6,7 +6,6 @@ import {HelpComponent} from './help/help.component'; import {DataService} from './services/data.service'; -// TODO: get rid of chart.js (+moment.js) @Component({ selector: 'app-root', @@ -15,8 +14,8 @@ import {DataService} from './services/data.service'; }) export class AppComponent implements OnInit{ - bugReport = {do: '', work: ''}; - isDocumentation = false; + bugReport = {do: '', work: ''}; // data from bug report inputs + isDocumentation = false; // true if user is on documentation pages devMode = false; constructor( @@ -36,7 +35,9 @@ export class AppComponent implements OnInit{ } ngOnInit() { + // try to log in user this.login.login().then(res => { + // return to home page if log failed, except when on documentation pages if (!res && !(/\/documentation/.test(this.router.url))) { this.router.navigate(['/']); } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 2d04295..37a5f20 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -26,12 +26,14 @@ import { ParametersPipe } from './parameters.pipe'; import { SettingsComponent } from './settings/settings.component'; import { UsersComponent } from './users/users.component'; import { ChangelogComponent } from './changelog/changelog.component'; -import { DocumentationDatabaseComponent } from './documentation/documentation-database/documentation-database.component'; +import { DocumentationDatabaseComponent } from + './documentation/documentation-database/documentation-database.component'; import { PredictionComponent } from './prediction/prediction.component'; import { HelpComponent } from './help/help.component'; import { ModelTemplatesComponent } from './model-templates/model-templates.component'; import { SizePipe } from './size.pipe'; -import { DocumentationArchitectureComponent } from './documentation/documentation-architecture/documentation-architecture.component'; +import { DocumentationArchitectureComponent } from + './documentation/documentation-architecture/documentation-architecture.component'; import { MaterialsComponent } from './materials/materials.component'; import { MaterialComponent } from './material/material.component'; import { DocumentationModelsComponent } from './documentation/documentation-models/documentation-models.component'; diff --git a/src/app/changelog/changelog.component.html b/src/app/changelog/changelog.component.html index e237f9a..8f47562 100644 --- a/src/app/changelog/changelog.component.html +++ b/src/app/changelog/changelog.component.html @@ -1,4 +1,3 @@ -
diff --git a/src/app/changelog/changelog.component.spec.ts b/src/app/changelog/changelog.component.spec.ts index 367c05d..163ed8c 100644 --- a/src/app/changelog/changelog.component.spec.ts +++ b/src/app/changelog/changelog.component.spec.ts @@ -1,51 +1,5 @@ -// import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -// -// import { ChangelogComponent } from './changelog.component'; -// import {ApiService} from '../services/api.service'; -// import {ModalService, RbUiComponentsModule} from '@inst-iot/bosch-angular-ui-components'; -// import {FormsModule} from '@angular/forms'; -// import {ValidationService} from '../services/validation.service'; -// import {DataService} from '../services/data.service'; -// import {RbCustomInputsModule} from '../rb-custom-inputs/rb-custom-inputs.module'; -// -// // TODO -// -// let apiServiceSpy: jasmine.SpyObj; -// let modalServiceSpy: jasmine.SpyObj; -// -// describe('ChangelogComponent', () => { -// let component: ChangelogComponent; -// let fixture: ComponentFixture; -// -// beforeEach(async(() => { -// const apiSpy = jasmine.createSpyObj('ApiService', ['get']); -// const modalSpy = jasmine.createSpyObj('ModalService', ['open']); -// -// TestBed.configureTestingModule({ -// declarations: [ ChangelogComponent ], -// imports: [ -// RbUiComponentsModule, -// RbCustomInputsModule -// ], -// providers: [ -// {provide: ApiService, useValue: apiSpy}, -// {provide: ModalService, useValue: modalSpy} -// ] -// }) -// .compileComponents(); -// -// apiServiceSpy = TestBed.inject(ApiService) as jasmine.SpyObj; -// modalServiceSpy = TestBed.inject(ModalService) as jasmine.SpyObj; -// })); -// -// beforeEach(() => { -// fixture = TestBed.createComponent(ChangelogComponent); -// component = fixture.componentInstance; -// component.ngOnInit(); -// fixture.detectChanges(); -// }); -// -// it('should create', () => { -// expect(component).toBeTruthy(); -// }); -// }); +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +describe('ChangelogComponent', () => { + +}); diff --git a/src/app/changelog/changelog.component.ts b/src/app/changelog/changelog.component.ts index 06f3f61..b3a66a9 100644 --- a/src/app/changelog/changelog.component.ts +++ b/src/app/changelog/changelog.component.ts @@ -10,10 +10,10 @@ import {ModalService} from '@inst-iot/bosch-angular-ui-components'; }) export class ChangelogComponent implements OnInit { - timestamp = new Date(); + timestamp = new Date(); // time from date input pageSize = 25; changelog: ChangelogModel[] = []; - modalDetail = 0; + modalDetail = 0; // index of changelog element to show details of constructor( private api: ApiService, @@ -24,7 +24,7 @@ export class ChangelogComponent implements OnInit { this.loadChangelog(); } - loadChangelog(page = 0) { + loadChangelog(page = 0) { // load changelog with page no relative to current page this.api.get(`/changelog/${ page > 0 ? this.changelog[0]._id : // use id if no new date was given Math.floor(new Date( @@ -32,12 +32,13 @@ export class ChangelogComponent implements OnInit { ).getTime() / 1000).toString(16) + '0000000000000000' // id from time }/${page}/${this.pageSize}`, data => { this.changelog = data.map(e => new ChangelogModel().deserialize(e)); - if (page) { + if (page) { // adjust date picker to new first element when user clicked on next page this.timestamp = new Date(this.changelog[0].date); } }); } + // show details of a changelog element with reference to needed modal showDetails(i: number, modal: TemplateRef) { this.modalDetail = i; this.modal.open(modal).then(() => {}); diff --git a/src/app/documentation/documentation-architecture/documentation-architecture.component.spec.ts b/src/app/documentation/documentation-architecture/documentation-architecture.component.spec.ts index ee6dd97..ce7417e 100644 --- a/src/app/documentation/documentation-architecture/documentation-architecture.component.spec.ts +++ b/src/app/documentation/documentation-architecture/documentation-architecture.component.spec.ts @@ -1,25 +1,5 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { DocumentationArchitectureComponent } from './documentation-architecture.component'; - describe('DocumentationArchitectureComponent', () => { - let component: DocumentationArchitectureComponent; - let fixture: ComponentFixture; - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ DocumentationArchitectureComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(DocumentationArchitectureComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); }); diff --git a/src/app/documentation/documentation-database/documentation-database.component.html b/src/app/documentation/documentation-database/documentation-database.component.html index 4562eb1..4a69938 100644 --- a/src/app/documentation/documentation-database/documentation-database.component.html +++ b/src/app/documentation/documentation-database/documentation-database.component.html @@ -1,4 +1,3 @@ -

The used database instance is a MongoDB instance running on the BIC, storing all application data. The admin database management page can be accessed @@ -399,6 +398,11 @@ Every time: The key used to find the required help text '/documentation/database' + + level + The minimum level required to read this help + 'write' + text The actual help text diff --git a/src/app/documentation/documentation-database/documentation-database.component.spec.ts b/src/app/documentation/documentation-database/documentation-database.component.spec.ts index febc10d..d5719be 100644 --- a/src/app/documentation/documentation-database/documentation-database.component.spec.ts +++ b/src/app/documentation/documentation-database/documentation-database.component.spec.ts @@ -1,41 +1,5 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { DocumentationDatabaseComponent } from './documentation-database.component'; -import {Component, Input} from '@angular/core'; -import {RbCustomInputsModule} from '../../rb-custom-inputs/rb-custom-inputs.module'; - -// TODO - -@Component({selector: 'app-img-magnifier', template: ''}) -class ImgMagnifierStubComponent { - @Input() magnifierSize: {width: number, height: number}; -} - describe('DocumentationDatabaseComponent', () => { - let component: DocumentationDatabaseComponent; - let fixture: ComponentFixture; - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ - DocumentationDatabaseComponent, - ImgMagnifierStubComponent - ], - imports: [ - RbCustomInputsModule - ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(DocumentationDatabaseComponent); - component = fixture.componentInstance; - component.ngOnInit(); - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); }); diff --git a/src/app/documentation/documentation-models/documentation-models.component.spec.ts b/src/app/documentation/documentation-models/documentation-models.component.spec.ts index d1adf71..904d2e2 100644 --- a/src/app/documentation/documentation-models/documentation-models.component.spec.ts +++ b/src/app/documentation/documentation-models/documentation-models.component.spec.ts @@ -1,25 +1,5 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { DocumentationModelsComponent } from './documentation-models.component'; - describe('DocumentationModelsComponent', () => { - let component: DocumentationModelsComponent; - let fixture: ComponentFixture; - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ DocumentationModelsComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(DocumentationModelsComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); }); diff --git a/src/app/documentation/documentation.component.html b/src/app/documentation/documentation.component.html index 1eb1257..994c74e 100644 --- a/src/app/documentation/documentation.component.html +++ b/src/app/documentation/documentation.component.html @@ -1,4 +1,3 @@ -

View the presentation explaining the main functions diff --git a/src/app/documentation/documentation.component.spec.ts b/src/app/documentation/documentation.component.spec.ts index 364435c..5e393fe 100644 --- a/src/app/documentation/documentation.component.spec.ts +++ b/src/app/documentation/documentation.component.spec.ts @@ -1,42 +1,5 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { DocumentationComponent } from './documentation.component'; -import {RbCustomInputsModule} from '../rb-custom-inputs/rb-custom-inputs.module'; -import {ApiService} from '../services/api.service'; - -// TODO - -let apiServiceSpy: jasmine.SpyObj; - describe('DocumentationComponent', () => { - let component: DocumentationComponent; - let fixture: ComponentFixture; - beforeEach(async(() => { - const apiSpy = jasmine.createSpyObj('ApiService', ['post', 'put']); - - TestBed.configureTestingModule({ - declarations: [ DocumentationComponent ], - imports: [ - RbCustomInputsModule - ], - providers: [ - {provide: ApiService, useValue: apiSpy} - ] - }) - .compileComponents(); - - apiServiceSpy = TestBed.inject(ApiService) as jasmine.SpyObj; - })); - - beforeEach(() => { - fixture = TestBed.createComponent(DocumentationComponent); - component = fixture.componentInstance; - component.ngOnInit(); - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); }); diff --git a/src/app/error/error.component.spec.ts b/src/app/error/error.component.spec.ts index d48f3f6..f871065 100644 --- a/src/app/error/error.component.spec.ts +++ b/src/app/error/error.component.spec.ts @@ -1,48 +1,5 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { ErrorComponent } from './error.component'; -import {ModalService, RbUiComponentsModule} from '@inst-iot/bosch-angular-ui-components'; -import {By} from '@angular/platform-browser'; - -// TODO - describe('ErrorComponent', () => { - let component: ErrorComponent; - let fixture: ComponentFixture; - let css; // get native element by css selector - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ ErrorComponent ], - imports: [ - RbUiComponentsModule, - ], - providers: [ - ModalService - ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(ErrorComponent); - component = fixture.componentInstance; - component.ngOnInit(); - fixture.detectChanges(); - css = (selector) => fixture.debugElement.query(By.css(selector)).nativeElement; - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('should show the alert', () => { - expect(css('rb-alert')).toBeTruthy(); - }); - - it('should have the right message', () => { - component.message = 'test'; - fixture.detectChanges(); - expect(css('.dialog-text').innerText).toBe('test'); - }); }); diff --git a/src/app/error/error.component.ts b/src/app/error/error.component.ts index 5ecd4e0..7771fb3 100644 --- a/src/app/error/error.component.ts +++ b/src/app/error/error.component.ts @@ -7,8 +7,8 @@ import { Component, OnInit } from '@angular/core'; }) export class ErrorComponent implements OnInit { - message = ''; - details: string[] = []; + message = ''; // main error message + details: string[] = []; // array of error detail paragraphs constructor() { } diff --git a/src/app/exists.pipe.spec.ts b/src/app/exists.pipe.spec.ts index 2616a58..a485fa5 100644 --- a/src/app/exists.pipe.spec.ts +++ b/src/app/exists.pipe.spec.ts @@ -1,6 +1,5 @@ import { ExistsPipe } from './exists.pipe'; -// TODO describe('ExistsPipe', () => { it('create an instance', () => { diff --git a/src/app/exists.pipe.ts b/src/app/exists.pipe.ts index 2fefbd7..18fb1f3 100644 --- a/src/app/exists.pipe.ts +++ b/src/app/exists.pipe.ts @@ -7,7 +7,6 @@ import { Pipe, PipeTransform } from '@angular/core'; export class ExistsPipe implements PipeTransform { transform(value: unknown, key?): unknown { - // console.log(new Date().getTime()); return value || value === 0 ? (key ? value[key] : value) : ''; } diff --git a/src/app/help/help.component.html b/src/app/help/help.component.html index 7e6450b..c4c96a5 100644 --- a/src/app/help/help.component.html +++ b/src/app/help/help.component.html @@ -13,7 +13,7 @@

-

+

{{content.text}}

diff --git a/src/app/help/help.component.scss b/src/app/help/help.component.scss index b7b3479..bd39691 100644 --- a/src/app/help/help.component.scss +++ b/src/app/help/help.component.scss @@ -1,3 +1,7 @@ .delete-btn { float: right; } + +.content-text { + white-space: pre-line; +} diff --git a/src/app/help/help.component.spec.ts b/src/app/help/help.component.spec.ts index 191ecee..b90b354 100644 --- a/src/app/help/help.component.spec.ts +++ b/src/app/help/help.component.spec.ts @@ -1,25 +1,5 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { HelpComponent } from './help.component'; - describe('HelpComponent', () => { - let component: HelpComponent; - let fixture: ComponentFixture; - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ HelpComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(HelpComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); }); diff --git a/src/app/help/help.component.ts b/src/app/help/help.component.ts index 019b469..990dea9 100644 --- a/src/app/help/help.component.ts +++ b/src/app/help/help.component.ts @@ -12,9 +12,9 @@ import {LoginService} from '../services/login.service'; }) export class HelpComponent implements OnInit { - content: HelpModel = new HelpModel().deserialize({text: null, level: 'none'}); - edit = false; - private route = ''; + content: HelpModel = new HelpModel().deserialize({text: null, level: 'none'}); // help content + edit = false; // set true to change to edit mode + private route = ''; // URIComponent encoded route which serves as a key to fetch the help document constructor( private router: Router, @@ -24,8 +24,8 @@ export class HelpComponent implements OnInit { ) { } ngOnInit(): void { + // remove ids from path this.route = encodeURIComponent(this.router.url.replace(/\/[0-9a-f]{24}/, '')); - // remove ids from path and get help content this.api.get('/help/' + this.route, (data, err) => { if (!err) { // content was found this.content = new HelpModel().deserialize(data); @@ -33,7 +33,6 @@ export class HelpComponent implements OnInit { else { this.content.text = ''; } - console.log(this.content); }); } diff --git a/src/app/home/home.component.spec.ts b/src/app/home/home.component.spec.ts index 5db4493..9781a98 100644 --- a/src/app/home/home.component.spec.ts +++ b/src/app/home/home.component.spec.ts @@ -1,39 +1,5 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { HomeComponent } from './home.component'; -import {Component} from '@angular/core'; -import {By} from '@angular/platform-browser'; - -// TODO - -@Component({selector: 'app-login', template: ''}) -class LoginStubComponent {} describe('HomeComponent', () => { - let component: HomeComponent; - let fixture: ComponentFixture; - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ - HomeComponent, - LoginStubComponent - ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(HomeComponent); - component = fixture.componentInstance; - component.ngOnInit(); - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('should load the login component', () => { - expect(fixture.debugElement.query(By.css('app-login'))).toBeTruthy(); - }); }); diff --git a/src/app/img-magnifier/img-magnifier.component.spec.ts b/src/app/img-magnifier/img-magnifier.component.spec.ts index e0e40b8..08e5e16 100644 --- a/src/app/img-magnifier/img-magnifier.component.spec.ts +++ b/src/app/img-magnifier/img-magnifier.component.spec.ts @@ -1,39 +1,5 @@ -// import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -// -// import { ImgMagnifierComponent } from './img-magnifier.component'; -// -// // TODO -// -// let windowServiceSpy: jasmine.SpyObj; -// -// describe('ImgMagnifierComponent', () => { -// let component: ImgMagnifierComponent; -// let fixture: ComponentFixture; -// -// beforeEach(async(() => { -// const windowSpy = jasmine.createSpyObj('Window', ['pageXOffset', 'pageYOffset']); -// -// TestBed.configureTestingModule({ -// declarations: [ ImgMagnifierComponent ], -// imports: [ -// ], -// providers: [ -// {provide: Window, useValue: windowSpy} -// ] -// }) -// .compileComponents(); -// -// windowServiceSpy = TestBed.inject(Window) as jasmine.SpyObj; -// })); -// -// beforeEach(() => { -// fixture = TestBed.createComponent(ImgMagnifierComponent); -// component = fixture.componentInstance; -// component.ngOnInit(); -// fixture.detectChanges(); -// }); -// -// it('should create', () => { -// expect(component).toBeTruthy(); -// }); -// }); +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +describe('ImgMagnifierComponent', () => { + +}); diff --git a/src/app/img-magnifier/img-magnifier.component.ts b/src/app/img-magnifier/img-magnifier.component.ts index 299967b..838dde8 100644 --- a/src/app/img-magnifier/img-magnifier.component.ts +++ b/src/app/img-magnifier/img-magnifier.component.ts @@ -7,13 +7,13 @@ import {AfterViewInit, Component, ElementRef, Input, OnInit, ViewChild} from '@a }) export class ImgMagnifierComponent implements OnInit, AfterViewInit { - @Input() src: string; - @Input() zoom: number; - @Input() magnifierSize: {width: number, height: number}; + @Input() src: string; // image source + @Input() zoom: number; // zoom level + @Input() magnifierSize: {width: number, height: number}; // size of the magnifier @ViewChild('mainImg') mainImg: ElementRef; backgroundSize; - magnifierPos = {x: 0, y: 0}; + magnifierPos = {x: 0, y: 0}; // position of the magnifier showMagnifier = false; constructor( @@ -29,7 +29,7 @@ export class ImgMagnifierComponent implements OnInit, AfterViewInit { }, 1); } - calcPos(event) { + calcPos(event) { // calculate the current magnifier position const img = this.mainImg.nativeElement.getBoundingClientRect(); this.magnifierPos.x = Math.min( img.width - this.magnifierSize.width, @@ -42,7 +42,7 @@ export class ImgMagnifierComponent implements OnInit, AfterViewInit { } calcBackgroundSize() { - this.backgroundSize = this.mainImg ? (this.mainImg.nativeElement.width * this.zoom - this.magnifierSize.width) + 'px ' + - (this.mainImg.nativeElement.height * this.zoom - this.magnifierSize.height) + 'px ' : '0 0'; + this.backgroundSize = this.mainImg ? (this.mainImg.nativeElement.width * this.zoom - this.magnifierSize.width) + + 'px ' + (this.mainImg.nativeElement.height * this.zoom - this.magnifierSize.height) + 'px ' : '0 0'; } } diff --git a/src/app/login/login.component.spec.ts b/src/app/login/login.component.spec.ts index c8613a7..a4b41e0 100644 --- a/src/app/login/login.component.spec.ts +++ b/src/app/login/login.component.spec.ts @@ -1,141 +1,5 @@ import {async, ComponentFixture, fakeAsync, TestBed, tick} from '@angular/core/testing'; -import { LoginComponent } from './login.component'; -import {LoginService} from '../services/login.service'; -import {ValidationService} from '../services/validation.service'; -import {FormsModule} from '@angular/forms'; -import {By} from '@angular/platform-browser'; -import {ValidateDirective} from '../validate.directive'; -import {RbUiComponentsModule} from '@inst-iot/bosch-angular-ui-components'; -import {ApiService} from '../services/api.service'; -import {RouterTestingModule} from '@angular/router/testing'; -import {Router} from '@angular/router'; - -// TODO - -let validationServiceSpy: jasmine.SpyObj; -let loginServiceSpy: jasmine.SpyObj; -let apiServiceSpy: jasmine.SpyObj; -let routerServiceSpy: Router; describe('LoginComponent', () => { - let component: LoginComponent; - let fixture: ComponentFixture; - let css; // get native element by css selector - let cssd; // get debug element by css selector - beforeEach(async(() => { - const validationSpy = jasmine.createSpyObj('ValidationService', ['username', 'password']); - const loginSpy = jasmine.createSpyObj('LoginService', ['login']); - const apiSpy = jasmine.createSpyObj('ApiService', ['post', 'put']); - - TestBed.configureTestingModule({ - declarations: [ LoginComponent, ValidateDirective ], - imports: [ - RbUiComponentsModule, - FormsModule, - RouterTestingModule - ], - providers: [ - {provide: ValidationService, useValue: validationSpy}, - {provide: LoginService, useValue: loginSpy}, - {provide: ApiService, useValue: apiSpy} - ] - }) - .compileComponents(); - - validationServiceSpy = TestBed.inject(ValidationService) as jasmine.SpyObj; - loginServiceSpy = TestBed.inject(LoginService) as jasmine.SpyObj; - apiServiceSpy = TestBed.inject(ApiService) as jasmine.SpyObj; - routerServiceSpy = TestBed.inject(Router); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(LoginComponent); - component = fixture.componentInstance; - component.ngOnInit(); - fixture.detectChanges(); - cssd = (selector) => fixture.debugElement.query(By.css(selector)); - css = (selector) => fixture.debugElement.query(By.css(selector)).nativeElement; - }); - - it('should create', () => { - validationServiceSpy.username.and.returnValue({ok: true, error: ''}); - validationServiceSpy.password.and.returnValue({ok: true, error: ''}); - expect(component).toBeTruthy(); - }); - - // it('should have the `Please log in` heading', () => { - // expect(css('h2').innerText).toBe('Please log in'); - // }); - // - // it('should have empty credential inputs', () => { - // expect(css('rb-form-input[label=username] input').value).toBe(''); - // expect(css('rb-form-input[label=password] input').value).toBe(''); - // }); - // - // it('should have an empty message at the beginning', () => { - // expect(css('.message').innerText).toBe(''); - // }); - // - // it('should have a login button', async () => { - // validationServiceSpy.username.and.returnValue({ok: true, error: ''}); - // validationServiceSpy.password.and.returnValue({ok: true, error: ''}); - // await fixture.whenStable(); - // fixture.detectChanges(); - // expect(css('.login-button')).toBeTruthy(); - // expect(css('.login-button').disabled).toBeTruthy(); - // }); - // - // it('should reject a wrong username', async () => { - // validationServiceSpy.username.and.returnValue({ok: false, error: 'username must only contain a-z0-9-_.'}); - // component.username = 'ab#'; - // fixture.detectChanges(); - // await fixture.whenRenderingDone(); - // expect(component.loginForm.controls.username.valid).toBeFalsy(); - // expect(validationServiceSpy.username).toHaveBeenCalledWith('ab#'); - // }); - // - // it('should reject a wrong password', async () => { - // validationServiceSpy.password.and.returnValue({ok: false, error: 'password must only contain a-zA-Z0-9!"#%&\'()*+,-./:;<=>?@[]^_`{|}~'}); - // component.password = 'abc'; - // - // fixture.detectChanges(); - // await fixture.whenRenderingDone(); - // expect(component.loginForm.controls.password.valid).toBeFalsy(); - // expect(validationServiceSpy.password).toHaveBeenCalledWith('abc'); - // }); - // - // it('should enable the login button with valid credentials', async () => { - // validationServiceSpy.username.and.returnValue({ok: true, error: ''}); - // validationServiceSpy.password.and.returnValue({ok: true, error: ''}); - // loginServiceSpy.login.and.returnValue(new Promise(r => r(true))); - // - // fixture.detectChanges(); - // await fixture.whenRenderingDone(); - // - // cssd('.login-button').triggerEventHandler('click', null); - // expect(css('.login-button').disabled).toBeFalsy(); - // expect(loginServiceSpy.login.calls.count()).toBe(1); - // }); - // - // it('should call the LoginService with valid credentials', () => { - // validationServiceSpy.username.and.returnValue({ok: true, error: ''}); - // validationServiceSpy.password.and.returnValue({ok: true, error: ''}); - // loginServiceSpy.login.and.returnValue(new Promise(r => r(true))); - // - // cssd('.login-button').triggerEventHandler('click', null); - // expect(loginServiceSpy.login.calls.count()).toBe(1); - // }); - // - // it('should display an error if the LoginService could not authenticate', fakeAsync(() => { - // validationServiceSpy.username.and.returnValue({ok: true, error: ''}); - // validationServiceSpy.password.and.returnValue({ok: true, error: ''}); - // loginServiceSpy.login.and.returnValue(new Promise(r => r(false))); - // - // cssd('.login-button').triggerEventHandler('click', null); - // expect(loginServiceSpy.login.calls.count()).toBe(1); - // tick(); - // fixture.detectChanges(); - // expect(css('.message').innerText).toBe('Wrong credentials!'); - // })); }); diff --git a/src/app/login/login.component.ts b/src/app/login/login.component.ts index 46cd572..9e5a4ce 100644 --- a/src/app/login/login.component.ts +++ b/src/app/login/login.component.ts @@ -16,7 +16,7 @@ export class LoginComponent implements OnInit { password = ''; email = ''; message = ''; // message below login fields - passreset = false; + passreset = false; // to toggle between normal login and password reset form @ViewChild('loginForm') loginForm; @@ -32,7 +32,7 @@ export class LoginComponent implements OnInit { } userLogin() { - if (this.passreset) { + if (this.passreset) { // reset password this.api.post('/user/passreset', {name: this.username, email: this.email}, (data, err) => { if (err) { this.message = 'Could not find a valid user'; @@ -49,7 +49,7 @@ export class LoginComponent implements OnInit { if (this.login.isLevel.read) { this.router.navigate(['/samples']); } - else { + else { // navigate prediction users to prediction as they cannot access samples this.router.navigate(['/prediction']); } } diff --git a/src/app/material/material.component.spec.ts b/src/app/material/material.component.spec.ts index 7293b78..f4e6e5b 100644 --- a/src/app/material/material.component.spec.ts +++ b/src/app/material/material.component.spec.ts @@ -1,25 +1,5 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { MaterialComponent } from './material.component'; - describe('MaterialComponent', () => { - let component: MaterialComponent; - let fixture: ComponentFixture; - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ MaterialComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(MaterialComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); }); diff --git a/src/app/material/material.component.ts b/src/app/material/material.component.ts index c9a4342..c861241 100644 --- a/src/app/material/material.component.ts +++ b/src/app/material/material.component.ts @@ -19,12 +19,12 @@ export class MaterialComponent implements OnInit, AfterContentChecked { @ViewChild('materialForm') materialForm: NgForm; - material: MaterialModel; - materialNames: string[] = []; + material: MaterialModel; // material to edit + materialNames: string[] = []; // all other material names for unique validation - modalText = {list: '', suggestion: ''}; - loading = 0; - checkFormAfterInit = true; + modalText = {list: '', suggestion: ''}; // modal for group and supplier correction + loading = 0; // number of loading instances + checkFormAfterInit = true; // revalidate all fields on the next AfterContentChecked constructor( private api: ApiService, @@ -42,6 +42,7 @@ export class MaterialComponent implements OnInit, AfterContentChecked { this.material = new MaterialModel().deserialize(data); this.loading--; this.d.load('materials', () => { + // filter out name of the edited material as it can stay the same this.materialNames = this.d.arr.materials.map(e => e.name).filter(e => e !== this.material.name); this.loading--; }); @@ -58,12 +59,14 @@ export class MaterialComponent implements OnInit, AfterContentChecked { } ngAfterContentChecked() { + // attach validators if (this.materialForm && this.material.properties.material_template) { // material template is set this.d.id.materialTemplates[this.material.properties.material_template].parameters.forEach((parameter, i) => { this.attachValidator(this.materialForm, 'materialParameter' + i, parameter.range); }); } + // revalidate if (this.checkFormAfterInit && this.materialForm !== undefined && this.materialForm.form.get('propertiesSelect')) { this.checkFormAfterInit = false; Object.keys(this.materialForm.form.controls).forEach(field => { @@ -97,7 +100,7 @@ export class MaterialComponent implements OnInit, AfterContentChecked { materialSave() { this.api.put('/material/' + this.material._id, this.material.sendFormat(), () => { - delete this.d.arr.materials; + delete this.d.arr.materials; // reload materials this.d.load('materials'); this.router.navigate(['/materials']); }); @@ -107,7 +110,7 @@ export class MaterialComponent implements OnInit, AfterContentChecked { this.modal.open(modal).then(result => { if (result) { this.api.delete('/material/' + this.material._id, (ignore, error) => { - if (error) { + if (error) { // material cannot be deleted as it is still referenced by active samples const modalRef = this.modal.openComponent(ErrorComponent); modalRef.instance.message = 'Cannot delete material as it is still in use!'; } diff --git a/src/app/materials/materials.component.spec.ts b/src/app/materials/materials.component.spec.ts index d89957d..58172d3 100644 --- a/src/app/materials/materials.component.spec.ts +++ b/src/app/materials/materials.component.spec.ts @@ -1,25 +1,5 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { MaterialsComponent } from './materials.component'; - describe('MaterialsComponent', () => { - let component: MaterialsComponent; - let fixture: ComponentFixture; - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ MaterialsComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(MaterialsComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); }); diff --git a/src/app/materials/materials.component.ts b/src/app/materials/materials.component.ts index c7a331a..0764d3e 100644 --- a/src/app/materials/materials.component.ts +++ b/src/app/materials/materials.component.ts @@ -12,13 +12,13 @@ import {ModalService} from '@inst-iot/bosch-angular-ui-components'; }) export class MaterialsComponent implements OnInit { - materials: MaterialModel[] = []; - templateKeys: {key: string, label: string}[] = []; - materialStatus = {validated: true, new: true, deleted: false}; - materialSearch = ''; - sampleSelect = false; + materials: MaterialModel[] = []; // all materials + templateKeys: {key: string, label: string}[] = []; // material template keys + materialStatus = {validated: true, new: true, deleted: false}; // material statuses to show + materialSearch = ''; // material name search string + sampleSelect = false; // set to true to show checkboxes for validation - page = 1; + page = 1; // page settings pages = 0; pageSize = 25; @@ -36,8 +36,8 @@ export class MaterialsComponent implements OnInit { this.templateKeys.push({key: parameter.name, label: `${this.ucFirst(template.name)} ${parameter.name}`}); }); }); + // filter out duplicates this.templateKeys = this.templateKeys.filter((e, i, a) => !a.slice(0, i).find(el => el.key === e.key)); - console.log(this.templateKeys); }); } @@ -51,7 +51,7 @@ export class MaterialsComponent implements OnInit { } validate() { - if (this.sampleSelect) { + if (this.sampleSelect) { // selection was done do actual validation this.materials.forEach(sample => { if (sample.selected) { this.api.put('/material/validate/' + sample._id); @@ -60,12 +60,12 @@ export class MaterialsComponent implements OnInit { this.loadMaterials(); this.sampleSelect = false; } - else { + else { // activate validation mode this.sampleSelect = true; } } - selectAll(event) { + selectAll(event) { // toggle selection for all items except deleted ones this.materials.forEach(material => { if (material.status !== 'deleted') { material.selected = event.target.checked; @@ -86,11 +86,11 @@ export class MaterialsComponent implements OnInit { }); } - ucFirst(string) { + ucFirst(string) { // convert first character of string to uppercase return string[0].toUpperCase() + string.slice(1); } - materialFilter(ms) { + materialFilter(ms) { // filter function for material names return e => e.name.indexOf(ms) >= 0; } diff --git a/src/app/model-templates/model-templates.component.html b/src/app/model-templates/model-templates.component.html index fd62fcf..e361d20 100644 --- a/src/app/model-templates/model-templates.component.html +++ b/src/app/model-templates/model-templates.component.html @@ -1,4 +1,3 @@ - New model diff --git a/src/app/model-templates/model-templates.component.spec.ts b/src/app/model-templates/model-templates.component.spec.ts index f6dafa2..a61d323 100644 --- a/src/app/model-templates/model-templates.component.spec.ts +++ b/src/app/model-templates/model-templates.component.spec.ts @@ -1,25 +1,5 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { ModelTemplatesComponent } from './model-templates.component'; - describe('ModelTemplatesComponent', () => { - let component: ModelTemplatesComponent; - let fixture: ComponentFixture; - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ ModelTemplatesComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(ModelTemplatesComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); }); diff --git a/src/app/model-templates/model-templates.component.ts b/src/app/model-templates/model-templates.component.ts index 849592d..1ce77a6 100644 --- a/src/app/model-templates/model-templates.component.ts +++ b/src/app/model-templates/model-templates.component.ts @@ -13,12 +13,12 @@ import omit from 'lodash/omit'; }) export class ModelTemplatesComponent implements OnInit { - newModel = false; - modelGroup = ''; - oldModelGroup = ''; - oldModelName = ''; - model = new ModelItemModel().models[0]; - groups = []; + newModel = false; // display new model dialog + modelGroup = ''; // group of the edited model + oldModelGroup = ''; // group of the edited model before editing started + oldModelName = ''; // name of the edited model before editing started + model = new ModelItemModel().models[0]; // edited model + groups = []; // all model group names constructor( private api: ApiService, @@ -40,13 +40,12 @@ export class ModelTemplatesComponent implements OnInit { } saveModel() { - console.log(this.modelGroup); - console.log(this.oldModelGroup); - if (this.oldModelGroup !== '' && this.modelGroup !== this.oldModelGroup) { // group was changed, delete model in old group + // group was changed, delete model in old group + if (this.oldModelGroup !== '' && this.modelGroup !== this.oldModelGroup) { this.delete(null, this.oldModelName, this.oldModelGroup); } this.api.post('/model/' + this.modelGroup, omit(this.model, '_id'), () => { - this.newModel = false; + this.newModel = false; // reset model edit parameters this.loadGroups(); this.modelGroup = ''; this.oldModelGroup = ''; @@ -57,7 +56,7 @@ export class ModelTemplatesComponent implements OnInit { delete(modal, name, group = null) { new Promise(resolve => { - if (modal) { + if (modal) { // if modal was given, wait for result this.modal.open(modal).then(result => { resolve(result); }); @@ -67,12 +66,12 @@ export class ModelTemplatesComponent implements OnInit { } }).then(res => { if (res) { - if (group) { // delete group + if (group) { // delete model group if given this.api.delete(`/model/${group}/${name}`, () => { this.loadGroups(); }); } - else { // delete file + else { // delete model file this.api.delete(`/model/file/${name}`, () => { this.d.arr.modelFiles.splice(this.d.arr.modelFiles.findIndex(e => e.name === name), 1); }); diff --git a/src/app/object.pipe.spec.ts b/src/app/object.pipe.spec.ts index ee8c297..dd4963c 100644 --- a/src/app/object.pipe.spec.ts +++ b/src/app/object.pipe.spec.ts @@ -1,6 +1,5 @@ import { ObjectPipe } from './object.pipe'; -// TODO describe('ObjectPipe', () => { it('create an instance', () => { diff --git a/src/app/parameters.pipe.spec.ts b/src/app/parameters.pipe.spec.ts index e733aad..28ba71e 100644 --- a/src/app/parameters.pipe.spec.ts +++ b/src/app/parameters.pipe.spec.ts @@ -1,6 +1,5 @@ import { ParametersPipe } from './parameters.pipe'; -// TODO describe('ParametersPipe', () => { it('create an instance', () => { diff --git a/src/app/parameters.pipe.ts b/src/app/parameters.pipe.ts index c3372e1..e8eecb4 100644 --- a/src/app/parameters.pipe.ts +++ b/src/app/parameters.pipe.ts @@ -6,7 +6,8 @@ import { Pipe, PipeTransform } from '@angular/core'; export class ParametersPipe implements PipeTransform { transform(value: {name: string, range: object}[]): string { - return `{${value.map(e => `${e.name}: <${JSON.stringify(e.range).replace('{}', 'any').replace(/["{}]/g, '')}>`).join(', ')}}`; + return `{${value.map(e => `${e.name}: <${JSON.stringify(e.range).replace('{}', 'any') + .replace(/["{}]/g, '')}>`).join(', ')}}`; } } diff --git a/src/app/prediction/prediction.component.html b/src/app/prediction/prediction.component.html index b503af5..9dcb575 100644 --- a/src/app/prediction/prediction.component.html +++ b/src/app/prediction/prediction.component.html @@ -1,4 +1,3 @@ -
diff --git a/src/app/prediction/prediction.component.spec.ts b/src/app/prediction/prediction.component.spec.ts index e605e71..14de212 100644 --- a/src/app/prediction/prediction.component.spec.ts +++ b/src/app/prediction/prediction.component.spec.ts @@ -1,47 +1,5 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { PredictionComponent } from './prediction.component'; -import {ApiService} from '../services/api.service'; -import {RbUiComponentsModule} from '@inst-iot/bosch-angular-ui-components'; -import {FormsModule} from '@angular/forms'; -import {ValidationService} from '../services/validation.service'; -import {DataService} from '../services/data.service'; -import {ChartsModule} from 'ng2-charts'; - -// TODO - -let apiServiceSpy: jasmine.SpyObj; - describe('PredictionComponent', () => { - let component: PredictionComponent; - let fixture: ComponentFixture; - beforeEach(async(() => { - const apiSpy = jasmine.createSpyObj('ApiService', ['post']); - - TestBed.configureTestingModule({ - declarations: [ PredictionComponent ], - imports: [ - RbUiComponentsModule, - ChartsModule - ], - providers: [ - {provide: ApiService, useValue: apiSpy} - ] - }) - .compileComponents(); - - apiServiceSpy = TestBed.inject(ApiService) as jasmine.SpyObj; - })); - - beforeEach(() => { - fixture = TestBed.createComponent(PredictionComponent); - component = fixture.componentInstance; - component.ngOnInit(); - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); }); diff --git a/src/app/prediction/prediction.component.ts b/src/app/prediction/prediction.component.ts index 755b039..af9da65 100644 --- a/src/app/prediction/prediction.component.ts +++ b/src/app/prediction/prediction.component.ts @@ -29,11 +29,12 @@ import {ModelItemModel} from '../models/model-item.model'; }) export class PredictionComponent implements OnInit { - result: {predictions: string[], mean: string}; + result: {predictions: string[], mean: string}; // prediction result from python container loading = false; activeGroup: ModelItemModel = new ModelItemModel(); activeModelIndex = 0; - multipleSamples = false; // if true, spectra belong to different samples, otherwise multiple spectra from the same sample are given + // if true, spectra belong to different samples, otherwise multiple spectra from the same sample are given + multipleSamples = false; spectrumNames: string[] = []; spectrum: string[][] = [[]]; flattenedSpectra = []; @@ -50,7 +51,7 @@ export class PredictionComponent implements OnInit { readonly chartOptions: ChartOptions = { scales: { xAxes: [{ticks: {min: 400, max: 4000, stepSize: 400, reverse: true}}], - yAxes: [{ticks: {min: 0, max: 1}}] + yAxes: [{ticks: {}}] }, responsive: true, tooltips: {enabled: false}, @@ -82,13 +83,16 @@ export class PredictionComponent implements OnInit { if (files.hasOwnProperty(i)) { const fileReader = new FileReader(); fileReader.onload = () => { + // parse to database spectrum representation this.spectrum = fileReader.result.toString().split('\r\n').map(e => e.split(',').map(el => parseFloat(el))) .filter(el => el.length === 2) as any; + // flatten to format needed for prediction this.flattenedSpectra[i] = {labels: this.spectrum.map(e => e[0]), values: this.spectrum.map(e => e[1])}; + // add to chart this.chart[i] = cloneDeep(this.chartInit); this.chart[i].data = this.spectrum.map(e => ({x: parseFloat(e[0]), y: parseFloat(e[1])})); load --; - if (load <= 0) { + if (load <= 0) { // all loaded this.loadPrediction(); } }; @@ -99,24 +103,21 @@ export class PredictionComponent implements OnInit { loadPrediction() { this.loading = true; - console.log(this.activeGroup); - console.log(this.activeModelIndex); this.api.post(this.activeGroup.models[this.activeModelIndex].url, this.flattenedSpectra, data => { - this.result = { + this.result = { // parse result into prediction and mean string predictions: Object.entries(omit(data, ['mean', 'std', 'label'])) .map((p: any) => p[1].map(e => `${p[0]}: ${e} ${data.label[p[0]]}`)) .reduce((s, e) => s.map((el, i) => this.clip(el) + ', ' + e[i])), mean: Object.keys(data.mean).map(e => - this.clip(`${e}: ${data.mean[e]} ${data.label[e]}`) + (data.std[e] !== '' ? ` (standard deviation: ${data.std[e]})` : '') + this.clip(`${e}: ${data.mean[e]} ${data.label[e]}`) + + (data.std[e] !== '' ? ` (standard deviation: ${data.std[e]})` : '') ).join(', ') }; - console.log(this.result); this.loading = false; }); } - groupChange(index) { - console.log(index); + groupChange(index) { // group was changed this.activeGroup = this.d.arr.modelGroups[index]; this.activeModelIndex = 0; this.result = undefined; diff --git a/src/app/rb-custom-inputs/rb-array-input/array-input-helper.service.spec.ts b/src/app/rb-custom-inputs/rb-array-input/array-input-helper.service.spec.ts index 0f80e61..1809cf1 100644 --- a/src/app/rb-custom-inputs/rb-array-input/array-input-helper.service.spec.ts +++ b/src/app/rb-custom-inputs/rb-array-input/array-input-helper.service.spec.ts @@ -1,18 +1,5 @@ import { TestBed } from '@angular/core/testing'; -import { ArrayInputHelperService } from './array-input-helper.service'; - -// TOdo - describe('ArrayInputHelperService', () => { - let service: ArrayInputHelperService; - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(ArrayInputHelperService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); }); diff --git a/src/app/rb-custom-inputs/rb-array-input/array-input-helper.service.ts b/src/app/rb-custom-inputs/rb-array-input/array-input-helper.service.ts index 5f71f55..f549644 100644 --- a/src/app/rb-custom-inputs/rb-array-input/array-input-helper.service.ts +++ b/src/app/rb-custom-inputs/rb-array-input/array-input-helper.service.ts @@ -10,7 +10,7 @@ export class ArrayInputHelperService { constructor() { } - values(id: string) { + values(id: string) { // observable which returns new values as they come for subscribed id return new Observable<{index: number, value: any}>(observer => { this.com.subscribe(data => { if (data.id === id) { @@ -20,7 +20,7 @@ export class ArrayInputHelperService { }); } - newValue(id: string, index: number, value: any) { + newValue(id: string, index: number, value: any) { // set new value this.com.next({id, index, value}); } } diff --git a/src/app/rb-custom-inputs/rb-array-input/rb-array-input.component.spec.ts b/src/app/rb-custom-inputs/rb-array-input/rb-array-input.component.spec.ts index aae616a..2a6a4be 100644 --- a/src/app/rb-custom-inputs/rb-array-input/rb-array-input.component.spec.ts +++ b/src/app/rb-custom-inputs/rb-array-input/rb-array-input.component.spec.ts @@ -1,26 +1,5 @@ -// import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -// -// import { RbArrayInputComponent } from './rb-array-input.component'; -// -// describe('RbArrayInputComponent', () => { -// let component: RbArrayInputComponent; -// let fixture: ComponentFixture; -// -// beforeEach(async(() => { -// TestBed.configureTestingModule({ -// declarations: [ RbArrayInputComponent ] -// }) -// .compileComponents(); -// })); -// -// beforeEach(() => { -// fixture = TestBed.createComponent(RbArrayInputComponent); -// component = fixture.componentInstance; -// component.ngOnInit(); -// fixture.detectChanges(); -// }); -// -// it('should create', () => { -// expect(component).toBeTruthy(); -// }); -// }); +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +describe('RbArrayInputComponent', () => { + +}); diff --git a/src/app/rb-custom-inputs/rb-array-input/rb-array-input.component.ts b/src/app/rb-custom-inputs/rb-array-input/rb-array-input.component.ts index 90c79b7..3243070 100644 --- a/src/app/rb-custom-inputs/rb-array-input/rb-array-input.component.ts +++ b/src/app/rb-custom-inputs/rb-array-input/rb-array-input.component.ts @@ -37,7 +37,7 @@ export class RbArrayInputListenerDirective { ) { } @HostListener('ngModelChange', ['$event']) - onChange(event) { + onChange(event) { // emit new value this.helperService.newValue(this.rbArrayInputListener, this.index, event); } } @@ -52,7 +52,7 @@ export class RbArrayInputListenerDirective { }) export class RbArrayInputComponent implements ControlValueAccessor, OnInit, AfterViewInit { - pushTemplate: any = ''; + pushTemplate: any = ''; // array element template @Input('pushTemplate') set _pushTemplate(value) { this.pushTemplate = value; if (this.values.length) { @@ -98,7 +98,8 @@ export class RbArrayInputComponent implements ControlValueAccessor, OnInit, Afte if (this.pushTemplate !== null) { if (this.pushPath) { // remove last element if last two are empty - if (this.values[this.values.length - 1][this.pushPath] === '' && this.values[this.values.length - 2][this.pushPath] === '') { + if (this.values[this.values.length - 1][this.pushPath] === '' && + this.values[this.values.length - 2][this.pushPath] === '') { this.values.pop(); } // add element if last all are filled @@ -131,6 +132,7 @@ export class RbArrayInputComponent implements ControlValueAccessor, OnInit, Afte writeValue(obj: any) { // add empty value on init if (obj) { if (this.pushTemplate !== null) { + // filter out empty values if (this.pushPath) { this.values = [...obj.filter(e => e[this.pushPath] !== ''), cloneDeep(this.pushTemplate)]; } @@ -150,22 +152,6 @@ export class RbArrayInputComponent implements ControlValueAccessor, OnInit, Afte this.values = ['']; } } - // this.values = obj ? obj : []; - // console.log('-----'); - // console.log(obj); - // console.log(this.pushPath); - // if (this.values && this.values.length) { - // this.values = obj.filter(e => this.pushPath ? e[this.pushPath] !== '' : e !== ''); - // } - // console.log(this.values); - // // console.log(obj.filter(e => this.pushPath ? e[this.pushPath] !== '' : e !== '')); - // // this.values = obj ? obj.filter(e => this.pushPath ? e[this.pushPath] !== '' : e !== '') : []; - // if (this.values.length === 0 || this.values[0] !== '') { - // // add empty last field if pushTemplate is specified - // if (this.pushTemplate !== null) { - // this.values.push(cloneDeep(this.pushTemplate)); - // } - // } } registerOnChange(fn: any) { diff --git a/src/app/rb-custom-inputs/rb-custom-inputs.module.ts b/src/app/rb-custom-inputs/rb-custom-inputs.module.ts index 890205f..d286532 100644 --- a/src/app/rb-custom-inputs/rb-custom-inputs.module.ts +++ b/src/app/rb-custom-inputs/rb-custom-inputs.module.ts @@ -1,7 +1,8 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { RbTableComponent } from './rb-table/rb-table.component'; -import {RbArrayInputComponent, RbArrayInputListenerDirective, RbArrayInputItemDirective} from './rb-array-input/rb-array-input.component'; +import {RbArrayInputComponent, RbArrayInputListenerDirective, RbArrayInputItemDirective} from + './rb-array-input/rb-array-input.component'; import {RbUiComponentsModule} from '@inst-iot/bosch-angular-ui-components'; import {FormsModule} from '@angular/forms'; import { RbIconButtonComponent } from './rb-icon-button/rb-icon-button.component'; diff --git a/src/app/rb-custom-inputs/rb-icon-button/rb-icon-button.component.spec.ts b/src/app/rb-custom-inputs/rb-icon-button/rb-icon-button.component.spec.ts index 2e59d72..6283e78 100644 --- a/src/app/rb-custom-inputs/rb-icon-button/rb-icon-button.component.spec.ts +++ b/src/app/rb-custom-inputs/rb-icon-button/rb-icon-button.component.spec.ts @@ -1,29 +1,5 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { RbIconButtonComponent } from './rb-icon-button.component'; -import {RbCustomInputsModule} from '../rb-custom-inputs.module'; - -// TODO - describe('RbIconButtonComponent', () => { - let component: RbIconButtonComponent; - let fixture: ComponentFixture; - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ RbIconButtonComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(RbIconButtonComponent); - component = fixture.componentInstance; - component.ngOnInit(); - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); }); diff --git a/src/app/rb-custom-inputs/rb-table/rb-table.component.scss b/src/app/rb-custom-inputs/rb-table/rb-table.component.scss index d05e75f..57f52f6 100644 --- a/src/app/rb-custom-inputs/rb-table/rb-table.component.scss +++ b/src/app/rb-custom-inputs/rb-table/rb-table.component.scss @@ -34,6 +34,5 @@ table.ellipsis { white-space: nowrap; overflow: hidden; max-width: 200px; - //min-width: 100px; } } diff --git a/src/app/rb-custom-inputs/rb-table/rb-table.component.spec.ts b/src/app/rb-custom-inputs/rb-table/rb-table.component.spec.ts index 6b0005d..eea8bfc 100644 --- a/src/app/rb-custom-inputs/rb-table/rb-table.component.spec.ts +++ b/src/app/rb-custom-inputs/rb-table/rb-table.component.spec.ts @@ -1,28 +1,5 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { RbTableComponent } from './rb-table.component'; - -// TODO - describe('RbTableComponent', () => { - let component: RbTableComponent; - let fixture: ComponentFixture; - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ RbTableComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(RbTableComponent); - component = fixture.componentInstance; - component.ngOnInit(); - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); }); diff --git a/src/app/sample/sample.component.spec.ts b/src/app/sample/sample.component.spec.ts index 516ea40..0d4a057 100644 --- a/src/app/sample/sample.component.spec.ts +++ b/src/app/sample/sample.component.spec.ts @@ -1,76 +1,5 @@ -// import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -// -// import { SampleComponent } from './sample.component'; -// import {ApiService} from '../services/api.service'; -// import {ValidationService} from '../services/validation.service'; -// import {DataService} from '../services/data.service'; -// import {ModalService, RbUiComponentsModule} from '@inst-iot/bosch-angular-ui-components'; -// import {FormsModule} from '@angular/forms'; -// import {ActivatedRoute, Router} from '@angular/router'; -// import {AutocompleteService} from '../services/autocomplete.service'; -// import {RbCustomInputsModule} from '../rb-custom-inputs/rb-custom-inputs.module'; -// -// // TODO -// -// let routerServiceSpy: jasmine.SpyObj; -// let activatedRouteServiceSpy: jasmine.SpyObj; -// let apiServiceSpy: jasmine.SpyObj; -// let validationServiceSpy: jasmine.SpyObj; -// let autocompleteServiceSpy: jasmine.SpyObj; -// let modalServiceSpy: jasmine.SpyObj; -// let dataServiceSpy: jasmine.SpyObj; -// -// describe('SampleComponent', () => { -// let component: SampleComponent; -// let fixture: ComponentFixture; -// -// beforeEach(async(() => { -// const routerSpy = jasmine.createSpyObj('Router', ['navigate']); -// const activatedRouteSpy = jasmine.createSpyObj('ActivatedRoute', ['snapshot']); -// const apiSpy = jasmine.createSpyObj('ApiService', ['get', 'post', 'put', 'delete']); -// const validationSpy = jasmine.createSpyObj('ValidationService', ['generate']); -// const autocompleteSpy = jasmine.createSpyObj('AutocompleteService', ['bind']); -// const modalSpy = jasmine.createSpyObj('ModalService', ['open']); -// const dataSpy = jasmine.createSpyObj('DataService', ['load', 'idReload']); -// -// TestBed.configureTestingModule({ -// declarations: [ SampleComponent ], -// imports: [ -// RbUiComponentsModule, -// RbCustomInputsModule, -// FormsModule -// ], -// providers: [ -// {provide: Router, useValue: routerSpy}, -// {provide: ActivatedRoute, useValue: {snapshot: {paramMap: {get: (id) => '12345'}}}}, -// {provide: ApiService, useValue: apiSpy}, -// {provide: ValidationService, useValue: validationSpy}, -// {provide: AutocompleteService, useValue: autocompleteSpy}, -// {provide: ModalService, useValue: modalSpy}, -// {provide: DataService, useValue: dataSpy} -// ] -// }) -// .compileComponents(); -// -// routerServiceSpy = TestBed.inject(Router) as jasmine.SpyObj; -// activatedRouteServiceSpy = TestBed.inject(ActivatedRoute) as jasmine.SpyObj; -// apiServiceSpy = TestBed.inject(ApiService) as jasmine.SpyObj; -// validationServiceSpy = TestBed.inject(ValidationService) as jasmine.SpyObj; -// autocompleteServiceSpy = TestBed.inject(AutocompleteService) as jasmine.SpyObj; -// modalServiceSpy = TestBed.inject(ModalService) as jasmine.SpyObj; -// dataServiceSpy = TestBed.inject(DataService) as jasmine.SpyObj; -// -// // activatedRouteServiceSpy.snapshot.and.returnValue({paramMap: {get: () => '12345'}}); -// })); -// -// beforeEach(() => { -// fixture = TestBed.createComponent(SampleComponent); -// component = fixture.componentInstance; -// component.ngOnInit(); -// fixture.detectChanges(); -// }); -// -// it('should create', () => { -// expect(component).toBeTruthy(); -// }); -// }); +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +describe('SampleComponent', () => { + +}); diff --git a/src/app/sample/sample.component.ts b/src/app/sample/sample.component.ts index 3186c67..19b7f29 100644 --- a/src/app/sample/sample.component.ts +++ b/src/app/sample/sample.component.ts @@ -25,8 +25,6 @@ import {ModalService} from '@inst-iot/bosch-angular-ui-components'; import {DataService} from '../services/data.service'; import {LoginService} from '../services/login.service'; -// TODO: additional property value not validated on edit - @Component({ selector: 'app-sample', templateUrl: './sample.component.html', @@ -81,8 +79,9 @@ export class SampleComponent implements OnInit, AfterContentChecked { checkFormAfterInit = false; modalText = {list: '', suggestion: ''}; cmSampleIndex = '0'; - measurementDeleteList = []; // buffer with measurements to delete, if the user confirms and saves the cm changes - measurementRestoreData: MeasurementModel[] = []; // deleted measurements if user is allowed and measurements are available + measurementDeleteList = []; // buffer with measurements to delete, if the user confirms and saves the cm changes + // deleted measurements if user is allowed and measurements are available + measurementRestoreData: MeasurementModel[] = []; charts = [[]]; // chart data for spectra readonly chartInit = [{ @@ -118,7 +117,6 @@ export class SampleComponent implements OnInit, AfterContentChecked { ) { } ngOnInit(): void { - console.log(this.baseSample); this.mode = this.router.url === '/samples/new' ? 'new' : ''; this.loading = 7; this.d.load('materials', () => { @@ -150,7 +148,8 @@ export class SampleComponent implements OnInit, AfterContentChecked { }); this.d.load('materialTemplates', () => { if (!this.material.properties.material_template) { - this.material.properties.material_template = this.d.latest.materialTemplates.find(e => e.name === 'plastic')._id; + this.material.properties.material_template = + this.d.latest.materialTemplates.find(e => e.name === 'plastic')._id; } this.loading--; }); @@ -167,9 +166,9 @@ export class SampleComponent implements OnInit, AfterContentChecked { if (this.login.isLevel.dev) { // load measurement restore data this.api.get('/measurement/sample/' + sampleIds[0], (data, ignore) => { if (data) { - this.measurementRestoreData = data.filter(e => e.status === 'deleted').map(e => new MeasurementModel().deserialize(e)); + this.measurementRestoreData = + data.filter(e => e.status === 'deleted').map(e => new MeasurementModel().deserialize(e)); } - console.log(this.measurementRestoreData); }); } } @@ -182,7 +181,8 @@ export class SampleComponent implements OnInit, AfterContentChecked { this.samples = [new SampleModel().deserialize(sData)]; this.baseSample.deserialize(sData); this.material = new MaterialModel().deserialize(sData.material); // read material - this.customFields = this.baseSample.notes.custom_fields && this.baseSample.notes.custom_fields !== {} ? // read custom fields + // read custom fields + this.customFields = this.baseSample.notes.custom_fields && this.baseSample.notes.custom_fields !== {} ? Object.keys(this.baseSample.notes.custom_fields).map(e => [e, this.baseSample.notes.custom_fields[e]]) : []; if (this.baseSample.notes.sample_references.length) { // read sample references this.sampleReferences = []; @@ -214,11 +214,10 @@ export class SampleComponent implements OnInit, AfterContentChecked { } this.checkFormAfterInit = true; this.loading--; - sampleIds.slice(1).forEach(sampleId => { + sampleIds.slice(1).forEach(sampleId => { // load further samples for batch edit this.api.get('/sample/' + sampleId, data => { this.samples.push(new SampleModel().deserialize(data)); ['type', 'color', 'batch', 'notes'].forEach((key) => { - console.log(isEqual(data[key], this.baseSample[key])); if (!isEqual(data[key], this.baseSample[key])) { this.baseSample[key] = undefined; } @@ -228,7 +227,6 @@ export class SampleComponent implements OnInit, AfterContentChecked { } this.loading--; this.checkFormAfterInit = true; - console.log(this.baseSample.material.name); }); }); }); @@ -239,6 +237,7 @@ export class SampleComponent implements OnInit, AfterContentChecked { } ngAfterContentChecked() { + // attach validators if (this.samples.length) { // conditions are displayed this.samples.forEach((gSample, gIndex) => { if (this.d.id.conditionTemplates[gSample.condition.condition_template]) { @@ -260,6 +259,7 @@ export class SampleComponent implements OnInit, AfterContentChecked { }); } + // revalidate inputs if (this.checkFormAfterInit) { if (this.view.base) { // validate sampleForm if (this.sampleForm !== undefined && this.sampleForm.form.get('cf-key0')) { @@ -277,13 +277,13 @@ export class SampleComponent implements OnInit, AfterContentChecked { (this.d.id.conditionTemplates[this.samples[0].condition.condition_template].parameters.length - 1)) as any; } if (this.samples[0].measurements.length) { // if there are measurements, last measurement field exists - formReady = formReady && this.cmForm.form.get('measurementParameter-0-' + (this.samples[0].measurements.length - 1) + + formReady = formReady && + this.cmForm.form.get('measurementParameter-0-' + (this.samples[0].measurements.length - 1) + '-' + (this.d.id.measurementTemplates[this.samples[0].measurements[this.samples[0].measurements.length - 1] .measurement_template].parameters.length - 1)) as any; } if (formReady) { // fields are ready, do validation this.checkFormAfterInit = false; - console.log('init'); Object.keys(this.cmForm.form.controls).forEach(field => { this.cmForm.form.get(field).updateValueAndValidity(); }); @@ -346,7 +346,7 @@ export class SampleComponent implements OnInit, AfterContentChecked { } }); this.baseSample.notes.sample_references = this.sampleReferences - .filter(e => e[0] && e[1] && e[2]) + .filter(e => e[0] && e[1] && e[2]) // filter empty values .map(e => ({sample_id: e[2], relation: e[1]})); } if (this.samples.length === 0) { // only save new sample for the first time in mode new, otherwise save changes @@ -363,7 +363,6 @@ export class SampleComponent implements OnInit, AfterContentChecked { } else { this.samples.forEach((sample, i) => { - console.log(sample._id); this.api.put('/sample/' + sample._id, this.baseSample.sendFormat(false), data => { merge(this.samples[i], omit(data, ['condition'])); this.samples[i].material = this.d.arr.materials.find(e => e._id === this.samples[0].material_id); @@ -381,7 +380,10 @@ export class SampleComponent implements OnInit, AfterContentChecked { if (sample.condition.condition_template) { // condition was set this.api.put('/sample/' + sample._id, {condition: pick(sample.condition, - ['condition_template', ...this.d.id.conditionTemplates[sample.condition.condition_template].parameters.map(e => e.name)] + [ + 'condition_template', + ...this.d.id.conditionTemplates[sample.condition.condition_template].parameters.map(e => e.name) + ] )} ); } @@ -439,7 +441,8 @@ export class SampleComponent implements OnInit, AfterContentChecked { else { // no matching material found if (this.baseSample.material_id !== null) { // reset previous match this.material = new MaterialModel(); - this.material.properties.material_template = this.d.latest.materialTemplates.find(e => e.name === 'plastic')._id; + this.material.properties.material_template = + this.d.latest.materialTemplates.find(e => e.name === 'plastic')._id; } this.baseSample.material_id = null; } @@ -450,8 +453,8 @@ export class SampleComponent implements OnInit, AfterContentChecked { setNewMaterial(value = null) { if (value === null) { // toggle dialog this.newMaterial = !this.baseSample.material_id; - } - else if (value || (!value && this.baseSample.material_id !== null )) { // set to false only if material already exists + } // set to false only if material already exists + else if (value || (!value && this.baseSample.material_id !== null )) { this.newMaterial = value; } if (this.newMaterial) { // set validators if dialog is open @@ -476,7 +479,7 @@ export class SampleComponent implements OnInit, AfterContentChecked { } // remove the measurement at the specified index - removeMeasurement(gIndex, mIndex) { // TODO: do not delete directly but only after confirmation + removeMeasurement(gIndex, mIndex) { if (this.samples[gIndex].measurements[mIndex]._id !== null) { this.measurementDeleteList.push(this.samples[gIndex].measurements[mIndex]._id); } @@ -490,7 +493,7 @@ export class SampleComponent implements OnInit, AfterContentChecked { this.samples[gIndex].measurements[mIndex].values = {}; } - fileToArray(files, gIndex, mIndex, parameter) { + fileToArray(files, gIndex, mIndex, parameter) { // process spectrum file input for (const i in files) { if (files.hasOwnProperty(i)) { const fileReader = new FileReader(); @@ -500,6 +503,7 @@ export class SampleComponent implements OnInit, AfterContentChecked { this.addMeasurement(gIndex); index = this.samples[gIndex].measurements.length - 1; } + // autofill further parameters this.samples[gIndex].measurements[index].values.device = this.samples[gIndex].measurements[mIndex].values.device; this.samples[gIndex].measurements[index].values.filename = files[i].name; @@ -578,17 +582,18 @@ export class SampleComponent implements OnInit, AfterContentChecked { this.sampleReferenceIdFind(value); } - sampleReferenceList(value) { + sampleReferenceList(value) { // get list of sample reference number suggestions return new Observable(observer => { if (value !== '') { this.api.get<{ _id: string, number: string }[]>( '/samples?status[]=validated&status[]=new&page-size=25&sort=number-asc&fields[]=number&fields[]=_id&' + - 'filters[]=%7B%22mode%22%3A%22stringin%22%2C%22field%22%3A%22number%22%2C%22values%22%3A%5B%22' + value + '%22%5D%7D', data => { - this.sampleReferenceAutocomplete[this.currentSRIndex] = data.map(e => e.number); - this.sampleReferenceFinds = data; - observer.next(data.map(e => e.number)); - observer.complete(); - this.sampleReferenceIdFind(value); + 'filters[]=%7B%22mode%22%3A%22stringin%22%2C%22field%22%3A%22number%22%2C%22values%22%3A%5B%22' + value + + '%22%5D%7D', data => { + this.sampleReferenceAutocomplete[this.currentSRIndex] = data.map(e => e.number); + this.sampleReferenceFinds = data; + observer.next(data.map(e => e.number)); + observer.complete(); + this.sampleReferenceIdFind(value); }); } else { @@ -598,7 +603,7 @@ export class SampleComponent implements OnInit, AfterContentChecked { }); } - sampleReferenceIdFind(value) { + sampleReferenceIdFind(value) { // sample reference id from number const idFind = this.sampleReferenceFinds.find(e => e.number === value); if (idFind) { this.sampleReferences[this.currentSRIndex][2] = idFind._id; @@ -626,11 +631,3 @@ export class SampleComponent implements OnInit, AfterContentChecked { } } } - - - -// 1. ngAfterViewInit wird ja jedes mal nach einem ngOnChanges aufgerufen, also zB wenn sich dein ngFor aufbaut. Du könntest also in der -// Methode prüfen, ob die Daten schon da sind und dann dementsprechend handeln. Das wäre die Eleganteste Variante -// 2. Der state "dirty" soll eigentlich anzeigen, wenn ein Form-Field vom User geändert wurde; damit missbrauchst du es hier etwas -// 3. Die Dirty-Variante: Pack in deine ngFor ein {{ onFirstLoad(data) }} rein, das einfach ausgeführt wird. müsstest dann natürlich -// abfangen, dass das nicht nach jedem view-cycle neu getriggert wird. Schön ist das nicht, aber besser als mit Timeouts^^ diff --git a/src/app/samples/samples.component.scss b/src/app/samples/samples.component.scss index faf9435..7b92037 100644 --- a/src/app/samples/samples.component.scss +++ b/src/app/samples/samples.component.scss @@ -106,18 +106,6 @@ rb-table { } } -.sort-active-asc { - color: $color-bosch-dark-blue; - background: linear-gradient(to bottom, #FFF 17%, $color-bosch-light-blue-w50 17%);; - border-radius: 0 0 8px 8px; -} - -.sort-active-desc { - color: $color-bosch-dark-blue; - background: linear-gradient(to top, #FFF 17%, $color-bosch-light-blue-w50 17%);; - border-radius: 8px 8px 0 0; -} - .filters:after { content:""; clear:both; @@ -202,11 +190,6 @@ textarea.linkmodal { .sample-details-table { - ::ng-deep .table-wrapper { - max-height: 80vh; - overflow-y: scroll; - } - td { max-width: none; } diff --git a/src/app/samples/samples.component.spec.ts b/src/app/samples/samples.component.spec.ts index c2fb4b1..f28f8af 100644 --- a/src/app/samples/samples.component.spec.ts +++ b/src/app/samples/samples.component.spec.ts @@ -1,77 +1,5 @@ -// import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -// -// import { SamplesComponent } from './samples.component'; -// import {ApiService} from '../services/api.service'; -// import {AutocompleteService} from '../services/autocomplete.service'; -// import {DataService} from '../services/data.service'; -// import {LoginService} from '../services/login.service'; -// import {LocalStorageService} from 'angular-2-local-storage'; -// import {ModalService, RbUiComponentsModule} from '@inst-iot/bosch-angular-ui-components'; -// import {ValidationService} from '../services/validation.service'; -// import {RbCustomInputsModule} from '../rb-custom-inputs/rb-custom-inputs.module'; -// import {FormsModule} from '@angular/forms'; -// -// // TODO -// -// let apiServiceSpy: jasmine.SpyObj; -// let autocompleteServiceSpy: jasmine.SpyObj; -// let modalServiceSpy: jasmine.SpyObj; -// let dataServiceSpy: jasmine.SpyObj; -// let loginServiceSpy: jasmine.SpyObj; -// let localStorageServiceSpy: jasmine.SpyObj; -// let windowServiceSpy: jasmine.SpyObj; -// -// -// -// describe('SamplesComponent', () => { -// let component: SamplesComponent; -// let fixture: ComponentFixture; -// -// beforeEach(async(() => { -// const apiSpy = jasmine.createSpyObj('ApiService', ['post', 'put']); -// const autocompleteSpy = jasmine.createSpyObj('AutocompleteService', ['bind']); -// const loginSpy = jasmine.createSpyObj('LoginService', ['login', 'isLevel']); -// const modalSpy = jasmine.createSpyObj('ModalService', ['open']); -// const dataSpy = jasmine.createSpyObj('DataService', ['load', 'idReload']); -// const localStorageSpy = jasmine.createSpyObj('LocalStorageService', ['set', 'remove']); -// const windowSpy = jasmine.createSpyObj('Window', ['location']); -// -// TestBed.configureTestingModule({ -// declarations: [ SamplesComponent ], -// imports: [ -// RbUiComponentsModule, -// RbCustomInputsModule, -// FormsModule -// ], -// providers: [ -// {provide: ApiService, useValue: apiSpy}, -// {provide: AutocompleteService, useValue: autocompleteSpy}, -// {provide: ModalService, useValue: modalSpy}, -// {provide: DataService, useValue: dataSpy}, -// {provide: LoginService, useValue: loginSpy}, -// {provide: LocalStorageService, useValue: localStorageSpy}, -// {provide: Window, useValue: windowSpy} -// ] -// }) -// .compileComponents(); -// -// apiServiceSpy = TestBed.inject(ApiService) as jasmine.SpyObj; -// autocompleteServiceSpy = TestBed.inject(AutocompleteService) as jasmine.SpyObj; -// modalServiceSpy = TestBed.inject(ModalService) as jasmine.SpyObj; -// dataServiceSpy = TestBed.inject(DataService) as jasmine.SpyObj; -// loginServiceSpy = TestBed.inject(LoginService) as jasmine.SpyObj; -// localStorageServiceSpy = TestBed.inject(LocalStorageService) as jasmine.SpyObj; -// windowServiceSpy = TestBed.inject(Window) as jasmine.SpyObj; -// })); -// -// beforeEach(() => { -// fixture = TestBed.createComponent(SamplesComponent); -// component = fixture.componentInstance; -// component.ngOnInit(); -// fixture.detectChanges(); -// }); -// -// it('should create', () => { -// expect(component).toBeTruthy(); -// }); -// }); +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +describe('SamplesComponent', () => { + +}); diff --git a/src/app/samples/samples.component.ts b/src/app/samples/samples.component.ts index 88061e7..0fff0ed 100644 --- a/src/app/samples/samples.component.ts +++ b/src/app/samples/samples.component.ts @@ -11,11 +11,6 @@ import {DataService} from '../services/data.service'; import {LocalStorageService} from 'angular-2-local-storage'; import {Router} from '@angular/router'; -// TODO: turn off sort field -// TODO reset sort when field is excluded -// TODO: Eh DPT -// TODO: filter button -// TODO: check if connect-src to model works interface LoadSamplesOptions { @@ -41,10 +36,10 @@ export class SamplesComponent implements OnInit { @ViewChild('pageSizeSelection') pageSizeSelection: ElementRef; @ViewChild('linkarea') linkarea: ElementRef; - downloadSpectra = false; // TODO: streamline these options after csv option handling is clear + downloadSpectra = false; // download options downloadCondition = false; downloadFlatten = true; - samples: SampleModel[] = []; + samples: SampleModel[] = []; // all samples to display totalSamples = 0; // total number of samples csvUrl = ''; // store url separate so it only has to be generated when clicking the download button filters = { @@ -68,8 +63,8 @@ export class SamplesComponent implements OnInit { {field: 'added', label: 'Added', active: false, autocomplete: [], mode: 'eq', values: ['']} ] }; - page = 1; - pages = 1; + page = 1; // current page + pages = 1; // total number of pages loadSamplesQueue = []; // arguments of queued up loadSamples() calls keys: KeyInterface[] = [ {id: 'number', label: 'Number', active: true, sortable: true}, @@ -85,12 +80,12 @@ export class SamplesComponent implements OnInit { {id: 'status', label: 'Status', active: false, sortable: true}, {id: 'added', label: 'Added', active: true, sortable: true} ]; - isActiveKey: {[key: string]: boolean} = {}; - activeKeys: KeyInterface[] = []; + isActiveKey: {[key: string]: boolean} = {}; // object to check if key is currently active + activeKeys: KeyInterface[] = []; // list of active keys activeTemplateKeys = {material: [], condition: [], measurements: []}; - sampleDetailsSample: any = null; + sampleDetailsSample: any = null; // sample for the sample details dialog sampleSelect = 0; // modes: 0 - no selection, 1 - sample edit selection, 2 - validation selection - loading = 0; + loading = 0; // number of loading instances constructor( @@ -170,7 +165,8 @@ export class SamplesComponent implements OnInit { }); } - loadSamples(options: LoadSamplesOptions = {}, event = null) { // set toPage to null to reload first page, queues calls + // set toPage to null to reload first page, queues calls + loadSamples(options: LoadSamplesOptions = {}, event = null) { if (event) { // adjust active keys this.keys.forEach(key => { if (event.hasOwnProperty(key.id)) { @@ -194,7 +190,7 @@ export class SamplesComponent implements OnInit { this.loading ++; this.api.get(this.sampleUrl({paging: true, pagingOptions: options}), (sData, err, headers) => { this.loading --; - if (err) { + if (err) { // remove stored options on error to avoid loop this.storage.remove('samplesPreferences'); this.api.requestError(err); } @@ -223,7 +219,8 @@ export class SamplesComponent implements OnInit { export?: boolean, host?: boolean }) { // return url to fetch samples - const additionalTableKeys = ['material_id', '_id', 'user_id']; // keys which should always be added if export = false + // keys which should always be added if export = false + const additionalTableKeys = ['material_id', '_id', 'user_id']; const query: string[] = []; query.push(...Object.keys(this.filters.status).filter(e => this.filters.status[e]).map(e => 'status[]=' + e)); if (options.paging) { @@ -241,7 +238,7 @@ export class SamplesComponent implements OnInit { query.push('page-size=' + this.filters.pageSize); } query.push('sort=' + this.filters.sort); - if (options.export) { + if (options.export) { // append API key on export query.push('key=' + this.d.d.userKey.key); } this.keys.forEach(key => { @@ -255,9 +252,11 @@ export class SamplesComponent implements OnInit { .map(e => { e.values = e.values.filter(el => el !== ''); // do not include empty values if (e.field === 'added') { // correct timezone - e.values = e.values.map(el => new Date(new Date(el).getTime() - new Date(el).getTimezoneOffset() * 60000).toISOString()); + e.values = e.values.map( + el => new Date(new Date(el).getTime() - new Date(el).getTimezoneOffset() * 60000).toISOString() + ); } - if (e.mode === 'null') { + if (e.mode === 'null') { // handle null mode e.mode = 'in'; e.values = [null, '']; } @@ -270,7 +269,8 @@ export class SamplesComponent implements OnInit { query.push('filters[]=' + encodeURIComponent( JSON.stringify({mode: 'eq', field: 'condition', values: [{}]}))); } if (this.filters.no.measurements) { - query.push('filters[]=' + encodeURIComponent( JSON.stringify( {mode: 'eq', field: 'measurements', values: [null]}))); + query.push('filters[]=' + + encodeURIComponent( JSON.stringify( {mode: 'eq', field: 'measurements', values: [null]}))); } if (!options.export) { additionalTableKeys.forEach(key => { @@ -279,7 +279,7 @@ export class SamplesComponent implements OnInit { } }); } - else { + else { // export options if (options.csv) { query.push('output=csv'); } @@ -338,7 +338,6 @@ export class SamplesComponent implements OnInit { this.updateActiveKeys(); } - // TODO: avoid reloading resetPreferences() { this.storage.remove('samplesPreferences'); this.window.location.reload(); @@ -346,7 +345,6 @@ export class SamplesComponent implements OnInit { updateFilterFields(field) { const filter = this.filters.filters.find(e => e.field === field); - console.log(filter); filter.active = !(filter.values.length === 1 && filter.values[0] === ''); } @@ -380,20 +378,24 @@ export class SamplesComponent implements OnInit { }); } - sampleDetails(id: string, modal: TemplateRef) { + sampleDetails(id: string, modal: TemplateRef) { // show sample details this.sampleDetailsSample = null; this.api.get('/sample/' + id, data => { this.sampleDetailsSample = new SampleModel().deserialize(data); if (data.notes.custom_fields) { // convert custom_fields for more optimized display - this.sampleDetailsSample.notes.custom_fields_entries = Object.entries(this.sampleDetailsSample.notes.custom_fields); + this.sampleDetailsSample.notes.custom_fields_entries = + Object.entries(this.sampleDetailsSample.notes.custom_fields); } else { this.sampleDetailsSample.custom_fields_entries = []; } - if (Object.keys(data.condition).length) { - this.sampleDetailsSample.condition_entries = Object.entries(omit(this.sampleDetailsSample.condition, ['condition_template'])) + if (Object.keys(data.condition).length) { // convert condition + this.sampleDetailsSample.condition_entries = + Object.entries(omit(this.sampleDetailsSample.condition, ['condition_template'])) .map(e => { - e[0] = `${this.ucFirst(this.d.id.conditionTemplates[this.sampleDetailsSample.condition.condition_template].name)} ${e[0]}`; + e[0] = `${this.ucFirst( + this.d.id.conditionTemplates[this.sampleDetailsSample.condition.condition_template].name + )} ${e[0]}`; return e; }); } @@ -401,9 +403,11 @@ export class SamplesComponent implements OnInit { this.sampleDetailsSample.condition_entries = []; } this.sampleDetailsSample.measurement_entries = []; - this.sampleDetailsSample.measurements.forEach(measurement => { // convert measurements for more optimized display without dpt + // convert measurements for more optimized display without dpt + this.sampleDetailsSample.measurements.forEach(measurement => { const name = this.d.id.measurementTemplates[measurement.measurement_template].name; - this.sampleDetailsSample.measurement_entries.push(...Object.entries(measurement.values).filter(e => e[0] !== 'dpt') + this.sampleDetailsSample.measurement_entries + .push(...Object.entries(measurement.values).filter(e => e[0] !== 'dpt') .map(e => ({name: this.ucFirst(name) + ' ' + e[0], value: e[1]}))); }); new Promise(resolve => { @@ -429,7 +433,7 @@ export class SamplesComponent implements OnInit { } validate() { - if (this.sampleSelect) { + if (this.sampleSelect) { // do actual validation this.samples.forEach(sample => { if (sample.selected) { this.api.put('/sample/validate/' + sample._id); @@ -438,12 +442,12 @@ export class SamplesComponent implements OnInit { this.loadSamples(); this.sampleSelect = 0; } - else { + else { // get into validation mode this.sampleSelect = 2; } } - batchEdit() { + batchEdit() { // redirect to batch edit if (this.sampleSelect) { this.router.navigate(['/samples/edit/' + this.samples.filter(e => e.selected).map(e => e._id).join(',')]); this.sampleSelect = 0; @@ -464,7 +468,7 @@ export class SamplesComponent implements OnInit { }); } - selectAll(event) { + selectAll(event) { // toggle select all except deleted samples this.samples.forEach(sample => { if (sample.status !== 'deleted') { sample.selected = event.target.checked; @@ -485,13 +489,13 @@ export class SamplesComponent implements OnInit { event.stopPropagation(); } - clipboard() { + clipboard() { // copy contents to clipboard this.linkarea.nativeElement.select(); this.linkarea.nativeElement.setSelectionRange(0, 99999); document.execCommand('copy'); } - ucFirst(string) { + ucFirst(string) { // convert first character of string to uppercase return string[0].toUpperCase() + string.slice(1); } diff --git a/src/app/services/api.service.spec.ts b/src/app/services/api.service.spec.ts index 60c0f0c..0006d74 100644 --- a/src/app/services/api.service.spec.ts +++ b/src/app/services/api.service.spec.ts @@ -1,143 +1,5 @@ import {async, TestBed} from '@angular/core/testing'; -import { ApiService } from './api.service'; -import {HttpClient} from '@angular/common/http'; -import {LocalStorageService} from 'angular-2-local-storage'; -import {Observable} from 'rxjs'; -import {ModalService} from '@inst-iot/bosch-angular-ui-components'; - -let apiService: ApiService; -let httpClientSpy: jasmine.SpyObj; -let localStorageServiceSpy: jasmine.SpyObj; -let modalServiceSpy: jasmine.SpyObj; -let windowServiceSpy: jasmine.SpyObj; - -// TODO -// TODO: test options describe('ApiService', () => { - beforeEach(() => { - const httpSpy = jasmine.createSpyObj('HttpClient', ['get', 'post', 'put', 'delete']); - const localStorageSpy = jasmine.createSpyObj('LocalStorageService', ['get']); - const modalSpy = jasmine.createSpyObj('ModalService', ['openComponent']); - const windowSpy = jasmine.createSpyObj('Window', ['location']); - TestBed.configureTestingModule({ - providers: [ - ApiService, - {provide: HttpClient, useValue: httpSpy}, - {provide: LocalStorageService, useValue: localStorageSpy}, - {provide: ModalService, useValue: modalSpy}, - {provide: Window, useValue: windowSpy} - ] - }); - - apiService = TestBed.inject(ApiService); - httpClientSpy = TestBed.inject(HttpClient) as jasmine.SpyObj; - localStorageServiceSpy = TestBed.inject(LocalStorageService) as jasmine.SpyObj; - modalServiceSpy = TestBed.inject(ModalService) as jasmine.SpyObj; - windowServiceSpy = TestBed.inject(Window) as jasmine.SpyObj; - }); - - it('should be created', () => { - expect(apiService).toBeTruthy(); - }); - - it('shows an error message when the request fails', () => { - const getReturn = new Observable(observer => { - observer.error('error'); - }); - httpClientSpy.get.and.returnValue(getReturn); - localStorageServiceSpy.get.and.returnValue(undefined); - modalServiceSpy.openComponent.and.returnValue({instance: {message: ''}} as any); - - apiService.get('/testurl'); - expect(httpClientSpy.get).toHaveBeenCalledWith('/api/testurl', jasmine.any(Object)); - expect(modalServiceSpy.openComponent.calls.count()).toBe(1); - }); - - it('returns the error message if the callback function had an error parameter', () => { - const getReturn = new Observable(observer => { - observer.error('error'); - }); - httpClientSpy.get.and.returnValue(getReturn); - localStorageServiceSpy.get.and.returnValue(undefined); - modalServiceSpy.openComponent.and.returnValue({instance: {message: ''}} as any); - - apiService.get('/testurl', (data, error) => { - expect(modalServiceSpy.openComponent.calls.count()).toBe(0); - expect(error).toBe('error'); - }); - }); - - it('should do get requests without auth if not available', async(() => { - const getReturn = new Observable(observer => { - observer.next({body: 'data', headers: {keys: () => []}}); - }); - httpClientSpy.get.and.returnValue(getReturn); - localStorageServiceSpy.get.and.returnValue(undefined); - - apiService.get('/testurl', res => { - expect(res).toBe('data'); - expect(httpClientSpy.get).toHaveBeenCalledWith('/api/testurl', jasmine.any(Object)); - expect(localStorageServiceSpy.get).toHaveBeenCalledWith('basicAuth'); - }); - })); - - it('should do get requests with basic auth if available', async(() => { - const getReturn = new Observable(observer => { - observer.next('data'); - }); - httpClientSpy.get.and.returnValue(getReturn); - localStorageServiceSpy.get.and.returnValue('basicAuth'); - - apiService.get('/testurl', res => { - expect(res).toBe('data'); - expect(httpClientSpy.get).toHaveBeenCalledWith('/api/testurl', jasmine.any(Object)); - expect(localStorageServiceSpy.get).toHaveBeenCalledWith('basicAuth'); - }); - })); - - it('should do post requests', async(() => { - const resReturn = new Observable(observer => { - observer.next('data'); - }); - httpClientSpy.post.and.returnValue(resReturn); - localStorageServiceSpy.get.and.returnValue('basicAuth'); - - apiService.post('/testurl', 'reqData', res => { - expect(res).toBe('data'); - expect(httpClientSpy.post).toHaveBeenCalledWith('/api/testurl', 'reqData', jasmine.any(Object)); - expect(localStorageServiceSpy.get).toHaveBeenCalledWith('basicAuth'); - }); - })); - - it('should do put requests', async(() => { - const resReturn = new Observable(observer => { - observer.next('data'); - }); - httpClientSpy.put.and.returnValue(resReturn); - localStorageServiceSpy.get.and.returnValue('basicAuth'); - - apiService.put('/testurl', 'reqData', res => { - expect(res).toBe('data'); - expect(httpClientSpy.put).toHaveBeenCalledWith('/api/testurl', 'reqData', jasmine.any(Object)); - expect(localStorageServiceSpy.get).toHaveBeenCalledWith('basicAuth'); - }); - })); - - it('should do delete requests', async(() => { - const resReturn = new Observable(observer => { - observer.next('data'); - }); - httpClientSpy.delete.and.returnValue(resReturn); - localStorageServiceSpy.get.and.returnValue('basicAuth'); - - apiService.delete('/testurl', res => { - expect(res).toBe('data'); - expect(httpClientSpy.delete).toHaveBeenCalledWith('/api/testurl', jasmine.any(Object)); - expect(localStorageServiceSpy.get).toHaveBeenCalledWith('basicAuth'); - }); - })); - - // TODO: test return headers }); diff --git a/src/app/services/api.service.ts b/src/app/services/api.service.ts index 190edda..c982e38 100644 --- a/src/app/services/api.service.ts +++ b/src/app/services/api.service.ts @@ -5,7 +5,6 @@ import {Observable} from 'rxjs'; import {ErrorComponent} from '../error/error.component'; import {ModalService} from '@inst-iot/bosch-angular-ui-components'; -// TODO: find solution when client wants to visit subpage but is not logged in to redirect to login without showing request failed errors @Injectable({ providedIn: 'root' @@ -25,6 +24,7 @@ export class ApiService { return this.host; } + // main HTTP methods get(url, f: (data?: T, err?, headers?) => void = () => {}) { this.requestErrorHandler(this.http.get(this.url(url), this.options()), f); } @@ -41,20 +41,25 @@ export class ApiService { this.requestErrorHandler(this.http.delete(this.url(url), this.options()), f); } + // execute request and handle errors private requestErrorHandler(observable: Observable, f: (data?: T, err?, headers?) => void) { - observable.subscribe(data => { - f(data.body, undefined, data.headers.keys().reduce((s, e) => {s[e.toLowerCase()] = data.headers.get(e); return s; }, {})); - }, err => { - if (f.length > 1) { + observable.subscribe(data => { // successful request + f( + data.body, + undefined, + data.headers.keys().reduce((s, e) => {s[e.toLowerCase()] = data.headers.get(e); return s; }, {}) + ); + }, err => { // error + if (f.length > 1) { // pass on error f(undefined, err, undefined); } - else { + else { // handle directly this.requestError(err); } }); } - requestError(err) { + requestError(err) { // network error dialog const modalRef = this.modalService.openComponent(ErrorComponent); modalRef.instance.message = 'Network request failed!'; const details = [err.error.status]; @@ -67,7 +72,7 @@ export class ApiService { }); } - private url(url) { + private url(url) { // detect if host was given, otherwise use default host if (/http[s]?:\/\//.test(url)) { return url; } @@ -76,10 +81,12 @@ export class ApiService { } } + // generate request options private options(): {headers: HttpHeaders, observe: 'body'} { return {headers: this.authOptions(), observe: 'response' as 'body'}; } + // generate Basic Auth private authOptions(): HttpHeaders { const auth = this.storage.get('basicAuth'); if (auth) { diff --git a/src/app/services/autocomplete.service.spec.ts b/src/app/services/autocomplete.service.spec.ts index 4b57bd1..d265fb7 100644 --- a/src/app/services/autocomplete.service.spec.ts +++ b/src/app/services/autocomplete.service.spec.ts @@ -1,37 +1,5 @@ import { TestBed } from '@angular/core/testing'; -import { AutocompleteService } from './autocomplete.service'; - -// TODO - -let autocompleteService: AutocompleteService; - describe('AutocompleteService', () => { - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [AutocompleteService] - }); - autocompleteService = TestBed.inject(AutocompleteService); - }); - - it('should be created', () => { - expect(autocompleteService).toBeTruthy(); - }); - - it('should should return a bind function', () => { - expect(autocompleteService.bind('a', ['b'])).toBeTruthy(); - }); - - it('should return search results', () => { - autocompleteService.search(['aa', 'ab', 'bb'], 'a').subscribe(res => { - expect(res).toEqual(['aa', 'ab']); - }); - }); - - it('should return an empty array if no result was found', () => { - autocompleteService.search(['aa', 'ab', 'bb'], 'c').subscribe(res => { - expect(res).toEqual([]); - }); - }); }); diff --git a/src/app/services/data.service.spec.ts b/src/app/services/data.service.spec.ts index 2fcc8f5..505ec04 100644 --- a/src/app/services/data.service.spec.ts +++ b/src/app/services/data.service.spec.ts @@ -1,33 +1,5 @@ import { TestBed } from '@angular/core/testing'; -import { DataService } from './data.service'; -import {ApiService} from './api.service'; -import {HttpClient} from '@angular/common/http'; -import {LocalStorageService} from 'angular-2-local-storage'; -import {ModalService} from '@inst-iot/bosch-angular-ui-components'; - -// TODO - -let apiServiceSpy: jasmine.SpyObj; - - describe('DataService', () => { - let service: DataService; - beforeEach(() => { - const apiSpy = jasmine.createSpyObj('ApiService', ['post', 'put']); - - TestBed.configureTestingModule({ - providers: [ - {provide: ApiService, useValue: apiSpy} - ] - }); - service = TestBed.inject(DataService); - - apiServiceSpy = TestBed.inject(ApiService) as jasmine.SpyObj; - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); }); diff --git a/src/app/services/data.service.ts b/src/app/services/data.service.ts index 68dd3f4..60955cf 100644 --- a/src/app/services/data.service.ts +++ b/src/app/services/data.service.ts @@ -16,7 +16,7 @@ export class DataService { private api: ApiService ) { } - private collectionMap = { + private collectionMap = { // list of available collections materials: {path: '/materials?status[]=validated&status[]=new', model: MaterialModel, type: 'idArray'}, materialSuppliers: {path: '/material/suppliers', model: null, type: 'idArray'}, materialGroups: {path: '/material/groups', model: null, type: 'idArray'}, @@ -36,7 +36,7 @@ export class DataService { id: {[key: string]: {[id: string]: any}} = {}; // data in format _id: data d: {[key: string]: any} = {}; // data not in array format - contact = {name: 'CR/APS1-Lingenfelser', mail: 'dominic.lingenfelser@bosch.com'}; + contact = {name: 'CR/APS1-Lingenfelser', mail: 'dominic.lingenfelser@bosch.com'}; // global contact data load(collection, f = () => {}) { // load data if (this.arr[collection]) { // data already loaded @@ -46,7 +46,11 @@ export class DataService { this.api.get(this.collectionMap[collection].path, data => { if (this.collectionMap[collection].type !== 'string') { // array data this.arr[collection] = data - .map(e => this.collectionMap[collection].model ? new this.collectionMap[collection].model().deserialize(e) : e); + .map( + e => this.collectionMap[collection].model ? + new this.collectionMap[collection].model().deserialize(e) : e + ); + // load ids if (this.collectionMap[collection].type === 'idArray' || this.collectionMap[collection].type === 'template') { this.idReload(collection); } @@ -59,9 +63,10 @@ export class DataService { } } + // generate id object idReload(collection) { this.id[collection] = this.arr[collection].reduce((s, e) => {s[e._id] = e; return s; }, {}); - if (this.collectionMap[collection].type === 'template') { + if (this.collectionMap[collection].type === 'template') { // generate array with latest templates const tmpTemplates = {}; this.arr[collection].forEach(template => { if (tmpTemplates[template.first_id]) { // already found another version diff --git a/src/app/services/login.service.spec.ts b/src/app/services/login.service.spec.ts index c243804..56d3de8 100644 --- a/src/app/services/login.service.spec.ts +++ b/src/app/services/login.service.spec.ts @@ -1,95 +1,5 @@ import { TestBed } from '@angular/core/testing'; -import { LoginService } from './login.service'; -import {LocalStorageService} from 'angular-2-local-storage'; -import {ApiService} from './api.service'; -import {Router} from '@angular/router'; - -// TODO - -let loginService: LoginService; -let apiServiceSpy: jasmine.SpyObj; -let localStorageServiceSpy: jasmine.SpyObj; -let routerServiceSpy: jasmine.SpyObj; - describe('LoginService', () => { - beforeEach(() => { - const apiSpy = jasmine.createSpyObj('ApiService', ['get']); - const localStorageSpy = jasmine.createSpyObj('LocalStorageService', ['set', 'remove']); - const routerSpy = jasmine.createSpyObj('Router', ['navigate']); - TestBed.configureTestingModule({ - providers: [ - LoginService, - {provide: ApiService, useValue: apiSpy}, - {provide: LocalStorageService, useValue: localStorageSpy}, - {provide: Router, useValue: routerSpy} - ] - }); - - loginService = TestBed.inject(LoginService); - apiServiceSpy = TestBed.inject(ApiService) as jasmine.SpyObj; - localStorageServiceSpy = TestBed.inject(LocalStorageService) as jasmine.SpyObj; - routerServiceSpy = TestBed.inject(Router) as jasmine.SpyObj; - }); - - it('should be created', () => { - expect(loginService).toBeTruthy(); - }); - - // describe('login', () => { - // it('should store the basic auth', () => { - // localStorageServiceSpy.set.and.returnValue(true); - // apiServiceSpy.get.and.callFake(() => {}); - // loginService.login('username', 'password'); - // expect(localStorageServiceSpy.set).toHaveBeenCalledWith('basicAuth', 'dXNlcm5hbWU6cGFzc3dvcmQ='); - // }); - // - // it('should remove the basic auth if login fails', () => { - // localStorageServiceSpy.set.and.returnValue(true); - // localStorageServiceSpy.remove.and.returnValue(true); - // apiServiceSpy.get.and.callFake((a, b) => {b(undefined, 'error'); }); - // loginService.login('username', 'password'); - // expect(localStorageServiceSpy.remove.calls.count()).toBe(1); - // expect(localStorageServiceSpy.remove).toHaveBeenCalledWith('basicAuth'); - // }); - // - // it('should resolve true when login succeeds', async () => { - // localStorageServiceSpy.set.and.returnValue(true); - // apiServiceSpy.get.and.callFake((a, b) => {b({status: 'Authorization successful', method: 'basic'} as any, undefined); }); - // expect(await loginService.login('username', 'password')).toBeTruthy(); - // }); - // - // it('should resolve false when a wrong result comes in', async () => { - // localStorageServiceSpy.set.and.returnValue(true); - // apiServiceSpy.get.and.callFake((a, b) => {b({status: 'xxx', method: 'basic'} as any, undefined); }); - // expect(await loginService.login('username', 'password')).toBeFalsy(); - // }); - // - // it('should resolve false on an error', async () => { - // localStorageServiceSpy.set.and.returnValue(true); - // apiServiceSpy.get.and.callFake((a, b) => {b(undefined, 'error'); }); - // expect(await loginService.login('username', 'password')).toBeFalsy(); - // }); - // }); - // - // describe('canActivate', () => { - // it('should return false at first', done => { - // apiServiceSpy.get.and.callFake((a, b) => {b(undefined, 'error'); }); - // loginService.canActivate(null, null).subscribe(res => { - // expect(res).toBeFalsy(); - // done(); - // }); - // }); - // - // it('returns true if login was successful', async done => { - // localStorageServiceSpy.set.and.returnValue(true); - // apiServiceSpy.get.and.callFake((a, b) => {b({status: 'Authorization successful', method: 'basic'} as any, undefined); }); - // await loginService.login('username', 'password'); - // loginService.canActivate(null, null).subscribe(res => { - // expect(res).toBeTruthy(); - // done(); - // }); - // }); - // }); }); diff --git a/src/app/services/login.service.ts b/src/app/services/login.service.ts index 2d5330b..f7ea05a 100644 --- a/src/app/services/login.service.ts +++ b/src/app/services/login.service.ts @@ -10,19 +10,20 @@ import {DataService} from './data.service'; }) export class LoginService implements CanActivate { - private pathPermissions = [ + private pathPermissions = [ // minimum level needed for the specified paths {path: 'materials', permission: 'dev'}, {path: 'templates', permission: 'dev'}, {path: 'changelog', permission: 'dev'}, {path: 'users', permission: 'admin'} ]; - readonly levels = [ + readonly levels = [ // all user levels in ascending permissions order 'predict', 'read', 'write', 'dev', 'admin' ]; + // returns true or false depending on whether the user fulfills the minimum level isLevel: {[level: string]: boolean} = {}; hasPrediction = false; // true if user has prediction models specified userId = ''; @@ -99,6 +100,7 @@ export class LoginService implements CanActivate { this.hasPrediction = false; } + // canActivate for Angular routing canActivate(route: ActivatedRouteSnapshot = null, state: RouterStateSnapshot = null): Observable { return new Observable(observer => { new Promise(resolve => { @@ -112,7 +114,8 @@ export class LoginService implements CanActivate { } }).then(res => { const pathPermission = this.pathPermissions.find(e => e.path.indexOf(route.url[0].path) >= 0); - const ok = res && (!pathPermission || this.isLevel[pathPermission.permission]); // check if level is permitted for path + // check if level is permitted for path + const ok = res && (!pathPermission || this.isLevel[pathPermission.permission]); observer.next(ok); observer.complete(); if (!ok) { diff --git a/src/app/services/validation.service.spec.ts b/src/app/services/validation.service.spec.ts index 16601a6..a2560a8 100644 --- a/src/app/services/validation.service.spec.ts +++ b/src/app/services/validation.service.spec.ts @@ -1,116 +1,5 @@ import { TestBed } from '@angular/core/testing'; -import { ValidationService } from './validation.service'; - -// TODO - -let validationService: ValidationService; describe('ValidationService', () => { - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [ValidationService] - }); - validationService = TestBed.inject(ValidationService); - }); - - it('should be created', () => { - expect(validationService).toBeTruthy(); - }); - - // it('should return true on a correct username', () => { - // expect(validationService.username('abc')).toEqual({ok: true, error: ''}); - // }); - // - // it('should return an error on an incorrect username', () => { - // expect(validationService.username('abc#')).toEqual({ok: false, error: 'username must only contain a-z0-9-_.'}); - // }); - // - // it('should return true on a correct password', () => { - // expect(validationService.password('Abc123!#')).toEqual({ok: true, error: ''}); - // }); - // - // it('should return an error on a password too short', () => { - // expect(validationService.password('Abc123')).toEqual({ok: false, error: 'password must have at least 8 characters'}); - // }); - // - // it('should return an error on a password without a lowercase letter', () => { - // expect(validationService.password('ABC123!#')).toEqual({ok: false, error: 'password must have at least one lowercase character'}); - // }); - // - // it('should return an error on a password without an uppercase letter', () => { - // expect(validationService.password('abc123!#')).toEqual({ok: false, error: 'password must have at least one uppercase character'}); - // }); - // - // it('should return an error on a password without a number', () => { - // expect(validationService.password('Abcabc!#')).toEqual({ok: false, error: 'password must have at least one number'}); - // }); - // - // it('should return an error on a password without a special character', () => { - // expect(validationService.password('Abc12345')).toEqual({ok: false, error: 'password must have at least one of the following characters !"#%&\'()*+,-.\\/:;<=>?@[]^_`{|}~'}); - // }); - // - // it('should return an error on a password with a character not allowed', () => { - // expect(validationService.password('Abc123!€')).toEqual({ok: false, error: 'password must only contain a-zA-Z0-9!"#%&\'()*+,-./:;<=>?@[]^_`{|}~'}); - // }); - // - // it('should return true on a correct string', () => { - // expect(validationService.string('Abc')).toEqual({ok: true, error: ''}); - // }); - // - // it('should return an error on a string too long', () => { - // expect(validationService.string('abcabcabcbabcbabcabcabacbabcabcabcbabcbabcabcabacbabcabcabcbabcbabcabcabacbabcabcabcbabcbabcabcabacbabcabcabcbabcbabcabcabacbacab')).toEqual({ok: false, error: 'must contain max 128 characters'}); - // }); - // - // it('should return true on a string in the list', () => { - // expect(validationService.stringOf('Abc', ['Abc', 'Def'])).toEqual({ok: true, error: ''}); - // }); - // - // it('should return an error on a string not in the list', () => { - // expect(validationService.stringOf('abc', ['Abc', 'Def'])).toEqual({ok: false, error: 'must be one of Abc, Def'}); - // }); - // - // it('should return true on a string of correct length', () => { - // expect(validationService.stringLength('Abc', 5)).toEqual({ok: true, error: ''}); - // }); - // - // it('should return an error on a string longer than specified', () => { - // expect(validationService.stringLength('Abc', 2)).toEqual({ok: false, error: 'must contain max 2 characters'}); - // }); - // - // it('should return true on a number in the range', () => { - // expect(validationService.minMax(2, -2, 2)).toEqual({ok: true, error: ''}); - // }); - // - // it('should return an error on a number below the range', () => { - // expect(validationService.minMax(0, 1, 3)).toEqual({ok: false, error: 'must be between 1 and 3'}); - // }); - // - // it('should return an error on a number above the range', () => { - // expect(validationService.minMax(3.1, 1, 3)).toEqual({ok: false, error: 'must be between 1 and 3'}); - // }); - // - // it('should return true on a number above min', () => { - // expect(validationService.min(2, -2)).toEqual({ok: true, error: ''}); - // }); - // - // it('should return an error on a number below min', () => { - // expect(validationService.min(0, 1)).toEqual({ok: false, error: 'must not be below 1'}); - // }); - // - // it('should return true on a number below max', () => { - // expect(validationService.max(2, 2)).toEqual({ok: true, error: ''}); - // }); - // - // it('should return an error on a number above max', () => { - // expect(validationService.max(2, 1)).toEqual({ok: false, error: 'must not be above 1'}); - // }); - // - // it('should return true on a string not in the list', () => { - // expect(validationService.unique('Abc', ['Def', 'Ghi'])).toEqual({ok: true, error: ''}); - // }); - // - // it('should return an error on a string from the list', () => { - // expect(validationService.unique('Abc', ['Abc', 'Def'])).toEqual({ok: false, error: 'values must be unique'}); - // }); }); diff --git a/src/app/services/validation.service.ts b/src/app/services/validation.service.ts index 3031ea8..24a18d9 100644 --- a/src/app/services/validation.service.ts +++ b/src/app/services/validation.service.ts @@ -63,7 +63,7 @@ export class ValidationService { return {ok: true, error: ''}; } - stringOf(data, list) { + stringOf(data, list) { // string must be in list const {ignore, error} = Joi.string().allow('').valid(...list.map(e => e.toString())).validate(data); if (error) { return {ok: false, error: 'must be one of ' + list.join(', ')}; @@ -71,7 +71,7 @@ export class ValidationService { return {ok: true, error: ''}; } - stringNin(data, list) { + stringNin(data, list) { // string must not be in list const {ignore, error} = Joi.string().invalid(...list).validate(data); if (error) { return {ok: false, error: 'value not allowed'}; @@ -79,7 +79,7 @@ export class ValidationService { return {ok: true, error: ''}; } - stringLength(data, length) { + stringLength(data, length) { // string with maximum length const {ignore, error} = Joi.string().max(length).allow('').validate(data); if (error) { return {ok: false, error: 'must contain max ' + length + ' characters'}; @@ -87,7 +87,7 @@ export class ValidationService { return {ok: true, error: ''}; } - minMax(data, min, max) { + minMax(data, min, max) { // number between min and max const {ignore, error} = Joi.number().allow('').min(min).max(max).validate(data); if (error) { return {ok: false, error: `must be between ${min} and ${max}`}; @@ -95,7 +95,7 @@ export class ValidationService { return {ok: true, error: ''}; } - min(data, min) { + min(data, min) { // number above min const {ignore, error} = Joi.number().allow('').min(min).validate(data); if (error) { return {ok: false, error: `must not be below ${min}`}; @@ -103,7 +103,7 @@ export class ValidationService { return {ok: true, error: ''}; } - max(data, max) { + max(data, max) { // number below max const {ignore, error} = Joi.number().allow('').max(max).validate(data); if (error) { return {ok: false, error: `must not be above ${max}`}; diff --git a/src/app/settings/settings.component.html b/src/app/settings/settings.component.html index 4c3ae5e..18b2cd3 100644 --- a/src/app/settings/settings.component.html +++ b/src/app/settings/settings.component.html @@ -1,4 +1,3 @@ -
diff --git a/src/app/settings/settings.component.spec.ts b/src/app/settings/settings.component.spec.ts index 53b49f9..bc8e253 100644 --- a/src/app/settings/settings.component.spec.ts +++ b/src/app/settings/settings.component.spec.ts @@ -1,62 +1,5 @@ -// import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -// -// import { SettingsComponent } from './settings.component'; -// import {ApiService} from '../services/api.service'; -// import {LoginService} from '../services/login.service'; -// import {Router} from '@angular/router'; -// import {RbCustomInputsModule} from '../rb-custom-inputs/rb-custom-inputs.module'; -// import {FormsModule} from '@angular/forms'; -// import {ValidationService} from '../services/validation.service'; -// import {RbUiComponentsModule} from '@inst-iot/bosch-angular-ui-components'; -// -// // TODO -// -// let routerServiceSpy: jasmine.SpyObj; -// let apiServiceSpy: jasmine.SpyObj; -// let loginServiceSpy: jasmine.SpyObj; -// let validationServiceSpy: jasmine.SpyObj; -// -// -// describe('SettingsComponent', () => { -// let component: SettingsComponent; -// let fixture: ComponentFixture; -// -// beforeEach(async(() => { -// const routerSpy = jasmine.createSpyObj('Router', ['navigate']); -// const apiSpy = jasmine.createSpyObj('ApiService', ['get', 'post', 'put']); -// const loginSpy = jasmine.createSpyObj('LoginService', ['login', 'canActivate']); -// const validationSpy = jasmine.createSpyObj('ValidationService', ['generate']); -// -// TestBed.configureTestingModule({ -// declarations: [ SettingsComponent ], -// imports: [ -// RbUiComponentsModule, -// RbCustomInputsModule, -// FormsModule -// ], -// providers: [ -// {provide: Router, useValue: routerSpy}, -// {provide: ApiService, useValue: apiSpy}, -// {provide: LoginService, useValue: loginSpy}, -// {provide: ValidationService, useValue: validationSpy}, -// ] -// }) -// .compileComponents(); -// -// routerServiceSpy = TestBed.inject(Router) as jasmine.SpyObj; -// apiServiceSpy = TestBed.inject(ApiService) as jasmine.SpyObj; -// loginServiceSpy = TestBed.inject(LoginService) as jasmine.SpyObj; -// validationServiceSpy = TestBed.inject(ValidationService) as jasmine.SpyObj; -// })); -// -// beforeEach(() => { -// fixture = TestBed.createComponent(SettingsComponent); -// component = fixture.componentInstance; -// component.ngOnInit(); -// fixture.detectChanges(); -// }); -// -// it('should create', () => { -// expect(component).toBeTruthy(); -// }); -// }); +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +describe('SettingsComponent', () => { + +}); diff --git a/src/app/settings/settings.component.ts b/src/app/settings/settings.component.ts index 313d727..5b6e553 100644 --- a/src/app/settings/settings.component.ts +++ b/src/app/settings/settings.component.ts @@ -12,9 +12,9 @@ import {LoginService} from '../services/login.service'; }) export class SettingsComponent implements OnInit { - user: UserModel = new UserModel(); - password = ''; - messageUser = ''; + user: UserModel = new UserModel(); // user to edit + password = ''; // new password + messageUser = ''; // messages for user and pass part messagePass = ''; constructor( @@ -34,7 +34,7 @@ export class SettingsComponent implements OnInit { if (err) { this.messageUser = err.error.status; } - else { + else { // login with new credentials this.login.login(data.name).then(res => { if (res) { this.router.navigate(['/samples']); @@ -52,7 +52,7 @@ export class SettingsComponent implements OnInit { if (err) { this.messagePass = err.error.status; } - else { + else { // login with new credentials this.login.login('', this.password).then(res => { if (res) { this.router.navigate(['/samples']); diff --git a/src/app/templates/templates.component.html b/src/app/templates/templates.component.html index 59dee18..f7b286c 100644 --- a/src/app/templates/templates.component.html +++ b/src/app/templates/templates.component.html @@ -1,4 +1,3 @@ - diff --git a/src/app/templates/templates.component.spec.ts b/src/app/templates/templates.component.spec.ts index a2755f3..041857e 100644 --- a/src/app/templates/templates.component.spec.ts +++ b/src/app/templates/templates.component.spec.ts @@ -1,57 +1,5 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { TemplatesComponent } from './templates.component'; -import {LoginService} from '../services/login.service'; -import {ValidationService} from '../services/validation.service'; -import {ApiService} from '../services/api.service'; -import {DataService} from '../services/data.service'; -import {RbUiComponentsModule} from '@inst-iot/bosch-angular-ui-components'; -import {FormsModule} from '@angular/forms'; -import {RbCustomInputsModule} from '../rb-custom-inputs/rb-custom-inputs.module'; - -// TODO - -let apiServiceSpy: jasmine.SpyObj; -let validationServiceSpy: jasmine.SpyObj; -let dataServiceSpy: jasmine.SpyObj; - describe('TemplatesComponent', () => { - let component: TemplatesComponent; - let fixture: ComponentFixture; - beforeEach(async(() => { - const apiSpy = jasmine.createSpyObj('ApiService', ['post', 'put']); - const validationSpy = jasmine.createSpyObj('ValidationService', ['string', 'parameterName', 'parameterRange']); - const dataSpy = jasmine.createSpyObj('DataService', ['load', 'idReload']); - - TestBed.configureTestingModule({ - declarations: [ TemplatesComponent ], - imports: [ - RbUiComponentsModule, - RbCustomInputsModule, - FormsModule - ], - providers: [ - {provide: ApiService, useValue: apiSpy}, - {provide: ValidationService, useValue: validationSpy}, - {provide: DataService, useValue: dataSpy} - ] - }) - .compileComponents(); - - apiServiceSpy = TestBed.inject(ApiService) as jasmine.SpyObj; - validationServiceSpy = TestBed.inject(ValidationService) as jasmine.SpyObj; - dataServiceSpy = TestBed.inject(DataService) as jasmine.SpyObj; - })); - - beforeEach(() => { - fixture = TestBed.createComponent(TemplatesComponent); - component = fixture.componentInstance; - component.ngOnInit(); - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); }); diff --git a/src/app/templates/templates.component.ts b/src/app/templates/templates.component.ts index fa56f36..ea3c471 100644 --- a/src/app/templates/templates.component.ts +++ b/src/app/templates/templates.component.ts @@ -28,12 +28,18 @@ import {DataService} from '../services/data.service'; }) export class TemplatesComponent implements OnInit { - collection = 'measurement'; - templates: TemplateModel[] = []; + collection = 'measurement'; // collection to view + templates: TemplateModel[] = []; // all templates of current collection templateGroups: {[first_id: string]: TemplateModel[]} = {}; // templates grouped by first_id templateEdit: {[first_id: string]: TemplateModel} = {}; // latest template of each first_id for editing - groupsView: {first_id: string, name: string, version: number, expanded: boolean, edit: boolean, entries: TemplateModel[]}[] = []; - arr = ['testA', 'testB', 'testC']; + groupsView: { // grouped templates + first_id: string, + name: string, + version: number, + expanded: boolean, + edit: boolean, + entries: TemplateModel[] + }[] = []; constructor( private api: ApiService, @@ -55,7 +61,7 @@ export class TemplatesComponent implements OnInit { templateFormat() { this.templateGroups = {}; this.templateEdit = {}; - this.templates.forEach(template => { + this.templates.forEach(template => { // group templates if (this.templateGroups[template.first_id]) { this.templateGroups[template.first_id].push(template); } @@ -94,7 +100,7 @@ export class TemplatesComponent implements OnInit { }); if (valid) { const sendData = {name: template.name, parameters: template.parameters.map(e => omit(e, ['rangeString']))}; - if (first_id === 'null') { + if (first_id === 'null') { // new template this.api.post(`/template/${this.collection}/new`, sendData, () => { delete this.d.arr[this.collection + 'Templates']; this.d.load(this.collection + 'Templates', () => { @@ -113,16 +119,20 @@ export class TemplatesComponent implements OnInit { }); } } - else { - console.log('not valid'); - } } newTemplate() { if (!this.templateEdit.null) { const template = new TemplateModel(); template.name = 'new template'; - this.groupsView.push({first_id: 'null', name: 'new template', version: 0, expanded: true, edit: true, entries: [template]}); + this.groupsView.push({ + first_id: 'null', + name: 'new template', + version: 0, + expanded: true, + edit: true, + entries: [template] + }); this.templateEdit.null = new TemplateModel(); } } diff --git a/src/app/users/users.component.html b/src/app/users/users.component.html index b745808..50ce9ff 100644 --- a/src/app/users/users.component.html +++ b/src/app/users/users.component.html @@ -1,4 +1,3 @@ - New user diff --git a/src/app/users/users.component.spec.ts b/src/app/users/users.component.spec.ts index 7229d14..afb7f45 100644 --- a/src/app/users/users.component.spec.ts +++ b/src/app/users/users.component.spec.ts @@ -1,53 +1,5 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { UsersComponent } from './users.component'; -import {ApiService} from '../services/api.service'; -import {LoginService} from '../services/login.service'; -import {ModalService} from '@inst-iot/bosch-angular-ui-components'; -import {RbCustomInputsModule} from '../rb-custom-inputs/rb-custom-inputs.module'; - -// TODO - -let apiServiceSpy: jasmine.SpyObj; -let modalServiceSpy: jasmine.SpyObj; -let loginServiceSpy: jasmine.SpyObj; - - describe('UsersComponent', () => { - let component: UsersComponent; - let fixture: ComponentFixture; - beforeEach(async(() => { - const apiSpy = jasmine.createSpyObj('ApiService', ['get', 'post', 'put']); - const modalSpy = jasmine.createSpyObj('ModalService', ['open']); - const loginSpy = jasmine.createSpyObj('LoginService', ['login', 'canActivate']); - - TestBed.configureTestingModule({ - declarations: [ UsersComponent ], - imports: [ - RbCustomInputsModule - ], - providers: [ - {provide: ApiService, useValue: apiSpy}, - {provide: ModalService, useValue: modalSpy}, - {provide: LoginService, useValue: loginSpy}, - ] - }) - .compileComponents(); - - apiServiceSpy = TestBed.inject(ApiService) as jasmine.SpyObj; - modalServiceSpy = TestBed.inject(ModalService) as jasmine.SpyObj; - loginServiceSpy = TestBed.inject(LoginService) as jasmine.SpyObj; - })); - - beforeEach(() => { - fixture = TestBed.createComponent(UsersComponent); - component = fixture.componentInstance; - component.ngOnInit(); - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); }); diff --git a/src/app/users/users.component.ts b/src/app/users/users.component.ts index 7ae4c85..eb0ea74 100644 --- a/src/app/users/users.component.ts +++ b/src/app/users/users.component.ts @@ -13,12 +13,12 @@ import {DataService} from '../services/data.service'; }) export class UsersComponent implements OnInit { - users: UserModel[] = []; - deletedUsers: UserModel[] = []; - newUser: UserModel | null = null; - newUserPass = ''; - modelSelect: {id: string, name: string}[] = []; - modelIds: {[id: string]: string} = {}; + users: UserModel[] = []; // all active users + deletedUsers: UserModel[] = []; // all deleted users + newUser: UserModel | null = null; // data of new user + newUserPass = ''; // password of new user + modelSelect: {id: string, name: string}[] = []; // list of all models for selection + modelIds: {[id: string]: string} = {}; // all models by id constructor( private api: ApiService, @@ -41,9 +41,7 @@ export class UsersComponent implements OnInit { } saveUser(user: UserModel) { - console.log(user.models); user.models = user.models.filter(e => e !== ''); - console.log(user.models); this.api.put('/user/' + user.origName, user.sendFormat('admin'), data => { user.deserialize(data); user.edit = false; @@ -51,7 +49,7 @@ export class UsersComponent implements OnInit { } saveNewUser() { - // this.newUser.models = this.newUser.models.filter(e => e !== '' || e !== undefined); + this.newUser.models = this.newUser.models.filter(e => e !== ''); this.api.post('/user/new', {...this.newUser.sendFormat('admin'), pass: this.newUserPass}, data => { this.newUser = null; this.users.push(new UserModel().deserialize(data)); diff --git a/src/app/validate.directive.spec.ts b/src/app/validate.directive.spec.ts index 30b9b57..eacdf0a 100644 --- a/src/app/validate.directive.spec.ts +++ b/src/app/validate.directive.spec.ts @@ -1,14 +1,5 @@ -// import { ValidateDirective } from './validate.directive'; -// import {ValidationService} from './services/validation.service'; -// -// // TODO -// -// const validationSpy = {test: () => {}}; -// const validationServiceSpy: jasmine.SpyObj = spyOn(validationSpy, 'test'); -// -// describe('ValidateDirective', () => { -// it('should create an instance', () => { -// const directive = new ValidateDirective(validationServiceSpy); -// expect(directive).toBeTruthy(); -// }); -// }); +import { ValidateDirective } from './validate.directive'; + +describe('ValidateDirective', () => { + +});