pwa, save sample view preferences
@@ -1,4 +1,4 @@
 | 
				
			|||||||
# Digital fingerprint of plastics - UI
 | 
					# DeFinMa - UI
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This is the Angular front end for the digital fingerprint of plastics web page hosted in the bic
 | 
					This is the Angular front end for the digital fingerprint of plastics web page hosted in the bic
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										26
									
								
								angular.json
									
									
									
									
									
								
							
							
						
						@@ -3,7 +3,7 @@
 | 
				
			|||||||
  "version": 1,
 | 
					  "version": 1,
 | 
				
			||||||
  "newProjectRoot": "projects",
 | 
					  "newProjectRoot": "projects",
 | 
				
			||||||
  "projects": {
 | 
					  "projects": {
 | 
				
			||||||
    "UI": {
 | 
					    "definma": {
 | 
				
			||||||
      "projectType": "application",
 | 
					      "projectType": "application",
 | 
				
			||||||
      "schematics": {
 | 
					      "schematics": {
 | 
				
			||||||
        "@schematics/angular:component": {
 | 
					        "@schematics/angular:component": {
 | 
				
			||||||
@@ -17,7 +17,7 @@
 | 
				
			|||||||
        "build": {
 | 
					        "build": {
 | 
				
			||||||
          "builder": "@angular-devkit/build-angular:browser",
 | 
					          "builder": "@angular-devkit/build-angular:browser",
 | 
				
			||||||
          "options": {
 | 
					          "options": {
 | 
				
			||||||
            "outputPath": "dist/UI",
 | 
					            "outputPath": "dist/definma",
 | 
				
			||||||
            "index": "src/index.html",
 | 
					            "index": "src/index.html",
 | 
				
			||||||
            "main": "src/main.ts",
 | 
					            "main": "src/main.ts",
 | 
				
			||||||
            "polyfills": "src/polyfills.ts",
 | 
					            "polyfills": "src/polyfills.ts",
 | 
				
			||||||
@@ -30,7 +30,8 @@
 | 
				
			|||||||
                "glob": "**/*",
 | 
					                "glob": "**/*",
 | 
				
			||||||
                "input": "./node_modules/@inst-iot/bosch-angular-ui-components/assets",
 | 
					                "input": "./node_modules/@inst-iot/bosch-angular-ui-components/assets",
 | 
				
			||||||
                "output": "./assets"
 | 
					                "output": "./assets"
 | 
				
			||||||
              }
 | 
					              },
 | 
				
			||||||
 | 
					              "src/manifest.webmanifest"
 | 
				
			||||||
            ],
 | 
					            ],
 | 
				
			||||||
            "styles": [
 | 
					            "styles": [
 | 
				
			||||||
              "src/styles.scss"
 | 
					              "src/styles.scss"
 | 
				
			||||||
@@ -64,26 +65,28 @@
 | 
				
			|||||||
                  "maximumWarning": "6kb",
 | 
					                  "maximumWarning": "6kb",
 | 
				
			||||||
                  "maximumError": "10kb"
 | 
					                  "maximumError": "10kb"
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
              ]
 | 
					              ],
 | 
				
			||||||
 | 
					              "serviceWorker": true,
 | 
				
			||||||
 | 
					              "ngswConfigPath": "ngsw-config.json"
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "serve": {
 | 
					        "serve": {
 | 
				
			||||||
          "builder": "@angular-devkit/build-angular:dev-server",
 | 
					          "builder": "@angular-devkit/build-angular:dev-server",
 | 
				
			||||||
          "options": {
 | 
					          "options": {
 | 
				
			||||||
            "browserTarget": "UI:build",
 | 
					            "browserTarget": "definma:build",
 | 
				
			||||||
            "proxyConfig": "src/proxy.conf.json"
 | 
					            "proxyConfig": "src/proxy.conf.json"
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
          "configurations": {
 | 
					          "configurations": {
 | 
				
			||||||
            "production": {
 | 
					            "production": {
 | 
				
			||||||
              "browserTarget": "UI:build:production"
 | 
					              "browserTarget": "definma:build:production"
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "extract-i18n": {
 | 
					        "extract-i18n": {
 | 
				
			||||||
          "builder": "@angular-devkit/build-angular:extract-i18n",
 | 
					          "builder": "@angular-devkit/build-angular:extract-i18n",
 | 
				
			||||||
          "options": {
 | 
					          "options": {
 | 
				
			||||||
            "browserTarget": "UI:build"
 | 
					            "browserTarget": "definma:build"
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "test": {
 | 
					        "test": {
 | 
				
			||||||
@@ -95,7 +98,8 @@
 | 
				
			|||||||
            "karmaConfig": "karma.conf.js",
 | 
					            "karmaConfig": "karma.conf.js",
 | 
				
			||||||
            "assets": [
 | 
					            "assets": [
 | 
				
			||||||
              "src/favicon.ico",
 | 
					              "src/favicon.ico",
 | 
				
			||||||
              "src/assets"
 | 
					              "src/assets",
 | 
				
			||||||
 | 
					              "src/manifest.webmanifest"
 | 
				
			||||||
            ],
 | 
					            ],
 | 
				
			||||||
            "styles": [
 | 
					            "styles": [
 | 
				
			||||||
              "src/styles.scss"
 | 
					              "src/styles.scss"
 | 
				
			||||||
@@ -120,15 +124,15 @@
 | 
				
			|||||||
          "builder": "@angular-devkit/build-angular:protractor",
 | 
					          "builder": "@angular-devkit/build-angular:protractor",
 | 
				
			||||||
          "options": {
 | 
					          "options": {
 | 
				
			||||||
            "protractorConfig": "e2e/protractor.conf.js",
 | 
					            "protractorConfig": "e2e/protractor.conf.js",
 | 
				
			||||||
            "devServerTarget": "UI:serve"
 | 
					            "devServerTarget": "definma:serve"
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
          "configurations": {
 | 
					          "configurations": {
 | 
				
			||||||
            "production": {
 | 
					            "production": {
 | 
				
			||||||
              "devServerTarget": "UI:serve:production"
 | 
					              "devServerTarget": "definma:serve:production"
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }},
 | 
					    }},
 | 
				
			||||||
  "defaultProject": "UI"
 | 
					  "defaultProject": "definma"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
pushstate: enabled
 | 
					pushstate: enabled
 | 
				
			||||||
force_https: true
 | 
					force_https: true
 | 
				
			||||||
root: UI
 | 
					root: definma
 | 
				
			||||||
location_include: ../../*.conf
 | 
					location_include: ../../*.conf
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,7 +16,7 @@ module.exports = function (config) {
 | 
				
			|||||||
      clearContext: false // leave Jasmine Spec Runner output visible in browser
 | 
					      clearContext: false // leave Jasmine Spec Runner output visible in browser
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    coverageIstanbulReporter: {
 | 
					    coverageIstanbulReporter: {
 | 
				
			||||||
      dir: require('path').join(__dirname, './coverage/UI'),
 | 
					      dir: require('path').join(__dirname, './coverage/definma'),
 | 
				
			||||||
      reports: ['html', 'lcovonly', 'text-summary'],
 | 
					      reports: ['html', 'lcovonly', 'text-summary'],
 | 
				
			||||||
      fixWebpackSourcePaths: true
 | 
					      fixWebpackSourcePaths: true
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										29
									
								
								ngsw-config.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "$schema": "./node_modules/@angular/service-worker/config/schema.json",
 | 
				
			||||||
 | 
					  "index": "/index.html",
 | 
				
			||||||
 | 
					  "assetGroups": [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "name": "app",
 | 
				
			||||||
 | 
					      "installMode": "prefetch",
 | 
				
			||||||
 | 
					      "resources": {
 | 
				
			||||||
 | 
					        "files": [
 | 
				
			||||||
 | 
					          "/favicon.ico",
 | 
				
			||||||
 | 
					          "/index.html",
 | 
				
			||||||
 | 
					          "/manifest.webmanifest",
 | 
				
			||||||
 | 
					          "/*.css",
 | 
				
			||||||
 | 
					          "/*.js"
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }, {
 | 
				
			||||||
 | 
					      "name": "assets",
 | 
				
			||||||
 | 
					      "installMode": "lazy",
 | 
				
			||||||
 | 
					      "updateMode": "prefetch",
 | 
				
			||||||
 | 
					      "resources": {
 | 
				
			||||||
 | 
					        "files": [
 | 
				
			||||||
 | 
					          "/assets/**",
 | 
				
			||||||
 | 
					          "/*.(eot|svg|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani)"
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										9
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						@@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "ui",
 | 
					  "name": "definma",
 | 
				
			||||||
  "version": "0.0.0",
 | 
					  "version": "0.5.5",
 | 
				
			||||||
  "lockfileVersion": 1,
 | 
					  "lockfileVersion": 1,
 | 
				
			||||||
  "requires": true,
 | 
					  "requires": true,
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
@@ -630,6 +630,11 @@
 | 
				
			|||||||
      "resolved": "https://registry.npmjs.org/@angular/router/-/router-9.1.7.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@angular/router/-/router-9.1.7.tgz",
 | 
				
			||||||
      "integrity": "sha512-ycrkhkCbfOMCe9PngFjnyk8nH5jt0Kyb2NPtjmaGOtSCuZBZ0kOU0rQGmQnj3d2PiT0Yir59S8eEAf3Fh0iDuw=="
 | 
					      "integrity": "sha512-ycrkhkCbfOMCe9PngFjnyk8nH5jt0Kyb2NPtjmaGOtSCuZBZ0kOU0rQGmQnj3d2PiT0Yir59S8eEAf3Fh0iDuw=="
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "@angular/service-worker": {
 | 
				
			||||||
 | 
					      "version": "9.1.12",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-9.1.12.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-UsmhPfhIYq9LanuFT6V7Kmkr5Vjl2CMjKkL1gqhChkywNW4vavAYsBkuVji8P76ZKliq41TCG01z6xIAWji8QA=="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "@babel/code-frame": {
 | 
					    "@babel/code-frame": {
 | 
				
			||||||
      "version": "7.8.3",
 | 
					      "version": "7.8.3",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,6 +23,7 @@
 | 
				
			|||||||
    "@angular/platform-browser": "~9.1.7",
 | 
					    "@angular/platform-browser": "~9.1.7",
 | 
				
			||||||
    "@angular/platform-browser-dynamic": "~9.1.7",
 | 
					    "@angular/platform-browser-dynamic": "~9.1.7",
 | 
				
			||||||
    "@angular/router": "~9.1.7",
 | 
					    "@angular/router": "~9.1.7",
 | 
				
			||||||
 | 
					    "@angular/service-worker": "~9.1.7",
 | 
				
			||||||
    "@hapi/joi": "^17.1.1",
 | 
					    "@hapi/joi": "^17.1.1",
 | 
				
			||||||
    "@inst-iot/bosch-angular-ui-components": "^0.7.2",
 | 
					    "@inst-iot/bosch-angular-ui-components": "^0.7.2",
 | 
				
			||||||
    "angular-2-local-storage": "^3.0.2",
 | 
					    "angular-2-local-storage": "^3.0.2",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,12 +2,7 @@ import { Component, isDevMode} from '@angular/core';
 | 
				
			|||||||
import {LoginService} from './services/login.service';
 | 
					import {LoginService} from './services/login.service';
 | 
				
			||||||
import {NavigationStart, Router} from '@angular/router';
 | 
					import {NavigationStart, Router} from '@angular/router';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO: add multiple samples at once
 | 
					 | 
				
			||||||
// TODO: validation: DPT: filename
 | 
					 | 
				
			||||||
// TODO: filter by not completely filled/no measurements
 | 
					// TODO: filter by not completely filled/no measurements
 | 
				
			||||||
// TODO: validation of samples
 | 
					 | 
				
			||||||
// TODO: centralize fetching of materials / templates, etc.
 | 
					 | 
				
			||||||
// TODO: PWA
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO: get rid of chart.js (+moment.js)
 | 
					// TODO: get rid of chart.js (+moment.js)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,6 +28,8 @@ import { UsersComponent } from './users/users.component';
 | 
				
			|||||||
import { ChangelogComponent } from './changelog/changelog.component';
 | 
					import { ChangelogComponent } from './changelog/changelog.component';
 | 
				
			||||||
import { DocumentationDatabaseComponent } from './documentation-database/documentation-database.component';
 | 
					import { DocumentationDatabaseComponent } from './documentation-database/documentation-database.component';
 | 
				
			||||||
import { PredictionComponent } from './prediction/prediction.component';
 | 
					import { PredictionComponent } from './prediction/prediction.component';
 | 
				
			||||||
 | 
					import { ServiceWorkerModule } from '@angular/service-worker';
 | 
				
			||||||
 | 
					import { environment } from '../environments/environment';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@NgModule({
 | 
					@NgModule({
 | 
				
			||||||
  declarations: [
 | 
					  declarations: [
 | 
				
			||||||
@@ -65,7 +67,8 @@ import { PredictionComponent } from './prediction/prediction.component';
 | 
				
			|||||||
    ReactiveFormsModule,
 | 
					    ReactiveFormsModule,
 | 
				
			||||||
    FormFieldsModule,
 | 
					    FormFieldsModule,
 | 
				
			||||||
    CommonModule,
 | 
					    CommonModule,
 | 
				
			||||||
    ChartsModule
 | 
					    ChartsModule,
 | 
				
			||||||
 | 
					    ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production })
 | 
				
			||||||
  ],
 | 
					  ],
 | 
				
			||||||
  providers: [
 | 
					  providers: [
 | 
				
			||||||
    ModalService,
 | 
					    ModalService,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,7 +18,6 @@
 | 
				
			|||||||
    <td>Automatically generated unique id</td>
 | 
					    <td>Automatically generated unique id</td>
 | 
				
			||||||
    <td>'5f2e63c98d1c020f8cda6e06'</td>
 | 
					    <td>'5f2e63c98d1c020f8cda6e06'</td>
 | 
				
			||||||
  </tr>
 | 
					  </tr>
 | 
				
			||||||
<!--  TODO: new names-->
 | 
					 | 
				
			||||||
  <tr>
 | 
					  <tr>
 | 
				
			||||||
    <td>type</td>
 | 
					    <td>type</td>
 | 
				
			||||||
    <td>
 | 
					    <td>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,10 +22,6 @@ import {Observable} from 'rxjs';
 | 
				
			|||||||
import {ModalService} from '@inst-iot/bosch-angular-ui-components';
 | 
					import {ModalService} from '@inst-iot/bosch-angular-ui-components';
 | 
				
			||||||
import {DataService} from '../services/data.service';
 | 
					import {DataService} from '../services/data.service';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO: clean up this mess !!!
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// TODO: only show condition (if not set) and measurements in edit sample dialog at first
 | 
					 | 
				
			||||||
// TODO: multiple samples for base data, extend multiple measurements, conditions
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Component({
 | 
					@Component({
 | 
				
			||||||
  selector: 'app-sample',
 | 
					  selector: 'app-sample',
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@ import {SampleModel} from '../models/sample.model';
 | 
				
			|||||||
import {LoginService} from '../services/login.service';
 | 
					import {LoginService} from '../services/login.service';
 | 
				
			||||||
import {ModalService} from '@inst-iot/bosch-angular-ui-components';
 | 
					import {ModalService} from '@inst-iot/bosch-angular-ui-components';
 | 
				
			||||||
import {DataService} from '../services/data.service';
 | 
					import {DataService} from '../services/data.service';
 | 
				
			||||||
 | 
					import {LocalStorageService} from 'angular-2-local-storage';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface LoadSamplesOptions {
 | 
					interface LoadSamplesOptions {
 | 
				
			||||||
@@ -28,8 +29,6 @@ interface KeyInterface {
 | 
				
			|||||||
  styleUrls: ['./samples.component.scss']
 | 
					  styleUrls: ['./samples.component.scss']
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO: save last settings
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export class SamplesComponent implements OnInit {
 | 
					export class SamplesComponent implements OnInit {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @ViewChild('pageSizeSelection') pageSizeSelection: ElementRef<HTMLElement>;
 | 
					  @ViewChild('pageSizeSelection') pageSizeSelection: ElementRef<HTMLElement>;
 | 
				
			||||||
@@ -89,29 +88,39 @@ export class SamplesComponent implements OnInit {
 | 
				
			|||||||
    public autocomplete: AutocompleteService,
 | 
					    public autocomplete: AutocompleteService,
 | 
				
			||||||
    public login: LoginService,
 | 
					    public login: LoginService,
 | 
				
			||||||
    private modalService: ModalService,
 | 
					    private modalService: ModalService,
 | 
				
			||||||
    public d: DataService
 | 
					    public d: DataService,
 | 
				
			||||||
 | 
					    private storage: LocalStorageService
 | 
				
			||||||
  ) {
 | 
					  ) {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ngOnInit(): void {
 | 
					  ngOnInit(): void {
 | 
				
			||||||
 | 
					    let loading = 7;
 | 
				
			||||||
 | 
					    const onLoad = () => {
 | 
				
			||||||
 | 
					      if ((--loading) <= 0) {
 | 
				
			||||||
 | 
					        this.loadSamples();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.calcFieldSelectKeys();
 | 
					    this.calcFieldSelectKeys();
 | 
				
			||||||
    this.d.load('materials', () => {
 | 
					    this.d.load('materials', () => {
 | 
				
			||||||
      this.filters.filters.find(e => e.field === 'material.name').autocomplete = this.d.arr.materials.map(e => e.name);
 | 
					      this.filters.filters.find(e => e.field === 'material.name').autocomplete = this.d.arr.materials.map(e => e.name);
 | 
				
			||||||
      this.loadSamples();
 | 
					      onLoad();
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    this.d.load('materialSuppliers', () => {
 | 
					    this.d.load('materialSuppliers', () => {
 | 
				
			||||||
      this.filters.filters.find(e => e.field === 'material.supplier').autocomplete = this.d.arr.materialSuppliers;
 | 
					      this.filters.filters.find(e => e.field === 'material.supplier').autocomplete = this.d.arr.materialSuppliers;
 | 
				
			||||||
 | 
					      onLoad();
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    this.d.load('materialGroups', () => {
 | 
					    this.d.load('materialGroups', () => {
 | 
				
			||||||
      this.filters.filters.find(e => e.field === 'material.group').autocomplete = this.d.arr.materialGroups;
 | 
					      this.filters.filters.find(e => e.field === 'material.group').autocomplete = this.d.arr.materialGroups;
 | 
				
			||||||
 | 
					      onLoad();
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    this.d.load('userKey');
 | 
					    this.d.load('userKey', onLoad);
 | 
				
			||||||
    this.d.load('conditionTemplates');
 | 
					    this.d.load('conditionTemplates', onLoad);
 | 
				
			||||||
    this.loadTemplateKeys('material', 'type');
 | 
					    this.loadTemplateKeys('material', 'type', onLoad);
 | 
				
			||||||
    this.loadTemplateKeys('measurement', 'status');
 | 
					    this.loadTemplateKeys('measurement', 'status', onLoad);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  loadTemplateKeys(collection, insertBefore) {
 | 
					  loadTemplateKeys(collection, insertBefore, f) {
 | 
				
			||||||
    this.d.load(collection + 'Templates', () => {
 | 
					    this.d.load(collection + 'Templates', () => {
 | 
				
			||||||
      const templateKeys = [];
 | 
					      const templateKeys = [];
 | 
				
			||||||
      this.d.arr[collection + 'Templates'].forEach(item => {
 | 
					      this.d.arr[collection + 'Templates'].forEach(item => {
 | 
				
			||||||
@@ -138,8 +147,8 @@ export class SamplesComponent implements OnInit {
 | 
				
			|||||||
      });
 | 
					      });
 | 
				
			||||||
      this.keys.splice(this.keys.findIndex(e => e.id === insertBefore), 0, ...templateKeys);
 | 
					      this.keys.splice(this.keys.findIndex(e => e.id === insertBefore), 0, ...templateKeys);
 | 
				
			||||||
      this.keys = [...this.keys];  // complete overwrite array to invoke update in rb-multiselect
 | 
					      this.keys = [...this.keys];  // complete overwrite array to invoke update in rb-multiselect
 | 
				
			||||||
      this.updateActiveKeys();
 | 
					      this.loadPreferences();
 | 
				
			||||||
      this.calcFieldSelectKeys();
 | 
					      f();
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -156,6 +165,7 @@ export class SamplesComponent implements OnInit {
 | 
				
			|||||||
    if (this.loadSamplesQueue.length <= 1) {  // nothing queued up
 | 
					    if (this.loadSamplesQueue.length <= 1) {  // nothing queued up
 | 
				
			||||||
      this.sampleLoader(this.loadSamplesQueue[0]);
 | 
					      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
 | 
				
			||||||
@@ -256,6 +266,38 @@ export class SamplesComponent implements OnInit {
 | 
				
			|||||||
    this.loadSamples({toPage: delta});
 | 
					    this.loadSamples({toPage: delta});
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  storePreferences() {
 | 
				
			||||||
 | 
					    const store = {
 | 
				
			||||||
 | 
					      filters: {
 | 
				
			||||||
 | 
					        ...pick(this.filters, ['status', 'pageSize', 'toPage', 'sort']),
 | 
				
			||||||
 | 
					        filters: this.filters.filters.map(e => pick(e, ['field', 'active', 'mode', 'values']))
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      keys: this.keys.map(e => pick(e, ['id', 'active']))
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    this.storage.set('samplesPreferences', store);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  loadPreferences() {
 | 
				
			||||||
 | 
					    const store: any = this.storage.get('samplesPreferences');
 | 
				
			||||||
 | 
					    if (store) {
 | 
				
			||||||
 | 
					      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};
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      store.keys.forEach(key => {
 | 
				
			||||||
 | 
					        const keyIndex = this.keys.findIndex(e => e.id === key.id);
 | 
				
			||||||
 | 
					        if (keyIndex >= 0) {
 | 
				
			||||||
 | 
					          this.keys[keyIndex].active = key.active;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      this.calcFieldSelectKeys();
 | 
				
			||||||
 | 
					      this.updateActiveKeys();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  updateFilterFields(field) {
 | 
					  updateFilterFields(field) {
 | 
				
			||||||
    const filter = this.filters.filters.find(e => e.field === field);
 | 
					    const filter = this.filters.filters.find(e => e.field === field);
 | 
				
			||||||
    filter.active = true;
 | 
					    filter.active = true;
 | 
				
			||||||
@@ -390,4 +432,6 @@ export class SamplesComponent implements OnInit {
 | 
				
			|||||||
  ucFirst(string) {
 | 
					  ucFirst(string) {
 | 
				
			||||||
    return string[0].toUpperCase() + string.slice(1);
 | 
					    return string[0].toUpperCase() + string.slice(1);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										
											BIN
										
									
								
								src/assets/icons/icon-128x128.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 26 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/icons/icon-144x144.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 30 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/icons/icon-152x152.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 30 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/icons/icon-192x192.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 39 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/icons/icon-384x384.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 136 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/icons/icon-512x512.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 235 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/icons/icon-72x72.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 10 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/icons/icon-96x96.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 16 KiB  | 
@@ -6,8 +6,11 @@
 | 
				
			|||||||
  <base href="/">
 | 
					  <base href="/">
 | 
				
			||||||
  <meta name="viewport" content="width=device-width, initial-scale=1">
 | 
					  <meta name="viewport" content="width=device-width, initial-scale=1">
 | 
				
			||||||
  <link rel="icon" type="image/x-icon" href="favicon.ico">
 | 
					  <link rel="icon" type="image/x-icon" href="favicon.ico">
 | 
				
			||||||
 | 
					  <link rel="manifest" href="manifest.webmanifest">
 | 
				
			||||||
 | 
					  <meta name="theme-color" content="#1976d2">
 | 
				
			||||||
</head>
 | 
					</head>
 | 
				
			||||||
<body>
 | 
					<body>
 | 
				
			||||||
  <app-root></app-root>
 | 
					  <app-root></app-root>
 | 
				
			||||||
 | 
					  <noscript>Please enable JavaScript to continue using this application.</noscript>
 | 
				
			||||||
</body>
 | 
					</body>
 | 
				
			||||||
</html>
 | 
					</html>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										59
									
								
								src/manifest.webmanifest
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,59 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "name": "definma",
 | 
				
			||||||
 | 
					  "short_name": "definma",
 | 
				
			||||||
 | 
					  "theme_color": "#1976d2",
 | 
				
			||||||
 | 
					  "background_color": "#fafafa",
 | 
				
			||||||
 | 
					  "display": "standalone",
 | 
				
			||||||
 | 
					  "scope": "./",
 | 
				
			||||||
 | 
					  "start_url": "./",
 | 
				
			||||||
 | 
					  "icons": [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "src": "assets/icons/icon-72x72.png",
 | 
				
			||||||
 | 
					      "sizes": "72x72",
 | 
				
			||||||
 | 
					      "type": "image/png",
 | 
				
			||||||
 | 
					      "purpose": "maskable any"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "src": "assets/icons/icon-96x96.png",
 | 
				
			||||||
 | 
					      "sizes": "96x96",
 | 
				
			||||||
 | 
					      "type": "image/png",
 | 
				
			||||||
 | 
					      "purpose": "maskable any"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "src": "assets/icons/icon-128x128.png",
 | 
				
			||||||
 | 
					      "sizes": "128x128",
 | 
				
			||||||
 | 
					      "type": "image/png",
 | 
				
			||||||
 | 
					      "purpose": "maskable any"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "src": "assets/icons/icon-144x144.png",
 | 
				
			||||||
 | 
					      "sizes": "144x144",
 | 
				
			||||||
 | 
					      "type": "image/png",
 | 
				
			||||||
 | 
					      "purpose": "maskable any"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "src": "assets/icons/icon-152x152.png",
 | 
				
			||||||
 | 
					      "sizes": "152x152",
 | 
				
			||||||
 | 
					      "type": "image/png",
 | 
				
			||||||
 | 
					      "purpose": "maskable any"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "src": "assets/icons/icon-192x192.png",
 | 
				
			||||||
 | 
					      "sizes": "192x192",
 | 
				
			||||||
 | 
					      "type": "image/png",
 | 
				
			||||||
 | 
					      "purpose": "maskable any"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "src": "assets/icons/icon-384x384.png",
 | 
				
			||||||
 | 
					      "sizes": "384x384",
 | 
				
			||||||
 | 
					      "type": "image/png",
 | 
				
			||||||
 | 
					      "purpose": "maskable any"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "src": "assets/icons/icon-512x512.png",
 | 
				
			||||||
 | 
					      "sizes": "512x512",
 | 
				
			||||||
 | 
					      "type": "image/png",
 | 
				
			||||||
 | 
					      "purpose": "maskable any"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||