code improvements

This commit is contained in:
VLE2FE
2020-09-03 15:51:53 +02:00
parent 1440e9a6fc
commit c38d0be457
73 changed files with 276 additions and 1686 deletions

View File

@ -1,76 +1,5 @@
// import { async, ComponentFixture, TestBed } from '@angular/core/testing';
//
// import { SampleComponent } from './sample.component';
// import {ApiService} from '../services/api.service';
// import {ValidationService} from '../services/validation.service';
// import {DataService} from '../services/data.service';
// import {ModalService, RbUiComponentsModule} from '@inst-iot/bosch-angular-ui-components';
// import {FormsModule} from '@angular/forms';
// import {ActivatedRoute, Router} from '@angular/router';
// import {AutocompleteService} from '../services/autocomplete.service';
// import {RbCustomInputsModule} from '../rb-custom-inputs/rb-custom-inputs.module';
//
// // TODO
//
// let routerServiceSpy: jasmine.SpyObj<Router>;
// let activatedRouteServiceSpy: jasmine.SpyObj<ActivatedRoute>;
// let apiServiceSpy: jasmine.SpyObj<ApiService>;
// let validationServiceSpy: jasmine.SpyObj<ValidationService>;
// let autocompleteServiceSpy: jasmine.SpyObj<AutocompleteService>;
// let modalServiceSpy: jasmine.SpyObj<ModalService>;
// let dataServiceSpy: jasmine.SpyObj<DataService>;
//
// describe('SampleComponent', () => {
// let component: SampleComponent;
// let fixture: ComponentFixture<SampleComponent>;
//
// beforeEach(async(() => {
// const routerSpy = jasmine.createSpyObj('Router', ['navigate']);
// const activatedRouteSpy = jasmine.createSpyObj('ActivatedRoute', ['snapshot']);
// const apiSpy = jasmine.createSpyObj('ApiService', ['get', 'post', 'put', 'delete']);
// const validationSpy = jasmine.createSpyObj('ValidationService', ['generate']);
// const autocompleteSpy = jasmine.createSpyObj('AutocompleteService', ['bind']);
// const modalSpy = jasmine.createSpyObj('ModalService', ['open']);
// const dataSpy = jasmine.createSpyObj('DataService', ['load', 'idReload']);
//
// TestBed.configureTestingModule({
// declarations: [ SampleComponent ],
// imports: [
// RbUiComponentsModule,
// RbCustomInputsModule,
// FormsModule
// ],
// providers: [
// {provide: Router, useValue: routerSpy},
// {provide: ActivatedRoute, useValue: {snapshot: {paramMap: {get: (id) => '12345'}}}},
// {provide: ApiService, useValue: apiSpy},
// {provide: ValidationService, useValue: validationSpy},
// {provide: AutocompleteService, useValue: autocompleteSpy},
// {provide: ModalService, useValue: modalSpy},
// {provide: DataService, useValue: dataSpy}
// ]
// })
// .compileComponents();
//
// routerServiceSpy = TestBed.inject(Router) as jasmine.SpyObj<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>;
//
// // activatedRouteServiceSpy.snapshot.and.returnValue({paramMap: {get: () => '12345'}});
// }));
//
// beforeEach(() => {
// fixture = TestBed.createComponent(SampleComponent);
// component = fixture.componentInstance;
// component.ngOnInit();
// fixture.detectChanges();
// });
//
// it('should create', () => {
// expect(component).toBeTruthy();
// });
// });
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
describe('SampleComponent', () => {
});

View File

