sorting implemented
This commit is contained in:
parent
09598c4ba7
commit
81621e77cc
@ -13,7 +13,7 @@ export class SampleModel extends BaseModel {
|
|||||||
condition: {condition_template: string, [prop: string]: string} | {} = {};
|
condition: {condition_template: string, [prop: string]: string} | {} = {};
|
||||||
material_id: IdModel = null;
|
material_id: IdModel = null;
|
||||||
material: MaterialModel;
|
material: MaterialModel;
|
||||||
measurements: MeasurementModel[];
|
measurements: MeasurementModel[] = [];
|
||||||
note_id: IdModel = null;
|
note_id: IdModel = null;
|
||||||
user_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: {}};
|
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: confirmation for new group/supplier
|
||||||
// TODO: DPT preview
|
// TODO: DPT preview
|
||||||
// TODO: work on better recognition for file input
|
// 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>
|
</div>
|
||||||
|
|
||||||
<rb-accordion>
|
<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>
|
<rb-accordion-body>
|
||||||
<form>
|
<form (change)="loadSamples({event: $event})">
|
||||||
<rb-form-select name="statusSelect" label="Status" [(ngModel)]="filters.status">
|
<div class="status-selection">
|
||||||
<option value="validated">validated</option>
|
<label class="label">Status</label>
|
||||||
<option value="new">new</option>
|
<rb-form-checkbox name="status-validated" [(ngModel)]="filters.status.validated" [disabled]="!filters.status.new">
|
||||||
<option value="all">all</option>
|
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>
|
</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>
|
</form>
|
||||||
</rb-accordion-body>
|
</rb-accordion-body>
|
||||||
</rb-accordion>
|
</rb-accordion>
|
||||||
|
|
||||||
|
<ng-container *ngTemplateOutlet="paging"></ng-container>
|
||||||
|
|
||||||
<rb-table>
|
<rb-table>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Number</th>
|
<th *ngFor="let key of activeKeys">
|
||||||
<th>Material number</th>
|
<div class="sort-header">
|
||||||
<th>Material name</th>
|
<span>{{key.name}}</span>
|
||||||
<th>Supplier</th>
|
<span class="rb-ic rb-ic-up" [ngClass]="{'sort-active-desc': filters.sort === key.key + '-' + 'desc'}" (click)="setSort(key.key + '-' + 'desc')"></span>
|
||||||
<th>Material</th>
|
<span class="rb-ic rb-ic-down" [ngClass]="{'sort-active-asc': filters.sort === key.key + '-' + 'asc'}" (click)="setSort(key.key + '-' + 'asc')"></span>
|
||||||
<th>GF</th>
|
</div>
|
||||||
<th>CF</th>
|
</th>
|
||||||
<th>M</th>
|
|
||||||
<th>type</th>
|
|
||||||
<th>Color</th>
|
|
||||||
<th>Batch</th>
|
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr *ngFor="let sample of samples">
|
<tr *ngFor="let sample of samples">
|
||||||
<td>{{sample.number}}</td>
|
<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].name}}</td>
|
||||||
<td>{{materials[sample.material_id].supplier}}</td>
|
<td>{{materials[sample.material_id].supplier}}</td>
|
||||||
<td>{{materials[sample.material_id].group}}</td>
|
<!-- <td>{{materials[sample.material_id].group}}</td>-->
|
||||||
<td>{{materials[sample.material_id].glass_fiber}}</td>
|
<!-- <td>{{materials[sample.material_id].glass_fiber}}</td>-->
|
||||||
<td>{{materials[sample.material_id].carbon_fiber}}</td>
|
<!-- <td>{{materials[sample.material_id].carbon_fiber}}</td>-->
|
||||||
<td>{{materials[sample.material_id].mineral}}</td>
|
<!-- <td>{{materials[sample.material_id].mineral}}</td>-->
|
||||||
<td>{{sample.type}}</td>
|
<td>{{sample.type}}</td>
|
||||||
<td>{{sample.color}}</td>
|
<td>{{sample.color}}</td>
|
||||||
<td>{{sample.batch}}</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>
|
<td><a [routerLink]="'/samples/edit/' + sample._id"><span class="rb-ic rb-ic-edit"></span></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
</rb-table>
|
</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;
|
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';
|
import {ApiService} from '../services/api.service';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
interface LoadSamplesOptions {
|
||||||
|
toPage?: number;
|
||||||
|
event?: Event;
|
||||||
|
firstPage?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-samples',
|
selector: 'app-samples',
|
||||||
templateUrl: './samples.component.html',
|
templateUrl: './samples.component.html',
|
||||||
styleUrls: ['./samples.component.scss']
|
styleUrls: ['./samples.component.scss']
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// TODO: always show first page on sort change
|
||||||
|
|
||||||
export class SamplesComponent implements OnInit { // TODO: implement paging
|
export class SamplesComponent implements OnInit { // TODO: implement paging
|
||||||
|
|
||||||
|
@ViewChild('pageSizeSelection') pageSizeSelection: HTMLElement;
|
||||||
|
|
||||||
materials = {};
|
materials = {};
|
||||||
samples = [];
|
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(
|
constructor(
|
||||||
private api: ApiService
|
private api: ApiService
|
||||||
@ -24,15 +54,61 @@ export class SamplesComponent implements OnInit { // TODO: implement paging
|
|||||||
});
|
});
|
||||||
this.loadSamples();
|
this.loadSamples();
|
||||||
});
|
});
|
||||||
|
this.api.get('/samples/count', (data: {count: number}) => {
|
||||||
|
this.totalSamples = data.count;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
loadSamples() {
|
loadSamples(options: LoadSamplesOptions = {}) { // set toPage to null to reload first page, queues calls
|
||||||
this.api.get(`/samples?status=${this.filters.status}`, sData => {
|
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 = sData as any;
|
||||||
this.samples.forEach(sample => {
|
this.samples.forEach(sample => {
|
||||||
sample.material_number = this.materials[sample.material_id].numbers.find(e => sample.color === e.color).number;
|
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});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user