sorting implemented
This commit is contained in:
		@@ -13,7 +13,7 @@ export class SampleModel extends BaseModel {
 | 
			
		||||
  condition: {condition_template: string, [prop: string]: string} | {} = {};
 | 
			
		||||
  material_id: IdModel = null;
 | 
			
		||||
  material: MaterialModel;
 | 
			
		||||
  measurements: MeasurementModel[];
 | 
			
		||||
  measurements: MeasurementModel[] = [];
 | 
			
		||||
  note_id: IdModel = null;
 | 
			
		||||
  user_id: IdModel = null;
 | 
			
		||||
  notes: {comment: string, sample_references: {sample_id: IdModel, relation: string}[], custom_fields: {[prop: string]: string}} = {comment: '', sample_references: [], custom_fields: {}};
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,9 @@ import {MeasurementModel} from '../models/measurement.model';
 | 
			
		||||
// TODO: confirmation for new group/supplier
 | 
			
		||||
// TODO: DPT preview
 | 
			
		||||
// TODO: work on better recognition for file input
 | 
			
		||||
// TODO: only show condition (if not set) and measurements in edit sample dialog at first
 | 
			
		||||
// TODO: multiple spectra, drag and drop
 | 
			
		||||
// TODO: multiple samples for base data, extend multiple measurements, conditions
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -6,48 +6,77 @@
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<rb-accordion>
 | 
			
		||||
  <rb-accordion-title><span class="rb-ic rb-ic-filter"></span>  Filter</rb-accordion-title>
 | 
			
		||||
  <rb-accordion-title [open]="true"><span class="rb-ic rb-ic-filter"></span>  Filter</rb-accordion-title>
 | 
			
		||||
  <rb-accordion-body>
 | 
			
		||||
    <form>
 | 
			
		||||
      <rb-form-select name="statusSelect" label="Status" [(ngModel)]="filters.status">
 | 
			
		||||
        <option value="validated">validated</option>
 | 
			
		||||
        <option value="new">new</option>
 | 
			
		||||
        <option value="all">all</option>
 | 
			
		||||
    <form (change)="loadSamples({event: $event})">
 | 
			
		||||
      <div class="status-selection">
 | 
			
		||||
        <label class="label">Status</label>
 | 
			
		||||
        <rb-form-checkbox name="status-validated" [(ngModel)]="filters.status.validated" [disabled]="!filters.status.new">
 | 
			
		||||
          validated
 | 
			
		||||
        </rb-form-checkbox>
 | 
			
		||||
        <rb-form-checkbox name="status-new" [(ngModel)]="filters.status.new" [disabled]="!filters.status.validated">
 | 
			
		||||
          new
 | 
			
		||||
        </rb-form-checkbox>
 | 
			
		||||
      </div>
 | 
			
		||||
      <rb-form-select name="pageSizeSelection" label="page size" [(ngModel)]="filters.pageSize" class="page-size-selection" #pageSizeSelection>
 | 
			
		||||
        <option value="10">10</option>
 | 
			
		||||
        <option value="25">25</option>
 | 
			
		||||
        <option value="50">50</option>
 | 
			
		||||
        <option value="100">100</option>
 | 
			
		||||
        <option value="250">250</option>
 | 
			
		||||
        <option value="500">500</option>
 | 
			
		||||
      </rb-form-select>
 | 
			
		||||
 | 
			
		||||
      <button class="rb-btn rb-secondary" (click)="loadSamples()">Apply filters</button>
 | 
			
		||||
<!--      <button class="rb-btn rb-secondary" (click)="loadSamples()">Apply filters</button>-->
 | 
			
		||||
    </form>
 | 
			
		||||
  </rb-accordion-body>
 | 
			
		||||
</rb-accordion>
 | 
			
		||||
 | 
			
		||||
<ng-container *ngTemplateOutlet="paging"></ng-container>
 | 
			
		||||
 | 
			
		||||
<rb-table>
 | 
			
		||||
  <tr>
 | 
			
		||||
    <th>Number</th>
 | 
			
		||||
    <th>Material number</th>
 | 
			
		||||
    <th>Material name</th>
 | 
			
		||||
    <th>Supplier</th>
 | 
			
		||||
    <th>Material</th>
 | 
			
		||||
    <th>GF</th>
 | 
			
		||||
    <th>CF</th>
 | 
			
		||||
    <th>M</th>
 | 
			
		||||
    <th>type</th>
 | 
			
		||||
    <th>Color</th>
 | 
			
		||||
    <th>Batch</th>
 | 
			
		||||
    <th *ngFor="let key of activeKeys">
 | 
			
		||||
      <div class="sort-header">
 | 
			
		||||
        <span>{{key.name}}</span>
 | 
			
		||||
        <span class="rb-ic rb-ic-up" [ngClass]="{'sort-active-desc': filters.sort === key.key + '-' + 'desc'}" (click)="setSort(key.key + '-' + 'desc')"></span>
 | 
			
		||||
        <span class="rb-ic rb-ic-down" [ngClass]="{'sort-active-asc': filters.sort === key.key + '-' + 'asc'}" (click)="setSort(key.key + '-' + 'asc')"></span>
 | 
			
		||||
      </div>
 | 
			
		||||
    </th>
 | 
			
		||||
    <th></th>
 | 
			
		||||
  </tr>
 | 
			
		||||
 | 
			
		||||
  <tr *ngFor="let sample of samples">
 | 
			
		||||
    <td>{{sample.number}}</td>
 | 
			
		||||
    <td>{{sample.material_number}}</td>
 | 
			
		||||
<!--    <td>{{sample.material_number}}</td>-->
 | 
			
		||||
    <td>{{materials[sample.material_id].name}}</td>
 | 
			
		||||
    <td>{{materials[sample.material_id].supplier}}</td>
 | 
			
		||||
    <td>{{materials[sample.material_id].group}}</td>
 | 
			
		||||
    <td>{{materials[sample.material_id].glass_fiber}}</td>
 | 
			
		||||
    <td>{{materials[sample.material_id].carbon_fiber}}</td>
 | 
			
		||||
    <td>{{materials[sample.material_id].mineral}}</td>
 | 
			
		||||
<!--    <td>{{materials[sample.material_id].group}}</td>-->
 | 
			
		||||
<!--    <td>{{materials[sample.material_id].glass_fiber}}</td>-->
 | 
			
		||||
<!--    <td>{{materials[sample.material_id].carbon_fiber}}</td>-->
 | 
			
		||||
<!--    <td>{{materials[sample.material_id].mineral}}</td>-->
 | 
			
		||||
    <td>{{sample.type}}</td>
 | 
			
		||||
    <td>{{sample.color}}</td>
 | 
			
		||||
    <td>{{sample.batch}}</td>
 | 
			
		||||
    <td>{{sample.added | date}}</td>
 | 
			
		||||
    <td><a [routerLink]="'/samples/edit/' + sample._id"><span class="rb-ic rb-ic-edit"></span></a></td>
 | 
			
		||||
  </tr>
 | 
			
		||||
</rb-table>
 | 
			
		||||
 | 
			
		||||
<ng-container *ngTemplateOutlet="paging"></ng-container>
 | 
			
		||||
 | 
			
		||||
<ng-template #paging>
 | 
			
		||||
  <div class="paging">
 | 
			
		||||
    <button class="rb-btn rb-link" type="button" (click)="loadPage(-1)" [disabled]="page === 1">
 | 
			
		||||
      <span class="rb-ic  rb-ic-back-left"></span>
 | 
			
		||||
    </button>
 | 
			
		||||
    <rb-form-input label="page" (change)="loadPage({toPage: $event.target.value - page})" [ngModel]="page"></rb-form-input>
 | 
			
		||||
    <span>
 | 
			
		||||
      of {{pages()}}
 | 
			
		||||
    </span>
 | 
			
		||||
    <button class="rb-btn rb-link" type="button" (click)="loadPage(1)" [disabled]="page >= pages()">
 | 
			
		||||
      <span class="rb-ic  rb-ic-forward-right"></span>
 | 
			
		||||
    </button>
 | 
			
		||||
  </div>
 | 
			
		||||
</ng-template>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -22,3 +22,83 @@
 | 
			
		||||
    color: #000;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
form {
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.status-selection {
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  margin-bottom: 10px;
 | 
			
		||||
  float: left;
 | 
			
		||||
  margin-right: 15px;
 | 
			
		||||
 | 
			
		||||
  label {
 | 
			
		||||
    display: block;
 | 
			
		||||
    font-weight: 700;
 | 
			
		||||
    font-size: 10px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  rb-form-checkbox {
 | 
			
		||||
    float: left;
 | 
			
		||||
    margin-right: 10px;
 | 
			
		||||
    margin-top: -10px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.page-size-selection {
 | 
			
		||||
  max-width: 125px;
 | 
			
		||||
  float: left;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.paging {
 | 
			
		||||
  rb-form-input {
 | 
			
		||||
    max-width: 50px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  > * {
 | 
			
		||||
    float: left;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  > button {
 | 
			
		||||
    margin-top: 18px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  > span {
 | 
			
		||||
    margin-top: 20px;
 | 
			
		||||
    margin-left: 5px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.sort-header {
 | 
			
		||||
  display: inline-grid;
 | 
			
		||||
  grid-template-columns: 1fr auto;
 | 
			
		||||
  grid-column-gap: 5px;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
 | 
			
		||||
  :first-child {
 | 
			
		||||
    grid-row: span 2;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  :nth-child(2) {
 | 
			
		||||
    margin-bottom: -3px;
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  :nth-child(3) {
 | 
			
		||||
    margin-top: -3px;
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.sort-active-asc {
 | 
			
		||||
  color: $color-bosch-dark-blue;
 | 
			
		||||
  background: linear-gradient(to bottom, #FFF 17%, $color-bosch-light-blue-w50 17%);;
 | 
			
		||||
  border-radius: 0 0 8px 8px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.sort-active-desc {
 | 
			
		||||
  color: $color-bosch-dark-blue;
 | 
			
		||||
  background: linear-gradient(to top, #FFF 17%, $color-bosch-light-blue-w50 17%);;
 | 
			
		||||
  border-radius: 8px 8px 0 0;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,16 +1,46 @@
 | 
			
		||||
import { Component, OnInit } from '@angular/core';
 | 
			
		||||
import {Component, OnInit, ViewChild} from '@angular/core';
 | 
			
		||||
import {ApiService} from '../services/api.service';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
interface LoadSamplesOptions {
 | 
			
		||||
  toPage?: number;
 | 
			
		||||
  event?: Event;
 | 
			
		||||
  firstPage?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-samples',
 | 
			
		||||
  templateUrl: './samples.component.html',
 | 
			
		||||
  styleUrls: ['./samples.component.scss']
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
// TODO: always show first page on sort change
 | 
			
		||||
 | 
			
		||||
export class SamplesComponent implements OnInit {  // TODO: implement paging
 | 
			
		||||
 | 
			
		||||
  @ViewChild('pageSizeSelection') pageSizeSelection: HTMLElement;
 | 
			
		||||
 | 
			
		||||
  materials = {};
 | 
			
		||||
  samples = [];
 | 
			
		||||
  filters = {status: 'validated'};
 | 
			
		||||
  totalSamples = 0;  // total number of samples
 | 
			
		||||
  filters = {status: {new: true, validated: true}, pageSize: 25, toPage: 0, sort: 'added-asc'};
 | 
			
		||||
  page = 1;
 | 
			
		||||
  loadSamplesQueue = [];  // arguments of queued up loadSamples() calls
 | 
			
		||||
  activeKeys = [
 | 
			
		||||
    {name: 'Number', key: 'number'},
 | 
			
		||||
    // {name: 'Material number', key: ''},
 | 
			
		||||
    {name: 'Material name', key: ''},
 | 
			
		||||
    {name: 'Supplier', key: ''},
 | 
			
		||||
    // {name: 'Material', key: ''},
 | 
			
		||||
    // {name: 'GF', key: ''},
 | 
			
		||||
    // {name: 'CF', key: ''},
 | 
			
		||||
    // {name: 'M', key: ''},
 | 
			
		||||
    {name: 'Type', key: 'type'},
 | 
			
		||||
    {name: 'Color', key: 'color'},
 | 
			
		||||
    {name: 'Batch', key: 'batch'},
 | 
			
		||||
    {name: 'Added', key: 'added'},
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  constructor(
 | 
			
		||||
    private api: ApiService
 | 
			
		||||
@@ -24,15 +54,61 @@ export class SamplesComponent implements OnInit {  // TODO: implement paging
 | 
			
		||||
      });
 | 
			
		||||
      this.loadSamples();
 | 
			
		||||
    });
 | 
			
		||||
    this.api.get('/samples/count', (data: {count: number}) => {
 | 
			
		||||
      this.totalSamples = data.count;
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  loadSamples() {
 | 
			
		||||
    this.api.get(`/samples?status=${this.filters.status}`, sData => {
 | 
			
		||||
  loadSamples(options: LoadSamplesOptions = {}) {  // set toPage to null to reload first page, queues calls
 | 
			
		||||
    this.loadSamplesQueue.push(options);
 | 
			
		||||
    if (this.loadSamplesQueue.length <= 1) {  // nothing queued up
 | 
			
		||||
      this.sampleLoader(this.loadSamplesQueue[0]);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private sampleLoader(options: LoadSamplesOptions) {  // actual loading of the sample, do not call directly
 | 
			
		||||
    const query: string[] = [];
 | 
			
		||||
    query.push('status=' + (this.filters.status.new && this.filters.status.validated ? 'all' : (this.filters.status.new ? 'new' : 'validated')));
 | 
			
		||||
    if (this.samples[0]) {  // do not include from-id when page size was changed
 | 
			
		||||
      if (!options.firstPage && (!options.event || ((options.event.target as HTMLElement).id.indexOf(this.pageSizeSelection.id) < 0))) {
 | 
			
		||||
        query.push('from-id=' + this.samples[0]._id);
 | 
			
		||||
      }
 | 
			
		||||
      else {
 | 
			
		||||
        this.page = 1;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    if (options.toPage) {
 | 
			
		||||
      query.push('to-page=' + options.toPage);
 | 
			
		||||
    }
 | 
			
		||||
    query.push('page-size=' + this.filters.pageSize);
 | 
			
		||||
    query.push('sort=' + this.filters.sort);
 | 
			
		||||
 | 
			
		||||
    this.api.get('/samples?' + query.join('&'), sData => {
 | 
			
		||||
      this.samples = sData as any;
 | 
			
		||||
      this.samples.forEach(sample => {
 | 
			
		||||
        sample.material_number = this.materials[sample.material_id].numbers.find(e => sample.color === e.color).number;
 | 
			
		||||
      });
 | 
			
		||||
      this.loadSamplesQueue.shift();
 | 
			
		||||
      if (this.loadSamplesQueue.length > 0) {  // execute next queue item
 | 
			
		||||
        this.sampleLoader(this.loadSamplesQueue[0]);
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  loadPage(delta) {
 | 
			
		||||
    if (!/[0-9]+/.test(delta) || (this.page <= 1 && delta < 0)) {  // invalid delta
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    this.page += delta;
 | 
			
		||||
    this.loadSamples({toPage: delta});
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  pages() {
 | 
			
		||||
    return Math.ceil(this.totalSamples / this.filters.pageSize);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setSort(string) {
 | 
			
		||||
    this.filters.sort = string;
 | 
			
		||||
    this.loadSamples({firstPage: true});
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user