Merge pull request #44 in DEFINMA/definma-ui from f/filter-separation to master
* commit '2aad393c0d6f4fa24df2c888ff9e81cac12d89b3': Fix a typo Performance updates Added value converter to correctly display values Seperate the fields into 3 categories
This commit is contained in:
		@@ -10,12 +10,6 @@
 | 
			
		||||
        <span *rbFormMultiSelectOption="let key">{{key.id}}</span>
 | 
			
		||||
    </rb-form-multi-select>
 | 
			
		||||
 | 
			
		||||
    <!--
 | 
			
		||||
    <rb-icon-button icon="forward-right" mode="primary" (click)="updateGroups()">
 | 
			
		||||
        Apply groups 
 | 
			
		||||
    </rb-icon-button>
 | 
			
		||||
    -->
 | 
			
		||||
 | 
			
		||||
    <div id="divChart">
 | 
			
		||||
        <canvas id="myChart">
 | 
			
		||||
        </canvas>
 | 
			
		||||
 
 | 
			
		||||
@@ -6,3 +6,7 @@ app-login {
 | 
			
		||||
  width: 70%;
 | 
			
		||||
  float: right;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
rb-form-multi-select {
 | 
			
		||||
  width: 20%;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -120,7 +120,8 @@ export class HomeComponent implements OnInit {
 | 
			
		||||
            label: 'Number of samples per group',
 | 
			
		||||
            data: data.data,
 | 
			
		||||
            backgroundColor: fillPattern,
 | 
			
		||||
            borderWidth: 2
 | 
			
		||||
            pointRadius: 4,
 | 
			
		||||
            pointHoverRadius: 7
 | 
			
		||||
          }]
 | 
			
		||||
        },
 | 
			
		||||
        options: {
 | 
			
		||||
 
 | 
			
		||||
@@ -3,9 +3,9 @@
 | 
			
		||||
    <rb-icon-button icon="add" mode="primary" class="space-left">New sample</rb-icon-button>
 | 
			
		||||
  </a>
 | 
			
		||||
  <rb-icon-button *ngIf="sampleSelect === 2" mode="secondary" icon="close" (click)="sampleSelect = 0"
 | 
			
		||||
                  class="validation-close" iconOnly></rb-icon-button>
 | 
			
		||||
  <rb-icon-button *ngIf="login.isLevel.dev" [icon]="sampleSelect === 2 ? 'checkmark' : 'clear-all'"
 | 
			
		||||
                  mode="secondary" (click)="validate()">
 | 
			
		||||
    class="validation-close" iconOnly></rb-icon-button>
 | 
			
		||||
  <rb-icon-button *ngIf="login.isLevel.dev" [icon]="sampleSelect === 2 ? 'checkmark' : 'clear-all'" mode="secondary"
 | 
			
		||||
    (click)="validate()">
 | 
			
		||||
    {{sampleSelect === 2 ? 'Validate' : 'Validation'}}
 | 
			
		||||
  </rb-icon-button>
 | 
			
		||||
</div>
 | 
			
		||||
@@ -19,23 +19,22 @@
 | 
			
		||||
      <div class="status-selection">
 | 
			
		||||
        <label class="label">Status</label>
 | 
			
		||||
        <rb-form-checkbox name="status-validated" [(ngModel)]="filters.status.validated"
 | 
			
		||||
                          [disabled]="!filters.status.new && !filters.status.deleted"
 | 
			
		||||
                          (ngModelChange)="loadSamples({firstPage: true})">
 | 
			
		||||
          [disabled]="!filters.status.new && !filters.status.deleted" (ngModelChange)="loadSamples({firstPage: true})">
 | 
			
		||||
          validated
 | 
			
		||||
        </rb-form-checkbox>
 | 
			
		||||
        <rb-form-checkbox name="status-new" [(ngModel)]="filters.status.new"
 | 
			
		||||
                          [disabled]="!filters.status.validated && !filters.status.deleted"
 | 
			
		||||
                          (ngModelChange)="loadSamples({firstPage: true})">
 | 
			
		||||
          [disabled]="!filters.status.validated && !filters.status.deleted"
 | 
			
		||||
          (ngModelChange)="loadSamples({firstPage: true})">
 | 
			
		||||
          new
 | 
			
		||||
        </rb-form-checkbox>
 | 
			
		||||
        <rb-form-checkbox name="status-deleted" [(ngModel)]="filters.status.deleted"
 | 
			
		||||
                          [disabled]="!filters.status.validated && !filters.status.new"
 | 
			
		||||
                          (ngModelChange)="loadSamples({firstPage: true})" *ngIf="login.isLevel.dev">
 | 
			
		||||
          [disabled]="!filters.status.validated && !filters.status.new" (ngModelChange)="loadSamples({firstPage: true})"
 | 
			
		||||
          *ngIf="login.isLevel.dev">
 | 
			
		||||
          deleted
 | 
			
		||||
        </rb-form-checkbox>
 | 
			
		||||
      </div>
 | 
			
		||||
      <rb-form-select name="pageSizeSelection" label="page size" [(ngModel)]="filters.pageSize" class="selection"
 | 
			
		||||
                      (ngModelChange)="loadSamples({firstPage: true})" #pageSizeSelection>
 | 
			
		||||
        (ngModelChange)="loadSamples({firstPage: true})" #pageSizeSelection>
 | 
			
		||||
        <option value="3">3</option>
 | 
			
		||||
        <option value="10">10</option>
 | 
			
		||||
        <option value="25">25</option>
 | 
			
		||||
@@ -45,10 +44,13 @@
 | 
			
		||||
        <option value="500">500</option>
 | 
			
		||||
      </rb-form-select>
 | 
			
		||||
 | 
			
		||||
      <rb-form-multi-select name="fieldSelect" idField="id" [items]="keys" [(ngModel)]="isActiveKey" label="Fields"
 | 
			
		||||
                            class="selection" (ngModelChange)="loadSamples({}, $event)">
 | 
			
		||||
        <span *rbFormMultiSelectOption="let item" class="load-first-page">{{item.label}}</span>
 | 
			
		||||
      </rb-form-multi-select>
 | 
			
		||||
      <div id="multi">
 | 
			
		||||
        <rb-form-multi-select *ngFor="let item of categories | keyvalue: originalOrder" name="fieldSelect" idField="id"
 | 
			
		||||
          [items]="item.value" [(ngModel)]="isActiveKey" [label]="item.key" class="selection"
 | 
			
		||||
          (ngModelChange)="loadSamples({}, $event, item.key)">
 | 
			
		||||
          <span *rbFormMultiSelectOption="let item" class="load-first-page">{{item.label}}</span>
 | 
			
		||||
        </rb-form-multi-select>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <rb-icon-button icon="reset" mode="secondary" (click)="resetPreferences()" class="reset-preferences">
 | 
			
		||||
        Reset to default
 | 
			
		||||
@@ -59,7 +61,7 @@
 | 
			
		||||
          <ng-container *ngIf="isActiveKey[filter.field]">
 | 
			
		||||
            <rb-form-checkbox [name]="'filteractive-' + filter.field" [(ngModel)]="filter.active"></rb-form-checkbox>
 | 
			
		||||
            <rb-form-select [name]="'filtermode-' + filter.field" class="filtermode" [(ngModel)]="filter.mode"
 | 
			
		||||
                            (ngModelChange)="updateFilterFields(filter.field)">
 | 
			
		||||
              (ngModelChange)="updateFilterFields(filter.field)">
 | 
			
		||||
              <option value="eq" title="field is equal to value">=</option>
 | 
			
		||||
              <option value="ne" title="field is not equal to value">≠</option>
 | 
			
		||||
              <option value="lt" title="field is lower than value"><</option>
 | 
			
		||||
@@ -73,29 +75,25 @@
 | 
			
		||||
            </rb-form-select>
 | 
			
		||||
            <div class="filter-inputs">
 | 
			
		||||
              <rb-array-input [(ngModel)]="filter.values" [name]="'filter-' + filter.field"
 | 
			
		||||
                              [pushTemplate]="!(filter.mode === 'in' || filter.mode === 'nin') ? null :''"
 | 
			
		||||
                              (ngModelChange)="updateFilterFields(filter.field)">
 | 
			
		||||
                <ng-container *rbArrayInputItem="let item"
 | 
			
		||||
                              [ngSwitch]="(filter.autocomplete.length ? 'autocomplete' : '') +
 | 
			
		||||
                [pushTemplate]="!(filter.mode === 'in' || filter.mode === 'nin') ? null :''"
 | 
			
		||||
                (ngModelChange)="updateFilterFields(filter.field)">
 | 
			
		||||
                <ng-container *rbArrayInputItem="let item" [ngSwitch]="(filter.autocomplete.length ? 'autocomplete' : '') +
 | 
			
		||||
                              (filter.field == 'added' ? 'date' : (filter.field == 'type' ? 'type' : ''))">
 | 
			
		||||
                  <rb-form-date-input *ngSwitchCase="'date'" [rbArrayInputListener]="'filter-' + filter.field"
 | 
			
		||||
                                      [name]="'filter-' + filter.field + item.i" [index]="item.i"
 | 
			
		||||
                                      [label]="filter.label" [(ngModel)]="item.value"
 | 
			
		||||
                                      [disabled]="filter.mode === 'null'"></rb-form-date-input>
 | 
			
		||||
                    [name]="'filter-' + filter.field + item.i" [index]="item.i" [label]="filter.label"
 | 
			
		||||
                    [(ngModel)]="item.value" [disabled]="filter.mode === 'null'"></rb-form-date-input>
 | 
			
		||||
                  <rb-form-input *ngSwitchCase="''" [rbArrayInputListener]="'filter-' + filter.field"
 | 
			
		||||
                                 [name]="'filter-' + filter.field + item.i" [index]="item.i"
 | 
			
		||||
                                 [label]="filter.label" [(ngModel)]="item.value" [disabled]="filter.mode === 'null'">
 | 
			
		||||
                    [name]="'filter-' + filter.field + item.i" [index]="item.i" [label]="filter.label"
 | 
			
		||||
                    [(ngModel)]="item.value" [disabled]="filter.mode === 'null'">
 | 
			
		||||
                  </rb-form-input>
 | 
			
		||||
                  <rb-form-input *ngSwitchCase="'autocomplete'" [rbArrayInputListener]="'filter-' + filter.field"
 | 
			
		||||
                                 [name]="'filter-' + filter.field + item.i" [index]="item.i"
 | 
			
		||||
                                 [label]="filter.label" [(ngModel)]="item.value"
 | 
			
		||||
                                 [rbDebounceTime]="0" (keydown)="preventDefault($event, 'Enter')"
 | 
			
		||||
                                 [rbFormInputAutocomplete]="autocomplete.bind(this, filter.autocomplete)"
 | 
			
		||||
                                 [disabled]="filter.mode === 'null'"
 | 
			
		||||
                                 ngModel></rb-form-input>
 | 
			
		||||
                    [name]="'filter-' + filter.field + item.i" [index]="item.i" [label]="filter.label"
 | 
			
		||||
                    [(ngModel)]="item.value" [rbDebounceTime]="0" (keydown)="preventDefault($event, 'Enter')"
 | 
			
		||||
                    [rbFormInputAutocomplete]="autocomplete.bind(this, filter.autocomplete)"
 | 
			
		||||
                    [disabled]="filter.mode === 'null'" ngModel></rb-form-input>
 | 
			
		||||
                  <rb-form-select *ngSwitchCase="'type'" [rbArrayInputListener]="'filter-' + filter.field"
 | 
			
		||||
                                  [name]="'filter-' + filter.field + item.i" [index]="item.i"
 | 
			
		||||
                                  [label]="filter.label" [(ngModel)]="item.value">
 | 
			
		||||
                    [name]="'filter-' + filter.field + item.i" [index]="item.i" [label]="filter.label"
 | 
			
		||||
                    [(ngModel)]="item.value">
 | 
			
		||||
                    <option value="as-delivered/raw">as-delivered/raw</option>
 | 
			
		||||
                    <option value="processed">processed</option>
 | 
			
		||||
                  </rb-form-select>
 | 
			
		||||
@@ -119,7 +117,6 @@
 | 
			
		||||
  </rb-accordion-body>
 | 
			
		||||
</rb-accordion>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<ng-container *ngTemplateOutlet="paging"></ng-container>
 | 
			
		||||
 | 
			
		||||
<div class="samples-loading" *ngIf="loading">
 | 
			
		||||
@@ -137,7 +134,7 @@
 | 
			
		||||
    <div class="link-dialog">
 | 
			
		||||
      <label for="jsonUrl">URL for JSON download</label>
 | 
			
		||||
      <textarea class="linkmodal" id="jsonUrl" #linkarea [value]="sampleUrl({export: true, host: true})"
 | 
			
		||||
                (keydown)="preventDefault($event)"></textarea>
 | 
			
		||||
        (keydown)="preventDefault($event)"></textarea>
 | 
			
		||||
      <rb-form-checkbox class="space-right" name="download-spectra" [(ngModel)]="downloadSpectra">
 | 
			
		||||
        add spectra
 | 
			
		||||
      </rb-form-checkbox>
 | 
			
		||||
@@ -161,7 +158,7 @@
 | 
			
		||||
 | 
			
		||||
<rb-table class="samples-table" scrollTop ellipsis>
 | 
			
		||||
  <tr>
 | 
			
		||||
	<th *ngIf="login.isLevel.write">
 | 
			
		||||
    <th *ngIf="login.isLevel.write">
 | 
			
		||||
      <span class="rb-ic rb-ic-edit clickable" *ngIf="login.isLevel.dev" (click)="batchEdit()"></span>
 | 
			
		||||
      <span class="rb-ic rb-ic-close clickable" *ngIf="sampleSelect === 1" (click)="sampleSelect = 0"></span>
 | 
			
		||||
    </th>
 | 
			
		||||
@@ -184,39 +181,22 @@
 | 
			
		||||
  </tr>
 | 
			
		||||
 | 
			
		||||
  <tr *ngFor="let sample of samples; index as i" class="clickable" (click)="sampleDetails(sample._id, sampleModal)">
 | 
			
		||||
	<td *ngIf="login.isLevel.write">
 | 
			
		||||
      <a [routerLink]="'/samples/edit/' + sample._id"
 | 
			
		||||
         *ngIf="sample.status !== 'deleted' &&
 | 
			
		||||
    <td *ngIf="login.isLevel.write">
 | 
			
		||||
      <a [routerLink]="'/samples/edit/' + sample._id" *ngIf="sample.status !== 'deleted' &&
 | 
			
		||||
         (login.isLevel.dev || (login.isLevel.write && sample.user_id === login.userId))">
 | 
			
		||||
        <span class="rb-ic rb-ic-edit clickable"></span>
 | 
			
		||||
      </a>
 | 
			
		||||
      <span class="rb-ic rb-ic-undo clickable" *ngIf="sample.status === 'deleted' && login.isLevel.dev"
 | 
			
		||||
            (click)="restoreSample(sample._id, restoreConfirm, $event)"></span>
 | 
			
		||||
        (click)="restoreSample(sample._id, restoreConfirm, $event)"></span>
 | 
			
		||||
    </td>
 | 
			
		||||
	<td *ngIf="sampleSelect">
 | 
			
		||||
    <td *ngIf="sampleSelect">
 | 
			
		||||
      <rb-form-checkbox *ngIf="sample.status !== 'deleted'" [name]="'validate-' + i" (click)="stopPropagation($event)"
 | 
			
		||||
                        [(ngModel)]="sample.selected">
 | 
			
		||||
        [(ngModel)]="sample.selected">
 | 
			
		||||
      </rb-form-checkbox>
 | 
			
		||||
    </td>
 | 
			
		||||
    <td *ngIf="isActiveKey['number']">{{sample.number}}</td>
 | 
			
		||||
    <td *ngIf="isActiveKey['material.numbers']">{{d.id.materials[sample.material_id].numbers}}</td>
 | 
			
		||||
    <td *ngIf="isActiveKey['material.name']">{{d.id.materials[sample.material_id].name}}</td>
 | 
			
		||||
    <td *ngIf="isActiveKey['material.supplier']">{{d.id.materials[sample.material_id].supplier}}</td>
 | 
			
		||||
    <td *ngIf="isActiveKey['material.group']">{{d.id.materials[sample.material_id].group}}</td>
 | 
			
		||||
    <td *ngFor="let key of activeTemplateKeys.material">
 | 
			
		||||
      {{d.id.materials[sample.material_id].properties[key[2]] | exists}}
 | 
			
		||||
    <td *ngFor="let item of activeKeys; index as j">
 | 
			
		||||
      {{data[i].data[j]}}
 | 
			
		||||
    </td>
 | 
			
		||||
    <td *ngIf="isActiveKey['type']">{{sample.type}}</td>
 | 
			
		||||
    <td *ngIf="isActiveKey['color']">{{sample.color}}</td>
 | 
			
		||||
    <td *ngIf="isActiveKey['batch']">{{sample.batch}}</td>
 | 
			
		||||
    <td *ngFor="let key of activeTemplateKeys.condition">
 | 
			
		||||
      {{sample.condition ? sample.condition[key[1]] : '' | exists}}
 | 
			
		||||
    </td>
 | 
			
		||||
    <td *ngIf="isActiveKey['notes.comment']">{{sample.notes | exists: 'comment'}}</td>
 | 
			
		||||
    <td *ngIf="isActiveKey['notes']">{{sample.notes | object: ['_id', 'sample_references']}}</td>
 | 
			
		||||
    <td *ngFor="let key of activeTemplateKeys.measurements">{{sample[key[1]] | exists: key[2]}}</td>
 | 
			
		||||
    <td *ngIf="isActiveKey['status']">{{sample.status}}</td>
 | 
			
		||||
    <td *ngIf="isActiveKey['added']">{{sample.added | date:'dd/MM/yy'}}</td>
 | 
			
		||||
  </tr>
 | 
			
		||||
</rb-table>
 | 
			
		||||
 | 
			
		||||
@@ -245,13 +225,34 @@
 | 
			
		||||
  <ng-template #sampleDetailsTemplate>
 | 
			
		||||
    <h3>{{sampleDetailsSample.number}}</h3>
 | 
			
		||||
    <rb-table class="sample-details-table">
 | 
			
		||||
      <tr><th>Material</th><td>{{sampleDetailsSample.material.name}}</td></tr>
 | 
			
		||||
      <tr><th>Supplier</th><td>{{sampleDetailsSample.material.supplier}}</td></tr>
 | 
			
		||||
      <tr><th>Group</th><td>{{sampleDetailsSample.material.group}}</td></tr>
 | 
			
		||||
      <tr><th>Type</th><td>{{sampleDetailsSample.type}}</td></tr>
 | 
			
		||||
      <tr><th>color</th><td>{{sampleDetailsSample.color}}</td></tr>
 | 
			
		||||
      <tr><th>Batch</th><td>{{sampleDetailsSample.batch}}</td></tr>
 | 
			
		||||
      <tr><th>Comment</th><td>{{sampleDetailsSample.notes.comment | exists}}</td></tr>
 | 
			
		||||
      <tr>
 | 
			
		||||
        <th>Material</th>
 | 
			
		||||
        <td>{{sampleDetailsSample.material.name}}</td>
 | 
			
		||||
      </tr>
 | 
			
		||||
      <tr>
 | 
			
		||||
        <th>Supplier</th>
 | 
			
		||||
        <td>{{sampleDetailsSample.material.supplier}}</td>
 | 
			
		||||
      </tr>
 | 
			
		||||
      <tr>
 | 
			
		||||
        <th>Group</th>
 | 
			
		||||
        <td>{{sampleDetailsSample.material.group}}</td>
 | 
			
		||||
      </tr>
 | 
			
		||||
      <tr>
 | 
			
		||||
        <th>Type</th>
 | 
			
		||||
        <td>{{sampleDetailsSample.type}}</td>
 | 
			
		||||
      </tr>
 | 
			
		||||
      <tr>
 | 
			
		||||
        <th>color</th>
 | 
			
		||||
        <td>{{sampleDetailsSample.color}}</td>
 | 
			
		||||
      </tr>
 | 
			
		||||
      <tr>
 | 
			
		||||
        <th>Batch</th>
 | 
			
		||||
        <td>{{sampleDetailsSample.batch}}</td>
 | 
			
		||||
      </tr>
 | 
			
		||||
      <tr>
 | 
			
		||||
        <th>Comment</th>
 | 
			
		||||
        <td>{{sampleDetailsSample.notes.comment | exists}}</td>
 | 
			
		||||
      </tr>
 | 
			
		||||
      <tr *ngFor="let customField of sampleDetailsSample.notes.custom_fields_entries">
 | 
			
		||||
        <th>{{customField[0]}}</th>
 | 
			
		||||
        <td>{{customField[1]}}</td>
 | 
			
		||||
@@ -272,8 +273,14 @@
 | 
			
		||||
        <th>{{measurement.name}}</th>
 | 
			
		||||
        <td>{{measurement.value}}</td>
 | 
			
		||||
      </tr>
 | 
			
		||||
      <tr><th>User</th><td>{{sampleDetailsSample.user}}</td></tr>
 | 
			
		||||
      <tr><th>Status</th><td>{{sampleDetailsSample.status}}</td></tr>
 | 
			
		||||
      <tr>
 | 
			
		||||
        <th>User</th>
 | 
			
		||||
        <td>{{sampleDetailsSample.user}}</td>
 | 
			
		||||
      </tr>
 | 
			
		||||
      <tr>
 | 
			
		||||
        <th>Status</th>
 | 
			
		||||
        <td>{{sampleDetailsSample.status}}</td>
 | 
			
		||||
      </tr>
 | 
			
		||||
    </rb-table>
 | 
			
		||||
  </ng-template>
 | 
			
		||||
</ng-template>
 | 
			
		||||
@@ -282,4 +289,4 @@
 | 
			
		||||
  <rb-dialog dialogTitle="Restore sample">
 | 
			
		||||
    Do you really want to restore this sample?
 | 
			
		||||
  </rb-dialog>
 | 
			
		||||
</ng-template>
 | 
			
		||||
</ng-template>
 | 
			
		||||
@@ -28,6 +28,10 @@ rb-table {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
rb-form-multi-select{
 | 
			
		||||
  min-width: 9rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.status-selection {
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  margin-bottom: 10px;
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,7 @@ 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 { KeyValue } from '@angular/common';
 | 
			
		||||
 | 
			
		||||
interface LoadSamplesOptions {
 | 
			
		||||
  toPage?: number;
 | 
			
		||||
@@ -24,6 +25,11 @@ interface KeyInterface {
 | 
			
		||||
  sortable: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface Data {
 | 
			
		||||
  id: string;
 | 
			
		||||
  data: any[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-samples',
 | 
			
		||||
  templateUrl: './samples.component.html',
 | 
			
		||||
@@ -39,6 +45,7 @@ export class SamplesComponent implements OnInit {
 | 
			
		||||
  downloadCondition = false;
 | 
			
		||||
  downloadFlatten = true;
 | 
			
		||||
  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
 | 
			
		||||
  filters = {
 | 
			
		||||
@@ -65,27 +72,44 @@ export class SamplesComponent implements OnInit {
 | 
			
		||||
  page = 1;   // current page
 | 
			
		||||
  pages = 1;  // total number of pages
 | 
			
		||||
  loadSamplesQueue = [];  // arguments of queued up loadSamples() calls
 | 
			
		||||
  keys: KeyInterface[] = [
 | 
			
		||||
  materialKeys: 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.comment', label: 'Comment', active: false, sortable: false }
 | 
			
		||||
  ];
 | 
			
		||||
  conditionKeys: KeyInterface[] = [
 | 
			
		||||
    { id: 'notes', label: 'Notes', active: false, sortable: false },
 | 
			
		||||
  ];
 | 
			
		||||
  measurementKeys: KeyInterface[] = [
 | 
			
		||||
    { id: 'material.name', label: 'Product name', active: true, sortable: true },
 | 
			
		||||
    { id: 'status', label: 'Status', active: false, sortable: true },
 | 
			
		||||
    { id: 'added', label: 'Added', active: true, sortable: true }
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  // 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
 | 
			
		||||
  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
 | 
			
		||||
 | 
			
		||||
  // 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(", ") : "",
 | 
			
		||||
    'notes.comment': (v: any, sample: any) => sample['notes']['comment']
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  constructor(
 | 
			
		||||
    private api: ApiService,
 | 
			
		||||
@@ -96,8 +120,7 @@ export class SamplesComponent implements OnInit {
 | 
			
		||||
    private storage: LocalStorageService,
 | 
			
		||||
    private window: Window,
 | 
			
		||||
    private router: Router
 | 
			
		||||
  ) {
 | 
			
		||||
  }
 | 
			
		||||
  ) {}
 | 
			
		||||
 | 
			
		||||
  ngOnInit(): void {
 | 
			
		||||
    this.loading = 8;
 | 
			
		||||
@@ -123,7 +146,7 @@ export class SamplesComponent implements OnInit {
 | 
			
		||||
    this.d.load('userKey', onLoad);
 | 
			
		||||
    this.d.load('conditionTemplates', onLoad);
 | 
			
		||||
    this.loadTemplateKeys('material', 'type', onLoad);
 | 
			
		||||
    this.loadTemplateKeys('condition', 'notes.comment', onLoad);
 | 
			
		||||
    this.loadTemplateKeys('condition', 'notes', onLoad);
 | 
			
		||||
    this.loadTemplateKeys('measurement', 'status', onLoad);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -157,18 +180,17 @@ export class SamplesComponent implements OnInit {
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      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.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.loadPreferences();
 | 
			
		||||
      f();
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // set toPage to null to reload first page, queues calls
 | 
			
		||||
  loadSamples(options: LoadSamplesOptions = {}, event = null) {
 | 
			
		||||
  loadSamples(options: LoadSamplesOptions = {}, event = null, category?) {
 | 
			
		||||
    if (event) {  // adjust active keys
 | 
			
		||||
      console.log(event);
 | 
			
		||||
      this.keys.forEach(key => {
 | 
			
		||||
      this.categories[category].forEach(key => {
 | 
			
		||||
        if (event.hasOwnProperty(key.id)) {
 | 
			
		||||
          key.active = event[key.id];
 | 
			
		||||
        }
 | 
			
		||||
@@ -179,7 +201,7 @@ export class SamplesComponent implements OnInit {
 | 
			
		||||
      }
 | 
			
		||||
      this.updateActiveKeys();
 | 
			
		||||
    }
 | 
			
		||||
    if(options.firstPage){
 | 
			
		||||
    if (options.firstPage) {
 | 
			
		||||
      this.storage.set('currentPage', 1);
 | 
			
		||||
    }
 | 
			
		||||
    this.loadSamplesQueue.push(options);
 | 
			
		||||
@@ -203,13 +225,14 @@ export class SamplesComponent implements OnInit {
 | 
			
		||||
        }
 | 
			
		||||
        this.pages = Math.ceil(this.totalSamples / this.filters.pageSize);
 | 
			
		||||
        this.samples = sData as any;
 | 
			
		||||
        this.storeData();
 | 
			
		||||
        this.loadSamplesQueue.shift();
 | 
			
		||||
        if (this.loadSamplesQueue.length > 0) {  // execute next queue item
 | 
			
		||||
          this.sampleLoader(this.loadSamplesQueue[0]);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
    if(this.storage.get('currentPage') !== this.page){
 | 
			
		||||
    if (this.storage.get('currentPage') !== this.page) {
 | 
			
		||||
      this.loadPage(Number(this.storage.get('currentPage')) - this.page);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
@@ -247,13 +270,14 @@ export class SamplesComponent implements OnInit {
 | 
			
		||||
    if (options.export) {  // append API key on export
 | 
			
		||||
      query.push('key=' + this.d.d.userKey.key);
 | 
			
		||||
    }
 | 
			
		||||
    this.keys.forEach(key => {
 | 
			
		||||
      // do not load material properties for table
 | 
			
		||||
      if (key.active && (options.export || (!options.export && key.id.indexOf('material.') < 0))) {
 | 
			
		||||
        query.push('fields[]=' + key.id);
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    for (let category in this.categories) {
 | 
			
		||||
      this.categories[category].forEach(key => {
 | 
			
		||||
        if (key.active && (options.export || (!options.export && key.id.indexOf('material.') < 0))) {
 | 
			
		||||
          query.push('fields[]=' + key.id);
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
    query.push(...cloneDeep(this.filters.filters)
 | 
			
		||||
      .map(e => {
 | 
			
		||||
        e.values = e.values.filter(el => el !== '');  // do not include empty values
 | 
			
		||||
@@ -314,14 +338,20 @@ export class SamplesComponent implements OnInit {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  storePreferences() {
 | 
			
		||||
    let keys = [];
 | 
			
		||||
    for (let category in this.categories) {
 | 
			
		||||
      keys.push(...this.categories[category].map(e => pick(e, ['id', 'active'])));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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']))
 | 
			
		||||
      keys: keys
 | 
			
		||||
    };
 | 
			
		||||
    this.storage.set('samplesPreferences', store);
 | 
			
		||||
    this.calcFieldSelectKeys();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  loadPreferences() {
 | 
			
		||||
@@ -334,10 +364,13 @@ export class SamplesComponent implements OnInit {
 | 
			
		||||
          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;
 | 
			
		||||
        for (let category in this.categories) {
 | 
			
		||||
          const keyIndex = this.categories[category].findIndex(e => e.id === key.id);
 | 
			
		||||
          if (keyIndex >= 0) {
 | 
			
		||||
            this.categories[category][keyIndex].active = key.active;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
@@ -361,28 +394,23 @@ export class SamplesComponent implements OnInit {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  updateActiveKeys() {  // array with all activeKeys
 | 
			
		||||
    this.activeKeys = this.keys.filter(e => e.active);
 | 
			
		||||
    this.filters.filters.forEach(filter => {  // disable filters of fields not displayed
 | 
			
		||||
      if (!this.isActiveKey[filter.field]) {
 | 
			
		||||
        filter.active = false;
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
    this.activeTemplateKeys.material = this.keys
 | 
			
		||||
      .filter(e => e.id.indexOf('material.properties.') >= 0 && e.active)
 | 
			
		||||
      .map(e => e.id.split('.')
 | 
			
		||||
        .map(el => decodeURIComponent(el)));
 | 
			
		||||
    this.activeTemplateKeys.condition = this.keys.filter(e => e.id.indexOf('condition.') >= 0 && e.active)
 | 
			
		||||
      .map(e => e.id.split('.')
 | 
			
		||||
        .map(el => decodeURIComponent(el)));
 | 
			
		||||
    this.activeTemplateKeys.measurements = this.keys.filter(e => e.id.indexOf('measurements.') >= 0 && e.active)
 | 
			
		||||
      .map(e => e.id.split('.')
 | 
			
		||||
        .map(el => decodeURIComponent(el)));
 | 
			
		||||
    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
 | 
			
		||||
        if (!this.isActiveKey[filter.field]) {
 | 
			
		||||
          filter.active = false;
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  calcFieldSelectKeys() {
 | 
			
		||||
    this.keys.forEach(key => {
 | 
			
		||||
      this.isActiveKey[key.id] = key.active;
 | 
			
		||||
    });
 | 
			
		||||
    for (let category in this.categories) {
 | 
			
		||||
      this.categories[category].forEach(key => {
 | 
			
		||||
        this.isActiveKey[key.id] = key.active;
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  sampleDetails(id: string, modal: TemplateRef<any>) {  // show sample details
 | 
			
		||||
@@ -417,7 +445,7 @@ export class SamplesComponent implements OnInit {
 | 
			
		||||
          .push(...Object.entries(measurement.values).filter(e => e[0] !== 'dpt')
 | 
			
		||||
            .map(e => ({ name: this.ucFirst(name) + ' ' + e[0], value: e[1] })));
 | 
			
		||||
      });
 | 
			
		||||
      new Promise(resolve => {
 | 
			
		||||
      new Promise<void>(resolve => {
 | 
			
		||||
        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 => {
 | 
			
		||||
@@ -505,4 +533,28 @@ export class SamplesComponent implements OnInit {
 | 
			
		||||
  ucFirst(string) {  // convert first character of string to uppercase
 | 
			
		||||
    return string[0].toUpperCase() + string.slice(1);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  refreshMultiSelect() {
 | 
			
		||||
    for (let collection in this.categories) {
 | 
			
		||||
      this.categories[collection] = [...this.categories[collection]];
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // stores data in a unified way
 | 
			
		||||
  storeData() {
 | 
			
		||||
    this.data = [];
 | 
			
		||||
    this.samples.forEach(sample => {
 | 
			
		||||
      let value = [];
 | 
			
		||||
      this.activeKeys.forEach(key => {
 | 
			
		||||
        let id = key.id.split('material.')[1];
 | 
			
		||||
        let tmpValue = id ? this.d.id.materials[sample.material_id][id] : sample[key.id];
 | 
			
		||||
        value.push(this.valueConverters[key.id] ? this.valueConverters[key.id](tmpValue, sample) : tmpValue);
 | 
			
		||||
      });
 | 
			
		||||
      this.data.push({ id: sample._id, data: value });
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  originalOrder = (a: KeyValue<number, string>, b: KeyValue<number, string>): number => {
 | 
			
		||||
    return 0;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user