Change the first character of all end-of-line comments to upper case
This commit is contained in:
parent
c2aead6799
commit
f0ed0a0e68
@ -38,7 +38,7 @@ const routes: Routes = [
|
||||
{path: 'documentation/database', component: DocumentationDatabaseComponent},
|
||||
{path: 'documentation/models', component: DocumentationModelsComponent},
|
||||
|
||||
// if not authenticated
|
||||
// If not authenticated
|
||||
{ path: '**', redirectTo: '' }
|
||||
];
|
||||
|
||||
|
@ -14,8 +14,8 @@ import {DataService} from './services/data.service';
|
||||
})
|
||||
export class AppComponent implements OnInit{
|
||||
|
||||
bugReport = {do: '', work: ''}; // data from bug report inputs
|
||||
isDocumentation = false; // true if user is on documentation pages
|
||||
bugReport = {do: '', work: ''}; // Data from bug report inputs
|
||||
isDocumentation = false; // True if user is on documentation pages
|
||||
devMode = false;
|
||||
|
||||
constructor(
|
||||
@ -35,9 +35,9 @@ export class AppComponent implements OnInit{
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
// try to log in user
|
||||
// Try to log in user
|
||||
this.login.login().then(res => {
|
||||
// return to home page if log failed, except when on documentation pages
|
||||
// Return to home page if log failed, except when on documentation pages
|
||||
if (!res && !(/\/documentation/.test(this.router.url))) {
|
||||
this.router.navigate(['/']);
|
||||
}
|
||||
|
@ -10,10 +10,10 @@ import {ModalService} from '@inst-iot/bosch-angular-ui-components';
|
||||
})
|
||||
export class ChangelogComponent implements OnInit {
|
||||
|
||||
timestamp = new Date(); // time from date input
|
||||
timestamp = new Date(); // Time from date input
|
||||
pageSize = 25;
|
||||
changelog: ChangelogModel[] = [];
|
||||
modalDetail = 0; // index of changelog element to show details of
|
||||
modalDetail = 0; // Index of changelog element to show details of
|
||||
|
||||
constructor(
|
||||
private api: ApiService,
|
||||
@ -24,21 +24,21 @@ export class ChangelogComponent implements OnInit {
|
||||
this.loadChangelog();
|
||||
}
|
||||
|
||||
loadChangelog(page = 0) { // load changelog with page no relative to current page
|
||||
loadChangelog(page = 0) { // Load changelog with page no relative to current page
|
||||
this.api.get<ChangelogModel[]>(`/changelog/${
|
||||
page > 0 ? this.changelog[0]._id : // use id if no new date was given
|
||||
page > 0 ? this.changelog[0]._id : // Use id if no new date was given
|
||||
Math.floor(new Date(
|
||||
new Date(this.timestamp).getTime() - new Date(this.timestamp).getTimezoneOffset() * 60000 // adjust timezone
|
||||
).getTime() / 1000).toString(16) + '0000000000000000' // id from time
|
||||
new Date(this.timestamp).getTime() - new Date(this.timestamp).getTimezoneOffset() * 60000 // Adjust timezone
|
||||
).getTime() / 1000).toString(16) + '0000000000000000' // Id from time
|
||||
}/${page}/${this.pageSize}`, data => {
|
||||
this.changelog = data.map(e => new ChangelogModel().deserialize(e));
|
||||
if (page) { // adjust date picker to new first element when user clicked on next page
|
||||
if (page) { // Adjust date picker to new first element when user clicked on next page
|
||||
this.timestamp = new Date(this.changelog[0].date);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// show details of a changelog element with reference to needed modal
|
||||
// Show details of a changelog element with reference to needed modal
|
||||
showDetails(i: number, modal: TemplateRef<any>) {
|
||||
this.modalDetail = i;
|
||||
this.modal.open(modal).then(() => {});
|
||||
|
@ -7,8 +7,8 @@ import { Component, OnInit } from '@angular/core';
|
||||
})
|
||||
export class ErrorComponent implements OnInit {
|
||||
|
||||
message = ''; // main error message
|
||||
details: string[] = []; // array of error detail paragraphs
|
||||
message = ''; // Main error message
|
||||
details: string[] = []; // Array of error detail paragraphs
|
||||
|
||||
constructor() { }
|
||||
|
||||
|
@ -12,8 +12,8 @@ import {LoginService} from '../services/login.service';
|
||||
})
|
||||
export class HelpComponent implements OnInit {
|
||||
|
||||
content: HelpModel = new HelpModel().deserialize({text: null, level: 'none'}); // help content
|
||||
edit = false; // set true to change to edit mode
|
||||
content: HelpModel = new HelpModel().deserialize({text: null, level: 'none'}); // Help content
|
||||
edit = false; // Set true to change to edit mode
|
||||
private route = ''; // URIComponent encoded route which serves as a key to fetch the help document
|
||||
|
||||
constructor(
|
||||
@ -24,10 +24,10 @@ export class HelpComponent implements OnInit {
|
||||
) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
// remove ids from path
|
||||
// Remove ids from path
|
||||
this.route = encodeURIComponent(this.router.url.replace(/\/[0-9a-f]{24}/, ''));
|
||||
this.api.get<HelpModel>('/help/' + this.route, (data, err) => {
|
||||
if (!err) { // content was found
|
||||
if (!err) { // Content was found
|
||||
this.content = new HelpModel().deserialize(data);
|
||||
}
|
||||
else {
|
||||
|
@ -45,7 +45,7 @@ export class HomeComponent implements OnInit {
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
temp.push({ id: data[i], count: 0, active: false });
|
||||
}
|
||||
this.keys = temp; // invoke update in rb-multiselect
|
||||
this.keys = temp; // Invoke update in rb-multiselect
|
||||
this.initChart();
|
||||
|
||||
// Only neccesary if keys get preselected
|
||||
@ -60,7 +60,7 @@ export class HomeComponent implements OnInit {
|
||||
let query = '/samples?status%5B%5D=validated&status=new&filters%5B%5D=%7B%22mode%22%3A%22in%22%2C%22field%22%3A%22material.group%22%2C%22values%22%3A%5B';
|
||||
let temp = '';
|
||||
this.keys.forEach(key => {
|
||||
temp += key.active ? '%22' + key.id.split("%").join("%25") + '%22%2C' : ""; // replace split().join() with replaceAll()
|
||||
temp += key.active ? '%22' + key.id.split("%").join("%25") + '%22%2C' : ""; // Replace split().join() with replaceAll()
|
||||
});
|
||||
if (temp === '') {
|
||||
this.countSamples('');
|
||||
|
@ -7,13 +7,13 @@ import {AfterViewInit, Component, ElementRef, Input, OnInit, ViewChild} from '@a
|
||||
})
|
||||
export class ImgMagnifierComponent implements OnInit, AfterViewInit {
|
||||
|
||||
@Input() src: string; // image source
|
||||
@Input() zoom: number; // zoom level
|
||||
@Input() magnifierSize: {width: number, height: number}; // size of the magnifier
|
||||
@Input() src: string; // Image source
|
||||
@Input() zoom: number; // Zoom level
|
||||
@Input() magnifierSize: {width: number, height: number}; // Size of the magnifier
|
||||
@ViewChild('mainImg') mainImg: ElementRef;
|
||||
|
||||
backgroundSize;
|
||||
magnifierPos = {x: 0, y: 0}; // position of the magnifier
|
||||
magnifierPos = {x: 0, y: 0}; // Position of the magnifier
|
||||
showMagnifier = false;
|
||||
|
||||
constructor(
|
||||
@ -29,7 +29,7 @@ export class ImgMagnifierComponent implements OnInit, AfterViewInit {
|
||||
}, 1);
|
||||
}
|
||||
|
||||
calcPos(event) { // calculate the current magnifier position
|
||||
calcPos(event) { // Calculate the current magnifier position
|
||||
const img = this.mainImg.nativeElement.getBoundingClientRect();
|
||||
this.magnifierPos.x = Math.min(
|
||||
img.width - this.magnifierSize.width,
|
||||
|
@ -12,11 +12,11 @@ import {ApiService} from '../services/api.service';
|
||||
})
|
||||
export class LoginComponent implements OnInit {
|
||||
|
||||
username = ''; // credentials
|
||||
username = ''; // Credentials
|
||||
password = '';
|
||||
email = '';
|
||||
message = ''; // message below login fields
|
||||
passreset = false; // to toggle between normal login and password reset form
|
||||
message = ''; // Message below login fields
|
||||
passreset = false; // To toggle between normal login and password reset form
|
||||
|
||||
@ViewChild('loginForm') loginForm;
|
||||
|
||||
@ -32,7 +32,7 @@ export class LoginComponent implements OnInit {
|
||||
}
|
||||
|
||||
userLogin() {
|
||||
if (this.passreset) { // reset password
|
||||
if (this.passreset) { // Reset password
|
||||
this.api.post('/user/passreset', {name: this.username, email: this.email}, (data, err) => {
|
||||
if (err) {
|
||||
this.message = 'Could not find a valid user';
|
||||
@ -49,7 +49,7 @@ export class LoginComponent implements OnInit {
|
||||
if (this.login.isLevel.read) {
|
||||
this.router.navigate(['/samples']);
|
||||
}
|
||||
else { // navigate prediction users to prediction as they cannot access samples
|
||||
else { // Navigate prediction users to prediction as they cannot access samples
|
||||
this.router.navigate(['/prediction']);
|
||||
}
|
||||
}
|
||||
|
@ -19,12 +19,12 @@ export class MaterialComponent implements OnInit, AfterContentChecked {
|
||||
|
||||
@ViewChild('materialForm') materialForm: NgForm;
|
||||
|
||||
material: MaterialModel; // material to edit
|
||||
materialNames: string[] = []; // all other material names for unique validation
|
||||
material: MaterialModel; // Material to edit
|
||||
materialNames: string[] = []; // All other material names for unique validation
|
||||
|
||||
modalText = {list: '', suggestion: ''}; // modal for group and supplier correction
|
||||
loading = 0; // number of loading instances
|
||||
checkFormAfterInit = true; // revalidate all fields on the next AfterContentChecked
|
||||
modalText = {list: '', suggestion: ''}; // Modal for group and supplier correction
|
||||
loading = 0; // Number of loading instances
|
||||
checkFormAfterInit = true; // Revalidate all fields on the next AfterContentChecked
|
||||
|
||||
constructor(
|
||||
private api: ApiService,
|
||||
@ -42,7 +42,7 @@ export class MaterialComponent implements OnInit, AfterContentChecked {
|
||||
this.material = new MaterialModel().deserialize(data);
|
||||
this.loading--;
|
||||
this.d.load('materials', () => {
|
||||
// filter out name of the edited material as it can stay the same
|
||||
// Filter out name of the edited material as it can stay the same
|
||||
this.materialNames = this.d.arr.materials.map(e => e.name).filter(e => e !== this.material.name);
|
||||
this.loading--;
|
||||
});
|
||||
@ -59,14 +59,14 @@ export class MaterialComponent implements OnInit, AfterContentChecked {
|
||||
}
|
||||
|
||||
ngAfterContentChecked() {
|
||||
// attach validators
|
||||
if (this.materialForm && this.material.properties.material_template) { // material template is set
|
||||
// Attach validators
|
||||
if (this.materialForm && this.material.properties.material_template) { // Material template is set
|
||||
this.d.id.materialTemplates[this.material.properties.material_template].parameters.forEach((parameter, i) => {
|
||||
this.attachValidator(this.materialForm, 'materialParameter' + i, parameter.range);
|
||||
});
|
||||
}
|
||||
|
||||
// revalidate
|
||||
// Revalidate
|
||||
if (this.checkFormAfterInit && this.materialForm !== undefined && this.materialForm.form.get('propertiesSelect')) {
|
||||
this.checkFormAfterInit = false;
|
||||
Object.keys(this.materialForm.form.controls).forEach(field => {
|
||||
@ -75,7 +75,7 @@ export class MaterialComponent implements OnInit, AfterContentChecked {
|
||||
}
|
||||
}
|
||||
|
||||
// attach validators specified in range to input with name
|
||||
// Attach validators specified in range to input with name
|
||||
attachValidator(form, name: string, range: {[prop: string]: any}) {
|
||||
if (form && form.form.get(name)) {
|
||||
const validators = [];
|
||||
@ -100,7 +100,7 @@ export class MaterialComponent implements OnInit, AfterContentChecked {
|
||||
|
||||
materialSave() {
|
||||
this.api.put('/material/' + this.material._id, this.material.sendFormat(), () => {
|
||||
delete this.d.arr.materials; // reload materials
|
||||
delete this.d.arr.materials; // Reload materials
|
||||
this.d.load('materials');
|
||||
this.router.navigate(['/materials']);
|
||||
});
|
||||
@ -110,7 +110,7 @@ export class MaterialComponent implements OnInit, AfterContentChecked {
|
||||
this.modal.open(modal).then(result => {
|
||||
if (result) {
|
||||
this.api.delete('/material/' + this.material._id, (ignore, error) => {
|
||||
if (error) { // material cannot be deleted as it is still referenced by active samples
|
||||
if (error) { // Material cannot be deleted as it is still referenced by active samples
|
||||
const modalRef = this.modal.openComponent(ErrorComponent);
|
||||
modalRef.instance.message = 'Cannot delete material as it is still in use!';
|
||||
}
|
||||
@ -123,16 +123,16 @@ export class MaterialComponent implements OnInit, AfterContentChecked {
|
||||
}
|
||||
|
||||
checkTypo(event, list, mKey, modal: TemplateRef<any>) {
|
||||
// user did not click on suggestion and entry is not in list
|
||||
// User did not click on suggestion and entry is not in list
|
||||
if (!(event.relatedTarget && (event.relatedTarget.className.indexOf('rb-dropdown-item') >= 0 ||
|
||||
event.relatedTarget.className.indexOf('close-btn rb-btn rb-passive-link') >= 0)) &&
|
||||
this.d.arr[list].indexOf(this.material[mKey]) < 0) {
|
||||
this.modalText.list = mKey;
|
||||
this.modalText.suggestion = this.d.arr[list] // find possible entry from list
|
||||
this.modalText.suggestion = this.d.arr[list] // Find possible entry from list
|
||||
.map(e => ({v: e, s: strCompare.sorensenDice(e, this.material[mKey])}))
|
||||
.sort((a, b) => b.s - a.s)[0].v;
|
||||
this.modal.open(modal).then(result => {
|
||||
if (result) { // use suggestion
|
||||
if (result) { // Use suggestion
|
||||
this.material[mKey] = this.modalText.suggestion;
|
||||
}
|
||||
});
|
||||
|
@ -12,13 +12,13 @@ import {ModalService} from '@inst-iot/bosch-angular-ui-components';
|
||||
})
|
||||
export class MaterialsComponent implements OnInit {
|
||||
|
||||
materials: MaterialModel[] = []; // all materials
|
||||
templateKeys: {key: string, label: string}[] = []; // material template keys
|
||||
materialStatus = {validated: true, new: true, deleted: false}; // material statuses to show
|
||||
materialSearch = ''; // material name search string
|
||||
sampleSelect = false; // set to true to show checkboxes for validation
|
||||
materials: MaterialModel[] = []; // All materials
|
||||
templateKeys: {key: string, label: string}[] = []; // Material template keys
|
||||
materialStatus = {validated: true, new: true, deleted: false}; // Material statuses to show
|
||||
materialSearch = ''; // Material name search string
|
||||
sampleSelect = false; // Set to true to show checkboxes for validation
|
||||
|
||||
page = 1; // page settings
|
||||
page = 1; // Page settings
|
||||
pages = 0;
|
||||
pageSize = 25;
|
||||
|
||||
@ -36,7 +36,7 @@ export class MaterialsComponent implements OnInit {
|
||||
this.templateKeys.push({key: parameter.name, label: `${this.ucFirst(template.name)} ${parameter.name}`});
|
||||
});
|
||||
});
|
||||
// filter out duplicates
|
||||
// Filter out duplicates
|
||||
this.templateKeys = this.templateKeys.filter((e, i, a) => !a.slice(0, i).find(el => el.key === e.key));
|
||||
});
|
||||
}
|
||||
@ -51,7 +51,7 @@ export class MaterialsComponent implements OnInit {
|
||||
}
|
||||
|
||||
validate() {
|
||||
if (this.sampleSelect) { // selection was done do actual validation
|
||||
if (this.sampleSelect) { // Selection was done do actual validation
|
||||
this.materials.forEach(sample => {
|
||||
if (sample.selected) {
|
||||
this.api.put('/material/validate/' + sample._id);
|
||||
@ -60,12 +60,12 @@ export class MaterialsComponent implements OnInit {
|
||||
this.loadMaterials();
|
||||
this.sampleSelect = false;
|
||||
}
|
||||
else { // activate validation mode
|
||||
else { // Activate validation mode
|
||||
this.sampleSelect = true;
|
||||
}
|
||||
}
|
||||
|
||||
selectAll(event) { // toggle selection for all items except deleted ones
|
||||
selectAll(event) { // Toggle selection for all items except deleted ones
|
||||
this.materials.forEach(material => {
|
||||
if (material.status !== 'deleted') {
|
||||
material.selected = event.target.checked;
|
||||
@ -86,11 +86,11 @@ export class MaterialsComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
ucFirst(string) { // convert first character of string to uppercase
|
||||
ucFirst(string) { // Convert first character of string to uppercase
|
||||
return string[0].toUpperCase() + string.slice(1);
|
||||
}
|
||||
|
||||
materialFilter(ms) { // filter function for material names
|
||||
materialFilter(ms) { // Filter function for material names
|
||||
return e => e.name.indexOf(ms) >= 0;
|
||||
}
|
||||
|
||||
|
@ -13,12 +13,12 @@ import omit from 'lodash/omit';
|
||||
})
|
||||
export class ModelTemplatesComponent implements OnInit {
|
||||
|
||||
newModel = false; // display new model dialog
|
||||
modelGroup = ''; // group of the edited model
|
||||
oldModelGroup = ''; // group of the edited model before editing started
|
||||
oldModelName = ''; // name of the edited model before editing started
|
||||
model = new ModelItemModel().models[0]; // edited model
|
||||
groups = []; // all model group names
|
||||
newModel = false; // Display new model dialog
|
||||
modelGroup = ''; // Group of the edited model
|
||||
oldModelGroup = ''; // Group of the edited model before editing started
|
||||
oldModelName = ''; // Name of the edited model before editing started
|
||||
model = new ModelItemModel().models[0]; // Edited model
|
||||
groups = []; // All model group names
|
||||
|
||||
constructor(
|
||||
private api: ApiService,
|
||||
@ -40,12 +40,12 @@ export class ModelTemplatesComponent implements OnInit {
|
||||
}
|
||||
|
||||
saveModel() {
|
||||
// group was changed, delete model in old group
|
||||
// Group was changed, delete model in old group
|
||||
if (this.oldModelGroup !== '' && this.modelGroup !== this.oldModelGroup) {
|
||||
this.delete(null, this.oldModelName, this.oldModelGroup);
|
||||
}
|
||||
this.api.post('/model/' + this.modelGroup, omit(this.model, '_id'), () => {
|
||||
this.newModel = false; // reset model edit parameters
|
||||
this.newModel = false; // Reset model edit parameters
|
||||
this.loadGroups();
|
||||
this.modelGroup = '';
|
||||
this.oldModelGroup = '';
|
||||
@ -56,7 +56,7 @@ export class ModelTemplatesComponent implements OnInit {
|
||||
|
||||
delete(modal, name, group = null) {
|
||||
new Promise(resolve => {
|
||||
if (modal) { // if modal was given, wait for result
|
||||
if (modal) { // If modal was given, wait for result
|
||||
this.modal.open(modal).then(result => {
|
||||
resolve(result);
|
||||
});
|
||||
@ -66,12 +66,12 @@ export class ModelTemplatesComponent implements OnInit {
|
||||
}
|
||||
}).then(res => {
|
||||
if (res) {
|
||||
if (group) { // delete model group if given
|
||||
if (group) { // Delete model group if given
|
||||
this.api.delete(`/model/${group}/${name}`, () => {
|
||||
this.loadGroups();
|
||||
});
|
||||
}
|
||||
else { // delete model file
|
||||
else { // Delete model file
|
||||
this.api.delete(`/model/file/${name}`, () => {
|
||||
this.d.arr.modelFiles.splice(this.d.arr.modelFiles.findIndex(e => e.name === name), 1);
|
||||
});
|
||||
|
@ -30,11 +30,11 @@ import * as FileSaver from 'file-saver'
|
||||
})
|
||||
export class PredictionComponent implements OnInit {
|
||||
|
||||
result: { predictions: any[], mean: any[] }; // prediction result from python container
|
||||
result: { predictions: any[], mean: any[] }; // Prediction result from python container
|
||||
loading = false;
|
||||
activeGroup: ModelItemModel = new ModelItemModel();
|
||||
activeModelIndex = 0;
|
||||
// if true, spectra belong to different samples, otherwise multiple spectra from the same sample are given
|
||||
// If true, spectra belong to different samples, otherwise multiple spectra from the same sample are given
|
||||
multipleSamples = false;
|
||||
spectrumNames: string[] = [];
|
||||
spectrum: string[][] = [[]];
|
||||
@ -84,16 +84,16 @@ export class PredictionComponent implements OnInit {
|
||||
if (files.hasOwnProperty(i)) {
|
||||
const fileReader = new FileReader();
|
||||
fileReader.onload = () => {
|
||||
// parse to database spectrum representation
|
||||
// Parse to database spectrum representation
|
||||
this.spectrum = fileReader.result.toString().split('\r\n').map(e => e.split(',').map(el => parseFloat(el)))
|
||||
.filter(el => el.length === 2) as any;
|
||||
// flatten to format needed for prediction
|
||||
// Flatten to format needed for prediction
|
||||
this.flattenedSpectra[i] = {labels: this.spectrum.map(e => e[0]), values: this.spectrum.map(e => e[1])};
|
||||
// add to chart
|
||||
// Add to chart
|
||||
this.chart[i] = cloneDeep(this.chartInit);
|
||||
this.chart[i].data = this.spectrum.map(e => ({x: parseFloat(e[0]), y: parseFloat(e[1])}));
|
||||
load --;
|
||||
if (load <= 0) { // all loaded
|
||||
if (load <= 0) { // All loaded
|
||||
this.loadPrediction();
|
||||
}
|
||||
};
|
||||
@ -105,18 +105,18 @@ export class PredictionComponent implements OnInit {
|
||||
loadPrediction() {
|
||||
this.loading = true;
|
||||
this.api.post<any>(this.activeGroup.models[this.activeModelIndex].url, this.flattenedSpectra, data => {
|
||||
let tmp = Object.entries(omit(data, ['mean', 'std', 'label'])) // form: [[label, [{value, color}]]]
|
||||
.map((entry: any) => entry[1].map(e => ({category: entry[0], label: data.label[entry[0]], value: e.value, color: e.color}))); // form: [[{category, label, value, color}]]
|
||||
let tmp = Object.entries(omit(data, ['mean', 'std', 'label'])) // Form: [[label, [{value, color}]]]
|
||||
.map((entry: any) => entry[1].map(e => ({category: entry[0], label: data.label[entry[0]], value: e.value, color: e.color}))); // Form: [[{category, label, value, color}]]
|
||||
this.result = {
|
||||
predictions: tmp[0].map((ignore, columnIndex) => tmp.map(row => row[columnIndex])), // transpose tmp
|
||||
predictions: tmp[0].map((ignore, columnIndex) => tmp.map(row => row[columnIndex])), // Transpose tmp
|
||||
mean: Object.entries(data.mean)
|
||||
.map((entry:any) => ({category: entry[0], label: data.label[entry[0]], value: entry[1].value, color: entry[1].color, std: data.std[entry[0]]})) // form: [{category, label, value, color}]
|
||||
.map((entry:any) => ({category: entry[0], label: data.label[entry[0]], value: entry[1].value, color: entry[1].color, std: data.std[entry[0]]})) // Form: [{category, label, value, color}]
|
||||
};
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
groupChange(index) { // group was changed
|
||||
groupChange(index) { // Group was changed
|
||||
this.activeGroup = this.d.arr.modelGroups[index];
|
||||
this.activeModelIndex = 0;
|
||||
this.result = undefined;
|
||||
|
@ -10,7 +10,7 @@ export class ArrayInputHelperService {
|
||||
|
||||
constructor() { }
|
||||
|
||||
values(id: string) { // observable which returns new values as they come for subscribed id
|
||||
values(id: string) { // Observable which returns new values as they come for subscribed id
|
||||
return new Observable<{index: number, value: any}>(observer => {
|
||||
this.com.subscribe(data => {
|
||||
if (data.id === id) {
|
||||
@ -20,7 +20,7 @@ export class ArrayInputHelperService {
|
||||
});
|
||||
}
|
||||
|
||||
newValue(id: string, index: number, value: any) { // set new value
|
||||
newValue(id: string, index: number, value: any) { // Set new value
|
||||
this.com.next({id, index, value});
|
||||
}
|
||||
}
|
||||
|
@ -14,8 +14,8 @@ import cloneDeep from 'lodash/cloneDeep';
|
||||
import {ArrayInputHelperService} from './array-input-helper.service';
|
||||
|
||||
|
||||
@Directive({ // directive for template and input values
|
||||
// tslint:disable-next-line:directive-selector
|
||||
@Directive({ // Directive for template and input values
|
||||
// Tslint:disable-next-line:directive-selector
|
||||
selector: '[rbArrayInputItem]'
|
||||
})
|
||||
export class RbArrayInputItemDirective {
|
||||
@ -23,8 +23,8 @@ export class RbArrayInputItemDirective {
|
||||
}
|
||||
}
|
||||
|
||||
@Directive({ // directive for change detection
|
||||
// tslint:disable-next-line:directive-selector
|
||||
@Directive({ // Directive for change detection
|
||||
// Tslint:disable-next-line:directive-selector
|
||||
selector: '[rbArrayInputListener]'
|
||||
})
|
||||
export class RbArrayInputListenerDirective {
|
||||
@ -37,14 +37,14 @@ export class RbArrayInputListenerDirective {
|
||||
) { }
|
||||
|
||||
@HostListener('ngModelChange', ['$event'])
|
||||
onChange(event) { // emit new value
|
||||
onChange(event) { // Emit new value
|
||||
this.helperService.newValue(this.rbArrayInputListener, this.index, event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Component({
|
||||
// tslint:disable-next-line:component-selector
|
||||
// Tslint:disable-next-line:component-selector
|
||||
selector: 'rb-array-input',
|
||||
templateUrl: './rb-array-input.component.html',
|
||||
styleUrls: ['./rb-array-input.component.scss'],
|
||||
@ -52,7 +52,7 @@ export class RbArrayInputListenerDirective {
|
||||
})
|
||||
export class RbArrayInputComponent implements ControlValueAccessor, OnInit, AfterViewInit {
|
||||
|
||||
pushTemplate: any = ''; // array element template
|
||||
pushTemplate: any = ''; // Array element template
|
||||
@Input('pushTemplate') set _pushTemplate(value) {
|
||||
this.pushTemplate = value;
|
||||
if (this.values.length) {
|
||||
@ -64,7 +64,7 @@ export class RbArrayInputComponent implements ControlValueAccessor, OnInit, Afte
|
||||
@ContentChild(RbArrayInputItemDirective) item: RbArrayInputItemDirective;
|
||||
@ContentChild(RbArrayInputListenerDirective) item2: RbArrayInputListenerDirective;
|
||||
|
||||
values = []; // main array to display
|
||||
values = []; // Main array to display
|
||||
|
||||
onChange = (ignore?: any): void => {};
|
||||
onTouched = (ignore?: any): void => {};
|
||||
@ -78,9 +78,9 @@ export class RbArrayInputComponent implements ControlValueAccessor, OnInit, Afte
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => { // needed to find reference
|
||||
this.helperService.values(this.item2.rbArrayInputListener).subscribe(data => { // action on value change
|
||||
// assign value
|
||||
setTimeout(() => { // Needed to find reference
|
||||
this.helperService.values(this.item2.rbArrayInputListener).subscribe(data => { // Action on value change
|
||||
// Assign value
|
||||
if (this.pushPath) {
|
||||
this.values[data.index][this.pushPath] = data.value;
|
||||
}
|
||||
@ -94,26 +94,26 @@ export class RbArrayInputComponent implements ControlValueAccessor, OnInit, Afte
|
||||
|
||||
updateArray() {
|
||||
let res;
|
||||
// adjust fields if pushTemplate is specified
|
||||
// Adjust fields if pushTemplate is specified
|
||||
if (this.pushTemplate !== null) {
|
||||
if (this.pushPath) {
|
||||
// remove last element if last two are empty
|
||||
// Remove last element if last two are empty
|
||||
if (this.values[this.values.length - 1][this.pushPath] === '' &&
|
||||
this.values[this.values.length - 2][this.pushPath] === '') {
|
||||
this.values.pop();
|
||||
}
|
||||
// add element if last all are filled
|
||||
// Add element if last all are filled
|
||||
else if (this.values.filter(e => e[this.pushPath] !== '').length === this.values.length) {
|
||||
this.values.push(cloneDeep(this.pushTemplate));
|
||||
}
|
||||
res = this.values.filter(e => e[this.pushPath] !== '');
|
||||
}
|
||||
else {
|
||||
// remove last element if last two are empty
|
||||
// Remove last element if last two are empty
|
||||
if (this.values[this.values.length - 1] === '' && this.values[this.values.length - 2] === '') {
|
||||
this.values.pop();
|
||||
}
|
||||
else if (this.values.filter(e => e !== '').length === this.values.length) { // add element if all are is filled
|
||||
else if (this.values.filter(e => e !== '').length === this.values.length) { // Add element if all are is filled
|
||||
this.values.push(cloneDeep(this.pushTemplate));
|
||||
}
|
||||
res = this.values.filter(e => e !== '');
|
||||
@ -126,13 +126,13 @@ export class RbArrayInputComponent implements ControlValueAccessor, OnInit, Afte
|
||||
if (!res.length) {
|
||||
res = [''];
|
||||
}
|
||||
this.onChange(res); // trigger ngModel with filled elements
|
||||
this.onChange(res); // Trigger ngModel with filled elements
|
||||
}
|
||||
|
||||
writeValue(obj: any) { // add empty value on init
|
||||
writeValue(obj: any) { // Add empty value on init
|
||||
if (obj) {
|
||||
if (this.pushTemplate !== null) {
|
||||
// filter out empty values
|
||||
// Filter out empty values
|
||||
if (this.pushPath) {
|
||||
this.values = [...obj.filter(e => e[this.pushPath] !== ''), cloneDeep(this.pushTemplate)];
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ import {Component, Input, OnInit} from '@angular/core';
|
||||
|
||||
|
||||
@Component({
|
||||
// tslint:disable-next-line:component-selector
|
||||
// Tslint:disable-next-line:component-selector
|
||||
selector: 'rb-icon-button',
|
||||
templateUrl: './rb-icon-button.component.html',
|
||||
styleUrls: ['./rb-icon-button.component.scss']
|
||||
|
@ -1,7 +1,7 @@
|
||||
import {Component, Input, OnInit} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
// tslint:disable-next-line:component-selector
|
||||
// Tslint:disable-next-line:component-selector
|
||||
selector: 'rb-table',
|
||||
templateUrl: './rb-table.component.html',
|
||||
styleUrls: ['./rb-table.component.scss']
|
||||
|
@ -49,41 +49,41 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
||||
@ViewChild('sampleForm') sampleForm: NgForm;
|
||||
@ViewChild('cmForm') cmForm: NgForm;
|
||||
|
||||
baseSample = new SampleModel(); // base sample which is saved
|
||||
sampleCount = 1; // number of samples to be generated
|
||||
samples: SampleModel[] = []; // gets filled with response data after saving the sample
|
||||
baseSample = new SampleModel(); // Base sample which is saved
|
||||
sampleCount = 1; // Number of samples to be generated
|
||||
samples: SampleModel[] = []; // Gets filled with response data after saving the sample
|
||||
|
||||
sampleReferences: [string, string, string][] = [['', '', '']];
|
||||
sampleReferenceFinds: {_id: string, number: string}[] = []; // raw sample reference data from db
|
||||
currentSRIndex = 0; // index of last entered sample reference
|
||||
sampleReferenceFinds: {_id: string, number: string}[] = []; // Raw sample reference data from db
|
||||
currentSRIndex = 0; // Index of last entered sample reference
|
||||
sampleReferenceAutocomplete: string[][] = [[]];
|
||||
|
||||
customFields: [string, string][] = [];
|
||||
availableCustomFields: string[] = [];
|
||||
|
||||
newMaterial = false; // true if new material should be created
|
||||
materials: MaterialModel[] = []; // all materials
|
||||
materialNames = []; // only names for autocomplete
|
||||
material = new MaterialModel(); // object of current selected material
|
||||
defaultDevice = ''; // default device for spectra
|
||||
newMaterial = false; // True if new material should be created
|
||||
materials: MaterialModel[] = []; // All materials
|
||||
materialNames = []; // Only names for autocomplete
|
||||
material = new MaterialModel(); // Object of current selected material
|
||||
defaultDevice = ''; // Default device for spectra
|
||||
|
||||
// component mode, either new for generating new samples, editOne or editMulti, editing one or multiple samples
|
||||
// Component mode, either new for generating new samples, editOne or editMulti, editing one or multiple samples
|
||||
mode = 'new';
|
||||
view = { // active views
|
||||
base: false, // base sample
|
||||
baseSum: false, // base sample summary
|
||||
cm: false, // conditions and measurements
|
||||
cmSum: false // conditions and measurements summary
|
||||
view = { // Active views
|
||||
base: false, // Base sample
|
||||
baseSum: false, // Base sample summary
|
||||
cm: false, // Conditions and measurements
|
||||
cmSum: false // Conditions and measurements summary
|
||||
};
|
||||
loading = 0; // number of currently loading instances
|
||||
loading = 0; // Number of currently loading instances
|
||||
checkFormAfterInit = false;
|
||||
modalText = {list: '', suggestion: ''};
|
||||
cmSampleIndex = '0';
|
||||
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
|
||||
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
|
||||
charts = [[]]; // Chart data for spectra
|
||||
readonly chartInit = [{
|
||||
data: [],
|
||||
label: 'Spectrum',
|
||||
@ -135,7 +135,7 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
||||
this.d.load('measurementTemplates', () => {
|
||||
this.d.load('user', () => {
|
||||
this.defaultDevice = this.d.d.user.devices[0];
|
||||
// spectrum device must be from user's devices list
|
||||
// Spectrum device must be from user's devices list
|
||||
this.d.arr.measurementTemplates.forEach(template => {
|
||||
const device = template.parameters.find(e => e.name === 'device');
|
||||
if (device) {
|
||||
@ -163,7 +163,7 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
||||
this.mode = 'editOne';
|
||||
this.view.baseSum = true;
|
||||
this.view.cm = true;
|
||||
if (this.login.isLevel.dev) { // load measurement restore data
|
||||
if (this.login.isLevel.dev) { // Load measurement restore data
|
||||
this.api.get<MeasurementModel[]>('/measurement/sample/' + sampleIds[0], (data, ignore) => {
|
||||
if (data) {
|
||||
this.measurementRestoreData =
|
||||
@ -177,22 +177,22 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
||||
this.view.base = true;
|
||||
}
|
||||
this.loading += sampleIds.length;
|
||||
this.api.get<SampleModel>('/sample/' + sampleIds[0], sData => { // special treatment for first id
|
||||
this.api.get<SampleModel>('/sample/' + sampleIds[0], sData => { // Special treatment for first id
|
||||
this.samples = [new SampleModel().deserialize(sData)];
|
||||
this.baseSample.deserialize(sData);
|
||||
this.material = new MaterialModel().deserialize(sData.material); // read material
|
||||
// read custom fields
|
||||
this.material = new MaterialModel().deserialize(sData.material); // Read material
|
||||
// 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
|
||||
if (this.baseSample.notes.sample_references.length) { // Read sample references
|
||||
this.sampleReferences = [];
|
||||
this.sampleReferenceAutocomplete = [];
|
||||
let loadCounter = this.baseSample.notes.sample_references.length; // count down instances still loading
|
||||
let loadCounter = this.baseSample.notes.sample_references.length; // Count down instances still loading
|
||||
this.baseSample.notes.sample_references.forEach(reference => {
|
||||
this.api.get<SampleModel>('/sample/' + reference.sample_id, srData => { // get sample numbers for ids
|
||||
this.api.get<SampleModel>('/sample/' + reference.sample_id, srData => { // Get sample numbers for ids
|
||||
this.sampleReferences.push([srData.number, reference.relation, reference.sample_id]);
|
||||
this.sampleReferenceAutocomplete.push([srData.number]);
|
||||
if (!--loadCounter) { // insert empty template when all instances were loaded
|
||||
if (!--loadCounter) { // Insert empty template when all instances were loaded
|
||||
this.sampleReferences.push(['', '', '']);
|
||||
this.sampleReferenceAutocomplete.push([]);
|
||||
}
|
||||
@ -201,20 +201,20 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
||||
}
|
||||
if (this.mode === 'editOne') {
|
||||
this.charts = [[]];
|
||||
let spectrumCounter = 0; // generate charts for spectrum measurements
|
||||
let spectrumCounter = 0; // Generate charts for spectrum measurements
|
||||
this.samples[0].measurements.forEach((measurement, i) => {
|
||||
this.charts[0].push(cloneDeep(this.chartInit));
|
||||
if (measurement.values.dpt) {
|
||||
setTimeout(() => {
|
||||
this.generateChart(measurement.values.dpt, 0, i);
|
||||
}, spectrumCounter * 20); // generate charts one after another to avoid freezing the UI
|
||||
}, spectrumCounter * 20); // Generate charts one after another to avoid freezing the UI
|
||||
spectrumCounter ++;
|
||||
}
|
||||
});
|
||||
}
|
||||
this.checkFormAfterInit = true;
|
||||
this.loading--;
|
||||
sampleIds.slice(1).forEach(sampleId => { // load further samples for batch edit
|
||||
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) => {
|
||||
@ -237,8 +237,8 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
||||
}
|
||||
|
||||
ngAfterContentChecked() {
|
||||
// attach validators
|
||||
if (this.samples.length) { // conditions are displayed
|
||||
// Attach validators
|
||||
if (this.samples.length) { // Conditions are displayed
|
||||
this.samples.forEach((gSample, gIndex) => {
|
||||
if (this.d.id.conditionTemplates[gSample.condition.condition_template]) {
|
||||
this.d.id.conditionTemplates[gSample.condition.condition_template].parameters.forEach((parameter, pIndex) => {
|
||||
@ -253,15 +253,15 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
||||
});
|
||||
}
|
||||
|
||||
if (this.sampleForm && this.material.properties.material_template) { // material template is set
|
||||
if (this.sampleForm && this.material.properties.material_template) { // Material template is set
|
||||
this.d.id.materialTemplates[this.material.properties.material_template].parameters.forEach((parameter, i) => {
|
||||
this.attachValidator(this.sampleForm, 'materialParameter' + i, parameter.range);
|
||||
});
|
||||
}
|
||||
|
||||
// revalidate inputs
|
||||
// Revalidate inputs
|
||||
if (this.checkFormAfterInit) {
|
||||
if (this.view.base) { // validate sampleForm
|
||||
if (this.view.base) { // Validate sampleForm
|
||||
if (this.sampleForm !== undefined && this.sampleForm.form.get('cf-key0')) {
|
||||
this.checkFormAfterInit = false;
|
||||
Object.keys(this.sampleForm.form.controls).forEach(field => {
|
||||
@ -269,20 +269,20 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
||||
});
|
||||
}
|
||||
}
|
||||
else { // validate cmForm
|
||||
// check that all fields are ready for validation
|
||||
let formReady: boolean = this.cmForm !== undefined; // forms exist
|
||||
if (this.samples[0].condition.condition_template) { // if condition is set, last condition field exists
|
||||
else { // Validate cmForm
|
||||
// Check that all fields are ready for validation
|
||||
let formReady: boolean = this.cmForm !== undefined; // Forms exist
|
||||
if (this.samples[0].condition.condition_template) { // If condition is set, last condition field exists
|
||||
formReady = formReady && this.cmForm.form.get('conditionParameter-0-' +
|
||||
(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
|
||||
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) +
|
||||
'-' + (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
|
||||
if (formReady) { // Fields are ready, do validation
|
||||
this.checkFormAfterInit = false;
|
||||
Object.keys(this.cmForm.form.controls).forEach(field => {
|
||||
this.cmForm.form.get(field).updateValueAndValidity();
|
||||
@ -292,7 +292,7 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
||||
}
|
||||
}
|
||||
|
||||
// attach validators specified in range to input with name
|
||||
// Attach validators specified in range to input with name
|
||||
attachValidator(form, name: string, range: {[prop: string]: any}) {
|
||||
if (form && form.form.get(name)) {
|
||||
const validators = [];
|
||||
@ -319,25 +319,25 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
||||
setTimeout(() => this.checkFormAfterInit = true, 0);
|
||||
}
|
||||
|
||||
// save base sample
|
||||
// Save base sample
|
||||
saveSample() {
|
||||
if (this.samples.length === 0) {
|
||||
this.loading = this.sampleCount; // set up loading spinner
|
||||
this.loading = this.sampleCount; // Set up loading spinner
|
||||
}
|
||||
new Promise<void>(resolve => {
|
||||
if (this.newMaterial) { // save material first if new one exists
|
||||
if (this.newMaterial) { // Save material first if new one exists
|
||||
this.material.numbers = this.material.numbers.filter(e => e !== '');
|
||||
this.api.post<MaterialModel>('/material/new', this.material.sendFormat(), data => {
|
||||
this.d.arr.materials.push(data); // add material to data
|
||||
this.d.arr.materials.push(data); // Add material to data
|
||||
this.material = data;
|
||||
this.baseSample.material_id = data._id; // add new material id to sample data
|
||||
this.baseSample.material_id = data._id; // Add new material id to sample data
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
else {
|
||||
resolve();
|
||||
}
|
||||
}).then(() => { // save sample
|
||||
}).then(() => { // Save sample
|
||||
if (this.baseSample.notes) {
|
||||
this.baseSample.notes.custom_fields = {};
|
||||
this.customFields.forEach(element => {
|
||||
@ -346,10 +346,10 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
||||
}
|
||||
});
|
||||
this.baseSample.notes.sample_references = this.sampleReferences
|
||||
.filter(e => e[0] && e[1] && e[2]) // filter empty values
|
||||
.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
|
||||
if (this.samples.length === 0) { // Only save new sample for the first time in mode new, otherwise save changes
|
||||
for (let i = 0; i < this.sampleCount; i ++) {
|
||||
this.api.post<SampleModel>('/sample/new', this.baseSample.sendFormat(), data => {
|
||||
this.samples[i] = new SampleModel().deserialize(data);
|
||||
@ -374,10 +374,10 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
||||
});
|
||||
}
|
||||
|
||||
// save conditions and measurements
|
||||
cmSave() { // save measurements and conditions
|
||||
// Save conditions and measurements
|
||||
cmSave() { // Save measurements and conditions
|
||||
this.samples.forEach(sample => {
|
||||
if (sample.condition.condition_template) { // condition was set
|
||||
if (sample.condition.condition_template) { // Condition was set
|
||||
this.api.put('/sample/' + sample._id,
|
||||
{condition: pick(sample.condition,
|
||||
[
|
||||
@ -387,21 +387,21 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
||||
)}
|
||||
);
|
||||
}
|
||||
sample.measurements.forEach(measurement => { // save measurements
|
||||
sample.measurements.forEach(measurement => { // Save measurements
|
||||
if (Object.keys(measurement.values).map(e => measurement.values[e]).join('') !== '') {
|
||||
Object.keys(measurement.values).forEach(key => { // map empty values to null
|
||||
Object.keys(measurement.values).forEach(key => { // Map empty values to null
|
||||
measurement.values[key] = measurement.values[key] === '' ? null : measurement.values[key];
|
||||
});
|
||||
if (measurement._id === null) { // new measurement
|
||||
if (measurement._id === null) { // New measurement
|
||||
measurement.sample_id = sample._id;
|
||||
this.api.post<MeasurementModel>('/measurement/new', measurement.sendFormat());
|
||||
}
|
||||
else { // update measurement
|
||||
else { // Update measurement
|
||||
this.api.put<MeasurementModel>('/measurement/' + measurement._id,
|
||||
measurement.sendFormat(['sample_id', 'measurement_template']));
|
||||
}
|
||||
}
|
||||
else if (measurement._id !== null) { // existing measurement was left empty to delete
|
||||
else if (measurement._id !== null) { // Existing measurement was left empty to delete
|
||||
this.api.delete('/measurement/' + measurement._id);
|
||||
}
|
||||
});
|
||||
@ -414,7 +414,7 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
||||
}
|
||||
|
||||
restoreMeasurements() {
|
||||
let spectrumCounter = 0; // generate charts for spectrum measurements
|
||||
let spectrumCounter = 0; // Generate charts for spectrum measurements
|
||||
const measurementCount = this.samples[0].measurements.length;
|
||||
this.measurementRestoreData.forEach((measurement, i) => {
|
||||
this.api.put('/measurement/restore/' + measurement._id, {}, () => {
|
||||
@ -423,7 +423,7 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
||||
if (measurement.values.dpt) {
|
||||
setTimeout(() => {
|
||||
this.generateChart(measurement.values.dpt, 0, measurementCount + i);
|
||||
}, spectrumCounter * 20); // generate charts one after another to avoid freezing the UI
|
||||
}, spectrumCounter * 20); // Generate charts one after another to avoid freezing the UI
|
||||
spectrumCounter ++;
|
||||
}
|
||||
this.checkFormAfterInit = true;
|
||||
@ -431,15 +431,15 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
||||
});
|
||||
}
|
||||
|
||||
// set material based on found material name
|
||||
// Set material based on found material name
|
||||
findMaterial(name) {
|
||||
const res = this.d.arr.materials.find(e => e.name === name); // search for match
|
||||
if (res) { // material found
|
||||
const res = this.d.arr.materials.find(e => e.name === name); // Search for match
|
||||
if (res) { // Material found
|
||||
this.material = cloneDeep(res);
|
||||
this.baseSample.material_id = this.material._id;
|
||||
}
|
||||
else { // no matching material found
|
||||
if (this.baseSample.material_id !== null) { // reset previous match
|
||||
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;
|
||||
@ -449,36 +449,36 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
||||
this.setNewMaterial();
|
||||
}
|
||||
|
||||
// set newMaterial, if value === null -> toggle
|
||||
// Set newMaterial, if value === null -> toggle
|
||||
setNewMaterial(value = null) {
|
||||
if (value === null) { // toggle dialog
|
||||
if (value === null) { // Toggle dialog
|
||||
this.newMaterial = !this.baseSample.material_id;
|
||||
} // 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
|
||||
if (this.newMaterial) { // Set validators if dialog is open
|
||||
this.sampleForm.form.get('materialname').setValidators([Validators.required]);
|
||||
}
|
||||
else { // material name must be from list if dialog is closed
|
||||
else { // Material name must be from list if dialog is closed
|
||||
this.sampleForm.form.get('materialname')
|
||||
.setValidators([Validators.required, this.validation.generate('stringOf', [this.materialNames])]);
|
||||
}
|
||||
this.sampleForm.form.get('materialname').updateValueAndValidity();
|
||||
}
|
||||
|
||||
// add a new measurement for generated sample at index
|
||||
// Add a new measurement for generated sample at index
|
||||
addMeasurement(gIndex) {
|
||||
this.samples[gIndex].measurements.push(
|
||||
new MeasurementModel(this.d.latest.measurementTemplates.find(e => e.name === 'spectrum')._id)
|
||||
);
|
||||
if (!this.charts[gIndex]) { // add array if there are no charts yet
|
||||
if (!this.charts[gIndex]) { // Add array if there are no charts yet
|
||||
this.charts[gIndex] = [];
|
||||
}
|
||||
this.charts[gIndex].push(cloneDeep(this.chartInit));
|
||||
}
|
||||
|
||||
// remove the measurement at the specified index
|
||||
// Remove the measurement at the specified index
|
||||
removeMeasurement(gIndex, mIndex) {
|
||||
if (this.samples[gIndex].measurements[mIndex]._id !== null) {
|
||||
this.measurementDeleteList.push(this.samples[gIndex].measurements[mIndex]._id);
|
||||
@ -487,23 +487,23 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
||||
this.charts[gIndex].splice(mIndex, 1);
|
||||
}
|
||||
|
||||
// clear entered measurement data at the specified index due to template change
|
||||
// Clear entered measurement data at the specified index due to template change
|
||||
clearMeasurement(gIndex, mIndex) {
|
||||
this.charts[gIndex][mIndex][0].data = [];
|
||||
this.samples[gIndex].measurements[mIndex].values = {};
|
||||
}
|
||||
|
||||
fileToArray(files, gIndex, mIndex, parameter) { // process spectrum file input
|
||||
fileToArray(files, gIndex, mIndex, parameter) { // Process spectrum file input
|
||||
for (const i in files) {
|
||||
if (files.hasOwnProperty(i)) {
|
||||
const fileReader = new FileReader();
|
||||
fileReader.onload = () => {
|
||||
let index: number = mIndex;
|
||||
if (Number(i) > 0) { // append further spectra
|
||||
if (Number(i) > 0) { // Append further spectra
|
||||
this.addMeasurement(gIndex);
|
||||
index = this.samples[gIndex].measurements.length - 1;
|
||||
}
|
||||
// autofill further parameters
|
||||
// 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;
|
||||
@ -530,16 +530,16 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
||||
}
|
||||
|
||||
checkTypo(event, list, mKey, modal: TemplateRef<any>) {
|
||||
// user did not click on suggestion and entry is not in list
|
||||
// User did not click on suggestion and entry is not in list
|
||||
if (!(event.relatedTarget && (event.relatedTarget.className.indexOf('rb-dropdown-item') >= 0 ||
|
||||
event.relatedTarget.className.indexOf('close-btn rb-btn rb-passive-link') >= 0)) &&
|
||||
this.d.arr[list].indexOf(this.material[mKey]) < 0) {
|
||||
this.modalText.list = mKey;
|
||||
this.modalText.suggestion = this.d.arr[list] // find possible entry from list
|
||||
this.modalText.suggestion = this.d.arr[list] // Find possible entry from list
|
||||
.map(e => ({v: e, s: strCompare.sorensenDice(e, this.material[mKey])}))
|
||||
.sort((a, b) => b.s - a.s)[0].v;
|
||||
this.modal.open(modal).then(result => {
|
||||
if (result) { // use suggestion
|
||||
if (result) { // Use suggestion
|
||||
this.material[mKey] = this.modalText.suggestion;
|
||||
}
|
||||
});
|
||||
@ -569,12 +569,12 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
||||
filledFields ++;
|
||||
}
|
||||
});
|
||||
// append new field
|
||||
// Append new field
|
||||
if (filledFields === fieldNo) {
|
||||
this.sampleReferences.push(['', '', '']);
|
||||
this.sampleReferenceAutocomplete.push([]);
|
||||
}
|
||||
// remove if two end fields are empty
|
||||
// Remove if two end fields are empty
|
||||
if (fieldNo > 1 && this.sampleReferences[fieldNo - 1][0] === '' && this.sampleReferences[fieldNo - 2][0] === '') {
|
||||
this.sampleReferences.pop();
|
||||
this.sampleReferenceAutocomplete.pop();
|
||||
@ -582,7 +582,7 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
||||
this.sampleReferenceIdFind(value);
|
||||
}
|
||||
|
||||
sampleReferenceList(value) { // get list of sample reference number suggestions
|
||||
sampleReferenceList(value) { // Get list of sample reference number suggestions
|
||||
return new Observable(observer => {
|
||||
if (value !== '') {
|
||||
this.api.get<{ _id: string, number: string }[]>(
|
||||
@ -603,7 +603,7 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
||||
});
|
||||
}
|
||||
|
||||
sampleReferenceIdFind(value) { // sample reference id from number
|
||||
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;
|
||||
@ -621,7 +621,7 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
||||
return this.samples.map(e => e.number).join(', ');
|
||||
}
|
||||
|
||||
uniqueCfValues(index) { // returns all names until index for unique check
|
||||
uniqueCfValues(index) { // Returns all names until index for unique check
|
||||
return this.customFields ? this.customFields.slice(0, index).map(e => e[0]) : [];
|
||||
}
|
||||
|
||||
|
@ -41,13 +41,13 @@ export class SamplesComponent implements OnInit {
|
||||
@ViewChild('pageSizeSelection') pageSizeSelection: ElementRef<HTMLElement>;
|
||||
@ViewChild('linkarea') linkarea: ElementRef<HTMLTextAreaElement>;
|
||||
|
||||
downloadSpectra = false; // download options
|
||||
downloadSpectra = false; // Download options
|
||||
downloadCondition = false;
|
||||
downloadFlatten = true;
|
||||
samples: SampleModel[] = []; // all samples to display
|
||||
samples: SampleModel[] = []; // All samples to display
|
||||
data: Data[] = [];
|
||||
totalSamples = 0; // total number of samples
|
||||
csvUrl = ''; // store url separate so it only has to be generated when clicking the download button
|
||||
totalSamples = 0; // Total number of samples
|
||||
csvUrl = ''; // Store url separate so it only has to be generated when clicking the download button
|
||||
filters = {
|
||||
status: { new: true, validated: true, deleted: false },
|
||||
pageSize: 25,
|
||||
@ -69,9 +69,9 @@ export class SamplesComponent implements OnInit {
|
||||
{ field: 'added', label: 'Added', active: false, autocomplete: [], mode: 'eq', values: [''] }
|
||||
]
|
||||
};
|
||||
page = 1; // current page
|
||||
pages = 1; // total number of pages
|
||||
loadSamplesQueue = []; // arguments of queued up loadSamples() calls
|
||||
page = 1; // Current page
|
||||
pages = 1; // Total number of pages
|
||||
loadSamplesQueue = []; // Arguments of queued up loadSamples() calls
|
||||
materialKeys: KeyInterface[] = [
|
||||
{ id: 'number', label: 'Number', active: true, sortable: true },
|
||||
{ id: 'material.numbers', label: 'Material numbers', active: false, sortable: false },
|
||||
@ -91,20 +91,20 @@ export class SamplesComponent implements OnInit {
|
||||
{ id: 'added', label: 'Added', active: true, sortable: true }
|
||||
];
|
||||
|
||||
// combines the 3 different categories
|
||||
// Combines the 3 different categories
|
||||
categories = {
|
||||
material: this.materialKeys,
|
||||
condition: this.conditionKeys,
|
||||
measurement: this.measurementKeys
|
||||
};
|
||||
|
||||
isActiveKey: { [key: string]: boolean } = {}; // object to check if key is currently active
|
||||
activeKeys: KeyInterface[] = []; // list of active keys
|
||||
sampleDetailsSample: any = null; // sample for the sample details dialog
|
||||
sampleSelect = 0; // modes: 0 - no selection, 1 - sample edit selection, 2 - validation selection
|
||||
loading = 0; // number of loading instances
|
||||
isActiveKey: { [key: string]: boolean } = {}; // Object to check if key is currently active
|
||||
activeKeys: KeyInterface[] = []; // List of active keys
|
||||
sampleDetailsSample: any = null; // Sample for the sample details dialog
|
||||
sampleSelect = 0; // Modes: 0 - no selection, 1 - sample edit selection, 2 - validation selection
|
||||
loading = 0; // Number of loading instances
|
||||
|
||||
// change the way values are displayed
|
||||
// Change the way values are displayed
|
||||
valueConverters = {
|
||||
'added': (v: string, _sample) => new Date(v).toLocaleDateString(),
|
||||
'notes': (v: any, _sample: any) => v.sample_references.length > 0 ? Object.keys(v.sample_references).map(r => v.sample_references[r].relation).join(", ") : "",
|
||||
@ -156,7 +156,7 @@ export class SamplesComponent implements OnInit {
|
||||
this.d.arr[collection + 'Templates'].forEach(item => {
|
||||
item.parameters.forEach(parameter => {
|
||||
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))) {
|
||||
const collectionNames = {
|
||||
material: 'material.properties',
|
||||
@ -181,22 +181,22 @@ export class SamplesComponent implements OnInit {
|
||||
});
|
||||
});
|
||||
this.categories[collection].splice(this.categories[collection].findIndex(e => e.id === insertBefore), 0, ...templateKeys);
|
||||
this.categories[collection] = [...this.categories[collection]]; // complete overwrite array to invoke update in rb-multiselect
|
||||
this.categories[collection] = [...this.categories[collection]]; // Complete overwrite array to invoke update in rb-multiselect
|
||||
this.loadPreferences();
|
||||
f();
|
||||
});
|
||||
}
|
||||
|
||||
// set toPage to null to reload first page, queues calls
|
||||
// Set toPage to null to reload first page, queues calls
|
||||
loadSamples(options: LoadSamplesOptions = {}, event = null, category?) {
|
||||
if (event) { // adjust active keys
|
||||
if (event) { // Adjust active keys
|
||||
this.categories[category].forEach(key => {
|
||||
if (event.hasOwnProperty(key.id)) {
|
||||
key.active = event[key.id];
|
||||
}
|
||||
});
|
||||
const sortId = this.filters.sort.replace(/(-asc|-desc)/, '');
|
||||
if (event.hasOwnProperty(sortId) && !event[sortId]) { // reset sort if sort field was unselected
|
||||
if (event.hasOwnProperty(sortId) && !event[sortId]) { // Reset sort if sort field was unselected
|
||||
this.setSort('_id-asc');
|
||||
}
|
||||
this.updateActiveKeys();
|
||||
@ -205,17 +205,17 @@ export class SamplesComponent implements OnInit {
|
||||
this.storage.set('currentPage', 1);
|
||||
}
|
||||
this.loadSamplesQueue.push(options);
|
||||
if (this.loadSamplesQueue.length <= 1) { // nothing queued up
|
||||
if (this.loadSamplesQueue.length <= 1) { // Nothing queued up
|
||||
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.loading++;
|
||||
this.api.get(this.sampleUrl({ paging: true, pagingOptions: options }), (sData, err, headers) => {
|
||||
this.loading--;
|
||||
if (err) { // remove stored options on error to avoid loop
|
||||
if (err) { // Remove stored options on error to avoid loop
|
||||
this.storage.remove('samplesPreferences');
|
||||
this.api.requestError(err);
|
||||
}
|
||||
@ -227,7 +227,7 @@ export class SamplesComponent implements OnInit {
|
||||
this.samples = sData as any;
|
||||
this.storeData();
|
||||
this.loadSamplesQueue.shift();
|
||||
if (this.loadSamplesQueue.length > 0) { // execute next queue item
|
||||
if (this.loadSamplesQueue.length > 0) { // Execute next queue item
|
||||
this.sampleLoader(this.loadSamplesQueue[0]);
|
||||
}
|
||||
}
|
||||
@ -247,13 +247,13 @@ export class SamplesComponent implements OnInit {
|
||||
csv?: boolean,
|
||||
export?: boolean,
|
||||
host?: boolean
|
||||
}) { // return url to fetch samples
|
||||
// keys which should always be added if export = false
|
||||
}) { // Return url to fetch samples
|
||||
// Keys which should always be added if export = false
|
||||
const additionalTableKeys = ['material_id', '_id', 'user_id'];
|
||||
const query: string[] = [];
|
||||
query.push(...Object.keys(this.filters.status).filter(e => this.filters.status[e]).map(e => 'status[]=' + e));
|
||||
if (options.paging) {
|
||||
if (this.samples[0]) { // do not include from-id when page size was changed
|
||||
if (this.samples[0]) { // Do not include from-id when page size was changed
|
||||
if (!options.pagingOptions.firstPage) {
|
||||
query.push('from-id=' + this.samples[0]._id);
|
||||
}
|
||||
@ -267,7 +267,7 @@ export class SamplesComponent implements OnInit {
|
||||
query.push('page-size=' + this.filters.pageSize);
|
||||
}
|
||||
query.push('sort=' + this.filters.sort);
|
||||
if (options.export) { // append API key on export
|
||||
if (options.export) { // Append API key on export
|
||||
query.push('key=' + this.d.d.userKey.key);
|
||||
}
|
||||
|
||||
@ -280,13 +280,13 @@ export class SamplesComponent implements OnInit {
|
||||
}
|
||||
query.push(...cloneDeep(this.filters.filters)
|
||||
.map(e => {
|
||||
e.values = e.values.filter(el => el !== ''); // do not include empty values
|
||||
if (e.field === 'added') { // correct timezone
|
||||
e.values = e.values.filter(el => el !== ''); // Do not include empty values
|
||||
if (e.field === 'added') { // Correct timezone
|
||||
e.values = e.values.map(
|
||||
el => new Date(new Date(el).getTime() - new Date(el).getTimezoneOffset() * 60000).toISOString()
|
||||
);
|
||||
}
|
||||
if (e.mode === 'null') { // handle null mode
|
||||
if (e.mode === 'null') { // Handle null mode
|
||||
e.mode = 'in';
|
||||
e.values = [null, ''];
|
||||
}
|
||||
@ -304,12 +304,12 @@ export class SamplesComponent implements OnInit {
|
||||
}
|
||||
if (!options.export) {
|
||||
additionalTableKeys.forEach(key => {
|
||||
if (query.indexOf('fields[]=' + key) < 0) { // add key if not already added
|
||||
if (query.indexOf('fields[]=' + key) < 0) { // Add key if not already added
|
||||
query.push('fields[]=' + key);
|
||||
}
|
||||
});
|
||||
}
|
||||
else { // export options
|
||||
else { // Export options
|
||||
if (options.csv) {
|
||||
query.push('output=csv');
|
||||
}
|
||||
@ -329,7 +329,7 @@ export class SamplesComponent implements OnInit {
|
||||
}
|
||||
|
||||
loadPage(delta) {
|
||||
if (!/[0-9]+/.test(delta) || this.page + delta < 1) { // invalid delta
|
||||
if (!/[0-9]+/.test(delta) || this.page + delta < 1) { // Invalid delta
|
||||
return;
|
||||
}
|
||||
this.page += delta;
|
||||
@ -393,11 +393,11 @@ export class SamplesComponent implements OnInit {
|
||||
this.loadSamples({ firstPage: true });
|
||||
}
|
||||
|
||||
updateActiveKeys() { // array with all activeKeys
|
||||
updateActiveKeys() { // Array with all activeKeys
|
||||
this.activeKeys = [];
|
||||
for (let category in this.categories) {
|
||||
this.activeKeys.push(...this.categories[category].filter(e => e.active));
|
||||
this.filters.filters.forEach(filter => { // disable filters of fields not displayed
|
||||
this.filters.filters.forEach(filter => { // Disable filters of fields not displayed
|
||||
if (!this.isActiveKey[filter.field]) {
|
||||
filter.active = false;
|
||||
}
|
||||
@ -413,18 +413,18 @@ export class SamplesComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
sampleDetails(id: string, modal: TemplateRef<any>) { // show sample details
|
||||
sampleDetails(id: string, modal: TemplateRef<any>) { // Show sample details
|
||||
this.sampleDetailsSample = null;
|
||||
this.api.get<SampleModel>('/sample/' + id, data => {
|
||||
this.sampleDetailsSample = new SampleModel().deserialize(data);
|
||||
if (data.notes.custom_fields) { // convert custom_fields for more optimized display
|
||||
if (data.notes.custom_fields) { // Convert custom_fields for more optimized display
|
||||
this.sampleDetailsSample.notes.custom_fields_entries =
|
||||
Object.entries(this.sampleDetailsSample.notes.custom_fields);
|
||||
}
|
||||
else {
|
||||
this.sampleDetailsSample.custom_fields_entries = [];
|
||||
}
|
||||
if (Object.keys(data.condition).length) { // convert condition
|
||||
if (Object.keys(data.condition).length) { // Convert condition
|
||||
this.sampleDetailsSample.condition_entries =
|
||||
Object.entries(omit(this.sampleDetailsSample.condition, ['condition_template']))
|
||||
.map(e => {
|
||||
@ -438,7 +438,7 @@ export class SamplesComponent implements OnInit {
|
||||
this.sampleDetailsSample.condition_entries = [];
|
||||
}
|
||||
this.sampleDetailsSample.measurement_entries = [];
|
||||
// convert measurements for more optimized display without dpt
|
||||
// Convert measurements for more optimized display without dpt
|
||||
this.sampleDetailsSample.measurements.forEach(measurement => {
|
||||
const name = this.d.id.measurementTemplates[measurement.measurement_template].name;
|
||||
this.sampleDetailsSample.measurement_entries
|
||||
@ -446,7 +446,7 @@ export class SamplesComponent implements OnInit {
|
||||
.map(e => ({ name: this.ucFirst(name) + ' ' + e[0], value: e[1] })));
|
||||
});
|
||||
new Promise<void>(resolve => {
|
||||
if (data.notes.sample_references.length) { // load referenced samples if available
|
||||
if (data.notes.sample_references.length) { // Load referenced samples if available
|
||||
let loadingCounter = data.notes.sample_references.length;
|
||||
this.sampleDetailsSample.notes.sample_references.forEach(reference => {
|
||||
this.api.get<SampleModel>('/sample/' + reference.sample_id, rData => {
|
||||
@ -468,7 +468,7 @@ export class SamplesComponent implements OnInit {
|
||||
}
|
||||
|
||||
validate() {
|
||||
if (this.sampleSelect) { // do actual validation
|
||||
if (this.sampleSelect) { // Do actual validation
|
||||
this.samples.forEach(sample => {
|
||||
if (sample.selected) {
|
||||
this.api.put('/sample/validate/' + sample._id);
|
||||
@ -477,12 +477,12 @@ export class SamplesComponent implements OnInit {
|
||||
this.loadSamples();
|
||||
this.sampleSelect = 0;
|
||||
}
|
||||
else { // get into validation mode
|
||||
else { // Get into validation mode
|
||||
this.sampleSelect = 2;
|
||||
}
|
||||
}
|
||||
|
||||
batchEdit() { // redirect to batch edit
|
||||
batchEdit() { // Redirect to batch edit
|
||||
if (this.sampleSelect) {
|
||||
this.router.navigate(['/samples/edit/' + this.samples.filter(e => e.selected).map(e => e._id).join(',')]);
|
||||
this.sampleSelect = 0;
|
||||
@ -503,7 +503,7 @@ export class SamplesComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
selectAll(event) { // toggle select all except deleted samples
|
||||
selectAll(event) { // Toggle select all except deleted samples
|
||||
this.samples.forEach(sample => {
|
||||
if (sample.status !== 'deleted') {
|
||||
sample.selected = event.target.checked;
|
||||
@ -524,13 +524,13 @@ export class SamplesComponent implements OnInit {
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
clipboard() { // copy contents to clipboard
|
||||
clipboard() { // Copy contents to clipboard
|
||||
this.linkarea.nativeElement.select();
|
||||
this.linkarea.nativeElement.setSelectionRange(0, 99999);
|
||||
document.execCommand('copy');
|
||||
}
|
||||
|
||||
ucFirst(string) { // convert first character of string to uppercase
|
||||
ucFirst(string) { // Convert first character of string to uppercase
|
||||
return string[0].toUpperCase() + string.slice(1);
|
||||
}
|
||||
|
||||
@ -540,7 +540,7 @@ export class SamplesComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
// stores data in a unified way
|
||||
// Stores data in a unified way
|
||||
storeData() {
|
||||
this.data = [];
|
||||
this.samples.forEach(sample => {
|
||||
|
@ -24,7 +24,7 @@ export class ApiService {
|
||||
return this.host;
|
||||
}
|
||||
|
||||
// main HTTP methods
|
||||
// Main HTTP methods
|
||||
get<T>(url, f: (data?: T, err?, headers?) => void = () => {}) {
|
||||
this.requestErrorHandler<T>(this.http.get(this.url(url), this.options()), f);
|
||||
}
|
||||
@ -41,25 +41,25 @@ export class ApiService {
|
||||
this.requestErrorHandler<T>(this.http.delete(this.url(url), this.options()), f);
|
||||
}
|
||||
|
||||
// execute request and handle errors
|
||||
// Execute request and handle errors
|
||||
private requestErrorHandler<T>(observable: Observable<any>, f: (data?: T, err?, headers?) => void) {
|
||||
observable.subscribe(data => { // successful request
|
||||
observable.subscribe(data => { // Successful request
|
||||
f(
|
||||
data.body,
|
||||
undefined,
|
||||
data.headers.keys().reduce((s, e) => {s[e.toLowerCase()] = data.headers.get(e); return s; }, {})
|
||||
);
|
||||
}, err => { // error
|
||||
if (f.length > 1) { // pass on error
|
||||
}, err => { // Error
|
||||
if (f.length > 1) { // Pass on error
|
||||
f(undefined, err, undefined);
|
||||
}
|
||||
else { // handle directly
|
||||
else { // Handle directly
|
||||
this.requestError(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
requestError(err) { // network error dialog
|
||||
requestError(err) { // Network error dialog
|
||||
const modalRef = this.modalService.openComponent(ErrorComponent);
|
||||
modalRef.instance.message = 'Network request failed!';
|
||||
const details = [err.error.status];
|
||||
@ -72,7 +72,7 @@ export class ApiService {
|
||||
});
|
||||
}
|
||||
|
||||
private url(url) { // detect if host was given, otherwise use default host
|
||||
private url(url) { // Detect if host was given, otherwise use default host
|
||||
if (/http[s]?:\/\//.test(url)) {
|
||||
return url;
|
||||
}
|
||||
@ -81,12 +81,12 @@ export class ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
// generate request options
|
||||
// Generate request options
|
||||
private options(): {headers: HttpHeaders, observe: 'body'} {
|
||||
return {headers: this.authOptions(), observe: 'response' as 'body'};
|
||||
}
|
||||
|
||||
// generate Basic Auth
|
||||
// Generate Basic Auth
|
||||
private authOptions(): HttpHeaders {
|
||||
const auth = this.storage.get('basicAuth');
|
||||
if (auth) {
|
||||
|
@ -16,7 +16,7 @@ export class DataService {
|
||||
private api: ApiService
|
||||
) { }
|
||||
|
||||
private collectionMap = { // list of available collections
|
||||
private collectionMap = { // List of available collections
|
||||
materials: {path: '/materials?status[]=validated&status[]=new', model: MaterialModel, type: 'idArray'},
|
||||
materialSuppliers: {path: '/material/suppliers', model: null, type: 'idArray'},
|
||||
materialGroups: {path: '/material/groups', model: null, type: 'idArray'},
|
||||
@ -31,31 +31,31 @@ export class DataService {
|
||||
userKey: {path: '/user/key', model: BaseModel, type: 'string'}
|
||||
};
|
||||
|
||||
arr: {[key: string]: any[]} = {}; // array of data
|
||||
latest: {[key: string]: any[]} = {}; // array of latest template versions
|
||||
id: {[key: string]: {[id: string]: any}} = {}; // data in format _id: data
|
||||
d: {[key: string]: any} = {}; // data not in array format
|
||||
arr: {[key: string]: any[]} = {}; // Array of data
|
||||
latest: {[key: string]: any[]} = {}; // Array of latest template versions
|
||||
id: {[key: string]: {[id: string]: any}} = {}; // Data in format _id: data
|
||||
d: {[key: string]: any} = {}; // Data not in array format
|
||||
|
||||
contact = {name: 'CR/APS1-Lingenfelser', mail: 'dominic.lingenfelser@bosch.com'}; // global contact data
|
||||
contact = {name: 'CR/APS1-Lingenfelser', mail: 'dominic.lingenfelser@bosch.com'}; // Global contact data
|
||||
|
||||
load(collection, f = () => {}) { // load data
|
||||
if (this.arr[collection]) { // data already loaded
|
||||
load(collection, f = () => {}) { // Load data
|
||||
if (this.arr[collection]) { // Data already loaded
|
||||
f();
|
||||
}
|
||||
else { // load data
|
||||
else { // Load data
|
||||
this.api.get<any>(this.collectionMap[collection].path, data => {
|
||||
if (this.collectionMap[collection].type !== 'string') { // array data
|
||||
if (this.collectionMap[collection].type !== 'string') { // Array data
|
||||
this.arr[collection] = data
|
||||
.map(
|
||||
e => this.collectionMap[collection].model ?
|
||||
new this.collectionMap[collection].model().deserialize(e) : e
|
||||
);
|
||||
// load ids
|
||||
// Load ids
|
||||
if (this.collectionMap[collection].type === 'idArray' || this.collectionMap[collection].type === 'template') {
|
||||
this.idReload(collection);
|
||||
}
|
||||
}
|
||||
else { // not array data
|
||||
else { // Not array data
|
||||
this.d[collection] = new this.collectionMap[collection].model().deserialize(data);
|
||||
}
|
||||
f();
|
||||
@ -63,13 +63,13 @@ export class DataService {
|
||||
}
|
||||
}
|
||||
|
||||
// generate id object
|
||||
// Generate id object
|
||||
idReload(collection) {
|
||||
this.id[collection] = this.arr[collection].reduce((s, e) => {s[e._id] = e; return s; }, {});
|
||||
if (this.collectionMap[collection].type === 'template') { // generate array with latest templates
|
||||
if (this.collectionMap[collection].type === 'template') { // Generate array with latest templates
|
||||
const tmpTemplates = {};
|
||||
this.arr[collection].forEach(template => {
|
||||
if (tmpTemplates[template.first_id]) { // already found another version
|
||||
if (tmpTemplates[template.first_id]) { // Already found another version
|
||||
if (template.version > tmpTemplates[template.first_id].version) {
|
||||
tmpTemplates[template.first_id] = template;
|
||||
}
|
||||
|
@ -10,22 +10,22 @@ import {DataService} from './data.service';
|
||||
})
|
||||
export class LoginService implements CanActivate {
|
||||
|
||||
private pathPermissions = [ // minimum level needed for the specified paths
|
||||
private pathPermissions = [ // Minimum level needed for the specified paths
|
||||
{path: 'materials', permission: 'dev'},
|
||||
{path: 'templates', permission: 'dev'},
|
||||
{path: 'changelog', permission: 'dev'},
|
||||
{path: 'users', permission: 'admin'}
|
||||
];
|
||||
readonly levels = [ // all user levels in ascending permissions order
|
||||
readonly levels = [ // All user levels in ascending permissions order
|
||||
'predict',
|
||||
'read',
|
||||
'write',
|
||||
'dev',
|
||||
'admin'
|
||||
];
|
||||
// returns true or false depending on whether the user fulfills the minimum level
|
||||
// Returns true or false depending on whether the user fulfills the minimum level
|
||||
isLevel: {[level: string]: boolean} = {};
|
||||
hasPrediction = false; // true if user has prediction models specified
|
||||
hasPrediction = false; // True if user has prediction models specified
|
||||
userId = '';
|
||||
|
||||
private loggedIn;
|
||||
@ -41,22 +41,22 @@ export class LoginService implements CanActivate {
|
||||
|
||||
login(username = '', password = '') {
|
||||
return new Promise(resolve => {
|
||||
if (username !== '' || password !== '') { // some credentials given
|
||||
if (username !== '' || password !== '') { // Some credentials given
|
||||
let credentials: string[];
|
||||
const credentialString: string = this.storage.get('basicAuth');
|
||||
if (credentialString) { // found stored credentials
|
||||
if (credentialString) { // Found stored credentials
|
||||
credentials = atob(credentialString).split(':');
|
||||
}
|
||||
else {
|
||||
credentials = ['', ''];
|
||||
}
|
||||
if (username !== '' && password !== '') { // all credentials given
|
||||
if (username !== '' && password !== '') { // All credentials given
|
||||
this.storage.set('basicAuth', btoa(username + ':' + password));
|
||||
}
|
||||
else if (username !== '') { // username given
|
||||
else if (username !== '') { // Username given
|
||||
this.storage.set('basicAuth', btoa(username + ':' + credentials[1]));
|
||||
}
|
||||
else if (password !== '') { // password given
|
||||
else if (password !== '') { // Password given
|
||||
this.storage.set('basicAuth', btoa(credentials[0] + ':' + password));
|
||||
}
|
||||
}
|
||||
@ -66,7 +66,7 @@ export class LoginService implements CanActivate {
|
||||
this.loggedIn = true;
|
||||
this.levels.forEach(level => {
|
||||
this.isLevel[level] = this.levels.indexOf(data.level) >= this.levels.indexOf(level);
|
||||
if (this.isLevel.dev) { // set hasPrediction
|
||||
if (this.isLevel.dev) { // Set hasPrediction
|
||||
this.hasPrediction = true;
|
||||
}
|
||||
else {
|
||||
@ -100,7 +100,7 @@ export class LoginService implements CanActivate {
|
||||
this.hasPrediction = false;
|
||||
}
|
||||
|
||||
// canActivate for Angular routing
|
||||
// CanActivate for Angular routing
|
||||
canActivate(route: ActivatedRouteSnapshot = null, state: RouterStateSnapshot = null): Observable<boolean> {
|
||||
return new Observable<boolean>(observer => {
|
||||
new Promise(resolve => {
|
||||
@ -114,7 +114,7 @@ export class LoginService implements CanActivate {
|
||||
}
|
||||
}).then(res => {
|
||||
const pathPermission = this.pathPermissions.find(e => e.path.indexOf(route.url[0].path) >= 0);
|
||||
// check if level is permitted for path
|
||||
// Check if level is permitted for path
|
||||
const ok = res && (!pathPermission || this.isLevel[pathPermission.permission]);
|
||||
observer.next(ok);
|
||||
observer.complete();
|
||||
|
@ -19,7 +19,7 @@ export class ValidationService {
|
||||
|
||||
constructor() { }
|
||||
|
||||
generate(method, args) { // generate a Validator function
|
||||
generate(method, args) { // Generate a Validator function
|
||||
return (control: AbstractControl): {[key: string]: any} | null => {
|
||||
let ok;
|
||||
let error;
|
||||
@ -63,7 +63,7 @@ export class ValidationService {
|
||||
return {ok: true, error: ''};
|
||||
}
|
||||
|
||||
stringOf(data, list) { // string must be in list
|
||||
stringOf(data, list) { // String must be in list
|
||||
const {ignore, error} = Joi.string().allow('').valid(...list.map(e => e.toString())).validate(data);
|
||||
if (error) {
|
||||
return {ok: false, error: 'must be one of ' + list.join(', ')};
|
||||
@ -71,7 +71,7 @@ export class ValidationService {
|
||||
return {ok: true, error: ''};
|
||||
}
|
||||
|
||||
stringNin(data, list) { // string must not be in list
|
||||
stringNin(data, list) { // String must not be in list
|
||||
const {ignore, error} = Joi.string().invalid(...list).validate(data);
|
||||
if (error) {
|
||||
return {ok: false, error: 'value not allowed'};
|
||||
@ -79,7 +79,7 @@ export class ValidationService {
|
||||
return {ok: true, error: ''};
|
||||
}
|
||||
|
||||
stringLength(data, length) { // string with maximum length
|
||||
stringLength(data, length) { // String with maximum length
|
||||
const {ignore, error} = Joi.string().max(length).allow('').validate(data);
|
||||
if (error) {
|
||||
return {ok: false, error: 'must contain max ' + length + ' characters'};
|
||||
@ -87,7 +87,7 @@ export class ValidationService {
|
||||
return {ok: true, error: ''};
|
||||
}
|
||||
|
||||
minMax(data, min, max) { // number between min and max
|
||||
minMax(data, min, max) { // Number between min and max
|
||||
const {ignore, error} = Joi.number().allow('').min(min).max(max).validate(data);
|
||||
if (error) {
|
||||
return {ok: false, error: `must be between ${min} and ${max}`};
|
||||
@ -95,7 +95,7 @@ export class ValidationService {
|
||||
return {ok: true, error: ''};
|
||||
}
|
||||
|
||||
min(data, min) { // number above min
|
||||
min(data, min) { // Number above min
|
||||
const {ignore, error} = Joi.number().allow('').min(min).validate(data);
|
||||
if (error) {
|
||||
return {ok: false, error: `must not be below ${min}`};
|
||||
@ -103,7 +103,7 @@ export class ValidationService {
|
||||
return {ok: true, error: ''};
|
||||
}
|
||||
|
||||
max(data, max) { // number below max
|
||||
max(data, max) { // Number below max
|
||||
const {ignore, error} = Joi.number().allow('').max(max).validate(data);
|
||||
if (error) {
|
||||
return {ok: false, error: `must not be above ${max}`};
|
||||
|
@ -12,9 +12,9 @@ import {LoginService} from '../services/login.service';
|
||||
})
|
||||
export class SettingsComponent implements OnInit {
|
||||
|
||||
user: UserModel = new UserModel(); // user to edit
|
||||
password = ''; // new password
|
||||
messageUser = ''; // messages for user and pass part
|
||||
user: UserModel = new UserModel(); // User to edit
|
||||
password = ''; // New password
|
||||
messageUser = ''; // Messages for user and pass part
|
||||
messagePass = '';
|
||||
|
||||
constructor(
|
||||
@ -34,7 +34,7 @@ export class SettingsComponent implements OnInit {
|
||||
if (err) {
|
||||
this.messageUser = err.error.status;
|
||||
}
|
||||
else { // login with new credentials
|
||||
else { // Login with new credentials
|
||||
this.login.login(data.name).then(res => {
|
||||
if (res) {
|
||||
this.router.navigate(['/samples']);
|
||||
@ -52,7 +52,7 @@ export class SettingsComponent implements OnInit {
|
||||
if (err) {
|
||||
this.messagePass = err.error.status;
|
||||
}
|
||||
else { // login with new credentials
|
||||
else { // Login with new credentials
|
||||
this.login.login('', this.password).then(res => {
|
||||
if (res) {
|
||||
this.router.navigate(['/samples']);
|
||||
|
@ -28,11 +28,11 @@ import {DataService} from '../services/data.service';
|
||||
})
|
||||
export class TemplatesComponent implements OnInit {
|
||||
|
||||
collection = 'measurement'; // collection to view
|
||||
templates: TemplateModel[] = []; // all templates of current collection
|
||||
templateGroups: {[first_id: string]: TemplateModel[]} = {}; // templates grouped by first_id
|
||||
templateEdit: {[first_id: string]: TemplateModel} = {}; // latest template of each first_id for editing
|
||||
groupsView: { // grouped templates
|
||||
collection = 'measurement'; // Collection to view
|
||||
templates: TemplateModel[] = []; // All templates of current collection
|
||||
templateGroups: {[first_id: string]: TemplateModel[]} = {}; // Templates grouped by first_id
|
||||
templateEdit: {[first_id: string]: TemplateModel} = {}; // Latest template of each first_id for editing
|
||||
groupsView: { // Grouped templates
|
||||
first_id: string,
|
||||
name: string,
|
||||
version: number,
|
||||
@ -61,7 +61,7 @@ export class TemplatesComponent implements OnInit {
|
||||
templateFormat() {
|
||||
this.templateGroups = {};
|
||||
this.templateEdit = {};
|
||||
this.templates.forEach(template => { // group templates
|
||||
this.templates.forEach(template => { // Group templates
|
||||
if (this.templateGroups[template.first_id]) {
|
||||
this.templateGroups[template.first_id].push(template);
|
||||
}
|
||||
@ -100,7 +100,7 @@ export class TemplatesComponent implements OnInit {
|
||||
});
|
||||
if (valid) {
|
||||
const sendData = {name: template.name, parameters: template.parameters.map(e => omit(e, ['rangeString']))};
|
||||
if (first_id === 'null') { // new template
|
||||
if (first_id === 'null') { // New template
|
||||
this.api.post<TemplateModel>(`/template/${this.collection}/new`, sendData, () => {
|
||||
delete this.d.arr[this.collection + 'Templates'];
|
||||
this.d.load(this.collection + 'Templates', () => {
|
||||
|
@ -13,12 +13,12 @@ import {DataService} from '../services/data.service';
|
||||
})
|
||||
export class UsersComponent implements OnInit {
|
||||
|
||||
users: UserModel[] = []; // all active users
|
||||
deletedUsers: UserModel[] = []; // all deleted users
|
||||
newUser: UserModel | null = null; // data of new user
|
||||
newUserPass = ''; // password of new user
|
||||
modelSelect: {id: string, name: string}[] = []; // list of all models for selection
|
||||
modelIds: {[id: string]: string} = {}; // all models by id
|
||||
users: UserModel[] = []; // All active users
|
||||
deletedUsers: UserModel[] = []; // All deleted users
|
||||
newUser: UserModel | null = null; // Data of new user
|
||||
newUserPass = ''; // Password of new user
|
||||
modelSelect: {id: string, name: string}[] = []; // List of all models for selection
|
||||
modelIds: {[id: string]: string} = {}; // All models by id
|
||||
|
||||
constructor(
|
||||
private api: ApiService,
|
||||
|
@ -13,4 +13,4 @@ export const environment = {
|
||||
* This import should be commented out in production mode because it will have a negative impact
|
||||
* on performance if an error is thrown.
|
||||
*/
|
||||
// import 'zone.js/dist/zone-error'; // Included with Angular CLI.
|
||||
// Import 'zone.js/dist/zone-error'; // Included with Angular CLI.
|
||||
|
@ -19,14 +19,14 @@
|
||||
*/
|
||||
|
||||
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
|
||||
// import 'classlist.js'; // Run `npm install --save classlist.js`.
|
||||
// Import 'classlist.js'; // Run `npm install --save classlist.js`.
|
||||
|
||||
/**
|
||||
* Web Animations `@angular/platform-browser/animations`
|
||||
* Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
|
||||
* Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
|
||||
*/
|
||||
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
|
||||
// Import 'web-animations-js'; // Run `npm install --save web-animations-js`.
|
||||
|
||||
/**
|
||||
* By default, zone.js will patch all possible macroTask and DomEvents
|
||||
@ -41,9 +41,9 @@
|
||||
*
|
||||
* The following flags will work for all browsers.
|
||||
*
|
||||
* (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
|
||||
* (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
|
||||
* (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
|
||||
* (window as any).__Zone_disable_requestAnimationFrame = true; // Disable patch requestAnimationFrame
|
||||
* (window as any).__Zone_disable_on_property = true; // Disable patch onProperty such as onclick
|
||||
* (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // Disable patch specified eventNames
|
||||
*
|
||||
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
|
||||
* with the following flag, it will bypass `zone.js` patch for IE/Edge
|
||||
|
Loading…
Reference in New Issue
Block a user