1
0
Эх сурвалжийг харах

refactor(admin-ui): Create BaseListComponent to share list logic

Michael Bromley 7 жил өмнө
parent
commit
594dc51ddc

+ 1 - 1
admin-ui/src/app/administrator/components/administrator-list/administrator-list.component.html

@@ -7,7 +7,7 @@
     </vdr-ab-right>
 </vdr-action-bar>
 
-<vdr-data-table [items]="administrators$ | async"
+<vdr-data-table [items]="items$ | async"
                 [itemsPerPage]="itemsPerPage$ | async"
                 [totalItems]="totalItems$ | async"
                 [currentPage]="currentPage$ | async"

+ 12 - 55
admin-ui/src/app/administrator/components/administrator-list/administrator-list.component.ts

@@ -1,8 +1,8 @@
-import { Component, OnDestroy, OnInit } from '@angular/core';
+import { Component } from '@angular/core';
 import { ActivatedRoute, Router } from '@angular/router';
-import { combineLatest, Observable, Subject } from 'rxjs';
-import { map, takeUntil } from 'rxjs/operators';
+import { GetAdministrators, GetAdministrators_administrators_items } from 'shared/generated-types';
 
+import { BaseListComponent } from '../../../common/base-list.component';
 import { DataService } from '../../../data/providers/data.service';
 
 @Component({
@@ -10,58 +10,15 @@ import { DataService } from '../../../data/providers/data.service';
     templateUrl: './administrator-list.component.html',
     styleUrls: ['./administrator-list.component.scss'],
 })
