diff --git a/karma.conf.js b/karma.conf.js index 6df3baf..7603521 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -13,7 +13,10 @@ module.exports = function (config) { require('@angular-devkit/build-angular/plugins/karma') ], 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: { dir: require('path').join(__dirname, './coverage/definma'), diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 320f25c..0b415c5 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -2,7 +2,6 @@ import { Component, isDevMode} from '@angular/core'; import {LoginService} from './services/login.service'; import {NavigationStart, Router} from '@angular/router'; -// TODO: filter by not completely filled/no measurements // TODO: get rid of chart.js (+moment.js) @@ -19,7 +18,8 @@ export class AppComponent { constructor( public login: LoginService, - public router: Router + public router: Router, + private window: Window ) { this.devMode = isDevMode(); this.router.events.subscribe(event => { @@ -38,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. %0D%0A%0D%0A--- REPORT DATA --- %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%0AappCodeName: ${navigator.appCodeName} %0D%0AappVersion: ${navigator.appVersion} @@ -47,8 +47,8 @@ URL: ${window.location}%0D%0A%0D%0AWhat did you do?%0D%0A${encodeURIComponent(th %0D%0Aoscpu: ${navigator.oscpu} %0D%0Aplatform: ${navigator.platform} %0D%0AuserAgent: ${navigator.userAgent} -%0D%0AinnerWidth: ${window.innerWidth} -%0D%0AinnerHeight: ${window.innerHeight}`; +%0D%0AinnerWidth: ${this.window.innerWidth} +%0D%0AinnerHeight: ${this.window.innerHeight}`; } closeBugReport(close) { @@ -56,7 +56,7 @@ URL: ${window.location}%0D%0A%0D%0AWhat did you do?%0D%0A${encodeURIComponent(th } toTheTop() { - window.scroll(0, 0); + this.window.scroll(0, 0); } } diff --git a/src/app/rb-custom-inputs/rb-table/rb-table.component.scss b/src/app/rb-custom-inputs/rb-table/rb-table.component.scss index 57f52f6..d05e75f 100644 --- a/src/app/rb-custom-inputs/rb-table/rb-table.component.scss +++ b/src/app/rb-custom-inputs/rb-table/rb-table.component.scss @@ -34,5 +34,6 @@ table.ellipsis { white-space: nowrap; overflow: hidden; max-width: 200px; + //min-width: 100px; } } diff --git a/src/app/samples/samples.component.html b/src/app/samples/samples.component.html index 69a14f9..340f824 100644 --- a/src/app/samples/samples.component.html +++ b/src/app/samples/samples.component.html @@ -73,7 +73,7 @@ (ngModelChange)="updateFilterFields(filter.field)"> + (filter.field == 'added' ? 'date' : (filter.field == 'type' ? 'type' : ''))"> @@ -86,6 +86,12 @@ [rbDebounceTime]="0" (keydown)="preventDefault($event, 'Enter')" [rbFormInputAutocomplete]="autocomplete.bind(this, filter.autocomplete)" ngModel> + + + + @@ -132,17 +138,17 @@ all - +
{{key.label}} - +
- +
@@ -165,6 +171,9 @@ {{sample.type}} {{sample.color}} {{sample.batch}} + + {{sample.condition ? sample.condition[key[1]] : '' | exists}} + {{sample.notes | object: ['_id', 'sample_references']}} {{sample[key[1]] | exists: key[2]}} {{sample.status}} @@ -188,7 +197,7 @@ - + of {{pages}} ({{totalSamples}} samples) diff --git a/src/app/samples/samples.component.scss b/src/app/samples/samples.component.scss index 4c4df56..5b7e7d0 100644 --- a/src/app/samples/samples.component.scss +++ b/src/app/samples/samples.component.scss @@ -54,7 +54,7 @@ rb-table { .paging { height: 50px; rb-form-input { - max-width: 50px; + max-width: 65px; } > * { @@ -72,23 +72,34 @@ rb-table { } .sort-header { - display: inline-grid; - grid-template-columns: 1fr auto; - grid-column-gap: 5px; width: 100%; + position: relative; - :first-child { - grid-row: span 2; + & > span:first-child { + max-width: 180px; + overflow: hidden; + display: block; + text-overflow: ellipsis; + margin-right: 20px; } - :nth-child(2) { - margin-bottom: -3px; - cursor: pointer; - } + div { + display: grid; + grid-template-columns: 1fr; + position: absolute; + right: 0; + top: 0; + background: #FFF; - :nth-child(3) { - margin-top: -3px; - cursor: pointer; + :nth-child(1) { + margin-bottom: -3px; + cursor: pointer; + } + + :nth-child(2) { + margin-top: -3px; + cursor: pointer; + } } } diff --git a/src/app/samples/samples.component.ts b/src/app/samples/samples.component.ts index cf0aa27..2b5f0b2 100644 --- a/src/app/samples/samples.component.ts +++ b/src/app/samples/samples.component.ts @@ -78,7 +78,7 @@ export class SamplesComponent implements OnInit { ]; isActiveKey: {[key: string]: boolean} = {}; activeKeys: KeyInterface[] = []; - activeTemplateKeys = {material: [], measurements: []}; + activeTemplateKeys = {material: [], condition: [], measurements: []}; sampleDetailsSample: any = null; validation = false; // true to activate validation mode @@ -89,12 +89,13 @@ export class SamplesComponent implements OnInit { public login: LoginService, private modalService: ModalService, public d: DataService, - private storage: LocalStorageService + private storage: LocalStorageService, + private window: Window ) { } ngOnInit(): void { - let loading = 7; + let loading = 8; const onLoad = () => { if ((--loading) <= 0) { this.loadSamples(); @@ -117,6 +118,7 @@ export class SamplesComponent implements OnInit { this.d.load('userKey', onLoad); this.d.load('conditionTemplates', onLoad); this.loadTemplateKeys('material', 'type', onLoad); + this.loadTemplateKeys('condition', 'notes', onLoad); this.loadTemplateKeys('measurement', 'status', onLoad); } @@ -128,15 +130,16 @@ export class SamplesComponent implements OnInit { const parameterName = encodeURIComponent(parameter.name); // exclude spectrum and duplicates 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({ - id: `${collection === 'material' ? 'material.properties' : collection + 's.' + item.name}.${parameterName}`, - label: `${this.ucFirst(item.name)} ${this.ucFirst(parameter.name)}`, + id: `${collectionNames[collection]}.${parameterName}`, + label: `${this.ucFirst(item.name)} ${parameter.name}`, active: false, sortable: true }); this.filters.filters.push({ - field: `${collection === 'material' ? 'material.properties' : collection + 's.' + item.name}.${parameterName}`, - label: `${this.ucFirst(item.name)} ${this.ucFirst(parameter.name)}`, + field: `${collectionNames[collection]}.${parameterName}`, + label: `${this.ucFirst(item.name)} ${parameter.name}`, active: false, autocomplete: [], mode: 'eq', @@ -153,6 +156,7 @@ export class SamplesComponent implements OnInit { } loadSamples(options: LoadSamplesOptions = {}, event = null) { // set toPage to null to reload first page, queues calls + console.log(this.isActiveKey); if (event) { // adjust active keys this.keys.forEach(key => { if (event.hasOwnProperty(key.id)) { @@ -169,15 +173,21 @@ export class SamplesComponent implements OnInit { } 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) => { - if (!options.toPage && headers['x-total-items']) { - this.totalSamples = headers['x-total-items']; + this.api.get(this.sampleUrl({paging: true, pagingOptions: options}), (sData, err, headers) => { + if (err) { + this.storage.remove('samplesPreferences'); + this.api.requestError(err); } - this.pages = Math.ceil(this.totalSamples / this.filters.pageSize); - this.samples = sData as any; - this.loadSamplesQueue.shift(); - if (this.loadSamplesQueue.length > 0) { // execute next queue item - this.sampleLoader(this.loadSamplesQueue[0]); + else { + if (!options.toPage && headers['x-total-items']) { + this.totalSamples = headers['x-total-items']; + } + this.pages = Math.ceil(this.totalSamples / this.filters.pageSize); + this.samples = sData as any; + this.loadSamplesQueue.shift(); + if (this.loadSamplesQueue.length > 0) { // execute next queue item + this.sampleLoader(this.loadSamplesQueue[0]); + } } }); } @@ -216,7 +226,7 @@ export class SamplesComponent implements OnInit { } this.keys.forEach(key => { // 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); } }); @@ -253,12 +263,13 @@ export class SamplesComponent implements OnInit { query.push('fields[]=condition'); } } - return (options.host && isDevMode() ? window.location.host : '') + + return (options.host && isDevMode() ? this.window.location.host : '') + (options.export ? this.api.hostName : '') + '/samples?' + query.join('&'); } loadPage(delta) { + console.log(delta); if (!/[0-9]+/.test(delta) || (this.page <= 1 && delta < 0)) { // invalid delta return; } @@ -293,9 +304,9 @@ export class SamplesComponent implements OnInit { this.keys[keyIndex].active = key.active; } }); - this.calcFieldSelectKeys(); - this.updateActiveKeys(); } + this.calcFieldSelectKeys(); + this.updateActiveKeys(); } updateFilterFields(field) { @@ -313,10 +324,18 @@ export class SamplesComponent implements OnInit { updateActiveKeys() { // array with all activeKeys 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 .filter(e => e.id.indexOf('material.properties.') >= 0 && e.active) .map(e => e.id.split('.') .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) .map(e => e.id.split('.') .map(el => decodeURIComponent(el))); diff --git a/src/app/services/api.service.ts b/src/app/services/api.service.ts index 2771787..fe875da 100644 --- a/src/app/services/api.service.ts +++ b/src/app/services/api.service.ts @@ -44,24 +44,29 @@ export class ApiService { observable.subscribe(data => { f(data.body, undefined, data.headers.keys().reduce((s, e) => {s[e.toLowerCase()] = data.headers.get(e); return s; }, {})); }, err => { - if (f.length === 2) { - f(undefined, err); + console.log(f.length); + if (f.length > 1) { + f(undefined, err, undefined); } else { - const modalRef = this.modalService.openComponent(ErrorComponent); - modalRef.instance.message = 'Network request failed!'; - const details = [err.error.status]; - if (err.error.details) { - details.push(err.error.details); - } - modalRef.instance.details = details; - modalRef.result.then(() => { - this.window.location.reload(); - }); + this.requestError(err); } }); } + requestError(err) { + const modalRef = this.modalService.openComponent(ErrorComponent); + modalRef.instance.message = 'Network request failed!'; + const details = [err.error.status]; + if (err.error.details) { + details.push(err.error.details); + } + modalRef.instance.details = details; + modalRef.result.then(() => { + this.window.location.reload(); + }); + } + private url(url) { if (/http[s]?:\/\//.test(url)) { return url;