Merged PR 1277: #3149 Process Change and Caching

#3149 Process Change and Caching
This commit is contained in:
Lorenz Hilpert
2022-06-20 15:39:00 +00:00
committed by Nino Righi
parent 70a4451f90
commit 0a25eeadbe
6 changed files with 104 additions and 72 deletions

View File

@@ -91,7 +91,7 @@ export class GoodsOutSearchFilterComponent implements OnInit, OnDestroy {
}
});
this._goodsOutSearchStore.search();
this._goodsOutSearchStore.search({});
}
async updateBreadcrumb() {

View File

@@ -55,15 +55,15 @@ export class GoodsOutSearchComponent implements OnInit, OnDestroy {
ngOnInit() {
this._goodsOutSearchStore.loadSettings();
this._activatedRoute.queryParams.pipe(takeUntil(this._onDestroy$)).subscribe((params) => {
// Reset Filter when query params are empty
this.processId$.pipe(takeUntil(this._onDestroy$), withLatestFrom(this._activatedRoute.queryParams)).subscribe(([processId, params]) => {
if (params && Object.keys(params).length === 0) {
this._goodsOutSearchStore.setQueryParams(params);
this._goodsOutSearchStore.loadSettings();
} else {
// this._goodsOutSearchStore.resetFilter(params);
}
});
this.processId$.pipe(takeUntil(this._onDestroy$)).subscribe((processId) => {
this._breadcrumb.addOrUpdateBreadcrumbIfNotExists({
key: processId,
name: 'Warenausgabe',

View File

@@ -1,11 +1,12 @@
import { HttpErrorResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { CacheService } from '@core/cache';
import { DomainGoodsService } from '@domain/oms';
import { ComponentStore, tapResponse } from '@ngrx/component-store';
import { ListResponseArgsOfOrderItemListItemDTO, OrderItemListItemDTO, QuerySettingsDTO } from '@swagger/oms';
import { UiFilter } from '@ui/filter';
import { isResponseArgs } from '@utils/object';
import { Subject } from 'rxjs';
import { Observable, Subject } from 'rxjs';
import { switchMap, mergeMap, withLatestFrom, filter, take, tap } from 'rxjs/operators';
export interface GoodsOutSearchState {
@@ -72,7 +73,7 @@ export class GoodsOutSearchStore extends ComponentStore<GoodsOutSearchState> {
readonly searchResultCleared = this._searchResultClearedSubject.asObservable();
constructor(private _domainGoodsInService: DomainGoodsService) {
constructor(private _domainGoodsInService: DomainGoodsService, private _cache: CacheService) {
super({
fetching: false,
hits: 0,
@@ -142,29 +143,46 @@ export class GoodsOutSearchStore extends ComponentStore<GoodsOutSearchState> {
}
}
searchRequest(options?: { take?: number; skip?: number }) {
searchRequest(options?: { take?: number; skip?: number; reload?: boolean }) {
return this.filter$.pipe(
filter((f) => f instanceof UiFilter),
take(1),
mergeMap((filter) =>
this._domainGoodsInService.searchWarenausgabe({
...filter.getQueryToken(),
skip: options?.skip ?? this.results.length,
take: options?.take ?? 50,
skip: options.reload ? 0 : options?.skip ?? this.results.length,
take: options.reload ? this.results.length : options?.take ?? 50,
})
)
);
}
search = this.effect(($) =>
$.pipe(
tap((_) => this.patchState({ fetching: true })),
search = this.effect((options$: Observable<{ siletReload?: boolean }>) =>
options$.pipe(
tap((options) => {
if (options.siletReload) {
this.patchState({ fetching: true });
}
}),
withLatestFrom(this.results$),
switchMap(([_, _results]) =>
this.searchRequest(this.searchOptions).pipe(
switchMap(([_options, _results]) => {
const queryToken = this.filter?.getQueryToken();
if (queryToken && this._cache.get(queryToken)) {
const cached = this._cache.get(queryToken);
this.patchState(cached);
}
return this.searchRequest({ ...this.searchOptions, reload: _options.siletReload }).pipe(
tapResponse(
(res) => {
const results = [...(_results ?? []), ...(res.result ?? [])];
let results: OrderItemListItemDTO[] = [];
if (_options.siletReload) {
results = res.result;
} else {
results = [...(_results ?? []), ...(res.result ?? [])];
}
this.patchState({
hits: res.hits,
@@ -172,6 +190,14 @@ export class GoodsOutSearchStore extends ComponentStore<GoodsOutSearchState> {
fetching: false,
});
if (queryToken) {
this._cache.set(queryToken, {
hits: res.hits,
results,
fetching: false,
});
}
this._searchResultSubject.next(res);
},
(err: Error) => {
@@ -187,8 +213,8 @@ export class GoodsOutSearchStore extends ComponentStore<GoodsOutSearchState> {
console.error('GoodsInSearchStore.search()', err);
}
)
)
)
);
})
)
);

View File

@@ -99,7 +99,7 @@ export class GoodsOutSearchMainComponent implements OnInit, OnDestroy {
this._cdr.markForCheck();
});
this._goodsOutSearchStore.search();
this._goodsOutSearchStore.search({});
}
async updateBreadcrumb(processId: number) {

View File

@@ -6,30 +6,32 @@
[deltaEnd]="150"
[itemLength]="itemLength$ | async"
>
<shared-goods-in-out-order-group *ngFor="let bueryNumberGroup of items$ | async | groupBy: byBuyerNumberFn">
<ng-container *ngFor="let orderNumberGroup of bueryNumberGroup.items | groupBy: byOrderNumberFn; let lastOrderNumber = last">
<ng-container
*ngFor="let processingStatusGroup of orderNumberGroup.items | groupBy: byProcessingStatusFn; let lastProcessingStatus = last"
>
<ng-container *ngIf="processId$ | async; let processId">
<shared-goods-in-out-order-group *ngFor="let bueryNumberGroup of items$ | async | groupBy: byBuyerNumberFn">
<ng-container *ngFor="let orderNumberGroup of bueryNumberGroup.items | groupBy: byOrderNumberFn; let lastOrderNumber = last">
<ng-container
*ngFor="let compartmentCodeGroup of processingStatusGroup.items | groupBy: byCompartmentCodeFn; let lastCompartmentCode = last"
*ngFor="let processingStatusGroup of orderNumberGroup.items | groupBy: byProcessingStatusFn; let lastProcessingStatus = last"
>
<shared-goods-in-out-order-group-item
*ngFor="let item of compartmentCodeGroup.items; let firstItem = first"
[item]="item"
[showCompartmentCode]="firstItem"
(click)="navigateToDetails(item)"
[selectable]="item | goodsOutItemSelectable: selectionRules:selectedItems"
[selected]="item | goodsOutItemSelected: selectedOrderItemSubsetIds"
(selectedChange)="setSelectedItem(item, $event)"
></shared-goods-in-out-order-group-item>
<div class="divider" *ngIf="!lastCompartmentCode"></div>
<ng-container
*ngFor="let compartmentCodeGroup of processingStatusGroup.items | groupBy: byCompartmentCodeFn; let lastCompartmentCode = last"
>
<shared-goods-in-out-order-group-item
*ngFor="let item of compartmentCodeGroup.items; let firstItem = first; trackBy: trackByFn"
[item]="item"
[showCompartmentCode]="firstItem"
(click)="navigateToDetails(processId, item)"
[selectable]="item | goodsOutItemSelectable: selectionRules:selectedItems"
[selected]="item | goodsOutItemSelected: selectedOrderItemSubsetIds"
(selectedChange)="setSelectedItem(item, $event)"
></shared-goods-in-out-order-group-item>
<div class="divider" *ngIf="!lastCompartmentCode"></div>
</ng-container>
<div class="divider" *ngIf="!lastProcessingStatus"></div>
</ng-container>
<div class="divider" *ngIf="!lastProcessingStatus"></div>
<div class="divider" *ngIf="!lastOrderNumber"></div>
</ng-container>
<div class="divider" *ngIf="!lastOrderNumber"></div>
</ng-container>
</shared-goods-in-out-order-group>
</shared-goods-in-out-order-group>
</ng-container>
</ui-scroll-container>
<ng-template #emptyMessage>

View File

@@ -1,5 +1,5 @@
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy, ViewChild } from '@angular/core';
import { first, map, shareReplay, takeUntil } from 'rxjs/operators';
import { debounceTime, first, map, shareReplay, takeUntil, withLatestFrom } from 'rxjs/operators';
import { KeyValueDTOOfStringAndString, OrderItemListItemDTO } from '@swagger/oms';
import { ActivatedRoute, Router } from '@angular/router';
import { GoodsOutSearchStore } from '../goods-out-search.store';
@@ -10,7 +10,6 @@ import { CommandService } from '@core/command';
import { OrderItemsContext } from '@domain/oms';
import { UiErrorModalComponent, UiModalService } from '@ui/modal';
import { UiScrollContainerComponent } from '@ui/scroll-container';
import { Config } from '@core/config';
export interface GoodsOutSearchResultsState {
selectedOrderItemSubsetIds: number[];
@@ -67,14 +66,12 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
byCompartmentCodeFn = (item: OrderItemListItemDTO) => item.compartmentCode;
get processId() {
return +this._activatedRoute.snapshot.parent.data.processId;
}
processId$ = this._activatedRoute.parent.data.pipe(map((data) => +data.processId));
private _onDestroy$ = new Subject();
trackByFn = (item: OrderItemListItemDTO) => `${item.orderId}${item.orderItemId}${item.orderItemSubsetId}`;
constructor(
private _goodsOutSearchStore: GoodsOutSearchStore,
private _router: Router,
@@ -89,16 +86,22 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
}
ngOnInit() {
this.processId$.pipe(takeUntil(this._onDestroy$)).subscribe((processId) => {
this._goodsOutSearchStore.setQueryParams(this._activatedRoute.snapshot.queryParams);
this._activatedRoute.queryParams.pipe(takeUntil(this._onDestroy$)).subscribe((queryParams) => {
this.updateBreadcrumb(queryParams);
});
this.processId$
.pipe(takeUntil(this._onDestroy$), debounceTime(1), withLatestFrom(this._activatedRoute.queryParams))
.subscribe(([processId, params]) => {
console.log('processId', processId);
console.log('params', params);
this.initInitialSearch(processId);
this.createBreadcrumb(processId);
this.removeBreadcrumbs(processId);
});
this._goodsOutSearchStore.setQueryParams(params);
this.updateBreadcrumb(processId, params);
this.initInitialSearch(processId, params);
this.createBreadcrumb(processId, params);
this.removeBreadcrumbs(processId);
this._goodsOutSearchStore.clearResults();
this._goodsOutSearchStore.search({ siletReload: true });
});
this._goodsOutSearchStore.searchResultCleared.pipe(takeUntil(this._onDestroy$)).subscribe((_) => this.clearSelectedItems());
}
@@ -107,10 +110,10 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
this._onDestroy$.next();
this._onDestroy$.complete();
this.updateBreadcrumb(this._goodsOutSearchStore.filter?.getQueryParams());
// this.updateBreadcrumb(this._goodsOutSearchStore.filter?.getQueryParams());
}
async removeBreadcrumbs(processId) {
async removeBreadcrumbs(processId: number) {
const detailsCrumbs = await this._breadcrumb.getBreadcrumbsByKeyAndTags$(processId, ['goods-out', 'details']).pipe(first()).toPromise();
const editCrumbs = await this._breadcrumb.getBreadcrumbsByKeyAndTags$(processId, ['goods-out', 'edit']).pipe(first()).toPromise();
@@ -124,24 +127,24 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
});
}
async createBreadcrumb(processId: number) {
async createBreadcrumb(processId: number, params: Record<string, string>) {
await this._breadcrumb.addOrUpdateBreadcrumbIfNotExists({
key: processId,
name: this.getBreadcrumbName(),
name: this.getBreadcrumbName(params),
path: `/kunde/${processId}/goods/out/results`,
section: 'customer',
params: this._goodsOutSearchStore.filter?.getQueryParams(),
params,
tags: ['goods-out', 'results', 'filter'],
});
}
async updateBreadcrumb(queryParams: Record<string, string> = this._goodsOutSearchStore.filter?.getQueryParams()) {
async updateBreadcrumb(processId: number, queryParams: Record<string, string>) {
const scroll_position = this.scrollContainer?.scrollPos;
const take = this._goodsOutSearchStore.results?.length;
if (queryParams) {
const crumbs = await this._breadcrumb
.getBreadcrumbsByKeyAndTags$(this.processId, ['goods-out', 'results', 'filter'])
.getBreadcrumbsByKeyAndTags$(processId, ['goods-out', 'results', 'filter'])
.pipe(first())
.toPromise();
@@ -157,23 +160,23 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
}
}
getBreadcrumbName() {
const input = this._goodsOutSearchStore.filter?.getQueryParams()?.main_qs;
getBreadcrumbName(params: Record<string, string>) {
const input = params?.main_qs;
return input?.replace('ORD:', '') ?? 'Alle';
}
initInitialSearch(processId: number) {
initInitialSearch(processId: number, params: Record<string, string>) {
if (this._goodsOutSearchStore.hits === 0) {
this._goodsOutSearchStore.searchResult$.pipe(takeUntil(this._onDestroy$)).subscribe(async (result) => {
if (result.hits === 0) {
await this._router.navigate([`/kunde/${this.processId}/goods/out`], {
await this._router.navigate([`/kunde/${processId}/goods/out`], {
queryParams: this._goodsOutSearchStore.filter.getQueryParams(),
});
} else {
await this.createBreadcrumb(processId);
await this.createBreadcrumb(processId, params);
if (result.hits === 1) {
await this.navigateToDetails(result.result[0]);
await this.navigateToDetails(processId, result.result[0]);
} else {
if (!!this._goodsOutSearchStore.searchOptions?.take) {
this._goodsOutSearchStore.searchOptions = undefined;
@@ -182,7 +185,7 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
}
}
});
this._goodsOutSearchStore.search();
this._goodsOutSearchStore.search({});
}
const { scroll_position, take } = this._goodsOutSearchStore.queryParams;
@@ -193,21 +196,22 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
async loadMore() {
if (this._goodsOutSearchStore.hits > this._goodsOutSearchStore.results.length && !this._goodsOutSearchStore.fetching) {
this._goodsOutSearchStore.search();
this._goodsOutSearchStore.search({});
}
}
navigateToDetails(orderItem: OrderItemListItemDTO) {
navigateToDetails(processId: number, orderItem: OrderItemListItemDTO) {
console.log('navigateToDetails', orderItem);
const orderNumber = orderItem.orderNumber;
const processingStatus = orderItem.processingStatus;
const compartmentCode = orderItem.compartmentCode;
if (compartmentCode) {
this._router.navigate([
`/kunde/${this.processId}/goods/out/details/compartment/${encodeURIComponent(compartmentCode)}/${processingStatus}`,
`/kunde/${processId}/goods/out/details/compartment/${encodeURIComponent(compartmentCode)}/${processingStatus}`,
]);
} else {
this._router.navigate([`/kunde/${this.processId}/goods/out/details/order/${encodeURIComponent(orderNumber)}/${processingStatus}`]);
this._router.navigate([`/kunde/${processId}/goods/out/details/order/${encodeURIComponent(orderNumber)}/${processingStatus}`]);
}
}