Moved from tslint to eslint as tslint was depreciated.
Added prettier and also prettied all the typescript files using prettier ESLint is using the AirBnB rules which are the most strict to lint the files.
This commit is contained in:
@ -5,59 +5,93 @@
|
||||
</mat-card-title-group>
|
||||
<mat-card-content>
|
||||
<form [formGroup]="form" fxLayout="column">
|
||||
<div fxLayout="row" fxLayoutAlign="space-around start" fxLayout.lt-md="column" fxLayoutGap="20px"
|
||||
fxLayoutGap.lt-md="0px">
|
||||
<div
|
||||
fxLayout="row"
|
||||
fxLayoutAlign="space-around start"
|
||||
fxLayout.lt-md="column"
|
||||
fxLayoutGap="20px"
|
||||
fxLayoutGap.lt-md="0px"
|
||||
>
|
||||
<mat-form-field fxFlex>
|
||||
<mat-label>Code</mat-label>
|
||||
<input matInput placeholder="Code" formControlName="code">
|
||||
<input matInput placeholder="Code" formControlName="code" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div fxLayout="row" fxLayoutAlign="space-around start" fxLayout.lt-md="column" fxLayoutGap="20px"
|
||||
fxLayoutGap.lt-md="0px">
|
||||
<div
|
||||
fxLayout="row"
|
||||
fxLayoutAlign="space-around start"
|
||||
fxLayout.lt-md="column"
|
||||
fxLayoutGap="20px"
|
||||
fxLayoutGap.lt-md="0px"
|
||||
>
|
||||
<mat-form-field fxFlex="75">
|
||||
<mat-label>Name</mat-label>
|
||||
<input matInput #nameElement placeholder="Name" formControlName="name">
|
||||
<input matInput #nameElement placeholder="Name" formControlName="name" />
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex="25">
|
||||
<mat-label>Units</mat-label>
|
||||
<input matInput placeholder="Units" formControlName="units">
|
||||
<input matInput placeholder="Units" formControlName="units" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div fxLayout="row" fxLayoutAlign="space-around start" fxLayout.lt-md="column" fxLayoutGap="20px"
|
||||
fxLayoutGap.lt-md="0px">
|
||||
<div
|
||||
fxLayout="row"
|
||||
fxLayoutAlign="space-around start"
|
||||
fxLayout.lt-md="column"
|
||||
fxLayoutGap="20px"
|
||||
fxLayoutGap.lt-md="0px"
|
||||
>
|
||||
<mat-form-field fxFlex>
|
||||
<mat-label>Fraction</mat-label>
|
||||
<input matInput type="number" placeholder="Fraction" formControlName="fraction">
|
||||
<input matInput type="number" placeholder="Fraction" formControlName="fraction" />
|
||||
</mat-form-field>
|
||||
<mat-form-field cdk-overlay-origin="">
|
||||
<mat-label>Fraction Units</mat-label>
|
||||
<input matInput placeholder="Fraction Units" formControlName="fractionUnits">
|
||||
<input matInput placeholder="Fraction Units" formControlName="fractionUnits" />
|
||||
</mat-form-field>
|
||||
<mat-form-field cdk-overlay-origin="">
|
||||
<mat-label>Yield</mat-label>
|
||||
<input matInput type="number" placeholder="Yield" formControlName="productYield">
|
||||
<input matInput type="number" placeholder="Yield" formControlName="productYield" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div fxLayout="row" fxLayoutAlign="space-around start" fxLayout.lt-md="column" fxLayoutGap="20px"
|
||||
fxLayoutGap.lt-md="0px">
|
||||
<div
|
||||
fxLayout="row"
|
||||
fxLayoutAlign="space-around start"
|
||||
fxLayout.lt-md="column"
|
||||
fxLayoutGap="20px"
|
||||
fxLayoutGap.lt-md="0px"
|
||||
>
|
||||
<mat-form-field fxFlex>
|
||||
<mat-label>{{item.isPurchased ? 'Purchase Price' : 'Cost Price' }}</mat-label>
|
||||
<input matInput type="number" placeholder="{{item.isPurchased ? 'Purchase Price' : 'Cost Price' }}"
|
||||
formControlName="price">
|
||||
<mat-label>{{ item.isPurchased ? 'Purchase Price' : 'Cost Price' }}</mat-label>
|
||||
<input
|
||||
matInput
|
||||
type="number"
|
||||
placeholder="{{ item.isPurchased ? 'Purchase Price' : 'Cost Price' }}"
|
||||
formControlName="price"
|
||||
/>
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex [hidden]="!item.isSold">
|
||||
<mat-label>Sale Price</mat-label>
|
||||
<input matInput type="number" placeholder="Sale Price" formControlName="salePrice">
|
||||
<input matInput type="number" placeholder="Sale Price" formControlName="salePrice" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div fxLayout="row" fxLayoutAlign="space-around start" fxLayout.lt-md="column" fxLayoutGap="20px"
|
||||
fxLayoutGap.lt-md="0px">
|
||||
<div
|
||||
fxLayout="row"
|
||||
fxLayoutAlign="space-around start"
|
||||
fxLayout.lt-md="column"
|
||||
fxLayoutGap="20px"
|
||||
fxLayoutGap.lt-md="0px"
|
||||
>
|
||||
<mat-checkbox formControlName="isPurchased">Is Purchased?</mat-checkbox>
|
||||
<mat-checkbox formControlName="isSold">Is Sold?</mat-checkbox>
|
||||
<mat-checkbox formControlName="isActive">Is Active?</mat-checkbox>
|
||||
</div>
|
||||
<div fxLayout="row" fxLayoutAlign="space-around start" fxLayout.lt-md="column" fxLayoutGap="20px"
|
||||
fxLayoutGap.lt-md="0px">
|
||||
<div
|
||||
fxLayout="row"
|
||||
fxLayoutAlign="space-around start"
|
||||
fxLayout.lt-md="column"
|
||||
fxLayoutGap="20px"
|
||||
fxLayoutGap.lt-md="0px"
|
||||
>
|
||||
<mat-form-field fxFlex>
|
||||
<mat-label>Product Type</mat-label>
|
||||
<mat-select placeholder="Product Group" formControlName="productGroup">
|
||||
@ -71,7 +105,9 @@
|
||||
</mat-card-content>
|
||||
<mat-card-actions>
|
||||
<button mat-raised-button color="primary" (click)="save()">Save</button>
|
||||
<button mat-raised-button color="warn" (click)="confirmDelete()" *ngIf="!!item.id">Delete</button>
|
||||
<button mat-raised-button color="warn" (click)="confirmDelete()" *ngIf="!!item.id">
|
||||
Delete
|
||||
</button>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
</div>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import {ProductDetailComponent} from './product-detail.component';
|
||||
import { ProductDetailComponent } from './product-detail.component';
|
||||
|
||||
describe('ProductDetailComponent', () => {
|
||||
let component: ProductDetailComponent;
|
||||
@ -8,9 +8,8 @@ describe('ProductDetailComponent', () => {
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ProductDetailComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
declarations: [ProductDetailComponent],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
import {AfterViewInit, Component, ElementRef, OnInit, ViewChild} from '@angular/core';
|
||||
import {ToasterService} from '../../core/toaster.service';
|
||||
import {ActivatedRoute, Router} from '@angular/router';
|
||||
import {ProductService} from '../product.service';
|
||||
import {Product} from '../../core/product';
|
||||
import {ProductGroup} from '../../core/product-group';
|
||||
import {ConfirmDialogComponent} from '../../shared/confirm-dialog/confirm-dialog.component';
|
||||
import { AfterViewInit, Component, ElementRef, OnInit, ViewChild } from '@angular/core';
|
||||
import { ToasterService } from '../../core/toaster.service';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { ProductService } from '../product.service';
|
||||
import { Product } from '../../core/product';
|
||||
import { ProductGroup } from '../../core/product-group';
|
||||
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import {FormBuilder, FormGroup} from '@angular/forms';
|
||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'app-product-detail',
|
||||
templateUrl: './product-detail.component.html',
|
||||
styleUrls: ['./product-detail.component.css']
|
||||
styleUrls: ['./product-detail.component.css'],
|
||||
})
|
||||
export class ProductDetailComponent implements OnInit, AfterViewInit {
|
||||
@ViewChild('nameElement', { static: true }) nameElement: ElementRef;
|
||||
@ -25,14 +25,14 @@ export class ProductDetailComponent implements OnInit, AfterViewInit {
|
||||
private dialog: MatDialog,
|
||||
private fb: FormBuilder,
|
||||
private toaster: ToasterService,
|
||||
private ser: ProductService
|
||||
private ser: ProductService,
|
||||
) {
|
||||
this.createForm();
|
||||
}
|
||||
|
||||
createForm() {
|
||||
this.form = this.fb.group({
|
||||
code: {value: '', disabled: true},
|
||||
code: { value: '', disabled: true },
|
||||
name: '',
|
||||
units: '',
|
||||
fraction: '',
|
||||
@ -43,16 +43,15 @@ export class ProductDetailComponent implements OnInit, AfterViewInit {
|
||||
isPurchased: '',
|
||||
isSold: '',
|
||||
isActive: '',
|
||||
productGroup: ''
|
||||
productGroup: '',
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.route.data
|
||||
.subscribe((data: { item: Product, productGroups: ProductGroup[] }) => {
|
||||
this.productGroups = data.productGroups;
|
||||
this.showItem(data.item);
|
||||
});
|
||||
this.route.data.subscribe((data: { item: Product; productGroups: ProductGroup[] }) => {
|
||||
this.productGroups = data.productGroups;
|
||||
this.showItem(data.item);
|
||||
});
|
||||
}
|
||||
|
||||
showItem(item: Product) {
|
||||
@ -69,7 +68,7 @@ export class ProductDetailComponent implements OnInit, AfterViewInit {
|
||||
isPurchased: this.item.isPurchased,
|
||||
isSold: this.item.isSold,
|
||||
isActive: this.item.isActive,
|
||||
productGroup: this.item.productGroup.id ? this.item.productGroup.id : ''
|
||||
productGroup: this.item.productGroup.id ? this.item.productGroup.id : '',
|
||||
});
|
||||
}
|
||||
|
||||
@ -80,35 +79,33 @@ export class ProductDetailComponent implements OnInit, AfterViewInit {
|
||||
}
|
||||
|
||||
save() {
|
||||
this.ser.saveOrUpdate(this.getItem())
|
||||
.subscribe(
|
||||
(result) => {
|
||||
this.toaster.show('Success', '');
|
||||
this.router.navigateByUrl('/products');
|
||||
},
|
||||
(error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
}
|
||||
);
|
||||
this.ser.saveOrUpdate(this.getItem()).subscribe(
|
||||
(result) => {
|
||||
this.toaster.show('Success', '');
|
||||
this.router.navigateByUrl('/products');
|
||||
},
|
||||
(error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
delete() {
|
||||
this.ser.delete(this.item.id)
|
||||
.subscribe(
|
||||
(result) => {
|
||||
this.toaster.show('Success', '');
|
||||
this.router.navigateByUrl('/products');
|
||||
},
|
||||
(error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
}
|
||||
);
|
||||
this.ser.delete(this.item.id).subscribe(
|
||||
(result) => {
|
||||
this.toaster.show('Success', '');
|
||||
this.router.navigateByUrl('/products');
|
||||
},
|
||||
(error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
confirmDelete(): void {
|
||||
const dialogRef = this.dialog.open(ConfirmDialogComponent, {
|
||||
width: '250px',
|
||||
data: {title: 'Delete Product?', content: 'Are you sure? This cannot be undone.'}
|
||||
data: { title: 'Delete Product?', content: 'Are you sure? This cannot be undone.' },
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe((result: boolean) => {
|
||||
|
||||
@ -1,15 +1,18 @@
|
||||
import {inject, TestBed} from '@angular/core/testing';
|
||||
import { inject, TestBed } from '@angular/core/testing';
|
||||
|
||||
import {ProductListResolverService} from './product-list-resolver.service';
|
||||
import { ProductListResolverService } from './product-list-resolver.service';
|
||||
|
||||
describe('ProductListResolverService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [ProductListResolverService]
|
||||
providers: [ProductListResolverService],
|
||||
});
|
||||
});
|
||||
|
||||
it('should be created', inject([ProductListResolverService], (service: ProductListResolverService) => {
|
||||
expect(service).toBeTruthy();
|
||||
}));
|
||||
it('should be created', inject(
|
||||
[ProductListResolverService],
|
||||
(service: ProductListResolverService) => {
|
||||
expect(service).toBeTruthy();
|
||||
},
|
||||
));
|
||||
});
|
||||
|
||||
@ -1,16 +1,14 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {ActivatedRouteSnapshot, Resolve, RouterStateSnapshot} from '@angular/router';
|
||||
import {Product} from '../core/product';
|
||||
import {Observable} from 'rxjs/internal/Observable';
|
||||
import {ProductService} from './product.service';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router';
|
||||
import { Product } from '../core/product';
|
||||
import { Observable } from 'rxjs/internal/Observable';
|
||||
import { ProductService } from './product.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class ProductListResolver implements Resolve<Product[]> {
|
||||
|
||||
constructor(private ser: ProductService) {
|
||||
}
|
||||
constructor(private ser: ProductService) {}
|
||||
|
||||
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Product[]> {
|
||||
return this.ser.list();
|
||||
|
||||
@ -5,15 +5,17 @@ import { map, tap } from 'rxjs/operators';
|
||||
import { merge, Observable, of as observableOf } from 'rxjs';
|
||||
import { Product } from '../../core/product';
|
||||
|
||||
|
||||
export class ProductListDataSource extends DataSource<Product> {
|
||||
private filterValue: string;
|
||||
|
||||
constructor(private paginator: MatPaginator, private sort: MatSort, private filter: Observable<string>, public data: Product[]) {
|
||||
constructor(
|
||||
private paginator: MatPaginator,
|
||||
private sort: MatSort,
|
||||
private filter: Observable<string>,
|
||||
public data: Product[],
|
||||
) {
|
||||
super();
|
||||
this.filter = filter.pipe(
|
||||
tap(x => this.filterValue = x)
|
||||
);
|
||||
this.filter = filter.pipe(tap((x) => (this.filterValue = x)));
|
||||
}
|
||||
|
||||
connect(): Observable<Product[]> {
|
||||
@ -21,35 +23,43 @@ export class ProductListDataSource extends DataSource<Product> {
|
||||
observableOf(this.data),
|
||||
this.filter,
|
||||
this.paginator.page,
|
||||
this.sort.sortChange
|
||||
this.sort.sortChange,
|
||||
];
|
||||
|
||||
return merge(...dataMutations).pipe(
|
||||
map((x: any) => {
|
||||
return this.getFilteredData([...this.data]);
|
||||
}),
|
||||
tap((x: Product[]) => this.paginator.length = x.length)
|
||||
).pipe(
|
||||
map((x: any) => {
|
||||
return this.getPagedData(this.getSortedData(x));
|
||||
})
|
||||
);
|
||||
return merge(...dataMutations)
|
||||
.pipe(
|
||||
map((x: any) => {
|
||||
return this.getFilteredData([...this.data]);
|
||||
}),
|
||||
tap((x: Product[]) => (this.paginator.length = x.length)),
|
||||
)
|
||||
.pipe(
|
||||
map((x: any) => {
|
||||
return this.getPagedData(this.getSortedData(x));
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
}
|
||||
disconnect() {}
|
||||
|
||||
private getFilteredData(data: Product[]): Product[] {
|
||||
const filter = (this.filterValue === undefined) ? '' : this.filterValue;
|
||||
const filter = this.filterValue === undefined ? '' : this.filterValue;
|
||||
return filter.split(' ').reduce((p: Product[], c: string) => {
|
||||
return p.filter(x => {
|
||||
const productString = (
|
||||
x.code + ' ' + x.name + ' ' + x.units + ' ' + x.productGroup + (x.isPurchased ? ' purchased' : ' made')
|
||||
+ (x.isSold ? 'sold' : 'used') + (x.isActive ? 'active' : 'deactive')
|
||||
).toLowerCase();
|
||||
return productString.indexOf(c) !== -1;
|
||||
}
|
||||
);
|
||||
return p.filter((x) => {
|
||||
const productString = (
|
||||
x.code +
|
||||
' ' +
|
||||
x.name +
|
||||
' ' +
|
||||
x.units +
|
||||
' ' +
|
||||
x.productGroup +
|
||||
(x.isPurchased ? ' purchased' : ' made') +
|
||||
(x.isSold ? 'sold' : 'used') +
|
||||
(x.isActive ? 'active' : 'deactive')
|
||||
).toLowerCase();
|
||||
return productString.indexOf(c) !== -1;
|
||||
});
|
||||
}, Object.assign([], data));
|
||||
}
|
||||
|
||||
|
||||
@ -11,38 +11,54 @@
|
||||
</mat-card-title-group>
|
||||
<mat-card-content>
|
||||
<form [formGroup]="form" fxLayout="column">
|
||||
<div fxLayout="row" fxLayout.lt-md="column" fxLayoutGap="20px" fxLayoutGap.lt-md="0px"
|
||||
fxLayoutAlign="space-around start">
|
||||
<div
|
||||
fxLayout="row"
|
||||
fxLayout.lt-md="column"
|
||||
fxLayoutGap="20px"
|
||||
fxLayoutGap.lt-md="0px"
|
||||
fxLayoutAlign="space-around start"
|
||||
>
|
||||
<mat-form-field fxFlex>
|
||||
<input type="text" matInput #filterElement placeholder="Filter" formControlName="filter" autocomplete="off">
|
||||
<input
|
||||
type="text"
|
||||
matInput
|
||||
#filterElement
|
||||
placeholder="Filter"
|
||||
formControlName="filter"
|
||||
autocomplete="off"
|
||||
/>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</form>
|
||||
<mat-table #table [dataSource]="dataSource" matSort aria-label="Elements">
|
||||
|
||||
<!-- Name Column -->
|
||||
<ng-container matColumnDef="name">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header>Name</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row"><a [routerLink]="['/products', row.id]">{{row.name}} ({{showExtended ?
|
||||
row.fraction + ' ' + row.fractionUnits + ' = 1 ':''}}{{row.units}})</a></mat-cell>
|
||||
<mat-cell *matCellDef="let row"
|
||||
><a [routerLink]="['/products', row.id]"
|
||||
>{{ row.name }} ({{
|
||||
showExtended ? row.fraction + ' ' + row.fractionUnits + ' = 1 ' : ''
|
||||
}}{{ row.units }})</a
|
||||
></mat-cell
|
||||
>
|
||||
</ng-container>
|
||||
|
||||
<!-- Cost Price Column -->
|
||||
<ng-container matColumnDef="costPrice">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header>Cost Price</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row">{{row.costPrice | currency:'INR'}}</mat-cell>
|
||||
<mat-cell *matCellDef="let row">{{ row.costPrice | currency: 'INR' }}</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Yield Column -->
|
||||
<ng-container matColumnDef="productYield">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header>Yield</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row">{{row.productYield | percent:'1.2-2'}}</mat-cell>
|
||||
<mat-cell *matCellDef="let row">{{ row.productYield | percent: '1.2-2' }}</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Product Group Column -->
|
||||
<ng-container matColumnDef="productGroup">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header>Product Group</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row">{{row.productGroup}}</mat-cell>
|
||||
<mat-cell *matCellDef="let row">{{ row.productGroup }}</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Info Column -->
|
||||
@ -52,35 +68,37 @@
|
||||
<div layout="row">
|
||||
<div flex>
|
||||
<mat-icon>
|
||||
{{ row.isPurchased ? "shopping_cart" : "remove_shopping_cart" }}
|
||||
{{ row.isPurchased ? 'shopping_cart' : 'remove_shopping_cart' }}
|
||||
</mat-icon>
|
||||
<b> {{ row.isPurchased ? "Purchased" : "Made" }}</b>
|
||||
<b> {{ row.isPurchased ? 'Purchased' : 'Made' }}</b>
|
||||
</div>
|
||||
<div flex>
|
||||
<mat-icon>
|
||||
{{ row.isSold ? "restaurant_menu" : "import_contacts" }}
|
||||
{{ row.isSold ? 'restaurant_menu' : 'import_contacts' }}
|
||||
</mat-icon>
|
||||
<b> {{ row.isSold ? "Sold" : "Used" }}</b>
|
||||
<b> {{ row.isSold ? 'Sold' : 'Used' }}</b>
|
||||
</div>
|
||||
<div flex>
|
||||
<mat-icon>
|
||||
{{ row.isActive ? "visibility" : "visibility_off" }}
|
||||
{{ row.isActive ? 'visibility' : 'visibility_off' }}
|
||||
</mat-icon>
|
||||
<b> {{ row.isActive ? "Active" : "Deactivated" }}</b>
|
||||
<b> {{ row.isActive ? 'Active' : 'Deactivated' }}</b>
|
||||
</div>
|
||||
</div>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
|
||||
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
|
||||
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
|
||||
</mat-table>
|
||||
|
||||
<mat-paginator #paginator
|
||||
[length]="dataSource.data.length"
|
||||
[pageIndex]="0"
|
||||
[pageSize]="50"
|
||||
[pageSizeOptions]="[25, 50, 100, 250, 5000]">
|
||||
<mat-paginator
|
||||
#paginator
|
||||
[length]="dataSource.data.length"
|
||||
[pageIndex]="0"
|
||||
[pageSize]="50"
|
||||
[pageSizeOptions]="[25, 50, 100, 250, 5000]"
|
||||
>
|
||||
</mat-paginator>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import {ComponentFixture, fakeAsync, TestBed} from '@angular/core/testing';
|
||||
import { ComponentFixture, fakeAsync, TestBed } from '@angular/core/testing';
|
||||
|
||||
import {ProductListComponent} from './product-list.component';
|
||||
import { ProductListComponent } from './product-list.component';
|
||||
|
||||
describe('ProductListComponent', () => {
|
||||
let component: ProductListComponent;
|
||||
@ -8,9 +8,8 @@ describe('ProductListComponent', () => {
|
||||
|
||||
beforeEach(fakeAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ProductListComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
declarations: [ProductListComponent],
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(ProductListComponent);
|
||||
component = fixture.componentInstance;
|
||||
|
||||
@ -12,10 +12,9 @@ import { ToCsvService } from '../../shared/to-csv.service';
|
||||
@Component({
|
||||
selector: 'app-product-list',
|
||||
templateUrl: './product-list.component.html',
|
||||
styleUrls: ['./product-list.component.css']
|
||||
styleUrls: ['./product-list.component.css'],
|
||||
})
|
||||
export class ProductListComponent implements OnInit, AfterViewInit {
|
||||
|
||||
constructor(private route: ActivatedRoute, private fb: FormBuilder, private toCsv: ToCsvService) {
|
||||
this.showExtended = false;
|
||||
this.createForm();
|
||||
@ -48,24 +47,20 @@ export class ProductListComponent implements OnInit, AfterViewInit {
|
||||
|
||||
createForm() {
|
||||
this.form = this.fb.group({
|
||||
filter: ''
|
||||
filter: '',
|
||||
});
|
||||
}
|
||||
|
||||
listenToFilterChange() {
|
||||
return this.form.get('filter').valueChanges
|
||||
.pipe(
|
||||
startWith(''),
|
||||
debounceTime(150),
|
||||
distinctUntilChanged()
|
||||
);
|
||||
return this.form
|
||||
.get('filter')
|
||||
.valueChanges.pipe(startWith(''), debounceTime(150), distinctUntilChanged());
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.route.data
|
||||
.subscribe((data: { list: Product[] }) => {
|
||||
this.list = data.list;
|
||||
});
|
||||
this.route.data.subscribe((data: { list: Product[] }) => {
|
||||
this.list = data.list;
|
||||
});
|
||||
this.dataSource = new ProductListDataSource(this.paginator, this.sort, this.filter, this.list);
|
||||
}
|
||||
|
||||
@ -84,10 +79,12 @@ export class ProductListComponent implements OnInit, AfterViewInit {
|
||||
FractionUnits: 'fractionUnits',
|
||||
CostPrice: 'costPrice',
|
||||
Yield: 'yield',
|
||||
ProductGroup: 'productGroup'
|
||||
ProductGroup: 'productGroup',
|
||||
};
|
||||
|
||||
const csvData = new Blob([this.toCsv.toCsv(headers, this.dataSource.data)], {type: 'text/csv;charset=utf-8;'});
|
||||
const csvData = new Blob([this.toCsv.toCsv(headers, this.dataSource.data)], {
|
||||
type: 'text/csv;charset=utf-8;',
|
||||
});
|
||||
const link = document.createElement('a');
|
||||
link.href = window.URL.createObjectURL(csvData);
|
||||
link.setAttribute('download', 'products.csv');
|
||||
|
||||
@ -1,15 +1,18 @@
|
||||
import {inject, TestBed} from '@angular/core/testing';
|
||||
import { inject, TestBed } from '@angular/core/testing';
|
||||
|
||||
import {ProductResolverService} from './product-resolver.service';
|
||||
import { ProductResolverService } from './product-resolver.service';
|
||||
|
||||
describe('ProductResolverService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [ProductDetailResolverService]
|
||||
providers: [ProductDetailResolverService],
|
||||
});
|
||||
});
|
||||
|
||||
it('should be created', inject([ProductDetailResolverService], (service: ProductDetailResolverService) => {
|
||||
expect(service).toBeTruthy();
|
||||
}));
|
||||
it('should be created', inject(
|
||||
[ProductDetailResolverService],
|
||||
(service: ProductDetailResolverService) => {
|
||||
expect(service).toBeTruthy();
|
||||
},
|
||||
));
|
||||
});
|
||||
|
||||
@ -1,16 +1,14 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {ActivatedRouteSnapshot, Resolve, Router, RouterStateSnapshot} from '@angular/router';
|
||||
import {ProductService} from './product.service';
|
||||
import {Product} from '../core/product';
|
||||
import {Observable} from 'rxjs/internal/Observable';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, Resolve, Router, RouterStateSnapshot } from '@angular/router';
|
||||
import { ProductService } from './product.service';
|
||||
import { Product } from '../core/product';
|
||||
import { Observable } from 'rxjs/internal/Observable';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class ProductResolver implements Resolve<Product> {
|
||||
|
||||
constructor(private ser: ProductService, private router: Router) {
|
||||
}
|
||||
constructor(private ser: ProductService, private router: Router) {}
|
||||
|
||||
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Product> {
|
||||
const id = route.paramMap.get('id');
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import {ProductRoutingModule} from './product-routing.module';
|
||||
import { ProductRoutingModule } from './product-routing.module';
|
||||
|
||||
describe('ProductRoutingModule', () => {
|
||||
let productRoutingModule: ProductRoutingModule;
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
import {NgModule} from '@angular/core';
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {RouterModule, Routes} from '@angular/router';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
import {ProductListResolver} from './product-list-resolver.service';
|
||||
import {ProductResolver} from './product-resolver.service';
|
||||
import {ProductDetailComponent} from './product-detail/product-detail.component';
|
||||
import {ProductListComponent} from './product-list/product-list.component';
|
||||
import { ProductListResolver } from './product-list-resolver.service';
|
||||
import { ProductResolver } from './product-resolver.service';
|
||||
import { ProductDetailComponent } from './product-detail/product-detail.component';
|
||||
import { ProductListComponent } from './product-list/product-list.component';
|
||||
|
||||
import {AuthGuard} from '../auth/auth-guard.service';
|
||||
import {ProductGroupListResolver} from '../product-group/product-group-list-resolver.service';
|
||||
import { AuthGuard } from '../auth/auth-guard.service';
|
||||
import { ProductGroupListResolver } from '../product-group/product-group-list-resolver.service';
|
||||
|
||||
const productRoutes: Routes = [
|
||||
{
|
||||
@ -16,51 +16,41 @@ const productRoutes: Routes = [
|
||||
component: ProductListComponent,
|
||||
canActivate: [AuthGuard],
|
||||
data: {
|
||||
permission: 'Products'
|
||||
permission: 'Products',
|
||||
},
|
||||
resolve: {
|
||||
list: ProductListResolver
|
||||
}
|
||||
list: ProductListResolver,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'new',
|
||||
component: ProductDetailComponent,
|
||||
canActivate: [AuthGuard],
|
||||
data: {
|
||||
permission: 'Products'
|
||||
permission: 'Products',
|
||||
},
|
||||
resolve: {
|
||||
item: ProductResolver,
|
||||
productGroups: ProductGroupListResolver
|
||||
}
|
||||
productGroups: ProductGroupListResolver,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
component: ProductDetailComponent,
|
||||
canActivate: [AuthGuard],
|
||||
data: {
|
||||
permission: 'Products'
|
||||
permission: 'Products',
|
||||
},
|
||||
resolve: {
|
||||
item: ProductResolver,
|
||||
productGroups: ProductGroupListResolver
|
||||
}
|
||||
}
|
||||
productGroups: ProductGroupListResolver,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
RouterModule.forChild(productRoutes)
|
||||
|
||||
],
|
||||
exports: [
|
||||
RouterModule
|
||||
],
|
||||
providers: [
|
||||
ProductListResolver,
|
||||
ProductResolver
|
||||
]
|
||||
imports: [CommonModule, RouterModule.forChild(productRoutes)],
|
||||
exports: [RouterModule],
|
||||
providers: [ProductListResolver, ProductResolver],
|
||||
})
|
||||
export class ProductRoutingModule {
|
||||
}
|
||||
export class ProductRoutingModule {}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import {ProductModule} from './product.module';
|
||||
import { ProductModule } from './product.module';
|
||||
|
||||
describe('ProductModule', () => {
|
||||
let productModule: ProductModule;
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import {NgModule} from '@angular/core';
|
||||
import {CommonModule} from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import {ProductListComponent} from './product-list/product-list.component';
|
||||
import {ProductDetailComponent} from './product-detail/product-detail.component';
|
||||
import {ProductRoutingModule} from './product-routing.module';
|
||||
import { ProductListComponent } from './product-list/product-list.component';
|
||||
import { ProductDetailComponent } from './product-detail/product-detail.component';
|
||||
import { ProductRoutingModule } from './product-routing.module';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
@ -15,9 +15,9 @@ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { MatSortModule } from '@angular/material/sort';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
import {CdkTableModule} from '@angular/cdk/table';
|
||||
import {ReactiveFormsModule} from '@angular/forms';
|
||||
import {FlexLayoutModule} from '@angular/flex-layout';
|
||||
import { CdkTableModule } from '@angular/cdk/table';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { FlexLayoutModule } from '@angular/flex-layout';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@ -36,12 +36,8 @@ import {FlexLayoutModule} from '@angular/flex-layout';
|
||||
MatSelectModule,
|
||||
MatCheckboxModule,
|
||||
ReactiveFormsModule,
|
||||
ProductRoutingModule
|
||||
ProductRoutingModule,
|
||||
],
|
||||
declarations: [
|
||||
ProductListComponent,
|
||||
ProductDetailComponent
|
||||
]
|
||||
declarations: [ProductListComponent, ProductDetailComponent],
|
||||
})
|
||||
export class ProductModule {
|
||||
}
|
||||
export class ProductModule {}
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import {inject, TestBed} from '@angular/core/testing';
|
||||
import { inject, TestBed } from '@angular/core/testing';
|
||||
|
||||
import {ProductService} from './product.service';
|
||||
import { ProductService } from './product.service';
|
||||
|
||||
describe('ProductService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [ProductService]
|
||||
providers: [ProductService],
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -1,50 +1,52 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {Observable} from 'rxjs/internal/Observable';
|
||||
import {catchError} from 'rxjs/operators';
|
||||
import {HttpClient, HttpHeaders, HttpParams} from '@angular/common/http';
|
||||
import {Product} from '../core/product';
|
||||
import {ErrorLoggerService} from '../core/error-logger.service';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs/internal/Observable';
|
||||
import { catchError } from 'rxjs/operators';
|
||||
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
|
||||
import { Product } from '../core/product';
|
||||
import { ErrorLoggerService } from '../core/error-logger.service';
|
||||
|
||||
const httpOptions = {
|
||||
headers: new HttpHeaders({'Content-Type': 'application/json'})
|
||||
headers: new HttpHeaders({ 'Content-Type': 'application/json' }),
|
||||
};
|
||||
|
||||
const url = '/api/products';
|
||||
const serviceName = 'ProductService';
|
||||
|
||||
@Injectable({providedIn: 'root'})
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class ProductService {
|
||||
|
||||
constructor(private http: HttpClient, private log: ErrorLoggerService) {
|
||||
}
|
||||
constructor(private http: HttpClient, private log: ErrorLoggerService) {}
|
||||
|
||||
get(id: string): Observable<Product> {
|
||||
const getUrl: string = (id === null) ? `${url}` : `${url}/${id}`;
|
||||
return <Observable<Product>>this.http.get<Product>(getUrl)
|
||||
.pipe(
|
||||
catchError(this.log.handleError(serviceName, `get id=${id}`))
|
||||
);
|
||||
const getUrl: string = id === null ? `${url}` : `${url}/${id}`;
|
||||
return <Observable<Product>>(
|
||||
this.http
|
||||
.get<Product>(getUrl)
|
||||
.pipe(catchError(this.log.handleError(serviceName, `get id=${id}`)))
|
||||
);
|
||||
}
|
||||
|
||||
list(): Observable<Product[]> {
|
||||
return <Observable<Product[]>>this.http.get<Product[]>(`${url}/list`)
|
||||
.pipe(
|
||||
catchError(this.log.handleError(serviceName, 'getList'))
|
||||
);
|
||||
return <Observable<Product[]>>(
|
||||
this.http
|
||||
.get<Product[]>(`${url}/list`)
|
||||
.pipe(catchError(this.log.handleError(serviceName, 'getList')))
|
||||
);
|
||||
}
|
||||
|
||||
save(product: Product): Observable<Product> {
|
||||
return <Observable<Product>>this.http.post<Product>(`${url}`, product, httpOptions)
|
||||
.pipe(
|
||||
catchError(this.log.handleError(serviceName, 'save'))
|
||||
);
|
||||
return <Observable<Product>>(
|
||||
this.http
|
||||
.post<Product>(`${url}`, product, httpOptions)
|
||||
.pipe(catchError(this.log.handleError(serviceName, 'save')))
|
||||
);
|
||||
}
|
||||
|
||||
update(product: Product): Observable<Product> {
|
||||
return <Observable<Product>>this.http.put<Product>(`${url}/${product.id}`, product, httpOptions)
|
||||
.pipe(
|
||||
catchError(this.log.handleError(serviceName, 'update'))
|
||||
);
|
||||
return <Observable<Product>>(
|
||||
this.http
|
||||
.put<Product>(`${url}/${product.id}`, product, httpOptions)
|
||||
.pipe(catchError(this.log.handleError(serviceName, 'update')))
|
||||
);
|
||||
}
|
||||
|
||||
saveOrUpdate(product: Product): Observable<Product> {
|
||||
@ -56,17 +58,19 @@ export class ProductService {
|
||||
}
|
||||
|
||||
delete(id: string): Observable<Product> {
|
||||
return <Observable<Product>>this.http.delete<Product>(`${url}/${id}`, httpOptions)
|
||||
.pipe(
|
||||
catchError(this.log.handleError(serviceName, 'delete'))
|
||||
);
|
||||
return <Observable<Product>>(
|
||||
this.http
|
||||
.delete<Product>(`${url}/${id}`, httpOptions)
|
||||
.pipe(catchError(this.log.handleError(serviceName, 'delete')))
|
||||
);
|
||||
}
|
||||
|
||||
autocomplete(query: string): Observable<Product[]> {
|
||||
const options = {params: new HttpParams().set('q', query)};
|
||||
return <Observable<Product[]>>this.http.get<Product[]>(`${url}/query`, options)
|
||||
.pipe(
|
||||
catchError(this.log.handleError(serviceName, 'autocomplete'))
|
||||
);
|
||||
const options = { params: new HttpParams().set('q', query) };
|
||||
return <Observable<Product[]>>(
|
||||
this.http
|
||||
.get<Product[]>(`${url}/query`, options)
|
||||
.pipe(catchError(this.log.handleError(serviceName, 'autocomplete')))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user