committed by
GitHub
48 changed files with 4353 additions and 1131 deletions
@ -0,0 +1,24 @@ |
|||||
|
# Catalog |
||||
|
|
||||
|
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 12.2.0. |
||||
|
|
||||
|
## Code scaffolding |
||||
|
|
||||
|
Run `ng generate component component-name --project catalog` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project catalog`. |
||||
|
> Note: Don't forget to add `--project catalog` or else it will be added to the default project in your `angular.json` file. |
||||
|
|
||||
|
## Build |
||||
|
|
||||
|
Run `ng build catalog` to build the project. The build artifacts will be stored in the `dist/` directory. |
||||
|
|
||||
|
## Publishing |
||||
|
|
||||
|
After building your library with `ng build catalog`, go to the dist folder `cd dist/catalog` and run `npm publish`. |
||||
|
|
||||
|
## Running unit tests |
||||
|
|
||||
|
Run `ng test catalog` to execute the unit tests via [Karma](https://karma-runner.github.io). |
||||
|
|
||||
|
## Further help |
||||
|
|
||||
|
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. |
||||
@ -0,0 +1,7 @@ |
|||||
|
{ |
||||
|
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json", |
||||
|
"dest": "../../dist/catalog/config", |
||||
|
"lib": { |
||||
|
"entryFile": "src/public-api.ts" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
import { ModuleWithProviders, NgModule } from '@angular/core'; |
||||
|
import { CATALOG_ROUTE_PROVIDERS } from './providers/route.provider'; |
||||
|
|
||||
|
@NgModule() |
||||
|
export class CatalogConfigModule { |
||||
|
static forRoot(): ModuleWithProviders<CatalogConfigModule> { |
||||
|
return { |
||||
|
ngModule: CatalogConfigModule, |
||||
|
providers: [CATALOG_ROUTE_PROVIDERS], |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,2 @@ |
|||||
|
export * from './policy-names'; |
||||
|
export * from './route-names'; |
||||
@ -0,0 +1,8 @@ |
|||||
|
export const enum eCatalogPolicyNames { |
||||
|
Catalog = 'CatalogService.Products', |
||||
|
ProductManagement = 'CatalogService.Products', |
||||
|
|
||||
|
ProductManagementCreate = 'CatalogService.Products.Create', |
||||
|
ProductManagementUpdate = 'CatalogService.Products.Update', |
||||
|
ProductManagementDelete = 'CatalogService.Products.Delete', |
||||
|
} |
||||
@ -0,0 +1,4 @@ |
|||||
|
export const enum eCatalogRouteNames { |
||||
|
Catalog = 'CatalogService::Menu:CatalogManagement', |
||||
|
Products = 'CatalogService::Menu:Products', |
||||
|
} |
||||
@ -0,0 +1 @@ |
|||||
|
export * from './route.provider'; |
||||
@ -0,0 +1,31 @@ |
|||||
|
import { eLayoutType, RoutesService } from '@abp/ng.core'; |
||||
|
import { APP_INITIALIZER } from '@angular/core'; |
||||
|
import { eCatalogPolicyNames } from '../enums/policy-names'; |
||||
|
import { eCatalogRouteNames } from '../enums/route-names'; |
||||
|
|
||||
|
export const CATALOG_ROUTE_PROVIDERS = [ |
||||
|
{ provide: APP_INITIALIZER, useFactory: configureRoutes, deps: [RoutesService], multi: true }, |
||||
|
]; |
||||
|
|
||||
|
export function configureRoutes(routesService: RoutesService) { |
||||
|
return () => { |
||||
|
routesService.add([ |
||||
|
{ |
||||
|
path: '/catalog', |
||||
|
name: eCatalogRouteNames.Catalog, |
||||
|
layout: eLayoutType.application, |
||||
|
parentName: null, |
||||
|
iconClass: 'bi bi-collection-fill', |
||||
|
requiredPolicy: eCatalogPolicyNames.Catalog, |
||||
|
}, |
||||
|
{ |
||||
|
path: '/catalog/products', |
||||
|
name: eCatalogRouteNames.Products, |
||||
|
parentName: eCatalogRouteNames.Catalog, |
||||
|
order: 1, |
||||
|
requiredPolicy: eCatalogPolicyNames.ProductManagement, |
||||
|
iconClass: 'bi bi-tag-fill', |
||||
|
}, |
||||
|
]); |
||||
|
}; |
||||
|
} |
||||
@ -0,0 +1,3 @@ |
|||||
|
export * from './catalog-config.module'; |
||||
|
export * from './enums'; |
||||
|
export * from './providers'; |
||||
@ -0,0 +1,44 @@ |
|||||
|
// Karma configuration file, see link for more information
|
||||
|
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||
|
|
||||
|
module.exports = function (config) { |
||||
|
config.set({ |
||||
|
basePath: '', |
||||
|
frameworks: ['jasmine', '@angular-devkit/build-angular'], |
||||
|
plugins: [ |
||||
|
require('karma-jasmine'), |
||||
|
require('karma-chrome-launcher'), |
||||
|
require('karma-jasmine-html-reporter'), |
||||
|
require('karma-coverage'), |
||||
|
require('@angular-devkit/build-angular/plugins/karma') |
||||
|
], |
||||
|
client: { |
||||
|
jasmine: { |
||||
|
// you can add configuration options for Jasmine here
|
||||
|
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
|
||||
|
// for example, you can disable the random execution with `random: false`
|
||||
|
// or set a specific seed with `seed: 4321`
|
||||
|
}, |
||||
|
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||
|
}, |
||||
|
jasmineHtmlReporter: { |
||||
|
suppressAll: true // removes the duplicated traces
|
||||
|
}, |
||||
|
coverageReporter: { |
||||
|
dir: require('path').join(__dirname, '../../coverage/catalog'), |
||||
|
subdir: '.', |
||||
|
reporters: [ |
||||
|
{ type: 'html' }, |
||||
|
{ type: 'text-summary' } |
||||
|
] |
||||
|
}, |
||||
|
reporters: ['progress', 'kjhtml'], |
||||
|
port: 9876, |
||||
|
colors: true, |
||||
|
logLevel: config.LOG_INFO, |
||||
|
autoWatch: true, |
||||
|
browsers: ['Chrome'], |
||||
|
singleRun: false, |
||||
|
restartOnFileChange: true |
||||
|
}); |
||||
|
}; |
||||
@ -0,0 +1,7 @@ |
|||||
|
{ |
||||
|
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json", |
||||
|
"dest": "../../dist/catalog", |
||||
|
"lib": { |
||||
|
"entryFile": "src/public-api.ts" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
{ |
||||
|
"name": "@eshoponabp/catalog", |
||||
|
"version": "0.0.1", |
||||
|
"peerDependencies": { |
||||
|
"@angular/common": "^12.2.0", |
||||
|
"@angular/core": "^12.2.0", |
||||
|
"@abp/ng.theme.shared": "~5.0.0-rc.2", |
||||
|
"@abp/ng.core": "~5.0.0-rc.2", |
||||
|
"@ngx-validate/core": "~0.1.1" |
||||
|
}, |
||||
|
"dependencies": { |
||||
|
"tslib": "^2.3.0" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
import { NgModule } from '@angular/core'; |
||||
|
import { RouterModule, Routes } from '@angular/router'; |
||||
|
|
||||
|
const routes: Routes = [ |
||||
|
{ path: '', redirectTo: 'products', pathMatch: 'full' }, |
||||
|
{ |
||||
|
path: 'products', |
||||
|
loadChildren: () => import('./pages/product/product.module').then(m => m.ProductModule), |
||||
|
}, |
||||
|
]; |
||||
|
|
||||
|
@NgModule({ |
||||
|
imports: [RouterModule.forChild(routes)], |
||||
|
exports: [RouterModule], |
||||
|
}) |
||||
|
export class CatalogRoutingModule {} |
||||
@ -0,0 +1,7 @@ |
|||||
|
import { NgModule } from '@angular/core'; |
||||
|
import { CatalogRoutingModule } from './catalog-routing.module'; |
||||
|
|
||||
|
@NgModule({ |
||||
|
imports: [CatalogRoutingModule], |
||||
|
}) |
||||
|
export class CatalogModule {} |
||||
@ -0,0 +1,17 @@ |
|||||
|
# Proxy Generation Output |
||||
|
|
||||
|
This directory includes the output of the latest proxy generation. |
||||
|
The files and folders in it will be overwritten when proxy generation is run again. |
||||
|
Therefore, please do not place your own content in this folder. |
||||
|
|
||||
|
In addition, `generate-proxy.json` works like a lock file. |
||||
|
It includes information used by the proxy generator, so please do not delete or modify it. |
||||
|
|
||||
|
Finally, the name of the files and folders should not be changed for two reasons: |
||||
|
- Proxy generator will keep creating them at those paths and you will have multiple copies of the same content. |
||||
|
- ABP Suite generates files which include imports from this folder. |
||||
|
|
||||
|
> **Important Notice:** If you are building a module and are planning to publish to npm, |
||||
|
> some of the generated proxies are likely to be exported from public-api.ts file. In such a case, |
||||
|
> please make sure you export files directly and not from barrel exports. In other words, |
||||
|
> do not include index.ts exports in your public-api.ts exports. |
||||
File diff suppressed because it is too large
@ -0,0 +1,2 @@ |
|||||
|
import * as Products from './products'; |
||||
|
export { Products }; |
||||
@ -0,0 +1,3 @@ |
|||||
|
export * from './models'; |
||||
|
export * from './product.service'; |
||||
|
export * from './public-product.service'; |
||||
@ -0,0 +1,24 @@ |
|||||
|
import type { AuditedEntityDto } from '@abp/ng.core'; |
||||
|
|
||||
|
export interface CreateProductDto { |
||||
|
code: string; |
||||
|
name: string; |
||||
|
imageName?: string; |
||||
|
price: number; |
||||
|
stockCount: number; |
||||
|
} |
||||
|
|
||||
|
export interface ProductDto extends AuditedEntityDto<string> { |
||||
|
code?: string; |
||||
|
name?: string; |
||||
|
imageName?: string; |
||||
|
price: number; |
||||
|
stockCount: number; |
||||
|
} |
||||
|
|
||||
|
export interface UpdateProductDto { |
||||
|
name: string; |
||||
|
imageName?: string; |
||||
|
price: number; |
||||
|
stockCount: number; |
||||
|
} |
||||
@ -0,0 +1,58 @@ |
|||||
|
import type { CreateProductDto, ProductDto, UpdateProductDto } from './models'; |
||||
|
import { RestService } from '@abp/ng.core'; |
||||
|
import type { ListResultDto, PagedAndSortedResultRequestDto, PagedResultDto } from '@abp/ng.core'; |
||||
|
import { Injectable } from '@angular/core'; |
||||
|
|
||||
|
@Injectable({ |
||||
|
providedIn: 'root', |
||||
|
}) |
||||
|
export class ProductService { |
||||
|
apiName = 'Catalog'; |
||||
|
|
||||
|
create = (input: CreateProductDto) => |
||||
|
this.restService.request<any, ProductDto>({ |
||||
|
method: 'POST', |
||||
|
url: '/api/catalog/product', |
||||
|
body: input, |
||||
|
}, |
||||
|
{ apiName: this.apiName }); |
||||
|
|
||||
|
delete = (id: string) => |
||||
|
this.restService.request<any, void>({ |
||||
|
method: 'DELETE', |
||||
|
url: `/api/catalog/product/${id}`, |
||||
|
}, |
||||
|
{ apiName: this.apiName }); |
||||
|
|
||||
|
get = (id: string) => |
||||
|
this.restService.request<any, ProductDto>({ |
||||
|
method: 'GET', |
||||
|
url: `/api/catalog/product/${id}`, |
||||
|
}, |
||||
|
{ apiName: this.apiName }); |
||||
|
|
||||
|
getList = () => |
||||
|
this.restService.request<any, ListResultDto<ProductDto>>({ |
||||
|
method: 'GET', |
||||
|
url: '/api/catalog/product', |
||||
|
}, |
||||
|
{ apiName: this.apiName }); |
||||
|
|
||||
|
getListPaged = (input: PagedAndSortedResultRequestDto) => |
||||
|
this.restService.request<any, PagedResultDto<ProductDto>>({ |
||||
|
method: 'GET', |
||||
|
url: '/api/catalog/product/paged', |
||||
|
params: { sorting: input.sorting, skipCount: input.skipCount, maxResultCount: input.maxResultCount }, |
||||
|
}, |
||||
|
{ apiName: this.apiName }); |
||||
|
|
||||
|
update = (id: string, input: UpdateProductDto) => |
||||
|
this.restService.request<any, ProductDto>({ |
||||
|
method: 'PUT', |
||||
|
url: `/api/catalog/product/${id}`, |
||||
|
body: input, |
||||
|
}, |
||||
|
{ apiName: this.apiName }); |
||||
|
|
||||
|
constructor(private restService: RestService) {} |
||||
|
} |
||||
@ -0,0 +1,27 @@ |
|||||
|
import type { ProductDto } from './models'; |
||||
|
import { RestService } from '@abp/ng.core'; |
||||
|
import type { ListResultDto } from '@abp/ng.core'; |
||||
|
import { Injectable } from '@angular/core'; |
||||
|
|
||||
|
@Injectable({ |
||||
|
providedIn: 'root', |
||||
|
}) |
||||
|
export class PublicProductService { |
||||
|
apiName = 'Catalog'; |
||||
|
|
||||
|
get = (id: string) => |
||||
|
this.restService.request<any, ProductDto>({ |
||||
|
method: 'GET', |
||||
|
url: `/api/catalog/public-product/${id}`, |
||||
|
}, |
||||
|
{ apiName: this.apiName }); |
||||
|
|
||||
|
getList = () => |
||||
|
this.restService.request<any, ListResultDto<ProductDto>>({ |
||||
|
method: 'GET', |
||||
|
url: '/api/catalog/public-product', |
||||
|
}, |
||||
|
{ apiName: this.apiName }); |
||||
|
|
||||
|
constructor(private restService: RestService) {} |
||||
|
} |
||||
@ -0,0 +1 @@ |
|||||
|
export * from './product'; |
||||
@ -0,0 +1,3 @@ |
|||||
|
export * from './product-routing.module'; |
||||
|
export * from './product.component'; |
||||
|
export * from './product.module'; |
||||
@ -0,0 +1,22 @@ |
|||||
|
import { AuthGuard, PermissionGuard } from '@abp/ng.core'; |
||||
|
import { NgModule } from '@angular/core'; |
||||
|
import { RouterModule, Routes } from '@angular/router'; |
||||
|
import { eCatalogPolicyNames } from '@eshoponabp/catalog/config'; |
||||
|
import { ProductComponent } from './product.component'; |
||||
|
|
||||
|
const routes: Routes = [ |
||||
|
{ |
||||
|
path: '', |
||||
|
component: ProductComponent, |
||||
|
canActivate: [AuthGuard, PermissionGuard], |
||||
|
data: { |
||||
|
requiredPolicy: eCatalogPolicyNames.ProductManagement, |
||||
|
}, |
||||
|
}, |
||||
|
]; |
||||
|
|
||||
|
@NgModule({ |
||||
|
imports: [RouterModule.forChild(routes)], |
||||
|
exports: [RouterModule], |
||||
|
}) |
||||
|
export class ProductRoutingModule {} |
||||
@ -0,0 +1,167 @@ |
|||||
|
<div class="card"> |
||||
|
<div class="card-header"> |
||||
|
<div class="row"> |
||||
|
<div class="col col-md-6"> |
||||
|
<h5 class="card-title">{{ 'CatalogService::Products' | abpLocalization }}</h5> |
||||
|
</div> |
||||
|
<div class="text-right col col-md-6"> |
||||
|
<button class="btn btn-primary" (click)="onCreate()" *abpPermission="permissions.create"> |
||||
|
{{ 'CatalogService::NewProduct' | abpLocalization }} |
||||
|
</button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="card-body"> |
||||
|
<ngx-datatable [rows]="items" [count]="count" [list]="list" default> |
||||
|
<ngx-datatable-column |
||||
|
[name]="'AbpUi::Actions' | abpLocalization" |
||||
|
[sortable]="false" |
||||
|
*abpPermission="permissions.update + ' || ' + permissions.delete" |
||||
|
> |
||||
|
<ng-template let-row="row" ngx-datatable-cell-template> |
||||
|
<div ngbDropdown container="body" class="d-inline-block"> |
||||
|
<button |
||||
|
class="btn btn-primary btn-sm dropdown-toggle" |
||||
|
data-toggle="dropdown" |
||||
|
aria-haspopup="true" |
||||
|
ngbDropdownToggle |
||||
|
> |
||||
|
<i class="mr-1 fa fa-cog"></i>{{ 'AbpUi::Actions' | abpLocalization }} |
||||
|
</button> |
||||
|
<div ngbDropdownMenu> |
||||
|
<button |
||||
|
class="dropdown-item" |
||||
|
(click)="onEdit(row)" |
||||
|
*abpPermission="permissions.update" |
||||
|
> |
||||
|
{{ 'AbpUi::Edit' | abpLocalization }} |
||||
|
</button> |
||||
|
<button |
||||
|
class="dropdown-item" |
||||
|
(click)="onDelete(row)" |
||||
|
*abpPermission="permissions.delete" |
||||
|
> |
||||
|
{{ 'AbpUi::Delete' | abpLocalization }} |
||||
|
</button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</ng-template> |
||||
|
</ngx-datatable-column> |
||||
|
<ngx-datatable-column |
||||
|
[name]="'CatalogService::DisplayName:Code' | abpLocalization" |
||||
|
prop="code" |
||||
|
></ngx-datatable-column> |
||||
|
<ngx-datatable-column |
||||
|
[name]="'CatalogService::DisplayName:Name' | abpLocalization" |
||||
|
prop="name" |
||||
|
></ngx-datatable-column> |
||||
|
<ngx-datatable-column |
||||
|
[name]="'CatalogService::DisplayName:ImageName' | abpLocalization" |
||||
|
prop="imageName" |
||||
|
></ngx-datatable-column> |
||||
|
<ngx-datatable-column |
||||
|
[name]="'CatalogService::DisplayName:Price' | abpLocalization" |
||||
|
prop="price" |
||||
|
></ngx-datatable-column> |
||||
|
<ngx-datatable-column |
||||
|
[name]="'CatalogService::DisplayName:StockCount' | abpLocalization" |
||||
|
prop="stockCount" |
||||
|
></ngx-datatable-column> |
||||
|
</ngx-datatable> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<abp-modal [(visible)]="isModalVisible" [busy]="modalBusy"> |
||||
|
<ng-template #abpHeader> |
||||
|
<h3> |
||||
|
{{ (selected?.id ? 'AbpUi::Edit' : 'CatalogService::NewProduct') | abpLocalization }} |
||||
|
</h3> |
||||
|
</ng-template> |
||||
|
|
||||
|
<ng-template #abpBody> |
||||
|
<ng-template #loaderRef |
||||
|
><div class="text-center"><i class="fa fa-pulse fa-spinner"></i></div |
||||
|
></ng-template> |
||||
|
|
||||
|
<form *ngIf="form; else loaderRef" [formGroup]="form" (ngSubmit)="save()"> |
||||
|
<div class="mb-3"> |
||||
|
<label class="form-label" for="code"> |
||||
|
{{ 'CatalogService::DisplayName:Code' | abpLocalization }} * |
||||
|
</label> |
||||
|
<input |
||||
|
type="text" |
||||
|
class="form-control" |
||||
|
id="code" |
||||
|
formControlName="code" |
||||
|
[readonly]="selected?.id" |
||||
|
[placeholder]="'CatalogService::DisplayName:Code' | abpLocalization" |
||||
|
/> |
||||
|
</div> |
||||
|
|
||||
|
<div class="mb-3"> |
||||
|
<label class="form-label" for="name"> |
||||
|
{{ 'CatalogService::DisplayName:Name' | abpLocalization }} * |
||||
|
</label> |
||||
|
<input |
||||
|
type="text" |
||||
|
class="form-control" |
||||
|
id="name" |
||||
|
formControlName="name" |
||||
|
[placeholder]="'CatalogService::DisplayName:Name' | abpLocalization" |
||||
|
/> |
||||
|
</div> |
||||
|
|
||||
|
<div class="mb-3"> |
||||
|
<label class="form-label" for="imageName"> |
||||
|
{{ 'CatalogService::DisplayName:ImageName' | abpLocalization }} * |
||||
|
</label> |
||||
|
<input |
||||
|
type="text" |
||||
|
class="form-control" |
||||
|
id="imageName" |
||||
|
formControlName="imageName" |
||||
|
[placeholder]="'CatalogService::DisplayName:ImageName' | abpLocalization" |
||||
|
/> |
||||
|
</div> |
||||
|
|
||||
|
<div class="mb-3"> |
||||
|
<label class="form-label" for="price"> |
||||
|
{{ 'CatalogService::DisplayName:Price' | abpLocalization }} * |
||||
|
</label> |
||||
|
<input |
||||
|
type="number" |
||||
|
class="form-control" |
||||
|
id="price" |
||||
|
formControlName="price" |
||||
|
[placeholder]="'CatalogService::DisplayName:Price' | abpLocalization" |
||||
|
/> |
||||
|
</div> |
||||
|
|
||||
|
<div class="mb-3"> |
||||
|
<label class="form-label" for="stockCount"> |
||||
|
{{ 'CatalogService::DisplayName:StockCount' | abpLocalization }} * |
||||
|
</label> |
||||
|
<input |
||||
|
type="number" |
||||
|
class="form-control" |
||||
|
id="stockCount" |
||||
|
formControlName="stockCount" |
||||
|
[placeholder]="'CatalogService::DisplayName:StockCount' | abpLocalization" |
||||
|
/> |
||||
|
</div> |
||||
|
</form> |
||||
|
|
||||
|
<ng-template #loaderRef |
||||
|
><div class="text-center"><i class="fa fa-pulse fa-spinner"></i></div |
||||
|
></ng-template> |
||||
|
</ng-template> |
||||
|
|
||||
|
<ng-template #abpFooter> |
||||
|
<button type="button" class="btn btn-secondary" abpClose> |
||||
|
{{ 'AbpUi::Cancel' | abpLocalization }} |
||||
|
</button> |
||||
|
<abp-button iconClass="fa fa-check" [disabled]="form?.invalid" (click)="save()">{{ |
||||
|
'AbpUi::Save' | abpLocalization |
||||
|
}}</abp-button> |
||||
|
</ng-template> |
||||
|
</abp-modal> |
||||
@ -0,0 +1,106 @@ |
|||||
|
import { ListService } from '@abp/ng.core'; |
||||
|
import { Confirmation, ConfirmationService } from '@abp/ng.theme.shared'; |
||||
|
import { Component, OnInit } from '@angular/core'; |
||||
|
import { FormBuilder, FormGroup, Validators } from '@angular/forms'; |
||||
|
import { eCatalogPolicyNames } from '@eshoponabp/catalog/config'; |
||||
|
import { finalize } from 'rxjs/operators'; |
||||
|
import { ProductDto } from '../../lib/proxy/products/models'; |
||||
|
import { ProductService } from '../../lib/proxy/products/product.service'; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'lib-product', |
||||
|
templateUrl: './product.component.html', |
||||
|
styleUrls: ['./product.component.css'], |
||||
|
providers: [ListService], |
||||
|
}) |
||||
|
export class ProductComponent implements OnInit { |
||||
|
permissions = { |
||||
|
create: eCatalogPolicyNames.ProductManagementCreate, |
||||
|
update: eCatalogPolicyNames.ProductManagementUpdate, |
||||
|
delete: eCatalogPolicyNames.ProductManagementDelete, |
||||
|
}; |
||||
|
|
||||
|
items: ProductDto[] = []; |
||||
|
count = 0; |
||||
|
|
||||
|
selected: ProductDto; |
||||
|
|
||||
|
isModalVisible: boolean; |
||||
|
|
||||
|
modalBusy = false; |
||||
|
|
||||
|
form: FormGroup; |
||||
|
constructor( |
||||
|
public readonly list: ListService, |
||||
|
private readonly service: ProductService, |
||||
|
private confirmationService: ConfirmationService, |
||||
|
private fb: FormBuilder |
||||
|
) { |
||||
|
this.list.maxResultCount = 10; |
||||
|
} |
||||
|
|
||||
|
ngOnInit(): void { |
||||
|
const productStreamCreator = query => this.service.getListPaged(query); |
||||
|
|
||||
|
this.list.hookToQuery(productStreamCreator).subscribe(response => { |
||||
|
this.items = response.items; |
||||
|
this.count = response.totalCount; |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
buildForm() { |
||||
|
this.form = this.fb.group({ |
||||
|
name: [this.selected.name, { validators: [Validators.required] }], |
||||
|
code: [this.selected.code, { validators: [Validators.required] }], |
||||
|
imageName: [this.selected.imageName, { validators: [Validators.required] }], |
||||
|
price: [this.selected.price, { validators: [Validators.required] }], |
||||
|
stockCount: [this.selected.stockCount, { validators: [Validators.required] }], |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
onEdit(product: ProductDto) { |
||||
|
this.selected = product; |
||||
|
this.openModal(); |
||||
|
} |
||||
|
|
||||
|
onCreate() { |
||||
|
this.selected = {} as ProductDto; |
||||
|
this.openModal(); |
||||
|
} |
||||
|
|
||||
|
openModal() { |
||||
|
this.isModalVisible = true; |
||||
|
this.buildForm(); |
||||
|
} |
||||
|
|
||||
|
onDelete(product: ProductDto) { |
||||
|
this.confirmationService |
||||
|
.warn('CatalogService::ProductDeletionConfirmationMessage', 'AbpUi::AreYouSure', { |
||||
|
messageLocalizationParams: [product.name], |
||||
|
}) |
||||
|
.subscribe((status: Confirmation.Status) => { |
||||
|
if (status === Confirmation.Status.confirm) { |
||||
|
this.service.delete(product.id).subscribe(() => this.list.get()); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
save() { |
||||
|
if (!this.form.valid || this.modalBusy) return; |
||||
|
this.modalBusy = true; |
||||
|
|
||||
|
const { id } = this.selected; |
||||
|
(id |
||||
|
? this.service.update(id, { |
||||
|
...this.selected, |
||||
|
...this.form.value, |
||||
|
}) |
||||
|
: this.service.create({ ...this.form.value }) |
||||
|
) |
||||
|
.pipe(finalize(() => (this.modalBusy = false))) |
||||
|
.subscribe(() => { |
||||
|
this.isModalVisible = false; |
||||
|
this.list.get(); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,21 @@ |
|||||
|
import { CoreModule } from '@abp/ng.core'; |
||||
|
import { ThemeSharedModule } from '@abp/ng.theme.shared'; |
||||
|
import { CommonModule } from '@angular/common'; |
||||
|
import { NgModule } from '@angular/core'; |
||||
|
import { NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap'; |
||||
|
import { NgxValidateCoreModule } from '@ngx-validate/core'; |
||||
|
import { ProductRoutingModule } from './product-routing.module'; |
||||
|
import { ProductComponent } from './product.component'; |
||||
|
|
||||
|
@NgModule({ |
||||
|
declarations: [ProductComponent], |
||||
|
imports: [ |
||||
|
CommonModule, |
||||
|
ProductRoutingModule, |
||||
|
ThemeSharedModule, |
||||
|
CoreModule, |
||||
|
NgbDropdownModule, |
||||
|
NgxValidateCoreModule, |
||||
|
], |
||||
|
}) |
||||
|
export class ProductModule {} |
||||
@ -0,0 +1,4 @@ |
|||||
|
export * from './catalog-routing.module'; |
||||
|
export * from './catalog.module'; |
||||
|
export * from './lib/proxy/products'; |
||||
|
export * from './pages'; |
||||
@ -0,0 +1,28 @@ |
|||||
|
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||
|
|
||||
|
import 'zone.js'; |
||||
|
import 'zone.js/testing'; |
||||
|
import { getTestBed } from '@angular/core/testing'; |
||||
|
import { |
||||
|
BrowserDynamicTestingModule, |
||||
|
platformBrowserDynamicTesting |
||||
|
} from '@angular/platform-browser-dynamic/testing'; |
||||
|
|
||||
|
declare const require: { |
||||
|
context(path: string, deep?: boolean, filter?: RegExp): { |
||||
|
keys(): string[]; |
||||
|
<T>(id: string): T; |
||||
|
}; |
||||
|
}; |
||||
|
|
||||
|
// First, initialize the Angular testing environment.
|
||||
|
getTestBed().initTestEnvironment( |
||||
|
BrowserDynamicTestingModule, |
||||
|
platformBrowserDynamicTesting(), |
||||
|
{ teardown: { destroyAfterEach: true }}, |
||||
|
); |
||||
|
|
||||
|
// Then we find all the tests.
|
||||
|
const context = require.context('./', true, /\.spec\.ts$/); |
||||
|
// And load the modules.
|
||||
|
context.keys().map(context); |
||||
@ -0,0 +1,20 @@ |
|||||
|
/* To learn more about this file see: https://angular.io/config/tsconfig. */ |
||||
|
{ |
||||
|
"extends": "../../tsconfig.json", |
||||
|
"compilerOptions": { |
||||
|
"outDir": "../../out-tsc/lib", |
||||
|
"target": "es2015", |
||||
|
"declaration": true, |
||||
|
"declarationMap": true, |
||||
|
"inlineSources": true, |
||||
|
"types": [], |
||||
|
"lib": [ |
||||
|
"dom", |
||||
|
"es2018" |
||||
|
] |
||||
|
}, |
||||
|
"exclude": [ |
||||
|
"src/test.ts", |
||||
|
"**/*.spec.ts" |
||||
|
] |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
/* To learn more about this file see: https://angular.io/config/tsconfig. */ |
||||
|
{ |
||||
|
"extends": "./tsconfig.lib.json", |
||||
|
"compilerOptions": { |
||||
|
"declarationMap": false |
||||
|
}, |
||||
|
"angularCompilerOptions": { |
||||
|
"compilationMode": "partial" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
/* To learn more about this file see: https://angular.io/config/tsconfig. */ |
||||
|
{ |
||||
|
"extends": "../../tsconfig.json", |
||||
|
"compilerOptions": { |
||||
|
"outDir": "../../out-tsc/spec", |
||||
|
"types": [ |
||||
|
"jasmine" |
||||
|
] |
||||
|
}, |
||||
|
"files": [ |
||||
|
"src/test.ts" |
||||
|
], |
||||
|
"include": [ |
||||
|
"**/*.spec.ts", |
||||
|
"**/*.d.ts" |
||||
|
] |
||||
|
} |
||||
File diff suppressed because it is too large
@ -0,0 +1,5 @@ |
|||||
|
{ |
||||
|
"dependencies": { |
||||
|
"@ngxs/store": "^3.7.3" |
||||
|
} |
||||
|
} |
||||
@ -1,6 +1,21 @@ |
|||||
{ |
{ |
||||
"culture": "tr", |
"culture": "tr", |
||||
"texts": { |
"texts": { |
||||
"CatalogService:000001": "{productCode} kodlu bir ürün zaten var!" |
"CatalogService:000001": "{productCode} kodlu bir ürün zaten var!", |
||||
|
"Permission:GroupName": "Katalog", |
||||
|
"Permission:Products": "Ürünler", |
||||
|
"Permission:Products.Edit": "Düzenleme", |
||||
|
"Permission:Products.Delete": "Silme", |
||||
|
"Permission:Products.Create": "Oluşturma", |
||||
|
"Menu:CatalogManagement": "Katalog Yönetimi", |
||||
|
"Menu:Products": "Ürünler", |
||||
|
"NewProduct": "Yeni Ürün", |
||||
|
"Products": "Ürünler", |
||||
|
"DisplayName:Name": "İsim", |
||||
|
"DisplayName:Code": "Kod", |
||||
|
"DisplayName:ImageName": "Resim Adı", |
||||
|
"DisplayName:Price": "Fiyat", |
||||
|
"DisplayName:StockCount": "Stok Adedi", |
||||
|
"ProductDeletionConfirmationMessage": "{0} ürününü silmek istediğinizden emin misiniz?" |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,15 @@ |
|||||
|
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. |
||||
|
# yarn lockfile v1 |
||||
|
|
||||
|
|
||||
|
"@ngxs/store@^3.7.3": |
||||
|
version "3.7.3" |
||||
|
resolved "https://registry.yarnpkg.com/@ngxs/store/-/store-3.7.3.tgz#74e2878d527fc12dace343ce43fd79fa1a2645af" |
||||
|
integrity sha512-JjATXC7FsxxQu2SaayP/iLe4O+5/RkRov3/J7WkaQmV6/JWFNkkdOwbEa6pDbh/po0JO7DHHMk3huIUNpDu67g== |
||||
|
dependencies: |
||||
|
tslib "^1.9.0" |
||||
|
|
||||
|
tslib@^1.9.0: |
||||
|
version "1.14.1" |
||||
|
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" |
||||
|
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== |
||||
Loading…
Reference in new issue