mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-28 22:42:11 +01:00
Merged PR 836: #2161 Ui Scroll Container Implementation
#2161 Ui Scroll Container Implementation
This commit is contained in:
committed by
Andreas Schickinger
parent
7ad7177f89
commit
6c52fcd555
80
angular.json
80
angular.json
@@ -3056,6 +3056,86 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@ui/scroll-container": {
|
||||
"projectType": "library",
|
||||
"root": "apps/ui/scroll-container",
|
||||
"sourceRoot": "apps/ui/scroll-container/src",
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"tsConfig": "apps/ui/scroll-container/tsconfig.lib.json",
|
||||
"project": "apps/ui/scroll-container/ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"tsConfig": "apps/ui/scroll-container/tsconfig.lib.prod.json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "apps/ui/scroll-container/src/test.ts",
|
||||
"tsConfig": "apps/ui/scroll-container/tsconfig.spec.json",
|
||||
"karmaConfig": "apps/ui/scroll-container/karma.conf.js"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"apps/ui/scroll-container/tsconfig.lib.json",
|
||||
"apps/ui/scroll-container/tsconfig.spec.json"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@ui/loader": {
|
||||
"projectType": "library",
|
||||
"root": "apps/ui/loader",
|
||||
"sourceRoot": "apps/ui/loader/src",
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"tsConfig": "apps/ui/loader/tsconfig.lib.json",
|
||||
"project": "apps/ui/loader/ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"tsConfig": "apps/ui/loader/tsconfig.lib.prod.json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "apps/ui/loader/src/test.ts",
|
||||
"tsConfig": "apps/ui/loader/tsconfig.spec.json",
|
||||
"karmaConfig": "apps/ui/loader/karma.conf.js"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"apps/ui/loader/tsconfig.lib.json",
|
||||
"apps/ui/loader/tsconfig.spec.json"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultProject": "sales"
|
||||
|
||||
@@ -31,6 +31,7 @@ import { CustomerOrderItemCardComponent } from './customer-order-details/order-i
|
||||
import { UiSpinnerModule } from 'apps/ui/spinner/src/lib/ui-spinner.module';
|
||||
import { HistoryModule } from '@modal/history';
|
||||
import { CantSelectGuestModalModule } from '../modals/cant-select-guest/cant-select-guest-modal.module';
|
||||
import { UiScrollContainerModule } from '@ui/scroll-container';
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
@@ -44,6 +45,7 @@ import { CantSelectGuestModalModule } from '../modals/cant-select-guest/cant-sel
|
||||
FormsModule,
|
||||
UiRadioModule,
|
||||
UiCommonModule,
|
||||
UiScrollContainerModule,
|
||||
UiSpinnerModule,
|
||||
HistoryModule,
|
||||
CantSelectGuestModalModule,
|
||||
|
||||
@@ -2,7 +2,12 @@
|
||||
<div class="hits">{{ hits$ | async }} Titel</div>
|
||||
</div>
|
||||
|
||||
<div class="scroll-container" *ngIf="!(listEmpty$ | async); else emptyMessage">
|
||||
<ui-scroll-container
|
||||
*ngIf="!(listEmpty$ | async); else emptyMessage"
|
||||
[loading]="loading$ | async"
|
||||
[deltaEnd]="150"
|
||||
[itemLength]="(items$ | async).length"
|
||||
>
|
||||
<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
|
||||
@@ -27,8 +32,7 @@
|
||||
<div class="divider" *ngIf="!lastOrderNumber"></div>
|
||||
</ng-container>
|
||||
</shared-goods-in-out-order-group>
|
||||
<div *ngIf="loading$ | async; let loading" [uiLoader]="loading"><div class="loading-text">Inhalte werden geladen</div></div>
|
||||
</div>
|
||||
</ui-scroll-container>
|
||||
|
||||
<ng-template #emptyMessage>
|
||||
<div class="empty-message">
|
||||
|
||||
@@ -10,19 +10,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
.scroll-container {
|
||||
@apply h-full overflow-y-scroll relative grid grid-flow-row gap-3;
|
||||
max-height: calc(100vh - 350px);
|
||||
}
|
||||
|
||||
.empty-message {
|
||||
@apply bg-white text-center font-semibold text-inactive-branch py-10 rounded-card;
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
@apply mt-2 text-center font-semibold text-base text-inactive-branch;
|
||||
}
|
||||
|
||||
.divider {
|
||||
@apply h-px-2;
|
||||
}
|
||||
|
||||
@@ -19,11 +19,11 @@ import { GoodsInCleanupListStore } from './goods-in-cleanup-list.store';
|
||||
export class GoodsInCleanupListComponent implements OnInit, OnDestroy {
|
||||
@ViewChildren(GoodsInOutOrderGroupItemComponent) listItems: QueryList<GoodsInOutOrderGroupItemComponent>;
|
||||
|
||||
items$ = this._store.results$;
|
||||
items$ = this._store.results$.pipe(shareReplay());
|
||||
|
||||
hits$ = this._store.hits$;
|
||||
|
||||
loading$ = this._store.fetching$;
|
||||
loading$ = this._store.fetching$.pipe(shareReplay());
|
||||
|
||||
selectedOrderItemSubsetIds$ = this._store.selectedOrderItemSubsetIds$;
|
||||
|
||||
|
||||
@@ -3,11 +3,12 @@ import { NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { GoodsInOutOrderGroupModule } from '@shared/goods-in-out';
|
||||
import { UiCommonModule } from '@ui/common';
|
||||
import { UiScrollContainerModule } from '@ui/scroll-container';
|
||||
import { UiSpinnerModule } from 'apps/ui/spinner/src/lib/ui-spinner.module';
|
||||
import { GoodsInCleanupListComponent } from './goods-in-cleanup-list.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, UiCommonModule, GoodsInOutOrderGroupModule, UiSpinnerModule, RouterModule],
|
||||
imports: [CommonModule, UiCommonModule, GoodsInOutOrderGroupModule, UiSpinnerModule, UiScrollContainerModule, RouterModule],
|
||||
exports: [GoodsInCleanupListComponent],
|
||||
declarations: [GoodsInCleanupListComponent],
|
||||
providers: [],
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'goods-in-list-item-loading',
|
||||
templateUrl: 'goods-in-list-item-loading.component.html',
|
||||
styleUrls: ['goods-in-list-item-loading.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class GoodsInListItemLoadingComponent {
|
||||
constructor() {}
|
||||
}
|
||||
@@ -6,12 +6,11 @@ import { UiInputModule } from '@ui/input';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { PipesModule } from 'apps/shared/goods-in-out/src/lib/pipes/pipes.module';
|
||||
import { GoodsInListItemComponent } from './goods-in-list-item.component';
|
||||
import { GoodsInListItemLoadingComponent } from './goods-in-list-item-loading/goods-in-list-item-loading.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, PipesModule, UiIconModule, ProductImageModule, FormsModule, UiInputModule],
|
||||
exports: [GoodsInListItemComponent, GoodsInListItemLoadingComponent],
|
||||
declarations: [GoodsInListItemComponent, GoodsInListItemLoadingComponent],
|
||||
exports: [GoodsInListItemComponent],
|
||||
declarations: [GoodsInListItemComponent],
|
||||
providers: [],
|
||||
})
|
||||
export class GoodsInListItemModule {}
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { DomainGoodsService } from '@domain/oms';
|
||||
import { ListResponseArgsOfOrderItemListItemDTO } from '@swagger/oms';
|
||||
import { BehaviorSubject, Subject } from 'rxjs';
|
||||
import { map, switchMap, tap, withLatestFrom } from 'rxjs/operators';
|
||||
|
||||
@Injectable()
|
||||
export class GoodsInListService {
|
||||
loading$ = new BehaviorSubject<boolean>(false);
|
||||
|
||||
searchResponse$ = new BehaviorSubject<ListResponseArgsOfOrderItemListItemDTO>(undefined);
|
||||
|
||||
private search$ = new Subject<boolean>();
|
||||
|
||||
constructor(private domainGoodsInService: DomainGoodsService) {
|
||||
this.initSearch();
|
||||
}
|
||||
|
||||
private initSearch() {
|
||||
this.search$
|
||||
.pipe(
|
||||
tap(() => this.loading$.next(true)),
|
||||
withLatestFrom(this.searchResponse$),
|
||||
switchMap(([refresh, searchResponse]) =>
|
||||
this.domainGoodsInService
|
||||
.goodsInList({
|
||||
take: refresh ? searchResponse?.result?.length || 20 : 20,
|
||||
skip: refresh ? 0 : searchResponse?.result?.length || 0,
|
||||
})
|
||||
.pipe(
|
||||
map((response) => {
|
||||
if (refresh) {
|
||||
return response;
|
||||
} else {
|
||||
return searchResponse?.result
|
||||
? ({
|
||||
...response,
|
||||
result: [...searchResponse.result, ...response.result],
|
||||
} as ListResponseArgsOfOrderItemListItemDTO)
|
||||
: response;
|
||||
}
|
||||
})
|
||||
)
|
||||
),
|
||||
tap(() => {
|
||||
this.loading$.next(false);
|
||||
})
|
||||
)
|
||||
.subscribe(this.searchResponse$);
|
||||
}
|
||||
|
||||
search(refresh?: boolean) {
|
||||
this.search$.next(!!refresh);
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,11 @@
|
||||
<div class="list-count">{{ hits$ | async }} Titel</div>
|
||||
<div class="list-main">
|
||||
<div class="scroll-container">
|
||||
<ng-container *ngFor="let item of items$ | async; let last = last">
|
||||
<goods-in-list-item-loading *ngIf="loading$ | async"></goods-in-list-item-loading>
|
||||
<goods-in-list-item
|
||||
*ngIf="!(loading$ | async)"
|
||||
uiIsInViewport
|
||||
[options]="viewportEnterOptions"
|
||||
(viewportEntered)="checkIfReload($event)"
|
||||
[class.last]="last"
|
||||
[item]="item"
|
||||
[editSsc]="editSsc"
|
||||
(refresh)="refreshList()"
|
||||
></goods-in-list-item>
|
||||
<hr />
|
||||
</ng-container>
|
||||
<goods-in-list-item-loading *ngIf="loading$ | async"></goods-in-list-item-loading>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ui-scroll-container [loading]="loading$ | async" (reachEnd)="loadMore()" [deltaEnd]="150" [itemLength]="(items$ | async).length">
|
||||
<ng-container *ngFor="let item of items$ | async">
|
||||
<goods-in-list-item [item]="item" [editSsc]="editSsc" (refresh)="refreshList()"></goods-in-list-item>
|
||||
<hr />
|
||||
</ng-container>
|
||||
</ui-scroll-container>
|
||||
|
||||
<div class="actions">
|
||||
<button *ngIf="!editSsc" class="cta-edit-ssc cta-action-primary" (click)="editSsc = true">
|
||||
|
||||
@@ -6,21 +6,8 @@
|
||||
@apply text-active-branch text-right mb-3 font-semibold text-base;
|
||||
}
|
||||
|
||||
.list-main {
|
||||
@apply bg-white rounded-t-card pb-5 shadow-card;
|
||||
height: calc(100vh - 310px);
|
||||
|
||||
.list-main-title {
|
||||
@apply text-2xl font-bold text-center;
|
||||
}
|
||||
|
||||
.list-main-paragraph {
|
||||
@apply text-2xl mb-12 text-center;
|
||||
}
|
||||
|
||||
.scroll-container {
|
||||
@apply h-full overflow-y-scroll relative;
|
||||
}
|
||||
::ng-deep page-goods-in-list ui-scroll-container .scroll-container {
|
||||
@apply bg-white;
|
||||
}
|
||||
|
||||
hr {
|
||||
|
||||
@@ -1,26 +1,27 @@
|
||||
import { AfterViewInit, ChangeDetectionStrategy, Component, OnDestroy, OnInit, QueryList, ViewChildren } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { BreadcrumbService } from '@core/breadcrumb';
|
||||
import { DomainOmsService } from '@domain/oms';
|
||||
import { BehaviorSubject, combineLatest, Observable, Subject } from 'rxjs';
|
||||
import { first, map, shareReplay, takeUntil } from 'rxjs/operators';
|
||||
import { map, shareReplay, takeUntil } from 'rxjs/operators';
|
||||
import { GoodsInListItemComponent } from './goods-in-list-item/goods-in-list-item.component';
|
||||
import { GoodsInListService } from './goods-in-list-service';
|
||||
import { GoodsInListStore } from './goods-in-list.store';
|
||||
|
||||
@Component({
|
||||
selector: 'page-goods-in-list',
|
||||
templateUrl: 'goods-in-list.component.html',
|
||||
styleUrls: ['goods-in-list.component.scss'],
|
||||
providers: [GoodsInListService],
|
||||
providers: [GoodsInListStore],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class GoodsInListComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
@ViewChildren(GoodsInListItemComponent) listItems: QueryList<GoodsInListItemComponent>;
|
||||
|
||||
items$ = this._goodsInListService.searchResponse$.pipe(map((res) => res?.result || []));
|
||||
items$ = this._store.results$.pipe(shareReplay());
|
||||
|
||||
hits$ = this._goodsInListService.searchResponse$.pipe(map((res) => res?.hits || 0));
|
||||
hits$ = this._store.hits$;
|
||||
|
||||
loading$ = this._goodsInListService.loading$.pipe(shareReplay());
|
||||
loading$ = this._store.loading$.pipe(shareReplay());
|
||||
|
||||
editSsc: boolean;
|
||||
|
||||
@@ -28,34 +29,31 @@ export class GoodsInListComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
|
||||
showSaveSscSpinner$ = new BehaviorSubject<boolean>(false);
|
||||
|
||||
protected readonly viewportEnterOptions: IntersectionObserverInit = {
|
||||
threshold: 0.75,
|
||||
};
|
||||
|
||||
private _onDestroy$ = new Subject();
|
||||
|
||||
constructor(
|
||||
private _goodsInListService: GoodsInListService,
|
||||
private _breadcrumb: BreadcrumbService,
|
||||
private _domainOmsService: DomainOmsService
|
||||
private _domainOmsService: DomainOmsService,
|
||||
private _store: GoodsInListStore,
|
||||
private _router: Router
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this._goodsInListService.search();
|
||||
this.initInitialSearch();
|
||||
this.updateBreadcrumb();
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this._onDestroy$.next();
|
||||
this._onDestroy$.complete();
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
this.registerEditSscDisabled();
|
||||
|
||||
this.listItems.changes.pipe(takeUntil(this._onDestroy$)).subscribe(() => this.registerEditSscDisabled());
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this._onDestroy$.next();
|
||||
this._onDestroy$.complete();
|
||||
}
|
||||
|
||||
async updateBreadcrumb() {
|
||||
await this._breadcrumb.addOrUpdateBreadcrumbIfNotExists({
|
||||
key: 'goods-in',
|
||||
@@ -72,11 +70,23 @@ export class GoodsInListComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
);
|
||||
}
|
||||
|
||||
async checkIfReload(target: HTMLElement) {
|
||||
const hits = await this.hits$.pipe(first()).toPromise();
|
||||
const itemLength = (await this.items$.pipe(first()).toPromise())?.length;
|
||||
if (target.classList.contains('last') && itemLength < hits) {
|
||||
this._goodsInListService.search();
|
||||
initInitialSearch() {
|
||||
if (this._store.hits === 0) {
|
||||
this._store.searchResult$.pipe(takeUntil(this._onDestroy$)).subscribe(async (result) => {
|
||||
if (result.hits === 0) {
|
||||
await this._router.navigate(['/goods/in']);
|
||||
} else {
|
||||
await this.updateBreadcrumb();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this._store.search();
|
||||
}
|
||||
|
||||
async loadMore() {
|
||||
if (this._store.hits > this._store.results.length && !this._store.loading) {
|
||||
this._store.search();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,6 +116,6 @@ export class GoodsInListComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
}
|
||||
|
||||
refreshList() {
|
||||
this._goodsInListService.search(true);
|
||||
this._store.reload();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { UiCommonModule } from '@ui/common';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { UiScrollContainerModule } from '@ui/scroll-container';
|
||||
import { UiSpinnerModule } from 'apps/ui/spinner/src/lib/ui-spinner.module';
|
||||
import { GoodsInListItemModule } from './goods-in-list-item/goods-in-list-item.module';
|
||||
import { GoodsInListReorderModalModule } from './goods-in-list-reorder-modal/goods-in-list-reorder-modal.module';
|
||||
@@ -9,7 +10,15 @@ import { GoodsInListReorderModalModule } from './goods-in-list-reorder-modal/goo
|
||||
import { GoodsInListComponent } from './goods-in-list.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, UiCommonModule, UiIconModule, GoodsInListItemModule, GoodsInListReorderModalModule, UiSpinnerModule],
|
||||
imports: [
|
||||
CommonModule,
|
||||
UiCommonModule,
|
||||
UiIconModule,
|
||||
GoodsInListItemModule,
|
||||
GoodsInListReorderModalModule,
|
||||
UiScrollContainerModule,
|
||||
UiSpinnerModule,
|
||||
],
|
||||
exports: [],
|
||||
declarations: [GoodsInListComponent],
|
||||
providers: [],
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
import { createServiceFactory, SpectatorService } from '@ngneat/spectator';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { GoodsInListService } from './goods-in-list-service';
|
||||
import { DomainGoodsService } from '@domain/oms';
|
||||
import { of } from 'rxjs';
|
||||
import { ListResponseArgsOfOrderItemListItemDTO } from '@swagger/oms';
|
||||
import { first } from 'rxjs/operators';
|
||||
|
||||
describe('GoodsInListService', () => {
|
||||
let spectator: SpectatorService<GoodsInListService>;
|
||||
let domainGoodsInServiceMock: jasmine.SpyObj<DomainGoodsService>;
|
||||
|
||||
const createService = createServiceFactory({
|
||||
service: GoodsInListService,
|
||||
imports: [RouterTestingModule],
|
||||
mocks: [DomainGoodsService],
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
spectator = createService();
|
||||
domainGoodsInServiceMock = spectator.inject(DomainGoodsService);
|
||||
});
|
||||
|
||||
it('should create the service', () => {
|
||||
expect(spectator.service).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('search()', () => {
|
||||
it('should call next on search$ subject', () => {
|
||||
spectator.service['search$'].next = jasmine.createSpy();
|
||||
spectator.service.search();
|
||||
expect(spectator.service['search$'].next).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should set loading$ to true', () => {
|
||||
spectator.service.loading$.next = jasmine.createSpy();
|
||||
spectator.service.search();
|
||||
expect(spectator.service.loading$.next).toHaveBeenCalledWith(true);
|
||||
});
|
||||
|
||||
it('should call domainGoodsInService.goodsInList() with take 20 and result 0 when searchResponse is not set', () => {
|
||||
domainGoodsInServiceMock.goodsInList = jasmine.createSpy().and.returnValue(of({}));
|
||||
spectator.service.search();
|
||||
expect(domainGoodsInServiceMock.goodsInList).toHaveBeenCalledWith({ take: 20, skip: 0 });
|
||||
});
|
||||
|
||||
it('should call domainGoodsInService.goodsInList() with take 20 and result length when searchResponse is set', () => {
|
||||
spectator.service.searchResponse$.next({ result: new Array(20) } as ListResponseArgsOfOrderItemListItemDTO);
|
||||
domainGoodsInServiceMock.goodsInList = jasmine.createSpy().and.returnValue(of({}));
|
||||
spectator.service.search();
|
||||
expect(domainGoodsInServiceMock.goodsInList).toHaveBeenCalledWith({ take: 20, skip: 20 });
|
||||
});
|
||||
|
||||
it('should add the response to the current searchResponse', async () => {
|
||||
domainGoodsInServiceMock.goodsInList = jasmine.createSpy().and.returnValue(of({ result: new Array(20) }));
|
||||
spectator.service.search();
|
||||
spectator.service.search();
|
||||
|
||||
const response = await spectator.service.searchResponse$.pipe(first()).toPromise();
|
||||
expect(response.result.length).toBe(40);
|
||||
});
|
||||
});
|
||||
});
|
||||
131
apps/page/goods-in/src/lib/goods-in-list/goods-in-list.store.ts
Normal file
131
apps/page/goods-in/src/lib/goods-in-list/goods-in-list.store.ts
Normal file
@@ -0,0 +1,131 @@
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { DomainAvailabilityService } from '@domain/availability';
|
||||
import { DomainGoodsService } from '@domain/oms';
|
||||
import { ComponentStore, tapResponse } from '@ngrx/component-store';
|
||||
import { ListResponseArgsOfOrderItemListItemDTO, OrderItemListItemDTO, QueryTokenDTO } from '@swagger/oms';
|
||||
import { isResponseArgs } from '@utils/object';
|
||||
import { Subject } from 'rxjs';
|
||||
import { switchMap, tap, withLatestFrom } from 'rxjs/operators';
|
||||
|
||||
export interface GoodsInListState {
|
||||
message?: string;
|
||||
loading: boolean;
|
||||
hits: number;
|
||||
results: OrderItemListItemDTO[];
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class GoodsInListStore extends ComponentStore<GoodsInListState> {
|
||||
get results() {
|
||||
return this.get((s) => s.results);
|
||||
}
|
||||
readonly results$ = this.select((s) => s.results);
|
||||
|
||||
get hits() {
|
||||
return this.get((s) => s.hits);
|
||||
}
|
||||
readonly hits$ = this.select((s) => s.hits);
|
||||
|
||||
get loading() {
|
||||
return this.get((s) => s.loading);
|
||||
}
|
||||
readonly loading$ = this.select((s) => s.loading);
|
||||
|
||||
private _searchResultSubject = new Subject<ListResponseArgsOfOrderItemListItemDTO>();
|
||||
|
||||
readonly searchResult$ = this._searchResultSubject.asObservable();
|
||||
|
||||
constructor(private _domainGoodsInService: DomainGoodsService) {
|
||||
super({
|
||||
loading: false,
|
||||
hits: 0,
|
||||
results: [],
|
||||
});
|
||||
}
|
||||
|
||||
search = this.effect(($) =>
|
||||
$.pipe(
|
||||
tap((_) => this.patchState({ loading: true })),
|
||||
withLatestFrom(this.results$),
|
||||
switchMap(([_, _results]) =>
|
||||
this.searchRequest().pipe(
|
||||
tapResponse(
|
||||
(res) => {
|
||||
const results = [...(_results ?? []), ...(res.result ?? [])];
|
||||
this.patchState({
|
||||
hits: res.hits,
|
||||
results,
|
||||
loading: false,
|
||||
});
|
||||
this._searchResultSubject.next(res);
|
||||
},
|
||||
(err: Error) => {
|
||||
if (err instanceof HttpErrorResponse && isResponseArgs(err.error)) {
|
||||
this._searchResultSubject.next(err.error);
|
||||
} else {
|
||||
this._searchResultSubject.next({
|
||||
error: true,
|
||||
message: err.message,
|
||||
});
|
||||
}
|
||||
this.patchState({ loading: false });
|
||||
console.error('GoodsInListStore.search()', err);
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
reload = this.effect(($) =>
|
||||
$.pipe(
|
||||
tap((_) => this.patchState({ loading: true })),
|
||||
withLatestFrom(this.results$),
|
||||
switchMap(([_, results]) =>
|
||||
this.searchRequest({ take: results?.length ?? 0, skip: 0 }).pipe(
|
||||
tapResponse(
|
||||
(res) => {
|
||||
this.patchState({
|
||||
hits: res.hits,
|
||||
results: res.result,
|
||||
loading: false,
|
||||
});
|
||||
|
||||
this._searchResultSubject.next(res);
|
||||
},
|
||||
(err: Error) => {
|
||||
if (err instanceof HttpErrorResponse && isResponseArgs(err.error)) {
|
||||
this._searchResultSubject.next(err.error);
|
||||
} else {
|
||||
this._searchResultSubject.next({
|
||||
error: true,
|
||||
message: err.message,
|
||||
});
|
||||
}
|
||||
this.patchState({ loading: false });
|
||||
console.error('GoodsInListStore.reload()', err);
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
clearResults() {
|
||||
this.patchState({
|
||||
loading: false,
|
||||
hits: 0,
|
||||
message: undefined,
|
||||
results: [],
|
||||
});
|
||||
}
|
||||
|
||||
searchRequest(options?: { take?: number; skip?: number }) {
|
||||
const queryToken: QueryTokenDTO = {
|
||||
skip: options?.skip ?? this.results.length,
|
||||
take: options?.take ?? 20,
|
||||
};
|
||||
return this._domainGoodsInService.goodsInList(queryToken);
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="hits">{{ hits$ | async }} Titel</div>
|
||||
</div>
|
||||
|
||||
<div class="scroll-container" uiScrollContainer (reachEnd)="loadMore()" [deltaEnd]="150">
|
||||
<ui-scroll-container [loading]="loading$ | async" (reachEnd)="loadMore()" [deltaEnd]="150" [itemLength]="(items$ | async).length">
|
||||
<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
|
||||
@@ -28,8 +28,7 @@
|
||||
<div class="divider" *ngIf="!lastOrderNumber"></div>
|
||||
</ng-container>
|
||||
</shared-goods-in-out-order-group>
|
||||
<div *ngIf="loading$ | async; let loading" [uiLoader]="loading"><div class="loading-text">Inhalte werden geladen</div></div>
|
||||
</div>
|
||||
</ui-scroll-container>
|
||||
|
||||
<div class="actions" *ngIf="actions$ | async; let actions">
|
||||
<button
|
||||
|
||||
@@ -10,15 +10,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.scroll-container {
|
||||
@apply h-full overflow-y-scroll relative grid grid-flow-row gap-3;
|
||||
max-height: calc(100vh - 350px);
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
@apply mt-2 text-center font-semibold text-base text-inactive-branch;
|
||||
}
|
||||
|
||||
.divider {
|
||||
@apply h-px-2;
|
||||
}
|
||||
|
||||
@@ -19,11 +19,11 @@ import { GoodsInReservationStore } from './goods-in-reservation.store';
|
||||
export class GoodsInReservationComponent implements OnInit, OnDestroy {
|
||||
@ViewChildren(GoodsInOutOrderGroupItemComponent) listItems: QueryList<GoodsInOutOrderGroupItemComponent>;
|
||||
|
||||
items$ = this._store.results$;
|
||||
items$ = this._store.results$.pipe(shareReplay());
|
||||
|
||||
hits$ = this._store.hits$;
|
||||
|
||||
loading$ = this._store.loading$;
|
||||
loading$ = this._store.loading$.pipe(shareReplay());
|
||||
|
||||
takeAwayAvailabilities$ = this._store.takeAwayAvailabilities$.pipe(shareReplay());
|
||||
|
||||
|
||||
@@ -2,12 +2,13 @@ import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { GoodsInOutOrderGroupModule } from '@shared/goods-in-out';
|
||||
import { UiCommonModule } from '@ui/common';
|
||||
import { UiScrollContainerModule } from 'apps/ui/scroll-container/src/public-api';
|
||||
import { UiSpinnerModule } from 'apps/ui/spinner/src/lib/ui-spinner.module';
|
||||
|
||||
import { GoodsInReservationComponent } from './goods-in-reservation.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, UiCommonModule, GoodsInOutOrderGroupModule, UiSpinnerModule],
|
||||
imports: [CommonModule, UiCommonModule, UiScrollContainerModule, GoodsInOutOrderGroupModule, UiSpinnerModule],
|
||||
exports: [GoodsInReservationComponent],
|
||||
declarations: [GoodsInReservationComponent],
|
||||
providers: [],
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="hits">{{ hits$ | async }} Titel</div>
|
||||
<div class="scroll-container" uiScrollContainer (reachEnd)="loadMore()" [deltaEnd]="150">
|
||||
<ui-scroll-container [loading]="loading$ | async" (reachEnd)="loadMore()" [deltaEnd]="150" [itemLength]="(items$ | async).length">
|
||||
<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
|
||||
@@ -22,5 +22,4 @@
|
||||
<div class="divider" *ngIf="!lastOrderNumber"></div>
|
||||
</ng-container>
|
||||
</shared-goods-in-out-order-group>
|
||||
<div *ngIf="loading$ | async; let loading" [uiLoader]="loading"><div class="loading-text">Inhalte werden geladen</div></div>
|
||||
</div>
|
||||
</ui-scroll-container>
|
||||
|
||||
@@ -6,15 +6,6 @@
|
||||
@apply text-active-branch text-right mb-3 font-semibold text-base;
|
||||
}
|
||||
|
||||
.scroll-container {
|
||||
@apply h-full overflow-y-scroll relative grid grid-flow-row gap-3;
|
||||
max-height: calc(100vh - 280px);
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
@apply mt-2 text-center font-semibold text-base text-inactive-branch;
|
||||
}
|
||||
|
||||
.divider {
|
||||
height: 2px;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy } from '@angular/core';
|
||||
import { first, takeUntil } from 'rxjs/operators';
|
||||
import { first, shareReplay, takeUntil } from 'rxjs/operators';
|
||||
import { OrderItemListItemDTO } from '@swagger/oms';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { GoodsInSearchStore } from '../goods-in-search.store';
|
||||
@@ -13,11 +13,11 @@ import { BreadcrumbService } from '@core/breadcrumb';
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class GoodsInSearchResultsComponent implements OnInit, OnDestroy {
|
||||
items$ = this._goodsInSearchStore.results$;
|
||||
items$ = this._goodsInSearchStore.results$.pipe(shareReplay());
|
||||
|
||||
hits$ = this._goodsInSearchStore.hits$;
|
||||
|
||||
loading$ = this._goodsInSearchStore.fetching$;
|
||||
loading$ = this._goodsInSearchStore.fetching$.pipe(shareReplay());
|
||||
|
||||
byBuyerNumberFn = (item: OrderItemListItemDTO) => item.buyerNumber;
|
||||
|
||||
|
||||
@@ -4,9 +4,10 @@ import { CommonModule } from '@angular/common';
|
||||
import { GoodsInSearchResultsComponent } from './goods-in-search-results.component';
|
||||
import { UiCommonModule } from '@ui/common';
|
||||
import { GoodsInOutOrderGroupModule } from '@shared/goods-in-out';
|
||||
import { UiScrollContainerModule } from '@ui/scroll-container';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, GoodsInOutOrderGroupModule, UiCommonModule],
|
||||
imports: [CommonModule, GoodsInOutOrderGroupModule, UiCommonModule, UiScrollContainerModule],
|
||||
exports: [GoodsInSearchResultsComponent],
|
||||
declarations: [GoodsInSearchResultsComponent],
|
||||
})
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { UiLoaderComponent } from './ui-loader.component';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, UiIconModule],
|
||||
exports: [UiLoaderComponent],
|
||||
declarations: [UiLoaderComponent],
|
||||
})
|
||||
export class UiLoaderModule {}
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="hits">{{ hits$ | async }} Titel</div>
|
||||
<div class="scroll-container" uiScrollContainer (reachEnd)="loadMore()" [deltaEnd]="150">
|
||||
<ui-scroll-container [loading]="loading$ | async" (reachEnd)="loadMore()" [deltaEnd]="150" [itemLength]="(items$ | async).length">
|
||||
<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
|
||||
@@ -24,8 +24,7 @@
|
||||
<div class="divider" *ngIf="!lastOrderNumber"></div>
|
||||
</ng-container>
|
||||
</shared-goods-in-out-order-group>
|
||||
<div *ngIf="loading$ | async; let loading" [uiLoader]="loading"><div class="loading-text">Inhalte werden geladen</div></div>
|
||||
</div>
|
||||
</ui-scroll-container>
|
||||
|
||||
<button
|
||||
class="cta-fetched"
|
||||
|
||||
@@ -6,15 +6,6 @@
|
||||
@apply text-active-customer text-right mb-3 font-semibold text-base;
|
||||
}
|
||||
|
||||
.scroll-container {
|
||||
@apply h-full overflow-y-scroll relative grid grid-flow-row gap-3;
|
||||
max-height: calc(100vh - 280px);
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
@apply mt-2 text-center font-semibold text-base text-inactive-customer;
|
||||
}
|
||||
|
||||
.divider {
|
||||
height: 2px;
|
||||
}
|
||||
|
||||
@@ -20,11 +20,11 @@ export interface GoodsOutSearchResultsState {
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearchResultsState> implements OnInit, OnDestroy {
|
||||
items$ = this._goodsOutSearchStore.results$;
|
||||
items$ = this._goodsOutSearchStore.results$.pipe(shareReplay());
|
||||
|
||||
hits$ = this._goodsOutSearchStore.hits$;
|
||||
|
||||
loading$ = this._goodsOutSearchStore.fetching$;
|
||||
loading$ = this._goodsOutSearchStore.fetching$.pipe(shareReplay());
|
||||
loadingFetchedActionButton$ = new BehaviorSubject<boolean>(false);
|
||||
|
||||
selectedOrderItemSubsetIds$ = this.select((s) => s.selectedOrderItemSubsetIds);
|
||||
|
||||
@@ -7,9 +7,10 @@ import { UiCommonModule } from '@ui/common';
|
||||
import { GoodsOutItemSelectablePipe } from './goods-out-item-selectable.pipe';
|
||||
import { GoodsOutItemSelectedPipe } from './goods-out-item-selectede.pipe';
|
||||
import { UiSpinnerModule } from 'apps/ui/spinner/src/lib/ui-spinner.module';
|
||||
import { UiScrollContainerModule } from '@ui/scroll-container';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, GoodsInOutOrderGroupModule, UiCommonModule, UiSpinnerModule],
|
||||
imports: [CommonModule, GoodsInOutOrderGroupModule, UiCommonModule, UiSpinnerModule, UiScrollContainerModule],
|
||||
exports: [GoodsOutSearchResultsComponent],
|
||||
declarations: [GoodsOutSearchResultsComponent, GoodsOutItemSelectablePipe, GoodsOutItemSelectedPipe],
|
||||
})
|
||||
|
||||
@@ -93,9 +93,9 @@ export class GoodsInOutOrderGroupItemComponent extends ComponentStore<GoodsInOut
|
||||
return 0;
|
||||
}
|
||||
|
||||
const stockInfo = this.showInStock.find((stock) => stock.ean === ean);
|
||||
const stockInfo = this.showInStock?.find((stock) => stock?.ean === ean);
|
||||
if (stockInfo) {
|
||||
return stockInfo.inStock - stockInfo.removedFromStock;
|
||||
return stockInfo?.inStock - (stockInfo?.removedFromStock || 0);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -7,18 +7,10 @@ import { IsInViewportDirective } from './is-in-viewport.directive';
|
||||
import { GroupByPipe } from './pipes/group-by.pipe';
|
||||
import { StripHtmlTagsPipe } from './pipes/strip-html-tags.pipe';
|
||||
import { SubstrPipe } from './pipes/substr.pipe';
|
||||
import { ScrollContainerDirective } from './scroll-container.directive';
|
||||
import { SkeletonLoaderComponent } from './skeleton-loader';
|
||||
|
||||
const components = [SkeletonLoaderComponent];
|
||||
const directives = [
|
||||
UiClickOutsideDirective,
|
||||
IsInViewportDirective,
|
||||
ScrollContainerDirective,
|
||||
BlobImageDirective,
|
||||
UiAutofocusDirective,
|
||||
UiFocusDirective,
|
||||
];
|
||||
const directives = [UiClickOutsideDirective, IsInViewportDirective, BlobImageDirective, UiAutofocusDirective, UiFocusDirective];
|
||||
const pipes = [StripHtmlTagsPipe, SubstrPipe, GroupByPipe];
|
||||
@NgModule({
|
||||
imports: [],
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
export * from './click-outside.directive';
|
||||
export * from './common.module';
|
||||
export * from './is-in-viewport.directive';
|
||||
export * from './scroll-container.directive';
|
||||
export * from './date';
|
||||
export * from './skeleton-loader';
|
||||
export * from './defs';
|
||||
|
||||
25
apps/ui/loader/README.md
Normal file
25
apps/ui/loader/README.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# Loader
|
||||
|
||||
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 10.2.4.
|
||||
|
||||
## Code scaffolding
|
||||
|
||||
Run `ng generate component component-name --project loader` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project loader`.
|
||||
|
||||
> Note: Don't forget to add `--project loader` or else it will be added to the default project in your `angular.json` file.
|
||||
|
||||
## Build
|
||||
|
||||
Run `ng build loader` to build the project. The build artifacts will be stored in the `dist/` directory.
|
||||
|
||||
## Publishing
|
||||
|
||||
After building your library with `ng build loader`, go to the dist folder `cd dist/loader` and run `npm publish`.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `ng test loader` 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.
|
||||
32
apps/ui/loader/karma.conf.js
Normal file
32
apps/ui/loader/karma.conf.js
Normal file
@@ -0,0 +1,32 @@
|
||||
// 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-istanbul-reporter'),
|
||||
require('@angular-devkit/build-angular/plugins/karma'),
|
||||
],
|
||||
client: {
|
||||
clearContext: false, // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
coverageIstanbulReporter: {
|
||||
dir: require('path').join(__dirname, '../../../coverage/ui/loader'),
|
||||
reports: ['html', 'lcovonly', 'text-summary'],
|
||||
fixWebpackSourcePaths: true,
|
||||
},
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
singleRun: false,
|
||||
restartOnFileChange: true,
|
||||
});
|
||||
};
|
||||
7
apps/ui/loader/ng-package.json
Normal file
7
apps/ui/loader/ng-package.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json",
|
||||
"dest": "../../../dist/ui/loader",
|
||||
"lib": {
|
||||
"entryFile": "src/public-api.ts"
|
||||
}
|
||||
}
|
||||
11
apps/ui/loader/package.json
Normal file
11
apps/ui/loader/package.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "@ui/loader",
|
||||
"version": "0.0.1",
|
||||
"peerDependencies": {
|
||||
"@angular/common": "^10.2.4",
|
||||
"@angular/core": "^10.2.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.0"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { createHostFactory, SpectatorHost } from '@ngneat/spectator';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { UiButtonLoaderComponent, UiLoaderComponent } from './ui-loader.component';
|
||||
import { UiButtonLoaderComponent, UiLoaderComponent } from './loader.component';
|
||||
|
||||
describe('UiLoaderComponent', () => {
|
||||
let spectator: SpectatorHost<UiLoaderComponent>;
|
||||
@@ -7,8 +7,8 @@ interface IUiLoader {
|
||||
|
||||
@Component({
|
||||
selector: '[uiLoader]:not(button)',
|
||||
templateUrl: 'ui-loader.component.html',
|
||||
styleUrls: ['ui-loader.component.scss'],
|
||||
templateUrl: 'loader.component.html',
|
||||
styleUrls: ['loader.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class UiLoaderComponent implements IUiLoader {
|
||||
@@ -23,8 +23,8 @@ export class UiLoaderComponent implements IUiLoader {
|
||||
|
||||
@Component({
|
||||
selector: 'button[uiLoader]',
|
||||
templateUrl: 'ui-loader.component.html',
|
||||
styleUrls: ['ui-loader.component.scss'],
|
||||
templateUrl: 'loader.component.html',
|
||||
styleUrls: ['loader.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class UiButtonLoaderComponent implements IUiLoader {
|
||||
13
apps/ui/loader/src/lib/loader.module.ts
Normal file
13
apps/ui/loader/src/lib/loader.module.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { UiLoaderComponent } from './loader.component';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { UiButtonLoaderComponent } from '@ui/loader';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, UiIconModule],
|
||||
exports: [UiLoaderComponent, UiButtonLoaderComponent],
|
||||
declarations: [UiLoaderComponent, UiButtonLoaderComponent],
|
||||
})
|
||||
export class UiLoaderModule {}
|
||||
6
apps/ui/loader/src/public-api.ts
Normal file
6
apps/ui/loader/src/public-api.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
/*
|
||||
* Public API Surface of loader
|
||||
*/
|
||||
|
||||
export * from './lib/loader.component';
|
||||
export * from './lib/loader.module';
|
||||
24
apps/ui/loader/src/test.ts
Normal file
24
apps/ui/loader/src/test.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||
|
||||
import 'zone.js/dist/zone';
|
||||
import 'zone.js/dist/zone-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());
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
||||
25
apps/ui/loader/tsconfig.lib.json
Normal file
25
apps/ui/loader/tsconfig.lib.json
Normal file
@@ -0,0 +1,25 @@
|
||||
/* 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"
|
||||
]
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"skipTemplateCodegen": true,
|
||||
"strictMetadataEmit": true,
|
||||
"enableResourceInlining": true
|
||||
},
|
||||
"exclude": [
|
||||
"src/test.ts",
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
||||
10
apps/ui/loader/tsconfig.lib.prod.json
Normal file
10
apps/ui/loader/tsconfig.lib.prod.json
Normal file
@@ -0,0 +1,10 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "./tsconfig.lib.json",
|
||||
"compilerOptions": {
|
||||
"declarationMap": false
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"enableIvy": false
|
||||
}
|
||||
}
|
||||
17
apps/ui/loader/tsconfig.spec.json
Normal file
17
apps/ui/loader/tsconfig.spec.json
Normal file
@@ -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"
|
||||
]
|
||||
}
|
||||
17
apps/ui/loader/tslint.json
Normal file
17
apps/ui/loader/tslint.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"extends": "../../../tslint.json",
|
||||
"rules": {
|
||||
"directive-selector": [
|
||||
true,
|
||||
"attribute",
|
||||
"lib",
|
||||
"camelCase"
|
||||
],
|
||||
"component-selector": [
|
||||
true,
|
||||
"element",
|
||||
"lib",
|
||||
"kebab-case"
|
||||
]
|
||||
}
|
||||
}
|
||||
25
apps/ui/scroll-container/README.md
Normal file
25
apps/ui/scroll-container/README.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# ScrollContainer
|
||||
|
||||
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 10.2.4.
|
||||
|
||||
## Code scaffolding
|
||||
|
||||
Run `ng generate component component-name --project scroll-container` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project scroll-container`.
|
||||
|
||||
> Note: Don't forget to add `--project scroll-container` or else it will be added to the default project in your `angular.json` file.
|
||||
|
||||
## Build
|
||||
|
||||
Run `ng build scroll-container` to build the project. The build artifacts will be stored in the `dist/` directory.
|
||||
|
||||
## Publishing
|
||||
|
||||
After building your library with `ng build scroll-container`, go to the dist folder `cd dist/scroll-container` and run `npm publish`.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `ng test scroll-container` 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.
|
||||
32
apps/ui/scroll-container/karma.conf.js
Normal file
32
apps/ui/scroll-container/karma.conf.js
Normal file
@@ -0,0 +1,32 @@
|
||||
// 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-istanbul-reporter'),
|
||||
require('@angular-devkit/build-angular/plugins/karma'),
|
||||
],
|
||||
client: {
|
||||
clearContext: false, // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
coverageIstanbulReporter: {
|
||||
dir: require('path').join(__dirname, '../../../coverage/ui/scroll-container'),
|
||||
reports: ['html', 'lcovonly', 'text-summary'],
|
||||
fixWebpackSourcePaths: true,
|
||||
},
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
singleRun: false,
|
||||
restartOnFileChange: true,
|
||||
});
|
||||
};
|
||||
7
apps/ui/scroll-container/ng-package.json
Normal file
7
apps/ui/scroll-container/ng-package.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json",
|
||||
"dest": "../../../dist/ui/scroll-container",
|
||||
"lib": {
|
||||
"entryFile": "src/public-api.ts"
|
||||
}
|
||||
}
|
||||
11
apps/ui/scroll-container/package.json
Normal file
11
apps/ui/scroll-container/package.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "@ui/scroll-container",
|
||||
"version": "0.0.1",
|
||||
"peerDependencies": {
|
||||
"@angular/common": "^10.2.4",
|
||||
"@angular/core": "^10.2.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<div *ngIf="loading" [uiLoader]="loading"><div class="loading-text">Inhalte werden geladen</div></div>
|
||||
@@ -0,0 +1,7 @@
|
||||
.loading-text {
|
||||
@apply mt-2 text-center font-semibold text-base text-inactive-branch;
|
||||
}
|
||||
|
||||
::ng-deep .customer ui-content-loader .loading-text {
|
||||
@apply text-inactive-customer;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'ui-content-loader',
|
||||
templateUrl: 'content-loader.component.html',
|
||||
styleUrls: ['content-loader.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class UiContentLoaderComponent implements OnInit {
|
||||
@Input() loading: boolean;
|
||||
|
||||
constructor() {}
|
||||
|
||||
ngOnInit() {}
|
||||
}
|
||||
3
apps/ui/scroll-container/src/lib/content-loader/index.ts
Normal file
3
apps/ui/scroll-container/src/lib/content-loader/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
// start:ng42.barrel
|
||||
export * from './content-loader.component';
|
||||
// end:ng42.barrel
|
||||
3
apps/ui/scroll-container/src/lib/directives/index.ts
Normal file
3
apps/ui/scroll-container/src/lib/directives/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
// start:ng42.barrel
|
||||
export * from './scroll-container.directive';
|
||||
// end:ng42.barrel
|
||||
@@ -3,7 +3,7 @@ import { Subject } from 'rxjs';
|
||||
import { filter } from 'rxjs/operators';
|
||||
|
||||
@Directive({ selector: '[uiScrollContainer]' })
|
||||
export class ScrollContainerDirective implements OnChanges, OnInit {
|
||||
export class UiScrollContainerDirective implements OnChanges, OnInit {
|
||||
@Input('uiScrollContainer')
|
||||
direction: 'horizontal' | 'vertical' = 'vertical';
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
<div
|
||||
#scrollContainer
|
||||
class="scroll-container"
|
||||
[class.scroll-bar]="showScrollbar"
|
||||
[class.scrollbar-gap]="scrollPersantage > 99"
|
||||
[uiScrollContainer]="direction"
|
||||
(reachEnd)="reachedEnd()"
|
||||
(reachStart)="reachedStart()"
|
||||
[deltaEnd]="deltaEnd"
|
||||
>
|
||||
<ng-content *ngIf="!loading; else loader"></ng-content>
|
||||
|
||||
<ng-template #loader>
|
||||
<ng-container *ngIf="useLoadAnimation; else contentLoader">
|
||||
<ui-skeleton-loader></ui-skeleton-loader>
|
||||
<ui-skeleton-loader *ngFor="let skeletons of createSkeletons()"></ui-skeleton-loader>
|
||||
</ng-container>
|
||||
|
||||
<ng-template #contentLoader>
|
||||
<ui-content-loader [loading]="loading"></ui-content-loader>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
|
||||
<div *ngIf="!loading" class="spacer"></div>
|
||||
</div>
|
||||
@@ -0,0 +1,20 @@
|
||||
.scroll-container {
|
||||
@apply h-full overflow-y-scroll relative grid grid-flow-row gap-3;
|
||||
max-height: calc(100vh - 280px);
|
||||
}
|
||||
|
||||
.spacer {
|
||||
height: 140px;
|
||||
}
|
||||
|
||||
::ng-deep ui-scroll-container .scroll-bar::-webkit-scrollbar {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
::ng-deep ui-scroll-container .scroll-bar::-webkit-scrollbar-track {
|
||||
background-color: white !important;
|
||||
}
|
||||
|
||||
.scrollbar-gap::-webkit-scrollbar-track {
|
||||
margin-bottom: 10rem;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ScrollContainerComponent } from './scroll-container.component';
|
||||
|
||||
describe('ScrollContainerComponent', () => {
|
||||
let component: ScrollContainerComponent;
|
||||
let fixture: ComponentFixture<ScrollContainerComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ScrollContainerComponent],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ScrollContainerComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,60 @@
|
||||
import { ChangeDetectionStrategy, Component, ElementRef, EventEmitter, Input, Output, ViewChild } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'ui-scroll-container',
|
||||
templateUrl: 'scroll-container.component.html',
|
||||
styleUrls: ['scroll-container.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class UiScrollContainerComponent {
|
||||
@ViewChild('scrollContainer', { read: ElementRef, static: false })
|
||||
scrollContainer: ElementRef;
|
||||
|
||||
@Output() reachEnd = new EventEmitter<void>();
|
||||
|
||||
@Output() reachStart = new EventEmitter<void>();
|
||||
|
||||
@Input()
|
||||
direction: 'horizontal' | 'vertical' = 'vertical';
|
||||
|
||||
@Input() deltaStart = 0;
|
||||
|
||||
@Input() deltaEnd = 0;
|
||||
|
||||
@Input() loading = false;
|
||||
|
||||
@Input() itemLength: number;
|
||||
|
||||
@Input() showScrollbar = true;
|
||||
|
||||
@Input() useLoadAnimation = true;
|
||||
|
||||
constructor() {}
|
||||
|
||||
createSkeletons() {
|
||||
if (this.itemLength && this.itemLength !== 0) {
|
||||
return Array.from(Array(this.itemLength - 1), (_, i) => i);
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
reachedEnd() {
|
||||
this.reachEnd.emit();
|
||||
}
|
||||
|
||||
reachedStart() {
|
||||
this.reachStart.emit();
|
||||
}
|
||||
|
||||
get scrollPersantage() {
|
||||
const scrollHeight = this.scrollContainer?.nativeElement?.scrollHeight - this.scrollContainer?.nativeElement?.clientHeight;
|
||||
if (scrollHeight === 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const scrollTop = this.scrollContainer?.nativeElement?.scrollTop;
|
||||
|
||||
return (100 / scrollHeight) * scrollTop;
|
||||
}
|
||||
}
|
||||
15
apps/ui/scroll-container/src/lib/scroll-container.module.ts
Normal file
15
apps/ui/scroll-container/src/lib/scroll-container.module.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { UiLoaderModule } from '@ui/loader';
|
||||
import { UiContentLoaderComponent } from '@ui/scroll-container';
|
||||
import { UiScrollContainerDirective } from './directives';
|
||||
import { UiScrollContainerComponent } from './scroll-container.component';
|
||||
import { UiSkeletonLoaderComponent } from './skeleton-loader';
|
||||
|
||||
@NgModule({
|
||||
declarations: [UiScrollContainerComponent, UiSkeletonLoaderComponent, UiContentLoaderComponent, UiScrollContainerDirective],
|
||||
imports: [CommonModule, UiIconModule, UiLoaderModule],
|
||||
exports: [UiScrollContainerComponent, UiScrollContainerDirective],
|
||||
})
|
||||
export class UiScrollContainerModule {}
|
||||
@@ -0,0 +1,3 @@
|
||||
// start:ng42.barrel
|
||||
export * from './skeleton-loader.component';
|
||||
// end:ng42.barrel
|
||||
@@ -56,3 +56,27 @@
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
::ng-deep .customer ui-skeleton-loader {
|
||||
.header {
|
||||
.left {
|
||||
@apply bg-inactive-customer !important;
|
||||
}
|
||||
|
||||
.right {
|
||||
@apply bg-inactive-customer !important;
|
||||
}
|
||||
}
|
||||
|
||||
.thumbnail {
|
||||
@apply bg-inactive-customer;
|
||||
}
|
||||
|
||||
.item {
|
||||
@apply bg-inactive-customer;
|
||||
}
|
||||
|
||||
.title {
|
||||
@apply bg-inactive-customer;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'ui-skeleton-loader',
|
||||
templateUrl: 'skeleton-loader.component.html',
|
||||
styleUrls: ['skeleton-loader.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class UiSkeletonLoaderComponent {
|
||||
constructor() {}
|
||||
}
|
||||
9
apps/ui/scroll-container/src/public-api.ts
Normal file
9
apps/ui/scroll-container/src/public-api.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
* Public API Surface of scroll-container
|
||||
*/
|
||||
|
||||
export * from './lib/directives';
|
||||
export * from './lib/skeleton-loader';
|
||||
export * from './lib/content-loader';
|
||||
export * from './lib/scroll-container.component';
|
||||
export * from './lib/scroll-container.module';
|
||||
24
apps/ui/scroll-container/src/test.ts
Normal file
24
apps/ui/scroll-container/src/test.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||
|
||||
import 'zone.js/dist/zone';
|
||||
import 'zone.js/dist/zone-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());
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
||||
25
apps/ui/scroll-container/tsconfig.lib.json
Normal file
25
apps/ui/scroll-container/tsconfig.lib.json
Normal file
@@ -0,0 +1,25 @@
|
||||
/* 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"
|
||||
]
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"skipTemplateCodegen": true,
|
||||
"strictMetadataEmit": true,
|
||||
"enableResourceInlining": true
|
||||
},
|
||||
"exclude": [
|
||||
"src/test.ts",
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
||||
10
apps/ui/scroll-container/tsconfig.lib.prod.json
Normal file
10
apps/ui/scroll-container/tsconfig.lib.prod.json
Normal file
@@ -0,0 +1,10 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "./tsconfig.lib.json",
|
||||
"compilerOptions": {
|
||||
"declarationMap": false
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"enableIvy": false
|
||||
}
|
||||
}
|
||||
17
apps/ui/scroll-container/tsconfig.spec.json
Normal file
17
apps/ui/scroll-container/tsconfig.spec.json
Normal file
@@ -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"
|
||||
]
|
||||
}
|
||||
17
apps/ui/scroll-container/tslint.json
Normal file
17
apps/ui/scroll-container/tslint.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"extends": "../../../tslint.json",
|
||||
"rules": {
|
||||
"directive-selector": [
|
||||
true,
|
||||
"attribute",
|
||||
"lib",
|
||||
"camelCase"
|
||||
],
|
||||
"component-selector": [
|
||||
true,
|
||||
"element",
|
||||
"lib",
|
||||
"kebab-case"
|
||||
]
|
||||
}
|
||||
}
|
||||
83
package-lock.json
generated
83
package-lock.json
generated
@@ -4819,6 +4819,30 @@
|
||||
"requires": {
|
||||
"is-extendable": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"fill-range": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
||||
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"to-regex-range": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"is-number": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||
"dev": true
|
||||
},
|
||||
"to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-number": "^7.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -7644,29 +7668,6 @@
|
||||
"schema-utils": "^2.6.5"
|
||||
}
|
||||
},
|
||||
"fill-range": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://pkgs.dev.azure.com/hugendubel/_packaging/hugendubel/npm/registry/fill-range/-/fill-range-4.0.0.tgz",
|
||||
"integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"extend-shallow": "^2.0.1",
|
||||
"is-number": "^3.0.0",
|
||||
"repeat-string": "^1.6.1",
|
||||
"to-regex-range": "^2.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"extend-shallow": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://pkgs.dev.azure.com/hugendubel/_packaging/hugendubel/npm/registry/extend-shallow/-/extend-shallow-2.0.1.tgz",
|
||||
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-extendable": "^0.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"finalhandler": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
|
||||
@@ -9396,26 +9397,6 @@
|
||||
"integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==",
|
||||
"dev": true
|
||||
},
|
||||
"is-number": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://pkgs.dev.azure.com/hugendubel/_packaging/hugendubel@Local/npm/registry/is-number/-/is-number-3.0.0.tgz",
|
||||
"integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"kind-of": "^3.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"kind-of": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://pkgs.dev.azure.com/hugendubel/_packaging/hugendubel@Local/npm/registry/kind-of/-/kind-of-3.2.2.tgz",
|
||||
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-buffer": "^1.1.5"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"is-number-object": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz",
|
||||
@@ -18478,22 +18459,6 @@
|
||||
"safe-regex": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"to-regex-range": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://pkgs.dev.azure.com/hugendubel/_packaging/hugendubel@Local/npm/registry/to-regex-range/-/to-regex-range-2.1.1.tgz",
|
||||
"integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"repeat-string": "^1.6.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"is-number": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"toidentifier": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
|
||||
|
||||
@@ -265,7 +265,13 @@
|
||||
"apps/ui/select-bullet/src/public-api.ts"
|
||||
],
|
||||
"@page/goods-out": [
|
||||
"apps/page/goods-out//src/public-api.ts"
|
||||
"apps/page/goods-out/src/public-api.ts"
|
||||
],
|
||||
"@ui/scroll-container": [
|
||||
"apps/ui/scroll-container/src/public-api.ts"
|
||||
],
|
||||
"@ui/loader": [
|
||||
"apps/ui/loader/src/public-api.ts"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user