Merge pull request #21 in ~VLE2FE/definma-ui from development to master
* commit '9197e8a1875f5a696861e44cfec3547b8a5cccfa': started testing fixed type filter pwa, save sample view preferences added prediction prototype
@@ -1,4 +1,4 @@
 | 
				
			|||||||
# Digital fingerprint of plastics - UI
 | 
					# DeFinMa - UI
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This is the Angular front end for the digital fingerprint of plastics web page hosted in the bic
 | 
					This is the Angular front end for the digital fingerprint of plastics web page hosted in the bic
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										26
									
								
								angular.json
									
									
									
									
									
								
							
							
						
						@@ -3,7 +3,7 @@
 | 
				
			|||||||
  "version": 1,
 | 
					  "version": 1,
 | 
				
			||||||
  "newProjectRoot": "projects",
 | 
					  "newProjectRoot": "projects",
 | 
				
			||||||
  "projects": {
 | 
					  "projects": {
 | 
				
			||||||
    "UI": {
 | 
					    "definma": {
 | 
				
			||||||
      "projectType": "application",
 | 
					      "projectType": "application",
 | 
				
			||||||
      "schematics": {
 | 
					      "schematics": {
 | 
				
			||||||
        "@schematics/angular:component": {
 | 
					        "@schematics/angular:component": {
 | 
				
			||||||
@@ -17,7 +17,7 @@
 | 
				
			|||||||
        "build": {
 | 
					        "build": {
 | 
				
			||||||
          "builder": "@angular-devkit/build-angular:browser",
 | 
					          "builder": "@angular-devkit/build-angular:browser",
 | 
				
			||||||
          "options": {
 | 
					          "options": {
 | 
				
			||||||
            "outputPath": "dist/UI",
 | 
					            "outputPath": "dist/definma",
 | 
				
			||||||
            "index": "src/index.html",
 | 
					            "index": "src/index.html",
 | 
				
			||||||
            "main": "src/main.ts",
 | 
					            "main": "src/main.ts",
 | 
				
			||||||
            "polyfills": "src/polyfills.ts",
 | 
					            "polyfills": "src/polyfills.ts",
 | 
				
			||||||
@@ -30,7 +30,8 @@
 | 
				
			|||||||
                "glob": "**/*",
 | 
					                "glob": "**/*",
 | 
				
			||||||
                "input": "./node_modules/@inst-iot/bosch-angular-ui-components/assets",
 | 
					                "input": "./node_modules/@inst-iot/bosch-angular-ui-components/assets",
 | 
				
			||||||
                "output": "./assets"
 | 
					                "output": "./assets"
 | 
				
			||||||
              }
 | 
					              },
 | 
				
			||||||
 | 
					              "src/manifest.webmanifest"
 | 
				
			||||||
            ],
 | 
					            ],
 | 
				
			||||||
            "styles": [
 | 
					            "styles": [
 | 
				
			||||||
              "src/styles.scss"
 | 
					              "src/styles.scss"
 | 
				
			||||||
@@ -64,26 +65,28 @@
 | 
				
			|||||||
                  "maximumWarning": "6kb",
 | 
					                  "maximumWarning": "6kb",
 | 
				
			||||||
                  "maximumError": "10kb"
 | 
					                  "maximumError": "10kb"
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
              ]
 | 
					              ],
 | 
				
			||||||
 | 
					              "serviceWorker": true,
 | 
				
			||||||
 | 
					              "ngswConfigPath": "ngsw-config.json"
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "serve": {
 | 
					        "serve": {
 | 
				
			||||||
          "builder": "@angular-devkit/build-angular:dev-server",
 | 
					          "builder": "@angular-devkit/build-angular:dev-server",
 | 
				
			||||||
          "options": {
 | 
					          "options": {
 | 
				
			||||||
            "browserTarget": "UI:build",
 | 
					            "browserTarget": "definma:build",
 | 
				
			||||||
            "proxyConfig": "src/proxy.conf.json"
 | 
					            "proxyConfig": "src/proxy.conf.json"
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
          "configurations": {
 | 
					          "configurations": {
 | 
				
			||||||
            "production": {
 | 
					            "production": {
 | 
				
			||||||
              "browserTarget": "UI:build:production"
 | 
					              "browserTarget": "definma:build:production"
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "extract-i18n": {
 | 
					        "extract-i18n": {
 | 
				
			||||||
          "builder": "@angular-devkit/build-angular:extract-i18n",
 | 
					          "builder": "@angular-devkit/build-angular:extract-i18n",
 | 
				
			||||||
          "options": {
 | 
					          "options": {
 | 
				
			||||||
            "browserTarget": "UI:build"
 | 
					            "browserTarget": "definma:build"
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "test": {
 | 
					        "test": {
 | 
				
			||||||
@@ -95,7 +98,8 @@
 | 
				
			|||||||
            "karmaConfig": "karma.conf.js",
 | 
					            "karmaConfig": "karma.conf.js",
 | 
				
			||||||
            "assets": [
 | 
					            "assets": [
 | 
				
			||||||
              "src/favicon.ico",
 | 
					              "src/favicon.ico",
 | 
				
			||||||
              "src/assets"
 | 
					              "src/assets",
 | 
				
			||||||
 | 
					              "src/manifest.webmanifest"
 | 
				
			||||||
            ],
 | 
					            ],
 | 
				
			||||||
            "styles": [
 | 
					            "styles": [
 | 
				
			||||||
              "src/styles.scss"
 | 
					              "src/styles.scss"
 | 
				
			||||||
@@ -120,15 +124,15 @@
 | 
				
			|||||||
          "builder": "@angular-devkit/build-angular:protractor",
 | 
					          "builder": "@angular-devkit/build-angular:protractor",
 | 
				
			||||||
          "options": {
 | 
					          "options": {
 | 
				
			||||||
            "protractorConfig": "e2e/protractor.conf.js",
 | 
					            "protractorConfig": "e2e/protractor.conf.js",
 | 
				
			||||||
            "devServerTarget": "UI:serve"
 | 
					            "devServerTarget": "definma:serve"
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
          "configurations": {
 | 
					          "configurations": {
 | 
				
			||||||
            "production": {
 | 
					            "production": {
 | 
				
			||||||
              "devServerTarget": "UI:serve:production"
 | 
					              "devServerTarget": "definma:serve:production"
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }},
 | 
					    }},
 | 
				
			||||||
  "defaultProject": "UI"
 | 
					  "defaultProject": "definma"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
pushstate: enabled
 | 
					pushstate: enabled
 | 
				
			||||||
force_https: true
 | 
					force_https: true
 | 
				
			||||||
root: UI
 | 
					root: definma
 | 
				
			||||||
location_include: ../../*.conf
 | 
					location_include: ../../*.conf
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,10 +13,13 @@ module.exports = function (config) {
 | 
				
			|||||||
      require('@angular-devkit/build-angular/plugins/karma')
 | 
					      require('@angular-devkit/build-angular/plugins/karma')
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    client: {
 | 
					    client: {
 | 
				
			||||||
      clearContext: false // leave Jasmine Spec Runner output visible in browser
 | 
					      clearContext: false, // leave Jasmine Spec Runner output visible in browser
 | 
				
			||||||
 | 
					      jasmine: {
 | 
				
			||||||
 | 
					        random: false
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    coverageIstanbulReporter: {
 | 
					    coverageIstanbulReporter: {
 | 
				
			||||||
      dir: require('path').join(__dirname, './coverage/UI'),
 | 
					      dir: require('path').join(__dirname, './coverage/definma'),
 | 
				
			||||||
      reports: ['html', 'lcovonly', 'text-summary'],
 | 
					      reports: ['html', 'lcovonly', 'text-summary'],
 | 
				
			||||||
      fixWebpackSourcePaths: true
 | 
					      fixWebpackSourcePaths: true
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										29
									
								
								ngsw-config.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "$schema": "./node_modules/@angular/service-worker/config/schema.json",
 | 
				
			||||||
 | 
					  "index": "/index.html",
 | 
				
			||||||
 | 
					  "assetGroups": [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "name": "app",
 | 
				
			||||||
 | 
					      "installMode": "prefetch",
 | 
				
			||||||
 | 
					      "resources": {
 | 
				
			||||||
 | 
					        "files": [
 | 
				
			||||||
 | 
					          "/favicon.ico",
 | 
				
			||||||
 | 
					          "/index.html",
 | 
				
			||||||
 | 
					          "/manifest.webmanifest",
 | 
				
			||||||
 | 
					          "/*.css",
 | 
				
			||||||
 | 
					          "/*.js"
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }, {
 | 
				
			||||||
 | 
					      "name": "assets",
 | 
				
			||||||
 | 
					      "installMode": "lazy",
 | 
				
			||||||
 | 
					      "updateMode": "prefetch",
 | 
				
			||||||
 | 
					      "resources": {
 | 
				
			||||||
 | 
					        "files": [
 | 
				
			||||||
 | 
					          "/assets/**",
 | 
				
			||||||
 | 
					          "/*.(eot|svg|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani)"
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										9
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						@@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "ui",
 | 
					  "name": "definma",
 | 
				
			||||||
  "version": "0.0.0",
 | 
					  "version": "0.5.5",
 | 
				
			||||||
  "lockfileVersion": 1,
 | 
					  "lockfileVersion": 1,
 | 
				
			||||||
  "requires": true,
 | 
					  "requires": true,
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
@@ -630,6 +630,11 @@
 | 
				
			|||||||
      "resolved": "https://registry.npmjs.org/@angular/router/-/router-9.1.7.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@angular/router/-/router-9.1.7.tgz",
 | 
				
			||||||
      "integrity": "sha512-ycrkhkCbfOMCe9PngFjnyk8nH5jt0Kyb2NPtjmaGOtSCuZBZ0kOU0rQGmQnj3d2PiT0Yir59S8eEAf3Fh0iDuw=="
 | 
					      "integrity": "sha512-ycrkhkCbfOMCe9PngFjnyk8nH5jt0Kyb2NPtjmaGOtSCuZBZ0kOU0rQGmQnj3d2PiT0Yir59S8eEAf3Fh0iDuw=="
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "@angular/service-worker": {
 | 
				
			||||||
 | 
					      "version": "9.1.12",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-9.1.12.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-UsmhPfhIYq9LanuFT6V7Kmkr5Vjl2CMjKkL1gqhChkywNW4vavAYsBkuVji8P76ZKliq41TCG01z6xIAWji8QA=="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "@babel/code-frame": {
 | 
					    "@babel/code-frame": {
 | 
				
			||||||
      "version": "7.8.3",
 | 
					      "version": "7.8.3",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,6 +23,7 @@
 | 
				
			|||||||
    "@angular/platform-browser": "~9.1.7",
 | 
					    "@angular/platform-browser": "~9.1.7",
 | 
				
			||||||
    "@angular/platform-browser-dynamic": "~9.1.7",
 | 
					    "@angular/platform-browser-dynamic": "~9.1.7",
 | 
				
			||||||
    "@angular/router": "~9.1.7",
 | 
					    "@angular/router": "~9.1.7",
 | 
				
			||||||
 | 
					    "@angular/service-worker": "~9.1.7",
 | 
				
			||||||
    "@hapi/joi": "^17.1.1",
 | 
					    "@hapi/joi": "^17.1.1",
 | 
				
			||||||
    "@inst-iot/bosch-angular-ui-components": "^0.7.2",
 | 
					    "@inst-iot/bosch-angular-ui-components": "^0.7.2",
 | 
				
			||||||
    "angular-2-local-storage": "^3.0.2",
 | 
					    "angular-2-local-storage": "^3.0.2",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,11 +10,13 @@ import {SettingsComponent} from './settings/settings.component';
 | 
				
			|||||||
import {UsersComponent} from './users/users.component';
 | 
					import {UsersComponent} from './users/users.component';
 | 
				
			||||||
import {ChangelogComponent} from './changelog/changelog.component';
 | 
					import {ChangelogComponent} from './changelog/changelog.component';
 | 
				
			||||||
import {DocumentationDatabaseComponent} from './documentation-database/documentation-database.component';
 | 
					import {DocumentationDatabaseComponent} from './documentation-database/documentation-database.component';
 | 
				
			||||||
 | 
					import {PredictionComponent} from './prediction/prediction.component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const routes: Routes = [
 | 
					const routes: Routes = [
 | 
				
			||||||
  {path: '', component: HomeComponent},
 | 
					  {path: '', component: HomeComponent},
 | 
				
			||||||
  {path: 'home', component: HomeComponent},
 | 
					  {path: 'home', component: HomeComponent},
 | 
				
			||||||
 | 
					  {path: 'prediction', component: PredictionComponent},
 | 
				
			||||||
  {path: 'samples', component: SamplesComponent, canActivate: [LoginService]},
 | 
					  {path: 'samples', component: SamplesComponent, canActivate: [LoginService]},
 | 
				
			||||||
  {path: 'samples/new', component: SampleComponent, canActivate: [LoginService]},
 | 
					  {path: 'samples/new', component: SampleComponent, canActivate: [LoginService]},
 | 
				
			||||||
  {path: 'samples/edit/:id', component: SampleComponent, canActivate: [LoginService]},
 | 
					  {path: 'samples/edit/:id', component: SampleComponent, canActivate: [LoginService]},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
<rb-full-header id="top">
 | 
					<rb-full-header id="top">
 | 
				
			||||||
  <nav *rbMainNavItems>
 | 
					  <nav *rbMainNavItems>
 | 
				
			||||||
    <a routerLink="/home" routerLinkActive="active" rbLoadingLink>Home</a>
 | 
					    <a routerLink="/home" routerLinkActive="active" rbLoadingLink>Home</a>
 | 
				
			||||||
 | 
					    <a routerLink="/prediction" routerLinkActive="active" rbLoadingLink *ngIf="login.isLevel.admin">Prediction</a>
 | 
				
			||||||
    <a routerLink="/samples" routerLinkActive="active" rbLoadingLink *ngIf="login.isLoggedIn">Samples</a>
 | 
					    <a routerLink="/samples" routerLinkActive="active" rbLoadingLink *ngIf="login.isLoggedIn">Samples</a>
 | 
				
			||||||
    <a routerLink="/templates" routerLinkActive="active" rbLoadingLink *ngIf="login.isLevel.dev">
 | 
					    <a routerLink="/templates" routerLinkActive="active" rbLoadingLink *ngIf="login.isLevel.dev">
 | 
				
			||||||
      Templates
 | 
					      Templates
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,8 +4,13 @@ import {By} from '@angular/platform-browser';
 | 
				
			|||||||
import {RbUiComponentsModule} from '@inst-iot/bosch-angular-ui-components';
 | 
					import {RbUiComponentsModule} from '@inst-iot/bosch-angular-ui-components';
 | 
				
			||||||
import {RouterTestingModule} from '@angular/router/testing';
 | 
					import {RouterTestingModule} from '@angular/router/testing';
 | 
				
			||||||
import {LoginService} from './services/login.service';
 | 
					import {LoginService} from './services/login.service';
 | 
				
			||||||
 | 
					import {Router} from '@angular/router';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let loginServiceSpy: jasmine.SpyObj<LoginService>;
 | 
					let loginServiceSpy: jasmine.SpyObj<LoginService>;
 | 
				
			||||||
 | 
					let routerServiceSpy: jasmine.SpyObj<Router>;
 | 
				
			||||||
 | 
					let windowServiceSpy: jasmine.SpyObj<Window>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe('AppComponent', () => {
 | 
					describe('AppComponent', () => {
 | 
				
			||||||
  let component: AppComponent;
 | 
					  let component: AppComponent;
 | 
				
			||||||
@@ -14,6 +19,8 @@ describe('AppComponent', () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  beforeEach(async(() => {
 | 
					  beforeEach(async(() => {
 | 
				
			||||||
    const loginSpy = jasmine.createSpyObj('LoginService', ['login', 'canActivate']);
 | 
					    const loginSpy = jasmine.createSpyObj('LoginService', ['login', 'canActivate']);
 | 
				
			||||||
 | 
					    const routerSpy = jasmine.createSpyObj('Router', ['navigate', 'events']);
 | 
				
			||||||
 | 
					    const windowSpy = jasmine.createSpyObj('Window', ['location', 'innerWidth', 'innerHeight', 'scroll']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    TestBed.configureTestingModule({
 | 
					    TestBed.configureTestingModule({
 | 
				
			||||||
      declarations: [ AppComponent ],
 | 
					      declarations: [ AppComponent ],
 | 
				
			||||||
@@ -22,10 +29,15 @@ describe('AppComponent', () => {
 | 
				
			|||||||
        RouterTestingModule
 | 
					        RouterTestingModule
 | 
				
			||||||
      ],
 | 
					      ],
 | 
				
			||||||
      providers: [
 | 
					      providers: [
 | 
				
			||||||
        {provide: LoginService, useValue: loginSpy}
 | 
					        {provide: LoginService, useValue: loginSpy},
 | 
				
			||||||
 | 
					        {provide: Router, useValue: routerSpy},
 | 
				
			||||||
 | 
					        {provide: Window, useValue: windowSpy}
 | 
				
			||||||
      ]
 | 
					      ]
 | 
				
			||||||
    }).compileComponents();
 | 
					    }).compileComponents();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    loginServiceSpy = TestBed.inject(LoginService) as jasmine.SpyObj<LoginService>;
 | 
					    loginServiceSpy = TestBed.inject(LoginService) as jasmine.SpyObj<LoginService>;
 | 
				
			||||||
 | 
					    routerServiceSpy = TestBed.inject(Router) as jasmine.SpyObj<Router>;
 | 
				
			||||||
 | 
					    windowServiceSpy = TestBed.inject(Window) as jasmine.SpyObj<Window>;
 | 
				
			||||||
  }));
 | 
					  }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  beforeEach(() => {
 | 
					  beforeEach(() => {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,12 +2,6 @@ import { Component, isDevMode} from '@angular/core';
 | 
				
			|||||||
import {LoginService} from './services/login.service';
 | 
					import {LoginService} from './services/login.service';
 | 
				
			||||||
import {NavigationStart, Router} from '@angular/router';
 | 
					import {NavigationStart, Router} from '@angular/router';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO: add multiple samples at once
 | 
					 | 
				
			||||||
// TODO: validation: DPT: filename
 | 
					 | 
				
			||||||
// TODO: filter by not completely filled/no measurements
 | 
					 | 
				
			||||||
// TODO: validation of samples
 | 
					 | 
				
			||||||
// TODO: centralize fetching of materials / templates, etc.
 | 
					 | 
				
			||||||
// TODO: PWA
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO: get rid of chart.js (+moment.js)
 | 
					// TODO: get rid of chart.js (+moment.js)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -24,7 +18,8 @@ export class AppComponent {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  constructor(
 | 
					  constructor(
 | 
				
			||||||
    public login: LoginService,
 | 
					    public login: LoginService,
 | 
				
			||||||
    public router: Router
 | 
					    public router: Router,
 | 
				
			||||||
 | 
					    private window: Window
 | 
				
			||||||
  ) {
 | 
					  ) {
 | 
				
			||||||
    this.devMode = isDevMode();
 | 
					    this.devMode = isDevMode();
 | 
				
			||||||
    this.router.events.subscribe(event => {
 | 
					    this.router.events.subscribe(event => {
 | 
				
			||||||
@@ -43,7 +38,7 @@ export class AppComponent {
 | 
				
			|||||||
    return `mailto:lukas.veit@de.bosch.com?subject=Bug report&body=Thanks for sending the report! Your bug will be (hopefully) fixed soon.
 | 
					    return `mailto:lukas.veit@de.bosch.com?subject=Bug report&body=Thanks for sending the report! Your bug will be (hopefully) fixed soon.
 | 
				
			||||||
%0D%0A%0D%0A--- REPORT DATA ---
 | 
					%0D%0A%0D%0A--- REPORT DATA ---
 | 
				
			||||||
%0D%0A%0D%0ATime: ${new Date().toString()}%0D%0A
 | 
					%0D%0A%0D%0ATime: ${new Date().toString()}%0D%0A
 | 
				
			||||||
URL: ${window.location}%0D%0A%0D%0AWhat did you do?%0D%0A${encodeURIComponent(this.bugReport.do)}
 | 
					URL: ${this.window.location}%0D%0A%0D%0AWhat did you do?%0D%0A${encodeURIComponent(this.bugReport.do)}
 | 
				
			||||||
%0D%0A%0D%0AWhat did not work?%0D%0A${encodeURIComponent(this.bugReport.work)}%0D%0A%0D%0ABrowser:%0D%0A
 | 
					%0D%0A%0D%0AWhat did not work?%0D%0A${encodeURIComponent(this.bugReport.work)}%0D%0A%0D%0ABrowser:%0D%0A
 | 
				
			||||||
%0D%0AappCodeName: ${navigator.appCodeName}
 | 
					%0D%0AappCodeName: ${navigator.appCodeName}
 | 
				
			||||||
%0D%0AappVersion: ${navigator.appVersion}
 | 
					%0D%0AappVersion: ${navigator.appVersion}
 | 
				
			||||||
@@ -52,8 +47,8 @@ URL: ${window.location}%0D%0A%0D%0AWhat did you do?%0D%0A${encodeURIComponent(th
 | 
				
			|||||||
%0D%0Aoscpu: ${navigator.oscpu}
 | 
					%0D%0Aoscpu: ${navigator.oscpu}
 | 
				
			||||||
%0D%0Aplatform: ${navigator.platform}
 | 
					%0D%0Aplatform: ${navigator.platform}
 | 
				
			||||||
%0D%0AuserAgent: ${navigator.userAgent}
 | 
					%0D%0AuserAgent: ${navigator.userAgent}
 | 
				
			||||||
%0D%0AinnerWidth: ${window.innerWidth}
 | 
					%0D%0AinnerWidth: ${this.window.innerWidth}
 | 
				
			||||||
%0D%0AinnerHeight: ${window.innerHeight}`;
 | 
					%0D%0AinnerHeight: ${this.window.innerHeight}`;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  closeBugReport(close) {
 | 
					  closeBugReport(close) {
 | 
				
			||||||
@@ -61,7 +56,7 @@ URL: ${window.location}%0D%0A%0D%0AWhat did you do?%0D%0A${encodeURIComponent(th
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  toTheTop() {
 | 
					  toTheTop() {
 | 
				
			||||||
    window.scroll(0, 0);
 | 
					    this.window.scroll(0, 0);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,6 +27,9 @@ import { SettingsComponent } from './settings/settings.component';
 | 
				
			|||||||
import { UsersComponent } from './users/users.component';
 | 
					import { UsersComponent } from './users/users.component';
 | 
				
			||||||
import { ChangelogComponent } from './changelog/changelog.component';
 | 
					import { ChangelogComponent } from './changelog/changelog.component';
 | 
				
			||||||
import { DocumentationDatabaseComponent } from './documentation-database/documentation-database.component';
 | 
					import { DocumentationDatabaseComponent } from './documentation-database/documentation-database.component';
 | 
				
			||||||
 | 
					import { PredictionComponent } from './prediction/prediction.component';
 | 
				
			||||||
 | 
					import { ServiceWorkerModule } from '@angular/service-worker';
 | 
				
			||||||
 | 
					import { environment } from '../environments/environment';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@NgModule({
 | 
					@NgModule({
 | 
				
			||||||
  declarations: [
 | 
					  declarations: [
 | 
				
			||||||
@@ -46,7 +49,8 @@ import { DocumentationDatabaseComponent } from './documentation-database/documen
 | 
				
			|||||||
    SettingsComponent,
 | 
					    SettingsComponent,
 | 
				
			||||||
    UsersComponent,
 | 
					    UsersComponent,
 | 
				
			||||||
    ChangelogComponent,
 | 
					    ChangelogComponent,
 | 
				
			||||||
    DocumentationDatabaseComponent
 | 
					    DocumentationDatabaseComponent,
 | 
				
			||||||
 | 
					    PredictionComponent
 | 
				
			||||||
  ],
 | 
					  ],
 | 
				
			||||||
  imports: [
 | 
					  imports: [
 | 
				
			||||||
    LocalStorageModule.forRoot({
 | 
					    LocalStorageModule.forRoot({
 | 
				
			||||||
@@ -63,7 +67,8 @@ import { DocumentationDatabaseComponent } from './documentation-database/documen
 | 
				
			|||||||
    ReactiveFormsModule,
 | 
					    ReactiveFormsModule,
 | 
				
			||||||
    FormFieldsModule,
 | 
					    FormFieldsModule,
 | 
				
			||||||
    CommonModule,
 | 
					    CommonModule,
 | 
				
			||||||
    ChartsModule
 | 
					    ChartsModule,
 | 
				
			||||||
 | 
					    ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production })
 | 
				
			||||||
  ],
 | 
					  ],
 | 
				
			||||||
  providers: [
 | 
					  providers: [
 | 
				
			||||||
    ModalService,
 | 
					    ModalService,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,21 +1,44 @@
 | 
				
			|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 | 
					import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { ChangelogComponent } from './changelog.component';
 | 
					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';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let apiServiceSpy: jasmine.SpyObj<ApiService>;
 | 
				
			||||||
 | 
					let modalServiceSpy: jasmine.SpyObj<ModalService>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe('ChangelogComponent', () => {
 | 
					describe('ChangelogComponent', () => {
 | 
				
			||||||
  let component: ChangelogComponent;
 | 
					  let component: ChangelogComponent;
 | 
				
			||||||
  let fixture: ComponentFixture<ChangelogComponent>;
 | 
					  let fixture: ComponentFixture<ChangelogComponent>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  beforeEach(async(() => {
 | 
					  beforeEach(async(() => {
 | 
				
			||||||
 | 
					    const apiSpy = jasmine.createSpyObj('ApiService', ['get']);
 | 
				
			||||||
 | 
					    const modalSpy = jasmine.createSpyObj('ModalService', ['open']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    TestBed.configureTestingModule({
 | 
					    TestBed.configureTestingModule({
 | 
				
			||||||
      declarations: [ ChangelogComponent ]
 | 
					      declarations: [ ChangelogComponent ],
 | 
				
			||||||
 | 
					      imports: [
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					      providers: [
 | 
				
			||||||
 | 
					        {provide: ApiService, useValue: apiSpy},
 | 
				
			||||||
 | 
					        {provide: ModalService, useValue: modalSpy}
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
    .compileComponents();
 | 
					    .compileComponents();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    apiServiceSpy = TestBed.inject(ApiService) as jasmine.SpyObj<ApiService>;
 | 
				
			||||||
 | 
					    modalServiceSpy = TestBed.inject(ModalService) as jasmine.SpyObj<ModalService>;
 | 
				
			||||||
  }));
 | 
					  }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  beforeEach(() => {
 | 
					  beforeEach(() => {
 | 
				
			||||||
    fixture = TestBed.createComponent(ChangelogComponent);
 | 
					    fixture = TestBed.createComponent(ChangelogComponent);
 | 
				
			||||||
    component = fixture.componentInstance;
 | 
					    component = fixture.componentInstance;
 | 
				
			||||||
 | 
					    component.ngOnInit();
 | 
				
			||||||
    fixture.detectChanges();
 | 
					    fixture.detectChanges();
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,7 +18,6 @@
 | 
				
			|||||||
    <td>Automatically generated unique id</td>
 | 
					    <td>Automatically generated unique id</td>
 | 
				
			||||||
    <td>'5f2e63c98d1c020f8cda6e06'</td>
 | 
					    <td>'5f2e63c98d1c020f8cda6e06'</td>
 | 
				
			||||||
  </tr>
 | 
					  </tr>
 | 
				
			||||||
<!--  TODO: new names-->
 | 
					 | 
				
			||||||
  <tr>
 | 
					  <tr>
 | 
				
			||||||
    <td>type</td>
 | 
					    <td>type</td>
 | 
				
			||||||
    <td>
 | 
					    <td>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,6 +2,8 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { DocumentationDatabaseComponent } from './documentation-database.component';
 | 
					import { DocumentationDatabaseComponent } from './documentation-database.component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe('DocumentationDatabaseComponent', () => {
 | 
					describe('DocumentationDatabaseComponent', () => {
 | 
				
			||||||
  let component: DocumentationDatabaseComponent;
 | 
					  let component: DocumentationDatabaseComponent;
 | 
				
			||||||
  let fixture: ComponentFixture<DocumentationDatabaseComponent>;
 | 
					  let fixture: ComponentFixture<DocumentationDatabaseComponent>;
 | 
				
			||||||
@@ -16,6 +18,7 @@ describe('DocumentationDatabaseComponent', () => {
 | 
				
			|||||||
  beforeEach(() => {
 | 
					  beforeEach(() => {
 | 
				
			||||||
    fixture = TestBed.createComponent(DocumentationDatabaseComponent);
 | 
					    fixture = TestBed.createComponent(DocumentationDatabaseComponent);
 | 
				
			||||||
    component = fixture.componentInstance;
 | 
					    component = fixture.componentInstance;
 | 
				
			||||||
 | 
					    component.ngOnInit();
 | 
				
			||||||
    fixture.detectChanges();
 | 
					    fixture.detectChanges();
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,11 @@
 | 
				
			|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 | 
					import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { DocumentationComponent } from './documentation.component';
 | 
					import { DocumentationComponent } from './documentation.component';
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe('DocumentationComponent', () => {
 | 
					describe('DocumentationComponent', () => {
 | 
				
			||||||
  let component: DocumentationComponent;
 | 
					  let component: DocumentationComponent;
 | 
				
			||||||
@@ -8,7 +13,10 @@ describe('DocumentationComponent', () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  beforeEach(async(() => {
 | 
					  beforeEach(async(() => {
 | 
				
			||||||
    TestBed.configureTestingModule({
 | 
					    TestBed.configureTestingModule({
 | 
				
			||||||
      declarations: [ DocumentationComponent ]
 | 
					      declarations: [ DocumentationComponent ],
 | 
				
			||||||
 | 
					      imports: [
 | 
				
			||||||
 | 
					        RbCustomInputsModule
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
    .compileComponents();
 | 
					    .compileComponents();
 | 
				
			||||||
  }));
 | 
					  }));
 | 
				
			||||||
@@ -16,6 +24,7 @@ describe('DocumentationComponent', () => {
 | 
				
			|||||||
  beforeEach(() => {
 | 
					  beforeEach(() => {
 | 
				
			||||||
    fixture = TestBed.createComponent(DocumentationComponent);
 | 
					    fixture = TestBed.createComponent(DocumentationComponent);
 | 
				
			||||||
    component = fixture.componentInstance;
 | 
					    component = fixture.componentInstance;
 | 
				
			||||||
 | 
					    component.ngOnInit();
 | 
				
			||||||
    fixture.detectChanges();
 | 
					    fixture.detectChanges();
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,8 @@ import { ErrorComponent } from './error.component';
 | 
				
			|||||||
import {ModalService, RbUiComponentsModule} from '@inst-iot/bosch-angular-ui-components';
 | 
					import {ModalService, RbUiComponentsModule} from '@inst-iot/bosch-angular-ui-components';
 | 
				
			||||||
import {By} from '@angular/platform-browser';
 | 
					import {By} from '@angular/platform-browser';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe('ErrorComponent', () => {
 | 
					describe('ErrorComponent', () => {
 | 
				
			||||||
  let component: ErrorComponent;
 | 
					  let component: ErrorComponent;
 | 
				
			||||||
  let fixture: ComponentFixture<ErrorComponent>;
 | 
					  let fixture: ComponentFixture<ErrorComponent>;
 | 
				
			||||||
@@ -25,6 +27,7 @@ describe('ErrorComponent', () => {
 | 
				
			|||||||
  beforeEach(() => {
 | 
					  beforeEach(() => {
 | 
				
			||||||
    fixture = TestBed.createComponent(ErrorComponent);
 | 
					    fixture = TestBed.createComponent(ErrorComponent);
 | 
				
			||||||
    component = fixture.componentInstance;
 | 
					    component = fixture.componentInstance;
 | 
				
			||||||
 | 
					    component.ngOnInit();
 | 
				
			||||||
    fixture.detectChanges();
 | 
					    fixture.detectChanges();
 | 
				
			||||||
    css = (selector) => fixture.debugElement.query(By.css(selector)).nativeElement;
 | 
					    css = (selector) => fixture.debugElement.query(By.css(selector)).nativeElement;
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,7 @@
 | 
				
			|||||||
import { ExistsPipe } from './exists.pipe';
 | 
					import { ExistsPipe } from './exists.pipe';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe('ExistsPipe', () => {
 | 
					describe('ExistsPipe', () => {
 | 
				
			||||||
  it('create an instance', () => {
 | 
					  it('create an instance', () => {
 | 
				
			||||||
    const pipe = new ExistsPipe();
 | 
					    const pipe = new ExistsPipe();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,8 @@ import { HomeComponent } from './home.component';
 | 
				
			|||||||
import {Component} from '@angular/core';
 | 
					import {Component} from '@angular/core';
 | 
				
			||||||
import {By} from '@angular/platform-browser';
 | 
					import {By} from '@angular/platform-browser';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Component({selector: 'app-login', template: ''})
 | 
					@Component({selector: 'app-login', template: ''})
 | 
				
			||||||
class LoginStubComponent {}
 | 
					class LoginStubComponent {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -23,6 +25,7 @@ describe('HomeComponent', () => {
 | 
				
			|||||||
  beforeEach(() => {
 | 
					  beforeEach(() => {
 | 
				
			||||||
    fixture = TestBed.createComponent(HomeComponent);
 | 
					    fixture = TestBed.createComponent(HomeComponent);
 | 
				
			||||||
    component = fixture.componentInstance;
 | 
					    component = fixture.componentInstance;
 | 
				
			||||||
 | 
					    component.ngOnInit();
 | 
				
			||||||
    fixture.detectChanges();
 | 
					    fixture.detectChanges();
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,21 +1,40 @@
 | 
				
			|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 | 
					import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { ImgMagnifierComponent } from './img-magnifier.component';
 | 
					import { ImgMagnifierComponent } from './img-magnifier.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';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let windowServiceSpy: jasmine.SpyObj<Window>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe('ImgMagnifierComponent', () => {
 | 
					describe('ImgMagnifierComponent', () => {
 | 
				
			||||||
  let component: ImgMagnifierComponent;
 | 
					  let component: ImgMagnifierComponent;
 | 
				
			||||||
  let fixture: ComponentFixture<ImgMagnifierComponent>;
 | 
					  let fixture: ComponentFixture<ImgMagnifierComponent>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  beforeEach(async(() => {
 | 
					  beforeEach(async(() => {
 | 
				
			||||||
 | 
					    const windowSpy = jasmine.createSpyObj('Window', []);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    TestBed.configureTestingModule({
 | 
					    TestBed.configureTestingModule({
 | 
				
			||||||
      declarations: [ ImgMagnifierComponent ]
 | 
					      declarations: [ ImgMagnifierComponent ],
 | 
				
			||||||
 | 
					      imports: [
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					      providers: [
 | 
				
			||||||
 | 
					        {provide: Window, useValue: windowSpy}
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
    .compileComponents();
 | 
					    .compileComponents();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    windowServiceSpy = TestBed.inject(Window) as jasmine.SpyObj<Window>;
 | 
				
			||||||
  }));
 | 
					  }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  beforeEach(() => {
 | 
					  beforeEach(() => {
 | 
				
			||||||
    fixture = TestBed.createComponent(ImgMagnifierComponent);
 | 
					    fixture = TestBed.createComponent(ImgMagnifierComponent);
 | 
				
			||||||
    component = fixture.componentInstance;
 | 
					    component = fixture.componentInstance;
 | 
				
			||||||
 | 
					    component.ngOnInit();
 | 
				
			||||||
    fixture.detectChanges();
 | 
					    fixture.detectChanges();
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,8 @@ import {By} from '@angular/platform-browser';
 | 
				
			|||||||
import {ValidateDirective} from '../validate.directive';
 | 
					import {ValidateDirective} from '../validate.directive';
 | 
				
			||||||
import {RbUiComponentsModule} from '@inst-iot/bosch-angular-ui-components';
 | 
					import {RbUiComponentsModule} from '@inst-iot/bosch-angular-ui-components';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let validationServiceSpy: jasmine.SpyObj<ValidationService>;
 | 
					let validationServiceSpy: jasmine.SpyObj<ValidationService>;
 | 
				
			||||||
let loginServiceSpy: jasmine.SpyObj<LoginService>;
 | 
					let loginServiceSpy: jasmine.SpyObj<LoginService>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
import { UserModel } from './user.model';
 | 
					import { UserModel } from './user.model';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe('User.Model', () => {
 | 
					describe('UserModel', () => {
 | 
				
			||||||
  it('should create an instance', () => {
 | 
					  it('should create an instance', () => {
 | 
				
			||||||
    expect(new UserModel()).toBeTruthy();
 | 
					    expect(new UserModel()).toBeTruthy();
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,7 @@
 | 
				
			|||||||
import { ObjectPipe } from './object.pipe';
 | 
					import { ObjectPipe } from './object.pipe';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe('ObjectPipe', () => {
 | 
					describe('ObjectPipe', () => {
 | 
				
			||||||
  it('create an instance', () => {
 | 
					  it('create an instance', () => {
 | 
				
			||||||
    const pipe = new ObjectPipe();
 | 
					    const pipe = new ObjectPipe();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,7 @@
 | 
				
			|||||||
import { ParametersPipe } from './parameters.pipe';
 | 
					import { ParametersPipe } from './parameters.pipe';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe('ParametersPipe', () => {
 | 
					describe('ParametersPipe', () => {
 | 
				
			||||||
  it('create an instance', () => {
 | 
					  it('create an instance', () => {
 | 
				
			||||||
    const pipe = new ParametersPipe();
 | 
					    const pipe = new ParametersPipe();
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										20
									
								
								src/app/prediction/prediction.component.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					<h2>Prediction</h2>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<h4 *ngIf="result !== '' || loading" [@inOut]>
 | 
				
			||||||
 | 
					  Result: {{result}}<rb-loading-spinner *ngIf="loading"></rb-loading-spinner>
 | 
				
			||||||
 | 
					</h4>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<rb-form-file name="spectrum-upload" label="spectrum file" maxSize="10000000" class="space-below"
 | 
				
			||||||
 | 
					              (ngModelChange)="fileToArray($event)" placeholder="Select file or drag and drop" dragDrop ngModel>
 | 
				
			||||||
 | 
					</rb-form-file>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<div class="dpt-chart">
 | 
				
			||||||
 | 
					  <canvas baseChart
 | 
				
			||||||
 | 
					          class="dpt-chart"
 | 
				
			||||||
 | 
					          [datasets]="chart"
 | 
				
			||||||
 | 
					          [labels]="[]"
 | 
				
			||||||
 | 
					          [options]="chartOptions"
 | 
				
			||||||
 | 
					          [legend]="false"
 | 
				
			||||||
 | 
					          chartType="scatter">
 | 
				
			||||||
 | 
					  </canvas>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
							
								
								
									
										4
									
								
								src/app/prediction/prediction.component.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					.dpt-chart {
 | 
				
			||||||
 | 
					  max-width: 800px;
 | 
				
			||||||
 | 
					  margin: 0 auto;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										44
									
								
								src/app/prediction/prediction.component.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,44 @@
 | 
				
			|||||||
 | 
					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';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let apiServiceSpy: jasmine.SpyObj<ApiService>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe('PredictionComponent', () => {
 | 
				
			||||||
 | 
					  let component: PredictionComponent;
 | 
				
			||||||
 | 
					  let fixture: ComponentFixture<PredictionComponent>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  beforeEach(async(() => {
 | 
				
			||||||
 | 
					    const apiSpy = jasmine.createSpyObj('ApiService', ['post']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    TestBed.configureTestingModule({
 | 
				
			||||||
 | 
					      declarations: [ PredictionComponent ],
 | 
				
			||||||
 | 
					      imports: [
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					      providers: [
 | 
				
			||||||
 | 
					        {provide: ApiService, useValue: apiSpy}
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .compileComponents();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    apiServiceSpy = TestBed.inject(ApiService) as jasmine.SpyObj<ApiService>;
 | 
				
			||||||
 | 
					  }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  beforeEach(() => {
 | 
				
			||||||
 | 
					    fixture = TestBed.createComponent(PredictionComponent);
 | 
				
			||||||
 | 
					    component = fixture.componentInstance;
 | 
				
			||||||
 | 
					    component.ngOnInit();
 | 
				
			||||||
 | 
					    fixture.detectChanges();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should create', () => {
 | 
				
			||||||
 | 
					    expect(component).toBeTruthy();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
							
								
								
									
										74
									
								
								src/app/prediction/prediction.component.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,74 @@
 | 
				
			|||||||
 | 
					import { Component, OnInit } from '@angular/core';
 | 
				
			||||||
 | 
					import {ChartOptions} from 'chart.js';
 | 
				
			||||||
 | 
					import {ApiService} from '../services/api.service';
 | 
				
			||||||
 | 
					import {animate, style, transition, trigger} from '@angular/animations';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Component({
 | 
				
			||||||
 | 
					  selector: 'app-prediction',
 | 
				
			||||||
 | 
					  templateUrl: './prediction.component.html',
 | 
				
			||||||
 | 
					  styleUrls: ['./prediction.component.scss'],
 | 
				
			||||||
 | 
					  animations: [
 | 
				
			||||||
 | 
					    trigger(
 | 
				
			||||||
 | 
					      'inOut', [
 | 
				
			||||||
 | 
					        transition(':enter', [
 | 
				
			||||||
 | 
					          style({height: 0, opacity: 0}),
 | 
				
			||||||
 | 
					          animate('0.5s ease-out', style({height: '*', opacity: 1}))
 | 
				
			||||||
 | 
					        ]),
 | 
				
			||||||
 | 
					        transition(':leave', [
 | 
				
			||||||
 | 
					          style({height: '*', opacity: 1}),
 | 
				
			||||||
 | 
					          animate('0.5s ease-in', style({height: 0, opacity: 0}))
 | 
				
			||||||
 | 
					        ])
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					  ]
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class PredictionComponent implements OnInit {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  readonly predictionUrl = 'https://definma-model-test.apps.de1.bosch-iot-cloud.com/predict';
 | 
				
			||||||
 | 
					  result = '';
 | 
				
			||||||
 | 
					  loading = false;
 | 
				
			||||||
 | 
					  spectrum: string[][] = [[]];
 | 
				
			||||||
 | 
					  chart = [{
 | 
				
			||||||
 | 
					    data: [],
 | 
				
			||||||
 | 
					    label: 'Spectrum',
 | 
				
			||||||
 | 
					    showLine: true,
 | 
				
			||||||
 | 
					    fill: false,
 | 
				
			||||||
 | 
					    pointRadius: 0,
 | 
				
			||||||
 | 
					    borderColor: '#00a8b0',
 | 
				
			||||||
 | 
					    borderWidth: 2
 | 
				
			||||||
 | 
					  }];
 | 
				
			||||||
 | 
					  readonly chartOptions: ChartOptions = {
 | 
				
			||||||
 | 
					    scales: {
 | 
				
			||||||
 | 
					      xAxes: [{ticks: {min: 400, max: 4000, stepSize: 400, reverse: true}}],
 | 
				
			||||||
 | 
					      yAxes: [{ticks: {min: 0, max: 1}}]
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    responsive: true,
 | 
				
			||||||
 | 
					    tooltips: {enabled: false},
 | 
				
			||||||
 | 
					    hover: {mode: null},
 | 
				
			||||||
 | 
					    maintainAspectRatio: true,
 | 
				
			||||||
 | 
					    plugins: {datalabels: {display: false}}
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  constructor(
 | 
				
			||||||
 | 
					    private api: ApiService
 | 
				
			||||||
 | 
					  ) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ngOnInit(): void {
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fileToArray(files) {
 | 
				
			||||||
 | 
					    const fileReader = new FileReader();
 | 
				
			||||||
 | 
					    fileReader.onload = () => {
 | 
				
			||||||
 | 
					      this.spectrum = fileReader.result.toString().split('\r\n').map(e => e.split(','));
 | 
				
			||||||
 | 
					      this.loading = true;
 | 
				
			||||||
 | 
					      this.api.post<{result: string}>(this.predictionUrl, this.spectrum, data => {
 | 
				
			||||||
 | 
					        this.result = data.result;
 | 
				
			||||||
 | 
					        this.loading = false;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      this.chart[0].data = this.spectrum.map(e => ({x: parseFloat(e[0]), y: parseFloat(e[1])}));
 | 
				
			||||||
 | 
					      console.log(this.chart);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    fileReader.readAsText(files[0]);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -2,6 +2,8 @@ import { TestBed } from '@angular/core/testing';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { ArrayInputHelperService } from './array-input-helper.service';
 | 
					import { ArrayInputHelperService } from './array-input-helper.service';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TOdo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe('ArrayInputHelperService', () => {
 | 
					describe('ArrayInputHelperService', () => {
 | 
				
			||||||
  let service: ArrayInputHelperService;
 | 
					  let service: ArrayInputHelperService;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,6 +16,7 @@ describe('RbArrayInputComponent', () => {
 | 
				
			|||||||
  beforeEach(() => {
 | 
					  beforeEach(() => {
 | 
				
			||||||
    fixture = TestBed.createComponent(RbArrayInputComponent);
 | 
					    fixture = TestBed.createComponent(RbArrayInputComponent);
 | 
				
			||||||
    component = fixture.componentInstance;
 | 
					    component = fixture.componentInstance;
 | 
				
			||||||
 | 
					    component.ngOnInit();
 | 
				
			||||||
    fixture.detectChanges();
 | 
					    fixture.detectChanges();
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,6 +2,8 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { RbIconButtonComponent } from './rb-icon-button.component';
 | 
					import { RbIconButtonComponent } from './rb-icon-button.component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe('RbIconButtonComponent', () => {
 | 
					describe('RbIconButtonComponent', () => {
 | 
				
			||||||
  let component: RbIconButtonComponent;
 | 
					  let component: RbIconButtonComponent;
 | 
				
			||||||
  let fixture: ComponentFixture<RbIconButtonComponent>;
 | 
					  let fixture: ComponentFixture<RbIconButtonComponent>;
 | 
				
			||||||
@@ -16,6 +18,7 @@ describe('RbIconButtonComponent', () => {
 | 
				
			|||||||
  beforeEach(() => {
 | 
					  beforeEach(() => {
 | 
				
			||||||
    fixture = TestBed.createComponent(RbIconButtonComponent);
 | 
					    fixture = TestBed.createComponent(RbIconButtonComponent);
 | 
				
			||||||
    component = fixture.componentInstance;
 | 
					    component = fixture.componentInstance;
 | 
				
			||||||
 | 
					    component.ngOnInit();
 | 
				
			||||||
    fixture.detectChanges();
 | 
					    fixture.detectChanges();
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,5 +34,6 @@ table.ellipsis {
 | 
				
			|||||||
    white-space: nowrap;
 | 
					    white-space: nowrap;
 | 
				
			||||||
    overflow: hidden;
 | 
					    overflow: hidden;
 | 
				
			||||||
    max-width: 200px;
 | 
					    max-width: 200px;
 | 
				
			||||||
 | 
					    //min-width: 100px;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,6 +2,8 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { RbTableComponent } from './rb-table.component';
 | 
					import { RbTableComponent } from './rb-table.component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe('RbTableComponent', () => {
 | 
					describe('RbTableComponent', () => {
 | 
				
			||||||
  let component: RbTableComponent;
 | 
					  let component: RbTableComponent;
 | 
				
			||||||
  let fixture: ComponentFixture<RbTableComponent>;
 | 
					  let fixture: ComponentFixture<RbTableComponent>;
 | 
				
			||||||
@@ -16,6 +18,7 @@ describe('RbTableComponent', () => {
 | 
				
			|||||||
  beforeEach(() => {
 | 
					  beforeEach(() => {
 | 
				
			||||||
    fixture = TestBed.createComponent(RbTableComponent);
 | 
					    fixture = TestBed.createComponent(RbTableComponent);
 | 
				
			||||||
    component = fixture.componentInstance;
 | 
					    component = fixture.componentInstance;
 | 
				
			||||||
 | 
					    component.ngOnInit();
 | 
				
			||||||
    fixture.detectChanges();
 | 
					    fixture.detectChanges();
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
<script src="../models/template.model.ts"></script><h2>{{new ? 'Add new sample' : 'Edit sample ' + sample.number}}</h2>
 | 
					<h2>{{new ? 'Add new sample' : 'Edit sample ' + sample.number}}</h2>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<rb-loading-spinner *ngIf="loading"></rb-loading-spinner>
 | 
					<rb-loading-spinner *ngIf="loading"></rb-loading-spinner>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,27 +1,70 @@
 | 
				
			|||||||
// import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 | 
					import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 | 
				
			||||||
//
 | 
					
 | 
				
			||||||
// import { SampleComponent } from './sample.component';
 | 
					import { SampleComponent } from './sample.component';
 | 
				
			||||||
//
 | 
					import {ApiService} from '../services/api.service';
 | 
				
			||||||
// // TODO: tests
 | 
					import {ValidationService} from '../services/validation.service';
 | 
				
			||||||
//
 | 
					import {DataService} from '../services/data.service';
 | 
				
			||||||
// describe('SampleComponent', () => {
 | 
					import {ModalService, RbUiComponentsModule} from '@inst-iot/bosch-angular-ui-components';
 | 
				
			||||||
//   let component: SampleComponent;
 | 
					import {FormsModule} from '@angular/forms';
 | 
				
			||||||
//   let fixture: ComponentFixture<SampleComponent>;
 | 
					import {ActivatedRoute, Router} from '@angular/router';
 | 
				
			||||||
//
 | 
					import {AutocompleteService} from '../services/autocomplete.service';
 | 
				
			||||||
//   beforeEach(async(() => {
 | 
					
 | 
				
			||||||
//     TestBed.configureTestingModule({
 | 
					// TODO
 | 
				
			||||||
//       declarations: [ SampleComponent ]
 | 
					
 | 
				
			||||||
//     })
 | 
					let routerServiceSpy: jasmine.SpyObj<Router>;
 | 
				
			||||||
//     .compileComponents();
 | 
					let activatedRouteServiceSpy: jasmine.SpyObj<ActivatedRoute>;
 | 
				
			||||||
//   }));
 | 
					let apiServiceSpy: jasmine.SpyObj<ApiService>;
 | 
				
			||||||
//
 | 
					let validationServiceSpy: jasmine.SpyObj<ValidationService>;
 | 
				
			||||||
//   beforeEach(() => {
 | 
					let autocompleteServiceSpy: jasmine.SpyObj<AutocompleteService>;
 | 
				
			||||||
//     fixture = TestBed.createComponent(SampleComponent);
 | 
					let modalServiceSpy: jasmine.SpyObj<ModalService>;
 | 
				
			||||||
//     component = fixture.componentInstance;
 | 
					let dataServiceSpy: jasmine.SpyObj<DataService>;
 | 
				
			||||||
//     fixture.detectChanges();
 | 
					
 | 
				
			||||||
//   });
 | 
					describe('SampleComponent', () => {
 | 
				
			||||||
//
 | 
					  let component: SampleComponent;
 | 
				
			||||||
//   it('should create', () => {
 | 
					  let fixture: ComponentFixture<SampleComponent>;
 | 
				
			||||||
//     expect(component).toBeTruthy();
 | 
					
 | 
				
			||||||
//   });
 | 
					  beforeEach(async(() => {
 | 
				
			||||||
// });
 | 
					    const routerSpy = jasmine.createSpyObj('Router', ['navigate']);
 | 
				
			||||||
 | 
					    const activatedRouteSpy = jasmine.createSpyObj('ActivatedRoute', ['snapshot']);
 | 
				
			||||||
 | 
					    const apiSpy = jasmine.createSpyObj('ApiService', ['post', 'put']);
 | 
				
			||||||
 | 
					    const validationSpy = jasmine.createSpyObj('ValidationService', ['generate']);
 | 
				
			||||||
 | 
					    const autocompleteSpy = jasmine.createSpyObj('AutocompleteService', []);
 | 
				
			||||||
 | 
					    const modalSpy = jasmine.createSpyObj('ModalService', ['open']);
 | 
				
			||||||
 | 
					    const dataSpy = jasmine.createSpyObj('DataService', ['load', 'idReload']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    TestBed.configureTestingModule({
 | 
				
			||||||
 | 
					      declarations: [ SampleComponent ],
 | 
				
			||||||
 | 
					      imports: [
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					      providers: [
 | 
				
			||||||
 | 
					        {provide: Router, useValue: routerSpy},
 | 
				
			||||||
 | 
					        {provide: ActivatedRoute, useValue: activatedRouteSpy},
 | 
				
			||||||
 | 
					        {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<Router>;
 | 
				
			||||||
 | 
					    activatedRouteServiceSpy = TestBed.inject(ActivatedRoute) as jasmine.SpyObj<ActivatedRoute>;
 | 
				
			||||||
 | 
					    apiServiceSpy = TestBed.inject(ApiService) as jasmine.SpyObj<ApiService>;
 | 
				
			||||||
 | 
					    validationServiceSpy = TestBed.inject(ValidationService) as jasmine.SpyObj<ValidationService>;
 | 
				
			||||||
 | 
					    autocompleteServiceSpy = TestBed.inject(AutocompleteService) as jasmine.SpyObj<AutocompleteService>;
 | 
				
			||||||
 | 
					    modalServiceSpy = TestBed.inject(ModalService) as jasmine.SpyObj<ModalService>;
 | 
				
			||||||
 | 
					    dataServiceSpy = TestBed.inject(DataService) as jasmine.SpyObj<DataService>;
 | 
				
			||||||
 | 
					  }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  beforeEach(() => {
 | 
				
			||||||
 | 
					    fixture = TestBed.createComponent(SampleComponent);
 | 
				
			||||||
 | 
					    component = fixture.componentInstance;
 | 
				
			||||||
 | 
					    component.ngOnInit();
 | 
				
			||||||
 | 
					    fixture.detectChanges();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should create', () => {
 | 
				
			||||||
 | 
					    expect(component).toBeTruthy();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,10 +22,6 @@ import {Observable} from 'rxjs';
 | 
				
			|||||||
import {ModalService} from '@inst-iot/bosch-angular-ui-components';
 | 
					import {ModalService} from '@inst-iot/bosch-angular-ui-components';
 | 
				
			||||||
import {DataService} from '../services/data.service';
 | 
					import {DataService} from '../services/data.service';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO: clean up this mess !!!
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// TODO: only show condition (if not set) and measurements in edit sample dialog at first
 | 
					 | 
				
			||||||
// TODO: multiple samples for base data, extend multiple measurements, conditions
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Component({
 | 
					@Component({
 | 
				
			||||||
  selector: 'app-sample',
 | 
					  selector: 'app-sample',
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -73,7 +73,7 @@
 | 
				
			|||||||
                              (ngModelChange)="updateFilterFields(filter.field)">
 | 
					                              (ngModelChange)="updateFilterFields(filter.field)">
 | 
				
			||||||
                <ng-container *rbArrayInputItem="let item"
 | 
					                <ng-container *rbArrayInputItem="let item"
 | 
				
			||||||
                              [ngSwitch]="(filter.autocomplete.length ? 'autocomplete' : '') +
 | 
					                              [ngSwitch]="(filter.autocomplete.length ? 'autocomplete' : '') +
 | 
				
			||||||
                              (filter.field == 'added' ? 'date' : '')">
 | 
					                              (filter.field == 'added' ? 'date' : (filter.field == 'type' ? 'type' : ''))">
 | 
				
			||||||
                  <rb-form-date-input *ngSwitchCase="'date'" [rbArrayInputListener]="'filter-' + filter.field"
 | 
					                  <rb-form-date-input *ngSwitchCase="'date'" [rbArrayInputListener]="'filter-' + filter.field"
 | 
				
			||||||
                                      [name]="'filter-' + filter.field + item.i" [index]="item.i"
 | 
					                                      [name]="'filter-' + filter.field + item.i" [index]="item.i"
 | 
				
			||||||
                                      [label]="filter.label" [(ngModel)]="item.value"></rb-form-date-input>
 | 
					                                      [label]="filter.label" [(ngModel)]="item.value"></rb-form-date-input>
 | 
				
			||||||
@@ -86,6 +86,12 @@
 | 
				
			|||||||
                                 [rbDebounceTime]="0" (keydown)="preventDefault($event, 'Enter')"
 | 
					                                 [rbDebounceTime]="0" (keydown)="preventDefault($event, 'Enter')"
 | 
				
			||||||
                                 [rbFormInputAutocomplete]="autocomplete.bind(this, filter.autocomplete)"
 | 
					                                 [rbFormInputAutocomplete]="autocomplete.bind(this, filter.autocomplete)"
 | 
				
			||||||
                                 ngModel></rb-form-input>
 | 
					                                 ngModel></rb-form-input>
 | 
				
			||||||
 | 
					                  <rb-form-select *ngSwitchCase="'type'" [rbArrayInputListener]="'filter-' + filter.field"
 | 
				
			||||||
 | 
					                                  [name]="'filter-' + filter.field + item.i" [index]="item.i"
 | 
				
			||||||
 | 
					                                  [label]="filter.label" [(ngModel)]="item.value">
 | 
				
			||||||
 | 
					                    <option value="as-delivered/raw">as-delivered/raw</option>
 | 
				
			||||||
 | 
					                    <option value="processed">processed</option>
 | 
				
			||||||
 | 
					                  </rb-form-select>
 | 
				
			||||||
                </ng-container>
 | 
					                </ng-container>
 | 
				
			||||||
              </rb-array-input>
 | 
					              </rb-array-input>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
@@ -132,17 +138,17 @@
 | 
				
			|||||||
    <th *ngIf="validation">
 | 
					    <th *ngIf="validation">
 | 
				
			||||||
      <rb-form-checkbox name="validate-all" (change)="selectAll($event)">all</rb-form-checkbox>
 | 
					      <rb-form-checkbox name="validate-all" (change)="selectAll($event)">all</rb-form-checkbox>
 | 
				
			||||||
    </th>
 | 
					    </th>
 | 
				
			||||||
    <th *ngFor="let key of activeKeys">
 | 
					    <th *ngFor="let key of activeKeys" [title]="key.label">
 | 
				
			||||||
      <div class="sort-header">
 | 
					      <div class="sort-header">
 | 
				
			||||||
        <span>{{key.label}}</span>
 | 
					        <span>{{key.label}}</span>
 | 
				
			||||||
        <ng-container *ngIf="key.sortable">
 | 
					        <div *ngIf="key.sortable">
 | 
				
			||||||
          <span class="rb-ic rb-ic-up sort-arr-up" (click)="setSort(key.id + '-' + 'desc')">
 | 
					          <span class="rb-ic rb-ic-up sort-arr-up" (click)="setSort(key.id + '-' + 'desc')">
 | 
				
			||||||
            <span *ngIf="filters.sort === key.id + '-' + 'desc'"></span>
 | 
					            <span *ngIf="filters.sort === key.id + '-' + 'desc'"></span>
 | 
				
			||||||
          </span>
 | 
					          </span>
 | 
				
			||||||
          <span class="rb-ic rb-ic-down sort-arr-down" (click)="setSort(key.id + '-' + 'asc')">
 | 
					          <span class="rb-ic rb-ic-down sort-arr-down" (click)="setSort(key.id + '-' + 'asc')">
 | 
				
			||||||
            <span *ngIf="filters.sort === key.id + '-' + 'asc'"></span>
 | 
					            <span *ngIf="filters.sort === key.id + '-' + 'asc'"></span>
 | 
				
			||||||
          </span>
 | 
					          </span>
 | 
				
			||||||
        </ng-container>
 | 
					        </div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </th>
 | 
					    </th>
 | 
				
			||||||
    <th *ngIf="login.isLevel.write"></th>
 | 
					    <th *ngIf="login.isLevel.write"></th>
 | 
				
			||||||
@@ -165,6 +171,9 @@
 | 
				
			|||||||
    <td *ngIf="isActiveKey['type']">{{sample.type}}</td>
 | 
					    <td *ngIf="isActiveKey['type']">{{sample.type}}</td>
 | 
				
			||||||
    <td *ngIf="isActiveKey['color']">{{sample.color}}</td>
 | 
					    <td *ngIf="isActiveKey['color']">{{sample.color}}</td>
 | 
				
			||||||
    <td *ngIf="isActiveKey['batch']">{{sample.batch}}</td>
 | 
					    <td *ngIf="isActiveKey['batch']">{{sample.batch}}</td>
 | 
				
			||||||
 | 
					    <td *ngFor="let key of activeTemplateKeys.condition">
 | 
				
			||||||
 | 
					      {{sample.condition ? sample.condition[key[1]] : '' | exists}}
 | 
				
			||||||
 | 
					    </td>
 | 
				
			||||||
    <td *ngIf="isActiveKey['notes']">{{sample.notes | object: ['_id', 'sample_references']}}</td>
 | 
					    <td *ngIf="isActiveKey['notes']">{{sample.notes | object: ['_id', 'sample_references']}}</td>
 | 
				
			||||||
    <td *ngFor="let key of activeTemplateKeys.measurements">{{sample[key[1]] | exists: key[2]}}</td>
 | 
					    <td *ngFor="let key of activeTemplateKeys.measurements">{{sample[key[1]] | exists: key[2]}}</td>
 | 
				
			||||||
    <td *ngIf="isActiveKey['status']">{{sample.status}}</td>
 | 
					    <td *ngIf="isActiveKey['status']">{{sample.status}}</td>
 | 
				
			||||||
@@ -188,7 +197,7 @@
 | 
				
			|||||||
    <button class="rb-btn rb-link" type="button" (click)="loadPage(-1)" [disabled]="page === 1">
 | 
					    <button class="rb-btn rb-link" type="button" (click)="loadPage(-1)" [disabled]="page === 1">
 | 
				
			||||||
      <span class="rb-ic  rb-ic-back-left"></span>
 | 
					      <span class="rb-ic  rb-ic-back-left"></span>
 | 
				
			||||||
    </button>
 | 
					    </button>
 | 
				
			||||||
    <rb-form-input label="page" (change)="loadPage({toPage: $event.target.value - page})" [ngModel]="page">
 | 
					    <rb-form-input label="page" (ngModelChange)="loadPage($event - page)" [ngModel]="page">
 | 
				
			||||||
    </rb-form-input>
 | 
					    </rb-form-input>
 | 
				
			||||||
    <span>
 | 
					    <span>
 | 
				
			||||||
      of {{pages}} ({{totalSamples}} samples)
 | 
					      of {{pages}} ({{totalSamples}} samples)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -54,7 +54,7 @@ rb-table {
 | 
				
			|||||||
.paging {
 | 
					.paging {
 | 
				
			||||||
  height: 50px;
 | 
					  height: 50px;
 | 
				
			||||||
  rb-form-input {
 | 
					  rb-form-input {
 | 
				
			||||||
    max-width: 50px;
 | 
					    max-width: 65px;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  > * {
 | 
					  > * {
 | 
				
			||||||
@@ -72,24 +72,35 @@ rb-table {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.sort-header {
 | 
					.sort-header {
 | 
				
			||||||
  display: inline-grid;
 | 
					 | 
				
			||||||
  grid-template-columns: 1fr auto;
 | 
					 | 
				
			||||||
  grid-column-gap: 5px;
 | 
					 | 
				
			||||||
  width: 100%;
 | 
					  width: 100%;
 | 
				
			||||||
 | 
					  position: relative;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  :first-child {
 | 
					  & > span:first-child {
 | 
				
			||||||
    grid-row: span 2;
 | 
					    max-width: 180px;
 | 
				
			||||||
 | 
					    overflow: hidden;
 | 
				
			||||||
 | 
					    display: block;
 | 
				
			||||||
 | 
					    text-overflow: ellipsis;
 | 
				
			||||||
 | 
					    margin-right: 20px;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  :nth-child(2) {
 | 
					  div {
 | 
				
			||||||
 | 
					    display: grid;
 | 
				
			||||||
 | 
					    grid-template-columns: 1fr;
 | 
				
			||||||
 | 
					    position: absolute;
 | 
				
			||||||
 | 
					    right: 0;
 | 
				
			||||||
 | 
					    top: 0;
 | 
				
			||||||
 | 
					    background: #FFF;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    :nth-child(1) {
 | 
				
			||||||
      margin-bottom: -3px;
 | 
					      margin-bottom: -3px;
 | 
				
			||||||
      cursor: pointer;
 | 
					      cursor: pointer;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  :nth-child(3) {
 | 
					    :nth-child(2) {
 | 
				
			||||||
      margin-top: -3px;
 | 
					      margin-top: -3px;
 | 
				
			||||||
      cursor: pointer;
 | 
					      cursor: pointer;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.sort-active-asc {
 | 
					.sort-active-asc {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,27 +1,72 @@
 | 
				
			|||||||
// import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 | 
					import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 | 
				
			||||||
//
 | 
					
 | 
				
			||||||
// import { SamplesComponent } from './samples.component';
 | 
					import { SamplesComponent } from './samples.component';
 | 
				
			||||||
//
 | 
					import {ApiService} from '../services/api.service';
 | 
				
			||||||
// // TODO: tests
 | 
					import {AutocompleteService} from '../services/autocomplete.service';
 | 
				
			||||||
//
 | 
					import {DataService} from '../services/data.service';
 | 
				
			||||||
// describe('SamplesComponent', () => {
 | 
					import {LoginService} from '../services/login.service';
 | 
				
			||||||
//   let component: SamplesComponent;
 | 
					import {LocalStorageService} from 'angular-2-local-storage';
 | 
				
			||||||
//   let fixture: ComponentFixture<SamplesComponent>;
 | 
					import {ModalService} from '@inst-iot/bosch-angular-ui-components';
 | 
				
			||||||
//
 | 
					import {ValidationService} from '../services/validation.service';
 | 
				
			||||||
//   beforeEach(async(() => {
 | 
					
 | 
				
			||||||
//     TestBed.configureTestingModule({
 | 
					// TODO
 | 
				
			||||||
//       declarations: [ SamplesComponent ]
 | 
					
 | 
				
			||||||
//     })
 | 
					let apiServiceSpy: jasmine.SpyObj<ApiService>;
 | 
				
			||||||
//     .compileComponents();
 | 
					let autocompleteServiceSpy: jasmine.SpyObj<AutocompleteService>;
 | 
				
			||||||
//   }));
 | 
					let modalServiceSpy: jasmine.SpyObj<ModalService>;
 | 
				
			||||||
//
 | 
					let dataServiceSpy: jasmine.SpyObj<DataService>;
 | 
				
			||||||
//   beforeEach(() => {
 | 
					let loginServiceSpy: jasmine.SpyObj<LoginService>;
 | 
				
			||||||
//     fixture = TestBed.createComponent(SamplesComponent);
 | 
					let localStorageServiceSpy: jasmine.SpyObj<LocalStorageService>;
 | 
				
			||||||
//     component = fixture.componentInstance;
 | 
					let windowServiceSpy: jasmine.SpyObj<Window>;
 | 
				
			||||||
//     fixture.detectChanges();
 | 
					
 | 
				
			||||||
//   });
 | 
					
 | 
				
			||||||
//
 | 
					
 | 
				
			||||||
//   it('should create', () => {
 | 
					describe('SamplesComponent', () => {
 | 
				
			||||||
//     expect(component).toBeTruthy();
 | 
					  let component: SamplesComponent;
 | 
				
			||||||
//   });
 | 
					  let fixture: ComponentFixture<SamplesComponent>;
 | 
				
			||||||
// });
 | 
					
 | 
				
			||||||
 | 
					  beforeEach(async(() => {
 | 
				
			||||||
 | 
					    const apiSpy = jasmine.createSpyObj('ApiService', ['post', 'put']);
 | 
				
			||||||
 | 
					    const autocompleteSpy = jasmine.createSpyObj('AutocompleteService', []);
 | 
				
			||||||
 | 
					    const loginSpy = jasmine.createSpyObj('LoginService', ['login', 'canActivate']);
 | 
				
			||||||
 | 
					    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', []);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    TestBed.configureTestingModule({
 | 
				
			||||||
 | 
					      declarations: [ SamplesComponent ],
 | 
				
			||||||
 | 
					      imports: [
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					      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<ApiService>;
 | 
				
			||||||
 | 
					    autocompleteServiceSpy = TestBed.inject(AutocompleteService) as jasmine.SpyObj<AutocompleteService>;
 | 
				
			||||||
 | 
					    modalServiceSpy = TestBed.inject(ModalService) as jasmine.SpyObj<ModalService>;
 | 
				
			||||||
 | 
					    dataServiceSpy = TestBed.inject(DataService) as jasmine.SpyObj<DataService>;
 | 
				
			||||||
 | 
					    loginServiceSpy = TestBed.inject(LoginService) as jasmine.SpyObj<LoginService>;
 | 
				
			||||||
 | 
					    localStorageServiceSpy = TestBed.inject(LocalStorageService) as jasmine.SpyObj<LocalStorageService>;
 | 
				
			||||||
 | 
					    windowServiceSpy = TestBed.inject(Window) as jasmine.SpyObj<Window>;
 | 
				
			||||||
 | 
					  }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  beforeEach(() => {
 | 
				
			||||||
 | 
					    fixture = TestBed.createComponent(SamplesComponent);
 | 
				
			||||||
 | 
					    component = fixture.componentInstance;
 | 
				
			||||||
 | 
					    component.ngOnInit();
 | 
				
			||||||
 | 
					    fixture.detectChanges();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should create', () => {
 | 
				
			||||||
 | 
					    expect(component).toBeTruthy();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,9 @@ import {SampleModel} from '../models/sample.model';
 | 
				
			|||||||
import {LoginService} from '../services/login.service';
 | 
					import {LoginService} from '../services/login.service';
 | 
				
			||||||
import {ModalService} from '@inst-iot/bosch-angular-ui-components';
 | 
					import {ModalService} from '@inst-iot/bosch-angular-ui-components';
 | 
				
			||||||
import {DataService} from '../services/data.service';
 | 
					import {DataService} from '../services/data.service';
 | 
				
			||||||
 | 
					import {LocalStorageService} from 'angular-2-local-storage';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO: turn off sort field
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface LoadSamplesOptions {
 | 
					interface LoadSamplesOptions {
 | 
				
			||||||
@@ -28,8 +31,6 @@ interface KeyInterface {
 | 
				
			|||||||
  styleUrls: ['./samples.component.scss']
 | 
					  styleUrls: ['./samples.component.scss']
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO: save last settings
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export class SamplesComponent implements OnInit {
 | 
					export class SamplesComponent implements OnInit {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @ViewChild('pageSizeSelection') pageSizeSelection: ElementRef<HTMLElement>;
 | 
					  @ViewChild('pageSizeSelection') pageSizeSelection: ElementRef<HTMLElement>;
 | 
				
			||||||
@@ -79,7 +80,7 @@ export class SamplesComponent implements OnInit {
 | 
				
			|||||||
  ];
 | 
					  ];
 | 
				
			||||||
  isActiveKey: {[key: string]: boolean} = {};
 | 
					  isActiveKey: {[key: string]: boolean} = {};
 | 
				
			||||||
  activeKeys: KeyInterface[] = [];
 | 
					  activeKeys: KeyInterface[] = [];
 | 
				
			||||||
  activeTemplateKeys = {material: [], measurements: []};
 | 
					  activeTemplateKeys = {material: [], condition: [], measurements: []};
 | 
				
			||||||
  sampleDetailsSample: any = null;
 | 
					  sampleDetailsSample: any = null;
 | 
				
			||||||
  validation = false;  // true to activate validation mode
 | 
					  validation = false;  // true to activate validation mode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -89,29 +90,41 @@ export class SamplesComponent implements OnInit {
 | 
				
			|||||||
    public autocomplete: AutocompleteService,
 | 
					    public autocomplete: AutocompleteService,
 | 
				
			||||||
    public login: LoginService,
 | 
					    public login: LoginService,
 | 
				
			||||||
    private modalService: ModalService,
 | 
					    private modalService: ModalService,
 | 
				
			||||||
    public d: DataService
 | 
					    public d: DataService,
 | 
				
			||||||
 | 
					    private storage: LocalStorageService,
 | 
				
			||||||
 | 
					    private window: Window
 | 
				
			||||||
  ) {
 | 
					  ) {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ngOnInit(): void {
 | 
					  ngOnInit(): void {
 | 
				
			||||||
 | 
					    let loading = 8;
 | 
				
			||||||
 | 
					    const onLoad = () => {
 | 
				
			||||||
 | 
					      if ((--loading) <= 0) {
 | 
				
			||||||
 | 
					        this.loadSamples();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.calcFieldSelectKeys();
 | 
					    this.calcFieldSelectKeys();
 | 
				
			||||||
    this.d.load('materials', () => {
 | 
					    this.d.load('materials', () => {
 | 
				
			||||||
      this.filters.filters.find(e => e.field === 'material.name').autocomplete = this.d.arr.materials.map(e => e.name);
 | 
					      this.filters.filters.find(e => e.field === 'material.name').autocomplete = this.d.arr.materials.map(e => e.name);
 | 
				
			||||||
      this.loadSamples();
 | 
					      onLoad();
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    this.d.load('materialSuppliers', () => {
 | 
					    this.d.load('materialSuppliers', () => {
 | 
				
			||||||
      this.filters.filters.find(e => e.field === 'material.supplier').autocomplete = this.d.arr.materialSuppliers;
 | 
					      this.filters.filters.find(e => e.field === 'material.supplier').autocomplete = this.d.arr.materialSuppliers;
 | 
				
			||||||
 | 
					      onLoad();
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    this.d.load('materialGroups', () => {
 | 
					    this.d.load('materialGroups', () => {
 | 
				
			||||||
      this.filters.filters.find(e => e.field === 'material.group').autocomplete = this.d.arr.materialGroups;
 | 
					      this.filters.filters.find(e => e.field === 'material.group').autocomplete = this.d.arr.materialGroups;
 | 
				
			||||||
 | 
					      onLoad();
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    this.d.load('userKey');
 | 
					    this.d.load('userKey', onLoad);
 | 
				
			||||||
    this.d.load('conditionTemplates');
 | 
					    this.d.load('conditionTemplates', onLoad);
 | 
				
			||||||
    this.loadTemplateKeys('material', 'type');
 | 
					    this.loadTemplateKeys('material', 'type', onLoad);
 | 
				
			||||||
    this.loadTemplateKeys('measurement', 'status');
 | 
					    this.loadTemplateKeys('condition', 'notes', onLoad);
 | 
				
			||||||
 | 
					    this.loadTemplateKeys('measurement', 'status', onLoad);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  loadTemplateKeys(collection, insertBefore) {
 | 
					  loadTemplateKeys(collection, insertBefore, f) {
 | 
				
			||||||
    this.d.load(collection + 'Templates', () => {
 | 
					    this.d.load(collection + 'Templates', () => {
 | 
				
			||||||
      const templateKeys = [];
 | 
					      const templateKeys = [];
 | 
				
			||||||
      this.d.arr[collection + 'Templates'].forEach(item => {
 | 
					      this.d.arr[collection + 'Templates'].forEach(item => {
 | 
				
			||||||
@@ -119,15 +132,16 @@ export class SamplesComponent implements OnInit {
 | 
				
			|||||||
          const parameterName = encodeURIComponent(parameter.name);
 | 
					          const parameterName = encodeURIComponent(parameter.name);
 | 
				
			||||||
          // exclude spectrum and duplicates
 | 
					          // exclude spectrum and duplicates
 | 
				
			||||||
          if (parameter.name !== 'dpt' && !templateKeys.find(e => new RegExp('.' + parameterName + '$').test(e.id))) {
 | 
					          if (parameter.name !== 'dpt' && !templateKeys.find(e => new RegExp('.' + parameterName + '$').test(e.id))) {
 | 
				
			||||||
 | 
					            const collectionNames = {material: 'material.properties', condition: 'condition', measurement: 'measurements.' + item.name};
 | 
				
			||||||
            templateKeys.push({
 | 
					            templateKeys.push({
 | 
				
			||||||
              id: `${collection === 'material' ? 'material.properties' : collection + 's.' + item.name}.${parameterName}`,
 | 
					              id: `${collectionNames[collection]}.${parameterName}`,
 | 
				
			||||||
              label: `${this.ucFirst(item.name)} ${this.ucFirst(parameter.name)}`,
 | 
					              label: `${this.ucFirst(item.name)} ${parameter.name}`,
 | 
				
			||||||
              active: false,
 | 
					              active: false,
 | 
				
			||||||
              sortable: true
 | 
					              sortable: true
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
            this.filters.filters.push({
 | 
					            this.filters.filters.push({
 | 
				
			||||||
              field: `${collection === 'material' ? 'material.properties' : collection + 's.' + item.name}.${parameterName}`,
 | 
					              field: `${collectionNames[collection]}.${parameterName}`,
 | 
				
			||||||
              label: `${this.ucFirst(item.name)} ${this.ucFirst(parameter.name)}`,
 | 
					              label: `${this.ucFirst(item.name)} ${parameter.name}`,
 | 
				
			||||||
              active: false,
 | 
					              active: false,
 | 
				
			||||||
              autocomplete: [],
 | 
					              autocomplete: [],
 | 
				
			||||||
              mode: 'eq',
 | 
					              mode: 'eq',
 | 
				
			||||||
@@ -138,12 +152,13 @@ export class SamplesComponent implements OnInit {
 | 
				
			|||||||
      });
 | 
					      });
 | 
				
			||||||
      this.keys.splice(this.keys.findIndex(e => e.id === insertBefore), 0, ...templateKeys);
 | 
					      this.keys.splice(this.keys.findIndex(e => e.id === insertBefore), 0, ...templateKeys);
 | 
				
			||||||
      this.keys = [...this.keys];  // complete overwrite array to invoke update in rb-multiselect
 | 
					      this.keys = [...this.keys];  // complete overwrite array to invoke update in rb-multiselect
 | 
				
			||||||
      this.updateActiveKeys();
 | 
					      this.loadPreferences();
 | 
				
			||||||
      this.calcFieldSelectKeys();
 | 
					      f();
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  loadSamples(options: LoadSamplesOptions = {}, event = null) {  // set toPage to null to reload first page, queues calls
 | 
					  loadSamples(options: LoadSamplesOptions = {}, event = null) {  // set toPage to null to reload first page, queues calls
 | 
				
			||||||
 | 
					    console.log(this.isActiveKey);
 | 
				
			||||||
    if (event) {  // adjust active keys
 | 
					    if (event) {  // adjust active keys
 | 
				
			||||||
      this.keys.forEach(key => {
 | 
					      this.keys.forEach(key => {
 | 
				
			||||||
        if (event.hasOwnProperty(key.id)) {
 | 
					        if (event.hasOwnProperty(key.id)) {
 | 
				
			||||||
@@ -156,10 +171,16 @@ export class SamplesComponent implements OnInit {
 | 
				
			|||||||
    if (this.loadSamplesQueue.length <= 1) {  // nothing queued up
 | 
					    if (this.loadSamplesQueue.length <= 1) {  // nothing queued up
 | 
				
			||||||
      this.sampleLoader(this.loadSamplesQueue[0]);
 | 
					      this.sampleLoader(this.loadSamplesQueue[0]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    this.storePreferences();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private sampleLoader(options: LoadSamplesOptions) {  // actual loading of the sample, do not call directly
 | 
					  private sampleLoader(options: LoadSamplesOptions) {  // actual loading of the sample, do not call directly
 | 
				
			||||||
    this.api.get(this.sampleUrl({paging: true, pagingOptions: options}), (sData, ignore, headers) => {
 | 
					    this.api.get(this.sampleUrl({paging: true, pagingOptions: options}), (sData, err, headers) => {
 | 
				
			||||||
 | 
					      if (err) {
 | 
				
			||||||
 | 
					        this.storage.remove('samplesPreferences');
 | 
				
			||||||
 | 
					        this.api.requestError(err);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      else {
 | 
				
			||||||
        if (!options.toPage && headers['x-total-items']) {
 | 
					        if (!options.toPage && headers['x-total-items']) {
 | 
				
			||||||
          this.totalSamples = headers['x-total-items'];
 | 
					          this.totalSamples = headers['x-total-items'];
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -169,6 +190,7 @@ export class SamplesComponent implements OnInit {
 | 
				
			|||||||
        if (this.loadSamplesQueue.length > 0) {  // execute next queue item
 | 
					        if (this.loadSamplesQueue.length > 0) {  // execute next queue item
 | 
				
			||||||
          this.sampleLoader(this.loadSamplesQueue[0]);
 | 
					          this.sampleLoader(this.loadSamplesQueue[0]);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -206,7 +228,7 @@ export class SamplesComponent implements OnInit {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    this.keys.forEach(key => {
 | 
					    this.keys.forEach(key => {
 | 
				
			||||||
      // do not load material properties for table
 | 
					      // do not load material properties for table
 | 
				
			||||||
      if (key.active && (options.export || (!options.export && key.id.indexOf('material') < 0))) {
 | 
					      if (key.active && (options.export || (!options.export && key.id.indexOf('material.') < 0))) {
 | 
				
			||||||
        query.push('fields[]=' + key.id);
 | 
					        query.push('fields[]=' + key.id);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
@@ -243,12 +265,13 @@ export class SamplesComponent implements OnInit {
 | 
				
			|||||||
        query.push('fields[]=condition');
 | 
					        query.push('fields[]=condition');
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return (options.host && isDevMode() ? window.location.host : '') +
 | 
					    return (options.host && isDevMode() ? this.window.location.host : '') +
 | 
				
			||||||
      (options.export ? this.api.hostName : '') +
 | 
					      (options.export ? this.api.hostName : '') +
 | 
				
			||||||
      '/samples?' + query.join('&');
 | 
					      '/samples?' + query.join('&');
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  loadPage(delta) {
 | 
					  loadPage(delta) {
 | 
				
			||||||
 | 
					    console.log(delta);
 | 
				
			||||||
    if (!/[0-9]+/.test(delta) || (this.page <= 1 && delta < 0)) {  // invalid delta
 | 
					    if (!/[0-9]+/.test(delta) || (this.page <= 1 && delta < 0)) {  // invalid delta
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -256,6 +279,38 @@ export class SamplesComponent implements OnInit {
 | 
				
			|||||||
    this.loadSamples({toPage: delta});
 | 
					    this.loadSamples({toPage: delta});
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  storePreferences() {
 | 
				
			||||||
 | 
					    const store = {
 | 
				
			||||||
 | 
					      filters: {
 | 
				
			||||||
 | 
					        ...pick(this.filters, ['status', 'pageSize', 'toPage', 'sort']),
 | 
				
			||||||
 | 
					        filters: this.filters.filters.map(e => pick(e, ['field', 'active', 'mode', 'values']))
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      keys: this.keys.map(e => pick(e, ['id', 'active']))
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    this.storage.set('samplesPreferences', store);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  loadPreferences() {
 | 
				
			||||||
 | 
					    const store: any = this.storage.get('samplesPreferences');
 | 
				
			||||||
 | 
					    if (store) {
 | 
				
			||||||
 | 
					      this.filters = {...this.filters, ...pick(store.filters, ['status', 'pageSize', 'toPage', 'sort'])};
 | 
				
			||||||
 | 
					      store.filters.filters.forEach(filter => {
 | 
				
			||||||
 | 
					        const filterIndex = this.filters.filters.findIndex(e => e.field === filter.field);
 | 
				
			||||||
 | 
					        if (filterIndex >= 0) {
 | 
				
			||||||
 | 
					          this.filters.filters[filterIndex] = {...this.filters.filters[filterIndex], ...filter};
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      store.keys.forEach(key => {
 | 
				
			||||||
 | 
					        const keyIndex = this.keys.findIndex(e => e.id === key.id);
 | 
				
			||||||
 | 
					        if (keyIndex >= 0) {
 | 
				
			||||||
 | 
					          this.keys[keyIndex].active = key.active;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this.calcFieldSelectKeys();
 | 
				
			||||||
 | 
					    this.updateActiveKeys();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  updateFilterFields(field) {
 | 
					  updateFilterFields(field) {
 | 
				
			||||||
    const filter = this.filters.filters.find(e => e.field === field);
 | 
					    const filter = this.filters.filters.find(e => e.field === field);
 | 
				
			||||||
    filter.active = true;
 | 
					    filter.active = true;
 | 
				
			||||||
@@ -271,10 +326,18 @@ export class SamplesComponent implements OnInit {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  updateActiveKeys() {  // array with all activeKeys
 | 
					  updateActiveKeys() {  // array with all activeKeys
 | 
				
			||||||
    this.activeKeys = this.keys.filter(e => e.active);
 | 
					    this.activeKeys = this.keys.filter(e => e.active);
 | 
				
			||||||
 | 
					    this.filters.filters.forEach(filter => {
 | 
				
			||||||
 | 
					      if (!this.isActiveKey[filter.field]) {
 | 
				
			||||||
 | 
					        filter.active = false;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
    this.activeTemplateKeys.material = this.keys
 | 
					    this.activeTemplateKeys.material = this.keys
 | 
				
			||||||
      .filter(e => e.id.indexOf('material.properties.') >= 0 && e.active)
 | 
					      .filter(e => e.id.indexOf('material.properties.') >= 0 && e.active)
 | 
				
			||||||
      .map(e => e.id.split('.')
 | 
					      .map(e => e.id.split('.')
 | 
				
			||||||
        .map(el => decodeURIComponent(el)));
 | 
					        .map(el => decodeURIComponent(el)));
 | 
				
			||||||
 | 
					    this.activeTemplateKeys.condition = this.keys.filter(e => e.id.indexOf('condition.') >= 0 && e.active)
 | 
				
			||||||
 | 
					      .map(e => e.id.split('.')
 | 
				
			||||||
 | 
					        .map(el => decodeURIComponent(el)));
 | 
				
			||||||
    this.activeTemplateKeys.measurements = this.keys.filter(e => e.id.indexOf('measurements.') >= 0 && e.active)
 | 
					    this.activeTemplateKeys.measurements = this.keys.filter(e => e.id.indexOf('measurements.') >= 0 && e.active)
 | 
				
			||||||
      .map(e => e.id.split('.')
 | 
					      .map(e => e.id.split('.')
 | 
				
			||||||
        .map(el => decodeURIComponent(el)));
 | 
					        .map(el => decodeURIComponent(el)));
 | 
				
			||||||
@@ -390,4 +453,6 @@ export class SamplesComponent implements OnInit {
 | 
				
			|||||||
  ucFirst(string) {
 | 
					  ucFirst(string) {
 | 
				
			||||||
    return string[0].toUpperCase() + string.slice(1);
 | 
					    return string[0].toUpperCase() + string.slice(1);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,7 @@ let httpClientSpy: jasmine.SpyObj<HttpClient>;
 | 
				
			|||||||
let localStorageServiceSpy: jasmine.SpyObj<LocalStorageService>;
 | 
					let localStorageServiceSpy: jasmine.SpyObj<LocalStorageService>;
 | 
				
			||||||
let modalServiceSpy: jasmine.SpyObj<ModalService>;
 | 
					let modalServiceSpy: jasmine.SpyObj<ModalService>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO
 | 
				
			||||||
// TODO: test options
 | 
					// TODO: test options
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe('ApiService', () => {
 | 
					describe('ApiService', () => {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,29 +25,36 @@ export class ApiService {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  get<T>(url, f: (data?: T, err?, headers?) => void = () => {}) {
 | 
					  get<T>(url, f: (data?: T, err?, headers?) => void = () => {}) {
 | 
				
			||||||
    this.requestErrorHandler<T>(this.http.get(this.host + url, this.options()), f);
 | 
					    this.requestErrorHandler<T>(this.http.get(this.url(url), this.options()), f);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  post<T>(url, data = null, f: (data?: T, err?, headers?) => void = () => {}) {
 | 
					  post<T>(url, data = null, f: (data?: T, err?, headers?) => void = () => {}) {
 | 
				
			||||||
    this.requestErrorHandler<T>(this.http.post(this.host + url, data, this.options()), f);
 | 
					    this.requestErrorHandler<T>(this.http.post(this.url(url), data, this.options()), f);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  put<T>(url, data = null, f: (data?: T, err?, headers?) => void = () => {}) {
 | 
					  put<T>(url, data = null, f: (data?: T, err?, headers?) => void = () => {}) {
 | 
				
			||||||
    this.requestErrorHandler<T>(this.http.put(this.host + url, data, this.options()), f);
 | 
					    this.requestErrorHandler<T>(this.http.put(this.url(url), data, this.options()), f);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  delete<T>(url, f: (data?: T, err?, headers?) => void = () => {}) {
 | 
					  delete<T>(url, f: (data?: T, err?, headers?) => void = () => {}) {
 | 
				
			||||||
    this.requestErrorHandler<T>(this.http.delete(this.host + url, this.options()), f);
 | 
					    this.requestErrorHandler<T>(this.http.delete(this.url(url), this.options()), f);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private requestErrorHandler<T>(observable: Observable<any>, f: (data?: T, err?, headers?) => void) {
 | 
					  private requestErrorHandler<T>(observable: Observable<any>, f: (data?: T, err?, headers?) => void) {
 | 
				
			||||||
    observable.subscribe(data => {
 | 
					    observable.subscribe(data => {
 | 
				
			||||||
      f(data.body, undefined, data.headers.keys().reduce((s, e) => {s[e.toLowerCase()] = data.headers.get(e); return s; }, {}));
 | 
					      f(data.body, undefined, data.headers.keys().reduce((s, e) => {s[e.toLowerCase()] = data.headers.get(e); return s; }, {}));
 | 
				
			||||||
    }, err => {
 | 
					    }, err => {
 | 
				
			||||||
      if (f.length === 2) {
 | 
					      console.log(f.length);
 | 
				
			||||||
        f(undefined, err);
 | 
					      if (f.length > 1) {
 | 
				
			||||||
 | 
					        f(undefined, err, undefined);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      else {
 | 
					      else {
 | 
				
			||||||
 | 
					        this.requestError(err);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  requestError(err) {
 | 
				
			||||||
    const modalRef = this.modalService.openComponent(ErrorComponent);
 | 
					    const modalRef = this.modalService.openComponent(ErrorComponent);
 | 
				
			||||||
    modalRef.instance.message = 'Network request failed!';
 | 
					    modalRef.instance.message = 'Network request failed!';
 | 
				
			||||||
    const details = [err.error.status];
 | 
					    const details = [err.error.status];
 | 
				
			||||||
@@ -59,7 +66,14 @@ export class ApiService {
 | 
				
			|||||||
      this.window.location.reload();
 | 
					      this.window.location.reload();
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
    });
 | 
					
 | 
				
			||||||
 | 
					  private url(url) {
 | 
				
			||||||
 | 
					    if (/http[s]?:\/\//.test(url)) {
 | 
				
			||||||
 | 
					      return url;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					      return this.host + url;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private options(): {headers: HttpHeaders, observe: 'body'} {
 | 
					  private options(): {headers: HttpHeaders, observe: 'body'} {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,6 +2,8 @@ import { TestBed } from '@angular/core/testing';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { AutocompleteService } from './autocomplete.service';
 | 
					import { AutocompleteService } from './autocomplete.service';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let autocompleteService: AutocompleteService;
 | 
					let autocompleteService: AutocompleteService;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe('AutocompleteService', () => {
 | 
					describe('AutocompleteService', () => {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,13 +1,30 @@
 | 
				
			|||||||
import { TestBed } from '@angular/core/testing';
 | 
					import { TestBed } from '@angular/core/testing';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { DataService } from './data.service';
 | 
					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<ApiService>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe('DataService', () => {
 | 
					describe('DataService', () => {
 | 
				
			||||||
  let service: DataService;
 | 
					  let service: DataService;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  beforeEach(() => {
 | 
					  beforeEach(() => {
 | 
				
			||||||
    TestBed.configureTestingModule({});
 | 
					    const apiSpy = jasmine.createSpyObj('ApiService', ['post', 'put']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    TestBed.configureTestingModule({
 | 
				
			||||||
 | 
					      providers: [
 | 
				
			||||||
 | 
					        {provide: ApiService, useValue: apiSpy}
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
    service = TestBed.inject(DataService);
 | 
					    service = TestBed.inject(DataService);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    apiServiceSpy = TestBed.inject(ApiService) as jasmine.SpyObj<ApiService>;
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  it('should be created', () => {
 | 
					  it('should be created', () => {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,8 @@ import { LoginService } from './login.service';
 | 
				
			|||||||
import {LocalStorageService} from 'angular-2-local-storage';
 | 
					import {LocalStorageService} from 'angular-2-local-storage';
 | 
				
			||||||
import {ApiService} from './api.service';
 | 
					import {ApiService} from './api.service';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let loginService: LoginService;
 | 
					let loginService: LoginService;
 | 
				
			||||||
let apiServiceSpy: jasmine.SpyObj<ApiService>;
 | 
					let apiServiceSpy: jasmine.SpyObj<ApiService>;
 | 
				
			||||||
let localStorageServiceSpy: jasmine.SpyObj<LocalStorageService>;
 | 
					let localStorageServiceSpy: jasmine.SpyObj<LocalStorageService>;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,8 @@
 | 
				
			|||||||
import { TestBed } from '@angular/core/testing';
 | 
					import { TestBed } from '@angular/core/testing';
 | 
				
			||||||
import { ValidationService } from './validation.service';
 | 
					import { ValidationService } from './validation.service';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let validationService: ValidationService;
 | 
					let validationService: ValidationService;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe('ValidationService', () => {
 | 
					describe('ValidationService', () => {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,21 +1,45 @@
 | 
				
			|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 | 
					import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { SettingsComponent } from './settings.component';
 | 
					import { SettingsComponent } from './settings.component';
 | 
				
			||||||
 | 
					import {ApiService} from '../services/api.service';
 | 
				
			||||||
 | 
					import {LoginService} from '../services/login.service';
 | 
				
			||||||
 | 
					import {Router} from '@angular/router';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let routerServiceSpy: jasmine.SpyObj<Router>;
 | 
				
			||||||
 | 
					let apiServiceSpy: jasmine.SpyObj<ApiService>;
 | 
				
			||||||
 | 
					let loginServiceSpy: jasmine.SpyObj<LoginService>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe('SettingsComponent', () => {
 | 
					describe('SettingsComponent', () => {
 | 
				
			||||||
  let component: SettingsComponent;
 | 
					  let component: SettingsComponent;
 | 
				
			||||||
  let fixture: ComponentFixture<SettingsComponent>;
 | 
					  let fixture: ComponentFixture<SettingsComponent>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  beforeEach(async(() => {
 | 
					  beforeEach(async(() => {
 | 
				
			||||||
 | 
					    const routerSpy = jasmine.createSpyObj('Router', ['navigate']);
 | 
				
			||||||
 | 
					    const apiSpy = jasmine.createSpyObj('ApiService', ['post', 'put']);
 | 
				
			||||||
 | 
					    const loginSpy = jasmine.createSpyObj('LoginService', ['login', 'canActivate']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    TestBed.configureTestingModule({
 | 
					    TestBed.configureTestingModule({
 | 
				
			||||||
      declarations: [ SettingsComponent ]
 | 
					      declarations: [ SettingsComponent ],
 | 
				
			||||||
 | 
					      providers: [
 | 
				
			||||||
 | 
					        {provide: Router, useValue: routerSpy},
 | 
				
			||||||
 | 
					        {provide: ApiService, useValue: apiSpy},
 | 
				
			||||||
 | 
					        {provide: LoginService, useValue: loginSpy},
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
    .compileComponents();
 | 
					    .compileComponents();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    routerServiceSpy = TestBed.inject(Router) as jasmine.SpyObj<Router>;
 | 
				
			||||||
 | 
					    apiServiceSpy = TestBed.inject(ApiService) as jasmine.SpyObj<ApiService>;
 | 
				
			||||||
 | 
					    loginServiceSpy = TestBed.inject(LoginService) as jasmine.SpyObj<LoginService>;
 | 
				
			||||||
  }));
 | 
					  }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  beforeEach(() => {
 | 
					  beforeEach(() => {
 | 
				
			||||||
    fixture = TestBed.createComponent(SettingsComponent);
 | 
					    fixture = TestBed.createComponent(SettingsComponent);
 | 
				
			||||||
    component = fixture.componentInstance;
 | 
					    component = fixture.componentInstance;
 | 
				
			||||||
 | 
					    component.ngOnInit();
 | 
				
			||||||
    fixture.detectChanges();
 | 
					    fixture.detectChanges();
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,21 +1,51 @@
 | 
				
			|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 | 
					import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { TemplatesComponent } from './templates.component';
 | 
					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';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let apiServiceSpy: jasmine.SpyObj<ApiService>;
 | 
				
			||||||
 | 
					let validationServiceSpy: jasmine.SpyObj<ValidationService>;
 | 
				
			||||||
 | 
					let dataServiceSpy: jasmine.SpyObj<DataService>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe('TemplatesComponent', () => {
 | 
					describe('TemplatesComponent', () => {
 | 
				
			||||||
  let component: TemplatesComponent;
 | 
					  let component: TemplatesComponent;
 | 
				
			||||||
  let fixture: ComponentFixture<TemplatesComponent>;
 | 
					  let fixture: ComponentFixture<TemplatesComponent>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  beforeEach(async(() => {
 | 
					  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({
 | 
					    TestBed.configureTestingModule({
 | 
				
			||||||
      declarations: [ TemplatesComponent ]
 | 
					      declarations: [ TemplatesComponent ],
 | 
				
			||||||
 | 
					      imports: [
 | 
				
			||||||
 | 
					        RbUiComponentsModule,
 | 
				
			||||||
 | 
					        FormsModule
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					      providers: [
 | 
				
			||||||
 | 
					        {provide: ApiService, useValue: apiSpy},
 | 
				
			||||||
 | 
					        {provide: ValidationService, useValue: validationSpy},
 | 
				
			||||||
 | 
					        {provide: DataService, useValue: dataSpy}
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
    .compileComponents();
 | 
					    .compileComponents();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    apiServiceSpy = TestBed.inject(ApiService) as jasmine.SpyObj<ApiService>;
 | 
				
			||||||
 | 
					    validationServiceSpy = TestBed.inject(ValidationService) as jasmine.SpyObj<ValidationService>;
 | 
				
			||||||
 | 
					    dataServiceSpy = TestBed.inject(DataService) as jasmine.SpyObj<DataService>;
 | 
				
			||||||
  }));
 | 
					  }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  beforeEach(() => {
 | 
					  beforeEach(() => {
 | 
				
			||||||
    fixture = TestBed.createComponent(TemplatesComponent);
 | 
					    fixture = TestBed.createComponent(TemplatesComponent);
 | 
				
			||||||
    component = fixture.componentInstance;
 | 
					    component = fixture.componentInstance;
 | 
				
			||||||
 | 
					    component.ngOnInit();
 | 
				
			||||||
    fixture.detectChanges();
 | 
					    fixture.detectChanges();
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,21 +1,45 @@
 | 
				
			|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 | 
					import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { UsersComponent } from './users.component';
 | 
					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';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let apiServiceSpy: jasmine.SpyObj<ApiService>;
 | 
				
			||||||
 | 
					let modalServiceSpy: jasmine.SpyObj<ModalService>;
 | 
				
			||||||
 | 
					let loginServiceSpy: jasmine.SpyObj<LoginService>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe('UsersComponent', () => {
 | 
					describe('UsersComponent', () => {
 | 
				
			||||||
  let component: UsersComponent;
 | 
					  let component: UsersComponent;
 | 
				
			||||||
  let fixture: ComponentFixture<UsersComponent>;
 | 
					  let fixture: ComponentFixture<UsersComponent>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  beforeEach(async(() => {
 | 
					  beforeEach(async(() => {
 | 
				
			||||||
 | 
					    const apiSpy = jasmine.createSpyObj('ApiService', ['post', 'put']);
 | 
				
			||||||
 | 
					    const modalSpy = jasmine.createSpyObj('ModalService', ['open']);
 | 
				
			||||||
 | 
					    const loginSpy = jasmine.createSpyObj('LoginService', ['login', 'canActivate']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    TestBed.configureTestingModule({
 | 
					    TestBed.configureTestingModule({
 | 
				
			||||||
      declarations: [ UsersComponent ]
 | 
					      declarations: [ UsersComponent ],
 | 
				
			||||||
 | 
					      providers: [
 | 
				
			||||||
 | 
					        {provide: ApiService, useValue: apiSpy},
 | 
				
			||||||
 | 
					        {provide: ModalService, useValue: modalSpy},
 | 
				
			||||||
 | 
					        {provide: LoginService, useValue: loginSpy},
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
    .compileComponents();
 | 
					    .compileComponents();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    apiServiceSpy = TestBed.inject(ApiService) as jasmine.SpyObj<ApiService>;
 | 
				
			||||||
 | 
					    modalServiceSpy = TestBed.inject(ModalService) as jasmine.SpyObj<ModalService>;
 | 
				
			||||||
 | 
					    loginServiceSpy = TestBed.inject(LoginService) as jasmine.SpyObj<LoginService>;
 | 
				
			||||||
  }));
 | 
					  }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  beforeEach(() => {
 | 
					  beforeEach(() => {
 | 
				
			||||||
    fixture = TestBed.createComponent(UsersComponent);
 | 
					    fixture = TestBed.createComponent(UsersComponent);
 | 
				
			||||||
    component = fixture.componentInstance;
 | 
					    component = fixture.componentInstance;
 | 
				
			||||||
 | 
					    component.ngOnInit();
 | 
				
			||||||
    fixture.detectChanges();
 | 
					    fixture.detectChanges();
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,14 @@
 | 
				
			|||||||
// import { ValidateDirective } from './validate.directive';
 | 
					// import { ValidateDirective } from './validate.directive';
 | 
				
			||||||
 | 
					// import {ValidationService} from './services/validation.service';
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// // TODO
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// const validationSpy = {test: () => {}};
 | 
				
			||||||
 | 
					// const validationServiceSpy: jasmine.SpyObj<any> = spyOn(validationSpy, 'test');
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
// describe('ValidateDirective', () => {
 | 
					// describe('ValidateDirective', () => {
 | 
				
			||||||
//   it('should create an instance', () => {
 | 
					//   it('should create an instance', () => {
 | 
				
			||||||
//     const directive = new ValidateDirective();
 | 
					//     const directive = new ValidateDirective(validationServiceSpy);
 | 
				
			||||||
//     expect(directive).toBeTruthy();
 | 
					//     expect(directive).toBeTruthy();
 | 
				
			||||||
//   });
 | 
					//   });
 | 
				
			||||||
// });
 | 
					// });
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										
											BIN
										
									
								
								src/assets/icons/icon-128x128.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 26 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/icons/icon-144x144.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 30 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/icons/icon-152x152.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 30 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/icons/icon-192x192.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 39 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/icons/icon-384x384.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 136 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/icons/icon-512x512.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 235 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/icons/icon-72x72.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 10 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/icons/icon-96x96.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 16 KiB  | 
@@ -6,8 +6,11 @@
 | 
				
			|||||||
  <base href="/">
 | 
					  <base href="/">
 | 
				
			||||||
  <meta name="viewport" content="width=device-width, initial-scale=1">
 | 
					  <meta name="viewport" content="width=device-width, initial-scale=1">
 | 
				
			||||||
  <link rel="icon" type="image/x-icon" href="favicon.ico">
 | 
					  <link rel="icon" type="image/x-icon" href="favicon.ico">
 | 
				
			||||||
 | 
					  <link rel="manifest" href="manifest.webmanifest">
 | 
				
			||||||
 | 
					  <meta name="theme-color" content="#1976d2">
 | 
				
			||||||
</head>
 | 
					</head>
 | 
				
			||||||
<body>
 | 
					<body>
 | 
				
			||||||
  <app-root></app-root>
 | 
					  <app-root></app-root>
 | 
				
			||||||
 | 
					  <noscript>Please enable JavaScript to continue using this application.</noscript>
 | 
				
			||||||
</body>
 | 
					</body>
 | 
				
			||||||
</html>
 | 
					</html>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										59
									
								
								src/manifest.webmanifest
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,59 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "name": "definma",
 | 
				
			||||||
 | 
					  "short_name": "definma",
 | 
				
			||||||
 | 
					  "theme_color": "#1976d2",
 | 
				
			||||||
 | 
					  "background_color": "#fafafa",
 | 
				
			||||||
 | 
					  "display": "standalone",
 | 
				
			||||||
 | 
					  "scope": "./",
 | 
				
			||||||
 | 
					  "start_url": "./",
 | 
				
			||||||
 | 
					  "icons": [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "src": "assets/icons/icon-72x72.png",
 | 
				
			||||||
 | 
					      "sizes": "72x72",
 | 
				
			||||||
 | 
					      "type": "image/png",
 | 
				
			||||||
 | 
					      "purpose": "maskable any"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "src": "assets/icons/icon-96x96.png",
 | 
				
			||||||
 | 
					      "sizes": "96x96",
 | 
				
			||||||
 | 
					      "type": "image/png",
 | 
				
			||||||
 | 
					      "purpose": "maskable any"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "src": "assets/icons/icon-128x128.png",
 | 
				
			||||||
 | 
					      "sizes": "128x128",
 | 
				
			||||||
 | 
					      "type": "image/png",
 | 
				
			||||||
 | 
					      "purpose": "maskable any"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "src": "assets/icons/icon-144x144.png",
 | 
				
			||||||
 | 
					      "sizes": "144x144",
 | 
				
			||||||
 | 
					      "type": "image/png",
 | 
				
			||||||
 | 
					      "purpose": "maskable any"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "src": "assets/icons/icon-152x152.png",
 | 
				
			||||||
 | 
					      "sizes": "152x152",
 | 
				
			||||||
 | 
					      "type": "image/png",
 | 
				
			||||||
 | 
					      "purpose": "maskable any"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "src": "assets/icons/icon-192x192.png",
 | 
				
			||||||
 | 
					      "sizes": "192x192",
 | 
				
			||||||
 | 
					      "type": "image/png",
 | 
				
			||||||
 | 
					      "purpose": "maskable any"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "src": "assets/icons/icon-384x384.png",
 | 
				
			||||||
 | 
					      "sizes": "384x384",
 | 
				
			||||||
 | 
					      "type": "image/png",
 | 
				
			||||||
 | 
					      "purpose": "maskable any"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "src": "assets/icons/icon-512x512.png",
 | 
				
			||||||
 | 
					      "sizes": "512x512",
 | 
				
			||||||
 | 
					      "type": "image/png",
 | 
				
			||||||
 | 
					      "purpose": "maskable any"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||