diff --git a/src/app/home/home.component.html b/src/app/home/home.component.html index 7f03ce2..f4d5282 100644 --- a/src/app/home/home.component.html +++ b/src/app/home/home.component.html @@ -1,3 +1,23 @@ - +
+ + +
- + +
+ + {{key.id}} + + + + +
+ + +
+
diff --git a/src/app/home/home.component.ts b/src/app/home/home.component.ts index 1cb0ce7..792bf95 100644 --- a/src/app/home/home.component.ts +++ b/src/app/home/home.component.ts @@ -1,5 +1,15 @@ import { Component, OnInit } from '@angular/core'; import {LoginService} from '../services/login.service'; +import { ApiService } from '../services/api.service'; +import {Chart} from 'chart.js'; + + + +interface KeyInterface { + id: string; + count: number; + active: boolean; +} @Component({ selector: 'app-home', @@ -8,11 +18,121 @@ import {LoginService} from '../services/login.service'; }) export class HomeComponent implements OnInit { + keys: KeyInterface[] = []; + isActiveKey: { [key: string]: boolean } = {}; // object to check if key is currently active + myChart: Chart; + constructor( - public login: LoginService + public login: LoginService, + public api: ApiService ) { } ngOnInit() { + // fetch all available groups + this.fetchData('/material/groups', data => this.createGroup(data)); + //this.initChart(); + console.log(this.login.username); } + // api access with callback + async fetchData(URL: string, processor: any) { + this.api.get(URL, (sData, err, headers) => { + processor(sData); + }); + } + + // Fill interface with data + createGroup(data: any) { + let temp: KeyInterface[] = []; + + 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.calcFieldSelectKeys(); + // fetch all samples populated with according group + this.fetchData('/samples?status%5B%5D=validated&status=new&page-size=10&sort=_id-asc&fields%5B%5D=material.group', data => this.countSamples(data)); + } + + // loop through samples and count + countSamples(data: any) { + for (var i = 0; i < data.length; i++) { + this.keys.forEach(key => { + if (key.id === data[i].material.group) { + key.count += 1; + } + }); + } + this.initChart(); + } + + // preset select + calcFieldSelectKeys() { + this.keys.forEach(key => { + this.isActiveKey[key.id] = key.active; + }); + } + + // update keys based on select + updateGroups(event: any) { + this.keys.forEach(key => { + if (event.hasOwnProperty(key.id)) { + key.active = event[key.id]; + } + }); + this.myChart.destroy(); + this.initChart(); + } + + // get data for graph based on active keys + async getData() { + let nameList: string[] = []; + let dataList: number[] = []; + + this.keys.forEach(key => { + if (key.active) { + nameList.push(key.id); + dataList.push(key.count); + } + }) + return { names: nameList, data: dataList }; + } + + // draw graph + async initChart() { + const data = await this.getData(); + + const canvas = document.getElementById('myChart') as HTMLCanvasElement; + const width = canvas.clientWidth; + const height = canvas.clientHeight; + const ctx = canvas.getContext('2d'); + + var img = new Image(width, height); + img.src = "/assets/imgs/supergraphic.svg"; + img.onload = () => { + const fillPattern = ctx.createPattern(img, 'no-repeat'); + + this.myChart = new Chart("myChart", { + type: 'line', + data: { + labels: data.names, + datasets: [{ + label: 'Number of samples per group', + data: data.data, + backgroundColor: fillPattern, + borderWidth: 2 + }] + }, + options: { + scales: { + yAxes: [{ + ticks: { + beginAtZero: true + } + }] + } + } + }); + } + } } diff --git a/src/app/samples/samples.component.ts b/src/app/samples/samples.component.ts index 9ec3226..c8f598e 100644 --- a/src/app/samples/samples.component.ts +++ b/src/app/samples/samples.component.ts @@ -1,23 +1,22 @@ -import {Component, ElementRef, isDevMode, OnInit, TemplateRef, ViewChild} from '@angular/core'; -import {ApiService} from '../services/api.service'; -import {AutocompleteService} from '../services/autocomplete.service'; +import { Component, ElementRef, isDevMode, OnInit, TemplateRef, ViewChild } from '@angular/core'; +import { ApiService } from '../services/api.service'; +import { AutocompleteService } from '../services/autocomplete.service'; import cloneDeep from 'lodash/cloneDeep'; import pick from 'lodash/pick'; import omit from 'lodash/omit'; -import {SampleModel} from '../models/sample.model'; -import {LoginService} from '../services/login.service'; -import {ModalService} from '@inst-iot/bosch-angular-ui-components'; -import {DataService} from '../services/data.service'; -import {LocalStorageService} from 'angular-2-local-storage'; -import {Router} from '@angular/router'; - - +import { SampleModel } from '../models/sample.model'; +import { LoginService } from '../services/login.service'; +import { ModalService } from '@inst-iot/bosch-angular-ui-components'; +import { DataService } from '../services/data.service'; +import { LocalStorageService } from 'angular-2-local-storage'; +import { Router } from '@angular/router'; interface LoadSamplesOptions { toPage?: number; event?: Event; firstPage?: boolean; } + interface KeyInterface { id: string; label: string; @@ -43,46 +42,46 @@ export class SamplesComponent implements OnInit { 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}, + status: { new: true, validated: true, deleted: false }, pageSize: 25, toPage: 0, sort: 'added-asc', - no: {condition: false, measurements: false}, + no: { condition: false, measurements: false }, filters: [ - {field: 'number', label: 'Number', active: false, autocomplete: [], mode: 'eq', values: ['']}, - {field: 'material.name', label: 'Product name', active: false, autocomplete: [], mode: 'eq', values: ['']}, - {field: 'material.supplier', label: 'Supplier', active: false, autocomplete: [], mode: 'eq', values: ['']}, - {field: 'material.group', label: 'Material', active: false, autocomplete: [], mode: 'eq', values: ['']}, - {field: 'material.glass_fiber', label: 'GF', active: false, autocomplete: [], mode: 'eq', values: ['']}, - {field: 'material.carbon_fiber', label: 'CF', active: false, autocomplete: [], mode: 'eq', values: ['']}, - {field: 'material.mineral', label: 'M', active: false, autocomplete: [], mode: 'eq', values: ['']}, - {field: 'type', label: 'Type', active: false, autocomplete: [], mode: 'eq', values: ['']}, - {field: 'color', label: 'Color', active: false, autocomplete: [], mode: 'eq', values: ['']}, - {field: 'batch', label: 'Batch', active: false, autocomplete: [], mode: 'eq', values: ['']}, - {field: 'notes.comment', label: 'Comment', active: false, autocomplete: [], mode: 'eq', values: ['']}, - {field: 'added', label: 'Added', active: false, autocomplete: [], mode: 'eq', values: ['']} + { field: 'number', label: 'Number', active: false, autocomplete: [], mode: 'eq', values: [''] }, + { field: 'material.name', label: 'Product name', active: false, autocomplete: [], mode: 'eq', values: [''] }, + { field: 'material.supplier', label: 'Supplier', active: false, autocomplete: [], mode: 'eq', values: [''] }, + { field: 'material.group', label: 'Material', active: false, autocomplete: [], mode: 'eq', values: [''] }, + { field: 'material.glass_fiber', label: 'GF', active: false, autocomplete: [], mode: 'eq', values: [''] }, + { field: 'material.carbon_fiber', label: 'CF', active: false, autocomplete: [], mode: 'eq', values: [''] }, + { field: 'material.mineral', label: 'M', active: false, autocomplete: [], mode: 'eq', values: [''] }, + { field: 'type', label: 'Type', active: false, autocomplete: [], mode: 'eq', values: [''] }, + { field: 'color', label: 'Color', active: false, autocomplete: [], mode: 'eq', values: [''] }, + { field: 'batch', label: 'Batch', active: false, autocomplete: [], mode: 'eq', values: [''] }, + { field: 'notes.comment', label: 'Comment', active: false, autocomplete: [], mode: 'eq', values: [''] }, + { 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 keys: KeyInterface[] = [ - {id: 'number', label: 'Number', active: true, sortable: true}, - {id: 'material.numbers', label: 'Material numbers', active: false, sortable: false}, - {id: 'material.name', label: 'Product name', active: true, sortable: true}, - {id: 'material.supplier', label: 'Supplier', active: false, sortable: true}, - {id: 'material.group', label: 'Material', active: true, sortable: true}, - {id: 'type', label: 'Type', active: true, sortable: true}, - {id: 'color', label: 'Color', active: false, sortable: true}, - {id: 'batch', label: 'Batch', active: true, sortable: true}, - {id: 'notes.comment', label: 'Comment', active: false, sortable: false}, - {id: 'notes', label: 'Notes', active: false, sortable: false}, - {id: 'status', label: 'Status', active: false, sortable: true}, - {id: 'added', label: 'Added', active: true, sortable: true} + { id: 'number', label: 'Number', active: true, sortable: true }, + { id: 'material.numbers', label: 'Material numbers', active: false, sortable: false }, + { id: 'material.name', label: 'Product name', active: true, sortable: true }, + { id: 'material.supplier', label: 'Supplier', active: false, sortable: true }, + { id: 'material.group', label: 'Material', active: true, sortable: true }, + { id: 'type', label: 'Type', active: true, sortable: true }, + { id: 'color', label: 'Color', active: false, sortable: true }, + { id: 'batch', label: 'Batch', active: true, sortable: true }, + { id: 'notes.comment', label: 'Comment', active: false, sortable: false }, + { id: 'notes', label: 'Notes', active: false, sortable: false }, + { id: 'status', label: 'Status', active: false, sortable: true }, + { id: 'added', label: 'Added', active: true, sortable: true } ]; - isActiveKey: {[key: string]: boolean} = {}; // object to check if key is currently active + isActiveKey: { [key: string]: boolean } = {}; // object to check if key is currently active activeKeys: KeyInterface[] = []; // list of active keys - activeTemplateKeys = {material: [], condition: [], measurements: []}; + activeTemplateKeys = { material: [], condition: [], measurements: [] }; 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 @@ -105,7 +104,7 @@ export class SamplesComponent implements OnInit { const onLoad = () => { if ((--this.loading) <= 0) { this.loadSamples(); - } + } }; this.calcFieldSelectKeys(); @@ -164,10 +163,11 @@ export class SamplesComponent implements OnInit { f(); }); } - + // set toPage to null to reload first page, queues calls loadSamples(options: LoadSamplesOptions = {}, event = null) { if (event) { // adjust active keys + console.log(event); this.keys.forEach(key => { if (event.hasOwnProperty(key.id)) { key.active = event[key.id]; @@ -179,9 +179,9 @@ export class SamplesComponent implements OnInit { } this.updateActiveKeys(); } - if(options.firstPage){ - this.storage.set('currentPage', 1); - } + if(options.firstPage){ + this.storage.set('currentPage', 1); + } this.loadSamplesQueue.push(options); if (this.loadSamplesQueue.length <= 1) { // nothing queued up this.sampleLoader(this.loadSamplesQueue[0]); @@ -190,9 +190,9 @@ export class SamplesComponent implements OnInit { } 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 --; + 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 this.storage.remove('samplesPreferences'); this.api.requestError(err); @@ -209,9 +209,9 @@ export class SamplesComponent implements OnInit { } } }); - if(this.storage.get('currentPage') !== this.page){ - this.loadPage(Number(this.storage.get('currentPage')) - this.page); - } + if(this.storage.get('currentPage') !== this.page){ + this.loadPage(Number(this.storage.get('currentPage')) - this.page); + } } sampleUrl(options: { @@ -272,17 +272,17 @@ export class SamplesComponent implements OnInit { .map(e => 'filters[]=' + encodeURIComponent(JSON.stringify(pick(e, ['mode', 'field', 'values'])))) ); if (this.filters.no.condition) { - query.push('filters[]=' + encodeURIComponent( JSON.stringify({mode: 'eq', field: 'condition', values: [{}]}))); + query.push('filters[]=' + encodeURIComponent(JSON.stringify({ mode: 'eq', field: 'condition', values: [{}] }))); } if (this.filters.no.measurements) { query.push('filters[]=' + - encodeURIComponent( JSON.stringify( {mode: 'eq', field: 'measurements', values: [null]}))); + encodeURIComponent(JSON.stringify({ mode: 'eq', field: 'measurements', values: [null] }))); } if (!options.export) { additionalTableKeys.forEach(key => { - if (query.indexOf('fields[]=' + key) < 0) { // add key if not already added - query.push('fields[]=' + key); - } + if (query.indexOf('fields[]=' + key) < 0) { // add key if not already added + query.push('fields[]=' + key); + } }); } else { // export options @@ -307,10 +307,10 @@ export class SamplesComponent implements OnInit { loadPage(delta) { if (!/[0-9]+/.test(delta) || this.page + delta < 1) { // invalid delta return; - } - this.page += delta; - this.storage.set('currentPage', this.page); - this.loadSamples({toPage: delta}); + } + this.page += delta; + this.storage.set('currentPage', this.page); + this.loadSamples({ toPage: delta }); } storePreferences() { @@ -327,11 +327,11 @@ export class SamplesComponent implements OnInit { loadPreferences() { const store: any = this.storage.get('samplesPreferences'); if (store) { - this.filters = {...this.filters, ...pick(store.filters, ['status', 'pageSize', 'toPage', 'sort'])}; + this.filters = { ...this.filters, ...pick(store.filters, ['status', 'pageSize', 'toPage', 'sort']) }; store.filters.filters.forEach(filter => { const filterIndex = this.filters.filters.findIndex(e => e.field === filter.field); if (filterIndex >= 0) { - this.filters.filters[filterIndex] = {...this.filters.filters[filterIndex], ...filter}; + this.filters.filters[filterIndex] = { ...this.filters.filters[filterIndex], ...filter }; } }); store.keys.forEach(key => { @@ -357,7 +357,7 @@ export class SamplesComponent implements OnInit { setSort(string) { this.filters.sort = string; - this.loadSamples({firstPage: true}); + this.loadSamples({ firstPage: true }); } updateActiveKeys() { // array with all activeKeys @@ -399,12 +399,12 @@ export class SamplesComponent implements OnInit { if (Object.keys(data.condition).length) { // convert condition this.sampleDetailsSample.condition_entries = Object.entries(omit(this.sampleDetailsSample.condition, ['condition_template'])) - .map(e => { - e[0] = `${this.ucFirst( - this.d.id.conditionTemplates[this.sampleDetailsSample.condition.condition_template].name - )} ${e[0]}`; - return e; - }); + .map(e => { + e[0] = `${this.ucFirst( + this.d.id.conditionTemplates[this.sampleDetailsSample.condition.condition_template].name + )} ${e[0]}`; + return e; + }); } else { this.sampleDetailsSample.condition_entries = []; @@ -415,7 +415,7 @@ export class SamplesComponent implements OnInit { const name = this.d.id.measurementTemplates[measurement.measurement_template].name; this.sampleDetailsSample.measurement_entries .push(...Object.entries(measurement.values).filter(e => e[0] !== 'dpt') - .map(e => ({name: this.ucFirst(name) + ' ' + e[0], value: e[1]}))); + .map(e => ({ name: this.ucFirst(name) + ' ' + e[0], value: e[1] }))); }); new Promise(resolve => { if (data.notes.sample_references.length) { // load referenced samples if available @@ -423,7 +423,7 @@ export class SamplesComponent implements OnInit { this.sampleDetailsSample.notes.sample_references.forEach(reference => { this.api.get('/sample/' + reference.sample_id, rData => { reference.number = rData.number; - loadingCounter --; + loadingCounter--; if (!loadingCounter) { resolve(); } @@ -434,7 +434,7 @@ export class SamplesComponent implements OnInit { resolve(); } }).then(() => { - this.modalService.open(modal).then(() => {}); + this.modalService.open(modal).then(() => { }); }); }); }