Merge pull request #24 in ~VLE2FE/definma-ui from development to master

* commit '9c2095c31a9bfeebd2361b912b58f333e7645c3a':
  added buttons for resetting to defaults in samples and changed defaults, added loading spinner and added apply filters button (again)
This commit is contained in:
Veit Lukas (PEA4-Fe) 2020-08-18 12:38:23 +02:00
commit e95abf21d5
9 changed files with 63 additions and 19 deletions

View File

@ -1,4 +1,4 @@
add_header Content-Security-Policy "default-src 'none'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self'; font-src 'self'; connect-src https://definma-api.apps.de1.bosch-iot-cloud.com; form-action 'none'; frame-ancestors 'none'; base-uri 'self'"; add_header Content-Security-Policy "default-src 'none'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self'; font-src 'self'; connect-src https://*.apps.de1.bosch-iot-cloud.com; form-action 'none'; frame-ancestors 'none'; base-uri 'self'";
add_header X-Frame-Options DENY; add_header X-Frame-Options DENY;
add_header X-DNS-Prefetch-Control off; add_header X-DNS-Prefetch-Control off;
add_header Strict-Transport-Security "max-age=15552000; includeSubDomains"; add_header Strict-Transport-Security "max-age=15552000; includeSubDomains";

View File

@ -1,4 +1,4 @@
import { Component, isDevMode} from '@angular/core'; import {Component, isDevMode, OnInit} 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';
@ -10,7 +10,7 @@ import {NavigationStart, Router} from '@angular/router';
templateUrl: './app.component.html', templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'] styleUrls: ['./app.component.scss']
}) })
export class AppComponent { export class AppComponent implements OnInit{
bugReport = {do: '', work: ''}; bugReport = {do: '', work: ''};
isDocumentation = false; isDocumentation = false;
@ -29,6 +29,10 @@ export class AppComponent {
}); });
} }
ngOnInit() {
this.login.login();
}
logout() { logout() {
this.login.logout(); this.login.logout();
this.router.navigate(['/']); this.router.navigate(['/']);

View File

@ -1,6 +1,10 @@
<h2>Documentation</h2> <h2>Documentation</h2>
<p> <p>
Bosch IoT Cloud space where all applications are hosted:
<a href="https://apps.sys.de1.bosch-iot-cloud.com/organizations/b28baba5-f95f-4ce5-bc9c-3f45acd1dfb2">
https://apps.sys.de1.bosch-iot-cloud.com/organizations/b28baba5-f95f-4ce5-bc9c-3f45acd1dfb2
</a><br>
Find the API documentation here: Find the API documentation here:
<a href="https://definma-api.apps.de1.bosch-iot-cloud.com/api-doc/"> <a href="https://definma-api.apps.de1.bosch-iot-cloud.com/api-doc/">
https://definma-api.apps.de1.bosch-iot-cloud.com/api-doc/ https://definma-api.apps.de1.bosch-iot-cloud.com/api-doc/
@ -77,4 +81,13 @@
</tr> </tr>
</rb-table> </rb-table>
<h4>Architecture</h4>
<img src="/assets/imgs/architecture.svg" alt="architecture" class="space-below">
<p>
All applications are hosted in the bosch IoT Cloud. The API is hosted in a Node.js container, with a bound MongoDB
instance. <br>
The Angular UI is hosted in a staticfile container, serving the built Angular bundle. <br>
Finally any machine learning models are hosted in Python containers.
</p>

View File

@ -1,8 +1,6 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import {ApiService} from '../services/api.service'; import {ApiService} from '../services/api.service';
// TODO: links to BIC
// TODO: bic structure image
@Component({ @Component({
selector: 'app-documentation', selector: 'app-documentation',

View File

@ -261,5 +261,3 @@
</ng-template> </ng-template>
</form> </form>
</div> </div>
<button (click)="checkFormAfterInit = true">XXX</button>

View File

@ -50,11 +50,14 @@
<span *rbFormMultiSelectOption="let item" class="load-first-page">{{item.label}}</span> <span *rbFormMultiSelectOption="let item" class="load-first-page">{{item.label}}</span>
</rb-form-multi-select> </rb-form-multi-select>
<rb-icon-button icon="reset" mode="secondary" (click)="resetPreferences()" class="reset-preferences">
Reset to default
</rb-icon-button>
<div class="fieldfilters"> <div class="fieldfilters">
<div *ngFor="let filter of filters.filters"> <div *ngFor="let filter of filters.filters">
<ng-container *ngIf="isActiveKey[filter.field]"> <ng-container *ngIf="isActiveKey[filter.field]">
<rb-form-checkbox [name]="'filteractive-' + filter.field" [(ngModel)]="filter.active" <rb-form-checkbox [name]="'filteractive-' + filter.field" [(ngModel)]="filter.active"></rb-form-checkbox>
(ngModelChange)="loadSamples({firstPage: true})"></rb-form-checkbox>
<rb-form-select [name]="'filtermode-' + filter.field" class="filtermode" [(ngModel)]="filter.mode" <rb-form-select [name]="'filtermode-' + filter.field" class="filtermode" [(ngModel)]="filter.mode"
(ngModelChange)="updateFilterFields(filter.field)"> (ngModelChange)="updateFilterFields(filter.field)">
<option value="eq" title="field is equal to value">=</option> <option value="eq" title="field is equal to value">=</option>
@ -102,6 +105,10 @@
</ng-container> </ng-container>
</div> </div>
</div> </div>
<rb-icon-button icon="forward-right" mode="primary" (click)="loadSamples({firstPage: true})">
Apply filters
</rb-icon-button>
</form> </form>
</rb-accordion-body> </rb-accordion-body>
</rb-accordion> </rb-accordion>
@ -109,6 +116,8 @@
<ng-container *ngTemplateOutlet="paging"></ng-container> <ng-container *ngTemplateOutlet="paging"></ng-container>
<rb-loading-spinner class="samples-loading" *ngIf="loading"></rb-loading-spinner>
<div class="download space-below" *ngIf="login.isLevel.dev"> <div class="download space-below" *ngIf="login.isLevel.dev">
<rb-icon-button class="space-right" icon="download" mode="secondary" [rbModal]="linkModal"> <rb-icon-button class="space-right" icon="download" mode="secondary" [rbModal]="linkModal">
JSON download link JSON download link

View File

@ -53,6 +53,8 @@ rb-table {
.paging { .paging {
height: 50px; height: 50px;
float: left;
rb-form-input { rb-form-input {
max-width: 65px; max-width: 65px;
} }
@ -232,3 +234,12 @@ textarea.linkmodal {
float: right; float: right;
} }
} }
.samples-loading {
float: left;
transform: scale(0.5);
}
.reset-preferences {
float: right;
}

View File

@ -11,6 +11,11 @@ import {DataService} from '../services/data.service';
import {LocalStorageService} from 'angular-2-local-storage'; import {LocalStorageService} from 'angular-2-local-storage';
// TODO: turn off sort field // TODO: turn off sort field
// TODO reset sort when field is excluded
// TODO: material name to product
// TODO: Eh DPT
// TODO: filter button
// TODO: check if connect-src to model works
interface LoadSamplesOptions { interface LoadSamplesOptions {
@ -58,7 +63,6 @@ export class SamplesComponent implements OnInit {
{field: 'type', label: 'Type', active: false, autocomplete: [], mode: 'eq', values: ['']}, {field: 'type', label: 'Type', active: false, autocomplete: [], mode: 'eq', values: ['']},
{field: 'color', label: 'Color', active: false, autocomplete: [], mode: 'eq', values: ['']}, {field: 'color', label: 'Color', active: false, autocomplete: [], mode: 'eq', values: ['']},
{field: 'batch', label: 'Batch', active: false, autocomplete: [], mode: 'eq', values: ['']}, {field: 'batch', label: 'Batch', active: false, autocomplete: [], mode: 'eq', values: ['']},
{field: 'notes', label: 'Notes', active: false, autocomplete: [], mode: 'eq', values: ['']},
{field: 'added', label: 'Added', active: false, autocomplete: [], mode: 'eq', values: ['']} {field: 'added', label: 'Added', active: false, autocomplete: [], mode: 'eq', values: ['']}
] ]
}; };
@ -69,13 +73,13 @@ export class SamplesComponent implements OnInit {
{id: 'number', label: 'Number', active: true, sortable: true}, {id: 'number', label: 'Number', active: true, sortable: true},
{id: 'material.numbers', label: 'Material numbers', active: false, sortable: false}, {id: 'material.numbers', label: 'Material numbers', active: false, sortable: false},
{id: 'material.name', label: 'Material name', active: true, sortable: true}, {id: 'material.name', label: 'Material name', active: true, sortable: true},
{id: 'material.supplier', label: 'Supplier', active: true, sortable: true}, {id: 'material.supplier', label: 'Supplier', active: false, sortable: true},
{id: 'material.group', label: 'Material', active: false, sortable: true}, {id: 'material.group', label: 'Material', active: true, sortable: true},
{id: 'type', label: 'Type', active: true, sortable: true}, {id: 'type', label: 'Type', active: true, sortable: true},
{id: 'color', label: 'Color', active: true, sortable: true}, {id: 'color', label: 'Color', active: false, sortable: true},
{id: 'batch', label: 'Batch', active: true, sortable: true}, {id: 'batch', label: 'Batch', active: true, sortable: true},
{id: 'notes', label: 'Notes', active: false, sortable: false}, {id: 'notes', label: 'Notes', active: false, sortable: false},
{id: 'status', label: 'Status', active: true, sortable: true}, {id: 'status', label: 'Status', active: false, sortable: true},
{id: 'added', label: 'Added', active: true, sortable: true} {id: 'added', label: 'Added', active: true, sortable: true}
]; ];
isActiveKey: {[key: string]: boolean} = {}; isActiveKey: {[key: string]: boolean} = {};
@ -83,6 +87,7 @@ export class SamplesComponent implements OnInit {
activeTemplateKeys = {material: [], condition: [], 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
loading = 0;
constructor( constructor(
@ -97,9 +102,9 @@ export class SamplesComponent implements OnInit {
} }
ngOnInit(): void { ngOnInit(): void {
let loading = 8; this.loading = 8;
const onLoad = () => { const onLoad = () => {
if ((--loading) <= 0) { if ((--this.loading) <= 0) {
this.loadSamples(); this.loadSamples();
} }
}; };
@ -178,7 +183,9 @@ export class SamplesComponent implements OnInit {
} }
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.loading ++;
this.api.get(this.sampleUrl({paging: true, pagingOptions: options}), (sData, err, headers) => { this.api.get(this.sampleUrl({paging: true, pagingOptions: options}), (sData, err, headers) => {
this.loading --;
if (err) { if (err) {
this.storage.remove('samplesPreferences'); this.storage.remove('samplesPreferences');
this.api.requestError(err); this.api.requestError(err);
@ -317,12 +324,15 @@ export class SamplesComponent implements OnInit {
this.updateActiveKeys(); this.updateActiveKeys();
} }
// TODO: avoid reloading
resetPreferences() {
this.storage.remove('samplesPreferences');
this.window.location.reload();
}
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;
if (filter.active) {
this.loadSamples({firstPage: true});
}
} }
setSort(string) { setSort(string) {

View File

@ -4,6 +4,7 @@ import {UserModel} from '../models/user.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';
// TODO: somehow mail change triggered
@Component({ @Component({
selector: 'app-users', selector: 'app-users',