-export class AdministratorListComponent implements OnInit, OnDestroy {
-    administrators$: Observable<any[]>;
-    totalItems$: Observable<number>;
-    itemsPerPage$: Observable<number>;
-    currentPage$: Observable<number>;
-    private destroy$ = new Subject<void>();
-
-    constructor(private dataService: DataService, private router: Router, private route: ActivatedRoute) {}
-
-    ngOnInit() {
-        const administratorsQuery = this.dataService.administrator.getAdministrators(10, 0);
-
-        const fetchPage = ([currentPage, itemsPerPage]: [number, number]) => {
-            const take = itemsPerPage;
-            const skip = (currentPage - 1) * itemsPerPage;
-            administratorsQuery.ref.refetch({ options: { skip, take } });
-        };
-
-        this.administrators$ = administratorsQuery.stream$.pipe(map(data => data.administrators.items));
-        this.totalItems$ = administratorsQuery.stream$.pipe(map(data => data.administrators.totalItems));
-        this.currentPage$ = this.route.queryParamMap.pipe(
-            map(qpm => qpm.get('page')),
-            map(page => (!page ? 1 : +page)),
+export class AdministratorListComponent extends BaseListComponent<
+    GetAdministrators,
+    GetAdministrators_administrators_items
+> {
+    constructor(private dataService: DataService, router: Router, route: ActivatedRoute) {
+        super(router, route);
+        super.setQueryFn(
+            (...args: any[]) => this.dataService.administrator.getAdministrators(...args),
+            data => data.administrators,
         );
-        this.itemsPerPage$ = this.route.queryParamMap.pipe(
-            map(qpm => qpm.get('perPage')),
-            map(perPage => (!perPage ? 10 : +perPage)),
-        );
-
-        combineLatest(this.currentPage$, this.itemsPerPage$)
-            .pipe(takeUntil(this.destroy$))
-            .subscribe(fetchPage);
-    }
-
-    ngOnDestroy() {
-        this.destroy$.next();
-        this.destroy$.complete();
-    }
-
-    setPageNumber(page: number) {
-        this.setQueryParam('page', page);
-    }
-
-    setItemsPerPage(perPage: number) {
-        this.setQueryParam('perPage', perPage);
-    }
-
-    private setQueryParam(key: string, value: any) {
-        this.router.navigate(['./'], {
-            queryParams: { [key]: value },
-            relativeTo: this.route,
-            queryParamsHandling: 'merge',
-        });
     }
 }

+ 1 - 1
admin-ui/src/app/catalog/components/facet-list/facet-list.component.html

@@ -7,7 +7,7 @@
     </vdr-ab-right>
 </vdr-action-bar>
 
-<vdr-data-table [items]="facets$ | async"
+<vdr-data-table [items]="items$ | async"
                 [itemsPerPage]="itemsPerPage$ | async"
                 [totalItems]="totalItems$ | async"
                 [currentPage]="currentPage$ | async"

+ 7 - 57
admin-ui/src/app/catalog/components/facet-list/facet-list.component.ts

@@ -1,9 +1,8 @@
-import { Component, OnDestroy, OnInit } from '@angular/core';
+import { Component } from '@angular/core';
 import { ActivatedRoute, Router } from '@angular/router';
-import { combineLatest, Observable, Subject } from 'rxjs';
-import { map, takeUntil } from 'rxjs/operators';
-import { GetFacetList_facets_items } from 'shared/generated-types';
+import { GetFacetList, GetFacetList_facets_items } from 'shared/generated-types';
 
+import { BaseListComponent } from '../../../common/base-list.component';
 import { DataService } from '../../../data/providers/data.service';
 
 @Component({
@@ -11,58 +10,9 @@ import { DataService } from '../../../data/providers/data.service';
     templateUrl: './facet-list.component.html',
     styleUrls: ['./facet-list.component.scss'],
 })
-export class FacetListComponent implements OnInit, OnDestroy {
-    facets$: Observable<GetFacetList_facets_items[]>;
-    totalItems$: Observable<number>;
-    itemsPerPage$: Observable<number>;
-    currentPage$: Observable<number>;
-    private destroy$ = new Subject<void>();
-
-    constructor(private dataService: DataService, private router: Router, private route: ActivatedRoute) {}
-
-    ngOnInit() {
-        const facetsQuery = this.dataService.facet.getFacets(10, 0);
-
-        const fetchPage = ([currentPage, itemsPerPage]: [number, number]) => {
-            const take = itemsPerPage;
-            const skip = (currentPage - 1) * itemsPerPage;
-            facetsQuery.ref.refetch({ options: { skip, take } });
-        };
-
-        this.facets$ = facetsQuery.stream$.pipe(map(data => data.facets.items));
-        this.totalItems$ = facetsQuery.stream$.pipe(map(data => data.facets.totalItems));
-        this.currentPage$ = this.route.queryParamMap.pipe(
-            map(qpm => qpm.get('page')),
-            map(page => (!page ? 1 : +page)),
-        );
-        this.itemsPerPage$ = this.route.queryParamMap.pipe(
-            map(qpm => qpm.get('perPage')),
-            map(perPage => (!perPage ? 10 : +perPage)),
-        );
-
-        combineLatest(this.currentPage$, this.itemsPerPage$)
-            .pipe(takeUntil(this.destroy$))
-            .subscribe(fetchPage);
-    }
-
-    ngOnDestroy() {
-        this.destroy$.next();
-        this.destroy$.complete();
-    }
-
-    setPageNumber(page: number) {
-        this.setQueryParam('page', page);
-    }
-
-    setItemsPerPage(perPage: number) {
-        this.setQueryParam('perPage', perPage);
-    }
-
-    private setQueryParam(key: string, value: any) {
-        this.router.navigate(['./'], {
-            queryParams: { [key]: value },
-            relativeTo: this.route,
-            queryParamsHandling: 'merge',
-        });
+export class FacetListComponent extends BaseListComponent<GetFacetList, GetFacetList_facets_items> {
+    constructor(private dataService: DataService, router: Router, route: ActivatedRoute) {
+        super(router, route);
+        super.setQueryFn((...args: any[]) => this.dataService.facet.getFacets(...args), data => data.facets);
     }
 }

+ 1 - 1
admin-ui/src/app/catalog/components/product-list/product-list.component.html

@@ -7,7 +7,7 @@
     </vdr-ab-right>
 </vdr-action-bar>
 
-<vdr-data-table [items]="products$ | async"
+<vdr-data-table [items]="items$ | async"
                 [itemsPerPage]="itemsPerPage$ | async"
                 [totalItems]="totalItems$ | async"
                 [currentPage]="currentPage$ | async"

+ 10 - 56
admin-ui/src/app/catalog/components/product-list/product-list.component.ts

@@ -1,9 +1,9 @@
-import { Component, OnDestroy, OnInit } from '@angular/core';
+import { Component } from '@angular/core';
 import { ActivatedRoute, Router } from '@angular/router';
-import { combineLatest, Observable, Subject } from 'rxjs';
-import { map, takeUntil } from 'rxjs/operators';
-import { GetProductList_products_items } from 'shared/generated-types';
+import { Observable } from 'rxjs';
+import { GetProductList, GetProductList_products_items } from 'shared/generated-types';
 
+import { BaseListComponent } from '../../../common/base-list.component';
 import { DataService } from '../../../data/providers/data.service';
 
 @Component({
@@ -11,58 +11,12 @@ import { DataService } from '../../../data/providers/data.service';
     templateUrl: './product-list.component.html',
     styleUrls: ['./product-list.component.scss'],
 })
-export class ProductListComponent implements OnInit, OnDestroy {
-    products$: Observable<GetProductList_products_items[]>;
-    totalItems$: Observable<number>;
-    itemsPerPage$: Observable<number>;
-    currentPage$: Observable<number>;
-    private destroy$ = new Subject<void>();
-
-    constructor(private dataService: DataService, private router: Router, private route: ActivatedRoute) {}
-
-    ngOnInit() {
-        const productsQuery = this.dataService.product.getProducts(10, 0);
-
-        const fetchPage = ([currentPage, itemsPerPage]: [number, number]) => {
-            const take = itemsPerPage;
-            const skip = (currentPage - 1) * itemsPerPage;
-            productsQuery.ref.refetch({ options: { skip, take } });
-        };
-
-        this.products$ = productsQuery.stream$.pipe(map(data => data.products.items));
-        this.totalItems$ = productsQuery.stream$.pipe(map(data => data.products.totalItems));
-        this.currentPage$ = this.route.queryParamMap.pipe(
-            map(qpm => qpm.get('page')),
-            map(page => (!page ? 1 : +page)),
+export class ProductListComponent extends BaseListComponent<GetProductList, GetProductList_products_items> {
+    constructor(private dataService: DataService, router: Router, route: ActivatedRoute) {
+        super(router, route);
+        super.setQueryFn(
+            (...args: any[]) => this.dataService.product.getProducts(...args),
+            data => data.products,
         );
-        this.itemsPerPage$ = this.route.queryParamMap.pipe(
-            map(qpm => qpm.get('perPage')),
-            map(perPage => (!perPage ? 10 : +perPage)),
-        );
-
-        combineLatest(this.currentPage$, this.itemsPerPage$)
-            .pipe(takeUntil(this.destroy$))
-            .subscribe(fetchPage);
-    }
-
-    ngOnDestroy() {
-        this.destroy$.next();
-        this.destroy$.complete();
-    }
-
-    setPageNumber(page: number) {
-        this.setQueryParam('page', page);
-    }
-
-    setItemsPerPage(perPage: number) {
-        this.setQueryParam('perPage', perPage);
-    }
-
-    private setQueryParam(key: string, value: any) {
-        this.router.navigate(['./'], {
-            queryParams: { [key]: value },
-            relativeTo: this.route,
-            queryParamsHandling: 'merge',
-        });
     }
 }

+ 84 - 0
admin-ui/src/app/common/base-list.component.ts

@@ -0,0 +1,84 @@
+import { OnDestroy, OnInit } from '@angular/core';
+import { ActivatedRoute, Router } from '@angular/router';
+import { combineLatest, Observable, Subject } from 'rxjs';
+import { map, takeUntil } from 'rxjs/operators';
+
+import { QueryResult } from '../data/query-result';
+
+export type ListQueryFn<R> = (...args: any[]) => QueryResult<R>;
+export type MappingFn<T, R> = (result: R) => { items: T[]; totalItems: number };
+
+/**
+ * This is a base class which implements the logic required to fetch and manipluate
+ * a list of data from a query which returns a PaginatedList type.
+ */
+export class BaseListComponent<ResultType, ItemType> implements OnInit, OnDestroy {
+    items$: Observable<ItemType[]>;
+    totalItems$: Observable<number>;
+    itemsPerPage$: Observable<number>;
+    currentPage$: Observable<number>;
+    private destroy$ = new Subject<void>();
+    private listQueryFn: ListQueryFn<ResultType>;
+    private mappingFn: MappingFn<ItemType, ResultType>;
+
+    constructor(private router: Router, private route: ActivatedRoute) {}
+
+    /**
+     * Sets the fetch function for the list being implemented.
+     */
+    setQueryFn(listQueryFn: ListQueryFn<ResultType>, mappingFn: MappingFn<ItemType, ResultType>) {
+        this.listQueryFn = listQueryFn;
+        this.mappingFn = mappingFn;
+    }
+
+    ngOnInit() {
+        if (!this.listQueryFn) {
+            throw new Error(
+                `No listQueryFn has been defined. Please call super.setQueryFn() in the constructor.`,
+            );
+        }
+        const listQuery = this.listQueryFn(10, 0);
+
+        const fetchPage = ([currentPage, itemsPerPage]: [number, number]) => {
+            const take = itemsPerPage;
+            const skip = (currentPage - 1) * itemsPerPage;
+            listQuery.ref.refetch({ options: { skip, take } });
+        };
+
+        this.items$ = listQuery.stream$.pipe(map(data => this.mappingFn(data).items));
+        this.totalItems$ = listQuery.stream$.pipe(map(data => this.mappingFn(data).totalItems));
+        this.currentPage$ = this.route.queryParamMap.pipe(
+            map(qpm => qpm.get('page')),
+            map(page => (!page ? 1 : +page)),
+        );
+        this.itemsPerPage$ = this.route.queryParamMap.pipe(
+            map(qpm => qpm.get('perPage')),
+            map(perPage => (!perPage ? 10 : +perPage)),
+        );
+
+        combineLatest(this.currentPage$, this.itemsPerPage$)
+            .pipe(takeUntil(this.destroy$))
+            .subscribe(fetchPage);
+    }
+
+    ngOnDestroy() {
+        this.destroy$.next();
+        this.destroy$.complete();
+    }
+
+    setPageNumber(page: number) {
+        this.setQueryParam('page', page);
+    }
+
+    setItemsPerPage(perPage: number) {
+        this.setQueryParam('perPage', perPage);
+    }
+
+    private setQueryParam(key: string, value: any) {
+        this.router.navigate(['./'], {
+            queryParams: { [key]: value },
+            relativeTo: this.route,
+            queryParamsHandling: 'merge',
+        });
+    }
+}