basic account management (Login/Logout)
This commit is contained in:
parent
b28be4b792
commit
e6e5c22ece
68
package-lock.json
generated
68
package-lock.json
generated
@ -1887,9 +1887,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@inst-iot/bosch-angular-ui-components": {
|
"@inst-iot/bosch-angular-ui-components": {
|
||||||
"version": "0.6.0",
|
"version": "file:../Bosch-UI-Components/bosch-angular-ui-components/dist-lib/inst-iot-bosch-angular-ui-components-0.6.0.tgz",
|
||||||
"resolved": "https://rb-artifactory.bosch.com:443/artifactory/api/npm/iot-insights-release-local/@inst-iot/bosch-angular-ui-components/-/@inst-iot/bosch-angular-ui-components-0.6.0.tgz",
|
"integrity": "sha512-A4nKOvpdKzq+GWSZlL7U511Ii1vdSA905Q0tru7jAzpBzjRaYqCTiCvsAjRDLM+gVPpzgZ8HpMYfNfhMoNlG/w==",
|
||||||
"integrity": "sha1-+yjXwe/qCeBHYL+WoG7mOarPXIQ=",
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"tslib": "^1.10.0"
|
"tslib": "^1.10.0"
|
||||||
}
|
}
|
||||||
@ -2002,6 +2001,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/chart.js": {
|
||||||
|
"version": "2.9.22",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/chart.js/-/chart.js-2.9.22.tgz",
|
||||||
|
"integrity": "sha512-CneMxwh2T5fyMpXE5fuprTTmFtlLyZUFq1A3laUrCgOblDzupgiohrFg3jjsTIrqRI5K4qLZdrLN4zT9/MY5Dw==",
|
||||||
|
"requires": {
|
||||||
|
"moment": "^2.10.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/color-name": {
|
"@types/color-name": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
|
||||||
@ -3355,6 +3362,37 @@
|
|||||||
"integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
|
"integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"chart.js": {
|
||||||
|
"version": "2.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.9.3.tgz",
|
||||||
|
"integrity": "sha512-+2jlOobSk52c1VU6fzkh3UwqHMdSlgH1xFv9FKMqHiNCpXsGPQa/+81AFa+i3jZ253Mq9aAycPwDjnn1XbRNNw==",
|
||||||
|
"requires": {
|
||||||
|
"chartjs-color": "^2.1.0",
|
||||||
|
"moment": "^2.10.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"chartjs-color": {
|
||||||
|
"version": "2.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.4.1.tgz",
|
||||||
|
"integrity": "sha512-haqOg1+Yebys/Ts/9bLo/BqUcONQOdr/hoEr2LLTRl6C5LXctUdHxsCYfvQVg5JIxITrfCNUDr4ntqmQk9+/0w==",
|
||||||
|
"requires": {
|
||||||
|
"chartjs-color-string": "^0.6.0",
|
||||||
|
"color-convert": "^1.9.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"chartjs-color-string": {
|
||||||
|
"version": "0.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/chartjs-color-string/-/chartjs-color-string-0.6.0.tgz",
|
||||||
|
"integrity": "sha512-TIB5OKn1hPJvO7JcteW4WY/63v6KwEdt6udfnDE9iCAZgy+V4SrbSxoIbTw/xkUIapjEI4ExGtD0+6D3KyFd7A==",
|
||||||
|
"requires": {
|
||||||
|
"color-name": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"chartjs-plugin-datalabels": {
|
||||||
|
"version": "0.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/chartjs-plugin-datalabels/-/chartjs-plugin-datalabels-0.7.0.tgz",
|
||||||
|
"integrity": "sha512-PKVUX14nYhH0wcdCpgOoC39Gbzvn6cZ7O9n+bwc02yKD9FTnJ7/TSrBcfebmolFZp1Rcicr9xbT0a5HUbigS7g=="
|
||||||
|
},
|
||||||
"chokidar": {
|
"chokidar": {
|
||||||
"version": "3.4.0",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.0.tgz",
|
||||||
@ -3588,7 +3626,6 @@
|
|||||||
"version": "1.9.3",
|
"version": "1.9.3",
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"color-name": "1.1.3"
|
"color-name": "1.1.3"
|
||||||
}
|
}
|
||||||
@ -3596,8 +3633,7 @@
|
|||||||
"color-name": {
|
"color-name": {
|
||||||
"version": "1.1.3",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||||
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
|
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"color-string": {
|
"color-string": {
|
||||||
"version": "1.5.3",
|
"version": "1.5.3",
|
||||||
@ -8063,6 +8099,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
|
||||||
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
|
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
|
||||||
},
|
},
|
||||||
|
"lodash-es": {
|
||||||
|
"version": "4.17.15",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.15.tgz",
|
||||||
|
"integrity": "sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ=="
|
||||||
|
},
|
||||||
"lodash.clonedeep": {
|
"lodash.clonedeep": {
|
||||||
"version": "4.5.0",
|
"version": "4.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
|
||||||
@ -8658,6 +8699,11 @@
|
|||||||
"minimist": "^1.2.5"
|
"minimist": "^1.2.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"moment": {
|
||||||
|
"version": "2.27.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/moment/-/moment-2.27.0.tgz",
|
||||||
|
"integrity": "sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ=="
|
||||||
|
},
|
||||||
"move-concurrently": {
|
"move-concurrently": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
|
||||||
@ -8738,6 +8784,16 @@
|
|||||||
"integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==",
|
"integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"ng2-charts": {
|
||||||
|
"version": "2.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/ng2-charts/-/ng2-charts-2.3.2.tgz",
|
||||||
|
"integrity": "sha512-T0rPivwZITKtEtFRVodRCO+kIczWIP6V4YLZvf6Kg1jqc8jYGZ37H5ywT0Q7N0Rt5dJGhC5z1/38nWFBVFx5iw==",
|
||||||
|
"requires": {
|
||||||
|
"@types/chart.js": "^2.7.48",
|
||||||
|
"lodash-es": "^4.17.11",
|
||||||
|
"tslib": "^1.9.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"nice-try": {
|
"nice-try": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
|
||||||
|
@ -23,10 +23,13 @@
|
|||||||
"@angular/platform-browser-dynamic": "~9.1.7",
|
"@angular/platform-browser-dynamic": "~9.1.7",
|
||||||
"@angular/router": "~9.1.7",
|
"@angular/router": "~9.1.7",
|
||||||
"@hapi/joi": "^17.1.1",
|
"@hapi/joi": "^17.1.1",
|
||||||
"@inst-iot/bosch-angular-ui-components": "^0.6.0",
|
"@inst-iot/bosch-angular-ui-components": "file:../Bosch-UI-Components/bosch-angular-ui-components/dist-lib/inst-iot-bosch-angular-ui-components-0.6.0.tgz",
|
||||||
"angular-2-local-storage": "^3.0.2",
|
"angular-2-local-storage": "^3.0.2",
|
||||||
|
"chart.js": "^2.9.3",
|
||||||
|
"chartjs-plugin-datalabels": "^0.7.0",
|
||||||
"flatpickr": "^4.6.3",
|
"flatpickr": "^4.6.3",
|
||||||
"lodash": "^4.17.15",
|
"lodash": "^4.17.15",
|
||||||
|
"ng2-charts": "^2.3.2",
|
||||||
"quick-score": "0.0.8",
|
"quick-score": "0.0.8",
|
||||||
"rxjs": "~6.5.5",
|
"rxjs": "~6.5.5",
|
||||||
"tslib": "^1.10.0",
|
"tslib": "^1.10.0",
|
||||||
|
@ -4,19 +4,21 @@
|
|||||||
<a routerLink="/samples" routerLinkActive="active" rbLoadingLink *ngIf="loginService.isLoggedIn">Samples</a>
|
<a routerLink="/samples" routerLinkActive="active" rbLoadingLink *ngIf="loginService.isLoggedIn">Samples</a>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<nav *rbActionNavItems>
|
<ng-container *ngIf="loginService.isLoggedIn">
|
||||||
<a href="javascript:" [rbPopover]="userPopover" [anchor]="popoverAnchor">
|
<nav *rbActionNavItems>
|
||||||
Account <span class="rb-ic rb-ic-my-brand-frame" #popoverAnchor></span></a>
|
<a href="javascript:" [rbPopover]="userPopover" [anchor]="popoverAnchor">
|
||||||
</nav>
|
{{loginService.username}} <span class="rb-ic rb-ic-my-brand-frame" #popoverAnchor></span></a>
|
||||||
<ng-template #userPopover>
|
</nav>
|
||||||
<div class="spacing">
|
<ng-template #userPopover>
|
||||||
<p>
|
<div class="spacing">
|
||||||
Some user specific information
|
<p>
|
||||||
</p>
|
<!-- Some user specific information-->
|
||||||
|
</p>
|
||||||
|
|
||||||
<a href="javascript:" class="rb-btn rb-primary">Logout</a>
|
<button type="button" class="rb-btn rb-primary" (click)="logout()">Logout</button>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
<div *rbSubBrandHeader><span class="dev-label" *ngIf="devMode">DEVELOPMENT</span>Digital Fingerprint of Plastics</div>
|
<div *rbSubBrandHeader><span class="dev-label" *ngIf="devMode">DEVELOPMENT</span>Digital Fingerprint of Plastics</div>
|
||||||
</rb-full-header>
|
</rb-full-header>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { Component, isDevMode} from '@angular/core';
|
import { Component, isDevMode} from '@angular/core';
|
||||||
import {LoginService} from './services/login.service';
|
import {LoginService} from './services/login.service';
|
||||||
|
import {Router} from '@angular/router';
|
||||||
|
|
||||||
// TODO: add multiple samples at once
|
// TODO: add multiple samples at once
|
||||||
// TODO: guess properties from material name
|
// TODO: guess properties from material name
|
||||||
@ -16,11 +17,17 @@ import {LoginService} from './services/login.service';
|
|||||||
export class AppComponent {
|
export class AppComponent {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public loginService: LoginService
|
public loginService: LoginService,
|
||||||
|
private router: Router
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
get devMode() {
|
get devMode() {
|
||||||
return isDevMode();
|
return isDevMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logout() {
|
||||||
|
this.loginService.logout();
|
||||||
|
this.router.navigate(['/']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { BrowserModule } from '@angular/platform-browser';
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
|
import { ChartsModule } from 'ng2-charts';
|
||||||
|
|
||||||
import { AppRoutingModule } from './app-routing.module';
|
import { AppRoutingModule } from './app-routing.module';
|
||||||
import { AppComponent } from './app.component';
|
import { AppComponent } from './app.component';
|
||||||
@ -16,6 +17,7 @@ import { ValidateDirective } from './validate.directive';
|
|||||||
import {CommonModule} from '@angular/common';
|
import {CommonModule} from '@angular/common';
|
||||||
import { ErrorComponent } from './error/error.component';
|
import { ErrorComponent } from './error/error.component';
|
||||||
import { ObjectPipe } from './object.pipe';
|
import { ObjectPipe } from './object.pipe';
|
||||||
|
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
@ -34,6 +36,7 @@ import { ObjectPipe } from './object.pipe';
|
|||||||
storageType: 'localStorage'
|
storageType: 'localStorage'
|
||||||
}),
|
}),
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
|
BrowserAnimationsModule,
|
||||||
AppRoutingModule,
|
AppRoutingModule,
|
||||||
RbUiComponentsModule,
|
RbUiComponentsModule,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
@ -41,7 +44,8 @@ import { ObjectPipe } from './object.pipe';
|
|||||||
RbTableModule,
|
RbTableModule,
|
||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
FormFieldsModule,
|
FormFieldsModule,
|
||||||
CommonModule
|
CommonModule,
|
||||||
|
ChartsModule
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
ModalService
|
ModalService
|
||||||
|
@ -29,7 +29,7 @@ export class LoginComponent implements OnInit {
|
|||||||
login() {
|
login() {
|
||||||
this.loginService.login(this.username, this.password).then(ok => {
|
this.loginService.login(this.username, this.password).then(ok => {
|
||||||
if (ok) {
|
if (ok) {
|
||||||
this.message = 'Login successful'; // TODO: think about following action
|
this.message = 'Login successful';
|
||||||
this.router.navigate(['/samples']);
|
this.router.navigate(['/samples']);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -6,14 +6,14 @@
|
|||||||
<!--<form #sampleForm="ngForm">-->
|
<!--<form #sampleForm="ngForm">-->
|
||||||
<div class="sample">
|
<div class="sample">
|
||||||
<div>
|
<div>
|
||||||
<rb-form-input name="materialname" label="material name" [rbFormInputAutocomplete]="autocomplete.bind(this, materialNames)" [rbDebounceTime]="0" [rbInitialOpen]="true" (keydown)="preventSubmit($event)" (ngModelChange)="findMaterial($event)" appValidate="stringOf" [appValidateArgs]="[materialNames]" required [(ngModel)]="material.name" [autofocus]="true" #materialNameInput="ngModel">
|
<rb-form-input name="materialname" label="material name" [rbFormInputAutocomplete]="autocomplete.bind(this, materialNames)" [rbDebounceTime]="0" [rbInitialOpen]="true" (keydown)="preventDefault($event)" (ngModelChange)="findMaterial($event)" appValidate="stringOf" [appValidateArgs]="[materialNames]" required [(ngModel)]="material.name" [autofocus]="true" #materialNameInput="ngModel">
|
||||||
<ng-template rbFormValidationMessage="required">Cannot be empty</ng-template>
|
<ng-template rbFormValidationMessage="required">Cannot be empty</ng-template>
|
||||||
<ng-template rbFormValidationMessage="failure">Unknown material, add properties for new material</ng-template>
|
<ng-template rbFormValidationMessage="failure">Unknown material, add properties for new material</ng-template>
|
||||||
</rb-form-input>
|
</rb-form-input>
|
||||||
<button class="rb-btn rb-secondary" type="button" (click)="setNewMaterial(true)"><span class="rb-ic rb-ic-add"></span> New material</button>
|
<button class="rb-btn rb-secondary" type="button" (click)="setNewMaterial(true)"><span class="rb-ic rb-ic-add"></span> New material</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="material shaded-container" *ngIf="newMaterial">
|
<div class="material shaded-container" *ngIf="newMaterial" [@inOut]>
|
||||||
<h4>Material properties</h4>
|
<h4>Material properties</h4>
|
||||||
<rb-form-input name="supplier" label="supplier" [rbFormInputAutocomplete]="autocomplete.bind(this, suppliers)" [rbDebounceTime]="0" [rbInitialOpen]="true" appValidate="string" required [(ngModel)]="material.supplier" #supplierInput="ngModel">
|
<rb-form-input name="supplier" label="supplier" [rbFormInputAutocomplete]="autocomplete.bind(this, suppliers)" [rbDebounceTime]="0" [rbInitialOpen]="true" appValidate="string" required [(ngModel)]="material.supplier" #supplierInput="ngModel">
|
||||||
<ng-template rbFormValidationMessage="failure">{{supplierInput.errors.failure}}</ng-template>
|
<ng-template rbFormValidationMessage="failure">{{supplierInput.errors.failure}}</ng-template>
|
||||||
@ -38,7 +38,7 @@
|
|||||||
</rb-form-input>
|
</rb-form-input>
|
||||||
|
|
||||||
<div class="material-numbers">
|
<div class="material-numbers">
|
||||||
<div *ngFor="let number of material.numbers; index as i" class="two-col">
|
<div *ngFor="let number of material.numbers; index as i" class="two-col" [@inOut]>
|
||||||
<rb-form-input label="color" appValidate="string" [required]="i < material.numbers.length - 1" (keyup)="handleMaterialNumbers()" [(ngModel)]="number.color" ngModel [ngModelOptions]="{standalone: true}">
|
<rb-form-input label="color" appValidate="string" [required]="i < material.numbers.length - 1" (keyup)="handleMaterialNumbers()" [(ngModel)]="number.color" ngModel [ngModelOptions]="{standalone: true}">
|
||||||
</rb-form-input>
|
</rb-form-input>
|
||||||
<rb-form-input label="material number" appValidate="string" [(ngModel)]="number.number" ngModel [ngModelOptions]="{standalone: true}">
|
<rb-form-input label="material number" appValidate="string" [(ngModel)]="number.number" ngModel [ngModelOptions]="{standalone: true}">
|
||||||
@ -69,7 +69,7 @@
|
|||||||
<ng-template rbFormValidationMessage="failure">{{commentInput.errors.failure}}</ng-template>
|
<ng-template rbFormValidationMessage="failure">{{commentInput.errors.failure}}</ng-template>
|
||||||
</rb-form-input>
|
</rb-form-input>
|
||||||
<h5>Additional properties</h5>
|
<h5>Additional properties</h5>
|
||||||
<div *ngFor="let field of customFields; index as i" class="two-col">
|
<div *ngFor="let field of customFields; index as i" class="two-col" [@inOut]>
|
||||||
<div>
|
<div>
|
||||||
<rb-form-input [name]="'cf-key' + i" label="key" [rbFormInputAutocomplete]="autocomplete.bind(this, availableCustomFields)" [rbDebounceTime]="0" [rbInitialOpen]="true" appValidate="unique" [appValidateArgs]="[uniqueCfValues(i)]" (ngModelChange)="adjustCustomFields($event, i)" [ngModel]="field[0]" #keyInput="ngModel">
|
<rb-form-input [name]="'cf-key' + i" label="key" [rbFormInputAutocomplete]="autocomplete.bind(this, availableCustomFields)" [rbDebounceTime]="0" [rbInitialOpen]="true" appValidate="unique" [appValidateArgs]="[uniqueCfValues(i)]" (ngModelChange)="adjustCustomFields($event, i)" [ngModel]="field[0]" #keyInput="ngModel">
|
||||||
<ng-template rbFormValidationMessage="failure">{{keyInput.errors.failure}}</ng-template>
|
<ng-template rbFormValidationMessage="failure">{{keyInput.errors.failure}}</ng-template>
|
||||||
@ -89,7 +89,7 @@
|
|||||||
Condition
|
Condition
|
||||||
<button class="rb-btn rb-secondary condition-set" type="button" (click)="toggleCondition()" [disabled]="!conditionTemplates">{{condition ? 'Do not set condition' : 'Set condition'}}</button>
|
<button class="rb-btn rb-secondary condition-set" type="button" (click)="toggleCondition()" [disabled]="!conditionTemplates">{{condition ? 'Do not set condition' : 'Set condition'}}</button>
|
||||||
</h4>
|
</h4>
|
||||||
<div *ngIf="condition">
|
<div *ngIf="condition" [@inOut]>
|
||||||
<rb-form-select name="conditionSelect" label="Condition" (ngModelChange)="selectCondition($event)" [ngModel]="condition._id">
|
<rb-form-select name="conditionSelect" label="Condition" (ngModelChange)="selectCondition($event)" [ngModel]="condition._id">
|
||||||
<option *ngFor="let c of conditionTemplates" [value]="c._id">{{c.name}}</option>
|
<option *ngFor="let c of conditionTemplates" [value]="c._id">{{c.name}}</option>
|
||||||
</rb-form-select>
|
</rb-form-select>
|
||||||
@ -105,8 +105,8 @@
|
|||||||
|
|
||||||
<div class="measurements shaded-container">
|
<div class="measurements shaded-container">
|
||||||
<h4>Measurements</h4>
|
<h4>Measurements</h4>
|
||||||
<div *ngFor="let measurement of sample.measurements; index as mIndex">
|
<div *ngFor="let measurement of sample.measurements; index as mIndex" [@inOut]>
|
||||||
<rb-form-select name="measurementTemplateSelect" label="Template" [(ngModel)]="measurement.measurement_template">
|
<rb-form-select name="measurementTemplateSelect" label="Template" [(ngModel)]="measurement.measurement_template" (ngModelChange)="clearChart(mIndex)">
|
||||||
<option *ngFor="let m of measurementTemplates" [value]="m._id">{{m.name}}</option>
|
<option *ngFor="let m of measurementTemplates" [value]="m._id">{{m.name}}</option>
|
||||||
</rb-form-select>
|
</rb-form-select>
|
||||||
|
|
||||||
@ -115,9 +115,16 @@
|
|||||||
<ng-template rbFormValidationMessage="failure">{{parameterInput.errors.failure}}</ng-template>
|
<ng-template rbFormValidationMessage="failure">{{parameterInput.errors.failure}}</ng-template>
|
||||||
<ng-template rbFormValidationMessage="required">Cannot be empty</ng-template>
|
<ng-template rbFormValidationMessage="required">Cannot be empty</ng-template>
|
||||||
</rb-form-input>
|
</rb-form-input>
|
||||||
<rb-form-file *ngIf="parameter.range.type" [name]="'measurementParameter' + mIndex + '-' + pIndex" [label]="parameter.name" maxSize="10000000" (change)="fileToArray($event, mIndex, parameter.name)" required ngModel>
|
<rb-form-file *ngIf="parameter.range.type" [name]="'measurementParameter' + mIndex + '-' + pIndex" [label]="parameter.name" maxSize="10000000" (ngModelChange)="fileToArray($event, mIndex, parameter.name)" placeholder="Select file or drag and drop" dragDrop required ngModel>
|
||||||
<ng-template rbFormValidationMessage="required">Cannot be empty</ng-template>
|
<ng-template rbFormValidationMessage="required">Cannot be empty</ng-template>
|
||||||
</rb-form-file>
|
</rb-form-file>
|
||||||
|
<canvas baseChart *ngIf="parameter.range.type && charts[mIndex][0].data.length > 0" class="dpt-chart" [@inOut]
|
||||||
|
[datasets]="charts[mIndex]"
|
||||||
|
[labels]="[]"
|
||||||
|
[options]="chartOptions"
|
||||||
|
[legend]="false"
|
||||||
|
chartType="scatter">
|
||||||
|
</canvas>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button class="rb-btn rb-danger" type="button" (click)="removeMeasurement(mIndex)"><span class="rb-ic rb-ic-delete"></span> Delete measurement</button>
|
<button class="rb-btn rb-danger" type="button" (click)="removeMeasurement(mIndex)"><span class="rb-ic rb-ic-delete"></span> Delete measurement</button>
|
||||||
@ -130,7 +137,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<button class="rb-btn rb-primary" type="submit" (click)="saveSample()" [disabled]="!sampleForm.form.valid">Save sample</button>
|
<button class="rb-btn rb-primary" type="submit" (click)="saveSample()" [disabled]="!sampleForm.form.valid">Save sample</button>
|
||||||
|
@ -15,3 +15,7 @@ td:first-child {
|
|||||||
grid-template-columns: 1fr 1fr;
|
grid-template-columns: 1fr 1fr;
|
||||||
grid-column-gap: 10px;
|
grid-column-gap: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dpt-chart {
|
||||||
|
max-width: 400px;
|
||||||
|
}
|
||||||
|
@ -14,20 +14,35 @@ import {NgForm, Validators} from '@angular/forms';
|
|||||||
import {ValidationService} from '../services/validation.service';
|
import {ValidationService} from '../services/validation.service';
|
||||||
import {TemplateModel} from '../models/template.model';
|
import {TemplateModel} from '../models/template.model';
|
||||||
import {MeasurementModel} from '../models/measurement.model';
|
import {MeasurementModel} from '../models/measurement.model';
|
||||||
|
import { ChartOptions } from 'chart.js';
|
||||||
|
import {animate, style, transition, trigger} from '@angular/animations';
|
||||||
|
|
||||||
// TODO: tests
|
// TODO: tests
|
||||||
// TODO: confirmation for new group/supplier
|
// TODO: confirmation for new group/supplier
|
||||||
// TODO: DPT preview
|
|
||||||
// TODO: work on better recognition for file input
|
// TODO: work on better recognition for file input
|
||||||
// TODO: only show condition (if not set) and measurements in edit sample dialog at first
|
// TODO: only show condition (if not set) and measurements in edit sample dialog at first
|
||||||
// TODO: multiple spectra, drag and drop
|
// TODO: multiple spectra
|
||||||
// TODO: multiple samples for base data, extend multiple measurements, conditions
|
// TODO: multiple samples for base data, extend multiple measurements, conditions
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-sample',
|
selector: 'app-sample',
|
||||||
templateUrl: './sample.component.html',
|
templateUrl: './sample.component.html',
|
||||||
styleUrls: ['./sample.component.scss']
|
styleUrls: ['./sample.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 SampleComponent implements OnInit, AfterContentChecked {
|
export class SampleComponent implements OnInit, AfterContentChecked {
|
||||||
|
|
||||||
@ -49,6 +64,27 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
|||||||
measurementTemplates: TemplateModel[];
|
measurementTemplates: TemplateModel[];
|
||||||
loading = 0; // number of currently loading instances
|
loading = 0; // number of currently loading instances
|
||||||
checkFormAfterInit = false;
|
checkFormAfterInit = false;
|
||||||
|
charts = []; // chart data for spectrums
|
||||||
|
readonly chartInit = [{
|
||||||
|
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(
|
constructor(
|
||||||
private router: Router,
|
private router: Router,
|
||||||
@ -90,6 +126,19 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
|||||||
this.loading++;
|
this.loading++;
|
||||||
this.api.get<SampleModel>('/sample/' + this.route.snapshot.paramMap.get('id'), sData => {
|
this.api.get<SampleModel>('/sample/' + this.route.snapshot.paramMap.get('id'), sData => {
|
||||||
this.sample.deserialize(sData);
|
this.sample.deserialize(sData);
|
||||||
|
this.charts = [];
|
||||||
|
const spectrumTemplate = this.measurementTemplates.find(e => e.name === 'spectrum')._id;
|
||||||
|
let spectrumCounter = 0;
|
||||||
|
this.sample.measurements.forEach((measurement, i) => {
|
||||||
|
this.charts.push(_.cloneDeep(this.chartInit));
|
||||||
|
if (measurement.measurement_template === spectrumTemplate) {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.generateChart(measurement.values.dpt, i);
|
||||||
|
console.log(this.charts);
|
||||||
|
}, spectrumCounter * 20);
|
||||||
|
spectrumCounter ++;
|
||||||
|
}
|
||||||
|
});
|
||||||
this.material = sData.material;
|
this.material = sData.material;
|
||||||
this.customFields = this.sample.notes.custom_fields && this.sample.notes.custom_fields !== {} ? Object.keys(this.sample.notes.custom_fields).map(e => [e, this.sample.notes.custom_fields[e]]) : [['', '']];
|
this.customFields = this.sample.notes.custom_fields && this.sample.notes.custom_fields !== {} ? Object.keys(this.sample.notes.custom_fields).map(e => [e, this.sample.notes.custom_fields[e]]) : [['', '']];
|
||||||
if ('condition_template' in this.sample.condition) {
|
if ('condition_template' in this.sample.condition) {
|
||||||
@ -225,8 +274,8 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
|||||||
this.setNewMaterial();
|
this.setNewMaterial();
|
||||||
}
|
}
|
||||||
|
|
||||||
preventSubmit(event) {
|
preventDefault(event) {
|
||||||
if (event.key === 'Enter') {
|
if (event.key && event.key === 'Enter' || event.type === 'dragover') {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -285,6 +334,7 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
|||||||
|
|
||||||
addMeasurement() {
|
addMeasurement() {
|
||||||
this.sample.measurements.push(new MeasurementModel(this.measurementTemplates[0]._id));
|
this.sample.measurements.push(new MeasurementModel(this.measurementTemplates[0]._id));
|
||||||
|
this.charts.push(_.cloneDeep(this.chartInit));
|
||||||
}
|
}
|
||||||
|
|
||||||
removeMeasurement(index) {
|
removeMeasurement(index) {
|
||||||
@ -292,14 +342,24 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
|||||||
this.api.delete('/measurement/' + this.sample.measurements[index]._id);
|
this.api.delete('/measurement/' + this.sample.measurements[index]._id);
|
||||||
}
|
}
|
||||||
this.sample.measurements.splice(index, 1);
|
this.sample.measurements.splice(index, 1);
|
||||||
|
this.charts.splice(index, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
fileToArray(event, mIndex, parameter) {
|
clearChart(index) {
|
||||||
|
this.charts[index][0].data = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
fileToArray(files, mIndex, parameter) {
|
||||||
const fileReader = new FileReader();
|
const fileReader = new FileReader();
|
||||||
fileReader.onload = () => {
|
fileReader.onload = () => {
|
||||||
this.sample.measurements[mIndex].values[parameter] = fileReader.result.toString().split('\r\n').map(e => e.split(','));
|
this.sample.measurements[mIndex].values[parameter] = fileReader.result.toString().split('\r\n').map(e => e.split(','));
|
||||||
|
this.generateChart(this.sample.measurements[mIndex].values[parameter], mIndex);
|
||||||
};
|
};
|
||||||
fileReader.readAsText(event.target.files[0]);
|
fileReader.readAsText(files[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
generateChart(spectrum, index) {
|
||||||
|
this.charts[index][0].data = spectrum.map(e => ({x: parseFloat(e[0]), y: parseFloat(e[1])}));
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleCondition() {
|
toggleCondition() {
|
||||||
|
@ -45,7 +45,7 @@
|
|||||||
<option value="in">∈</option>
|
<option value="in">∈</option>
|
||||||
<option value="nin">∉</option>
|
<option value="nin">∉</option>
|
||||||
</rb-form-select>
|
</rb-form-select>
|
||||||
<div>
|
<div class="filter-inputs">
|
||||||
<ng-container *ngFor="let ignore of [].constructor(filter.values.length); index as i">
|
<ng-container *ngFor="let ignore of [].constructor(filter.values.length); index as i">
|
||||||
<rb-form-date-input *ngIf="filter.field === 'added'; else noDate" [name]="'filter-' + filter.field + i" [label]="filter.label" [(ngModel)]="filter.values[i]" (ngModelChange)="updateFilterFields(filter.field)"></rb-form-date-input>
|
<rb-form-date-input *ngIf="filter.field === 'added'; else noDate" [name]="'filter-' + filter.field + i" [label]="filter.label" [(ngModel)]="filter.values[i]" (ngModelChange)="updateFilterFields(filter.field)"></rb-form-date-input>
|
||||||
<ng-template #noDate>
|
<ng-template #noDate>
|
||||||
@ -54,11 +54,6 @@
|
|||||||
</ng-template>
|
</ng-template>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
<!-- <rb-form-date-input *ngIf="filter.field === 'added'; else noDate" [name]="'filter-' + filter.field" [label]="filter.label" [(ngModel)]="filter.values[0]" (ngModelChange)="loadSamples({firstPage: true})"></rb-form-date-input>-->
|
|
||||||
<!-- <ng-template #noDate>-->
|
|
||||||
<!-- <rb-form-input *ngIf="!filter.autocomplete.length" [name]="'filter-' + filter.field" [label]="filter.label" [(ngModel)]="filter.values[0]" (ngModelChange)="loadSamples({firstPage: true})"></rb-form-input>-->
|
|
||||||
<!-- <rb-form-input *ngIf="filter.autocomplete.length" [name]="'filter-' + filter.field" [label]="filter.label" [rbFormInputAutocomplete]="autocomplete.bind(this, filter.autocomplete)" [rbDebounceTime]="0" (keydown)="preventDefault($event, 'Enter')" [(ngModel)]="filter.values[0]" (ngModelChange)="loadSamples({firstPage: true})" ngModel></rb-form-input>-->
|
|
||||||
<!-- </ng-template>-->
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -91,8 +86,6 @@
|
|||||||
<th *ngFor="let key of activeKeysArray()">
|
<th *ngFor="let key of activeKeysArray()">
|
||||||
<div class="sort-header">
|
<div class="sort-header">
|
||||||
<span>{{key.label}}</span>
|
<span>{{key.label}}</span>
|
||||||
<!-- <span class="rb-ic rb-ic-up" [ngClass]="{'sort-active-desc': filters.sort === key.id + '-' + 'desc'}" (click)="setSort(key.id + '-' + 'desc')"></span>-->
|
|
||||||
<!-- <span class="rb-ic rb-ic-down" [ngClass]="{'sort-active-asc': filters.sort === key.id + '-' + 'asc'}" (click)="setSort(key.id + '-' + 'asc')"></span>-->
|
|
||||||
<span class="rb-ic rb-ic-up sort-arr-up" (click)="setSort(key.id + '-' + 'desc')"><span *ngIf="filters.sort === key.id + '-' + 'desc'"></span></span>
|
<span class="rb-ic rb-ic-up sort-arr-up" (click)="setSort(key.id + '-' + 'desc')"><span *ngIf="filters.sort === key.id + '-' + 'desc'"></span></span>
|
||||||
<span class="rb-ic rb-ic-down sort-arr-down" (click)="setSort(key.id + '-' + 'asc')"><span *ngIf="filters.sort === key.id + '-' + 'asc'"></span></span>
|
<span class="rb-ic rb-ic-down sort-arr-down" (click)="setSort(key.id + '-' + 'asc')"><span *ngIf="filters.sort === key.id + '-' + 'asc'"></span></span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -169,3 +169,8 @@ textarea.linkmodal {
|
|||||||
min-height: 200px;
|
min-height: 200px;
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.filter-inputs > * {
|
||||||
|
display: inline-block;
|
||||||
|
max-width: 250px;
|
||||||
|
}
|
||||||
|
@ -42,6 +42,11 @@ export class LoginService implements CanActivate {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logout() {
|
||||||
|
this.storage.remove('basicAuth');
|
||||||
|
this.loggedIn = false;
|
||||||
|
}
|
||||||
|
|
||||||
canActivate(route: ActivatedRouteSnapshot = null, state: RouterStateSnapshot = null): Observable<boolean> {
|
canActivate(route: ActivatedRouteSnapshot = null, state: RouterStateSnapshot = null): Observable<boolean> {
|
||||||
return new Observable<boolean>(observer => {
|
return new Observable<boolean>(observer => {
|
||||||
if (this.loggedIn === undefined) {
|
if (this.loggedIn === undefined) {
|
||||||
@ -60,4 +65,8 @@ export class LoginService implements CanActivate {
|
|||||||
get isLoggedIn() {
|
get isLoggedIn() {
|
||||||
return this.loggedIn;
|
return this.loggedIn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get username() {
|
||||||
|
return atob(this.storage.get('basicAuth')).split(':')[0];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user