@ -25,8 +25,6 @@ import {ModalService} from '@inst-iot/bosch-angular-ui-components';
import {DataService} from '../services/data.service';
import {LoginService} from '../services/login.service';
// TODO: additional property value not validated on edit
@Component({
selector: 'app-sample',
templateUrl: './sample.component.html',
@ -81,8 +79,9 @@ export class SampleComponent implements OnInit, AfterContentChecked {
checkFormAfterInit = false;
modalText = {list: '', suggestion: ''};
cmSampleIndex = '0';
measurementDeleteList = []; // buffer with measurements to delete, if the user confirms and saves the cm changes
measurementRestoreData: MeasurementModel[] = []; // deleted measurements if user is allowed and measurements are available
measurementDeleteList = []; // buffer with measurements to delete, if the user confirms and saves the cm changes
// deleted measurements if user is allowed and measurements are available
measurementRestoreData: MeasurementModel[] = [];
charts = [[]]; // chart data for spectra
readonly chartInit = [{
@ -118,7 +117,6 @@ export class SampleComponent implements OnInit, AfterContentChecked {
) { }
ngOnInit(): void {
console.log(this.baseSample);
this.mode = this.router.url === '/samples/new' ? 'new' : '';
this.loading = 7;
this.d.load('materials', () => {
@ -150,7 +148,8 @@ export class SampleComponent implements OnInit, AfterContentChecked {
});
this.d.load('materialTemplates', () => {
if (!this.material.properties.material_template) {
this.material.properties.material_template = this.d.latest.materialTemplates.find(e => e.name === 'plastic')._id;
this.material.properties.material_template =
this.d.latest.materialTemplates.find(e => e.name === 'plastic')._id;
}
this.loading--;
});
@ -167,9 +166,9 @@ export class SampleComponent implements OnInit, AfterContentChecked {
if (this.login.isLevel.dev) { // load measurement restore data
this.api.get<MeasurementModel[]>('/measurement/sample/' + sampleIds[0], (data, ignore) => {
if (data) {
this.measurementRestoreData = data.filter(e => e.status === 'deleted').map(e => new MeasurementModel().deserialize(e));
this.measurementRestoreData =
data.filter(e => e.status === 'deleted').map(e => new MeasurementModel().deserialize(e));
}
console.log(this.measurementRestoreData);
});
}
}
@ -182,7 +181,8 @@ export class SampleComponent implements OnInit, AfterContentChecked {
this.samples = [new SampleModel().deserialize(sData)];
this.baseSample.deserialize(sData);
this.material = new MaterialModel().deserialize(sData.material); // read material
this.customFields = this.baseSample.notes.custom_fields && this.baseSample.notes.custom_fields !== {} ? // read custom fields
// read custom fields
this.customFields = this.baseSample.notes.custom_fields && this.baseSample.notes.custom_fields !== {} ?
Object.keys(this.baseSample.notes.custom_fields).map(e => [e, this.baseSample.notes.custom_fields[e]]) : [];
if (this.baseSample.notes.sample_references.length) { // read sample references
this.sampleReferences = [];
@ -214,11 +214,10 @@ export class SampleComponent implements OnInit, AfterContentChecked {
}
this.checkFormAfterInit = true;
this.loading--;
sampleIds.slice(1).forEach(sampleId => {
sampleIds.slice(1).forEach(sampleId => { // load further samples for batch edit
this.api.get<SampleModel>('/sample/' + sampleId, data => {
this.samples.push(new SampleModel().deserialize(data));
['type', 'color', 'batch', 'notes'].forEach((key) => {
console.log(isEqual(data[key], this.baseSample[key]));
if (!isEqual(data[key], this.baseSample[key])) {
this.baseSample[key] = undefined;
}
@ -228,7 +227,6 @@ export class SampleComponent implements OnInit, AfterContentChecked {
}
this.loading--;
this.checkFormAfterInit = true;
console.log(this.baseSample.material.name);
});
});
});
@ -239,6 +237,7 @@ export class SampleComponent implements OnInit, AfterContentChecked {
}
ngAfterContentChecked() {
// attach validators
if (this.samples.length) { // conditions are displayed
this.samples.forEach((gSample, gIndex) => {
if (this.d.id.conditionTemplates[gSample.condition.condition_template]) {
@ -260,6 +259,7 @@ export class SampleComponent implements OnInit, AfterContentChecked {
});
}
// revalidate inputs
if (this.checkFormAfterInit) {
if (this.view.base) { // validate sampleForm
if (this.sampleForm !== undefined && this.sampleForm.form.get('cf-key0')) {
@ -277,13 +277,13 @@ export class SampleComponent implements OnInit, AfterContentChecked {
(this.d.id.conditionTemplates[this.samples[0].condition.condition_template].parameters.length - 1)) as any;
}
if (this.samples[0].measurements.length) { // if there are measurements, last measurement field exists
formReady = formReady && this.cmForm.form.get('measurementParameter-0-' + (this.samples[0].measurements.length - 1) +
formReady = formReady &&
this.cmForm.form.get('measurementParameter-0-' + (this.samples[0].measurements.length - 1) +
'-' + (this.d.id.measurementTemplates[this.samples[0].measurements[this.samples[0].measurements.length - 1]
.measurement_template].parameters.length - 1)) as any;
}
if (formReady) { // fields are ready, do validation
this.checkFormAfterInit = false;
console.log('init');
Object.keys(this.cmForm.form.controls).forEach(field => {
this.cmForm.form.get(field).updateValueAndValidity();
});
@ -346,7 +346,7 @@ export class SampleComponent implements OnInit, AfterContentChecked {
}
});
this.baseSample.notes.sample_references = this.sampleReferences
.filter(e => e[0] && e[1] && e[2])
.filter(e => e[0] && e[1] && e[2]) // filter empty values
.map(e => ({sample_id: e[2], relation: e[1]}));
}
if (this.samples.length === 0) { // only save new sample for the first time in mode new, otherwise save changes
@ -363,7 +363,6 @@ export class SampleComponent implements OnInit, AfterContentChecked {
}
else {
this.samples.forEach((sample, i) => {
console.log(sample._id);
this.api.put<SampleModel>('/sample/' + sample._id, this.baseSample.sendFormat(false), data => {
merge(this.samples[i], omit(data, ['condition']));
this.samples[i].material = this.d.arr.materials.find(e => e._id === this.samples[0].material_id);
@ -381,7 +380,10 @@ export class SampleComponent implements OnInit, AfterContentChecked {
if (sample.condition.condition_template) { // condition was set
this.api.put('/sample/' + sample._id,
{condition: pick(sample.condition,
['condition_template', ...this.d.id.conditionTemplates[sample.condition.condition_template].parameters.map(e => e.name)]
[
'condition_template',
...this.d.id.conditionTemplates[sample.condition.condition_template].parameters.map(e => e.name)
]
)}
);
}
@ -439,7 +441,8 @@ export class SampleComponent implements OnInit, AfterContentChecked {
else { // no matching material found
if (this.baseSample.material_id !== null) { // reset previous match
this.material = new MaterialModel();
this.material.properties.material_template = this.d.latest.materialTemplates.find(e => e.name === 'plastic')._id;
this.material.properties.material_template =
this.d.latest.materialTemplates.find(e => e.name === 'plastic')._id;
}
this.baseSample.material_id = null;
}
@ -450,8 +453,8 @@ export class SampleComponent implements OnInit, AfterContentChecked {
setNewMaterial(value = null) {
if (value === null) { // toggle dialog
this.newMaterial = !this.baseSample.material_id;
}
else if (value || (!value && this.baseSample.material_id !== null )) { // set to false only if material already exists
} // set to false only if material already exists
else if (value || (!value && this.baseSample.material_id !== null )) {
this.newMaterial = value;
}
if (this.newMaterial) { // set validators if dialog is open
@ -476,7 +479,7 @@ export class SampleComponent implements OnInit, AfterContentChecked {
}
// remove the measurement at the specified index
removeMeasurement(gIndex, mIndex) { // TODO: do not delete directly but only after confirmation
removeMeasurement(gIndex, mIndex) {
if (this.samples[gIndex].measurements[mIndex]._id !== null) {
this.measurementDeleteList.push(this.samples[gIndex].measurements[mIndex]._id);
}
@ -490,7 +493,7 @@ export class SampleComponent implements OnInit, AfterContentChecked {
this.samples[gIndex].measurements[mIndex].values = {};
}
fileToArray(files, gIndex, mIndex, parameter) {
fileToArray(files, gIndex, mIndex, parameter) { // process spectrum file input
for (const i in files) {
if (files.hasOwnProperty(i)) {
const fileReader = new FileReader();
@ -500,6 +503,7 @@ export class SampleComponent implements OnInit, AfterContentChecked {
this.addMeasurement(gIndex);
index = this.samples[gIndex].measurements.length - 1;
}
// autofill further parameters
this.samples[gIndex].measurements[index].values.device =
this.samples[gIndex].measurements[mIndex].values.device;
this.samples[gIndex].measurements[index].values.filename = files[i].name;
@ -578,17 +582,18 @@ export class SampleComponent implements OnInit, AfterContentChecked {
this.sampleReferenceIdFind(value);
}
sampleReferenceList(value) {
sampleReferenceList(value) { // get list of sample reference number suggestions
return new Observable(observer => {
if (value !== '') {
this.api.get<{ _id: string, number: string }[]>(
'/samples?status[]=validated&status[]=new&page-size=25&sort=number-asc&fields[]=number&fields[]=_id&' +
'filters[]=%7B%22mode%22%3A%22stringin%22%2C%22field%22%3A%22number%22%2C%22values%22%3A%5B%22' + value + '%22%5D%7D', data => {
this.sampleReferenceAutocomplete[this.currentSRIndex] = data.map(e => e.number);
this.sampleReferenceFinds = data;
observer.next(data.map(e => e.number));
observer.complete();
this.sampleReferenceIdFind(value);
'filters[]=%7B%22mode%22%3A%22stringin%22%2C%22field%22%3A%22number%22%2C%22values%22%3A%5B%22' + value +
'%22%5D%7D', data => {
this.sampleReferenceAutocomplete[this.currentSRIndex] = data.map(e => e.number);
this.sampleReferenceFinds = data;
observer.next(data.map(e => e.number));
observer.complete();
this.sampleReferenceIdFind(value);
});
}
else {
@ -598,7 +603,7 @@ export class SampleComponent implements OnInit, AfterContentChecked {
});
}
sampleReferenceIdFind(value) {
sampleReferenceIdFind(value) { // sample reference id from number
const idFind = this.sampleReferenceFinds.find(e => e.number === value);
if (idFind) {
this.sampleReferences[this.currentSRIndex][2] = idFind._id;
@ -626,11 +631,3 @@ export class SampleComponent implements OnInit, AfterContentChecked {
}
}
}
// 1. ngAfterViewInit wird ja jedes mal nach einem ngOnChanges aufgerufen, also zB wenn sich dein ngFor aufbaut. Du könntest also in der
// Methode prüfen, ob die Daten schon da sind und dann dementsprechend handeln. Das wäre die Eleganteste Variante
// 2. Der state "dirty" soll eigentlich anzeigen, wenn ein Form-Field vom User geändert wurde; damit missbrauchst du es hier etwas
// 3. Die Dirty-Variante: Pack in deine ngFor ein {{ onFirstLoad(data) }} rein, das einfach ausgeführt wird. müsstest dann natürlich
// abfangen, dass das nicht nach jedem view-cycle neu getriggert wird. Schön ist das nicht, aber besser als mit Timeouts^^